Springboot全局异常处理案例--@ControllerAdvice

image

源码在最后

1.添加依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.72</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

2.自定义一个错误接口类,包含错误码和错误信息

package com.example.demo.util;

/**
 * @author lyd
 * @Description:
 * @date 16:15
 */
public interface BaseErrorInfoInterface {


	/**
	 * 得到错误码
	 *
	 * @return {@link String}
	 */
	String getResultCode();

	/**
	 * 得到错误信息
	 *
	 * @return {@link String}
	 */
	String getResultMsg();

}

3.自定义一个枚举类,实现错误接口类,在这个枚举里面自定义一些错误类型

package com.example.demo.util;


/**
 * 常见的枚举
 *
 * @author lyd
 * @Description: 自定义枚举类
 * @date 16:16
 */
public enum CommonEnum implements BaseErrorInfoInterface {

	SUCCESS("200", "成功"),
	BODY_NOT_MATCH("400", "请求的数据格式不符"),
	SIGNATURE_NOT_MATCH("401", "请求的数字签名不匹配!"),
	OT_FOUND("404", "未找到该资源!"),
	INTERNAL_SERVER_ERROR("500", "服务器内部错误!"),
	SERVER_BUSY("503", "服务器正忙,请稍后再试!");

	/**
	 * 错误码
	 */
	private String resultCode;

	/**
	 * 错误描述
	 */
	private String resultMsg;

	CommonEnum(String resultCode, String resultMsg) {
		this.resultCode = resultCode;
		this.resultMsg = resultMsg;
	}

	@Override
	public String getResultCode() {
		return resultCode;
	}

	@Override
	public String getResultMsg() {
		return resultMsg;
	}
}

4.自定义一个异常类,等会处理业务异常的时候用

package com.example.demo.exception;

import com.example.demo.util.BaseErrorInfoInterface;

/**
 * @author lyd
 * @Description: 自定义异常类
 * @date 16:25
 */
public class BizException extends RuntimeException {


	/**
	 * 错误代码
	 */
	private String errorCode;
	/**
	 * 错误信息
	 */
	private String errorMsg;

	public BizException() {
		super();
	}

	public BizException(String message, String errorMsg) {
		super(message);
		this.errorMsg = errorMsg;
	}

	public BizException(String message, String errorCode, String errorMsg) {
		super(message);
		this.errorCode = errorCode;
		this.errorMsg = errorMsg;
	}

	public BizException(BaseErrorInfoInterface baseErrorInfoInterface) {
		super(baseErrorInfoInterface.getResultCode());
		this.errorCode = baseErrorInfoInterface.getResultCode();
		this.errorMsg = baseErrorInfoInterface.getResultMsg();
	}

	public BizException(BaseErrorInfoInterface baseErrorInfoInterface, Throwable cause) {
		super(baseErrorInfoInterface.getResultCode(), cause);
		this.errorCode = baseErrorInfoInterface.getResultCode();
		this.errorMsg = baseErrorInfoInterface.getResultMsg();
	}

	public BizException(Throwable cause, String errorCode, String errorMsg) {
		super(errorCode, cause);
		this.errorCode = errorCode;
		this.errorMsg = errorMsg;
	}

	public String getErrorCode() {
		return errorCode;
	}

	public void setErrorCode(String errorCode) {
		this.errorCode = errorCode;
	}

	public String getErrorMsg() {
		return errorMsg;
	}

	public void setErrorMsg(String errorMsg) {
		this.errorMsg = errorMsg;
	}

	@Override
	public synchronized Throwable fillInStackTrace() {
		return super.fillInStackTrace();
	}
}

5.再定义一个数据响应格式,便于数据交互

package com.example.demo.util;

import com.alibaba.fastjson.JSONObject;

/**
 * @author lyd
 * @Description: 自定义数据传输格式
 * @date 16:40
 */
public class ResultBody {

	/**
	 * 响应代码
	 */
	private String code;
	/**
	 * 响应消息
	 */
	private String message;
	/**
	 * 响应结果
	 */
	private Object result;

	public ResultBody() {
	}

	public ResultBody(BaseErrorInfoInterface baseErrorInfoInterface) {
		this.code = baseErrorInfoInterface.getResultCode();
		this.message = baseErrorInfoInterface.getResultMsg();
	}

	/**
	 * 成功
	 *
	 * @param data 数据
	 * @return {@link ResultBody}
	 */
	public static ResultBody success(Object data) {
		ResultBody resultBody = new ResultBody();
		resultBody.setCode(CommonEnum.SUCCESS.getResultCode());
		resultBody.setMessage(CommonEnum.SUCCESS.getResultMsg());
		resultBody.setResult(data);
		return resultBody;
	}

