SpringBoot-SpringMVC中的ContentNegotiationStrategy内容协商策略的作用和原理

Easymesh之拓扑模块(二) 介绍 easymesh 拓扑消息:Topo discovery、Topo notification、Topo query、Topo response 阅读详情
/**
 * 为什么要有内容协商策略?
 * 因为在客户端和服务端之前请求响应的时候,客户端期望得到服务端返回指定类型的内容
 * 而这个过程,是客户端和服务端之间进行协商的过程,从而可以有多种协商方式,也称为协商策略
 */
class ContentNegotiationManager {
    // 进行内容协商的各种策略集合
    private final List<ContentNegotiationStrategy> strategies = new ArrayList<>();
    // 解析对于文件类型的后缀,因为对于文件,文件后缀名一般就是响应的类型
    private final Set<MediaTypeFileExtensionResolver> resolvers = new LinkedHashSet<>();

    // 给定内容协商策略
    public ContentNegotiationManager(ContentNegotiationStrategy... strategies) {
        this(Arrays.asList(strategies));
    }

    // 初始化
    public ContentNegotiationManager(Collection<ContentNegotiationStrategy> strategies) {
        this.strategies.addAll(strategies);
        for (ContentNegotiationStrategy strategy : this.strategies) {
            // 保存媒体类型文件的解析器,因为对于文件,文件后缀名一般就是响应的类型
            if (strategy instanceof MediaTypeFileExtensionResolver) {
                this.resolvers.add((MediaTypeFileExtensionResolver) strategy);
            }
        }
    }

    // 支持默认的协商策略为获取请求头中的支持的类型
    public ContentNegotiationManager() {
        this(new HeaderContentNegotiationStrategy());
    }

    // 使用内容协商策略进行解析客户端需要的响应类型
    public List<MediaType> resolveMediaTypes(NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
        // 遍历所有的内容协商策略
        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;
    }

    // 解析文件扩展名
    @Override
    public List<String> resolveFileExtensions(MediaType mediaType) {
        // 使用文件解析器对该媒体类型进行解析
        return doResolveExtensions(resolver -> resolver.resolveFileExtensions(mediaType));
    }

    // 使用文件解析器对该媒体类型进行解析
    private List<String> doResolveExtensions(Function<MediaTypeFileExtensionResolver, List<String>> extractor) {
        List<String> result = null;
        // 遍历所有的文件类型解析器
        for (MediaTypeFileExtensionResolver resolver : this.resolvers) {
            // 执行解析,获取文件的扩展名
            List<String> extensions = extractor.apply(resolver);
            // 如果该解析器没有解析到扩展名,不处理
            if (CollectionUtils.isEmpty(extensions)) {
                continue;
            }
            // 解析到扩展名
            result = (result != null ? result : new ArrayList<>(4));
            // 遍历所有的扩展名
            for (String extension : extensions) {
                // 保存解析到的所有扩展名
                if (!result.contains(extension)) {
                    result.add(extension);
                }
            }
        }
        return (result != null ? result : Collections.emptyList());
    }
}

// 内容协商策略,还可以自定义,就是获取某个地方设置的需要的响应类型,比如请求头,请求参数,请求路径中
public class ContentNegotiationStrategy {
    /**
     * 基于参数的内容协商策略实现
     * {@link org.springframework.web.accept.ParameterContentNegotiationStrategy}
     */
    public List<MediaType> resolveMediaTypes(NativeWebRequest request) {
        // private String parameterName = "format";这就是默认的参数名称,/url?format=json,表示客户端需要json类型的数据
        String key = request.getParameter(getParameterName());
        // 如果存在该参数的值
        if (StringUtils.hasText(key)) {
            // 查询服务器端支持的所有媒体类型,是否存在客户端指定的媒体类型
            MediaType mediaType = this.lookupMediaType(key);
            // 如果存在
            if (mediaType != null) {
                // 处理匹配上的逻辑
                this.handleMatch(key, mediaType);
                // 返回协商的结果类型
                return Collections.singletonList(mediaType);
            }
            // 没有找到客户端匹配的媒体类型,处理没有匹配上的逻辑,用其他方式看一下是否能返回该媒体类型
            mediaType = this.handleNoMatch(webRequest, key);
            // 如果其他方式匹配上了
            if (mediaType != null) {
                // 保存映射关系,防止下次再去找
                this.addMapping(key, mediaType);
                // 返回兜底的媒体类型
                return Collections.singletonList(mediaType);
            }
        }
        // 如果客户端没有指定参数format的key媒体类型,默认支持所有
        return MEDIA_TYPE_ALL_LIST;
    }

