大数跨境
0
0

太强了!Spring Boot + JAXB 处理XML只需5行代码

太强了!Spring Boot + JAXB 处理XML只需5行代码 Spring全家桶实战案例
2025-09-06
0
导读:太强了!Spring Boot + JAXB 处理XML只需5行代码
Spring Boot 3实战案例锦集PDF电子书已更新至130篇!

🎉🎉《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.实战案例

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对象。

@XmlAccessorType(XmlAccessType.FIELD)@XmlRootElement(name = "user")@XmlType(propOrder = { "id""name""age"})public class User {  @XmlAttribute(name = "id")  private Long id ;  @XmlElement(name = "name")  private String name ;  @XmlElement(name = "age")  private Integer age ;  @XmlElement(name = "birthday")  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讲"33new Date());StringWriter writer = new StringWriter();marshaller.marshal(user, writer);String xmlString = writer.toString();System.out.println(xmlString);

输出结果

2.4 自定义适配器

接下来,我们将上面的birthday属性修改为LocalDate类型,如下:

@XmlElement(name = "birthday")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");  @Override  public LocalDate unmarshal(String v) throws Exception {    return LocalDate.parse(v, FORMATTER);  }  @Override  public String marshal(LocalDate v) throws Exception {    return v.format(FORMATTER);  }}

接着,在birthday字段上添加如下注解

@XmlJavaTypeAdapter(LocalDateAdapter.class)@XmlElement(name = "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 [id=1, name=Spring Boot3实战案例200讲, age=33, birthday=2025-08-09]

2.6 生成Schema & 验证XML

JAXB 提供以下内置支持:

  • 根据带注解的 Java 类生成 XML 模式定义(XSD)

  • 在反序列化(Unmarshalling)过程中,依据这些 XSD 模式对 XML 文档进行校验

生成Schema

JAXBContext context = JAXBContext.newInstance(User.class);context.generateSchema(new SchemaOutputResolver() {  @Override  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依赖,那么你不需要做任何事。如下

@GetMapping(value = "/query", produces = "application/xml")public ResponseEntity<?> query() {  return ResponseEntity.ok(new User(1L, "Spring Boot3实战案例200讲"33LocalDate.now())) ;}

只需要将produces设置为 application/xml

XML转User对象

@PostMapping("/save")public ResponseEntity<?> save(@RequestBody User user) {  return ResponseEntity.ok(user) ;}

验证XML的有效性

要想实现验证功能,我们需要自定义Jaxb2RootElementHttpMessageConverter,如下示例:

@Componentpublic class PackJaxb2RootElementHttpMessageConverter extends Jaxb2RootElementHttpMessageConverter {  @Override  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实现不一样的通用DAO,值得学习

在 Spring Boot 中加载属性文件的7种方法

Spring Boot中通过3种方式初始化数据,你们如何选择?

SpringBoot多租户3种架构实现方案详解

优雅!基于Spring Boot字段加密后的模糊查询,支持MyBatis, JPA

基于SpringBoot通过3种方式轻松搞定敏感字段加密处理

性能优化!7个策略,让Spring Boot 处理每秒百万请求

5种实现方式配置Spring Boot API接口超时时间

【声明】内容源于网络
0
0
Spring全家桶实战案例
Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
内容 832
粉丝 0
Spring全家桶实战案例 Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
总阅读38
粉丝0
内容832