SpringMVC内容协商-扩展参数解析-2

SpringMVC内容协商-扩展参数解析-2

在上一篇SpringMVC内容协商-扩展参数解析中利用SpringBoot提供的钩子,实现了请求入参和返参的数据解析,但是可以看到我们依赖的是RequestResponseBodyMethodProcessor,这就要求我们在方法体上和参数上添加@ResponseBody@RequestBody标签,但是如果我们不依赖这两个标签要如何实现呢?

过程

按照之前的思路,我们应该直接去扩展HandlerMethodArgumentResolverHandlerMethodReturnValueHandler 而不依赖于SpringMVC为我们提供的类,但是如何扩展?

在上一篇中,我们是利用SpringBoot提供的SpringMVC自动配置来完成,我们可以在去查看一下是否有提供类似的可配置的钩子。我们到WebMvcConfigurer里查看,发现确实有一个这样的函数。

	default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {}
	default void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers{}

但是在使用时我们可以发现这两个函数的注释

does not override the built-in support for resolving handler method arguments.

这说明我们无法覆盖内建的解析器,意思是假使我们添加了自己解析器,但是解析器的顺序无法排在框架里自带的解析器。举个例子,如果我们实现了一个Json数据解析器,但是使用这个配置添加到了SpringMVC中,在匹配合适的解析器的时候还是会使用自带的,因为自带的排在我们自己编写类的前面,所有优先选择。现在我们的目标是扩展编写Properties的解析类,但是Properties可以被Json数据解析器解析,所以我们就不能使用这种方式。

怎么做?我们目标就是把框架里的解析器列表取出来,然后把我们自己编写的解析器放到第一个,之后就不会匹配到自带的了。

  • 首先我们先要知道这个解析器列表在那里,所以我们断点在DispatcherServletHandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); 中查看是哪一个子类适配。运行之后发现是RequestMappingHandlerAdapter
  • 之后我们进入RequestMappingHandlerAdapter可以发现里面提供了get/setArgumentResolversget/setReturnValueHandlers两个方法,所以我们可以取出来之后把我们的实现类设置到第一个

实现

接着我们上篇的代码

创建自己的入参和返参解析类,解析类只要实现HandlerMethodArgumentResolverHandlerMethodReturnValueHandler 两个接口即可。

  • 入参
package com.hwk.springmvc.web.servlet.handler;
import com.hwk.springmvc.http.converter.properties.PropertiesHttpMessageConverter;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import javax.servlet.http.HttpServletRequest;
import java.util.Properties;
public class PeopertiesHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        //说明支持的类型
        return Properties.class.equals(parameter.getParameterType());
    }
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        //在这里做处理
        ServletWebRequest servletWebRequest = (ServletWebRequest) webRequest;
        //Servlet Request API 获取到原生的请求
        HttpServletRequest request = servletWebRequest.getRequest();

        PropertiesHttpMessageConverter converter = new PropertiesHttpMessageConverter();

        HttpInputMessage inputMessage = new ServletServerHttpRequest(request);
		
        return converter.read(null, null, inputMessage);
    }
}

  • 返参
package com.hwk.springmvc.web.servlet.handler;
import com.hwk.springmvc.http.converter.properties.PropertiesHttpMessageConverter;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Properties;
public class PropertiesHandlerMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return Properties.class.equals(returnType.getParameterType());
    }

    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType,
                                  ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest) throws Exception {

        Properties properties = (Properties) returnValue;
        PropertiesHttpMessageConverter converter = new PropertiesHttpMessageConverter();

        //在这里做处理
        ServletWebRequest servletWebRequest = (ServletWebRequest) webRequest;
        //Servlet Request API 获取到原生的请求
        HttpServletRequest request = servletWebRequest.getRequest();

        //获取媒体类型
        String contentType = request.getHeader("Content-Type");

        MediaType mediaType = MediaType.parseMediaType(contentType);
        //获取Response
        HttpServletResponse response = servletWebRequest.getResponse();
        HttpOutputMessage message = new ServletServerHttpResponse(response);
        converter.write(properties, mediaType, message);
        //通知SpringMVC 已经处理完成
        mavContainer.setRequestHandled(true);
    }
}

接下去就是如何配置到SpringMVC中了。由于RequestMappingHandlerAdapter也是一个Bean,所以我们直接使用自动注入的方式取到,然后获取解析列表,添加我们自己的解析器就可以了。

package com.hwk.springmvc.config;

import com.hwk.springmvc.web.servlet.handler.PeopertiesHandlerMethodArgumentResolver;
import com.hwk.springmvc.http.converter.properties.PropertiesHttpMessageConverter;
import com.hwk.springmvc.web.servlet.handler.PropertiesHandlerMethodReturnValueHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

@Configuration
public class RestWebMvcConfigurer implements WebMvcConfigurer {
    @Autowired
    private RequestMappingHandlerAdapter requestMappingHandlerAdapter;

    @PostConstruct
    public void init(){
        //获取当前RequestMappingHandlerAdapter
        List<HandlerMethodArgumentResolver> resolvers = requestMappingHandlerAdapter.getArgumentResolvers();
        //因为resolvers是不可变的  所有需要创建一个容器在添加我们自定义的Resolver
        List<HandlerMethodArgumentResolver> newResolvers = new ArrayList<>(resolvers.size() + 1);
        //添加自定义Resolver
        newResolvers.add(new PeopertiesHandlerMethodArgumentResolver());
        //添加之前容器存在的Resolver
        newResolvers.addAll(resolvers);
        requestMappingHandlerAdapter.setArgumentResolvers(newResolvers);

        List<HandlerMethodReturnValueHandler> returnValueHandlers = requestMappingHandlerAdapter.getReturnValueHandlers();
        List<HandlerMethodReturnValueHandler> newReturnValues = new ArrayList<>();
        newReturnValues.add(new PropertiesHandlerMethodReturnValueHandler());
        newReturnValues.addAll(returnValueHandlers);
        requestMappingHandlerAdapter.setReturnValueHandlers(newReturnValues);
    }
}

之后我们取到两个注解在此运行也是可以成功的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值