    /**
     * 基于请求头的内容协商策略实现
     * {@link org.springframework.web.accept.HeaderContentNegotiationStrategy}
     */
    public List<MediaType> resolveMediaTypes(NativeWebRequest request) {
        // 获取请求头ACCEPT
        String[] headerValueArray = request.getHeaderValues(HttpHeaders.ACCEPT);
        // 如果没有请求头
        if (headerValueArray == null) {
            // 支持所有
            return MEDIA_TYPE_ALL_LIST;
        }
        //
        List<String> headerValues = Arrays.asList(headerValueArray);
        // 将请求头的字符串解析成MediaType
        List<MediaType> mediaTypes = MediaType.parseMediaTypes(headerValues);
        // 找到最合适的媒体类型,根据权重等等方式
        MediaType.sortBySpecificityAndQuality(mediaTypes);
        // 返回找到的媒体类型
        return !CollectionUtils.isEmpty(mediaTypes) ? mediaTypes : MEDIA_TYPE_ALL_LIST;
    }

}

// 这是一个处理返回值的处理器,内部调用所有的消息转换器,将内容进行响应
public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolver implements HandlerMethodReturnValueHandler {
    // 内容协商管理器,管理了多个内容协商策略
    private final ContentNegotiationManager contentNegotiationManager;

    // 使用消息处理器对消息进行响应,我们只保留内容协商的核心源码
    protected <T> void writeWithMessageConverters(T value, MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) {
        // 最终需要响应给客户端的数据类型
        MediaType selectedMediaType = null;
        // 响应流中是否已经设置了响应类型
        MediaType contentType = outputMessage.getHeaders().getContentType();
        boolean isContentTypePreset = contentType != null && contentType.isConcrete();
        // 如果设置了,直接使用指定的响应类型,不需要进行协商
        if (isContentTypePreset) {
            selectedMediaType = contentType;
        }
        // 开始进行内容协商
        else {
            HttpServletRequest request = inputMessage.getServletRequest();
            // 获取客户端需要的响应类型
            List<MediaType> acceptableTypes = this.getAcceptableMediaTypes(request);
            // 获取服务端需要的响应类型
            List<MediaType> producibleTypes = this.getProducibleMediaTypes(request, valueType, targetType);

            // 客户端和服务端进行类型协商,得到最终响应的结果
            List<MediaType> mediaTypesToUse = new ArrayList<>();
            for (MediaType requestedType : acceptableTypes) {
                for (MediaType producibleType : producibleTypes) {
                    if (requestedType.isCompatibleWith(producibleType)) {
                        mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType));
                    }
                }
            }
            // 如果没有协商一致,抛出异常
            if (mediaTypesToUse.isEmpty()) {
                if (body != null) {
                    throw new HttpMediaTypeNotAcceptableException(producibleTypes);
                }
                return;
            }
            // 因为协商之后,可能存在多种符合条件的组合,我们需要选出最佳的一组响应类型
            for (MediaType mediaType : mediaTypesToUse) {
                if (mediaType.isConcrete()) {
                    selectedMediaType = mediaType;
                    break;
                }
                if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) {
                    selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
                    break;
                }
            }
        }
        // 协商完成,得到最终的响应类型
        if (selectedMediaType != null) {
            // 开始遍历所有的消息转换器,将最终的结果按照指定的媒体类型响应
            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)) {
                    // 如果可以,执行ResponseBodyAdvice接口的回调,ResponseBodyAdvice接口是响应之前对象返回值做的最后操作
                    // 可以改变最终的返回结果,达到最终的统一结果返回
                    body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType, (Class<? extends HttpMessageConverter<?>>) converter.getClass(), inputMessage, outputMessage);
                    // 如果存在返回结果
                    if (body != null) {
                        // 写如响应头
                        Object theBody = body;
                        addContentDispositionHeader(inputMessage, outputMessage);
                        // 调用消息转换器的写如方法,将数据写到响应流中
                        if (genericConverter != null) {
                            genericConverter.write(body, targetType, selectedMediaType, outputMessage);
                        } else {
                            ((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
                        }
                    }
                    return;
                }
            }
        }
    }

    // 获取客户端能接受的内容类型
    private List<MediaType> getAcceptableMediaTypes(HttpServletRequest request) {
        // 使用内容协商管理器,获取客户端需要的响应类型
        return this.contentNegotiationManager.resolveMediaTypes(new ServletWebRequest(request));
    }

    // 获取服务端能响应的内容类型
    protected List<MediaType> getProducibleMediaTypes(HttpServletRequest request, Class<?> valueClass, @Nullable Type targetType) {
        Set<MediaType> mediaTypes = (Set<MediaType>) request.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
        // 如果在请求域中设置当前请求服务器响应的媒体类型,因为可以在@RequestMapping中设置
        if (!CollectionUtils.isEmpty(mediaTypes)) {
            return new ArrayList<>(mediaTypes);
        }
        // 如果没有设置
        List<MediaType> result = new ArrayList<>();
        // 遍历所有的消息转换器,获取所有可以处理指定类型的消息转换器支持的媒体类型
        for (HttpMessageConverter<?> converter : this.messageConverters) {
            // 如果可以响应该返回值
            if (converter.canWrite(valueClass, null)) {
                // 则获取该转换器支持的媒体类型
                result.addAll(converter.getSupportedMediaTypes(valueClass));
            }
        }
        // 返回消息转换器中支持写出的媒体类型
        return (result.isEmpty() ? Collections.singletonList(MediaType.ALL) : result);
    }

}

