🎉🎉《Spring Boot实战案例合集》目前已更新166个案例,我们将持续不断的更新。文末有电子书目录。
💪💪永久更新承诺
我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务。
💌💌如何获取
订阅我们的合集《点我订阅》,并通过私信联系我们,我们将第一时间将电子书发送给您。
环境:SpringBoot3.4.2
1. 简介
在项目开发中,处理XML格式的API响应是常见需求,尤其在对接遗留系统、政务平台或金融行业等对数据结构要求严格的场景时,XML因其自描述性、命名空间支持和强类型约束成为首选。然而,Spring Boot默认集成的Jackson XML虽能快速实现XML与Java对象互转,但在复杂场景下存在局限。
相比之下,JAXB作为JDK原生技术(JDK11之后需要自行引入依赖包),与XML Schema深度集成,可通过XSD文件自动生成强类型Java类,天然支持数据校验,减少手动编码错误。
本篇文章中,我们将详细的介绍JAXB的使用,以及如何与Spring Boot结合使用。
2.1 引入依赖
由于我们使用的Java21版本,所以需要自行引入JAXB相关依赖(11版本之前是不需要的)。
<dependency><groupId>jakarta.xml.bind</groupId><artifactId>jakarta.xml.bind-api</artifactId></dependency><dependency><groupId>org.glassfish.jaxb</groupId><artifactId>jaxb-runtime</artifactId></dependency>
2.2 JAXB中常用注解
@XmlRootElement
指定 XML 的根元素。默认情况下,根元素名称源自类名,但可通过 name 属性显式覆盖。(例:@XmlRootElement(name = "user") 将根元素设为 <user> 而非类名默认值。)
@XmlType
定义字段在 XML 输出中的排列顺序,通过 propOrder 数组指定。(例:@XmlType(propOrder = {"id", "name"}) 强制字段按 id、name 顺序输出。)
@XmlElement
指定被注解的 Java 字段或属性对应的 XML 元素名称。(例:@XmlElement(name = "username") 将字段映射为 <username> 而非默认字段名。)
@XmlAttribute
表示被注解的字段或属性应作为 XML 属性(而非元素)呈现。(例:@XmlAttribute 将 id 字段转为 <item id="123"> 中的属性形式。)
@XmlTransient
标记字段或属性在 XML 序列化/反序列化时被忽略(即不包含在 XML 中)。(例:@XmlTransient 可排除敏感字段如 password 不被输出。)
@XmlAccessorType
指定 JAXB 绑定时字段/属性的访问规则,控制哪些成员参与序列化。常用值:XmlAccessType.FIELD:所有字段自动映射(包括非 public 字段);XmlAccessType.PROPERTY:通过 getter/setter 方法映射;XmlAccessType.NONE:仅显式注解的成员生效。
2.3 对象转XML
序列化(Marshalling)允许应用程序将带有 JAXB 注解的 Java 对象转换为 XML 数据。默认情况下,序列化器(Marshaller)在生成 XML 输出时使用 UTF-8 编码。
首先,我们通过上面的注解定义如下POJO对象。
public class User {private Long id ;private String name ;private Integer age ;private Date birthday ;}
通过如下示例将上面的对象转为XML字符串。
JAXBContext context = JAXBContext.newInstance(User.class);Marshaller marshaller = context.createMarshaller();marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);User user = new User(1L, "Spring Boot3实战案例200讲", 33, new Date());StringWriter writer = new StringWriter();marshaller.marshal(user, writer);String xmlString = writer.toString();System.out.println(xmlString);
输出结果
2.4 自定义适配器
接下来,我们将上面的birthday属性修改为LocalDate类型,如下:
private LocalDate birthday ;
再次运行上面的代码输出结果(注意构造函数中使用LocalDate.now())
birthday并没有值。默认情况下jaxb是不支持java8中的日期类型的,我们需要自定义适配器,如下定义:
public class LocalDateAdapter extends XmlAdapter<String, LocalDate> {private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");public LocalDate unmarshal(String v) throws Exception {return LocalDate.parse(v, FORMATTER);}public String marshal(LocalDate v) throws Exception {return v.format(FORMATTER);}}
接着,在birthday字段上添加如下注解
private LocalDate birthday ;
再次运行上面的代码,输出结果
2.5 XML转对象
Unmarshalling 使应用程序能够将 XML 数据转换为 JAXB 注释的 Java 对象。
String xmlString = """<user id="1"><name>Spring Boot3实战案例200讲</name><age>33</age><birthday>2025-08-08</birthday></user>""" ;JAXBContext context = JAXBContext.newInstance(User.class);Unmarshaller unmarshaller = context.createUnmarshaller();StringReader reader = new StringReader(xmlString) ;User user = (User) unmarshaller.unmarshal(reader) ;System.err.println(user) ;
输出结果
User
2.6 生成Schema & 验证XML
JAXB 提供以下内置支持:
根据带注解的 Java 类生成 XML 模式定义(XSD)
在反序列化(Unmarshalling)过程中,依据这些 XSD 模式对 XML 文档进行校验
生成Schema
JAXBContext context = JAXBContext.newInstance(User.class);context.generateSchema(new SchemaOutputResolver() {public Result createOutput(String namespaceUri, String suggestedFileName) throws IOException {return new StreamResult(new File("user.xsd"));}});
生成的user.xsd文件内容:
验证XML
JAXBContext context = JAXBContext.newInstance(User.class);Unmarshaller unmarshaller = context.createUnmarshaller();// 加载并设置SchemaSchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);Schema schema = schemaFactory.newSchema(new File("user.xsd"));unmarshaller.setSchema(schema);String xmlString = """<user id="1"><name>Spring Boot3实战案例200讲</name><age1>33</age1><birthday>2025-08-08</birthday></user>""";StringReader reader = new StringReader(xmlString);User user = (User) unmarshaller.unmarshal(reader) ;System.err.println(user) ;
在该示例代码中,我们故意将age 错写为 age1,运行结果如下:
2.7 整合Spring Boot
在Spring 中,默认提供了JAXB2RootElementHttpMessageConverter转换器也就是如果,你的项目中已经包含了jaxb依赖,那么你不需要做任何事。如下
(value = "/query", produces = "application/xml")public ResponseEntity<?> query() {return ResponseEntity.ok(new User(1L, "Spring Boot3实战案例200讲", 33, LocalDate.now())) ;}
只需要将produces设置为 application/xml
XML转User对象
("/save")public ResponseEntity<?> save( User user) {return ResponseEntity.ok(user) ;}
验证XML的有效性
要想实现验证功能,我们需要自定义Jaxb2RootElementHttpMessageConverter,如下示例:
public class PackJaxb2RootElementHttpMessageConverter extends Jaxb2RootElementHttpMessageConverter {protected void customizeUnmarshaller(Unmarshaller unmarshaller) {SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);Schema schema;try {schema = schemaFactory.newSchema(new File("user.xsd"));} catch (SAXException e) {throw new RuntimeException("XSD解析失败", e) ;}unmarshaller.setSchema(schema) ;}}
再次访问接口(将age写为age1)
你可以通过 @ExceptionHandler 进行全局的异常处理。
建议重写readFromSource方法,在该方法中我们可以知道当前要序列化的是哪个对象,根据对象动态设置Schema。
推荐文章
高并发!Spring Boot 响应式 SSE 实时推送,单机吞吐量10万+
Jackson在Spring Boot高级应用技巧【Long精度丢失, @JsonValue, 数据脱敏】
性能优化!Spring Boot 弃用 Jackson,性能提升50%
拒绝重复造轮子!Spring Boot 六大核心AOP切面,开发必备
Spring Boot中通过3种方式初始化数据,你们如何选择?
优雅!基于Spring Boot字段加密后的模糊查询,支持MyBatis, JPA
基于SpringBoot通过3种方式轻松搞定敏感字段加密处理
性能优化!7个策略,让Spring Boot 处理每秒百万请求


