springboot集成swagger(swagger使用介绍)(汉化教程)

时间:2024-03-31 16:58:12

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步。
其中主要要项目如下:

  1. Swagger-tools:提供各种与Swagger进行集成和交互的工具。例如模式检验、Swagger 1.2文档转换成Swagger 2.0文档等功能。

  2. Swagger-core: 用于Java/Scala的的Swagger实现。与JAX-RS(Jersey、Resteasy、CXF…)、Servlets和Play框架进行集成。

  3. Swagger-js: 用于JavaScript的Swagger实现。

  4. Swagger-node-express: Swagger模块,用于node.js的Express web应用框架。

  5. Swagger-ui:一个无依赖的HTML、JS和CSS集合,可以为Swagger兼容API动态生成优雅文档。

  6. Swagger-codegen:一个模板驱动引擎,通过分析用户Swagger资源声明以各种语言生成客户端代码。

接下来就让我们开启集成之路吧!!

  1. 创建springboot 项目
  2. 引入swagger 依赖, 这里需要注意的springboot的版本跟swagger 版本直接的关系,不建议都用最新版本,很有可以会造成项目访问不了swagger UI。
        <!--swagger2-->
        <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.7.0</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.7.0</version>
        </dependency>
  1. 创建swagger config类:
@Configuration
public class Swagger2Config {

    @Bean
    public Docket testApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("demo for test")
                .genericModelSubstitutes(DeferredResult.class)
//                .genericModelSubstitutes(ResponseEntity.class)
                .useDefaultResponseMessages(false)
                .forCodeGeneration(true)
                .pathMapping("/")// base,最终调用接口后会和paths拼接在一起
                .select()
                .paths(regex("/api/.*"))//过滤的接口
                .build()
                .apiInfo(testApiInfo());
    }

    @Bean
    public Docket demoApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("demo")
                .genericModelSubstitutes(DeferredResult.class)
//              .genericModelSubstitutes(ResponseEntity.class)
                .useDefaultResponseMessages(false)
                .forCodeGeneration(false)
                .pathMapping("/")
                .select()
                .paths((regex("/demo/.*")))//过滤的接口
                .build()
                .apiInfo(demoApiInfo());
    }

    private ApiInfo testApiInfo() {
        return new ApiInfoBuilder()
                .title("SpringBoot 集成 Swagger2")//大标题
                .description("Rest api document")//详细描述
                .version("1.0")//版本
                .termsOfServiceUrl("NO terms of service")
                .contact(new Contact("Glen", "https://blog.csdn.net/qq_35623773", "[email protected]"))//作者
                .license("The Apache License, Version 2.0")
                .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
                .build();
    }

    private ApiInfo demoApiInfo() {
        return new ApiInfoBuilder()
                .title("SpringBoot 集成 Swagger2")//大标题
                .description("Rest api document")//详细描述
                .version("1.0")//版本
                .termsOfServiceUrl("NO terms of service")
                .contact(new Contact("Glen", "https://blog.csdn.net/qq_35623773", "[email protected]"))//作者
                .license("The Apache License, Version 2.0")
                .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
                .build();
    }

    @Bean
    public Docket OnlyRestApi() {
        Predicate<RequestHandler> predicate = new Predicate<RequestHandler>() {
            @Override
            public boolean apply(RequestHandler input) {
                Class<?> declaringClass = input.declaringClass();
                // 排除特定类
                if (declaringClass == BasicErrorController.class)
                    return false;
                // 包含特定的类
                if(declaringClass.isAnnotationPresent(RestController.class))
                    return true;
                // 包含特定注解的方法
                if(input.isAnnotatedWith(GetMapping.class) || input.isAnnotatedWith(PostMapping.class))
                    return true;
                return false;
            }
        };
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(restApiInfo())
                .groupName("Only rest api.")
                .useDefaultResponseMessages(false)
                .select()
                .apis(predicate)
                .build();
    }

    private ApiInfo restApiInfo() {
        return new ApiInfoBuilder()
                .title("Only include rest api.")//大标题
                .version("1.0")//版本
                .build();
    }
}

Docket 简介:

