A.3 springboot swagger

springboot swagger

1. 介绍

目前大部分项目都是前后端分离,或者是以服务的形式暴露RESTful API接口,但是如何向调用方提供接口说明文档?如何快速单元测试我们的接口?如何在更改了接口之后快速的更新于接口文档中?带着这些问题,引入swagger。

特性:

  • swagger可以生成互动性的API控制台
  • 调用者和开发者尝试API
  • 形成一种合作契约,让团队更加敏捷的开发
  • 对代码有一定的入侵型

2. 集成

2.1 POM配置

pom中增加swagger的依赖

<!--Swagger Restful UI 集成依赖-->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.4.0</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.4.0</version>
</dependency>

2.2 开启swagger

在入口程序的启动类(Application.java)上增加@EnableSwagger2的注解

@EnableSwagger2
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        //启动入口
        SpringApplication.run(Application.class, args);
    }

}

2.3 配置swagger

@Configuration
public class AppConfig {
    
    /**
     * 创建swagger ui的摘要
     * @return
     */
    @Bean
    public Docket docket() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                // 扫描的class的包路径
                .apis(RequestHandlerSelectors.basePackage("pers.mateng.demo.springboot"))
                // 只扫描类上有API注解的class
//                .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                // 只扫描方法上有ApiOperation注解的方法
//                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                .paths(PathSelectors.any())
                .build();
    }

    /**
     * swagger ui的标题信息
     * @return
     */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("标题")
                .description("副标题")
                .version("1.0")
                .build();
    }

}

2.4 声明 API

修改UserController,注意类注解(@Api)和方法注解(@ApiOperation)

@RestController
@RequestMapping(path="user")
@Api(tags="用户管理")
public class UserController {
    
    @Autowired
    private UserDao userDao;
    
    @ApiOperation(value="查询用户", notes="测试无请求参数的swagger-ui")
    @RequestMapping(method=RequestMethod.GET)
    public List<User> findAll() {
        return userDao.findAll();
    }
    
    @ApiOperation(value="增加用户-测试1", notes="测试application/x-www-form-urlencoded形式提交参数")
    @RequestMapping(method=RequestMethod.POST)
    public User add(@ModelAttribute User user) {
        return userDao.save(user);
    }
    
    @ApiOperation(value="修改用户-测试1", notes="测试application/json形式提交参数")
    @RequestMapping(path="/{id}", method=RequestMethod.PUT)
    public User update1(@ApiParam(value="用户id") @PathVariable Long id, @RequestBody User user) {
        User temp = userDao.findOne(id);
        if(temp != null) {
            temp.setName(user.getName());
            temp.setAge(user.getAge());
            return userDao.save(temp);
        }
        return null;
    }
    
    @ApiOperation(value="根据id查询用户", notes="测试path参数提交")
    @GetMapping(path="/{id}")
    public User findById(@ApiParam(value="用户id") @PathVariable Long id) {
        return userDao.findOne(id);
    }
    
    @ApiOperation(value="根据id删除用户", notes="测试path参数提交")
    @DeleteMapping(path="/{id}")
    public Boolean del(@ApiParam(value="用户id") @PathVariable Long id) {
        userDao.delete(id);
        return Boolean.TRUE;
    }
}

3. 验证

启动工程,使用eclipse的run as重新启动Application的main函数

使用浏览器访问http://localhost:8888/swagger-ui.html。即可查看UserControlerl中暴漏的接口

填写参数后,点击 “try it out” 即可发送请求

4. 进阶详解

4.1 @ModelAttribute 的参数说明

在swagger-ui上查看“增加用户-测试1”接口,发现该接口的描述并不完善,问题如下:

  • 所有的请求参数都没有中文描述
  • 增加用户时参数“id”是不需要的

那么接口调用方是无法更好的理解接口的使用,解决办法如下

方法一

  • 使用 @ApiIgnore,让 swagger 忽略该实体类的参数
  • 使用 @ApiImplicitParams 重新声明参数的类型、说明、是否必须、参数位置

详细代码如下:

@ApiOperation(value="增加用户-测试2")
@RequestMapping(path="add2", method=RequestMethod.POST)
@ApiImplicitParams({
    @ApiImplicitParam(value="用户名", name="name", required=true, dataType="String", paramType="form"),
    @ApiImplicitParam(value="年龄", name="age", required=false, dataType="integer", paramType="form")
})
public User add2(@ApiIgnore @ModelAttribute User user) {
    return userDao.save(user);
}

