Spring Boot 优雅实现统一数据返回格式+统一异常处理+统一日志处理

        在我们的项目开发中,我们都会对数据返回格式进行统一的处理,这样可以方便前端人员取数据,当然除了正常流程的数据返回格式需要统一以外,我们也需要对异常的情况进行统一的处理,以及项目必备的日志。

1. 统一返回格式

        在项目开发中返回的是json格式的数据,也就是统一json数据返回格式,一般情况下返回数据的基本格式包含是否成功、响应状态码、返回的消息、以及返回的数据。格式如下:

{
  "success": 布尔,      // 是否成功
  "code": 数字,         // 响应状态码
  "message": 字符串,    // 返回的消息
  "data": {}           //  放置响应的数据
}

1.1 添加枚举类

        该类定义了以上统一格式的前三部分:是否成功、响应状态码、返回的消息;可自行根据项目需要进行后续的添加或者删改。

创建一个result包,下面放置ResultCodeEnum枚举类

/**
 * 状态码
 *
 */
public enum ResultCodeEnum {
 
    SUCCESS(true, 20000, "成功"),
 
    UNKNOWN_REASON(false, 20001, "未知错误");
 
    private final Boolean success;
 
    private final Integer code;
 
    private final String message;
 
    ResultCodeEnum(Boolean success, Integer code, String message) {
        this.success = success;
        this.code = code;
        this.message = message;
    }
 
    public Boolean getSuccess() {
        return success;
    }
 
    public Integer getCode() {
        return code;
    }
 
    public String getMessage() {
        return message;
    }
 
    @Override
    public String toString() {
        return "ResultCodeEnum{" + "success=" + success + ", code=" + code + ", message='" + message + '\'' + '}';
    }
}

1.2 添加统一返回格式的类

该类是用来和前端交互的类,定义的就是本文开头所说的格式

在result包下创建一个统一返回格式的类R

/**
 * 统一返回格式类
 *
 */
public class R {
 
    /**
     * 是否成功
     */
    private Boolean success;
 
    /**
     * 状态码
     */
    private Integer code;
 
    /**
     * 返回的消息
     */
    private String message;
 
    /**
     * 放置响应的数据
     */
    private Map<String, Object> data = new HashMap<>();
 
    public R() {}
 
    /** 以下是定义一些常用到的格式,可以看到调用了我们创建的枚举类 */
    
    public static R ok() {
        R r = new R();
        r.setSuccess(ResultCodeEnum.SUCCESS.getSuccess());
        r.setCode(ResultCodeEnum.SUCCESS.getCode());
        r.setMessage(ResultCodeEnum.SUCCESS.getMessage());
        return r;
    }
 
    public static R error() {
        R r = new R();
        r.setSuccess(ResultCodeEnum.UNKNOWN_REASON.getSuccess());
        r.setCode(ResultCodeEnum.UNKNOWN_REASON.getCode());
        r.setMessage(ResultCodeEnum.UNKNOWN_REASON.getMessage());
        return r;
    }
 
    public static R setResult(ResultCodeEnum resultCodeEnum) {
        R r = new R();
        r.setSuccess(resultCodeEnum.getSuccess());
        r.setCode(resultCodeEnum.getCode());
        r.setMessage(resultCodeEnum.getMessage());
        return r;
    }
 
    public R success(Boolean success) {
        this.setSuccess(success);
        return this;
    }
 
    public R message(String message) {
        this.setMessage(message);
        return this;
    }
 
    public R code(Integer code) {
        this.setCode(code);
        return this;
    }
 
    public R data(String key, Object value) {
        this.data.put(key, value);
        return this;
    }
 
    public R data(Map<String, Object> map) {
        this.setData(map);
        return this;
    }
 
    /** 以下是get/set方法,如果项目有集成lombok可以使用@Data注解代替 */
 
    public Boolean getSuccess() {
        return success;
    }
 
    public void setSuccess(Boolean success) {
        this.success = success;
    }
 
    public Integer getCode() {
        return code;
    }
 
    public void setCode(Integer code) {
        this.code = code;
    }
 
    public String getMessage() {
        return message;
    }
 
    public void setMessage(String message) {
        this.message = message;
    }
 
    public Map<String, Object> getData() {
        return data;
    }
 
    public void setData(Map<String, Object> data) {
        this.data = data;
    }
}

 1.3 测试

/**
 * 测试控制器
 *
 */
@RestController
@RequestMapping("testR")
public class TestController {
 
