spring boot 八:SpringBoot响应返回xml数据

news2025/1/16 18:56:48

spring boot 八:SpringBoot响应返回xml数据

1 前言

根据DispatcherServlet源码分析,研究SpringBoot的Controller返回xml数据的一些方法,包含单独配置和全局配置返回xml数据两种方式。

依赖的SpringBoot版本:

<parent>
    <artifactId>spring-boot-starter-parent</artifactId>
    <groupId>org.springframework.boot</groupId>
    <version>2.5.4</version>
</parent>

2 使用

2.1 源码分析:

搜索spring-webmvc包下的DispatcherServlet类:

在这里插入图片描述

DispatcherServlet类下的doDispatch方法,为该方法打上断点,debug模式启动SpringBoot,编写test controller 使用 postman发起debug:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

RequestMappingHandlerAdapter中:

在这里插入图片描述

此处可见,returnValue的值为返回的people对象:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

返回值的handler总共15个:

在这里插入图片描述

选择处理的handler时,会调用handler的supportsReturnType方法,判断是否支持处理:

在这里插入图片描述

由RequestResponseBodyMethodProcessor(该类继承了AbstractMessageConverterMethodProcessor抽象类)的supportsReturnType方法可知:

在这里插入图片描述

类上含有@RestController(@RestController注解包含了@ResponseBody注解)注解,或方法上含有@ResponseBody注解,判断是可以处理的,因此处理returnValue的handler是RequestResponseBodyMethodProcessor:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

取请求头中为Accept的值,赋予acceptableTypes:

在这里插入图片描述

如下在浏览器请求头中的Accept, 其中q值代表权重,q值约大,代表浏览器更能优先接受的类型:

在这里插入图片描述

postman中,亦可见:

在这里插入图片描述

上述可知,RequestResponseBodyMethodProcessor的messageConvertors有10个,其中单独处理某个实体类为xml的HttpMessageConverter,为Jaxb2RootElementHttpMessageConverter,其位于spring-web包下:

在这里插入图片描述

它也是10个HttpMessageConverter中的最后一个(就在处理json的MappingJackson2HttpMessageConverter后面):

在这里插入图片描述

观察其源码可知,该convertor能否支持使用的前提(即canWrite必须返回true,才可支持使用):

1,实体类的class上,必须有XmlRootElement注解(javax.xml.bind.annotation包下,jdk自带注解,该注解的范围是Type,仅支持在类上使用);

2,this.canWrite(mediaType)亦返回true,才可处理;

在这里插入图片描述

因为Jaxb2RootElementHttpMessageConverter继承了抽象类AbstractXmlHttpMessageConverter,所以其初始化支持的MediaType就有如下3种,其中就包含:application/xml。this.canWrite(mediaType)即判断传入的媒体类型,是否是配置的3种之一,即可返回true:

在这里插入图片描述

故而只需要满足在实体类上增加注解:@XmlRootElement,同时请求的mediaType为:application/xml等,即可返回xml结果。

在这里插入图片描述

另外特别需要注意的是getProducibleMediaTypes方法,该方法执行时,比如@RequestMapping注解上不存在produces参数,那么就遍历全部的messageConvertors,canWrite返回true的,则将其支持的MediaType加入result的list中(@RequestMapping没有produces参数,则getProducibleMediaTypes刚开始获取的mediaTypes为null):

在这里插入图片描述

比如支持xml的Jaxb2RootElementHttpMessageConverter,虽然没有增加produces参数,但是只要controller请求方法的返回DTO上,包含了@XmlRootElement注解,也会将其支持的xml相关媒体类型加入result的:

在这里插入图片描述

在这里插入图片描述

注意:虽然有7种媒体类型(json、xml的媒体类型都有),但是排序筛选后,第一个application/json就已经满足情况,直接就break去后面和messageConvertors进行匹配了,所以也不会输出xml格式,因此,以上返回xml的条件,都需要满足(即controller返回的实体类加上@XmlRootElement外,还需要@RequestMapping注解上传入produces参数,值为application/xml等。同时可知返回json数据的情形下,一般是不会使用到@RequestMapping注解的produces参数的,因上述分析可知,排序筛选后,默认就是返回的json格式数据):

