JDBC的多条件动态查询
首先我们先分析一下多条件综合查询的实现方式有哪些?
1、直接将参数值拼接到SQL语句中,然后进行Select,但是说这种方式存在安全性问题,比如说SQL的注入,尽管我们可以通过正则等手段来过滤掉这些特殊字符,但是这样看上去不是很爽。
2、先使用占位符“?”来拼接SQL,然后再通过条件判断去填充PreparedStatement,但是这种方式显然很麻烦,因为我们在拼SQL的时候需要判断一次,在填充pst的时候还需要再进行判断,所以不是好的解决方案。
3、存储过程,这个因为本人对存储过程认识不是很深,所以这里不加描述;
其实方法很多,只是找一个相对好一点的,工作的这段时间做.NET项目时使用里面的SqlHelper感觉很犀利,记得以前学习的时候老师也给我们做了一个类似的,所以想写一个工具类。
Parameter.java:
1 package com.iflytek.page; 2 3 /** 4 * 查询参数工具类,用于表示条件参数对象 5 * 6 * @author xudongwang 2012-1-19 7 * 8 * Email:xdwangiflytek@gmail.com 9 */ 10 public class Parameter { 11 /** 12 * 数据库字段名 13 */ 14 private String field; 15 /** 16 * 参数值 Object 17 */ 18 private Object value; 19 /** 20 * 数据库操作符 =、>=、<、like... 21 */ 22 private String operator; 23 24 /** 25 * 构造方法 26 * 27 * @param field 28 * 数据库字段名 29 * @param operator 30 * 数据库操作符 =、>=、<、like... 31 * @param value 32 * 参数值 Object 33 */ 34 public Parameter(String field, String operator, Object value) { 35 super(); 36 this.field = field; 37 this.value = value; 38 this.operator = operator; 39 } 40 41 public String getField() { 42 return field; 43 } 44 45 public Object getValue() { 46 return value; 47 } 48 49 public String getOperator() { 50 return operator; 51 } 52 }
DynamicQuery.java:
1 package com.iflytek.page; 2 3 import java.sql.PreparedStatement; 4 import java.sql.SQLException; 5 import java.util.ArrayList; 6 7 /** 8 * 动态查询工具类,用于拼接SQL、填充PreparedStatement 9 * 10 * @author xudongwang 2012-1-19 11 * 12 * Email:xdwangiflytek@gmail.com 13 */ 14 public class DynamicQuery { 15 16 private String templet = " AND %s %s ?"; 17 private String baseSql; 18 private ArrayList<Parameter> parameters = new ArrayList<Parameter>(); 19 20 public DynamicQuery() { 21 22 } 23 24 /** 25 * baseSql需要带有where条件 26 * 27 * @param baseSql 28 */ 29 public void setBaseSql(String baseSql) { 30 this.baseSql = baseSql; 31 } 32 33 public void addParameter(Parameter parameter) { 34 parameters.add(parameter); 35 } 36 37 public String generateSql() { 38 StringBuffer sb = new StringBuffer(baseSql); 39 for (Parameter parameter : parameters) { 40 sb.append(String.format(templet, parameter.getField(), 41 parameter.getOperator())); 42 } 43 return sb.toString(); 44 } 45 46 public void fillPreparedStatement(PreparedStatement pst) 47 throws SQLException { 48 int count = 1; 49 for (Parameter p : parameters) { 50 // 这里使用SetObjcet的缺点是失去了类型的验证功能,如果大家不嫌麻烦,可以判断,根据类型,set不同的类型 51 pst.setObject(count, p.getValue()); 52 count++; 53 } 54 } 55 56 }
SelectServlet.java:
1 DynamicQuery query = new DynamicQuery(); 2 query.addParameter(new Parameter("name", "like", "xudongwang")); 3 query.addParameter(new Parameter("email", "=", "xdwangiflytek@gmail.com")); 4 StudentDao studentDao = new StudentDao(); 5 List<Stduent> students = studentDao.selectByQuery(query); 6 request.setAttribute("students", students);
StduentDao.java:
1 public List<Student> selectByQuery(DynamicQuery query) { 2 3 List<Student> students = new ArrayList<Student>(); 4 5 try { 6 String sql = "SELECT id,name,email FROM tbl_stduent"; 7 8 query.setBaseSql(sql); 9 //如果想排序,自行在sql后添加 10 sql = query.generateSql(); 11 Connection conn = null; 12 try { 13 conn = DbUtil.getConnection(); 14 PreparedStatement pst= conn.prepareStatement(sql); 15 //填充pst 16 query.fillPreparedStatement(pst); 17 ResultSet rs = pst.executeQuery(); 18 while (rs.next()) { 19 Student student = new Student(); 20 …… 21 students.add(student); 22 } 23 rs.close(); 24 pst.close(); 25 } finally { 26 if (conn != null) { 27 conn.close(); 28 } 29 } 30 } catch (Exception e) { 31 e.printStackTrace(); 32 } 33 return students; 34 }
下面来总结一下上面的整个流程:
1、 首先我们在Servlet、Action等控制器里将需要查询的表单参数值添加到查询条件列表中;
2、 在数据访问层DAO中设置基本的SQL;
3、 下面我们来迭代查询条件列表,使用占位符拼接SQL;
4、 在DAO中拿SQL创建PreparedStatement;
5、 迭代查询条件列表,为pst填充值;
6、 接下来,没有特殊(是否添加排序)的地方了,就是正常的executeQuery,while(rs.next()){...}