利用Java注解将常量类生成js文件供前端调用

简介:

  注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则等于没有某种标记,以后,javac编译器,开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记,就去干相应的事标记可以加在包,类,字段,方法,方法的参数以及局部变量上。

1)定义一个最简单的注解

1
2
3
public  @interface  MyAnnotation {
         //......
     }

2)把注解加在某个类上:

1
2
3
4
@MyAnnotation
     public  class  AnnotationTest{
         //......
     }

  我们的常量类注解如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package  com.gaochao.platform.util;
 
import  java.lang.annotation.ElementType;
import  java.lang.annotation.Retention;
import  java.lang.annotation.RetentionPolicy;
import  java.lang.annotation.Target;
 
/**
  * 常量中文转换注解
  * @author chao.gao
  * @date 2013-12-20 下午1:02:02
  * @version <b>1.0.0</b>
  */
@Retention (RetentionPolicy.RUNTIME)
@Target (ElementType.FIELD)
public  @interface  ConstantsText {
     /**
      * 数据字典的label,获取中文含义时使用
      * @author chao.gao
      * @date 2013-12-20 下午1:17:19
      * @return
      */
     public  String termsLable()  default  "" ;
 
     /**
      * 当数据字典中不存在对面的中文时使用,手动设置
      * @author chao.gao
      * @date 2013-12-20 下午1:17:40
      * @return
      */
     public  String text()  default  "" ;
}

  注解的上方有两个元注解,是注解的注解,含义及用法如下:

//Java中提供了四种元注解,专门负责注解其他的注解,分别如下
//@Retention元注解,表示需要在什么级别保存该注释信息(生命周期)。可选的RetentionPoicy参数包括:
//RetentionPolicy.SOURCE: 停留在java源文件,编译器被丢掉
//RetentionPolicy.CLASS:停留在class文件中,但会被VM丢弃(默认)
//RetentionPolicy.RUNTIME:内存中的字节码,VM将在运行时也保留注解,因此可以通过反射机制读取注解的信息
//@Target元注解,默认值为任何元素,表示该注解用于什么地方。可用的ElementType参数包括
//ElementType.CONSTRUCTOR: 构造器声明
//ElementType.FIELD: 成员变量、对象、属性(包括enum实例)
//ElementType.LOCAL_VARIABLE: 局部变量声明
//ElementType.METHOD: 方法声明
//ElementType.PACKAGE: 包声明
//ElementType.PARAMETER: 参数声明
//ElementType.TYPE: 类、接口(包括注解类型)或enum声明

//@Documented将注解包含在JavaDoc中
//@Inheried允许子类继承父类中的注解

  在常量类中应用注解:

1
2
3
4
5
6
7
8
public  class  RelationshipConstants {
public  static  final  String STATUS_SAVED =  "saved" ;
     public  static  final  String STATUS_FINISHED =  "finished" ;
 
     public  static  final  int  HAVE_YES =  1 ;
     public  static  final  int  HAVE_NO =  0 ;
     
}

  添加注解后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
             * 计划状态:已审核
             */
             @ConstantsText (text =  "我是手动审核" )
             public  static  final  String PLANSTATUS_AUDITED =  "audited" ;
 
             /**
             * 计划状态:已作废,从数据字典查找
             */
             @ConstantsText (termsLable =  "planStatus" )
             public  static  final  String PLANSTATUS_CANCELED =  "canceled" ;
 
             /**
             * 计划状态:已完结
             */
             @ConstantsText (termsLable =  "planStatus" )
             public  static  final  String PLANSTATUS_FINISHED =  "finished" ;


解释注解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public  static  String getText(Field field)  throws  Exception {
         String fieldValue = field.get( null ).toString();
         if  (field.isAnnotationPresent(ConstantsText. class )) {
             ConstantsText ct = field.getAnnotation(ConstantsText. class );
             if  (!StringUtils.isBlank(ct.text())) {
                 return  ct.text();
             }
             if  (!StringUtils.isBlank(ct.termsLable())) {
                 String resultStr =  "" ;
                 if  (map.get(ct.termsLable()) !=  null ) {
                     resultStr = map.get(ct.termsLable()).get(fieldValue);
                 else  {
                     logger.error( "数据字典中未找到:termsLable:["  + ct.termsLable() +  "]!" );
                 }
                 if  (resultStr !=  null )
                     return  resultStr;
                 else  {
                     logger.error( "数据字典中未找到termslable:["  + ct.termsLable() +  "],termsCode:["  + fieldValue +  "]的对应值!" );
                 }
             }
         }
         return  fieldValue;
     }
}

  生成js的逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
