多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
## 一、页面类异常处理 之前章节给大家讲的都是接口类的异常处理,那我们做页面模板时,Controller发生异常我们该怎么办?应该统一跳转到404页面。 面临的问题: **程序员抛出自定义异常CustomException,全局异常处理截获之后返回@ResponseBody AjaxResponse,不是ModelAndView,所以我们无法跳转到error.html页面,那我们该如何做页面的全局的异常处理?** 答: 1. 用面向切面的方式,将CustomException转换为ModelAndViewException。 2. 全局异常处理器拦截ModelAndViewException,返回ModelAndView,即error.html页面 3. 切入点是带@ModelView注解的Controller层方法 **使用这种方法处理页面类异常,程序员只需要在页面跳转的Controller上加@ModelView注解即可** ### 错误的写法 ~~~ @GetMapping("/freemarker") public String index(Model model) { try{ List<ArticleVO> articles = articleRestService.getAll(); model.addAttribute("articles", articles); }catch (Exception e){ return "error"; } return "fremarkertemp"; } ~~~ ### 正确的写法 ~~~ @ModelView @GetMapping("/freemarker") public String index(Model model) { List<ArticleVO> articles = articleRestService.getAll(); model.addAttribute("articles", articles); return "fremarkertemp"; } ~~~ ## 二 用面向切面的方法处理页面全局异常 因为用到了面向切面编程,所以引入maven依赖包 ~~~ <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> ~~~ 新定义一个异常类ModelViewException ~~~ public class ModelViewException extends RuntimeException{ //异常错误编码 private int code ; //异常信息 private String message; public static ModelViewException transfer(CustomException e) { return new ModelViewException(e.getCode(),e.getMessage()); } private ModelViewException(int code, String message){ this.code = code; this.message = message; } int getCode() { return code; } @Override public String getMessage() { return message; } } ~~~ ModelView 注解,只起到标注的作用 ~~~ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD})//只能在方法上使用此注解 public @interface ModelView { } ~~~ 以@ModelView注解为切入点,面向切面编程,将CustomException转换为ModelViewException抛出。 ~~~ @Aspect @Component @Slf4j public class ModelViewAspect { //设置切入点:这里直接拦截被@ModelView注解的方法 @Pointcut("@annotation(com.kimgao.bootlauch.config.exception.ModelView)") public void pointcut() { } /** * 当有ModelView的注解的方法抛出异常的时候,做如下的处理 */ @AfterThrowing(pointcut="pointcut()",throwing="e") public void afterThrowable(Throwable e) { log.error("切面发生了异常:", e); if(e instanceof CustomException){ throw ModelViewException.transfer((CustomException) e); } } } ~~~ ![](https://img.kancloud.cn/a2/ca/a2caa342467825cfa0c24878e1dc9c52_470x367.png) 全局异常处理器: ![](https://img.kancloud.cn/9f/25/9f2593f1272d325221742626b942a8ef_1825x682.png) ~~~ @ExceptionHandler(ModelViewException.class) public ModelAndView viewExceptionHandler(HttpServletRequest req, ModelViewException e) { ModelAndView modelAndView = new ModelAndView(); //将异常信息设置如modelAndView modelAndView.addObject("exception", e); modelAndView.addObject("url", req.getRequestURL()); modelAndView.setViewName("error"); //返回ModelAndView return modelAndView; } ~~~ ## 三 测试 创建error.html ~~~ <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <!--thymeleaf favicon.ico y --> <link rel="shortcut icon" th:href="@{/favicon.ico}"/> <head lang="en"> <meta charset="UTF-8" /> <title>error页面</title> </head> <body> <h1>error</h1> <div th:text="${exception}"></div> <div th:text="${url}"></div> </body> </html> ~~~ TemplateController中创建一个异常 引入异常service ~~~ @Resource ExceptionService exceptionService; ~~~ 制造一个异常,并返回ModelView ~~~ @ModelView @GetMapping("/thymeleaf") public String index(Model model, HttpSession session) { ... exceptionService.systemBizError(); ... ~~~ ![](https://img.kancloud.cn/70/b2/70b2e8742950801588c90cdc428a7a1e_888x500.png) 启动服务,运行页面 [http://127.0.0.1:8899/kimgao/template/thymeleaf](http://127.0.0.1:8899/kimgao/template/thymeleaf) 异常跳转到的error页面 ![](https://img.kancloud.cn/45/de/45de8bdc8bf923e52a1467a59f99e52c_1435x422.png) ## 四 总结 1. 全都用CustomException抛出异常,不在单独写try catch; 2. 模板、ajax、json混用可以加@ModelView跳转到error页面; 3. 服务端数据校验,需要加@Valid。