在这里插入图片描述

2.2 单Controller响应返回xml:

@Data
public class JackSonDemo {
    long uid;
    String name;
    Date now;
    LocalDateTime localDay;
}

需要返回xml的实体类上加上注解@XmlRootElement:

@XmlRootElement
@Data
public class JackSonDemoSub {
    String name;
    JackSonDemo jackSonDemo;
}

controller:

@RequestMapping(value = "/jackson")
@RestController
public class TestJackSonController {

    @RequestMapping(value = "/demo1")
    public JackSonDemo jackSonOne(@RequestParam(required = false) String name, @RequestParam(required = false) Integer uid){
        JackSonDemo jackSonDemo = new JackSonDemo();
        if(uid != null){
            jackSonDemo.setUid(uid);
        }else{
            jackSonDemo.setUid(100);
        }

        if(name != null){
            jackSonDemo.setName(name);
        }

        jackSonDemo.setNow(new Date());
        jackSonDemo.setLocalDay(LocalDateTime.now());
        return jackSonDemo;
    }

    @RequestMapping(value = "/demo2",produces = {"application/xml;"})
    public JackSonDemoSub jackSonDemoSub(@RequestParam(required = false) String name){
        JackSonDemo jackSonDemo = new JackSonDemo();
        jackSonDemo.setUid(100);
        if(name != null){
            jackSonDemo.setName(name);
        }
        jackSonDemo.setNow(new Date());
        jackSonDemo.setLocalDay(LocalDateTime.now());

        JackSonDemoSub jackSonDemoSub = new JackSonDemoSub();
        jackSonDemoSub.setJackSonDemo(jackSonDemo);
        jackSonDemoSub.setName("nihao");

        return jackSonDemoSub;
    }
}

全局配置的jackson objectMapper配置(目前是处理json的objectMapper):

@Configuration
public class JacksonGlobalConfig {

    @Bean(name = "jackson2ObjectMapperBuilder")
    /* 观察SpringBoot-2.5.4
    * jackson的自动配置类:JacksonAutoConfiguration 源码
    *  */
    @SuppressWarnings(value = "   deprecation ")
    public Jackson2ObjectMapperBuilder xiaoxuJackson2ObjectMapperBuilder(){
        System.out.println("1.jackson builder注入:");
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        builder.serializationInclusion(JsonInclude.Include.NON_NULL);
        builder.propertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
        builder.featuresToEnable(SerializationFeature.WRAP_ROOT_VALUE);

        /* 针对new Date  SimpleDateFormat线程不安全, 建议使用自定义的日期工具类,
        * 此处只做简单演示配置*/
        /* 注意: 使用 yyyy-MM-dd HH:mm:ss.fff 将报错 */
        /* 使用 dateFormat, new Date 和 LocalDateTime 均会产生对应效果*/
        /* new Date 不设置的情况下,默认返回时间戳 */
        builder.dateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"));
        /* 全局注册自定义序列化器 */
//        builder.serializerByType(JackSonDemo.class, new JackSonDemoSerializer());
        return builder;
    }

    @Bean(name = "jacksonObjectMapper")
    @Primary
    @ConditionalOnBean(name = {"jackson2ObjectMapperBuilder"})
    /* Jackson的ObjectMapper 是线程安全的, 不过SpringBoot2.5.4源码上使用的是非单例模式,这里和源码保持一致 */
    @Scope("prototype")
//    @Scope("singleton")
    public ObjectMapper xiaoxuJacksonObjectMapper(@Qualifier("jackson2ObjectMapperBuilder") Jackson2ObjectMapperBuilder builder){
        System.out.println("2.jackson objectMapper注入:");
        return builder.createXmlMapper(false).build();
    }

}

执行postman请求:

在这里插入图片描述

demo1接口依然返回json数据:

