Spring Boot从零入门6_Swagger2生成生产环境中REST API文档

Stella981
• 阅读 556

本文属于原创,转载注明出处,欢迎关注微信小程序小白AI博客 和微信公众号别打名名或者网站 https://xiaobaiai.net 或者我的CSDN http://blog.csdn.net/freeape

Spring Boot从零入门6_Swagger2生成生产环境中REST API文档

  • 1 前言

  • 2 Swagger2简介

  • 3 开始使用

  • 3.1 构建Restful WEB服务

  • 3.2 集成Swagger2

  • 3.3 集成Swagger2 UI

  • 4 Swagger2 深度配置

  • 4.1 深度配置目标

  • 4.2 文档信息配置

  • 4.3 API分组配置、API精细配置

  • 4.4 API历史版本管理

  • 4.5 其他配置

  • 5 总结

  • 6 参考文档

1 前言

在如今前后端分离开发的模式下,前端调用后端提供的API去实现数据的展示或者相关的数据操作,保证及时更新和完整的REST API文档将会大大地提高两边的工作效率,减少不必要的沟通成本。本文采用的Swagger2就是一个当前流行的通过少量的注解就可以生成漂亮的API文档工具,且在生成的在线文档中提供类似POSTMAN直接调试能力,不仅仅是静态的文档。接下来将会利用这个工具与Spring Boot项目结合,最终生成我们上一篇文章中所涉及到的REST API文档。

这一篇文章基本将Swagger2在生产环境中可能会用到的配置都有涉及,慢慢看吧,看了这一篇因该是够了。

2 Swagger2简介

Swagger是与用于实现 OpenAPI 文档广泛使用的工具,Swagger工具集包括开源工具,免费工具和商业工具的组合,可在API生命周期的不同阶段使用。

  • Swagger Editor(开源):使用Swagger编辑器,可以在浏览器内的YAML文档中编辑OpenAPI规范并支持实时预览文档,可以参考官方的Demo https://editor.swagger.io/

  • Swagger UI(开源):让Swagger产生的文档更漂亮,而且支持API交互操作,在生成文档后,直接在浏览器中浏览,并可以实现类似 curl命令或者 postman访问我们的API,并返回相关数据。

  • Swagger Codegen(开源): 是一个代码生成器,可以通过Swagger API定义生成不同语言版本的服务端和客户端工程代码。

  • Swagger Core(开源):用于生成Swagger API规范的示例和服务器集成,可轻松访问REST API,结合 Swagger UI,让生成的文档更漂亮。

  • Swagger Parser(开源):Java开发,解析OpenAPI定义的独立库

  • Swagger Inspector(免费):API在线测试工具,验证API并从现有API生成OpenAPI定义功能 https://goo.gl/fZYHWz

  • SwaggerHub(免费和商用版):API设计和文档化,为使用OpenAPI的团队打造。

3 开始使用

3.1 构建Restful WEB服务

参考《Spring Boot从零入门5_五脏俱全的RESTful Web Service构建》。构建好后有如下REST API:

# 获取所有用户信息GET http://localhost:8080/api/v1/users# 新增一个用户,参数通过body传递POST http://localhost:8080/api/v1/users# 更新一个用户信息PUT http://localhost:8080/api/v1/users/{id}# 删除指定用户DELETE http://localhost:8080/api/v1/users/{id}

3.2 集成Swagger2

构建好RESTful WEB服务后,接下来我们集成Swagger,然后对上节中的REST API自动生成接口文档。

3.2.1 pom.xml添加依赖

集成Swagger2,需要在pom.xml中添加依赖源:

<dependencies> <dependency>     <groupId>io.springfox</groupId>     <artifactId>springfox-swagger2</artifactId>     <!-- 截至2019年11月7日为止,最新版本为2.9.2 -->     <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->     <version>2.9.2</version> </dependency></dependencies>

3.2.2 Swagger 配置及初始化

