JAXB 使用记录 bean转xml xml转bean 数组 继承

news2024/10/6 4:10:11

JAXB 使用记录

部分内容引自
https://blog.csdn.net/gengzhy/article/details/127564536

基础介绍

JAXBContext类:是应用的入口,用于管理XML/Java绑定信息
Marshaller接口:将Java对象序列化为XML数据
Unmarshaller接口:将XML数据反序列化为Java对象
@XmlRootElement:将Java类或枚举类型映射到XML元素,用在Java类上,用于标注该类是xml的一个根节点
@XmlElement:将Java类的一个属性映射到与属性同名的一个XML元素。通常与@XmlTransient搭配使用。
@XmlTransient:通常与 @XmlElement 须搭配使用的。@XmlElement用在属性上,用于指定生成xml的节点名,@XmlTransient用在对应的getter方法上,起到关联的作用
@XmlElementWrapper :对于数组或集合(即包含多个元素的成员变量),生成一个包装该数组或集合的XML元素(称为包装器)。通常配合XmlElement一起使用,XmlElementWrapper指定数组名,XmlElement指定生成xml的节点名
@XmlElementRef:用在类属性的getter方法上(即该属性是一个JavaBean),并且该属性是某些子类的父类,起到引用的作用。同时标注得有@XmlElementRef的类属性,其子类上需要使用@XmlRootElement标注,否则转换异常,提示找不到具体的引用实现。另外,转换时,需要将其子类的class一起传递到JAXBContext上下文中,否则也无法转换
@XmlAccessorOrder:控制JAXB 绑定类中属性和字段的排序
@XmlType:将Java类或枚举类型映射到XML模式类型
@XmlAccessorType(XmlAccessType.FIELD) :控制字段或属性的序列化。FIELD表示JAXB将自动绑定Java类中的每个非静态的(static)、非瞬态的(由@XmlTransient标 注)字段到XML。还有XmlAccessType.PROPERTY和XmlAccessType.NONE
@XmlJavaTypeAdapter:使用定制的适配器(即扩展抽象类XmlAdapter并覆盖marshal()和unmarshal()方法),以序列化Java类为XML
@XmlAttribute:将Java类的一个属性映射到与属性同名的一个XML属性

工具类

package xmlAndBean;

import lombok.extern.slf4j.Slf4j;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Source;
import javax.xml.transform.sax.SAXSource;
import java.io.StringReader;
import java.io.StringWriter;

/**
 * @version : 1.0
 * @Description : xml工具类
 * @Date: 2023/10/9 9:03
 **/

public class XmlBeanUtils {

    /**
     * 构造方法私有
     **/
    private XmlBeanUtils() {
    }

    public static final String ENCODING_UTF = "UTF-8";
    public static final String ENCODING_GB = "GB18030";

    /**
     * @return java.lang.String
     * @Description : bean转xml不含报文头(GB18030编码格式)
     * @Param [obj]
     * @Param encoding 编码格式
     **/
    public static String beanToXml(Object obj,String encoding) {
        String result = null;
        try {
            JAXBContext context = JAXBContext.newInstance(obj.getClass());
            Marshaller marshaller = context.createMarshaller();
            // Marshaller.JAXB_FORMATTED_OUTPUT 决定是否在转换成xml时同时进行格式化(即按标签自动换行,否则即是一行的xml)
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
            // Marshaller.JAXB_ encoding  xml的编码方式
            marshaller.setProperty(Marshaller.JAXB_ENCODING, encoding);
            // 去掉生成xml的默认报文头
            marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
            StringWriter writer = new StringWriter();
            marshaller.marshal(obj, writer);
            result = writer.toString();
        } catch (Exception e) {
//            log.error("bean转xml报文失败", e);
        }
        return result;
    }


