溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

詳解Spring全局異常處理的三種方式

發(fā)布時間:2020-10-06 10:30:11 來源:腳本之家 閱讀:151 作者:MacSam 欄目:編程語言

在J2EE項(xiàng)目的開發(fā)中,不管是對底層的數(shù)據(jù)庫操作過程,還是業(yè)務(wù)層的處理過程,還是控制層的處理過程,都不可避免會遇到各種可預(yù)知的、不可預(yù)知的異常需要處理。每個過程都單獨(dú)處理異常,系統(tǒng)的代碼耦合度高,工作量大且不好統(tǒng)一,維護(hù)的工作量也很大。 那么,能不能將所有類型的異常處理從各處理過程解耦出來,這樣既保證了相關(guān)處理過程的功能較單一,也實(shí)現(xiàn)了異常信息的統(tǒng)一處理和維護(hù)?答案是肯定的。下面將介紹使用Spring MVC統(tǒng)一處理異常的解決和實(shí)現(xiàn)過程

  • 使用Spring MVC提供的SimpleMappingExceptionResolver
  • 實(shí)現(xiàn)Spring的異常處理接口HandlerExceptionResolver 自定義自己的異常處理器
  • 使用@ExceptionHandler注解實(shí)現(xiàn)異常處理

(一) SimpleMappingExceptionResolver

使用這種方式具有集成簡單、有良好的擴(kuò)展性、對已有代碼沒有入侵性等優(yōu)點(diǎn),但該方法僅能獲取到異常信息,若在出現(xiàn)異常時,對需要獲取除異常以外的數(shù)據(jù)的情況不適用。

@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能準(zhǔn)確顯示定義的異常處理頁面,達(dá)到了統(tǒng)一異常處理的目標(biāo)

1.定義一個類實(shí)現(xiàn)HandlerExceptionResolver接口,這次貼一個自己以前的代碼

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, "業(yè)務(wù)判空異常", 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的配置中,這里只貼出了相關(guān)部分

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

這是筆者現(xiàn)在項(xiàng)目的使用方式,這里也僅貼出了相關(guān)部分

1.首先定義一個父類,實(shí)現(xiàn)一些基礎(chǔ)的方法

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 = "系統(tǒng)忙,請稍后再試"; 

   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.針對你需要捕捉的異常實(shí)現(xiàn)相對應(yīng)的處理方式

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);  
   }

 }

以上就三種處理方式,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI