JPA多条件查询

本文详细解析了一个用于查询任务列表的API实现,包括控制器、实现层和服务层的代码细节。介绍了如何通过POST请求获取不同类型的任务列表,如清点、验收和消毒任务,并展示了如何使用JPA进行分页查询和条件过滤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.controller
/**
	 * 	获取查询任务列表
	 *  <p>type为任务类型,1清点,2验收,3验收,4消毒
	 */
	@PostMapping(value = "/listPage/{type}")
	public EasyUIPagination getPageStorageTaskList(@PathVariable("type") Integer type, SterilizeTaskVo sterilizeTaskVo,
											   QueryTaskListVo params) throws Exception
	{
		Page<InventoryCheckTaskListVo> page = storageTaskService.getPageStorageTaskList(type,sterilizeTaskVo,params);
		return PageToPaginationUtil.toPagination(page);
	}
2.impl
@Override
	public Page<InventoryCheckTaskListVo> getPageStorageTaskList(Integer type, SterilizeTaskVo sterilizeTaskVo, QueryTaskListVo params) throws Exception {
		//分页
		Pageable pageable = JpaUtil.getPagebleBySort(params.getOrder(), params.getSort(),
				params.getPage(), params.getRows());

		//查询条件
		Specification<InventoryCheckTask> spec = (root, query, cb) -> {
			List<Predicate> list = new ArrayList<>();
			//任务类型
			if (type != null) {
				Predicate typePre = cb.equal(root.get("taskType").as(Integer.class), type);
				list.add(typePre);
			}
			//所属客户
			if (StringUtils.isNotBlank(sterilizeTaskVo.getCustomer())) {
				list.add(cb.equal(root.get("customer").get("id").as(String.class), sterilizeTaskVo.getCustomer()));
			}
			//所属机构模糊查询
			if (StringUtils.isNotBlank(sterilizeTaskVo.getCustomerOrgName())) {
				list.add(cb.like(root.get("customerOrg").get("name").as(String.class), "%"+sterilizeTaskVo.getCustomerOrgName()+"%"));
			}
			//所属状态
			if (StringUtils.isNotBlank(sterilizeTaskVo.getStatus())) {
				list.add(cb.equal(root.get("status").as(Integer.class), sterilizeTaskVo.getStatus()));
			}
			//开始日期
			if (StringUtils.isNotBlank(sterilizeTaskVo.getSterilizeTimeStart())) {
				list.add(cb.greaterThanOrEqualTo(root.get("createDate").as(String.class), sterilizeTaskVo.getSterilizeTimeStart()));
			}
			//结束日期
			if (StringUtils.isNotBlank(sterilizeTaskVo.getSterilizeTimeEnd())) {
				//日期加1
				DateTimeFormatter timeDtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
				LocalDate localDate = LocalDate.parse(sterilizeTaskVo.getSterilizeTimeEnd(), timeDtf);
				String tmp = localDate.plusDays(1).format(timeDtf);
				list.add(cb.lessThan(root.get("createDate").as(String.class), tmp));
			}
			return cb.and(list.toArray(new Predicate[list.size()]));
		};
		//查询结果
		Page<InventoryCheckTask> page = inventoryCheckTaskRepository.findAll(spec, pageable);

		if(page==null || page.getTotalElements()<1) {
			return new PageImpl<>(new ArrayList<>(0), pageable, 0);
		}

		List<InventoryCheckTask> lists = page.getContent();

		if(lists!=null && lists.size()>0) {

			List<InventoryCheckTaskListVo> arr = InventoryCheckTaskListVo.taskData2Vo(lists);
			return new PageImpl<>(arr, pageable, page.getTotalElements());
		}
		return new PageImpl<>(new ArrayList<>(0), pageable, 0);
	}
3.JPAUtil
public class JpaUtil {
	
	/**
	 * 获取排序分页查询条件
	 * @param order		升序降序
	 * @param sortStr	字段
	 * @param page		页数
	 * @param rows		条数
	 * @return	
	 */
	public static Pageable getPagebleBySort(String order,String sortStr,Integer page,Integer rows) {
		Sort sort = null;
		Pageable pageable = null;
		if(sortStr!=null && !"".equals(sortStr))
		{
			if(order==null || "".equals(order)){
				sort = Sort.by(Sort.Direction.ASC, sortStr);
			}else{
				sort = Sort.by(Sort.Direction.fromString(order), sortStr);
			}
			pageable = PageRequest.of(page - 1, rows,sort);
		}else {
			pageable = PageRequest.of(page - 1, rows);
		}
		return pageable;
	}

