springboot 加入 日志+ controller 加入全局异常捕获

提下比较好点

包含将捕获的异常堆栈完整的返回给前端。方便 后端人员用 swagger 或 knife 工具验证接口时,直接看到异常。

有啥用呢?在现场环境,或不方便远程服务器机器时,非常有用!!!

同时,文件日志太有用了!!!  尤其在无法查看 控制台时,简直就是救命稻草!!!

(无法看控制台,却能看到日志文件的情况 ,在 Azure 云 服务非常常见。)


我用的idea,springboot 2.7.15,不需要额外引入 库。

加入日志

application.yml 内需要加入log配置:

logging:
  config: classpath:logback-spring.xml
  file:
    name: logs\app.log
  level:
    # 全局日志级别,可选TRACE, DEBUG, INFO, WARN, ERROR
    # 优先级大于logback-spring.xml中<root>标签下的配置
    root: INFO

上面写了 logback-spring.xml 的配置文件是放在 classpath 下,所以我们开发时,放在和 application.yaml 同级目录即可。

贴上通用的 logback-spring.xml 模板:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/base.xml" />

    <!-- 日志输出级别 -->
    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="FILE"/>
    </root>

    <!-- 控制台输出 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 文件输出 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/app.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天滚动 -->
            <fileNamePattern>logs/app.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!-- 保留 7 天的日志 -->
            <maxHistory>7</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
</configuration>

在使用上,controller,service,dao,这些常用bean 的 class头部引入标签:

@Slf4j 即可

之后 在bean 内部就能直接用了:

log.info("xxx");

log.error("xxx");


controller 加入全局异常捕获

对于那些和业务无关的异常,controller 再也不用对乱七八糟的异常各种捕获了,service,dao 也可以直接往外抛异常了。

这是多么开心的事!!!

全部异常捕获类:

package com.example.demo.config;

import com.example.demo.utils.LogExceptionStackUtil;
import com.example.demo.utils.Result;
import com.example.demo.utils.SCSRestfulException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.client.RestClientException;

import java.util.logging.Logger;

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 专门处理 访问 restul 接口时的异常
     * @param e
     * @return
     */
    @ExceptionHandler(RestClientException.class)
    public Result<String> handleException(SCSRestfulException e)
    {
        StackTraceElement stackTrace = e.getStackTrace()[0];
        String methodName = stackTrace.getMethodName();
        String fileName = stackTrace.getFileName();
        String className = stackTrace.getClassName();
        int lineNumber = stackTrace.getLineNumber();
        log.error("异常发生在文件{}的类{}中的方法{}的第{}行',异常信息:{}", fileName,className,methodName,lineNumber,e.getMessage());

        String errMsg = LogExceptionStackUtil.logExceptionStack(e);
        log.error("====>"+errMsg);

        return Result.Label.ERROR_DataSourceServerAccessIsNotResponded.as(errMsg);
    }

    /**
     * 捕获基类Throwable
     * HttpStatus.INTERNAL_SERVER_ERROR 对应 code=500
     * @param e
     * @return
     */
    @ExceptionHandler
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<String> handler(Throwable e) {

        String errMsg = LogExceptionStackUtil.logExceptionStack(e);
        log.error("====>"+errMsg);

        return Result.Label.ERROR_ServerIsError.as(errMsg);
    }
}
Result 类
package com.example.demo.utils;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;

/**
 * @author Rain
 * @date 2023/11/30
 */
@ApiModel(description= "响应数据结构")
@Data
public class Result<T> implements Serializable {