    /**
     * @return java.lang.String
     * 报文格式:
     * <?xml version="1.0" encoding="GB18030"?>
     * <ROOT>
     * <HEAD>
     * …
     * </HEAD>
     * <DATA>
     * <title1 >…</title1>
     * <title2 >…</title2>
     * …
     * </DATA>
     * </ROOT>
     * @Description : 组装报文
     * @Param [xmlHead, xmlData]
     **/
    public static String indentFormat(String xmlHead, String xmlData) {
        try {
            String xmlHeader = "<?xml version=\"1.0\" encoding=\"GB18030\"?>\n";
            StringBuilder xml = new StringBuilder();
            xml.append(xmlHeader).append("<ROOT>\n").append(xmlHead).append(xmlData).append("\n</ROOT>");
            return xml.toString();
        } catch (Exception e) {
//            log.error("组装xml报文失败", e);
            return null;
        }
    }

    /**
     * xml转对象
     *
     * @param xml
     * @param msgVo
     * @param <T>
     * @return
     */
    public static <T> T xmlToBean(String xml, Class<T> msgVo) {
        if (msgVo == null) {
            return null;
        }
        try {
            JAXBContext context = JAXBContext.newInstance(msgVo);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            Source source = trunSource(xml);
            return (T) unmarshaller.unmarshal(source);
        } catch (Exception e) {
//            log.error("xml转对象异常:", e);
        }
        return null;
    }

    /**
     * 忽略xml命名空间
     *
     * @param xmlStr
     * @return
     * @throws SAXException
     * @throws ParserConfigurationException
     */
    private static Source trunSource(String xmlStr) throws SAXException, ParserConfigurationException {
        StringReader reader = new StringReader(xmlStr);
        SAXParserFactory sax = SAXParserFactory.newInstance();
        sax.setNamespaceAware(false);
        XMLReader xmlReader = sax.newSAXParser().getXMLReader();
        return new SAXSource(xmlReader, new InputSource(reader));
    }


    /**
     * Java Bean 转 Xml
     *
     * @param bean         - Java Bean
     * @param inheritClazz - Java Bean中嵌套的类,且有继承关系的Java Class
     * @return - xml
     */
    public static String beanToXml(Object bean, String encoding,Class<?>... inheritClazz) {
        try {
            JAXBContext context = initContext(bean.getClass(), inheritClazz);
            Marshaller marshaller = context.createMarshaller();
            // 格式化xml
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            // Marshaller.JAXB_ encoding  xml的编码方式
            marshaller.setProperty(Marshaller.JAXB_ENCODING, encoding);
            // 去掉生成xml的默认报文头
            marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);

            StringWriter writer = new StringWriter();
            marshaller.marshal(bean, writer);
            return writer.toString();
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * Xml 转 Java Bean
     *
     * @param xml          - xml
     * @param beanClazz    - Java Bean Class
     * @param inheritClazz - Java Bean中嵌套的类,且有继承关系的Java Class
     * @return - bean
     */
    public static Object xmlToBean(String xml, Class<?> beanClazz, Class<?>... inheritClazz) {
        try {
            JAXBContext context = initContext(beanClazz, inheritClazz);
            Unmarshaller um = context.createUnmarshaller();
            StringReader sr = new StringReader(xml);
            return um.unmarshal(sr);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 初始化JAXBContext
     *
     * @param mainClazz    - 序列化或反序列化Class
     * @param inheritClazz - Java Bean中嵌套的类,且有继承关系的Java Class
     * @return - JAXBContext
     */
    private static JAXBContext initContext(Class<?> mainClazz, Class<?>... inheritClazz) throws JAXBException {
        JAXBContext context;
        if (inheritClazz != null) {
            Class<?>[] clazzArr = new Class[inheritClazz.length + 1];
            clazzArr[0] = mainClazz;
            System.arraycopy(inheritClazz, 0, clazzArr, 1, clazzArr.length - 1);
            context = JAXBContext.newInstance(clazzArr);
        } else {
            context = JAXBContext.newInstance(mainClazz);
        }
        return context;
    }


}

xml结构

结构如下:

<ROOT>
<HEAD></HEAD>
<DATA>
		<title1 ></title1>
		<title2 ></title2><RECORD>
            <LIST1 p_type="G">
                <title1 ></title1>
            </LIST1>
            <LIST1 p_type="G">
                <title1 ></title1>
            </LIST1>
        </RECORD>
</DATA>
</ROOT>
①存在继承关系的bean转xml

基类:用于统一,方便向下转型

/**
 * @version : 1.0
 * @Description : 基类
 * @Date: 2023/10/9 19:55
 **/
public class BaseDTO {
}

DATA标签实体类同时继承基类

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.util.List;

/**
 * @version : 1.0
 * @Description :
 * @Date: 2023/10/9 19:55
 **/
@Setter
@Getter
@ToString
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "DATA")
public class BookDTO extends BaseDTO{

    @XmlElement(name = "name")
    @XmlJavaTypeAdapter(CdataXmlAdapter.class)
    private String bookName;

    @XmlElement(name = "id")
    private String bookId;

    //@XmlElementWrapper(name = "RECORD")
//    @XmlElement(name = "LIST1")
//    private List<DescDTO> descDTOList;
}

HEAD标签实体类

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

/**
 * @version : 1.0
 * @Description :
 * @Date: 2023/10/9 19:58

 **/
@Getter
@Setter
@ToString
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "HEAD")
public class HeadDTO {

