当前位置: 首页 > news >正文

springBoot统一响应类型3.4版本

前言:

通过实践而发现真理,又通过实践而证实真理和发展真理。从感性认识而能动地发展到理性认识,又从理性认识而能动地指导革命实践,改造主观世界和客观世界。实践、认识、再实践、再认识,这种形式,循环往复以至无穷,而实践和认识之每一循环的内容,都比较地进到了高一级的程度。

简单回顾统一响应

统一响应的起源环境:在前后端分离的大背景下,为了提高前后端交流的效率和质量的一个工具

本系列内容:

1.0 抽象出统一响应的三个属性,利用构造函数

2.0 创建工具类,更优雅的创建统一响应对象

3.0 全局响应

3.3 全局异常响应

正片:
统一响应类

/**
 * 基础统一响应类
 * @param <T>
 */

@Data
public class apiResult<T> {

    private int code;
    private String message;
    private T data;

    /**
     * 带有data返回的构造函数
     * @param code
     * @param message
     * @param data
     */
    public apiResult(int code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    /**
     * 不带data的构造函数
     * @param code
     * @param message
     */
    public apiResult(int code,String message){
        this.code = code;
        this.message = message;
    }
}

该版本足够适用百分之98以上的情况了!

剩下百分之2呢?

全局响应

全局异常响应

为了更好的实现全局响应和全局异常响应,创建一个工具类,专门用于构建成功和失败响应的实例

统一响应工具类
/**
 * 统一响应对象构建工具类
 * <p>提供快速创建标准化API响应结果的工厂方法,封装常见成功/错误响应构造逻辑
 *
 * @see org.springframework.http.HttpStatus HTTP状态码常量参考
 */


public class apiResultUnit {

    /**
     * 默认成功HTTP状态码 (200 OK)
     */
    private static final int OK = HttpStatus.OK.value();

    /**
     * 默认错误HTTP状态码 (500 Internal Server Error)
     */
    private static int NO = HttpStatus.INTERNAL_SERVER_ERROR.value();

    /**
     *  基本响应
     *
     * @param data 响应数据
     * @param <T> 响应数据类型
     * @return
     */
    public static <T> apiResult<T> success(T data) {
        return new apiResult<>(OK, "操作成功", data);
    }

    /**
     *  自定义信息统一响应
     * @param message 自定义提示信息
     * @param data 响应数据
     * @return
     * @param <T> 响应数据类型
     */
    public static <T> apiResult<T> success(String message, T data) {
        return new apiResult<>(OK, message, data);
    }

    /**
     *  完全自定义统一响应
     * @param code  自定义提示编码
     * @param message 自定义提示信息
     * @param data  响应数据
     * @return
     * @param <T>   响应数据类型
     */
    public static <T> apiResult<T> success(int code, String message, T data) {
        return new apiResult<>(code, message, data);
    }

    /**
     *  基本失败响应
     * @return
     * @param <T> 响应数据类型
     */
    public static <T> apiResult<T> error() {
        return new apiResult<>(NO, "系统错误,请联系管理员");
    }

    /**
     *  自定义信息统一失败响应
     * @param message 自定义提示信息
     * @return
     * @param <T> 响应数据类型
     */
    public static <T> apiResult<T> error(String message) {
        return new apiResult<>(NO, message);
    }

    /**
     *  完全自定义统一失败响应
     * @param code  自定义编码
     * @param message 自定义提示信息
     * @return
     * @param <T> 响应数据类型
     */
    public static <T> apiResult<T> error(int code, String message) {
        return new apiResult<>(code, message);
    }

}

在新版本中,更换了全局响应和全局异常响应的顺序,所以先完成全局异常响应

新创建一个全局异常处理类

为什么要新建一个呢?目前真不知道,因为别人就是这么写的,写了还成了,等后续实践加深

业务异常响应类
@Data
@AllArgsConstructor
public class BusinessException extends RuntimeException {


    /**
     * 异常编码
     * 异常信息
     */
    private int code;
    private String message;

    /**
     * 无参构造函数
     */
    public BusinessException() {
        super();
    }
}

代码简简单单

核心点在于继承了RuntimeException,从名字来看很简单理解,运行时的异常

public class RuntimeException extends Exception {
    @java.io.Serial
    static final long serialVersionUID = -7034897190745766939L;

