注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则等于没有某种标记,以后,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,如需转载请自行联系原作者