基本思路
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@AllArgsConstructorpublic 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@Slf4jpublic 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@Slf4jpublic 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@Slf4jpublic 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@NoArgsConstructorpublic class CustomerException extends RuntimeException {/*** 错误码*/protected Integer errorCode;/*** 错误信息*/protected String errorMsg;}
5、测试
5.1、正常请求

5.2、业务exception

5.3、全局异常捕获

