SpringBoot 异常处理的最佳实践

news2024/12/29 10:38:42

SpringBoot 异常处理的最佳实践

在 Web 开发中,异常处理是非常重要的一环。在 SpringBoot 框架中,异常处理方式有很多种,但是如何选择最佳实践呢?本文将介绍 SpringBoot 异常处理的最佳实践,并附带代码示例。

在这里插入图片描述

异常处理的最佳实践

异常处理的最佳实践包括以下几个方面:

  1. 统一异常处理

在 SpringBoot 中,我们可以使用 @ControllerAdvice 注解实现全局异常处理。使用 @ControllerAdvice 注解,我们可以集中处理所有 Controller 层抛出的异常,而不必在每个 Controller 中单独处理。在 GlobalExceptionHandler 类中定义异常处理方法,并根据具体的业务需求对异常进行相应的处理,可以大大提高代码的可维护性和可读性。

  1. 自定义异常

在 SpringBoot 中,我们可以通过自定义异常类来处理特定的异常情况,并在 GlobalExceptionHandler 类中定义对应的异常处理方法。自定义异常类可以继承 RuntimeException 或 Exception 类,根据具体的业务需求进行选择。自定义异常类可以包含异常码、异常信息等属性,方便我们对异常进行更加细致的处理。

  1. 统一返回结果

在 SpringBoot 中,我们可以定义一个统一的返回结果类,用于封装接口返回结果。在接口返回时,我们可以使用该类作为返回值,并根据具体的业务需求封装返回结果的状态码、消息和数据等信息。

  1. 参数校验

在 SpringBoot 中,我们可以使用 javax.validation.constraints 包中的注解对参数进行校验。在 Controller 层中,我们可以使用 @Validated 注解对参数进行校验,并在对应的 Service 层方法中进行处理。如果参数校验失败,会抛出 MethodArgumentNotValidException 异常,在 GlobalExceptionHandler 类中的 handleMethodArgumentNotValidException 方法中进行处理。

  1. 日志记录

在 SpringBoot 中,我们可以使用日志框架记录系统运行时的异常信息。在 GlobalExceptionHandler 类中的异常处理方法中,我们可以使用日志框架记录异常发生的时间、异常类型、异常信息等相关信息,方便我们进行排查和问题定位。

完整代码示例

下面是一个完整的使用 SpringBoot 异常处理的示例代码:

@ControllerAdvice
public class GlobalExceptionHandler {
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ErrorResponse handleException(Exception e) {
        logger.error("系统异常", e);
        return new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), "系统异常");
    }

    @ExceptionHandler(UserNotFoundException.class)
    @ResponseBody
    public ErrorResponse handleUserNotFoundException(UserNotFoundException e) {
        logger.warn("用户不存在", e);
        return new ErrorResponse(HttpStatus.NOT_FOUND.value(), "用户不存在");
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public ErrorResponse handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        List<ObjectError> allErrors = bindingResult.getAllErrors();
        List<String> errorMessages = new ArrayList<>();
        for (ObjectError error : allErrors) {
            errorMessages.add(error.getDefaultMessage());
        }
        String errorMessage = String.join(",", errorMessages);
        logger.warn("参数无效", e);
        return new ErrorResponse(HttpStatus.BAD_REQUEST.value(), errorMessage);
    }
}

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    @PostMapping("/add")
    public Result addUser(@Validated @RequestBody User user) {
        userService.addUser(user);
        return Result.success();
    }

    @GetMapping("/{id}")
    public Result getUserById(@PathVariable("id") Long id) {
        User user = userService.getUserById(id);
        if (user == null) {
            throw new UserNotFoundException();
        }
        return Result.success(user);
    }
}

@Service
public class UserService {
    @Autowired
    private UserDao userDao;

    public void addUser(User user) {
        userDao.save(user);
    }

    public User getUserById(Long id) {
        return userDao.findById(id).orElse(null);
    }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    @NotNull(message = "用户名不能为空")
    privateLong id;

    @NotBlank(message = "用户名不能为空")
    private String username;