/**
 * 使用案例
 */
@Configuration
class Demo {
    /**
     * http://localhost:8080/luck?format=luck,这个时候,就会执行LuckHttpMessageConverter的write方法,返回luck.toString()
     * {@link LuckConfig#configureMessageConverters}
     */
    @GetMapping("/luck")
    public Luck luck() {
        return new Luck(100, "luck");
    }

    @Configuration
    public class LuckConfig implements WebMvcConfigurer {
        /**
         * 启请求参数内容协商,可以通过?format=json,xxx来与服务器协商需要得到什么样的数据内容
         * {@link WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter#configureContentNegotiation(org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer)}
         * 如果是SpringBoot,会有自动配置,使用spring.mvc.contentnegotiation.favor-parameter=true开启之后,就会自动添加ParameterContentNegotiationStrategy
         * 否则只有默认的HeaderContentNegotiationStrategy
         */
        @Override
        public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
            // 基于请求参数的内容协商策略,基于参数的内容协商支持一下这三种响应类型
            Map<String, MediaType> mediaTypes = Map.of(
                    "json", MediaType.APPLICATION_JSON,
                    "xml", MediaType.APPLICATION_XML,
                    // 自定义的响应类型
                    "luck", MediaType.parseMediaType("application/luck")
            );
            // 基于参数的协商策略,可以自定义参数名称,默认为format
            ParameterContentNegotiationStrategy paramStrategy = new ParameterContentNegotiationStrategy(mediaTypes);
            // 基于请求头的内容协商策略
            HeaderContentNegotiationStrategy headerStrategy = new HeaderContentNegotiationStrategy();
            // 配置mvc应用的所有内容协商策略,这些协商策略在请求响应的时候发生作用,客户端和服务端进行内容协商,服务器响应与客户端期望的媒体类型
            configurer.strategies(Arrays.asList(paramStrategy, headerStrategy));
        }

        // 添加自定义的消息内容转换器,与内容协商策略可以搭配使用,完成自定义响应媒体类型的响应
        @Override
        public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
            // 这个一个自定义类型的案例
            class LuckHttpMessageConverter implements HttpMessageConverter<Luck> {

                @Override
                public boolean canRead(Class<?> clazz, MediaType mediaType) {
                    // 该消息转换器只支持写入,不支持读取,读取的操作交给其他的消息转换器处理
                    return false;
                }

                @Override
                public boolean canWrite(Class<?> clazz, MediaType mediaType) {
                    return clazz.isAssignableFrom(Luck.class);
                }

