上一篇给了两个执行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?