使用建造者模式构建动态SQL语句
本节来看一个实战案例,这个案例参考了开源框架 JPA 的 SQL 构造模式。
实际应用中,在构造 SQL 查询条件的时候,需要根据不同的条件来拼接 SQL 字符串。如果查询条件复杂,SQL 拼接的过程也会变得非常复杂,从而给代码维护带来非常大的困难。
下面我们用建造者类 QueryRuleSqlBuilder 将复杂的 SQL 构造过程进行封装,用 QueryRule 对象专门保存 SQL 查询时的条件,最后根据查询条件,自动生成 SQL 语句。
首先创建 QueryRule 类,代码如下。
实际应用中,在构造 SQL 查询条件的时候,需要根据不同的条件来拼接 SQL 字符串。如果查询条件复杂,SQL 拼接的过程也会变得非常复杂,从而给代码维护带来非常大的困难。
下面我们用建造者类 QueryRuleSqlBuilder 将复杂的 SQL 构造过程进行封装,用 QueryRule 对象专门保存 SQL 查询时的条件,最后根据查询条件,自动生成 SQL 语句。
首先创建 QueryRule 类,代码如下。
import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * QueryRule 主要功能用于构造查询条件 */ public final class QueryRule implements Serializable { private static final long serialVersionUID = 1L; public static final int ASC_ORDER = 101; public static final int DESC_ORDER = 102; public static final int LIKE = 1; public static final int IN = 2; public static final int NOTIN = 3; public static final int BETWEEN = 4; public static final int EQ = 5; public static final int NOTEQ = 6; public static final int GT = 7; public static final int GE = 8; public static final int LT = 9; public static final int LE = 10; public static final int ISNULL = 11; public static final int ISNOTNULL = 12; public static final int ISEMPTY = 13; public static final int ISNOTEMPTY = 14; public static final int AND = 201; public static final int OR = 202; private List<Rule> ruleList = new ArrayList<Rule>(); private List<QueryRule> queryRuleList = new ArrayList<QueryRule>(); private String propertyName; private QueryRule() { } private QueryRule(String propertyName) { this.propertyName = propertyName; } public static QueryRule getInstance() { return new QueryRule(); } /** * 添加升序规则 * * @param propertyName * @return */ public QueryRule addAscOrder(String propertyName) { this.ruleList.add(new Rule(ASC_ORDER, propertyName)); return this; } /** * 添加降序规则 * * @param propertyName */ public QueryRule addDescOrder(String propertyName) { this.ruleList.add(new Rule(DESC_ORDER, propertyName)); return this; } public QueryRule andIsNull(String propertyName) { this.ruleList.add(new Rule(ISNULL, propertyName).setAndOr(AND)); return this; } public QueryRule andIsNotNull(String propertyName) { this.ruleList.add(new Rule(ISNOTNULL, propertyName).setAndOr(AND)); return this; } public QueryRule andIsEmpty(String propertyName) { this.ruleList.add(new Rule(ISEMPTY, propertyName).setAndOr(AND)); return this; } public QueryRule andIsNotEmpty(String propertyName) { this.ruleList.add(new Rule(ISNOTEMPTY, propertyName).setAndOr(AND)); return this; } public QueryRule andLike(String propertyName, Object value) { this.ruleList.add(new Rule(LIKE, propertyName, new Object[]{value}).setAndOr(AND)); return this; } public QueryRule andEqual(String propertyName, Object value) { this.ruleList.add(new Rule(EQ, propertyName, new Object[]{value}).setAndOr(AND)); return this; } public QueryRule andBetween(String propertyName, Object... values) { this.ruleList.add(new Rule(BETWEEN, propertyName, values).setAndOr(AND)); return this; } public QueryRule andIn(String propertyName, List<Object> values) { this.ruleList.add(new Rule(IN, propertyName, new Object[]{values}).setAndOr(AND)); return this; } public QueryRule andIn(String propertyName, Object... values) { this.ruleList.add(new Rule(IN, propertyName, values).setAndOr(AND)); return this; } public QueryRule andNotIn(String propertyName, List<Object> values) { this.ruleList.add(new Rule(NOTIN, propertyName, new Object[]{values}).setAndOr(AND)); return this; } public QueryRule orNotIn(String propertyName, Object... values) { this.ruleList.add(new Rule(NOTIN, propertyName, values).setAndOr(OR)); return this; } public QueryRule andNotEqual(String propertyName, Object value) { this.ruleList.add(new Rule(NOTEQ, propertyName, new Object[]{value}).setAndOr(AND)); return this; } public QueryRule andGreaterThan(String propertyName, Object value) { this.ruleList.add(new Rule(GT, propertyName, new Object[]{value}).setAndOr(AND)); return this; } public QueryRule andGreaterEqual(String propertyName, Object value) { this.ruleList.add(new Rule(GE, propertyName, new Object[]{value}).setAndOr(AND)); return this; } public QueryRule andLessThan(String propertyName, Object value) { this.ruleList.add(new Rule(LT, propertyName, new Object[]{value}).setAndOr(AND)); return this; } public QueryRule andLessEqual(String propertyName, Object value) { this.ruleList.add(new Rule(LE, propertyName, new Object[]{value}).setAndOr(AND)); return this; } public QueryRule orIsNull(String propertyName) { this.ruleList.add(new Rule(ISNULL, propertyName).setAndOr(OR)); return this; } public QueryRule orIsNotNull(String propertyName) { this.ruleList.add(new Rule(ISNOTNULL, propertyName).setAndOr(OR)); return this; } public QueryRule orIsEmpty(String propertyName) { this.ruleList.add(new Rule(ISEMPTY, propertyName).setAndOr(OR)); return this; } public QueryRule orIsNotEmpty(String propertyName) { this.ruleList.add(new Rule(ISNOTEMPTY, propertyName).setAndOr(OR)); return this; } public QueryRule orLike(String propertyName, Object value) { this.ruleList.add(new Rule(LIKE, propertyName, new Object[]{value}).setAndOr(OR)); return this; } public QueryRule orEqual(String propertyName, Object value) { this.ruleList.add(new Rule(EQ, propertyName, new Object[]{value}).setAndOr(OR)); return this; } public QueryRule orBetween(String propertyName, Object... values) { this.ruleList.add(new Rule(BETWEEN, propertyName, values).setAndOr(OR)); return this; } public QueryRule orIn(String propertyName, List<Object> values) { this.ruleList.add(new Rule(IN, propertyName, new Object[]{values}).setAndOr(OR)); return this; } public QueryRule orIn(String propertyName, Object... values) { this.ruleList.add(new Rule(IN, propertyName, values).setAndOr(OR)); return this; } public QueryRule orNotEqual(String propertyName, Object value) { this.ruleList.add(new Rule(NOTEQ, propertyName, new Object[]{value}).setAndOr(OR)); return this; } public QueryRule orGreaterThan(String propertyName, Object value) { this.ruleList.add(new Rule(GT, propertyName, new Object[]{value}).setAndOr(OR)); return this; } public QueryRule orGreaterEqual(String propertyName, Object value) { this.ruleList.add(new Rule(GE, propertyName, new Object[]{value}).setAndOr(OR)); return this; } public QueryRule orLessThan(String propertyName, Object value) { this.ruleList.add(new Rule(LT, propertyName, new Object[]{value}).setAndOr(OR)); return this; } public QueryRule orLessEqual(String propertyName, Object value) { this.ruleList.add(new Rule(LE, propertyName, new Object[]{value}).setAndOr(OR)); return this; } public List<Rule> getRuleList() { return this.ruleList; } public List<QueryRule> getQueryRuleList() { return this.queryRuleList; } public String getPropertyName() { return this.propertyName; } protected class Rule implements Serializable { private static final long serialVersionUID = 1L; private int type; //规则的类型 private String property_name; private Object[] values; private int andOr = AND; public Rule(int paramInt, String paramString) { this.property_name = paramString; this.type = paramInt; } public Rule(int paramInt, String paramString, Object[] paramArrayOfObject) { this.property_name = paramString; this.values = paramArrayOfObject; this.type = paramInt; } public Rule setAndOr(int andOr) { this.andOr = andOr; return this; } public int getAndOr() { return this.andOr; } public Object[] getValues() { return this.values; } public int getType() { return this.type; } public String getPropertyName() { return this.property_name; } } }然后创建 QueryRuleSqlBuilder 类,代码如下:
import builder.QueryRule.Rule; import org.apache.commons.lang3.ArrayUtils; import org.springframework.util.StringUtils; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * 根据QueryRule自动构建sql语句 */ public class QueryRuleSqlBuilder { private int CURR_INDEX = 0; //记录参数所在的位置 private List<String> properties; //保存列名列表 private List<Object> values; //保存参数值列表 private List<Order> orders; //保存排序规则列表 private String whereSql = ""; private String orderSql = ""; private Object[] valueArr = new Object[]{}; private Map<Object, Object> valueMap = new HashMap<Object, Object>(); /** * 或得查询条件 * * @return */ private String getWhereSql() { return this.whereSql; } /** * 获得排序条件 * * @return */ private String getOrderSql() { return this.orderSql; } /** * 获得参数值列表 * * @return */ public Object[] getValues() { return this.valueArr; } /** * 获取参数列表 * * @return */ private Map<Object, Object> getValueMap() { return this.valueMap; } /** * 创建SQL构造器 * * @param queryRule */ public QueryRuleSqlBuilder(QueryRule queryRule) { CURR_INDEX = 0; properties = new ArrayList<String>(); values = new ArrayList<Object>(); orders = new ArrayList<Order>(); for (QueryRule.Rule rule : queryRule.getRuleList()) { switch (rule.getType()) { case QueryRule.BETWEEN: processBetween(rule); break; case QueryRule.EQ: processEqual(rule); break; case QueryRule.LIKE: processLike(rule); break; case QueryRule.NOTEQ: processNotEqual(rule); break; case QueryRule.GT: processGreaterThen(rule); break; case QueryRule.GE: processGreaterEqual(rule); break; case QueryRule.LT: processLessThen(rule); break; case QueryRule.LE: processLessEqual(rule); break; case QueryRule.IN: processIN(rule); break; case QueryRule.NOTIN: processNotIN(rule); break; case QueryRule.ISNULL: processIsNull(rule); break; case QueryRule.ISNOTNULL: processIsNotNull(rule); break; case QueryRule.ISEMPTY: processIsEmpty(rule); break; case QueryRule.ISNOTEMPTY: processIsNotEmpty(rule); break; case QueryRule.ASC_ORDER: processOrder(rule); break; case QueryRule.DESC_ORDER: processOrder(rule); break; default: throw new IllegalArgumentException("type " + rule.getType() + " not supported."); } } //拼装where语句 appendWhereSql(); //拼装排序语句 appendOrderSql(); //拼装参数值 appendValues(); } /** * 去掉order * * @param sql * @return */ private String removeOrders(String sql) { Pattern p = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*", Pattern.CASE_INSENSITIVE); Matcher m = p.matcher(sql); StringBuffer sb = new StringBuffer(); while (m.find()) { m.appendReplacement(sb, ""); } m.appendTail(sb); return sb.toString(); } /** * 去掉select * * @param sql * @return */ private String removeSelect(String sql) { if (sql.toLowerCase().matches("from\\s+")) { int beginPos = sql.toLowerCase().indexOf("from"); return sql.substring(beginPos); } else { return sql; } } /** * 处理like * * @param rule */ private void processLike(QueryRule.Rule rule) { if (ArrayUtils.isEmpty(rule.getValues())) { return; } Object obj = rule.getValues()[0]; if (obj != null) { String value = obj.toString(); if (!StringUtils.isEmpty(value)) { value = value.replace('*', '%'); obj = value; } } add(rule.getAndOr(), rule.getPropertyName(), "like", "%" + rule.getValues()[0] + "%"); } /** * 处理between * * @param rule */ private void processBetween(QueryRule.Rule rule) { if ((ArrayUtils.isEmpty(rule.getValues())) || (rule.getValues().length < 2)) { return; } add(rule.getAndOr(), rule.getPropertyName(), "", "between", rule.getValues()[0], "and"); add(0, "", "", "", rule.getValues()[1], ""); } /** * 处理 = * * @param rule */ private void processEqual(QueryRule.Rule rule) { if (ArrayUtils.isEmpty(rule.getValues())) { return; } add(rule.getAndOr(), rule.getPropertyName(), "=", rule.getValues()[0]); } /** * 处理 <> * * @param rule */ private void processNotEqual(QueryRule.Rule rule) { if (ArrayUtils.isEmpty(rule.getValues())) { return; } add(rule.getAndOr(), rule.getPropertyName(), "<>", rule.getValues()[0]); } /** * 处理 > * * @param rule */ private void processGreaterThen( QueryRule.Rule rule) { if (ArrayUtils.isEmpty(rule.getValues())) { return; } add(rule.getAndOr(), rule.getPropertyName(), ">", rule.getValues()[0]); } /** * 处理>= * * @param rule */ private void processGreaterEqual( QueryRule.Rule rule) { if (ArrayUtils.isEmpty(rule.getValues())) { return; } add(rule.getAndOr(), rule.getPropertyName(), ">=", rule.getValues()[0]); } /** * 处理< * * @param rule */ private void processLessThen(QueryRule.Rule rule) { if (ArrayUtils.isEmpty(rule.getValues())) { return; } add(rule.getAndOr(), rule.getPropertyName(), "<", rule.getValues()[0]); } /** * 处理<= * * @param rule */ private void processLessEqual( QueryRule.Rule rule) { if (ArrayUtils.isEmpty(rule.getValues())) { return; } add(rule.getAndOr(), rule.getPropertyName(), "<=", rule.getValues()[0]); } /** * 处理 is null * * @param rule */ private void processIsNull(QueryRule.Rule rule) { add(rule.getAndOr(), rule.getPropertyName(), "is null", null); } /** * 处理 is not null * * @param rule */ private void processIsNotNull(QueryRule.Rule rule) { add(rule.getAndOr(), rule.getPropertyName(), "is not null", null); } /** * 处理 <>'' * * @param rule */ private void processIsNotEmpty(QueryRule.Rule rule) { add(rule.getAndOr(), rule.getPropertyName(), "<>", "''"); } /** * 处理 ='' * * @param rule */ private void processIsEmpty(QueryRule.Rule rule) { add(rule.getAndOr(), rule.getPropertyName(), "=", "''"); } /** * 处理in和not in * * @param rule * @param name */ private void inAndNotIn(QueryRule.Rule rule, String name) { if (ArrayUtils.isEmpty(rule.getValues())) { return; } if ((rule.getValues().length == 1) && (rule.getValues()[0] != null) && (rule.getValues()[0] instanceof List)) { List<Object> list = (List) rule.getValues()[0]; if ((list != null) && (list.size() > 0)) { for (int i = 0; i < list.size(); i++) { if (i == 0 && i == list.size() - 1) { add(rule.getAndOr(), rule.getPropertyName(), "", name + " (", list.get(i), ")"); } else if (i == 0 && i < list.size() - 1) { add(rule.getAndOr(), rule.getPropertyName(), "", name + " (", list.get(i), ""); } if (i > 0 && i < list.size() - 1) { add(0, "", ",", "", list.get(i), ""); } if (i == list.size() - 1 && i != 0) { add(0, "", ",", "", list.get(i), ")"); } } } } else { Object[] list = rule.getValues(); for (int i = 0; i < list.length; i++) { if (i == 0 && i == list.length - 1) { add(rule.getAndOr(), rule.getPropertyName(), "", name + " (", list[i], ")"); } else if (i == 0 && i < list.length - 1) { add(rule.getAndOr(), rule.getPropertyName(), "", name + " (", list[i], ""); } if (i > 0 && i < list.length - 1) { add(0, "", ",", "", list[i], ""); } if (i == list.length - 1 && i != 0) { add(0, "", ",", "", list[i], ")"); } } } } /** * 处理 not in * * @param rule */ private void processNotIN(QueryRule.Rule rule) { inAndNotIn(rule, "not in"); } /** * 处理 in * * @param rule */ private void processIN(QueryRule.Rule rule) { inAndNotIn(rule, "in"); } /** * 处理 order by * * @param rule 查询规则 */ private void processOrder(Rule rule) { switch (rule.getType()) { case QueryRule.ASC_ORDER: // propertyName非空 if (!StringUtils.isEmpty(rule.getPropertyName())) { orders.add(Order.asc(rule.getPropertyName())); } break; case QueryRule.DESC_ORDER: // propertyName非空 if (!StringUtils.isEmpty(rule.getPropertyName())) { orders.add(Order.desc(rule.getPropertyName())); } break; default: break; } } /** * 加入到sql查询规则队列 * * @param andOr and 或者 or * @param key 列名 * @param split 列名与值之间的间隔 * @param value 值 */ private void add(int andOr, String key, String split, Object value) { add(andOr, key, split, "", value, ""); } /** * 加入到sql查询规则队列 * * @param andOr and 或则 or * @param key 列名 * @param split 列名与值之间的间隔 * @param prefix 值前缀 * @param value 值 * @param suffix 值后缀 */ private void add(int andOr, String key, String split, String prefix, Object value, String suffix) { String andOrStr = (0 == andOr ? "" : (QueryRule.AND == andOr ? " and " : " or ")); properties.add(CURR_INDEX, andOrStr + key + " " + split + prefix + (null != value ? " ? " : " ") + suffix); if (null != value) { values.add(CURR_INDEX, value); CURR_INDEX++; } } /** * 拼装 where 语句 */ private void appendWhereSql() { StringBuffer whereSql = new StringBuffer(); for (String p : properties) { whereSql.append(p); } this.whereSql = removeSelect(removeOrders(whereSql.toString())); } /** * 拼装排序语句 */ private void appendOrderSql() { StringBuffer orderSql = new StringBuffer(); for (int i = 0; i < orders.size(); i++) { if (i > 0 && i < orders.size()) { orderSql.append(","); } orderSql.append(orders.get(i).toString()); } this.orderSql = removeSelect(removeOrders(orderSql.toString())); } /** * 拼装参数值 */ private void appendValues() { Object[] val = new Object[values.size()]; for (int i = 0; i < values.size(); i++) { val[i] = values.get(i); valueMap.put(i, values.get(i)); } this.valueArr = val; } public String builder(String tableName) { String ws = removeFirstAnd(this.getWhereSql()); String whereSql = ("".equals(ws) ? ws : (" where " + ws)); String sql = "select * from " + tableName + whereSql; Object[] values = this.getValues(); String orderSql = this.getOrderSql(); orderSql = (StringUtils.isEmpty(orderSql) ? " " : (" order by " + orderSql)); sql += orderSql; return sql; } private String removeFirstAnd(String sql) { if (StringUtils.isEmpty(sql)) { return sql; } return sql.trim().toLowerCase().replaceAll("^\\s*and", "") + " "; } }接着创建 Order 类,代码如下:
/** * sql排序组件 */ public class Order { private boolean ascending; //升序还是降序 private String propertyName; //哪个字段升序,哪个字段降序 public String toString() { return propertyName + ' ' + (ascending ? "asc" : "desc"); } /** * Constructor for Order. */ protected Order(String propertyName, boolean ascending) { this.propertyName = propertyName; this.ascending = ascending; } /** * Ascending order * * @param propertyName * @return Order */ public static Order asc(String propertyName) { return new Order(propertyName, true); } /** * Descending order * * @param propertyName * @return Order */ public static Order desc(String propertyName) { return new Order(propertyName, false); } }最后编写客户端测试代码,如下:
/** * Created by 新宝库. */ public class Test { public static void main(String[] args) { QueryRule queryRule = QueryRule.getInstance(); queryRule.addAscOrder("age") .andEqual("addr", "HeBei") .andLike("name", "新宝库") .andGreaterEqual("age", 18); QueryRuleSqlBuilder builder = new QueryRuleSqlBuilder(queryRule); System.out.println(builder.builder("t_member")); System.out.println("Params: " + Arrays.toString(builder.getValues())); } }这样一来,客户端代码就非常清楚了,运行结果如下所示:
select * from t_member where addr = ? and name like ? order by age asc
Params: [HeBei, %新宝库%]
所有教程
- C语言入门
- C语言编译器
- C语言项目案例
- 数据结构
- C++
- STL
- C++11
- socket
- GCC
- GDB
- Makefile
- OpenCV
- Qt教程
- Unity 3D
- UE4
- 游戏引擎
- Python
- Python并发编程
- TensorFlow
- Django
- NumPy
- Linux
- Shell
- Java教程
- 设计模式
- Java Swing
- Servlet
- JSP教程
- Struts2
- Maven
- Spring
- Spring MVC
- Spring Boot
- Spring Cloud
- Hibernate
- Mybatis
- MySQL教程
- MySQL函数
- NoSQL
- Redis
- MongoDB
- HBase
- Go语言
- C#
- MATLAB
- JavaScript
- Bootstrap
- HTML
- CSS教程
- PHP
- 汇编语言
- TCP/IP
- vi命令
- Android教程
- 区块链
- Docker
- 大数据
- 云计算