当前位置: 首页 > news >正文

SpringJPA使用崩溃了

环境

JDK11
SpringBoot 2.7.11
querydsl 5.0.0
mysql-connector-j 8.0.33

前言

使用获MybatisPlus的同学,当遇到SpringJPA的项目,那真的崩溃。构建一个条件,需要判断空,不判断就报错了,一行代码的事情,必须写三行。用过的都懂

解决办法

使用反射和dsl封装一下。只要写一个入参的类,就可以构造出查询条件直接查询,免去了繁琐的if判断

测试类如下

构造查询参数BookQuery ,使用封装的QObject 构造查询参数直接查询

@SpringBootTest
public class BookRepositoryTest extends TestCommon {@ResourceBookRepository bookRepository;@ResourceJPAQueryFactory queryFactory;@Testvoid repo() {// 构造查询参数BookQuery bookQuery = new BookQuery();bookQuery.setRange(Range.between(15, 20));// 查询QObject qry = new QObject(BookJpa.class, bookQuery);Predicate exp = qry.predicate();System.out.println(exp);System.out.println(bookRepository.findAll(exp));}@Testvoid fact() throws ParseException {// 构造查询参数BookQuery bookQuery = new BookQuery();bookQuery.setRange(Range.between(15, 20));bookQuery.setDayRange(Range.between(DateFormatUtils.ISO_8601_EXTENDED_DATE_FORMAT.parse("2024-12-30"), DateFormatUtils.ISO_8601_EXTENDED_DATE_FORMAT.parse("2024-12-31")));// 查询QObject qry = new QObject(BookJpa.class, bookQuery);Predicate exp = qry.predicate();System.out.println(exp);List<?> list = queryFactory.from(qry).where(exp).offset(1).limit(3).fetch();System.out.println(list);}
}

关键代码

  • QObject
public class QObject extends EntityPathBase<Object> {private Object queryParam;public QObject(Class<?> clazz, Object queryParam) {super(clazz, variable(clazz));this.queryParam = queryParam;}static String variable(Class<?> clazz) {char[] charArray = clazz.getSimpleName().toCharArray();charArray[0] = Character.toLowerCase(charArray[0]);return String.valueOf(charArray);}@Overridepublic BooleanPath createBoolean(String property) {return super.createBoolean(property);}@Overridepublic <A extends Enum<A>> EnumPath<A> createEnum(String property, Class<A> type) {return super.createEnum(property, type);}@Overridepublic <A extends Comparable> DatePath<A> createDate(String property, Class<? super A> type) {return super.createDate(property, type);}@Overridepublic <A extends Comparable> DateTimePath<A> createDateTime(String property, Class<? super A> type) {return super.createDateTime(property, type);}@Overridepublic <A extends Number & Comparable<?>> NumberPath<A> createNumber(String property, Class<? super A> type) {return super.createNumber(property, type);}@Overridepublic StringPath createString(String property) {return super.createString(property);}public <A extends Comparable> ComparablePath<A> createComparable(String property, Class<? super A> type) {return super.createComparable(property, type);}@Overridepublic <A extends Comparable> TimePath<A> createTime(String property, Class<? super A> type) {return super.createTime(property, type);}public <T> Predicate predicate() {return QueryUtils.predicate(queryParam, this);}
}
  • QueryUtils
public class QueryUtils {public static <T> Predicate predicate(Object param, Class<T> clazz) {QObject q = new QObject(clazz, param);return predicate(param, q);}public static Predicate predicate(Object param, QObject q) {Predicate qr = null;Field[] fields = FieldUtils.getAllFields(param.getClass());try {for (Field field : fields) {field.setAccessible(true);String name = field.getName();Class<Comparable<?>> type = (Class<Comparable<?>>) field.getType();Object value = field.get(param);if (ObjectUtil.isNotEmpty(value)) {if (value instanceof Range) {Range<? extends Comparable> range = (Range) value;type = (Class<Comparable<?>>) range.getMaximum().getClass();qr = ExpressionUtils.and(qr, q.createComparable(name, type).between(range.getMinimum(), range.getMaximum()));} else if (value instanceof Comparable) {qr = ExpressionUtils.and(qr, q.createComparable(name, type).in((Comparable) value));} else if (value instanceof Collection) {Collection<? extends Comparable<?>> collection = (Collection<? extends Comparable<?>>) value;type = (Class<Comparable<?>>) collection.iterator().next().getClass();qr = ExpressionUtils.and(qr, q.createComparable(name, type).in(collection));} else if (value.getClass().isArray()) {Collection<? extends Comparable<?>> collection = Arrays.stream(((Object[]) value)).map(item -> (Comparable<?>) item).collect(Collectors.toList());type = (Class<Comparable<?>>) collection.iterator().next().getClass();qr = ExpressionUtils.and(qr, q.createComparable(name, type).in(collection));}}}} catch (Exception e) {throw new RuntimeException(e);}return qr;}
}
  • BookQuery

import lombok.Data;import java.util.Date;
import java.util.List;/*** @author dzh* @since 2024/12/30*/
@Data
public class BookQuery {private List<Long> id;private List<String> title;private Range<Integer> range;private Range<Date> dayRange;
}
  • BookJpa

import lombok.Data;import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;/*** @author dzh* @since 2024/12/30*/
@Data
@Entity
@Table(name = "book")
public class BookJpa {@Idprivate Long id;private String title;private Integer range;private Date dayRange;
}
  • BookRepository

import com.db.entity.BookJpa;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;@Repository
public interface BookRepository extends JpaRepository<BookJpa,Integer>, QuerydslPredicateExecutor<BookJpa> {
}
  • Range
package com.db.query;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** 区间* @author dzh* @since 2024/12/31*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Range<T> {private T minimum;private T maximum;
}

总结

毕竟是封装的功能,肯定没有原始的灵活,但是这个已经解决了项目中95%以上的查询逻辑。
有人说反射耗费性能,可以自行增加缓存,或者调用有缓存的工具类


http://www.mrgr.cn/news/82024.html

相关文章:

  • Requests库02|Cookie和Session
  • GraphRAG: 一种结合图结构和检索增强生成的工程实现思路
  • Python 字符串定义及前缀
  • C++ 设计模式:工厂方法(Factory Method)
  • 04-微服务02
  • 【UE5 C++课程系列笔记】15——Assert的基本使用
  • Web安全 - “Referrer Policy“ Security 头值不安全
  • RK3568 bsp 9 - USB调试记录
  • 深度学习blog- 数学基础(全是数学)
  • C++类与对象(三)-- 再谈构造函数(细嗦初始化列表)、static成员
  • 《机器学习》从入门到实战——逻辑回归
  • 机器学习之逻辑回归算法、数据标准化处理及数据预测和数据的分类结果报告
  • JDK 21 的重要特性
  • Java方法使用详解:从基本概念到进阶技巧
  • 一个响应式的系统 具有黑白俩个主题
  • 学习vue3的笔记
  • Vue 中el-table-column 进行循环,页面没渲染成功
  • 基本算法——聚类
  • Android原生Widget使用步骤
  • Unity开发AR之Vuforia-MultiTarget笔记
  • 在React中引入tailwind css(图文详解)
  • 刷机TP-Link tp-link-WDR5660
  • 打印进度条
  • vue下载和上传的地址动态ip地址配置方法
  • sentinel-请求限流、线程隔离、本地回调、熔断
  • SAP SD信贷管理后台配置(上)