# 01-实用配置
# 一、验证登录拦截器
import com.dong.common.config.interceptor.TokenInterceptor;
import com.dong.common.properties.CheckTokenProperties;
import com.dong.common.utils.ToolUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.ArrayList;
import java.util.List;
/**
* web配置
*
* @Author qixiaodong
* @Date 2020/8/28 16:58
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private TokenInterceptor tokenInterceptor;
@Autowired
private CheckTokenProperties checkTokenProperties;
@Override
public void addInterceptors(InterceptorRegistry registry) {
List<String> excludeUrls = checkTokenProperties.getExcludeUrls();
if (ToolUtil.isEmpty(excludeUrls)) {
excludeUrls = new ArrayList<>();
}
// 注册拦截器
registry.addInterceptor(tokenInterceptor)
.addPathPatterns("/**")
.excludePathPatterns(excludeUrls);
}
}
token拦截器
import com.dong.common.config.exception.BusinessException;
import com.dong.common.config.thread.TokenThreadLocal;
import com.dong.common.constant.exception.ErrorCode;
import com.dong.common.utils.UserInfoUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Author qixiaodong
* @Date 2020/9/7 12:56
*/
@Slf4j
@Component
public class TokenInterceptor implements HandlerInterceptor {
@Value("${spring.profiles.active}")
private String profilesActive;
@Value("${jwt-assertion}")
String jwtAssertion;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
TokenThreadLocal.setAliToken(jwtAssertion);
if (!(handler instanceof HandlerMethod)) {
return true;
}
boolean checkUser = UserInfoUtil.checkUser(request);
log.info("checkUser 返回: {}", checkUser);
String osName = System.getProperties().getProperty("os.name");
if (!checkUser
&& "Linux".equals(osName)
&& ("test".equalsIgnoreCase(profilesActive)
|| "uat".equalsIgnoreCase(profilesActive)
|| "prod".equalsIgnoreCase(profilesActive))) {
throw new BusinessException(ErrorCode.TOKEN_VERIFICATION_FAILURE);
}
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
UserInfoUtil.delUser();
TokenThreadLocal.delAliToken();
}
}
# 二、跨域配置
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source =
new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig());
return new CorsFilter(source);
}
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
return corsConfiguration;
}
# 三、消息转换器
@Bean
public HttpMessageConverters fastJsonHttpMessageConverters() {
FastJsonHttpMessageConverter messageConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(
//是否输出值为null的字段,默认为false
SerializerFeature.WriteMapNullValue,
//字符类型字段如果为null,输出为”“,而非null
SerializerFeature.WriteNullStringAsEmpty,
//消除对同一对象循环引用的问题,默认为false
SerializerFeature.DisableCircularReferenceDetect,
//Boolean字段如果为null,输出为false,而非null
SerializerFeature.WriteNullBooleanAsFalse,
//数值字段如果为null,输出为0,而非null
SerializerFeature.WriteNullNumberAsZero,
//Enum输出name()或者original,默认为false
SerializerFeature.WriteEnumUsingToString,
//List字段如果为null,输出为[],而非null
SerializerFeature.WriteNullListAsEmpty,
//结果是否格式化,默认为false
SerializerFeature.PrettyFormat,
//按字段名称排序后输出。默认为false
SerializerFeature.SortField
);
fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
//避免以map结构返回结果时,value为null的情况
fastJsonConfig.setSerializeFilters((ValueFilter) (o, s, o1) -> {
if (null == o1) {
o1 = "";
}
return o1;
});
//Long类型转json精度损失问题
SerializeConfig serializeConfig = fastJsonConfig.getSerializeConfig();
serializeConfig.put(BigInteger.class, ToStringSerializer.instance);
serializeConfig.put(Long.class, ToStringSerializer.instance);
serializeConfig.put(Long.TYPE, ToStringSerializer.instance);
fastJsonConfig.setSerializeConfig(serializeConfig);
messageConverter.setFastJsonConfig(fastJsonConfig);
List<MediaType> fastMediaTypes = new ArrayList<>();
//MediaType.APPLICATION_JSON_UTF8 标记为过时,
//官方解释:主流浏览器如谷歌符合正常规范,不需要设置字符编码
fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
messageConverter.setSupportedMediaTypes(fastMediaTypes);
return new HttpMessageConverters(messageConverter);
}
# 四、接口访问日志
import com.alibaba.fastjson.JSONObject;
import com.dong.common.properties.ApiLoggerProperties;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.entity.ContentType;
import org.apache.logging.log4j.util.Strings;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
/**
* 切面 记录api调用情况
*/
@Slf4j
@Aspect
@Component
public class ApiLogger {
@Autowired
private ApiLoggerProperties apiLoggerProperties;
/**
* 定义命名的切点:所有控制层@Controller标注类的 public方法 该方法仅供@Pointcut注解依附
*/
@Pointcut("execution(public * com.dong..controller..*.*(..))")
public void pointcut() {
}
@Around("pointcut()")
public Object successCallLogger(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
HttpServletRequest request =
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String requestURI = request.getRequestURI();
List<String> excludeUrls = apiLoggerProperties.getExcludeUrls();
if (null != excludeUrls && !excludeUrls.isEmpty()) {
AntPathMatcher antPathMatcher = new AntPathMatcher();
for (String excludeUrl : excludeUrls) {
if (antPathMatcher.match(excludeUrl,requestURI)) {
return proceedingJoinPoint.proceed();
}
}
}
String method = request.getMethod();
String param = request.getQueryString();
String contentType = request.getContentType();
if (Strings.isBlank(param)) {
param = "";
if ((Strings.isNotBlank(contentType) && contentType.contains(ContentType.APPLICATION_JSON.getMimeType()))) {
Object[] args = proceedingJoinPoint.getArgs();
if (null != args) {
List<Object> objects = Arrays.asList(args);
Iterator<Object> iterator = objects.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
if (!(next instanceof HttpServletRequest)) {
param += JSONObject.toJSONString(next);
if (iterator.hasNext()) {
param += ",";
}
}
}
}
}
}
Signature signature = proceedingJoinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Object target = proceedingJoinPoint.getTarget();
Method currentMethod = target.getClass().getMethod(methodSignature.getName(),
methodSignature.getParameterTypes());
String name = "";
ApiOperation apiOperation = currentMethod.getAnnotation(ApiOperation.class);
if (null != apiOperation) {
name = apiOperation.value() + ":";
}
if (Strings.isBlank(name)) {
if (HttpMethod.GET.name().equalsIgnoreCase(method)) {
GetMapping mapping = currentMethod.getAnnotation(GetMapping.class);
if (null != mapping && Strings.isNotBlank(mapping.name())) {
name = mapping.name() + ":";
}
}
if (HttpMethod.POST.name().equalsIgnoreCase(method)) {
PostMapping mapping = currentMethod.getAnnotation(PostMapping.class);
if (null != mapping && Strings.isNotBlank(mapping.name())) {
name = mapping.name() + ":";
}
}
if (HttpMethod.PUT.name().equalsIgnoreCase(method)) {
PutMapping mapping = currentMethod.getAnnotation(PutMapping.class);
if (null != mapping && Strings.isNotBlank(mapping.name())) {
name = mapping.name() + ":";
}
}
if (HttpMethod.DELETE.name().equalsIgnoreCase(method)) {
DeleteMapping mapping = currentMethod.getAnnotation(DeleteMapping.class);
if (null != mapping && Strings.isNotBlank(mapping.name())) {
name = mapping.name() + ":";
}
}
if (Strings.isBlank(name)) {
RequestMapping mapping = currentMethod.getAnnotation(RequestMapping.class);
if (null != mapping && Strings.isNotBlank(mapping.name())) {
name = mapping.name() + ":";
}
}
}
String className = currentMethod.getDeclaringClass().getName();
name = name + className.substring(className.lastIndexOf(".") + 1);
StopWatch watch = new StopWatch();
watch.start();
try {
Object proceed = proceedingJoinPoint.proceed();
String result = JSONObject.toJSONString(proceed);
if (watch.isRunning()) {
watch.stop();
}
double timeSeconds = watch.getLastTaskInfo().getTimeSeconds();
log.info("{},执行结果:{},执行时间:{}秒,请求路径:{},{} 参数:{},响应结果:{}", name, true, timeSeconds, requestURI, method,
param, result);
return proceed;
} catch (Throwable throwable) {
if (watch.isRunning()) {
watch.stop();
}
double timeSeconds = watch.getLastTaskInfo().getTimeSeconds();
log.error("{},执行结果:{},执行时间:{}秒,请求路径:{},{} 参数:{},异常信息:{}", name, false, timeSeconds, requestURI, method,
param, throwable.getMessage(), throwable);
throw throwable;
}
}
}
# 五、全局异常处理器
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.feihe.common.constant.exception.ErrorCode;
import com.feihe.common.utils.ToolUtil;
import com.netflix.hystrix.exception.HystrixRuntimeException;
import com.netflix.hystrix.exception.HystrixTimeoutException;
import feign.FeignException;
import io.lettuce.core.RedisCommandTimeoutException;
import io.lettuce.core.RedisException;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.connector.ClientAbortException;
import org.apache.ibatis.transaction.TransactionException;
import org.codehaus.groovy.runtime.typehandling.GroovyCastException;
import org.mybatis.spring.MyBatisSystemException;
import org.redisson.client.WriteRedisConnectionException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.RecoverableDataAccessException;
import org.springframework.dao.TransientDataAccessResourceException;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.transaction.TransactionSystemException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MultipartException;
import java.io.EOFException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.StreamCorruptedException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.nio.channels.ClosedChannelException;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
/**
* 全局异常处理器
*
* @Author qixiaodong
* @Date 2020/9/7 9:26
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@Value("${spring.cloud.client.ip-address:unknownIp}")
String localIp;
@Value("${spring.profiles.active}")
String profilesActive;
/**
* 业务异常-全局处理
*/
@ExceptionHandler({BusinessException.class})
@ResponseStatus(HttpStatus.OK)
public Object handleException(BusinessException exception) {
return buildResult(exception);
}
/**
* 未知异常
*/
@ExceptionHandler({Exception.class})
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(Exception exception) {
return buildResult(exception, ErrorCode.UNKNOWN_EXCEPTION);
}
/**
* sentinel
* AuthorityException 黑白名单控制
*/
@ExceptionHandler({AuthorityException.class})
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(AuthorityException exception) {
return buildResult(exception, ErrorCode.NO_OPERATIONAL_PERMISSION, "您已被列入黑名单");
}
/**
* sentinel
* DegradeException 熔断降级
*/
@ExceptionHandler({DegradeException.class})
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(DegradeException exception) {
return buildResult(exception, ErrorCode.SYSTEM_EXCEPTION, "服务不可用");
}
/**
* sentinel
* FlowException 流量控制
*/
@ExceptionHandler({FlowException.class})
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(FlowException exception) {
return buildResult(exception, ErrorCode.SYSTEM_EXCEPTION, "系统繁忙...");
}
/**
* sentinel
* ParamFlowException 热点参数限流
*/
@ExceptionHandler({ParamFlowException.class})
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(ParamFlowException exception) {
return buildResult(exception, ErrorCode.SYSTEM_EXCEPTION, "系统繁忙...");
}
/**
* sentinel
* SystemBlockException 系统自适应限流
*/
@ExceptionHandler({SystemBlockException.class})
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(SystemBlockException exception) {
return buildResult(exception, ErrorCode.SYSTEM_EXCEPTION, "系统繁忙...");
}
/**
* 空指针
*/
@ExceptionHandler(NullPointerException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(NullPointerException exception) {
return buildResult(exception, null, "空指针异常");
}
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(HttpRequestMethodNotSupportedException exception) {
return buildResult(exception, null, "请求方式不支持");
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(MethodArgumentNotValidException exception) {
List<ObjectError> allErrors = exception.getBindingResult().getAllErrors();
StringBuilder message = new StringBuilder("参数错误:");
Iterator<ObjectError> iterator = allErrors.iterator();
while (iterator.hasNext()) {
ObjectError next = iterator.next();
message.append(next.getDefaultMessage());
if (iterator.hasNext()) {
message.append(",");
}
}
return buildResult(exception, ErrorCode.PARAM_IS_FAILURE, message.toString());
}
@ExceptionHandler({ConnectException.class})
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(ConnectException exception) {
return buildResult(exception, ErrorCode.NETWORK_ERROR, "网络连接超时");
}
@ExceptionHandler({RedisException.class})
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(RedisException exception) {
return buildResult(exception, null, "Redis服务异常");
}
@ExceptionHandler({RedisConnectionFailureException.class})
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(RedisConnectionFailureException exception) {
return buildResult(exception, null, "Redis服务异常");
}
@ExceptionHandler({RedisCommandTimeoutException.class})
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(RedisCommandTimeoutException exception) {
return buildResult(exception, null, "Redis链接异常");
}
@ExceptionHandler({SocketTimeoutException.class})
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(SocketTimeoutException exception) {
return buildResult(exception, null, "连接超时异常");
}
@ExceptionHandler({HystrixTimeoutException.class})
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(HystrixTimeoutException exception) {
return buildResult(exception, null, "熔断器超时异常");
}
/**
* 熔断器异常
*/
@ExceptionHandler(HystrixRuntimeException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(HystrixRuntimeException exception) {
return buildResult(exception, null, "熔断器异常");
}
/**
* 无权访问该资源异常
*/
@ExceptionHandler(UndeclaredThrowableException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(UndeclaredThrowableException exception) {
return buildResult(exception, null, "无权访问该资源异常");
}
/**
* 未知的反射异常
*/
@ExceptionHandler(ReflectiveOperationException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(ReflectiveOperationException exception) {
return buildResult(exception, null, "未知的反射异常");
}
/**
* 反射异常
*/
@ExceptionHandler(InvocationTargetException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(InvocationTargetException exception) {
return buildResult(exception, null, "反射异常");
}
/**
* 拦截sql运行时异常,处理sql注入
*/
@ExceptionHandler(SQLException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(SQLException exception) {
return buildResult(exception, null, "sql异常");
}
/**
* sql语法错误
*/
@ExceptionHandler(BadSqlGrammarException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(BadSqlGrammarException exception) {
return buildResult(exception, null, "sql语法错误");
}
/**
* MySql连接异常
*/
@ExceptionHandler(RecoverableDataAccessException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(RecoverableDataAccessException exception) {
return buildResult(exception, null, "MySql连接异常");
}
/**
* 数据库事务异常
*/
@ExceptionHandler(TransactionException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(TransactionException exception) {
return buildResult(exception, null, "数据库事务异常");
}
/**
* 数据库查询错误
*/
@ExceptionHandler(MybatisPlusException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(MybatisPlusException exception) {
return buildResult(exception, null, "数据库查询错误");
}
/**
* 数学计算错误
*/
@ExceptionHandler(ArithmeticException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(ArithmeticException exception) {
return buildResult(exception, null, "数学计算错误");
}
/**
* 数组索引越界
*/
@ExceptionHandler(ArrayIndexOutOfBoundsException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(ArrayIndexOutOfBoundsException exception) {
return buildResult(exception, null, "数组索引越界");
}
/**
* 类加载异常
*/
@ExceptionHandler(ClassNotFoundException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(ClassNotFoundException exception) {
return buildResult(exception, null, "类加载异常");
}
/**
* 方法参数异常
*/
@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(IllegalArgumentException exception) {
return buildResult(exception, null, "方法参数异常");
}
/**
* 对象强制类型转换异常
*/
@ExceptionHandler(ClassCastException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(ClassCastException exception) {
return buildResult(exception, null, "对象强制类型转换异常");
}
/**
* 数据格式转换异常
*/
@ExceptionHandler(NumberFormatException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(NumberFormatException exception) {
return buildResult(exception, null, "数据格式转换异常");
}
/**
* 未知的IO异常
*/
@ExceptionHandler(IOException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(IOException exception) {
return buildResult(exception, null, "未知的IO异常");
}
/**
* 方法未找到异常
*/
@ExceptionHandler(NoSuchMethodException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(NoSuchMethodException exception) {
return buildResult(exception, null, "方法未找到异常");
}
/**
* 文件结束异常
*/
@ExceptionHandler(EOFException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(EOFException exception) {
return buildResult(exception, null, "文件结束异常");
}
/**
* 文件未找到异常
*/
@ExceptionHandler(FileNotFoundException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(FileNotFoundException exception) {
return buildResult(exception, null, "文件未找到异常");
}
/**
* 类库访问异常
*/
@ExceptionHandler(IllegalAccessException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(IllegalAccessException exception) {
return buildResult(exception, null, "类库访问异常");
}
/**
* 数组负下标异常
*/
@ExceptionHandler(NegativeArraySizeException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(NegativeArraySizeException exception) {
return buildResult(exception, null, "数组负下标异常");
}
/**
* 数组存储异常
*/
@ExceptionHandler(ArrayStoreException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(ArrayStoreException exception) {
return buildResult(exception, null, "数组存储异常");
}
/**
* 克隆方法不支持
*/
@ExceptionHandler(CloneNotSupportedException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(CloneNotSupportedException exception) {
return buildResult(exception, null, "克隆方法不支持");
}
/**
* 枚举常量不存在异常
*/
@ExceptionHandler(EnumConstantNotPresentException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(EnumConstantNotPresentException exception) {
return buildResult(exception, null, "枚举常量不存在异常");
}
/**
* 违法的线程状态异常
*/
@ExceptionHandler(IllegalThreadStateException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(IllegalThreadStateException exception) {
return buildResult(exception, null, "违法的线程状态异常");
}
/**
* 违法的状态异常
*/
@ExceptionHandler(IllegalMonitorStateException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(IllegalMonitorStateException exception) {
return buildResult(exception, null, "违法的状态异常");
}
/**
* 实例化异常
*/
@ExceptionHandler(InstantiationException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(InstantiationException exception) {
return buildResult(exception, null, "实例化异常");
}
/**
* 异常中断
*/
@ExceptionHandler(InterruptedException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(InterruptedException exception) {
return buildResult(exception, null, "异常中断");
}
/**
* 属性不存在异常
*/
@ExceptionHandler(NoSuchFieldException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(NoSuchFieldException exception) {
return buildResult(exception, null, "属性不存在异常");
}
/**
* 字符串索引越界异常
*/
@ExceptionHandler(StringIndexOutOfBoundsException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(StringIndexOutOfBoundsException exception) {
return buildResult(exception, null, "字符串索引越界异常");
}
/**
* 类型不存在异常
*/
@ExceptionHandler(TypeNotPresentException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(TypeNotPresentException exception) {
return buildResult(exception, null, "类型不存在异常");
}
@ExceptionHandler(HttpMessageConversionException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(HttpMessageConversionException exception) {
return buildResult(exception, null, "Http数据解析错误");
}
/**
* JSON转换异常
*/
@ExceptionHandler(JSONException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(JSONException exception) {
return buildResult(exception, null, "JSON转换异常");
}
/**
* 浏览器意外关闭
*/
@ExceptionHandler(ClientAbortException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(ClientAbortException exception) {
return buildResult(exception, null, "浏览器意外关闭");
}
/**
* 上传文件超过最大限制
*/
@ExceptionHandler(MultipartException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(MultipartException exception) {
return buildResult(exception, null, "文件上传异常");
}
/**
* 数据完整性异常
*/
@ExceptionHandler(DataIntegrityViolationException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(DataIntegrityViolationException exception) {
return buildResult(exception, null, "数据库数据完整性异常");
}
/**
* 客户端响应已结束无法继续向其输出内容
*/
@ExceptionHandler(IllegalStateException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(IllegalStateException exception) {
return buildResult(exception, null, "客户端响应已结束无法继续向其输出内容");
}
/**
* 事务无法回滚异常,操作连接已关闭
*/
@ExceptionHandler(TransactionSystemException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(TransactionSystemException exception) {
return buildResult(exception, null, "事务无法回滚异常,操作连接已关闭");
}
/**
* 数据库查询参数错误
*/
@ExceptionHandler(MyBatisSystemException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(MyBatisSystemException exception) {
return buildResult(exception, null, "数据库查询参数错误");
}
/**
* Groovy数据赋值错误
*/
@ExceptionHandler(GroovyCastException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(GroovyCastException exception) {
return buildResult(exception, null, "Groovy数据赋值错误");
}
/**
* Feign调用异常
*/
@ExceptionHandler(FeignException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(FeignException exception) {
return buildResult(exception, null, "Feign调用异常");
}
/**
* 数据库字段类型错误
*/
@ExceptionHandler(TransientDataAccessResourceException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(TransientDataAccessResourceException exception) {
return buildResult(exception, null, "数据库字段类型错误");
}
@ExceptionHandler(WriteRedisConnectionException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(WriteRedisConnectionException exception) {
return buildResult(exception, null, "redis连接异常");
}
@ExceptionHandler(ClosedChannelException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(ClosedChannelException exception) {
return buildResult(exception, null, "网络故障");
}
/**
* 数据流意外中断异常
*/
@ExceptionHandler(StreamCorruptedException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Object handleException(StreamCorruptedException exception) {
return buildResult(exception, null, "数据流意外中断异常");
}
/**
* 设置堆栈信息
*/
private JSONObject buildResult(Exception exception) {
return this.buildResult(exception, null);
}
private JSONObject buildResult(Exception exception, ErrorCode errorCode) {
return this.buildResult(exception, errorCode, null);
}
private JSONObject buildResult(Exception exception, ErrorCode errorCode, String msg) {
log.error("捕获全局异常:"+exception.getMessage(), exception);
JSONObject result = new JSONObject();
if (exception instanceof BusinessException) {
BusinessException businessException = (BusinessException) exception;
result.put("code", businessException.getCode());
result.put("message", businessException.getMessage());
} else {
if (ToolUtil.isEmpty(errorCode)) {
errorCode = ErrorCode.UNKNOWN_EXCEPTION;
}
}
if (ToolUtil.isNotEmpty(errorCode)) {
result.put("code", errorCode.code());
result.put("message", errorCode.msg());
}
if (ToolUtil.isNotEmpty(msg)) {
result.put("message", msg);
}
StackTraceElement[] traceArr = exception.getStackTrace();
if (ToolUtil.isNotEmpty(traceArr)) {
StringBuilder trace = new StringBuilder();
trace.append(exception.getClass().getName()).append(':')
.append(exception.getMessage()).append('\n');
trace.append(traceArr[0].toString());
result.put("stackTrace", ("prod".equalsIgnoreCase(profilesActive)?"":localIp+":")+trace.toString());
}
return result;
}
}
# 六、多环境暴露给maven
POM.xml配置
- profiles配置:
<profiles> <!--除了dev、test 还可以再添加多个配置--> <profile> <id>dev</id> <!--设置默认为dev环境--> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <profileActive>dev</profileActive> </properties> </profile> <profile> <id>test</id> <properties> <profileActive>test</profileActive> </properties> </profile> </profiles>
- 插件配置:
<plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <!--把多环境配置 暴露给maven--> <configuration> <delimiters>@</delimiters> <useDefaultDelimiters>false</useDefaultDelimiters> </configuration> </plugin> </plugins>
配置文件设置:
spring: profiles: active: @profileActive@
效果图