# 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

  1. POM.xml配置

    1. 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>
    
    1. 插件配置:
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-resources-plugin</artifactId>
            <!--把多环境配置 暴露给maven-->
            <configuration>
                <delimiters>@</delimiters>
                <useDefaultDelimiters>false</useDefaultDelimiters>
            </configuration>
        </plugin>
    </plugins>
    
  2. 配置文件设置:

    spring:
      profiles:
        active: @profileActive@
    
  3. 效果图 效果图

Last Updated: 12/15/2023, 8:18:50 AM