A simple example of JAVA custom annotation used

  As a JAVA developer of the concept notes must be no stranger. As we usually have a good number of common @Controller, @ Service, @ Test, @ Override and so on, correct use of annotations can indeed facilitate our development to @Controller for example, after adding the annotation framework level for us saving a lot needs to write common code in the Servlet level, greatly reducing the amount of code duplication actual development.

  In addition to using these annotations provided by the framework, we can also customize annotations to facilitate their development for our application, let's look at how to customize and use annotations, and provides a practical example of using a custom annotations.

  The concept notes

  Starting from JDK 1.5, Java adds support for metadata (MetaData), that is, Annotation (annotation). Notes code is actually a special mark, which is used to replace the configuration file: The traditional way to tell the class how to run through the configuration file, after the notes have technology, developers can annotate how to tell the class to run. Typical applications annotations in Java technology is there: by reflection technique to get inside the class notes, to decide how to run the class. 

  For annotations, official statement is: a comment can be added to the metadata java code, classes, methods, variables, parameters, and packages can be used to modify annotations. Notes for which it modified the code and no direct effect.

  Annotation is actually a data structure, additional information is added to our classes, properties, methods, we can use some extensions to the host logical judgment.

  Notes life cycle has three stages: 1, Java source file stage; 2, compiled into class files stage; 3, run-time phase.

  We can be configured through a meta-annotation our custom annotations life cycle, in the actual production, the most widely used is to use annotations in the run stage, so under normal circumstances we will custom annotation lifecycle configured to run on the entry into force .

  Yuan notes

  Mentioned above, we can configure annotations life cycle through metadata annotation, we can use the same configuration meta-annotation annotation objects, and so the role of the basic attributes. Meta-annotation is a modification of annotations for annotation.

  JDK 1.5 is provided in the four standard annotation based on annotation to the annotation types, we call meta-annotation (meta-annotation), they are:

   @Target、@Retention、@Documented、@Inherited

  We can use these four yuan notes to annotate our custom annotation type, then, we one by one these four yuan notes roles are introduced.

  1, Target annotation: effect of the annotation is: annotations described range (ie: the modified annotation can be used in any place). Target annotation for explaining that it is annotated based annotation can be modified target range: annotation can be used to modify packages, types (classes, interfaces, enumerations, annotation category), a member of class (method, constructor, member variables, enumeration value), method arguments and local variables (such as a loop variable, the catch parameters), when used @Target annotation class can be defined more clearly know what it can be used to modify the object, which is defined in the range ElementType enumeration.

  2, Reteniton Note: The effect of annotation is: Description retention time annotations (i.e.: annotations are described in the modification of its class to be retained when). Reteniton annotation is used to annotate classes are limited to those in which it is annotated notes after class to the other, may be retained until when, a total of three strategies, as defined in RetentionPolicy enumeration.

  3, Documented Note: the role of the annotation is: when describing the class to generate help files using the javadoc tool if you want to keep its annotation information.

  4, Inherited Notes: The role of the annotation is: is it modified the notes are inherited (If a class uses the annotation is @Inherited modified, it will automatically have a subclass of the notes).
  Target and Reteniton which is our most frequent.

  example

  Basics annotated relatively small, we started direct example of a practical production.

  In production, for describing a class encountered rating information, for each rating category attribute items when the score. Ratings are many items (getter / setter Ignore all save space):