                @Override
                public List<MediaType> getSupportedMediaTypes() {
                    // 只支持自定义的媒体类型
                    return Collections.singletonList(MediaType.parseMediaType("application/luck"));
                }


                @Override
                public Luck read(Class<? extends Luck> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
                    // 因为当前消息转换器不可读,所以不用处理
                    return null;
                }

                @Override
                public void write(Luck luck, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
                    // 当前消息转换器可写,所以在这里处理响应
                    OutputStream stream = outputMessage.getBody();
                    stream.write(luck.toString().getBytes(StandardCharsets.UTF_8));
                }
            }
            converters.add(new LuckHttpMessageConverter());
        }

    }
}

【ESP32-IDF笔记】20-配置以太网网络(W5500) 基于ESP32IDF和官方的ethernet驱动,配置W5500以太网驱动芯片,实现ESP32的有线网络 阅读详情

相关推荐

一文读懂GPU通信互联技术:GPUDirect、NVLink与RDMA

GPUDirect是NVIDIA开发的一项技术,旨在实现GPU与其他设备(如网络接口卡NIC和存储设备)之间的直接通信和数据传输,而无需CPU的参与。传统上,数据在GPU和另一个设备之间传输时,必须通过CPU,这导致潜在的性能瓶颈和延迟增加。GPUDirect技术则通过绕过CPU,直接访问和传输数据,显著提高系统性能。NVLink是NVIDIA开发的一种高速、高带宽的互连技术,用于连接多个GPU之间或GPU与其他设备(如CPU、内存等)之间的通信。

异构算力老群群(在读985计算机博士生)的技术博客 7769

ContentNegotiationStrategy与自定义ContentNegotiationStrategy

文章目录ContentNegotiationStrategy自定义ContentNegotiationStrategy ContentNegotiationStrategy //WebMvcConfigurationSupport#mvcContentNegotiationManager public ContentNegotiationManager mvcContentNegotiationManager() { if (this.contentNegotiationManager == null)

richest_qi的博客 695

基于Simulink的前馈解耦SVPWM整流器仿真

本文提出了一种基于Simulink的前馈解耦SVPWM整流器仿真方案,针对传统双闭环控制存在的耦合严重、电压利用率低等问题进行优化。通过前馈补偿dq轴耦合项(ωLiq和ωLid)结合SVPWM调制算法,实现了电流跟踪误差<3%、电压利用率达0.99、THD<3%的性能指标。文章详细阐述了系统架构设计,包括前馈解耦原理推导、SVPWM算法实现步骤,并提供了完整的Simulink建模方法。仿真结果表明,该方案在动态响应速度(25ms)和直流电压纹波(1.1%)方面显著优于传统SPWM控制。同时给出了

MHD0815的博客 162

Spring Web : 策略接口 ContentNegotiationStrategy

ContentNegotiationStrategy是Spring Web的策略接口,所定义的策略对象用于从请求对象中的各种信息判断该请求的MediaType。 源代码 package org.springframework.web.accept; import java.util.Collections; import java.util.List; import org.springfra...

Details Inside Spring 1338

别再只调PID了!手把手教你从LC谐振到检波,搞定STM32智能车电磁循迹硬件电路

本文深入解析STM32智能车电磁循迹硬件电路设计,从LC谐振选频到数字信号处理,提供完整的信号链路设计要点与实战技巧。通过优化电磁杆布局和信号放大电路,显著提升赛道位置检测精度,误差可控制在±0.5cm以内,为智能车竞赛提供可靠硬件支持。

weixin_29220405的博客 261

算法面经手撕系列(2)--手撕BatchNormlization

手动实现/手撕BatchNormlization

罟霖同学的站点 864

自定义ContentNegotiationStrategy实现内容协商

在Spring Web MVC中,内容协商(Content Negotiation)是一种根据客户端请求来决定响应内容格式的机制。默认情况下,Spring提供了多种内容协商策略,但有时我们可能需要根据特定的业务逻辑来实现自定义的内容协商策略。假设我们有一个需求:根据请求头中的Accept-Language字段来决定返回JSON还是XML格式的数据。测试2:设置了Accept-Language头为en-US时,返回JSON格式的数据。测试1:未设置Accept-Language头时,返回XML格式的数据。

m0_74337424的博客 568

