Spring MVC处理异常有3种方式:
(1)使用@ExceptionHandler注解实现异常处理;
(2)使用Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver;
(3)实现Spring的异常处理接口HandlerExceptionResolver 自定义自己的异常处理器;
一、使用@ExceptionHandler进行处理
1.创建异常基类,使用@ExceptionHandler声明异常处理
BusinessException和SystemException为自定义异常类,代码如下:
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
|
package
com.twosnail.exception;
import
javax.servlet.http.HttpServletRequest;
import
org.springframework.stereotype.Controller;
import
org.springframework.web.bind.annotation.ExceptionHandler;
@Controller
public
class
BasicExController {
/**
* 基于@ExceptionHandler异常处理基类
* @return
*/
@ExceptionHandler
public
String exception( HttpServletRequest request , Exception ex ) {
// 根据不同错误转向不同页面
if
( ex
instanceof
BusinessException ) {
return
"business-error"
;
}
else
if
( ex
instanceof
SystemException ) {
return
"system-error"
;
}
else
{
return
"error"
;
}
}
}
|
2、使所有需要异常处理的Controller都继承该类,如下所示:
1
|
public
class
DemoController
extends
BasicExController {}
|
然而,Dao层、Service层、Controller层抛出的异常(BusinessException、SystemException和其它异常)都能准确显示定义的异常处理页面,达到了统一异常处理的目标。
总结:使用@ExceptionHandler注解实现异常处理,具有集成简单、有扩展性好(只需要将要异常处理的Controller类继承于BasicExController即可)、不需要附加Spring配置等优点,但该方法对已有代码存在入侵性(需要修改已有代码,使继承于BasicExController),在异常处理时不能获取除异常以外的数据。
二、SimpleMappingExceptionResolver简单异常处理器
SimpleMappingExceptionResolver有两种配置方式,可以按自己需求而定,配置代码如下:
1、第一种,在Spring的配置文件中,增加以下内容:
在这里,可以设置跳转相应页面。
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
|
<
bean
class
=
"org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"
>
<!-- 定义默认的异常处理页面,当该异常类型的注册时使用 -->
<
property
name
=
"defaultErrorView"
value
=
"error"
></
property
>
<!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception -->
<
property
name
=
"exceptionAttribute"
value
=
"ex"
></
property
>
<!-- 定义需要特殊处理的异常,用类名或完全路径名作为key,异常也页名作为值 -->
<
property
name
=
"exceptionMappings"
>
<
props
>
<
prop
key
=
"com.twosnail.exception.BusinessException"
>business-error</
prop
>
<
prop
key
=
"com.twosnail.exception.SystemException"
>system-error</
prop
>
</
props
>
</
property
>
<!-- 相关状态码对应的错误页面 -->
<
property
name
=
"statusCodes"
>
<
props
>
<
prop
key
=
"errors/500"
>500</
prop
>
<
prop
key
=
"errors/404"
>404</
prop
>
</
props
>
</
property
>
<!-- 设置日志输出级别,不定义则默认不输出警告等错误日志信息 -->
<
property
name
=
"warnLogCategory"
value
=
"WARN"
/>
<!-- 默认HTTP状态码 -->
<
property
name
=
"defaultStatusCode"
value
=
"500"
/>
</
bean
>
|
2、第二种,通过自定义java类,继承SimpleMappingExceptionResolver
然后在Spring的配置。代码如下:
1
2
3
4
5
6
7
8
9
|
<
bean
id
=
"exceptionResolver"
class
=
"com.twosnail.exception.MyselfSimpleMappingExceptionResolver"
>
<
property
name
=
"exceptionMappings"
>
<
props
>
<
prop
key
=
"com.twosnail.exception.SystemException"
>error/500</
prop
>
<
prop
key
=
"com.twosnail.exception.BusinessException"
>error/errorpage</
prop
>
<
prop
key
=
"java.lang.exception"
>error/500</
prop
>
</
props
>
</
property
>
</
bean
>
|
java类代码如下,在这里可以处理相应逻辑,如下,分别处理了jsp页面和json数据:
1
2
3
4
5
6
7
8
9
10
11
1
3
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
|
package
com.twosnail.exception;
import
java.io.IOException;
import
java.io.PrintWriter;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
org.springframework.web.servlet.ModelAndView;
import
org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
public
class
MyselfSimpleMappingExceptionResolver
extends
SimpleMappingExceptionResolver {
@Override
protected
ModelAndView doResolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
// Expose ModelAndView for chosen error view.
String viewName = determineViewName(ex, request);
if
(viewName !=
null
) {
// JSP格式返回
if
(!(request.getHeader(
"accept"
).indexOf(
"application/json"
) > -
1
|| (request
.getHeader(
"X-Requested-With"
) !=
null
&& request
.getHeader(
"X-Requested-With"
).indexOf(
"XMLHttpRequest"
) > -
1
))) {
// 如果不是异步请求
// Apply HTTP status code for error views, if specified.
// Only apply it if we're processing a top-level request.
Integer statusCode = determineStatusCode(request, viewName);
if
(statusCode !=
null
) {
applyStatusCodeIfPossible(request, response, statusCode);
}
return
getModelAndView(viewName, ex, request);
}
else
{
// JSON格式返回
try
{
PrintWriter writer = response.getWriter();
writer.write(ex.getMessage());
writer.flush();
}
catch
(IOException e) {
e.printStackTrace();
}
return
null
;
}
}
else
{
return
null
;
}
}
}
|
总结:使用SimpleMappingExceptionResolver进行异常处理,具有集成简单、有良好的扩展性、对已有代码没有入侵性等优点,但方法1仅能获取到异常信息,若在出现异常时,对需要获取除异常以外的数据的情况不适用。
三、HandlerExceptionResolver自定义异常
1.在Spring的配置文件中,增加以下内容:
1
|
<
bean
id
=
"exceptionHandler"
class
=
"com.twosnail.exception.MyExceptionHandler"
/>
|
2.添加自定义的MyExceptionHandler类,代码如下:
在这里,单独打印出了异常路径,便于在日志中查看,在对SystemException异常进行了特殊处理:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
5
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
54
|
package
com.twosnail.exception;
import
java.util.Map;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
org.springframework.web.servlet.HandlerExceptionResolver;
import
org.springframework.web.servlet.ModelAndView;
import
org.springframework.web.servlet.View;
import
org.springframework.web.servlet.view.RedirectView;
public
class
MyExceptionHandler
implements
HandlerExceptionResolver {
public
ModelAndView resolveException( HttpServletRequest request, HttpServletResponse response,
Object handler, Exception exception ) {
System.out.println(
"【抛出异常】--异常路径为:"
+
request.getServletPath() +
"\n【异常信息】--"
+ exception.getMessage() ) ;
//如果不是抛出的action业务异常则不处理
if
( !( exception
instanceof
SystemException ) ) {
return
null
;
}
final
SystemException actionE = (SystemException) exception;
ModelAndView model =
null
;
if
( actionE.getForwardType() == SystemException.FORWARD ) {
//进入页面渲染
model =
new
ModelAndView( actionE.getModelPath(), actionE.getAttributes());
}
else
if
( actionE.getForwardType() == SystemException.REDIRECT ) {
model =
new
ModelAndView(
new
RedirectView( actionE.getModelPath(),
true
));
}
else
{
//直接返回页面内容
model =
new
ModelAndView(
new
View() {
@Override
public
void
render(Map<String, ?> arg0, HttpServletRequest arg1,
HttpServletResponse arg2)
throws
Exception {
arg2.setContentType(
"text/html"
);
arg2.setCharacterEncoding( actionE.getEncode() );
if
( actionE.getResponseBody() !=
null
) {
arg2.getWriter().print( actionE.getResponseBody() );
}
}
@Override
public
String getContentType() {
return
"text/html; charset=utf-8"
;
}
} );
}
return
model;
}
}
|
总结:从上面的集成过程可知,使用实现HandlerExceptionResolver接口的异常处理器进行异常处理,具有集成简单、有良好的扩展性、对已有代码没有入侵性等优点。在异常处理时能获取导致出现异常的对象,有利于提供更详细的异常处理信息。而SimpleMappingExceptionResolver就是HandlerExceptionResolver的默认实现类