第一次发博客,不知道该怎么写,算了直接提出问题吧先:
现在持久层框架用的最多的应该是hibernate、mybatis或者包含现在的jpa吧,也是前两天接触jpa,我也不晓得为什么这玩意能火起来而且尤其是国外用的比mybatis多的多的多,我擦,百思不得其解。想了半天也只有在不使用多表或者动态多条件的情况下这东西能用用,可是哪个应用会出现全部功能都是单表操作呢,我估计很少吧。所以与其代码中写一大推原生sql,拼接各种条件,然后返回自定义对象可能还不是那么完美的情况下,直接使用mybatis它不香么…
okok,跑偏了,说说今天的主题:假如你用了jpa并且有多表关联很可能还有很多动态条件(可以传值可以为空,传值时动态拼接查询语句),那么代码中耦合sql语句并且各种 if 判空,这显得非常不优雅而且在业务变动的情况下很麻烦,所以想到了有没有类似mybatis中的动态语句生成工具 SQL.java这个类,原本是想着直接拿过来用,结果遗憾的是mybatis中的这个工具并不能达到我的需求,不是那么健全。基于这个情况在网上也没有找到合适的工具类(不重复造轮子我们只是轮子的搬运工),因此花了三天死掉了好多脑细胞的情况下自己搞了一个工具类(主要废弃了好几种方案最终采用了目前的这个),代码不多也很简单,就是装的不够优雅所以发出来让大家帮忙优化优化。
举个例子:假如我们有以下这么一个jpa查询,并且班级、性别和年龄条件都是动态的,这个业务含义应该不用解释很简单,
select s from Student s where class='class2' and ((age>=20 and sex='男') or (age <=16 and sex = '女'))
那么可以按照如下写法:
Cnd.select("select s from Student s")
.andExp("name","like","%张三%")
.andExp("class","=","class2")
.andExps(Cnd.exps(Cnd.exp("age",">=","20").andExp("sex","=","男")).orExps(Cnd.exp("age","<=","16").andExp("sex","=","女")));
执行后生成的SQL语句长这样:
select s from Student s where name like :name_0 and class = :class_0 and ((age >= :age_0 and sex = :sex_0) or (age <= :age_1 and sex = :sex_1))
然后Cnd中会封装查询参数,可以用在后边查询流程:
一般业务不会太复杂,但是条件可以是动态的,上边写法当名称或者年龄为空时生成的查询语句不会包含这个条件
so还是挺简单,直接上代码,
public class Cnd {
private String select = "";
private StringBuilder cndStr = new StringBuilder();
private Map<String, Object> conditions = new HashMap<String, Object>();
private Cnd() {
}
/**
* 获取条件表达式
* @param ql 查询语句
*/
public static Cnd select(String ql) {
Cnd cnd = new Cnd();
cnd.select = ql;
return cnd;
}
/**
* 获取条件表达式
*
* @param name
* @param operator
* @param value
* @return
*/
public static Cnd exp(String name, String operator, Object value) {
Cnd cnd = new Cnd();
if(!cnd.validate(value)) {
return cnd;
}
String alias = cnd.setAlias(name,value);
cnd.cndStr.append(" where ").append(name).append(" ").append(operator).append(" ").append(":").append(alias);
return cnd;
}
/**
* 获取条件表达式组
*
* @param cnd
* @return
*/
public static Cnd exps(Cnd cnd) {
Cnd cnd1 = new Cnd();
cnd1.andExps(cnd);
return cnd1;
}
/**
* 增加 and条件表达式
*
* @param name
* @param operator
* @param value
* @return
*/
public Cnd andExp(String name, String operator, Object value) {
if(!validate(value)) {
return this;
}
if(value instanceof Cnd) {
Cnd cnd = (Cnd)value;
Iterator<Map.Entry<String, Object>> entries = cnd.conditions.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<String, Object> entry = entries.next();
String k = entry.getKey();
Object v = entry.getValue();
String alias = setAlias(k,v);
cnd.cndStr.replace(cnd.cndStr.indexOf(k),cnd.cndStr.indexOf(k)+k.length(),alias);
conditions.put(alias,v);
}
if(cnd.