	/**
	 * 错误
	 *
	 * @param errorInfo 错误信息
	 * @return {@link ResultBody}
	 */
	public static ResultBody error(BaseErrorInfoInterface errorInfo) {
		ResultBody resultBody = new ResultBody();
		resultBody.setCode(errorInfo.getResultCode());
		resultBody.setMessage(errorInfo.getResultMsg());
		resultBody.setResult(null);
		return resultBody;
	}

	/**
	 * 错误
	 *
	 * @return {@link ResultBody}
	 */
	public static ResultBody error(String code, String message) {
		ResultBody resultBody = new ResultBody();
		resultBody.setCode(code);
		resultBody.setMessage(message);
		resultBody.setResult(null);
		return resultBody;
	}

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public Object getResult() {
		return result;
	}

	public void setResult(Object result) {
		this.result = result;
	}

	@Override
	public String toString() {
		return JSONObject.toJSONString(this);
	}
}

6.最关键的一步:自定义一个全局异常处理类,用到两个注解@ControllerAdvice @ExceptionHandler

package com.example.demo.exception;

import com.example.demo.util.ResultBody;
import com.example.demo.util.CommonEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;

/**
 * @author lyd
 * @Description:自定义全局异常处理类
 * @date 16:12
 */
@ControllerAdvice
public class MyExceptionHandler {

	private static final Logger logger = LoggerFactory.getLogger(MyExceptionHandler.class);

	/**
	 * 自定义的业务异常处理程序
	 *
	 * @param httpServletRequest http servlet请求
	 * @param ex
	 * @return {@link ResultBody}
	 */
	@ExceptionHandler(value = BizException.class)
	@ResponseBody
	public ResultBody bizExceptionHandler(HttpServletRequest httpServletRequest, BizException ex) {
		logger.error("啦啦啦啦啦发生业务异常,原因是:" + ex.getErrorMsg());
		return ResultBody.error(ex.getErrorCode(), ex.getErrorMsg());
	}

	/**
	 * 空指针异常处理程序
	 *
	 * @param req 要求的事情
	 * @param e   e
	 * @return {@link ResultBody}
	 */
	@ExceptionHandler(value = NullPointerException.class)
	@ResponseBody
	public ResultBody exceptionHandler(HttpServletRequest req, NullPointerException e) {
		logger.error("啦啦啦啦发生空指针异常!原因是:", e);
		return ResultBody.error(CommonEnum.BODY_NOT_MATCH);
	}

	/**
	 * 其他异常处理程序
	 *
	 * @param req 要求的事情
	 * @param e   e
	 * @return {@link ResultBody}
	 */
	@ExceptionHandler(value = Exception.class)
	@ResponseBody
	public ResultBody exceptionHandler(HttpServletRequest req, Exception e) {
		logger.error("啦啦啦啦发生未知异常!原因是:", e);
		return ResultBody.error(CommonEnum.INTERNAL_SERVER_ERROR);
	}

}

7.定义一个实体类,等会掉接口测试使用

package com.example.demo.pojo;

import java.io.Serializable;

/**
 * @author lyd
 * @Description:
 * @date 17:19
 */
public class User implements Serializable {

	private int id;
	private String name;
	private int age;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

}

8.controller层定义几个接口做测试

package com.example.demo.controller;

import com.example.demo.exception.BizException;
import com.example.demo.pojo.User;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

@RestController
public class UserRestController {


	@PostMapping("/user")
	public boolean insert(User user) {
		System.out.println("开始新增...");
		//如果姓名为空就手动抛出一个自定义的异常!
		if (user.getName() == null) {
			throw new BizException("-1", "用户姓名不能为空!");
		}
		return true;
	}

	@PutMapping("/user")
	public boolean update(User user) {
		System.out.println("开始更新...");
		//这里故意造成一个空指针的异常,并且不进行处理
		String str = null;
		str.equals("111");
		return true;
	}

	@DeleteMapping("/user")
	public boolean delete(User user) {
		System.out.println("开始删除...");
		//这里故意造成一个字符转换异常,并且不进行处理
		Integer.parseInt("abc123");
		System.out.println("发生异常后继续执行");
		return true;
	}

	@GetMapping("/user")
	public List<User> findByUser(User user) {
		System.out.println("开始查询...");
		List<User> userList = new ArrayList<>();
		User user2 = new User();
		user2.setId(1);
		user2.setName("liuliu");
		user2.setAge(18);
		userList.add(user2);
		return userList;
	}


}

最后使用postman测试

先使用Post请求测试

image

image

可以看到有手动异常抛出

再测一下Delete请求的,看看自动的捕捉异常

image
image

项目源码

https://github.com/Wranglery/test-ControllerAdvice

posted @ 2021-07-07 10:35  西红柿里没有番茄  阅读(207)  评论(0编辑  收藏  举报