|
spring3.0開發(fā)d異常處理,如果只有jsp請(qǐng)求能捕獲到異常,是不足夠的, 有時(shí)候AJAX返回json數(shù)據(jù)時(shí)遇到異常。這時(shí)候默認(rèn)的處理方式不能滿足了, 需要自定義的方式支持同步和ajax異步異常處理。
Spring3.0中對(duì)異常的處理方法一共提供了兩種:一種是使用HandlerExceptionResolver接口;一種是在Controller類內(nèi)部使用@ExceptionHandler注解。使用第一種方式可以實(shí)現(xiàn)全局異常控制,并且Spring已經(jīng)提供了一個(gè)默認(rèn)的實(shí)現(xiàn)類SimpleMappingExceptionResolver;使用第二種方式可以在Controller內(nèi)部實(shí)現(xiàn)更個(gè)性化的異常處理方式,靈活性更高。一般來說,項(xiàng)目中只需要采用第一種方式就可以了,每個(gè)人都自己定義異常的展現(xiàn)方式,太過個(gè)性不統(tǒng)一。
以配置文件的方式進(jìn)行異常管理
在配置dispacher-servlet.xml

配置多個(gè)異常處理的地方。
以注解的方式配置異常管理
為了方便閱讀, 把代碼發(fā)全一點(diǎn)
-
@Controller
-
public class ExceptionHandlerController
-
{
-
private final Logger log = LoggerFactory.getLogger(getClass());
-
-
@ExceptionHandler(ManagerSecurityException.class)
-
public ModelAndView handleManagerSecurityException(ManagerSecurityException e,
-
HttpServletResponse response)
-
throws IOException
-
{
-
log.info("Manager exception handler " + e.getMessage());
-
-
response.sendError(HttpServletResponse.SC_FORBIDDEN,
-
e.getMessage());
-
return new ModelAndView("viewName",new HashMap());
-
}
-
}
這樣的配置處理jstl請(qǐng)求jsp沒有問題, 如果是jquery的 $.post的方法請(qǐng)求, 那么如果還是返回 error.jsp ,那在 js的success函數(shù)里則不能很好地輸出顯示。
問題又來了: 如果在 handleManagerSecurityException方法的上面打上注解 @ResponeBody 那么這樣又只能返回 json格式串的異常處理, 你想同步請(qǐng)求跳到到error.jsp又不行啦!
解決辦法是這樣的:定制化異常處理
下面我們來看看CustomSimpleMappingExceptionResolver.java是如何做到支持JSP和JSON格式返回的異常錯(cuò)誤的
-
@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").indexOf("XMLHttpRequest")>-1)){//如果不是異步請(qǐng)求
-
// 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格式返回
-
Map model=new HashMap();
-
if(this.logger.isDebugEnabled()){
-
model.put("debug", true);
-
}//exception
-
model.put(ConfigConstants.RESULT, ex.getMessage());
-
model.put("failure", true);
-
try {
-
response.getWriter().write("有異常啦!");
-
} catch (IOException e) {
-
e.printStackTrace();
-
}
-
return new ModelAndView();
-
}
-
return null;
-
}
-
else {
-
return null;
-
}
-
}
這里判斷 request.getHeader("accept").indexOf("application/json") 是不是異步請(qǐng)求
下面給出同步和異步請(qǐng)求的Header
同步的text/html
=== MimeHeaders ===
host = localhost:8888
user-agent = Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8
accept = text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
accept-language = en,zh;q=0.7,en-gb;q=0.3
accept-encoding = gzip,deflate
accept-charset = ISO-8859-1,utf-8;q=0.7,*;q=0.7
keep-alive = 115
connection = keep-alive
cookie = JSESSIONID=BB7441E4B481FF64A5BCC8E6F596C330
異步的application/json
=== MimeHeaders ===
host = localhost:8888
user-agent = Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8
accept = application/json, text/javascript, */*
accept-language = en,zh;q=0.7,en-gb;q=0.3
accept-encoding = gzip,deflate
accept-charset = ISO-8859-1,utf-8;q=0.7,*;q=0.7
keep-alive = 115
connection = keep-alive
content-type = application/x-www-form-urlencoded
x-requested-with = XMLHttpRequest
referer = http://localhost:8888/auth/auth/dictionary/dictionaryForm.html
cookie = JSESSIONID=A4B59EA87C9B83B71C0D455634746411
請(qǐng)注意
try {
response.getWriter().write("有異常啦!");
} catch (IOException e) {
e.printStackTrace();
}
return new ModelAndView();
關(guān)鍵就在最后這1句 return new ModelAndView();
為什么不寫 return null; 或者 return new ModelAndView('jsonView', model); 呢?
因?yàn)閟pring3的源碼里這樣寫著了
-
protected ModelAndView processHandlerException(HttpServletRequest request,
-
HttpServletResponse response,
-
Object handler,
-
Exception ex) throws Exception {
-
-
// Check registerer HandlerExceptionResolvers...
-
ModelAndView exMv = null;
-
for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
-
exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
-
if (exMv != null) {
-
break;
-
}
-
}
-
if (exMv != null) {
-
if (exMv.isEmpty()) {
-
return null;
-
}
-
if (logger.isDebugEnabled()) {
-
logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv,
-
ex);
-
}
-
WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
-
return exMv;
-
}
-
-
throw ex;
-
}
注意看
if (exMv != null) {
if (exMv.isEmpty()) {
return null;
}
這句和最后一句: throw ex;
如果你寫 respone.getWriter().write("有異常啦"); 你也要 new一個(gè)空的ModelAndView,上面的代碼表明, 如果你 return null; 它就跑出異常 throw ex; 如果沒人接收, 則會(huì)調(diào)用你配置的默認(rèn)異常處理器 或者中斷不做任何輸出。
好了, 這樣可以同時(shí)支持同步和AJAX異步請(qǐng)求異常處理了。
|