Spring框架下如何用Java正确校验查询条件是否为空?
咱们先梳理下你遇到的核心问题:空值判断逻辑不严谨导致无法正确识别空查询条件,加上isEmpty()方法实现不准确,使得明明没有有效查询条件时,代码仍会进入WHERE分支甚至触发ID相关逻辑。下面一步步来修复:
1. 替换错误的字符串空值判断逻辑
你代码里用data.getEmployeeID()!="" && data.getEmployeeID()!=null来判断员工ID是否非空,这有两个明显问题:
- 判断顺序错误:应该先检查
!=null,虽然Java中null != ""不会抛异常,但不符合代码规范,也容易混淆 - 没处理空白字符串:比如用户输入全空格的字符串,
isEmpty()会返回false,但实际是无效输入
推荐用Spring自带的org.springframework.util.StringUtils.hasText()工具方法,它会同时校验null、空字符串和全空白字符串:
if(StringUtils.hasText(data.getEmployeeID())) { criteria.add(CRITERIA_EMPLOYEEID2); System.out.println("Employee IDs"); input_empID = true; }
员工姓名的判断也同步改成:
if(StringUtils.hasText(data.getEmployeeName())) { criteria.add(nameCriteriaHelper(data.getEmployeeName())); System.out.println("Employee Name AKOOO"); input_empName = true; }
2. 修复EmployeeSearchDto.isEmpty()方法
你提到isEmpty()无法准确判定空条件,大概率是这个方法的实现逻辑有问题。比如它可能只检查了部分字段,或者判断逻辑写反了。正确的isEmpty()应该检查所有查询字段是否都处于空/默认状态:
假设你的EmployeeSearchDto结构如下,对应的isEmpty()实现参考:
public class EmployeeSearchDto { private String employeeID; private String employeeName; private Integer departmentID; private Integer positionID; private Integer workplaceID; public boolean isEmpty() { return !StringUtils.hasText(employeeID) && !StringUtils.hasText(employeeName) && (departmentID == null || departmentID == 0) && (positionID == null || positionID == 0) && (workplaceID == null || workplaceID == 0); } }
(如果你的字段默认值不是0,记得对应调整判断逻辑)
3. 优化SQL拼接,避免无效WHERE子句
当所有查询条件都为空时,原来的代码会拼接出WHERE但后面没有任何条件,直接导致SQL语法错误。可以调整逻辑:只有当criteria列表不为空时,才添加WHERE子句:
// 替换原来的if(!data.isEmpty())块 if(!criteria.isEmpty()) { query = query.concat("WHERE "); query = query.concat(String.join(" OR ", criteria)); }
这样即使isEmpty()判断有误,只要没有有效条件,就不会生成无效的WHERE子句。
4. 修复ID为null时的逻辑触发问题
原来的判断data.getEmployeeID()!="" && data.getEmployeeID()!=null,当employeeID是null时,data.getEmployeeID()!=""是true,但data.getEmployeeID()!=null是false,理论上不会触发ID逻辑。但如果isEmpty()误判为非空,就会进入WHERE分支导致SQL错误。用上面的StringUtils.hasText()和优化后的SQL拼接逻辑,就能彻底避免这个问题。
修改后的核心代码片段
public List<Object> searchEmployee(EmployeeSearchDto data) { Session session = sessionFactory.openSession(); final String CRITERIA_EMPLOYEEID = "emp.employeeID =:id"; final String CRITERIA_EMPLOYEEID2 = "emp.employeeID LIKE:id"; final String CRITERIA_POSITION= "emp.positionID =:posID"; final String CRITERIA_DEPARTMENT="emp.departmentID =:deptID"; final String CRITERIA_WORKPLACE = "emp.workplaceID =:workID"; Boolean selected_dept = false; Boolean selected_pos = false; Boolean selected_work = false; Boolean input_empID = false; Boolean input_empName = false; // 把全局临时变量改成方法局部变量,避免线程安全问题 String firstName = ""; String middleName = ""; String lastName = ""; String completeName = ""; String firstLastName = ""; boolean searchbyOne = false; boolean searchbyFandL = false; boolean searchbyCompName = false; List<String> criteria = new ArrayList<>(); List<Object> employees = null; try{ String query = "Select emp.employeeID, emp.firstName, emp.middleName, emp.lastName, " + "pos.positionName, dept.deptName, work.workplaceName " + "from Employee emp " + "INNER JOIN Department dept ON emp.departmentID = dept.deptID " + "INNER JOIN Position pos ON emp.positionID = pos.positionID " + "INNER JOIN Workplace work ON emp.workplaceID = work.workplaceID "; // 逐个检查查询字段 if(StringUtils.hasText(data.getEmployeeID())) { criteria.add(CRITERIA_EMPLOYEEID2); System.out.println("Employee IDs"); input_empID = true; } if(StringUtils.hasText(data.getEmployeeName())) { criteria.add(nameCriteriaHelper(data.getEmployeeName())); System.out.println("Employee Name AKOOO"); input_empName = true; } if(data.getDepartmentID() != null && data.getDepartmentID() != 0) { criteria.add(CRITERIA_DEPARTMENT); System.out.println("Dept ID "); selected_dept = true; } if(data.getPositionID() != null && data.getPositionID() != 0) { criteria.add(CRITERIA_POSITION); System.out.println("POS ID "); selected_pos = true; } if(data.getWorkplaceID() != null && data.getWorkplaceID() != 0) { criteria.add(CRITERIA_WORKPLACE); System.out.println("Work ID "); selected_work = true; } // 只有存在有效条件时才添加WHERE if(!criteria.isEmpty()) { query = query.concat("WHERE "); query = query.concat(String.join(" OR ", criteria)); } query = query.concat(" ORDER BY emp.joinDate DESC"); System.out.println("QUERY: " + query); Query q = session.createQuery(query); if(input_empID) { q.setParameter("id", "%" + data.getEmployeeID() + "%"); } if(input_empName) { if(searchbyOne) q.setParameter("inputName", "%" + data.getEmployeeName() + "%"); if(searchbyFandL) q.setParameter("firstLastName", "%" + firstLastName+ "%"); if(searchbyCompName) q.setParameter("completeName", "%" + completeName+ "%"); } if(selected_dept) { q.setParameter("deptID", data.getDepartmentID()); } if(selected_pos) { q.setParameter("posID", data.getPositionID()); } if(selected_work) { q.setParameter("workID", data.getWorkplaceID()); } employees = (List<Object>) q.list(); }catch(Exception e){ e.printStackTrace(); }finally{ session.close(); } return employees; }
额外小建议
- 尽量避免手动拼接SQL,容易出现语法错误和SQL注入风险,推荐用Hibernate Criteria API或者Spring Data JPA的Specification构建动态查询
- 不要用全局变量存储查询临时数据(比如
firstName、searchbyOne),多线程环境下会出现数据错乱
内容的提问来源于stack exchange,提问作者Snow