    @ApiModelProperty(value = "响应代码{<br />" +
            "Success(0),<br />" +
            "<br />" +
            "        Failure(-1),<br />" +
            "<br />" +
            "        FAILED_InvalidParameter(-2),<br />" +
            "<br />" +
            "        FAILED_UnsupportedDataSourceType(-3),<br />" +
            "<br />" +
            "        FAILED_UnauthorizedCodeOfDataLake(-4),<br />" +
            "<br />" +
            "        FAILED_NoDataMatchConditions(-5),<br />" +
            "<br />" +
            "        ERROR_DataSourceServerAccessIsNotResponded(-6),<br />" +
            "<br />" +
            "        ERROR_ServerIsError(-7);<br />" +
            "<br />" +
            "        ERROR_InvalidToken(-8);<br />" +
            "<br />" +
            "        ERROR_TokenIsExpirated(-9);<br />" +
            "}")
    private Integer code;

    @ApiModelProperty(value = "响应信息")
    private String msg;

    @ApiModelProperty(value = "数据")
    private T data;

    private Result(){

    }

    private static <T> Result<T> build(Label label) {
        return build(label, null);
    }

    private static <T> Result<T> build(Label label, T result) {

        return build(label, label.name(), result);
    }

    private static <T> Result<T> build(Label label, String message, T result) {
        Result<T> resultJson = new Result<>();
        resultJson.code = label.code;
        resultJson.msg = message;
        resultJson.data = result;
        return resultJson;
    }



    public static enum Label {

        /**
         * code 遵守如下约定:
         * 正数 代表 期望现象;
         * 负值 代表悲观现象;
         * 0 代表 基本符合预期。
         */
        Success(0),

        /**
         * 虽然异常,但无法提供更多额外信息
         */
        Failure(-1),

        /**
         * 无效参数
         * 不符合服务端基本校验要求
         */
        FAILED_InvalidParameter(-2),

        /**
         * 数据源类型不支持
         */
        FAILED_UnsupportedDataSourceType(-3),

        /**
         * 您的 code 未经授权,无法提供token
         */
        FAILED_UnauthorizedCodeOfDataLake(-4),

        /**
         * 您的没有数据能够匹配您的条件查询
         */
        FAILED_NoDataMatchConditions(-5),

        /**
         * 数据源服务器访问异常
         */
        ERROR_DataSourceServerAccessIsNotResponded(-6),

        /**
         * 零件查询服务异常
         */
        ERROR_ServerIsError(-7),

        /**
         * 无效 token
         */
        ERROR_InvalidToken(-8),

        /**
         * token 过期
         */
        ERROR_TokenIsExpirated(-9);

        private Integer code;

        Label(Integer code) {
            this.code = code;
        }

        public <T> Result<T> as(){
            return Result.build(this);
        }

        public <T> Result<T> as(T data){
            return Result.build(this,data);
        }
    }
}
上面有 swagger 的标签,这里的对它的配置,就不赘述了。如果觉得懒,那些标签删了也行。


LogExceptionStackUtil 类
package com.example.demo.utils;

import java.io.PrintWriter;
import java.io.StringWriter;

/**
 * @author Rain
 * 将 异常的堆栈信息输出的 外部的 String 流中
 */
public class LogExceptionStackUtil {
    public static String logExceptionStack(Throwable e) {
        StringWriter errorsWriter = new StringWriter();
        e.printStackTrace(new PrintWriter(errorsWriter));
        return errorsWriter.toString();
    }
}

如标题所说的好处,将

e.printStackTrace() 

内容直接打印到日志出来,并且也能将堆栈内容,通过 Result 返回给前端(比如 swagger) ,是多么快乐的事。

贴上 swagger 调用时发生异常时的效果:

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

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

相关文章

ChatGPT数据分析应用——漏斗分析

ChatGPT数据分析应用——漏斗分析 ​ 漏斗分析在数据分析中也比较常用&#xff0c;主要是用于发现各个转化流程中哪个环节有问题。接下来我们让ChatGPT解释这个方法的概念并提供相应的案例。发送如下内容给ChatGPT。 ​ ChatGPT收到上述内容后&#xff0c;返回如下结果。 漏斗…

分布式架构下 网络通信的底层实现原理(一)

