赞
踩
根据之前的配置逻辑整理出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; } }
返回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); } }
在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())); }
参数解析器解析请求信息转换成参数,提供给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; }
实现一个自定义的参数解析器。梳理一下大致的思路。首先我们定义一种自己要解析的参数类型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(); }
可以看到我们自定义的参数处理器被注册到this.resolvers中了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。