package cn.chnmuseum.party.common.mvc; import cn.chnmuseum.party.common.enums.RESPONSE_CODE_ENUM; import cn.chnmuseum.party.common.enums.RESULT_INFO_ENUM; import com.google.common.base.Splitter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.shiro.authz.UnauthenticatedException; import org.apache.shiro.authz.UnauthorizedException; import org.springframework.beans.ConversionNotSupportedException; import org.springframework.context.support.DefaultMessageSourceResolvable; import org.springframework.dao.DataAccessException; import org.springframework.dao.DuplicateKeyException; import org.springframework.http.converter.HttpMessageConversionException; import org.springframework.http.converter.HttpMessageNotWritableException; import org.springframework.validation.BindException; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; import org.springframework.validation.ObjectError; import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.HttpMediaTypeNotSupportedException; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.multipart.support.MissingServletRequestPartException; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; import java.sql.SQLIntegrityConstraintViolationException; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * 全局异常处理 * * @author Danny Lee * @date 2019/8/1 */ @Slf4j @RestControllerAdvice public class GlobalExceptionAdvisor { /** * 捕获全局异常,处理所有不可知的异常 * * @param exception 异常对象 */ @ExceptionHandler(Exception.class) public Object handleException(Exception exception) { log.error("\r\n ************** 操作出现异常:{}", ExceptionUtils.getStackTrace(exception)); Class<?> eClass = exception.getClass(); cn.chnmuseum.party.common.validator.HttpResult httpResult = new cn.chnmuseum.party.common.validator.HttpResult(); if (eClass.equals(HttpRequestMethodNotSupportedException.class)) { addResCodeToMap(RESPONSE_CODE_ENUM.METHOD_NOT_SUPPORTED, httpResult); } else if (eClass.equals(HttpMediaTypeNotAcceptableException.class)) { addResCodeToMap(RESPONSE_CODE_ENUM.MEDIA_TYPE_NOT_ACCEPT, httpResult); } else if (eClass.equals(HttpMediaTypeNotSupportedException.class)) { addResCodeToMap(RESPONSE_CODE_ENUM.MEDIA_TYPE_NOT_SUPPORTED, httpResult); } else if (eClass.equals(ConversionNotSupportedException.class)) { addResCodeToMap(RESPONSE_CODE_ENUM.SERVER_ERROR, httpResult); } else if (eClass.equals(HttpMessageNotWritableException.class)) { addResCodeToMap(RESPONSE_CODE_ENUM.SERVER_ERROR, httpResult); } else { addResCodeToMap(RESPONSE_CODE_ENUM.SERVER_ERROR, httpResult); } return httpResult; } @ExceptionHandler(BindException.class) @ResponseBody public cn.chnmuseum.party.common.validator.HttpResult handle(BindException ex) { String message = ex.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(" \n ")); // BindingResult bindingResult = ex.getBindingResult(); // StringBuilder errMsg = new StringBuilder(bindingResult.getFieldErrors().size() * 16); // errMsg.append("Invalid request:"); // for (int i = 0; i < bindingResult.getFieldErrors().size(); i++) { // if (i > 0) { // errMsg.append(","); // } // FieldError error = bindingResult.getFieldErrors().get(i); // errMsg.append(error.getField()).append(":").append(error.getDefaultMessage()); // } // String message1 = Splitter.onPattern("\r\n|\n|\r").trimResults().splitToList(ex.getLocalizedMessage()).get(1); // if (message1 != null) { // String substring = message1.substring(message1.indexOf("on field"), message1.indexOf("rejected value")); // if (substring.toUpperCase().contains("REMARKS")) { // return new cn.chnmuseum.party.common.validator.HttpResult("400", "备注字数超过" + message1, ""); // } // } return new cn.chnmuseum.party.common.validator.HttpResult("400", message, ""); } //处理请求参数格式错误 @RequestParam上validate失败后抛出的异常是javax.validation.ConstraintViolationException @ExceptionHandler(ConstraintViolationException.class) @ResponseBody public String constraintViolationExceptionHandler(ConstraintViolationException e) { return e.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining()); } /** * 处理请求参数格式错误 @RequestBody上validate失败后抛出的异常是MethodArgumentNotValidException异常。 * * @param exception 错误信息集合 * @return 错误信息 */ @ExceptionHandler(MethodArgumentNotValidException.class) public cn.chnmuseum.party.common.validator.HttpResult validationBodyException(MethodArgumentNotValidException exception) { BindingResult result = exception.getBindingResult(); String msg = null; if (result.hasErrors()) { List<ObjectError> errors = result.getAllErrors(); for (ObjectError objectError : errors) { FieldError fieldError = (FieldError) objectError; if (fieldError.getDefaultMessage() != null) { log.info("Data check failure : object{" + fieldError.getObjectName() + "},field{" + fieldError.getField() + "},errorMessage{" + fieldError.getDefaultMessage() + "}"); msg = fieldError.getDefaultMessage(); } } } return new cn.chnmuseum.party.common.validator.HttpResult("400", msg); } @ExceptionHandler(DataAccessException.class) public cn.chnmuseum.party.common.validator.HttpResult dataAccessException(DataAccessException exception) { return new cn.chnmuseum.party.common.validator.HttpResult("400", exception.getLocalizedMessage()); } @ExceptionHandler(DuplicateKeyException.class) @ResponseBody public cn.chnmuseum.party.common.validator.HttpResult duplicateKeyException(DuplicateKeyException e) { String localizedMessage = e.getLocalizedMessage(); String message = Splitter.on(System.lineSeparator()).trimResults().splitToList(localizedMessage).get(1); String substring = message.substring(message.indexOf("Exception:")); if (substring.toUpperCase().contains("NAME")) { return new cn.chnmuseum.party.common.validator.HttpResult("400", "名称已存在,请修改名称", ""); } else if (substring.toUpperCase().contains("CODE")) { return new cn.chnmuseum.party.common.validator.HttpResult("400", "编码已存在", ""); } return new cn.chnmuseum.party.common.validator.HttpResult("400", message, ""); } @ExceptionHandler(SQLIntegrityConstraintViolationException.class) @ResponseBody public cn.chnmuseum.party.common.validator.HttpResult sqlIntegrityConstraintViolationException(SQLIntegrityConstraintViolationException e) { String localizedMessage = e.getLocalizedMessage(); String message = Splitter.on(System.lineSeparator()).trimResults().splitToList(localizedMessage).get(1); String substring = message.substring(message.indexOf("Exception:")); if (substring.toUpperCase().contains("NAME")) { return new cn.chnmuseum.party.common.validator.HttpResult("400", "名称已存在,请修改名称", ""); } else if (substring.toUpperCase().contains("CODE")) { return new cn.chnmuseum.party.common.validator.HttpResult("400", "编码已存在", ""); } return new cn.chnmuseum.party.common.validator.HttpResult("400", message, ""); } /** * 参数类型转换错误 * * @param exception 错误 * @return 错误信息 */ @ExceptionHandler(HttpMessageConversionException.class) public cn.chnmuseum.party.common.validator.HttpResult httpMessageConversionException(HttpMessageConversionException exception) { log.error(exception.getCause().getLocalizedMessage()); return new cn.chnmuseum.party.common.validator.HttpResult("400", exception.getCause().getLocalizedMessage()); } /** * 捕获业务异常 * * @param exception 自定义接口异常类 * @return 返回的异常信息map */ @ExceptionHandler(InterfaceException.class) public cn.chnmuseum.party.common.validator.HttpResult handleInterfaceException(InterfaceException exception) { cn.chnmuseum.party.common.validator.HttpResult httpResult = new cn.chnmuseum.party.common.validator.HttpResult(); httpResult.setResultCode(exception.getErrorCode()); httpResult.setMessage(exception.getErrorMsg()); return httpResult; } /** * 捕获Shiro无权限异常 未授权异常 * * @param exception 无权限异常 * @return 返回的异常信息map */ @ExceptionHandler(UnauthorizedException.class) public Object handleUnauthorizedException(UnauthorizedException exception) { cn.chnmuseum.party.common.validator.HttpResult httpResult = new cn.chnmuseum.party.common.validator.HttpResult(); // 无权限 addResCodeToMap(RESPONSE_CODE_ENUM.ACCOUNT_AUTHENTICATION_FAILED, httpResult); return httpResult; } /** * 捕获Shiro无权限异常 未认证异常 * * @param exception 无权限异常 * @return 返回的异常信息map */ @ExceptionHandler(UnauthenticatedException.class) public Object handleUnauthenticatedException(UnauthenticatedException exception) { cn.chnmuseum.party.common.validator.HttpResult httpResult = new cn.chnmuseum.party.common.validator.HttpResult(); // 无权限 addResCodeToMap(RESPONSE_CODE_ENUM.ACCOUNT_AUTHENTICATION_FAILED, httpResult); return httpResult; } @ExceptionHandler(MissingServletRequestPartException.class) public Object handleServletRequestPartException(MissingServletRequestPartException exception) { Map<String, Object> map = new LinkedHashMap<>(); map.put(RESULT_INFO_ENUM.RESULT_CODE.getKey(), "400"); map.put(RESULT_INFO_ENUM.RESULT_MSG.getKey(), "请选择文件后点击上传"); return map; } /** * 添加异常信息到map中 * * @param responseCodeEnum 错误响应编码枚举类对象 * @param httpResult 响应对象 */ private void addResCodeToMap(RESPONSE_CODE_ENUM responseCodeEnum, cn.chnmuseum.party.common.validator.HttpResult httpResult) { httpResult.setResultCode(responseCodeEnum.getResultCode()); httpResult.setMessage(responseCodeEnum.getMessage()); } }