方法二

  • 升级 swagger的版本到2.7.0
  • 使用 @ApiModelProperty(hidden=true) 隐藏参数
  • 使用 @ApiModelProperty(value = "xxx") 描述参数的说明
  • 使用 @ApiModelProperty(required=false) 标识参数是否必须输入

修改实体类User,==注意每个属性的注解==

@Entity
@Table(name="TB_USER")
public class User {
    
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="U_ID")
    @ApiModelProperty(hidden=true)
    private Long id;
    
    @Column(name="U_NAME", nullable = false, length=32, unique=true)
    @ApiModelProperty(value = "用户名称", required=true)
    private String name;
    
    @Column(name="U_AGE", length=4)
    @ApiModelProperty(value = "年龄", required=false)
    private Integer age;
    
    
    get/set...
}

4.2 @RequestBody 的参数说明

在 swagger-ui 上查看“修改用户-测试1”接口,发现该接口的描述并不完善,问题如下:

  • 所有的请求参数都没有中文描述
  • 为了追求 RESTful 风格,导致id声明了两次,在 Path 和 Resquestbody 中各声明了一次

所以接口调用方是无法更好的理解接口的使用,解决办法如下

方法一

不使用@Resquestbody 直接使用@ModelAttribute + @ApiImplicitParams的方法,==也就是4.1章节中的方法一==

代码如下:

@ApiOperation(value="修改用户-测试2", notes="测试application/x-www-form-urlencoded形式提交参数")
@RequestMapping(path="update2", method=RequestMethod.PUT)
@ApiImplicitParams({
    @ApiImplicitParam(value="用户id", name="id", required=true, dataType="Integer", paramType="form"),
    @ApiImplicitParam(value="用户名", name="name", required=true, dataType="String", paramType="form"),
    @ApiImplicitParam(value="年龄", name="age", required=false, dataType="integer", paramType="form")
})
public User update2(@ApiIgnore @ModelAttribute User user) {
    User temp = userDao.findOne(user.getId());
    if(temp != null) {
        temp.setName(user.getName());
        temp.setAge(user.getAge());
        return userDao.save(temp);
    }
    return null;
}

方法二

==也就是4.1章节中的方法二==

  • 使用 @ApiModelProperty(hidden=true) 隐藏参数
  • 使用 @ApiModelProperty(value = "xxx") 描述参数的说明
  • 使用 @ApiModelProperty(required=false) 标识参数是否必须输入

在实体类 User上增加注解,代码如下:

@Entity
@Table(name="TB_USER")
public class User {
    
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="U_ID")
    @ApiModelProperty(hidden=true)
    private Long id;
    
    @Column(name="U_NAME", nullable = false, length=32, unique=true)
    @ApiModelProperty(value = "用户名称", required=true)
    private String name;
    
    @Column(name="U_AGE", length=4)
    @ApiModelProperty(value = "年龄", required=false)
    private Integer age;

    get/set……
    
}

4.3 @PathVariable/@RequestParam 的参数说明

在这两个注解的前面增加swagger的注解@ApiParam(value="xxx")

@DeleteMapping(path="/{id}")
public Boolean del(@ApiParam(value="用户id") @PathVariable Long id) {
    userDao.delete(id);
    return Boolean.TRUE;
}

@GetMapping(path="/name")
public String findByName(@ApiParam(value="用户名") @RequestParam String name) {
    return name;
}

4.4 总结

在4.1章节和4.2章节中,处理参数的说明都使用了两种方法,概括的讲,方法一是在方法体的注解上想办法解决,方法二是在参数的属性上想办法解决。

方法一的优缺点分析:

  • 缺点:写的代码多。
  • 优点:适应性好,例如:有多个api接口都需要使用同一个javabean作为入参,但是每个接口实际暴露的参数不一样。就可以复用同一个javabean,而在各自的方法上处理。
  • 优点:对javabean没有入侵性。
  • 适合formdata/x-www-form-urlencoded表单提交。

方法二的优缺点:

  • 缺点:复用性差,例如:有多个api接口都需要使用同一个javabean作为入参,但是每个接口实际暴露的参数不一样。不能复用同一个javabean。
  • 缺点:如果一个javabean即作为入参,又作为出参。
  • 优点:代码写的少。
  • 适合application/json提交参数。

5. 源码

springboot-demo-3

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

推荐阅读更多精彩内容