欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring Boot学习笔记(三)——Spring-data-jpa扩展封装

程序员文章站 2022-04-23 16:05:45
...

上篇文章我们分享了下Spring-data-jpa的基本使用方法,但在实际使用中可能会有更复杂的用法,现在我们来看看他的更高级玩法,并做了完美的封装,使用起来更加智能简单。Spring-data-jpa为我们提供了JpaSpecificationExecutor接口,只要简单实现toPredicate方法就可以实现复杂的查询,下面就来看看具体如何使用。

首先我们来看看JpaSpecificationExecutor这个类

public interface JpaSpecificationExecutor<T> {
    T findOne(Specification<T> var1);

    List<T> findAll(Specification<T> var1);

    Page<T> findAll(Specification<T> var1, Pageable var2);

    List<T> findAll(Specification<T> var1, Sort var2);

    long count(Specification<T> var1);
}

可以看出他是个接口,里面提供了基本的使用方法,其中重要的一个参数是Specification<T>我们再来看看这个这个参数

public interface Specification<T> {
    Predicate toPredicate(Root<T> var1, CriteriaQuery<?> var2, CriteriaBuilder var3);
}

发现他也是一个接口,并且只有一个方法,因此这个方法就是我们查询的关键所在,实际他就是向我们提供的构建查询条件的关键接口,我们只要实现他的方法按照JPA 2.0 criteria api写好查询条件就可以了,接下来看看具体如何来怎么使用

由上一篇我么知道使用Spring-data-jpa我们需要继承JpaRepository接口,为了做复杂查询还需继承JpaSpecificationExecutor接口,因此我们可以建一个BaseRepository类来同时继承这两个类

/**
 * 基类的数据访问接口(继承了CrudRepository,PagingAndSortingRepository,
 * JpaSpecificationExecutor的特性)
 *
 * Created by mj on 2017/12/17.
 */
@NoRepositoryBean
public abstract interface BaseRepository<T, ID extends Serializable> extends JpaRepository<T,ID>, JpaSpecificationExecutor<T> {

    /**
     *
     * 使用QBL进行查询列表
     *
     * @author mj 2016年10月26日
     * @param query
     * @return
     */
    public abstract List<T> findAll(BaseQuery query);

    /**
     *
     * 封装分页查询
     *
     * @author mj 2016年10月26日
     * @param query
     * @param pageable
     * @return
     */
    public abstract Page<T> findAll(BaseQuery query, Pageable pageable);

    /**
     *
     * 封装排序查询
     *
     * @author mj 2016年10月26日
     * @param query
     * @param sort
     * @return
     */
    public abstract List<T> findAll(BaseQuery query, Sort sort);

    /**
     *
     * 使用QBL定位记录
     *
     * @author mj 2016年10月26日
     * @param query
     * @return
     */
    public abstract T findOne(BaseQuery query);

    /**
     *
     * 更新方法
     *
     * @author mj 2016年10月26日
     * @param t
     * @param updateFileds
     * @param where
     * @return
     */
    public abstract int update(T t, BaseQuery where, String... updateFileds);

    /**
     *
     * 根据唯一主键更新方法
     *
     * @author mj 2016年10月26日
     * @param t
     * @param id
     * @param updateFileds
     * @return
     */
    public abstract int updateById(T t, ID id, String... updateFileds);
}

其中里面的一些方法暂时不用关心是对jpa的一些功能扩展加强后面会讲到,然后我们来构建查询条件,通过以上讲述我们只需创建 一个类来实现Specification<T>接口即可

/**
 * 自定义Query语言转Specification
 *
 * @version 
 * @author mj 2016年10月26日 下午3:46:50
 * @param
 * 
 */
public class QueryToSpecification implements Specification {
	private  BaseQuery query;
	
	
	public QueryToSpecification(BaseQuery query) {
		super();
		this.query = query;
	}

