問題:
當前項目是作為手機APP后台支持,使用spring mvc + mybaits + shiro進行開發。后台服務與手機端交互是發送JSON數據。如果后台發生異常,會直接返回異常頁面,顯示異常內容,如果是404請求不到資源或者500這類服務器的問題,可能會導致返回404和500異常頁面,手機端的處理就非常麻煩,為了解決這個問題,就需要做全局的異常處理。
解決方案:
(1)自定義或者使用spring自帶的各種異常處理器
例如spring基於注解的異常解析器AnnotationHandlerMethodExceptionResolver 、spring自帶全局異常處理器SimpleMappingExceptionResolver、自定義實現spring的全局異常解析器HandlerExceptionResolver來處理。
AnnotationHandlerMethodExceptionResolver目前我所知道的是需要在方法上定義異常的類型,如果異常類型多了,寫起代碼太麻煩,所以我認為不好用。(那位大俠知道不用定義異常類型就處理所有異常,可以留言告訴我,謝謝!)
spring自帶全局異常處理器SimpleMappingExceptionResolver也是比較繁瑣的,需要配置的地方太多了,不喜歡用。
自定義實現spring的全局異常解析器HandlerExceptionResolver來處理我認為是最方便的,當然,這個是針對我目前的業務場景而言,並不是絕對的。
由於Java的異常機制,如果發生大量異常,對jvm的性能會產生很大的影響,輕則性能下降10%,重則導致jvm內存溢出,我個人認為能不拋異常就最好不拋,所以,我主要使用自定義實現spring的全局異常解析器HandlerExceptionResolver來處理業務問題。
(2)自定義實現spring的全局異常解析器HandlerExceptionResolver
2.1 只需要在spring-mvc的配置文件中定義一個全局異常處理類
- <!-- 全局異常處理 -->
- <bean id="exceptionHandler" class="com.aaa.bbb.exception.DefaultExceptionHandler" />
2.2 實現HandlerExceptionResolver(第一種實現方式)
這種方式需要下載溫少寫的fastjson,我用的是1.2.6版本,可以百度后自己下載。
- public class DefaultExceptionHandler implements HandlerExceptionResolver {
- private static Logger log = LoggerFactory.getLogger(DefaultExceptionHandler.class);
- public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
- ModelAndView mv = new ModelAndView();
- /* 使用FastJson提供的FastJsonJsonView視圖返回,不需要捕獲異常 */
- FastJsonJsonView view = new FastJsonJsonView();
- Map<String, Object> attributes = new HashMap<String, Object>();
- attributes.put("code", "1000001");
- attributes.put("msg", ex.getMessage());
- view.setAttributesMap(attributes);
- mv.setView(view);
- log.debug("異常:" + ex.getMessage(), ex);
- return mv;
- }
- }
2.2 實現HandlerExceptionResolver(第二種實現方式)
- public class DefaultExceptionHandler implements HandlerExceptionResolver {
- private static Logger log = LoggerFactory.getLogger(DefaultExceptionHandler.class);
- public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
- ModelAndView mv = new ModelAndView();
- /* 使用response返回 */
- response.setStatus(HttpStatus.OK.value()); //設置狀態碼
- response.setContentType(MediaType.APPLICATION_JSON_VALUE); //設置ContentType
- response.setCharacterEncoding("UTF-8"); //避免亂碼
- response.setHeader("Cache-Control", "no-cache, must-revalidate");
- try {
- response.getWriter().write("{\"success\":false,\"msg\":\"" + ex.getMessage() + "\"}");
- } catch (IOException e) {
- log.error("與客戶端通訊異常:"+ e.getMessage(), e);
- }
- log.debug("異常:" + ex.getMessage(), ex);
- return mv;
- }
- }
到此,spring mvc全局異常處理返回json就搞定了,發生異常后,返回的都是json數據,不會再有煩人的異常內容。不過這還不算完整,需要在web.xml中加入異常代碼404或者500的處理才能算完。
(1)web頁面異常處理配置
1.1 <exception-type>java.lang.Throwable</exception-type>表示發生java.lang.Throwable類型的異常,<location>/error_500</location>表示到/error_500地址處理,
例如用戶請求【http://www.a.com/user/login/getUser】 ,應用名稱是user,如果請求發生java.lang.Throwable,那么請求會轉到【http://www.a.com/user/error_500】
1.2 <error-code>404</error-code>表示發生404請求失敗,<location>/error_404</location>表示到/error_404處理,
例如用戶請求【http://www.a.com/user/login/getUser】,應用名稱是user ,如果用戶請求發生404異常,請求資源找不到,那么請求會轉到【http://www.a.com/user/error_404】
- <!-- web異常頁面處理 -->
- <error-page>
- <exception-type>java.lang.Throwable</exception-type>
- <location>/error_500</location>
- </error-page>
- <error-page>
- <exception-type>java.lang.Exception</exception-type>
- <location>/error_404</location>
- </error-page>
- <error-page>
- <error-code>500</error-code>
- <location>/error_500</location>
- </error-page>
- <error-page>
- <error-code>501</error-code>
- <location>/error_500</location>
- </error-page>
- <error-page>
- <error-code>502</error-code>
- <location>/error_500</location>
- </error-page>
- <error-page>
- <error-code>404</error-code>
- <location>/error_404</location>
- </error-page>
- <error-page>
- <error-code>403</error-code>
- <location>/error_404</location>
- </error-page>
- <error-page>
- <error-code>400</error-code>
- <location>/error_404</location>
- </error-page>
(2)后台處理
如果發生以上異常,請求會轉到【http://www.a.com/user/error_404】,那么在后台就需要做相應的處理,處理方式就是在Controller層定義處理異常的方法
- /**
- * 請求異常
- * @return
- * @throws Exception
- * String
- */
- @RequestMapping(value = "/error_404", produces = "text/html;charset=UTF-8")
- @ResponseBody
- public String error_404() throws Exception {
- return "{\"msg\":\"找不到頁面\",\"code\":\"1000001\"}";
- }
- /**
- * 服務器異常
- * @return
- * String
- */
- @RequestMapping(value ="/error_500", produces = "text/html;charset=UTF-8")
- public String error_500() { <pre name="code" class="java"> return "{\"msg\":\"服務器處理失敗\",\"code\":\"1000002\"}";
- }
最后,基本上所有的異常都能被捕獲,能夠出現異常時,友好的提示用戶端,也能避免服務器端拋異常導致的問題。