美文网首页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"
      • Lemois:请问其中创建用户中的Model例子是怎么才会显示出来的,为什么我在写的时候对象不能生成例子?谢谢!
      • zxy1994:mark
      • yshenhn:转载了您的这边文章,您写的博客和spring cloud太棒啦,买来看了大部分能力,简单易懂,再跟着博客看看,源码搞搞很容易理解.啥时候再出一些spring boot或者spring cloud深入一点的书.:grin: :grin: :grin:
      • 欧尼酱嘿嘿嘿:几句代码就配置好了 666 谢谢博主
        程序猿DD:@欧尼酱嘿嘿嘿 感谢支持~
      • 守望者阿阳:@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