关于springboot:九-SpringBoot起飞之路整合集成Swagger-2-And-3

3次阅读

共计 12541 个字符,预计需要花费 32 分钟才能阅读完成。

趣味的敌人能够去理解一下其余几篇,你的赞就是对我最大的反对,感激大家!

(一) SpringBoot 腾飞之路 -HelloWorld

(二) SpringBoot 腾飞之路 - 入门原理剖析

(三) SpringBoot 腾飞之路 -YAML 配置小结(入门必知必会)

(四) SpringBoot 腾飞之路 - 动态资源解决

(五) SpringBoot 腾飞之路 -Thymeleaf 模板引擎

(六) SpringBoot 腾飞之路 - 整合 JdbcTemplate-Druid-MyBatis

(七) SpringBoot 腾飞之路 - 整合 SpringSecurity

(八) SpringBoot 腾飞之路 - 整合 Shiro

阐明:

  • 3.0 的版本没怎么用过,只是进行了简略的整合,或者会有一些不欠缺的中央,欢送大家交换分享
  • SpringBoot 腾飞之路 系列文章的源码,均同步上传到 github 了,有须要的小伙伴,随便去 down

    • https://github.com/ideal-20/S…

一 初识 Swagger

跳过铺垫,请间接翻越到 第二大点 ~

(一) 先谈谈前后端拆散

在最早的 JavaWeb 时代的时候,如果想要返回一个页面,你须要一行一行的去 print,如果遇到变量,还须要本人进行字符串的拼接

Public class TestServlet extends HttpServlet {
    @Override  
    public void doGet(HttpServletRequest request, HttpServletResponseresp response) 
            throws ServletException, IOException {String name = req.getParameter("name");  
        String age = req.getParameter("age");  
        PrintWriter out = resp.getWriter();  
        out.println("<html>");  
        out.println("<head><title> 展现数据 </title></head>");  
        out.println("<body>name:" + name + "<br/> age:" + age +"</body>");  
        out.println("</html>");       
    } 
}

接着 JSP 就呈现了,其本质尽管还是一个 Servlet,不过编写一个 JSP 的形式和编写 HTML 的是基本一致的,然而 JSP 开始容许咱们在页面中通过 %% 引入 Java 代码,也就是说咱们能够通过在 JSP 页面中通过书写 Java 代码达到显示动静内容的成果,例如在 JSP 中定义方法、书写控制台输入语句等等,大部分你能想到的逻辑都能够在这里来做

起初一看这不行啊,业务逻辑和视图逻辑都混一块了,越写越乱,一个页面就几百行甚至上千行,真可怕啊,起初大家就想了个法子,用 MVC 来解耦啊,把 JSP 的业务抽取进去交给后盾的 Serlvet 去做,JSP 用来承载数据,展现页面

如下代码:从 session 中取到数据,而后再 JSP 中进行遍历,不过这段代码有简略用了一些标签,这是咱们前面要说的

最初 JSP 会被编译成 Servlet

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page import="cn.ideal.pojo.Good" %>
<!-- 
   申请 /index.do 进行初始化
-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>  
   <body>
    <img src="img/cart.jpg" height="60px" width="60px">
    <a href="cart.view"> 已洽购
    <c:out value="${sumNum}" default="没有任何"/> 商品
    </a><br>
   <br>
    <table border="1">    
   <%
      ArrayList<Good> goodList = (ArrayList<Good>)session.getAttribute("goodList");
      for (Good good : goodList){out.println("<tr>") ; 
        out.println("<td> <img src='" + good.getGoodImg() + "'> </td>");
        String id = good.getGoodId();
        out.println("<td> <a href=shopping.view?id=" + id + "> 洽购 </a></td>");
        out.println("</tr>"); 
       } 
    %>
    </table></body>
</html>

尽管 JSP 不解决业务逻辑了,看起来也没那么臃肿了,然而如上所示,JSP 想获取 Servlet 传来 的一些内容,依然须要通过 %% 去获取,例如拿到后遍历,判断等内容还须要本人在 JSP 中写 Java 代码

EL 和 JSTL 表达式就来了,通过一些定义好的标签,简略的拿到数据以及展现

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!-- 
   申请 /index.do 进行初始化
