SpringBoot自定义异常处理、全局异常处理和统一响应结构体

本文详细介绍了一种在Java项目中实现异常处理和统一响应数据体结构的设计方案。包括定义枚举类管理异常分类,编写自定义异常,全局异常处理策略,以及统一响应结果的编写与使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 异常处理

1). 定义枚举类,管理异常分类

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

import java.util.LinkedHashMap;

@NoArgsConstructor
@AllArgsConstructor
public enum ResponseCode {

    /*-----Basic-----*/
    SUCCESS(200,"操作成功"),
    FAIL(500,"操作失败"),

    /*-----User (StartCode: 1000)-----*/
    USER_PASSWORD_ERROR(1000,"密码错误"),
    USER_NOT_FOUND(1001,"用户不存在");

    public Integer code;

    public String msg;

    public static LinkedHashMap<Integer,String> getArrayMessage(){
        LinkedHashMap<Integer,String> responseMessages = new LinkedHashMap<>();
        for (ResponseCode statusEnum : ResponseCode.values()) {
            responseMessages.put(statusEnum.code,statusEnum.msg);
        }
        return responseMessages;
    }

}

这个枚举类比较重要,后面都会用到。

2). 编写自定义异常

import lombok.*;
import com.xxx.xxx.response.ResponseCode;

import java.io.Serializable;

@EqualsAndHashCode(callSuper = true)
@Data
@Builder
@AllArgsConstructor
//如果在编译时出现“java: 已在类 top.yuanmen.oa、
// .exception.RequestException中定义了构造器
// RequestException()”则删除此注解
//@NoArgsConstructor
public class RequestException extends RuntimeException implements Serializable {
    private Integer code;
    private String msg;
    private Exception e;

    public RequestException(ResponseCode responseCode, Exception e) {
        this.code = responseCode.code;
        this.msg = responseCode.msg;
        this.e = e;
    }


    public RequestException(ResponseCode responseCode) {
        this.code = responseCode.code;
        this.msg = responseCode.msg;
    }

    public synchronized static RequestException fail(String msg){
        return RequestException.builder().code(ResponseCode.FAIL.code).msg(msg).build();
    }

    public synchronized static RequestException fail(String msg,Exception e){
        return RequestException.builder().code(ResponseCode.FAIL.code).msg(msg).e(e).build();
    }

    public synchronized static RequestException fail(Integer code,String msg,Exception e){
        return RequestException.builder().code(code).msg(msg).e(e).build();
    }

}

3). 使用

    @Override
    public void addUser(User user) {
        try {
            boolean res = this.insert(user);
            if (!res) throw new RequestException(ResponseCode.FAIL);
        } catch (Exception e){
            throw new RequestException(ResponseCode.FAIL);
        }
    }

我这里的方法是添加一个用户信息,我在表中用户的phone是规定的11位,就用这个来造成异常:

    @Test
    public void userServiceTest() {
        User user = User.builder().loginId("875044497").username("admin").password("123456")
                .gender(1).phone("13980449849000").email("8750444497").department_id("1032513234847997954").build();
        userService.addUser(user);
    }

4. 全局异常处理

全局异常处理主要用来处理我们上面自定义的异常没考虑到的范围。这里的全局异常主要是针对controller层的。
使用注解@ControllerAdvice将一个类标记为全局异常处理类即可:

import com.xxx.xxx.exception.RequestException;
import com.xxx.xxx.response.ResponseCode;
import com.xxx.xxx.response.ResponseResult;
import lombok.extern.log4j.Log4j;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

@ControllerAdvice(basePackages = {"com.xxx.xxx.controller"})
@Log4j
public class GlobalDefaultExceptionHandler {

    //请求异常
    @ExceptionHandler(value = RequestException.class)
    @ResponseBody
    public ResponseResult requestExceptionHandler(RequestException e){
        if(e.getE()!=null) e.printStackTrace();
        return ResponseResult.builder().msg(e.getMsg()).code(e.getCode()).build();
    }

    //参数验证异常
    @ExceptionHandler(value = DataIntegrityViolationException.class)
    @ResponseBody
    public ResponseResult requestExceptionHandler(DataIntegrityViolationException e){
        return ResponseResult.builder().msg(ResponseCode.SYSTEM_DATA_FAIL.msg).code(ResponseCode.FAIL.code).build();
    }
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public ResponseResult methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e){
        BindingResult result = e.getBindingResult();
        String s = "参数验证失败";
        if(result.hasErrors()){
            List<ObjectError> errors = result.getAllErrors();
            s = errors.get(0).getDefaultMessage();
        }
        return ResponseResult.builder().code(ResponseCode.SYSTEM_PARAM_FAIL.code).msg(s).build();
    }

    //所有异常
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ResponseResult requestExceptionHandler(Exception e){
        e.printStackTrace();
        return ResponseResult.builder().msg("系统出现了一点小问题,正在修复中~").code(ResponseCode.FAIL.code).build();
    }

}

2. 统一响应数据体结构

1). 编写统一结果响应体

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ApiModel(value = "请求结果响应体")
public class ResponseResult<T> implements Serializable {

    @ApiModelProperty("错误码")
    private Integer code;

    @ApiModelProperty("数据体")
    private T data;

    @ApiModelProperty("消息")
    private String msg;

    @ApiModelProperty("响应时间戳")
    private final long timestamps = System.currentTimeMillis();

    public synchronized static <T> ResponseResult<T> build(ResponseCode statusEnum) {
        return build(statusEnum,null);
    }

    public synchronized static <T> ResponseResult<T> build(ResponseCode responseCode, T data) {
        ResponseResult<T> res = new ResponseResult<>();
        res.setCode(responseCode.code);
        res.setMsg(responseCode.msg);
        res.setData(data);
        return res;
    }

    public synchronized static <T> ResponseResult<T> ok() {
        return build(ResponseCode.SUCCESS,null);
    }

    public synchronized static <T> ResponseResult<T> okHasData(T data) {
        return build(ResponseCode.SUCCESS,data);
    }

    private static final long serialVersionUID = 8992436576262574064L;
}

2). 使用

主要是在controller中使用:

import com.baomidou.mybatisplus.plugins.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import com.xxx.xxx.dto.UserDTO;
import com.xxx.xxx.entity.User;
import com.xxx.xxx.response.ResponseResult;
import com.xxx.xxx.service.IUserService;

@RequestMapping("/user")
@RestController
@Api(tags = {"用户操作"})
public class UserController {

    @Autowired
    private IUserService userService;

    @PostMapping("/list")
    @ApiOperation("用户列表")
    @ApiImplicitParam(paramType = "header",name = "Authorization",value = "身份认证Token")
    public ResponseResult<Page<User>> list(@RequestBody @ApiParam("分页信息")UserDTO page){
        Page<User> resultPage = userService.selectPage(new Page<>(page.getPage(), page.getPageSize()));
        return ResponseResult.okHasData(resultPage);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值