    @GetMapping("ok")
    public R testOk() {
        Map<String, Object> data = new HashMap<>();
        data.put("name", "李太白");
        return R.ok().data(data);
    }
}

        可以看到格式是正确的,只要我们返回数据的时候使用R这个类返回就行了,不过有一种情况,就是当我们代码中抛出异常之后返回的格式就不是这样子了,下面我演示一下在代码中添加int a = 1/0的语句,肯定导致抛异常的; 

/**
 * 测试控制器
 *
 */
@RestController
@RequestMapping("testR")
public class TestController {
 
    @GetMapping("ok")
    public R testOk() {
        int a = 1/0;
        Map<String, Object> data = new HashMap<>();
        data.put("name", "李太白");
        return R.ok().data(data);
    }
}

        可以发现返回的格式已经不是我们所需要的格式了,这种情况会给前端人员带来不必要的麻烦,所以我们也需要对异常情况进行统一的格式处理; 

2. 统一异常处理

        经过上面的演示,相信你已经明白我们为什么需要进行统一的异常处理了,当然处理统一的异常处理以外我们在开发项目中也会主动的抛出异常,像这种情况我们需要配合自定义异常来完成;

2.1 添加统一异常处理器

创建一个handler包,在该包下面添加GlobalExceptionHandler类

/**
 * 统一异常处理
 * ControllerAdvice注解的含义是当异常抛到controller层时会拦截下来
 */
@ControllerAdvice
public class GlobalExceptionHandler {
 
    /**
     * 使用ExceptionHandler注解声明处理Exception异常
     *
     */
    @ResponseBody
    @ExceptionHandler(Exception.class)
    public R exception(Exception e) {
        // 控制台打印异常
        e.printStackTrace();
        // 返回错误格式信息
        return R.error();
    }
 
}

2.2 测试统一异常处理

        可以看到现在出现异常之后返回的格式已经是我们所需要的格式了,如果我们想让这个错误信息更加明确,我们可以通过添加自定义异常来实现。

2.3 添加自定义异常类

新建exception包,在该包下添加自定义异常类

/**
 * 测试自定义异常类
 * 需要继承运行时异常RuntimeException
 */
public class TestException extends RuntimeException {
    private Integer code;
 
    public TestException(ResultCodeEnum resultCodeEnum) {
        // 调用父类的方法添加信息
        super(resultCodeEnum.getMessage());
        this.code = resultCodeEnum.getCode();
    }
 
    public Integer getCode() {
        return code;
    }
}

 2.4 在统一异常处理类GlobalExceptionHandler中添加一个自定义异常的处理

/**
 * 统一异常处理
 * ControllerAdvice注解的含义是当异常抛到controller层时会拦截下来
 */
@ControllerAdvice
public class GlobalExceptionHandler {
 
    /**
     * 使用ExceptionHandler注解声明处理Exception异常
     *
     */
    @ResponseBody
    @ExceptionHandler(Exception.class)
    public R exception(Exception e) {
        // 控制台打印异常
        e.printStackTrace();
        // 返回错误格式信息
        return R.error();
    }
 
    /**
     * 使用ExceptionHandler注解声明处理TestException异常
     *
     */
    @ResponseBody
    @ExceptionHandler(TestException.class)
    public R exception(TestException e) {
        // 控制台打印异常
        e.printStackTrace();
        // 返回错误格式信息
        return R.error().message(e.getMessage()).code(e.getCode());
    }
 
}

 2.5 测试自定义异常

在枚举类中添加一个状态信息

TEST_NUMBER(false, 500, "计算错误");
/**
 * 测试控制器
 *
 */
@RestController
@RequestMapping("testR")
public class TestController {
 
    @GetMapping("ok")
    public R testOk() {
    try{

        int a = 1/0;
    }catch{
        throw new TestException(ResultCodeEnum.TEST_NUMBER);    
    }
        Map<String, Object> data = new HashMap<>();
        data.put("name", "李太白");
        return R.ok().data(data);
    }
}

3. 统一日志处理 

为了更方便我们进行错误的调式,一般会在项目中集成日志。

3.1 添加日志配置文件

在resources下添加日志的配置,文件名必须是logback-spring.xml

以下配置一般不需要修改,要改的话也只是修改日志的输出目录

<property name="log.path" value="D:/javaWeb/log" />

value就是日志的输出位置

