一个JPA环境下原生SQL查询的工具类

感谢JFinal的Db.paginate方法,此实现参考之。

我们在JPA环境下,某些查询的SQL可能是动态生成的,查询或者分页我们就需要手动使用EntityManager来查询,参数处理和结果集就需要手动,此工具类就是干这些脏活累活的。废话不多说,直接上代码。

import cn.palmte.gpas.bean.Page;
import org.hibernate.Session;
import org.hibernate.transform.Transformers;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * @author xiongshiyan at 2018/5/9
 * @see cn.zytx.common.db.QueryHelper
 * @see Record
 * SQL语句用{@see QueryHelper}封装。结果集用JavaBean或者{@see Record}来封装。JavaBean需要保证别名就是属性。
 * 可以使用{@see QueryHelper}完全处理参数,也可以不处理,支持?和:的方式
 */
public class Pagination {
    private EntityManager entityManager;

    public Pagination(EntityManager entityManager){
        this.entityManager = entityManager;
    }
    public Pagination(){}

    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public EntityManager getEntityManager() {
        return entityManager;
    }

    /**
     * 返回查询的一个Record,没有则为null
     */
    public Record findFirst(String sql , Object... params){
        return findFirst(sql , Record.class , params);
    }
    public Record findFirst(String sql , Map<String , Object> searchMap){
        return findFirst(sql , Record.class , searchMap);
    }

    /**
     * 返回查询的一个实体,没有则为null
     */
    public <T> T findFirst(String sql , Class<T> clazz , Object... params){
        List<T> ts = find(sql, clazz, params);
        return (ts == null || ts.size() == 0) ? null : ts.get(0);
    }
    public <T> T findFirst(String sql , Class<T> clazz ,Map<String , Object> searchMap){
        List<T> ts = find(sql, clazz, searchMap);
        return (ts == null || ts.size() == 0) ? null : ts.get(0);
    }


    public List<Record> find(String sql , Object... params){
        return find(sql, Record.class , params);
    }
    public List<Record> find(String sql , Map<String , Object> searchMap){
        return find(sql, Record.class , searchMap);
    }
    public List<Record> find(String sql){
        return find(sql, Record.class , (Map<String , Object>)null);
    }

    /**
     * 查询列表
     * @param sql native sql语句,可以包含?
     * @param clazz 返回的类型,可以是JavaBean,可以是Record
     * @param params 参数列表
     * @param <T> 泛型
     * @return 查询列表结果
     */
    public <T> List<T> find(String sql , Class<T> clazz , Object... params){
        Session session = entityManager.unwrap(Session.class);
        org.hibernate.Query query = session.createSQLQuery(sql);

        //0-Based
        for (int i = 0; i < params.length; i++) {
            query.setParameter(i , params[i]);
        }

        List list = getList(query, clazz);

        return list;
    }
    /**
     * 查询列表
     * @param sql native sql语句,可以包含 :具名参数
     * @param clazz 返回的类型,可以是JavaBean,可以是Record
     * @param searchMap 具名参数列表
     * @param <T> 泛型
     * @return 查询列表结果
     */
    public <T> List<T> find(String sql , Class<T> clazz , Map<String , Object> searchMap){
        Session session = entityManager.unwrap(Session.class);
        org.hibernate.Query query = session.createSQLQuery(sql);

        if(null != searchMap) {
            searchMap.forEach(query::setParameter);
        }

        List list = getList(query, clazz);

        return list;
    }



    /**----------------------------------------------record-positioned-parameter---------------------------------------------------*/
    public Page<Record> paginate( String nativeSQL,int pageNumber, int pageSize, Object... params){
        String nativeCountSQL = getCountSQL(nativeSQL);
        return paginate( null, nativeSQL, nativeCountSQL, Record.class,pageNumber, pageSize, params);
    }

    public Page<Record> paginate( String nativeSQL, Boolean isGroupBySql, int pageNumber, int pageSize, Object... params){
        String nativeCountSQL = getCountSQL(nativeSQL);
        return paginate( isGroupBySql, nativeSQL, nativeCountSQL, Record.class, pageNumber, pageSize,params);
    }
    public Page<Record> paginate( String nativeSQL, String nativeCountSQL, int pageNumber, int pageSize, Object... params){
        return paginate( null, nativeSQL, nativeCountSQL, Record.class, pageNumber, pageSize,params);
    }