	/**
	 * 获取排序分页查询条件
	 * @param pageParams 分页封装参数
	 * @return	
	 */
	public static Pageable getPagebleByPageParams(EasyUIPagingationParam pageParams) {
		return getPagebleBySort(
				pageParams.getOrder(),
				pageParams.getSort(),
				pageParams.getPage(),
				pageParams.getRows());
	}
}
### JPA 多条件查询的实现方式与示例 在 JPA 中,多条件查询可以通过多种方式进行实现。以下是几种常用的方式及其具体实现示例。 --- #### 1. 使用 `Criteria API` 进行动态查询 `Criteria API` 是一种类型安全的方式来构建动态查询。它允许开发者通过编程方式创建查询条件,非常适合复杂的多条件查询场景[^1]。 ```java @Service public class OrgService { @Autowired private OrgRepository orgRepository; public Page<OrgInfo> findOrgByCondition(OrgParam orgParam, Pageable pageable) { return orgRepository.findAll((root, query, cb) -> { List<Predicate> predicates = new ArrayList<>(); if (!StringUtils.isEmpty(orgParam.getFlag())) { predicates.add(cb.equal(root.get("flag"), orgParam.getFlag())); } if (!StringUtils.isEmpty(orgParam.getParentId())) { predicates.add(cb.equal(root.get("parentId"), orgParam.getParentId())); } if (!StringUtils.isEmpty(orgParam.getName())) { predicates.add(cb.like(root.get("name"), orgParam.getName() + "%")); } if (orgParam.getMinSeqno() != null && orgParam.getMaxSeqno() != null) { predicates.add(cb.between(root.get("seqno"), orgParam.getMinSeqno(), orgParam.getMaxSeqno())); } return cb.and(predicates.toArray(new Predicate[0])); }, pageable); } } ``` 在这个例子中,`Predicates` 被用来存储所有的查询条件,并最终通过 `cb.and()` 将它们组合成一个完整的查询条件[^1]。 --- #### 2. 使用 `Specification` 接口进行封装 `Specification` 是 Spring Data JPA 对 `Criteria API` 的进一步抽象,使得我们可以更容易地重用查询逻辑[^2]。 ```java public class MerchantSpecs { public static Specification<Merchant> withAccountAndDisplay(Merchant merchant) { return (root, query, cb) -> { List<Predicate> predicates = new ArrayList<>(); if (merchant.getAccount() != null) { predicates.add(cb.like(root.get("account"), "%" + merchant.getAccount() + "%")); } if (merchant.getDisplay() != null) { predicates.add(cb.equal(root.get("display"), merchant.getDisplay())); } return cb.and(predicates.toArray(new Predicate[0])); }; } } @Service public class MerchantService { @Autowired private MerchantRepository merchantRepository; public Page<Merchant> searchMerchants(Merchant merchant, Pageable pageable) { Specification<Merchant> spec = MerchantSpecs.withAccountAndDisplay(merchant); return merchantRepository.findAll(spec, pageable); } } ``` 在这里,`withAccountAndDisplay` 方法返回了一个 `Specification` 对象,该对象可以被多次复用以减少重复代码[^2]。 --- #### 3. 使用 JPQL 实现静态查询 JPQL(Java Persistence Query Language)是一种类似于 SQL 的查询语言,适合于较为固定的查询场景。虽然不如 `Criteria API` 和 `Specification` 那样灵活,但对于简单查询仍然非常有效[^3]。 ```java @Repository public interface UserRepository extends JpaRepository<User, Long> { @Query("SELECT u FROM User u WHERE (:username IS NULL OR u.username LIKE %:username%) AND (:age IS NULL OR u.age BETWEEN :minAge AND :maxAge)") List<User> findByDynamicConditions(@Param("username") String username, @Param("age") Integer minAge, @Param("age") Integer maxAge); } ``` 这个例子展示了如何使用参数化查询来支持部分条件匹配的情况。注意这里的占位符 `(:param IS NULL ...)` 可以帮助避免因某些条件为空而导致的错误[^3]。 --- #### 4. 结合 Native Query 实现复杂查询 如果 JPQL 不足以满足需求,或者需要执行特定数据库的功能时,可以选择使用原生 SQL 查询[^3]。 ```java @Repository public interface UserRepository extends JpaRepository<User, Long> { @Query(value = "SELECT * FROM users WHERE username LIKE ?1%", nativeQuery = true) List<User> findUsersByUsernameLike(String usernamePrefix); } ``` 尽管这种方法失去了 ORM 的一些优势,但在特殊情况下可能是唯一的选择[^3]。 --- ### 注意事项 - **性能优化**:无论采用哪种方式,都应注意查询效率问题。合理利用索引、分页等功能能够显著提升大规模数据环境下的表现。 - **安全性**:当涉及用户输入的数据时,务必防止 SQL 注入攻击的发生。优先选用预编译语句或框架内置的安全措施。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值