    @XmlElement(name = "SEND_NODE")
    private String send;


    @XmlElement(name = "RECV_NODE")
    private String receive;
}

根标签实体类
其中针对DATA标签,每个接口的DATA标签可能都不相同,这里使用了@XmlElementRef标签结合基类(BaseDTO ),在使用中将接口的实体类继承BaseDTO基类,并标注@XmlRootElement(name = “DATA”),即可实现每个接口拥有独立的对象实现bean转xml

import lombok.*;

import javax.xml.bind.annotation.*;

/**
 * @version : 1.0
 * @Description :
 * @Date: 2023/10/9 19:55
 **/
@Setter
@Getter
@ToString
@NoArgsConstructor
@AllArgsConstructor
@XmlAccessorType(XmlAccessType.FIELD)
//@XmlType(propOrder = { "head", "data" }) 这句加不加无所谓
@XmlRootElement(name = "ROOT")
public class RootDTO {

    @XmlElement(name = "HEAD")
    private HeadDTO head;

    //@XmlElement(name = "DATA")
    //@XmlElementRef 注解要加载对象上不能加在get方法上,不然报错如下
    //com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 5 counts of IllegalAnnotationExceptions类的两个属性具有相同名称 "head"
    @XmlElementRef(name = "DATA")
    private BaseDTO data;
    
}

测试类

public class XmlTest {

    public static void main(String[] args) {

		//继承基类
        BookDTO bookDTO = new BookDTO();
        bookDTO.setBookName("name");
        bookDTO.setBookId("id");
		//HEAD标签实体类,一般内容固定
        HeadDTO headDTO = new HeadDTO();
        headDTO.setSend("send");
        headDTO.setReceive("rece");

        RootDTO rootDTO = new RootDTO();
        rootDTO.setHead(headDTO);
        //因为BookDTO 继承基类所以此处能设置成功
        rootDTO.setData(bookDTO);


        //bean转xml,需要将BookDTO.class(子类)传入以告知
        System.out.println(XmlBeanUtils.beanToXml(rootDTO,XmlBeanUtils.ENCODING_GB,BookDTO.class));
        //xml转bean
        System.out.println(XmlBeanUtils.xmlToBean(xml,  RootDTO.class,BookDTO.class));
    }
}

运行结果:
在这里插入图片描述

②存在数组的bean转xml

DATA标签实体类同时继承基类

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.util.List;

/**
 * @version : 1.0
 * @Description :
 * @Date: 2023/10/9 19:55
 **/
@Setter
@Getter
@ToString
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "DATA")
public class BookDTO extends BaseDTO{

