上一篇给了两个执行jpql、sql查询语句的工具类。但在实际使用起来的时候还是存在许多不便。最主要的就是要在java代码里拼凑一句sql语句是很不方便的,比如经常需要根据不同的条件,拼凑不同的where条件。mybatis提供的<where><if>标签就可以很方便的达成这种目的。
上网搜索了一下,发现原来mybatis3还增加了这种东西:http://www.mybatis.org/mybatis-3/zh/statement-builders.html
可以方便的用java代码拼凑sql语句,本来是想直接使用的,但感觉还是有点不太符合自己的想法,于是仿照它重新写了一个。
直接上代码:
1.首先是一个基类,这里面就直接实现了拼凑sql的各种方法。
1.AbstractSQL.java
package com.csair.nrs.jpa.statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.csair.nrs.util.StringUtils;
import com.csair.nrs.util.exception.NrsException;
/**
* 写sql语句的类
* @author abo on Apr 27, 2018
*
*/
public abstract class AbstractSQL<T> {
/**
* 获得自身
* @author abo on Apr 28, 2018
*
* @return
*/
protected abstract T getSelf();
private static final String AND = "and";
private static final String OR = "or";
private static final String LEFTKUOHAO = "(";
private static final String RIGHTKUOHAO = ")";
/**
* 每个参数的唯一标志
*/
private int paramNum = 0;
/**
* 获取下一个参数标志
* @author abo on May 2, 2018
*
* @return
*/
private String getParamKey() {
return "param" + paramNum++;
}
boolean distinct = false; // 是否 select distinct
List<String> selectColumns = new ArrayList<String>(); // 查询字段
List<String> tables = new ArrayList<String>(); // 查询表格
StringBuilder joinClause = new StringBuilder(); // join 子句
// 这个list 既用来记录 where 条件 也 用来 记录 having条件
List<String> whereList = new ArrayList<String>();
List<String> groupColumns = new ArrayList<String>(); // 分组字段
List<String> orderColumns = new ArrayList<String>(); // 排序字段
/**
* where子句
*/
String whereClause = null;
private void createWhereClause() {
if (whereClause == null) {
StringBuilder where = new StringBuilder();
if (whereList.size() > 1) {
where.append(" where");
for (int i = 1; i < whereList.size(); i++) { // 跳过第一个连接符
String condition = whereList.get(i);
where.append(" ").append(condition);
// 左括号,跳过它后面的连接符
if (LEFTKUOHAO.equals(condition)) {
i++;
}
}
}
// 赋值
whereClause = where.toString();
// 清空whereList给having用
whereList = new ArrayList<String>();
}
}
/**
* having子句
*/
String havingClause = null;
private void createHavingClause() {
if (havingClause == null) {
StringBuilder having = new StringBuilder();
if (whereList.size() > 1) {
having.append(" having");
for (int i = 1; i < whereList.size(); i++) { // 跳过第一个连接符
String condition = whereList.get(i);
having.append(" ").append(condition);
// 左括号,跳过它后面的连接符
if (LEFTKUOHAO.equals(condition)) {
i++;
}
}
}
// 赋值
havingClause = having.toString();
}
}
/**
* 记录这条sql里面的参数
*/
Map<String, Object> params = new HashMap<String, Object>();
/**
* 切换到select distinct模式
* @author abo on Apr 27, 2018
*
* @return
*/
public T distinct() {
distinct = true;
return this.getSelf();
}
/**
* select 的字段
* <br>eg: select("table.a", "table.b as c"); 或 select("*");
* @author abo on Apr 27, 2018
*
* @param columns
* @return
*/
public T select(String... columns) {
for (String column : columns) {
// 去掉前后空格
column = column.trim();
// 去掉前后逗号
if (column.startsWith(",")) {
column = column.substring(1);
}
if (column.endsWith(",")) {
column = column.substring(0, column.length() - 1);
}
// 添加到字段列表
selectColumns.add(column);
}
return this.getSelf();
}
/**
* from 的表
* <br>eg: from("tableA", "tableB as b");
* @author abo on Apr 27, 2018
*
* @param tables
* @return
*/
public T from(String... tables) {
for (String table : tables) {
// 去掉前后空格
table = table.trim();
// 去掉前后逗号
if (table.startsWith(",")) {
table = table.substring(1);
}
if (table.endsWith(",")) {
table = table.substring(0, table.length() - 1);
}
// 添加到表列表
this.tables.add(table);
}
return this.getSelf();
}
/**
* eg: inner_join("tableB as b on a.name = b.name")
* @author abo on Apr 27, 2018
*
* @param joins
* @return
*/
public T inner_join(String... joins) {
for (String join : joins) {
join = join.trim();
joinClause.append(" inner join ").append(join);
}
return this.getSelf();
}
/**
* eg: left_join("tableB as b on a.name = b.name")
* @author abo on Apr 27, 2018
*
* @param joins
* @return
*/
public T left_join(String... joins) {
for (String join : joins) {
join = join.trim();
joinClause.append(" left join ").append(join);
}
return this.getSelf();
}
/**
* eg: rigth_join("tableB as b on a.name = b.name")
* @author abo on Apr 27, 2018
*
* @param joins
* @return
*/
public T rigth_join(String... joins) {
for (String join : joins) {
join = join.trim();
joinClause.append(" right join ").append(join);
}
return this.getSelf();
}
/**
* 下一个条件的分隔符
*/
private String link = AND; // 默认都是and
private String getLink() {
String whereLink = link;
link = AND; // 下一个是 and
return whereLink;
}
/**
* 添加where条件
* <br> eg: where("table.name is null");
* <br>默认以and连接这些条件,如果要用or,则 or().where(...);
* @author abo on Apr 28, 2018
*
* @param conditions
* @return
*/
public T where(String... conditions) {
// 获取这一批条件的连接符
String whereLink = getLink();
for (String condition : conditions) {
condition = condition.trim();
whereList.add(whereLink);
whereList.add(condition);
}
return this.getSelf();
}
/**
* 切换下一个条件为 or
* @author abo on Apr 28, 2018
*
* @return
*/
public T or() {
link = OR;
return this.getSelf();
}
/**
* 在当前条件中 插入一个左括号 "("
* <br> 默认以and连接,如果要用or,则 or().kuoHao();
* <br> 结束括号 用 kuoHaoEnd();
* @author abo on Apr 28, 2018
*
* @return
*/
public T kuoHao() {
whereList.add(getLink());
whereList.add(LEFTKUOHAO);
return this.getSelf();
}
/**
* 结束一个括号的内容 ")"
* <br> 如果 "(" 与 ")" 之间没有东西,会自动去掉的
* @author abo on Apr 28, 2018
*
* @return
*/
public T kuoHaoEnd() {
int i = whereList.size() - 1;
if (LEFTKUOHAO.equals(whereList.get(i))) {
// 如果前一个就是 (
whereList.remove(i);
whereList.remove(i - 1);
} else {
whereList.add(RIGHTKUOHAO);
}
return this.getSelf();
}
/**
* 插入一个等于条件
* <br> param不为 null 时eq("table.name", param); 效果等于 where/having("table.name = :key").addParam("key", param);
* <br> param为 null 时,将跳过这个条件,如果想判断字段为 null ,可使用 where("table.name is null");
* <br> 默认以and连接这个条件,如果要用or,则 or().eq(...);
* @author abo on Apr 28, 2018
*
* @param column
* @param param
* @return
*/
public T eq(String column, Object param) {
if (param != null) {
column = column.trim();
// 获取参数标志
String key = getParamKey();
// 拼 条件
String condition = column + " = :" + key;
this.where(condition);
this.addParam(key, param);
} else {
// 重置连接符
this.getLink();
}
return this.getSelf();
}
/**
* 插入一个不等于条件
* <br> param不为 null 时 not_eq("table.name", param); 效果等于 where/having("table.name != :key").addParam("key", param);
* <br> param为 null 时,将跳过这个条件,如果想判断字段不为 null ,可使用 where("table.name is not null");
* <br> 默认以and连接这个条件,如果要用or,则 or().not_eq(...);
* @author abo on Apr 28, 2018
*
* @param column
* @param param
* @return
*/
public T not_eq(String column, Object param) {
if (param != null) {
column = column.trim();
// 获取参数标志
String key = getParamKey();
// 拼 条件
String condition = column + " != :" + key;
this.where(condition);
this.addParam(key, param);
} else {
// 重置连接符
this.getLink();
}
return this.getSelf();
}
/**
* 添加一个like条件
* <br> param不为 null 时 like("table.name", param); 效果等于 where/having("table.name like :key").addParam("key", param);
* <br> param为 null 时,将跳过这个条件,如果想判断字段为 null ,可使用 where("table.name is null");
* <br> 默认以and连接这个条件,如果要用or,则 or().like(...);
* @author abo on Apr 28, 2018
*
* @param column
* @param param
* @return
*/
public T like(String column, String param) {
if (param != null) {
column = column.trim();
// 获取参数标志
String key = getParamKey();
// 拼 条件
String condition = column + " like :" + key;
this.where(condition);
this.addParam(key, param);
} else {
// 重置连接符
this.getLink();
}
return this.getSelf();
}
/**
* 添加一个like条件
* <br> param不为 null 时 not_like("table.name", param); 效果等于 where/having("table.name not like :key").addParam("key", param);
* <br> param为 null 时,将跳过这个条件,如果想判断字段不为 null ,可使用 where("table.name is not null");
* <br> 默认以and连接这个条件,如果要用or,则 or().not_like(...);
* @author abo on Apr 28, 2018
*
* @param column
* @param param
* @return
*/
public T not_like(String column, String param) {
if (param != null) {
column = column.trim();
// 获取参数标志
String key = getParamKey();
// 拼 条件
String condition = column + " like :" + key;
this.where(condition);
this.addParam(key, param);
} else {
// 重置连接符
this.getLink();
}
return this.getSelf();
}
/**
* 模糊查询
* <br> param不为 null 时 containText("table.name", param); 效果等于 like("table.name", "%" + param + "%");
* <br> param为 null 时,将跳过这个条件,如果想判断字段为 null ,可使用 where("table.name is null");
* <br> 默认以and连接这个条件,如果要用or,则 or().containText(...);
* @author abo on Apr 28, 2018
*
* @param column
* @param param
* @return
*/
public T containText(String column, String param) {
if (param != null) {
this.like(column, "%" + param + "%");
} else {
// 重置连接符
this.getLink();
}
return this.getSelf();
}
/**
* 允许in(...,...,...) 中集合的最大个数
*/
private static final int MAX_IN_PARAM = 2000;
/**
* 添加一个in条件
* <br> params不为 null 时 in("table.name", params); 效果等于 where/having("table.name in (:key)").addParam("key", params);
* <br> params为 null 时,将跳过这个条件
* <br> 默认以and连接这个条件,如果要用or,则 or().in(...);
* <br> params长度为0时,这个条件将永远不为真
* @author abo on Apr 28, 2018
*
* @param column
* @param param
* @return
*/
public T in(String column, Collection<?> params) {
if (params != null) {
if (params.isEmpty()) {
this.where("1 = 0");
} else {
column = column.trim();
// 分页避免in的集合过大
List<Collection<?>> pages = splitCollection(params, MAX_IN_PARAM);
this.kuoHao();
for (Collection<?> collection : pages) {
// 获取参数标志
String key = getParamKey();
// 拼 条件
String condition = column + " in (:" + key + ")";
// 用或连接
this.or();
this.where(condition);
this.addParam(key, collection);
}
this.kuoHaoEnd();
}
} else {
// 重置连接符
this.getLink();
}
return this.getSelf();
}
/**
* 添加一个not in条件
* <br> params不为 null 时 not_in("table.name", params); 效果等于 where/having("table.name not in (:key)").addParam("key", params);
* <br> params为 null 时,将跳过这个条件
* <br> 默认以and连接这个条件,如果要用or,则 or().not_in(...);
* <br> params长度为0时,这个条件将永远为真
* @author abo on Apr 28, 2018
*
* @param column
* @param param
* @return
*/
public T not_in(String column, Collection<?> params) {
if (params != null) {
if (params.isEmpty()) {
this.where("1 = 1");
} else {
column = column.trim();
// 分页避免in的集合过大
List<Collection<?>> pages = splitCollection(params, MAX_IN_PARAM);
this.kuoHao();
for (Collection<?> collection : pages) {
// 获取参数标志
String key = getParamKey();
// 拼 条件
String condition = column + " not in (:" + key + ")";
// 用与连接
this.where(condition);
this.addParam(key, collection);
}
this.kuoHaoEnd();
}
} else {
// 重置连接符
this.getLink();
}
return this.getSelf();
}
/**
* 大于 >
* <br> param不为 null 时 gt("table.name", param); 效果等于 where/having("table.name > :key").addParam("key", param);
* <br> param为 null 时,将跳过这个条件
* <br> 默认以and连接这个条件,如果要用or,则 or().gt(...);
* @author abo on Apr 28, 2018
*
* @param column
* @param param
* @return
*/
public T gt(String column, Object param) {
if (param != null) {
column = column.trim();
// 获取参数标志
String key = getParamKey();
// 拼 条件
String condition = column + " > :" + key;
this.where(condition);
this.addParam(key, param);
} else {
// 重置连接符
this.getLink();
}
return this.getSelf();
}
/**
* 大于等于 >=
* <br> param不为 null 时 gte("table.name", param); 效果等于 where/having("table.name >= :key").addParam("key", param);
* <br> param为 null 时,将跳过这个条件
* <br> 默认以and连接这个条件,如果要用or,则 or().gte(...);
* @author abo on Apr 28, 2018
*
* @param column
* @param param
* @return
*/
public T gte(String column, Object param) {
if (param != null) {
column = column.trim();
// 获取参数标志
String key = getParamKey();
// 拼 条件
String condition = column + " >= :" + key;
this.where(condition);
this.addParam(key, param);
} else {
// 重置连接符
this.getLink();
}
return this.getSelf();
}
/**
* 小于 <
* <br> param不为 null 时 lt("table.name", param); 效果等于 where/having("table.name < :key").addParam("key", param);
* <br> param为 null 时,将跳过这个条件
* <br> 默认以and连接这个条件,如果要用or,则 or().lt(...);
* @author abo on Apr 28, 2018
*
* @param column
* @param param
* @return
*/
public T lt(String column, Object param) {
if (param != null) {
column = column.trim();
// 获取参数标志
String key = getParamKey();
// 拼 条件
String condition = column + " < :" + key;
this.where(condition);
this.addParam(key, param);
} else {
// 重置连接符
this.getLink();
}
return this.getSelf();
}
/**
* 小于等于 <=
* <br> param不为 null 时 lte("table.name", param); 效果等于 where/having("table.name <= :key").addParam("key", param);
* <br> param为 null 时,将跳过这个条件
* <br> 默认以and连接这个条件,如果要用or,则 or().lte(...);
* @author abo on Apr 28, 2018
*
* @param column
* @param param
* @return
*/
public T lte(String column, Object param) {
if (param != null) {
column = column.trim();
// 获取参数标志
String key = getParamKey();
// 拼 条件
String condition = column + " <= :" + key;
this.where(condition);
this.addParam(key, param);
} else {
// 重置连接符
this.getLink();
}
return this.getSelf();
}
/**
* group by 的字段
* <br> eg: group_by("table.a", "table.b");
* @author abo on Apr 28, 2018
*
* @param columns
* @return
*/
public T group_by(String... columns) {
for (String column : columns) {
// 去掉前后空格
column = column.trim();
// 去掉前后逗号
if (column.startsWith(",")) {
column = column.substring(1);
}
if (column.endsWith(",")) {
column = column.substring(0, column.length() - 1);
}
groupColumns.add(column);
}
return this.getSelf();
}
/**
* 添加having条件
* <br> eg: having("sum(table.name) > 2");
* <br>默认以and连接这些条件,如果要用or,则 or().having(...);
* <br>调用 having 之后, 可继续用 eq、in 等 组织 where子句的方法组织having语句
* <br> eg: having("sum(table.name) > 2").eq(...).in(...) 或 having().eq(...).in(...)
* @author abo on Apr 28, 2018
*
* @param conditions
* @return
*/
public T having(String... conditions) {
// 先把where子句保留起来
createWhereClause();
// 直接调用where
return this.where(conditions);
}
/**
* order by 的字段
* <br> eg: order_by("table.a", "table.b desc");
* @author abo on Apr 28, 2018
*
* @param columns
* @return
*/
public T order_by(String... columns) {
for (String column : columns) {
// 去掉前后空格
column = column.trim();
// 去掉前后逗号
if (column.startsWith(",")) {
column = column.substring(1);
}
if (column.endsWith(",")) {
column = column.substring(0, column.length() - 1);
}
orderColumns.add(column);
}
return this.getSelf();
}
/**
* 添加语句中的参数值
* @author abo on Apr 28, 2018
*
* @param key
* @param param
* @return
*/
public T addParam(String key, Object param) {
params.put(key, param);
return this.getSelf();
}
/**
* 添加语句中的参数值
* @author abo on Apr 28, 2018
*
* @param params
* @return
*/
public T addParams(Map<String, Object> params) {
for (Entry<String, Object> param : params.entrySet()) {
this.addParam(param.getKey(), param.getValue());
}
return this.getSelf();
}
/**
* 获取 语句 中的参数
* @author abo on Apr 28, 2018
*
* @return
*/
public Map<String, Object> getParams() {
return params;
}
/**
* 按指定大小,分隔集合,将集合按规定个数分为n个部分
*
* @param list
* @param len
* @return
*/
private static List<Collection<?>> splitCollection(Collection<?> collection, int len) {
if (collection == null || collection.size() == 0 || len < 1) {
return null;
}
// 先转换成set去重
// 再转换成list
List<?> list = new ArrayList<Object>(new HashSet<Object>(collection));
// 建一个结果
List<Collection<?>> result = new ArrayList<Collection<?>>();
int size = list.size();
int count = (size + len - 1) / len;
for (int i = 0; i < count; i++) {
List<?> subList = list.subList(i * len,
((i + 1) * len > size ? size : len * (i + 1)));
result.add(subList);
}
return result;
}
/**
* 转换成 查询 语句
*/
@Override
public String toString() {
StringBuilder sqlBuilder = new StringBuilder();
// select
sqlBuilder.append("select");
if (distinct) {
sqlBuilder.append(" distinct");
}
if (selectColumns == null || selectColumns.isEmpty()) {
sqlBuilder.append(" *");
} else {
sqlBuilder.append(" ").append(StringUtils.join(selectColumns, ", "));
}
// from
sqlBuilder.append(" from");
if (tables == null || tables.isEmpty()) {
throw new NrsException("sql语句不完整,缺少from的表。");
}
sqlBuilder.append(" ").append(StringUtils.join(tables, ", "));
// join
sqlBuilder.append(joinClause);
// where
createWhereClause();
sqlBuilder.append(whereClause);
// group by
if (groupColumns != null && !groupColumns.isEmpty()) {
sqlBuilder.append(" group by ").append(StringUtils.join(groupColumns, ", "));
}
// having
createHavingClause();
sqlBuilder.append(havingClause);
// order by
if (orderColumns != null && !orderColumns.isEmpty()) {
sqlBuilder.append(" order by ").append(StringUtils.join(orderColumns, ", "));
}
return sqlBuilder.toString();
}
}
然后是两个类分别继承这个基类,分别用来编写jpql和sql语句。
2.JPQL.java
package com.csair.nrs.jpa.statement;
import java.util.ArrayList;
import java.util.List;
import com.csair.nrs.jpa.BaseEntity;
import com.csair.nrs.jpa.query.JpqlQuery;
import com.csair.nrs.util.ReflectUtil;
import com.csair.nrs.util.domain.ExPage;
import com.csair.nrs.util.domain.ExPageImpl;
import com.csair.nrs.util.domain.ExPageable;
import com.csair.nrs.util.domain.ExSort;
import com.csair.nrs.util.domain.ExSort.Direction;
import com.csair.nrs.util.domain.ExSort.Order;
/**
* 写jpql语句的类
* @author abo on Apr 28, 2018
*
*/
public class JPQL extends AbstractSQL<JPQL> {
@Override
protected JPQL getSelf() {
return this;
}
/**
* 新建一个jpql语句
*/
public JPQL() {
super();
}
/**
* 复制一个jpql
* @param another
*/
private JPQL(JPQL another) {
this();
this.selectColumns = another.selectColumns;
this.distinct = another.distinct;
this.groupColumns = another.groupColumns;
this.havingClause = another.havingClause;
this.joinClause = another.joinClause;
this.orderColumns = another.orderColumns;
this.tables = another.tables;
this.whereClause = another.whereClause;
this.whereList = another.whereList;
this.params = another.params;
}
/**
* 分页查询时用来查询记录总数的jpql
*/
private JPQL countJpql;
/**
* 利用这条jpql查询结果集
* @author abo on Apr 28, 2018
*
* @param resultClass
* <br>resultClass 可以为entity 、简单的javabean 或 基础数据类型 或 Object[].class
* <br>简单的javabean只需属性名与类型 与 对应entity的属性名与类型 相同即可
* <br>基础数据类型 见ReflectUtil.stringToObject
* @return
*/
public <T> List<T> queryList(Class<T> resultClass) {
return new JpqlQuery<T>(BaseEntity.getEntityManager(), this.toString(), resultClass).setParams(this.getParams()).getResultList();
}
/**
* 利用这条jpql查询单个结果
* @author abo on Apr 28, 2018
*
* @param resultClass
* <br>resultClass 可以为entity 、简单的javabean 或 基础数据类型 或 Object[].class
* <br>简单的javabean只需属性名与类型 与 对应entity的属性名与类型 相同即可
* <br>基础数据类型 见ReflectUtil.stringToObject
* @return
*/
public <T> T querySingle(Class<T> resultClass) {
return new JpqlQuery<T>(BaseEntity.getEntityManager(), this.toString(), resultClass).setParams(this.getParams()).getSingleResult();
}
/**
* 是否忽略分页参数中的排序参数
*/
private boolean ignoreSort = false;
/**
* 忽略分页参数中的排序参数
* @author abo on May 2, 2018
*
* @return
*/
public JPQL ignoreSort() {
ignoreSort = true;
return this;
}
/**
* 利用这条jpql分页查询
* <br> 默认按照select的第一项做 count 计算总数, 也可通过setCountJpql设置
* <br> 默认会按照pageRequest中的sort order的属性名 转换为 驼峰命名 进行排序,如果想忽略其中的sort条件,可先调用ignoreSort()
* @author abo on Apr 28, 2018
*
* @param resultClass
* <br>resultClass 可以为entity 、简单的javabean 或 基础数据类型 或 Object[].class
* <br>简单的javabean只需属性名与类型 与 对应entity的属性名与类型 相同即可
* <br>基础数据类型 见ReflectUtil.stringToObject
* @param pageRequest
* @return
*/
public <T> ExPage<T> queryPage(Class<T> resultClass, ExPageable pageRequest) {
// 插入排序条件
ExSort sort = pageRequest.getSort();
if (sort != null && !ignoreSort) {
for (Order order : sort.getOrders()) {
String orderClause = ReflectUtil.underlineToCamel(order.getProperty());
if (Direction.DESC.equals(order.getDirection())) {
orderClause = orderClause + " desc";
} else {
orderClause = orderClause + " asc";
}
this.order_by(orderClause);
}
}
// 查询结果
List<T> result = new JpqlQuery<T>(BaseEntity.getEntityManager(), this.toString(), resultClass).setPageParams(getParams(), pageRequest).getResultList();
// 查询总数
Long count = this.getCountJpql().querySingle(Long.class);
return new ExPageImpl<T>(result, pageRequest, count);
}
/**
* 默认按照select的第一项进行count计算,也可自己设置
* @author abo on Apr 28, 2018
*
* @return
*/
public JPQL getCountJpql() {
if (countJpql == null) {
// 复制一个
countJpql = new JPQL(this);
// 拿到select的第一个字段
String first = countJpql.selectColumns.get(0);
// 按,分割
first = first.split(",")[0].trim();
if (first.contains(" ")) {
// 包含空格,取空格之前的
first = first.substring(0, first.indexOf(" "));
}
first = "count(" + first + ")";
List<String> selectColumns = new ArrayList<String>();
selectColumns.add(first);
countJpql.selectColumns = selectColumns;
// 不需要order
countJpql.orderColumns = new ArrayList<String>();
}
return countJpql;
}
/**
* 设置分页查询记录总数的jpql
* @author abo on Apr 28, 2018
*
* @param countJpql
*/
public JPQL setCountJpql(JPQL countJpql) {
this.countJpql = countJpql;
return this;
}
}
这里面又增加了3个query方法,结合上篇的工具类,可以在写完jpql之后直接执行查询。这里的BaseEntity.getEntityManager()只是获取到jpq的entityManage,用其他任何方法,只要能获取到entityManage都是可以的。
3.SQL.java
package com.csair.nrs.jpa.statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.Type;
import com.csair.nrs.jpa.BaseEntity;
import com.csair.nrs.jpa.query.SqlQuery;
import com.csair.nrs.util.ReflectUtil;
import com.csair.nrs.util.domain.ExPage;
import com.csair.nrs.util.domain.ExPageImpl;
import com.csair.nrs.util.domain.ExPageable;
import com.csair.nrs.util.domain.ExSort;
import com.csair.nrs.util.domain.ExSort.Direction;
import com.csair.nrs.util.domain.ExSort.Order;
/**
* 写sql语句的类
* <br> 在能使用JPQL的情况下推荐使用 jpql
* @author abo on Apr 28, 2018
*
*/
public class SQL extends AbstractSQL<SQL> {
@Override
protected SQL getSelf() {
return this;
}
/**
* 新建一个sql语句
*/
public SQL() {
super();
}
/**
* 复制一个sql
* @param another
*/
private SQL(SQL another) {
this();
this.selectColumns = another.selectColumns;
this.distinct = another.distinct;
this.groupColumns = another.groupColumns;
this.havingClause = another.havingClause;
this.joinClause = another.joinClause;
this.orderColumns = another.orderColumns;
this.tables = another.tables;
this.whereClause = another.whereClause;
this.whereList = another.whereList;
this.params = another.params;
}
/**
* 分页查询时用来查询记录总数的sql
*/
private SQL countSql;
/**
* 记录查询字段的类型
*/
private Map<String, Type> scalarMap = new HashMap<String, Type>();
/**
* 设置select中字段的数据类型,推荐手动进行设置
* <br> eg: select("table.name").addScalar("name", xxx); 或 select("table.name as a").addScalar("a", xxx);
* @author abo on Apr 28, 2018
*
* @param alias 字段别名
* @param type 从StandardBasicTypes中取
* @return
*/
public SQL addScalar(String alias, Type type) {
scalarMap.put(alias, type);
return this;
}
/**
* 利用这条sql查询结果集
* @author abo on Apr 28, 2018
*
* @param resultClass
* <br>resultClass 可以为简单的javabean 或 基础数据类型 或 Object[].class
* <br>简单的javabean 需 所含属性皆为基础数据类型
* <br>基础数据类型 见ReflectUtil.stringToObject / 或者是addScalar设置的具体类型
* @return
*/
public <T> List<T> queryList(Class<T> resultClass) {
return new SqlQuery<T>(BaseEntity.getEntityManager(), this.toString(), resultClass).setParams(this.getParams()).addScalars(scalarMap).getResultList();
}
/**
* 利用这条sql查询单个结果
* @author abo on Apr 28, 2018
*
* @param resultClass
* <br>resultClass 可以为简单的javabean 或 基础数据类型 或 Object[].class
* <br>简单的javabean 需 所含属性皆为基础数据类型
* <br>基础数据类型 见ReflectUtil.stringToObject / 或者是addScalar设置的具体类型
* @return
*/
public <T> T querySingle(Class<T> resultClass) {
return new SqlQuery<T>(BaseEntity.getEntityManager(), this.toString(), resultClass).setParams(this.getParams()).addScalars(scalarMap).getSingleResult();
}
/**
* 是否忽略分页参数中的排序参数
*/
private boolean ignoreSort = false;
/**
* 忽略分页参数中的排序参数
* @author abo on May 2, 2018
*
* @return
*/
public SQL ignoreSort() {
ignoreSort = true;
return this;
}
/**
* 利用这条sql分页查询
* <br> 默认按照select的第一项做 count 计算总数, 也可通过setCountSql设置
* <br> 默认会按照pageRequest中的sort order的属性名 转换为 下划线 进行排序,如果想忽略其中的sort条件,可先调用ignoreSort()
* @author abo on Apr 28, 2018
*
* @param resultClass
* <br>resultClass 可以为简单的javabean 或 基础数据类型 或 Object[].class
* <br>简单的javabean 需 所含属性皆为基础数据类型
* <br>基础数据类型 见ReflectUtil.stringToObject / 或者是addScalar设置的具体类型
* @param pageRequest
* @return
*/
public <T> ExPage<T> queryPage(Class<T> resultClass, ExPageable pageRequest) {
// 插入排序条件
ExSort sort = pageRequest.getSort();
if (sort != null && !ignoreSort) {
for (Order order : sort.getOrders()) {
String orderClause = ReflectUtil.camelToUnderline(order.getProperty());
if (Direction.DESC.equals(order.getDirection())) {
orderClause = orderClause + " desc";
} else {
orderClause = orderClause + " asc";
}
this.order_by(orderClause);
}
}
// 查询结果
List<T> result = new SqlQuery<T>(BaseEntity.getEntityManager(), this.toString(), resultClass).setPageParams(getParams(), pageRequest).addScalars(scalarMap).getResultList();
// 查询总数
Long count = this.getCountSql().querySingle(Long.class);
return new ExPageImpl<T>(result, pageRequest, count);
}
/**
* 默认按照select的第一项进行count计算,也可自己设置
* @author abo on Apr 28, 2018
*
* @return
*/
public SQL getCountSql() {
if (countSql == null) {
// 复制一个
countSql = new SQL(this);
// 拿到select的第一个字段
String first = countSql.selectColumns.get(0);
// 按,分割
first = first.split(",")[0].trim();
if (first.contains(" ")) {
// 包含空格,取空格之前的
first = first.substring(0, first.indexOf(" "));
}
first = "count(" + first + ") as ct";
List<String> selectColumns = new ArrayList<String>();
selectColumns.add(first);
countSql.selectColumns = selectColumns;
countSql.addScalar("ct", StandardBasicTypes.LONG);
// 不需要order
countSql.orderColumns = new ArrayList<String>();
}
return countSql;
}
/**
* 设置分页查询记录总数的sql
* @author abo on Apr 28, 2018
*
* @param countsql
*/
public SQL setCountSql(SQL countSql) {
this.countSql = countSql;
return this;
}
}
这里面再次保留addScalar方法,用来对字段类型进行设置。
这样就大功告成了,写sql,可以像这个样子:
return new SQL() {{
select("*");
addScalar("id", StandardBasicTypes.LONG).addScalar("log_level", StandardBasicTypes.INTEGER)
.addScalar("log_msg", StandardBasicTypes.STRING).addScalar("userno", StandardBasicTypes.STRING)
.addScalar("from_class", StandardBasicTypes.STRING).addScalar("from_method", StandardBasicTypes.STRING).addScalar("from_line", StandardBasicTypes.INTEGER)
.addScalar("log_time", StandardBasicTypes.TIMESTAMP);
from(tableName);
if (whereMap != null) {
containText("userno", whereMap.get("userno"));
containText("log_msg", whereMap.get("logMsg"));
containText("from_class", whereMap.get("fromClass"));
containText("from_method", whereMap.get("fromMethod"));
gte("log_time", whereMap.get("startLogTime"));
lte("log_time", whereMap.get("endLogTime"));
}
}}.queryPage(ModuleLogVO.class, pageRequest);
这风格,是不是很mybatis?