    public Page<Record> paginate( Boolean isGroupBySql, String nativeSQL ,String nativeCountSQL ,int pageNumber, int pageSize, Object... params){
        return paginate( isGroupBySql, nativeSQL, nativeCountSQL, Record.class,pageNumber, pageSize, params);
    }

    /**----------------------------------------------record-maped-parameter---------------------------------------------------*/
    public Page<Record> paginate( String nativeSQL,int pageNumber, int pageSize, Map<String , Object> searchMap){
        String nativeCountSQL = getCountSQL(nativeSQL);
        return paginate( null, nativeSQL, nativeCountSQL, Record.class,pageNumber, pageSize, searchMap);
    }

    public Page<Record> paginate( String nativeSQL, Boolean isGroupBySql, int pageNumber, int pageSize, Map<String , Object> searchMap){
        String nativeCountSQL = getCountSQL(nativeSQL);
        return paginate( isGroupBySql, nativeSQL, nativeCountSQL, Record.class, pageNumber, pageSize,searchMap);
    }
    public Page<Record> paginate(String nativeSQL, String nativeCountSQL, int pageNumber, int pageSize, Map<String , Object> searchMap){
        return paginate( null, nativeSQL, nativeCountSQL, Record.class, pageNumber, pageSize,searchMap);
    }

    public Page<Record> paginate( Boolean isGroupBySql, String nativeSQL ,String nativeCountSQL ,int pageNumber, int pageSize, Map<String , Object> searchMap){
        return paginate( isGroupBySql, nativeSQL, nativeCountSQL, Record.class,pageNumber, pageSize, searchMap);
    }


    /**----------------------------------------------JavaBean-positioned-parameter---------------------------------------------------*/
    public <T> Page<T> paginate( Boolean isGroupBySql, String nativeSQL , Class<T> clazz, int pageNumber, int pageSize,Object... params){
        String nativeCountSQL = getCountSQL(nativeSQL);
        return paginate( isGroupBySql, nativeSQL, nativeCountSQL, clazz, pageNumber, pageSize,params);
    }
    public <T> Page<T> paginate( String nativeSQL ,String nativeCountSQL, Class<T> clazz,int pageNumber, int pageSize, Object... params){
        return paginate( null, nativeSQL, nativeCountSQL, clazz, pageNumber, pageSize, params);
    }

    public <T> Page<T> paginate(String nativeSQL , Class<T> clazz ,int pageNumber, int pageSize,  Object... params){
        String nativeCountSQL = getCountSQL(nativeSQL);
        return paginate( null, nativeSQL, nativeCountSQL ,clazz ,pageNumber, pageSize, params);
    }

    /**----------------------------------------------JavaBean-maped-parameter---------------------------------------------------*/
    public <T> Page<T> paginate( String nativeSQL , Class<T> clazz ,int pageNumber, int pageSize, Map<String , Object> searchMap){
        String nativeCountSQL = getCountSQL(nativeSQL);
        return paginate( null, nativeSQL, nativeCountSQL ,clazz ,pageNumber, pageSize, searchMap);
    }
    public <T> Page<T> paginate( Boolean isGroupBySql, String nativeSQL , Class<T> clazz,int pageNumber, int pageSize, Map<String , Object> searchMap){
        String nativeCountSQL = getCountSQL(nativeSQL);
        return paginate( isGroupBySql, nativeSQL, nativeCountSQL, clazz, pageNumber, pageSize,searchMap);
    }
    public <T> Page<T> paginate( String nativeSQL ,String nativeCountSQL, Class<T> clazz,int pageNumber, int pageSize, Map<String , Object> searchMap){
        return paginate( null, nativeSQL, nativeCountSQL, clazz, pageNumber, pageSize, searchMap);
    }