-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>  
   <body>
    <img src="img/cart.jpg" height="60px" width="60px">
    <a href="showCart.jsp"> 已洽购
    
    <c:out value="${sessionScope.cart.sumNum}" default="没有任何"/> 品
    </a><br>
   <br>
    <table border="1">    
    <c:forEach var="good" items="${cart.goodList}">
    <tr>
        <td><img src='${good.goodImg}'></td>
        <td><c:out value='${good.getPrice()}'/> 元 </td>
           <td><a href="shopping.view?id=${good.bookId}&type=1&method=1"> 洽购 </a></td>
    </tr>
    </c:forEach>
    </table>
    </body>
</html>

再到起初,Freemarker、Thymeleaf、Velocity 等,模板引擎就来了,他们和 JSP 的表达式写法很类似,有本人的一套表达式来拿到并且解决数据,例如这样:

<table border="1">
  <tr>
    <th>Name</th>
    <th>Age</th>
  </tr>
  <tr th:each="user : ${userList}">
    <td th:text="${user.nickname}">NULL</td>
    <td th:text="${user.age}">0</td>
  </tr>
</table>

这样一套老开发模式,实际上大部分压力都放在了后端人员上,因为例如前端发来一份 html,后端还须要批改为 JSP,也就是用标签替换其中一些固定的内容,实现动态效果,然而我的项目比拟大的状况下,不论从人力亦或是开发成本来看都是不适合的,而且术业有专攻,如果后端只须要管本人后盾业务的事件就行了该多好

这个时候前端就开始异军突起了,他们开始只应用简略 HTML、CSS 来展现数据,也就是纯正的页面展现,通过 JS,把数据申请失去的数据进行填充,最开始可能会应用操作 DOM,然而随着前端框架的欠缺,例如当初常见的 Vue、Angular,前端都开始用 MVC 这套,也就是 html 作为视图,js 作为控制器,异步申请,通过标签来展现数据,间接把数据填充到 html 页面中

<!DOCTYPE html>
<html lang="en" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <style>
    [v-clock] {display: none;}
  </style>
</head>
<body>
<div id="hello-8" v-clock>
  <div>{{info.name}}</div>
  <div>{{info.blog}}</div>
  <div>{{info.about.country}}</div>
  <div>{{info.about.phone}}</div>
  <div>{{info.students[0].name}}</div>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

<script>
    var vm = new Vue({
        el: "#hello-8",
        data() {
            return {info: {}
            }
        },
        mounted() {axios.get("../json/data.json").then(response => (this.info = response.data));
        }
    })
</script>
</body>
</html>

这就意味着,后端只须要给出依据前端接口须要的,返回对应数据(例如 JSON)就能够了

这种通过 API 进行交互的形式实际上也是松耦合的,单方都比拟灵便且独立

(二) 为什么用 Swagger

后面感觉始终在说题外话,然而问题的要害就在于这一点,这种模块开发,前后拆散的状况下,前端或者后端的沟通就会极为重要,有时候没能做到及时的协商,就会呈现很多意想不到的问题,同时前后端拆散大行其道,也就代表着接口调用会大量的呈现,如果你的 API 同时对接 Web、IOS、Android 等多个开发,为了缩小沟通的代价,那必然就是要写文档的,用来记录所有接口的细节

然而如何创立一个繁多且简单的文档就是一个十分吃力的事件了,毕竟要思考的中央十分多,同时随着代码的迭代,API 文档更新治理肯定要严格把控,否则都会带来不必要的麻烦,显然传统的 Wiki

手写文档肯定是一个十分麻烦的过程,Swagger 他就来了

(三) 什么是 Swagger

Swagger 是一个标准和残缺的框架,用于生成、形容、调用和可视化 RESTful 格调的 Web 服务

其总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的办法,参数和模型严密集成到服务器端的代码,容许 API 来始终保持同步。

刚开始的时候,Swagger 只是一种标准,产品开发迭代的时候,通过更新形容文件就能够生成接口文档和客户 / 服务端代码,然而开发人员时不时就会遗记更新此文件,间接改代码,后序,作为大头的 Spring 就将其正式纳入麾下,建设了 Spring-swagger 我的项目,即当初的 springfox(swagger2)

其最大的长处就是,能实时同步 API 和文档,只须要通过简略的整合亦配合一些注解,就能够体验到其丰盛的性能

通常就目前为止,大部分我的项目中还是在用 Swagger2,通过 maven 仓库也能够看到,2.9.2 是使用率最高的,同样前面咱们还会演示一下 Swagger3 的版本,因为它毕竟是往年刚出的,其简化了很多配置,个人感觉还算香

阐明

二 Springboot 集成 Swagger 2

(一) 依赖及初始化

