Spring Boot学习笔记(三)——Spring-data-jpa扩展封装
上篇文章我们分享了下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进行简单操作以及复杂操作的封装,如需其他操作方式可以在这基础上对其构建条件进行修改,上面实例是我个人搭建博客的代码,基本可以满足大部分需求,可以直接拿来使用,相信大家也会有更好的玩法可以一起分享交流。