SpringBoot中使用springfox+swagger2书写API文档

时间:2022-09-04 19:32:34

随着前后端的分离,借口文档变的尤其重要,springfox是通过注解的形式自动生成API文档,利用它,可以很方便的书写restful API,swagger主要用于展示springfox生成的API文档。

官网地址:http://springfox.github.io/springfox/

Springfox大致原理

springfox的大致原理就是,在项目启动的过种中,spring上下文在初始化的过程,框架自动跟据配置加载一些swagger相关的bean到当前的上下文中,并自动扫描系统中可能需要生成api文档那些类,并生成相应的信息缓存起来。如果项目MVC控制层用的是springMvc那么会自动扫描所有Controller类,跟据这些Controller类中的方法生成相应的api文档。

Spring集成Springfox步骤及说明:

一、添加Swagger2依赖

    <!-- Swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>

二、application.properties中添加配置

#解决中文乱码问题
banner.charset=UTF-8
server.tomcat.uri-encoding=UTF-8
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true
spring.messages.encoding=UTF-8 #Swagger Configure Properties
sop.swagger.enable=true
sop.swagger.packageScan=com.example
sop.swagger.title=UserController Restfull API
sop.swagger.description=UserController Restfull API
sop.swagger.version=3.0

三、创建SwaggerConfigProperties加载配置项

package com.example.config;

import java.io.Serializable;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component; @ConfigurationProperties(prefix = "sop.swagger")
@Component
public class SwaggerConfigProperties implements Serializable {
/**
* 是否开启Swagger
*/
private boolean enable = false;
/**
* 要扫描的包
*/
private String packageScan;
/**
* 标题
*/
private String title;
/**
* 描述
*/
private String description;
/**
* 版本信息
*/
private String version; public boolean isEnable() {
return enable;
} public void setEnable(boolean enable) {
this.enable = enable;
} public String getPackageScan() {
return packageScan;
} public void setPackageScan(String packageScan) {
this.packageScan = packageScan;
} public String getTitle() {
return title;
} public void setTitle(String title) {
this.title = title;
} public String getDescription() {
return description;
} public void setDescription(String description) {
this.description = description;
} public String getVersion() {
return version;
} public void setVersion(String version) {
this.version = version;
}
}

四、创建Swagger2配置类

package com.example.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
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; @Configuration
@EnableSwagger2
public class Swagger2 {
@Autowired
private SwaggerConfigProperties scp; @Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.web"))
.paths(PathSelectors.any())
.build();
} private ApiInfo apiInfo() { return new ApiInfoBuilder()
.title(scp.getTitle())
.description(scp.getDescription())
.version("1.0")
.build();
}
}

五、创建model

package com.example.model;

import io.swagger.annotations.ApiModelProperty;

public class User {
@ApiModelProperty(value = "主键")
private Long id;
@ApiModelProperty(value = "名字")
private String name;
@ApiModelProperty(value = "年龄")
private Integer age;
@ApiModelProperty(value = "密码")
private String password; public Long getId() {
return id;
} public void setId(Long id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} @Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", password=" + password +
'}';
}
}

六、创建Controller

package com.example.web;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map; import com.example.model.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore; @RestController
@Api("userController相关api")
public class UserController {
@ApiOperation("获取用户信息")
@ApiImplicitParams({
@ApiImplicitParam(paramType = "header", name = "username", dataType = "String", required = true,
value = "用户的姓名", defaultValue = "xiaoqiang"),
@ApiImplicitParam(paramType = "query", name = "password", dataType = "String", required = true, value = "用户的密码",
defaultValue = "xiaoxiong")
})
@ApiResponses({
@ApiResponse(code = 400, message = "请求参数没填好"),
@ApiResponse(code = 404, message = "请求路径没有或页面跳转路径不对")
})
@RequestMapping(value = "/getUser", method = RequestMethod.GET)
public User getUser(@RequestHeader("username") String username, @RequestParam("password") String password) {
User user = new User();
user.setName(username);
user.setPassword(password);
return user;
} @ApiOperation(value = "创建用户", notes = "根据User对象创建用户")
@ApiImplicitParam(name = "user", value = "用户详细实体user", required = true, dataType = "User")
@RequestMapping(value = "", method = RequestMethod.POST)
public String postUser(@RequestBody User user) {
Map<Long, User> users = Collections.synchronizedMap(new HashMap<Long, User>());
users.put(user.getId(), user);
return "success";
} @ApiIgnore
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home() {
return "hello";
}
}

