美文网首页springboot技术spring boot
Spring Boot中使用Swagger2构建强大的RESTf

Spring Boot中使用Swagger2构建强大的RESTf

作者: 程序猿DD | 来源:发表于2016-04-18 22:40 被阅读83150次

由于Spring Boot能够快速开发、便捷部署等特性,相信有很大一部分Spring Boot的用户会用来构建RESTful API。而我们构建RESTful API的目的通常都是由于多终端的原因,这些终端会共用很多底层业务逻辑,因此我们会抽象出这样一层来同时服务于多个移动端或者Web前端。

这样一来,我们的RESTful API就有可能要面对多个开发人员或多个开发团队:IOS开发、Android开发或是Web开发等。为了减少与其他团队平时开发期间的频繁沟通成本,传统做法我们会创建一份RESTful API文档来记录所有接口细节,然而这样的做法有以下几个问题:

  • 由于接口众多,并且细节复杂(需要考虑不同的HTTP请求类型、HTTP头部信息、HTTP请求内容等),高质量地创建这份文档本身就是件非常吃力的事,下游的抱怨声不绝于耳。
  • 随着时间推移,不断修改接口实现的时候都必须同步修改接口文档,而文档与代码又处于两个不同的媒介,除非有严格的管理机制,不然很容易导致不一致现象。

为了解决上面这样的问题,本文将介绍RESTful API的重磅好伙伴Swagger2,它可以轻松的整合到Spring Boot中,并与Spring MVC程序配合组织出强大RESTful API文档。它既可以减少我们创建文档的工作量,同时说明内容又整合入实现代码中,让维护文档和修改代码整合为一体,可以让我们在修改代码逻辑的同时方便的修改文档说明。另外Swagger2也提供了强大的页面测试功能来调试每个RESTful API。具体效果如下图所示:

alt=

下面来具体介绍,如果在Spring Boot中使用Swagger2。首先,我们需要一个Spring Boot实现的RESTful API工程,若您没有做过这类内容,建议先阅读
Spring Boot构建一个较为完成的RESTful APIs和单元测试

下面的内容我们会以教程样例中的Chapter3-1-1进行下面的实验(Chpater3-1-5是我们的结果工程,亦可参考)。

添加Swagger2依赖

pom.xml中加入Swagger2的依赖


<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.2.2</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.2.2</version>
</dependency>

创建Swagger2配置类

Application.java同级创建Swagger2的配置类Swagger2


@Configuration
@EnableSwagger2
public class Swagger2 {

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.didispace.web"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Spring Boot中使用Swagger2构建RESTful APIs")
                .description("更多Spring Boot相关文章请关注:http://blog.didispace.com/")
                .termsOfServiceUrl("http://blog.didispace.com/")
                .contact("程序猿DD")
                .version("1.0")
                .build();
    }

}

如上代码所示,通过@Configuration注解,让Spring来加载该类配置。再通过@EnableSwagger2注解来启用Swagger2。

再通过createRestApi函数创建Docket的Bean之后,apiInfo()用来创建该Api的基本信息(这些基本信息会展现在文档页面中)。select()函数返回一个ApiSelectorBuilder实例用来控制哪些接口暴露给Swagger来展现,本例采用指定扫描的包路径来定义,Swagger会扫描该包下所有Controller定义的API,并产生文档内容(除了被@ApiIgnore指定的请求)。

添加文档内容

在完成了上述配置后,其实已经可以生产文档内容,但是这样的文档主要针对请求本身,而描述主要来源于函数等命名产生,对用户并不友好,我们通常需要自己增加一些说明来丰富文档内容。如下所示,我们通过@ApiOperation注解来给API增加说明、通过@ApiImplicitParams@ApiImplicitParam注解来给参数增加说明。


@RestController
@RequestMapping(value="/users")     // 通过这里配置使下面的映射都在/users下,可去除
public class UserController {

    static Map<Long, User> users = Collections.synchronizedMap(new HashMap<Long, User>());

    @ApiOperation(value="获取用户列表", notes="")
    @RequestMapping(value={""}, method=RequestMethod.GET)
    public List<User> getUserList() {
        List<User> r = new ArrayList<User>(users.values());
        return r;
    }

    @ApiOperation(value="创建用户", notes="根据User对象创建用户")
    @ApiImplicitParam(name = "user", value = "用户详细实体user", required = true, dataType = "User")
    @RequestMapping(value="", method=RequestMethod.POST)
    public String postUser(@RequestBody User user) {
        users.put(user.getId(), user);
        return "success";
    }

    @ApiOperation(value="获取用户详细信息", notes="根据url的id来获取用户详细信息")
    @ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Long")
    @RequestMapping(value="/{id}", method=RequestMethod.GET)
    public User getUser(@PathVariable Long id) {
        return users.get(id);
    }

