項目場景:
工作中需要給下游第三方收費系統(tǒng)做數(shù)據(jù)擋板,由于下游系統(tǒng)使用的是soap webservice
,里面涉及各種xml跟bean的互轉,在此介紹一下使用的方法。基于springboot搭建webservice的過程將會在下篇博客介紹
互轉方法
這里介紹兩種方法.
- 使用
jackson
進行互轉,Spring boot
項目自帶的json
和bean
的互轉的框架,他其實還有xml
與bean
的互轉。 - 使用
jaxws
進行xml
與bean
的互轉
使用jackson進行互轉
因為Spring Boot 項目其他依賴基本上都會引入,只是缺少一個依賴
com.fasterxml.jackson.dataformat:jackson-dataformat-xml
,所以只需要引入這一個依賴即可。
- gradle引入
implementation('com.fasterxml.jackson.dataformat:jackson-dataformat-xml')
- maven 引入
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.13.5</version>
</dependency>
- 可以做成一個通用的XMLUtils工具類,代碼如下:
public static String javaBean2Xml(Object javaBean) throws JsonProcessingException {
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.setDefaultUseWrapper(false);
//字段為null就自動忽略,不再序列化
xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//XML標簽名:使用駱駝命名的屬性名,
xmlMapper.setPropertyNamingStrategy(PropertyNamingStrategies.UPPER_CAMEL_CASE);
//設置轉換模式,就是根據(jù)getter、setter方法,設置為第一個字母小寫這種
xmlMapper.enable(MapperFeature.USE_STD_BEAN_NAMING);
return xmlMapper.writeValueAsString(javaBean);
}
public static <T> T Xml2javaBean(String javaBean, Class<T> tClass) throws JsonProcessingException {
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.setDefaultUseWrapper(false);
//字段為null,自動忽略,不再序列化
xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//XML標簽名:使用駱駝命名的屬性名,
xmlMapper.setPropertyNamingStrategy(PropertyNamingStrategies.UPPER_CAMEL_CASE);
//設置轉換模式,就是根據(jù)getter、setter方法,設置為第一個字母小寫這種
xmlMapper.enable(MapperFeature.USE_STD_BEAN_NAMING);
return xmlMapper.readValue(javaBean, tClass);
}
- POJO類,后續(xù)都會用這個做例子
public class Student {
private String name;
private String teacher;
private Integer age;
....省略構造函數(shù)和getter和setter
}
- 測試案例
public static void main(String[] args) throws JsonProcessingException {
Student student = new Student("張三","張老師", 26);
String s = XMLUtils.javaBean2Xml(student);
System.out.println(s);
System.out.println(XMLUtils.Xml2javaBean(s, Student.class));
}
結果:
- 可能會出現(xiàn)的bug
在使用
jackson
去進行轉換的時候,POJO類不管幾個構造函數(shù),一定要有無參構造,否則就會報錯。
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance ofStudent
(no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
- 如果想給POJO的屬性的XML起個別名怎么辦,
jackson
是提供了相關的注解。
- @JacksonXmlRootElement
namespace屬性:用于指定XML根元素命名空間的名稱。
localname屬性:用于指定XML根元素節(jié)點標簽的名稱。- @JacksonXmlProperty
namespace和localname屬性用于指定XML命名空間的名稱,isAttribute指定該屬 性作為XML的屬性()還是作為子標簽().- @JacksonXmlText注解將屬性直接作為未被標簽包裹的普通文本。
- @JacksonXmlCData將屬性包裹在CDATA標簽中。
- 集合元素的映射
@JacksonXmlElementWrapper可以將列表數(shù)據(jù)轉為XML節(jié)點。
useWrapping屬性設置是否設置外圍標簽名,默認true
其他的可以自己嘗試下,如果是List的集合的,是以一對多的一對應的,一里面定義了XML節(jié)點,就以一里面的定義為主。
-
補充完整的依賴,和
Spring Boot
已經(jīng)引入的依賴。文章來源:http://www.zghlxwxcb.cn/news/detail-804174.html- 完整依賴
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> <version>2.13.5</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.13.5</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.13.5</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.13.5</version> </dependency>
-
Spring Boot
已經(jīng)引入的依賴,以2.6.12為例
- 完整依賴
使用jaxws進行xml與bean的互轉
使用起來基本是跟
jackson
差不多的。好處就是jdk自己就有提供,不需要引入額外的工具包,主要是使用javax
下的JAXBContext
接口,利用Marshaller
和Unmarshaller
接口來進行xml
與bean
的互轉。
但是需要注意的是文章來源地址http://www.zghlxwxcb.cn/news/detail-804174.html
- 必須要提供
無參構造器
,否則會報錯com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions Student沒有無參數(shù)默認構造器。- 必須在類上提供@javax.xml.bind.annotation.XmlRootElement,否則會報錯javax.xml.bind.MarshalException
-with linked exception:
[com.sun.istack.SAXException2: 由于類型 “Student” 缺少 @XmlRootElement 注釋, 無法將該類型編集為元素]- 如果不提供@javax.xml.bind.annotation.XmlElement注解,那么所產(chǎn)生的XML節(jié)點均為屬性值,就是小寫。
- @javax.xml.bind.annotation.XmlElement定義的值不能跟getter方法一起出現(xiàn),否則會報錯com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
類的兩個屬性具有相同名稱 “name”
- 老規(guī)矩,工具類
public static String beanToXml (Object obj, Class<?> zlass) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(zlass);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "GBK");
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
StringWriter writer = new StringWriter();
marshaller.marshal(obj,writer);
return writer.toString();
}
public static <T> T xmlToBean (String xml, Class<T> zlass) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(zlass);
Unmarshaller unmarshaller = context.createUnmarshaller();
Object object = unmarshaller.unmarshal(new StringReader(xml));
return (T) object;
}
- Marshaller 接口中還定義了5個屬性,分別是:
- JAXB_ENCODING
這個屬性是設置編碼集,
marshaller.setProperty(Marshaller.JAXB_ENCODING, “GBK”);- JAXB_FORMATTED_OUTPUT
這個屬性是是否格式化生成的xml串 true-格式化,false-不格式化
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);- JAXB_SCHEMA_LOCATION
指定xsi:schemaLocation,它定義了XML Namespace和對應的XSD(Xml Schema Definition)文檔的位置的關系。它的值由一個或多個URI引用對組成,兩個URI之間以空白符分隔(空格和換行均可)。第一個URI是定義的XML Namespace的值,第二個URI給出Schema文檔的位置,Schema處理器將從這個位置讀取Schema文檔,該文檔的targetNamespace必須與第一個URI相匹配。
marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, “xxx.xxx.xxx”);- JAXB_NO_NAMESPACE_SCHEMA_LOCATION
如果沒有Namespeace,但是需要使用Schema,就需要用到JAXB_NO_NAMESPACE_SCHEMA_LOCATION,它可以指定將放置在已編組 XML 輸出中的 xsi:noNamespaceSchemaLocation 屬性值
marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, “xxx.xxx.xxx”);- JAXB_FRAGMENT
是否省略xml頭信息()true-省略,false-不省略
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);
- 代碼
public static void main(String[] args) throws Exception {
Student student = new Student("張三","張老師", 26);
String s = XMLUtils.beanToXml(student, Student.class);
System.out.println(s);
System.out.println(XMLUtils.xmlToBean(s, Student.class));
}
- 測試
- 最后補充幾個注解
- @XmlRootElement
類級別的注解,這個注解為根節(jié)點的注解,加在類上面,而且為必要的注解,如果沒有此注解,執(zhí)行beanToXml方法時將會報異常。這個根節(jié)點默認名字為類名,但是可以設置name屬性來修改根節(jié)點名字。namespace屬性可以用于指定生成的元素所屬的命名空間。- @XmlElement
字段,方法級別的注解,將java類的屬性映射為xml的一個結點。一般使用在屬性上,或者get方法上,其中常用的屬性有name、nillable、namespace、defaultValue。name可以設置結點的名稱;nillable 指定文本是否可以為空,true-可以為空,false-不可以為空,默認為false,如果設置為true,則該字段為空是,這個結點也會生成,但是值為空,如果是指為false,則該結點不生成;namespace屬性可以用于指定生成的元素所屬的命名空間;defaultValue 可以設置該結點的默認文本。- @XmlTransient
類,字段,方法級別的注解。當添加這個注解后,這個屬性或者類將不進行映射。需要注意的是該注解與所有其他JAXB注解相互排斥.- @XmlAccessorType
類級別注解,其中有一個value屬性,值為XmlAccessType的枚舉類。
1.XmlAccessType.PROPERTY 加這個value表示,會將所有擁有get方法和set方法的屬性(必須2個方法都有,否則不映射)映射成xml,除非加入@XmlTransient則不會映射,如果沒有get/set方法,則需要再屬性上加上@XmlElement。
2.XmlAccessType.FIELD
這個屬性是將類中非靜態(tài)的屬性都映射到xml中,并且不需要加get/set方法
3.XmlAccessType.PUBLIC_MEMBER
這個屬性值,是@XmlAccessorType的默認默認值,它會將屬性為public的屬性或者get/set方法同時為public的屬性映射成xml。
4.XmlAccessType.NONE
這個屬性表示任何屬性都不會被映射到xml中,除非使用其他注解,如@XmlElement- @XmlAccessorOrder
類級別的注解??刂粕蓪傩杂成鋢ml結點的順序。其中有一個value屬性,可以設置排序方式,XmlAccessOrder.ALPHABETICAL 為按照字母順序進行排序, XmlAccessOrder.UNDEFINED按照屬性順序進行排序,默認為XmlAccessOrder.UNDEFINED- @XmlJavaTypeAdapter
這個注解主要是解決一些數(shù)據(jù)格式化問題的,比如時間格式化。- @XmlElementWrapper
這個注解是加在集合上面的- @XmlAttribute
這個注解會將屬性變?yōu)樯弦粋€結點的屬性- @XmlType
類級別的注解,這個注解可以自定義排序,使用propOrder 屬性。
搞定收工!
到了這里,關于Spring boot項目java bean和xml互轉的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!