好了,之前的理解java注解二,理解java注解一,已经讲了java注解的一些基础知识,下面,我们来看看具体的应用。
之前的 讲解都比较简单,许多伙伴看了之后都会有些不满意,你这写的啥呀?和没写差不多啊,没啥干货!却是,我之前写的都是十分浅显的应用,稍稍看过一点java注解的都能做出来。
其实,许多伙伴感觉注解神奇,想要了解注解,可又不知道从何下手,注解看起来好神秘,好复杂,好难用。比如:看到同事在类上、方法上或者属性上加了一个注解,就可以进行权限的校验,参数的校验,甚至是属性的处理,猛然一看,云里雾里,好高大上!其实,你仔细剖开注解的面纱,就会发现,原来这个也没有太深入啊!
接下来,我就说一说特殊对象统一封装时,注解的使用。
首先,创建一个注解,标识这个对象是有附件的,需要递归(下钻)获取附件对象(开始水代码)。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AttachAnnotion {
}
然后就直接进入主题,创建一个附件对象AttachInfoList,标识一个上传附件的地方,其中包含refId与附件集合attachInfos:
@Data
public class AttachInfoList extends BaseVO{
private String refId ;
private List<AttachVO> attachVOList;
}
下面创建一个页面对象PageTestVO
@Data
public class PageTestVO extends BaseVO {
private String pageName;
@AttachAnnotion
private ParagraphVO paragraphVO;
//单个文件
private AttachInfoList attachInfo;
//多个文件
private List<AttachInfoList> attachInfos;
private String imageRefId;
}
其中paragraphVO是段落,其中也有文件信息
@Data
public class ParagraphVO extends BaseVO {
private String name ;
/**
* 附件
*/
private AttachInfoList attachInfoLists;
}
对象创建完毕,下面开始通过反射和注解处理问题,代码已经注释的比较详细了,伙伴们看下哈~
package com.example.demo;
import com.alibaba.fastjson.JSON;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class AnnoTest {
public static void main(String[] args) {
PageTestVO base = new PageTestVO();
List<AttachInfoList> attachInfos = new ArrayList<>();
// 单个--- attachInfo
AttachInfoList attachInfo = new AttachInfoList();
AttachVO test111 = new AttachVO("111", "test111");
List<AttachVO> list1 = new ArrayList<>();
list1.add(test111);
attachInfo.setAttachVOList(list1);
attachInfo.setRefId("test111");
base.setAttachInfo(attachInfo);
//多个 ----- attachInfos
AttachInfoList attachInfo2 = new AttachInfoList();
AttachVO test222 = new AttachVO("222", "test222");
List<AttachVO> list2 = new ArrayList<>();
list2.add(test222);
attachInfo2.setAttachVOList(list2);
AttachInfoList attachInfo3 = new AttachInfoList();
AttachVO test333 = new AttachVO("333", "test333");
List<AttachVO> list3 = new ArrayList<>();
list3.add(test333);
attachInfo3.setAttachVOList(list3);
List<AttachInfoList> attachInfoLists23 = new ArrayList<>();
attachInfoLists23.add(attachInfo2);
attachInfoLists23.add(attachInfo3);
base.setAttachInfos(attachInfoLists23);
//注解嵌套 -----paragraphVO
AttachInfoList attachInfo4 = new AttachInfoList();
AttachVO test444 = new AttachVO("444", "test444");
List<AttachVO> list4 = new ArrayList<>();
list4.add(test444);
attachInfo4.setAttachVOList(list4);
ParagraphVO paragraphVO = new ParagraphVO();
paragraphVO.setAttachInfoLists(attachInfo4);
base.setParagraphVO(paragraphVO);
dealAttachInfo(base, attachInfos);
System.out.println("数据附件提取:" + JSON.toJSON(attachInfos));
}
public static <T> void dealAttachInfo(T base, List<AttachInfoList> attachInfos) {
// 为空不处理
if (base == null) {
return;
}
// 对象是AttachInfoList,直接处理
if (base instanceof AttachInfoList) {
attachInfos.add((AttachInfoList) base);
return;
}
// 集合遍历处理
if (base instanceof List) {
Iterator it = ((List) base).iterator();
while (it.hasNext()) {
dealAttachInfo(it.next(), attachInfos);
}
} else {
//处理逻辑
Class<?> baseClass = base.getClass();
//遍历属性处理
Field[] fields = baseClass.getDeclaredFields();
try {
for (Field field : fields) {
String name = field.getName(); //属性名称
String getMethodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1); //获取该属性的方法名
Method method = baseClass.getMethod(getMethodName); //获取该属性的方法
Object obj = method.invoke(base); //该属性类型及值
//这个属性是AttachInfoList,那么直接封装禁attachInfos
if (obj == null) continue;
if (obj instanceof AttachInfoList) {
attachInfos.add((AttachInfoList) obj);
} else if (obj instanceof List && ((List) obj).size() > 0 && ((List) obj).get(0) instanceof AttachInfoList) {
attachInfos.addAll((List) obj);
} else {
//如果不是,继续查找注解,看看是否需要继续下钻
AttachAnnotion attachAnnotion = field.getDeclaredAnnotation(AttachAnnotion.class); //是否有文件注解
if (attachAnnotion != null) {
if (obj instanceof List) {
for (Object ob : (List) obj) {
dealAttachInfo(ob, attachInfos);
}
} else {
dealAttachInfo(obj, attachInfos);
}
}
}
}
} catch (Exception e) {
System.out.println("出现错误:" + e.getMessage() + " location:" + e.getLocalizedMessage());
}
}
}
}
给大家看下运行的结果:
com.example.demo.AnnoTest
数据附件提取:[{"attachVOList":[{"name":"test444","attachId":"444"}]},{"refId":"test111","attachVOList":[{"name":"test111","attachId":"111"}]},{"attachVOList":[{"name":"test222","attachId":"222"}]},{"attachVOList":[{"name":"test333","attachId":"333"}]}]
直接把代码全部复制过来了,这里我要说几点:一、这个逻辑我处理复杂了,其实不会出现这个:
//多个文件
private List<AttachInfoList> attachInfos;
因为AttachInfoList本身就是一个附件的集合,其中有一个关联的id,如果有多个,明显需要创建多个AttachInfoList,而不是再次集合到一起。代码中有些东西可以删掉,当然不处理也不会出问题,只是逻辑不走而已。
二、有些伙伴发现,哎?我不是用注解,只用反射,也能搞定啊!没错!是的,不使用注解也可以层层递归,获取到附件的信息,但是由于没有注解的标识,你会递归每个对象,不管这个对象有没有文件,这样,对性能来说就不太友好了,哪怕耗费的性能并不多。
三、这个其实只是把附件抽出来而已,如果要保存,还需要组装数据处理,注意refId 的关联创建等等,同时查询的时候似乎也可以对文件批量处理哦,有兴趣的小伙伴可以试下。