先初始化一个 Springboot 我的项目

(1) 引入依赖

<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-swagger2</artifactId>
   <version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-swagger-ui</artifactId>
   <version>2.9.2</version>
</dependency>

(2) 编写 Controller

@RestController
@RequestMapping("test/")
public class TestController {@RequestMapping("/testA")
    public String testA(){return "This is a test";}
}

(3) 创立 Swagger 配置类

@Configuration // 配置类
@EnableSwagger2 // 开启 Swagger2 的主动配置
public class SwaggerConfig {// 临时为空}

注:咱们应用的是 Swagger2

(4) 拜访测试

先测试一下 controller 有没有问题,接着通过如下地址就能够拜访到 swagger 的界面

http://localhost:8080/swagger-ui.html

能够看到大略这个页面分为三个局部,下面就是一些介绍信息,两头就是一个一个的接口信息,上面是实体

(二) 配置 Swagger 信息

咱们须要在咱们自定义的 Swagger 配置类中配置一些内容,就须要引入一个 Bean,Swagger 的实例 Bean 就是 Docket,所以咱们须要实例化一个 Docket

/**
 * 配置 docket 和 Swagger 的具体参数
 * @return
 */
@Bean 
public Docket docket() {return new Docket(DocumentationType.SWAGGER_2);}

大家能够点开 Docket 源码,而后能够看到它引入了 ApiInfo 这个类,其中定义了一些根本的信息例如,版本,题目等等

public static final Contact DEFAULT_CONTACT = new Contact("","", "");
  public static final ApiInfo DEFAULT = new ApiInfo("Api Documentation", "Api Documentation", "1.0", "urn:tos",
          DEFAULT_CONTACT, "Apache 2.0", "http://www.apache.org/licenses/LICENSE-2.0", new ArrayList<VendorExtension>());

