对于spring boot 使用@RestController 注解,使得controller 方法的返回结果最后会是json格式,但是json格式并不固定,如何才嫩定制呢?
由于本人未对spring mvc进行深度了解,不晓得spring是否是这样的扩展接口,也曾尝试通过看源码寻找,但是很遗憾并没有找到,
因此在这里提供一个个人看过源码后的一个小小的思路:
自定义一个HandlerMethodReturnValueHandler实现类,这是spring开放的扩展接口,用于处理controller返回结果,因此实现的目的是将结果封装成固定的对象,然后转成json,仅针对@RestController注解有效,其他注解则继续使用spring原生的默认机制
具体代码如下:
public class JsonResultReturnValueHandler implements HandlerMethodReturnValueHandler {
private static final Logger logger = LoggerFactory.getLogger(JsonResultReturnValueHandler.class);
@Override
public boolean supportsReturnType(MethodParameter returnType) {
Class cls = returnType.getContainingClass();
return cls.isAnnotationPresent(RestController.class);
}
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
mavContainer.setRequestHandled(true);
HttpServletRequest request = getNativeRequest(webRequest);
HttpServletResponse response = getNativeResponse(webRequest);
writeWithMessageConverters(returnValue, returnType, request, response);
}
private void writeWithMessageConverters(Object returnValue, MethodParameter returnType, HttpServletRequest request, HttpServletResponse response) {
JsonResult jr = JsonResultFactory.create(returnValue);
String rs = Utils.toJson(jr);
String encoding = request.getCharacterEncoding();
try {
response.setCharacterEncoding(encoding);
response.setContentType("text/html;charset=utf-8");
response.getWriter().write(rs);
response.getWriter().flush();
} catch (Exception e) {
logger.error("HttpServletResponse 写数据失败,ERROR:{}",e.getMessage(),e);
throw new BizException("Response 写数据失败",e);
} finally {
try {
response.getWriter().close();
} catch (Exception e) {
logger.error("[HttpResponse-ERROR-Witer close failure-ERRPR:{}]",e.getMessage(),e);
}
}
}
private HttpServletRequest getNativeRequest(NativeWebRequest webRequest){
return webRequest.getNativeRequest(HttpServletRequest.class);
}
private HttpServletResponse getNativeResponse(NativeWebRequest webRequest){
return webRequest.getNativeResponse(HttpServletResponse.class);
}
}
红色标记就是主要的代码,这里还有一个问题 ,spring默认将自定义的方法结果处理器放在最后的位置,而spring是按照顺序从前到后一次进行选择判断的,如果不将自定义放到第一个位置,则自定义的类将不会被选择到(仅针对此种方式实现,因未对spring做过度的修改,因此会有这样的问题),接下来就是要讲自定义的方法结果处理器设置到第一个位置,持有方法结果处理器的类,经过调试发现默认是RequestMappingHandlerAdapter,由于其属性final类型,不可修改且没有暴露修改接口,因此需要通过反射进行重新设置,
具体代码如下:
@Component
public class ApplicationContextExtension implements BeanFactoryPostProcessor {
private static final Logger logger = LoggerFactory.getLogger(ApplicationContextExtension.class);
private ConfigurableListableBeanFactory beanFactory;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
public void init() {
// RequestMappingHandlerAdapter 扩展
extensionRequestMappingHandlerAdapter();
}
private void extensionRequestMappingHandlerAdapter() {
logger.info("[自定义HandlerAdapter初始化.....]");
RequestMappingHandlerAdapter requestMappingHandlerAdapter = (RequestMappingHandlerAdapter) beanFactory.getBean("requestMappingHandlerAdapter");
handleRequestMappingHandlerAdapter(requestMappingHandlerAdapter);
}
private void handleRequestMappingHandlerAdapter(RequestMappingHandlerAdapter ha) {
try {
Field customReturnValueHandlersField = getField(ha.getClass(),"customReturnValueHandlers");
Field returnValueHandlersField = getField(ha.getClass(),"returnValueHandlers");
ReflectionUtils.makeAccessible(customReturnValueHandlersField);
ReflectionUtils.makeAccessible(returnValueHandlersField);
List<HandlerMethodReturnValueHandler> nativeCustomePropertyValue = (List<HandlerMethodReturnValueHandler>) ReflectionUtils.getField(customReturnValueHandlersField,ha);
HandlerMethodReturnValueHandlerComposite nativeDefaultPropertyValue = (HandlerMethodReturnValueHandlerComposite) ReflectionUtils.getField(returnValueHandlersField,ha);
if(Utils.isNotEmpty(nativeCustomePropertyValue)){
Field realField = getField(HandlerMethodReturnValueHandlerComposite.class,"returnValueHandlers");
ReflectionUtils.makeAccessible(realField);
List<HandlerMethodReturnValueHandler> realValue = (List<HandlerMethodReturnValueHandler>) ReflectionUtils.getField(realField,nativeDefaultPropertyValue);
for (HandlerMethodReturnValueHandler hma : nativeCustomePropertyValue){
if(realValue.contains(hma)){
realValue.remove(hma);
}
}
/**
* 因{@link HandlerMethodReturnValueHandlerComposite#returnValueHandlers}是final类型,因此new一个新对象替换
*/
HandlerMethodReturnValueHandlerComposite newHandlerComposite = new HandlerMethodReturnValueHandlerComposite();
newHandlerComposite.addHandlers(nativeCustomePropertyValue);// 自定义HandlerMethodReturnValueHandler
newHandlerComposite.addHandlers(realValue);// spring 默认HandlerMethodReturnValueHandler
ReflectionUtils.setField(returnValueHandlersField,ha,newHandlerComposite);
logger.info("[自定义HandlerAdapter初始化success");
}
} catch (Exception e) {
logger.error(ApplicationContextExtension.class.getName()+" extension failure,detail info is {}",e.getMessage(),e);
}
}
private Field getField(Class type,String fieldName) throws Exception {
return type.getDeclaredField(fieldName);
}
}
红色标记为主代码,
The End!