springboot 全局异常捕获和通用接口返回格式

460 阅读2分钟

配置之后当我们进行validate等相关操作时,我们就不再进行返回boolean,然后走不同的分支,在异常情况,可以直接抛出自定义异常,实现代码终止,并给前端返回异常信息.

1.自定义异常类.

/**
 * 自定义业务异常
 */
public class CustomException extends  RuntimeException{
    public CustomException(String message){
        super(message);
    }
}

2.通用接口返回格式

package com.example.aibinghaosi.common;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;


@Data
@AllArgsConstructor
@NoArgsConstructor
public class JsonData{
    /**
     * 状态码 正数 表示成功,0表示处理中,负数 表示失败
     */
    private Integer code;
    /**
     * 数据
     */
    private Object data;
    /**
     * 描述
     */
    private String msg;

    /**
     * 通用成功状态
     * @return 成功的状态
     */
    public static JsonData buildSuccess() {
        return new JsonData(1, true, "操作成功");
    }
    /**
     * 通用成功状态
     * @return 成功的状态
     */
    public static  JsonData buildSuccess(Object data) {
        return new JsonData(1, data, "操作成功");
    }

    /**
     * 失败
     * @param msg 失败信息
     */
    public static JsonData buildError(String msg) {
        return new JsonData(-1, null, msg);
    }

    /**
     * 失败
     * @param msg 失败信息
     * @param code 失败状态码
     */
    public static JsonData buildError(String msg, Integer code) {
        if(code>=0){
            System.out.println("失败的状态码必须小于0");
            return JsonData.buildError(msg);
        }
        return new JsonData(code, null, msg);
    }
}

3.全局异常捕获类

package com.example.aibinghaosi.config;

import com.example.aibinghaosi.common.CustomException;
import com.example.aibinghaosi.common.JsonData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import java.sql.SQLIntegrityConstraintViolationException;

/**
 * 全局异常处理
 * 可以针对不同的异常使用不同的处理方式.
 */
// 设置需要被捕获异常的类:添加了 RestController 或 Controller 的注解的controller类
@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 异常处理方法
     *
     * @return 返回给前端的信息
     */
    // 指定捕获异常类型(SQL异常)
    @ExceptionHandler({SQLIntegrityConstraintViolationException.class, DuplicateKeyException.class})
    public JsonData execeptionHandler1(SQLIntegrityConstraintViolationException ex) {
        log.info("发生了唯一值重复异常:{}", ex);
        // 判断是否违反了唯一约束
        if (ex.getMessage().contains("Duplicate entry")) {
            String[] strArr = ex.getMessage().split(" ");
            String msg = strArr[2] + "已存在!";
            return JsonData.buildError(msg);
        }
        return JsonData.buildError("未知错误!");
    }

    /**
     * 捕获字符串转成Long失败的异常
     */
    @ExceptionHandler({MethodArgumentTypeMismatchException.class})
    public JsonData execeptionHandler2(MethodArgumentTypeMismatchException ex) {
        log.info("发生了字符串转换成Long异常:{}", ex.getMessage());
        log.info("发生了字符串转换成Long异常,完整异常信息-------------------------:{}", ex);
        if (ex.getMessage().contains("Failed to convert value of type 'java.lang.String' to required type 'java.lang.Long'")) {
            String[] strArr = ex.getMessage().split("For input string:");
            String msg = "id:" + strArr[1] + "长度超限";
            return JsonData.buildError(msg);
        }
        return JsonData.buildError("未知错误!");
    }

    /**
     * 捕获用户自定义异常
     */
    @ExceptionHandler({CustomException.class})
    public JsonData execeptionHandler3(CustomException ex) {
        return JsonData.buildError(ex.getMessage());
    }

    /**
     * 异常处理方法
     *
     * @return 返回给前端的信息
     */
    // 指定捕获异常类型(SQL异常)
    @ExceptionHandler(Exception.class)
    public JsonData execeptionHandler999(Exception ex) {
        log.info("发生了异常:{}", ex);
        return JsonData.buildError("异常:" + ex.getMessage());
    }


}

4.使用案例.


@Data
@AllArgsConstructor
@Slf4j
public class ProxyAdd {

    UserService userService;
    UserStudiesService userStudiesService;

    /**
     * 新增用户
     *
     * @param registerUserDto
     * @return 用户id
     */
    public Long execute(RegisterUserDto registerUserDto) {
        this.validateDto(registerUserDto);
        this.validateUserExist(registerUserDto);
        UserEntity userEntity = new UserEntity();
        userEntity.setUsername(registerUserDto.getPhone());
        userEntity.setPhone(registerUserDto.getPhone());
        userEntity.setPassword(registerUserDto.getPassword());
        userService.save(userEntity);
        userStudiesService.addDefaultUserStudiesByUserId(userEntity.getId());
        return userEntity.getId();
    }

    /**
     * 校验dto是否可用
     *
     * @param registerUserDto
     */
    private void validateDto(RegisterUserDto registerUserDto) {
    
    
        //-----------------------------------使用自定义异常类------------------------------------
        
        if (registerUserDto.getPhone() == "") throw new CustomException("手机号不能为空");
        if (registerUserDto.getPassword() == "") throw new CustomException("密码不能为空");
        if (registerUserDto.getCaptcha() == "") throw new CustomException("验证码不能为空");
        
        //-----------------------------------使用自定义异常类------------------------------------
        
        
    }

    /**
     * 校验用户是否存在
     *
     * @param registerUserDto
     */
    private void validateUserExist(RegisterUserDto registerUserDto) {
        LambdaQueryWrapper<UserEntity> lqw = new LambdaQueryWrapper();
        lqw.eq(UserEntity::getPhone, registerUserDto.getPhone());
        lqw.or().eq(UserEntity::getPhone, registerUserDto.getPhone());
        int count = userService.count(lqw);
        if(count>0)throw  new CustomException("当前手机号已注册,请直接登录");
    }
}