    /**
     *
     * @param pageNumber pageNumber
     * @param pageSize pageSize
     * @param isGroupBySql 是否包含Group by语句,影响总行数
     * @param nativeSQL 原生SQL语句 {@see QueryHelper}
     * @param nativeCountSQL 原生求总行数的SQL语句 {@see QueryHelper}
     * @param clazz JavaBean风格的DTO或者Record,需要用别名跟JavaBean对应
     * @param <T> 返回JavaBean风格的DTO或者Record
     * @param params 按照顺序给条件
     */
    public <T> Page<T> paginate( Boolean isGroupBySql, String nativeSQL, String nativeCountSQL , Class<T> clazz , int pageNumber, int pageSize, Object... params){
        if (pageNumber < 1 || pageSize < 1) {
            throw new IllegalArgumentException("pageNumber and pageSize must more than 0");
        }
        Query countQuery = entityManager.createNativeQuery(nativeCountSQL);

        //坑死人,1-Based
        for (int i = 1; i <= params.length; i++) {
            countQuery.setParameter(i , params[i-1]);
        }

        List countQueryResultList = countQuery.getResultList();
        int size = countQueryResultList.size();
        if (isGroupBySql == null) {
            isGroupBySql = size > 1;
        }

        long totalRow;
        if (isGroupBySql) {
            totalRow = size;
        } else {
            totalRow = (size > 0) ? ((Number)countQueryResultList.get(0)).longValue() : 0;
        }
        if (totalRow == 0) {
            return new Page<>(new ArrayList<>(0), pageNumber, pageSize, 0, 0);
        }

        int totalPage = (int) (totalRow / pageSize);
        if (totalRow % pageSize != 0) {
            totalPage++;
        }

        if (pageNumber > totalPage) {
            return new Page<>(new ArrayList<>(0), pageNumber, pageSize, totalPage, (int)totalRow);
        }

        Session session = entityManager.unwrap(Session.class);
        int offset = pageSize * (pageNumber - 1);
        org.hibernate.Query query = session.createSQLQuery(nativeSQL).setFirstResult(offset).setMaxResults(pageSize);

        //坑死人,0-Based
        for (int i = 0; i < params.length; i++) {
            query.setParameter(i , params[i]);
        }

        final List list = getList(query, clazz);


        return new Page<T>(list, pageNumber, pageSize, totalPage, (int)totalRow);
    }
    /**
     *
     * @param pageNumber pageNumber
     * @param pageSize pageSize
     * @param isGroupBySql 是否包含Group by语句,影响总行数
     * @param nativeSQL 原生SQL语句 {@see QueryHelper}
     * @param nativeCountSQL 原生求总行数的SQL语句 {@see QueryHelper}
     * @param clazz JavaBean风格的DTO或者Record,需要用别名跟JavaBean对应
     * @param <T> 返回JavaBean风格的DTO或者Record
     * @param searchMap k-v条件
     */
    public <T> Page<T> paginate( Boolean isGroupBySql, String nativeSQL,String nativeCountSQL , Class<T> clazz ,int pageNumber, int pageSize, Map<String , Object> searchMap){
        if (pageNumber < 1 || pageSize < 1) {
            throw new IllegalArgumentException("pageNumber and pageSize must more than 0");
        }
        Query countQuery = entityManager.createNativeQuery(nativeCountSQL);

        if(null != searchMap) {
            searchMap.forEach(countQuery::setParameter);
        }

        List countQueryResultList = countQuery.getResultList();
        int size = countQueryResultList.size();
        if (isGroupBySql == null) {
            isGroupBySql = size > 1;
        }

        long totalRow;
        if (isGroupBySql) {
            totalRow = size;
        } else {
            totalRow = (size > 0) ? ((Number)countQueryResultList.get(0)).longValue() : 0;
        }
        if (totalRow == 0) {
            return new Page<>(new ArrayList<>(0), pageNumber, pageSize, 0, 0);
        }

        int totalPage = (int) (totalRow / pageSize);
        if (totalRow % pageSize != 0) {
            totalPage++;
        }

        if (pageNumber > totalPage) {
            return new Page<>(new ArrayList<>(0), pageNumber, pageSize, totalPage, (int)totalRow);
        }

        Session session = entityManager.unwrap(Session.class);
        int offset = pageSize * (pageNumber - 1);
        org.hibernate.Query query = session.createSQLQuery(nativeSQL).setFirstResult(offset).setMaxResults(pageSize);

        if(null != searchMap) {
            searchMap.forEach(query::setParameter);
        }

        final List list = getList(query, clazz);


        return new Page<T>(list, pageNumber, pageSize, totalPage, (int)totalRow);
    }

    private <T> List getList(org.hibernate.Query query, Class<T> clazz) {
        final List list;

        //Object[].class
        if(Object[].class == clazz){
            return query.list();
        }

        query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        List mapList = query.list();
        list = new ArrayList(mapList.size());
        mapList.forEach(map->{
            Map<String , Object> tmp = (Map<String , Object>) map;
            //Record.class
            if(Record.class == clazz){
                list.add(new Record(tmp));
                //Map及子类
            }else if(Map.class.isAssignableFrom(clazz)){
                list.add(tmp);
                //JavaBean风格
            }else {
                list.add(Map2Bean.convert(tmp , clazz));
            }
        });
        return list;
    }
    /*private <T> List getList(org.hibernate.Query query, Class<T> clazz) {
        final List list;

        if(Record.class == clazz){
            //返回Record
            query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
            List mapList = query.list();
            list = new ArrayList(mapList.size());
            mapList.forEach(map->{
                Map<String , Object> tmp = (Map<String , Object>) map;
                list.add(new Record(tmp));
            });
        }else {
            //返回JavaBean
            //只能返回简单的Javabean,不具备级联特性
            query.setResultTransformer(Transformers.aliasToBean(clazz));
            list = query.list();
        }
        return list;
    }*/






