JDK9以下使用无需引入,jdk9以上需要引入jar包
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
一:常用注解
@XmlRootElement
@XmlElement
@XmlAttribute
@XmlTransient
@XmlAccessorType
@XmlAccessorOrder
@XmlElementWrapper
@XmlJavaTypeAdapter
@XmlValue
@XmlType
二:工具类
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.StringReader;
import java.io.StringWriter;
/**
* @描述:
* @Date: 2023/2/23 10:41
* @Description: // PC002
* @Author: Duys
**/
@Slf4j
public class JaxbUtil {
/**
* xml转换成JavaBean
*
* @param xml
* @param c
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T converyToJavaBean(String xml, Class<T> c) {
T t = null;
try {
JAXBContext context = JAXBContext.newInstance(c);
Unmarshaller unmarshaller = context.createUnmarshaller();
t = (T) unmarshaller.unmarshal(new StringReader(xml));
} catch (Exception e) {
e.printStackTrace();
log.error("XML转Java异常.原因:{}", e.getMessage());
}
return t;
}
/**
* JavaBean转换成xml去除xml声明部分
*
* @param obj
* @param encoding
* @return
*/
public static String convertToXmlIgnoreXmlHead(Object obj, String encoding) {
String result = null;
try {
JAXBContext context = JAXBContext.newInstance(obj.getClass());
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, encoding);
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
StringWriter writer = new StringWriter();
marshaller.marshal(obj, writer);
result = writer.toString();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
三:注解使用
@XmlRootElement
将Java类或枚举映射成XML元素根节点,是唯一一个必须注解,name属性指定根节点名称,不指定默认为类名的小写;
import lombok.Data;
import javax.xml.bind.annotation.XmlRootElement;
/**
* @描述: 测试类
* @Date: 2023/3/8 13:50
* @Description: // PC002
* @Author: Duys
**/
@Data
@XmlRootElement(name = "test")
public class TestVo {
private String age;
}
import cn.hutool.json.JSONUtil;
import com.jfsoft.interfaces.core.service.LisInterfaceService;
import com.jfsoft.interfaces.entity.his.vo.Reqxml;
import com.jfsoft.interfaces.entity.his.vo.TestVo;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class LisTest {
@Test
public void test1() {
TestVo vo = new TestVo();
vo.setAge("50");
String xml = JaxbUtil.convertToXmlIgnoreXmlHead(vo, "utf-8");
log.info("xml >>> {}", xml);
}
}
生成的
xml >>>
<test>
<age>50</age>
</test>
@XmlElement
将Java类的一个属性映射为XML节点元素,name属性可自定义元素名;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* @描述: 测试类
* @Date: 2023/3/8 13:50
* @Description: // PC002
* @Author: Duys
**/
@XmlAccessorType(XmlAccessType.PROPERTY)
@XmlRootElement(name = "test")
public class TestVo {
private String age;
public String getAge() {
return age;
}
@XmlElement(name = "ageFull")
public void setAge(String age) {
this.age = age;
}
}
import com.jfsoft.interfaces.entity.his.vo.TestVo;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import java.io.StringWriter;
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class LisTest {
@Test
public void test0002() {
TestVo vo = new TestVo();
vo.setAge("50岁");
String xml = JaxbUtil.convertToXmlIgnoreXmlHead(vo, "utf-8");
log.info("xml >>> {}", xml);
}
}
xml >>>
<test>
<ageFull>50岁</ageFull>
</test>
@XmlAttribute
将Java类的一个属性映射为XML节点元素的属性,name属性可自定义属性名;
import javax.xml.bind.annotation.*;
/**
* @描述: 测试类
* @Date: 2023/3/8 13:50
* @Description: // PC002
* @Author: Duys
**/
@XmlAccessorType(XmlAccessType.PROPERTY)
@XmlRootElement(name = "test")
public class TestVo {
private String age;
public String getAge() {
return age;
}
@XmlAttribute(name = "value")
public void setAge(String age) {
this.age = age;
}
}
import com.jfsoft.interfaces.entity.his.vo.TestVo;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class LisTest {
@Test
public void test0002() {
TestVo vo = new TestVo();
vo.setAge("50岁");
String xml = JaxbUtil.convertToXmlIgnoreXmlHead(vo, "utf-8");
log.info("xml >>> {}", xml);
}
}
<test value="50岁"/>
@XmlValue
字段和方法级别的注解,简单理解就是定义xml元素文本值的类型
import lombok.Data;
import javax.xml.bind.annotation.*;
/**
* @描述: 测试类
* @Date: 2023/3/8 13:50
* @Description: // PC002
* @Author: Duys
**/
@Data
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "test")
public class TestVo {
@XmlAttribute(name = "value")
private String age;
@XmlValue
private String value;
}
import com.jfsoft.interfaces.entity.his.vo.TestVo;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class LisTest {
@Test
public void test0002() {
TestVo vo = new TestVo();
vo.setAge("50岁");
vo.setValue("11");
String xml = JaxbUtil.convertToXmlIgnoreXmlHead(vo, "utf-8");
log.info("xml >>> {}", xml);
}
}
xml >>> <test value="50岁">11</test>
@XmlType
将Java类或枚举类型映射到XML模式类型,常与@XmlRootElement、@XmlAccessorType共用,propOrder属性定义字段生成的XML节点顺序;
import lombok.Data;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
/**
* @描述: 测试类
* @Date: 2023/3/8 13:50
* @Description: // PC002
* @Author: Duys
**/
@Data
//@XmlAccessorType(XmlAccessType.FIELD) // XmlAccessType.FIELD ,属性名称须保持一致
@XmlRootElement(name = "test")
@XmlType(propOrder = {"value", "AGE"}) // 使用XmlAccessType.PUBLIC_MEMBER 访问时,propOrder属性中的条目对应于属性名称
public class TestVo {
private String age;
private String value;
public String getAGE() {
return age;
}
public void setAGE(String age) {
this.age = age;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
import com.jfsoft.interfaces.entity.his.vo.TestVo;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class LisTest {
@Test
public void test0002() {
TestVo vo = new TestVo();
vo.setAGE("50岁");
vo.setValue("11");
String xml = JaxbUtil.convertToXmlIgnoreXmlHead(vo, "utf-8");
log.info("xml >>> {}", xml);
}
}
xml >>>
<test>
<value>11</value>
<AGE>50岁</AGE>
</test>
@XmlAccessorType
控制字段或属性的序列化。该注解只有一个value属性,可取的值是一个名为XmlAccessType的枚举类型里的值,
XmlAccessType.FIELD:表示JAXB将自动绑定Java类中的每个非静态的(static)、非瞬态的(由@XmlTransient标注)字段到XML
XmlAccessType.PROPERTY表示java对象中所有通过getter/setter方式绑定成属性到XML
XmlAccessType.PUBLIC_MEMBER表示Java对象中所有的public访问权限的成员变量和通过getter/setter方式访问的成员变量,该值为默认值
XmlAccessType.NONE表示Java对象的所有属性都不映射为XML的元素
@XmlAccessorOrder
控制JAXB绑定类中属性和字段的排序,有两个属性,AccessorOrder.ALPHABETICAL——对生成的XML元素按字母书序排序,XmlAccessOrder.UNDEFINED——不排序,默认为该值;
import lombok.Data;
import javax.xml.bind.annotation.*;
/**
* @描述: 测试类
* @Date: 2023/3/8 13:50
* @Description: // PC002
* @Author: Duys
**/
@Data
@XmlAccessorOrder(value = XmlAccessOrder.ALPHABETICAL)
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "test")
public class TestVo {
private String age;
private String sex;
private String birthday;
private String value;
}
// 排序
xml >>>
<test>
<age>50岁</age>
<birthday>2002-01-01</birthday>
<sex>男</sex>
<value>11</value>
</test>
@XmlJavaTypeAdapter
自定义适配器(即扩展抽象类XmlAdapter并覆盖marshal()和unmarshal()方法),解决日期(Date),数字(Number)格式化问题;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @描述:
* @Date: 2023/3/8 15:34
* @Description: // PC002
* @Author: Duys
**/
public class MyAdapter extends XmlAdapter<String, Date> {
static final String STANDARM_DATE_FORMAT = "yyyy-MM-dd";
@Override
public Date unmarshal(String v) throws Exception {
if (v == null) {
return null;
}
DateFormat format = new SimpleDateFormat(STANDARM_DATE_FORMAT);
return format.parse(v);
}
@Override
public String marshal(Date v) throws Exception {
DateFormat format = new SimpleDateFormat(STANDARM_DATE_FORMAT);
return format.format(v);
}
}
import com.jfsoft.interfaces.entity.MyAdapter;
import lombok.Data;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.io.Serializable;
import java.util.Date;
/**
* @描述: 测试类
* @Date: 2023/3/8 13:50
* @Description: // PC002
* @Author: Duys
**/
@Data
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "test")
public class TestVo implements Serializable {
@XmlJavaTypeAdapter(MyAdapter.class)
private Date createDate;
}
import com.jfsoft.interfaces.entity.his.vo.TestVo;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Date;
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class LisTest {
@Test
public void test0002() {
TestVo vo = new TestVo();
vo.setCreateDate(new Date());
String xml = JaxbUtil.convertToXmlIgnoreXmlHead(vo, "utf-8");
log.info("xml >>> {}", xml);
}
}
// 输出
xml >>>
<test>
<createDate>2023-03-09</createDate>
</test>
@XmlElementWrapper
对于数组或集合(即包含多个元素的成员变量),生成一个包装该数组或集合的XML元素(称为包装器),该注解只能用在集合上;
import lombok.Data;
/**
* 申请单实体类
*/
@Data
public class RisOrdersVo {
/**
* 受检者姓名
*/
private String name;
/**
* 申请单号
*/
private String applyNo;
}
import com.jfsoft.interfaces.core.entity.vo.RisOrdersVo;
import com.jfsoft.interfaces.entity.MyAdapter;
import lombok.Data;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* @描述: 测试类
* @Date: 2023/3/8 13:50
* @Description: // PC002
* @Author: Duys
**/
@Data
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "test")
public class TestVo implements Serializable {
@XmlJavaTypeAdapter(MyAdapter.class)
private Date createDate;
@XmlElementWrapper(name = "orders")
@XmlElement(name = "order")
private List<RisOrdersVo> ordersVoList;
}
import com.jfsoft.interfaces.core.entity.vo.RisOrdersVo;
import com.jfsoft.interfaces.entity.his.vo.TestVo;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class LisTest {
@Test
public void test0002() {
RisOrdersVo risOrdersVo = new RisOrdersVo();
risOrdersVo.setName("张三");
risOrdersVo.setApplyNo("100001");
List<RisOrdersVo> list = new ArrayList<>();
list.add(risOrdersVo);
TestVo vo = new TestVo();
vo.setCreateDate(new Date());
vo.setOrdersVoList(list);
String xml = JaxbUtil.convertToXmlIgnoreXmlHead(vo, "utf-8");
log.info("xml >>> {}", xml);
}
}
// 输出
xml >>>
<test>
<createDate>2023-03-09</createDate>
<orders>
<order>
<applyNo>100001</applyNo>
<name>张三</name>
</order>
</orders>
</test>
@XmlTransient
用于标示在由Java对象映射XML时,忽略此属性,在生成的XML文件中将不出现此元素。该注解与所有其他JAXB注释相互排斥,也就是说与其他注释连用就会报错。
import lombok.Data;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import java.io.Serializable;
/**
* @描述: 测试类
* @Date: 2023/3/8 13:50
* @Description: // PC002
* @Author: Duys
**/
@Data
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "test")
public class TestVo implements Serializable {
private String t1;
@XmlTransient
private String t2;
@XmlTransient
private String t3;
}
import com.jfsoft.interfaces.entity.his.vo.TestVo;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class LisTest {
@Test
public void test0002() {
TestVo vo = new TestVo();
vo.setT1("1");
vo.setT2("2");
vo.setT3("3");
String xml = JaxbUtil.convertToXmlIgnoreXmlHead(vo, "utf-8");
log.info("xml >>> {}", xml);
}
}
// 输出
xml >>>
<test>
<t1>1</t1>
</test>
@XmlAccessorType 注解中如果属性值为XmlAccessType.FIELD,则表示通过成员变量来映射,set/get方法上的映射注解就是多余的,所以如果此时set/get方法上再标注元素或者属性映射注解,将抛属性重复性异常;
属性值为XmlAccessType.NONE不映射为XML元素的前提是Java字段或set/get方法上都没有映射注解