完成上述代码添加上,启动Spring Boot程序,访问:http://localhost:8080/swagger-ui.html
。就能看到前文所展示的RESTful API的页面。我们可以再点开具体的API请求,以POST类型的/users请求为例,可找到上述代码中我们配置的Notes信息以及参数user的描述信息,如下图所示。

SpringBoot中使用springfox+swagger2书写API文档

七、API文档访问与调试

在上图请求的页面中,我们看到user的Value是个输入框?是的,Swagger除了查看接口功能外,还提供了调试测试功能,我们可以点击上图中右侧的Model Schema(黄色区域:它指明了User的数据结构),此时Value中就有了user对象的模板,我们只需要稍适修改,点击下方“Try it out!”按钮,即可完成了一次请求调用!

此时,你也可以通过几个GET请求来验证之前的POST请求是否正确。

相比为这些接口编写文档的工作,我们增加的配置内容是非常少而且精简的,对于原有代码的侵入也在忍受范围之内。因此,在构建RESTful API的同时,加入swagger来对API文档进行管理,是个不错的选择。

八、springfox、swagger.annotations注解部分参数介绍

在上面只展示了如何使用,这里将对上面添加的swagger注解进行说明,笔记使用时参考了swagger annotations Api 手册,接下来进行部分常用注解使用说明介绍。

  • @ApiIgnore 忽略注解标注的类或者方法,不添加到API文档中
  • @ApiOperation 展示每个API基本信息
    • value api名称
    • notes 备注说明
  • @ApiImplicitParam 用于规定接收参数类型、名称、是否必须等信息
    • name 对应方法中接收参数名称
    • value 备注说明
    • required 是否必须 boolean
    • paramType 参数类型 body、path、query、header、form中的一种
    • body 使用@RequestBody接收数据 POST有效
    • path 在url中配置{}的参数
    • query 普通查询参数 例如 ?query=q ,jquery ajax中data设置的值也可以,例如 {query:”q”},springMVC中不需要添加注解接收
    • header 使用@RequestHeader接收数据
    • form 笔者未使用,请查看官方API文档
    • dataType 数据类型,如果类型名称相同,请指定全路径,例如 dataType = “java.util.Date”,springfox会自动根据类型生成模型
  • @ApiImplicitParams 包含多个@ApiImplicitParam
  • @ApiModelProperty 对模型中属性添加说明,例如 上面的PageInfoBeen、BlogArticleBeen这两个类中使用,只能使用在类中。
    • value 参数名称
    • required 是否必须 boolean
    • hidden 是否隐藏 boolean
    • 其他信息和上面同名属性作用相同,hidden属性对于集合不能隐藏,目前不知道原因
  • @ApiParam 对单独某个参数进行说明,使用在类中或者controller方法中都可以。注解中的属性和上面列出的同名属性作用相同

其他注解:https://github.com/swagger-api/swagger-core/wiki/Annotations#apimodel

九、springfox中的那些坑

springfox第一大坑:Controller类的参数,注意防止出现无限递归的情况。

Spring mvc有强大的参数绑定机制,可以自动把请求参数绑定为一个自定义的命令对像。所以,很多开发人员在写Controller时,为了偷懒,直接把一个实体对像作为Controller方法的一个参数。比如下面这个示例代码:
@RequestMapping(value = "update")
public String update(MenuVo menuVo, Model model){
}
这是大部分程序员喜欢在Controller中写的修改某个实体的代码。在跟swagger集成的时候,这里有一个大坑。如果MenuVo这个类中所有的属性都是基本类型,那还好,不会出什么问题。但如果这个类里面有一些其它的自定义类型的属性,而且这个属性又直接或间接的存在它自身类型的属性,那就会出问题。例如:假如MenuVo这个类是菜单类,在这个类时又含有MenuVo类型的一个属性parent代表它的父级菜单。这样的话,系统启动时swagger模块就因无法加载这个api而直接报错。报错的原因就是,在加载这个方法的过程中会解析这个update方法的参数,发现参数MenuVo不是简单类型,则会自动以递归的方式解释它所有的类属性。这样就很容易陷入无限递归的死循环。

为了解决这个问题,我目前只是自己写了一个OperationParameterReader插件实现类以及它依赖的ModelAttributeParameterExpander工具类,通过配置的方式替换掉到srpingfox原来的那两个类,偷梁换柱般的把参数解析这个逻辑替换掉,并避开无限递归。当然,这相当于是一种修改源码级别的方式。我目前还没有找到解决这个问题的更完美的方法,所以,只能建议大家在用spring-fox Swagger的时候尽量避免这种无限递归的情况。毕竟,这不符合springmvc命令对像的规范,springmvc参数的命令对像中最好只含有简单的基本类型属性。

