注解相當於一種標記,在程序中加了注解就等於為程序打上了某種標記,沒加,則等於沒有某種標記,以後,javac編譯器,開發工具和其他程序可以用反射來了解你的類及各種元素上有無何種標記,看你有什麼標記,就去干相應的事。標記可以加在包,類,字段,方法,方法的參數以及局部變量上。
1)定義一個最簡單的注解
public @interface MyAnnotation {
//......
}
2)把注解加在某個類上:
@MyAnnotation
public class AnnotationTest{
//......
}
我們的常量類注解如下:
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;
}
添加注解後
/**
* 計劃狀態:已審核
*/
@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";
解釋注解:
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的邏輯:
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文件如下
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:
oa.recruitmentText = {
have : {
"yes" : "1",
"no" : "0"
},
status : {
"saved" : "saved"
},
planstatus : {
"saved" : "saved",
"submited" : "submited",
"audited" : "我是手動審核",//這個是用的text
"canceled" : "已作廢",//這個是數據字典中
"finished" : "已完結"//這個也是數據字典中的
}
};
在js中使用,類似如下:
template: function(value) {
return oa.recruitmentText.planstatus[value.requirementDeptNames];
本文應用注解、反射等技術將Constants文件中定義的常量信息提供給前端js,減少了代碼量,同時也使前後端文本一致。