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 {
    @Resource
    BookRepository bookRepository;
    @Resource
    JPAQueryFactory queryFactory;

    @Test
    void 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));
    }

    @Test
    void 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);
    }

    @Override
    public BooleanPath createBoolean(String property) {
        return super.createBoolean(property);
    }

    @Override
    public <A extends Enum<A>> EnumPath<A> createEnum(String property, Class<A> type) {
        return super.createEnum(property, type);
    }

    @Override
    public <A extends Comparable> DatePath<A> createDate(String property, Class<? super A> type) {
        return super.createDate(property, type);
    }

    @Override
    public <A extends Comparable> DateTimePath<A> createDateTime(String property, Class<? super A> type) {
        return super.createDateTime(property, type);
    }

    @Override
    public <A extends Number & Comparable<?>> NumberPath<A> createNumber(String property, Class<? super A> type) {
        return super.createNumber(property, type);
    }

    @Override
    public 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);
    }

    @Override
    public <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 {
    @Id
    private 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%以上的查询逻辑。
有人说反射耗费性能,可以自行增加缓存,或者调用有缓存的工具类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值