	/**
	 * 【请在此输入描述文字】
	 * 
	 * (non-Javadoc)
	 * @see Specification#toPredicate(Root, CriteriaQuery, CriteriaBuilder)
	 */
	@Override
	public Predicate toPredicate(Root root, CriteriaQuery cquery, CriteriaBuilder cb) {
		return BaseQueryPredicateBuilder.getPredicate(root, cb, cquery,this.query);
	}

}

由此可看出我们实现了Specification<T>接口的toPredicate方法,里面的参数Root就是我们的实体类,CriteriaQuery为基本查询,CriteriaBuilder为查询条件构建,其中BaseQueryPredicateBuilder.getPredicate(root, cb, cquery,this.query);为具体的构建条件实现,我们继续来构建这个方法

/**
 * query转换builder类
 *
 * @version
 * @author mj 2016年10月26日 下午3:54:41
 * 
 */
public class BaseQueryPredicateBuilder {
	private static Logger log = LogManager.getLogger(BaseQueryPredicateBuilder.class);

	public static <T> Predicate getPredicate2(Root<T> root, CriteriaBuilder cb, BaseQuery query) {
		return getPredicate(root, cb, null, query);
	}

	public static <T> Predicate getPredicate(Root<T> root, CriteriaBuilder cb, CriteriaQuery<T> cquery,
			BaseQuery query) {

		List<Predicate> predicatesAnd = new ArrayList<Predicate>();
		try {
			Class<?> entityClass = queryEntity(query);
			if (entityClass == null) {
				// 是否返回NULL,待研究
				return null;
			}
			BeanInfo beanInfo = Introspector.getBeanInfo(query.getClass());
			PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
			for (PropertyDescriptor pd : pds) {
				Method readMethod = pd.getReadMethod();
				if ((pd.getName().indexOf("Page") == 0) || (pd.getName().indexOf("Sort") == 0)) {
					continue;
				}
				if (!pd.getName().equals("class")) {
					Object obj = readMethod.invoke(query);
					if (obj != null) {
						QBindAttrField fieldProp = (QBindAttrField) getBindFieldName(query, pd.getName());
						String bindAttrName = fieldProp.fieldName();
						if (bindAttrName == null) {
							// 查询字段名称默认等于属性名称
							bindAttrName = pd.getName();
						}
						Path<?> from = root;
						Expression expression = from.get(bindAttrName);
						switch (fieldProp.where()) {
						case equal:
							predicatesAnd.add(cb.equal(expression, obj));
							break;
						case greaterThanOrEqualTo:
							predicatesAnd.add(cb.greaterThanOrEqualTo(expression, (Comparable) obj));
							break;
						case lessThanOrEqualTo:
							predicatesAnd.add(cb.lessThanOrEqualTo(expression, (Comparable) obj));
							break;
						case like:
							predicatesAnd.add(cb.like(expression, "%" + (Comparable) obj + "%"));
							break;
						case greaterThan:
							predicatesAnd.add(cb.greaterThan(expression, (Comparable) obj));
							break;
						case lessThan:
							predicatesAnd.add(cb.lessThan(expression, (Comparable) obj));
							break;
						case notEqual:
							predicatesAnd.add(cb.notEqual(expression, (Comparable) obj));
							break;
						case in:
							if (pd.getPropertyType().getName().indexOf("List") > 0) {
								List<?> value = (List<?>) obj;
								if (value.size() == 0) {
									// 防止生成LIST时,没有传入值,而查询条件会做全查处理,此处做特殊处理返回空条件
									((List<?>) obj).add(null);
								}
								if (value.size() > 20) {
									Set<Object> set = new HashSet<Object>(value.size());
									// 如果in超过20个要去重处理
									set.addAll(value);
									value = new ArrayList<Object>(set);
								}
								predicatesAnd.add(expression.in(value));
							} else {
								List vList = new ArrayList<Object>();
								vList.add(obj);
								predicatesAnd.add(expression.in(vList));
							}
							// 特殊处理
							break;
						default:// 默认等于equal
							break;
						}
					}
				}

			}
		} catch (Exception e) {
			log.error(e);
		}

		// 组合条件
		if (predicatesAnd.isEmpty()) {
			return cb.isTrue(cb.literal(true));
		}

		if (predicatesAnd.size() == 1) {
			return predicatesAnd.iterator().next();
		}
		return cb.and(predicatesAnd.toArray(new Predicate[predicatesAnd.size()]));
	}

