Java SpringBoot 异常

使用异常

使用异常的方式很简单,Spring提供了两个注解:@ControllerAdvice@ExceptionHandler

  • @ControllerAdvice 控制器增强,使@ExceptionHandler@InitBinder@ModelAttribute注解的方法应用到所有的 @RequestMapping注解的方法
  • @ExceptionHandler 异常处理器,此注解的作用是当出现其定义的异常时进行处理的方法

    创建统一异常类

    ```java import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.TypeMismatchException; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.web.AbstractErrorController; import org.springframework.boot.autoconfigure.web.ErrorAttributes; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Controller; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartException; import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.sql.SQLException; import java.util.Map;

/**

  • 全局异常处理
  • 一般情况下,方法都有异常处理机制,但不能排除有个别异常没有处理,导致返回到前台,因此在这里做一个异常拦截,统一处理那些未被处理过的异常 *
  • @author ${author} on ${date} */ @ControllerAdvice @Controller @RequestMapping public class GlobalExceptionHandler extends AbstractErrorController {

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

    public GlobalExceptionHandler(ErrorAttributes errorAttributes) {

    1. super(errorAttributes);

    }

    @Value(“${server.error.path:${error.path:/error}}”) private static String errorPath = “/error”;

  1. /**
  2. * sql异常
  3. *
  4. * @param req
  5. * @param rsp
  6. * @param ex
  7. * @return
  8. * @throws Exception
  9. */
  10. @ResponseBody
  11. @ExceptionHandler(SQLException.class)
  12. public Result<String> sqlException(HttpServletRequest req, HttpServletResponse rsp, Exception ex) {
  13. LOGGER.error("!!! request uri:{} from {} server exception:{}", req.getRequestURI(), RequestUtil.getIpAddress(req), ex == null ? null : ex);
  14. return ResponseMsgUtil.builderResponse(1002, ex == null ? null : ex.getMessage(), null);
  15. }
  16. /**
  17. * 500错误.
  18. *
  19. * @param req
  20. * @param rsp
  21. * @param ex
  22. * @return
  23. * @throws Exception
  24. */
  25. @ResponseBody
  26. @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
  27. @ExceptionHandler(Exception.class)
  28. public Result<String> serverError(HttpServletRequest req, HttpServletResponse rsp, Exception ex) throws Exception {
  29. LOGGER.error("!!! request uri:{} from {} server exception:{}", req.getRequestURI(), RequestUtil.getIpAddress(req), ex == null ? null : ex);
  30. return ResponseMsgUtil.builderResponse(1002, ex == null ? null : ex.getMessage(), null);
  31. }
  32. /**
  33. * 404的拦截.
  34. *
  35. * @param request
  36. * @param response
  37. * @param ex
  38. * @return
  39. * @throws Exception
  40. */
  41. @ResponseBody
  42. @ResponseStatus(code = HttpStatus.NOT_FOUND)
  43. @ExceptionHandler(NoHandlerFoundException.class)
  44. public Result<String> notFound(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception {
  45. LOGGER.error("!!! request uri:{} from {} not found exception:{}", request.getRequestURI(), RequestUtil.getIpAddress(request), ex);
  46. return ResponseMsgUtil.builderResponse(404, ex == null ? null : ex.getMessage(), null);
  47. }
  48. @ExceptionHandler(MissingServletRequestParameterException.class)
  49. @ResponseBody
  50. public Result<String> paramException(MissingServletRequestParameterException ex) {
  51. LOGGER.error("缺少请求参数:{}", ex.getMessage());
  52. return ResponseMsgUtil.builderResponse(99999, "缺少参数:" + ex.getParameterName(), null);
  53. }
  54. //参数类型不匹配
  55. //getPropertyName()获取数据类型不匹配参数名称
  56. //getRequiredType()实际要求客户端传递的数据类型
  57. @ExceptionHandler(TypeMismatchException.class)
  58. @ResponseBody
  59. public Result<String> requestTypeMismatch(TypeMismatchException ex) {
  60. LOGGER.error("参数类型有误:{}", ex.getMessage());
  61. return ResponseMsgUtil.builderResponse(99999, "参数类型不匹配,参数" + ex.getPropertyName() + "类型应该为" + ex.getRequiredType(), null);
  62. }
  63. @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
  64. @ResponseBody
  65. public Result<String> requestMethod(HttpRequestMethodNotSupportedException ex) {
  66. LOGGER.error("请求方式有误:{}", ex.getMethod());
  67. return ResponseMsgUtil.builderResponse(99999, "请求方式有误:" + ex.getMethod(), null);
  68. }
  69. @ExceptionHandler(MultipartException.class)
  70. @ResponseBody
  71. public Result<String> fileSizeLimit(MultipartException m) {
  72. LOGGER.error("超过文件上传大小限制");
  73. return ResponseMsgUtil.builderResponse(99999, "超过文件大小限制,最大10MB", null);
  74. }
  75. /**
  76. * 重写/error请求, ${server.error.path:${error.path:/error}} IDEA报红无需处理,作用是获取spring底层错误拦截
  77. *
  78. * @param request
  79. * @param response
  80. * @return
  81. * @throws Exception
  82. */
  83. @ResponseBody
  84. @RequestMapping(value = "${server.error.path:${error.path:/error}}")
  85. public Result<String> handleErrors(HttpServletRequest request, HttpServletResponse response) throws Exception {
  86. HttpStatus status = getStatus(request);
  87. if (status == HttpStatus.NOT_FOUND) {
  88. throw new NoHandlerFoundException(request.getMethod(), request.getRequestURL().toString(), new HttpHeaders());
  89. }
  90. Map<String, Object> body = getErrorAttributes(request, true);
  91. return ResponseMsgUtil.builderResponse(Integer.parseInt(body.get("status").toString()), body.get("message").toString(), null);
  92. }
  93. @Override
  94. public String getErrorPath() {
  95. return errorPath;
  96. }

}

  1. 从上面可以看出来,定义了sql异常,500异常,404异常该做的事情,通过`@ExceptionHandler`注解来拦截程序中的异常,比如执行SQL时,抛出了异常,就会被统一异常给拦截,然后返回想要返回的数据<br />`@ResponseStatus`注解可加可不加,就是对响应码进行拦截,如代码上,对404响应码进行了拦截<br />最下面的`handleErrors`方法,是对Spring底层访问/error的时候进行了一次拦截,获取当前请求码,如果是404.抛出404的异常
  2. <a name="C4HF6"></a>
  3. ### 优化处理异常没有自定义返回数据
  4. ```java
  5. import com.alibaba.fastjson.JSON;
  6. import com.alibaba.fastjson.serializer.SerializerFeature;
  7. /**
  8. * 返回数据结果集合
  9. */
  10. public class Result<T> {
  11. private Integer code;
  12. private String resMsg;
  13. private T data;
  14. public Result() {
  15. }
  16. public Integer getCode() {
  17. return this.code;
  18. }
  19. public void setCode(Integer resCode) {
  20. this.code = resCode;
  21. }
  22. public String getResMsg() {
  23. return this.resMsg;
  24. }
  25. public void setResMsg(String resMsg) {
  26. this.resMsg = resMsg;
  27. }
  28. public T getData() {
  29. return this.data;
  30. }
  31. public void setData(T data) {
  32. this.data = data;
  33. }
  34. public String toJson() {
  35. return this.data == null ? JSON.toJSONString(this) : this.toJson(SerializerFeature.WriteNullListAsEmpty, SerializerFeature.WriteNullStringAsEmpty, SerializerFeature.WriteMapNullValue);
  36. }
  37. public String toJson(SerializerFeature... features) {
  38. return features == null ? this.toJson() : JSON.toJSONString(this, features);
  39. }
  40. public String toString() {
  41. return "Result{code=" + this.code + ", resMsg='" + this.resMsg + '\'' + ", data=" + this.data + '}';
  42. }
  43. }
  44. /**
  45. * 返回数据结果集合
  46. */
  47. public class ResponseMsgUtil {
  48. public ResponseMsgUtil() {
  49. }
  50. public static <T> Result<T> builderResponse(int code, String msg, T data) {
  51. Result<T> res = new Result();
  52. res.setCode(code);
  53. res.setResMsg(msg);
  54. res.setData(data);
  55. return res;
  56. }
  57. public static <T> Result<T> success(String msg) {
  58. return builderResponse(0, msg, null);
  59. }
  60. public static <T> Result<T> success(String msg, T data) {
  61. return builderResponse(0, msg, data);
  62. }
  63. public static <T> Result<T> success(T data) {
  64. return builderResponse(0, "Success", data);
  65. }
  66. public static <T> Result<T> success() {
  67. return builderResponse(0, "Success", null);
  68. }
  69. public static <T> Result<T> failure() {
  70. return builderResponse(1, "Failure", null);
  71. }
  72. public static <T> Result<T> failure(String msg) {
  73. return builderResponse(1, msg, null);
  74. }
  75. public static <T> Result<T> failure(T date) {
  76. return builderResponse(-1, "Failure", date);
  77. }
  78. public static <T> Result<T> illegalRequest() {
  79. return builderResponse(1008, "Illegal request", (T) null);
  80. }
  81. public static <T> Result<T> exception() {
  82. return builderResponse(1002, "request exception", (T) null);
  83. }
  84. public static <T> Result<T> paramsEmpty() {
  85. return builderResponse(1009, "the input parameter is null", (T) null);
  86. }
  87. }

测试

将这些准备都做好以后,项目跑起来,访问一个接口,故意不传某个必填项,就会被统一异常拦截,如下

  1. {
  2. code: 1002,
  3. data: null,
  4. msg: "Required String parameter 'id' is not present"
  5. }