什么是通信&#xff1f; 当我们通过浏览器访问一个网址时&#xff0c;一段时间后该网址会渲染出访问的内容&#xff0c;这个过程是怎么实现的呢&#xff1f; 这种通信方式是基于http协议实现的&#xff0c;那么什么是协议&#xff1f; 像一个中国人和一个外国人交流时&#xf…

Redis 配置文件详解

Units 单位 配置大小单位&#xff0c;开头定义了一些基本的度量单位&#xff0c;只支持bytes&#xff0c;不支持bit&#xff0c;大小写不敏感。 # Redis configuration file example. # # Note that in order to read the configuration file, Redis must be # started with …

无尘抹布在洁净室环境中的作用与重要性

导言&#xff1a; 洁净室环境&#xff0c;特别是在制药、电子和生物技术等行业中&#xff0c;对清洁和卫生的要求极为严格。无尘抹布在维护这些环境的洁净和卫生方面起着至关重要的作用。本文将探讨无尘抹布的重要性以及在洁净室环境中的各种应用。 了解无尘抹布 定义和组成&a…

TensorBoard——Pytorch版使用(附带案例演示)

TensorBoard是一个用于可视化机器学习实验结果的工具&#xff0c;可以帮助我们更好地理解和调试训练过程中的模型。 在PyTorch中&#xff0c;我们可以使用TensorBoardX库来与TensorBoard进行交互。TensorBoardX是一个PyTorch的扩展&#xff0c;它允许我们将PyTorch的训练中的关…

基于Vue的兴趣活动推荐APP的设计与实现

目 录 摘 要 I Abstract II 引 言 1 1 相关技术简介 3 1.1 框架 3 1.1.1 Spring MVC 3 1.1.2 Spring框架 3 1.1.3 MyBatis框架 3 1.1.4 VUE框架 3 1.2 开发语言 3 1.2.1 JAVA 3 1.2.2 JavaScript 4 1.3 设计模式 4 1.4 数据库 4 2 可行性分析 5 2.1 社会可行性 5 2.2 经济可行…

Extended Feature Pyramid Network for SmallObject Detection

摘要 各种尺度的特征耦合会削弱小对象的性能&#xff0c;本文中&#xff0c;我们提出了具有超高分辨率金字塔的扩展特征金字塔网络&#xff08;EFPN &#xff09;&#xff0c;专门用于小目标检测。具体来说&#xff0c;我们设计了一个新模块&#xff0c;称为特征纹理转移&#…

《Effective Modern C++》- 极精简版 5-14条

本文章属于专栏《业界Cpp进阶建议整理》 继续上篇《Effective Modern C》- 极精简版 1-4条。本文列出《Effective Modern C》的5-14条的个人理解的极精简版本。 Item5、优先考虑auto而非显示类型声明 auto的优势&#xff1a; 强制变量初始化在返回部分场景&#xff0c;会返回一…

释机器学习中的召回率、精确率、准确率

精确率和召回率又被叫做查准率和查全率&#xff0c;可以通过P-R图进行表示 如何理解P-R(精确率-召回率)曲线呢&#xff1f;或者说这些曲线是根据什么变化呢&#xff1f; 以逻辑回归举例&#xff0c;其输出值是0-1之间的数字。因此&#xff0c;如果我们想要判断用户的好坏&…

如何做好【沟通】管理

目录 管理的定义 管理的四大职能&#xff1a; 四共团队&#xff1a; 领导力&#xff1a; 沟通的四种类型听、说、读、写&#xff08;计划、报告&#xff09; 沟通四原则 思维框架&#xff1a;结构树报告 管理的定义 彼得.德鲁克&#xff1a;管理通过他人去完成任务的学…

基于java SSM图书管理系统简单版设计和实现

基于java SSM图书管理系统简单版设计和实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取源码联系…

c++ 11 新特性 不同数据类型之间转换函数之const_cast

