在统一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上并快速启动。



自定义统一api返回json格式(app后台框架搭建三)的更多相关文章

  1. 整合springboot(app后台框架搭建四)

    springboot可以说是为了适用SOA服务出现,一方面,极大的简便了配置,加速了开发速度:第二方面,也是一个嵌入式的web服务,通过jar包运行就是一个web服务: 还有提供了很多metric,i ...

  2. springmvc跨域+token验证(app后台框架搭建二)

    这是app后台框架搭建的第二课,主要针对app应用是跨域的运用,讲解怎么配置跨域服务:其次讲解怎么进行token验证,通过拦截器设置token验证和把token设置到http报文中.主要有如下:   ...

  3. ajax请求正常,返回json格式,后台没问题,浏览器500

    1.使用的是springmvc中的 @ResponseBody 注解   ,后台不报错,.正常走完:以为使用这个注解就可以正常返回json格式的数据:所以一直没有怀疑是注解的问题: 以为是ajax本身 ...

  4. thinkphp5.0--编写api,返回json格式

    前几天没有写php代码,今天写了一下,今天的任务主要是构建自己的异常体系类,出现一个问题,就是返回结果不是json格式,而是一个页面,我找了一两个小时,没有找到问题,以为代码的问题,用断点调试了一通, ...

  5. spring4+srpingmvc+mybatis基本框架(app后台框架搭建一)

    前言: 随着spring 越来越强大,用spring4来搭建框架也是很快速,问题是你是对spring了解有多深入.如果你是新手,那么在搭建的过程中可以遇到各种各样奇葩的问题. SSM框架的搭建是作为我 ...

  6. spring4+springmvc+mybatis基本框架(app后台框架搭建一)

    前言: 随着spring 越来越强大,用spring4来搭建框架也是很快速,问题是你是对spring了解有多深入.如果你是新手,那么在搭建的过程中可以遇到各种各样奇葩的问题. SSM框架的搭建是作为我 ...

  7. .NetCore Web Api 利用ActionFilterAttribute统一接口返回值格式

    .Net Core 同 Asp.Net MVC一样有几种过滤器,这里不再赘述每个过滤器的执行顺序与作用. 在实际项目开发过程中,统一API返回值格式对前端或第三方调用将是非常必要的,在.NetCore ...

  8. 3.自定义返回json格式的数据给前台(自定义Controller类中的Json方法)

    在mvc的项目中,我们前台做一些操作时,后台要返回一些结果给前台,这个时候我们就需要有一个状态来标识到底是什么类型的错误, 例如: 执行删除的时候,如果操作成功(1行受影响),我们需要返回状态为1并输 ...

  9. ASP.NET Web API 2 返回 Json格式

    最近在学习ASP.NET的Web API,刚刚开始以为会有些复杂,结果却非常简单. 学习的地址:http://www.asp.net/web-api/overview/getting-started- ...

随机推荐

  1. 数据库的优化(表优化和sql语句优化)

    在这里主要是分为表设计优化和sql语句优化两方面来实现. 首先的是表设计优化: 1.数据行的长度不要超过8020字节.如果是超过这个长度的话这条数据会占用两行,减低查询的效率. 2.能用数字类型就不要 ...

  2. 如何抽象一个 Vue 公共组件

    之前一直想写一篇关于抽象 Vue 组件的随笔,无奈一直没想到好的例子.恰巧最近为公司项目做了一个数字键盘的组件,于是就以这个为例聊聊如何抽象 Vue 的组件. 先上 Demo 与 源码.(demo最好 ...

  3. python之集合

    集合(set),它是一个无序的,不重复的数据组合,它是作用如下: 1.去重,也就是去除重复的内容.有一点值得注意的是:将一个列表(list)变成集合的时候,会自动去重. 2.关系测试.测试数据之间的交 ...

  4. JavaScript函数之作用域 / 作用链域 / 预解析

    关于作用域和作用链域的问题,很多文章讲的都很详细,本文属于摘录自己觉得对自己有价值的部分,留由后用,仅供参考,需要查看详细信息请点击我给出的原文链接查看原文件 做一个有爱的搬运工~~ -------- ...

  5. Linux下PHP连接MS SQLServer的办法

    Linux下PHP连接MS SQLServer的办法分析问题 本来PHP脚本读写SQLServer是没有什么问题的,在Apache for windows和Windows IIS下可以工作的很好,一般 ...

  6. shell编程/字库裁剪(2)——编程过程

    版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖.如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/7704085.html 作者:窗户 Q ...

  7. 最全的命令行(gradle)打包安卓apk

    最近研究安卓方面的打包,因为是React Native,不能使用Android studio打包.找了半天资料,发现没有一个全面的.下面,我来讲解自己下打包时自己遇到的各种坑. 1.首先,需要在项目顶 ...

  8. ios 类的内部结构

    1. Class 和 Object 的定义 /// An opaque type that represents an Objective-C class. typedef struct objc_c ...

  9. Vue源码后记-更多options参数(2)

    写起来感觉都是老三套,AST => render => VNode => patch 之前是把AST弄完了,对事件和过滤器处理如图: render函数也只看这两部分的转换吧! 首先是 ...

  10. 探究Angular依赖注入对象$injector

    $injector其实是一个IOC容器,包含了很多我们通过.module()和$provide创建的模块和服务.$injector服务提供了对依赖注入器对象的访问,当然我们也可以调用angular.i ...