XmlMapper详解及工具类封装

  • Post author:
  • Post category:其他




一、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;
        }
    }
}



版权声明:本文为u010349272原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。