一、XmlMapper说明
1、依赖包引入
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.11.2</version>
</dependency>
2、标签说明
@JacksonXmlRootElement
指定生成xml根标签的名字。用于类名,是xml最外层的根节点。注解中有localName属性,该属性如果不设置,那么生成的XML最外面就是Clazz。
@JacksonXmlProperty
指定包装标签名,或者指定标签内部属性名。该注解通常可以不需要,若不用,生成xml标签名称就是实体类属性名称。但是如果你想要你的xml节点名字,首字母大写。比如例子中的Content,那么必须加这个注解,并且注解的localName填上你想要的节点名字。最重要的是实体类原来的属性content必须首字母小写!否则会被识别成两个不同的属性。注解的isAttribute,确认是否为节点的属性,如下图中的“gradeId”。
@JacksonXmlElementWrapper
用于指定List等集合类,外围标签名;用在非集合类上无效。一般用于list,list外层的标签。若不用的话,useWrapping =false。
@JacksonXmlText
指定当前这个值,没有xml标签包裹。用实体类属性上,说明该属性是否为简单内容,如果是,那么生成xml时,不会生成对应标签名称。
@JsonIgnore
忽略该实体类的属性,该注解是用于实体类转json的,但用于转xml一样有效,具体原因个人推测是XmlMapper是ObjectMapper的子类。
@JacksonXmlCData
是为了生成<![CDATA[text]]>。
3、标签示例
@Data
public class GradeDomain {
@JacksonXmlProperty(localName = "gradeId",isAttribute = true)
private int gradeId;
@JacksonXmlText
private String gradeName;
}
@Data
public class ScoreDomain {
@JacksonXmlProperty(localName = "scoreName")
@JacksonXmlCData
private String name;
@JacksonXmlProperty(localName = "scoreNumber")
private int score;
}
@Data
@JacksonXmlRootElement(localName = "student")
public class StudentDomain {
@JsonIgnore
private String studentName;
@JacksonXmlProperty(localName = "age")
@JacksonXmlCData
private int age;
@JacksonXmlProperty(localName = "grade")
private GradeDomain grade;
@JacksonXmlElementWrapper(localName = "scoreList")
@JacksonXmlProperty(localName = "score")
private List<ScoreDomain> scores;
}
4、XmlMapper配置属性
ObjectMapper xmlMapper = new XmlMapper();
//反序列化时,若实体类没有对应的属性,是否抛出JsonMappingException异常,false忽略掉
xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//序列化是否绕根元素,true,则以类名为根元素
xmlMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
//忽略空属性
xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//XML标签名:使用骆驼命名的属性名,
xmlMapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);
//设置转换模式
xmlMapper.enable(MapperFeature.USE_STD_BEAN_NAMING);
5、main方法中具体的使用
public static void main(String[] agr) throws JsonProcessingException {
ObjectMapper xmlMapper = new XmlMapper();
xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
xmlMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
xmlMapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);
xmlMapper.enable(MapperFeature.USE_STD_BEAN_NAMING);
StudentDomain domain = new StudentDomain();
domain.setStudentName("张三");
domain.setAge(18);
GradeDomain grade = new GradeDomain();
grade.setGradeId(1);
grade.setGradeName("高三");
domain.setGrade(grade);
ScoreDomain score1 = new ScoreDomain();
score1.setName("语文");
score1.setScore(90);
ScoreDomain score2 = new ScoreDomain();
score2.setName("数学");
score2.setScore(98);
ScoreDomain score3 = new ScoreDomain();
score3.setName("英语");
score3.setScore(91);
List<ScoreDomain> scores = Arrays.asList(score1,score2,score3);
domain.setScores(scores);
String xml = xmlMapper.writeValueAsString(domain);
System.out.println(xml);
StudentDomain studentDomain = xmlMapper.readValue(xml,StudentDomain.class);
System.out.println(studentDomain);
}
6、main方法中具体的使用
实体类转成xml:
xml转成实体类:
二、XmlMapper测试
1、测试DTO
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.List;
@Data
// @JacksonXmlRootElement:指定生成xml根标签的名字;
@JacksonXmlRootElement(localName = "Class")
public class Group {
private Teacher teacher;
//@JacksonXmlElementWrapper:可用于指定List等集合类,外围标签名;
@JacksonXmlElementWrapper(localName = "Students")
//@JacksonXmlProperty:指定包装标签名,或者指定标签内部属性名;
@JacksonXmlProperty(localName = "Stu")
private List<Student> student;
@Data
@AllArgsConstructor
public static class TeacherType {
@JacksonXmlProperty(isAttribute = true, localName = "type")
private String type;
//@JacksonXmlText:指定当前这个值,没有xml标签包裹。
//这个值意义在于,一般这个值所在的类只有这一个正常属性,或者其他属性全部为 @JacksonXmlProperty(isAttribute = true,
@JacksonXmlText
private String grade;
}
@Data
public static class Teacher {
@JacksonXmlProperty(localName = "TypeCode")
private TeacherType teacherTypeCode;
private String name;
}
@Data
public static class Student {
@JacksonXmlProperty(isAttribute = true, localName = "stu_id")
private String id;
private String name;
private Integer age;
}
}
2、测试类
@Test
public void test() {
Group group = new Group();
Group.Teacher teacher = new Teacher();
teacher.setTeacherTypeCode(new TeacherType("语文老师", "A"));
teacher.setName("马老师");
group.setTeacher(teacher);
Student student = new Student();
student.setId("001");
student.setName("HealerJean");
student.setAge(25);
group.setStudent(Arrays.asList(student));
String xml = XmlUtils.toXml(group);
log.info("数据原文:【 {} 】", xml);
}
// XML标签名:使用骆驼命名的属性名,
xmlMapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);
<Class>
<Teacher>
<Name>马老师</Name>
<TypeCode type="语文老师">A</TypeCode>
</Teacher>
<Students>
<Stu stu_id="001">
<Name>HealerJean</Name>
<Age>25</Age>
</Stu>
</Students>
</Class>
// 自定义的转化转大写并加下划线,强制命令的不可以,比如下面的Class是强制命名的
xmlMapper.setPropertyNamingStrategy(new UpperCaseSnackNamingStrategy());
<Class>
<TEACHER>
<NAME>马老师</NAME>
<TypeCode type="语文老师">A</TypeCode>
</TEACHER>
<Students>
<Stu stu_id="001">
<NAME>HealerJean</NAME>
<AGE>25</AGE>
</Stu>
</Students>
</Class>
三、XmlMapper工具类封装
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.yunshidi.yespay.hxb.pds.api.model.comm.ResponseModel;
import java.io.IOException;
/**
* XML与Java实体类转换工具
*
* @author leizhigang
* @date 2020-08-04
*
*/
public class XmlMapperUtils {
public static final XmlMapper xmlMapper;
static {
xmlMapper = new XmlMapper();
SimpleModule module = new SimpleModule();
xmlMapper.registerModule(module);
//xmlMapper.setDefaultUseWrapper(false);
//字段为null,自动忽略,不再序列化
xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//XML标签名:使用骆驼命名的属性名,
xmlMapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);
//转化成加下划线和大写
xmlMapper.setPropertyNamingStrategy(new UpperCaseSnackNamingStrategy());
//设置转换模式
xmlMapper.enable(MapperFeature.USE_STD_BEAN_NAMING);
}
/**
* @param object
* @return
* @Description 将java对象转化为xml字符串
* @Title beanToXml
*/
public static String beanToXml(Object object) {
try {
return xmlMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new RuntimeException("Java对象转换为Xml失败", e);
}
}
/**
* @param xml
* @param clazz
* @return
* @Description 将xml字符串转化为java对象
* @Title xmlToBean
* */
public static <T> T xmlToBean(String xml, Class<T> clazz) {
try {
return xmlMapper.readValue(xml, clazz);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Xml转换为Java对象失败", e);
}
}
/**
* @param xml
* @return
* @Description 将xml字符串转化为java对象
* @Title xmlToBean
* */
public static <T> ResponseModel<T> xmlToBean(String xml) {
XmlMapper xmlMapper = new XmlMapper();
try {
return xmlMapper.readValue(xml, new TypeReference<ResponseModel<T>>() {
});
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new RuntimeException("Xml转换为Java对象失败", e);
}
}
/**
* @author leizhigang
* @version 1.0v
* @ClassName UpperCaseSnackNamingStrategy
* @date 2020-08-04
* @description 转大写并加下划线
*/
public static class UpperCaseSnackNamingStrategy extends PropertyNamingStrategy.PropertyNamingStrategyBase {
@Override
public String translate(String input) {
if (input == null) {
return input;
}
int length = input.length();
StringBuilder result = new StringBuilder(length * 2);
int resultLength = 0;
boolean wasPrevTranslated = false;
for (int i = 0; i < length; i++) {
char c = input.charAt(i);
if (i > 0 || c != '_') {
if (Character.isUpperCase(c)) {
if (!wasPrevTranslated && resultLength > 0 && result.charAt(resultLength - 1) != '_') {
result.append('_');
resultLength++;
}
wasPrevTranslated = true;
} else {
wasPrevTranslated = false;
}
c = Character.toUpperCase(c);
result.append(c);
resultLength++;
}
}
return resultLength > 0 ? result.toString() : input;
}
}
}