From e93330b51a3d2fffdbd43d4b8dccc19105802ad8 Mon Sep 17 00:00:00 2001 From: ajaxfan <909938737@qq.com> Date: Thu, 25 Mar 2021 18:59:52 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=B1=9E=E6=80=A7=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=E7=94=9F=E4=BA=A7=E7=8E=AF=E5=A2=83feign=E4=B8=8D?= =?UTF-8?q?=E6=B3=A8=E5=85=A5token?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mall/ebtp/common/config/FeignConfig.java | 7 +- ...usinessExceptionHandlerAdviceDefault.java} | 5 +- .../BusinessExceptionHandlerAdvicePro.java | 293 ++++++++++++++++++ 3 files changed, 301 insertions(+), 4 deletions(-) rename uboot-common/src/main/java/com/chinaunicom/mall/ebtp/common/exception/service/{BusinessExceptionHandlerAdvice.java => BusinessExceptionHandlerAdviceDefault.java} (98%) create mode 100644 uboot-common/src/main/java/com/chinaunicom/mall/ebtp/common/exception/service/BusinessExceptionHandlerAdvicePro.java diff --git a/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/common/config/FeignConfig.java b/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/common/config/FeignConfig.java index 339b704..6ff648c 100644 --- a/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/common/config/FeignConfig.java +++ b/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/common/config/FeignConfig.java @@ -1,15 +1,16 @@ package com.chinaunicom.mall.ebtp.common.config; import static com.chinaunicom.mall.ebtp.cloud.security.starter.common.Constants.AUTHORIZATION_HEADER; +import static com.chinaunicom.mall.ebtp.cloud.security.starter.common.Constants.COOKIE_TOKEN_CODE; import static com.chinaunicom.mall.ebtp.cloud.security.starter.common.Constants.CURRENT_ROLE_CODE; import static com.chinaunicom.mall.ebtp.cloud.security.starter.common.Constants.TOKEN_PREFIX; -import static com.chinaunicom.mall.ebtp.cloud.security.starter.common.Constants.COOKIE_TOKEN_CODE; import java.util.Optional; import java.util.stream.Stream; import org.apache.commons.lang3.RegExUtils; import org.apache.commons.lang3.StringUtils; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Configuration; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; @@ -21,6 +22,7 @@ import feign.RequestTemplate; * 通过拦截器来为header注入token */ @Configuration +@ConditionalOnProperty(name = "ebtp.universal.feign.token.interceptor", havingValue = "true", matchIfMissing = true) public class FeignConfig implements RequestInterceptor { /** @@ -42,7 +44,8 @@ public class FeignConfig implements RequestInterceptor { Optional.ofNullable(attributes.getRequest().getCookies()).ifPresent(cookies -> { Stream.of(cookies).filter(item -> StringUtils.equals(item.getName(), COOKIE_TOKEN_CODE)).findFirst() .ifPresent(token -> { - template.header(AUTHORIZATION_HEADER, String.format("%s%s", TOKEN_PREFIX, token.getValue())); + template.header(AUTHORIZATION_HEADER, + String.format("%s%s", TOKEN_PREFIX, token.getValue())); }); }); } diff --git a/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/common/exception/service/BusinessExceptionHandlerAdvice.java b/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/common/exception/service/BusinessExceptionHandlerAdviceDefault.java similarity index 98% rename from uboot-common/src/main/java/com/chinaunicom/mall/ebtp/common/exception/service/BusinessExceptionHandlerAdvice.java rename to uboot-common/src/main/java/com/chinaunicom/mall/ebtp/common/exception/service/BusinessExceptionHandlerAdviceDefault.java index 1dcdd7e..f87c422 100644 --- a/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/common/exception/service/BusinessExceptionHandlerAdvice.java +++ b/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/common/exception/service/BusinessExceptionHandlerAdviceDefault.java @@ -10,6 +10,7 @@ import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Profile; import org.springframework.dao.DataAccessException; import org.springframework.dao.DuplicateKeyException; import org.springframework.dao.EmptyResultDataAccessException; @@ -34,7 +35,6 @@ import com.chinaunicom.mall.ebtp.common.util.JsonUtils; import cn.hutool.core.convert.Convert; import cn.hutool.core.exceptions.ExceptionUtil; import io.seata.core.context.RootContext; -import io.seata.core.exception.RmTransactionException; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; @@ -51,7 +51,8 @@ import lombok.extern.slf4j.Slf4j; @ControllerAdvice @ResponseBody @ConditionalOnProperty(name = "mconfig.exception-handle-enabled", matchIfMissing = true) -public class BusinessExceptionHandlerAdvice { +@Profile({"test", "local", "uat"}) +public class BusinessExceptionHandlerAdviceDefault { /** * 业务异常处理 diff --git a/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/common/exception/service/BusinessExceptionHandlerAdvicePro.java b/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/common/exception/service/BusinessExceptionHandlerAdvicePro.java new file mode 100644 index 0000000..b62e246 --- /dev/null +++ b/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/common/exception/service/BusinessExceptionHandlerAdvicePro.java @@ -0,0 +1,293 @@ +package com.chinaunicom.mall.ebtp.common.exception.service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Profile; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.http.HttpStatus; +import org.springframework.transaction.TransactionSystemException; +import org.springframework.validation.BindException; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.MissingServletRequestParameterException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; + +import com.chinaunicom.mall.ebtp.common.base.entity.BaseResponse; +import com.chinaunicom.mall.ebtp.common.exception.entity.BusinessException; +import com.chinaunicom.mall.ebtp.common.util.JsonUtils; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.exceptions.ExceptionUtil; +import io.seata.core.context.RootContext; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +/** + * 异常处理 拦截BindException异常,返回HttpStatus是400的绑定错误信息 + * 拦截FrameException异常,返回HttpStatus是406的业务处理错误信息(支持自定义状态码) + * 拦截Exception异常,返回HttpStatus是500服务器内部异常 + * + * @author fqj + * @date 2020年9月3日 11:42:25 + */ +@Slf4j +@ControllerAdvice +@ResponseBody +@Profile({ "pro" }) +@ConditionalOnProperty(name = "mconfig.exception-handle-enabled", matchIfMissing = true) +public class BusinessExceptionHandlerAdvicePro { + + /** + * 业务异常处理 + * + * @param request 请求 + * @param exception ServiceErrorException异常对象 + * @return 响应 + */ + @ExceptionHandler(value = BusinessException.class) + @ResponseStatus(HttpStatus.OK) + public BaseResponse serviceErrorException(HttpServletRequest request, BusinessException exception) { + log.info(ExceptionUtil.stacktraceToString(exception)); + Map body = new HashMap<>(); + return BaseResponse.fail(exception.getCode(), exception.getMessage(), Convert.toStr(body)); + } + + /** + * hibernate valid 验证异常拦截 + * + * @param request 请求 + * @param exception ServiceErrorException异常对象 + * @return 响应 + */ + @ExceptionHandler(value = MethodArgumentNotValidException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public BaseResponse handleInvalidMethodArgException(HttpServletRequest request, + MethodArgumentNotValidException exception) { + // 堆栈信息转为字符串 + log.info(ExceptionUtil.stacktraceToString(exception)); + // 按需重新封装需要返回的错误信息 + List invalidArguments = new ArrayList<>(); + // 解析原错误信息,封装后返回,此处返回非法的字段名称,原始值,错误信息 + BindingResult bindingResult = exception.getBindingResult(); + for (FieldError error : bindingResult.getFieldErrors()) { + ArgumentInvalidResult invalidArgument = new ArgumentInvalidResult(); + invalidArgument.setDefaultMessage(error.getDefaultMessage()); + invalidArgument.setField(error.getField()); + invalidArgument.setRejectedValue(error.getRejectedValue()); + invalidArguments.add(invalidArgument); + } + Map body = new HashMap<>(); + body.put("errors", JsonUtils.objectToJson(invalidArguments)); + body.put("error", HttpStatus.BAD_REQUEST.getReasonPhrase()); + + return BaseResponse.fail(HttpStatus.BAD_REQUEST.value(), "参数验证错误", Convert.toStr(body)); + } + + /** + * 参数绑定异常 + * + * @param request 请求 + * @param exception BindException异常对象 + * @return 响应 + */ + @ExceptionHandler(value = BindException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public BaseResponse methodArgumentNotValidHandler(HttpServletRequest request, BindException exception) { + // 按需重新封装需要返回的错误信息 + List invalidArguments = new ArrayList<>(); + // 解析原错误信息,封装后返回,此处返回非法的字段名称,原始值,错误信息 + for (FieldError error : exception.getBindingResult().getFieldErrors()) { + ArgumentInvalidResult invalidArgument = new ArgumentInvalidResult(); + invalidArgument.setDefaultMessage(error.getDefaultMessage()); + invalidArgument.setField(error.getField()); + invalidArgument.setRejectedValue(error.getRejectedValue()); + invalidArguments.add(invalidArgument); + } + Map body = new HashMap<>(); + body.put("errors", JsonUtils.objectToJson(invalidArguments)); + body.put("error", HttpStatus.BAD_REQUEST.getReasonPhrase()); + + return BaseResponse.fail(HttpStatus.BAD_REQUEST.value(), "参数错误", Convert.toStr(body)); + } + + /** + * 请求方式异常 + * + * @param request 请求 + * @param exception HttpRequestMethodNotSupportedException异常对象 + * @return 响应 + */ + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) + public BaseResponse handleMethodNotSupportedException(HttpServletRequest request, + HttpRequestMethodNotSupportedException exception) { + Map body = new HashMap<>(); + body.put("errors", exception.getMessage()); + body.put("error", HttpStatus.METHOD_NOT_ALLOWED.getReasonPhrase()); + + return BaseResponse.fail(HttpStatus.METHOD_NOT_ALLOWED.value(), "错误的请求方式", Convert.toStr(body)); + } + + /** + * 参数缺失 + * + * @param request 请求 + * @param exception MissingServletRequestParameterException异常对象 + * @return 响应 + */ + @ExceptionHandler(MissingServletRequestParameterException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public BaseResponse handleMissingParameterException(HttpServletRequest request, + MissingServletRequestParameterException exception) { + Map body = new HashMap<>(); + body.put("errors", exception.getMessage()); + body.put("error", HttpStatus.BAD_REQUEST.getReasonPhrase()); + + return BaseResponse.fail(HttpStatus.BAD_REQUEST.value(), "参数缺失" + exception.getMessage(), Convert.toStr(body)); + } + + // ----------------------------data-------------------------------------- + + /** + * 数据库异常 + * + * @param request 请求 + * @param exception DataAccessException异常对象 + * @return 响应 + */ + @ExceptionHandler(DataAccessException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public BaseResponse handlerDataAccessException(HttpServletRequest request, DataAccessException exception) { + log.error(ExceptionUtil.stacktraceToString(exception)); + Map body = new HashMap<>(); + body.put("errors", exception.getMessage()); + body.put("error", HttpStatus.BAD_REQUEST.getReasonPhrase()); + + return BaseResponse.fail(HttpStatus.BAD_REQUEST.value(), "数据库异常" + exception.getMessage(), Convert.toStr(body)); + } + + /** + * 数据不存在 + * + * @param request 请求 + * @param exception EmptyResultDataAccessException异常对象 + * @return 响应 + */ + @ExceptionHandler(EmptyResultDataAccessException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public BaseResponse handleDataEmptyException(HttpServletRequest request, + EmptyResultDataAccessException exception) { + Map body = new HashMap<>(); + body.put("errors", exception.getMessage()); + body.put("error", HttpStatus.BAD_REQUEST.getReasonPhrase()); + + return BaseResponse.fail(HttpStatus.BAD_REQUEST.value(), "数据不存在", Convert.toStr(body)); + } + + /** + * 请求方式异常 + * + * @param request 请求 + * @param exception DuplicateKeyException异常对象 + * @return 响应 + */ + @ExceptionHandler(DuplicateKeyException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public BaseResponse handleDataDualException(HttpServletRequest request, DuplicateKeyException exception) { + Map body = new HashMap<>(); + body.put("errors", exception.getMessage()); + body.put("error", HttpStatus.BAD_REQUEST.getReasonPhrase()); + + return BaseResponse.fail(HttpStatus.BAD_REQUEST.value(), "数据重复插入", Convert.toStr(body)); + } + + /** + * 方法参数类型不匹配异常 + * + * @param request 请求 + * @param exception MethodArgumentTypeMismatchException异常对象 + * @return 响应 + */ + @ExceptionHandler(MethodArgumentTypeMismatchException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public BaseResponse handleMethodArgumentTypeException(HttpServletRequest request, + MethodArgumentTypeMismatchException exception) { + Map body = new HashMap<>(); + body.put("errors", exception.getMessage()); + body.put("error", HttpStatus.BAD_REQUEST.getReasonPhrase()); + + return BaseResponse.fail(HttpStatus.BAD_REQUEST.value(), "参数类型不匹配", Convert.toStr(body)); + } + + /** + * 全局异常处理 + * + * @param request 请求 + * @param exception Exception异常对象 + * @return 响应 + */ + @ExceptionHandler(value = Exception.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public BaseResponse handleException(HttpServletRequest request, Exception exception) { + // 堆栈信息转为字符串 + log.info(ExceptionUtil.stacktraceToString(exception)); + Map body = new HashMap<>(); + body.put("errors", exception.getMessage()); + body.put("error", HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase()); + + return BaseResponse.fail(HttpStatus.INTERNAL_SERVER_ERROR.value(), "系统异常" + exception.getMessage(), + Convert.toStr(body)); + } + + @ExceptionHandler({ TransactionSystemException.class }) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public BaseResponse handleTransactionSystemException(HttpServletRequest request, + TransactionSystemException exception) { + log.info(ExceptionUtil.stacktraceToString(exception)); + if (((String) Objects.requireNonNull(exception.getMessage())).contains("may be has finished")) { + String xid = RootContext.getXID(); + if (StringUtils.isNotEmpty(xid)) { + RootContext.unbind(); + log.debug("TransactionSystemException ----- suspending current transaction,xid = {}", xid); + } + } + return BaseResponse.fail("系统繁忙,请重试", exception.getMessage()); + } + + /** + * 参数异常 + */ + @Getter + @Setter + class ArgumentInvalidResult { + /** + * 字段名 + */ + private String field; + /** + * 输入的错误值 + */ + private Object rejectedValue; + /** + * 错误信息 + */ + private String defaultMessage; + } +} \ No newline at end of file