闲碎记事本 闲碎记事本
首页
  • JAVA
  • Cloudflare
  • 学完再改一遍UI
友链
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

YAN

我要偷偷记录...
首页
  • JAVA
  • Cloudflare
  • 学完再改一遍UI
友链
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • java

    • SpringBoot

    • SpringSecurity

    • MybatisPlus

    • Netty

    • sip

      • SIP使用
      • GB28181
      • GB35114
      • SM2工具类
      • SM3工具类
      • 证书构建
      • 使用注解实现XML构建与解析
        • 流媒体服务器
        • FFmpeg
      • 其他

    • linux

    • docker

    • redis

    • nginx

    • mysql

    • 其他

    • 环境搭建

    • 知识库
    • java
    • sip
    YAN
    2024-07-26
    目录

    使用注解实现XML构建与解析

    基于 dom4j 实现XML构建与解析

    # 导入依赖

    <dependency>
        <groupId>org.dom4j</groupId>
        <artifactId>dom4j</artifactId>
        <version>2.1.3</version>
    </dependency>
    <!-- XPATH 支持-->
    <dependency>
        <groupId>jaxen</groupId>
        <artifactId>jaxen</artifactId>
        <version>1.2.0</version>
    </dependency>
    
    

    # 测试代码

    点击查看
    
    @Getter
    @Setter
    @ToString
    @SIP("Control")
    @Accessors(chain = true)
    public class Control extends XMLMessage {
    
        public Control() {
    
        }
    
        @SIP("SN")
        private  String sn;
    
        @SIP("DeviceID")
        private  String deviceId;
    
        @SIP("PTZCmd")
        private  String ptzCmd;
    
        @SIP("Info")
        private List<Control.Info> info;
    
    
        @Data
        @EqualsAndHashCode(callSuper = true)
        @Accessors(chain = true)
        public static class  Info extends ChildNode {
    
            @SIP("ControlPriority")
            private String controlPriority;
        }
    
        @Override
        public String toXML() {
            return SimpleXmlHelper.toXml(this);
        }
    
    }
    
    
    
    private static XMLMessage getControl() {
        Control message = new Control();
        message.setSn("11");
        message.setDeviceId("64010000041310000345");
        message.setPtzCmd("A50F4D1000001021");
        List<Control.Info> list = Arrays.asList(
                new Control.Info().setControlPriority("1"),
                new Control.Info().setControlPriority("2")
        );
        message.setInfo(list);
        return message;
    }
    
    private static <T extends XMLMessage> T convert(XMLMessage message, Class<T> cla) {
        String xml = SimpleXmlHelper.toXml(message);
        System.out.println(xml);
        return SimpleXmlHelper.xlmToBeam(xml, cla);
    }
    
    
        public static void main(String[] args) {
            Control message = convert(getControl(), Control.class);
            System.out.println(message);
        }
    

    # 具体实现

    展开详情

    # 建立相关注解

    @Target({ElementType.FIELD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface XML {
    
        String value();
    
        boolean isChild() default false;
    }
    
    @Repeatable(SIPAttrs.class)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface XMLAttr {
    
        String value();
    
        String field();
    }
    
    @Target({ElementType.FIELD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface XMLAttrs {
    
        XMLAttr [] value();
    }
    
    
    @Getter
    public abstract class XMLMessage {
        
        public abstract String toXML();
    }
    

    子节点标识

    public abstract class ChildNode {
        
    }
    
    
    
    @Getter
    @Slf4j
    @SuppressWarnings("unused")
    public class SimpleXmlHelper {
    
        private  final  Document document;
    
        private final Element rootElement;
    
        private SimpleXmlHelper(String rootName){
            this.document = createDocument();
            this.rootElement = document.addElement(rootName);
        }
    
        /**
         * 构建一个 SimpleXmlHelper
         * @param rootName 根节点名字
         * @return SimpleXmlHelper
         */
        public static  SimpleXmlHelper build(String rootName){
            return new SimpleXmlHelper(rootName);
        }
    
        /**
         * 将对象转换为XML
         * @param obg 转换数据
         * @return   XML STR
         */
        public static <T extends XMLMessage> String toXml(T obg){
            SimpleXmlHelper simpleXmlHelper =  build(getRootElementNameByClass(obg.getClass()));
            simpleXmlHelper.fullElement(simpleXmlHelper.getRootElement(), obg);
            return simpleXmlHelper.writeXml();
        }
    
        /**
         * XLM  To Bean
         * @param xml xml
         * @param cla 需要构建的数据类型
         * @param <T>  数据泛型
         */
        public static <T extends XMLMessage> T xlmToBeam(String xml,Class<T> cla){
            Element rootElement = SimpleXmlHelper.getRoot(xml);
            return  elementToBean(rootElement,cla);
        }
    
    
        /**
         * 填充完整Element
         * @param current 当前 Element
         * @param t 填充数据
         * @param <T>  填充数据泛型
         */
        @SuppressWarnings("unchecked")
        private  <T> void fullElement(Element current, T t){
            for (Field field : ReflectUtil.getFields(t.getClass())) {
                String name = getNodeNameByField(field);
                if(null == name){
                    log.warn("当前跳过属性[{}],如果需要此属性请添加@SIP注解",field.getName());
                    continue;
                }
                Class<?> type = field.getType();
                //得到当前字段值
                Object fieldValue = ReflectUtil.getFieldValue(t, field);
                //得到字段所注解的属性
                List<Attribute> attrs = getAttrs(field, t);
                if(Collection.class.isAssignableFrom(type) ){
                    List<Object> valList = (List<Object>) fieldValue;
                    if(CollUtil.isEmpty(valList)){
                        continue;
                    }
                    for (Object val : valList) {
                        genElementByFieldName(current, val, name,attrs);
                    }
                }else {
                    genElementByFieldName(current, fieldValue, name,attrs);
                }
            }
        }
    
        /**
         * 构建一个名字为 tagName 并携带 attrs 属性的节点
         * @param current 当前 Element
         * @param val 当前属性值
         * @param tagName 当前xml tag名字
         * @param attrs 节点属性
         */
        private void genElementByFieldName(Element current, Object val, String tagName,List<Attribute> attrs) {
            if(val instanceof ChildNode){
                Element child = current.addElement(tagName);
                child.setAttributes(attrs);
                fullElement(child, val);
            }else {
                Element child;
                if(null == val){
                    child = createNullNextElement(current, tagName);
                }else {
                    child = createNextElement(current, tagName, val);
                }
                child.setAttributes(attrs);
            }
        }
    
        /**
         * Element To Bean
         * @param currentNode 当前XML节点
         * @param cla 需要构建的数据类型
         * @param <T>  数据泛型
         */
        @SuppressWarnings("unchecked")
        public static <T> T elementToBean(Node currentNode,Class<T> cla){
            try {
                T obg = cla.newInstance();
                //得到根节点名字
                for (Field field : ReflectUtil.getFields(obg.getClass())) {
                    String name = getNodeNameByField(field);
                    if(null == name){
                        continue;
                    }
                    Class<?> type = field.getType();
    
                    if(Collection.class.isAssignableFrom(type) ){
                        List<Node> nodes = findNodes(currentNode, genAllXpath(name));
                        if(CollUtil.isEmpty(nodes)){
                            continue;
                        }
                        ArrayList<Object> listVal = new ArrayList<>();
                        for (Node node : nodes) {
                            //转换为list泛型
                            Type actualTypeArgument = getActualTypeArgument(field);
                            T item = elementToBean(node, (Class<T>) actualTypeArgument);
                            listVal.add(item);
    
                        }
                        ReflectUtil.setFieldValue(obg,field,listVal);
                    }else {
                        Node nextNode = findNode(currentNode, name);
                        //判断 type 是不是 ChildNode的子类
                        if(ChildNode.class.isAssignableFrom(type)){
                            if(null == nextNode){
                                continue;
                            }
                            Object childOng = elementToBean(nextNode, type);
                            ReflectUtil.setFieldValue(obg,field,childOng);
                        }else {
                            //设置对象值
                            ReflectUtil.setFieldValue(obg,field, getNodeVal(nextNode));
                        }
    
                    }
                }
                return obg;
            } catch (Exception e) {
                log.error(" ogb to xml 失败");
                throw new RuntimeException(e);
            }
        }
    
        private static <T> void setObgAttrs(Node node, T obg) {
            List<Attribute> elementAttrs = getElementAttrs((DefaultElement)node);
            for (Attribute attribute : elementAttrs) {
                String attrName = attribute.getName();
                String attrVal= attribute.getValue();
                Field attrField = ReflectUtil.getField(obg.getClass(), attrName);
                if(null !=attrField){
                    ReflectUtil.setFieldValue(obg,attrField,attrVal);
                }
            }
        }
    
        /**
         * 得到field 注解属性
         * @param field field
         * @param obg 当前对象
         * @return    List<Attribute>
         */
        private static <T> List<Attribute> getAttrs(Field field, T obg) {
            SIPAttr[] attrs = getSipAttrs(field);
            Map<String, String> attrMap = new HashMap<>();
    
            List<Attribute> attributes = new ArrayList<>();
            if(0 < attrs.length){
                for (SIPAttr attr : attrs) {
                    String join = attr.field();
                    Object attrVal = ReflectUtil.getFieldValue(obg, join);
                    if(null == attrVal){
                        continue;
                    }
    
                    attributes.add(
                            new DefaultAttribute(attr.value(),String.valueOf(attrVal))
                    );
    
                }
            }
            return attributes;
        }
    
        /**
         * 得到 SIPAttr 注解
         * @param field 当前字段
         * @return SIPAttr[]
         */
        private static SIPAttr[] getSipAttrs(Field field) {
           return field.getDeclaredAnnotationsByType(SIPAttr.class);
        }
    
    
        public static  Type   getActualTypeArgument(Field field){
            Type genericType = field.getGenericType();
            if (genericType instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) genericType;
    
                // 获取泛型类型的实际类型参数
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                return actualTypeArguments[0];
            } else {
                log.error("请为:{}属性指定泛型",field.getName());
                throw new RuntimeException(String.format("请为:%s属性指定泛型",field.getName()));
            }
        }
    
        /**
         * 得到XML 根节点类型
         * @param xml xml
         * @return  根节点名字
         */
        public static String getXlmRootNodeName(String xml){
            return  getNodeName(SimpleXmlHelper.getRoot(xml));
        }
    
        /**
         * 得到根节点名字 (class中 {@link SIP} 的值)
         * @param cls class
         * @return 根节点名字
         * @param <T> T
         */
        public static <T> String getRootElementNameByClass(Class<T> cls){
            SIP cla = cls.getAnnotation(SIP.class);
            if(cla == null){
                log.warn("请给{}添加@SIP注解",cls.getName());
                throw new RuntimeException(String.format("请给%s添加@SIP注解",cls.getName()));
            }
            return cla.value();
        }
    
        /**
         * 得到根节点名字 (class中 {@link SIP} 的值)
         * @param field class
         * @return 根节点名字
         */
        public static  String getNodeNameByField(Field field){
            SIP annotation = field.getAnnotation(SIP.class);
            if(null == annotation){
                return null;
            }
            return annotation.value();
        }
    
        /**
         * 创建 根Element  的下级Element
         * @param key Element name
         * @return 下级Element
         */
        public  Element createRootNextElement(String key) {
            return createRootNextElement(key,null);
        }
    
        /**
         * 创建 根Element  的下级Element,并设置值
         * @param key Element name
         * @return 下级Element
         */
        public  Element createRootNextElement(String key,Map<String,String> nodes) {
            return createNextElement(rootElement,key,nodes);
        }
    
        /**
         * 创建 指定Element  的下级Element
         * @param key Element name
         * @return 下级Element
         */
        public  Element createNextElement(Element element, String key) {
            return element.addElement(key);
        }
    
        /**
         * 创建 指定Element  的下级Element,并设置值
         * @param key Element name
         * @param nodes nodes 节点值key val形式
         * @return 下级Element
         */
        public  Element createNextElement(Element element, String key, Map<String,String> nodes) {
            Element current = createNextElement(element,key);
            if(null == nodes){
                return current;
            }
            nodes.forEach((k,v)-> current.addElement(k).setText(v));
            return current;
        }
    
        /**
         * 创建 指定Element  的下级Element,并设置空值
         * @param key Element name
         * @param val val 节点值
         * @return 下级Element
         */
        @SuppressWarnings("all")
        public  Element createNullNextElement(Element element, String key) {
            return createNextElement(element,key, Arrays.asList(""));
        }
    
        /**
         * 创建 指定Element  的下级Element,并设置值
         * @param key Element name
         * @param val val 节点值
         * @return 下级Element
         */
        @SuppressWarnings("all")
        public  Element createNextElement(Element element, String key, Object ...val) {
            return createNextElement(element,key, Arrays.asList(val));
        }
    
        /**
         * 创建 指定Element  的下级Element,并设置值
         * @param key Element name
         * @param val val 节点值
         * @return 下级Element
         */
        public  Element createNextElement(Element element, String key, List<Object> val) {
            Element current = createNextElement(element,key);
            val.stream().map(String::valueOf).forEach(current::addText);
            return current;
        }
    
        /**
         * 根节点下添加 k,v
         * @param key  key
         * @param val val
         */
        public  void appendRoot(String key,String val) {
            setElementNodeVal(rootElement,key,val);
        }
    
    
        /**
         * 指定 current 下添加 k,v
         * @param current  当前current
         * @param key  key
         * @param val val
         */
        public  void setElementNodeVal(Element current, String key, String val) {
    //        Element element = current.addElement(key);
            Element element = createNextElement(current,key);
            if(null!=val && !val.isEmpty()){
                element.setText(val);
            }
        }
    
    
        /**
         * 写出 XML
         * @return XML
         */
        public String writeXml() {
            try{
                StringWriter content = new StringWriter();
                OutputFormat format = OutputFormat.createPrettyPrint();
                XMLWriter writer = new XMLWriter(content, format);
                writer.write(document);
                writer.close();
                return  content.toString();
            } catch (IOException e) {
                throw  new RuntimeException("生成XML错误");
            }
        }
    
        /**
         * 得到 List<Element>  需要判空
         * @param element Element
         * @param name name
         * @return 获取到的 List<Element>
         */
        public static List<Element> findElements(Element element, String name) {
            return  element.elements(name);
        }
    
        /**
         * 得到 Element Attrs
         * @param element Element
         * @return 获取到的 Element
         */
        public static  List<Attribute>  getElementAttrs(DefaultElement element) {
           return element.attributes();
        }
    
        /**
         * 得到 Element  需要判空
         * @param element Element
         * @param name name
         * @return 获取到的 Element
         */
        public static Element findElement(Element element, String name) {
            return  element.element(name);
        }
    
        /**
         * 得到 Element
         * @param element Element
         * @param name name
         * @return Element 内容
         */
        public static String findElementVal(Element element, String name) {
            Element elm = element.element(name);
            if(null == elm){
                return null;
            }
            return elm.getText();
        }
    
        public static String genAllXpath(String xpath) {
            return "//"+xpath;
        }
    
        /**
         * 得到 Nodes  需要判空
         * @param node node
         * @param xpath xpath
         * @return 获取到的 List<Node>
         */
        public static List<Node> findNodes(Node node, String xpath) {
            XPath userXPath = node.createXPath(xpath);
            return  userXPath.selectNodes(node);
        }
    
        /**
         * 得到 Node  需要判空
         * @param node 当前 node
         * @param xpath xpath
         * @return 获取到的 Node
         */
        public static Node findNode(Node node, String xpath) {
            XPath userXPath = node.createXPath(xpath);
            return  userXPath.selectSingleNode(node);
        }
    
        /**
         * 得到 Node  需要判空
         * @param node 当前Node
         * @param xpath xpath
         * @return Node内容
         */
        public static String findNodeVal(Node node, String xpath) {
            XPath userXPath = node.createXPath(xpath);
            Node selectNode = userXPath.selectSingleNode(node);
            if(null == selectNode){
                return  null;
            }
            return  selectNode.getText();
        }
    
        /**
         * 得到 Node 名字
         * */
        public static String getNodeName(Node node) {
            return  node.getName();
        }
    
        /**
         * 得到 Node 值
         * */
        public static String getNodeVal(Node node) {
            if(null == node){
                return "";
            }
            return  node.getText();
        }
    
    
        /**
         * 读取XML
         * @param xml xml内容
         * @return  Document
         */
        public  static Document read(String xml) {
            try {
                SAXReader reader = new SAXReader();
                return reader.read(new StringReader(xml));
            } catch (Exception e) {
                throw new RuntimeException("读取XML失败");
            }
        }
    
        /**
         * 得到根节点
         * @param document document
         * @return  Element
         */
        public  static Element getRoot(Document document) {
            try {
                return document.getRootElement();
            } catch (Exception e) {
                throw new RuntimeException("读取XML失败");
            }
        }
    
        /**
         * 得到根节点
         * @param xml xml内容
         * @return  Element
         */
        public  static Element getRoot(String xml) {
            try {
                return read(xml).getRootElement();
            } catch (Exception e) {
                throw new RuntimeException("读取XML失败");
            }
        }
        
    }
    
    
    上次更新: 2025/05/14, 01:34:05
    证书构建
    流媒体服务器

    ← 证书构建 流媒体服务器→

    最近更新
    01
    Caddy操作指南
    04-25
    02
    Swap空间
    04-22
    03
    Alist使用
    04-21
    更多文章>
    Theme by Vdoing | Copyright © 2022-2025 YAN | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式