    @ApiOperation(value="更新用户详细信息", notes="根据url的id来指定更新对象,并根据传过来的user信息来更新用户详细信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Long"),
            @ApiImplicitParam(name = "user", value = "用户详细实体user", required = true, dataType = "User")
    })
    @RequestMapping(value="/{id}", method=RequestMethod.PUT)
    public String putUser(@PathVariable Long id, @RequestBody User user) {
        User u = users.get(id);
        u.setName(user.getName());
        u.setAge(user.getAge());
        users.put(id, u);
        return "success";
    }

    @ApiOperation(value="删除用户", notes="根据url的id来指定删除对象")
    @ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Long")
    @RequestMapping(value="/{id}", method=RequestMethod.DELETE)
    public String deleteUser(@PathVariable Long id) {
        users.remove(id);
        return "success";
    }

}

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

alt

API文档访问与调试

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

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

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

完整结果示例可查看Chapter3-1-5

参考信息

相关文章

网友评论

  • 38c65df179d4:很有帮助,我要订阅你。
  • 刘彦青:报bean 加载错误: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'afterAppController': Unsatisfied dependency expressed through field 'applyService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'srTraApplyService': Unsatisfied dependency expressed through field 'srBusesService'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'io.sr.modules.user.api.SrBusesService': FactoryBean threw exception on object creation; nested exception is java.lang.NullPointerException
  • 没有故事的老大爷:很不错, 感谢
  • 起个名字啦嘛喃:你好,请问下,通过这个能否生成json格式的接口文档,
  • 吉祥噜噜:求注解用法官网地址。上swagger.io找了一圈没找到介绍注解用法的页面。
    吉祥噜噜:已找到 https://github.com/swagger-api/swagger-core/wiki/Annotations#apimodel
  • 57cd5be28f8f:swagger注解写的过多,ApiImplicitParams不能通过拦截器或者aop配置吗?
  • 安静听歌:你好,请问输入参数为map的时候,应该怎么描述呢
  • 第三只筷子:版本换成2.7.0比较好,这样传入对象为参数时,对象中的字段会分开输入,有多个输入框😬
    程序猿DD:@第三只筷子 可以看看我做的starter,用的2.7.0
  • 蜗牛小传:楼主看了你的文章后,正好把Swagger加到现在做的项目中。但是有个问题一直不知道怎么回事。在swagger的ui页面,试用的是POST请求,输入参数后程序得不到参数(1、String arg = request.getQueryString();2、String userno=request.getParameter("userno");)这两种方式获取到的值都为null。请问这个要怎么处理?期待收到您的答复
  • From汉圈的程序猿:为什么我运行出来没有样式 只有光秃秃的输入框和超链接
  • Arestory:页面什么的都出来了,可是当我在swagger页面上面测试带参数的post接口时候,返回的结果一直是这样
    {
    "timestamp": 1509691629812,
    "status": 400,
    "error": "Bad Request",
    "exception": "org.springframework.web.bind.MissingServletRequestParameterException",
    "message": "Required String parameter 'account' is not present",
    "path": "/register.do"
    }
    用postman就不会
    pkxutao:paramType = "query"
  • 00fc87d16fbb:请问其中创建用户中的Model例子是怎么才会显示出来的,为什么我在写的时候对象不能生成例子?谢谢!
  • zxy1994:mark
  • yshenhn:转载了您的这边文章,您写的博客和spring cloud太棒啦,买来看了大部分能力,简单易懂,再跟着博客看看,源码搞搞很容易理解.啥时候再出一些spring boot或者spring cloud深入一点的书.:grin: :grin: :grin:
  • e5633f0ce040:几句代码就配置好了 666 谢谢博主
    程序猿DD:@欧尼酱嘿嘿嘿 感谢支持~
  • 15abe37933a3:@Bean
    public Docket createRestApi() {
    return new Docket(DocumentationType.SWAGGER_2)
    .apiInfo(apiInfo())
    .select()
    .apis(RequestHandlerSelectors.basePackage("com.didispace.web"))
    .paths(PathSelectors.any())
    .build();
    }
    上面的代码中的 basePackage 支持模糊匹配吗?
  • 95607e4d6472:补充代码:
    Demo代码缺少参数:所有/{id}的请求中,id参数需要添加paramType="path"

    @ApiOperation(value="删除用户", notes="根据url的id来指定删除对象")
    @ApiImplicitParam(name = "id",paramType = "path", value = "用户ID", required = true, dataType = "Long")
    @RequestMapping(value="/{id}", method=RequestMethod.DELETE)
    public String deleteUser(@PathVariable Long id) {
    users.remove(id);
    return "success";
    }
  • 17eaf06b1c54:受用了,感谢!在此提出一个问题,http://localhost:8080/swagger-ui.html 这个url可以更改的吧,比如不想出现swagger-ui.html,将它替换成其地址,这个应该在哪里更改呢?非常感谢!
    17eaf06b1c54:“将它替换成其它地址”,手残打错。
  • 陈小白_:这样会不会对代码有太大侵入性?
  • xiangyue:博主,其实你可以不用在Controller代码里面进行配置的, 只需要上面那个配置文件即可,swagger会自动寻找你的配置,这样代码的侵入就不存在啦,正式运行的时候去掉相应的依赖就okay
    6afe2bab256f:@xiangyue 好像没有注释说明
    xiangyue: @张光光 swagger会自动扫描你的controller里面的接口的!如果不针对具体方法指定请求方式,它会将put,get,post等请求方式全部实现
    张光光: @xiangyue 那怎么针对具体的接口进行配置?
  • 不想当码农的程序员:swagger 2.2.2 和 fegin有冲突。 现在swagger已经是2.7了
  • 8ba605054de8:请问这个方式能生成swagger.json文件吗?
  • _苏陌年:请教一下如果参数是个实体类,里面的字段如何设置成拥有默认值,例如user类,name 默认值为xiaoming 而不是string
    xiangyue:可以参考下我的,其实没必要传类,swagger自动帮你扫描,http://www.jianshu.com/p/8d0f5b2064a3
  • 915f1433e136:请问下 swagger-ui.html这个在哪?为什么我下载的没看到,还有看其他资料说是要改index.html里面的url为 http:xx.xx.com/api-docs的形式,为什么api-docs也没看到,求解。
    NormanHu:swagger的版本问题,你跟楼主的依赖核对一下
  • 3013c6234bf6:spring boot使用swagger后,使用的模板是Thymeleaf,但是访问/swagger-ui.html后,页面是出来了,不过js文件没有加载到,这是咋回事呢?
    程序猿DD:@3013c6234bf6 日志里启动的时候有打印出/v2/api-docs这个映射吗?如果没有的话,就是Swagger创建的配置不对。
  • 5ca05e2f4a41:正在引入swagger,写的很好,学习了
  • 流花飘原:感觉这样写 代码侵入很强啊。。改动起来也不方便呢
    xiangyue:可以参考下我写的,http://www.jianshu.com/p/8d0f5b2064a3
    xiangyue: @流花飘原 可以向上参照下我的评论哟
  • 快看看:我用spring cloud +swagger 启动都正常,但是访问不到swagger-ui.html啊
    cf9c163abc5a:你的配置类没Swagger配置类没被加载,在其它配置类中导入
  • c62ce50e8fbb:感谢楼主分享,请问swagger有没有导出功能。就是把所有的请求导出做一个文档。 @程序猿DD
    程序猿DD:@honshe丶D 用editor导出
  • 8df40295b983:我的springboot项目中使用了Thymeleaf,导致swaggerui页面样式无法加载,api也无法显示,配置中是否要注意其他呢
    xiangyue:是不是你没有将静态资源的配置注释掉?可以参考下我的http://www.jianshu.com/p/8d0f5b2064a3
  • dad4d8cc1b4e:Swagger 加载太慢了,怎么解决?
    df2e9104e2df:@触动心灵的旋律 请问Eclipse怎么将注解通过正则匹配注释掉啊,有详细教程吗?
    6562c9d9e900:在打注解的时候,用上全限定名 ,在打线上包的时候正则匹配,关于swagger的所有注解注释掉。如果你用 的eclipse 或者myeclipse 很简单,idea 就不知道怎么搞了,应该也有类似的。。这个方法比较简单出爆。本地的话就无所谓啦,
    ae30b28dc08b:@翟玉勇 同感,项目越来越大之后启动太慢了
  • 默默守护:支持,楼主写的超好,最近正好用spring boot
  • 265e90b74be7:比《JavaEE开发的颠覆者:Spring Boot 实战》这本书写的要好:+1:,已加关注,博主加油:feet:
    Angeladaddy:严重同意,这本书我买了就后悔了,啥也没讲透,还不如看官网
    265e90b74be7:@程序猿DD 那本书给我的感觉就是整篇贴代码,代码里面写注释,自己理解没讲清楚,写的也浅尝辄止,看的提不起兴趣来,比同期今年4月份出版的《Spring In Action 第四版》质量要差的多:sweat:,博主写作风格和国外作者风格相近:+1:
    程序猿DD::scream:评价太高啦…不过会坚持继续分享的:angry:

本文标题:Spring Boot中使用Swagger2构建强大的RESTf

本文链接:https://www.haomeiwen.com/subject/gmmalttx.html