SpringBoot处理(Controller、interceptor、filter)全局异常

Posted on   FLGB  阅读(643)  评论(0编辑  收藏  举报

## 1、Controller层的全局异常处理

通过对Controller添加注释@ControllerAdvice可以实现Controller层的全局异常处理

统一的拦截异常处理类AppExceptionHandler

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
@Slf4j
@RestControllerAdvice
public class AppExceptionHandler {
    @Autowired
    protected MessageSource messageSource;
 
    @ExceptionHandler({UserLoginException.class})
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public Result handleUserLoginException(final UserLoginException userLoginException) {
        log.error("LiveAppExceptionHandler->UserLoginException={}", userLoginException);
        return Result.error(userLoginException.getCode(), userLoginException.getMessage());
    }
     
    @ExceptionHandler({UrlException.class})
    @ResponseStatus(HttpStatus.OK)
    public Result handleChanceException(final UrlException urlException) {
        log.error("【UrlException】:", UrlException);
        return Result.error(urlException.getCode(), urlException.getMessage());
    }
 
    @ExceptionHandler({Exception.class})
    @ResponseStatus(HttpStatus.OK)
    public Result handleException(final Exception exception) {
        log.error("【exception】:", exception);
        return Result.error(AdminErrorCodeEnum.A0001);
    }
 
}

  

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
Result 统一封装的返回类
 
@Data
public class Result<T> {
    private int code;
    private T data;
    private String msg;
 
 
    public static <T> Result<T> success(T response) {
        Result<T> result = new Result<>();
        result.setCode(0);
        result.setData(response);
        return result;
    }
 
    public static Result error(int code, String message) {
        Result result = new Result();
        result.setCode(code);
        result.setMsg(message);
        return result;
    }
 
    public static Result error(AppErrorCodeEnum errorCodeEnum) {
        Result result = new Result();
        result.setCode(errorCodeEnum.getCode());
        result.setMsg(errorCodeEnum.getMessage());
        return result;
    }
 
    public static Result error(AppErrorCodeEnum errorCodeEnum, MessageSource messageSource, Object... params) {
        Result jsonResult = new Result();
        jsonResult.setCode(errorCodeEnum.getCode());
        jsonResult.setMsg(messageSource.getMessage(String.valueOf(errorCodeEnum.getCode()), params, errorCodeEnum.getMessage(), Locale.SIMPLIFIED_CHINESE));
        return jsonResult;
    }
}

  

## 2、Interceptor异常统一处理

Interceptor是基于SpringMVC框架的,有时候我们需要拦截器中进行逻辑处理时(比如:tonken登陆验证)需要抛出异常,那么这里抛出的异常是可以被@ControllerAdvice注释的异常处理类捕获的。

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
InterceptorConfig 配置类,将具体的拦截器类注册到InterceptorConfig 中
```bash
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
 
    @Autowired
    SessionInterceptor userLoginInterceptor;
 
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        InterceptorRegistration interceptorRegistration = registry.addInterceptor(userLoginInterceptor);
        interceptorRegistration.addPathPatterns("/**");
        interceptorRegistration.excludePathPatterns(
                "/login/**"
        );
}
 
```
实际的业务拦截器类SessionInterceptor
```bash
@Slf4j
@Component
public class SessionInterceptor implements HandlerInterceptor {
 
    @Autowired
    RedisTemplate redisTemplate;
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String token = request.getHeader("token");
        if (StringUtils.isEmpty(token)){
            log.error("传入token参数值为空={},请先登录",token);
            throw new UserLoginException(AppErrorCodeEnum.A0003.getCode(),AppErrorCodeEnum.A0003.getMessage() );
        }
        //从redis中获取token
        LiveTokenDTO liveTokenDTO = (LiveTokenDTO) redisTemplate.opsForValue().get(token);
        if(ObjectUtil.isNotEmpty(liveTokenDTO)){ 
            return true;
        } else {
            log.error("SessionInterceptor->userToken用户会话解析为空");
            throw new UserLoginException(AppErrorCodeEnum.A0003.getCode(),AppErrorCodeEnum.A0003.getMessage() );
        }
    }
 
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }
```
 
异常类
 
```bash
@data
public class UserLoginException extends RuntimeException{
    int code;
    String message;
 
}
```
枚举类
 
```bash
@Getter
public enum AppErrorCodeEnum {
 
    A0000(10000, "参数校验失败"),
    A0001(10001, "系统繁忙,请稍后再试"),
    A0002(10002, "登录失败"),
    A0003(10003, "token失效,请重新登录");
    private int code;
 
    private String message;
 
    private String subCode;
 
    private String subMessage;
 
    AppErrorCodeEnum(int code, String message) {
        this.code = code;
        this.message = message;
    }
 
    public void setSubCodeAndSubMessage(String subCode, String subMessage) {
        setSubCode(subCode);
        setSubMessage(subMessage);
    }
 
    private void setSubCode(String subCode) {
        this.subCode = subCode;
    }
 
    private void setSubMessage(String subMessage) {
        this.subMessage = subMessage;
    }
}

  

## 3、Filter异常统一处理

过滤器Filter和基于Servlet框架编写的,抛出的异常是不可以被@ControllerAdvice注释的异常处理类捕获的,常见的异常处理的方法有两种:
(1)通过请求转发到特定的异常处理controller中进行处理

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
(1)通过请求转发到特定的异常处理controller中进行处理
   
定义一个filter异常处理的Controller
```bash
@Slf4j
@RestController
@RequestMapping("/filter")
public class FilterExceptionController {
 
    @RequestMapping("exception")
    public void handleException() {
        throw new UrlException(AppErrorCodeEnum.A0003.getCode(), AppErrorCodeEnum.A0003.getMessage());
 
    }
}
```
请求url路径过滤器
```bash
@Slf4j
@Component
public class RequestUrlFilter implements Filter {
 
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
 
        String path = ((HttpServletRequest) servletRequest).getRequestURI();
        if (!path.contains("/app")) {
//            throw new UrlException(401, "filter内部抛出异常");//AppExceptionHandler 全局异常捕获不到
//转发给filter异常处理的Controller,controller中直接抛出异常,AppExceptionHandler全局异常就可已捕获到了       servletRequest.getRequestDispatcher("/filter/exception").forward(servletRequest,servletResponse);
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }
 
}

  

(2)、SpringBoot 提供了 ErrorController 这个接口能力;其内置了一个 BasicErrorController 对异常进行统一的处理,当在 Controller 发生异常的时候会自动把请求 forward 到 /error 这个请求 path 下(/error 是 SpringBoot 提供的一个默认的mapping)。BasicErrorController 提供两种返回错误:1、页面返回;2、json 返回。

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
@RestController
public class UrlErrorController extends BasicErrorController {
 
    public UrlErrorController() {
        super(new DefaultErrorAttributes(), new ErrorProperties());
    }
 
    @Override
    @RequestMapping(produces = {MediaType.APPLICATION_JSON_VALUE})
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
        HttpStatus status = getStatus(request);
        return new ResponseEntity((String) body.get("message"), status);
    }
}
```
将filter异常直接抛出
 
@Slf4j
@Component
public class RequestUrlFilter implements Filter {
 
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
 
        String path = ((HttpServletRequest) servletRequest).getRequestURI();
        if (!path.contains("/app")) {
            throw new UrlException(401, "filter内部抛出异常");
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }
 
}

返回:java.lang.RuntimeException: UrlException(code=401, message=filter内部抛出异常)

相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix

随笔 - 205, 文章 - 1, 评论 - 7, 阅读 - 14万

Copyright © 2025 FLGB
Powered by .NET 9.0 on Kubernetes

点击右上角即可分享
微信分享提示