在这里插入图片描述

2.3 全部配置Controller响应返回xml:

如果希望全局配置返回为xml格式,那么需要额外添加jackson-dataformat-xml依赖(必须添加该jackson依赖,否则全局配置使用builder.createXmlMapper(true).build()时,会提示找不到com.fasterxml.jackson.dataformat.xml.XmlMapper类):

<parent>
    <artifactId>spring-boot-starter-parent</artifactId>
    <groupId>org.springframework.boot</groupId>
    <version>2.5.4</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>

    <dependency>
        <groupId>com.fasterxml.jackson.dataformat</groupId>
        <artifactId>jackson-dataformat-xml</artifactId>
        <version>2.11.1</version>
    </dependency>
</dependencies>

修改全局jackson objectMapper配置:

@Configuration
public class JacksonGlobalConfig {

    @Bean(name = "jackson2ObjectMapperBuilder")
    /* 观察SpringBoot-2.5.4
    * jackson的自动配置类:JacksonAutoConfiguration 源码
    *  */
    @SuppressWarnings(value = "   deprecation ")
    public Jackson2ObjectMapperBuilder xiaoxuJackson2ObjectMapperBuilder(){
        System.out.println("1.jackson builder注入:");
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        builder.serializationInclusion(JsonInclude.Include.NON_NULL);
        builder.propertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
        builder.featuresToEnable(SerializationFeature.WRAP_ROOT_VALUE);

        /* 针对new Date  SimpleDateFormat线程不安全, 建议使用自定义的日期工具类,
        * 此处只做简单演示配置*/
        /* 注意: 使用 yyyy-MM-dd HH:mm:ss.fff 将报错 */
        /* 使用 dateFormat, new Date 和 LocalDateTime 均会产生对应效果*/
        /* new Date 不设置的情况下,默认返回时间戳 */
        builder.dateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"));
        /* 全局注册自定义序列化器 */
//        builder.serializerByType(JackSonDemo.class, new JackSonDemoSerializer());
        return builder;
    }

    @Bean(name = "jacksonObjectMapper")
    @Primary
    @ConditionalOnBean(name = {"jackson2ObjectMapperBuilder"})
    /* Jackson的ObjectMapper 是线程安全的, 不过SpringBoot2.5.4源码上使用的是非单例模式,这里和源码保持一致 */
    @Scope("prototype")
//    @Scope("singleton")
    public ObjectMapper xiaoxuJacksonObjectMapper(@Qualifier("jackson2ObjectMapperBuilder") Jackson2ObjectMapperBuilder builder){
        System.out.println("2.jackson objectMapper注入:");
        return builder.createXmlMapper(true).build();
    }

}

针对controller不做改动,再次执行:

demo1:

在这里插入图片描述

demo2的返回实体类,去掉@XmlRootElement注解:

在这里插入图片描述

在这里插入图片描述

可见,全局配置后,均返回xml数据(即使demo2接口的返回实体类去掉@XmlRootElement注解,效果也是一致);但是注意区别,由上述源码分析可知,因为demo1接口的@RequestMapping注解没有添加produces参数,所以媒体类型最后依然是application/json(响应头的Content-Type有所区别),只是使用的jackson的XmlMapper进行处理的结果,故而返回xml格式的数据时,Controller上的@RequestMapping最好都加上produces = {“application/xml;”}参数。

若整个controller下的全部接口都是返回xml,无需单独配置,统一如下配置即可:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/145104.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

u盘有病毒怎么办?修复U盘,3个方法解决

U盘和外部的驱动器相比&#xff0c;它的体积更小&#xff0c;携带更加方便&#xff0c;可以轻松地与他人分享文件。虽然U盘使用很方便&#xff0c;但是有时会出现中病毒的情况。u盘有病毒怎么办&#xff1f;如果您也受到此问题的影响&#xff0c;我们可以提供一种有效的方法来修…

物联网架构实例—Ubuntu 安装Redis

