springboot全局响应类与swagger冲突

近日,在学习springboot全局异常处理与全局响应对象时,因为项目本身使用了swagger,启用全局响应处理类后,swagger页面无法使用,如下图

全局响应类需集成ResponseBodyAdvice接口,并添加注解@ControllerAdvice和@Component,交由spring进行管理 

经排查后,是由于全局响应类中supports方法拦截了请求,在supports方法的返回值前增加过滤判断,是swagger的Docket类则返回false

改动后代码如下:

 1 package com.myfather.demo3.exception;
 2 
 3 import com.myfather.demo3.common.AjaxResponse;
 4 import org.springframework.core.MethodParameter;
 5 import org.springframework.http.HttpStatus;
 6 import org.springframework.http.MediaType;
 7 import org.springframework.http.server.ServerHttpRequest;
 8 import org.springframework.http.server.ServerHttpResponse;
 9 import org.springframework.stereotype.Component;
10 import org.springframework.web.bind.annotation.ControllerAdvice;
11 import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
12 import springfox.documentation.spring.web.plugins.Docket;
13 
14 /**
15  * @Description 全局响应类
16  * @Author liangZai
17  * @Date 2020/12/17 22:09
18  * @Version 1.0
19  */
20 @Component
21 @ControllerAdvice
22 public class GlobalResponseAdvice implements ResponseBodyAdvice {
23     /**
24      * Whether this component supports the given controller method return type
25      * and the selected {@code HttpMessageConverter} type.
26      *
27      * @param returnType    the return type
28      * @param converterType the selected converter type
29      * @return {@code true} if {@link #beforeBodyWrite} should be invoked;
30      * {@code false} otherwise
31      */
32     @Override
33     public boolean supports(MethodParameter returnType, Class converterType) {
34         //默认结果为false,表示支持哪些方法,改为true之后为支持所有方法
35 //        return false;
36         return !returnType.getDeclaringClass().equals(Docket.class);
37 //        return true;
38     }
39 
40     /**
41      * Invoked after an {@code HttpMessageConverter} is selected and just before
42      * its write method is invoked.
43      *
44      * @param body                  the body to be written
45      * @param returnType            the return type of the controller method
46      * @param mediaType   the content type selected through content negotiation
47      * @param selectedConverterType the converter type selected to write to the response
48      * @param request               the current request
49      * @param response              the current response
50      * @return the body that was passed in or a modified (possibly new) instance
51      */
52     @Override
53     public Object beforeBodyWrite(Object body,
54                                   MethodParameter returnType,
55                                   MediaType mediaType,
56                                   Class selectedConverterType,
57                                   ServerHttpRequest request,
58                                   ServerHttpResponse response) {
59 
60         if(mediaType.equalsTypeAndSubtype(MediaType.APPLICATION_JSON)){
61             if(body instanceof AjaxResponse){
62                 response.setStatusCode(HttpStatus.valueOf((
63                         (AjaxResponse)body).getCode()
64                 ));
65                 return body;
66             }
67             else {
68                 response.setStatusCode(HttpStatus.OK);
69                 return AjaxResponse.success(body);
70             }
71         }
72         return null;
73     }
74 }
View Code

改动前

 代码改动后

以下贴出代码

统一响应类

package com.myfather.demo3.common;

import com.myfather.demo3.exception.CustomException;
import com.myfather.demo3.exception.CustomExceptionType;
import lombok.Data;

/**
 * @Description
 * @Author liangZai
 * @Date 2020/12/17 21:49
 * @Version 1.0
 */
@Data
public class AjaxResponse {

    private boolean isok;

    private int code;

    private String message;

    private Object data;

    private AjaxResponse() {
    }

    /**
     * 请求成功参数封装
     * @return
     */
    public static AjaxResponse success(){
        AjaxResponse response = new AjaxResponse();
        response.setIsok(true);
        response.setCode(200);
        response.setMessage("请求成功!");
        return response;
    }