在ArcGIS Pro软件中进行滑坡的敏感性和易发性分析

滑坡的敏感性和易发性分析需要综合地形、水文、地质及环境等多维数据,本文罗列了基于ArcGIS Pro软件进行的一系列可执行分析。

weixin_49609713的博客 1729

ContentNegotiation内容协商机制(二)---Spring MVC内容协商实现原理及自定义配置【享学Spring MVC】

前言 上文 介绍了Http内容协商的一些概念,以及Spring MVC对此实现的4种方式使用介绍。那么本文基于自定义扩展的需求,先从步骤、原理层面理解,然后提供一个实力来扩展内容协商的方式。 ContentNegotiationStrategy 在说到Spring MVC支持的协商机制的时候,就不得不提这个策略接口。从 上文 我们知道Spring MVC它支持了4种不同的协商机制,它都和此策略接...

架构师:通透,才能写出好代码! 2486

【Zephyr 系列 29】低功耗调试指南:电流测量、系统睡眠与功耗分析

Zephyr低功耗调试指南(150字摘要) 针对物联网设备续航需求,本文解析Zephyr低功耗调试方法:1️⃣ 机制:启用PM子系统和tickless idle,配置睡眠策略;2️⃣ 测量:推荐功耗分析仪捕捉μA级电流波动;3️⃣ 优化:管理唤醒源(如GPIO/RTC)、调整BLE广播/连接参数,挂起闲置外设;4️⃣ 分析:建立功耗文档,对比不同模式电流(如待机0.6mA vs广播3.2mA)。强调低功耗需系统性设计,初期即需纳入测试流程。下期将探讨Zephyr OTA升级实现。

hemoparrot的专栏 1180

在昇腾910B服务上部署搭建适配PDF解析工具Mineru2.5开源项目

本文介绍了在昇腾910B服务器上部署开源PDF解析工具Mineru2.5的过程。首先从昇腾社区下载mindie镜像并运行容器,安装系统依赖。针对部署过程中遇到的多个报错问题(如torchvision与torch版本不匹配、昇腾软件栈与NumPy 2.0不兼容等),提供了具体解决方案和兼容版本。通过设置环境变量、安装指定版本的Python依赖包,成功部署Mineru项目并下载模型。最后运行测试,验证了在NPU设备上运行pipeline的可行性。整个过程详细记录了版本适配和错误处理方法,为类似部署场景提供了参考

一起加油吧 2162

Spring Web MVC内容协商机制详解

在接下来的教程中,我们将探索如何自定义默认的内容协商策略,并提供一个编写自定义内容协商策略的示例。

m0_74337424的博客 452

非技术面试题精选大全

回答提示:一般人回答这个问题过于平常,只说姓名、年龄、爱好、工作经验,这些在简历上都有,其实,企业最希望知道的是求职者能否胜任工作,包括:最强的技能、最深入研究的知识领域、个性中最积极的部分、做过的最成功的事,主要的成就等,这些都可以和学习无关,也可以和学习有关,但要突出积极的个性和做事的能力,说得合情合理企业才会相信。企业喜欢有礼貌的求职者。

吃面爱放香菜的博客 434

SpringMVC内容协商

SpringMVC内容协商主要的功能是:根据请求头或请求参数来控制接口返回的数据格式。通过HttpMessageConvert实现。acceptformatSpringMVC内置了很多格式的转换器我们可以利用这个功能来控制接口的返回格式。如:通过format控制接口返回xml引入依赖开启参数模式访问测试:http://localhost:8080/test?format=xml。

爱码猿的博客 919

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

整合SpringMVC之内容协商ContentNegotiation机制

一.内容协商ContentNegotiation机制 1.需求概述 我们进行web开发时,现在一般都是设计成RESTful风格的url。如果此时我们希望在请求同一个RESTful的URL时,得到不同的PDF视图、JSON视图、Html视图,也就是说我们需要对同一个url返回多种不同的结果,这该如何实现? 要想实现上面的需求,这就可以用到我今天给大家讲解的内容协商ContentNegotiat...

qianfeng_dashuju的博客 473

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

SpringMVC源码解析-ContentNegotiationStrategy

