• 自定义统一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上并快速启动。



  • 相关阅读:
    学习小记: Kaggle Learn
    eclipse 一些快捷键
    Map接口
    学习笔记
    泛型方法 类 接口
    TreeSet
    xml
    Java笔试题目-my
    迭代器三种遍历方法
    线程请求其他线程资源
  • 原文地址:https://www.cnblogs.com/minsons/p/7101788.html
Copyright © 2020-2023  润新知