简介
系统中异常包括:编译时异常和运行时异常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