一.不同数据类型之间转换函数const_cast介绍 const_cast是C11中引入的一种类型转换操作符&#xff0c;用于修改类型的const或volatile属性。const_cast的主要用途是移除对象的常量性&#xff0c;它是唯一具有此能力的C风格的转型操作符。在C11中&#xff0c;const_cast可以完成…

Linux安装,配置,启动HBase

Linux安装&#xff0c;配置&#xff0c;启动HBase 一、HBase安装&#xff0c;配置 1、下载HBase安装包 Hbase官方下载地址: http://archive.apache.org/dist/hbase 选择相应的版本点击下载&#xff0c;这里以2.3.5为例 # linux可以通过wget命令下载 wget https://archive…

如何解决Firefox提示“此网站可能不支持TLS1.2协议”的问题 错误代码:SSL_ERROR_UNSUPPORTED_VERSION

1.问题描述 当你在Firefox浏览器中访问一个网站时&#xff0c;可能会遇到这样的提示&#xff1a;   之后&#xff0c;不停地刷新或 重新输入&#xff0c;怎么也访问不进去&#xff1f;&#xff1f; 2.解决步骤 按照以下步骤操作&#xff0c;可以降低Firefox对TLS版本的要求…

HEUFT电源维修x-ray发生器维修HBE211226

HEUFT电源维修x-ray发生器维修HBE211253;海富HEUFT在线液位检测X射线发生器维修&#xff0c;不限型型号系列。 德国海富推出HEUFT在线液位检测装置,满瓶检测系统HEUFT有着强大的功能,它的模块机构能整合很多程序,并依据不同的产品及其包装特性,照相技术,高频技术或X-ray技术。…

[eslint error] ‘v-model‘ should be on a new line.

错误详情 错误原因 此问题是由于.eslintrc.js文件中的vue/max-attributes-per-line配置错误产生的 esline默认要求属性单独开一行 错误解决 所以解决的方法有两个一个是遵从eslint默认规则让属性新开一行,能解决问题 但是我不喜欢看这样子的代码,所以我只好去改掉eslint的规…

声强和能量及其praat操作

强度、声压、能量、功率 这是我们在电学和声学等领域较常见到的词汇&#xff0c;但有时候可能会搞混淆&#xff0c;所以再整理一下。 强度&#xff08;intensity&#xff09; 强度&#xff0c;也叫做声强&#xff08;Sound intensity&#xff09;。《声学基础》中对于声强的…

Unity 关节:铰链、弹簧、固定、物理材质:摩檫力、 特效:拖尾、

组件-物理-关节&#xff1a;铰链&#xff08;类似门轴&#xff09; 自动动作、多少力可以将其断开、 弹簧可以连接另一个刚体&#xff08;拖动即可&#xff09; 固定一般是等待一个断裂力&#xff0c;造成四分五裂的效果。 物理材质 设置摩檫力&#xff0c;则可以创造冰面的…

K8S之实现业务的金丝雀发布

如何实现金丝雀发布 金丝雀发布简介优缺点在k8s中实现金丝雀发布 金丝雀发布简介 金丝雀发布的由来&#xff1a;17 世纪&#xff0c;英国矿井工人发现&#xff0c;金丝雀对瓦斯这种气体十分敏感。空气中哪怕有极其微量的瓦斯&#xff0c;金丝雀也会停止歌唱&#xff1b;当瓦斯…

redis缓存(穿透, 雪崩, 击穿, 数据不一致, 数据并发竞争 ), 分布式锁(watch乐观锁, setnx, redission)

redis的watch缓存机制 WATCH 机制原理&#xff1a; WATCH 机制&#xff1a;使用 WATCH 监视一个或多个 key , 跟踪 key 的 value 修改情况&#xff0c;如果有key 的 value 值在事务 EXEC 执行之前被修改了&#xff0c;整个事务被取消。EXEC 返回提示信息&#xff0c;表示 事务已…