反射动态操做类+注解灵活打标签 | 反射注解结合灵活高效实战

这是我参与更文挑战的第29天,活动详情查看: 更文挑战java

前言

  • 以前两篇文章咱们分别介绍了反射和注解的入门,其中也有同窗给到建议是从具体应用场景出发更容易理解精髓!今天笔者就结合下本身实际项目中使用到的功能!这里算是抛砖引玉了

功能需求

  • 针对一张表作一个表单查询功能!这个功能十分的简单没有技术难点无非就是咱们在写查询时注入条件写成动态条件判断!其余就没啥了

image-20210628142137773

  • 涉及公司内部数据,这里关键数据已经被我换掉了!
  • 除了查询之外,咱们还有生成数据的功能。结合对数据的管理咱们来看看如何注解反射左右开弓

数听说明

  • 首先数据存储在mongo中,查询是经过MongoTemplate来实现数据的查询
  • 存储的数据时间数据是时间戳,页面展现时须要格式化。这部分由接口处理
  • 关于数据状态已验收未验收实际存储的是一、2
  • 条件查询时目前是上面几种!每隔一段时间须要根据使用频率及用户反馈进行随意调节

实体定义

@Data
public class DangersBook implements Serializable {
    @TimeSequence
    @Ignore
    @Id
    @Query
    private Long id;
    @DangersNo
    @Ignore
    @Query
    @LikeQuery
    private String dangersNo;
    @Ids
    private String instance_id;
    @DangersType
    @Ids
    private String app_id;
    @Ids
    @Query
    @DangersEntId
    @OrQuery
    private String entId;
    private String created_by;
    @Query
    @Ids
    private String zuoyeleixing;
    @Date
    @Query
    private String pizhunkaishi;
    @Date
    @Query
    private String pizhunjieshu;
    @UpdateItem(value = "已验收")
    @Query
    @OrQuery
    private String yanshouStatus;
    @Query
    @Date
    @UpdateItem(value = "")
    private String finishTime;
    private String jianweixiuxukezheng;
    private String zuoyedengji;
    @Query
    @LikeQuery
    private String zuoyeneirong;
    /** * @Description 用于判断是否应该生成编号 */
    @Ignore
    @Query
    private String createDangerNo;
    private String laowubanzu;
    @Query
    private String test;
    @Query
    private String interrupt;
    @Query
    @OrQuery
    private String year;
}
复制代码

注解说明

  • 首先咱们须要先经过反射获取到DangersBook中的全部属性!这是咱们对反射的第一处运用!实际上在项目中凡是须要写活属性的获取的都是经过反射进行获取结合注解进行属性过滤!

TimeSequence

  • 在生成数据是数据的惟一id每每都是后端自行生成的这样才能保证真正的惟一!而TimeSequence注解就是对字段进行标注,这样咱们在程序中只要识别到属性中存在该注解就会进行惟一id生成
TimeSequence annotation = declaredField.getAnnotation(TimeSequence.class);
if (annotation!=null) {
    //雪花算法
    long generatorId = DistributedIDUtils.getInstance().getGeneratorId(1l, 2l, 3l);
    declaredField.setAccessible(true);
    declaredField.set(object, generatorId);
}
复制代码
  • 获取到TimeSequence以后咱们就能够经过雪花算法生成id而后经过属性将生成的id赋值进去!

Ignore

  • 还有一种状况是有些数据咱们不能进行任何操做,那么在反射中咱们经过注解进行获取来进行更新数据时就须要将这些数据过滤掉。Ignore就是这个做用
Ignore ignore = declaredField.getAnnotation(Ignore.class);
if (ignore != null) {
    continue;
}
复制代码

Query & Date & LikeQuery&OrQuery

  • 这三个都是在查询是涉及的。后面两个也是在Query基础上进行扩展的
