返回值封装,异常统一处理优雅解决接口所有问题

news2024/11/20 7:12:56

在项目整体架构设计的时候,我们经常需要做以下工作:

  1. 返回值的统一封装处理,因为只有规范好统一的返回值格式,才能不会给接口使用者带来疑惑和方便前端对接口的统一处理。
  2. 对异常码进行严格规定,什么错误返回什么码制,这样前端就可以根据不同的码制进行错误提示,同时也方便三方调用者对异常进行处理。要注意,微服务架构,不同的微服务之间的码制前缀要做区分,这样我们就可以根据码制很快定位到是哪个微服务出现问题。
  3. 对异常的统一拦截,这一点非常重要,因为一旦对异常没有做统一处理,严重就会导致堆栈乃至sql信息暴露给前端,这是非常严重的事故。

所以今天我会给大家展示如何对返回值进行统一封装,如何对异常进行统一拦截,异常码定义,根据自己的业务自行定义即可。

1. 返回值的封装

分为两步,首先定义返回值类型和字段,然后定义BaseController。

1.1 响应信息主体

我定义的这个涵盖了我们要返回的各种情况,大家可以参考

/**
 * 响应信息主体
 */
@Data
@NoArgsConstructor
public class R<T> implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 成功
     */
    public static final int SUCCESS = 200;

    /**
     * 失败
     */
    public static final int FAIL = 500;

    private int code;

    private String msg;

    private T data;

    public static <T> R<T> ok() {
        return restResult(null, SUCCESS, "操作成功");
    }

    public static <T> R<T> ok(T data) {
        return restResult(data, SUCCESS, "操作成功");
    }

    public static <T> R<T> ok(String msg) {
        return restResult(null, SUCCESS, msg);
    }

    public static <T> R<T> ok(String msg, T data) {
        return restResult(data, SUCCESS, msg);
    }

    public static <T> R<T> fail() {
        return restResult(null, FAIL, "操作失败");
    }

    public static <T> R<T> fail(String msg) {
        return restResult(null, FAIL, msg);
    }

    public static <T> R<T> fail(T data) {
        return restResult(data, FAIL, "操作失败");
    }

    public static <T> R<T> fail(String msg, T data) {
        return restResult(data, FAIL, msg);
    }

    public static <T> R<T> fail(int code, String msg) {
        return restResult(null, code, msg);
    }

    /**
     * 返回警告消息
     *
     * @param msg 返回内容
     * @return 警告消息
     */
    public static <T> R<T> warn(String msg) {
        return restResult(null, HttpStatus.WARN, msg);
    }

    /**
     * 返回警告消息
     *
     * @param msg 返回内容
     * @param data 数据对象
     * @return 警告消息
     */
    public static <T> R<T> warn(String msg, T data) {
        return restResult(data, HttpStatus.WARN, msg);
    }

    private static <T> R<T> restResult(T data, int code, String msg) {
        R<T> r = new R<>();
        r.setCode(code);
        r.setData(data);
        r.setMsg(msg);
        return r;
    }

    public static <T> Boolean isError(R<T> ret) {
        return !isSuccess(ret);
    }

    public static <T> Boolean isSuccess(R<T> ret) {
        return R.SUCCESS == ret.getCode();
    }
}

1.2 BaseController 的写法

**
 * web层通用数据处理
 */
public class BaseController {

    /**
     * 响应返回结果
     *
     * @param rows 影响行数
     * @return 操作结果
     */
    protected R<Void> toAjax(int rows) {
        return rows > 0 ? R.ok() : R.fail();
    }

    /**
     * 响应返回结果
     *
     * @param result 结果
     * @return 操作结果
     */
    protected R<Void> toAjax(boolean result) {
        return result ? R.ok() : R.fail();
    }

	//同时也可以将一些常用的方法放在这里,比如获取登录用户信息
}

1.3 示例

@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/workflow/category")
public class WfCategoryController extends BaseController {

 @GetMapping("/eventTest")
    public R<Void> eventTest(){

        applicationEventPublisher.publishEvent(new UserChangePasswordEvent("11111"));

        return R.ok();
    }
}

返回值:
在这里插入图片描述

2. 全局异常拦截

全局异常拦截的本质实际上采用的是spring的AOP拦截实现的,然后根据异常类型映射到不同的ExceptionHandler处理方法上。

2.1 引入AOP依赖

必须引入AOP依赖,我刚开始忘了依赖,怎么试都不对,所以一定要检查好,不要忘了。

        <!-- SpringBoot 拦截器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

2.2 写异常拦截器

在写异常拦截器的时候,我们得要分为这么几个部分,首先是自定义的业务异常拦截,验证类异常,比如参数校验类异常拦截处理,还有未知的运行时异常拦截,如果使用到Mybatis,还得要注意Mybatis系统异常的通用拦截处理,还有就是请求不支持异常,最后再是统一的大异常拦截。

