zoukankan      html  css  js  c++  java
  • SpringBoot(四)HandlerMethodReturnValueHandler

    你可能会有这样的需求,对你的Controller返回值进行一个二次封装,
    如下:code是结果码(1、成功,0、失败,2、未登录...),data为携带数据

    {"code":"1","data":{"name":"xiaoming","age":"30"}}


    在代码中的使用效果如下,添加一个自定义注解ResponseData,自动地就把数据封装成上面的格式

    @Controller
    public class Core {
    
        @ResponseData
        @RequestMapping("/data")
        public Map<String, Object> data() {
            Map<String,Object> res = new HashMap<>();
            res.put("name","xiaoming");
            res.put("age","30");
            return res;
        }
    }

    HandlerMethodReturnValueHandler

    这个接口的名字有点怪,处理函数返回值的处理器?姑且叫他返回值处理器吧,

    这是一个处理Controller返回值的接口,比如我们熟悉的ResponseBody注解,使用下面的代码就能简单地实现,
    这个切面的缺点是:如果函数没有返回值时,这个接口的代码就不会执行,如果通过其他方式传递返回值,用这个接口会觉得不习惯。

    import com.alibaba.druid.support.json.JSONUtils;
    import org.springframework.core.MethodParameter;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.context.request.NativeWebRequest;
    import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
    import org.springframework.web.method.support.ModelAndViewContainer;
    
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * Created by 12614 on 2018/5/11.
     */
    public class Example implements HandlerMethodReturnValueHandler {
        @Override
        public boolean supportsReturnType(MethodParameter methodParameter) {
            return methodParameter.hasMethodAnnotation(ResponseBody.class);
        }
    
        @Override
        public void handleReturnValue(Object o, MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, 
        NativeWebRequest nativeWebRequest) throws Exception { //TODO .setRequestHandled(true)表示此函数可以处理请求,不必交给别的代码处理 //E.G. modelAndViewContainer.setRequestHandled(true); nativeWebRequest .getNativeResponse(HttpServletResponse.class) .getWriter() .write(JSONUtils.toJSONString(o)); } }

    Spring配置

    <mvc:annotation-driven>  
        <mvc:return-value-handlers>  
            <bean class="xxxx全类名"></bean>  
        </mvc:return-value-handlers>  
    </mvc:annotation-driven>

    SpringBoot配置

    因为在SpringBoot下,默认的ResponseBody处理类就是HandlerMethodReturnValueHandler,此处理器的优先级比我们新添加的实现类高,

    WebMvcConfigurerAdapter 中配置HandlerMethodReturnValueHandler,代码其实是并不生效,

    如果你希望添加额外的返回值处理器,需要做的是改造默认的处理类(如果直接替换默认的处理类,原先的ResponseBody的处理逻辑将出错)。

    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    
    import java.util.List;
    
    /**
     * Created by 12614 on 2018/5/11.
     */
    @Configuration
    public class ApplicationConfigurer extends WebMvcConfigurerAdapter {
        @Override
        public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
            super.addReturnValueHandlers(returnValueHandlers);
            returnValueHandlers.add(new Example());
        }
    }

    RequestResponseBodyMethodProcessor是ResponseBody的默认处理程序,如果不是十分清楚它的作用,不希望改动任何默认处理逻辑,

    可以建立一个静态代理类,代码如下:

    import org.springframework.core.MethodParameter;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.support.WebDataBinderFactory;
    import org.springframework.web.context.request.NativeWebRequest;
    import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
    import org.springframework.web.method.support.ModelAndViewContainer;
    import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * Created by 12614 on 2018/5/11.
     */
    public class TestReturnValueHandler implements HandlerMethodReturnValueHandler {
        private RequestResponseBodyMethodProcessor target;
    
        public TestReturnValueHandler(RequestResponseBodyMethodProcessor target) {
            this.target = target;
        }
    
        @Override
        public boolean supportsReturnType(MethodParameter methodParameter) {
            System.out.println("TestReturnValueHandler:supportsReturnType");
            //我添加了一个自定义注解ResponseData,不知道怎么写可以直接复制ResponseBody源码
            return methodParameter.hasMethodAnnotation(ResponseData.class)||
                    methodParameter.hasMethodAnnotation(ResponseBody.class);
        }
    
        @Override
        public void handleReturnValue(Object o, MethodParameter methodParameter,
                                      ModelAndViewContainer modelAndViewContainer,
                                      NativeWebRequest nativeWebRequest) throws Exception {
            System.out.println("TestReturnValueHandler:handleReturnValue");
            if(methodParameter.hasMethodAnnotation(ResponseData.class)){
                //如果Controller中使用了我的自定义注解,那么对返回值进行封装
                Map<String,Object> res = new HashMap<>();
                res.put("code","1");
                res.put("data",o);
                target.handleReturnValue(res,methodParameter,modelAndViewContainer,nativeWebRequest);
            } else {
                target.handleReturnValue(o,methodParameter,modelAndViewContainer,nativeWebRequest);
            }
        }
    
        public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                      NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
            return target.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
        }
    }

    替换SpringBoot中HandlerMethodReturnValueHandler的默认实现类,需要在Spring中找到合适的切面,

    InitializingBean在执行完所有属性设置方法(即setXxx)将被自动调用,正好满足我们的需求,在InitializingBean中编辑我们的代码即可,代码如下:

    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
    import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
    import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 初始化切面
     *
     * Created by 12614 on 2018/5/11.
     */
    @Configuration
    public class InitializingAdvice implements InitializingBean {
    
        @Autowired
        private RequestMappingHandlerAdapter adapter;
    
        @Override
        public void afterPropertiesSet() throws Exception {
            List<HandlerMethodReturnValueHandler> returnValueHandlers = adapter.getReturnValueHandlers();
            List<HandlerMethodReturnValueHandler> handlers = new ArrayList(returnValueHandlers);
            this.decorateHandlers(handlers);
            adapter.setReturnValueHandlers(handlers);
        }
    
    
        private void decorateHandlers(List<HandlerMethodReturnValueHandler> handlers) {
            for (HandlerMethodReturnValueHandler handler : handlers) {
                if (handler instanceof RequestResponseBodyMethodProcessor) {
                    TestReturnValueHandler decorator = new TestReturnValueHandler(
                            (RequestResponseBodyMethodProcessor) handler);
                    int index = handlers.indexOf(handler);
                    handlers.set(index, decorator);
                    break;
                }
            }
        }
    }
  • 相关阅读:
    Construct Binary Tree from Preorder and Inorder Traversal
    Construct Binary Tree from Inorder and Postorder Traversal
    Maximum Depth of Binary Tree
    Sharepoint 2013 创建TimeJob 自动发送邮件
    IE8 不能够在Sharepoint平台上在线打开Office文档解决方案
    TFS安装与管理
    局域网通过IP查看对方计算机名,通过计算机名查看对方IP以及查看在线所有电脑IP
    JS 隐藏Sharepoint中List Item View页面的某一个字段
    SharePoint Calculated Column Formulas & Functions
    JS 两个一组数组转二维数组
  • 原文地址:https://www.cnblogs.com/chenss15060100790/p/9095496.html
Copyright © 2011-2022 走看看