一、前言
通过springframework的orm的org.springframework.orm.jpa.support.JpaDaoSupport实现通用dao对象实现,实现通用的实体服务类EntityService,便于业务服务类继承复用
二、代码示例
1.继承dao依赖类BaseJpaDao,代码如下
import java.util.List;@b@import javax.persistence.EntityManager;@b@import javax.persistence.PersistenceException;@b@import javax.persistence.Query;@b@import javax.persistence.TypedQuery;@b@import javax.persistence.criteria.CriteriaBuilder;@b@import javax.persistence.criteria.CriteriaQuery;@b@import javax.persistence.criteria.Root;@b@import javax.persistence.criteria.Selection;@b@@b@import org.springframework.orm.jpa.JpaCallback;@b@import org.springframework.orm.jpa.JpaTemplate;@b@import org.springframework.orm.jpa.support.JpaDaoSupport;@b@import org.springframework.util.Assert;@b@@b@import com.woopa.common.persist.expression.JpaCriteriaExpressionParser;@b@import com.woopa.common.persist.expression.SQLLikeExpressionParser; @b@@b@public class BaseJpaDao extends JpaDaoSupport {@b@ @b@ JpaTemplate template;@b@ @b@ protected void initDao(){@b@ template = super.getJpaTemplate();@b@ }@b@ /**@b@ * 分页查询@b@ * @param <T>@b@ * @param start@b@ * @param limit@b@ * @param queryString@b@ * @param values@b@ * @return@b@ */@b@ public <T> List<T> queryForPage(final int start, final int limit,@b@ final String queryString, final Object... values){@b@ return template.executeFind(new JpaCallback<List<T>>(){@b@ @Override@b@ public List<T> doInJpa(EntityManager em) throws PersistenceException {@b@ Query query = em.createQuery(queryString);@b@ if(values != null){@b@ for(int i=0,len=values.length; i<len; i++){@b@ query.setParameter(i+1, values[i]);@b@ }@b@ }@b@ @b@ template.prepareQuery(query);@b@ @b@ return query.setFirstResult(start).setMaxResults(limit).getResultList();@b@ }@b@ });@b@ }@b@ /**@b@ * 单对象查询,如查询结果集大于一条记录,则抛出异常@b@ * @param <T>@b@ * @param queryString@b@ * @param values@b@ * @return@b@ */@b@ public <T> T queryForObject(final String queryString, final Object... values){@b@ return template.execute(new JpaCallback<T>(){@b@ @Override@b@ public T doInJpa(EntityManager em) throws PersistenceException {@b@ Query query = em.createQuery(queryString);@b@ if(values != null){@b@ for(int i=0,len=values.length; i<len; i++){@b@ query.setParameter(i+1, values[i]);@b@ }@b@ }@b@ @b@ template.prepareQuery(query);@b@ @b@ return (T) query.getSingleResult();@b@ }@b@ });@b@ }@b@ /**@b@ * 简化表达式查询@b@ * IN查询表达可写为propertyName@I5,表示IN的参数有5个,@b@ * 同时参数values对应IN查询的参数必须是一个数组,数组长度应与@I后面的数字相等@b@ * @param <T>@b@ * @param entityClass 实体类@b@ * @param expressions@b@ * @param values@b@ * @return @b@ */@b@ public <T> List<T> queryByExpressions(final Class<T> entityClass, final String[] expressions, final Object... values){@b@ return template.executeFind(new JpaCallback<List<T>>(){@b@ @Override@b@ public List<T> doInJpa(EntityManager em)@b@ throws PersistenceException {@b@ TypedQuery<T> query = createQueryByExpressions(em, entityClass, expressions, values);@b@ @b@ template.prepareQuery(query);@b@ @b@ return query.getResultList();@b@ }@b@ });@b@ }@b@ /**@b@ * 简化表达式查询@b@ * IN查询表达可写为propertyName@I5,表示IN的参数有5个,@b@ * 同时参数values对应IN查询的参数必须是一个数组,数组长度应与@I后面的数字相等@b@ * @param <T>@b@ * @param entityClass 实体类@b@ * @param selectHeadString 自定义SELECT头@b@ * @param expressions@b@ * @param values@b@ * @return @b@ */@b@ public <T> T selectByExpressions(final Class entityClass, final String selectHeadString,@b@ final String[] expressions, final Object... values){@b@ Assert.notNull(expressions);@b@ Assert.notNull(expressions);@b@ Assert.notEmpty(expressions);@b@ @b@ return template.execute(new JpaCallback<T>(){@b@ @Override@b@ public T doInJpa(EntityManager em)@b@ throws PersistenceException {@b@ Query query = createQueryByExpressions(em, entityClass, selectHeadString, expressions, values);@b@ @b@ template.prepareQuery(query);@b@ @b@ return (T) query.getSingleResult();@b@ }@b@ });@b@ }@b@ /**@b@ * 简化表达式查询@b@ * IN查询表达可写为propertyName@I5,表示IN的参数有5个,@b@ * 同时参数values对应IN查询的参数必须是一个数组,数组长度应与@I后面的数字相等@b@ * @param <T>@b@ * @param entityClass 实体类@b@ * @param selectHeadString 自定义SELECT头@b@ * @param expressions@b@ * @param values@b@ * @return @b@ */@b@ public List selectMutilByExpressions(final Class entityClass, final String selectHeadString,@b@ final String[] expressions, final Object... values){@b@ Assert.notNull(expressions);@b@ Assert.notNull(expressions);@b@ Assert.notEmpty(expressions);@b@ @b@ return template.executeFind(new JpaCallback(){@b@ @Override@b@ public List doInJpa(EntityManager em)@b@ throws PersistenceException {@b@ Query query = createQueryByExpressions(em, entityClass, selectHeadString, expressions, values);@b@ @b@ template.prepareQuery(query);@b@ @b@ return query.getResultList();@b@ }@b@ });@b@ }@b@ @b@ @b@ /**@b@ * 简化表达式分页查询@b@ * IN查询表达可写为propertyName@I5,表示IN的参数有5个,@b@ * 同时参数values对应IN查询的参数必须是一个数组,数组长度应与@I后面的数字相等@b@ * @param <T>@b@ * @param entityClass 实体类@b@ * @param start@b@ * @param limit@b@ * @param expressions@b@ * @param values@b@ * @return @b@ */@b@ public <T> List<T> queryForPageByExpressions(final Class<T> entityClass, final int start, final int limit, @b@ final String[] expressions, final Object... values){@b@ return template.executeFind(new JpaCallback<List<T>>(){@b@ @Override@b@ public List<T> doInJpa(EntityManager em)@b@ throws PersistenceException {@b@ TypedQuery<T> query = createQueryByExpressions(em, entityClass, expressions, values);@b@ @b@ template.prepareQuery(query);@b@ @b@ return query.setFirstResult(start).setMaxResults(limit).getResultList();@b@ }@b@ });@b@ }@b@ @b@ /**@b@ * 辅助方法,根据查询表达式和参数创建Query对象@b@ */@b@ private <T> TypedQuery<T> createQueryByExpressions(EntityManager em, Class<T> entityClass,@b@ String[] expressions, Object... values) throws PersistenceException {@b@ TypedQuery<T> query = em.createQuery("select o from "+entityClass.getCanonicalName()+" o where 1=1"@b@ + SQLLikeExpressionParser.parseToHQL(expressions), entityClass);@b@ @b@ if (null != values){@b@ int index = 1;@b@ for(int i=0,len=values.length; i<len; i++){@b@ //判断如果参数是一个对象数组, 则为IN查询参数,分离数组对象按一般参数处理@b@ if(values[i].getClass().isArray()){@b@ Object[] inValues = (Object[]) values[i];@b@ for (int j = 0,inLen=inValues.length; j < inLen; j++){@b@ query.setParameter(index ++, inValues[j]);@b@ }@b@ }else{@b@ query.setParameter(index ++, values[i]);@b@ }@b@ }@b@ }@b@ return query;@b@ }@b@ /**@b@ * 辅助方法,根据查询表达式和参数创建Query对象, 可指定SELECT字段@b@ */@b@ private Query createQueryByExpressions(EntityManager em, Class entityClass, String selectHeadString, @b@ String[] expressions, Object... values) throws PersistenceException {@b@ if(selectHeadString == null){@b@ selectHeadString = "select o";@b@ }@b@ Query query = em.createQuery(selectHeadString+" from "+entityClass.getCanonicalName()+" o where 1=1"@b@ + SQLLikeExpressionParser.parseToHQL(expressions));@b@ @b@ if (null != values){@b@ int index = 1;@b@ for(int i=0,len=values.length; i<len; i++){@b@ //判断如果参数是一个对象数组, 则为IN查询参数,分离数组对象按一般参数处理@b@ if(values[i].getClass().isArray()){@b@ Object[] inValues = (Object[]) values[i];@b@ for (int j = 0,inLen=inValues.length; j < inLen; j++){@b@ query.setParameter(index ++, inValues[j]);@b@ }@b@ }else{@b@ query.setParameter(index ++, values[i]);@b@ }@b@ }@b@ }@b@ return query;@b@ }@b@ /**@b@ * 查询实体类,用查询表达式动态创建Criteria查询@b@ * <b>注意:查询表达式有括号的括号内表达式有且仅能有两个</b>@b@ * @param <T>@b@ * @param entityClass 实体类@b@ * @param expressions@b@ * @param values@b@ * @return@b@ */@b@ public <T> List<T> queryForEntityBean(final Class<T> entityClass,@b@ final String[] expressions, final Object... values){@b@ return template.executeFind(new JpaCallback<List<T>>(){@b@ @Override@b@ public List<T> doInJpa(EntityManager em) throws PersistenceException {@b@ CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();@b@ CriteriaQuery<T> criteriaQuery = criteriaBuilder.createQuery(entityClass);@b@ @b@ JpaCriteriaExpressionParser.handleExpressions(entityClass, criteriaBuilder, @b@ criteriaQuery, expressions, values);@b@ @b@ @b@ return em.createQuery(criteriaQuery).getResultList();@b@ }@b@ });@b@ }@b@ /**@b@ * 查询实体类,用查询表达式动态创建Criteria查询,可指定只查询那些属性字段<br/>@b@ * <b>查询表达式有括号的括号内表达式有且仅能有两个</b><br/>@b@ * <b>注意:实体类必须有指定字段的构造方法<br/>@b@ * 如实体类User,指定了name和password,则User必须有public User(String name,String password)构造方法</b>@b@ * @param <T>@b@ * @param entityClass 实体类@b@ * @param includeFields 包含的字段@b@ * @param expressions@b@ * @param values@b@ * @return@b@ */@b@ public <T> List<T> queryForEntityBean(final Class<T> entityClass, final String[] includeFields,@b@ final String[] expressions, final Object... values){@b@ return template.executeFind(new JpaCallback<List<T>>(){@b@ @Override@b@ public List<T> doInJpa(EntityManager em) throws PersistenceException {@b@ CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();@b@ CriteriaQuery<T> criteriaQuery = criteriaBuilder.createQuery(entityClass);@b@ @b@ Root<T> root = JpaCriteriaExpressionParser.handleExpressions(entityClass, criteriaBuilder, @b@ criteriaQuery, expressions, values);@b@@b@ if(includeFields != null){@b@ Selection<? extends T>[] selections = new Selection[includeFields.length];@b@ for(int i=0,len=includeFields.length; i<len; i++){@b@ selections[i] = root.get(includeFields[i]);@b@ }@b@ criteriaQuery.multiselect(selections);@b@ }@b@ @b@ return em.createQuery(criteriaQuery).getResultList();@b@ }@b@ });@b@ }@b@ /**@b@ * 单对象SQL查询@b@ * @param <T>@b@ * @param sql@b@ * @param values@b@ * @return@b@ */@b@ public <T> T getBySQL(final String sql, final Object... values){@b@ return getBySQL(null, sql, values);@b@ }@b@ @b@ /**@b@ * 单实体对象SQL查询@b@ * @param <T>@b@ * @param entityClass@b@ * @param sql@b@ * @param values@b@ * @return@b@ */@b@ public <T> T getBySQL(final Class<T> entityClass, final String sql, final Object... values){@b@ return template.execute(new JpaCallback<T>(){@b@ @Override@b@ public T doInJpa(EntityManager em) throws PersistenceException {@b@ Query query = null;@b@ if(entityClass != null){@b@ query = em.createNativeQuery(sql, entityClass);@b@ }else{@b@ query = em.createNativeQuery(sql);@b@ }@b@ if(values != null){@b@ for(int i=0,len=values.length; i<len; i++){@b@ query.setParameter(i+1, values[i]);@b@ }@b@ }@b@ @b@ template.prepareQuery(query);@b@ @b@ return (T) query.getSingleResult();@b@ }@b@ });@b@ }@b@ @b@ /**@b@ * SQL查询@b@ * @param <T>@b@ * @param sql@b@ * @param values@b@ * @return@b@ */@b@ public <T> List<T> listBySQL(final String sql, final Object... values){@b@ return listBySQL(null, sql, values);@b@ }@b@ /**@b@ * 实体对象集合SQL查询@b@ * @param <T>@b@ * @param entityClass@b@ * @param sql@b@ * @param values@b@ * @return@b@ */@b@ public <T> List<T> listBySQL(final Class<T> entityClass, final String sql, final Object... values){@b@ return template.executeFind(new JpaCallback<List<T>>(){@b@ @Override@b@ public List<T> doInJpa(EntityManager em) throws PersistenceException {@b@ Query query = null;@b@ if(entityClass != null){@b@ query = em.createNativeQuery(sql, entityClass);@b@ }else{@b@ query = em.createNativeQuery(sql);@b@ }@b@ if(values != null){@b@ for(int i=0,len=values.length; i<len; i++){@b@ query.setParameter(i+1, values[i]);@b@ }@b@ }@b@ @b@ template.prepareQuery(query);@b@ @b@ return query.getResultList();@b@ }@b@ });@b@ }@b@ /**@b@ * SQL分页查询@b@ * @param <T>@b@ * @param sql@b@ * @param start@b@ * @param limit@b@ * @param values@b@ * @return@b@ */@b@ public <T> List<T> listForPageBySQL(final String sql, final int start, final int limit,final Object... values){@b@ return template.executeFind(new JpaCallback<List<T>>(){@b@ @Override@b@ public List<T> doInJpa(EntityManager em) throws PersistenceException {@b@ Query query = em.createNativeQuery(sql);@b@ if(values != null){@b@ for(int i=0,len=values.length; i<len; i++){@b@ query.setParameter(i+1, values[i]);@b@ }@b@ }@b@ @b@ template.prepareQuery(query);@b@ @b@ return query.setFirstResult(start).setMaxResults(limit).getResultList();@b@ }@b@ });@b@ }@b@ /**@b@ * 执行SQL@b@ * @param sql@b@ * @param values@b@ * @return@b@ */@b@ public int executeSQL(final String sql, final Object... values){@b@ return template.execute(new JpaCallback(){@b@ @Override@b@ public Integer doInJpa(EntityManager em) throws PersistenceException {@b@ Query query = em.createNativeQuery(sql);@b@ if(values != null){@b@ for(int i=0,len=values.length; i<len; i++){@b@ query.setParameter(i+1, values[i]);@b@ }@b@ }@b@ @b@ return query.executeUpdate();@b@ }@b@ });@b@ }@b@ /**@b@ * 同一SQL不同参数批量执行,参数列表中对象可以是数组@b@ * @param sql@b@ * @param values @b@ * @return@b@ */@b@ public int[] batchExecuteSQL(final String sql, final List<? extends Object> values){@b@ return template.execute(new JpaCallback(){@b@ @Override@b@ public int[] doInJpa(EntityManager em) throws PersistenceException {@b@ Query query = em.createNativeQuery(sql);@b@ if(values != null){@b@ int[] resultInts = new int[values.size()];@b@ for(int i=0,len=values.size(); i<len; i++){@b@ Object value = values.get(i);@b@ if(value.getClass().isArray()){@b@ Object[] params = (Object[]) value;@b@ for(int j=0,plen=params.length; j<plen; j++){@b@ query.setParameter(j+1, params[j]);@b@ }@b@ }else{@b@ query.setParameter(1, value);@b@ }@b@ resultInts[i] = query.executeUpdate();@b@ }@b@ return resultInts;@b@ }@b@ @b@ return new int[]{query.executeUpdate()};@b@ }@b@ });@b@ }@b@}
2. 通用服务类接口IEntityService,如下所示
import java.util.Collection;@b@import java.util.List; @b@import com.woopa.common.persist.PageBean; @b@@b@public interface IEntityService<E> {@b@ @b@ void persist(E entity);@b@ @b@ void merge(E entity);@b@ @b@ void remove(E entity);@b@ @b@ void remove(Collection<E> entities);@b@ @b@ List<E> listAll();@b@ @b@ E get(String expression, Object... values);@b@ @b@ E get(String[] expressions, Object... values);@b@ @b@ List<E> listByExpression(String expression, Object... values);@b@ @b@ List<E> listByExpressions(String[] expressions, Object... values);@b@ @b@ List<E> listPageByExpression(final int start, final int limit,@b@ final String expression, final Object... values);@b@ @b@ List<E> listPageByExpressions(final int start, final int limit,@b@ final String[] expressions, final Object... values);@b@ @b@ PageBean<Object> queryForPageBean(int start, int limit, @b@ String listQueryString, String totalQueryString, Object... values);@b@ @b@ PageBean<E> queryForPageBeanByExpressions(int start, int limit, @b@ String[] expressions, Object... values);@b@}
3.通用服务实现类EntityService,代码如下
import java.util.Collection;@b@import java.util.HashMap;@b@import java.util.Iterator;@b@import java.util.List;@b@import java.util.Map;@b@@b@import com.woopa.common.util.Assert;@b@import com.woopa.common.util.ReflectUtils;@b@import com.woopa.common.persist.PageBean; @b@ @b@public class EntityService<E> implements IEntityService<E> {@b@ @b@ private int batchFetchSize = 20; @b@ @b@ private BaseJpaDao dao;@b@ @b@ protected Class<E> entityClass;@b@ @b@ @b@ public EntityService(){@b@ entityClass = ReflectUtils.getSuperClassGenricType(getClass(), 0);@b@ }@b@@b@ public void persist(Collection<E> entities) {@b@ Assert.notNull(entities);@b@ @b@ Iterator<E> ite = entities.iterator();@b@ @b@ for(int i=0; i<entities.size() && ite.hasNext(); i++){@b@ if(i!=0 && i%batchFetchSize == 0){@b@ dao.template.flush();@b@ }@b@ dao.template.persist(ite.next());@b@ }@b@ }@b@@b@ public void persist(E entity) {@b@ Assert.notNull(entity);@b@ @b@ dao.template.persist(entity);@b@ }@b@ @b@ public void merge(E entity) {@b@ Assert.notNull(entity);@b@ @b@ dao.template.merge(entity);@b@ }@b@@b@ /**@b@ * 更新一个实体对象@b@ * <b>注意:必须在一个事务中使用此方法</b>@b@ * @param entity@b@ */@b@ protected void refresh(E entity) {@b@ Assert.notNull(entity);@b@ @b@ dao.template.refresh(entity);@b@ }@b@@b@ public void remove(E entity) {@b@ Assert.notNull(entity);@b@ @b@ dao.template.remove(entity);@b@ }@b@@b@ public void remove(Collection<E> entities) {@b@ Assert.notNull(entities);@b@ @b@ Iterator<E> ite = entities.iterator();@b@ @b@ for(int i=0; i<entities.size() && ite.hasNext(); i++){@b@ if(i!=0 && i%batchFetchSize == 0){@b@ dao.template.flush();@b@ }@b@ dao.template.remove(ite.next());@b@ }@b@ }@b@ @b@ public E get(String expression, Object... values){@b@ return get(new String[]{expression}, values);@b@ }@b@ @b@ public E get(String[] expressions, Object... values){@b@ List<E> list = dao.queryByExpressions(entityClass, expressions, values);@b@ @b@ return list != null && list.size() > 0 ? list.get(0) : null;@b@ }@b@@b@ public List<E> listAll() {@b@ return dao.template.find("from "+entityClass.getCanonicalName()+" o");@b@ }@b@@b@ protected List<E> list(String queryString, Object... values) {@b@ return dao.template.find(queryString, values);@b@ }@b@ @b@ protected List<E> list(String queryString, String[] namedParams,@b@ Object... values) {@b@ Map<String, Object> params = null;@b@ if(namedParams != null){@b@ params = new HashMap<String, Object>(namedParams.length);@b@ for(int i=0,len=namedParams.length; i<len; i++){@b@ params.put(namedParams[i], values[i]);@b@ }@b@ }@b@ return dao.template.findByNamedParams(queryString, params);@b@ }@b@ @b@ public List<E> listByExpression(String expression, Object... values){@b@ return listByExpressions(new String[]{expression}, values);@b@ }@b@ @b@ public List<E> listByExpressions(String[] expressions, Object... values){@b@ return dao.queryByExpressions(entityClass, expressions, values);@b@ }@b@@b@@b@ public List<E> listPageByExpression(final int start, final int limit,@b@ final String expression, final Object... values){@b@ @b@ return listPageByExpressions(start, limit, new String[]{expression}, values);@b@ }@b@ @b@ public List<E> listPageByExpressions(final int start, final int limit,@b@ final String[] expressions, final Object... values){@b@ return dao.queryForPageByExpressions(entityClass, start, limit, expressions, values);@b@ }@b@ @b@ protected List<E> listForPage(int start, int limit, String queryString,@b@ Object... values) {@b@ return dao.queryForPage(start, limit, queryString, values);@b@ }@b@@b@ protected long queryForLong(String queryString, Object... values) {@b@ return dao.queryForObject(queryString, values);@b@ }@b@@b@ protected int queryForInt(String queryString, Object... values) {@b@ return dao.queryForObject(queryString, values);@b@ }@b@ @b@ protected <T> T getUnique(String queryString, Object... values){@b@ return dao.queryForObject(queryString, values);@b@ }@b@@b@ protected <T> List<T> queryForList(String queryString,@b@ Object... values) {@b@ return dao.template.find(queryString, values);@b@ }@b@@b@ protected <T> List<T> queryForPage(int start, int limit,@b@ String queryString, Object... values) {@b@ return dao.queryForPage(start, limit, queryString, values);@b@ }@b@@b@ public PageBean<Object> queryForPageBean(int start, int limit, @b@ String listQueryString , String totalQueryString, Object... values){@b@ List<Object> list = dao.queryForPage(start, limit, listQueryString, values);@b@ @b@ long totalRecords = dao.queryForObject(totalQueryString, values);@b@ @b@ return new PageBean<Object>(start, limit, list, totalRecords);@b@ }@b@ @b@ public PageBean<E> queryForPageBeanByExpressions(int start, int limit, @b@ String[] expressions, Object... values){@b@ List<E> list = dao.queryForPageByExpressions(entityClass, start, limit, expressions, values);@b@ @b@ long totalRecords = dao.selectByExpressions(entityClass, "SELECT COUNT(*)", expressions, values);@b@ @b@ return new PageBean<E>(start, limit, list, totalRecords);@b@ }@b@ @b@ public BaseJpaDao getDao() {@b@ return dao;@b@ }@b@@b@ public void setDao(BaseJpaDao dao) {@b@ this.dao = dao;@b@ }@b@@b@ public int getBatchFetchSize() {@b@ return batchFetchSize;@b@ }@b@@b@ public void setBatchFetchSize(int batchFetchSize) {@b@ this.batchFetchSize = batchFetchSize;@b@ }@b@}