可以看我下面写的案例:

/**
 * 全局异常处理器
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 请求方式不支持
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public R<Void> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
                                                       HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
        return R.fail(e.getMessage());
    }

    /**
     * Mybatis系统异常 通用处理
     */
    @ExceptionHandler(MyBatisSystemException.class)
    public R<Void> handleCannotFindDataSourceException(MyBatisSystemException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        String message = e.getMessage();
        if (message.contains("CannotFindDataSourceException")) {
            log.error("请求地址'{}', 未找到数据源", requestURI);
            return R.fail("未找到数据源,请联系管理员确认");
        }
        log.error("请求地址'{}', Mybatis系统异常", requestURI, e);
        return R.fail(message);
    }

    /**
     * 业务异常
     */
    @ExceptionHandler(ServiceException.class)
    public R<Void> handleServiceException(ServiceException e, HttpServletRequest request) {
        log.error(e.getMessage(), e);
        Integer code = e.getCode();
        return ObjectUtil.isNotNull(code) ? R.fail(code, e.getMessage()) : R.fail(e.getMessage());
    }

    /**
     * 拦截未知的运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    public R<Void> handleRuntimeException(RuntimeException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',发生未知异常.", requestURI, e);
        return R.fail(e.getMessage());
    }

    /**
     * 系统异常
     */
    @ExceptionHandler(Exception.class)
    public R<Void> handleException(Exception e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',发生系统异常.", requestURI, e);
        return R.fail(e.getMessage());
    }

    /**
     * 自定义验证异常
     */
    @ExceptionHandler(BindException.class)
    public R<Void> handleBindException(BindException e) {
        log.error(e.getMessage(), e);
        String message = StreamUtils.join(e.getAllErrors(), DefaultMessageSourceResolvable::getDefaultMessage, ", ");
        return R.fail(message);
    }

    /**
     * 自定义验证异常
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public R<Void> constraintViolationException(ConstraintViolationException e) {
        log.error(e.getMessage(), e);
        String message = StreamUtils.join(e.getConstraintViolations(), ConstraintViolation::getMessage, ", ");
        return R.fail(message);
    }

    /**
     * 自定义验证异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public R<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        log.error(e.getMessage(), e);
        String message = e.getBindingResult().getFieldError().getDefaultMessage();
        return R.fail(message);
    }
}

运行返回显示
在这里插入图片描述

异常统一处理和返回值封装就到此结束了,上面的稍微修改下,完全可以做生产用,希望大家多多点赞关注支持,后续给大家分享更多有用的知识点!!!

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

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

相关文章

ShardingSphere-JDBC 5.1.1 分库分表

分库分表解决的问题 mysql的扩展 mysql并不能完全利用高性能服务器的硬件&#xff0c;当cpu超过24个&#xff0c;内存超过128G时&#xff0c;mysql性能处于平缓&#xff0c;不在上升&#xff0c;所以在一个性能强大的服务器上运行多个实例&#xff0c;才更合理 mysql常见的扩…

java.sql.SQLException: No value specified for parameter 6

异常 java.sql.SQLException: No value specified for parameter 6 原因 sql中定义了6个参数&#xff0c;只传了5个参数

设计模式—“领域规则”

在特定领域中,某些变化虽然频繁,但可以抽象为某种规则。这时候,结合特定领域,将问题抽象为语法规则,从而给出在该领域下的一般性解决方案。 典型模式有:Interpreter Interpreter 动机 在软件构建过程中,如果某一个特定领域的问题比较复杂,类似的结构不断重复出现,…

.NET Microsoft.Extensions.Logging + NLog 记录日志到文件

最近想了解下面向对象开发&#xff0c;选择C# 语言 以及NET6.0 日志是开发中最常用的功能&#xff0c;本文记录下其中日志使用方法&#xff0c;理解不全的地方后续再学习补充 环境 Ubuntu 22.04.2 LTSdotnet 6.0.411 准备工作 # https://learn.microsoft.com/zh-cn/dotnet/c…

2023.6.21AgentGPT部署

在云服务器上使用Docker部署AgentGPT 需要自行提供OpenAI的API Key https://platform.openai.com/account/api-keys 需要自行提供云服务器或者虚拟机 需要自行解决网络的问题&#xff0c;本文中使用的是小喵咪解决网络的问题【需要订阅地址】 文章目录 在云服务器上使用Docker…

数据在内存中的存储-浮点型

常见的浮点型数据&#xff1a;单精度浮点型float、双精度浮点型double,还有long double类型。 浮点数表示的范围&#xff1a;float.h中定义 目录 一、浮点数存储的例子 二、浮点数存储规则 三、例题解释 一、浮点数存储的例子 #include<stdio.h> int main() {int …

王道操作系统学习笔记(1)——操作系统基本概念

前言 本文介绍了操作系统的基本概念&#xff0c;文章中的内容来自B站王道考研操作系统课程&#xff0c;想要完整学习的可以到B站官方看完整版。 一&#xff1a;操作系统基本概念 1.1.1&#xff1a;基本概念和功能 操作系统&#xff1a;系统资源的管理者&#xff08;处理机管…

QGIS 插件获取哨兵数据

基于 Sentinel Hub QGIS 插件&#xff0c;该插件允许您直接在 QGIS中配置和利用Sentinel Hub 服务的强大功能。该插件可视化 Sentinel 数据&#xff0c;可用于正在处理的任何其他项目中。 来自&#xff1a;GIS数据栈整理&#xff1a;GIS数据栈 一起来看看如何在QGIS中使用吧&am…

6张图表 + 1个案例 带你入门tcpdump的使用和原理

一、tcpdump简介 tcpdump是什么&#xff1f; 来看看 tcpdump官网怎么说&#xff1a;This is the home web site of tcpdump, a powerful command-line packet analyzer; and libpcap, a portable C/C library for network traffic capture. 不妨来看看chatGPT插件怎么说&…

【自我提升】openCV基本操作

写在前面&#xff1a;本篇博客主要是记录opnecv的基本操作&#xff0c;不记录安装等步骤。方便回顾和查找方法。 一、图像的IO操作&#xff0c;读取和保存方法 读取图像 在OpenCV中&#xff0c;读取图像的函数是imread()。该函数可以从指定的文件中加载图像&#xff0c;返回值…

Qt6.2教程——5.QT常用控件QLabel

1. QLabel简介 QLabel是Qt库中一个非常基础且重要的类。它主要用于在图形用户界面(GUI)中展示文本或图片。最常见的用法就是在窗口上显示一段文字或者标签&#xff0c;比如“用户名”&#xff0c;“密码”等等。QLabel继承自QFrame&#xff0c;因此它也可以具有框架。它能处理…

0005Java程序设计-jsp企业财务管理系统设计与实现

企业财务管理系统 摘要 对于企业集来说,财务管理的地位很重要。随着计算机和网络在企业中的广泛应用&#xff0c;企业发展速度在不断加快&#xff0c;在这种市场竞争冲击下企业财务管理系统必须优先发展&#xff0c;这样才能保证在竞争中处于优势地位。对此企业必须实现财务管…

安卓平板修改和平精英90帧、120帧超广角,2k/4k分辨率(无需root!!!)

前言&#xff1a;今天我们将探讨如何在安卓平板上修改和平精英超广角以及高帧率画质效果。 1、首先&#xff0c;我们要知道平板改超广角的好处是什么&#xff1f;我们都知道平板相比于手机显示宽度是要更大的&#xff0c;如果平板再改个超广角效果&#xff0c;甚至连脚都可以看…

避免滥用Qt信号与槽——改进taskBus 平台以吞吐20M IQ采样带宽

taskBus 软件无线电平台是一款依靠 stdin-stdout进行数据吞吐的教学平台。在平台创建之初&#xff0c;主要使用 RTL-SDR进行简单的窄带接收应用&#xff0c;并没有考虑采样率超过1.8M的情况。引入 USRP B210/B205mini后&#xff0c;采样率瞬间提高到2M以上&#xff0c;此时&…

springboot+vue项目中如何利用七牛云实现头像的上传

做了个前后端分离的项目&#xff0c;对于用户的头像修改一直不是很满意&#xff0c; 于是用了Vant4的组件库改成了文件点击上传&#xff0c;先是打算存到本地&#xff0c;了解到七牛云的方便后&#xff08;主要是免费&#xff09;&#xff0c;决定改成七牛云存储图片&#xff…

ElasticSearch的安装和访问

ElasticSearch的安装 前言: 本次下载是在Windows系统进行操作,版本为7.6.1,因为下周最新版本的8.1.2有问题 ElasticSearch基于Java开发,JDK最低1.8版本 ElasticSearch的版本要和之后引入的Maven的Jar包版本对应 1 下载ElasticSearch 官网:https://www.elastic.co/cn/ 产品…

01.2总线驱动设备设计思想

sysfs文件系统 sysfs文件系统是Linux2.6版本引入的虚拟文件系统。sysfs把连接在系统上的设备模型组织_ 成为一个分级的层次视图。并且可以向用户空间导出内核数据结构以及属性。 比如下面的图可以看出来当前支持的总线和相关的数据 在sys文件系统中每一个目录都对应着一个kob…

电商项目10:商品管理、仓库管理

电商项目10&#xff1a;商品管理、仓库管理 1、商品管理1.1、spu检索1.1.1、后端1.1.2、前端 1.2、sku检索1.2.1、后端 2、库存管理2.1、启动ware后端微服务2.2、仓库维护查询2.3、查询商品库存2.4、查询采购需求 1、商品管理 1.1、spu检索 1.1.1、后端 spu检索接口文档 S…