SpringBoot 使用异常自定义错误码

一、背景简介

       目前的前后端交互普遍通过 Restful 的形式,而错误处理仅仅通过 HTTP 状态码往往不满足需求;

       基于此,我们需要在 HTTP 状态码基础上拓展业务错误码;

       本文介绍一种基于 SpringBoot 和 Exception 的实现方案。

二、实验步骤

2.1  生成 SpringBoot 基础项目

       SpringBoot 官方提供了初始模板工程,下载地址:https://start.spring.io/

       SpringBoot 使用异常自定义错误码_第1张图片

2.2  定义包含错误码的异常

       a.  首先,我们需要定义一个 Enum 用于枚举错误码,方便使用和记忆

            建立一个 package,如 org.shida.demo.enums

package org.shida.demo.enums;

public enum ApiExceptionCode {

	RESOURCE_NOT_FOUND(101, "Resource not found");

	private Integer value;

	private String desc;

	private ApiExceptionCode(Integer value, String desc) {
		this.value = value;
		this.desc = desc;
	}

	public Integer getValue() {
		return value;
	}

	public void setValue(Integer value) {
		this.value = value;
	}

	public String getDesc() {
		return desc;
	}

	public void setDesc(String desc) {
		this.desc = desc;
	}

}

            本例中,定义了 RESOURCE_NOT_FOUND ,错误码为 101

       b.  然后,定义一个公共异常(父类异常)

            建立一个 package,如 org.shida.demo.exception

package org.shida.demo.exception;

public class ApiException extends RuntimeException{
	
	private static final long serialVersionUID = 1L;
	
	private Integer code;

	public ApiException(Integer code, String msg) {
		super(msg);
		this.code = code;
	}

	public Integer getCode() {
		return code;
	}

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

}

            接着,实现真正的异常,ResourceNotFoundException

package org.shida.demo.exception;

import org.shida.demo.enums.ApiExceptionCode;

public class ResourceNotFoundException extends ApiException{
	
	private static final long serialVersionUID = 1L;

	public ResourceNotFoundException(String msg) {
		super(ApiExceptionCode.RESOURCE_NOT_FOUND.getValue(), msg);
	}

}

2.3  定义 Controller 异常 处理公共方法

       建立一个 package,org.shida.demo.config

package org.shida.demo.config;

import javax.servlet.http.HttpServletRequest;

import org.shida.demo.exception.ApiException;
import org.shida.demo.exception.ExceptionResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
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.ResponseStatus;

@ControllerAdvice
public class GlobalExceptionHandler {

	private final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

	@ResponseBody
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	@ExceptionHandler(Exception.class)
	public ExceptionResponse handleException(HttpServletRequest request, Exception ex) {
		if (ex instanceof ApiException) {
			log.warn(ex.getMessage(), ex);
			ApiException apiException = (ApiException) ex;
			return ExceptionResponse.create(apiException.getCode(), apiException.getMessage());
		} else {
			log.error(ex.getMessage(), ex);
			return ExceptionResponse.create(HttpStatus.INTERNAL_SERVER_ERROR.value(), ex.getMessage());
		}
	}

}

       这里通过判断 异常是否是 ApiException ,分别构造前端响应方式

       其中,ExceptionResponse 定义如下,这也是前端最终的异常展示结构,即 code + message 形式

package org.shida.demo.exception;

public class ExceptionResponse {

	private String message;
	private Integer code;

	public ExceptionResponse(Integer code, String message) {
		this.message = message;
		this.code = code;
	}

	public static ExceptionResponse create(Integer code, String message) {
		return new ExceptionResponse(code, message);
	}

	public Integer getCode() {
		return code;
	}

	public String getMessage() {
		return message;
	}

}

2.4  编写一个简单的 Controller 进行测试

       建立一个 package,com.shida.demo.web

package org.shida.demo.web;

import org.shida.demo.exception.ResourceNotFoundException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class DemoController {

	@GetMapping("/demo/{hello}")
	public String sayHello(@PathVariable String hello) {
		if (hello.equals("exception")) {
			throw new ResourceNotFoundException("资源没有找到");
		} else {
			return hello;
		}
	}

}

2.5  启动程序,通过浏览器访问 http://localhost:8080/api/demo/hello

      SpringBoot 使用异常自定义错误码_第2张图片

       访问 http://localhost:8080/api/demo/exception ,模拟异常发生

       SpringBoot 使用异常自定义错误码_第3张图片

       客户端,首先通过 HTTP 状态码判断是否出现了错误,

       如果出现了错误,进一步可以通过提取 error data 中的 code 判断错误类型,同时提取 message

三、实验代码下载地址

       https://pan.baidu.com/s/1bxSSKfOiJM8hOcUJ09SIxA

你可能感兴趣的:(Spring)