项目中的全局异常是如何处理的

简介: 项目中的全局异常处理通常包括对预期异常(程序员手动抛出)和运行时异常的管理。项目已提供`BaseException`作为基础异常类,用于手动抛出异常,并通过`GlobalExceptionHandler`进行全局处理。`

项目中的全局异常是如何处理的?

全局异常处理逻辑

一般项目开发有两种异常:

  • 预期异常(程序员手动抛出)
  • 运行时异常

在目前的项目中已经提供了全局异常处理器

  • BaseException  基础异常,如果业务中需要手动抛出异常,则需要抛出该异常
package com.zzyl.exception;
import com.zzyl.enums.BasicEnum;
import lombok.Getter;
import lombok.Setter;
/**
 * BaseException
 * @author itheima
 **/
@Getter
@Setter
public class BaseException extends RuntimeException {
    private BasicEnum basicEnum;
    public BaseException(BasicEnum basicEnum) {
        this.basicEnum = basicEnum;
    }
}

其中BaseException中的参数为一个枚举,可以在BasicEnum自定义业务中涉及到的异常

package com.zzyl.enums;
import com.zzyl.base.IBasicEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
 * 基础枚举
 *
 * @author itcast
 */
@Getter
@AllArgsConstructor
public enum BasicEnum implements IBasicEnum {
    SUCCEED(200, "操作成功"),
    SECURITY_ACCESSDENIED_FAIL(401, "权限不足!"),
    LOGIN_FAIL(401, "用户登录失败"),
    LOGIN_LOSE_EFFICACY(401, "登录状态失效,请重新登录"),
    SYSYTEM_FAIL(500, "系统运行异常"),
    //权限相关异常:1400-1499
    DEPT_DEPTH_UPPER_LIMIT(1400, "部门最多4级"),
    PARENT_DEPT_DISABLE(1401, "父级部门为禁用状态,不允许启用"),
    DEPT_NULL_EXCEPTION(1402, "部门不能为空"),
    POSITION_DISTRIBUTED(1403, "职位已分配,不允许禁用"),
    MENU_NAME_DUPLICATE_EXCEPTION(1404, "菜单路由重复"),
  
    //业务相关异常:1500-1599
    WEBSOCKET_PUSH_MSG_ERROR(1500, "websocket推送消息失败"),
    CLOSE_BALANCE_ERROR(1501, "关闭余额账户失败"),
    MONTH_BILL_DUPLICATE_EXCEPTION(1502, "该老人的月度账单已生成,不可重复生成"),
    MONTH_OUT_CHECKIN_TERM(1503, "该月不在费用期限内");
    /**
     * 编码
     */
    public final int code;
    /**
     * 信息
     */
    public final String msg;
}
  • GlobalExceptionHandler  全局异常处理器
package com.zzyl.exception;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import com.zzyl.base.ResponseResult;
import com.zzyl.enums.BasicEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import java.io.FileNotFoundException;
import java.nio.file.AccessDeniedException;
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    /**
     * 处理自定义异常BaseException。
     * 返回自定义异常中的错误代码和错误消息。
     *
     * @param exception 自定义异常
     * @return 响应数据,包含错误代码和错误消息
     */
    @ExceptionHandler(BaseException.class)
    public ResponseResult<Object> handleBaseException(BaseException exception) {
        exception.printStackTrace();
        if (ObjectUtil.isNotEmpty(exception.getBasicEnum())) {
            log.error("自定义异常处理:{}", exception.getBasicEnum().getMsg());
        }
        return ResponseResult.error(exception.getBasicEnum());
    }
    /**
     * 处理其他未知异常。
     * 返回HTTP响应状态码500,包含错误代码和异常堆栈信息。
     *
     * @param exception 未知异常
     * @return 响应数据,包含错误代码和异常堆栈信息
     */
    @ExceptionHandler(Exception.class)
    public ResponseResult<Object> handleUnknownException(Exception exception) {
        exception.printStackTrace();
        if (ObjectUtil.isNotEmpty(exception.getCause())) {
            log.error("其他未知异常:{}", exception.getMessage());
        }
        return ResponseResult.error(500,exception.getMessage());
    }
}

项目中集成

程序员手动抛出业务异常

当床位新增失败的时候,可以直接抛出BaseException

@Override
public void addBed(BedDto bedDto) {
    Bed bed = BeanUtil.toBean(bedDto, Bed.class);
    bed.setCreateTime(LocalDateTime.now());
    bed.setCreateBy(1L);
    bed.setBedStatus(0);
    try {
        bedMapper.addBed(bed);
    } catch (Exception e) {
        throw new BaseException(BasicEnum.BED_INSERT_FAIL);
    }
}

测试:

当重复录入床位编号的时候,则会抛出:床位新增失败,而此时的执行逻辑就是走了全局异常处理器


不可知异常处理

比如,在文件上传的接口中,如果上传文件失败,则可以抛出RuntimeException异常,由于RuntimeException异常不是自定义异常,一旦触发就是走全局异常处理器的未知异常

/**
 * 文件上传
 *
 * @param file 文件
 * @return 上传结果
 * @throws Exception 异常
 */
@PostMapping("/upload")
@ApiOperation("文件上传")
public ResponseResult<String> upload(
        @ApiParam(value = "上传的文件", required = true)
        @RequestPart("file") MultipartFile file) throws Exception {
    // 校验是否为图片文件
    try {
        BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
    } catch (Exception e) {
        throw new RuntimeException("上传图片失败");
    }
    if (file.getSize() == 0) {
        throw new RuntimeException("上传图片不能为空");
    }
    // 获得原始文件名
    String originalFilename = file.getOriginalFilename();
    // 获得文件扩展名
    String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
    String fileName = UUID.randomUUID().toString() + extension;
    String filePath = fileStorageService.store(fileName, file.getInputStream());
    return ResponseResult.success(filePath);
}

结论:

  • 一旦文件上传失败,则会走全局异常处理器的未知异常
  • 如果系统抛出了其他异常,非BaseException,都会走未知异常
目录
相关文章
|
2月前
|
移动开发 API Android开发
mPaaS常见问题之初始化异常如何解决
mPaaS(移动平台即服务,Mobile Platform as a Service)是阿里巴巴集团提供的一套移动开发解决方案,它包含了一系列移动开发、测试、监控和运营的工具和服务。以下是mPaaS常见问题的汇总,旨在帮助开发者和企业用户解决在使用mPaaS产品过程中遇到的各种挑战
34 0
|
23天前
|
前端开发 程序员
项目中异常是如何处理的
项目中设定了全局异常处理器,统一处理预期和运行时异常。预期异常由程序员手动抛出,用于异常情况的接口返回;运行时异常为不可控错误,提供统一返回格式便于前端提示和后端排查。全局异常处理器借助@RestControllerAdvice和@ExceptionHandler注解,前者标识处理器,后者按异常类型定制前端响应,如预期异常直接返回,运行时异常则调整响应内容。
16 0
|
1月前
|
Java
SpringBoot全局异常@RestControllerAdvice全局异常
SpringBoot全局异常@RestControllerAdvice全局异常
11 0
|
3月前
|
测试技术
需求不明确的情况下,测试该如何处理?
需求不明确的情况下,测试该如何处理?
|
10月前
|
运维 Prometheus 监控
java异常 | 处理规范、全局异常、Error处理
java异常 | 处理规范、全局异常、Error处理
|
9月前
全局参数、异常处理
全局参数、异常处理
103 0
|
10月前
|
Java
定义全局异常和全局异常处理器
定义全局异常和全局异常处理器
|
XML 前端开发 安全
【全网最全】JSR303参数校验与全局异常处理(从理论到实践别用if判断参数了)
【全网最全】JSR303参数校验与全局异常处理(从理论到实践别用if判断参数了)
127 0
【全网最全】JSR303参数校验与全局异常处理(从理论到实践别用if判断参数了)
|
前端开发
前端工作小结52-错误的处理方式
前端工作小结52-错误的处理方式
64 0
前端工作小结52-错误的处理方式
GoogleGuava - 第 1 章 基本工具——Throwables:简化异常和错误的传播与检查
GoogleGuava - 第 1 章 基本工具——Throwables:简化异常和错误的传播与检查
133 0
GoogleGuava - 第 1 章 基本工具——Throwables:简化异常和错误的传播与检查