springfox有一个专用对象Docket,可以灵活的配置Swagger的各种属性,首先我们简单的创建一个Swagger配置类Swagger2Config.java

@Configuration@EnableSwagger2public class Swagger2Config {    @Bean("UsersApis")    public Docket usersApis() {        return new Docket(DocumentationType.SWAGGER_2)                .select()                .apis(RequestHandlerSelectors.any())                .paths(PathSelectors.any())                .build();    }}

这里的@Configuration注解用于定义配置类,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext类进行扫描,并用于构建Bean定义,初始化对象。@ComponentScan会自动获取所有的Spring Components,包括@Configuration类。另外这里的“用户管理模块”API生成配置很简单,对所有路径上API都去生成文档。

3.2.3 启动服务并验证

当完成Swagger2的配置类时,启动WEB服务,通过http://localhost:8080/v2/api-docs就可以访问生成文档内容,但是浏览器返回的是JSON内容,基本上很难给需要用到相关API的开发人员进行参考。这个时候就需要用到`Swagger2 UI`了。

3.3 集成Swagger2 UI

pom.xml添加依赖,然后重启WEB服务就可以了,再次访问http://localhost:8080/swagger-ui.html,这时候看到的就是WEB文档了。

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

Spring Boot从零入门6_Swagger2生成生产环境中REST API文档

从swagger-ui页面看到的内容有一部无关的内容,或者是如何明显表现跟项目相关的内容呢?下面章节详细讲解Swagger的各种配置,能够应用到实际生产环境中去。

4 Swagger2 深度配置

4.1 深度配置目标

首先,如果要将我们最后生成的API文档给生产环境的开发人员查阅,那么友好的展示信息和归类是很有必要的,我们接下来实现如下目标:

  • 文档的各种信息说明

  • 文档标题

  • 文档描述

  • 文档版本号

  • Logo

  • 文档责任人

  • 文档许可证信息

  • 文档服务条款

  • API分组

  • 组描述

  • 各API描述

  • 附加部分(非API)

  • 定制化文档页面风格

为了更好地展示API分组功能,这里另外加了一组REST API (代码层面上只需要将User相关的代码全部复制一份,将User关键字全部改为Product就可以了,包括大小写):

# 获取所有产品信息GET http://localhost:8080/api/v1/products# 新增一个产品,参数通过body传递POST http://localhost:8080/api/v1/products# 更新一个产品信息PUT http://localhost:8080/api/v1/products/{id}# 删除指定产品DELETE http://localhost:8080/api/v1/products/{id}

4.2 文档信息配置

