JPA复杂查询时间查询分页排序

JPA复杂查询时间查询分页排序

JPA复杂查询时间查询分页排序,工作上用到,因为项目是jpa,记录。代码囊括了:查询条件+时间范围+分页+排序
其实我也不太想用jpa,但是他也有优点,操作可以兼容多种数据库,mybatis也能,需要额外写代码。但我还是喜欢mybatis

public ResponseResultPage<AlarmEventHistoryPo> getHistory(String eventId, Integer page, Integer size, String startTime, String endTime, Boolean onlyHealthy) {
        //直接使用匿名内部类实现接口
        Specification<AlarmEventHistoryPo> specification = new Specification<AlarmEventHistoryPo>() {
            @Override
            public Predicate toPredicate(Root<AlarmEventHistoryPo> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicateList = new ArrayList<>();
                // 根据字段
                predicateList.add(cb.equal(root.get("eventId").as(String.class), eventId));

                // 开始时间
                if (StringUtils.isNotEmpty(startTime)) {
                    predicateList.add(cb.greaterThanOrEqualTo(root.get("createDate").as(String.class), startTime));
                }
                // 结束时间
                if (StringUtils.isNotEmpty(endTime)) {
                    predicateList.add(cb.lessThanOrEqualTo(root.get("createDate").as(String.class), endTime));
                }

                if (onlyHealthy != null && onlyHealthy) {// and ( pre or pre )
                    Predicate pred1 = cb.equal(root.get("type").as(String.class), "auto_healthy");
                    Predicate pred2 = cb.equal(root.get("type").as(String.class), "user_healthy");
                    predicateList.add(cb.or(pred1, pred2));
                }

                Predicate[] pre = new Predicate[predicateList.size()];
                pre = predicateList.toArray(pre);
                return query.where(pre).getRestriction();
            }
        };

        // 分页 + 排序
        Pageable pageable = PageRequest.of(page - 1, size, new Sort(Sort.Direction.DESC, "createDate"));
        Page<AlarmEventHistoryPo> alarmEventHistoryPos = alarmEventHistoryPoDao.findAll(specification, pageable);
        if (alarmEventHistoryPos == null) {
            return new ResponseResultPage<>(null);
        }
}        
@Repository
public interface AlarmEventHistoryPoDao extends JpaRepository<AlarmEventHistoryPo, String> {
    Page<AlarmEventHistoryPo> findAll(Specification specification, Pageable pageable);
}

2022年7月18日 追加修改----------------------↓↓↓↓↓↓↓↓↓↓

我发现有同学收藏点赞,在高版本hibernate已经注解弃用,不建议使用以上的方式,jpa没有模板引擎,整合其他模板引擎就太复杂。个人建议简单封装Query查询即可,例如下面这样:

import cn.hutool.core.collection.CollUtil;
import org.hibernate.Session;
import org.hibernate.query.Query;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author lingkang
 * Created by 2022/7/18
 * 封装原因:jpa整合模板引擎太复杂
 */
public class ComplexQueryUtils {
    /**
     * 对复杂查询的简单封装,有SQL注入处理
     * 若有入参,应该从 ?, ?, ? ... 算起, 例如 condition.put(" and vo.id = ?","svcrvtf-0qdYxo4q");
     *
     * @param session
     * @param sql
     * @param condition
     * @return
     */
    public static Query query(Session session, String sql, LinkedHashMap<String, Object> condition) {
        if (CollUtil.isEmpty(condition)) {
            return session.createQuery(sql);
        }
        StringBuilder sqlBuilder = new StringBuilder(sql);
        for (Map.Entry<String, Object> entry : condition.entrySet())
            sqlBuilder.append(entry.getKey());

        // 将 ? ? ? 替换成 ?1 ?2 ?3
        int i = 1;
        int index = sqlBuilder.indexOf("?");
        if (index != -1)
            for (; ; ) {
                sqlBuilder.replace(index, ++index, "?" + i++);
                index = sqlBuilder.indexOf("?", index);
                if (index == -1)
                    break;
            }
        Query query = session.createQuery(sqlBuilder.toString());
        i = 1;
        for (Map.Entry<String, Object> entry : condition.entrySet())
            if (entry.getValue() != null) {
                query.setParameter(i++, entry.getValue());
            }
        return query;
    }
}

使用方法:

        TenantVo tenant = UserUtils.getCurrentTenant();
        LinkedHashMap<String, Object> condition = new LinkedHashMap<>();
        if (tenant != null) {
            condition.put(" and fv.tenantId='" + tenant.getId() + "'", null);// 存在SQL注入
        }
        condition.put(" and vo.id = ?1","svcrvtf-0qdYxo4q");// SQL注入过滤

        // AFA
        List<ServiceVersionResourceVersionToFileVO> afa = ComplexQueryUtils.query(
                serviceDao.getSession(),
                "select vo from service vo left join File fv on vo.file.id=fv.id" +
                        " where vo.serviceVersion.service.id is not null" +
                        " and fv.id is not null ",
                condition
        )
                // .setFirstResult(9).setMaxResults(10)// 分页,第 10到20条数据
                .list();
posted @ 2022-09-16 00:08  凌康  阅读(215)  评论(0编辑  收藏  举报