    private String getCountSQL(String sql){
        String countSQL = "SELECT COUNT(*) AS totalRow " + sql.substring(sql.toUpperCase().indexOf("FROM"));
        return  replaceOrderBy(countSQL);
    }

    protected static class Holder {
        private static final Pattern ORDER_BY_PATTERN = Pattern.compile(
                "order\\s+by\\s+[^,\\s]+(\\s+asc|\\s+desc)?(\\s*,\\s*[^,\\s]+(\\s+asc|\\s+desc)?)*",
                Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
    }

    public String replaceOrderBy(String sql) {
        return Holder.ORDER_BY_PATTERN.matcher(sql).replaceAll("");
    }
}

此工具类可以将结果集封装为Object[]、Map、Bean、Record等。Record参考JFinal的Record(可以类比Map,但是类型更安全、更易处理)。

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Record
 * @author xiongshiyan
 */
public class Record implements Serializable {

    private static final long serialVersionUID = 905784513600884082L;
	
	private Map<String, Object> columns = new HashMap<>();

	public Record(){
    }

	public Record(Map<String, Object> columns){
        this.columns = columns;
    }

	public Map<String, Object> getColumns() {
		return columns;
	}
	public Record setColumns(Map<String, Object> columns) {
        this.getColumns().putAll(columns);
		return this;
	}
	
	public Record setColumns(Record record) {
		getColumns().putAll(record.getColumns());
		return this;
	}
	
	public Record remove(String column) {
		getColumns().remove(column);
		return this;
	}
	
	public Record remove(String... columns) {
		if (columns != null){
			for (String c : columns) {
				this.getColumns().remove(c);
			}
		}
		return this;
	}
	public Record removeNullValueColumns() {
		for (java.util.Iterator<Map.Entry<String, Object>> it = getColumns().entrySet().iterator(); it.hasNext();) {
			Map.Entry<String, Object> e = it.next();
			if (e.getValue() == null) {
				it.remove();
			}
		}
		return this;
	}
	
	/**
	 * Keep columns of this record and remove other columns.
	 * @param columns the column names of the record
	 */
	public Record keep(String... columns) {
		if (columns != null && columns.length > 0) {
			Map<String, Object> newColumns = new HashMap<String, Object>(columns.length);	// getConfig().containerFactory.getColumnsMap();
			for (String c : columns) {
                if (this.getColumns().containsKey(c)) {    // prevent put null value to the newColumns
                    newColumns.put(c, this.getColumns().get(c));
                }
            }
			
			this.getColumns().clear();
			this.getColumns().putAll(newColumns);
		}else {
            this.getColumns().clear();
        }
		return this;
	}
	
	/**
	 * Keep column of this record and remove other columns.
	 * @param column the column names of the record
	 */
	public Record keep(String column) {
		if (getColumns().containsKey(column)) {	// prevent put null value to the newColumns
			Object keepIt = getColumns().get(column);
			getColumns().clear();
			getColumns().put(column, keepIt);
		}else {
            getColumns().clear();
        }
		return this;
	}
	
	public Record clear() {
		getColumns().clear();
		return this;
	}
	
	public Record set(String column, Object value) {
		getColumns().put(column, value);
		return this;
	}
	
	public <T> T get(String column) {
		return (T)getColumns().get(column);
	}
	
	public <T> T get(String column, Object defaultValue) {
		Object result = getColumns().get(column);
		return (T)(result != null ? result : defaultValue);
	}
	
	/**
	 * Get column of mysql type: varchar, char, enum, set, text, tinytext, mediumtext, longtext
	 */
	public String getStr(String column) {
		return (String)getColumns().get(column);
	}
	
	/**
	 * Get column of mysql type: int, integer, tinyint(n) n > 1, smallint, mediumint
	 */
	public Integer getInt(String column) {
		return (Integer)getColumns().get(column);
	}
	
	/**
	 * Get column of mysql type: bigint
	 */
	public Long getLong(String column) {
		return (Long)getColumns().get(column);
	}