@Configuration@EnableSwagger2public class Swagger2Config {    @Bean("UsersApis")    public Docket usersApis() {        return new Docket(DocumentationType.SWAGGER_2)          // select()返回的是ApiSelectorBuilder对象,而非Docket对象                .select()                .apis(RequestHandlerSelectors.any())                .paths(PathSelectors.any())                                 // build()返回的是Docket对象                .build()                // 测试API时的主机URL                .host("https://xiaobaiai.net")                    // API前缀                .pathProvider(new RelativePathProvider(null) {                    @Override                    public String getApplicationBasePath() {                        return "/prefix";                    }                })                .apiInfo(apiInfo());    }        public ApiInfo apiInfo() {     // API负责人的联系信息     final Contact contact = new Contact(       "Ethan", "https://xiaobaiai.net", "ycm_hy@163.com");        return new ApiInfoBuilder()         // API文档标题            .title("X系统平台接口文档")            // API文档描述            .description("用户/产品相关API, 更多请关注公众号: 小白AI 或微信小程序:小白AI博客")            // 服务条款URL            .termsOfServiceUrl("https://github.com/yicm")            // API文档版本            .version("1.0")            // API负责人的联系信息            .contact(contact)            // API的许可证Url            .licenseUrl("http://license.coscl.org.cn/MulanPSL")            .license("MulanPSL")            .build();    }}

通过添加文档信息编译对象ApiInfoBuilder可以配置API文档的各种信息,包括标题、描述、服务条款、版本、责任人、许可证等。最后在Docket中添加信息配置对象即可生效。

注意:host设置的是域名或IPV4 + 端口,如下,path和host以及scheme等定义。

Spring Boot从零入门6_Swagger2生成生产环境中REST API文档

4.3 API分组配置、API精细配置

4.3.1 API分组展示

上面的文档信息配置中默认是没有对API分组的,即所有的API都展示在了一个页面,没有隔离,如果需要分组,那我们需要对不同API组分配Bean,目前示例可以分为用户API组和产品API组,然后通过apis()paths()进行API过滤。

为了不显示某个包下面API或某个URL路径下API, Docket提供了 apis()paths() 两 个方法来帮助我们在不同级别上过滤接口(上面示例我们默认对这两个设置是不做任何过滤,扫描所有API):

  • apis():这种方式可以通过指定包名的方式,让 Swagger2 只去某些包下面扫描

  • paths():这种方式可以通过筛选 API 的 URL 来进行过滤

apis和paths中的Predicates除了anyantnone,还支持regex正则表达式。

如:

PathSelectors.regex("/api/v2/users.*")

下面就是分组示例代码,实现分组,很简单,就是在Docket中配置组名就好了:

@Configuration@EnableSwagger2public class Swagger2Config {    @Bean    public Docket usersApis() {        return new Docket(DocumentationType.SWAGGER_2)          .groupName("用户管理接口")          // select()返回的是ApiSelectorBuilder对象,而非Docket对象                .select()                                .apis(RequestHandlerSelectors.basePackage("com.xiaobaiai.user"))                .paths(Predicates.or(                        // 两个**,可以匹配底下所有URL                        // 一个*,只能匹配一级URL分段                        PathSelectors.ant("/api/v1/users/**"),                        PathSelectors.ant("/api/v1/users/*")))                              // build()返回的是Docket对象                .build()                // 测试API时的主机URL                .host("https://xiaobaiai.net")                    // API前缀,最终所有API的基础地址就是host+prefix: https://xiaobaiai.net/prefix                .pathProvider(new RelativePathProvider(null) {                    @Override                    public String getApplicationBasePath() {                        return "/prefix";                    }                })                .apiInfo(apiInfo());    }        @Bean    public Docket productsApis() {        return new Docket(DocumentationType.SWAGGER_2)          .groupName("产品管理接口")          // select()返回的是ApiSelectorBuilder对象,而非Docket对象                .select()                                .apis(RequestHandlerSelectors.basePackage("com.xiaobaiai.product"))                .paths(Predicates.or(                        // 两个**,可以匹配底下所有URL                        // 一个*,只能匹配一级URL分段                        PathSelectors.ant("/api/v1/products/**"),                        PathSelectors.ant("/api/v1/products/*")))                              // build()返回的是Docket对象                .build()                // 测试API时的主机URL                .host("https://xiaobaiai.net")                    // API前缀                .pathProvider(new RelativePathProvider(null) {                    @Override                    public String getApplicationBasePath() {                        return "/prefix";                    }                })                .apiInfo(apiInfo());    }        public ApiInfo apiInfo() {     // API负责人的联系信息     final Contact contact = new Contact(       "Ethan", "https://xiaobaiai.net", "ycm_hy@163.com");        return new ApiInfoBuilder()         // API文档标题            .title("X系统平台接口文档")            // API文档描述            .description("用户/产品相关API, 更多请关注公众号: 小白AI 或微信小程序:小白AI博客")            // 服务条款URL            .termsOfServiceUrl("https://github.com/yicm")            // API文档版本            .version("1.0")            // API负责人的联系信息            .contact(contact)            // API的许可证Url            .licenseUrl("http://license.coscl.org.cn/MulanPSL")            .license("MulanPSL")            .build();    }}

分组配置完成后,重新启动,打开浏览器就可以看到效果了:

Spring Boot从零入门6_Swagger2生成生产环境中REST API文档

4.3.2 API精细配置

虽然上面我们已经可以控制API的显示和分组了,但是对于API一些更详细,对组内API再次归类之类的,比如小组的描述信息,以及每个API如何去控制它的参数说明,返回值说明等。这些都是通过注解去实现的,接下来我们讲述常用的注解及作用:

  1. @Api : 将这个注解添加到控制器类上,则可以给控制器添加描述类信息:

相关可设置参数有:

  • value:用作承载资源的API声明的“路径”,可以说是API URL的别名

  • tags:如果设置这个值、value的值会被覆盖

  • description:已过时,对api资源的描述

  • protocols:协议类型如: http, https, ws, wss.

  • hidden:配置为true ,隐藏此资源下的操作(试验了下,貌似无法生效,替代方案还是用@ApiIgnore吧)

  • produces:如 “application/json, application/xml”

  • consumes:如 “application/json, application/xml”

  • authorizations:高级特性认证时配置

示例:

// Swagger配置类@Configuration@EnableSwagger2public class Swagger2Config {@Bean    public Docket productsApis() {        return new Docket(DocumentationType.SWAGGER_2)          .groupName("产品管理接口")                .select()                .apis(RequestHandlerSelectors.basePackage("com.xiaobaiai.product"))                .paths(Predicates.or(                        PathSelectors.ant("/api/v1/products/**"),                        PathSelectors.ant("/api/v1/products/*")))                              .build()                .host("https://xiaobaiai.net")                    .pathProvider(new RelativePathProvider(null) {                    @Override                    public String getApplicationBasePath() {                        return "/prefix";                    }                })                .apiInfo(apiInfo())                .tags(new Tag("产品操作分组1", "产品查询相关操作."),                        new Tag("产品操作分组2", "产品添加或删除相关操作."),                        new Tag("产品操作分组3", "产品更新相关操作."),                        new Tag("产品操作分组4", "产品相关全部操作."));    }}

// 控制器类@RestController@RequestMapping("/api/v1")@Api(tags={"产品接口文档列表"})public class ProductServiceController { ... }

效果如下:

Spring Boot从零入门6_Swagger2生成生产环境中REST API文档

  1. @ApiIgnore: 作用在REST API控制器 方法上,则该API不会被显示出来:

    @ApiIgnore@RequestMapping(value = "/users/{id}", method = RequestMethod.DELETE)public ResponseEntity delete(@PathVariable("id") String id) { ... }

  2. @ApiOperation 注解用于控制器 方法上面,用于对方法的描述,相关参数设置描述如下:

    • value:接口的名称

    • notes:接口注意点说明

    • response: 接口的返回类型,比如说:response = String.class

    • hidden: 配置为true 将在文档中隐藏

    示例:

    @ApiOperation(value = "获取所有产品", notes = "每调用一次,就耗费流量100M", response = String.class)@GetMapping(value = "/products")public ResponseEntity<Object> getProduct() { return new ResponseEntity<>(productService.getProducts(), HttpStatus.OK);}
    

    最后效果就是:

    Spring Boot从零入门6_Swagger2生成生产环境中REST API文档

    1. @ApiImplicitParams@ApiImplicitParam  注解用于控制器方法传入参数的说明。默认情况下,Swagger会根据API方法中的传入参数进行参数说明的生成,不过参数说明默认就是变量名,因为这两个注解不一定需要。相关参数设置说明如下:
    • name:参数名称,注意一定要与实际方法的形参名一致,否则无法生效

    • value:参数值

    • defaultValue:参数默认值

    • required:是否为必需项

    • allowMultiple:是否允许重复

    • dataType:数据类型,如object,string,array,int,等

    • paramType:参数传递类型

    • header : 放在请求头。请求参数的获取: @RequestHeader(代码中接收注解)

    • query : 用于get请求的参数拼接。请求参数的获取: @RequestParam(代码中接收注解)

    • path : 用于restful接口,请求参数的获取: @PathVariable(代码中接收注解)

    • body : 放在请求体。请求参数的获取: @RequestBody(代码中接收注解)

    • form : 不常用

    • examples: 示例

    示例:

    // 如果只有一个参数,则仅仅@ApiImplicitParam就可以了@ApiImplicitParams({ @ApiImplicitParam(name="id", value="产品ID值", required = true), @ApiImplicitParam(name="product", value="产品内容", required = true)})@RequestMapping(value = "/products/{id}", method = RequestMethod.PUT)public ResponseEntity<Object> updateProduct(@PathVariable("id") String id, @RequestBody Product product) { productService.updateProduct(id, product); return new ResponseEntity<>("Product is updated successsfully", HttpStatus.OK);}
    

    Spring Boot从零入门6_Swagger2生成生产环境中REST API文档

    1. @ApiParam: 作用同ApiImplicitParam,单个参数描述一般常用该注解,而且该注解只能与JAX-RS 1.x/2.x注解结合使用。参数设置说明如下:
    • name: 参数名称

    • value: 参数值

    • required: 是否为必须项

    • defaultValue: 默认值

    • type: 参数类型

    • hidden: 是否因此该参数

    1. @ApiResponses@ApiResponse: 用于控制器方法返回值的说明,参数设置说明如下:
    • code: http的状态码

    • message:返回状态描述

    • response:状态响应,默认响应类为Void

    示例:

    @ApiOperation(value = "获取所有产品", notes = "每调用一次,就耗费流量100M",response =Product.class, responseContainer="List")@ApiResponses({    @ApiResponse(code = 200, message = "成功!", response=Product.class),    @ApiResponse(code = 401, message = "未授权!", response=Product.class),    @ApiResponse(code = 404, message = "页面未找到!", response=Product.class),    @ApiResponse(code = 403, message = "出错了!", response=Product.class)})@GetMapping(value = "/products")public ResponseEntity<Object> getProduct() { return new ResponseEntity<>(productService.getProducts(), HttpStatus.OK);}
    

    效果如下:

    Spring Boot从零入门6_Swagger2生成生产环境中REST API文档

    1. @Deprecated: 作用于控制器方法上,标注该方法已经过时,建议开发者采用新的方式之类的。

    2. @ApiModel:作用在JavaBean类上,说明JavaBean的用途,如我们定义的Product.java类。常用参数设置如下:

    • value:实体类别名,默认为类名字

    • description:描述

    • parent:父类,默认为Void.class

    • subTypes: 默认为{}

    • reference: 依赖,默认为""

    示例:

    @ApiModel(value="Product",description="对产品定义的描述")public class Product { ... }
    
    1. @ApiModelProperty: 同样用于在JavaBean类的属性上面,说明相关属性。类似于方法上说明的 @ApiImplicitParam。设置参数有:
    • name:属性名称,需与JavaBean内保持一致

    • value:属性值

    • notes:说明

    • dataType:数据类型

    • required:是否必须

    • readOnly:是否只读,默认为false

    • reference:依赖,默认为""

    • allowEmptyValue: 是否允许空值

    • allowableValues:允许值,默认为""

    4.4 API历史版本管理

    管理不同API版本有好几种方式:

    • 通过URL的方式,将版本号包含在URL中,如 /api/v1/users。通过这种方式,我们可以在Docket中过滤出不同版本,结合分组,可以实现不同版本的API管理。

    • 通过查询参数,将版本号作为一个具体参数,如 /api/users?version=1

    • 通过自定义HTTP头–定义一个新的头,其中包含请求中的版本号

    • 通过内容(Content)协商:版本号与接受的内容类型一起包含在“Accept”头中,如 curl -H "Accept: application/vnd.piomin.v1+json" http://localhost:8080/api/users

    这里我们对第一种方式示例展示:

    在Swagger2Config.java中新添加一个用户API Docket:

    @Configuration@EnableSwagger2public class Swagger2Config {    @Bean("UsersApis_V1")    public Docket usersApisV1() {        return new Docket(DocumentationType.SWAGGER_2)          .groupName("用户管理接口V1")                .select()                .apis(RequestHandlerSelectors.basePackage("com.xiaobaiai.user"))                .paths(Predicates.or(                        // 过滤版本v1                        PathSelectors.ant("/api/v1/users/**"),                        PathSelectors.ant("/api/v1/users/*")))                      .build()                .host("https://xiaobaiai.net")                    .pathProvider(new RelativePathProvider(null) {                    @Override                    public String getApplicationBasePath() {                        return "/prefix";                    }                })                .apiInfo(apiInfo());    }        @Bean("UsersApis_V21")    public Docket usersApisV2() {        return new Docket(DocumentationType.SWAGGER_2)          .groupName("用户管理接口V2")                .select()                .apis(RequestHandlerSelectors.basePackage("com.xiaobaiai.user"))                .paths(Predicates.or(                        // 过滤版本v1                        PathSelectors.ant("/api/v2/users/**"),                        PathSelectors.ant("/api/v2/users/*")))                      .build()                .host("https://xiaobaiai.net")                    .pathProvider(new RelativePathProvider(null) {                    @Override                    public String getApplicationBasePath() {                        return "/prefix";                    }                })                .apiInfo(apiInfo());    }        @Bean    public Docket productsApis() {        return new Docket(DocumentationType.SWAGGER_2)         .....    }        public ApiInfo apiInfo() {     final Contact contact = new Contact(       "Ethan", "https://xiaobaiai.net", "ycm_hy@163.com");        return new ApiInfoBuilder()            .title("X系统平台接口文档")            .description("用户/产品相关API, 更多请关注公众号: 小白AI 或微信小程序:小白AI博客")            .termsOfServiceUrl("https://github.com/yicm")            .version("1.0")            .contact(contact)            .licenseUrl("http://license.coscl.org.cn/MulanPSL")            .license("MulanPSL")            .build();    }}
    

    然后控制器添加新版本API方法:

    @RestController@RequestMapping("/api")public class UserServiceController { @Autowired UserService userService;  @DeleteMapping({"/v1/users/{id}", "/v2/users/{id}"}) public ResponseEntity<Object> delete(@PathVariable("id") String id) {  userService.deleteUser(id);  return new ResponseEntity<>("User is deleted successsfully", HttpStatus.OK); } @PutMapping({"/v1/users/{id}", "/v2/users/{id}"}) public ResponseEntity<Object> updateUser(@PathVariable("id") String id, @RequestBody User user) {  userService.updateUser(id, user);  return new ResponseEntity<>("User is updated successsfully", HttpStatus.OK); } @PostMapping({"/v1/users", "/v2/users"}) public ResponseEntity<Object> createUser(@RequestBody User user) {  userService.createUser(user);  return new ResponseEntity<>("User is created successfully", HttpStatus.CREATED); } @GetMapping({"/v1/users"}) @Deprecated public ResponseEntity<Object> getUser() {  return new ResponseEntity<>(userService.getUsers(), HttpStatus.OK); }  @GetMapping(value = "/v2/users") public ResponseEntity<Object> getUser(@RequestParam String id) {  return new ResponseEntity<>(userService.getUsers(), HttpStatus.OK); }}
    

    最后效果:

    Spring Boot从零入门6_Swagger2生成生产环境中REST API文档

    其他的方式类似也差不多,如在Header中区分版本,这里就不展开了。

    4.5 其他配置

    4.5.1 为每个API配置全局Token实现一次性授权

    当我们的REST API加入的授权机制时,即需具有对该API的访问权限,才能够操作该API,但是我们想在Swagger UI中去调试API,那么如何解决每个API一次性授权,全部API可访问呢?增加使用的方便性,不用每次都对每个API进行授权。不过需要在WEB服务中已经使用了API授权机制才会需要这项配置。这里暂不展开,后面单独讲述Spring Security + Swagger2 UI配置。

    4.5.2 在线文档页面中更换语言

    应该是不能的: https://github.com/swagger-api/swagger-ui#known-issues

    • translations is not implemented.

    5 总结

    这一篇从介绍Swagger2入手,讲述在Spring Boot中如何集成和配置Swagger2,并生成生成环境中的在线API文档,包括如何将API分组,组信息描述,API信息描述,API方法参数描述,如何对API版本进行管理等,最后还扩展了内容,包括如何为每个API配置全局Token等。内容很全,参考这一篇应该是够了,继续!

    6 参考文档

    文章难免疏漏,而公众号上每篇文章只能修改几个字,所以我会在我的小程序小白AI博客上也发一遍,任何的错误,我会在及时修改,欢迎随时交流。

    关注我的公众号,获取最新学习分享:

    Spring Boot从零入门6_Swagger2生成生产环境中REST API文档

    本文分享自微信公众号 - 别打名名(biedamingming)。
    如有侵权,请联系 support@oschina.cn 删除。
    本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

    点赞
    收藏
    评论区
    推荐文章
    blmius blmius
    2年前
    MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
    文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
    Jacquelyn38 Jacquelyn38
    2年前
    2020年前端实用代码段,为你的工作保驾护航
    有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
    皕杰报表之UUID
    ​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
    Stella981 Stella981
    2年前
    Spring Boot从零入门1_详述
    本文属于原创,转载注明出处,欢迎关注微信小程序小白AI博客和微信公众号别打名名或者网站https://xiaobaiai.net或者我的CSDNhttp://blog.csdn.net/freeape!(https://oscimg.oschina.net/oscnet/f8db20c4f3964337b76dc956a3a8
    Wesley13 Wesley13
    2年前
    MQTT安全性设计详解
    本文属于原创,转载注明出处,欢迎关注微信小程序小白AI博客微信公众号别打名名或者网站https://xiaobaiai.net或者我的CSDNhttp://blog.csdn.net/freeape!(https://oscimg.oschina.net/oscnet/ab92552a6bd64ed6a957d1854b677
    Stella981 Stella981
    2年前
    Spring Boot从零入门5_五脏俱全的RESTful Web Service构建
    本文属于原创,转载注明出处,欢迎关注微信小程序小白AI博客和微信公众号别打名名或者网站https://xiaobaiai.net或者我的CSDNhttp://blog.csdn.net/freeape!(https://oscimg.oschina.net/oscnet/378afc2c41cd4b4ba99acadb9d83
    Stella981 Stella981
    2年前
    Spring Boot从零入门3_创建Hello World及项目剖析
    本文属于原创,转载注明出处,欢迎关注微信小程序小白AI博客和微信公众号别打名名或者网站https://xiaobaiai.net或者我的CSDNhttp://blog.csdn.net/freeape!(https://oscimg.oschina.net/oscnet/89944effaec841a9b6bad0cce8cf
    Stella981 Stella981
    2年前
    Spring Boot从零入门2_核心模块详述和开发环境搭建
    本文属于原创,转载注明出处,欢迎关注微信小程序小白AI博客和微信公众号别打名名或者网站https://xiaobaiai.net或者我的CSDNhttp://blog.csdn.net/freeape!(https://oscimg.oschina.net/oscnet/824604023db348fd99425746632b
    Wesley13 Wesley13
    2年前
    MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
    背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
    Python进阶者 Python进阶者
    3个月前
    Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
    大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这