    /**
     * 请求成功带参
     * @param obj
     * @return
     */
    public static AjaxResponse success(Object obj){
        AjaxResponse response = new AjaxResponse();
        response.setIsok(true);
        response.setCode(200);
        response.setMessage("请求成功!");
        response.setData(obj);
        return response;
    }

    /**
     * 请求成功带参且自定义消息
     * @param obj
     * @param message
     * @return
     */
    public static AjaxResponse success(Object obj,String message){
        AjaxResponse response = new AjaxResponse();
        response.setIsok(true);
        response.setCode(200);
        response.setMessage(message);
        response.setData(obj);
        return response;
    }

    /**
     * 请求异常参数封装
     * @param e
     * @return
     */
    public static AjaxResponse error(CustomException e){
        AjaxResponse response = new AjaxResponse();
        response.setIsok(false);
        response.setCode(e.getCode());
        response.setMessage(e.getMessage());
        return response;
    }

    /**
     * 请求异常带参数且自定义消息
     * @param customExceptionType
     * @param message
     * @return
     */
    public static AjaxResponse error(CustomExceptionType customExceptionType,String message){
        AjaxResponse response = new AjaxResponse();
        response.setIsok(false);
        response.setCode(customExceptionType.getCode());
        response.setMessage(message);
        return response;
    }
}
View Code

自定义异常类

package com.myfather.demo3.exception;

import lombok.Data;

/**
 * @Description
 * @Author liangZai
 * @Date 2020/12/17 21:44
 * @Version 1.0
 */
@Data
public class CustomException extends RuntimeException {

    private int code;
    private String message;

    private CustomException() {
    }

    public CustomException(CustomExceptionType customExceptionType,String message) {
        this.code = customExceptionType.getCode();
        this.message = message;
    }

    public CustomException(CustomExceptionType customExceptionType) {
        this.code = customExceptionType.getCode();
        this.message = customExceptionType.getDesc();
    }
}
View Code

自定义异常code枚举类

package com.myfather.demo3.exception;

/**
 * 异常类型
 */
public enum CustomExceptionType {
    USER_INPUT_ERROR(400,"用户输入参数有误!"),
    SYSTEM_ERROR(500,"服务器异常!"),
    OTHER_ERROR(999,"系统出现未知异常,请联系管理员!"),
    ;
    private int code;
    private String desc;

    CustomExceptionType(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    public int getCode() {
        return code;
    }

    public String getDesc() {
        return desc;
    }
}
View Code

全局异常处理类

package com.myfather.demo3.exception;

import com.myfather.demo3.common.AjaxResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @Description
 * @Author liangZai
 * @Date 2020/12/17 22:02
 * @Version 1.0
 */
@ControllerAdvice
public class WebExceptionHandler {

    @ExceptionHandler(CustomException.class)
    @ResponseBody
    public AjaxResponse customerException(CustomException e){
        return AjaxResponse.error(e);
    }

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public AjaxResponse customerException(Exception e){
        return AjaxResponse.error(new CustomException(CustomExceptionType.OTHER_ERROR));
    }
}
View Code

swagger配置类

package com.myfather.demo3;

import io.swagger.annotations.Api;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * swagger配置文件
 *
 * @author liangZai
 */
@Configuration
@EnableSwagger2
@ComponentScan(basePackages = {"com.myfather.demo3"})
@ConditionalOnProperty(prefix = "myconfig", name = "swagger-ui-open", havingValue = "true")
public class SwaggerConfig {

    @Bean
    public Docket createAccepterRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                //分组名,不指定默认为default
                .groupName("我的API")
                .select()
                .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                // 定义要生成文档的Api的url路径规则
                .paths(PathSelectors.any())
                .build()
                // 设置swagger-ui.html页面上的一些元素信息
                .apiInfo(apiInfo())
                .enable(true);
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("我的RESTful API")
                .description("提供各种牛掰功能")
                .version("1.0")
                .build();
    }
}
View Code

 


posted @ 2020-12-18 15:26  靓仔-1  阅读(2578)  评论(0编辑  收藏  举报