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



相关文章
|
7月前
|
Java Unix Go
【Java】(8)Stream流、文件File相关操作,IO的含义与运用
Java 为 I/O 提供了强大的而灵活的支持,使其更广泛地应用到文件传输和网络编程中。!但本节讲述最基本的和流与 I/O 相关的功能。我们将通过一个个例子来学习这些功能。
309 1
|
前端开发 Java 物联网
智慧班牌源码,采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署
智慧班牌系统是一款基于信息化与物联网技术的校园管理工具,集成电子屏显示、人脸识别及数据交互功能,实现班级信息展示、智能考勤与家校互通。系统采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署与私有化定制。核心功能涵盖信息发布、考勤管理、教务处理及数据分析,助力校园文化建设与教学优化。其综合性和可扩展性有效打破数据孤岛,提升交互体验并降低管理成本,适用于日常教学、考试管理和应急场景,为智慧校园建设提供全面解决方案。
711 70
|
10月前
|
监控 Java API
Java语言按文件创建日期排序及获取最新文件的技术
这段代码实现了文件创建时间的读取、文件列表的获取与排序以及获取最新文件的需求。它具备良好的效率和可读性,对于绝大多数处理文件属性相关的需求来说足够健壮。在实际应用中,根据具体情况,可能还需要进一步处理如访问权限不足、文件系统不支持某些属性等边界情况。
458 14
|
11月前
|
存储 Java 数据安全/隐私保护
Java技术栈揭秘:Base64加密和解密文件的实战案例
以上就是我们今天关于Java实现Base64编码和解码的实战案例介绍。希望能对你有所帮助。还有更多知识等待你去探索和学习,让我们一同努力,继续前行!
683 5
|
10月前
|
存储 Java 编译器
深入理解Java虚拟机--类文件结构
本内容介绍了Java虚拟机与Class文件的关系及其内部结构。Class文件是一种与语言无关的二进制格式,包含JVM指令集、符号表等信息。无论使用何种语言,只要能生成符合规范的Class文件,即可在JVM上运行。文章详细解析了Class文件的组成,包括魔数、版本号、常量池、访问标志、类索引、字段表、方法表和属性表等,并说明其在Java编译与运行过程中的作用。
302 0
|
10月前
|
存储 人工智能 Java
java之通过Http下载文件
本文介绍了使用Java实现通过文件链接下载文件到本地的方法,主要涉及URL、HttpURLConnection及输入输出流的操作。
724 0
|
前端开发 JavaScript 数据可视化
58K star!这个让网页动起来的JS库,前端工程师直呼真香!
Anime.js 是一款轻量级但功能强大的JavaScript动画引擎,它能够以最简单的方式为网页元素添加令人惊艳的动效。这个项目在GitHub上已经获得58,000+星标,被广泛应用于电商页面、数据可视化、游戏开发等场景。
554 8
|
移动开发 JavaScript 前端开发
|
存储 JavaScript 前端开发
|
11月前
|
网络协议 安全 Java
实现Java语言的文件断点续传功能的技术方案。
像这样,我们就完成了一项看似高科技、实则亲民的小工程。这样的技术实现不仅具备实用性,也能在面对网络不稳定的挑战时,稳稳地、不失乐趣地完成工作。
588 0

热门文章

最新文章

  • 1
    前端如何存储数据:Cookie、LocalStorage 与 SessionStorage 全面解析
    1146
  • 2
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(九):强势分析Animation动画各类参数;从播放时间、播放方式、播放次数、播放方向、播放状态等多个方面,完全了解CSS3 Animation
    507
  • 3
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(八):学习transition过渡属性;本文学习property模拟、duration过渡时间指定、delay时间延迟 等多个参数
    392
  • 4
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(七):学习ransform属性;本文学习 rotate旋转、scale缩放、skew扭曲、tanslate移动、matrix矩阵 多个参数
    380
  • 5
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(六):全方面分析css的Flex布局,从纵、横两个坐标开始进行居中、两端等元素分布模式;刨析元素间隔、排序模式等
    498
  • 6
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(五):背景属性;float浮动和position定位;详细分析相对、绝对、固定三种定位方式;使用浮动并清除浮动副作用
    672
  • 7
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(四):元素盒子模型;详细分析边框属性、盒子外边距
    1151
  • 8
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(三):元素继承关系、层叠样式规则、字体属性、文本属性;针对字体和文本作样式修改
    266
  • 9
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(二):CSS伪类:UI伪类、结构化伪类;通过伪类获得子元素的第n个元素;创建一个伪元素展示在页面中;获得最后一个元素;处理聚焦元素的样式
    965
  • 10
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(一):CSS发展史;CSS样式表的引入;CSS选择器使用,附带案例介绍
    449