    @XmlElement(name = "name")
    @XmlJavaTypeAdapter(CdataXmlAdapter.class)
    private String bookName;

    @XmlElement(name = "id")
    private String bookId;

    //@XmlElementWrapper(name = "RECORD")
    @XmlElement(name = "LIST1")
    private List<DescDTO> descDTOList;
}

数组实体类对象

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import javax.xml.bind.annotation.*;

/**
 * @version : 1.0
 * @Description :
 * @Date: 2023/10/10 10:25
 **/
@Getter
@Setter
@ToString
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "LIST1")
public class DescDTO{

    @XmlAttribute(name = "p_type")
    private String pType;

    @XmlElement(name = "description")
    private String description;
}

假设在DATA标签实体类中存在数组属性,则使用@XmlElement(name = “LIST1”)进行标注,即可实现每个数组对象转换成xml时都被 包裹
测试类

public class XmlTest {

    public static void main(String[] args) {


        BookDTO bookDTO = new BookDTO();
        bookDTO.setBookName("name");
        bookDTO.setBookId("id");

        HeadDTO headDTO = new HeadDTO();
        headDTO.setSend("send");
        headDTO.setReceive("rece");

        RootDTO rootDTO = new RootDTO();
        rootDTO.setHead(headDTO);
        rootDTO.setData(bookDTO);

        DescDTO descDTO = new DescDTO();
        //descDTO.setPType("G");
        descDTO.setDescription("desc11111");
        DescDTO descDTO1 = new DescDTO();
        //descDTO1.setPType("G");
        descDTO1.setDescription("desc22222");

        ArrayList<DescDTO> descDTOS = new ArrayList<>();
        descDTOS.add(descDTO);
        descDTOS.add(descDTO1);
        bookDTO.setDescDTOList(descDTOS);

        String xml = XmlBeanUtils.beanToXml(rootDTO, XmlBeanUtils.ENCODING_GB, BookDTO.class);
        //bean转xml
        System.out.println(XmlBeanUtils.beanToXml(rootDTO,XmlBeanUtils.ENCODING_GB,BookDTO.class));
        //xml转bean
        System.out.println(XmlBeanUtils.xmlToBean(xml,  RootDTO.class,BookDTO.class));
    }
}

运行结果
在这里插入图片描述
如果需要再在数组外面套一层标签则:

    @XmlElementWrapper(name = "RECORD")
    @XmlElement(name = "LIST1")
    private List<DescDTO> descDTOList;

运行结果:
在这里插入图片描述

③存在数组且数组前后标签要求不一致的bean转xml

以标签开始,以标签结束
在数组对象中引入@XmlAttribute

    @XmlAttribute(name = "p_type")
    private String pType;

测试类:

//设置属性
descDTO.setPType("G");
public class XmlTest {

    public static void main(String[] args) {


        BookDTO bookDTO = new BookDTO();
        bookDTO.setBookName("name");
        bookDTO.setBookId("id");

        HeadDTO headDTO = new HeadDTO();
        headDTO.setSend("send");
        headDTO.setReceive("rece");

        RootDTO rootDTO = new RootDTO();
        rootDTO.setHead(headDTO);
        rootDTO.setData(bookDTO);

        DescDTO descDTO = new DescDTO();
        descDTO.setPType("G");
        descDTO.setDescription("desc11111");
        DescDTO descDTO1 = new DescDTO();
        descDTO1.setPType("G");
        descDTO1.setDescription("desc22222");

        ArrayList<DescDTO> descDTOS = new ArrayList<>();
        descDTOS.add(descDTO);
        descDTOS.add(descDTO1);
        bookDTO.setDescDTOList(descDTOS);

        String xml = XmlBeanUtils.beanToXml(rootDTO, XmlBeanUtils.ENCODING_GB, BookDTO.class);
        //bean转xml
        System.out.println(XmlBeanUtils.beanToXml(rootDTO,XmlBeanUtils.ENCODING_GB,BookDTO.class));
        //xml转bean
        System.out.println(XmlBeanUtils.xmlToBean(xml,  RootDTO.class,BookDTO.class));
    }
}

