我目前使用的项目是基于springboot的,但是还有很多人是基于spring的,这里分别给出这两种实现的方式.
然后我们复写该类的#
configureMessageConverters#
方法
public void configureMessageConverters(List<HttpMessageConverter>> converters) {
}
这个类用来配置消息转换的方法,我没有去看这个源码,但是这个应该是一个职责链模式.通过这个类我们可以添加一个我们自己的消息处理类
,或者只使用我们自己的消息处理类.
这里,我只是需要添加一个自己的消息处理类,所以,通过.
converters.add(new OSSFileURLMessageConverter());
来添加一个消息处理的流程.这里的
OSSFileURLMessageConverter
对象是我们自定义的一个消息处理类,下文会提到.
这样,我们就可以将我们在
OSSFileURLMessageConverter
里实现我们自己的处理逻辑了.
基于springmvc自定义message处理的方法.
如果是基于配置文件的话,我们可以配置一个消息转换类,下面是我之前项目中写的一段配置
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="mappingJacksonHttpMessageConverter"/>
list>
property>
bean>
<bean id="mappingJacksonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8value>
<value>application/json;charset=UTF-8value>
list>
property>
bean>
我们可以写一个类继承
MappingJacksonHttpMessageConverter类,
然后重写
writeInternal方法,在这个方法里面实现自己的业务逻辑.
ok,上面都是如何将消息交给spring,下面是具体的内容.
第一步,是先写一个类,这个类用来处理自定义注解,类里面主要有三个方法.
第一个方法用来处理自定义注解.
第二个方法用来筛选类, 让第一个方法只处理真正可能会有自定义注解类.
第三个方法,是针对第二个方法,进行再次筛选,确保没有遗漏.
下面是具体的代码.
核心逻辑
首先我们需要筛选一下需要处理的类,确保类似于第三方jar之类的类不会被处理,以免造成资源浪费.
public void strategy(Object object){
if (object instanceof Collection){
//删选集合
for (Object obj:(Collection)object){
//递归筛选集合内的实体
strategy(obj);
}
}else if (object instanceof Map){
//筛选Map
Set kyes=((Map) object).keySet();
for (Object key:kyes){
strategy(((Map) object).get(key));
}
}else if (object instanceof ExecuteResult){
Object obj=((ExecuteResult) object).getResult();
if (obj==null){
return;
}
strategy(obj);
}else if (object instanceof PageInfo){
//筛选分页
Object obje=((PageInfo) object).getList();
if (obje==null){
return;
}
strategy(obje);
}else if (object.getClass().getPackage().getName().indexOf(BASE_PACKAGE)!=-1){
//这一步,筛选出需要特殊处理的类
//到这一步,需要进行特殊处理的均已处理完毕,接下来,我们处理普通对象
//这一步,可以保证获取到的对象,没有特殊处理的对象,但是不保证对象的字段没有需要特殊处理的字段.
dispose(object);
}
else {
//忽略掉其余类
return;
}
}
PS:dispose(Object object)方法会在下面给出.
上面代码注释中已经给出了逻辑.里面的ExecuteResult类是自己封装的消息返回实体,所以需要特殊,而PageInfo是mybatis插件PageHelp的分页类,所以也需要特殊处理.
上面还用到了一个常量,BASE_PACKAGE,这个常量的作用是限制处理类所处包的范围,毕竟,我们需要使用自定义注解的地方,往往都是自己的实体类对象,所以,通过这一层可以进一步的限制处理类的范围.
到这一步的话,我们已经初步筛选了实体类,但是这时候还会有遗漏,因为很可能在其他类中可能含有我们要处理的类的对象,所以我们还需要进一步筛选.
private void dispose(Object object){
//标准流程,获取所有字段,然后依次遍历
Field[] fields=object.getClass().getDeclaredFields();
for (Field field:fields){
//先放开该字段的权限
field.setAccessible(Boolean.TRUE);
//处理该字段
doHandler(field,object);
//再次将字段的数据交给strategy方法,递归可以保证,没有遗漏的字段
//因为strategy给出了跳出条件,所以,不会处理非指定类,也不会造成死循环
try {
//先判断字段内容是否有值,如果没有值,则跳过
Object fieldValue=field.get(object);
if (fieldValue==null){
continue;
}
strategy(field.get(object));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
PS,doHandler(field,Object)方法是处理业务逻辑的地方,下文将会给出示例.
这样,我们就通过递归的方法完成了筛选,而且确保了没有遗漏的字段.上面这些部分都是一些通用的地方,主要目的就是限制处理的类和确保没有遗漏,这一部分可以抽取出来,作为模板方法来使用.
最后面其实相对来说是最不重要也是最重要的地方,实现业务逻辑,我这里逻辑比较简单,就是看看字段上面有没有@ImageUrl注解,有的话,就添加上OSS域名.
private void doHandler(Field field,Object obj){
//获取标注了ImageURL注解的字段
if (field.isAnnotationPresent(ImageURL.class)){
String suffix= field.getAnnotation(ImageURL.class).param();
//修改字段访问权限
field.setAccessible(Boolean.TRUE);
try {
//填充内容
field.set(obj, PropertiesConstans.IMAGE_PREFIX +field.get(obj)+ suffix);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
通过这种方式,就比较简单的实现了在返回json的时候,进行一些自定义处理的功能了.
这个方法还是能扩展的,比如,统一处理时间戳之类的.
修订记录
2017年8月1日,修改了方法中一个错误,这个错误会导致出现部分字段不处理.