public Docket(DocumentationType documentationType) {
    this.apiInfo = ApiInfo.DEFAULT;
    this.groupName = "default";
    this.enabled = true;
    this.genericsNamingStrategy = new DefaultGenericTypeNamingStrategy();
    this.applyDefaultResponseMessages = true;
    this.host = "";
    this.pathMapping = Optional.absent();
    this.apiSelector = ApiSelector.DEFAULT;
    this.enableUrlTemplating = false;
    this.vendorExtensions = Lists.newArrayList();
    this.documentationType = documentationType;
}

从构造方法中我们看出Docket 类包含11个属性,常用属性介绍:

apiInfo API 文档相关信息,对应实体类ApiInfoBuilder, 其中包含了API title, description, termsOfServiceUrl, license, version等API 相关信息
groupName 分组名
applyDefaultResponseMessages 解析response 信息, 默认为true
host url 前缀
pathMapping 设置api根路径
apiSelector 初始化并返回一个API选择构造器 ApiSelectorBuilder类的方法
documentationType API content-type

ApiSelectorBuilder类的方法:

ApiSelectorBuilder apis(Predicate selector):添加选择条件并返回添加后的ApiSelectorBuilder对象

ApiSelectorBuilder paths(Predicate selector):设置路径筛选,该方法中含一句pathSelector = and(pathSelector, selector);表明条件为相与

RequestHandlerSelectors类的方法:

Predicate any():返回包含所有满足条件的请求处理器的断言,该断言总为true

Predicate none():返回不满足条件的请求处理器的断言,该断言总为false

Predicate basePackage(final String basePackage):返回一个断言(Predicate),该断言包含所有匹配basePackage下所有类的请求路径的请求处理器

PathSelectors类的方法:

Predicate any():满足条件的路径,该断言总为true

Predicate none():不满足条件的路径,该断言总为false

Predicate regex(final String pathRegex):

当我们只需要restful 分格的api时, 我们可以对那些response是url或者vm模板的api进行相应的过滤, 可参考以下方法去实现:

 @Bean
    public Docket OnlyRestApi() {
        Predicate<RequestHandler> predicate = new Predicate<RequestHandler>() {
            @Override
            public boolean apply(RequestHandler input) {
                Class<?> declaringClass = input.declaringClass();
                // 排除特定类
                if (declaringClass == BasicErrorController.class)
                    return false;
                // 包含特定的类
                if(declaringClass.isAnnotationPresent(RestController.class))
                    return true;
                // 包含特定注解的方法
                if(input.isAnnotatedWith(GetMapping.class) || input.isAnnotatedWith(PostMapping.class))
                    return true;
                return false;
            }
        };
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(restApiInfo())
                .groupName("Only rest api.")
                .useDefaultResponseMessages(false)
                .select()
                .apis(predicate)
                .build();
    }

    private ApiInfo restApiInfo() {
        return new ApiInfoBuilder()
                .title("Only include rest api.")//大标题
                .version("1.0")//版本
                .build();
    }
  1. 修改restController
@RestController
@Api("查询公司信息")//用来说明当前 controller 的作用
public class CompanyManagerController {
    private final static Logger logger = LoggerFactory.getLogger(CompanyManagerController.class);
    @Autowired
    private CompanyService companyService;


    @GetMapping("/search/{pageNum}/{pageSize}/company")
    //api 具体描述
    @ApiOperation(value = "根据关键字或者区域查询多个公司", notes = "pageSize 为零时查询所有", tags = {"公司查询"}, httpMethod = "GET")
    //参数描述
    //@ApiImplicitParam(value = "pageNum", defaultValue = "不能为空", required = true)
    //多个参数时
    @ApiImplicitParams({
            @ApiImplicitParam(paramType="query", name = "pageNum", value = "页数", required = true, dataType = "int"),
            @ApiImplicitParam(paramType="query", name = "pageSize", value = "页面大小", required = true, dataType = "int"),
            @ApiImplicitParam(paramType="query", name = "keyword", value = "公司名称关键字", required = true, dataType = "String"),
            @ApiImplicitParam(paramType="query", name = "arCode", value = "区域编号", dataType = "String"),
            @ApiImplicitParam(paramType = "query", name = "arName", value = "区域名字", dataType = "String")
    })
    @ApiResponses({
            @ApiResponse(code = 404, message = "page not found")
    })
    public ResponseEntity<JsonResult> findCompany(@PathVariable("pageNum") int pageNum, @PathVariable("pageSize") int pageSize,
                                                  @RequestParam(value = "keyword", required = false, defaultValue = "") String keyword,
                                                  @RequestParam(value = "arCode", required = false) String arCode,
                                                  @RequestParam(value = "arName", required = false)  String arName){
    logger.info(String.format("get one page company, pageSize: %d, page: %d", pageNum, pageSize));
        JsonResult r = new JsonResult();
        try {
            verifyParames(keyword, arCode, arName);
            List<CMCompany> cmCompanies = companyService.findCompany(pageNum, pageSize, keyword, arCode, arName);
            r.setResult(new CompaniesListResource(cmCompanies));
            r.setStatus("ok");
        } catch (Exception e) {
            r.setResult(e.getClass().getName() + ":" + e.getMessage());
            r.setStatus("error");
            e.printStackTrace();
        }
        return ResponseEntity.ok(r);
    }

