Spring Filter+Advice实现统一响应以及全局异常处理

全局统一结构处理

全局统一处理分为异常的处理和结果的统一包装,filter 过滤器用于在 filter 在执行时出现的错误然后进行统一的包装结果;Advice 切面增强则是在接口调用时对返回值或者异常进行处理;
如果集成了swagger,那么需要在Filter中释放掉

path:
    ignores: #忽略的请求路径
      - "/swagger-ui.html/**"
      - "/v2/**"
      - "/swagger-resources/**"
      - "/webjars/**"
@AllArgsConstructor
public class UnifiedResultFilter extends OncePerRequestFilter {

    /** 将需要忽略的路径配置到yml文件中通过自动注入的方式进行获取 */
    private final ApplicationProperties applicationProperties;

    /** ant风格表达式匹配器 */
    private final AntPathMatcher matcher = new AntPathMatcher();

    /**
     * Do filter internal
     *
     * @param httpServletRequest  http servlet request
     * @param httpServletResponse http servlet response
     * @param filterChain         filter chain
     * @throws ServletException servlet exception
     * @throws IOException      io exception
     * @since 1.0.0
     */
    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                                    FilterChain filterChain) throws ServletException, IOException {
        ContentCachingResponseWrapper contentCachingResponseWrapper = new ContentCachingResponseWrapper(httpServletResponse);
        try {
            filterChain.doFilter(httpServletRequest, contentCachingResponseWrapper);
        } catch (Exception e) {
            wrapResponse(contentCachingResponseWrapper, e);
        }
        //刷新缓存数据,写入到真实的response中
        contentCachingResponseWrapper.copyBodyToResponse();
    }

    /**
     * Wrap response
     *
     * @param contentCachingResponseWrapper content caching response wrapper
     * @throws IOException io exception
     * @since 1.0.0
     */
    private void wrapResponse(ContentCachingResponseWrapper contentCachingResponseWrapper,
                              Exception e) throws IOException {

        byte[] resultBytes = contentCachingResponseWrapper.getContentAsByteArray();
        if (resultBytes.length > 0) {
            //重置一下读取的指针
            contentCachingResponseWrapper.resetBuffer();
        }
        ServletOutputStream outputStream = contentCachingResponseWrapper.getOutputStream();
        outputStream.write(JacksonUtils.toJsonAsBytes(Result.failed(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value())));
    }

    /**
     * 不需要进行拦截的路径,默认放掉swagger相关
     *
     * @param request request
     * @return boolean boolean
     * @since 1.0.0
     */
    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) {
        String path = request.getRequestURI().substring(request.getContextPath().length()).replaceAll("[/]+$", "");
        List<String> ignores = applicationProperties.getPath().getIgnores();
        //ant风格表达式进行匹配请求路径
        return ignores.stream().anyMatch(p -> matcher.match(p, path)) || !StringUtils.hasText(path);
    }
}

通过配置类注入进去,可以通过 FilterRegistrationBean 来执行注入Filter

@Configuration
public class ApplicationAutoConfig {

	/**
     * 添加跨域
     *
     * @return the filter registration bean
     * @since 1.0.0
     */
    @Bean
    public FilterRegistrationBean<CorsFilter> corsFilter() {
        //1. 添加 CORS配置信息
        CorsConfiguration config = new CorsConfiguration();
        //放行哪些原始域
        config.addAllowedOrigin("http://localhost:8080");
        //是否发送 Cookie
        config.setAllowCredentials(true);
        //放行哪些请求方式
        config.addAllowedMethod("*");
        //放行哪些原始请求头部信息
        config.addAllowedHeader("*");
        //暴露哪些头部信息
        config.addExposedHeader("*");
        //2. 添加映射路径
        UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
        corsConfigurationSource.registerCorsConfiguration("/**", config);
        //3. 返回新的CorsFilter
        FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean(new CorsFilter(corsConfigurationSource));
        bean.setOrder(0);
        bean.addUrlPatterns("/*");
        return bean;
    }

    @Bean
    public FilterRegistrationBean<ResponseFilter> responseFilter() {
        FilterRegistrationBean<ResponseFilter> bean = new FilterRegistrationBean(new ResponseFilter());
        bean.setOrder(Integer.MAX_VALUE);
        return bean;
    }

}

接口异常处理

@RestControllerAdvice
public class GlobalException {

	//可以自定义异常信息处理
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseData<String> handleBusinessLogicException(Exception e) {
        return ResponseData.failure(e.getMessage());
    }

    @ExceptionHandler(Throwable.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseData<String> handlerSystemException(Throwable e) {
        return ResponseData.failure(e.getMessage());
    }
}

接口结果处理

@RestControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ResultAdvice implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType,
                                  Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest,
                                  ServerHttpResponse serverHttpResponse) {
        ResponseData<Object> result = null;
        if (o instanceof Result) {
            result = (ResponseData<Object>) o;
        } else {
            result = ResponseData.ok(o);
        }
        return result;
    }
}

数据格式

@Data
public class ResponseData<T> {

    private T data;

    private Integer status;

    private String msg;

    public static <T> ResponseData<T> ok(T result) {
        return ok(result, "success");
    }

    public static <T> ResponseData<T> ok(T result, String msg) {
        ResponseData<T> responseData = new ResponseData<>();
        responseData.setData(result);
        responseData.setStatus(HttpStatus.OK.value());
        responseData.setMsg(msg);
        return responseData;
    }

    public static <T> ResponseData<T> failure(String msg) {
        ResponseData<T> responseData = new ResponseData<>();
        responseData.setMsg(msg);
        responseData.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        return responseData;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值