设为首页 加入收藏

TOP

Spring MVC内容协商实现原理及自定义配置【享学Spring MVC】(一)
2019-09-17 16:28:37 】 浏览:55
Tags:Spring MVC 内容 协商 实现 原理 定义 配置 享学

每篇一句

在绝对力量面前,一切技巧都是浮云

前言

上文 介绍了Http内容协商的一些概念,以及Spring MVC内置的4种协商方式使用介绍。本文主要针对Spring MVC内容协商方式:从步骤、原理层面理解,最后达到通过自己来扩展协商方式效果。

首先肯定需要介绍的,那必然就是Spring MVC的默认支持的四大协商策略的原理分析喽:

ContentNegotiationStrategy

该接口就是Spring MVC实现内容协商的策略接口:

// A strategy for resolving the requested media types for a request.
// @since 3.2
@FunctionalInterface
public interface ContentNegotiationStrategy {
    // @since 5.0.5
    List<MediaType> MEDIA_TYPE_ALL_LIST = Collections.singletonList(MediaType.ALL);

    // 将给定的请求解析为媒体类型列表
    // 返回的 List 首先按照 specificity 参数排序,其次按照 quality 参数排序
    // 如果请求的媒体类型不能被解析则抛出 HttpMediaTypeNotAcceptableException 异常
    List<MediaType> resolveMediaTypes(NativeWebRequest webRequest) throws HttpMediaTypeNotAcceptableException;
}

说白了,这个策略接口就是想知道客户端的请求需要什么类型(MediaType)的数据List。从 上文 我们知道Spring MVC它支持了4种不同的协商机制,它都和此策略接口相关的。
它的继承树:
在这里插入图片描述
从实现类的名字上就能看出它和上文提到的4种方式恰好是一一对应着的(ContentNegotiationManager除外)。

Spring MVC默认加载两个该策略接口的实现类:
ServletPathExtensionContentNegotiationStrategy-->根据文件扩展名(支持RESTful)。
HeaderContentNegotiationStrategy-->根据HTTP Header里的Accept字段(支持Http)。

HeaderContentNegotiationStrategy

Accept Header解析:它根据请求头Accept来协商。

public class HeaderContentNegotiationStrategy implements ContentNegotiationStrategy {
    @Override
    public List<MediaType> resolveMediaTypes(NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
    
        // 我的Chrome浏览器值是:[text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3]
        // postman的值是:[*/*]
        String[] headerValueArray = request.getHeaderValues(HttpHeaders.ACCEPT);
        if (headerValueArray == null) {
            return MEDIA_TYPE_ALL_LIST;
        }

        List<String> headerValues = Arrays.asList(headerValueArray);
        try {
            List<MediaType> mediaTypes = MediaType.parseMediaTypes(headerValues);
            // 排序
            MediaType.sortBySpecificityAndQuality(mediaTypes);
            // 最后Chrome浏览器的List如下:
            // 0 = {MediaType@6205} "text/html"
            // 1 = {MediaType@6206} "application/xhtml+xml"
            // 2 = {MediaType@6207} "image/webp"
            // 3 = {MediaType@6208} "image/apng"
            // 4 = {MediaType@6209} "application/signed-exchange;v=b3"
            // 5 = {MediaType@6210} "application/xml;q=0.9"
            // 6 = {MediaType@6211} "*/*;q=0.8"
            return !CollectionUtils.isEmpty(mediaTypes) ? mediaTypes : MEDIA_TYPE_ALL_LIST;
        } catch (InvalidMediaTypeException ex) {
            throw new HttpMediaTypeNotAcceptableException("Could not parse 'Accept' header " + headerValues + ": " + ex.getMessage());
        }
    }
}

可以看到,如果没有传递Accept,则默认使用MediaType.ALL 也就是*/*

AbstractMappingContentNegotiationStrategy

通过file extension/query param来协商的抽象实现类。在了解它之前,有必要先插队先了解MediaTypeFileExtensionResolver它的作用:

---

MediaTypeFileExtensionResolverMediaType和路径扩展名解析策略的接口,例如将 .json 解析成 application/json 或者反向解析

// @since 3.2
public interface MediaTypeFileExtensionResolver {

    // 根据指定的mediaType返回一组文件扩展名
    List<String> resolveFileExtensions(MediaType mediaType);
    // 返回该接口注册进来的所有的扩展名
    List<String> getAllFileExtensions();
}

继承树如下:
在这里插入图片描述
显然,本处只需要讲解它的直接实现子类MappingMediaTypeFileExtensionResolver即可:

MappingMediaTypeFileExtensionResolver
public class MappingMediaTypeFileExtensionResolver i
首页 上一页 1 2 3 4 5 6 7 下一页 尾页 1/7/7
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇thymeleaf各种问题,标签没用?网.. 下一篇小白学习如何打日志

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目