<?xml version="1.0" encoding="UTF-8"?>
<configuration  scan="true" scanPeriod="10 seconds">
    <!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
    <!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
    <!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
    <!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
    <contextName>logback</contextName>
    <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
    <property name="log.path" value="D:/javaWeb/log" />
 
    <!--控制台日志格式:彩色日志-->
    <!-- magenta:洋红 -->
    <!-- boldMagenta:粗红-->
    <!-- cyan:青色 -->
    <!-- white:白色 -->
    <!-- magenta:洋红 -->
    <property name="CONSOLE_LOG_PATTERN"
              value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level) |%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n)"/>
 
    <!--文件日志格式-->
    <property name="FILE_LOG_PATTERN"
              value="%date{yyyy-MM-dd HH:mm:ss} |%-5level |%thread |%file:%line |%logger |%msg%n" />
 
    <!--编码-->
    <property name="ENCODING"
              value="UTF-8" />
 
    <!--输出到控制台-->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <!--日志级别-->
            <level>DEBUG</level>
        </filter>
        <encoder>
            <!--日志格式-->
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <!--日志字符集-->
            <charset>${ENCODING}</charset>
        </encoder>
    </appender>
 
    <!--输出到文件-->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--日志过滤器:此日志文件只记录INFO级别的-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_info.log</file>
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天日志归档路径以及格式 -->
            <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>500MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
    </appender>
 
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 日志过滤器:此日志文件只记录WARN级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>WARN</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_warn.log</file>
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
    </appender>
 
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 日志过滤器:此日志文件只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_error.log</file>
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
            <charset>${ENCODING}</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
    </appender>
 
    <!--开发环境-->
    <springProfile name="dev">
        <!--可以灵活设置此处,从而控制日志的输出-->
        <root level="INFO">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="WARN_FILE" />
            <appender-ref ref="ERROR_FILE" />
        </root>
    </springProfile>
 
    <!--生产环境-->
    <springProfile name="pro">
        <root level="ERROR">
            <appender-ref ref="ERROR_FILE" />
        </root>
    </springProfile>
 
</configuration>

3.2 添加application.properties配置

配置文件需要设置下环境,需要跟日志配置文件中的<springProfile name="dev">对应上,不然不生效

# 设置环境
spring.profiles.active=dev

3.3 修改GlobalExceptionHandler类

/**
 * 统一异常处理
 * ControllerAdvice注解的含义是当异常抛到controller层时会拦截下来
 */
@ControllerAdvice
public class GlobalExceptionHandler {
 
    /**
     * 打印日志 
     * 如果项目有集成lombok可使用@Slf4j注解代替
     */
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
 
    /**
     * 使用ExceptionHandler注解声明处理Exception异常
     *
     */
    @ResponseBody
    @ExceptionHandler(Exception.class)
    public R exception(Exception e) {
        // 控制台打印异常
        log.error(e.getMessage());
        // 返回错误格式信息
        return R.error();
    }
 
    /**
     * 使用ExceptionHandler注解声明处理TestException异常
     *
     */
    @ResponseBody
    @ExceptionHandler(TestException.class)
    public R exception(TestException e) {
        // 控制台打印异常
        log.error(e.getMessage());
        // 返回错误格式信息
        return R.error().message(e.getMessage()).code(e.getCode());
    }
 
}

3.4 测试效果

日志生效了,而且在我们的D盘javaWeb目录下也有对应的日志文件了

 我们可以进一步的完善下,将日志堆栈信息输出到文件

3.5 定义工具类

 新建utils包,在该包下添加ExceptionUtils类

/**
 * 日志堆栈信息输出到文件工具类
 *
 */
