当前位置:   article > 正文

SpringMvc学习笔记---- 参数解析器和返回值处理器配置_spring返回值处理器

spring返回值处理器

SpringMVC学习笔记

参数解析器和返回值处理器配置

根据之前的配置逻辑整理出SpringMVC配置逻辑的关系图,再了解一下参数解析器和返回值处理器,配置自定义的参数处理器。

在这里插入图片描述

返回值处理器

返回值处理器用来对handler执行后的结果进行加工,一个典型的应用为含有@ResponseBody注解的方法被返回值处理器转成json形式。

在ServletInvocableHandlerMethod#invokeAndHandle的方法中找到对返回值处理器的调用。

匹配返回值处理器的逻辑和之前组件的匹配类似,具体为HandlerMethodReturnValueHandlerComposite中维护了HandlerMethodReturnValueHandler接口实现类的集合,依次匹配集合中的每个实现类,直到匹配成功后即停止。每个实现的返回值处理器有supportsReturnType和handleReturnValue方法。前者来匹配,后者在匹配成功进行返回值处理。

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()) {
				disableContentCachingIfNecessary(webRequest);
				mavContainer.setRequestHandled(true);
				return;
			}
		}
		else if (StringUtils.hasText(getResponseStatusReason())) {
			mavContainer.setRequestHandled(true);
			return;
		}

		mavContainer.setRequestHandled(false);
		Assert.state(this.returnValueHandlers != null, "No return value handlers");
		try {
			this.returnValueHandlers.handleReturnValue(
					returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
		}
		catch (Exception ex) {
			if (logger.isTraceEnabled()) {
				logger.trace(formatErrorForReturnValue(returnValue), ex);
			}
			throw ex;
		}
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

返回json数据的返回值处理器RequestResponseBodyMethodProcessor的源码

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
//类型检查,主要是检查方法或者所在类是否有ResponseBody注解
	@Override
	public boolean supportsReturnType(MethodParameter returnType) {
		return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
				returnType.hasMethodAnnotation(ResponseBody.class));
	}

    
//处理返回值,向响应体中传入数据。
	
	@Override
	public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
			throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

		mavContainer.setRequestHandled(true);
		ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
		ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

		// Try even with null return value. ResponseBodyAdvice could get involved.
		writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
	}

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

在SpringMVC中没有提供json和object相互转换的实现。但是在参数解析,和返回值处理中都需要这一功能。这需要我们手动导入第三方关于json转换的jar包。在WebMvcConfigurationSupport中会检测是否存在,如果存在会添加到配置中,这样才能实现ResponseBody注解的功能。

以jackson2Present为例

//兼容第三方
static {
		ClassLoader classLoader = WebMvcConfigurationSupport.class.getClassLoader();
		romePresent = ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", classLoader);
		jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", classLoader);
		jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) &&
				ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
		jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);
		jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader);
		jackson2CborPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", classLoader);
		gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
		jsonbPresent = ClassUtils.isPresent("javax.json.bind.Jsonb", classLoader);
		kotlinSerializationJsonPresent = ClassUtils.isPresent("kotlinx.serialization.json.Json", classLoader);
	}

//适配器中加入json解析功能

if (jackson2Present) {
			adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
			adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
		}
//加入含有json解析的HttpMessageConverter
if (jackson2Present) {
			Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
			if (this.applicationContext != null) {
				builder.applicationContext(this.applicationContext);
			}
			messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
		}
//加入含有json解析的exceptionHandlerResolver
if (jackson2Present) {
			exceptionHandlerResolver.setResponseBodyAdvice(
					Collections.singletonList(new JsonViewResponseBodyAdvice()));
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

参数解析器

参数解析器解析请求信息转换成参数,提供给handler进行函数。它的执行逻辑和返回值处理器基本一致。

protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

		MethodParameter[] parameters = getMethodParameters();
		if (ObjectUtils.isEmpty(parameters)) {
			return EMPTY_ARGS;
		}

		Object[] args = new Object[parameters.length];
		for (int i = 0; i < parameters.length; i++) {
			MethodParameter parameter = parameters[i];
			parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
			args[i] = findProvidedArgument(parameter, providedArgs);
			if (args[i] != null) {
				continue;
			}
			if (!this.resolvers.supportsParameter(parameter)) {
				throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
			}
			try {
				args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
			}
			catch (Exception ex) {
				// Leave stack trace for later, exception may actually be resolved and handled...
				if (logger.isDebugEnabled()) {
					String exMsg = ex.getMessage();
					if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
						logger.debug(formatArgumentError(parameter, exMsg));
					}
				}
				throw ex;
			}
		}
		return args;
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

实现一个自定义的参数解析器。梳理一下大致的思路。首先我们定义一种自己要解析的参数类型RequestSource。自定义参数解析器RequestSourceArgHandler,实现HandlerMethodArgumentResolver接口。在supportsParameter方法中指明要处理的参数类型为RequestSource。在resolveArgument方法中从请求头中获取sourceType来进行处理。有了参数解析器还要交给容器管理,根据SpringMVC配置逻辑,我们应当在注册类中通过@Bean的方式编写一个返回WebMvcConfigurer的方法,通过重写addArgumentResolvers方法来注册新的参数管理器。这样一个自定义参数处理器就完成了

//参数类型
@Data
public class RequestSource {
    String source;
}
//自定义的参数解析器
public class RequestSourceArgHandler implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        if(parameter.getParameterType().equals(RequestSource.class)){
            return true;
        }
        return false;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        String sourceType = webRequest.getHeader("sourceType");
        RequestSource requestSource = null;
        if(sourceType != null){
            requestSource = new RequestSource();
            requestSource.setSource(sourceType);
        }
        return requestSource;
    }
}
//注册
 @Bean
 public WebMvcConfigurer requestSourceMethodResolver(){
                return new WebMvcConfigurer() {
                        @Override
                        public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
                                resolvers.add(new RequestSourceArgHandler());
                        }
                };
        }
//Controller方法
@GetMapping("/hello2")
    public String hello2(RequestSource requestSource){
        return orderService.hello();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

可以看到我们自定义的参数处理器被注册到this.resolvers中了。

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/799276
推荐阅读
相关标签
  

闽ICP备14008679号