Java生鮮電商平台-異常模塊的設計與架構


Java生鮮電商平台-異常模塊的設計與架構

 

說明:任何一個軟件系統都會出現各式各樣的異常與錯誤,我們需要根據異常的情況進行捕獲與分析,改善自己的代碼,讓其更加的穩定的,快速的運行,那么作為一個

B2B的Java開源生鮮電商平台,我們的異常需要思考以下幾個維度。

 

1. 運行的代碼異常

    說明:代碼在運行的過程中,難免出現各種異常與錯誤,我們采用Log4j進行日志的記錄。

              在分層代碼解耦過程中,我們統一在Controller進行異常的捕獲與日志記錄。

 

相關的運行的代碼異常架構如下:

    /**
     * (商家店鋪)商品信息列表
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/goods/list", method = { RequestMethod.GET})
    public JsonResult goodsList(HttpServletRequest request, HttpServletResponse response) {
        try
        {
            //業務邏輯處理
            return new JsonResult(JsonResultCode.FAILURE, "系統錯誤,請稍后重試","");
        }catch(Exception ex){
            logger.error("[GoodsController][goodsList] exception :",ex);
            return new JsonResult(JsonResultCode.FAILURE, "系統錯誤,請稍后重試","");
        }
    }

說明:由於spring的事物控制在service層,所以service層不抓取異常。所有的異常都在controller進行抓取,而且抓取的是任何的異常

           異常的記錄采用某個類[]某個方法[] exception,這種方式,然后把所有的異常的堆棧信息進行打印出來,方便進行查看與分析,定位等

 

2. 全局異常

     說明:對於有可能出現的全局異常,我們采用Spring的全局異常處理器,進行代碼的統一處理。 

   2.1,對於業務層的異常,我們采用自定義異常進行獲取

  核心代碼如下:

     

/**
 * service異常,業務異常繼續於當前接口
 * 
 */
public class ServiceException extends RuntimeException {

    private static final long serialVersionUID = 4875141928739446984L;

    /**
     * 錯誤碼
     */
    protected String code;

    /**
     * 錯誤信息
     */
    protected String message;

    public ServiceException(String code, String message) {
        super();
        this.code = code;
        this.message = message;
    }

    public ServiceException(String code, String message, Throwable t) {
        super();
        this.code = code;
        this.message = message;
    }

    public ServiceException(String message) {
        super(message);
        this.message = message;
    }

    public ServiceException(String message, Throwable t) {
        super(message, t);
        this.message = message;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public String toString() {
        return "ServiceException [code=" + code + ", message=" + message + "]";
    }

 

   2.2 對於全局的異常,我們采用spring的統一進行處理,只需要在代碼中進行異常的拋出即可

      核心代碼如下:

     

/**
 * 全局異常處理類.對后台直接拋往前台頁面的異常進行封裝處理.
 */
public class ExceptionHandler extends SimpleMappingExceptionResolver {

    private static final Logger logger = LoggerFactory.getLogger(ExceptionHandler.class);

    @Override
    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) {

        ModelAndView mv = super.doResolveException(request, response, handler, ex);

        String url = WebUtils.getPathWithinApplication(request);

        logger.error("controller error.url=" + url, ex);

        /* 使用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");
        
        JsonResult jsonResult=new JsonResult(JsonResultCode.FAILURE,"系統錯誤,請聯系管理員","");
        
        if(ex instanceof ServiceException)
        {
            ServiceException serviceException=(ServiceException)ex;
            String code=serviceException.getCode();
            String message=serviceException.getMessage();
            jsonResult=new JsonResult(code,message,"");
        }
        try 
        {
            PrintWriter printWriter = response.getWriter();
            printWriter.write(JSONObject.fromObject(jsonResult).toString());
            printWriter.flush();
            printWriter.close();
        } catch (IOException e) 
        {
            logger.error("與客戶端通訊異常:" + e.getMessage(), e);
        }
        logger.error("異常:" + ex.getMessage(), ex);
        return mv;
    }
}

 

spring中還需要加上一段這樣的配置:

<!-- 全局異常處理.-->
<bean id="exceptionHandler" class="com.netcai.buyer.exception.ExceptionHandler"/>   

    

 

3. 代碼格式方面

   說明:我們控制所有的請求的接口,都需要返回JsonResult對象,另外,我們規定“200”字符串表示請求成功,非“200”表示失敗

    相關的代碼貼出來,請大家分享:

    

/**
 *  Controller層的 json格式對象
 */
public class JsonResult implements java.io.Serializable {

    private static final long serialVersionUID = 1L;
    
    /**
     * 返回的編碼
     */
    private String code;
    
    /**
     * 返回的信息
     */
    private String message;
    
    /***
     * 返回的對象
     */
    private Object object;

    public JsonResult() {
        super();
    }
    
    public JsonResult(String code, String message, Object object) {
        super();
        this.code = code;
        this.message = message;
        this.object = object;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getObject() {
        return object;
    }

    public void setObject(Object object) {
        this.object = object;
    }
}

 

相關的JsonResultCode對象如下:

/**
 */
public class JsonResultCode {

    /**成功**/
    public static final String SUCCESS="200";

    /**失敗**/
    public static final String FAILURE="201";
}

 

最終形成了一套完整的數據量的處理,另外還有特殊的情況,比如:404,500等等其他的業務請求,我們應該如何處理的?

由於我們是運行在tomcat下面的,我們在web.xml進行了配置。

代碼如下

<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>

我們把可能出現的任何情況都進行了攔截,然后交給spring來處理這種請求,最終形成一套自己的特殊異常處理

代碼如下:

/**
 * 錯誤統一處理
 */
@RestController
public class ErrorController {

    /**
     * 請求異常404
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/error_404", method = { RequestMethod.GET, RequestMethod.POST })
    public JsonResult error_404() throws Exception 
    {
        return new JsonResult(JsonResultCode.FAILURE, "404請求找不到請求", "");
    }
    
    /**
     * 服務器異常
     * @return JsonResult
     */
    @RequestMapping(value = "/error_500", method = { RequestMethod.GET, RequestMethod.POST })
    public JsonResult error_500()
    {    
        return new JsonResult(JsonResultCode.FAILURE, "500服務器內部錯誤", "");
    }
}

 

總結:我們通過3種情況來進行了所有可能異常的處理,全局異常,業務代碼異常,特殊情況異常,架構封裝,統一的數據返回與處理等等,進行了完美的結合,該項目運行一年半以來,采用這種異常架構后,從沒出現過返回給app什么500錯誤或者其他亂七八糟的錯誤,依然是正確的JsonResult對象,APP那邊也不用處理特殊情況,一舉兩得


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM