自定义统一api返回json格式(app后台框架搭建三)

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



时间: 2024-10-09 07:49:38

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

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

前几天没有写php代码,今天写了一下,今天的任务主要是构建自己的异常体系类,出现一个问题,就是返回结果不是json格式,而是一个页面,我找了一两个小时,没有找到问题,以为代码的问题,用断点调试了一通,最后居然是没有修改配置文件导致的,我居然把这个给忘记了. // 异常处理handle类 留空使用 \think\exception\Handle 'exception_handle' =>' ' 要是自己定义要就要把自己定义的目录填上去;

SpringMVC 统一返回JSON格式数据到前端

有时在给APP做接口功能的时候,都是返回JSON格式的数据,所以最好的只好在工程设置一个统一的数据返回方式 在SpringMVC 直接配置XML可以产生这种配置,比较简单 Spring的版本我用的是4.3.3的 <bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter&qu

web Api自定义部分Action的JSON格式输出

昨天项目中要部分Api的JSON格式需要特殊处理.最开始直接重写controller的JSON方法.经测试,当action直接返回数据的时候,不会调用Json方法. 然后找了各种方法,都不行.在群里问了.直到看到群友发的一个直接移除所有API的JSON格式方法的时候.图片如下: 然后就想到了Api的ActionFilterAttribute.就解决了自己的需求. 上代码.懒得写说明. 1 public class AppFilterAttribte : ActionFilterAttribute

ajax请求后台,返回json格式数据,模板!

添加一个用户的时候,需要找出公司下所有的部门,和相应部门下的角色,利用ajax请求,实现联动技术.将返回的json格式数据,添加到select标签下. <script type="text/javascript">        //加载出部门的信息            function loadGroup(){                            $.ajax({                    type:"post",  

webapi返回json格式优化

一.设置webapi返回json格式 在App_Start下的WebApiConfig的注册函数Register中添加下面这代码 config.Formatters.Remove(config.Formatters.XmlFormatter); 二.设置返回Json键值统一为小写 新建一个类并继承自DefaultContractResolver,重写ResolvePropertyName方法, public class UnderlineSplitContractResolver : Defau

SpringMVC通过实体类返回json格式的字符串,并在前端显示

一.除了搭建springmvc框架需要的jar包外,还需要这两个jar包 jackson-core-asl-1.9.2.jar和jackson-mapper-asl-1.9.2.jar 二.web,.xml配置 classpath:spring-servlet.xml指定springmvc配置文件的位置 <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" x

Spring Cloud Spring Boot mybatis分布式微服务云架构 返回JSON格式

在上述例子中,通过@ControllerAdvice统一定义不同Exception映射到不同错误处理页面.而当我们要实现RESTful API时,返回的错误是JSON格式的数据,而不是HTML页面,这时候我们也能轻松支持. 本质上,只需在@ExceptionHandler之后加入@ResponseBody,就能让处理函数return的内容转换为JSON格式. 下面以一个具体示例来实现返回JSON格式的异常处理. 创建统一的JSON返回对象,code:消息类型,message:消息内容,url:请

MVC web api 返回JSON的几种方式,JSON时间去T的几种方式。

MVC web api 返回JSON的几种方式 1.在WebApiConfig的Register中加入以下代码 1 config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html")); 2.在WebApiConfig的Register中加入以下代码 1 config.Formatters.Remove(config.Formatters.XmlFormatter);

如何让Asp.net webAPI返回JSON格式数据

ASP.NET Web API 是新一代的 HTTP 網路服務開發框架,除了可以透過 Visual Studio 2012 快速開發外 (內建於 ASP.NET MVC 4 的 Web API 專案範本內),也非常適合用於各種跨平台的行動裝置上,如果你想開發 RESTful 應用程式,那麼使用 ASP.NET Web API 應該是挺理想的解決方案.不過 ASP.NET Web API 內建支援 JSON 與 XML 兩種輸出格式,並依據瀏覽器端送出的 Accept 標頭自動決定回應的內容格式,