  private final String version;
  private final String title;
  private final String description;
  private final String termsOfServiceUrl;
  private final String license;
  private final String licenseUrl;
  private final Contact contact;
  private final List<VendorExtension> vendorExtensions;

大家可能曾经看进去了,这个中央的内容,就是负责刚开咱们关上那个 swagger-ui 页面的头部文档信息的,其默认值例如 Api Documentation、1.0、Apache 2.0 大家能够本人对照一下

好了,晓得了它的类和根本构造,咱们就要自定义这些信息了

/**
 * 配置文档信息
 * @return
 */
private ApiInfo apiInfo() {Contact contact = new Contact("BWH_Steven", "https://www.ideal-20.cn", "ideal_bwh@163.com");
    return new ApiInfo(
            "Swagger2 学习——现实二旬不止", // title- 题目
            "学习演示如何配置 Swagger2", // description- 形容
            "v1.0", // version- 版本
            "https://www.ideal-20.cn", // termsOfServiceUrl- 组织链接
            contact, // contact- 联系人信息
            "Apach 2.0 许可", // license- 许可
            "许可链接", // licenseUrl- 许可连贯
            new ArrayList<>()// vendorExtensions- 扩大);
}

配置完后,咱们还没有把它和 Docket 实例挂起钩来

/**
 * 配置 docket 和 Swagger 的具体参数
 * @return
 */
@Bean
public Docket docket() {return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
}

再次拜访地址,看看成果

http://localhost:8080/swagger-ui.html

(三) 配置自定义扫描形式配置

(1) 如何配置

留心的敌人大家看到,第一次拜访的时候下面还有一个默认的 basic-seeor-controller,而前面则没有了,这是因为我在演示配置信息的时候,遗记把我自定义扫描形式给正文掉了

所以,咱们当初来提一下如何本人定义扫描哪些接口

在 Docket 中能够通过调用 select() 办法来配置扫描的接口,要应用这个形式就必须在其后跟上 build,这是设计模式中的一种,建造者模式,具体如何配置呢,只须要在 select 和 build 中 apis 即可,因为 apis 中须要一个 requestHandlerSelector,所以 requestHandlerSelector 就是咱们最终要具体配置的中央

先上一份例子,对照下面的解释看

/**
 * 配置 docket 和 Swagger 的具体参数
 * @return
 */
@Bean
public Docket docket() {return new Docket(DocumentationType.SWAGGER_2)
        .apiInfo(apiInfo())
        // 通过.select() 办法,去配置扫描接口
        .select()
        // RequestHandlerSelectors 配置扫描接口的具体形式
        .apis(RequestHandlerSelectors.basePackage("cn.ideal.controller")) 
        .build();}

(2) 可选扫描形式

大家能够点进去 RequestHandlerSelectors 看一下,除了 basePackage 还有哪些

any()

  • 扫描我的项目中的所有接口

none()

  • 不扫描任何接口

withMethodAnnotation(final Class<? extends Annotation> annotation)

  • 通过办法上的注解扫描,如 withMethodAnnotation(GetMapping.class) 只扫描 get 申请

withClassAnnotation(final Class<? extends Annotation> annotation)

  • 通过类上的注解扫描,如 .withClassAnnotation(Controller.class) 只扫描有 controller 注解的类中的接口

basePackage(final String basePackage)

  • 依据包门路扫描接口

(3) 配置扫描过滤

当你写好 select 和 build 后,其实两者两头就只提供调用 apis 和 paths 了,而 paths 就是当初要说的扫描过滤

/**
 * 配置 docket 和 Swagger 的具体参数
 * @return
 */
@Bean
public Docket docket() {return new Docket(DocumentationType.SWAGGER_2)
            .apiInfo(apiInfo())
            .select()
            .apis(RequestHandlerSelectors.basePackage("cn.ideal.controller"))
            // 配置如何通过 path 过滤
            // 这里只扫描申请以 /test 结尾的接口
            .paths(PathSelectors.ant("/test/**"))
            .build();}

可选形式

any()

  • 扫描所有申请

none()

  • 任何申请都不扫描

regex(final String pathRegex)

  • 依据正则表达式

ant(final String antPattern)

  • 通过 ant() 管制(如上代码,能够应用一些通配符)

(四) 配置 Swagger 的开启和敞开

通过在 Docket 中调用 enable(boolean externallyConfiguredFlag) 能够管制 Swagger 的开和关,也就是说,如果配置 .enable(false) 浏览器中拜访就会出错

讲个理论点的例子,个别咱们会在开发以及测试阶段开启 Swagger,然而正式上线就会把它关掉

所以,咱们得动静的让其进行配置

首先,咱们先别离创立 dev 和 test 以及 prod,三个环境

  • 创立 application-dev.properties,设置 server.port=8080
  • 创立 application-test.properties,设置 server.port=8081
  • 创立 application-prod.properties,设置 server.port=8082
/**
 * 配置 docket 和 Swagger 的具体参数
 * @return
 */
@Bean
public Docket docket(Environment environment) {

    // 设置要显示 swagger 的环境
    Profiles of = Profiles.of("dev", "test");
    // 判断以后是否处于该环境
    boolean flag = environment.acceptsProfiles(of);

    return new Docket(DocumentationType.SWAGGER_2)
            .apiInfo(apiInfo())
            // 通过 enable() 接管决定是否要显示
            .enable(flag)
            .select()
            .apis(RequestHandlerSelectors.basePackage("cn.ideal.controller"))
            .paths(PathSelectors.ant("/test/**"))
            .build();}

在主配置 appplication.properties 中指定以后为开发版本 spring.profiles.active=dev

这样就能够拜访对应设置好的 8080 了,同理设置为别的,就只能拜访别的

(五) 配置分组

在 ui 界面其实大家能够留神到,右上角有一个 default,以及一个下拉选项(临时还没内容)

这里就是一个分组的概念,也就是咱们要实现 API 接口的分类

办法非常简单,只须要通过在 Docket 中,调用 groupName() 即可

@Bean
public Docket docketA(){return new Docket(DocumentationType.SWAGGER_2).groupName("groupA");
}
@Bean
public Docket docketB(){return new Docket(DocumentationType.SWAGGER_2).groupName("groupB");
}
@Bean
public Docket docketC(){return new Docket(DocumentationType.SWAGGER_2).groupName("groupC");
}

重启后,就能够看到分组的成果了,不同的组别里进行不同的配置,能达到不同的拜访成果

(六) 罕用注解

(一) 作用在类

(1) @Api()

写了一些罕用的注解和其参数,不肯定全,不过应该还是够用的

Swagger 配合注解更香喔 ~

@Api():示意这个类是 swagger 资源

  • tags:示意阐明内容,只写 tags 就能够省略属性名
  • value:同样是阐明,不过会被 tags 代替
@Api(value = "测试接口 value", tags = "测试接口 Tags")
@RestController
@RequestMapping("test/")
public class TestController {......}

下面同时定义了 tags 和 value,最初显示的只有 tags,两者都能够独自应用

(二) 作用在办法

(1) @ApiOperation()

@ApiOperation():对办法的阐明,注解位于办法上

  • value:办法的阐明
  • notes:额定正文阐明
  • response:返回的对象
  • tags:这个办法会被独自摘出来,从新分组
@ApiOperation(
        value = "用户信息查询方法 Value",
        notes = "这是用户信息查询方法的正文阐明",
        response = User.class,
        tags = {"用户信息查询方法 Tags"})
@GetMapping("/queryUser")
public User queryUser() {......}

阐明:正文须要点开每一个办法能力看到

补充:如果在办法上应用 @RequestMapping() 注解,那么文档中就会有各种类型的阐明,例如 GET、POST 等等等等,所以个别咱们会指定其申请类型,例如 @GetMapping("/queryUser")

(2) @ApiParam()

@ApiParam() :对办法参数的具体阐明

  • name:参数名
  • value:参数阐明
  • required:是否必填
@ApiOperation(value = "用户登录办法", notes = "用户登录正文阐明")
@PostMapping("/login")
public String login(@ApiParam(name = "username", value = "用户名", required = true) String username,
                    @ApiParam(name = "password", value = "明码", required = true) String password) {if ("123".equals(username) && "123".equals(password)) {return "登录胜利";} else {return "登录失败";}
}

点开这个办法,能够看到,这些注解都体现在文档中了

(三) 作用在模型类

(1) @ApiModel()

@ApiModel() 作用在模型类上,如 VO、BO,示意对类进行阐明

  • value:代表模型的名称
  • description:一段形容
(2) @ApiModelProperty()

@ApiModelProperty() 作用在类办法和属性上,示意对属性的阐明

  • value:字段阐明
  • name:重写属性名字
  • dataType:重写属性类型
  • required:是否必填
  • example:举例说明
  • hidden:暗藏

(两者一起演示)可在文档首页,以及具体方法波及到时,会显示此 model 阐明信息

三 Springboot 集成 Swagger3

大部分内容下面都有提过,所以这里只说一些不同的中央

一个就是依赖能够用 3.0 的 starter

其次就是配置中批改 return new Docket(DocumentationType.OAS_30)

同时不须要引入 @EnableSwagger2 注解了

都说启动类须要加 @EnableOpenApi , 试了一下,如同是不须要的

※ 启动门路变成了

http://localhost:8080/swagger-ui/index.html

(一) 引入依赖

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-boot-starter</artifactId>
    <version>3.0.0</version>
</dependency>

(二) 配置类

@Configuration
public class Swagger3Config {
    @Bean
    public Docket createRestApi(Environment environment) {
        // 设置要显示 swagger 的环境
        Profiles of = Profiles.of("dev", "test");
        // 判断以后是否处于该环境
        boolean flag = environment.acceptsProfiles(of);

        return new Docket(DocumentationType.OAS_30)
                .apiInfo(apiInfo())
                // 通过 enable() 接管决定是否要显示
                .enable(flag)
                // 通过.select() 办法,去配置扫描接口
                .select()
                // RequestHandlerSelectors 配置扫描接口的具体形式
                .apis(RequestHandlerSelectors.basePackage("cn.ideal.controller"))
                .paths(PathSelectors.ant("/test/**"))
                .build();}

    private ApiInfo apiInfo() {Contact contact = new Contact("BWH_Steven", "https://www.ideal-20.cn", "ideal_bwh@163.com");
        return new ApiInfo(
                "Swagger3 学习——现实二旬不止", // 题目
                "学习演示如何配置 Swagger2", // 形容
                "v1.0", // 版本
                "https://www.ideal-20.cn", // 组织链接
                contact, // 联系人信息
                "Apache 2.0 许可", // 许可
                "许可链接", // 许可连贯
                new ArrayList<>()// 扩大);
    }
}

看看成果

四 Swagger 测试

Swagger 不仅仅是一个一般的文档,它还能够间接在生成的文档上进行测试,随同着文档的阐明,测试起来也十分不便

例如点击 Try it out 后,因为测试一个查询方法,是没有参数的,所以间接点击 Excute,就能看到响应后果了

响应后果

五 结尾

如果文章中有什么有余,欢送大家留言交换,感激敌人们的反对!

如果能帮到你的话,那就来关注我吧!如果您更喜爱微信文章的浏览形式,能够关注我的公众号

在这里的咱们素不相识,却都在为了本人的梦而致力 ❤

一个保持推送原创开发技术文章的公众号:现实二旬不止

正文完
 0