雖然 JSON 為主流,但金融、政企、對接舊系統等場景仍強制要求 **XML 響應**。Spring MVC 內置 `Jaxb2RootElementHttpMessageConverter`,**零額外依賴** (JDK 6+ 內置 JAXB) 即可實現對象自動轉 XML。本文演示**實體類 JAXB 註解、統一響應基類、泛型數據字段、Controller 返回、XML 輸出效果**全流程。
<dependencies>
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.25</version></dependency>
<!-- JAXB 在 JDK 6-10 內置;JDK 11+ 需額外引入 -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId><version>2.3.3</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId><version>2.3.3</version>
</dependency>
</dependencies>
public class BaseXmlResult {
protected String code; // 業務狀態碼:0000 成功、其它失敗
protected String message; // 提示信息
public String getCode() { return code; }
public void setCode(String code) { this.code = code; }
public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; }
}
@XmlRootElement(name = "xml") // XML 根元素名@XmlAccessorType(XmlAccessType.NONE) // 僅序列化標註字段 public class XmlActionResult<T> extends BaseXmlResult { @XmlElements({ // 多態支持:根據實際類型輸出對應標籤 @XmlElement(name = "Person", type = Person.class), @XmlElement(name = "Man", type = Man.class), @XmlElement(name = "Woman", type = Woman.class) }) private T data; // 泛型業務數據 public T getData() { return data; } public void setData(T data) { this.data = data; } // 繼承 code、message getter/setter }
關鍵點:
@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
public class Person {
@XmlElement private String name;
@XmlElement private Integer sex; // 1 男 2 女
@XmlElement private Integer age;
private Date birthday; // 無 @XmlElement → 不輸出
public Person() {}
public Person(String name, Integer sex, Integer age) {
this.name = name; this.sex = sex; this.age = age;
}
// getter/setter 省略
// birthday 僅作演示:若需輸出需加 @XmlElement + @XmlJavaTypeAdapter 格式化日期
}
public class Man extends Person {
public Man(String name, int age) { super(name, 1, age); }
}
public class Woman extends Person {
public Woman(String name, int age) { super(name, 2, age); }
}
@Controller
@RequestMapping("/mvc")
public class HelloController {
@GetMapping("/helloXmlPerson/{name}")
@ResponseBody // 關鍵:觸發 HttpMessageConverter 轉換
public XmlActionResult<Person> helloXmlPerson(@PathVariable String name) {
XmlActionResult<Person> result = new XmlActionResult<>();
result.setCode("0000");
result.setMessage("請求成功: " + name);
result.setData(new Person("張三", 1, 28));
return result;
}
}
<mvc:annotation-driven /> <!-- 自動註冊 Jaxb2RootElementHttpMessageConverter -->或 JavaConfig:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new Jaxb2RootElementHttpMessageConverter());
}
}
GET /mvc/helloXmlPerson/nihao
<xml>
<code>0000</code>
<message>請求成功: nihao</message>
<Person>
<name>張三</name>
<sex>1</sex>
<age>28</age>
</Person>
</xml>
若 `setData(new Woman("李四", 25))`,輸出 `
| 需求 | 解決方案 |
|---|---|
| 日期格式化 | 字段加 `@XmlJavaTypeAdapter(DateAdapter.class)`,實現 `XmlAdapter |
| XML 命名空間 | 包級註解 `@XmlSchema(namespace="https://example.com", elementFormDefault=XmlNsForm.QUALIFIED)` (package-info.java) |
| CDATA 區塊 | 字段類型用 `javax.xml.bind.annotation.XmlCDATA` 包裝類,或自定義 Adapter 輸出 `` |
| 集合輸出包裝標籤 | `@XmlElementWrapper(name="persons")` + `@XmlElement(name="person")` → ` |
Spring MVC 返回 XML **零配置、零額外依賴 (JDK 內置 JAXB)**,核心在於:**實體類標註 JAXB 註解、統一響應基類封裝 code/message、泛型數據用 `@XmlElements` 支持多態、Controller 加 `@ResponseBody`、啟用 `