添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
很拉风的香菜  ·  C 指针数组 | 菜鸟教程·  1 年前    · 
玩篮球的甘蔗  ·  An Introduction to ...·  1 年前    · 

项目场景:

在SpringBoot项目中引入Spring-Cloud-Oauth2 实现客户端权限管理,项目中使用的是客户端模式,由于框架自带的校验及异常信息给的并不友好,不符合我们自己项目异常格式。需要我们自己在拦截器当中对客户端信息进行校验,校验成功时放行,失败时抛出自定义异常

filter逻辑如下:

@Component
public class CheckClientInfoFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) throws ServletException, IOException {
            //客户端信息校验..
            boolean isSuccess = checkClientInfo(request);
            if(!isSuccess){
                throw new CustomException("客户端信息非法!!!")
            filterChain.doFilter(request, response);

 全局异常处理:

@RestControllerAdvice
public class GlobalExceptionHandler {
	 * 处理自定义的业务异常
	 * @param req
	 * @param e
	 * @return ResponseResult
	@ExceptionHandler(value = BusinessException.class)
	public ResponseResult<Object> customExceptionHandler(HttpServletRequest req, CustomException e) {
		log.error("发生业务异常!原因是:{}", e.getErrorMsg());
        //按统一响应格式返回错误信息
		return ResponseResult.fail(e.getErrorCode(), e.getMessage());

一开始以为,上面这种直接在filter抛出的异常能够被全局异常处理类捕获,但实际上的错误响应却是这样

"timestamp": "2021-05-13T08:53:18.355+0000", "status": 500, "error": "Internal Server Error", "message": "客户端信息非法!!!", "path": "/oauth/token"

并不是我们期望的响应格式,我们的自定义异常并没有被全局异常处理类(GlobalExceptionHandler)捕获,而是被Spring框架捕获了

原因分析:

在Spring Boot由于全局异常处理@RestControllerAdvice只会去捕获所有Controller层抛出的异常,所以在filter当中抛出的异常GlobalExceptionHandler类是没有感知的,

所以在filter当中抛出的异常最终会被Spring框架自带的全局异常处理类BasicErrorController捕获,返回上面我们看到的Json响应

解决方案:

继承上面所说的BasicErrorController类,并重写error()方法,代码如下:

@Component
public class FilterErrorController extends BasicErrorController {
    public FilterErrorController() {
        super(new DefaultErrorAttributes(), new ErrorProperties());
    @Override
    @RequestMapping
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        HttpStatus status = getStatus(request);
        if (status == HttpStatus.NO_CONTENT) {
            return new ResponseEntity<>(status);
        Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
        //重写body自定义反参格式
        Map<String,Object> myBody = new HashMap<>();
        return new ResponseEntity<>(myBody, status);

这种方法虽然可以满足我们的要求,但是值得注意的是,如果重写该方法那么所有未被@RestControllerAdvice捕获的异常都会进入该方法当中,如果在filter当中抛出的异常信息不止一种,这个时候就会比较麻烦,需要通过body中携带的异常信息做判断才能做出相应的处理,但是body中携带的异常信息包括如下几个字段:

由于所有未被全局异常捕获的自定义异常,框架都会返回http状态码为500,我们只能拿到自定义异常的message而拿不到错误码,所以可用的字段只有message一项,我们要通过错误信息的字符串比对才能做出相应处理,这样的处理方式虽然也可以实现,但是非常不灵活。

在filter当中引入HandlerExceptionResolver类,通过该类的resolveException方法抛出自定义异常,代码如下:

@Component
public class CheckClientInfoFilter extends OncePerRequestFilter {
    @Autowired
    @Qualifier("handlerExceptionResolver")
    private HandlerExceptionResolver resolver;
    @Override
    protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) throws ServletException, IOException {
            //客户端信息校验..
            boolean isSuccess = checkClientInfo(request);
            if(!isSuccess){
                throw resolver.resolveException(request,response,                 
                               null,newCustomException("客户端信息非法!!!");
                return;
            filterChain.doFilter(request, response);

通过resolveException方法抛出的自定义异常可以被RestControllerAdvice捕获,从而满足我们的需求,最终得到的响应格式:

"info": { "resultCode": "9999", "resultMsg": "客户端信息非法!!!" "data": null 而 过滤器 是 tomcat 的规范 , 所以 全局异常可以拦截 拦截器的异常 , 但是。springboot中全局异常依赖于 @RestControllerAdvice。@RestControllerAdvice 基于 springmvc。springboot过滤器与拦截器详解。过滤器自定义异常我们需要手动进行处理。java中拦截器与过滤器区别。过滤器和拦截器的优先级。 这个比较简单,继承ErrorController接口实现自己的Controller即可。 可参见:org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController  代码参照[非最终代码,部分命名可能不规范,参考用]: package com.minipro 很多时候,我们在项目中使用 Filter 过滤器的时候, 或多或少会有自定义的异常抛出, 但是当客户端访问接口时, 如果是直接使用Throw 抛出异常, 那么返回的结果 就会是 request 内部的 500 错误码。这是我如果想返回自己的code和一些msg的时候就不方便了。 所以,我们采用 继承 请求的基类,BasicRequestController ,创建一个自己的ErrorContr... 我将权限管理分为三块: 1.资源权限:将url当做资源,可以给每个账号动态划分Url权限,访问不同的URl; 2.操作权限:将所有URL分为增、删、改、查4种操作权限,给用户分配对应的操作权限,如某个用户只有查操作权限那么他就无法做其他的操作; 3.角色权限:系统有多个角色,每个角色的权限都不同,如一个管理后台有着账号管理模块、商品模块等,为超级管理员的角色就可以看到所有模块并操作,而为售后的角色就只能看到商品模块,即使他知道账号管理模块下的URL也无权限操作。然后为用户设置角色就有对应的权限; 第一次写博客,暂时在构建一个SpringBoot后台项目 前端准备采取Vue,后台采取java 准备集成SpringBoot+shiro+mybaits基础上开展的用户的权限管理,定时任务,微信公众号等。 第一篇 关于SpringBoot自定义异常: 第一步,创建自定义异常,源码如下: filter函数: filter()函数可以对序列做过滤处理,就是说可以使用一个自定的函数过滤一个序列,把序列的每一项传到自定义的过滤函数里处理,并返回结果做过滤。最终一次性返回过滤后的结果。 filter()函数有两个参数: 第一个,自定函数名,必须的 第二个,需要过滤的列,也是必须的 需求,过滤大于5小于10的数: 复制代码 代码如下: # coding=utf8 # 定义大于5小于10的函数 def guolvhanshu(num):     if num>5 and num<10:         return num # 定义一个序列 seq=(12,50,8,17,6 private String msg; 再写一个全局异常处理。这里面的内容就是这,json的是处理当前程序异常,另一个是处理业务异常。@ExceptionHandler是异常的注解,@RestControllerAdvice通知注解