	/**
	 * 
	 * 获取查询实体类名称
	 * 
	 * @author liuyi 2016年4月16日
	 * @param query
	 * @return
	 */
	public static Class<?> queryEntity(BaseQuery query) {
		Annotation anno = query.getClass().getAnnotation(QBindEntity.class);
		if (anno != null)
			return ((QBindEntity) anno).entityClass();
		return null;
	}

	/**
	 * 
	 * 获取绑定字段属性值
	 * 
	 * @author liuyi 2016年4月16日
	 * @param PropertyName
	 * @return
	 */
	public static Annotation getBindFieldName(BaseQuery query, String PropertyName) {
		try {
			Field field = query.getClass().getDeclaredField(PropertyName);
			Annotation anno = field.getAnnotation(QBindAttrField.class);
			if (anno != null) {
				return ((QBindAttrField) anno);
			}
		} catch (SecurityException e) {
			log.error("[BaseQueryPredicateBuilder.getBindAttrName SecurityException:]" + e.getMessage());
		} catch (NoSuchFieldException e) {
			log.error("[BaseQueryPredicateBuilder.getBindAttrName NoSuchFieldException:]" + e.getMessage());
		}
		return null;
	}

}

这就是我们封装的查询条件逻辑,代码这里就不解释了大家可以自己看看很简单,但需要注意的是这里需要两个自定义注解QBindAttrField,QBindEntity和Where条件枚举类关键字,我们也创建一下,他们的功能就是用来映射后面查询需要的实体类和属性

/**
 * 查询绑定属性
 *
 * @version 
 * @author mj  2016年10月28日 下午6:20:57
 * 
 */