    private void verifyParames(String keyword, String arCode, String arName) throws Exception {
        if (StringUtils.isEmpty(keyword) && StringUtils.isEmpty(arCode) && StringUtils.isEmpty(arName)) {
            logger.error("keyword, arCode and arName is all null!!!");
            throw new Exception("params error!!");
        }
    }

    @GetMapping("/company/detail")
    //api 具体描述
    @ApiOperation(value = "根据id查询公司具体信息", notes = "查询公司所有信息及送货地址", tags = {"公司查询"}, httpMethod = "GET")
    //参数描述
    @ApiImplicitParam(value = "coid", defaultValue = "不能为空", required = true)
    @ApiResponses({
            @ApiResponse(code = 404, message = "page not found"),
            @ApiResponse(code = 400, message = "内部参数异常")
    })
    public ResponseEntity<JsonResult> findCompanyDetail(@RequestParam(value = "coid") String coid){
        logger.info("findCompanyDetail");
        JsonResult r = new JsonResult();
        try {
            CMCompany cmCompany = companyService.findCompany(coid);
            r.setResult(new CompanyResource(cmCompany));
            r.setStatus("ok");
        } catch (Exception e) {
            r.setResult(e.getClass().getName() + ":" + e.getMessage());
            r.setStatus("error");
            e.printStackTrace();
        }
        return ResponseEntity.ok(r);
    }
}

Swagger使用的注解及其说明:

@Api:用在类上,说明该类的作用。

@ApiOperation:注解来给API增加方法说明。

@ApiImplicitParams : 用在方法上包含一组参数说明。

@ApiImplicitParam:用来注解来给方法入参增加说明。

@ApiResponses:用于表示一组响应

@ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息

l   code:数字,例如400

l   message:信息,例如"请求参数没填好"

l   response:抛出异常的类   

@ApiModel:描述一个Model的信息(一般用在请求参数无法使用@ApiImplicitParam注解进行描述的时候)

l   @ApiModelProperty:描述一个model的属性

注意:@ApiImplicitParam的参数说明:

参数名 介绍
paramType: 指定参数放在哪个地方
header: 请求参数放置于Request Header,使用@RequestHeader获取
query: 请求参数放置于请求地址,使用@RequestParam获取
path: (用于restful接口)–>请求参数的获取:@PathVariable
name: 参数名
dataType: 参数类型
required: 参数是否必须传 true
value: 说明参数的意思
defaultValue: 参数的默认值

5.启动springBoot, 访问: http://localhost:8080/wx/swagger-ui.html#/
springboot集成swagger(swagger使用介绍)(汉化教程)

  1. 测试某一个具体的API(输入对应的参数, 点击 try it):
    springboot集成swagger(swagger使用介绍)(汉化教程)

到这里,集成就结束了, 附上源码: https://github.com/MrGlen/wxwl
参考: https://blog.csdn.net/sanyaoxu_2/article/details/80555328
官网:https://swagger.io/

swagger 汉化:https://www.jianshu.com/p/7e543f0f0bd8
这里直接使用汉化时有问题的,需要配置静态文件资源路径:

#配置静态资源访问
spring.mvc.static-path-pattern=/static/**
spring.resources.static-locations=classpath: META-INF/resources