package com.baidu.dsp.common.handler; import java.io.IOException; import java.lang.annotation.Annotation; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.InvalidPropertyException; import org.springframework.beans.TypeMismatchException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.core.convert.ConversionFailedException; import org.springframework.core.convert.TypeDescriptor; import org.springframework.stereotype.Service; import org.springframework.validation.BindException; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver; import com.baidu.dsp.common.constant.ErrorCode; import com.baidu.dsp.common.exception.AccessDeniedException; import com.baidu.dsp.common.exception.DocumentNotFoundException; import com.baidu.dsp.common.exception.FieldException; import com.baidu.dsp.common.exception.base.GlobalExceptionAware; import com.baidu.dsp.common.utils.ParamValidateUtils; import com.baidu.dsp.common.vo.JsonObjectBase; import com.baidu.dsp.common.vo.JsonObjectError; import com.baidu.dsp.common.vo.JsonObjectUtils; import com.github.knightliao.apollo.utils.io.FileUtils; /** * @author liaoqiqi * @version 2013-12-2 */ @Service public class MyExceptionHandler extends SimpleMappingExceptionResolver implements ApplicationContextAware { protected static final Logger LOG = LoggerFactory.getLogger(MyExceptionHandler.class); protected ApplicationContext context; public void setApplicationContext(ApplicationContext arg0) throws BeansException { this.context = arg0; } @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object o, Exception e) { LOG.warn(request.getRequestURI() + " ExceptionHandler FOUND. " + e.toString() + "\t" + e.getCause()); // PathVariable 出错 if (e instanceof TypeMismatchException) { return getParamErrors((TypeMismatchException) e); // Bean 参数无法映射错误 } else if (e instanceof InvalidPropertyException) { return getParamErrors((InvalidPropertyException) e); // @Valid 出错 } else if (e instanceof BindException) { return ParamValidateUtils.getParamErrors((BindException) e); // 业务校验处理 } else if (e instanceof FieldException) { return getParamErrors((FieldException) e); } else if (e instanceof DocumentNotFoundException) { response.setStatus(HttpServletResponse.SC_NOT_FOUND); try { FileUtils.closeWriter(response.getWriter()); } catch (IOException e1) { e1.printStackTrace(); } return null; // 用户没有请求方法的访问权限 } else if (e instanceof AccessDeniedException) { LOG.warn("details: " + ((AccessDeniedException) e).getErrorMessage()); return buildError("auth.access.denied", ErrorCode.ACCESS_NOAUTH_ERROR); } else if (e instanceof HttpRequestMethodNotSupportedException) { return buildError("syserror.httpmethod", ErrorCode.HttpRequestMethodNotSupportedException); } else if (e instanceof MissingServletRequestParameterException) { return buildError("syserror.param.miss", ErrorCode.MissingServletRequestParameterException); } else if (e instanceof GlobalExceptionAware) { LOG.error("details: ", e); GlobalExceptionAware g = (GlobalExceptionAware) e; return buildError(g.getErrorMessage(), g.getErrorCode()); } else { LOG.warn("details: ", e); return buildError("syserror.inner", ErrorCode.GLOBAL_ERROR); } } /** * 参数转换出错 * * @param e * * @return */ private ModelAndView getParamErrors(InvalidPropertyException e) { Map<String, String> errorMap = new HashMap<String, String>(); errorMap.put(e.getPropertyName(), " parameter cannot find"); JsonObjectBase jsonObject = JsonObjectUtils.buildFieldError(errorMap, ErrorCode.TYPE_MIS_MATCH); return JsonObjectUtils.JsonObjectError2ModelView((JsonObjectError) jsonObject); } /** * TypeMismatchException中获取到参数错误类型 * * @param e */ private ModelAndView getParamErrors(TypeMismatchException e) { Throwable t = e.getCause(); if (t instanceof ConversionFailedException) { ConversionFailedException x = (ConversionFailedException) t; TypeDescriptor type = x.getTargetType(); Annotation[] annotations = type != null ? type.getAnnotations() : new Annotation[0]; Map<String, String> errors = new HashMap<String, String>(); for (Annotation a : annotations) { if (a instanceof RequestParam) { errors.put(((RequestParam) a).value(), "parameter type error!"); } } if (errors.size() > 0) { return paramError(errors, ErrorCode.TYPE_MIS_MATCH); } } JsonObjectBase jsonObject = JsonObjectUtils.buildGlobalError("parameter type error!", ErrorCode.TYPE_MIS_MATCH); return JsonObjectUtils.JsonObjectError2ModelView((JsonObjectError) jsonObject); } /** * 业务字段错误校验,参数错误 * * @param fe * * @return */ private ModelAndView getParamErrors(FieldException fe) { if (fe.isGlobal()) { if (fe.getGlobalErrorArgs() == null || fe.getGlobalErrorArgs().length <= 0) { return buildError(fe.getGlobalErrorMsg(), ErrorCode.GLOBAL_ERROR); } else { return buildError(fe.getGlobalErrorMsg(), fe.getGlobalErrorArgs(), ErrorCode.GLOBAL_ERROR); } } else { // 构造error的映射 Map<String, String> errorMap = fe.getMessageErrorMap(); Map<String, Object[]> errorArgs = fe.getMessageErrorArgs(); if (errorMap != null) { if (errorArgs != null) { return paramError(errorMap, errorArgs, ErrorCode.FIELD_ERROR); } return paramError(errorMap, ErrorCode.FIELD_ERROR); } return paramError(new HashMap<String, String>(), ErrorCode.FIELD_ERROR); } } /** * 参数错误 * * @param paramErrors * @param paramErrorArgs * @param errorCode * * @return */ private ModelAndView paramError(Map<String, String> paramErrors, Map<String, Object[]> paramErrorArgs, ErrorCode errorCode) { JsonObjectBase jsonObject = JsonObjectUtils.buildFieldError(paramErrors, paramErrorArgs, errorCode); return JsonObjectUtils.JsonObjectError2ModelView((JsonObjectError) jsonObject); } /** * 参数错误 * * @param paramErrors * @param errorCode * * @return */ private ModelAndView paramError(Map<String, String> paramErrors, ErrorCode errorCode) { JsonObjectBase jsonObject = JsonObjectUtils.buildFieldError(paramErrors, errorCode); LOG.warn(jsonObject.toString()); return JsonObjectUtils.JsonObjectError2ModelView((JsonObjectError) jsonObject); } /** * 全局的错误 * * @param errorMsg * @param errorCode * * @return */ private ModelAndView buildError(String errorMsg, ErrorCode errorCode) { JsonObjectBase jsonObject = JsonObjectUtils.buildGlobalError(errorMsg, errorCode); return JsonObjectUtils.JsonObjectError2ModelView((JsonObjectError) jsonObject); } /** * 全局错误 * * @param errorMsg * @param args * @param errorCode * * @return */ private ModelAndView buildError(String errorMsg, Object[] args, ErrorCode errorCode) { JsonObjectBase jsonObject = JsonObjectUtils.buildGlobalError(errorMsg, errorCode); return JsonObjectUtils.JsonObjectError2ModelView((JsonObjectError) jsonObject); } }