运行结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1077106.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数字孪生和数据分析:数字化时代的力量结合

在当今数字化时代&#xff0c;数据是无处不在的。企业、政府和个人不仅生成了大量数据&#xff0c;还寻求从中获取有价值的信息以进行更好的决策。在这个背景下&#xff0c;数字孪生和数据分析成为了迎合这一需求的两个关键概念。本文带大家一起探讨二者之间相辅相成的关系。 一…

黑马店评-04缓存更新策略,保证MySQL数据库中的数据和Redis中缓存的数据一致性

缓存更新策略(数据一致) 更新策略 缓存更新是Redis为了节约内存而设计出来的机制,当我们向Redis插入太多数据时就会导致缓存中的数据过多,所以Redis会对部分数据进行更新即淘汰 低一致性需求(数据长久不发生变化): 使用内存淘汰机制,例如店铺类型信息的查询缓存,因为这部分…

day02_运算符_if

零、今日内容 1.运算符 2.scanner 3.if,ifelse,elseif 复习 学习方法: 睡觉前过电影(1jdk,配置环境变量2idea使用3HelloWorld程序解释 4变量5数据类型6String) 主方法是每次都要写的,因为代码要执行(psvm) 输出语句每次都要写的,因为要看结果(sout) 1.声明变量的语法格式 数据类…

网络安全(黑客)—0基础学习手册

目录梗概 一、自学网络安全学习的误区和陷阱 二、学习网络安全的一些前期准备 三、网络安全学习路线 四、学习资料的推荐 想自学网络安全&#xff08;黑客技术&#xff09;首先你得了解什么是网络安全&#xff01;什么是黑客&#xff01; 网络安全可以基于攻击和防御视角来…

Git【入门】从安装到会用(千字总结●超详细)

我的个人主页&#xff1a;☆光之梦☆_C语言基础语法&#xff08;超详细&#xff09;,【java入门】语法总结-CSDN博客 创作不易&#xff0c;如果能帮到你就好 注&#xff1a;你的 &#x1f44d;点赞 ⭐收藏 &#x1f4dd;评论 是对博主最大的支持与鼓励喔 认真看完这篇文章&am…

极智AI | 能够轻松构建大模型端到端应用的LangChain 到底是什么

欢迎关注我的公众号 [极智视界],获取我的更多经验分享 大家好,我是极智视界,本文来介绍一下 能够轻松构建大模型端到端应用的 LangChain,到底是什么。 邀您加入我的知识星球「极智视界」,星球内有超多好玩的项目实战源码下载,链接:https://t.zsxq.com/0aiNxERDq 先上官…

Cesium热力图

二、代码 <!doctype html> <html><head><meta charset"utf-8"><link rel"stylesheet" href"./css/common.css"><title>热力图</title><script src"./js/config.js"></script>…

手动实现SpringMVC底层机制

手动实现SpringMVC底层机制 &#x1f41f;准备工作&#x1f34d;搭建SpringMVC底层机制开发环境 实现任务阶段一&#x1f34d;开发ZzwDispatcherServlet&#x1f966;说明: 编写ZzwDispatcherServlet充当原生的DispatcherServlet(即核心控制器)&#x1f966;分析代码实现&#…

基于点标签的目标检测与计数深度学习框架盘点

(1)P2PNet <1>P2PNet提出 论文出处&#xff1a;Rethinking Counting and Localization in Crowds: A Purely Point-Based Framework 论文链接&#xff1a;https://arxiv.org/abs/2107.12746 开源代码&#xff1a;https://github.com/TencentYoutuResearch/CrowdCount…

物联网AI MicroPython传感器学习 之 MQ136硫化氢传感器

