springboot 集成完整的swagger2

不打扰是莪最后的温柔 提交于 2020-07-26 09:39:44

 

springboot 在集成swagger中会不会遇到各种问题:

1、swagger  进行接口鉴权(比如设置header的token,接口进行拦截处理)。

2、swagger 进行实体属性解析(pojo类的属性注解无法解析)。

3、swagger 进行响应码统一(code状态吗标识、200响应成功,响应体解析)。

4、swagger 设置接口共用参数(统一每个接口都存在的参数)。 

以下是解决问题配置信息

一、引入依赖包

      使用之前请更新或直接引用该版本依赖包

        更新版本地址:接口依赖jar https://mvnrepository.com/artifact/io.springfox/springfox-swagger2

                              ui   依赖jar https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>

 

二、创建swagger 配置类

  1、全局参数

        

    2、全局响应参数,每个接口都存在响应值,方便沟通

        

  3、设置安全认证

   点击 authorize 按钮输入验证信息,则每次调试接口都会传响应的信息

      

 废话少说!上配置代码

package com.example.config.swagger;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.web.bind.annotation.RequestMethod;
import springfox.documentation.builders.*;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.ArrayList;
import java.util.List;


/**
 *
 * @author niunafei
 *
 * @Profile 注解 标识加载在dev和test文件使用
 */
@Configuration
@EnableSwagger2
//@Profile({"dev", "test"})
public class SwaggerConfig {

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2).groupName("spring-test-interface")
                //加载配置信息
                .apiInfo(apiInfo())
                //设置全局参数
                .globalOperationParameters(globalParamBuilder())
                //设置全局响应参数
                .globalResponseMessage(RequestMethod.GET,responseBuilder())
                .globalResponseMessage(RequestMethod.POST,responseBuilder())
                .globalResponseMessage(RequestMethod.PUT,responseBuilder())
                .globalResponseMessage(RequestMethod.DELETE,responseBuilder())
                .select()
                //加载swagger 扫描包
                .apis(RequestHandlerSelectors.basePackage("com.example"))
                .paths(PathSelectors.any()).build()
                //设置安全认证
                .securitySchemes(security());

    }

    /**
     * 获取swagger创建初始化信息
     * @return
     */
    private ApiInfo apiInfo() {
        Contact contact = new Contact("niunafei", "", "niunafei0315@163.com");
        return new ApiInfoBuilder().title("swagger 测试文档").description("dev by niunafei").contact(contact)
                .version("1.0.0").build();
    }

    /**
     * 安全认证参数
     * @return
     */
    private List<ApiKey> security() {
        List<ApiKey> list=new ArrayList<>();
        list.add(new ApiKey("token", "token", "header"));
        return list;
    }

    /**
     * 构建全局参数列表
     * @return
     */
    private List<Parameter> globalParamBuilder(){
        List<Parameter> pars = new ArrayList<>();
        pars.add(parameterBuilder("token","令牌","string","header",false).build());
        return pars;
    }

    /**
     * 创建参数
     * @return
     */
    private ParameterBuilder parameterBuilder(String name,String desc,String type ,String parameterType,boolean required) {
        ParameterBuilder tokenPar = new ParameterBuilder();
        tokenPar.name(name).description(desc).modelRef(new ModelRef(type)).parameterType(parameterType).required(required).build();
        return tokenPar;
    }

    /**
     * 创建全局响应值
     * @return
     */
    private List<ResponseMessage> responseBuilder() {
        List<ResponseMessage> responseMessageList = new ArrayList<>();
        responseMessageList.add(new ResponseMessageBuilder().code(200).message("响应成功").build());
        responseMessageList.add(new ResponseMessageBuilder().code(500).message("服务器内部错误").build());
        return responseMessageList;
    }

}

  以上代码中 @Profile({"dev", "test"})注解是在开发环境和测试环境的时候加载该类,线上生产环境为安全不建议创建swagger的bean

 三、引入配置文件,并且配置好扫描类,但是仍然不能访问swagger 页面,这时候请考虑springboot的mvc指定访问路径

   addResourceHandlers 方法中已经指定swagger-ui访问页的路径

   同时该配置中处理了mvc 跨域的问题

     addCorsMappings 方法中是在拦截 addInterceptors 方法执行后进行的跨域设置
     corsFilter可以解决所有跨域问题
package com.example.config.mvc;

//import com.example.config.interceptor.LoginInterceptor;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;


/**
 * @author niunafei
 * @function
 * @email niunafei0315@163.com
 * @date 2019/6/28  下午12:28
 */