public class SysMark extends BaseEntity {
    private String markReasons;
    private String fj1ReasonSelf;
private Double fj1MarkSelf;
    private String fj2ReasonSelf;
private Double fj2MarkSelf;
    private String fj3ReasonSelf;
private Double fj3MarkSelf;
    private String fj4ReasonSelf;
private Double fj4MarkSelf;
    private String fj5ReasonSelf;
private Double fj5MarkSelf;
    private String jf1ReasonSelf;
private Double jf1MarkSelf;
    private String jf2ReasonSelf;
private Double jf2MarkSelf;
    private String jf3ReasonSelf;
private Double jf3MarkSelf;
    private String jf4ReasonSelf;
private Double jf4MarkSelf;
    private String jf5ReasonSelf;
private Double jf5MarkSelf;
    private String jf6ReasonSelf;
private Double jf6MarkSelf;
    private String llxz1ReasonSelf;
private Double llxz1MarkSelf;
    private String llxz2ReasonSelf;
private Double llxz2MarkSelf;
    private String llxz3ReasonSelf;
private Double llxz3MarkSelf;
    private String llxz4ReasonSelf;
private Double llxz4MarkSelf;
    private String zygw1ReasonSelf;
private Double zygw1MarkSelf;
    private String zygw2ReasonSelf;
private Double zygw2MarkSelf;
    private String zygw3ReasonSelf;
private Double zygw3MarkSelf;
    private String jsyw1ReasonSelf;
private Double jsyw1MarkSelf;
    private String jsyw2ReasonSelf;
private Double jsyw2MarkSelf;
    private String jsyw3ReasonSelf;
private Double jsyw3MarkSelf;
    private String jsyw4ReasonSelf;
private Double jsyw4MarkSelf;
    private String zgsx1ReasonSelf;
private Double zgsx1MarkSelf;
    private String zgsx2ReasonSelf;
private Double zgsx2MarkSelf;
    private String zgsx3ReasonSelf;
private Double zgsx3MarkSelf;
    private String zgsx4ReasonSelf;private Double zgsx4MarkSelf;
    private java.sql.Timestamp markTime;
    private java.sql.Timestamp updateTime;
    private String startTime;
    private String endTime;
    private String markId;
    private Double markMark;
    private String markMonth;
    private String markYear;
    private String markJiDu;
    private long uid;
    private String deptId;
}

  目前接到的需求是,将评分项汇总,组成一个  “评分项1:得分1;评分项2:得分2...”  的字符串。其中每个评分项得分在实际语义中包含三种情况:加分项,减分项,否决项(总分直接判0)。

  在通常情况下,我们一般便会通过 if - else 逐个判断每个属性是否有打分,判断该评分项的类型来决定得分是加分、减分还是直接判 0 。 

  但这样做会带来很多不方便,几十个 if 判断不说,万一我们要新增或减少一个评分项或者配错/漏配了一个评分项,我们需要那 if 的代码逐行的与类中的属性比对,非常的繁琐。这时候我们可以考虑自定义一个注解用于修饰这些属性,在定义属性时便为其附加 评分项名称 以及加减分/否决的属性,然后通过反射对所有属性统一进行处理。

  我们来定义出这个注解:

/**
 * @Author Nxy
 * @Date 2020/2/15 13:17
 * @Description 自定义评分原因注解
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(value = ElementType.FIELD)
public @interface MarkReason {
    //评分项目名称
    public String reasonName();
    //是否减分项
    public boolean isSubtraction() default true;
    //是否否决项
    public boolean isFouJue() default false;
}

  其中两个元注解的含义便是:@Retention(RetentionPolicy.RUNTIME):该注解在运行期生效;@Target(value = ElementType.FIELD):该注解作用于属性。

  我们为注解定义了三个属性 resonName、isSubtraction、isFouJue,被 MarkReason 注解修饰的属性可以拥有这三个属性。

  我们用该注解对上述评分类进行修饰后评分类变成这样:

public class SysMark extends BaseEntity {
    private String markReasons;
    private String fj1ReasonSelf;
    @MarkReason(reasonName = "责任区党员群众发生违法行为", isFouJue = true)
    private Double fj1MarkSelf;
    private String fj2ReasonSelf;
    @MarkReason(reasonName = "责任区党员群众发生撞“红线”及以上问题", isFouJue = true)
    private Double fj2MarkSelf;
    private String fj3ReasonSelf;
    @MarkReason(reasonName = "责任区党员群众参与群体上访、越级上访", isFouJue = true)
    private Double fj3MarkSelf;
    private String fj4ReasonSelf;
    @MarkReason(reasonName = "责任区发生打架斗殴等不良行为", isFouJue = true)
    private Double fj4MarkSelf;
    private String fj5ReasonSelf;
    @MarkReason(reasonName = "经研究其他否决项目的问题", isFouJue = true)
    private Double fj5MarkSelf;
    private String jf1ReasonSelf;
    @MarkReason(reasonName = "责任区党员群众发现安全重大隐患、防止安全事故、受到段级及以上表扬表彰或通报嘉奖", isSubtraction = false)
    private Double jf1MarkSelf;
    private String jf2ReasonSelf;
    @MarkReason(reasonName = "责任区党员群众参加技术比武获得名次", isSubtraction = false)
    private Double jf2MarkSelf;
    private String jf3ReasonSelf;
    @MarkReason(reasonName = "积极组织责任区党员群众 围绕安全、运输和技术难题立项攻关取得实效,受到总公司、 集团公司、段表彰", isSubtraction = false)
    private Double jf3MarkSelf;
    private String jf4ReasonSelf;
    @MarkReason(reasonName = "责任区党员群众完成急难险重任务成绩突出", isSubtraction = false)
    private Double jf4MarkSelf;
    private String jf5ReasonSelf;
    @MarkReason(reasonName = "责任区党员群众做好人好事、见义勇为事迹受到表彰奖励或媒体表扬", isSubtraction = false)
    private Double jf5MarkSelf;
    private String jf6ReasonSelf;
    @MarkReason(reasonName = "其他受到集团公司及以上表彰奖励", isSubtraction = false)
    private Double jf6MarkSelf;
    private String llxz1ReasonSelf;
    @MarkReason(reasonName = "责任区党员群众无故不参加上级组织的集体活动")
    private Double llxz1MarkSelf;
    private String llxz2ReasonSelf;
    @MarkReason(reasonName = "责任区内环境卫生差、备品摆放不整齐")
    private Double llxz2MarkSelf;
    private String llxz3ReasonSelf;
    @MarkReason(reasonName = "班组标准化验收不达标")
    private Double llxz3MarkSelf;
    private String llxz4ReasonSelf;
    @MarkReason(reasonName = "班组未完成生产任务,运输组织工作,旅客、货主等服务工作受到上级批评")
    private Double llxz4MarkSelf;
    private String zygw1ReasonSelf;
    @MarkReason(reasonName = "责任区党员群众发生迟到、早退")
    private Double zygw1MarkSelf;
    private String zygw2ReasonSelf;
    @MarkReason(reasonName = "责任区党员群众发生严重“两违”问题")
    private Double zygw2MarkSelf;
    private String zygw3ReasonSelf;
    @MarkReason(reasonName = "作业提醒不到位")
    private Double zygw3MarkSelf;
    private String jsyw1ReasonSelf;
    @MarkReason(reasonName = "不参加月度业务考试、模拟演练")
    private Double jsyw1MarkSelf;
    private String jsyw2ReasonSelf;
    @MarkReason(reasonName = "责任区党员群众月度考试或抽考成绩不达标")
    private Double jsyw2MarkSelf;
    private String jsyw3ReasonSelf;
    @MarkReason(reasonName = "应知应会考试、专业技能考核不达标")
    private Double jsyw3MarkSelf;
    private String jsyw4ReasonSelf;
    @MarkReason(reasonName = "责任区党员群众技术业务帮带效果不明显")
    private Double jsyw4MarkSelf;
    private String zgsx1ReasonSelf;
    @MarkReason(reasonName = "对责任区内职工思想动态不掌握、不熟悉、不了解,不能及时做思想工作")
    private Double zgsx1MarkSelf;
    private String zgsx2ReasonSelf;
    @MarkReason(reasonName = "未及时与发生“两违”问题的党员群众谈心谈")
    private Double zgsx2MarkSelf;
    private String zgsx3ReasonSelf;
    @MarkReason(reasonName = "未及时与困难党员群众谈心谈话")
    private Double zgsx3MarkSelf;
    private String zgsx4ReasonSelf;
    @MarkReason(reasonName = "未及时化解矛盾造成不良影响")
    private Double zgsx4MarkSelf;
    private java.sql.Timestamp markTime;
    private java.sql.Timestamp updateTime;
    private String startTime;
    private String endTime;
    private String markId;
    private Double markMark;
    private String markMonth;
    private String markYear;
    private String markJiDu;
    private long uid;
    private String deptId;
}

  这样一来,在每个属性被定义时,它的语义便被一同写进了其注解中。我们通过反射获取每个属性的注解,对所有属性进行统一的处理:

    /**
     * @Author Nxy
     * @Date 2020/2/15 14:14
     * @Description 汇总加减分原因
     */
    public static void setMarkReasons(BaseEntity markBean) throws IllegalAccessException, NoSuchFieldException {
        Class beanClass = markBean.getClass();
        Field[] fields = beanClass.getDeclaredFields();
        if (fields == null || fields.length == 0) {
            throw new RuntimeException(markBean + " has no field");
        }
        Field targetField = beanClass.getDeclaredField("markReasons");
        StringBuilder reasonsSb = new StringBuilder();
        //遍历属性
        for (Field field : fields) {
        //判断该属性是否被 MarkReason 注解修饰
if (field.isAnnotationPresent(MarkReason.class)) { //允许私有属性访问 field.setAccessible(true); String isSubtraction = "-"; MarkReason reasonAnno = field.getAnnotation(MarkReason.class);
          Object markMark = field.get(markBean);
          //判断该项是否已评分
          if(markMark==null){
            continue;
          }
//判断是否是减分项 if (!reasonAnno.isSubtraction()) { isSubtraction = "+"; } String project=""; //判断是否否决项 if(reasonAnno.isFouJue()){ project = "-100"; }else { project = isSubtraction + (double) markMark; } //拼装加减分原因 reasonsSb.append(reasonAnno.reasonName() + ":" + project + ";"); } }
     //汇总后将结果写入对象 targetField.setAccessible(
true); targetField.set(markBean, reasonsSb.toString()); }

  通过上面的方法,我们只需要在定义一个新的评分项时将其用 @MarkReason 注解修饰即可,汇总评分原因的代码不需要做任何改变。而使用传统的 if 判断的方法时,新增/删除/改变一个评分项,相应的 if 节点的代码都需要做出对应的改变。并且相较 if 判断,该方法的代码量也减少了非常多。

 

Guess you like

Origin www.cnblogs.com/niuyourou/p/12312879.html