基于tiles框架下spring mvc错误页面集成 朱雀 2022-07-14 15:49 130阅读 0赞 网站的异常处理最好是解耦的,并且都放在一个地方集中管理。 比如访问权限不够,跳转到指定页面,比如访问的页面不存在,或者404 500之类的错误。 本文介绍Spring的@ControllerAdvice来对这些异常统一进行处理。 Java代码 ![收藏代码][icon_star.png] 1. **import** java.io.IOException; 2. 3. **import** org.apache.logging.log4j.LogManager; 4. **import** org.apache.logging.log4j.Logger; 5. 6. **import** org.springframework.http.HttpStatus; 7. **import** org.springframework.web.bind.annotation.ControllerAdvice; 8. **import** org.springframework.web.bind.annotation.ExceptionHandler; 9. **import** org.springframework.web.bind.annotation.ResponseStatus; 10. **import** org.springframework.web.bind.annotation.RestController; 11. **import** org.springframework.web.context.request.WebRequest; 12. **import** org.springframework.web.servlet.ModelAndView; 13. **import** org.springframework.web.servlet.NoHandlerFoundException; 14. 15. @ControllerAdvice(annotations = \{RestController.**class**\}) 16. **public** **class** ExceptionReaper \{ 17. 18. **private** **static** **final** Logger logger = LogManager.getLogger(ExceptionReaper.**class**); 19. 20. @ExceptionHandler(value = \{ IOException.**class** , RuntimeException.**class** \}) 21. @ResponseStatus(HttpStatus.INTERNAL\_SERVER\_ERROR) 22. **public** ModelAndView exception(Exception exception, WebRequest request) \{ 23. logger.info("Catch an exception", exception); 24. **return** **new** ModelAndView("error/errorPage"); 25. \} 26. 27. @ExceptionHandler(value = \{ NoHandlerFoundException.**class** \}) 28. @ResponseStatus(HttpStatus.NOT\_FOUND) 29. **public** ModelAndView noMapping(Exception exception, WebRequest request) \{ 30. logger.info("No mapping exception", exception); 31. **return** **new** ModelAndView("error/notFound"); 32. \} 33. 34. \} 网上大部分的异常处理大致分为这么几种 1.web.xml配置对404和500之类的错误进行处理,比如访问不存在页面时跳转到一个静态页面,缺点是必须静态页面而且不太好用 Xml代码 ![收藏代码][icon_star.png] 1. **<****error-page****>** 2. **<****error-code****>**404**</****error-code****>** 3. **<****location****>**/building.jsp**</****location****>** 4. **</****error-page****>** 5. **<****error-page****>** 6. **<****error-code****>**500**</****error-code****>** 7. **<****location****>**/error.jsp**</****location****>** 8. **</****error-page****>** 2.配置exception handler,这样的话每个controller都要配置异常处理,或者在一个super controller里配置异常处理,所有controller继承他,缺点也是显而易见的。 Java代码 ![收藏代码][icon_star.png] 1. @Controller 2. **public** **class** MyController \{ 3. @ExceptionHandler(RuntimeException.**class**) 4. @ResponseBody 5. **public** String runtimeExceptionHandler(RuntimeException runtimeException) \{ 6. logger.error("error", runtimeException); 7. **return** "error"; 8. \} 9. \} 3.在applicationContext里面配置SimpleMappingExceptionResolver Java代码 ![收藏代码][icon_star.png] 1. @Bean 2. **public** SimpleMappingExceptionResolver exceptionResolver() \{ 3. SimpleMappingExceptionResolver exceptionResolver = **new** SimpleMappingExceptionResolver(); 4. Properties exceptionMappings = **new** Properties(); 5. exceptionMappings.put("java.lang.Exception", "error/errorPage"); 6. exceptionMappings.put("java.lang.RuntimeException", "error/errorPage"); 7. exceptionResolver.setExceptionMappings(exceptionMappings); 8. Properties statusCodes = **new** Properties(); 9. statusCodes.put("error/404", "404"); 10. statusCodes.put("error/error", "500"); 11. exceptionResolver.setStatusCodes(statusCodes); 12. **return** exceptionResolver; 13. \} 上面这三种处理方法比较常见,但是我觉得都不如@ControllerAdvice来的方便好用 完全可以把@ExceptionHandler放在@ControllerAdvice统一处理,不用每个controller都配置 Java代码 ![收藏代码][icon_star.png] 1. **import** java.io.IOException; 2. 3. **import** org.apache.logging.log4j.LogManager; 4. **import** org.apache.logging.log4j.Logger; 5. 6. **import** org.springframework.http.HttpStatus; 7. **import** org.springframework.web.bind.annotation.ControllerAdvice; 8. **import** org.springframework.web.bind.annotation.ExceptionHandler; 9. **import** org.springframework.web.bind.annotation.ResponseStatus; 10. **import** org.springframework.web.bind.annotation.RestController; 11. **import** org.springframework.web.context.request.WebRequest; 12. **import** org.springframework.web.servlet.ModelAndView; 13. **import** org.springframework.web.servlet.NoHandlerFoundException; 14. 15. @ControllerAdvice(annotations = \{RestController.**class**\}) 16. **public** **class** ExceptionReaper \{ 17. 18. **private** **static** **final** Logger logger = LogManager.getLogger(ExceptionReaper.**class**); 19. 20. @ExceptionHandler(value = \{ IOException.**class** , RuntimeException.**class** \}) 21. @ResponseStatus(HttpStatus.INTERNAL\_SERVER\_ERROR) 22. **public** ModelAndView exception(Exception exception, WebRequest request) \{ 23. logger.info("Catch an exception", exception); 24. **return** **new** ModelAndView("error/errorPage"); 25. \} 26. 27. @ExceptionHandler(value = \{ NoHandlerFoundException.**class** \}) 28. @ResponseStatus(HttpStatus.NOT\_FOUND) 29. **public** ModelAndView noMapping(Exception exception, WebRequest request) \{ 30. logger.info("No mapping exception", exception); 31. **return** **new** ModelAndView("error/notFound"); 32. \} 33. 34. \} @ControllerAdvice(annotations = \{RestController.class\}) 配置你需要拦截的类, @ControllerAdvice(basePackages = "com.demo") 这也可以 然后下面放@ExceptionHandler作为全局的异常处理 @ResponseStatus(HttpStatus.INTERNAL\_SERVER\_ERROR) 告诉浏览器这是什么错误类型 最后就可以记录日志,根据需求做一些处理,返回对应的ModelAndView跳转到对应的错误页面 需要注意的是,上面这些配置,只能配置你的程序中抛出的错误 1.如果是用户请求了一个不存在的页面,没有对应的@RequestMapping,此时Spring的DispatcherServlet就会处理掉返回404,不会进入任何一个controller 2.还有比如spring security之类的权限管理模块,如果用户的密码正确,但是该账户的权限组没有权限访问当前页面,此时权限模块会有自己的AccessDeniedHandler处理,也不会进入刚才配置的@ControllerAdvice 所以对于2中的情况,一般通过权限管理模块提供的方法去处理异常 比如spring security中 Java代码 ![收藏代码][icon_star.png] 1. @Override 2. **protected** **void** configure(HttpSecurity http) **throws** Exception \{ 3. 4. http 5. .authorizeRequests() 6. .antMatchers("/resources/\*\*") 7. .permitAll() 8. .anyRequest() 9. .authenticated() 10. .and() 11. .exceptionHandling() 12. .accessDeniedPage("/error/accessDenied.html") 13. .and() 14. .formLogin() 15. .loginPage("/login") 16. .permitAll() 17. .and() 18. .logout() 19. .permitAll(); 20. 21. \} 对于1中的情况,我们可以配置Spring在没有对应的@RequestMapping时,不要自行处理,让他抛出一个NoHandlerFoundException的异常,从而让我们配置的@ControllerAdvice进行统一处理 如果是xml风格的配置,可以在DispatcherServlet对应的配置文件中配置 如果是之前介绍的class风格的配置,可以这样配置: Java代码 ![收藏代码][icon_star.png] 1. dispatcherServlet.setThrowExceptionIfNoHandlerFound(**true**);//for NoHandlerFoundException Java代码 ![收藏代码][icon_star.png] 1. **import** javax.servlet.ServletContext; 2. **import** javax.servlet.ServletException; 3. **import** javax.servlet.ServletRegistration; 4. 5. **import** org.springframework.web.WebApplicationInitializer; 6. **import** org.springframework.web.context.ContextLoaderListener; 7. **import** org.springframework.web.context.request.RequestContextListener; 8. **import** org.springframework.web.context.support.AnnotationConfigWebApplicationContext; 9. **import** org.springframework.web.servlet.DispatcherServlet; 10. 11. **public** **class** WebInit **implements** WebApplicationInitializer \{ 12. 13. @Override 14. **public** **void** onStartup(ServletContext container) **throws** ServletException \{ 15. // Create the 'root' Spring application context 16. AnnotationConfigWebApplicationContext rootContext = **new** AnnotationConfigWebApplicationContext(); 17. rootContext.scan("com.demo"); 18. // Manage the lifecycle of the root application context 19. container.addListener(**new** ContextLoaderListener(rootContext)); 20. // Listener that exposes the request to the current thread 21. container.addListener(**new** RequestContextListener()); 22. // Create the dispatcher servlet's Spring application context 23. AnnotationConfigWebApplicationContext dispatcherContext = **new** AnnotationConfigWebApplicationContext(); 24. // Register and map the dispatcher servlet 25. DispatcherServlet dispatcherServlet = **new** DispatcherServlet(dispatcherContext); 26. dispatcherServlet.setThrowExceptionIfNoHandlerFound(**true**);//for NoHandlerFoundException 27. ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", dispatcherServlet); 28. dispatcher.setLoadOnStartup(1); 29. dispatcher.addMapping("/"); 30. \} 31. 32. \} 网站的异常处理基本都能实现了 注意:在处理404时需要在web.xml文件中加入配置文件,否则不能处理 <servlet> <servlet-name>spfood</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>throwExceptionIfNoHandlerFound</param-name> <param-value>true</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> [icon_star.png]: /images/20220709/6adfa51bbe2a42c8abafbfe6e4ef7344.png
还没有评论,来说两句吧...