为了账号安全,请及时绑定邮箱和手机立即绑定

Springboot实战:集成Swagger2

2021.04.11 23:09 693浏览

一、Swagger简介

在日常的工作中,我们往往需要给前端(WEB端、IOS、Android)或者第三方提供接口,这个时候我们就需要给他们提供一份详细的API说明文档。但维护一份详细的文档可不是一件简单的事情。

首先,编写一份详细的文档本身就是一件很费时费力的事情,另一方面,由于代码和文档是分离的,所以很容易导致文档和代码的不一致。这篇文章我们就来分享一种API文档维护的方式,即通过Swagger来自动生成Restuful API文档。

那什么是Swagger?我们可以直接看下官方的描述:

THE WORLD'S MOST POPULAR API TOOLING Swagger is the world’s largest framework of API developer tools for the OpenAPI Specification(OAS), enabling development across the entire API lifecycle, from design and documentation, to test and deployment.

这段话首先告诉大家Swagger是世界上最流行的API工具,并且Swagger的目的是支撑整个API生命周期的开发,包括设计、文档以及测试和部署。这篇文章中我们会用到Swagger的文档管理和测试功能。

对Swagger的作用有了基本的认识后,我们现在来看看怎么使用。

二、Swagger与Spring boot集成

第一步:引入对应jar包:

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

第二步,基本信息配置:

  1. @Configuration

  2. @EnableSwagger2

  3. public class Swagger2Config {

  4.    @Bean

  5.    public Docket createRestApi() {

  6.        return new Docket(DocumentationType.SWAGGER_2)

  7.                .apiInfo(apiInfo())

  8.                .select()

  9.                .apis(RequestHandlerSelectors.basePackage("com.pandy.blog.rest"))

  10.                .paths(PathSelectors.regex("/rest/.*"))

  11.                .build();

  12.    }


  13.    private ApiInfo apiInfo() {

  14.        return new ApiInfoBuilder()

  15.                .title("Blog系统Restful API")

  16.                .description("Blog系统Restful API")

  17.                .termsOfServiceUrl("http://127.0.0.1:8080/")

  18.                .contact("liuxiaopeng")

  19.                .version("1.0")

  20.                .build();

  21.    }


  22. }

基础的配置是对整个API文档的描述以及一些全局性的配置,对所有接口起作用。这里涉及到两个注解:

  • @Configuration是表示这是一个配置类,是JDK自带的注解,前面的文章中也已做过说明。

  • @EnableSwagger2的作用是启用Swagger2相关功能。

在这个配置类里面我么实例化了一个Docket对象,这个对象主要包括三个方面的信息:

  • 整个API的描述信息,即ApiInfo对象包括的信息,这部分信息会在页面上展示。

  • 指定生成API文档的包名。

  • 指定生成API的路径。按路径生成API可支持四种模式,这个可以参考其源码:


  1. public class PathSelectors {

  2.    private PathSelectors() {

  3.        throw new UnsupportedOperationException();

  4.    }


  5.    public static Predicate<String> any() {

  6.        return Predicates.alwaysTrue();

  7.    }


  8.    public static Predicate<String> none() {

  9.        return Predicates.alwaysFalse();

  10.    }


  11.    public static Predicate<String> regex(final String pathRegex) {

  12.        return new Predicate<String>() {

  13.            public boolean apply(String input) {

  14.                return input.matches(pathRegex);

  15.            }

  16.        };

  17.    }


  18.    public static Predicate<String> ant(final String antPattern) {

  19.        return new Predicate<String>() {

  20.            public boolean apply(String input) {

  21.                AntPathMatcher matcher = new AntPathMatcher();

  22.                return matcher.match(antPattern, input);

  23.            }

  24.        };

  25.    }

  26. }

从源码可以看出,Swagger总共支持任何路径都生成、任何路径都不生成以及正则匹配和ant 模式匹配四种方式。大家可能比较熟悉的是前三种,最后一种ant匹配,如果不熟悉ant的话就直接忽略吧,前三种应该足够大家在日常工作中使用了。

有了上面的配置我们就可以看到效果了,我在com.pandy.blog.rest这个包下面有一个ArticleRestController这个类,源码如下:

  1. @RestController

  2. public class ArticleRestController {


  3.    @Autowired

  4.    private ArticleService articleService;


  5.    @RequestMapping(value = "/rest/article", method = POST, produces = "application/json")

  6.    public WebResponse<Map<String, Object>> saveArticle(@RequestBody Article article) {

  7.        article.setUserId(1L);

  8.        articleService.saveArticle(article);

  9.        Map<String, Object> ret = new HashMap<>();

  10.        ret.put("id", article.getId());

  11.        WebResponse<Map<String, Object>> response = WebResponse.getSuccessResponse(ret);

  12.        return response;

  13.    }


  14.    @RequestMapping(value = "/rest/article/{id}", method = DELETE, produces = "application/json")

  15.    public WebResponse<?> deleteArticle(@PathVariable Long id) {

  16.        Article article = articleService.getById(id);

  17.        article.setStatus(-1);

  18.        articleService.updateArticle(article);

  19.        WebResponse<Object> response = WebResponse.getSuccessResponse(null);

  20.        return response;

  21.    }


  22.    @RequestMapping(value = "/rest/article/{id}", method = PUT, produces = "application/json")

  23.    public WebResponse<Object> updateArticle(@PathVariable Long id, @RequestBody Article article) {

  24.        article.setId(id);

  25.        articleService.updateArticle(article);

  26.        WebResponse<Object> response = WebResponse.getSuccessResponse(null);

  27.        return response;

  28.    }


  29.    @RequestMapping(value = "/rest/article/{id}", method = GET, produces = "application/json")

  30.    public WebResponse<Article> getArticle(@PathVariable Long id) {

  31.        Article article = articleService.getById(id);

  32.        WebResponse<Article> response = WebResponse.getSuccessResponse(article);

  33.        return response;

  34.    }


  35.    @RequestMapping(value = "/test/{id}", method = GET, produces = "application/json")

  36.    public WebResponse<?> getNoApi(){

  37.        WebResponse<?> response = WebResponse.getSuccessResponse(null);

  38.        return response;

  39.    }

  40. }

启动Spring boot,然后访问:http://127.0.0.1:8080/swagger-ui.html即可看到如下结果:

http://img4.sycdn.imooc.com/607311090001198701400140.jpg

这个页面上可以看到,除了最后一个接口/test/{id}外,其他接口都生成对应的文档,最后一个接口因为不满足我们配置的路径——“/rest/.*”,所以没有生成文档。

我们还可以点进去看一下每一个具体的接口,我们这里以“POST /rest/article”这个接口为例:

http://img1.sycdn.imooc.com/607311090001198701400140.jpg

可以看到,Swagger为每一个接口都生成了返回结果和请求参数的示例,并且能直接通过下面的"try it out"进行接口访问,方面大家对接口进行测试。整体上感觉Swagger还是很强大的,配置也比较简单。

三、Swagger API详细配置

不过大家看到这里肯定会有点疑问:

  • 第一个问题:这个返回结果和请求参数都没有文字性的描述,这个可不可以配置?

  • 第二个问题:这个请求参应该是直接根据对象反射出来的结果,但是不是对象的每个属性都是必传的,另外参数的值也不一定满足我们的需求,这个能否配置?

答案肯定是可以的,现在我们就来解决这两个问题,直接看配置的代码:

  1. package com.pandy.blog.rest;


  2. import com.pandy.blog.dto.WebResponse;

  3. import com.pandy.blog.po.Article;

  4. import com.pandy.blog.service.ArticleService;

  5. import io.swagger.annotations.ApiImplicitParam;

  6. import io.swagger.annotations.ApiImplicitParams;

  7. import io.swagger.annotations.ApiOperation;

  8. import io.swagger.annotations.ApiResponse;

  9. import io.swagger.annotations.ApiResponses;

  10. import org.springframework.beans.factory.annotation.Autowired;

  11. import org.springframework.context.annotation.Profile;

  12. import org.springframework.web.bind.annotation.PathVariable;

  13. import org.springframework.web.bind.annotation.RequestBody;

  14. import org.springframework.web.bind.annotation.RequestMapping;

  15. import org.springframework.web.bind.annotation.RestController;


  16. import java.util.HashMap;

  17. import java.util.List;

  18. import java.util.Map;


  19. import static org.springframework.web.bind.annotation.RequestMethod.DELETE;

  20. import static org.springframework.web.bind.annotation.RequestMethod.GET;

  21. import static org.springframework.web.bind.annotation.RequestMethod.POST;

  22. import static org.springframework.web.bind.annotation.RequestMethod.PUT;


  23. @RestController

  24. @RequestMapping("/rest")

  25. public class ArticleRestController {


  26.    @Autowired

  27.    private ArticleService articleService;


  28.    @RequestMapping(value = "/article", method = POST, produces = "application/json")

  29.    @ApiOperation(value = "添加文章", notes = "添加新的文章", tags = "Article",httpMethod = "POST")

  30.    @ApiImplicitParams({

  31.            @ApiImplicitParam(name = "title", value = "文章标题", required = true, dataType = "String"),

  32.            @ApiImplicitParam(name = "summary", value = "文章摘要", required = true, dataType = "String"),

  33.            @ApiImplicitParam(name = "status", value = "发布状态", required = true, dataType = "Integer")

  34.    })

  35.    @ApiResponses({

  36.            @ApiResponse(code=200,message="成功",response=WebResponse.class),

  37.    })

  38.    public WebResponse<Map<String,Object>> saveArticle(@RequestBody Article article){

  39.        articleService.saveArticle(article);

  40.        Map<String,Object> ret = new HashMap<>();

  41.        ret.put("id",article.getId());

  42.        WebResponse<Map<String,Object>> response = WebResponse.getSuccessResponse(ret);

  43.        return response;

  44.    }


  45.    @ApiOperation(value = "删除文章", notes = "根据ID删除文章", tags = "Article",httpMethod = "DELETE")

  46.    @ApiImplicitParams({

  47.            @ApiImplicitParam(name = "id", value = "文章ID", required = true, dataType = "Long")

  48.    })

  49.    @RequestMapping(value = "/{id}",method = DELETE,produces = "application/json")

  50.    public WebResponse<?>  deleteArticle(@PathVariable Long id){

  51.        Article article = articleService.getById(id);

  52.        article.setStatus(-1);

  53.        articleService.saveArticle(article);

  54.        return WebResponse.getSuccessResponse(new HashMap<>());

  55.    }


  56.    @ApiOperation(value = "获取文章列表", notes = "可以根据标题进行模糊查询", tags = "Article",httpMethod = "GET")

  57.    @ApiImplicitParams({

  58.            @ApiImplicitParam(name = "title", value = "文章标题", required = false, dataType = "String"),

  59.            @ApiImplicitParam(name = "pageSize", value = "每页文章数量", required = false, dataType = "Integer"),

  60.            @ApiImplicitParam(name = "pageNum", value = "分页的页码", required = false, dataType = "Integer")

  61.    })

  62.    @RequestMapping(value = "/article/list", method = GET, produces = "application/json")

  63.    public WebResponse<?> listArticles(String title, Integer pageSize, Integer pageNum) {

  64.        if (pageSize == null) {

  65.            pageSize = 10;

  66.        }

  67.        if (pageNum == null) {

  68.            pageNum = 1;

  69.        }

  70.        int offset = (pageNum - 1) * pageSize;

  71.        List<Article> articles =  articleService.getArticles(title, 1L, offset, pageSize);

  72.        return WebResponse.getSuccessResponse(articles);

  73.    }



  74.    @ApiOperation(value = "更新文章", notes = "更新文章内容", tags = "Article",httpMethod = "PUT")

  75.    @ApiImplicitParams({

  76.            @ApiImplicitParam(name = "id", value = "文章ID", required = true, dataType = "Long"),

  77.            @ApiImplicitParam(name = "title", value = "文章标题", required = false, dataType = "String"),

  78.            @ApiImplicitParam(name = "summary", value = "文章摘要", required = false, dataType = "String"),

  79.            @ApiImplicitParam(name = "status", value = "发布状态", required = false, dataType = "Integer")

  80.    })

  81.    @RequestMapping(value = "/article/{id}", method = PUT, produces = "application/json")

  82.    public WebResponse<?> updateArticle(@PathVariable Long id,@RequestBody Article article){

  83.        article.setId(id);

  84.        articleService.updateArticle(article);

  85.        return WebResponse.getSuccessResponse(new HashMap<>());

  86.    }

  87. }


点击查看更多内容
0人点赞

若觉得本文不错,就分享一下吧!

评论

相关文章推荐

正在加载中
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消