public  static  void  genJsFile(String fPath) {
         String webRoot = AppContext.getAppContext().getWebAppRoot() +  "/scripts/" ;
         fPath = webRoot;
         String tempPath = fPath;
         PathMatchingResourcePatternResolver util =  new  PathMatchingResourcePatternResolver();
         String fileName =  "" ;
         Map<String, StringBuffer> fileNameMap =  new  HashMap<String, StringBuffer>();
         try  {
             //获取所有*Constants.class文件
             Resource[] file = util.getResources( "classpath*:com/fx/oa/**/api/define/*Constants.class" );
             StringBuffer jsContent =  null ;
             for  (Resource resource : file) {
                 logger.info( "扫描到文件:>>>>>"  + resource.getURI());
                 jsContent =  null ;
                 String clazz = resource.getURI().toString();
                 jsContent =  new  StringBuffer();
                 //获取反射需要的常量类全路径,2:!/,6:.class
                 String className = clazz.substring(clazz.lastIndexOf( "!" ) +  2 , clazz.length() -  6 ).replace( "/" "." );
                 fileName = className.substring( 0 , className.indexOf( ".api" ));
                 //1:.
                 fileName = fileName.substring(fileName.lastIndexOf( "." ) +  1 );
                 if  ((fileName.length() >  0 ) && fileNameMap.containsKey(fileName)) {
                     jsContent = fileNameMap.get(fileName);
                 }
                 logger.info( "扫描到常量类:"  + className);
                 //获取顶级var变量名
                 String varName =  "oa."
                         + className.substring(className.lastIndexOf( "." ) +  1 ).replace( "Constants" "" ).toLowerCase();
                 jsContent.append(genContent(className, fileName, varName));
                 if  (jsContent.length() ==  0 ) {
                     logger.info( "常量类"  + className +  "未定义任何内容,跳过!" );
                     continue ;
                 else  {
                     fileNameMap.put(fileName, jsContent);
                 }
             }
             for  (String s : fileNameMap.keySet()) {
                 fPath += s;
                 File outDir =  new  File(fPath);
                 //输出JS文件
                 if  (!outDir.exists()) {
                     if  (!outDir.mkdir()) {
                         throw  new  RuntimeException( "创建目录:"  + outDir +  "失败!" );
                     }
                 }
                 StringBuffer f = fileNameMap.get(s);
                 File jsFile =  new  File(fPath +  "/"  + s +  ".js" );
                 logger.info( "生成Js文件路径(文件系统):"  + jsFile.getAbsolutePath());
                 logger.info( "生成Js文件路径(项目相对路径):"  + jsFile.getPath());
                 BufferedOutputStream bos =  new  BufferedOutputStream( new  FileOutputStream(jsFile));
                 bos.write(f.toString().getBytes());
                 bos.close();
                 fPath = tempPath;
             }
 
         catch  (Exception e) {
             logger.error(e.getMessage());
             throw  new  RuntimeException(e);
         }
     }
     
         @SuppressWarnings ({  "rawtypes" "unchecked"  })
     public  static  StringBuffer genContent(String className, String packageName, String varName)  throws  Exception {
         Class<?> clazz = Class.forName(className);
         StringBuffer jsContent =  new  StringBuffer();
         Field[] fields = clazz.getDeclaredFields();
         Map<String, List> map =  new  HashMap<String, List>();
         Map<String, List> mapText =  new  HashMap<String, List>();
         List<String> list =  null ;
         List<String> listText =  null ;
         String fieldName =  null , pre =  null , end =  null ;
         if  (fields.length ==  0 ) {
             logger.info(className +  "尚未定义任何常量!" );
             return  new  StringBuffer();
         }
         for  (Field field : fields) {
             fieldName = field.getName();
             int  fieldIndex = fieldName.indexOf( "_" );
             if  (fieldIndex == - 1 ) {
                 logger.error(className +  "字段:"  + fieldName +  "命名不符合规范!" );
                 throw  new  Exception(className +  "字段:"  + fieldName +  "命名不符合规范!" );
             }
             pre = fieldName.substring( 0 , fieldIndex);
             end = firstCharToUpper(fieldName.substring(fieldName.indexOf( "_" ) +  1 ).toLowerCase(),  "_" );
             if  (map.containsKey(pre)) {
                 list = map.get(pre);
                 list.add(end +  "-"  + field.get( null ).toString());
                 map.put(pre, list);
 
                 listText = mapText.get(pre);
                 listText.add(end +  "-"  + getText(field));
                 mapText.put(pre, listText);
             else  {
                 list =  new  ArrayList<String>();
                 list.add(end +  "-"  + field.get( null ).toString());
                 map.put(pre, list);
 
                 listText =  new  ArrayList<String>();
                 listText.add(end +  "-"  + getText(field));
                 mapText.put(pre, listText);
             }
         }
         String value =  null ;
         //处理英文
         jsContent.append(varName +  " = {" );
         for  (String key : map.keySet()) {
             jsContent.append( "\n\t"  + key.toLowerCase() +  " : {" );
             for  ( int  i =  0 ; i < map.get(key).size() -  1 ; i++) {
                 value = (String) map.get(key).get(i);
                 jsContent.append( "\n\t\t\""  + value.substring( 0 , value.indexOf( "-" )) +  "\"" );
                 jsContent.append( " : " );
                 jsContent.append( "\""  + value.substring(value.indexOf( "-" ) +  1 ) +  "\"," );
             }
             value = (String) map.get(key).get(map.get(key).size() -  1 );
             jsContent.append( "\n\t\t\""  + value.substring( 0 , value.indexOf( "-" )) +  "\"" );
             jsContent.append( " : " );
             jsContent.append( "\""  + value.substring(value.indexOf( "-" ) +  1 , value.length()) +  "\"\n" );
             jsContent.append( "\t}," );
         }
         jsContent.replace(jsContent.lastIndexOf( "," ), jsContent.lastIndexOf( "," ) +  1 "" );
         jsContent.append( "\n};\n" );
 
         //处理中文
         jsContent.append(varName +  "Text = {" );
         for  (String key : mapText.keySet()) {
             jsContent.append( "\n\t"  + key.toLowerCase() +  " : {" );
             for  ( int  i =  0 ; i < mapText.get(key).size() -  1 ; i++) {
                 value = (String) mapText.get(key).get(i);
                 jsContent.append( "\n\t\t\""  + value.substring( 0 , value.indexOf( "-" )) +  "\"" );
                 jsContent.append( " : " );
                 jsContent.append( "\""  + value.substring(value.indexOf( "-" ) +  1 ) +  "\"," );
             }
             value = (String) mapText.get(key).get(mapText.get(key).size() -  1 );
             jsContent.append( "\n\t\t\""  + value.substring( 0 , value.indexOf( "-" )) +  "\"" );
             jsContent.append( " : " );
             jsContent.append( "\""  + value.substring(value.indexOf( "-" ) +  1 , value.length()) +  "\"\n" );
             jsContent.append( "\t}," );
         }
         jsContent.replace(jsContent.lastIndexOf( "," ), jsContent.lastIndexOf( "," ) +  1 "" );
         jsContent.append( "\n};\n" );
         return  jsContent;
     }

  生成的js文件如下

1
2
3
4
5
6
7
8
9
10
11
requirements.js
         oa.requirements = {
                status : {
                    'saved' : 'saved' ,
                    'finished'  'finished'
                },
                have : {
                    'yes'  : 1,
                    'no'  : 0
                }
         }

引入js文件后,

通过 模块名.功能标识.含义   模块名.功能标识[含义方式即可取到相应的值.

oa.requirements.status.saved

"saved"


oa.requirements.status[‘saved’]

"saved"

使用说明补充:

在常量类中需要转换成中文含义的常量上面添加注解:

@ConstantsText(termsLable=”数据字典表中的termsLable”),数据库数据字典表中一定要有相应的记录,取得记录是根据termsLable+termsCode取得后面的中文,如果取不到,那么就还是原来的英文. 

@ConstantsText(text=”你自己添加的中文含义”)

生成的js就是如下效果,其实就是一个Map:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
oa.recruitmentText = {
                 have : {
                    "yes"  "1" ,
                    "no"  "0"
                 },
                 status : {
                    "saved"  "saved"
                 },
                 planstatus : {
                    "saved"  "saved" ,
                    "submited"  "submited" ,
                    "audited"  "我是手动审核" , //这个是用的text
                    "canceled"  "已作废" , //这个是数据字典中
                    "finished"  "已完结" //这个也是数据字典中的
                 }
             };

     在js中使用,类似如下:

1
2
template:  function (value) {
             return  oa.recruitmentText.planstatus[value.requirementDeptNames];

  本文应用注解、反射等技术将Constants文件中定义的常量信息提供给前端js,减少了代码量,同时也使前后端文本一致。





     本文转自 gaochaojs 51CTO博客,原文链接:http://blog.51cto.com/jncumter/1679756,如需转载请自行联系原作者



相关文章
|
9天前
|
存储 Java 开发者
Java 里的“变形金刚”:变量与常量的前世今生!
【6月更文挑战第14天】Java 中的变量和常量是编程基础,变量是可变的容器,用于存储不同类型的数据,如示例中的 `age`;常量(如 `MAX_VALUE`)是固定不变的值,用 `final` 定义。理解两者及其作用至关重要,它们确保程序的稳定性和准确性。在实际编程中,合理使用变量和常量可以提高代码可读性和可维护性。它们是构建程序的基础,对新手和资深开发者都极其重要。
|
9天前
|
Java API 数据库
Java一分钟之-JPA注解:@Entity, @Table, @Id等
【6月更文挑战第14天】Java Persistence API (JPA) 是Java开发中的ORM框架,通过注解简化数据访问层。本文介绍了三个核心注解:`@Entity`标识实体类,`@Table`自定义表名,`@Id`定义主键。易错点包括忘记添加`@Entity`、未正确设置主键。建议使用`@GeneratedValue`和`@Column`细化主键策略和字段映射。正确理解和应用这些注解能提高开发效率和代码质量。
25 3
|
9天前
|
存储 小程序 Java
打破传统,Java 变量与常量让你重新认识编程的魅力!
【6月更文挑战第14天】Java编程中的变量与常量赋予程序灵活性和动态性。变量如魔法盒子,其值可变,提供程序的适应性;常量则如灯塔,值恒定,确保稳定性。两者结合构建复杂程序,变量用于处理数据,常量定义规则。在项目中,规范管理变量和常量能提升代码可读性和维护性。无论是小游戏还是复杂系统,它们都是不可或缺的工具,激发编程的无限可能。
|
9天前
|
存储 Java 程序员
揭秘 Java 世界:从“小白”到“大神”,变量与常量的奇妙之旅!
【6月更文挑战第14天】Java编程基础中,变量与常量是构建程序的关键。变量像可变的盒子,存储变化的数据,如`int age = 25;`。常量(如`final double PI = 3.14159;`)是不可变值,用`final`定义。通过示例展示了变量可修改,常量不可改的特性。理解并熟练运用它们对于编程至关重要,伴随程序员从初学到精通的全过程。
|
9天前
|
JavaScript 前端开发 网络协议
前端JS发起的请求能暂停吗?
在讨论前端JS发起的请求是否能暂停时,需要明确两个概念:什么状态可以被认为是“暂停”?以及什么是JS发起的请求?
62 1
前端JS发起的请求能暂停吗?
|
9天前
|
Java
Java 基础深度解析:变量与常量的声明、赋值与初始化的权威指南
【6月更文挑战第14天】Java编程中的变量和常量是基础关键。声明变量如`int age;`,赋值与初始化可在声明时或后续代码中完成。常量用`final`修饰,如`public static final double PI = 3.14159;`,且只能赋值一次。变量命名应具描述性,常量值设定后尽量不变,注重代码的可读性和可维护性。熟练掌握这些将有助于编写高质量Java程序。
|
9天前
|
存储 Java 容器
Java 新手必看:变量与常量,你的编程启蒙导师!
【6月更文挑战第14天】Java编程入门涉及关键概念:变量和常量。变量如可变容器,存储不同值,如示例中的体重变化。常量如`final`定义的`PI`,值固定不变。理解并恰当使用两者对新手至关重要,它们构成编程基础,助力构建灵活且稳定的程序。在学习旅程中,与变量和常量同行,不断进步。
|
9天前
|
存储 Java
Java 新手进阶:从变量到常量,一步步走向编程巅峰!
【6月更文挑战第14天】Java新手应掌握变量与常量,它们是编程基础。通过示例展示变量(如矩形的长度和宽度)用于存储可变数据,常量(如重力加速度)用于表示固定值。理解不同类型的变量,如字符串、整型和浮点型,并用`final`关键字定义常量。在银行账户管理程序案例中,变量跟踪账户信息,常量表示年利率。熟悉这些概念将提升编程技能。
|
9天前
|
存储 Java 容器
那些年,我们一起学过的 Java 变量与常量
【6月更文挑战第14天】Java学习中,变量和常量至关重要。变量如灵活容器,存储各类数据,示例:`int number = 10; number = 20;`。常量如圆周率`PI`,定义后不可变。Java有整型、浮点型、字符型、字符串型等变量和常量。合理使用能提升代码规范性和可读性,命名规范至关重要。变量和常量是编程基础,影响深远,共同构建稳定系统。
|
9天前
|
存储 Java 开发者
在 Java 的星辰大海中,寻找变量与常量的那份执着与坚守。
【6月更文挑战第14天】Java 中的变量与常量各有特色。变量如善变的艺术家,值可随程序需求变化,适于存储动态数据;而常量如同坚定不移的灯塔,值恒定不变,为程序提供稳定参照。变量用于处理复杂情况,常量定义固定规则。两者在内存管理和编程风格上各有作用,共同构建程序并确保其正确性与稳定性。理解并巧妙运用它们的差异,能提升 Java 编程的效率和质量,探索编程的无限可能。