一、背景介绍
随着互联网技术的不断发展,网站项目架构基本都是前后端分离了,原来需要后端渲染数据展示,现在只需要提供Restful风格的Api接口给前端或移动端。这样API文档便成为了前后端开发人员联系的纽带。这就引入了一个新的问题:如何提供一个灵活高质量的API文档给多个开发人员或者团队?
-
对于一个项目,接口众多,并且细节复杂(接口参数的说明、要求等),如果要想高质量的创建API文档,想想就是一件很不容易的事情。对于很多开发人员来说,撰写文档是一件很痛苦的事情,至少对于我来说是这样的^^
-
随着项目的不断迭代更新,接口可能随时变动,每次接口的变动也避免不了API文档的同步更新,若更新不及时,可能会给不同的开发团队带来困扰,灵活性不够!
为了解决这些问题,本文将给您介绍Restful API的伙伴Swagger2,一款可以让你更好的书写API文档框架。并且它可以轻轻松松的整合到SpringBoot 中去!
二、初识 Swagger
2.1、认识 Swagger
官方网站 ,打开官网你就大概了解到 Swagger 能做什么?
Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标就是让维护API文档和修改代码整合为一体,在修改代码的同时也方便修改API文档说明,这样就可以使API信息始终保持同步!
作用:
- 接口文档的在线自动生成。
- API接口测试
先看一下使用 Swagger 给我们展现的一个效果:
看着是不是觉得很清晰呀!接下来我就具体介绍一下如何在SpringBoot 中使用Swagger2。
三、SpringBoot中使用Swagger2
3.1、导入依赖
Maven依赖如下,目前使用最新版本(2.9.2版本,该版本有个小坑后面会提到!)
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
3.2、创建一个Swagger配置类
package com.xmlvhy.boot.swagger.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* @ClassName SwaggerConfig1
* @Description TODO
* @Author 小莫
* @Date 2019/05/17 14:05
* @Version 1.0
**/
@Configuration
//开启Swagger2的自动化配置
@EnableSwagger2
public class SwaggerConfig {
/**
*功能描述: 配置Docket
* @Author 小莫
* @Date 14:07 2019/05/17
* @Param []
* @return springfox.documentation.spring.web.plugins.Docket
*/
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2);
}
}
说明:
1.@EnableSwagger2 是Swagger2的核心注解,即打开Swagger2的自动化配置;
2.@Configuration注解表明该类是一个配置类;
3.Swagger的实例Bean是Docket,所有通过配置Docket实例化来配置Swagger
以上便完成Swagger的一个基本配置,此时我们已经可以使用Swagger了,访问如下链接:
http://localhost:8080/swagger-ui.html
3.3、Swagger API文档详细配置
通过apiInfo()属性配置文档信息,相关内容属性通过配置文件注入方式设置。主要涉及到Swagger中 ApiInfo 以及 Contact 两个实体类,具体配置如下:
swagger:
title: SpringBoot整合Swagger2学习
description: Swagger2学习
version: 1.0
termsOfServiceUrl: https://www.xmlvhy.com
license: 测试许可
licenseUrl: https://www.xmlvhy.com
name: 芝君的个人技术博客
url: https://www.xmlvhy.com
email: 1059224309@qq.com
此时,配置类修改如下:
package com.xmlvhy.boot.swagger.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* @ClassName SwaggerConfig1
* @Description TODO
* @Author 小莫
* @Date 2019/05/17 14:05
* @Version 1.0
**/
@Configuration
@EnableConfigurationProperties(SwaggerConfig1.class)
@ConfigurationProperties(prefix = "swagger")
//开启Swagger2的自动化配置
@EnableSwagger2
//lombok插件注解,自动生成setter and getter
@Data
public class SwaggerConfig1 {
/*ApiInfo对象的属性*/
/*文档标题*/
private String title;
/*文档描述*/
private String description;
/*文档版本信息*/
private String version;
/*文档编辑组织团队链接*/
private String termsOfServiceUrl;
/*文档许可说明*/
private String license;
/*文档许可链接*/
private String licenseUrl;
/*Contact 对象属性*/
//联系人姓名
private String name;
//联系人访问链接
private String url;
//联系人email
private String email;
/**
*功能描述: 配置Docket
* @Author 小莫
* @Date 14:07 2019/05/17
* @Param []
* @return springfox.documentation.spring.web.plugins.Docket
*/
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
}
/**
*功能描述: 通过ApiInfo 来配置Api文档信息
* @Author 小莫
* @Date 15:12 2019/05/17
* @Param []
* @return springfox.documentation.service.ApiInfo
*/
private ApiInfo apiInfo(){
Contact contact = new Contact(name, url, email);
return new ApiInfoBuilder()
.title(title)
.description(description)
.version(version)
.termsOfServiceUrl(termsOfServiceUrl)
.license(license)
.licenseUrl(licenseUrl)
.contact(contact)
.build();
}
}
配置完成后,重启项目并访问,可以看到我们配置的信息:
3.4、配置我们要扫描的包
1.首先我们创建一个 OrderController.java
package com.xmlvhy.boot.swagger.controller;
import io.swagger.annotations.Api;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName OrderController
* @Description TODO
* @Author 小莫
* @Date 2019/05/16 12:54
* @Version 1.0
**/
@RequestMapping("/order")
@ResponseBody
@Controller
@Api(tags = "订单模块")
public class OrderController {
@PutMapping("modify")
public String modifyOrder(Long orderId,String name){
StringBuffer sb = new StringBuffer();
return sb.append(orderId).append(name).toString();
}
@DeleteMapping("delete")
public String removeOrder(Integer id, Long idL, HttpSession session, HttpServletRequest request){
return "delete";
}
@GetMapping
public String test(){
return "这是一个测试";
}
@GetMapping("/get_map_data")
public Map getMapData(){
Map<String,Object> ret = new HashMap<>();
ret.put("code",200);
ret.put("token","wqeqwdqwdqwdqwdfefe7656");
ret.put("msg","ok");
return ret;
}
}
@Api(tags = "订单模块") 是Swagger中的注解,该注解作用是:对该类的一个简要说明
2.构建 Docket 时通过其select()
方法来设置扫描接口策略,配置文件信息修改如下:
package com.xmlvhy.boot.swagger.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* @ClassName SwaggerConfig1
* @Description TODO
* @Author 小莫
* @Date 2019/05/17 14:05
* @Version 1.0
**/
@Configuration
//开启Swagger2的自动化配置
@EnableConfigurationProperties(SwaggerConfig1.class)
@ConfigurationProperties(prefix = "swagger")
@EnableSwagger2
@Data
public class SwaggerConfig1 {
/*ApiInfo对象的属性*/
/*文档标题*/
private String title;
/*文档描述*/
private String description;
/*文档版本信息*/
private String version;
/*文档编辑组织团队链接*/
private String termsOfServiceUrl;
/*文档许可说明*/
private String license;
/*文档许可链接*/
private String licenseUrl;
/*Contact 对象属性*/
//联系人姓名
private String name;
//联系人访问链接
private String url;
//联系人email
private String email;
/**
*功能描述: 配置Docket
* @Author 小莫
* @Date 14:07 2019/05/17
* @Param []
* @return springfox.documentation.spring.web.plugins.Docket
*/
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.xmlvhy.boot.swagger.controller"))
.build();
}
/**
*功能描述: 通过ApiInfo 来配置Api文档信息
* @Author 小莫
* @Date 15:12 2019/05/17
* @Param []
* @return springfox.documentation.service.ApiInfo
*/
private ApiInfo apiInfo(){
Contact contact = new Contact(name, url, email);
return new ApiInfoBuilder()
.title(title)
.description(description)
.version(version)
.termsOfServiceUrl(termsOfServiceUrl)
.license(license)
.licenseUrl(licenseUrl)
.contact(contact)
.build();
}
}
配置完成,重启项目并访问:
此时我们指定扫描的包下:OrderController.java 提供的接口全部被加载出来了
当然除了包路径扫描这种策略外,还有其它的方式可以指定扫描的接口,可以自己尝试,详情如下:
1.any() 默认的类型,表示扫描所有接口,所有接口都可以被扫描到
2.通过类上的注解扫描,只扫描 @RestController
如:.apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
3.通过方法上的注解扫描,只扫描get请求
如:.apis(RequestHandlerSelectors.withMethodAnnotation(GetMapping.class))
4.basePackage()根据包路径扫描接口
如:.apis(RequestHandlerSelectors.basePackage("com.xmlvhy.boot.swagger.controller"))
3.5、配置接口扫描过滤
通过以上的方式可以设置通过具体的类、方法来扫描接口,在这基础上还可以通过配置请求路径来指定扫描的接口。使用.paths(PathSelectors.ant("..."))
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
.select() .apis(RequestHandlerSelectors.basePackage("com.xmlvhy.boot.swagger.controller"))
.paths(PathSelectors.ant("/order/**"))
.build();
}
此时就指定了只扫描/order/**
下的所有接口;除了ant()外还有如下方式可以配置:
1.any() 表示任何请求都扫描
2.none() 表示任何请求都不扫描
3.regex(final String pathRegex) 表示通过正则表达式控制,返回true扫描,false不扫描
4.ant(final String antPattern) 表示通过ant()表达式控制,返回true扫描,false不扫描
3.5、配置要忽略的请求参数
可以通过.ignoredParameterTypes()
来配置要忽略的参数,我们先来看看,在OrderController的delete接口中,有 HttpServletRequest
和 HttpSession
两个参数,API文档中查看接口:
类似这种情况,我们就可以配置要忽略的参数了:
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
//.ignoredParameterTypes要在select()以及paths之前设置
.ignoredParameterTypes(HttpServletRequest.class, HttpSession.class)
.select() .apis(RequestHandlerSelectors.basePackage("com.xmlvhy.boot.swagger.controller"))
.paths(PathSelectors.ant("/order/**"))
.build();
}
3.6、配置API接口分组
此功能是很有必要的,当我们项目中有很多模块接口的时候这时候就需要做个区分,我们在查看api的时候就更方便了。当我们没有配置API分组的时候,默认是default,具体可看之前的截图。可以通过groupName()
方法来设置分组,如下:
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
.groupName("订单")
//.ignoredParameterTypes要在select()以及paths之前设置
.ignoredParameterTypes(HttpServletRequest.class, HttpSession.class)
.select()
.apis(RequestHandlerSelectors.basePackage("com.xmlvhy.boot.swagger.controller"))
.paths(PathSelectors.ant("/order/**"))
.build();
}
重启项目,查看效果:
当我们需要配置多个分组的时候,只需要配置多个Docket即可,如上我们在配置两个docket,分组分别设置为:会员和地址如下:
@Bean
public Docket docket1(){
return new Docket(DocumentationType.SWAGGER_2).groupName("会员");
}
@Bean
public Docket docket2(){
return new Docket(DocumentationType.SWAGGER_2).groupName("地址");
}
重启项目,查看效果:
备注:第一次进入Swagger文档页面展示的API信息,是以配置的第一个Docket中设置的规则为准!
3.7、配置是否启动Swagger
为什么需要这个配置呢?实际中,在生产环境,我们如果给外界暴露我们的接口是很不安全的,这就需要我们做一个限制,只允许在开发或者测试环境才可以查看或者其它限制。总之接口不要随便暴露给外界!!!本文我通过enable()方法来配置是否启用Swagger,如果设置false,那么API文档就不能在浏览中访问了:
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
.groupName("订单")
.enable(false)
//.ignoredParameterTypes要在select()以及paths之前设置
.ignoredParameterTypes(HttpServletRequest.class, HttpSession.class)
.select()
.apis(RequestHandlerSelectors.basePackage("com.xmlvhy.boot.swagger.controller"))
.paths(PathSelectors.ant("/order/**"))
.build();
}
项目重启,此时访问:
无法查看API文档信息了。
通过以上的配置,我们可以稍微修改一下,即通过SpringBoot 的多环境配置,当非处于生产环境中的时候,都可以查看API文档,反之不能查看。这样我们就实现了动态启动Swagger
@Bean
public Docket docket(Environment environment){
Profiles profiles = Profiles.of("pro");
boolean isEnable = environment.acceptsProfiles(profiles);
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
.groupName("订单")
.enable(!isEnable)
//.ignoredParameterTypes要在select()以及paths之前设置
.ignoredParameterTypes(HttpServletRequest.class, HttpSession.class)
.select()
.apis(RequestHandlerSelectors.basePackage("com.xmlvhy.boot.swagger.controller"))
.paths(PathSelectors.ant("/order/**"))
.build();
}
重启项目,此时查看效果,开发环境下可以正常访问:
3.8、配置一个全局参数
全局参数,只要扫描出来的接口都要有!应用场景:比如一个全局token参数信息。通过globalOperationParameters()来构造一个全局参数。如下:
@Bean
public Docket docket2(Environment environment){
Profiles profiles = Profiles.of("pro");
boolean isEnable = environment.acceptsProfiles(profiles);
//构造一个全局参数
Parameter parameter = new ParameterBuilder()
//参数名称
.name("token")
//参数类型,放在请求头中
.parameterType("header")
//参数描述
.description("用户令牌")
//是否必须
.required(true)
//参数类型
.modelRef(new ModelRef("String"))
.build();
List<Parameter> parameters = new ArrayList<>();
parameters.add(parameter);
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
.groupName("默认")
.globalOperationParameters(parameters)
.enable(!isEnable)
.select()
.apis(RequestHandlerSelectors.basePackage("com.xmlvhy.boot.swagger.controller"))
.build();
}
重启项目查看效果:
3.9、Swagger中实体类和Controller中的配置
创建一个User实体类,如下:
package com.xmlvhy.boot.swagger.entity;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @ClassName User
* @Description TODO
* @Author 小莫
* @Date 2019/05/16 12:00
* @Version 1.0
**/
@Data
@NoArgsConstructor
@AllArgsConstructor
//@ApiModel 为类添加注释
@ApiModel("用户实体")
public class User{
@ApiModelProperty(value = "用户Id")
private Integer userId;
@ApiModelProperty("用户名")
private String name;
@ApiModelProperty(value = "用户年龄")
private Integer age;
@ApiModelProperty(value = "手机号")
private String mobile;
@ApiModelProperty("电子邮箱")
private String email;
@ApiModelProperty("性别")
private String sex;
}
说明:
1.@ApiModel 为类添加注释
2.@ApiModelProperty 为类属性添加注释
创建一个UserController类,如下:
package com.xmlvhy.boot.swagger.controller;
import com.xmlvhy.boot.swagger.entity.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName UserController
* @Description TODO
* @Author 小莫
* @Date 2019/05/16 11:59
* @Version 1.0
**/
@Api(tags = "用户模块")
@RestController
@RequestMapping("/user")
public class UserController {
//模拟数据库
private static List<User> users = new ArrayList<>();
static {
users.add(new User(101,"xiaomo",26,"13641711060","1059224309@qq.com","男"));
users.add(new User(102,"xiaohong",16,"13641711xxx","105xxx9@qq.com","女"));
users.add(new User(103,"xiaowang",6,"13641711060","aa@qq.com","男"));
}
@ApiOperation(value = "获取用户信息",notes = "获取所有的用户信息列表")
@GetMapping("getUsers")
public List<User> getUsers(){
return users;
}
@ApiOperation(value = "保存一个用户信息")
@ApiImplicitParam(name = "user",value = "用户实体类")
@PostMapping("save")
public Object saveUser(@RequestBody User user){
return users.add(user);
}
@ApiOperation(value = "修改用户信息",notes = "根据用户id修改用户名")
@ApiImplicitParams({
@ApiImplicitParam(name = "id",value = "用户id",required = true,dataType = "int",paramType = "query"),
@ApiImplicitParam(name = "name",value = "用户姓名",required = true,dataType = "string",paramType = "query")
})
@PutMapping("putUser")
public Object putUser(@RequestParam(value = "id") int id, @RequestParam(value = "name") String name){
users.get(id).setName(name);
return "ok";
}
@ApiOperation(value = "获取单个用户信息",notes = "根据用户id查询某个用户信息")
@ApiImplicitParam(name = "id",value = "用户id",required = true,dataType = "int",paramType = "path")
@GetMapping("/getOne/{id}")
public Object getOneUser(@PathVariable(value = "id") int id){
return users.get(id);
}
@ApiOperation(value = "移除某个用户",notes = "根据id删除某个用户信息")
@ApiImplicitParam(name = "id",value = "用户ID")
@DeleteMapping("deleteUser")
public Object deleteUser(@RequestParam(value = "id") int id){
return users.remove(id);
}
}
重新修改一下Swagger配置类:
package com.xmlvhy.boot.swagger.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* @ClassName SwaggerConfig1
* @Description TODO
* @Author 小莫
* @Date 2019/05/17 14:05
* @Version 1.0
**/
@Configuration
//开启Swagger2的自动化配置
@EnableConfigurationProperties(SwaggerConfig1.class)
@ConfigurationProperties(prefix = "swagger")
@EnableSwagger2
@Data
public class SwaggerConfig1 {
/*ApiInfo对象的属性*/
/*文档标题*/
private String title;
/*文档描述*/
private String description;
/*文档版本信息*/
private String version;
/*文档编辑组织团队链接*/
private String termsOfServiceUrl;
/*文档许可说明*/
private String license;
/*文档许可链接*/
private String licenseUrl;
/*Contact 对象属性*/
//联系人姓名
private String name;
//联系人访问链接
private String url;
//联系人email
private String email;
/**
*功能描述: 默认组,显示所有模块接口,以定义dokect定义的扫描接口规则为准
* @Author 小莫
* @Date 16:58 2019/05/17
* @Param [environment]
* @return springfox.documentation.spring.web.plugins.Docket
*/
@Bean
public Docket docket2(Environment environment){
Profiles profiles = Profiles.of("dev", "test");
boolean isEnable = environment.acceptsProfiles(profiles);
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
.groupName("默认")
.enable(isEnable)
.select() .apis(RequestHandlerSelectors.basePackage("com.xmlvhy.boot.swagger.controller"))
.build();
}
/**
*功能描述: 配置Docket
* @Author 小莫
* @Date 14:07 2019/05/17
* @Param []
* @return springfox.documentation.spring.web.plugins.Docket
*/
@Bean
public Docket docket(Environment environment){
Profiles profiles = Profiles.of("dev", "test");
boolean isEnable = environment.acceptsProfiles(profiles);
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
.groupName("订单")
.enable(isEnable)
//.ignoredParameterTypes要在select()以及paths之前设置
.ignoredParameterTypes(HttpServletRequest.class, HttpSession.class)
.select()
.apis(RequestHandlerSelectors.basePackage("com.xmlvhy.boot.swagger.controller"))
.paths(PathSelectors.ant("/order/**"))
.build();
}
/**
*功能描述: 通过ApiInfo 来配置Api文档信息
* @Author 小莫
* @Date 15:12 2019/05/17
* @Param []
* @return springfox.documentation.service.ApiInfo
*/
private ApiInfo apiInfo(){
Contact contact = new Contact(name, url, email);
return new ApiInfoBuilder()
.title(title)
.description(description)
.version(version)
.termsOfServiceUrl(termsOfServiceUrl)
.license(license)
.licenseUrl(licenseUrl)
.contact(contact)
.build();
}
@Bean
public Docket docket1(Environment environment){
Profiles profiles = Profiles.of("dev", "test");
boolean isEnable = environment.acceptsProfiles(profiles);
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
.groupName("用户")
.enable(isEnable)
.select() .apis(RequestHandlerSelectors.basePackage("com.xmlvhy.boot.swagger.controller"))
.paths(PathSelectors.ant("/user/**"))
.build();
}
}
完成以上配置,重启项目,查看效果:
此时我们选择用户组,查看用户模块的API信息:
看用户模块中定义的接口,看着是不是更清晰了。我们主要来说明下,UserController中用到的Swagger中的相关注解:
//1. @Api 修饰整个类,描述Controller的作用
如:@Api(tags = "用户模块")
//2. @ApiOperation 描述一个类的一个方法,或者说一个接口
如:@ApiOperation(value = "获取用户信息",notes = "获取所有的用户信息列表")
value:描述大概信息 notes: 详细描述
//3. @ApiImplicitParam 一个请求参数;如:
@ApiOperation(value = "获取单个用户信息",notes = "根据用户id查询某个用户信息")
@ApiImplicitParam(name = "id",value = "用户id",required = true,dataType = "int",paramType = "path")
@GetMapping("/getOne/{id}")
public Object getOneUser(@PathVariable(value = "id") int id){
return users.get(id);
}
//4. @ApiImplicitParams 多个请求参数,如:
@ApiOperation(value = "修改用户信息",notes = "根据用户id修改用户名")
@ApiImplicitParams({
@ApiImplicitParam(name = "id",value = "用户id",required = true,dataType = "int",paramType = "query"),
@ApiImplicitParam(name = "name",value = "用户姓名",required = true,dataType = "string",paramType = "query")
})
@PutMapping("putUser")
public Object putUser(@RequestParam(value = "id") int id, @RequestParam(value = "name") String name){
users.get(id).setName(name);
return "ok";
}
/*其中内部参数功能:value: 备注输入参数名称(中文)name:备注输入参数名称(英文)required:该入参是否必填dataType:该入参的数据类型 paramType:前台接口调用时url 参数形式如:query 的形式:getUser?user=admin ;path的形式:getUser/user/admin*/
3.10、测试接口相关信息
四、修复 swaggerfox 升级 2.9.2版本问题
4.1、解决新版本问题
文章开篇,我有提到,整合Swagger新版本中,有一个小坑。这里具体说明下,当我们使用版本2.9.2时候,如果项目实体中有Integer类型的属性,当我们打开Api文档的时候会出现一个警告信息:
2019-05-17 17:31:47.743 WARN 4452 --- [nio-8080-exec-1] i.s.m.p.AbstractSerializableParameter : Illegal DefaultValue for parameter type integer
java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) ~[na:1.8.0_181]
at java.lang.Long.parseLong(Long.java:601) ~[na:1.8.0_181]
at java.lang.Long.valueOf(Long.java:803) ~[na:1.8.0_181]
at io.swagger.models.parameters.AbstractSerializableParameter.getExample(AbstractSerializableParameter.java:412) ~[swagger-models-1.5.20.jar:1.5.20]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_181]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_181]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688) [jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719) [jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) [jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:119) [jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:79) [jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:18) [jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727) [jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719) [jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) [jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727) [jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719) [jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) [jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeFields(MapSerializer.java:722) [jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:643) [jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:33) [jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727) [jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719) [jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) [jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480) [jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319) [jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:3905) [jackson-databind-2.9.8.jar:2.9.8]
at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3219) [jackson-databind-2.9.8.jar:2.9.8]
at springfox.documentation.spring.web.json.JsonSerializer.toJson(JsonSerializer.java:38) [springfox-spring-web-2.9.2.jar:null]
at springfox.documentation.swagger2.web.Swagger2Controller.getDocumentation(Swagger2Controller.java:105) [springfox-swagger2-2.9.2.jar:null]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_181]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_181]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) [spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) [spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) [spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) [spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039) [spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) [spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) [spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897) [spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) [tomcat-embed-core-9.0.19.jar:9.0.19]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) [spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) [tomcat-embed-core-9.0.19.jar:9.0.19]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) [tomcat-embed-core-9.0.19.jar:9.0.19]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.19.jar:9.0.19]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) [tomcat-embed-websocket-9.0.19.jar:9.0.19]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.19.jar:9.0.19]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.19.jar:9.0.19]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.19.jar:9.0.19]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.19.jar:9.0.19]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.19.jar:9.0.19]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.19.jar:9.0.19]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.19.jar:9.0.19]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.19.jar:9.0.19]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.19.jar:9.0.19]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
解决方案:
1.方案一:排除springfox-swagger2 引入的 swagger-annotations、swagger-models 1.5.20版本,手动引入1.5.21版本的jar。具体原因可以查看如下链接,这篇文章说的很详细!
https://blog.csdn.net/qq122516902/article/details/89673363
pom.xml 文件配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xmlvhy</groupId>
<artifactId>springboot-swagger</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>
<!--swagger2 相关依赖-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
<!--解决进入swagger页面报类型转换错误,排除2.9.2中的引用,手动增加1.5.21版本-->
<exclusions>
<exclusion>
<artifactId>swagger-models</artifactId>
<groupId>io.swagger</groupId>
</exclusion>
<exclusion>
<artifactId>swagger-annotations</artifactId>
<groupId>io.swagger</groupId>
</exclusion>
</exclusions>
</dependency>
<!--手动引入 swagger-models 以及 swagger-annotations 的 1.5.21 版本解决
java.lang.NumberFormatException: For input string: "" 错误
-->
<dependency>
<artifactId>swagger-annotations</artifactId>
<groupId>io.swagger</groupId>
<version>1.5.21</version>
</dependency>
<dependency>
<artifactId>swagger-models</artifactId>
<groupId>io.swagger</groupId>
<version>1.5.21</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
</dependency>
</dependencies>
</project>
2.方案二:通过方案一,我们可以了解得该警告并没有实质性影响,知识报错信息看着不好,所以我们通过设置报错包下的log级别来避开此警告信息,这种方式比较粗暴!
# 将 io.swagger.models.parameters.AbstractSerializableParameter 包下的日志级别设置为error,避免提示出现
# "" 转换为 integer 的类转换异常,不影响
logging:
level:
io.swagger.models.parameters.AbstractSerializableParameter: error
以上便是我学习Swagger做的相关总结,如有不对之处,还请指出!
参考链接:
https://blog.csdn.net/qq122516902/article/details/89417964
本篇文章涉及的源码,点击下载。
本文作者: AI码真香
本文标题: SpringBoot 中如何使用SwaggerAPI接口文档?
本文网址: https://www.xmlvhy.com/article/66.html
版权说明: 自由转载-非商用-非衍生-保持署名 署名-非商业性使用4.0 国际 (CC BY-NC 4.0)
类似文章
| 0 评论
还没有评论,快来抢沙发吧!