学物联网&#xff0c;来万物简单IoT物联网&#xff01;&#xff01; 一、产品简介 MQ136 是一种硫化氢检测传感器&#xff0c;感应范围为 1 - 200ppm。传感元件是 SnO2&#xff0c;它在清洁空气中的电导率较低。当存在 H₂S 气体时&#xff0c;传感器的电导率随着气体浓度的升…

Gralloc ION DMABUF in Camera Display

目录 Background knowledge Introduction ia pa va and memory addressing Memory Addressing Page Frame Management Memory area management DMA IOVA and IOMMU Introduce DMABUF What is DMABUF DMABUF 关键概念 DMABUF APIS –The Exporter DMABUF APIS –The…

PyTorch模型的多种导出方式提供给其他程序使用

PyTorch模型的多种导出方式提供给其他程序使用 flyfish PyTorch模型的多种导出方式 PyTorch模型的多种导出方式提供给其他程序使用1 模型可视化2 预训练模型3 ONNX模型导出有输入有输出TRAINING导出方式EVAL导出方式 4 自定义输入输出的名字&#xff0c;并可批量推理5 导出JI…

PyG两个data Datsaset v.s. InMemoryDataset

可以看到InMemoryDataset 对CPU更加友好 https://pytorch-geometric.readthedocs.io/en/latest/modules/data.html#pytorch-lightning-wrappers

Linux下C++编程-进度条

引言&#xff1a;本篇主要在linux下的C实现进度条的功能。按照多文件编程&#xff0c;同时使用Makefile文件完成多文件的编译、连接。 首先创建头文件&#xff1a; 1. progress.h #pragma once #include <iostream> #include <cstring> #include <iomanip>…

Navicat定时任务

Navicat定时任务 1、启动Navicat for MySQL工具&#xff0c;连接数据库。 2、查询定时任务选项是否开启 查询命令&#xff1a;SHOW VARIABLES LIKE ‘%event_scheduler%’; ON表示打开&#xff0c;OFF表示关闭。 打开定时任务命令 SET GLOBAL event_scheduler 0; 或者 SET G…

elasticsearch 8.5.3问题记录

一&#xff1a;解决 elasticsearch 高版本 warning: ignoring JAVA_HOMEC:\Program Files\Java\jdk-11&#xff1b; using bundled JDK if defined JAVA_HOME (set JAVA_HOME%JAVA_HOME%; )示例版本Elasticsearch 8.5.3 可以与 JDK 11 兼容&#xff0c;但不支持 JDK 17。确保选…

离散数学 期末复习

离散数学 期末复习 图片过多&#xff0c;若无法显示&#xff0c;请转至 https://chenhaotian.top/study/discrete-mathematics-final-review/ 访问全文 发布于 2023-06-18 第 1 章 命题逻辑 1.2 等值演算 真值表法 等值演算法 题&#xff1a;等值演算 题&#xff1a;等值演…

python 学习随笔 5

函数 在python中&#xff0c;函数也是对象。 def func():""" 这是文档字符串"""print("Hello World")fun带参数函数 函数和变量注解 def calc(a:int, b:int) -> int: # 为函数的形参和返回值标注类型return a b print(calc(1,3…

C语言重点突破(2)指针(三)

本章重点 1. 函数指针 2. 函数指针数组3. 指向函数指针数组的指针 4. 回调函数 1.函数指针 首先可以明确的是&#xff0c;函数指针和数组指针的类型都是指针类型&#xff0c;用来存放地址的&#xff0c;数组指针存放数组的地址&#xff0c;而函数指针存放的便是函数的地址。 …

ESPHome 通过http获取设备的状态

substitutions: { desc: 传感器, devicename: sensor }esphome:name: $devicenameplatform: ESP8266board: nodemcuv2arduino_version: latest# Enable logging logger:# Enable Home Assistant API api:encryption:key: "MhXiJqKKyCXTqjZWqtegaP1tQSUpPtbnXP9iV1i2TzE&qu…