@Target({java.lang.annotation.ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface QBindAttrField {
	public abstract String fieldName();
	public abstract Where where();
}
/**
 * 查询绑定实体类
 *
 * @version 
 * @author mj  2016年10月26日 下午6:18:03
 * 
 */
@Target({java.lang.annotation.ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface QBindEntity {
	public abstract Class<?> entityClass();
}
/**
 * 目前系统支持的where查询条件关键字
 *
 * @version 
 * @author mj  2016年10月26日 下午6:40:05
 * 
 */
public enum Where {
	in,
	like,
	equal,
	notEqual,
	lessThan,
	lessThanOrEqualTo,
	greaterThan,
	greaterThanOrEqualTo
}

接下来我们来实现上面提到的对jpa功能的扩展加强实现里面的方法,创建BaseSimpleJpaRepositoryEx类实现SimpleJpaRepository和BaseRepository接口

/**
 * 扩展对JAP功能加强
 *
 * @version
 * @author liuyi  2016年4月16日 下午2:40:16
 *
 */
@Transactional(readOnly=false,propagation=Propagation.SUPPORTS)
@NoRepositoryBean
public class BaseSimpleJpaRepositoryEx<T, ID extends Serializable>
        extends SimpleJpaRepository<T, ID> implements BaseRepository<T, ID> {

    private EntityManager baseEm;
    private JpaEntityInformation<T, ?> baseEmInfo;

    /**
     * BaseSimpleJpaRepositoryEx 构造器
     * @param domainClass
     * @param entityManager
     */
    public BaseSimpleJpaRepositoryEx(Class<T> domainClass, EntityManager entityManager) {
        super(domainClass, entityManager);
        baseEm = entityManager;
//        baseEmInfo = entityInformation;
    }

    /**
     * 自定义查询条件转换实现
     *
     * (non-Javadoc)
     */
    private Specification<T> getConditonByQuery(BaseQuery query) {
        return new QueryToSpecification(query);
    }

    /**
     * 封装自定义组合查询列表方法
     *
     * (non-Javadoc)
     */
    @SuppressWarnings("unchecked")
    @Override
    public List<T> findAll(BaseQuery query) {
        if(query.getSort()!=null){
            return findAll(getConditonByQuery(query), query.getSort());
        }
        else if(query.getPage()!=null){
            return (List<T>) findAll(getConditonByQuery(query),query.getPage());

        }else{
            return (List<T>) findAll(getConditonByQuery(query));
        }

    }

    /**
     *
     * 自定义组合查询分页方法
     *
     * @author liuyi 2016年4月18日
     * @param query
     * @param pageable
     * @return
     */
    @Override
    public Page<T> findAll(BaseQuery query,Pageable pageable) {
        return findAll(getConditonByQuery(query), pageable);
    }

    /**
     * 查询条件
     *
     * (non-Javadoc)
     */
    @Override
    public T findOne(BaseQuery query) {
        return findOne(getConditonByQuery(query));
    }


    @Override
    public List<T> findAll() {
        return super.findAll();
    }

    @Override
    protected CrudMethodMetadata getRepositoryMethodMetadata() {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.getRepositoryMethodMetadata();
    }

    @Override
    protected Class<T> getDomainClass() {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.getDomainClass();
    }

    @Override
    public T findOne(ID id) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.findOne(id);
    }

    @Override
    protected Map<String, Object> getQueryHints() {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.getQueryHints();
    }

    @Override
    public T getOne(ID id) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.getOne(id);
    }

    @Override
    public boolean exists(ID id) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.exists(id);
    }

    @Override
    public List<T> findAll(Iterable<ID> ids) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.findAll(ids);
    }

    @Override
    public List<T> findAll(Sort sort) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.findAll(sort);
    }

    @Override
    public Page<T> findAll(Pageable pageable) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.findAll(pageable);
    }

    @Override
    public T findOne(Specification<T> spec) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.findOne(spec);
    }

    @Override
    public List<T> findAll(Specification<T> spec) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.findAll(spec);
    }

    @Override
    public Page<T> findAll(Specification<T> spec, Pageable pageable) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.findAll(spec, pageable);
    }

    @Override
    public List<T> findAll(Specification<T> spec, Sort sort) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.findAll(spec, sort);
    }

    @Override
    public <S extends T> S findOne(Example<S> example) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.findOne(example);
    }

    @Override
    public <S extends T> long count(Example<S> example) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.count(example);
    }

    @Override
    public <S extends T> boolean exists(Example<S> example) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.exists(example);
    }

    @Override
    public <S extends T> List<S> findAll(Example<S> example) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.findAll(example);
    }

    @Override
    public <S extends T> List<S> findAll(Example<S> example, Sort sort) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.findAll(example, sort);
    }

    @Override
    public <S extends T> Page<S> findAll(Example<S> example, Pageable pageable) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.findAll(example, pageable);
    }

    @Override
    public long count() {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.count();
    }

    @Override
    public long count(Specification<T> spec) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.count(spec);
    }

    @Override
    protected Page<T> readPage(TypedQuery<T> query, Pageable pageable, Specification<T> spec) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.readPage(query, pageable, spec);
    }

    @Override
    protected <S extends T> Page<S> readPage(TypedQuery<S> query, Class<S> domainClass, Pageable pageable,
                                             Specification<S> spec) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.readPage(query, domainClass, pageable, spec);
    }

    @Override
    protected TypedQuery<T> getQuery(Specification<T> spec, Pageable pageable) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.getQuery(spec, pageable);
    }

    @Override
    protected <S extends T> TypedQuery<S> getQuery(Specification<S> spec, Class<S> domainClass, Pageable pageable) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.getQuery(spec, domainClass, pageable);
    }

    @Override
    protected TypedQuery<T> getQuery(Specification<T> spec, Sort sort) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.getQuery(spec, sort);
    }

    @Override
    protected <S extends T> TypedQuery<S> getQuery(Specification<S> spec, Class<S> domainClass, Sort sort) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.getQuery(spec, domainClass, sort);
    }

    @Override
    protected TypedQuery<Long> getCountQuery(Specification<T> spec) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.getCountQuery(spec);
    }

    @Override
    protected <S extends T> TypedQuery<Long> getCountQuery(Specification<S> spec, Class<S> domainClass) {
        // TODO 这是系统自动生成描述,请在此补完后续代码
        return super.getCountQuery(spec, domainClass);
    }

    /**
     * 封装自定义组合查询排序列表方法
     *
     * (non-Javadoc)
     */
    @Override
    public List<T> findAll(BaseQuery query, Sort sort) {
        return findAll(getConditonByQuery(query), sort);
    }

    @Transactional(readOnly=false,propagation=Propagation.REQUIRED)
    @Override
    public <S extends T> List<S> save(Iterable<S> arg0) {
        return super.save(arg0);
    }

    @Transactional(readOnly=false,propagation=Propagation.REQUIRED)
    @Override
    public <S extends T> S save(S entity) {
        return super.save(entity);
    }

    @Transactional(readOnly=false,propagation=Propagation.REQUIRED)
    @Override
    public <S extends T> S saveAndFlush(S entity) {
        return super.saveAndFlush(entity);
    }

    @Transactional(readOnly=false,propagation=Propagation.REQUIRED)
    @Override
    public void setRepositoryMethodMetadata(CrudMethodMetadata crudMethodMetadata) {
        super.setRepositoryMethodMetadata(crudMethodMetadata);
    }

    @Transactional(readOnly=false,propagation=Propagation.REQUIRED)
    @Override
    public void delete(ID id) {
        super.delete(id);
    }

    @Transactional(readOnly=false,propagation=Propagation.REQUIRED)
    @Override
    public void delete(T entity) {
        super.delete(entity);
    }

    @Transactional(readOnly=false,propagation=Propagation.REQUIRED)
    @Override
    public void delete(Iterable<? extends T> entities) {
        super.delete(entities);
    }

    @Transactional(readOnly=false,propagation=Propagation.REQUIRED)
    @Override
    public void deleteInBatch(Iterable<T> entities) {
        super.deleteInBatch(entities);
    }

    @Transactional(readOnly=false,propagation=Propagation.REQUIRED)
    @Override
    public void deleteAll() {
        super.deleteAll();
    }

    @Transactional(readOnly=false,propagation=Propagation.REQUIRED)
    @Override
    public void deleteAllInBatch() {
        super.deleteAllInBatch();
    }

    @Transactional(readOnly=false,propagation=Propagation.REQUIRED)
    @Override
    public void flush() {
        super.flush();
    }

    /**
     *
     * 自定义更新update方法
     *
     * @author liuyi 2016年7月16日
     * @param
     * @param where
     * @return
     */
    @Transactional(readOnly=false,propagation=Propagation.REQUIRED)
    public int  update(T t,BaseQuery where,String... updateFileds){
        CriteriaBuilder cb =baseEm.getEntityManagerFactory().getCriteriaBuilder();
        CriteriaUpdate<T> update =  (CriteriaUpdate<T>) cb.createCriteriaUpdate(t.getClass());
        Root<T> root = update.from((Class<T>) t.getClass());

        for(String fieldName:updateFileds){
            try {
                Object o = PropertyUtils.getProperty(t, fieldName);
                update.set(fieldName, o);
            } catch (Exception e) {
                GwsLogger.error("update error:"+e);
            }
        }
        update.where(BaseQueryPredicateBuilder.getPredicate2(root, cb,where));
        return baseEm.createQuery(update).executeUpdate();
    }

    /**
     *
     * 根据唯一主键更新相关数据
     *
     * @author liuyi 2016年7月16日
     * @param id
     * @param
     * @return
     */
    @Transactional(readOnly=false,propagation=Propagation.REQUIRED)
    public int updateById(T t,ID id,String... updateFileds){
        CriteriaBuilder cb =baseEm.getEntityManagerFactory().getCriteriaBuilder();
        CriteriaUpdate<T> update =  (CriteriaUpdate<T>) cb.createCriteriaUpdate(t.getClass());
        Root<T> root = update.from((Class<T>) t.getClass());
        for(String fieldName:updateFileds){
            try {
                Object o = PropertyUtils.getProperty(t, fieldName);
                update.set(fieldName, o);
            } catch (Exception e) {
                GwsLogger.error("update error:"+e);
            }
        }
        //定位主键信息
        Iterable<String> idAttributeNames = baseEmInfo.getIdAttributeNames();

        for(String key:idAttributeNames){
            if(key!=null&&key!=""){
                update.where(cb.equal(root.get(key), id));
                break;
            }
        }
        return baseEm.createQuery(update).executeUpdate();

    }


}

