1. 程式人生 > >springMvc異常處理定製化

springMvc異常處理定製化

開發十年,就只剩下這套架構體系了! >>>   

1、擴充套件SimpleMappingExceptionResolver來實現springMvc的定製
 

import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

@Service
public class DivExceptionResolver extends SimpleMappingExceptionResolver {

    private static final Logger LOGGER = LoggerFactory.getLogger(DivExceptionResolver.class);
    
    private static final String LOG_INTERVAL = "DIV:EXCEPTION:LOG:INTERVAL";
    
    private static final int INTERVAL = 10;

    @Resource
    private ExceptionMessageUtils exceptionMessageUtils;
    
    @Resource
    private JedisTemplate jedisTemplate;

    @Override
    public ModelAndView doResolveException(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex) {
    
        ErrorResp resp = new ErrorResp();
        resp.setSuccess(false);
        String code = exceptionMessageUtils.findCode(ex);
        String msg = exceptionMessageUtils.findLocaleMessage(code, ex);
        resp.setErrorCode(code);
        resp.setMsg(msg);
        logError(code, msg, ex);
        write(response, resp);
        exceptionCounter.addSystemException(ex.getMessage());
        return null;
    }

    protected void write(HttpServletResponse response, ErrorResp result) {
        PrintWriter out = null;
        try {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("success", result.isSuccess());
            map.put("msg", result.getMsg());
            map.put("errorCode", result.getErrorCode());

            String resStr = Base64.encodeBase64String(JsonUtil.toString(map).getBytes("utf-8"));
            response.setHeader("Access-Control-Allow-Origin", "*");//允許跨域
            response.setHeader("Content-Type","application/json;charset=UTF-8");//指定json
            response.setHeader("Access-Control-Allow-Methods", "*");//支援多方法
            out = response.getWriter();
            IOUtils.write(resStr, out);
        } catch (Exception ex) {
            LOGGER.error("error on exception wrapper output.", ex);
        } finally {
            IOUtils.closeQuietly(out);
        }
    }
    
    /**
     * 記錄日誌 modified by ysma
     */
    protected void logError(String code, String msg, Exception ex){
    	if(ex instanceof ReqRejectException) {
    		//指定型別異常 長時間列印一次日誌
    		String loged = jedisTemplate.get(LOG_INTERVAL);
    		if(loged == null){
    			LOGGER.error("code[{}], message: {} sys has rejected this request", code, msg);
    			jedisTemplate.setex(LOG_INTERVAL, "loged", INTERVAL);
    		}
    	} else {
    		LOGGER.error("code[{}], message: {}", code, msg, ex);
    	}
    }

}

 

2、解析異常,植入code和msg



@Component
public class ExceptionMessageUtils implements ServletContextAware {

    private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionMessageUtils.class);

    private ServletContext servletContext;

    @Override
    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }

    /**
     * 獲取異常碼
     * @return 本地的異常碼
     */
    public String findCode(Throwable throwable) {
        String code;
        if (throwable instanceof BaseException) {
            code = ((BaseException) throwable).getCode();
        } else {
            if (throwable instanceof DataAccessException || throwable instanceof SQLException) {
                code = SysExConstants.SQL_EXCEPTION;
            } else if (throwable instanceof IOException) {
                code = SysExConstants.IO_EXCEPTION;
            } else if (throwable instanceof TspErrorCodeException) {
                code = SysExConstants.TSP_EXECUTE_FALSE;
            } else {
                code = SysExConstants.UNKNOWN_EXCEPTION;
            }
        }
        return code;
    }

    /**
     * 獲取異常對應可讀錯誤文字,中文資源
     * @return 錯誤資訊
     */
    public String findChineseMessage(Throwable throwable) {
        String code = findCode(throwable);
        return findLocaleMessage(code, throwable, Locale.SIMPLIFIED_CHINESE);
    }

    /**
     * 獲取異常對應可讀錯誤文字,自動判斷資源
     * @param code 異常碼
     * @param throwable 異常
     * @return 錯誤資訊
     */
    public String findLocaleMessage(String code, Throwable throwable) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        Locale locale = RequestContextUtils.getLocale(request);
        return findLocaleMessage(code, throwable, locale);
    }

    /**
     * 獲取異常對應可讀錯誤文字
     * @param code 異常碼
     * @param throwable 異常
     * @param locale 原生代碼
     * @return 錯誤資訊
     */
    public String findLocaleMessage(String code, Throwable throwable, Locale locale) {
        Object[] args = null;
        if (throwable instanceof BaseException) {
            if (throwable.getMessage() != null) {
                return throwable.getMessage();
            }
            args = ((BaseException) throwable).getMessageArgs();
        }
        WebApplicationContext webApplicationContext = WebApplicationContextUtils
                .getWebApplicationContext(servletContext);
        return webApplicationContext.getMessage(code, args, throwable.getMessage(), locale);
    }
}

 

3、異常碼基本定義

public class BaseException extends RuntimeException {

    private static final long serialVersionUID = -2755280599112409861L;

    private String code;

    private Object[] messageArgs;

    public BaseException(String code) {
        this.code = code;
    }

    public BaseException(String code, Throwable cause) {
        super(cause);
        this.code = code;
    }

    public BaseException(String code, Object[] messageArgs) {
        this.code = code;
        this.messageArgs = messageArgs;
    }

    public BaseException(String code, String message, Object[] messageArgs) {
        super(message);
        this.code = code;
        this.messageArgs = messageArgs;
    }

    public BaseException(String code, String message, Throwable cause, Object[] messageArgs) {
        super(message, cause);
        this.code = code;
        this.messageArgs = messageArgs;
    }

    public BaseException(String code, Throwable cause, Object[] messageArgs) {
        super(cause);
        this.code = code;
        this.messageArgs = messageArgs;
    }

    public String getCode() {
        return code;
    }

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

    public Object[] getMessageArgs() {
        return messageArgs;
    }

    public void setMessageArgs(Object[] messageArgs) {
        this.messageArgs = messageArgs;
    }
}

 

4、錯誤碼國際化繫結

 <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basename" value="i18n.messages" />
    </bean>

國際話文字設定resource根i18n目錄下

 

5、異常常量控制

public class SysExConstants {

    public static final String TSP_TRANSFORM_OK = "1797100";

    public static final String TSP_TRANSFORM_FAIL = "1797101";

    /**
     * 未捕獲異常
     */
    public static final String UNKNOWN_EXCEPTION = "7100001";

    /**
     * IO異常
     */
    public static final String IO_EXCEPTION = "7100002";

    /**
     * SQL異常
     */
    public static final String SQL_EXCEPTION = "7100003";

    /**
     * solr執行異常
     */
    public static final String SOLR_EXCEPTION = "7100004";


    /**
     * REST 執行出錯
     */
    public static final String REST_CLIENT_ERROR = "7100008";


    /**
     * pebble exception
     */
    public static final String PEBBLE_CLIENT_ERROR = "7200001";

    /**
     * json入參解析異常
     */
    public static final String JSON_PARSE_EXCEPTION = "7100009";


}

 

6、如上springMVC異常