com.ay.sdksm.custom.components.expose.annation.Query queryField = declaredField.getAnnotation(com.ay.sdksm.custom.components.expose.annation.Query.class);
if (queryField != null) {
    //须要添加查询条件
    try {
        declaredField.setAccessible(true);
        Object o = declaredField.get(dangersBook);
        if (null != o&&!"".equals(o.toString())) {
            String svalue = o.toString();
            Date dateAnnotation = declaredField.getAnnotation(Date.class);
            LikeQuery likeQuery = declaredField.getAnnotation(LikeQuery.class);
            if (dateAnnotation != null) {
                String dateValue = svalue;
                if (StringUtils.isEmpty(dateValue)) {
                    continue;
                }
                String[] dateSplit = dateValue.split(",");
                String start = dateSplit[0];
                String end = start;
                if (dateSplit.length >= 2) {
                    end = dateSplit[1];
                }
                criteria.and(declaredField.getName()).gte(start).lte(end);

            } else if(likeQuery != null){
                Pattern pattern = Pattern.compile(String.format(".*%s.*", svalue), Pattern.CASE_INSENSITIVE);
                criteria.and(declaredField.getName()).regex(pattern);
            }else {
                OrQuery orQuery = declaredField.getAnnotation(OrQuery.class);
                if (null != orQuery) {
                    String[] split = svalue.split(",");
                    String start = split[0];
                    String end = split[0];
                    if (split.length > 1) {
                        end = split[1];
                    }
                    criteria.and(declaredField.getName()).in(start, end);
                } else {
                    if (svalue.contains("$ne")&& JsonUtils.getInstance().isJson(svalue)) {
                        JSONObject jsonObject = JSONObject.parseObject(svalue);
                        String $ne = jsonObject.getString("$ne");
                        criteria.and(declaredField.getName()).ne($ne);
                    }else if(svalue.contains("$like")&& JsonUtils.getInstance().isJson(svalue)){
                        //模糊查询
                        JSONObject jsonObject = JSONObject.parseObject(svalue);
                        String $like = jsonObject.getString("$like");
                        criteria.and(declaredField.getName()).is(String.format("/%s/",$like));
                    } else {
                        Class<?> type = declaredField.getType();
                        if (type == Long.class) {
                            criteria.and(declaredField.getName()).is(Long.valueOf(svalue));
                        } else {
                            criteria.and(declaredField.getName()).is(svalue);
                        }
                    }
                }
            }
        }
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}
复制代码
  • 首先须要配合Query注解表示须要对字段进行条件组装。当遇到Date咱们就须要将条件值进行定制处理咱们约定的条件值是已逗号间隔的时间段。这样咱们就能够动态的支持时间点、时间段的查询。
  • 而后遇到LikeQuery表示是模糊查询。
  • 还有部分状况是取反查询!总之咱们全部的需求均可以在注解Query基础后进行扩展。上面是初期版本其中没有通过设计表现出来就是有些if else荣誉代码!笔者这里也仅是展现注解的使用场景。
  • 后续或者说读者有时间能够本身根据设计模式中策略模式进行代码优化就会很简洁易懂!关于策略模式能够参考这篇文章就够了

DangersNo

DangersNo annotation = declaredField.getAnnotation(DangersNo.class);
if (annotation != null) {
    //根据业务生成指定格式的数据ID;这里比较复杂。代码省略。。。。。。
}
复制代码

注解总结

  • 总的来讲咱们能够根据本身不一样的业务需求开发出不一样的注解表示不一样的做用。而后在反射中所有同人对待!当遇到指定的注解时咱们就进行对应的业务开发!这点很适合策略模式在代码中咱们也能够简化咱们的if else 。

反射应用场景

  • 上面注解的使用场景也能够理解成是反射的使用场景。可是那个主要是说注解的。反射大可能是在框架中使用的比较多,由于框架须要高可调节性因此内部不少都是进行配置生效的。
  • 对于后端程序员来讲Spring应该不会是很陌生的。在Spring中咱们常见的也是必备的两个技能知识点是IOC+AOP。

IOC

  • IOC 依赖注入,在Spring中咱们须要哪一个对象再也不须要向传统方式那样New了,而是经过Spring的注入功能就能够轻松获取一个对象,这不只仅是方式的改变动是对咱们操做的简化,咱们不在须要为新建立的一个对象进行复杂的属性初始化了这些都被Spring完成了。他完成的主要手段就是经过反射。在项目初始化时spring会根据反射获取属性并进行属性填充!这是一个复杂的过程咱们今天仅需牢记在项目初期会经过反射进行属性初始化!在咱们使用到类的时候就能够直接经过类对象进行操做

AOP

  • AOP切面编程。你的项目中必定有日志功能,在每一个接口处都须要对接口进行记录包括入参出参已经其中耗时等基本信息。若是让你实现是否须要在每一个地方进行开发。这种方式咱们能够理解成埋点操做。这种方式是不可取的。由于相似日志功能这种通用性的功能咱们没法在每一处进行开发这非常耗费时间!
  • 在IOC的时候不只仅是经过反射初始化属性还会生成代理对象。这个代理对象的生成过程笔者这里是将它理解成一次反射生成的代理对象。不知道这里理解是否正确?若是错误忘指出。

总结

  • 反射有的人说影响性能。这的确是影响性能,可是它提升咱们程序的灵活性。我以前说过这事一个时间和空间的问题!鱼和熊掌不可兼得
  • 注解存在任何一个框架中。凡是一个成熟的框架必须有注解这样才能提升生产力

点赞,XDM程序员

相关文章
相关标签/搜索