1. 场景
在springmvc 的controller需要统一的返回接口,比如:需要在后台所有接口返回统一的json字符串。可以通过自定义注解,通过 HandlerMethodReturnValueHandler 对返回值的处理,该接口会在返回值之前,执行该接口的内部逻辑。
假设现在想返回一个接送字符串。格式:
{
status: 200
code : success
data :{
age: 100,
name : 小明
}
}
1. 创建返回结果类
public class ResponseResult<T> {
public Integer status;
public String code;
public T data;
// 构造 setter...
}
1. 创建一个返回结果的自定义注解包装类:
public @Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ResponseJson{
public String className() default "ResponseResult"; // 全路径名
}
2. 定义controller 逻辑,假设有如下一个接口,我们需要对返回值进行包装成ResponseResulltJson结构,加上自定义注解。
@ResponseResulltJson
@GetMapping(“/test”)
public Student test(@RequestParam(value="name") String name){
// 处理逻辑
Student student = new Student();
student.setName(name);
return student;
}
- 创建HandlerMethodReturnValueHandler接口实现类,下面的o就是上面test接口的返回值。
public class ExampleHandler implements HandlerMethodReturnValueHandler {
@Override
publicboolean supportsReturnType(MethodParameter methodParameter) {
return methodParameter.hasMethodAnnotation(ResponseJson.class);
}
@Override
public void handleReturnValue(Object o, MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,
NativeWebRequest nativeWebRequest)throws Exception {
HttpServletResponse response =
nativeWebRequest.getNativeResponse(HttpServletResponse.class);
response.setConentTpye(MediaType.APPLICATION_JSON_VALUE);
response.setCharactrer("UTF-8");
ResponseJson json = methodParameter.getAnnation(ResponseJson .class);
// 得到需要反射类对象,即结果类
Class responseResult= json.className();
// 通过反射从构造放入注入,需要注意,通过构造器注入的参数和newInstance传入的必须一致。
Object rp = Class.forName(responseResult).getConstrtor(Object.class).newInstance(o);
// 通过guava中Gson来json化,或者FastJson
Gson gson = new GSon();
response.getWriter().write(gson.toJson(rp));
}
}
4. 把上面的的handler添加进RequestMappingHandlerAdapter适配器中
public class RequestMappingHandlerAdapterWrapper{
@Autowired
private RequestMappingHandlerAdapter handlerAdapter;
@PostConstruct
public void register(){
handlerAdapter.setReturnValueHandlers(new ArrayList<RequestMappingHandlerAdapter >({{
this.add(new ExampleHandler ());
this.addAll(RequestMappingHandlerAdapterWrapper.this.handlerAdapter.[getReturnValueHandlers](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.html#getReturnValueHandlers--)());
}}))
}
}
为什么上面这样写就可以在Controller中的返回结果调用到这个处理器。
在RequestMappingHandlerAdapter中实现了InitializingBean这个接口,该接口具有唯一的函数AfterPropertiesSet(),意思是在容器启动时,会调用这个方法,该方法主要设置了一些默认的handlers,在初始化方法中主要有三种,@PostContruct、xml的init-method,实现InitalizingBean接口。这三种的执行顺序时@PostContruct、InitalizingBean、init-method,因此上面的register会先于AfterPropertiesSet方法执行,自然可以在设置默认的handler时起作用。
Data:2019/3/10