
由于
Spring Boot能够快速开发、便捷部署等特性,相信有很大一部分Spring Boot的用户会用来构建RESTful API。而我们构建RESTful API的目的通常都是由于多终端的原因,这些终端会共用很多底层业务逻辑,因此我们会抽象出这样一层来同时服务于多个移动端或者Web前端。本文将介绍RESTful API的重磅好伙伴Swagger2,它可以轻松的整合到Spring Boot中,并与Spring MVC程序配合组织出强大RESTful API文档。它既可以减少我们创建文档的工作量,同时说明内容又整合入实现代码中,让维护文档和修改代码整合为一体,可以让我们在修改代码逻辑的同时方便的修改文档说明。另外Swagger2也提供了强大的页面测试功能来调试每个RESTful API。此引用来自程序猿DD。
在Spring Boot中应用中Swagger2构建强大的API文档十分方便,只需要在项目中添加Swagger2的依赖,然后在Spring Boot的启动的main方法的类上加上注解@EnableSwagger2就可以完成构建工作。效果图如下:

在图中可以看出,我自定义的Controller只有FileController,而其他的都是Spring Boot的一些控制器,而这些API文档往往是我们不需要的,所以,仅仅使用Swagger2的默认方式显然是不能满足我们的需求的,所以,我们需要自定义Swagger文档。
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.0</version>
</dependency>我们写一个Swagger的配置类,添加上@Configuration注解方便被Spring Boot配置,添加@EnableSwagger2注解启动Swagger文档构建能力。需要注意的是,一般配置类可以放在Spring Boot启动类的同一个包里,如果没有放,那么请在Spring Boot的启动类上添加包扫描注解@ComponentScan(basePackages = {"com.lemon.security"}),然后配置类可以放在任何的这个包的子包下面。
package com.lemon.security.web.config;
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.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* @author lemon
* @date 2018/4/3 下午1:01
*/
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket createRestfulApiDocs() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.lemon.security.web.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("自定义RESTful API文档")
.description("更多内容请关注CSDN博客:https://blog.csdn.net/Lammonpeter")
.termsOfServiceUrl("https://blog.csdn.net/Lammonpeter")
.contact(new Contact("Lemon", "https://blog.csdn.net/Lammonpeter", "lemon_jiang@aliyun.com"))
.version("1.0.0")
.build();
}
}对上面的代码有如下解释:
通过createRestfulApiDocs方法创建Docket的Bean之后,apiInfo()用来创建该API的基本信息(这些基本信息会展现在文档页面中)。select()函数返回一个ApiSelectorBuilder实例用来控制哪些接口暴露给Swagger来展现,本例采用指定扫描的包路径来定义,Swagger会扫描该包下所有Controller定义的API,并产生文档内容(除了被@ApiIgnore指定的请求)。
在完成了上述配置后,其实已经可以生产文档内容,但是这样的文档主要针对请求本身,而描述主要来源于函数等命名产生,对用户并不友好,我们通常需要自己增加一些说明来丰富文档内容。如下所示,我们通过@ApiOperation注解来给API方法增加说明,通过@ApiImplicitParams、@ApiImplicitParam注解来给参数增加说明,通过@ApiModelProperty注解来给实体类的属性增加说明。
Controller添加文档说明:package com.lemon.security.web.controller;
import cn.hutool.core.io.IoUtil;
import com.lemon.security.web.dto.FileInfo;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
/**
* @author lemon
* @date 2018/4/2 下午2:19
*/
@RestController
@RequestMapping("/file")
public class FileController {
private static String folder = "/Users/lemon/IdeaProjects/spring-security/lemon-security-demo";
@PostMapping
@ApiOperation(value = "文件上传接口", notes = "访问此接口可以实现文件上传")
@ApiImplicitParam(name = "file", value = "使用MultipartFile的实例对象来接收文件数据", required = true, dataTypeClass = MultipartFile.class)
public FileInfo upload(@RequestParam("file") MultipartFile file) throws IOException {
System.out.println("上传文件的表单name值为:" + file.getName());
System.out.println("文件路径为:" + file.getOriginalFilename());
System.out.println("文件大小为:" + file.getSize());
File localFile = new File(folder, System.currentTimeMillis() + ".txt");
// 执行上传操作
file.transferTo(localFile);
return new FileInfo(localFile.getAbsolutePath());
}
@GetMapping("/{id}")
@ApiOperation(value = "文件下载接口", notes = "访问此接口并提供文件ID即可下载文件")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "文件ID", required = true, dataTypeClass = String.class),
@ApiImplicitParam(name = "request", value = "HttpServletRequest实例对象,自动注入,无需传递", required = true, dataTypeClass = HttpServletRequest.class),
@ApiImplicitParam(name = "response", value = "HttpServletResponse实例对象,自动注入,无需传递", required = true, dataTypeClass = HttpServletResponse.class)
})
public void download(@PathVariable String id, HttpServletRequest request, HttpServletResponse response) {
System.out.println(folder);
try (
// 这是JDK7的特性,关于流的操作,可以写在try后面的圆括号里,这样就无需手动关闭流
InputStream inputStream = new FileInputStream(new File(folder, id + ".txt"));
OutputStream outputStream = response.getOutputStream()
) {
// 设置下载的文件类型
response.setContentType("application/x-download");
// 设置下载后的文件名
response.setHeader("Content-Disposition", "attachment;filename=test.txt");
IoUtil.copy(inputStream, outputStream);
// 刷新输出流
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}其中,
@ApiOperation注解的value属性一般都是简单描述API的功能,notes属性详细描述API的功能;
@ApiImplicitParams用来描述一个方法的多个参数的注解;
@ApiImplicitParam用来表述单个参数,name属性来描述参数的名称,value用来描述参数的意思,required表示参数是否是必需值,dataTypeClass或者dataType指定了数据的类型。
这里仅仅是对注解进行说明,而代码本身来自上一节内容,即《Spring Security技术栈开发企业级认证与授权(六)使用REST方式处理文件服务》。
package com.lemon.security.web.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author lemon
* @date 2018/4/2 下午2:24
*/
@Data
public class FileInfo {
@ApiModelProperty(value = "文件上传后的文件路径")
private String path;
public FileInfo(String path) {
this.path = path;
}
}其中,@ApiModelProperty用来描述参数的意义。
配置完成以后,运行Spring Boot应用,在地址栏访问http://localhost:8080/swagger-ui.html就可以进入自定义的Swagger文档界面,效果图如下:


API文档访问与调试在上图请求的页面中,Swagger除了查看接口功能外,还提供了调试测试功能,点击“Try it out!”按钮,即可完成了一次请求调用!此时,你也可以通过几个POST请求来验证之前的POST请求是否正确。相比为这些接口编写文档的工作,我们增加的配置内容是非常少而且精简的,对于原有代码的侵入也在忍受范围之内。因此,在构建RESTful API的同时,加入Swagger来对API文档进行管理,是个不错的选择。