1.准备更新apt-get源sudo apt-get update2.安装执行Redis 安装命令sudo apt-get install redis-server3.检查安装状态sudo /etc/init.d/redis-server status查看Redis运行进程ps -aux|grep redis4.将Redis添加到服务器启动项修改/etc/rc.localvim /etc/rc.local将下面的命令加到…

阿里云办公安全产品专家高传贵:零信任,让全球办公安全更简单

2022 年 8 月 30 日&#xff0c;阿里云用户组&#xff08;AUG&#xff09;第 9 期活动在北京举办。活动现场&#xff0c;阿里云办公安全产品专家高传贵&#xff0c;向参会企业代表分享了零信任&#xff0c;让全球办公安全更简单。本文根据演讲内容整理而成。 大家下午好。我今天…

内部类导致的内存泄漏

前两天刷文章偶然翻到一篇因使用非静态内部类时导致内存泄漏的问题,出于好奇自己也动手一试 什么叫内存泄漏 内存泄漏&#xff08;Memory Leak&#xff09;是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放&#xff0c;造成系统内存的浪费&#xff0c;导致程序…

WuThreat首个发布全球领先的身份安全云产品ITDR Cloud

随着数字化、人工智能&#xff0c;公有/私有云&#xff0c;物联网络及5G等技术的全面普及和迭代更新&#xff0c;身份管理建设作为企业重要的基础设施。然而现在黑客攻击手段复杂多样&#xff0c;在历年的实战攻防演习中有大量的应用系统与基础设施的的身份入口被攻破&#xff…

【从零开始学习深度学习】38. Pytorch实战案例:梯度下降、随机梯度下降、小批量随机梯度下降3种优化算法对比【含数据集与源码】

本文将使用一个来自NASA测试不同飞机机翼噪音的数据集&#xff0c;通过梯度下降、随机梯度下降、小批量随机梯度下降这3种优化算法进行模型训练&#xff0c;比较3种训练结果的差异。 目录1. 梯度下降、随机梯度下降、小批量随机梯度下降区别2. 读取训练数据3. 从零实现3种梯度算…

多线程与高并发(16)——线程池原理(ThreadPoolExecutor源码)

本文从ThreadPoolExecutor源码来理解线程池原理。 ThreadPoolExecutor使用了AQS、位操作、CAS操作等。在看这篇文章之前&#xff0c;需要具备以下知识&#xff1a; 多线程与高并发&#xff08;6&#xff09;——CAS详解&#xff08;包含ABA问题&#xff09; 多线程与高并发&…

腾讯三面:进程写文件过程中,进程崩溃了,文件数据会丢吗?

进程写文件&#xff08;使用缓冲 IO&#xff09;过程中&#xff0c;写一半的时候&#xff0c;进程发生了崩溃&#xff0c;会丢失数据吗&#xff1f; 答案&#xff0c;是不会的。 因为进程在执行 write &#xff08;使用缓冲 IO&#xff09;系统调用的时候&#xff0c;实际上是…

企业宣传片制作配音,我们该从哪里找?

优秀的品质的配音是制作优质企业视频必不可少的硬件条件。因此&#xff0c;许多公司视频配音或旁白声音是由专门从事配音行业的人员配音的。 首先是在宣传视频中配音的作用 1.宣传视频的配音为您建立企业形象 2.宣传视频的配音将为您打开市场 3.宣传视频的配音将使您的宣传…

深入理解Synchronized

Synchronized 底层原理 Synchronized的语义底层是通过一个 Monitor 的对象来完成&#xff0c;其实wait/notify等方法也依赖于 Monitor 对象&#xff0c;这就是为什么只有在同步的块中&#xff0c;拿到锁之后&#xff0c;才能调用wait/notify等方法&#xff0c;否则会抛出java.…

AI助力产品质量检验,基于YOLO实现瓷砖缺陷问题检测识别

在我之前的文章中也写过很多关于生产质检相关的实践文章&#xff0c;一直觉得这块是比较有意思的应用方向&#xff0c;做出来的模型能够以一种更加直观贴切的形式展现出来&#xff0c;瓷砖缺陷问题检测识别也是一个比较老的话题了&#xff0c;今天还是想拿出来具体实践做一下&a…

