26.内容协商原理

将数据以xml的方式返回给浏览器,在参数解析器解析时涉及到内容协商。

@ResponseBody
    @RequestMapping("/test/person")
    public Person getPerson(){
        Person person = new Person();
        person.setAge(20);
        person.setBrith(new Date());
        person.setUserName("张三");
        return person;
    }


1. 开启请求参数协商模式,可以随时修改浏览器接受的参数类型,xml、json格式的数据

 

spring:
 contentnegotiation:
      favor-parameter: true


 

2.得到请求参数的返回值

 
 
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);


setResponseStatus(webRequest);

 返回值的参数类型如图所示:

 3.调用返回值处理器对得到的参数值、请求进行处理

try {
            this.returnValueHandlers.handleReturnValue(
                    returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        }


4,查找哪一种返回值处理器能够处理@Reponse注解的处理器,去处理相应的请求

返回值处理器的类型总共有15种

5.调用RequestResponseBodyMethodProcessor中的方法进行处理

writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
 6.内容协商处理时,首先获取到客户端(浏览器)的accept看浏览器能够处理哪些类型

List<MediaType> acceptableTypes = getAcceptableMediaTypes(request);
7.step Into进去,利用一个for循环,得到所有浏览器支持的类型。基本请求头的协商策略,确定客户端可以接受的内容类型。HeaderContentNegotiationStrategy.还有根据配置基于参数的内容协商策略

 

for (ContentNegotiationStrategy strategy : this.strategies) {
            List<MediaType> mediaTypes = strategy.resolveMediaTypes(request);
            if (mediaTypes.equals(MEDIA_TYPE_ALL_LIST)) {
                continue;
            }
            return mediaTypes;
        }
        return MEDIA_TYPE_ALL_LIST;
    }


 从accept获取数据

    String[] headerValueArray = request.getHeaderValues(HttpHeaders.ACCEPT);
mediaTypes的类型共有5种

8.后台服务器所支持的类型

List<MediaType> producibleTypes = getProducibleMediaTypes(request, valueType, targetType);
判断哪些MessageConverters能够转换person类型,将结果封装到result结果集里边。

for (HttpMessageConverter<?> converter : this.messageConverters) {
                if (converter instanceof GenericHttpMessageConverter && targetType != null) {
                    if (((GenericHttpMessageConverter<?>) converter).canWrite(targetType, valueClass, null)) {
                        result.addAll(converter.getSupportedMediaTypes());
                    }
                }
                else if (converter.canWrite(valueClass, null)) {
                    result.addAll(converter.getSupportedMediaTypes());
                }


类型转换器如图共有11种,其中能够转换对象类型的有10种

 9.将浏览器能够处理的类型与后台所能处理的类型进行对比,找出最适合的类型转换

for (MediaType requestedType : acceptableTypes) {
                for (MediaType producibleType : producibleTypes) {
                    if (requestedType.isCompatibleWith(producibleType)) {
                        mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType));
                    }
                }
            }


可用的媒体类型共有14种

 10.用消息转换器,将对象类型转换为xml/json类型的数据写入到响应体中

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);


objectWriter.writeValue(generator, value);

posted @ 2022-08-08 13:32  随遇而安==  阅读(14)  评论(0编辑  收藏  举报