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;
                }
            }
        }
    }
  • 相关阅读:
    ES6:Iterator遍历器
    前端:对BFC的理解
    前端:性能优化之防抖与节流
    ES6新增数据类型Symbol
    ajax和fetch、aixos的区别
    我对js数据类型的理解和深浅(copy)的应用场景
    egg的基本使用
    前端:css3的过渡与动画的基础知识
    Java基础篇之类
    JAVA基础篇之Scanner
  • 原文地址:https://www.cnblogs.com/chenss15060100790/p/9095496.html
Copyright © 2011-2022 走看看