自定义注解: @Query


/*** @author Lee* @description* @date 2019/12/25 11:36**/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Query {String propName() default "";Type type() default Type.EQUAL;/*** 连接查询的属性名,如User类中的dept*/String joinName() default "";/*** 默认左连接*/Join join() default Join.LEFT;/*** 多字段模糊搜索,仅支持String类型字段,多个用逗号隔开, 如@Query(blurry = "email,username")*/String blurry() default "";enum Type {//等于EQUAL//大于, GREATER_THAN//小于, LESS_THAN//模糊查询, INNER_LIKE//左模糊查询, LEFT_LIKE//  右模糊查询, RIGHT_LIKE// 小于, LESS_THAN_NQ// 包含, IN// 不等于,NOT_EQUAL// between,BETWEEN// 不为空,NOT_NULL}/*** @author lee* 适用于简单连接查询,复杂的请自定义该注解,或者使用sql查询*/enum Join {/** 左右连接 */LEFT, RIGHT,INNER}}

定义注解处理工具


/*** @author Lee* @date 2019-12-15 14:59:48*/
@Slf4j
@SuppressWarnings({"unchecked","all"})
public class QueryHelp {public static <R, Q> Predicate getPredicate(Root<R> root, Q query, CriteriaBuilder cb) {List<Predicate> list = new ArrayList<>();if(query == null){return cb.and(list.toArray(new Predicate[0]));}try {List<Field> fields = getAllFields(query.getClass(), new ArrayList<>());for (Field field : fields) {boolean accessible = field.isAccessible();field.setAccessible(true);Query q = field.getAnnotation(Query.class);if (q != null) {String propName = q.propName();String joinName = q.joinName();String blurry = q.blurry();String attributeName = isBlank(propName) ? field.getName() : propName;Class<?> fieldType = field.getType();Object val = field.get(query);if (ObjectUtil.isNull(val) || "".equals(val) || "null".equals(val) || "undefined".equals(val) ) {continue;}Join join = null;// 模糊多字段if (ObjectUtil.isNotEmpty(blurry)) {String[] blurrys = blurry.split(",");List<Predicate> orPredicate = new ArrayList<>();for (String s : blurrys) {orPredicate.add(cb.like(root.get(s).as(String.class), "%" + val.toString() + "%"));}Predicate[] p = new Predicate[orPredicate.size()];list.add(cb.or(orPredicate.toArray(p)));continue;}if (ObjectUtil.isNotEmpty(joinName)) {String[] joinNames = joinName.split(">");for (String name : joinNames) {switch (q.join()) {case LEFT:if(ObjectUtil.isNotNull(join)){join = join.join(name, JoinType.LEFT);} else {join = root.join(name, JoinType.LEFT);}break;case RIGHT:if(ObjectUtil.isNotNull(join)){join = join.join(name, JoinType.RIGHT);} else {join = root.join(name, JoinType.RIGHT);}break;case INNER:if(ObjectUtil.isNotNull(join)){join = join.join(name, JoinType.INNER);} else {join = root.join(name, JoinType.INNER);}break;default: break;}}}switch (q.type()) {case EQUAL:list.add(cb.equal(getExpression(attributeName,join,root).as((Class<? extends Comparable>) fieldType),val));break;case GREATER_THAN:list.add(cb.greaterThanOrEqualTo(getExpression(attributeName,join,root).as((Class<? extends Comparable>) fieldType), (Comparable) val));break;case LESS_THAN:list.add(cb.lessThanOrEqualTo(getExpression(attributeName,join,root).as((Class<? extends Comparable>) fieldType), (Comparable) val));break;case LESS_THAN_NQ:list.add(cb.lessThan(getExpression(attributeName,join,root).as((Class<? extends Comparable>) fieldType), (Comparable) val));break;case INNER_LIKE:list.add(cb.like(getExpression(attributeName,join,root).as(String.class), "%" + val.toString() + "%"));break;case LEFT_LIKE:list.add(cb.like(getExpression(attributeName,join,root).as(String.class), "%" + val.toString()));break;case RIGHT_LIKE:list.add(cb.like(getExpression(attributeName,join,root).as(String.class), val.toString() + "%"));break;case IN:if (CollUtil.isNotEmpty((Collection<Long>)val)) {list.add(getExpression(attributeName,join,root).in((Collection<Long>) val));}break;case NOT_EQUAL:list.add(cb.notEqual(getExpression(attributeName,join,root), val));break;case NOT_NULL:list.add(cb.isNotNull(getExpression(attributeName,join,root)));break;case BETWEEN:List<Object> between = new ArrayList<>((List<Object>)val);list.add(cb.between(getExpression(attributeName, join, root).as((Class<? extends Comparable>) between.get(0).getClass()),(Comparable) between.get(0), (Comparable) between.get(1)));break;default: break;}}field.setAccessible(accessible);}} catch (Exception e) {log.error(e.getMessage(), e);}int size = list.size();return cb.and(list.toArray(new Predicate[size]));}@SuppressWarnings("unchecked")private static <T, R> Expression<T> getExpression(String attributeName, Join join, Root<R> root) {if (ObjectUtil.isNotEmpty(join)) {return join.get(attributeName);} else {return root.get(attributeName);}}private static boolean isBlank(final CharSequence cs) {int strLen;if (cs == null || (strLen = cs.length()) == 0) {return true;}for (int i = 0; i < strLen; i++) {if (!Character.isWhitespace(cs.charAt(i))) {return false;}}return true;}private static List<Field> getAllFields(Class clazz, List<Field> fields) {if (clazz != null) {fields.addAll(Arrays.asList(clazz.getDeclaredFields()));getAllFields(clazz.getSuperclass(), fields);}return fields;}
}

使用说明:

@Query 注解实现简单的查询与复杂查询

简单查询:等于(默认)、大于等于、小于等于、左模糊、右模糊、中模糊、多字段模糊、NOT_EQUAL 、BETWEEN 、NOT_NULL。

复杂查询:包含(IN)查询、左连接、右连接

参数说明

字段名称 字段描述 默认值
propName 对象的属性名,如果字段名称与实体字段一致,则可以省略 “”
type 查询方式,默认为 EQUAL
blurry 多字段模糊查询,值为实体字段名称 “”
joinName 关联实体的名称 “”
join 连接查询方式,左连接或者右连接 LEFT

使用方式

  1. 创建一个查询类 QueryCriteria
@Data
public class QueryCriteria {// 等于@Queryprivate String a;// 左模糊@Query(type = Query.Type.LEFT_LIKE)private String b;// 右模糊@Query(type = Query.Type.RIGHT_LIKE)private String c;// 大于等于@Query(type = Query.Type.GREATER_THAN, propName = "createTime")private Timestamp startTime;// 小于等于@Query(type = Query.Type.LESS_THAN, propName = "createTime")private Timestamp endTime;// BETWEEN@Query(type = Query.Type.BETWEEN)private List<Timestamp> startTime;// 多字段模糊查询,blurry 为字段名称@Query(blurry = "a,b,c")private String blurry;// IN 查询@Query(type = Query.Type.IN)private List<String> d;// 左关联查询,left Join , joinName为关联实体名称@Query(joinName = "")private String e;// 右关联查询,right Join , joinName为关联实体名称@Query(joinName = "", join = Query.Join.RIGHT)private String f;// NOT_EQUAL 不等于@Query(type = Query.Type.NOT_EQUAL)private String g;// NOT_NULL 不为空@Query(type = Query.Type.NOT_NULL)private String g;
}
  1. 在控制器中使用
// Pageable 分页查询
public ResponseEntity query(QueryCriteria criteria, Pageable pageable){return new ResponseEntity(service.queryAll(criteria,pageable), HttpStatus.OK);
}
  1. Service 中查询
@Override
public Object queryAll(QueryCriteria criteria, Pageable pageable){Page<实体> page = repository.findAll(((root, criteriaQuery, cb) -> QueryHelp.getPredicate(root, criteria, cb)),pageable);return page;
}

使用例子

使用注解编写请求类

@Data
@ApiModel("油费记录查询dto")
public class QueryOilReqDto implements Serializable {@ApiModelProperty("车牌号")@Query(type = Query.Type.INNER_LIKE)private String brandNumber;@Query(type = Query.Type.BETWEEN)private List<Timestamp> createTime;}

查询方法:

 public Map queryOilCost(QueryOilReqDto reqDto, Pageable pageable) {final Page<CarCost> all = carCostRepository.findAll((root, criteriaQuery, criteriaBuilder)-> QueryHelp.getPredicate(root, reqDto, criteriaBuilder), pageable);Page<OilRespDto> map = all.map(oilRespDtoMapper::toDto);return PageUtil.toPage(map);}

自定义注解,实现jpa查询,使用起来很方便,记录一下相关推荐

  1. aop注解配置切点 spring_springboot aop 自定义注解方式实现一套完善的日志记录

    一:功能简介 本文主要记录如何使用aop切面的方式来实现日志记录功能. 主要记录的信息有: 操作人,方法名,参数,运行时间,操作类型(增删改查),详细描述,返回值. 二:项目结构图 如果想学习Java ...

  2. Spring data JPA使用@formula注解使用、查询不到内容

    @Formula注解就是使用查询语句动态生成类的一个属性,是一个虚拟的列,其并不存储在数据库中. 以下为一个与数据表映射的实体: @Data @Entity @Table ( name =" ...

  3. Spring Data JPA 查询方法的命名语法与参数

    3 Spring Data JPA 查询方法的命名语法与参数 在⼯作中,你是否经常为⽅法名的语义.命名规范⽽发愁?是否要为不同的查询条件写各种的 SQL 语句?是否为同⼀个实体的查询,写⼀个超级通⽤的 ...

  4. java 自定义注解 解析_java自定义注解

    1.Annotation的工作原理: JDK5.0中提供了注解的功能,允许开发者定义和使用自己的注解类型.该功能由一个定义注解类型的语法和描述一个注解声明的语法,读取注解的API,一个使用注解修饰的c ...

  5. 深入理解Java注解Annotation及自定义注解

    要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法. 元注解: 元注解的作用就是负责注解其他注解.Java5. ...

  6. 实现基于注解(Annotation)的数据库框架(三)自定义注解(Annotation)

    #前言# 之前已经简单介绍了系统的内置注解,我们已经对注解有了一个初步的印象,接下来就来看看如何自定义注解. 此文章仍然转载自上一篇的作者,因为他写的实在是太好了,非常适合刚接触注解的朋友去看,原文的 ...

  7. 深入理解Java:注解(Annotation)自定义注解入门

    要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法. 元注解: 元注解的作用就是负责注解其他注解.Java5. ...

  8. 一小时搞明白自定义注解(Annotation)

    原文链接:http://blog.csdn.net/u013045971/article/details/53433874 什么是注解 Annotation(注解)就是Java提供了一种元程序中的元素 ...

  9. 深入理解Java:注解(Annotation)基本概念、自定义注解、注解解析器

    深入理解Java:注解(Annotation)基本概念 什么是注解(Annotation): Annotation(注解)就是Java提供了一种元程序中的元素关联任何信息和着任何元数据(metadat ...

最新文章

  1. LeetCode之Sort List
  2. Harris’s Linked List
  3. 3dmax全局材质灯光细分插件_3Dmax渲染Vray渲染提速优化技巧
  4. centOS 7 yum安装MySQL5.6
  5. 这是时间的推移 不是系统的分类
  6. 【Codeforces - 769D】k-Interesting Pairs Of Integers(暴力,统计,思维,数学,异或)
  7. 腾讯云数据库Redis助力百万企业远程办公
  8. mysql哪些字段适合索引_(转)Mysql哪些字段适合建立索引
  9. 拳王公社:虚拟资源项目怎么做?如何操作赚钱?最新操作方法
  10. 【前端 · 面试 】HTTP 总结(七)—— HTTP 缓存概述
  11. Q83:怎么画多个PLY文件组合的图形[Multiple-Mesh Objects]
  12. C++使用命名管道使用进程间通信
  13. 树莓派使用 USB 摄像头做网络监控
  14. html注册页面教程视频,新手建站HTML 学习系列视频教程之HTML 简介
  15. 【收藏】计算机视觉领域全球顶级高校研究所团队总结
  16. 调研分析:全球与中国乙氧呋草黄市场现状及未来发展趋势
  17. 李佳琦、薇娅们的残酷生存物语
  18. 阿里首席风险官郑俊芳:安全是我们的生命线,将时刻保持敬畏心
  19. 云服务器aip,云服务器API接口-云服务器的使用
  20. String index out of range: -4 错误解析

热门文章

  1. 手机芯片性能排名天梯图2022
  2. 异步电动机转子磁动势——转子堵转时
  3. FPGA-出租车计价器的实现
  4. java fail 方法_java中的fail是什么意思
  5. 打地鼠java代码流程图_51单片机 普中51 打地鼠游戏 仿真 程序 流程图
  6. 3D相机面临的困难问题和解决方案
  7. Android 炫酷进度条
  8. 山东大学计算机学院复试名单,山东大学2012计算机学院拟录取名单。
  9. html 微信界面,微信界面.html
  10. 新媒体视频导演 - 导演学前班