	/**
	 * Get column of mysql type: unsigned bigint
	 */
	public java.math.BigInteger getBigInteger(String column) {
		return (java.math.BigInteger)getColumns().get(column);
	}
	
	/**
	 * Get column of mysql type: date, year
	 */
	public java.util.Date getDate(String column) {
		return (java.util.Date)getColumns().get(column);
	}
	
	/**
	 * Get column of mysql type: time
	 */
	public java.sql.Time getTime(String column) {
		return (java.sql.Time)getColumns().get(column);
	}
	
	/**
	 * Get column of mysql type: timestamp, datetime
	 */
	public java.sql.Timestamp getTimestamp(String column) {
		return (java.sql.Timestamp)getColumns().get(column);
	}
	
	/**
	 * Get column of mysql type: real, double
	 */
	public Double getDouble(String column) {
		return (Double)getColumns().get(column);
	}
	
	/**
	 * Get column of mysql type: float
	 */
	public Float getFloat(String column) {
		return (Float)getColumns().get(column);
	}
	
	/**
	 * Get column of mysql type: bit, tinyint(1)
	 */
	public Boolean getBoolean(String column) {
		return (Boolean)getColumns().get(column);
	}
	
	/**
	 * Get column of mysql type: decimal, numeric
	 */
	public java.math.BigDecimal getBigDecimal(String column) {
		return (java.math.BigDecimal)getColumns().get(column);
	}
	
	/**
	 * Get column of mysql type: binary, varbinary, tinyblob, blob, mediumblob, longblob
	 * I have not finished the test.
	 */
	public byte[] getBytes(String column) {
		return (byte[])getColumns().get(column);
	}
	
	/**
	 * Get column of any type that extends from Number
	 */
	public Number getNumber(String column) {
		return (Number)getColumns().get(column);
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append(super.toString()).append(" {");
		boolean first = true;
		for (Map.Entry<String, Object> e : getColumns().entrySet()) {
			if (first){
				first = false;
			}else {
                sb.append(", ");
            }
			
			Object value = e.getValue();
			if (value != null) {
                value = value.toString();
            }
			sb.append(e.getKey()).append(":").append(value);
		}
		sb.append("}");
		return sb.toString();
	}

	@Override
	public boolean equals(Object o) {
		if (!(o instanceof Record)) {
            return false;
        }
		if (o == this) {
            return true;
        }
		return this.getColumns().equals(((Record)o).getColumns());
	}

	@Override
	public int hashCode() {
		return getColumns() == null ? 0 : getColumns().hashCode();
	}
	
	/**
	 * Return column names of this record.
	 */
	public String[] getColumnNames() {
		Set<String> attrNameSet = getColumns().keySet();
		return attrNameSet.toArray(new String[attrNameSet.size()]);
	}
	
	/**
	 * Return column values of this record.
	 */
	public Object[] getColumnValues() {
		java.util.Collection<Object> attrValueCollection = getColumns().values();
		return attrValueCollection.toArray(new Object[attrValueCollection.size()]);
	}
	
	/**
	 * Return json string of this record.
	 */
	public String toJson() {
		throw new UnsupportedOperationException("还未实现");
	}
}

Page也是参考JFinal的实现,代表一页信息。

import java.io.Serializable;
import java.util.List;

/**
 * Page is the result of Model.paginate(......) or Db.paginate(......)
 */
public class Page<T> implements Serializable {
	
	private static final long serialVersionUID = -5395997221963176643L;
	
	private List<T> list;				// list result of this page
	private int pageNumber;				// page number
	private int pageSize=10;				// result amount of this page
	private int totalPage;				// total page
	private int totalRow;				// total row


	public Page(int pageNumber) {
		this.pageNumber = pageNumber;
	}

	/**
	 * Constructor.
	 * @param list the list of paginate result
	 * @param pageNumber the page number
	 * @param pageSize the page size
	 * @param totalPage the total page of paginate
	 * @param totalRow the total row of paginate
	 */
	public Page(List<T> list, int pageNumber, int pageSize, int totalPage, int totalRow) {
		this.list = list;
		this.pageNumber = pageNumber;
		this.pageSize = pageSize;
		this.totalPage = totalPage;
		this.totalRow = totalRow;
	}

	public Page(int pageNumber, int pageSize) {
		this.pageNumber = pageNumber;
		this.pageSize = pageSize;
	}
	
	/**
	 * Return list of this page.
	 */
	public List<T> getList() {
		return list;
	}
	
