开发者

深入了解SpringBoot中的统一返回和统一异常处理

开发者 https://www.devze.com 2024-01-26 10:18 出处:网络 作者: 程序员康康
目录一、统一返回结果1.1、统一返回对象1.2、系统常量1.3、web 层统一响应结果二、统一异常处理2.1、@ControllerAdvice注解2.2、ExceptionHandler 注解2.3、统一异常处理使用三、总结上篇文章我们学习了基
目录
  • 一、统一返回结果
    • 1.1、统一返回对象
    • 1.2、系统常量
    • 1.3、web 层统一响应结果
  • 二、统一异常处理
    • 2.1、@ControllerAdvice注解
    • 2.2、ExceptionHandler 注解
    • 2.3、统一异常处理使用
  • 三、总结

    上篇文章我们学习了基于 Token 认证的登录功能实现,分别使用了过滤器和拦截器去实现登录功能,这篇文章我们来学习项目中常用的统一返回结果和统一异常处理。

    一、统一返回结果

    前后端分离时代,如果没有一个统一的数据返回格式,前后端调试时,前端开发人员会骂娘的,同时约定相同的返回接口数据也有助于高效的工作。

    通常统一返回的格式包含三部分:

    • code:状态码,一般 200 表示正常
    • message:状态码对应的描述。
    • data:返回的数据

    1.1、统一返回对象

    新建一python个 SpringBoot 项目定义通用的响应对象

    package com.laoxiang.utils;
    
    import com.fasterXML.jackson.annotation.jsonInclude;
    
    import Java.io.Serializable;
    
    /**
    编程 * @author db
     * @version 1.0
     * @description ResponseResult
     * @since 2023/7/12
     */
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public class ResponseResult<T> implements Serializable {
        private static final long serialVersionUID = 2233637474601103587L;
    
        // 接口响应状态码
        private Integer code;
    
        // 接口响应信息
        private String msg;
    
        // 接口响应的数据
        private T data;
    
        public ResponseResult() {
            this.code = AppHttpCodeEnum.SUCCESS.getCode();
            this.msg = AppHttpCodeEnum.SUCCESS.getMsg();
        }
    
        public ResponseResult(Integer code, T data) {
            this.code = code;
            this.data = data;
        }
    
        public ResponseResult(Integer code, String msg, T data) {
            this.code = code;
            this.msg = msg;
            this.data = data;
        }
    
        public ResponseResult(Integer code, String msg) {
            this.code = code;
            this.msg = msg;
        }
    
        public static ResponseResult errorResult(int code, String msg) {
            ResponseResult result = new ResponseResult();
            return result.error(code, msg);
        }
    
        public static ResponseResult okResult() {
            ResponseResult result = new ResponseResult();
            return result;
        }
    
        public static ResponseResult okResult(int code, String msg) {
            ResponseResult result = new ResponseResult();
            return result.ok(code, null, msg);
        }
    
        public static ResponseResult okResult(Object data) {
            ResponseResult result = setAppHttpCodeEnum(AppHttpCodeEnum.SUCCESS, AppHttpCodeEnum.SUCCESS.getMsg());
            if (data != null) {
                result.setData(data);
            }
            FRKBFBqkoWreturn result;
        }
    
        public static ResponseResult errorResult(AppHttpCodeEnum enums) {
            return setAppHttpCodeEnum(enums, enums.getMsg());
        }
    
        public static ResponseResult errorResult(AppHttpCodeEnum enums, String msg) {
            return setAppHttpCodeEnum(enums, msg);
        }
    
        public static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums) {
            return okResult(enums.getCode(), enums.getMsg());
        }
    
        private static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums, String msg) {
          编程客栈  return okResult(enums.getCode(), msg);
        }
    
        public ResponseResult<?> error(Integer code, String msg) {
            this.code = code;
            this.msg = msg;
            return this;
        }
    
        public ResponseResult<?> ok(Integer code, T data) {
            this.code = code;
            this.data = data;
            return this;
        }
    
        public ResponseResult<?> ok(Integer code, T data, String msg) {
            this.code = code;
            this.data = data;
            this.msg = msg;
            return this;
        }
    
        public ResponseResult<?> ok(T data) {
            this.data = data;
            return this;
        }
    
        public Integer getCode() {
            return code;
        }
    
        public void setCode(Integer code) {
            this.code = code;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    
        public T getData() {
            return data;
        }
    
        public void setData(T data) {
            this.data = data;
        }
    }
    

    1.2、系统常量

    上面代码中提到了常量 AppHttpCodeEnum,定义自己的应用程序特定状态码,来表示具体的情况。通过定义的状态码就可以知道具体代表什么意思。

    package com.laoxiang.utils;
    
    /**
     * @author db
     * @version 1.0
     * @description AppHttpCodeEnum
     * @since 2023/7/12
     */
    public enum AppHttpCodeEnum {
        // 成功
        SUCCESS(200,"操作成功"),
        // 失败
        ERROR(500,"操作失败"),
    
        int code;
        String msg;
    
        AppHttpCodeEnum(int code, String errorMessage){
            this.code = code;
            this.msg = errorMessage;
        }
    
        public int getCode() {
            return code;
        }
    
        public String getMsg() {
            return msg;
        }
    }
    

    1.3、web 层统一响应结果

    下面的例子,可以看到在实际项目中接口返回值。

    深入了解SpringBoot中的统一返回和统一异常处理

    二、统一异常处理

    程序开发中不可避免的会遇到异常现象,如果不进行处理,遇到异常时,开发人员不能清晰地处理问题,或者使用 try{...}catch{...} 代码块进行处理,但是满屏的 try{...}catch{...} 代码块造成代码过于臃肿。

    有没有更好的处理方式呢?全局统一异常处理应运而生。@ControllerAdvice 注解搭配 @ExceptionHandler 进行全局统一异常处理。

    2.1、@ControllerAdvice注解

    @ControllerAdvice注解:用于声明一个全局控制器 Advice,相当于把 @ExceptionHandler@InitBinder 和 @ModelAttribute 注解的方法集中到一个地方。放在特定类上,被认为是全局异常处理器。

    2.2、ExceptionHandler 注解

    用于定义异常处理方法,处理特定类型的异常。放在全局异常处理器类中的具体方法上。 通过这两个注解的配合,可以实现全局的异常处理。当控制器中抛出异常时,SpringBoot 会自动调用匹配的 @ExceptionHandler 方法来处理异常,并返回定义的响应。

    步骤如下:

    • 新建一个统一异常处理类
    • 类上标注 @RestControllerAdvice 注解
    • 在方法上标注 @ExceptionHandler 注解,并且指定需要捕获的异常,可以同时捕获多个。

    新建 exception 包,在包下新建 GlobalExceptionHandler 类。代码如下:

    package com.duan.execption;
    
    
    import com.duan.pojo.AppHttpCodeEnum;
    import com.duan.pojo.ResponseResult;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bpythonind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.RestControllerAdvice;
    
    /**
     * @author db
     * @version 1.0
     * @description GlobalExceptionHandler
     * @since 2023/7/23
     */
    @RestControllerAdvice
    @Slf4j
    public class GlobalExceptionHandler {
    
        // 全局异常
        @ExceptionHandler(Exception.class)
        public ResponseResult exceptionHandler(Exception e){
            //打印异常信息
            log.error("出现了异常! {}",e);
            //从异常对象中获取提示信息封装返回
            return ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR.getCode(),e.getMessage());
        }
    
        // 自定义异常
        @ExceptionHandler(LxAdminException.class)
        public ResponseResult LxAdminExceptionHandler(LxAdminException e){
            //打印异常信息
            log.error("出现了异常! {}",e);
            //从异常对象中获取提示信息封装返回
            return ResponseResult.errorResult(e.getCode(),e.getMsg());
        }
    
    }
    

    exception包下新建自定义异常处理类 LxAdminException

    package com.duan.execption;
    
    
    import com.duan.pojo.AppHttpCodeEnum;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    /**
     * @author db
     * @version 1.0
     * @description LxAdminException  自定义异常
     * @since 2023/7/23
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class LxAdminException extends RuntimeException{
        private int code;
        private String msg;
    
        public LxAdminException(AppHttpCodeEnum httpCodeEnum) {
            super(httpCodeEnum.getMsg());
            this.code = httpCodeEnum.getCode();
            this.msg = httpCodeEnum.getMsg();
        }
    }
    

    2.3、统一异常处理使用

    在业务开发中,可以在 service 层处理业务时,可以手动抛出异常,由全局异常处理器处理进行统一处理。

    package com.duan.controller;
    
    
    import com.duan.execption.LxAdminException;
    import com.duan.pojo.AppHttpCodeEnum;
    import com.duan.pojo.ResponseResult;
    import com.duan.pojo.User;
    import com.duan.utils.JWTUtils;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.HashMap;
    import java.util.UUID;
    
    /**
     * @author db
     * @version 1.0
     * @description LoginController
     * @since 2023/12/19
     */
    @RestController
    @Slf4j
    public class LoginController {
    
        @PostMapping("/login")
        public ResponseResult login(@RequestBody User user){
            log.info("这是正常日志");
            if(!"admin".equals(user.getUsername()) && !"123456".equals(user.getPassword())){
                throw new LxAdminException(AppHttpCodeEnum.LOGIN_ERROR);
            }else{
                HashMap<String, Object> map = new HashMap<>();
                map.put("id", UUID.randomUUID().toString());
    
                // 生成token
                String token = JWTUtils.generateJwt(map);
                return ResponseResult.okResult(token);
            }
        }
    
    }
    

    当我们请求接口时,假如用户名称或者密码错误,接口就会响应:

    {
        "code": 505,
        "msg": "用户名或密码错误",
        "data": null
    }
    

    实际开发中还有许多的异常需要捕获,比如 Token 失效、过期等异常, 如果整合了其他的框架,还要注意这些框架抛出的异常,比如Spring Security 等框架。

    代码地址:https://gitee.com/duan138/practice-code/tree/dev/resultException

    三、总结

    在 SpringBoot 项目中,统一返回和统一异常处理是非常常用的一环,它们能提高应用的可读性和可维护性,统一返回有助于保持代码一致性和规范性,在前后端联调时更加方便,统一异常处理,减少了代码冗余,对异常处理更加易于管理。

    以上就是深入了解SpringBoot中的统一返回和统一异常处理的详细内容,更多关于SpringBoot统一返回和统一异常处理的资料请关注编程客栈(www.devze.com)其它相关文章!

    0

    精彩评论

    暂无评论...
    验证码 换一张
    取 消