public class ExceptionUtils {
    public static String getMessage(Exception e) {
        StringWriter sw = null;
        PrintWriter pw = null;
        try {
            sw = new StringWriter();
            pw = new PrintWriter(sw);
            // 将出错的栈信息输出到printWriter中
            e.printStackTrace(pw);
            pw.flush();
            sw.flush();
        } finally {
            if (sw != null) {
                try {
                    sw.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            if (pw != null) {
                pw.close();
            }
        }
        return sw.toString();
    }
}

3.6 再修改GlobalExceptionHandler类

/**
 * 统一异常处理
 * ControllerAdvice注解的含义是当异常抛到controller层时会拦截下来
 */
@ControllerAdvice
public class GlobalExceptionHandler {
 
    /**
     * 打印日志 如果项目有集成lombok可使用@Slf4j注解代替
     */
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
 
    /**
     * 使用ExceptionHandler注解声明处理Exception异常
     *
     */
    @ResponseBody
    @ExceptionHandler(Exception.class)
    public R exception(Exception e) {
        // 控制台打印异常  借助工具类将错误堆栈输出到文件
        log.error(ExceptionUtils.getMessage(e));
        // 返回错误格式信息
        return R.error();
    }
 
    /**
     * 使用ExceptionHandler注解声明处理TestException异常
     *
     */
    @ResponseBody
    @ExceptionHandler(TestException.class)
    public R exception(TestException e) {
        // 控制台打印异常   借助工具类将错误堆栈输出到文件
        log.error(ExceptionUtils.getMessage(e));
        // 返回错误格式信息
        return R.error().message(e.getMessage()).code(e.getCode());
    }
 
}

以上是根据一位博主的文章编写的,现在找不到那篇文章了,还请见谅。

这篇文章就到这里了,下次见!

🥇原创不易,还希望各位大佬支持一下!

👍点赞,你的认可是我创作的动力 !

🌟收藏,你的青睐是我努力的方向!

✏️评论,你的意见是我进步的财富!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Unity 编辑器篇|(九)编辑器美化类( GUIStyle、GUISkin、EditorStyles) (全面总结 | 建议收藏)

目录 1. GUIStyle1.1 参数总览1.2 样式代码 2. GUISkin2.1 参数总览2.2 创建自定义Skin 3. EditorStyles2.1 参数总览1.2 反射获取所有EditorStyles 1. GUIStyle GUIStyle是一个用于定制GUI控件样式的类&#xff0c;它包含了控件的外观属性&#xff0c;如字体、颜色、背景等。…

visual studio的安装及scanf报错的解决

visual studio是一款很不错的c语言编译器 下载地址&#xff1a;官网 点击后跳转到以下界面 下滑后点击下载Vasual Sutdio&#xff0c;选择社区版即可 选择位置存放下载文件后&#xff0c;即可开始安装 安装时会稍微等一小会儿。然后会弹出这个窗口&#xff0c;我们选择安装位…

OpenGL DIR

Mesa简介-CSDN博客 Mesa, also called Mesa3D and The Mesa 3D Graphics Library, is an open source software implementation of OpenGL, Vulkan, and other graphics API specifications. Mesa translates these specifications to vendor-specific graphics ha…

网络安全 | 苹果承认 GPU 安全漏洞存在,iPhone 12、M2 MacBook Air 等受影响

1 月 17 日消息&#xff0c;苹果公司确认了近期出现的有关 Apple GPU 存在安全漏洞的报告&#xff0c;并承认 iPhone 12 和 M2 MacBook Air 受影响。 该漏洞可能使攻击者窃取由芯片处理的数据&#xff0c;包括与 ChatGPT 的对话内容等隐私信息。 安全研究人员发现&#xff0c;…

IntelliJ IDEA 中输出乱码解决

最近tomcat突然在控制台输出乱码&#xff0c;各种乱码问题&#xff0c;查阅大量的资料&#xff0c;最终得以解决. IDEA控制台输出乱码 问题一&#xff1a;idea中tomcat控制台输出乱码 运行本地的tomcat\bin\start.bat文件页面显示正常 在idea中显示乱码 解决&#xff1a; 根…

【C++】:STL序列式容器list源码剖析

一、list概述 总的来说&#xff1a;环形双向链表 特点&#xff1a; 底层是使用链表实现的&#xff0c;支持双向顺序访问 在list中任何位置进行插入和删除的速度都很快 不支持随机访问&#xff0c;为了访问一个元素&#xff0c;必须遍历整个容器 与其他容器相比&#xff0c;额外…

数据结构之栈的基本操作

该顺序栈涉及到了存储整型数据的顺序栈还有存储字符型数据的顺序栈 实现的功能有&#xff1a;入栈、出栈、判断是否为空栈、求栈的长度、清空栈、销毁栈、得到栈顶元素 此外根据上述功能&#xff0c;编写了数值转换&#xff08;十进制转化八进制&#xff09;方法、括号匹配方法…

电梯节能落座-智慧停车场️,电梯不仅可载人也可以载汽车!

电梯不仅可载人也可以载汽车哦&#xff01; 在北京市丰台区&#xff0c;有这么一个智慧停车场&#x1f17f;️ &#xff0c;共298个停车位&#xff0c;全部智能一体化&#xff0c;简直是“豪华” “智能” 的象征。 523能源&#xff1a;小伍&#xff0c;你跑题了... 小伍&am…

儿童用什么样的台灯比较好?精选适合儿童使用的台灯

现在的青少年儿童大多数都是存在视力问题的&#xff0c;而且近视的年龄也越来越小&#xff0c;就拿我身边的朋友来说&#xff0c;孩子刚上小学就已经戴上了厚厚的近视眼镜了。因此很多家庭也开始重视孩子的历史健康问题&#xff0c;尤其是学习时用的那盏台灯。要知道现在的孩子…

JS中的File(四):文件流Streams API使用详解

目录 一、流的原理 二、流的分类 1、可读流&#xff08;ReadableStream&#xff09; 3、转换流&#xff08;TransformStream&#xff09; 三、流中的Request和Response对象 四、综合应用 PS&#xff1a;涉及到一些基本的文件操作和格式内容知识&#xff0c;可以进入我的主…

深度学习(2)--卷积神经网络(CNN)

卷积神经网络&#xff08;Convolutional Neural Networks&#xff09;是一种深度学习模型或类似于人工神经网络的多层感知器&#xff0c;常用来分析视觉图像。 一.卷积神经网络基础概念 传统网络是二维的&#xff0c;而卷积网络是三维的。 例如32x32x3的图片&#xff0c;在传…

阿里云云原生弹性方案:用弹性解决集群资源利用率难题

作者&#xff1a;赫曦 随着上云的认知更加普遍&#xff0c;我们发现除了以往占大部分的互联网类型的客户&#xff0c;一些传统的企业&#xff0c;一些制造类的和工业型企业客户也都开始使用云原生的方式去做 IT 架构的转型&#xff0c;提高集群资源使用率也成为企业上云的一致…

告别繁琐配置!JVS低代码逻辑引擎让你轻松实现高效数据处理

在当今高度数字化的世界中&#xff0c;逻辑引擎作为数据处理和业务逻辑的核心组件&#xff0c;其重要性不言而喻。它不仅关乎企业数据的准确处理&#xff0c;还影响着业务决策的效率和准确性。为了确保逻辑引擎的正常运行和准确性&#xff0c;配置和测试环节显得尤为重要。 本…

C++ 类与对象Oop

类与对象Oop 一、类&#xff1a;用户定义的数据类型&#xff0c;用于封装数据和方法1.1 对比结构体警告-->主要目的&#xff1a;初始化 1.2 定义类的过程并定义一个对象1.2.1 定义类例子 1.2.2 定义一个对象1.2.3 注意事项例子1.2.4 分成头文件和源文件的方式&#xff08;0&…

k8s之对外服务ingress

一、service 1、service作用 ①集群内部&#xff1a;不断跟踪pod的变化&#xff0c;不断更新endpoint中的pod对象&#xff0c;基于pod的IP地址不断变化的一种服务发现机制&#xff08;endpoint存储最终对外提供服务的IP地址和端口&#xff09; ②集群外部&#xff1a;类似负…

canal调度控制器CanalController源码分析

canal调度控制器初始化&#xff1a; public CanalController(final Properties properties) 1. 初始化instance公共全局配置&#xff1a; canal.instance.global.(mode、lazy、manager.address以及spring.xml&#xff0c;并放入内存 InstanceConfig globalInstanceConfig; …

看完买,开放式耳机质量榜单:南卡夺冠、韶音第5、Cleer排第7

​作为一名拥有丰富经验的开放式耳机用户&#xff0c;我想在此提醒大家&#xff0c;选择耳机时&#xff0c;千万不要盲目跟风或过于信赖所谓的“网红”或“大牌产品”。毕竟&#xff0c;每个人的需求和使用环境都是独一无二的&#xff0c;因此&#xff0c;适合自己的耳机才是最…

AP5191DC-DC宽电压LED降压恒流驱动器

产品描述 AP5191是一款PWM工作模式,高效率、外围 简 单、外置功率MOS管&#xff0c;适用于4.5-150V输入的高 精度降压LED恒流驱动芯片。输出最大功率150W&#xff0c; 最大电流6A。 AP5191可实现线性调光和PWM调光&#xff0c;线性 调 光脚有效电压范围0.55-2.6V. AP519…

centos7 arm服务器编译安装PaddlePaddle

前言 随着国产服务器发展&#xff0c;部署项目需要用在国产服务器上&#xff0c;官方教程里面很多没有讲解到&#xff0c;安装过程中出现了各种各样的问题&#xff0c;以下是对官方教程的补充&#xff0c;有什么问题&#xff0c;欢迎指正&#xff01; 一、环境准备 gcc: 8.2版…

(工具变量)各地区-距沿海港口最短距离汇总数据集

全国各省距沿海港口最短距离数据提供了中国各省份与最近海港之间的最短地理距离信息。这些数据对于理解和分析中国各省的地理优势、物流效率以及对外贸易潜力有一定帮助。沿海港口作为国际贸易的重要节点&#xff0c;其距离对于省份的出口入口物流成本、运输时间以及总体贸易便…