Spring Boot响应结果同时支持json和xml,Java Bean对象列表与xml互转

虽然目前接口都流行响应json格式数据,但平时开发还是免不了有返回xml格式数据的需求,遇到这种情况自己写个xml解析&转换器显然太明智了,对于使用SpringBoot开发的小伙伴儿还是挺幸福的,SpringBoot已经完美支持这两种格式的解析和转换。
对于@RestController 默认支持返回json格式数据,即使不做任何配置也能返回json数据,但是返回xml格式的数据该怎么做?

@RestController
public class DemoController {
@RequestMapping(value = "/query", produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE })
public Object demo() {

}
}

然后通过query.json或者query.xml分别获取json和xml数据(不能通过设置Content-Type头为application/json或application/xml访问)
说明:网上搜的一些关于SpringBoot返回xml格式的教程都要加jackson-dataformat-xml的依赖,但是作者没有引入这个依赖依然正常使用
话外音:SpringBoot默认使用JAXB进行JavaBean和xml之间的转换。JAXB(Java Architecture for XML Binding)是根据XML Schema映射到JavaBean的技术。过程中,JAXB将XML实例文档反向生成Java对象树的方法,并能将Java对象树的内容重新写到 XML实例文档。

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


接下来是Java Bean与xml怎样使用注解进行互转,尤其使用对象列表时如何优雅的使用注解转成xml呢?
先给出目标xml格式:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<BandWidthData>
<Result>success</Result>
<DetailInfo>expired 136 milliseconds.</DetailInfo>
<ChannelGroupIDs>
<ChannelGroupID ID="70813" Value="2180053898">
<Region Name="9050" Value="2180053898"/>
<Region Name="10200" Value="0"/>
</ChannelGroupID>
<ChannelGroupID ID="2539" Value="485842">
<Region Name="9050" Value="485842"/>
<Region Name="10200" Value="0"/>
</ChannelGroupID>
</ChannelGroupIDs>
</BandWidthData>

这个xml的结构有个较难的点就是如何使用注解表示这个ChannelGroupIDs列表?
先给出对应的Java Bean再解释各个注解的作用

最外层对象:
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) //返回xml格式时非必须,此注解是转json的蛇形命名用的
@XmlRootElement(name = "BandWidthData") // 定义xml根节点
@XmlType(propOrder = { "result", "detailInfo", "channelGroupBandwiths" }) // 定义xml节点的顺序
public class BandwidthDataResult {

private String result;
private List<ChannelGroupBandwithResult> channelGroupBandwiths;
private String detailInfo;
public String getResult() {
return result;
}

@XmlElement(name = "Result") //定义xml节点
public void setResult(String result) {
this.result = result;
}

public List<ChannelGroupBandwithResult> getChannelGroupBandwiths() {
return channelGroupBandwiths;
}

@XmlElementWrapper(name = "ChannelGroupIDs") // 定义list包装层节点的名称
@XmlElement(name = "ChannelGroupID") // 映射List中每个节点的名称
public void setChannelGroupBandwiths(List<ChannelGroupBandwithResult> channelGroupBandwiths) {
this.channelGroupBandwiths = channelGroupBandwiths;
}

public String getDetailInfo() {
return detailInfo;
}

@XmlElement(name = "DetailInfo")
public void setDetailInfo(String detailInfo) {
this.detailInfo = detailInfo;
}
}

中间对象:
import java.util.List;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
@XmlType(propOrder = { "channelGroupId", "channelGroupBandwith", "regionBandwiths" })
public class ChannelGroupBandwithResult {
private long channelGroupId;
private long channelGroupBandwith;
private List<RegionBandwithResult> regionBandwiths;

public long getChannelGroupId() {
return channelGroupId;
}

@XmlAttribute(name = "ID") // 映射将该对象的此属性为xml节点的属性
public void setChannelGroupId(long channelGroupId) {
this.channelGroupId = channelGroupId;
}

public long getChannelGroupBandwith() {
return channelGroupBandwith;
}

@XmlAttribute(name = "Value") // 同上
public void setChannelGroupBandwith(long channelGroupBandwith) {
this.channelGroupBandwith = channelGroupBandwith;
}


public List<RegionBandwithResult> getRegionBandwiths() {
return regionBandwiths;
}

@XmlElement(name = "Region")
public void setRegionBandwiths(List<RegionBandwithResult> regionBandwithResults) {
this.regionBandwiths = regionBandwithResults;
}
}

底层对象:
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
@XmlType(propOrder = { "regionName", "regionBandwith" })
public class RegionBandwithResult {
private String regionName;
private long regionBandwith;

public String getRegionName() {
return regionName;
}

@XmlAttribute(name = "Name")
public void setRegionName(String regionName) {
this.regionName = regionName;
}

public long getRegionBandwith() {
return regionBandwith;
}

@XmlAttribute(name = "Value")
public void setRegionBandwith(long regionBandwith) {
this.regionBandwith = regionBandwith;
}
}

至此基本可以支持Java Bean的List对象转xml格式了。
采坑记录:1、作者最初使用lombok的@Setter、@Getter生成bean的set和get方法,同时把@XmlAttribute(name = “Name”)注解标在属性上,导致别名name=”Name”失效了;2、xml的相关注解不要同时在set和get方法上使用。
其他注解:1、@XmlValue 映射List中对象的属性 到 xml节点的值,代码如下:

目标接收xml格式数据:
<?xml version="1.0" encoding="GB2312"?>
<BandWidthDatas>
<Result>success</Result>
<Datas>
<Data area="9050" chlgrp="10018487" >47870270,</Data>
<Data area="10200" chlgrp="10018487" >0,</Data>
<Data area="9050" chlgrp="33755" >6460458,</Data>
<Data area="10200" chlgrp="33755" >0,</Data>
</Datas>
</BandWidthDatas>

Java类的最外层对象结构:
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "BandWidthDatas")
public class BandWidthDataDTO {

private String result;

private List<BandWidthDetailDataDTO> datas;

@XmlElement(name = "Result")
public String getResult() {
return result;
}

public void setResult(String result) {
this.result = result;
}

@XmlElementWrapper(name = "Datas")
@XmlElement(name = "Data")
public List<BandWidthDetailDataDTO> getDatas() {
return datas;
}

public void setDatas(List<BandWidthDetailDataDTO> datas) {
this.datas = datas;
}
}

Java类最底层对象结构:
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlValue;

public class BandWidthDetailDataDTO {
private String area;
private String chlgrp;
private String value;

@XmlAttribute(name = "area")
public String getArea() {
return area;
}

public void setArea(String area) {
this.area = area;
}

@XmlAttribute(name = "chlgrp")
public String getChlgrp() {
return chlgrp;
}

public void setChlgrp(String chlgrp) {
this.chlgrp = chlgrp;
}

@XmlValue // 映射xml节点的值
public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}
}

haozi wechat
扫二维码关注我
鼓励原创