    /** Constructs a new runtime exception with {@code null} as its
     * detail message.  The cause is not initialized, and may subsequently be
     * initialized by a call to {@link #initCause}.
     */
    public RuntimeException() {
        super();
    }

    /** Constructs a new runtime exception with the specified detail message.
     * The cause is not initialized, and may subsequently be initialized by a
     * call to {@link #initCause}.
     *
     * @param   message   the detail message. The detail message is saved for
     *          later retrieval by the {@link #getMessage()} method.
     */
    public RuntimeException(String message) {
        super(message);
    }

    /**
     * Constructs a new runtime exception with the specified detail message and
     * cause.  <p>Note that the detail message associated with
     * {@code cause} is <i>not</i> automatically incorporated in
     * this runtime exception's detail message.
     *
     * @param  message the detail message (which is saved for later retrieval
     *         by the {@link #getMessage()} method).
     * @param  cause the cause (which is saved for later retrieval by the
     *         {@link #getCause()} method).  (A {@code null} value is
     *         permitted, and indicates that the cause is nonexistent or
     *         unknown.)
     * @since  1.4
     */
    public RuntimeException(String message, Throwable cause) {
        super(message, cause);
    }

    /** Constructs a new runtime exception with the specified cause and a
     * detail message of {@code (cause==null ? null : cause.toString())}
     * (which typically contains the class and detail message of
     * {@code cause}).  This constructor is useful for runtime exceptions
     * that are little more than wrappers for other throwables.
     *
     * @param  cause the cause (which is saved for later retrieval by the
     *         {@link #getCause()} method).  (A {@code null} value is
     *         permitted, and indicates that the cause is nonexistent or
     *         unknown.)
     * @since  1.4
     */
    public RuntimeException(Throwable cause) {
        super(cause);
    }

