这是我参与11月更文挑战的第27天,活动详情查看:2021最后一次更文挑战
本文相关代码:github.com/Dr-Water/fa…
一、Swagger简介
Swagger是一款Restful接口的文档在线自动生成和功能测试功能软件。 Swagger是一个规范和完整的框架,用于生成、描述、调用和可视化Restful风格的Web服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步。
二、Swagger优缺点
优点:
- 节省了大量手写接口文档的时间
- 通过注解自动生成在线文档
- 接口在线调用调试
缺点:
- 代码耦合,需要注解支持
- 代码侵入性比较强
- 无法测试错误的请求方式、参数及不限于这些
手动API痛点:
- 文档更新的时候,需要再次发送一份给前端,也就是文档更新交流不及时
- 接口返回结果不明确
- 不能直接在线测试接口,通常需要使用工具,比如postman
- 接口文档太多,不好管理
四、集成配置
4.1引入依赖
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
4.2 书写swagger配置类
package com.ratel.json.config;
import io.swagger.annotations.ApiOperation;
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.ApiKey;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.List;
import static com.google.common.collect.Lists.newArrayList;
/**
* @业务描述:
* @package_name: com.ratel.json.config
* @project_name: fast-json-test
* @author: ratelfu@qq.com
* @create_time: 2019-09-17 17:27
* @copyright (c) ratelfu 版权所有
*/
@Configuration
@EnableSwagger2
public class Swagger2Config {
/**
* 是否开启swagger,正式环境一般是需要关闭的 ,使用@value注解从application.yml中获取属性
*/
@Value("${swagger.enabled}")
private boolean enableSwagger;
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
//加了ApiOperation注解的类,才生成接口文档
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
//包下的类,才生成接口文档
//.apis(RequestHandlerSelectors.basePackage("com.ratel.controller"))
.paths(PathSelectors.any())
.build()
.securitySchemes(security());
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Spring Boot中使用Swagger2构建RESTful APIs")
.description("更多Spring Boot相关文章请关注:https://blog.csdn.net/weter_drop")
.termsOfServiceUrl("https://blog.csdn.net/weter_drop/")
.contact("ratel")
.version("1.0")
.build();
}
/**
*添加swagger的安全相关的参数,比如在请求头中添加 token
* @return
*/
private List<ApiKey> security() {
return newArrayList(
new ApiKey("token", "token", "header")
);
}
}
其中:
@Configuration 标注在类上,相当于把该类作为spring的xml配置文件中的,作用为:配置spring容器(应用上下文)。用@Bean标注方法等价于XML中配置bean。 @EnableSwagger2 的作用是启用Swagger2相关功能。 Docket对象包含三个方面信息:
- 整个API的描述信息,即ApiInfo对象包括的信息,这部分信息会在页面上展示。
- 指定生成API文档的包名。
- 指定生成API的路径。
4.3 controller的代码
package com.ratel.json.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ratel.json.entity.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* @业务描述:
* @package_name: com.ratel.json.controller
* @project_name: fast-json-test
* @author: ratelfu@qq.com
* @create_time: 2019-09-17 17:34
* @copyright (c) ratelfu 版权所有
*/
@RestController
@RequestMapping("/user")
@Api(description = "用户相关的controller")
public class UserController {
@ApiOperation("保存")
@PostMapping("/save")
public boolean save(@RequestBody String jsonString){
//方法一
//将前端传过来的json字符串转换为map
Map map = JSONObject.parseObject(jsonString, Map.class);
System.out.println(map);
//获取前端传过来的第一个list
String list1 = map.get("list1").toString();
List<User> objects = JSON.parseArray(list1,User.class);
for (User object : objects) {
System.out.println(object);
}
//获取前端传过来的第二个list
String list2 = map.get("list2").toString();
List<User> objects1 = JSON.parseArray(list2,User.class);
for (User object : objects1) {
System.out.println(object);
}
//方法二
System.out.println("=========================");
Map map1 = JSON.parseObject(jsonString, Map.class);
System.out.println(map1);
//User user = JSON.parseObject(jsonString, User.class);
// System.out.println(user);
//jsonToList(jsonString,User.class);
return true;
}
@ApiOperation("保存用户")
@PostMapping("/saveUser")
public boolean saveUser(@RequestBody User user){
System.out.println(user);
return true;
}
@ApiOperation(value = "获取用户", notes = "根据输入的用户名和密码获取用户")
@GetMapping("/getUser")
@ApiImplicitParams({
//name的值和方法请求参数的名字一样否则在swagger中会出现多个参数
@ApiImplicitParam(name = "userName", value = "用户名啊", required = true, dataType = "String", paramType = "query"),
@ApiImplicitParam(name = "password", value = "用户密码啊", required = false, dataType = "String", paramType = "query")
})
public User getUser(@RequestParam String userName,@RequestParam String password){
return new User(userName,password);
}
/**
* 将list类型的json字符串转为list
*
* @param jsonString
* @param clazz
* @param <T>
* @return
*/
public static <T> List<T> jsonToList(String jsonString, Class<T> clazz) {
List<T> offList = JSONObject.parseArray(jsonString, clazz);
return offList;
}
}
用户实体类
package com.ratel.json.entity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* @业务描述:
* @package_name: com.ratel.json.entity
* @project_name: fast-json-test
* @author: ratelfu@qq.com
* @create_time: 2019-09-17 17:15
* @copyright (c) ratelfu 版权所有
*/
@Data
@ApiModel
@AllArgsConstructor
public class User {
/**
*用户名
*/
@ApiModelProperty("用户名")
private String username;
/**
*用户密码
*/
@ApiModelProperty("用户密码")
private String password;
}
常用注解说明:
@Api:用于controller类上,说明该类的作用
tags=“说明该类的作用,可以在UI界面上看到的注解”
value=“该参数没什么意义,在UI界面上也看到,所以不需要配置”
description = "描述"
@ApiOperation:用在controller的方法上,用来说明方法用途、作用
value=“说明方法的用途、作用”
notes=“方法的备注说明”
@ApiImplicitParam:用来给方法入参增加说明
name:参数名
value:参数的汉字说明、解释
dataType: 参数类型,默认String
required : 参数是否必传,true必传
defaultValue:参数的默认值
paramType:参数放在哪个地方
header请求参数的获取:@RequestHeader,参数从请求头获取
query请求参数的获取:@RequestParam,参数从地址栏问号后面的参数获取
path(用于restful接口)请求参数的获取:@PathVariable,参数从URL地址上获取
body(不常用)参数从请求体中获取
form(不常用)参数从form表单中获取
**@ApiImplicitParams:**用在controller的方法上,一组@ApiImplicitParam **@ApiResponse:**用在 @ApiResponses里边,一般用于表达一个错误的响应信息
code:数字,例如400
message:信息,例如"请求参数没填好"
response:抛出异常的类
@ApiResponses: 用在controller的方法上,用于表示一组响应 @ApiModel: 用在返回对象类上,描述一个Model的信息(这种一般用在post创建的时候,使用@RequestBody这样的场景,请求参数无法使用@ApiImplicitParam注解进行描述的时候) @ApiModelProperty: 用在出入参数对象的字段上,表示对model属性的说明或者数据操作更改
value = 字段说明
name = 重写属性名字
dataType = 重写属性类型
required = 是否必填,true必填
example = 举例说明
hidden = 隐藏
@ApiIgnore: 使用该注解忽略这个API,不会生成接口文档。可注解在类和方法上
4.4 swagger访问页面
启动项目后,输入http://localhost:8080/swagger-ui.html访问,页面如下:
进行测试:
其中:
201 表示请求成功并且服务器创建了新的资源
401 表示未授权,请求要求身份验证
403 表示拒绝访问
404 找不到路径,即路径错误
如果项目需要验证token值则需要输入token值后进行测试:
和前端进行联调的时候核对字段:
可以使用下图红框所示:前提是你在相应的实体类上加上了@ApiModel 各个属性上加上了: @ApiModelProperty("用户名") 注解
五. 可能会遇到的问题
5.1 没有编写swagger配置类,会出现这样的错误
5.2、如果paramType与方法参数获取使用的注解不一致,会直接影响到参数的接收。
如下图,paramType设置header,应该用@RequestHeader接收,但用了@RequestParam接收参数,就会报错。
5.3 接收参数不一致报错如下:
5.4 API列表中同一个方法出现多个
原因:get方法没有在RequestMapping中指定method类型。
解决方案:控制层中定义的方法必须在@RequestMapper中显示的指定RequestMethod类型(get/post等),否则SawggerUi会默认为全类型皆可访问, API列表中会生成多条项目。
swagger原始json的获取方法
swagger的页面其实是由json数据组成,可以将这些json数据存储到数据库中,以便在不启动项目的情况下访问swagger。
http://localhost:8010/json/v2/api-docs