基本思路
1、定义返回代码的枚举类。
2、定义一个公共方法控制器 BaseRestController ,实现 success / error 系列的方法,便于自定义 Exception 类和业务控制器中调用。
3、捕获全局异常,可以自定义业务异常类,在方法中调用公共方法控制器 BaseRestController 中的 error 方法返回返回代码枚举类中的元素。
文件目录结构
环境
1、定义返回码类
将返回码类分为枚举类和常规类,好处是自由度较高,可以随喜好选择不同的返回方式
1.1、枚举类
ResponseCodeEnum
package com.example.boot.response;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum ResponseCodeEnum {
/**
* 通用
*/
SUCCESS(1, "ok"),
ERROR(0, "error"),
/**
* 系统错误
*/
InternalError(50000, "系统内部错误"),
/**
* 客户端错误
*/
ClientError(30000, "客户端错误"),
/**
* 其他错误
*/
OtherError(30000, "其他错误"),
;
private Integer code;
private String msg;
}
1.2、常规类
ResponseCode
package com.example.boot.response;
public class ResponseCode {
/**
* 成功
*/
public static int SUCCESSED = 1;
/**
* 失败
*/
public static int FAILED = 0;
/**
* 缺少请求参数异常
*/
public static int missingServletRequestParameterException = 50000;
/**
* 参数类型不匹配错误
*/
public static int methodArgumentTypeMismatchException = 50100;
}
2、定义返回体类
SpringBoot 会将对象封装成 json 返回出去。所以,我们需要定义一个用来封装返回体的对象。例如:code/msg/data 等
{
"code": 0,
"msg": "error",
"data": null
}
Response
package com.example.boot.response;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@JsonPropertyOrder(value = {"code", "msg", "data"})
public class Response<T> implements Serializable {
/**
* 响应码
*/
@JsonProperty("code")
private Integer code;
/**
* 返回消息
*/
@JsonProperty("msg")
private String msg;
/**
* 返回结果集
*/
@JsonProperty("data")
private T data;
}
3、定义控制器
3.1、定义公共方法控制器
BaseRestController
package com.example.boot.controller;
import com.example.boot.response.Response;
import com.example.boot.response.ResponseCode;
import com.example.boot.response.ResponseCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
public class BaseRestController {
public BaseRestController() {
log.info("BaseRestController 构造函数被调用了");
}
/**
* success 系列方法
*/
public Response success() {
Response response = new Response<>();
response.setCode(ResponseCode.SUCCESSED);
response.setData(null);
response.setMsg("ok");
return response;
}
public Response success(String msg) {
Response response = new Response<>();
response.setCode(ResponseCode.SUCCESSED);
response.setData(null);
response.setMsg(msg);
return response;
}
public Response success(String msg, Object data) {
Response response = new Response<>();
response.setCode(ResponseCode.SUCCESSED);
response.setData(data);
response.setMsg(msg);
return response;
}
public Response success(String msg, Integer code) {
Response response = new Response<>();
response.setCode(code);
response.setData(null);
response.setMsg(msg);
return response;
}
public Response success(String msg, Object data, Integer code) {
Response response = new Response<>();
response.setCode(code);
response.setData(data);
response.setMsg(msg);
return response;
}
public Response success(ResponseCodeEnum responseCodeEnum, Object data) {
Response response = new Response<>();
response.setCode(responseCodeEnum.getCode());
response.setMsg(responseCodeEnum.getMsg());
response.setData(data);
return response;
}
public Response success(ResponseCodeEnum responseCodeEnum) {
Response response = new Response<>();
response.setCode(responseCodeEnum.getCode());
response.setMsg(responseCodeEnum.getMsg());
response.setData(null);
return response;
}
/**
* error 系列方法
*/
public Response error() {
Response response = new Response<>();
response.setCode(ResponseCode.FAILED);
response.setData(null);
response.setMsg("ok");
return response;
}
public Response error(String msg) {
Response response = new Response<>();
response.setCode(ResponseCode.FAILED);
response.setData(null);
response.setMsg(msg);
return response;
}
public Response error(String msg, Object data) {
Response response = new Response<>();
response.setCode(ResponseCode.FAILED);
response.setData(data);
response.setMsg(msg);
return response;
}
public Response error(String msg, Integer code) {
Response response = new Response<>();
response.setCode(code);
response.setData(null);
response.setMsg(msg);
return response;
}
public Response error(String msg, Object data, Integer code) {
Response response = new Response<>();
response.setCode(code);
response.setData(data);
response.setMsg(msg);
return response;
}
public Response error(ResponseCodeEnum responseCodeEnum, Object data) {
Response response = new Response<>();
response.setCode(responseCodeEnum.getCode());
response.setMsg(responseCodeEnum.getMsg());
response.setData(data);
return response;
}
public Response error(ResponseCodeEnum responseCodeEnum) {
Response response = new Response<>();
response.setCode(responseCodeEnum.getCode());
response.setMsg(responseCodeEnum.getMsg());
response.setData(null);
return response;
}
}
3.2、定义业务控制器
IndexController
package com.example.boot.controller;
import com.example.boot.response.Response;
import com.example.boot.response.ResponseCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
public class IndexController extends BaseRestController {
public IndexController() {
log.info("IndexController 构造函数被调用了");
}
@RequestMapping(path = {
"/",
"/index"
})
public Response index() {
return success();
}
@RequestMapping(path = {
"/test"
})
public Response test(@RequestParam(name = "a") Integer a) {
if (a.equals(0)) {
// return error("a不能为0");
// throw new CustomerException(201, "自定义错误");
return error(ResponseCodeEnum.ArithmeticException);
}
int b = 10 / a;
return success();
}
}
在 test 方法里,我注释掉了两行代码。
1)因为在公共方法控制器 BaseRestController 中,我已经默认实现了success / error 系列的方法,所以在业务 controller 中可以这样返回 msg:
return error("a不能为0");
2)因为捕获了全局异常,所以可以在业务 controller 中直接 throw 我们自定义的异常类。
throw new CustomerException(201, "自定义错误");
不过我还是比较推荐使用返回码枚举类的方式来返回错误信息:
return error(ResponseCodeEnum.ArithmeticException);
4、定义异常类
4.1、定义一个处理全局异常的类。
GlobalExceptionHandler
package com.example.boot.exception;
import com.example.boot.controller.BaseRestController;
import com.example.boot.response.Response;
import com.example.boot.response.ResponseCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler extends BaseRestController {
/**
* 处理所有类型的异常
*/
@ExceptionHandler({
Exception.class,
})
public Response exceptionHandler(HttpServletRequest req, Exception e) {
log.error("全局异常捕获:", e);
Map<String, Object> detail = new HashMap<>();
detail.put("exception", e.toString());
return error("全局异常捕获", detail, ResponseCode.FAILED);
}
/**
* 处理自定义的业务异常
*/
@ExceptionHandler(value = CustomerException.class)
public Response customerExceptionHandler(HttpServletRequest req, Exception e) {
log.error("自定义业务异常:", e);
Map<String, Object> detail = new HashMap<>();
detail.put("exception", e.toString());
return error("自定义异常", detail, ResponseCode.FAILED);
}
}
4.2、定义业务异常类
根据业务需求,定义自己需要的异常类。
CustomerException
package com.example.boot.exception;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CustomerException extends RuntimeException {
/**
* 错误码
*/
protected Integer errorCode;
/**
* 错误信息
*/
protected String errorMsg;
}