全局的异常处理
1,配置异常解析器
SimpleMappingExceptionResolver 或者实现HandlerExceptionResolver接口自动以异常解析器
2,直接用全局的异常处理注解(@ControllerAdvice)
@ExceptionHandler(单用的话只能拦截当前类,配合@ControllerAdvice可以拦截所有的controller)
在异常处理的通知逻辑方法中可以控制遇到异常之后是跳转页面,还是返回json
跳转页面
protected ModelAndView handleViewError(String url, String errorStack, String errorMessage, String viewName) {
ModelAndView mav = new ModelAndView();
mav.addObject("exception", errorStack);
mav.addObject("url", url);
mav.addObject("message", errorMessage);
mav.addObject("timestamp", new Date());
mav.setViewName(viewName);
return mav;
}
返回json
protected ModelAndView handleAjaxError(HttpServletResponse rsp, String errorMessage, HttpStatus status) throws IOException {
rsp.setCharacterEncoding("UTF-8");
rsp.setStatus(status.value());
PrintWriter writer = rsp.getWriter();
writer.write(errorMessage);
writer.flush();
return null;
}
在J2EE项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预知的、不可预知的异常需要处理。每个过程都单独处理异常,系统的代码耦合度高,工作量大且不好统一,维护的工作量也很大。 那么,能不能将所有类型的异常处理从各处理过程解耦出来,这样既保证了相关处理过程的功能较单一,也实现了异常信息的统一处理和维护?答案是肯定的。下面将介绍使用Spring MVC统一处理异常的解决和实现过程
- 使用Spring MVC提供的SimpleMappingExceptionResolver
- 实现Spring的异常处理接口HandlerExceptionResolver 自定义自己的异常处理器
- 使用@ExceptionHandler注解实现异常处理
(一) SimpleMappingExceptionResolver
使用这种方式具有集成简单、有良好的扩展性、对已有代码没有入侵性等优点,但该方法仅能获取到异常信息,若在出现异常时,对需要获取除异常以外的数据的情况不适用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@Configuration
@EnableWebMvc
@ComponentScan
(basePackages = {
"com.balbala.mvc.web"
})
public
class
WebMVCConfig
extends
WebMvcConfigurerAdapter{
@Bean
public
SimpleMappingExceptionResolver simpleMappingExceptionResolver()
{
SimpleMappingExceptionResolver b =
new
SimpleMappingExceptionResolver();
Properties mappings =
new
Properties();
mappings.put(
"org.springframework.web.servlet.PageNotFound"
,
"page-404"
);
mappings.put(
"org.springframework.dao.DataAccessException"
,
"data-access"
);
mappings.put(
"org.springframework.transaction.TransactionException"
,
"transaction-Failure"
);
b.setExceptionMappings(mappings);
return
b;
}
}
|
(二) HandlerExceptionResolver
相比第一种来说,HandlerExceptionResolver能准确显示定义的异常处理页面,达到了统一异常处理的目标
1.定义一个类实现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
54
55
56
57
58
|
package
com.athena.common.handler;
import
com.athena.common.constants.ResponseCode;
import
com.athena.common.exception.AthenaException;
import
com.athena.common.http.RspMsg;
import
org.slf4j.Logger;
import
org.slf4j.LoggerFactory;
import
org.springframework.web.servlet.HandlerExceptionResolver;
import
org.springframework.web.servlet.ModelAndView;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
java.io.IOException;
import
java.io.PrintWriter;
/**
* Created by sam on 15/4/14.
*/
public
class
GlobalHandlerExceptionResolver
implements
HandlerExceptionResolver {
private
static
final
Logger LOG = LoggerFactory.getLogger(GlobalHandlerExceptionResolver.
class
);
/**
* 在这里处理所有得异常信息
*/
@Override
public
ModelAndView resolveException(HttpServletRequest req, HttpServletResponse resp, Object o, Exception ex) {
ex.printStackTrace();
if
(ex
instanceof
AthenaException) {
//AthenaException为一个自定义异常
ex.printStackTrace();
printWrite(ex.toString(), resp);
return
new
ModelAndView();
}
//RspMsg为一个自定义处理异常信息的类
//ResponseCode为一个自定义错误码的接口
RspMsg unknownException =
null
;
if
(ex
instanceof
NullPointerException) {
unknownException =
new
RspMsg(ResponseCode.CODE_UNKNOWN,
"业务判空异常"
,
null
);
}
else
{
unknownException =
new
RspMsg(ResponseCode.CODE_UNKNOWN, ex.getMessage(),
null
); }
printWrite(unknownException.toString(), resp);
return
new
ModelAndView();
}
/**
* 将错误信息添加到response中
*
* @param msg
* @param response
* @throws IOException
*/
public
static
void
printWrite(String msg, HttpServletResponse response) {
try
{
PrintWriter pw = response.getWriter();
pw.write(msg);
pw.flush();
pw.close();
}
catch
(Exception e) {
e.printStackTrace();
}
}
}
|
2.加入spring的配置中,这里只贴出了相关部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import
com.athena.common.handler.GlobalHandlerExceptionResolver;
import
org.springframework.context.annotation.Bean;
import
com.athena.common.handler.GlobalHandlerExceptionResolver;
import
org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* Created by sam on 15/4/14.
*/
public
class
WebSpringMvcConfig
extends
WebMvcConfigurerAdapter {
@Bean
public
GlobalHandlerExceptionResolver globalHandlerExceptionResolver() {
return
new
GlobalHandlerExceptionResolver();
}
}
|
(三)@ExceptionHandler
这是笔者现在项目的使用方式,这里也仅贴出了相关部分
1.首先定义一个父类,实现一些基础的方法
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
54
55
56
|
package
com.balabala.poet.base.spring;
import
com.google.common.base.Throwables;
import
com.raiyee.poet.base.exception.MessageException;
import
com.raiyee.poet.base.utils.Ajax;
import
org.slf4j.Logger;
import
org.slf4j.LoggerFactory;
import
org.springframework.core.annotation.AnnotationUtils;
import
org.springframework.http.HttpStatus;
import
org.springframework.web.bind.annotation.ResponseStatus;
import
org.springframework.web.servlet.ModelAndView;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
java.io.IOException;
import
java.io.PrintWriter;
import
java.util.Date;
public
class
BaseGlobalExceptionHandler {
protected
static
final
Logger logger =
null
;
protected
static
final
String DEFAULT_ERROR_MESSAGE =
"系统忙,请稍后再试"
;
protected
ModelAndView handleError(HttpServletRequest req, HttpServletResponse rsp, Exception e, String viewName, HttpStatus status)
throws
Exception {
if
(AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.
class
) !=
null
)
throw
e;
String errorMsg = e
instanceof
MessageException ? e.getMessage() : DEFAULT_ERROR_MESSAGE;
String errorStack = Throwables.getStackTraceAsString(e);
getLogger().error(
"Request: {} raised {}"
, req.getRequestURI(), errorStack);
if
(Ajax.isAjax(req)) {
return
handleAjaxError(rsp, errorMsg, status);
}
return
handleViewError(req.getRequestURL().toString(), errorStack, errorMsg, viewName);
}
protected
ModelAndView handleViewError(String url, String errorStack, String errorMessage, String viewName) {
ModelAndView mav =
new
ModelAndView();
mav.addObject(
"exception"
, errorStack);
mav.addObject(
"url"
, url);
mav.addObject(
"message"
, errorMessage);
mav.addObject(
"timestamp"
,
new
Date());
mav.setViewName(viewName);
return
mav;
}
protected
ModelAndView handleAjaxError(HttpServletResponse rsp, String errorMessage, HttpStatus status)
throws
IOException {
rsp.setCharacterEncoding(
"UTF-8"
);
rsp.setStatus(status.value());
PrintWriter writer = rsp.getWriter();
writer.write(errorMessage);
writer.flush();
return
null
;
}
public
Logger getLogger() {
return
LoggerFactory.getLogger(BaseGlobalExceptionHandler.
class
);
}
}
|
2.针对你需要捕捉的异常实现相对应的处理方式
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
|
package
com.balabala.poet.base.spring;
import
org.slf4j.Logger;
import
org.slf4j.LoggerFactory;
import
org.springframework.http.HttpStatus;
import
org.springframework.web.bind.annotation.ControllerAdvice;
import
org.springframework.web.bind.annotation.ExceptionHandler;
import
org.springframework.web.bind.annotation.ResponseStatus;
import
org.springframework.web.servlet.ModelAndView;
import
org.springframework.web.servlet.NoHandlerFoundException;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
@ControllerAdvice
public
class
GlobalExceptionHandler
extends
BaseGlobalExceptionHandler {
//比如404的异常就会被这个方法捕获
@ExceptionHandler
(NoHandlerFoundException.
class
)
@ResponseStatus
(HttpStatus.NOT_FOUND)
public
ModelAndView handle404Error(HttpServletRequest req, HttpServletResponse rsp, Exception e)
throws
Exception {
return
handleError(req, rsp, e,
"error-front"
, HttpStatus.NOT_FOUND);
}
//500的异常会被这个方法捕获
@ExceptionHandler
(Exception.
class
)
@ResponseStatus
(HttpStatus.INTERNAL_SERVER_ERROR)
public
ModelAndView handleError(HttpServletRequest req, HttpServletResponse rsp, Exception e)
throws
Exception {
return
handleError(req, rsp, e,
"error-front"
, HttpStatus.INTERNAL_SERVER_ERROR);
}
//TODO 你也可以再写一个方法来捕获你的自定义异常
//TRY NOW!!!
@Override
public
Logger getLogger() {
return
LoggerFactory.getLogger(GlobalExceptionHandler.
class
);
}
}
|
以上就三种处理方式,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。