本文最后更新于:2023年8月24日 晚上
在写spring项目的时候,特别是使用了安全框架security之后,异常的处理直接返回封装对象会导致结构非常多余,以下是我的统一异常处理
项目初始化
创建状态枚举类
stateEnum > RespResultEnum.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| package com.fsan.throw_demo.stateEnum;
public enum RespResultEnum {
SUCCESS(200, "成功!"), ERROR(500, "服务器出现问题,请尽快联系管理员!"), NOT_AUTHENTICATION(403, "权限认证失败!"), NULL_USERNAME(1001, "用户名为空!非法请求!"), NULL_PASSWORD(1002, "密码为空!非法请求!");
private Integer code; private String msg;
RespResultEnum(Integer code, String msg) { this.code = code; this.msg = msg; }
public Integer getCode() { return code; }
public void setCode(Integer code) { this.code = code; }
public String getMsg() { return msg; }
public void setMsg(String msg) { this.msg = msg; } }
|
创建返回的实体类
entity > RespResult.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| package com.fsan.throw_demo.entity;
import com.fsan.throw_demo.stateEnum.RespResultEnum; import lombok.Data;
@Data public class RespResult { private Integer code; private String msg; private Object data;
public static RespResult success(Object data) { RespResult respResult = new RespResult(); respResult.setCode(RespResultEnum.SUCCESS.getCode()); respResult.setMsg(RespResultEnum.SUCCESS.getMsg()); respResult.setData(data); return respResult; }
public static RespResult success() { RespResult respResult = new RespResult(); respResult.setCode(RespResultEnum.SUCCESS.getCode()); respResult.setMsg(RespResultEnum.SUCCESS.getMsg()); return respResult; }
public static RespResult fail(RespResultEnum respResultEnum) { RespResult respResult = new RespResult(); respResult.setCode(respResultEnum.getCode()); respResult.setMsg(respResultEnum.getMsg()); return respResult; }
public static RespResult error() { RespResult respResult = new RespResult(); respResult.setCode(RespResultEnum.ERROR.getCode()); respResult.setMsg(RespResultEnum.ERROR.getMsg()); return respResult; } }
|
简单建立User类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package com.fsan.throw_demo.entity;
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;
@Data @AllArgsConstructor @NoArgsConstructor public class User { private Long userId; private String username; private String password; }
|
异常统一处理
思路:
- 创建自定义异常类,接收状态枚举
- 定义响应拦截,接收抛出的自定义异常类的信息
- 使用
HttpServletResponse封装返回
创建自定义异常
exception > ValidateException.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package com.fsan.throw_demo.exception; import com.fsan.throw_demo.stateEnum.RespResultEnum;
public class ValidateException extends RuntimeException { private RespResultEnum respResultEnum;
public ValidateException(RespResultEnum respResultEnum) { super(respResultEnum.getMsg()); this.respResultEnum = respResultEnum; }
RespResultEnum getRespResultEnum() { return respResultEnum; } }
|
继承RuntimeException是自定义异常类的最佳选择,然后自定义异常类中存储状态枚举类方便后续封装返回
类的访问修饰符不写就是在同包下使用,如果要在其他包下调用,需要写上public
创建异常处理类
exception > GlobalException.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package com.fsan.throw_demo.exception;
import com.alibaba.fastjson.JSON; import com.fsan.throw_demo.entity.RespResult; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletResponse; import java.io.IOException;
@Slf4j @RestControllerAdvice public class GlobalException {
@ExceptionHandler(ValidateException.class) public void handler(ValidateException exception, HttpServletResponse resp) { resp.setStatus(200); resp.setContentType("application/json"); resp.setCharacterEncoding("utf-8"); try { resp.getWriter().write(JSON.toJSONString(RespResult.fail(exception.getRespResultEnum()))); } catch (IOException e) { e.printStackTrace(); log.error("================\n出现未知错误!\n================"); } } }
|
@RestControllerAdvice 设置在响应前执行
@ExceptionHandler(ValidateException.class) 接收抛出的ValidateException异常类
这里也可以将HttpServletResponse对象单独封装一份供其他类调用,如下:
utils > WebUtils
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com.fsan.throw_demo.utils; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletResponse; import java.io.IOException;
@Slf4j @Component public class WebUtils {
public void sendResp(HttpServletResponse response, String respResult) { try { response.setStatus(200); response.setContentType("application/json"); response.setCharacterEncoding("utf-8"); response.getWriter().write(respResult); } catch (IOException e) { e.printStackTrace(); log.error("================\n出现未知错误!\n================"); } } }
|
修改后的异常处理类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package com.fsan.throw_demo.exception;
import com.alibaba.fastjson.JSON; import com.fsan.throw_demo.entity.RespResult; import com.fsan.throw_demo.utils.WebUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletResponse;
@RestControllerAdvice public class GlobalException {
@Autowired private WebUtils webUtils;
@ExceptionHandler(ValidateException.class) public void handler(ValidateException exception, HttpServletResponse resp) { String respResult = JSON.toJSONString(RespResult.fail(exception.getRespResultEnum())); webUtils.sendResp(resp, respResult); } }
|