Administrator
发布于 2022-10-21 / 42 阅读
0
0

SpringMVC支持Ajax 、MessageConverter数据返回原理

概述

笼统一点的说就是导入jackson包,能够使用@ResponseBody,@RequestBody注解,这个不太详细写了,本来就是复习ssm

 

HttpMessageConverter

概述

使用 HttpMessageConverter 将请求信息转化并绑定到处理方法的入参中或将响应结果转为对应类型的响应信息,

Spring 提供了两种途径:

使用 @RequestBody / @ResponseBody 对处理方法进行标注

使用 HttpEntity / ResponseEntity 作为处理方法的入参或返回值

当控制器处理方法使用到 @RequestBody/@ResponseBody 或 HttpEntity/ResponseEntity 时, 
Spring 首先根据返回值和返回值类型找到合适的 HandlerMethodReturnValueHandler, 
进而根据参数类型或泛型类型的过滤得到匹配的 HttpMessageConverter, 
若找不到可用的 HttpMessageConverter 将报错

@RequestBody 和 @ResponseBody 不需要成对出现

示例

20201214153437800

image-1666342081096
 

流程解析

 

HttpEntityTest

    @RequestMapping("/responseEntity")
    public ResponseEntity<String> HttpEntityTest() {
        String response = "success";
        HttpHeaders headers = new HttpHeaders();
        headers.add("response", response);
        ResponseEntity responseEntity = new ResponseEntity(response,headers, HttpStatus.OK);
        return responseEntity;
    }
使用返回值类型是 ResponseEntity<String>举例,其他的返回值类型大差不差,只是调用的实现方法不一样
前面的统一流程

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
||
mav = invokeHandlerMethod(request, response, handlerMethod);
||
invocableMethod.invokeAndHandle(webRequest, mavContainer);
||
this.returnValueHandlers.handleReturnValue(
			returnValue, getReturnValueType(returnValue), mavContainer, webRequest);

 

handleReturnValue

public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
          ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
--
//根据方法的返回值,返回值类型选择出合适的HandlerMethodReturnValueHandler
--
      HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
      if (handler == null) {
          throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
      }
      --
      //处理器进行返回值处理
      --
      handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
  }

 

handleReturnValue

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

--
//不需要进行页面渲染的,都会设置这个属性值为true,以标志请求处理完成
//后续就不会调用也没有render方法
--
      mavContainer.setRequestHandled(true);
      if (returnValue == null) {
          return;
      }
--
//获取请求的输入信息以及要输出的信息
--
      ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
      ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

      Assert.isInstanceOf(HttpEntity.class, returnValue);
      HttpEntity<?> responseEntity = (HttpEntity<?>) returnValue;

--
//获取信息的Headers		 headers.add("response", response);
				[response:"success"]
--
      HttpHeaders outputHeaders = outputMessage.getHeaders();
      HttpHeaders entityHeaders = responseEntity.getHeaders();
      
      --
      //三个if进行一些别的判断,这里不关注
      --
      if (!entityHeaders.isEmpty()) {
          entityHeaders.forEach((key, value) -> {
              if (HttpHeaders.VARY.equals(key) && outputHeaders.containsKey(HttpHeaders.VARY)) {
                  List<String> values = getVaryRequestHeadersToAdd(outputHeaders, entityHeaders);
                  if (!values.isEmpty()) {
                      outputHeaders.setVary(values);
                  }
              }
              else {
                  outputHeaders.put(key, value);
              }
          });
      }

      if (responseEntity instanceof ResponseEntity) {
          int returnStatus = ((ResponseEntity<?>) responseEntity).getStatusCodeValue();
          outputMessage.getServletResponse().setStatus(returnStatus);
          if (returnStatus == 200) {
              if (SAFE_METHODS.contains(inputMessage.getMethod())
                      && isResourceNotModified(inputMessage, outputMessage)) {
                  // Ensure headers are flushed, no body should be written.
                  outputMessage.flush();
                  // Skip call to converters, as they may update the body.
                  return;
              }
          }
          else if (returnStatus / 100 == 3) {
              String location = outputHeaders.getFirst("location");
              if (location != null) {
                  saveFlashAttributes(mavContainer, webRequest, location);
              }
          }
      }

      // Try even with null body. ResponseBodyAdvice could get involved.
      --
      //使用MessageConverters进行数据的输出
      --
      writeWithMessageConverters(responseEntity.getBody(), returnType, inputMessage, outputMessage);

      // Ensure headers are flushed even if no body was written.
      outputMessage.flush();
  }

