java注解应用实例(处理文本\r\n换行显示)
本文连接:http://blog.csdn.net/tomorrow13210073213/article/details/68069785
转载请注明出处
- 需求背景
近期,开发了一个后台管理项目,主要功能是后台录入文本数据,前台页面展示,同时生成word文档;后台录入没有涉及到富文本编辑框,只有textarea,但要求保留textarea中输入的换行符;此时显示到web页面上时可以用“pre”等标签保留换行效果(\r\n),但存在如下问题:
(1)将web页面用“pdf4”导出成PDF之后,“pre”处理的换行效果无法保留;
(2)将数据导出到word(基于FreeMarker模板)之后,无法保留换行效果,或比较繁琐;
因此需要提供一种比较通用,比较简便的处理方式;
- 思路
引入注解之前的处理方式是:
(1)在前台处理:在jsp中或FreeMarker模板中庸相应的标记语言将相关字段分隔成字符串数组然后循环绑定到页面或word文档中;
这种方式会增加页面逻辑复杂度,稍不留神,就容易出错;(jsp过于庞大会引起一些不可预测的问题,如:[项目中实际遇到的问题](http://blog.csdn.net/tomorrow13210073213/article/details/50669214))
(2)在后台处理:在数据源类中定义另一个变量为List,对象传到页面进行数据绑定之前将所有相关字段处理一遍(分割成List),然后直接在页面或word中进行循环绑定;
这种方式减小了页面复杂度,但增加了后台代码的复杂度(每个字段都需要处理一遍);
然后就有了第三种处理方式,引入注解,将上面提到的第二种处理方式优化一下;给需要分割的字段加一个注解,只过滤所有带注解字段并处理数据就可以了;同时新增需要分割的字段时,只需要给这个字段加上相应的注解;
- 注解类定义
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BreakLine {
public String name();
}
java注解机制不了解的请自行百度/google,简单解释一下字段含义:
public String name();
name定义了需要将哪个字段进行分割;
拥有该注解的字段是一个List,用来保存分割后的列表;
不明白?往下看
* 工具类定义
public class BreakLineUtil {
public static <T> void anaLines(List<T> objList) {
if (objList == null || objList.size() == 0) {
return;
}
for (Object object : objList) {
anaLine(object);
}
}
public static void anaLine(Object target) {
try {
Class cla = target.getClass();
Field[] fils = getAllFiled(cla);
if (fils == null || fils.length == 0) {
return;
}
for (int i = 0; i < fils.length; i++) {
Field fil = fils[i];
BreakLine line = fil.getAnnotation(BreakLine.class);
if (line != null) {
String name = line.name();
if (name == null || name.trim().length() == 0) {
continue;
}
fil.setAccessible(true);
Field supFil = getSuperFiledVal(fils, name);
if (supFil == null) {
continue;
}
supFil.setAccessible(true);
String oneLine = (String) supFil.get(target);
if (oneLine == null || oneLine.trim().length() == 0) {
continue;
}
List<String> line_list = breakLine(oneLine);
fil.set(target, line_list);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return;
}
private static List<String> breakLine(String line) {
if (line == null || line.trim().length() == 0) {
return null;
}
List<String> line_list = new ArrayList<String>();
String[] lines = line.split("\r\n");
if (lines == null || lines.length == 0) {
return null;
}
for (String string : lines) {
line_list.add(string);
}
return line_list;
}
private static Field[] getAllFiled(Class cla) {
if (cla == null) {
return null;
}
Class classnew = cla;
List<Field> fils = new ArrayList<Field>();
for (int i = 0; i < 5; i++) {
Field[] fis = classnew.getDeclaredFields();
if (fis != null && fis.length > 0) {
for (Field field : fis) {
fils.add(field);
}
classnew = classnew.getSuperclass();
if (classnew == null) {
break;
}
}
}
if (fils == null || fils.size() == 0) {
return null;
}
Integer len = fils.size();
Field[] finalFils = new Field[len];
for (int i = 0; i < len; i++) {
finalFils[i] = fils.get(i);
}
return finalFils;
}
private static Field getSuperFiledVal(Field[] supFils, String name) {
for (Field field : supFils) {
if (field.getName().equals(name)) {
return field;
}
}
return null;
}
}
工具类中用到了java反射相关机制,此处不再赘述,简单解释一下思路:
用反射获取对象中全部字段,
Field[] fils = getAllFiled(cla);
拿到该字段的“BreakLine ”注解(若拿到空,表示这个字段没有“BreakLine ”注解),
BreakLine line = fil.getAnnotation(BreakLine.class);
若line非空,表示当前字段带有“BreakLine”注解,此时可以拿到当前注解的name()值,
String name = line.name();
这里的name我们定义为这个类中需要分割的那个字段的字段名;既然有了字段名,我们还是通过反射拿到字段对应的值,
String oneLine = (String) supFil.get(target);
然后将字段值用“\r\n”分割,并填充到当前字段中;
List<String> line_list = breakLine(oneLine);
fil.set(target, line_list);
完成;
以上,就完成了对注解类和工具类的定义,下面需要测试一下;
- 测试调用
基于项目保密考虑,下面的代码隐去了一些具体类含义,以及部分工具类;
BookBean
public class BookBean {
private String desc;
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
BookModel
public class BookModel extends BookBean {
public BookModel(BookBean bean) {
if (bean != null) {
BeanUtil.copyBean(bean, this);
BreakLineUtil.anaLine(this);
}
}
@BreakLine(name = "desc")
private List<String> desc_list;
public List<String> getDesc_list() {
return desc_list;
}
public void setDesc_list(List<String> desc_list) {
this.desc_list = desc_list;
}
}
项目中用MyBatis做数据持久化操作,BookBean 就是数据库表映射出来的类,BookModel 是BookBean 的子类,添加了desc_list字段,用来存储分割后的结果;desc_list字段上加了一个BreakLine注解,表示需要将name = “desc”对应的字段分割成List,并保存到desc_list字段中;
BookModel 提供了一个构造方法,通过BookBean 创建一个新的BookModel ,“BeanUtil.copyBean();”方法是项目内部用到的,不方便公开,作用就是将BookBean中属性值拷贝到BookModel同名的属性之内;
BreakLineUtil.anaLine(this);
上面这段代码的作用就是解解析BookModel 中的BreakLine注解;工具类会自动将BookBean的desc属性值分割成List,并存储到desc_list字段中;
实际业务中,后台将数据分割成List之后,前台(web页面、word等)就可以循环绑定数据了;
以上就是java注解应用的全部内容,同样的思路也可以应用到类似的需要批量处理的其他业务上(数字格式化、字段长度限制、代码字段翻译等);
代码片段中会有些不太规范或不太优雅的写法,还请诸君不吝指证;