免费注册网站大全,百度云平台建设网站,广东省网站备案,重庆市建设工程信息网官网安全监督信息网文章目录 demo地址实现效果引入基础类准备1.通用枚举与错误状态枚举2.定义通用返回结果3.自定义业务异常 统一异常捕获测试 demo地址
demo工程地址
实现效果
当我们输入1时#xff0c;正常的返回通用的响应结果当我们输入2时#xff0c;抛出异常#xff0c;被捕获然后返回… 文章目录 demo地址实现效果引入基础类准备1.通用枚举与错误状态枚举2.定义通用返回结果3.自定义业务异常 统一异常捕获测试 demo地址
demo工程地址
实现效果
当我们输入1时正常的返回通用的响应结果当我们输入2时抛出异常被捕获然后返回通用的结果可以看到两者的数据结构都是完全一样的 引入
很多时候当一个javaweb项目在运行的过程中出现一些不可预值的错误时会抛出异常例如下方我们在接口直接抛出一个运行时异常 对应接口的响应就变成如下图所示 这时的返回结果往往和我们与前端约定好的响应结果的数据结构出入很大而且也不方便我们去排查错误并且对用户体验也不好这时就需要我们配置一个统一的异常捕获对各种异常进行统一数据结构的返回方便前端展示对应的错误我们也可以在捕获到异常后进行对应的日志记录方便后续排查。
基础类准备
1.通用枚举与错误状态枚举
我们首先需要和前端沟通好统一的返回结果的数据结构和一些常见的错误状态这里我们使用一个错误状态枚举来展示业务内的一些报错为了枚举更好的拓展性这里我们先封装一个基础枚举类如下
封装通用枚举的好处可以参考我的这几个视频讲解封装通用枚举1封装通用枚举2(封装选项生成)封装通用枚举3(按类型获取枚举选项接口)
/*** Author: lzp* description: 通用枚举* Date: 2022/9/24*/
public interface BaseEnumP {/*** 获取标题*/String getTitle();/*** 获取值*/P getValue();/*** 通过value获取枚举对象* 2022-12-09日使用泛型优化此方法** param enumClass 枚举的类对象* param value 值* return*/static T extends BaseEnum T valueOf(ClassT enumClass, Object value) {if (value null) {return null;}T[] enumConstants enumClass.getEnumConstants();if (enumConstants null) {return null;}for (T enumConstant : enumConstants) {if (value.equals(enumConstant.getValue())) {return enumConstant;}}return null;}}接着我们实现通用枚举接口定义通用状态码枚举如下
这样可以把我们系统中可预知的异常全部定义在错误码枚举中我们可以给对应业务模块的错误码命名为指定范围内例如用户相关的错误咱们控制在 10001 ~ 10100之间
import lombok.Getter;
import online.longzipeng.mywebdemo.enums.BaseEnum;/*** Author: lzp* Date:2023/10/30* description: 通用错误状态码*/
Getter
public enum ErrorCodeEnum implements BaseEnumInteger {// 通用错误状态码SUCCESS(0, 成功),ERROR(-1, 失败),// 用户相关异常 10001 ~ 10100USER_LOGIN_ERROR(1001,账号或密码错误),;public final Integer value;public final String title;ErrorCodeEnum(Integer value, String title) {this.value value;this.title title;}}
2.定义通用返回结果
我们与前端约定好通用的返回结果的数据结构例如都带有codemsgdata分别表示该接口的响应状态码错误消息返回数据
为了通用防止任何数据类型这里我们使用泛型来指定响应的data为了方便通用的返回例如一般修改接口不需要返回数据此时在咱们就可以指定调用静态方法 Result.success();
package online.longzipeng.mywebdemo.commen;import lombok.Data;
import online.longzipeng.mywebdemo.commen.exception.ErrorCodeEnum;import java.io.Serializable;/*** 通用响应** author lzp*/
Data
public class ResultT implements Serializable {private static final long serialVersionUID 1L;/*** 编码0表示成功其他值表示失败*/private int code ErrorCodeEnum.SUCCESS.value;/*** 消息内容*/private String msg ErrorCodeEnum.SUCCESS.title;/*** 响应数据*/private T data;public static T ResultT error() {return generate(ErrorCodeEnum.ERROR.value, ErrorCodeEnum.ERROR.getTitle());}/*** 快速生成返回结果* param code 状态码* param msg 对应消息内容*/public static T ResultT generate(int code, String msg) {ResultT result new Result();result.setCode(code);result.setMsg(msg);return result;}public static T ResultT success() {return new Result();}public static T ResultT success(T data) {ResultT result new Result();result.setData(data);return result;}}
3.自定义业务异常
因为运行时异常是一种特殊的异常不需要我们显示的抛出和try catch处理所以很适合用于做我们的自定义业务异常然后我们希望业务出错了也统一返回Result的数据结构所以咱们自定义的异常也需要包含 code和msg字段
package online.longzipeng.mywebdemo.commen.exception;import lombok.Data;/*** 通用异常处理*/
Data
public class ServiceException extends RuntimeException {private static final long serialVersionUID 1L;/*** 错误码*/private int code;/*** 错误信息*/private String msg;public ServiceException(int code) {this.code code;}public ServiceException(int code, String msg) {this.code code;}public ServiceException(String msg) {super(msg);this.code ErrorCodeEnum.ERROR.value;this.msg msg;}/*** 使用通用错误枚举快速创建异常*/public ServiceException(ErrorCodeEnum errorCodeEnum) {this.code errorCodeEnum.getValue();this.msg errorCodeEnum.getTitle();}
}
统一异常捕获
在springboot2.x中咱们可以通过ControllerAdvice注解与ExceptionHandler注解来实现统一的异常捕获与处理为了方便返回结果这里我们使用RestControllerAdvice注解返回JSON格式的响应用于快速构建RESTful风格的程序。
如下
这里我们直接捕获到了自定义的业务异常从中取出结果并返回Result对象捕获Exception异常当发生不可预知的异常时在此统一捕获并打印错误日志
package online.longzipeng.mywebdemo.commen.exception;import online.longzipeng.mywebdemo.commen.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;/*** 通用异常处理器*/
RestControllerAdvice
public class ServiceExceptionHandler {private Logger logger LoggerFactory.getLogger(getClass());/*** 处理自定义异常*/ExceptionHandler(ServiceException.class)public Result handleRenException(ServiceException e) {return Result.generate(e.getCode(),e.getMsg());}/*** 处理未知异常*/ExceptionHandler(Exception.class)public Result handleException(Exception e) {logger.error(e.getMessage(), e);return Result.error();}
}
测试
我们创建一个用于测试的controller并在其中手动抛出一个业务异常如下
package online.longzipeng.mywebdemo.controller;import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import online.longzipeng.mywebdemo.commen.Result;
import online.longzipeng.mywebdemo.commen.exception.ErrorCodeEnum;
import online.longzipeng.mywebdemo.commen.exception.ServiceException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;/*** Author: lzp* description:* Date: 2023/10/30*/
RestController
RequestMapping(/test)
Api(tags 测试接口)
public class TestController {GetMapping(/error)ApiOperation(测试异常抛出)public ResultString testError(RequestParam ApiParam(1 正常 2抛出错误) Integer type) {if (type 2) {throw new ServiceException(ErrorCodeEnum.USER_LOGIN_ERROR);}return Result.success(你好呀~);}}
显示结果如下
当我们输入1时正常的返回通用的响应结果当我们输入2时返回对应的错误可以看到两者的数据结构都是完全一样的