Golang.org/x库初探1——image库

Golang有一个很有意思的官方库&#xff0c;叫golang.org/x&#xff0c;x可能是extends&#xff0c;experimental&#xff0c;总之是一些在官方库中没有&#xff0c;但是又很有用的库。最近花点时间把这里有用的介绍一下。 Image库 提供更多的图像格式 golang.org/x/image库整…

Linux 网络驱动

1. linux 里面驱动三巨头&#xff1a;字符设备驱动、块设备驱动、网络设备驱动。2.嵌入式网络硬件分为两部分&#xff1a; MAC 和 PHY。如果一款芯片数据手册说自己支持网络&#xff0c;一般都是说的这款 SOC 内置 MAC&#xff0c; MAC 类似 I2C 控制器、SPI 控制器一样的外设。…

Java三大技术平台是什么?

为了使软件开发人员、服务提供商和设备生产商可以针对特定的市场进行开发&#xff0c;SUN公司将Java划分为三个技术平台&#xff0c;它们分别是 JavaSE、 JavaEE和 JavaME。Java SE( Java Platform Standard Edition)标准版&#xff0c;是为开发普通桌面和商务应用程序提供的解…

零宽断言正则表达式替换方案

一、背景 safari浏览器不支持零宽断言正则表达式 二、解决方案 使用其他正则替换零宽断言正则&#xff08;包含&#xff1a;(?<)正向肯定预查、(?<!)正向否定预查、(?)反向肯定预查、(?!)反向否定预查&#xff09; 三、涉及场景 1、仅校验&#xff0c;不取值 如表…

首汽约车驶向极速统一之路!出行平台如何基于StarRocks构建实时数仓?

作者&#xff1a;王满&#xff0c;高级数据架构工程师首汽约车&#xff08;以下简称 “首约”&#xff09;是首汽集团为响应交通运输部号召&#xff0c;积极拥抱互联网&#xff0c;推动传统出租车行业转型升级&#xff0c;加强建设交通强国而打造的网约车出行平台。 在用车服务…

KernelSU: 内核 ROOT 方案, KernelSU KernelSU KernelSU 新的隐藏root防止检测 封号方案

大约一年多以前&#xff0c;我在一篇讲Android 上 ROOT 的过去、现在和未来https://mp.weixin.qq.com/s?__bizMjM5Njg5ODU2NA&mid2257499009&idx1&sn3cfce1ea7deb6e0e4f2ac170cffd7cc1&scene21#wechat_redirect 的文章中提到&#xff1a; 我认为&#xff0c;随…

三菱FX5U 多个表格运行指令 DRVTBL

简述该指令可以用GX Works3预先在表格数据中设定的控制方式的动作&#xff0c;&#xff08;连续或步进&#xff09; 执行多行。 本文演示了步进执行多行。指令解释2.1梯形图中的指令第一个参数&#xff1a;输出脉冲的轴编号 &#xff0c;K1,K2,K3,K4... 第二个参数&#xff1a;…

ESP8266 Windows开发环境搭建(IDE1.5)好用不骗人

最近一个项目需要用ESP8266&#xff0c;找了很多文章进行环境搭建编译都很问题&#xff0c;不是make Menuconfig 不出来&#xff0c;就是编译报错&#xff0c;现总结如下。 我在自己电脑上没弄出来&#xff0c;就安装了一个虚拟机很干净的环境没有其它开发环境影响。 提前去官…

逆向入门|全国建筑市场监管公共服务平台JS逆向

看了志远的公开课&#xff0c;自己做一下练手。 全国建筑市场监管公共服务平台&#xff08;四库一平台&#xff09; 先点到 数据这里打开f12看一眼 第一个就是 https://jzsc.mohurd.gov.cn/api/webApi/dataservice/query/comp/list?pg1&pgsz15&total450 取这个地址…