springfox第二大坑:api分组相关,Docket实例不能延迟加载

springfox默认会把所有api分成一组,这样通过类似于http://127.0.0.1:8080/jadDemo/swagger-ui.html这样的地址访问时,会在同一个页面里加载所有api列表。这样,如果系统稍大一点,api稍微多一点,页面就会出现假死的情况,所以很有必要对api进行分组。api分组,是通过在ApiConf这个配置文件中,通过@Bean注解定义一些Docket实例,网上常见的配置如下:

@EnableWebMvc
@EnableSwagger2
public class ApiConfig {
@Bean
public Docket customDocket() {
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
}
}

上述代码中通过@Bean注入一个Docket,这个配置并不是必须的,如果没有这个配置,框架会自己生成一个默认的Docket实例。这个Docket实例的作用就是指定所有它能管理的api的公共信息,比如api版本、作者等等基本信息,以及指定只列出哪些api(通过api地址或注解过滤)。
Docket实例可以有多个,比如如下代码:

@EnableWebMvc
@EnableSwagger2
public class ApiConfig {
@Bean
public Docket customDocket1() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("apiGroup1").apiInfo(apiInfo()).select()
.paths(PathSelectors.ant("/sys/**"));
}
@Bean
public Docket customDocket2() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("apiGroup2").apiInfo(apiInfo())
.select()
.paths(PathSelectors.ant("/shop/**"));
}
}

当在项目中配置了多个Docket实例时,也就可以对api进行分组了,比如上面代码将api分为了两组。在这种情况下,必须给每一组指定一个不同的名称,比如上面代码中的"apiGroup1"和"apiGroup2",每一组可以用paths通过ant风格的地址表达式来指定哪一组管理哪些api。比如上面配置中,第一组管理地址为/sys/开头的api第二组管理/shop/开头的api。当然,还有很多其它的过滤方式,比如跟据类注解、方法注解、地址正则表达式等等。分组后,在api 列表界面右上角的下拉选项中就可以选择不同的api组。这样就把项目的api列表分散到不同的页面了。这样,即方便管理,又不致于页面因需要加载太多api而假死。
然而,同使用@Configuration一样,我并不赞成使用@Bean来配置Docket实例给api分组。因为这样,同样会把代码写死。所以,我推荐在xml文件中自己配置Docket实例实现这些类似的功能。当然,考虑到Docket中的众多属性,直接配置bean比较麻烦,可以自己为Docket写一个FactoryBean,然后在xml文件中配置FactoryBean就行了。然而将Docket配置到xml中时。又会遇到一个大坑,就那是,spring对bean的加载方式默认是延迟加载的,在xml中直接配置这些Docket实例Bean后。你会发现,没有一点效果,页面左上角的下拉列表中跟本没有你的分组项。
这个问题曾困扰过我好几个小时,后来凭经验推测出可能是因为sping bean默认延迟加载,这个Docket实例还没加载到spring context中。实事证明,我的猜测是对的。我不知道这算是springfox的一个bug,还是因为我跟本不该把对Docket的配置从原来的java代码中搬到xml配置文件中来。

springfox其它的坑:

springfox还有些其它的坑,比如@ApiOperation注解中,如果不指定httpMethod属性具体为某个get或post方法时,api列表中,会它get,post,delete,put等所有方法都列出来,搞到api列表重复的太多,很难看。另外,还有在测试时,遇到登录权限问题,等等。这一堆堆的比较容易解决的小坑,因为篇幅有限,我就不多说了。还有比如@Api、@ApiOperation及@ApiParam等等注解的用法,网上很多这方面的文档,我就不重复了。


开源:Swagger Butler 1.1.0发布,利用ZuulRoute信息简化配置内容

Swagger Butler是一个基于Swagger与Zuul构建的API文档汇集工具。通过构建一个简单的Spring Boot应用,增加一些配置就能将现有整合了Swagger的Web应用的API文档都汇总到一起,方便查看与测试。

项目地址

快速入门

该工具的时候非常简单,先通过下面几步简单入门:

第一步:构建一个基础的Spring Boot应用

如您还不知道如何创建Spring Boot应用,可以先阅读本篇入门文章