通过getConditonByQuery(BaseQuery query)方法可以看到获取了我们实现的构造条件实例,从而作为复杂条件查询的Specification<T>参数设置达到查询效果,至此我们已经封装好了复杂查询,但此时还不能用,这里有个坑,虽然我们实现了jpa功能加强扩展但并没有指定扩展的具体实现类,所以jpa找不到这个实现bean,因此我们还需要最后一步操作就是指定我们实现的这个扩展类BaseSimpleJpaRepositoryEx,我们创建一个jpa工厂类BaseRepositoryFactoryBean来确定具体的实现类

/**
 * 自定义jpa工厂类 可确定具体的实现类
 * Created by mj on 2017/12/20.
 */
public class BaseRepositoryFactoryBean <R extends JpaRepository<T, I>, T,
        I extends Serializable> extends JpaRepositoryFactoryBean<R, T, I> {

    public BaseRepositoryFactoryBean(Class<? extends R> repositoryInterface) {
        super(repositoryInterface);
    }

    @Override
    protected RepositoryFactorySupport createRepositoryFactory(EntityManager em) {
        return new BaseRepositoryFactory(em);
    }

    //创建一个内部类,该类不用在外部访问
    private static class BaseRepositoryFactory<T, I extends Serializable>
            extends JpaRepositoryFactory {

        private final EntityManager em;

        public BaseRepositoryFactory(EntityManager em) {
            super(em);
            this.em = em;
        }

        //设置具体的实现类是BaseRepositoryImpl
        @Override
        protected Object getTargetRepository(RepositoryInformation information) {
            return new BaseSimpleJpaRepositoryEx<T, I>((Class<T>) information.getDomainType(), em);
        }

        //设置具体的实现类的class
        @Override
        protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
            return BaseSimpleJpaRepositoryEx.class;
        }
    }
}

