SpringMVC异常处理
简介
系统中异常包括:编译时异常和运行时异常RuntimeException;
编译异常就是检查异常,需要捕获;运行时异常可以捕获也可以不捕获。
异常处理思路
在springmvc中,异常处理的思路
系统的dao、service、controller出现异常都通过throwsException向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理。springmvc提供全局异常处理器进行统一异常处理。
异常处理结构体系
SpringMVC通过HandlerExceptionResolver处理程序的异常,HandlerExceptionResolver仅有一个接口方法:
/* * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.web.servlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Interface to be implemented by objects that can resolve exceptions thrown during * handler mapping or execution, in the typical case to error views. Implementors are * typically registered as beans in the application context. * * <p>Error views are analogous to JSP error pages but can be used with any kind of * exception including any checked exception, with potentially fine-grained mappings for * specific handlers. * * @author Juergen Hoeller * @since 22.11.2003 */ public interface HandlerExceptionResolver { /** * Try to resolve the given exception that got thrown during handler execution, * returning a {@link ModelAndView} that represents a specific error page if appropriate. * <p>The returned {@code ModelAndView} may be {@linkplain ModelAndView#isEmpty() empty} * to indicate that the exception has been resolved successfully but that no view * should be rendered, for instance by setting a status code. * @param request current HTTP request * @param response current HTTP response * @param handler the executed handler, or {@code null} if none chosen at the * time of the exception (for example, if multipart resolution failed) * @param ex the exception that got thrown during handler execution * @return a corresponding {@code ModelAndView} to forward to, or {@code null} * for default processing */ ModelAndView resolveException( HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex); }
HandlerExceptionResolver拥有几个常见实现类:
异常处理方案
DefaultHandlerExceptionResolver
SpringMVC默认装配了DefaultHandlerExceptionResolver,它会将SpringMVC框架的异常转换为相应的相应状态码。
异常和相应状态码对应表:
在web.xml响应状态码配置一个对应页面,比如:
<error-page> <error>404</error> <location>/static/404.html</location> </error-page>
示例
在webapp下,创建static文件夹,再创建404.html
404.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>你来晚了,页面飞走了</h1> </body> </html>
web.xml中添加404页面
<error-page> <error-code>404</error-code> <location>/static/404.html</location> </error-page>
springmvc.xml中添加如下内容,否则会被拦截
<mvc:resources location="/static/" mapping="/static/**"/>
重启tomcat
请求一个不存在的页面
SimpleMappingExceptionResolver
如果希望当指定的异常发生时,把它映射到要显示的错误的网页中,此时用SimpleMappingExceptionResolver进行解析。DispatcherServlet中没有实现SimpleMappingExceptionResolver的Bean,所有需要在springmvc的配置文件中进行配置。
示例如下:
package com.qzcsbj.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import java.util.Date; @Controller public class ExceptionController { @RequestMapping("/testSimpleMappingExceptionResolver") public String testSimpleMappingExceptionResolver() { String[] values = new String[10]; // 下标越界了 System.out.println(values[11]); return "success"; } }
重启tomcat
访问:http://localhost:8080/testSimpleMappingExceptionResolver
报500错误
处理异常
springmvc.xml中添加:
<mvc:annotation-driven /> <!-- 配置使用SimpleMappingExceptionResolver来映射异常 --> <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!-- 给异常命名一个别名 --> <property name="exceptionAttribute" value="ex"/> <property name="exceptionMappings"> <props> <prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop> </props> </property> </bean>
在/WEB-INF/jsp下新建一个error.jsp视图,error.jsp内容为:
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <html> <head> <title>Title</title> </head> <body> <h1>Error Page</h1> <h1>出现了异常</h1> ${requestScope.ex} </body> </html>
请求:http://localhost:8080/testSimpleMappingExceptionResolver
AnnotationMethodHandlerExceptionResolver
SpringMVC默认注册了AnnotationMethodHandlerExceptionResolver,它允许通过@ExceptionHandler注解指定处理特定异常的方法。
package com.qzcsbj.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @Controller public class ExceptionController2 { @ExceptionHandler(value = { RuntimeException.class }) public ModelAndView handleArithmeticException2(Exception ex) { System.out.println("出异常了:" + ex); ModelAndView mv = new ModelAndView("error"); mv.addObject("exception", ex); return mv; } @ExceptionHandler(value = { ArithmeticException.class }) public ModelAndView handleArithmeticException(Exception ex) { System.out.println("出异常了,算术异常:" + ex); ModelAndView mv = new ModelAndView("error"); mv.addObject("exception", ex); return mv; } @RequestMapping("/testExceptionHandler1") public String test1() { String s=null; System.out.println(s.length()); // 空指针异常 return "success"; } @RequestMapping("/testExceptionHandler2") public String test2() { int i=100/0; // 算数异常 return "success"; } }
error.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> <html> <head> <title>Title</title> </head> <body> <h1>Error Page</h1> <h1>出现了异常</h1> ${requestScope.exception} </body> </html>
请求:http://localhost:8080/testExceptionHandler1
请求:http://localhost:8080/testExceptionHandler2
若将handleArithmeticException方法注释掉,则发生ArithmeticException异常将由handleArithmeticException2进行处理(handleArithmeticException2将处理下面两个异常)。
修改控制器
package com.qzcsbj.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @Controller public class ExceptionController2 { @ExceptionHandler(value = { RuntimeException.class }) public ModelAndView handleArithmeticException2(Exception ex) { System.out.println("出异常了:" + ex); ModelAndView mv = new ModelAndView("error"); mv.addObject("exception", ex); return mv; } // @ExceptionHandler(value = { ArithmeticException.class }) // public ModelAndView handleArithmeticException(Exception ex) { // System.out.println("出异常了,算术异常:" + ex); // ModelAndView mv = new ModelAndView("error"); // mv.addObject("exception", ex); // return mv; // } @RequestMapping("/testExceptionHandler1") public String test1() { String s=null; System.out.println(s.length()); // 空指针异常 return "success"; } @RequestMapping("/testExceptionHandler2") public String test2() { int i=100/0; // 算数异常 return "success"; } }
重启tomcat
请求:http://localhost:8080/testExceptionHandler1
请求:http://localhost:8080/testExceptionHandler2
缺点:
进行异常处理的方法必须与出错的方法在同一个Controller里面。
不能全局控制异常,每个类都要写一遍。
全局异常处理
上文说到@ExceptionHandler需要进行异常处理的方法必须与出错的方法在同一个Controller里面。那么当代码加入了@ControllerAdvice,则不需要必须在同一个controller 中了。
修改控制器
package com.qzcsbj.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @Controller public class ExceptionController2 { // @ExceptionHandler(value = { RuntimeException.class }) // public ModelAndView handleArithmeticException2(Exception ex) // { // System.out.println("出异常了:" + ex); // ModelAndView mv = new ModelAndView("error"); // mv.addObject("exception", ex); // return mv; // } // @ExceptionHandler(value = { ArithmeticException.class }) // public ModelAndView handleArithmeticException(Exception ex) { // System.out.println("出异常了,算术异常:" + ex); // ModelAndView mv = new ModelAndView("error"); // mv.addObject("exception", ex); // return mv; // } @RequestMapping("/testExceptionHandler1") public String test1() { String s=null; System.out.println(s.length()); // 空指针异常 return "success"; } @RequestMapping("/testExceptionHandler2") public String test2() { int i=100/0; // 算数异常 return "success"; } }
package com.qzcsbj.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.servlet.ModelAndView; @ControllerAdvice @Controller public class WebExceptionController { @ExceptionHandler(value = { RuntimeException.class }) public ModelAndView handleRuntimeException2(Exception ex) { System.out.println("【全局异常处理】出异常了: " + ex); ModelAndView mv = new ModelAndView("error"); mv.addObject("exception", ex); return mv; } }
重启tomcat
请求:http://localhost:8080/testExceptionHandler1
请求:http://localhost:8080/testExceptionHandler2
原文会持续更新,原文地址:https://www.cnblogs.com/uncleyong/p/17060269.html
__EOF__
关于博主:擅长性能、全链路、自动化、企业级自动化持续集成(DevTestOps)、测开等
面试必备:项目实战(性能、自动化)、简历笔试,https://www.cnblogs.com/uncleyong/p/15777706.html
测试提升:从测试小白到高级测试修炼之路,https://www.cnblogs.com/uncleyong/p/10530261.html
欢迎分享:如果您觉得文章对您有帮助,欢迎转载、分享,也可以点击文章右下角【推荐】一下!