writeWithMessageConverters

前面还有一长串的前置判断和赋值,节约空间就不黏贴了
--------------------------
选择出来的媒体类型不为null
---
if (selectedMediaType != null) {
        selectedMediaType = selectedMediaType.removeQualityValue();
        --
        //增强for循环,选择出合适的converter
        --
        for (HttpMessageConverter<?> converter : this.messageConverters) {
            GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?
                    (GenericHttpMessageConverter<?>) converter : null);
            if (genericConverter != null ?
                    ((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :
                    converter.canWrite(valueType, selectedMediaType)) {
                body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,
                        (Class<? extends HttpMessageConverter<?>>) converter.getClass(),
                        inputMessage, outputMessage);
                if (body != null) {
                    Object theBody = body;
                    LogFormatUtils.traceDebug(logger, traceOn ->
                            "Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");
                    addContentDispositionHeader(inputMessage, outputMessage);
                    if (genericConverter != null) {
                        genericConverter.write(body, targetType, selectedMediaType, outputMessage);
                    }
                    else {
                        ((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
                    }
                }
                else {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Nothing to write: null body");
                    }
                }
                return;
            }
        }
    }

上述writeWithMessageConverters完成后,response里就完成响应值的绑定

image-1666343499097
 

messageConverters

image-1666343423181
 

问题:messageConverters什么时候有的?

messageConverters只在某些handlerAdapters的returnValueHandlers中存在;
例如:RequestMappingHandlerAdapter

image-1666343665991
 
那么RequestMappingHandlerAdapter什么时候有的messageConverters?

还是之前源码说的一样
在AnnotationDrivenBeanDefinitionParser类下,
有public BeanDefinition parse(Element element, ParserContext context) {}这么一个方法
其中有一部分是这样的:
--
在项目启动的时候,根据配置文件、context等获取到messageConverters
--
ManagedList<?> messageConverters = getMessageConverters(element, source, context);

而在getMessageConverters内部,会注册什么样的messageConverters也是已经写好了的
messageConverters部分代码如下:
if (convertersElement == null || Boolean.valueOf(convertersElement.getAttribute("register-defaults"))) {
          messageConverters.setSource(source);
          messageConverters.add(createConverterDefinition(ByteArrayHttpMessageConverter.class, source));

          RootBeanDefinition stringConverterDef = createConverterDefinition(StringHttpMessageConverter.class, source);
          stringConverterDef.getPropertyValues().add("writeAcceptCharset", false);
          messageConverters.add(stringConverterDef);

          messageConverters.add(createConverterDefinition(ResourceHttpMessageConverter.class, source));
          messageConverters.add(createConverterDefinition(ResourceRegionHttpMessageConverter.class, source));
          messageConverters.add(createConverterDefinition(SourceHttpMessageConverter.class, source));
          messageConverters.add(createConverterDefinition(AllEncompassingFormHttpMessageConverter.class, source));

          if (romePresent) {
              messageConverters.add(createConverterDefinition(AtomFeedHttpMessageConverter.class, source));
              messageConverters.add(createConverterDefinition(RssChannelHttpMessageConverter.class, source));
          }


……

--
在注册RequestMappingHandlerAdapter的时候,将messageConverters加入进去
--
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
      handlerAdapterDef.setSource(source);
      handlerAdapterDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
      handlerAdapterDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
      handlerAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
      --
      将messageConverters加入
      --
      handlerAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
      addRequestBodyAdvice(handlerAdapterDef);
      addResponseBodyAdvice(handlerAdapterDef);

 
image-1666344222655


评论