通过代码可以很清楚看到是如何指定的,最后在应用程序的启动类上加上@EnableJpaRepositories指定自动启动扫描这个工厂即可

@EnableJpaRepositories(basePackages = {"com.xiaoma"},
		repositoryFactoryBeanClass = BaseRepositoryFactoryBean.class//指定自己的工厂类
)
@SpringBootApplication
public class BlogApplication {

	public static void main(String[] args) {
		SpringApplication.run(BlogApplication.class, args);
		System.out.println("========================================xiaomage blog server is started!");
		GwsLogger.info("xiaomage blog server is started!");
	}
}

至此我们的封装就大功告成,下面就让我们来感受一下效果吧!

首先创建一个实体类Tag

/**
 * Tag 实体类
 * Created by mj on 2017/12/17.
 */
@Entity
@Table(name = "tag")
public class Tag implements Serializable {

    @Id
    @GeneratedValue
    @Column(name = "tag_id")
    private Integer tagId;

    @Column(name = "tag_name")
    private String tagName;

    @Column(name = "create_time")
    private Integer createTime;

    @Column(name = "update_time")
    private Integer updateTime;

    此处省略get()/set()方法
}

创建TagRepository接口继承BaseRepository

/**
 * Created by mj on 2017/12/17.
 */
public interface TagRepository extends BaseRepository<Tag,Integer> {
}

创建TagQueryFilter查询条件过滤类

/**
 * Created by mj on 2017/12/24.
 */
@QBindEntity(entityClass = Tag.class)
public class TagQueryFilter extends BaseQuery {

