1. 1 不可撤销
  2. 2 小年兽 程嘉敏
  3. 3 手放开 李圣杰
  4. 4 迷人的危险3(翻自 dance flow) FAFA
  5. 5 山楂树之恋 程佳佳
  6. 6 summertime cinnamons / evening cinema
  7. 7 不谓侠(Cover 萧忆情Alex) CRITTY
  8. 8 神武醉相思(翻自 优我女团) 双笙
  9. 9 空山新雨后 音阙诗听 / 锦零
  10. 10 Wonderful U (Demo Version) AGA
  11. 11 广寒宫 丸子呦
  12. 12 陪我看日出 回音哥
  13. 13 春夏秋冬的你 王宇良
  14. 14 世界が终わるまでは… WANDS
  15. 15 多想在平庸的生活拥抱你 隔壁老樊
  16. 16 千禧 徐秉龙
  17. 17 我的一个道姑朋友 双笙
  18. 18 大鱼  (Cover 周深) 双笙
  19. 19 霜雪千年(Cover 洛天依 / 乐正绫) 双笙 / 封茗囧菌
  20. 20 云烟成雨(翻自 房东的猫) 周玥
  21. 21 情深深雨濛濛 杨胖雨
  22. 22 Five Hundred Miles Justin Timberlake / Carey Mulligan / Stark Sands
  23. 23 斑马斑马 房东的猫
  24. 24 See You Again Wiz Khalifa / Charlie Puth
  25. 25 Faded Alan Walker / Iselin Solheim
  26. 26 Natural J.Fla
  27. 27 New Soul Vox Angeli
  28. 28 ハレハレヤ(朗朗晴天)(翻自 v flower) 猫瑾
  29. 29 像鱼 王贰浪
  30. 30 Bye Bye Bye Lovestoned
  31. 31 Blame You 眠 / Lopu$
  32. 32 Believer J.Fla
  33. 33 书信 戴羽彤
  34. 34 柴 鱼 の c a l l i n g【已售】 幸子小姐拜托了
  35. 35 夜空中最亮的星(翻自 逃跑计划) 戴羽彤
  36. 36 慢慢喜欢你 LIve版(翻自 莫文蔚) 戴羽彤
  37. 37 病变(翻自 cubi) 戴羽彤
  38. 38 那女孩对我说 (完整版) Uu
  39. 39 绿色 陈雪凝
  40. 40 月牙湾 LIve版(翻自 F.I.R.) 戴羽彤
夜空中最亮的星(翻自 逃跑计划) - 戴羽彤
00:00 / 04:10

夜空中最亮的星 能否听清

那仰望的人 心底的孤独和叹息

夜空中最亮的星 能否记起

那曾与我同行 消失在风里的身影

我祈祷拥有一颗透明的心灵

和会流泪的眼睛

给我再去相信的勇气

越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请指引我靠近你

夜空中最亮的星 是否知道

那曾与我同行的身影 如今在哪里

夜空中最亮的星 是否在意

是等太阳先升起 还是意外先来临

我宁愿所有痛苦都留在心底

也不愿忘记你的眼睛

哦 给我再去相信的勇气

哦 越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请照亮我向前行 哒~

我祈祷拥有一颗透明的心灵

和会流泪的眼睛 哦

给我再去相信的勇气

哦 越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请照亮我向前行

Spring boot集中异常处理

集中异常处理

以下代码可在github获取:https://github.com/Syske/learning-dome-code/tree/master/springboot-learning

方式一:ExceptionHandle

定义自己的异常类型,根据不同类型做不同处理,比如我定义的MyException:

public class MyException extends RuntimeException {
    public MyException(String msg) {
        super(msg);
    }
}

然后通过MyExceptionHandle处理该异常,需要注意的是异常不能在filter中抛出,抛出也没法捕获

@RestControllerAdvice
public class MyExceptionHandle {

    @ExceptionHandler(MyException.class)
    public Result exceptionHandle(MyException e) {
        return Result.getFailed( "system error:MyException" + e.getMessage());
    }
}

在controller、service以及拦截器的预处理方法中都可以完美捕获,这里特殊说下拦截器:

public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        //throw new MyException("拦截器错误:MyInterceptor");
        // 这里的异常会完美捕获,并返回
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        throw new MyException("拦截器错误:MyInterceptor");
        /** 能捕获异常信息并返回给客户端,但并不会覆盖已经请求成功的返回结果,但会包含在返回结果中,比如我的返回结果:
         {"code":1,"success":true,"msg":"请求成功","result":true}{"code":0,"success":false,"msg":"system error:MyException拦截器错误:MyInterceptor","result":null}
         */
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        throw new MyException("拦截器错误:MyInterceptor");
        // 这里抛出的异常并不能被捕获,会直接在后台抛出,相当于回掉函数,请求结果已经返回
    }
}

上面的解释已经够清楚了,就不做过多说明了。刚刚我们说了,上面的这种方式,对于filter是不起作用的,下面我们说的这种方式,主要就是针对filter来说的

方式二:ExceptionFilter

