技术分享 | Spring Boot 集成 Swagger

Swagger UI 允许任何人(无论您是开发团队还是最终用户)都可以可视化 API 资源并与之交互,而无需任何实现逻辑。它是根据您的 OpenAPI(以前称为 Swagger)规范自动生成的,具有可视化文档,可简化后端实现和客户端使用。

为什么使用Swagger

  • 跨语言性,支持 40 多种语言,Swagger 已经慢慢演变成了 OpenAPI 规范;
  • Swagger UI 呈现出来的是一份可交互式的 API 文档,我们可以直接在文档页面尝试 API 的调用,省去了准备复杂的调用参数的过程;
  • 对于某些没有前端界面 UI 的功能,可以用它来测试接口;
  • 联调方便,如果出问题,直接测试接口,实时检查参数和返回值,就可以快速定位问题。

Swagger快速开始

这里选择 2.9.2 版本。

<!-- swagger -->
<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 配置类,在工程下新建 config 包并添加一个 SwaggerConfig 配置类。

SwaggerConfig.java

```java
import com.google.common.collect.Lists;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.schema.ModelRef;
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;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    //作为Springfox框架的主要接口的构建器,提供合理的默认值和方便的配置方法。
    @Bean
    public Docket docket() {

        ParameterBuilder builder = new ParameterBuilder();
        builder.parameterType("header").name("token")
                .description("token值")
                .required(true)
                .modelRef(new ModelRef("string")); // 在swagger里显示header

        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("aitest_interface")
                .apiInfo(apiInfo())
                .globalOperationParameters(Lists.newArrayList(builder.build()))
                .select().paths(PathSelectors.any()).build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("aitest-mini系统")
                .description("aitest-mini接口文档")
                .contact(new Contact("tlibn", "", "103@qq.com"))
                .version("1.0")
                .build();
    }

}

添加控制器

添加一个控制器,在工程下新建 controller包并添加一个Controller控制器,如果已经存在Controller控制器,则直接启动服务也可以,如上章我们编写了HogwartsTestUserController类,此时直接启动服务即可。




打开 swagger 接口文档界面

启动 Spring Boot 服务,打开浏览器,访问:http://127.0.0.1:8081/swagger-ui.html,进入swagger接口文档界面。


测试

展开 hogwarts-test-user-controller 的任意接口,输入参数并点击执行,就可以看到接口测试结果了。

[图片上传失败...(image-769100-1654759268643)]
Swagger 常用注解

swagger 通过注解表明该接口会生成文档,包括接口名、请求方法、参数、返回信息的等等。
Api:修饰整个类,描述 Controller 的作用

Api(tags = "霍格沃兹测试学院-用户管理模块", hidden = true)



ApiOperation:描述一个类的一个方法,或者说一个接口

ApiOperation("查询用户列表")


ApiParam:单个参数描述
ApiModel:用对象来接收参数

ApiModel(value = "用户登录类", description = "请求类")


ApiProperty:用对象接收参数时,描述对象的一个字段

ApiModelProperty(value="用户id", example="1",required=true)


ApiResponse:HTTP 响应其中 1 个描述
ApiResponses:HTTP 响应整体描述
ApiIgnore:使用该注解忽略这个 API
ApiError :发生错误返回的信息
ApiImplicitParam:一个请求参数
ApiImplicitParams:多个请求参数
更多参见 https://github.com/swagger-api/swagger-core/wiki/Annotations-1.5.X#quick-annotation-overview

添加 Swagger 常用注解后的效果

添加 Swagger 常用注解后的示例代码
HogwartsTestUserController.java

@Api(tags = "霍格沃兹测试学院-用户管理模块", hidden = true)
@RestController
@RequestMapping("/api/user")
public class HogwartsTestUserController {

/**
 * 查询用户列表,返回一个JSON数组
 * */
@ApiOperation("查询用户列表")
@GetMapping("/users")
@ResponseStatus(HttpStatus.OK)
public Object getUsers(){
    List<UserDto> list = getData();
    return list;
}

/**
 * 查询用户信息,返回一个新建的JSON对象
 * */
@ApiOperation("查询用户信息")
@GetMapping("/users/{id}")
@ResponseStatus(HttpStatus.OK)
public Object getUser(@PathVariable("id") Long id){

    if(Objects.isNull(id)){
        return null;
    }

    List<UserDto> list= getData();
    UserDto userDto = getUserDto(id, list);

    return userDto;
}

/**
 * 新增用户
 * */
@ApiOperation("新增用户")
@PostMapping("/users")
@ResponseStatus(HttpStatus.CREATED)
public Object addUser(@RequestBody UserDto user){

    List<UserDto> list= getData();
    list.add(user);//模拟向列表中增加数据
    return user;
}

/**
 * 编辑用户
 * */
@ApiOperation("编辑用户")
@PutMapping("/users/{id}")
@ResponseStatus(HttpStatus.CREATED)
public Object editUser(@PathVariable("id") Long id,@RequestBody UserDto user){
    List<UserDto> list = getData();
    for (UserDto userDto:list) {
        if(id.equals(userDto.getId())){
            userDto = user;
            break;
        }
    }

    return user;
}

/**
 * 删除用户
 * */
@ApiOperation("删除用户")
@DeleteMapping("/users/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public Object deleteUser(@PathVariable("id") Long id){
    List<UserDto> list = getData();
    UserDto userDto = getUserDto(id, list);
    return  userDto;
}

/**
 * 模拟数据
 * */
private List<UserDto> getData(){
    List<UserDto> list=new ArrayList<>();

    UserDto userDto = new UserDto();
    userDto.setId(1L);
    userDto.setName("admin");
    userDto.setPwd("admin");
    list.add(userDto);

    userDto = new UserDto();
    userDto.setId(2L);
    userDto.setName("HogwartsTest1");
    userDto.setPwd("HogwartsTest1");
    list.add(userDto);

    userDto = new UserDto();
    userDto.setId(3L);
    userDto.setName("HogwartsTest2");
    userDto.setPwd("HogwartsTest2");
    list.add(userDto);

    userDto = new UserDto();
    userDto.setId(4L);
    userDto.setName("HogwartsTest3");
    userDto.setPwd("HogwartsTest3");
    list.add(userDto);

    return  list;
}

/**
 *  模拟根据id查询列表中的数据
 * @param id
 * @param list
 * @return
 */
private UserDto getUserDto( Long id, List<UserDto> list) {
    UserDto UserDto = null;
    for (UserDto user : list) {
        if (id.equals(user.getId())) {
            UserDto = user;
            break;
        }
    }
    return UserDto;
}

}



UserDto.java

@ApiModel(value = "用户登录类", description = "请求类")
public class UserDto {

 @ApiModelProperty(value="用户id", example="1",required=true)
 private Long id;

 @ApiModelProperty(value="用户名称", example="hogwarts1",required=true)
 private String name;

 @ApiModelProperty(value="用户密码", example="hogwarts2",required=true)
 private String pwd;

 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 String getPwd() {
     return pwd;
 }

 public void setPwd(String pwd) {
     this.pwd = pwd;
 }

}


Spring Boot 集成 Swagger就先讲到这里,大家可以照着代码,多练习一下哦~

[原文链接](https://mp.weixin.qq.com/s?__biz=MzU3NDM4ODEzMg==&mid=2247500463&idx=1&sn=24ea9238dc2eb1ce1745530cbe8464be&chksm=fd31a064ca462972926ce900ae0b2e40e1df4629e97cee80a05aee758b49fc8be26b72b97729#rd)

[更多技术文章](https://qrcode.ceba.ceshiren.com/link?name=article&project_id=qrcode&from=jianshu&timestamp=1652589012&author=BB)

喜欢软件测试的小伙伴们,如果我的博客对你有帮助、如果你喜欢我的博客内容,请 “点赞” “评论” “收藏” 一键三连哦!
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,000评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,745评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,561评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,782评论 1 298
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,798评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,394评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,952评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,852评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,409评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,483评论 3 341
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,615评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,303评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,979评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,470评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,571评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,041评论 3 377
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,630评论 2 359

推荐阅读更多精彩内容