/** * 处理请求中的媒体类型的策略接口 */ public interface ContentNegotiationStrategy { /** * 将给定的请求解析为媒体类型列表 * 返回的 List 首先按照 specificity 参数排序,其次按照 quality 参数排序 * * webRequest: 当前的请求 * 返

晚晴小筑 1523

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Spring-web源码解析之ContentNegotiationStrategy

基于4.1.7.RELEASE request和mediatypes解析的策略类,其唯一的一个接口是 List resolveMediaTypes(NativeWebRequest webRequest) throws HttpMediaTypeNotAcceptableException; 该接口负责将给与的request解析出对应的MediaType来,其实现有以下几种 F

子沭的博客 1791

spring-web源码解析之ContentNegotiationManager

基于4.1.7.RELEASE 此类实现了两个接口,一个是 ContentNegotiationStrategy ,一个是 MediaTypeFileExtensionResolver ,由此它就可以完成两种功能 1 根据request中的内容,解析出MediaType的List列表。 2 根据MediaType,解析出对应的url后缀名。 该类只有含ContentNegotiationS

子沭的博客 7625

Spring MVC Content Negotiation

在这篇文章中,我想讨论如何配置和使用Spring的内容协商,主要是使用HTTP消息转换器的RESTful控制器。在另一篇博文中,我将展示如何设置专门为使用内容协商使用Spring的ContentNegotiatingViewResolver视图。

carl.zhao的专栏 6667

Spring mvc 视图解析器 ContentNegotiatingViewResolver 源码分析

步骤概要: 方法resolveViewName中获取mediaType(由accept-header中获取,springmvc每个view的默认contenttype为text/html),根据访问的viewname与mediaType查找候选视图集合candidateViews,再根据方法getBestView获取最优视图并返回。

z69183787的专栏 3万+

spring ContentNegotiationManagerFactoryBean 内容协商

一.什么是内容协商 简单点说,就是同一资源,可以有多种表现形式,比如xml、json等,具体使用哪种表现形式,是可以协商的。 这是RESTfull的一个重要特性,Spring Web MVC也支持这个功能。         1.Spring MVC REST是如何决定采用何种方式(视图)来展示内容呢? 一:根据Http请求的header中的Accept属性的值来判读,

流沙-岁月 1万+

内容协商 (Content Negotiation)

大多数响应包含一个实体,此实体包含人类用户能理解的信息。通常,希望提供给用户相应于请求最容易得到的实体。对服务器和缓存来说,不幸的是,并不是所有的用户都对这个最容易得到的实体有喜好,并且并不是所有的用户代理(如web浏览器)都能一致的呈现这些实体。所以,HTTP提供了一些“内容协商”机制 — 当有多个可得的表现形式的时候,对特定的响应选择最好的表现形式的处理过程。注意:没有称做“格式协商”(译注:

深度Java 3720

spring4.1 请求rest接口406问题解决(转换JSON)

前文说明,本来项目使用的是springmvc 的模式,然后接口都是使用的是 @Controller + @ResponseBody 配置json转换的代码是 <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property

walle167的博客 4632

spring-web源码解析之AbstractMappingContentNegotiationStrategy

基于4.1.7.RELEASE 该类是一个虚基类,ParameterContentNegotiationStrategy,PathExtensionContentNegotiationStrategy,ServletPathExtensionContentNegotiationStrategy都是从该类派生出来的,我们来看类的主要几个代码。 @Override public List reso

子沭的博客 955

Spring MVC ContentNegotiation内容协商机制(一个请求路径返回多种数据格式)源码解析

java形式配置Spring ContentNegotiationManager,内容协商机制,一个请求可以返回多种数据格式

点滴之积 9344

Day97-MCP 协议实战:把 Spring Boot 服务变成 AI 可调用工具源

MCP(Model Context Protocol)是 Anthropic 推的开放协议,让 AI 以统一方式连外部工具与数据。本文用 Spring Boot 手搓一个 MCP Server 暴露工具,讲清 Tools/Resources 两类能力,并对比 Function Calling 说清什么场景该上 MCP、什么场景它是过度设计。

雨1986的博客 467
上一篇: SpringBoot,SpringMVC中Validator中实现参数绑定的原理和总结
下一篇: SpringBoot中,错误页和异常处理定制实现原理
安缇吖
博客等级 码龄9年 411粉丝 135原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值