第二步:在pom.xml中引入依赖

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
</parent> <dependencies>
<dependency>
<groupId>com.didispace</groupId>
<artifactId>swagger-butler-core</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>

第三步:创建应用主类,增加@EnableSwaggerButler注解开启Swagger Butler功能

@EnableSwaggerButler
@SpringBootApplication
public class StaticApplication { public static void main(String[] args) {
SpringApplication.run(StaticApplication.class);
} }

第四步:配置文件中增加Swagger文档的地址配置

spring.application.name=swagger-butler-example-static
server.port=11000 # default config
swagger.butler.api-docs-path=/v2/api-docs
swagger.butler.swagger-version=2.0 # swagger resource
zuul.routes.user.path=/service-a/**
zuul.routes.user.url=http://localhost:10010/
swagger.butler.resources.user.name=user-service # swagger resource
zuul.routes.product.path=/service-b/**
zuul.routes.product.url=http://localhost:10020/
swagger.butler.resources.product.name=product-service
swagger.butler.resources.product.api-docs-path=/xxx/v2/api-docs
swagger.butler.resources.product.swagger-version=2.0

上面配置了两个文档位置,由于这里还没有引入服务发现机制,所以Zuul的路由需要我们自己配置。然后在配置resource信息的时候,从1.1.0版本开始做了较大的调整,由于具体的访问路径是可以通过路由信息产生的,所以对于resource的配置信息只关注三个内容:

  • name:API文档在swagger中展现名称
  • api-docs-path:要获取的swagger文档的具体路径;如果不配置会使用全局的swagger.butler.api-docs-path配置,默认为/v2/api-docs。;这里的配置主要用户一些特殊情况,比如服务自身设置了context-path,或者修改了swagger默认的文档路径
  • swagger-version:swagger版本信息;如果不配置会使用全局的swagger.butler.swagger-version配置,默认为2.0

第五步:访问http://localhost:11000/swagger-ui.html

SpringBoot中使用springfox+swagger2书写API文档Example

代码示例具体可见swagger-butler-example-static目录

Zuul的路由与SwaggerResources配置之间的关系

如上示例中<route-name>展示了Zuul的路由名称与SwaggerResources配置之间的关联关系

zuul.routes.<route-name>.path=/service-b/**
zuul.routes.<route-name>.url=http://localhost:10020/ swagger.butler.resources.<route-name>.name=product-service
swagger.butler.resources.<route-name>.api-docs-path=/xxx/v2/api-docs
swagger.butler.resources.<route-name>.swagger-version=2.0

注意:在没有使用自动配置或整合服务治理的时候,要生成Swagger文档的时候,resources信息中的name属性是必须配置的,api-docs-pathswagger-version不配置的时候会使用默认的全局配置

全局配置

对于Swagger文档获取的全局配置内容,目前主要包含下面几个参数:

swagger.butler.api-docs-path=/v2/api-docs
swagger.butler.swagger-version=2.0

使用Zuul中的路由自动配置(新特性)

在快速入门示例中我们配置了两个路由信息,同时为这两个路由信息配置了对应的Swagger信息来获取API文档详情,从1.1.0版本开始,增加了几个通过Zuul的路由配置来自动生成文档信息的参数,这样可以减少快速入门示例中那些繁琐的配置。对于快速入门例子,我们可以做如下改造:

# swagger resource
zuul.routes.user.path=/service-a/**
zuul.routes.user.url=http://localhost:10010/ # swagger resource
zuul.routes.product.path=/service-b/**
zuul.routes.product.url=http://localhost:10020/ # use zuul routes generate swagger resources
swagger.butler.auto-generate-from-zuul-routes=true

在设置了swagger.butler.auto-generate-from-zuul-routes=true之后会默认的根据zuul中的路由信息来生成SwaggerResource。其中,原来resource中的name会使用zuul route的名称(比如:上面的user和product),而api-docs-pathswagger-version配置会使用默认的全局配置。如果resource中的三个参数有特殊情况要处理,可以采用快速入门中的配置方式来特别指定即可。

忽略某些路由生成

# swagger resource
zuul.routes.user.path=/service-a/**
zuul.routes.user.url=http://localhost:10010/ # swagger resource
zuul.routes.product.path=/service-b/**
zuul.routes.product.url=http://localhost:10020/ # use zuul routes generate swagger resources
swagger.butler.auto-generate-from-zuul-routes=true
swagger.butler.ignore-routes=product

如上示例,通过swagger.butler.ignore-routes参数可以从当前配置的路由信息中排除某些路由内容不生成文档,配置内容为zuul中的路由名称,配置多个的时候使用,分割。

注意:swagger.butler.ignore-routesswagger.butler.generate-routes不能同时配置。这两个参数都不配置的时候,默认为zuul中的所有路由生成文档。

指定某些路由生成

# swagger resource
zuul.routes.user.path=/service-a/**
zuul.routes.user.url=http://localhost:10010/ # swagger resource
zuul.routes.product.path=/service-b/**
zuul.routes.product.url=http://localhost:10020/ # use zuul routes generate swagger resources
swagger.butler.auto-generate-from-zuul-routes=true
swagger.butler.generate-routes=product

如上示例,通过swagger.butler.generate-routes参数可以从当前配置的路由信息中指定某些路由内容生成文档,配置内容为zuul中的路由名称,配置多个的时候使用,分割。

注意:swagger.butler.ignore-routesswagger.butler.generate-routes不能同时配置。这两个参数都不配置的时候,默认为zuul中的所有路由生成文档。

与服务治理整合

与eureka整合

在整合eureka获取所有该注册中心下的API文档时,只需要在上面工程的基础上增加下面的配置:

第一步pom.xml中增加eureka依赖,比如:

<dependencies>
<dependency>
<groupId>com.didispace</groupId>
<artifactId>swagger-butler-core</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.3.2.RELEASE</version>
</dependency>
</dependencies>

第二步:应用主类增加@EnableDiscoveryClient,比如:

@EnableDiscoveryClient
@EnableSwaggerButler
@SpringBootApplication
public class EurekaApplication { public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class);
} }

第三步:修改配置文件,增加eureka的配置,比如:

spring.application.name=swagger-butler-example-eureka
server.port=11001 eureka.client.service-url.defaultZone=http://eureka.didispace.com/eureka/ swagger.butler.auto-generate-from-zuul-routes=true
swagger.butler.generate-routes=swagger-service-a, swagger-service-b swagger.butler.resources.swagger-service-b.api-docs-path=/xxx/v2/api-docs

由于整合了eureka之后,zuul会默认为所有注册服务创建路由配置(默认的路由名为服务名),所以只需要通过swagger.butler.auto-generate-from-zuul-routes=true参数开启根据路由信息生成文档配置的功能,配合swagger.butler.ignore-routesswagger.butler.generate-routes参数就可以指定要生成的范围了,如果某些服务需要特殊配置,也可以通过wagger.butler.resources.*的配置来覆盖默认设置,比如上面的swagger.butler.resources.swagger-service-b.api-docs-path=/xxx/v2/api-docs指定了swagger-service-b服务获取swagger文档的请求路径为/xxx/v2/api-docs

代码示例具体可见swagger-butler-example-eureka目录

与consul整合

在整合eureka获取所有该注册中心下的API文档时,只需要在上面工程的基础上增加下面的配置:

第一步pom.xml中增加consul依赖,比如:

<dependencies>
<dependency>
<groupId>com.didispace</groupId>
<artifactId>swagger-butler-core</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
<version>1.3.2.RELEASE</version>
</dependency>
</dependencies>

第二步:应用主类增加@EnableDiscoveryClient,比如:

@EnableDiscoveryClient
@EnableSwaggerButler
@SpringBootApplication
public class EurekaApplication { public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class);
} }

第三步:配置文件中增加eureka的配置,比如:

spring.application.name=swagger-butler-example-consul
server.port=11002 spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500 swagger.butler.auto-generate-from-zuul-routes=true
swagger.butler.generate-routes=swagger-service-a, swagger-service-b swagger.butler.resources.swagger-service-b.api-docs-path=/xxx/v2/api-docs

这里除了consul自身的配置之外,其他内容与整合eureka时候的是一样的。

代码示例具体可见swagger-butler-example-consul目录

SpringBoot中使用springfox+swagger2书写API文档的更多相关文章

  1. 使用springfox&plus;swagger2书写API文档(十八)

    使用springfox+swagger2书写API文档 springfox是通过注解的形式自动生成API文档,利用它,可以很方便的书写restful API,swagger主要用于展示springfo ...

  2. springfox&plus;swagger2生成API文档

    1.建立一个spring mvc工程: 2.添加POM依赖: <properties> <springfoxversion>2.6.1</springfoxversion ...

  3. Spring Boot中使用Swagger2构建API文档

    程序员都很希望别人能写技术文档,自己却很不愿意写文档.因为接口数量繁多,并且充满业务细节,写文档需要花大量的时间去处理格式排版,代码修改后还需要同步修改文档,经常因为项目时间紧等原因导致文档滞后于代码 ...

  4. SpringBoot&plus;rest接口&plus;swagger2生成API文档&plus;validator&plus;mybatis&plus;aop&plus;国际化

    代码地址:JillWen_SpringBootDemo mybatis 1. 添加依赖: <dependency> <groupId>org.mybatis.spring.bo ...

  5. 白话SpringCloud &vert; 第十一章:路由网关&lpar;Zuul&rpar;:利用swagger2聚合API文档

    前言 通过之前的两篇文章,可以简单的搭建一个路由网关了.而我们知道,现在都奉行前后端分离开发,前后端开发的沟通成本就增加了,所以一般上我们都是通过swagger进行api文档生成的.现在由于使用了统一 ...

  6. Spring Boot 2&period;X&lpar;十五&rpar;:集成 Swagger2 开发 API 文档(在线&plus;离线)

    前言 相信很多后端开发在项目中都会碰到要写 api 文档,不管是给前端.移动端等提供更好的对接,还是以后为了以后交接方便,都会要求写 api 文档. 而手写 api 文档的话有诸多痛点: 文档更新的时 ...

  7. springboot &plus; swagger2 生成api文档

    直接贴代码: <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-sw ...

  8. Spring Boot 整合Swagger2构建API文档

    1.pom.xml中引入依赖 <dependency> <groupId>io.springfox</groupId> <artifactId>spri ...

  9. SpringFox swagger2 and SpringFox swagger2 UI 接口文档生成与查看

    依赖: <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 --> <dependency ...

随机推荐

  1. Git Commit Template 提交模板

    多人协作开发一个项目时,版本控制工具是少不了的,git是linux 内核开发时引入的一个优秀代码管理工具,利用它能很好使团队协作完成一个项目.为了规范团队的代码提交,也方便出版本时的release n ...

  2. JS实现日历控件选择后自动填充

    最近在做人事档案的项目,在做项目的初期对B/S这块不是很熟悉,感觉信心不是很强,随着和师哥同组人员的交流后发现,调试程序越来越好了,现在信心是倍增,只要自己自己踏实的去研究.理解代码慢慢的效果就出来了 ...

  3. Swift中文教程&lpar;一&rpar;--欢迎来到Swift的世界

    原文:Swift中文教程(一)--欢迎来到Swift的世界 Apple凌晨时在WWDC发布了Swift编程语言,语法简介我很喜欢,市面上没有完整的中文教程,我在ibooks里面下载了英文原版,现在开始 ...

  4. Ubuntu16&period;04重新安装MySQL数据库

    安装之前先检查mysql是否卸载干净 dpkg --list|grep mysql 如果没有卸载干净请看上篇文章将mysql卸载干净 Ubuntu16.04彻底卸载MySQL 开始安装 可以直接默认安 ...

  5. npm报错没有权限

    在npm install经常会报错没有权限 这个时候需要清除一下缓存 npm cache clean --force

  6. maven 核心概念

    1). 项目构建过程中的各个环节 . 清理 . 编译 . 测试 . 报告 . 打包 . 安装 . 部署 2). 配置环境变量 . 配置 JDK 配置 JAVA_HOME + PATH maven 需要 ...

  7. sql server维护解决方案(备份、检查完整性、索引碎片整理)

    请务必看原文 原文:https://ola.hallengren.com/frequently-asked-questions.html 经常问的问题 入门 如何开始使用SQL Server维护解决方 ...

  8. Java 开源博客 Solo 1&period;6&period;0 发布 - 新后台

    简介 Solo 是一款一个命令就能搭建好的 Java 开源博客系统,并内置了 15+ 套精心制作的皮肤.除此之外,Solo 还有着非常活跃的社区,文章分享到社区后可以让很多人看到,产生丰富的交流互动. ...

  9. 面试笔试总结(二)之 C&plus;&plus;基础

    上节,一定要写出基于引用计数的智能指针 明白单例模式 会写出代码 复习: 1- 2- 推荐leveldb ....是c++的写代码很规范的地方?比如智能指针在这里... 对类进行改造 可以改成Sing ...

  10. &lpar;原創&rpar; Gvim 個人習慣常用設定 &lpar;vim&rpar;

    不定期更新這篇,因為查詢到好用的設定或者插件就會更新自己的設定. "set nocompatible let $LANG='zh_TW.UTF-8' set langmenu=zh_tw.u ...