    @QBindAttrField(fieldName = "tagId", where = Where.equal)
    private Integer tagId;

    @QBindAttrField(fieldName = "tagName", where = Where.equal)
    private String tagName;

    public Integer getTagId() {
        return tagId;
    }

    public void setTagId(Integer tagId) {
        this.tagId = tagId;
    }

    public String getTagName() {
        return tagName;
    }

    public void setTagName(String tagName) {
        this.tagName = tagName;
    }
}

创建TagServiceImpl业务实现类实现findTags()方法,TagService此处省略

/**
 * Created by mj on 2017/12/24.
 */
@Service
public class TagServiceImpl implements TagService {

    @Autowired
    private TagRepository tagRepository;

    /**
     * 分页查询文章所有标签 返回标签list
     * @param tag
     * @return
     */
    @Override
    public Page<Tag> findTags(Tag tag, Integer pageNo, Integer pageSize, String sortField) {

        //组合查询语句
        TagQueryFilter query = new TagQueryFilter();
        if (null != tag){
            if (StringUtils.isNotBlank(tag.getTagName())){
                query.setTagName(tag.getTagName());
            }
        }
        Sort sort = new Sort(Sort.Direction.DESC,sortField);
        Pageable pageable = new PageRequest(pageNo,pageSize,sort);
        Page<Tag> pageList = tagRepository.findAll(query,pageable);
        
        return pageList;
    }
}

这样我们就实现了通过tagName作为条件的分页排序查询,如需其他条件只需set其他的属性即可,怎么样很简单吧

创建TagController

/**
 * Created by mj on 2017/12/24.
 */
@Controller
@RequestMapping(value = "admin")
public class TagController {
    @Autowired
    private TagService tagService;

    /**
     * 分页查询文章所有标签
     * @param tag
     * @return
     */
    @RequestMapping(value = "/findTags")
    @ResponseBody
    public RetResult findTags(Tag tag, Integer pageNo, Integer pageSize) {

        String code = CommConstant.GWSCOD0000;
        String message = CommConstant.GWSMSG0000;
        GwsLogger.info("博客文章标签开始:code={},message={},tag={}",code,message,tag);

        Page<Tag> tags = null;
        try {
            if (null == pageNo){
                pageNo = 0;
            }else {
                pageNo = pageNo-1;
            }
            tags = tagService.findTags(tag,pageNo,pageSize,CommConstant.SORT_FIELD_UTIME);
        }catch (Exception e){
            code = CommConstant.GWSCOD0001;
            message = CommConstant.GWSMSG0001;
            GwsLogger.error("博客文章标签异常:code={},message={},e={}",code,message,e);
        }
        GwsLogger.info("博客文章标签结束,code={},message={},tags={}",code,message,tags);
        return RetResult.setRetDate(code,message,tags);
    }
}

然后通过请求测试http://127.0.0.1:8081/admin/findTags?tagName=SpringBoot&pageNo=1&pageSize=3即可看到结果

{
    "code": "000",
    "data": {
        "content": [
            {
                "createTime": 1513934861,
                "createTimeStr": "2017-12-22",
                "tagId": 2,
                "tagName": "SpringBoot",
                "updateTime": 1513934861,
                "updateTimeStr": "2017-12-22"
            }
        ],
        "first": true,
        "last": true,
        "number": 0,
        "numberOfElements": 1,
        "size": 3,
        "sort": [
            {
                "ascending": false,
                "descending": true,
                "direction": "DESC",
                "ignoreCase": false,
                "nullHandling": "NATIVE",
                "property": "updateTime"
            }
        ],
        "totalElements": 1,
        "totalPages": 1
    },
    "extraData": null,
    "message": "success"
}
好了至此我们已经使用Spring-data-jpa进行简单操作以及复杂操作的封装,如需其他操作方式可以在这基础上对其构建条件进行修改,上面实例是我个人搭建博客的代码,基本可以满足大部分需求,可以直接拿来使用,相信大家也会有更好的玩法可以一起分享交流。


相关标签: jpa spring data jpa