    /**
     * Constructs a new runtime exception with the specified detail
     * message, cause, suppression enabled or disabled, and writable
     * stack trace enabled or disabled.
     *
     * @param  message the detail message.
     * @param cause the cause.  (A {@code null} value is permitted,
     * and indicates that the cause is nonexistent or unknown.)
     * @param enableSuppression whether or not suppression is enabled
     *                          or disabled
     * @param writableStackTrace whether or not the stack trace should
     *                           be writable
     *
     * @since 1.7
     */
    protected RuntimeException(String message, Throwable cause,
                               boolean enableSuppression,
                               boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

尽管作者看不懂英文,但是根据代码的内容,可以知道,继承这个类是为了读取Throwable里的

message

RuntimeException里是没有各种信息的,它的信息来源于父类的Throwable,继承该类是为了将业务异常和系统异常区分开

全局异常响应配置(简易版)
@Slf4j
@RestControllerAdvice
public class GlobalExcResult {

    @ExceptionHandler(Throwable.class)
    public apiResult handleException(Throwable throwable){

        if (throwable instanceof BusinessException){
            BusinessException e = new BusinessException();
            log.info("请求出现业务异常:",throwable);
            return apiResultUnit.error(e.getCode(),e.getMessage());
        }
        log.error("请求出现系统异常:",throwable);
        return apiResultUnit.error("服务器内部错误");
    }
}

目前阶段,这个业务判断无用

为什么呢?

因为我们还没有写BusinessException里的内容

所以现在的报错,基本都是运行时的报错

看看效果

    @GetMapping("/id")
    public apiResult<UserPageEntity> id(int id) {
        UserPageEntity userPageEntity = userPageServer.UserByID(id);
        return apiResultUnit.success(userPageEntity);
    }

测试代码,简单的一个返回

如果报错,它会返回一个内部服务器错误

半全局响应配置
@Slf4j
@ControllerAdvice
public class GlobalApiResult implements ResponseBodyAdvice<Object> {

    /**
     * 此Advice是否使用于该返回类型和Converter类型(意思是可以配置多个哦)
     * @param returnType 接口类型详细:包括路径,参数等
     * @param converterType 自动选择的转换器类型
     * @return 返回true表示将会走接下来的方法(beforeBodyWrite), 否则不会
     */
    @Override
    public boolean supports(MethodParameter returnType,
                            Class<? extends HttpMessageConverter<?>> converterType) {
        //false -> true  用于测试,正式的时需要修改
        return true;
    }
    /**
     * HttpMessageConverter转换之前进行的操作
     * @param body 业务层接口返回值
     * @param returnType 返回类型
     * @param selectedContentType 根据请求头协商的ContentType
     * @param selectedConverterType 自动选择的转换器类型
     * @param request 当前请求
     * @param response 当前响应
     * @return 返回至前端的数据,参数为,形参
     */
    @Override
    public Object beforeBodyWrite(Object body,
                                  MethodParameter returnType,
                                  MediaType selectedContentType,
                                  Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                  ServerHttpRequest request,
                                  ServerHttpResponse response) {
        //第二步: 将body传入统一响应工具类中的默认成功响应
        return apiResultUnit.success("3.0全新版本",body);
    }
}

运行

响应内容来自body,给上断点看看

我们将body转换一下类型即可

真(全局响应配置)
@Slf4j
@ControllerAdvice
public class GlobalApiResult implements ResponseBodyAdvice<Object> {

    /**
     * 此Advice是否使用于该返回类型和Converter类型(意思是可以配置多个哦)
     * @param returnType 接口类型详细:包括路径,参数等
     * @param converterType 自动选择的转换器类型
     * @return 返回true表示将会走接下来的方法(beforeBodyWrite), 否则不会
     */
    @Override
    public boolean supports(MethodParameter returnType,
                            Class<? extends HttpMessageConverter<?>> converterType) {
        //false -> true  用于测试,正式的时需要修改
        return true;
    }
    /**
     * HttpMessageConverter转换之前进行的操作
     * @param body 业务层接口返回值
     * @param returnType 返回类型
     * @param selectedContentType 根据请求头协商的ContentType
     * @param selectedConverterType 自动选择的转换器类型
     * @param request 当前请求
     * @param response 当前响应
     * @return 返回至前端的数据,参数为,形参
     */
    @Override
    public Object beforeBodyWrite(Object body,
                                  MethodParameter returnType,
                                  MediaType selectedContentType,
                                  Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                  ServerHttpRequest request,
                                  ServerHttpResponse response) {

        //类型转换
        if(body instanceof apiResult){
            return (apiResult)body;
        }
//第二步: 将body传入统一响应工具类中的默认成功响应
        return apiResultUnit.success("3.0全新版本",body);
    }
}

最垃圾最简易的全局响应如上

http://www.dtcms.com/a/100026.html

相关文章:

  • LlamaIndex实现(基于PDF|CSV文件)RAG检索增强生成:NaiveRAG
  • 量子计算:未来计算技术的革命性突破
  • 【奶茶经济学的符号暴力本质】
  • 【软件开发】可复用的数据库导入工具类
  • J2EE框架技术 第五章 Spring注入与作用域
  • 【C++】STL库_stack_queue 的模拟实现
  • 【leetcode】通过两种遍历方式构造二叉树
  • 前端页面缓存问题
  • opencv之指纹验证
  • spring-security原理与应用系列:securityFilterChainBuilders
  • 职测-言语理解与表达
  • SD-WAN组网方案
  • pycharm相对路径引用方法
  • C++ 多态:面向对象编程的核心概念(一)
  • Android Product Flavors 深度解析与最佳实践:构建多版本应用的全方位指南
  • Redis的补充和RESP
  • 【工具】BioPred一个用于精准医疗中生物标志物分析的 R 软件包
  • C# StreamReader/StreamWriter 使用详解
  • 什么是 RBAC 权限模型?
  • jmeter web压力测试 压测
  • Android学习总结之算法篇三(打家劫舍)
  • 蓝桥杯—最小公倍数
  • Linux系统之dump命令的基本使用
  • Linux系统禁用swap
  • Xenium | 细胞邻域(Cellular Neighborhood)分析(fixed radius)
  • Spring AI MCP Server + Cline 快速搭建一个数据库 ChatBi 助手
  • QML编程中的性能优化二
  • C语言指针2
  • 2024蓝桥杯省赛C/C++大学B组 题解
  • [物联网iot]对比WIFI、MQTT、TCP、UDP通信协议