	/**
	 * Return page number.
	 */
	public int getPageNumber() {
		return pageNumber;
	}
	
	/**
	 * Return page size.
	 */
	public int getPageSize() {
		return pageSize;
	}
	
	/**
	 * Return total page.
	 */
	public int getTotalPage() {

		totalPage = totalRow / pageSize;
		if (totalRow % pageSize > 0) {
			totalPage++;
		}
		return totalPage;
	}
	
	/**
	 * Return total row.
	 */
	public int getTotalRow() {
		return totalRow;
	}
	
	public boolean isFirstPage() {
		return pageNumber == 1;
	}
	
	public boolean isLastPage() {
		return pageNumber == totalPage;
	}

	public void setList(List<T> list) {
		this.list = list;
	}

	public void setPageNumber(int pageNumber) {
		this.pageNumber = pageNumber;
	}

	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

	public void setTotalPage(int totalPage) {
		this.totalPage = totalPage;
	}

	public void setTotalRow(int totalRow) {
		this.totalRow = totalRow;
	}

	@Override
	public String toString() {
		return "Page{" +
				"list=" + list +
				", pageNumber=" + pageNumber +
				", pageSize=" + pageSize +
				", totalPage=" + totalPage +
				", totalRow=" + totalRow +
				'}';
	}
}

其中的一个关键实现,Map-->Bean依赖于一个工具类Map2Bean,支持基本数据类型、下划线转驼峰命名方式、继承(域名不能相同),但是不支持map、list、set等,查询返回的结果集应该不存在这些数据类型吧。应该还有更好的实现。

import java.lang.reflect.Field;
import java.util.*;

/**
 * 将查询结果 map 封装成对应的javaBean,支持级联 ,但是属性不能重复
 * 对应的javaBean的属性名必须以小驼峰形式命名,否则无法填充数据
 * @author zenghl
 * @author xiongshiyan
 */
public class Map2Bean {

    private Map2Bean(){
    }

    /**
     * 将 map 数据封装成javaBean
     * @param map Map类型数据
     * @param clazz 需要转换的JavaBean
     * @param <T> 泛型
     * @return JavaBean
     */
    public static  <T> T convert(Map<String,Object> map,Class<T> clazz){
        Map<String, Object> tmp = _2CamelWith(map);

        try {
            final T instance = clazz.newInstance();
            //Field[] fields = clazz.getDeclaredFields();
            List<Field> fields = new ArrayList<>();
            parseAllFields(clazz , fields);

            for (Field field : fields) {
                String fieldName = field.getName();
                Class<?> type = field.getType();
                if(!ObjectKit.canSetValueDirectly(type)){
                    ObjectKit.setValue(instance, field, convert(tmp, type));
                }else {
                    Object value = tmp.get(fieldName);
                    if(null == value){
                        //null没得必要设置
                        continue;
                    }
                    ObjectKit.setValue(instance, field, value);
                    /*map.forEach((k,v)->{
                        String columnToField = StrKit._2Camel(k);
                        if(fieldName.equals(columnToField)) {
                            ObjectKit.setValue(instance, field, v);
                        }
                    });*/
                }
            }

            return instance;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 递归获取某个类的所有的属性
     * getDeclaredFields 获取某个类的所有的字段,包括私有的,但是不包括父类的
     * getFields 获得某个类的所有的公共(public)的字段,包括父类中的字段
     */
    private static void parseAllFields(Class<?> clazz , List<Field> list){
        if(clazz != Object.class){
            Field[] fields = clazz.getDeclaredFields();
            list.addAll(Arrays.asList(fields));
            parseAllFields(clazz.getSuperclass() , list);
        }
    }
    /**
     * 将map中的下划线转换为小驼峰key添加进去
     */
    private static Map<String, Object> _2CamelWith(Map<String, Object> map) {
        final Map<String , Object> tmp = new LinkedHashMap<>(map);
        map.forEach((k , v) ->{
            if(k.contains("_")){
                //原来的还是保留,万一有些Bean中字段有"_"呢 map.remove(k);
                tmp.put(StrKit._2Camel(k) , v);
            }}
        );
        return tmp;
    }

}

此工具类的关键是注入一个EntityManager。在SpringBoot环境中,我们可以将Pagination注入,然后使用即可。其中注入EntityManager在单数据源和多数据源的情况还需要特别注意。见下一篇博文。

 

SQL语句的动态生成见另外一篇博文:

一个处理SQL语句多条件添加的工具类

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值