SpringMVC异常处理
简介
系统中异常包括:编译时异常和运行时异常RuntimeException;
编译异常就是检查异常,需要捕获;运行时异常可以捕获也可以不捕获。
异常处理思路
在springmvc中,异常处理的思路
系统的dao、service、controller出现异常都通过throwsException向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理。springmvc提供全局异常处理器进行统一异常处理。
异常处理结构体系
SpringMVC通过HandlerExceptionResolver处理程序的异常,HandlerExceptionResolver仅有一个接口方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | /* * 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响应状态码配置一个对应页面,比如:
1 2 3 4 | <error-page> <error>404</error> <location>/ static /404.html</location> </error-page> |
示例
在webapp下,创建static文件夹,再创建404.html
404.html
1 2 3 4 5 6 7 8 9 10 | <!DOCTYPE html> <html lang= "en" > <head> <meta charset= "UTF-8" > <title>Title</title> </head> <body> <h1>你来晚了,页面飞走了</h1> </body> </html> |
web.xml中添加404页面
1 2 3 4 | <error-page> <error-code>404</error-code> <location>/ static /404.html</location> </error-page> |
springmvc.xml中添加如下内容,否则会被拦截
1 | <mvc:resources location= "/static/" mapping= "/static/**" /> |
重启tomcat
请求一个不存在的页面
SimpleMappingExceptionResolver
如果希望当指定的异常发生时,把它映射到要显示的错误的网页中,此时用SimpleMappingExceptionResolver进行解析。DispatcherServlet中没有实现SimpleMappingExceptionResolver的Bean,所有需要在springmvc的配置文件中进行配置。
示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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中添加:
1 2 3 4 5 6 7 8 9 10 11 | <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内容为:
1 2 3 4 5 6 7 8 9 10 11 | <%@ 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注解指定处理特定异常的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 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
1 2 3 4 5 6 7 8 9 10 11 | <%@ 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将处理下面两个异常)。
修改控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 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 中了。
修改控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 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" ; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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
欢迎分享:如果您觉得文章对您有帮助,欢迎转载、分享,也可以点击文章右下角【推荐】一下!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?