@Configuration
public class WebMvcConfigurerAdapter extends WebMvcConfigurationSupport {

//    @Autowired
//    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 添加拦截接口请求处理,
//        registry.addInterceptor(loginInterceptor).addPathPatterns("/api/**");
    }

    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        //定向swagger 位置
        registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
        registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

    /**
     * 拦截后的跨域解决
     *
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowCredentials(true).allowedHeaders("*").allowedOrigins("*").allowedMethods("GET",
                "POST", "PUT", "OPTIONS");
    }

    /**
     * 处理拦截前处理检测 授权跨域问题
     *
     * @return
     */
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfig());
        return new CorsFilter(source);
    }

    /**
     * @return
     */
    private CorsConfiguration corsConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        // 请求常用的三种配置,*代表允许所有,当时你也可以自定义属性(比如header只能带什么,只能是post方式等等)
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.setMaxAge(3600L);
        return corsConfiguration;
    }

}

 

四、swagger 返回扫描的问题

 接口层请使用泛型返回,个人定义的统一返回类

ApiModel是生成swagger时扫描的实体注解
ApiModelProperty 是属性注解
ApiHttpCode 是一个响应值的枚举类


 
 
package com.example.config.response;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

/**
 * @author niunafei
 * @function
 * @email niunafei0315@163.com
 * @date 2019/6/28  下午2:00
 */
@ApiModel()
public class ApiResult<T> {

    private static final Object RESULT_OBJECT=new Object();

    @ApiModelProperty(value = "编码", name = "code", dataType = "int", example = "200")
    private Integer code;

    @ApiModelProperty(value = "提示", name = "msg", dataType = "string", example = "success")
    private String msg;

    @ApiModelProperty(value = "内容", name = "data", dataType = "t")
    private T data;

    public ApiResult() {
    }

    public ApiResult(ApiHttpCode code, T data) {
        this.code = code.getCode();
        this.msg = code.getDesc();
        this.data = data;
    }

    public ApiResult(Integer code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public static ApiResult<Object> ok() {
        return ApiResult.ok(ApiHttpCode.SUCCESS, RESULT_OBJECT);
    }

    public static <T> ApiResult<T> ok(T data) {
        return ApiResult.ok(ApiHttpCode.SUCCESS, data);
    }

    public static <T> ApiResult<T> ok(ApiHttpCode code, T data) {
        return ApiResult.ok(code.getCode(), code.getDesc(), data);
    }

    public static <T> ApiResult<T> ok(Integer code, String msg, T data) {
        return new ApiResult(code, msg, data);
    }

    public static ApiResult<Object> error() {
        return ApiResult.error(ApiHttpCode.ERROR, new Object());
    }

    public static <T> ApiResult<T> error(T data) {
        return ApiResult.error(ApiHttpCode.ERROR, data);
    }

    public static <T> ApiResult<T> error(ApiHttpCode code) {
        return ApiResult.error(code.getCode(),code.getDesc(),null);
    }

    public static <T> ApiResult<T> error(ApiHttpCode code, T data) {
        return ApiResult.error(code.getCode(), code.getDesc(), data);
    }

    public static <T> ApiResult<T> error(Integer code, String msg) {
        return ApiResult.error(code, msg, null);
    }

    public static <T> ApiResult<T> error(Integer code, String msg, T data) {
        return new ApiResult(code, msg, data);
    }

    public Integer getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    public T getData() {
        return data;
    }
}

 

ApiHttpCode枚举类
package com.example.config.response;

/**
 * @author niunafei
 * @function
 * @email niunafei0315@163.com
 * @date 2019/6/28  下午2:02
 */
public enum ApiHttpCode {
    /**
     * 响应成功
     */
    SUCCESS(200, "OK"),
    /**
     * 服务器异常
     */
    ERROR(500, "ERROR"),
    /**
     * 未授权访问
     */
    UNAUTHORIZED(401, "访问未授权");

    private int code;
    private String desc;

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

    public int getCode() {
        return code;
    }

    public String getDesc() {
        return desc;
    }

    public static ApiHttpCode valueOf(int value) {
        for (ApiHttpCode role : ApiHttpCode.values()) {
            if (role.code == value) {
                return role;
            }
        }
        return null;
    }
}

 

五、接口层引用

@Api注解添加

接口方法上添加@ApiOperation 才可以生成文档

@ApiImplicitParams 用来定义接口参数,并指定描述的,

@ApiResponses  用来定义添加额外的响应值,与配置类中的全局响应功能一致。

 

    

访问接口页面 http://localhost:8888/spring-demo/swagger-ui.html

访问格式:http://IP地址或域名:端口/应用名称/swagger-ui.html

 

 

 

无关后话,与swagger 无关:授权检测的创建继承HandlerInterceptorAdapter 方法

package com.example.config.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author niunafei
 * @function
 * @email niunafei0315@163.com
 * @date 2019/6/28  下午12:31
 */
@Component
public class LoginInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //未开启权限检测 跳过
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object
            o, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse
            httpServletResponse, Object o, Exception e) throws Exception {

    }
}

 

 

 

token出现验证异常 https://www.cnblogs.com/fengli9998/p/7852685.html

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!