    @NotBlank(message = "密码不能为空")
    private String password;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> {
    private Integer code;
    private String message;
    private T data;

    public static <T> Result<T> success() {
        return new Result<>(HttpStatus.OK.value(), "成功", null);
    }

    public static <T> Result<T> success(T data) {
        return new Result<>(HttpStatus.OK.value(), "成功", data);
    }

    public static <T> Result<T> error(Integer code, String message) {
        return new Result<>(code, message, null);
    }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ErrorResponse {
    private Integer code;
    private String message;
}

public class UserNotFoundException extends RuntimeException {
}

@Repository
public interface UserDao extends JpaRepository<User, Long> {
}

在上面的代码示例中,我们定义了一个 GlobalExceptionHandler 类,用于处理全局异常。在该类中,我们定义了三个异常处理方法:handleException、handleUserNotFoundException 和 handleMethodArgumentNotValidException。分别用于处理系统异常、用户不存在异常和参数无效异常。在每个方法中,我们都使用日志框架记录异常信息,并返回封装好的 ErrorResponse 对象。

在 UserController 类中,我们使用 @Validated 注解对 addUser 方法中的 User 参数进行了校验。如果校验失败,会抛出 MethodArgumentNotValidException 异常,在 GlobalExceptionHandler 类中的 handleMethodArgumentNotValidException 方法中进行处理。

在 UserService 类中,我们使用了 JpaRepository 接口,对 User 数据进行了持久化操作。

最后,我们定义了 User、Result、ErrorResponse 和 UserNotFoundException 四个类,分别用于封装用户信息、接口返回结果、错误信息和用户不存在异常。

结论

在本文中,我们介绍了 SpringBoot 异常处理的最佳实践,并附带了完整的代码示例。在使用 SpringBoot 进行 Web 开发时,我们应该充分考虑异常处理的方方面面,以保证代码的可维护性和可读性。通过使用统一异常处理、自定义异常、统一返回结果、参数校验和日志记录等技术手段,我们可以更加高效地进行异常处理,提高系统的稳定性和可靠性。

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

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

相关文章

flutter - 编写 阿里云-金融级实名认证插件

项目中有实名认证的需求&#xff0c;用户上传身份证反正面&#xff0c;进行人脸核验&#xff0c;后台集成的是阿里云的金融级实名认证SDK&#xff0c;巧合的是阿里云没有packages 需要自己造轮子。 废话不多少&#xff0c;直接上代码&#xff1a; 新建项目 ProjectType Plugin…

网站图片优化技巧及最佳实践

&#x1f482; 个人网站:【海拥】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 目录 前言使用适当的图片格式…

0017-TIPS-pawnyable : eBPF

原文 BPFの導入 検証器とJITコンパイラ eBPFのバグの悪用 题目下载 BPF介绍 BPF 在介绍eBPF之前&#xff0c;先介绍其前身BPF。 随着时代的发展&#xff0c;BPF的用途越来越广泛&#xff0c;扩展也越来越多。在重大更改后的BPF有时被称为eBPF&#xff08;扩展BPF&#xff09…

路漫漫其修远兮,吾将上下而求索

路漫漫其修远兮&#xff0c;吾将上下而求索 一、坚定信念二、持之以恒地努力三、谦虚和学习的态度四、上下而求索也要遵循道德底线和原则五、建立合适的人际关系和互助机制六、坚定自己的信仰和信念七、个人经验与体会 路漫漫其修远兮&#xff0c;吾将上下而求索——这句话不仅…

python期末上机题:

1、编写Python程序&#xff0c;创建类Temperature&#xff0c;其包含成员变量degree&#xff08;表示温度&#xff09;以及实例方法ToHuaShiDu()和ToSheShiDu&#xff0c;并编写测试代码。 程序运行示例&#xff1a; 请输入摄氏温度&#xff1a;30 摄氏温度 30.0&#xff0…

栈和队列(一)

文章目录 顺序表&#xff0c;链表的有点和缺点链表顺序表 栈和队列栈的实现栈的应用&#xff08;括号匹配问题&#xff09; 顺序表&#xff0c;链表的有点和缺点 链表 优点&#xff1a; 1、任意位置插入删除&#xff0c;时间复杂度位O(1) 2、按需申请释放空间 缺点&#xff1a…

Prompt Engineering 面面观

作者&#xff1a;紫气东来 项目地址&#xff1a;https://zhuanlan.zhihu.com/p/632369186 一、概述 提示工程&#xff08;Prompt Engineering&#xff09;&#xff0c;也称为 In-Context Prompting&#xff0c;是指在不更新模型权重的情况下如何与 LLM 交互以引导其行为以获得…

Latex长表格

示例一&#xff1a; 输出一个长表格的示例。 代码&#xff1a; \documentclass[jou,apacite]{apa6} \usepackage{multirow} \usepackage{array} \newcolumntype{P}[1]{>{\centering\arraybackslash}p{#1}} \usepackage{longtable}%\usepackage{showframe} % to visualize…

极致呈现系列之:Echarts漏斗图的流光溢彩

目录 什么是漏斗图漏斗图的特点及应用场景漏斗图的特点漏斗图常见的的应用场景&#xff1a; Echarts中漏斗的常用属性Vue3中创建漏斗图美化漏斗图样式 在数据分析和可视化中&#xff0c;我们经常需要比较不同阶段的数据比例或流程的渐进筛选过程。漏斗图作为一种专门用于展示这…

Qt使用技巧--定义Private类

如果查看Qt的源码&#xff0c;会发现很多类都会有一个***Private类。这是Qt用于封装私有操作的一种设计模式。 给出一个继承自QObject的Private类具体的实现&#xff1a; MyClass.h #include "QObject"class MyClassPrivate; class MyClass: public QObject{ Q_OB…

LangChain让LLM连接更多能力

随着LLM&#xff08;Large language models &#xff09;的发展&#xff0c;不仅仅出现了很多新的应用&#xff0c;一些开发框架也发展很快&#xff0c;典型的就是本文介绍的项目——LangChain&#xff0c;目前LangChain几乎一天一个版本&#xff0c;几个月时间Star数目已经49k…

<C++> C++11 Lambda表达式

C11 Lambda表达式 1.C98中的一个例子 在C98中&#xff0c;如果想要对一个数据集合中的元素进行排序&#xff0c;可以使用std::sort方法。 #include <algorithm> #include <functional> int main() {int array[] {4, 1, 8, 5, 3, 7, 0, 9, 2, 6};// 默认按照小于…

软考:软件工程:面向对象技术与UML,时序图,用例图,类对象,封装,继承,多态

软考&#xff1a;软件工程: 提示&#xff1a;系列被面试官问的问题&#xff0c;我自己当时不会&#xff0c;所以下来自己复盘一下&#xff0c;认真学习和总结&#xff0c;以应对未来更多的可能性 关于互联网大厂的笔试面试&#xff0c;都是需要细心准备的 &#xff08;1&#…

iOS 集成Jenkins pipeline 完整流程

文章目录 一 创建一个Jenkins pipeline 项目配置分支参数在工程中添加 ExportOptions.plist 文件创建放置打包文件的文件夹在工程里面添加shell脚本文件配置pipeline sript构建 一 创建一个Jenkins pipeline 项目 配置分支参数 选择参数化构建构成&#xff0c;如上图所示&#…

网络层实验报告

计算机网络综合实训 实训报告二 所在院系 计算机与信息工程学院 学科专业名称 计算机科学与技术 导师及职称 柯宗武 教授 提交时间 2022.3.29 网络层实验报告 &#xff08;湖北师范大学计算机与信息工程学院 中国 黄石 435002&#xff09; 1 IP分析 1.1背景知识 1.1.1 什么是…

SpringMVC系列-2 HTTP请求调用链

背景 本文作为 SpringMVC系列 第二篇&#xff0c;介绍HTTP请求的调用链&#xff1a;从请求进入Tomcat到数据流返回客户端的完整过程。为了尽可能把流程表达清楚&#xff0c;进行了很多减支处理&#xff0c;只关注主线逻辑。 本文也作为SpringMVC系列后续文章的基础&#xff0…

软考A计划-系统集成项目管理工程师--一般常识-上

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff…

SpringBoot 异常处理的主要组件有哪些

SpringBoot 异常处理的主要组件有哪些 在 SpringBoot 应用程序中&#xff0c;异常处理是一个非常重要的话题。当应用程序出现异常时&#xff0c;我们需要对异常进行处理&#xff0c;以保证应用程序的稳定性和可靠性。SpringBoot 提供了一系列的组件&#xff0c;用于处理各种类…

简析IAST—Agent篇 | 信息安全

一、IAST简单介绍 IAST(Interactive Application Security Testing)交互式应用程序安全测试&#xff0c;通过服务端部署Agent探针&#xff0c;流量代理/VPN或主机系统软件等方式&#xff0c;监控Web应用程序运行时函数执行并与扫描器实时交互&#xff0c;高效、精准的安全漏洞&…

LeetCode 面试题 16.19. 水域大小

LeetCode 面试题 16.19. 水域大小 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/group-anagrams/description/ 博主Github&#xff1a;https://github.com/GDUT-Rp/LeetCode 题目&#xff1a; 你有一个用于表示一片…