JPA/Hibernate复用JPQL查询方案咨询(Quarkus Panache环境)
解决方案
针对你的需求,完全可以复用现有权限校验逻辑,不需要强制切换到Criteria查询,结合Quarkus Panache的特性,有以下几种可行方案:
1. 基于PanacheQuery的复用方案
利用Panache的查询拼接能力,把权限校验的NamedQuery作为基础,动态添加搜索条件:
步骤1:定义包含权限逻辑的基础NamedQuery
先把权限校验的WHERE条件封装成一个基础NamedQuery(比如命名为Employee.withAccessPermissions),只保留权限相关的条件,不包含搜索或ID查询的部分:
@Entity @NamedQuery(name = "Employee.withAccessPermissions", query = "SELECT e FROM Employee e " + "JOIN Company c ON c.id = e.companyId " + "WHERE EXISTS (" + " SELECT 1 FROM User u " + " WHERE u.companyId = c.id AND u.id = :currentUserId" + ") OR EXISTS (" + " SELECT 1 FROM Cooperation co " + " WHERE (co.companyAId = :userCompanyId AND co.companyBId = c.id) " + " OR (co.companyBId = :userCompanyId AND co.companyAId = c.id)" + ")") class Employee extends PanacheEntityBase { @Id String id; LocalDate dateOfBirth; String companyId; // 关联实体根据实际逻辑补充 }
步骤2:复用基础查询实现搜索和ID查询
通过Panache的find方法或PanacheQuery的链式调用,在基础查询上动态添加条件:
实现搜索功能(companyId或dateOfBirth范围)
public PanacheQuery<Employee> searchEmployees(String currentUserId, String userCompanyId, String companyId, LocalDate startDate, LocalDate endDate) { PanacheQuery<Employee> query = Employee.find("#Employee.withAccessPermissions", Parameters.with("currentUserId", currentUserId) .and("userCompanyId", userCompanyId)); // 动态添加companyId过滤 if (companyId != null) { query = query.filter("companyId", companyId); } // 动态添加dateOfBirth范围过滤 if (startDate != null && endDate != null) { query = query.filter("dateOfBirth BETWEEN ?1 AND ?2", startDate, endDate); } return query; }
实现通过ID获取Employee
直接在基础查询上添加ID条件,确保权限校验被执行:
public Optional<Employee> getEmployeeById(String currentUserId, String userCompanyId, String employeeId) { return Employee.find("#Employee.withAccessPermissions AND e.id = :employeeId", Parameters.with("currentUserId", currentUserId) .and("userCompanyId", userCompanyId) .and("employeeId", employeeId)) .singleResultOptional(); }
注意:绝对不要用EntityManager.find或Employee.findById,这些方法会绕开权限校验逻辑,必须通过带权限条件的查询获取实体。
2. 封装权限校验的通用方法
如果不想每次手动拼接查询,可以封装一个通用方法统一处理权限校验:
@ApplicationScoped public class EmployeeRepository { private PanacheQuery<Employee> getBasePermissionQuery(String currentUserId, String userCompanyId) { return Employee.find("#Employee.withAccessPermissions", Parameters.with("currentUserId", currentUserId) .and("userCompanyId", userCompanyId)); } // 搜索方法 public PanacheQuery<Employee> search(String currentUserId, String userCompanyId, String companyId, LocalDate startDate, LocalDate endDate) { PanacheQuery<Employee> query = getBasePermissionQuery(currentUserId, userCompanyId); if (companyId != null) query = query.filter("companyId", companyId); if (startDate != null && endDate != null) query = query.filter("dateOfBirth BETWEEN ?1 AND ?2", startDate, endDate); return query; } // 按ID查询 public Optional<Employee> getById(String currentUserId, String userCompanyId, String id) { return getBasePermissionQuery(currentUserId, userCompanyId) .filter("id", id) .singleResultOptional(); } }
3. 避免遗漏权限校验的保障措施
为防止团队成员意外使用无权限校验的获取方法,可以做以下限制:
- 将
Employee类的构造函数设为包私有,仅允许通过Repository类访问 - 对外暴露的所有实体获取方法都封装在Repository中,强制带上权限校验逻辑
- 可选:用Quarkus CDI拦截器对
EntityManager.find操作做拦截,校验是否经过权限逻辑
是否需要用Criteria查询?
不需要。Panache的NamedQuery拼接和动态过滤已经能满足需求,且比Criteria更简洁易读。只有当权限逻辑需要高度动态化(比如根据用户角色动态生成条件)时,才考虑用Criteria或Panache的PanacheQuery.from构建动态查询。
内容的提问来源于stack exchange,提问作者Werner de Groot
相关产品推荐
相关产品推荐

