利用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,如需转载请自行联系原作者



相关文章
|
11天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
39 2
|
5天前
|
存储 缓存 安全
java 中操作字符串都有哪些类,它们之间有什么区别
Java中操作字符串的类主要有String、StringBuilder和StringBuffer。String是不可变的,每次操作都会生成新对象;StringBuilder和StringBuffer都是可变的,但StringBuilder是非线程安全的,而StringBuffer是线程安全的,因此性能略低。
|
22天前
|
存储 安全 Java
java.util的Collections类
Collections 类位于 java.util 包下,提供了许多有用的对象和方法,来简化java中集合的创建、处理和多线程管理。掌握此类将非常有助于提升开发效率和维护代码的简洁性,同时对于程序的稳定性和安全性有大有帮助。
43 17
|
14天前
|
存储 缓存 安全
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见。本文介绍了使用 `File.createTempFile` 方法和自定义创建临时文件的两种方式,详细探讨了它们的使用场景和注意事项,包括数据缓存、文件上传下载和日志记录等。强调了清理临时文件、确保文件名唯一性和合理设置文件权限的重要性。
38 2
|
14天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
18天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
67 4
|
28天前
|
Java 开发者 Spring
[Java]自定义注解
本文介绍了Java中的四个元注解(@Target、@Retention、@Documented、@Inherited)及其使用方法,并详细讲解了自定义注解的定义和使用细节。文章还提到了Spring框架中的@AliasFor注解,通过示例帮助读者更好地理解和应用这些注解。文中强调了注解的生命周期、继承性和文档化特性,适合初学者和进阶开发者参考。
49 14
|
19天前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
40 2
|
28天前
|
前端开发 Java
[Java]讲解@CallerSensitive注解
本文介绍了 `@CallerSensitive` 注解及其作用,通过 `Reflection.getCallerClass()` 方法返回调用方的 Class 对象。文章还详细解释了如何通过配置 VM Options 使自定义类被启动类加载器加载,以识别该注解。涉及的 VM Options 包括 `-Xbootclasspath`、`-Xbootclasspath/a` 和 `-Xbootclasspath/p`。最后,推荐了几篇关于 ClassLoader 的详细文章,供读者进一步学习。
32 12
|
23天前
|
存储 安全 Java
如何保证 Java 类文件的安全性?
Java类文件的安全性可以通过多种方式保障,如使用数字签名验证类文件的完整性和来源,利用安全管理器和安全策略限制类文件的权限,以及通过加密技术保护类文件在传输过程中的安全。
下一篇
无影云桌面