定义一个controller,请求路径可以自己指定,比如/error/exthrow:

@Controller
public class ExceptionController {

    @RequestMapping("/error/exthrow")
    public void rethrow(HttpServletRequest request) throws Exception {
        throw ((Exception) request.getAttribute("filter.error"));
    }
}

再定义一个异常拦截器,在需要抛出异常的拦截器中直接抛出异常,然后在异常拦截器中try-catch,发生异常时直接转发至前面定义的异常controller,这里需要注意的是,如果你的filter是实现Filter或者继承OncePerRequestFilter,那你不需要任何处理,直接request.setAttribute("filter.error", e)就可以了。

由于我把自己的filter交给shiro管理,而且是继承BasicHttpAuthenticationFilter的,不知到什么原因,直接catch到的异常类型是ServletException,为了拿到真正的异常信息,我需要通过getCause()方法获取filter中抛出的异常。因为controller抛出的异常最后还是会交给我们定义的MyExceptionHandle去处理,如果获取到的异常不是我们自定义的异常或者他的子类的话,就会返回500错误(在这个示例前,我以为所有的filter都是这样的,后来实践后发现并不是这样😂)。

@Component
public class ExceptionFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            chain.doFilter(request, response);
        } catch (Exception e) {            
            request.setAttribute("filter.error", e);
            //将异常分发到/error/exthrow控制器
            request.getRequestDispatcher("/error/exthrow").forward(request, response);
        }
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void destroy() {

    }
}

我的filter:

实现Filter接口:

public class MyFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        throw new MyException("MyFilter过滤器抛出异常");
        //filterChain.doFilter(servletRequest, servletResponse);
    }
   
}

filter2继承OncePerRequestFilter:

public class MyFilter2 extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        throw new MyException("MyFilter2异常");
    }
}

filter配置类:

 @Bean
    public FilterRegistrationBean myFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new MyFilter());
        registration.setName("myFilter");
        registration.addUrlPatterns("/*");
        //此处尽量小,要比其他Filter靠前
        registration.setOrder(1);
        return registration;
    }

    @Bean
    public FilterRegistrationBean myFilter2Registration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new MyFilter2());
        registration.setName("myFilter2");
        registration.addUrlPatterns("/*");
        //此处尽量小,要比其他Filter靠前
        registration.setOrder(2);
        return registration;
    }

    /**
     * 配置拦截器
     * @return
     */
    @Bean
    public FilterRegistrationBean exceptionFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new ExceptionFilter());
        registration.setName("exceptionFilter");
        //此处尽量小,要比其他Filter靠前
        registration.setOrder(-1);
        return registration;
    }

方式三:BasicErrorController

其实spring boot原生提供了异常集中处理,我们经常会看到:

但是这种方式不够友好,而且大部分情况不满足我们的需求,我们可以通过继承这个controller,然后重写error方法或者errorHtml方法,或者两个都重写,区别是errorHtml是处理请求头为text/html的请求发生的异常,而error是除了这个之外的其他异常。

下面是我定义的baseController,error部分返回的结果是空,还需要进一步的研究:

@RestController
@RequestMapping(value = "error")
public class MyBaseErrorController extends BasicErrorController {

    public MyBaseErrorController(ErrorAttributes errorAttributes) {
        super(errorAttributes, new ErrorProperties());
    }

    @Override
    @RequestMapping(produces = {MediaType.ALL_VALUE})
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {

        return new ResponseEntity<Map<String, Object>>(Result.failedResultMap(000, "未知错误"), HttpStatus.OK);
    }

    @RequestMapping(
            produces = {"text/html"}
    )
    public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
        HttpStatus status = this.getStatus(request);
        response.setStatus(status.value());
        return null;
    }

}

最后,对于以上问题我最后的解决方法是继承ErrorController,然后定义errorHtml和error,更重要的是@RequestMapping注解,然后在方法中response写入返回值,这种方式不够优雅🤣:

@RestController
@RequestMapping(value = "error")
public class MyBaseErrorController implements ErrorController {
    private static final String path_default = "/error";

    @Autowired
    private ErrorAttributes errorAttributes;


    @RequestMapping(produces = {MediaType.ALL_VALUE})
    public void error(HttpServletRequest request,  HttpServletResponse response) {
        setJsonError(response);
    }


    @RequestMapping(
            produces = {"text/html"}
    )
    public void errorHtml(HttpServletRequest request, HttpServletResponse response) {
        setJsonError(response);
    }

    @Override
    public String getErrorPath() {
        return path_default;
    }

    private void setJsonError(HttpServletResponse response) {
        PrintWriter writer = null;
        try {
            response.setStatus(200);
            response.setHeader("Content-type", "text/html;charset=UTF-8");
            response.setCharacterEncoding("UTF-8");
            writer = response.getWriter();
            writer.write(JSON.toJSONString(Result.getFailed("未知错误", null)));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }

}

代码可在github获取:https://github.com/Syske/learning-dome-code/tree/master/springboot-learning

posted @ 2020-04-14 21:45  云中志  阅读(398)  评论(0编辑  收藏  举报