在统一json自定义格式的方式有多种:1,直接重写@reposeBody的实现,2,自定义一个注解,自己去解析对象成为json字符串进行返回
第一种方式,我就不推荐,想弄得的话,可以自己去研究一下源码
第二种方式,主要通过定义注解,通过 HandlerMethodReturnValueHandler 对返回值的处理,而不让他进去viewResolver处理
==================================================================================
1,讲解HandlerMethodReturnValueHandler 处理原理 (简单介绍,网上资料很多)
2,如何实现自定义统一的json返回格式
==================================================================================
1,HandlerMethodReturnValueHandler
HandlerMethodReturnValueHandler是RequestMappingHandlerAdapter用来处理完映射控制类方法返回的值处理,RequestMappingHandlerAdapter
类包含默认的值处理器链的所有处理引擎,默认是会加入handlers.add(new ModelAttributeMethodProcessor(true)); getDefaultReturnValueHandlers()方法里可以查看到所有默认的处理引擎。
对处理后的对象,会调用RequestMappingHandlerAdapter里invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod)
方法:
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); try { WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); invocableMethod.setDataBinderFactory(binderFactory); invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); ModelAndViewContainer mavContainer = new ModelAndViewContainer(); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); modelFactory.initModel(webRequest, mavContainer, invocableMethod); mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response); asyncWebRequest.setTimeout(this.asyncRequestTimeout); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.setTaskExecutor(this.taskExecutor); asyncManager.setAsyncWebRequest(asyncWebRequest); asyncManager.registerCallableInterceptors(this.callableInterceptors); asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors); if (asyncManager.hasConcurrentResult()) { Object result = asyncManager.getConcurrentResult(); mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0]; asyncManager.clearConcurrentResult(); if (logger.isDebugEnabled()) { logger.debug("Found concurrent result value [" + result + "]"); } invocableMethod = invocableMethod.wrapConcurrentResult(result); } invocableMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null; } return getModelAndView(mavContainer, modelFactory, webRequest); } finally { webRequest.requestCompleted(); } }
关键是调用 invocableMethod.invokeAndHandle(webRequest, mavContainer);
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); setResponseStatus(webRequest); if (returnValue == null) { if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) { mavContainer.setRequestHandled(true); return; } } else if (StringUtils.hasText(getResponseStatusReason())) { mavContainer.setRequestHandled(true); return; } mavContainer.setRequestHandled(false); try { this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex); } throw ex; } }
首先设置 mavContainer.setRequestHandled(false);说明是会按处理链进行处理,如果设置为true就是处理完就结束了。
this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); 是真正获取处理链,然后从处理链中选择合适的引擎并依次处理。
HandlerMethodReturnValueHandler 只提供两个接口,
public interface HandlerMethodReturnValueHandler { boolean supportsReturnType(MethodParameter returnType); void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception; }
第一方法是判断是否支持值处理引擎,第二方法是对值进行处理,并确定是否继续进行下一个处理引擎执行。
所以,第一个supportsReturnType(MethodParameter returnType)的判断一定要正确,如果不正确,就永远不会被执行,这是关键。
具体的执行,就可以按这几个关键的类去debug一下就可以了。
-----------------------------------------------------------------------------------------------------------------
2, 具体的实现
2.1 定义注解:用于识别json转换处理的
import java.lang.annotation.*; /** * Created by ThinkPad on 2017/6/22. */ @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface AppResponsBody { String type() default "json"; }
2.2 处理引擎的:需要实现 HandlerMethodReturnValueHandler
/** * Created by ThinkPad on 2017/6/22. */ public class FormatJsonReturnValueHandler implements HandlerMethodReturnValueHandler{ @Override public boolean supportsReturnType(MethodParameter returnType) { System.out.println("===========sdfdsf==============="+ returnType.getMethodAnnotation(AppResponsBody.class)); boolean hasJSONAnno = returnType.getMethodAnnotation(AppResponsBody.class) != null || returnType.getMethodAnnotation(AppResponsBody.class) != null; return hasJSONAnno; } @Override public void handleReturnValue(Object obj, MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest) throws Exception { modelAndViewContainer.setRequestHandled(true); AppResponsBody res=methodParameter.getMethodAnnotation(AppResponsBody.class); String type = res.type(); HttpServletResponse response=nativeWebRequest.getNativeResponse(HttpServletResponse.class); response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); PrintWriter writer = null; Gson gson=new Gson(); ResultInfo info=new ResultInfo(); info.setData(obj); try { writer = response.getWriter(); writer.write(gson.toJson(info)); writer.flush(); } catch (IOException ex) { ex.printStackTrace(); } finally { if (writer != null) writer.close(); } } }
2.3 注册你编写的HandlerMethodReturnValueHandler引擎 到webConfig配置文件里
@Configuration @EnableWebMvc @ComponentScan(basePackages = {"com.ouyang.teson"},useDefaultFilters = true) public class WebConfig extends WebMvcConfigurerAdapter{
配置文件里增加以下:
@Bean public FormatJsonReturnValueHandler JsonReturnHandler(){ FormatJsonReturnValueHandler formatJsonReturnValueHandler=new FormatJsonReturnValueHandler(); return formatJsonReturnValueHandler; } @Override public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) { returnValueHandlers.add(JsonReturnHandler()); }
另外,还需要定义一个响应类处理统一格式的:ResultInfo.java
public class ResultInfo { public long code; public String message; public Object data; public long getCode() { if(code==0l){ code=200l; } return code; } public void setCode(long code) { this.code = code; } public String getMessage() { if(message==null){ message="处理成功!"; } return message; } public void setMessage(String message) { this.message = message; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } }
至此,我们的所有工作完成,接着进行测试操作:
浏览测试结果:
注意:
如果中途有什么问题,自己可以debug以下,用intellij可以很方便的下载源码,直接debug,这一点很不错,这也没有什么难度。
下一节,要讲的就是怎么使用spring-boot快速搭建api后台框架,即是把该配置迁移到spring-boot上并快速启动。