1.7 文档注释使用
1.7.1 接口组定义
- 接口有时候应该是分组的,而且大部分都是在一个controller中的,比如app管理相关的接口应该都在AppController中,那么不同的业务的时候,应该定义/划分不同的接口组。接口组可以使用
@Api
来划分。
注意,对于swagger,不要使用@RequestMapping
因为@RequestMapping支持任意请求方式,swagger会为这个接口生成7种请求方式的接口文档
@Api(tags = "app管理") //可以当作是这个组的名字。
@RestController
@RequestMapping("app")
public class AppController {
@RequestMapping(value = "/hello",method = RequestMethod.GET)
public String hello(){
return "hello swagger!";
}
}
可以理解成基于tags来分组
如果这个Controller下(接口组)下面没有接口,那么在swagger ui中是不会显示的,如果有的话就会这样显示:
1.7.2 接口定义
- 使用了
@Api
来标注一个Controller之后,如果下面有接口,那么就会默认生成文档,但没有我们自定义的说明:
- 我们可以使用
@ApiOperation
来描述接口,比如:
//只要我们的接口中,返回值中存在实体类,他就会被扫描外wagger中
@ApiOperation(value = "获取用户",notes = "获取用户接口")
@GetMapping("/getUser")
public User getUser(String name,String password){
return new User(name,password);
}
常用配置项:
- value:可以当作是接口的简称
- notes:接口的描述
- tags:可以额外定义接口组,比如这个接口外层已经有
@Api(tags = "用户管理")
,将接口划分到了“用户管理”中,但你可以额外的使用tags,例如tags = "角色管理"
让角色管理中也有这个接口文档。
1.7.3 定义接口请求参数
- 上面使用了
@ApiOperation
来了描述接口,还缺少接口请求参数的说明.
对于GET方式,swagger不推荐使用body方式来传递数据,所以虽然Spring MVC可以自动封装参数,也是不希望在GET方式时使用json、form-data等方式来传递,这时候最好使用路径参数或者url参数。(虽然POSTMAN等是支持的,swagger在线测试是不支持这个操作的),所以如果接口传递的数据是json或者form-data方式的,还是使用POST方式好。可翻看之前的博客SpringMVC-09-传递参数的几种方式
1.7.3.1 请求参数是实体类
-
此时我们需要使用
@ApiModel
来标注实体类,然后在接口中定义入参为实体类即可: -
@ApiModel:用来标类,@ApiModel内的注释 不要出现相同 否则会将相同的vo字段进行合并
- 常用配置项:
- value:实体类简称
- description:实体类说明
- 常用配置项:
-
@ApiModelProperty:用来描述类的字段的意义。
- 常用配置项:
- value:字段说明
- example:设置请求示例(Example Value)的默认值,如果不配置,当字段为string的时候,此时请求示例中默认值为”“,对于int类型数据若没有默认值,则默认是””空字符串,会造成NumberFormatException,
- 常用配置项:
1.给int类型的字段使用@ApiModelPorperty注解时添加example属性
2.去除原swagger中的swagger-models和swagger-annotations,自行引入高版本的annotations和models
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.5.22</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.5.22</version>
</dependency>
- notes:参数类型为String,作用为该字段的注释说明
- name:用新的字段名来替代旧的字段名。
- position:参数类型为int,作用为允许显式地对模型中的属性排序。
- allowableValues:限制值得范围,例如
{1,2,3}
代表只能取这三个值;[1,6]
代表取1到6的值;(1,6)
代表1到6的值,不包括1和6;还可以使用infinity或-infinity来无限值,比如[1, infinity]
代表最小值为1,最大值无穷大。 - required:标记字段是否必填,默认是false,
- hidden:用来隐藏字段,默认是false,如果要隐藏需要使用true,因为字段默认都会显示,就算没有
@ApiModelProperty
。 - allowEmptyValue:参数类型为boolean,作用为是否允许传递空值,默认为false
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(value = "用户实体类",description = "用户实体对象") // 先使用@ApiModel来标注类
public class User {
// 使用ApiModelProperty来标注字段属性。
@ApiModelProperty(value = "name",required = true,example = "toy")
private String name;
@ApiModelProperty(value = "name",required = true,example = "123456")
private String password;
//swagger在入参赋值时需要的getter,setter来置值
}
- 定义成入参:
@ApiOperation(value = "获取用户",notes = "获取用户通过传递实体json")
@PostMapping("/getUser")
public User getUserPost(@RequestBody User user){
return user;
}
1.7.2.2 请求参数是非实体类
-
对于非实体类参数,可以使用
@ApiImplicitParams
和@ApiImplicitParam
来声明请求参数。
@ApiImplicitParams
用在方法头上,@ApiImplicitParam
定义在@ApiImplicitParams
里面,一个@ApiImplicitParam
对应一个参数。@ApiImplicitParam
常用配置项: -
name:用来定义参数的名字,也就是字段的名字,可以与接口的入参名对应。如果不对应,也会生成,所以可以用来定义额外参数!
-
value:用来描述参数
-
required:用来标注参数是否必填
-
paramType有path,query,body,form,header等方式,但对于对于非实体类参数的时候,常用的只有path,query,header;body和form是不常用的。body不适用于多个零散参数的情况,只适用于json对象等情况。【如果你的接口是
form-data
,x-www-form-urlencoded
的时候可能不能使用swagger页面API调试,但可以在后面讲到基于BootstrapUI的swagger增强中调试,基于BootstrapUI的swagger支持指定form-data
或x-www-form-urlencoded
】 -
也可以仅仅使用@ApiParam作用在方法上参数不用声明,@ApiParam使用配置和@ApiImplicitParam一样对于3.0.0比2.X有点是可以适配所有类型的参数请求方式,2.x需要测试时手动选择
//只要我们的接口中,返回值中存在实体类,他就会被扫描外wagger中 @ApiOperation(value = "获取用户",notes = "获取用户接口") @GetMapping("/getUser") public User getUser(@ApiParam(name = "name",value = "账户",required = true) String name,@ApiParam(name = "password",value = "密码",required = true)String password){ return new User(name,password); }
query方式入参
//query方式入参
@ApiOperation(value = "获取用户1",notes = "获取用户接口1-query方式入参")
@GetMapping("/getUser1")
@ApiImplicitParams({
@ApiImplicitParam(name = "name",value = "账户",required = true,paramType = "query"),
@ApiImplicitParam(name = "password",value = "密码",required = true,paramType = "query")
})
public User getUser1(String name,String password){
return new User(name,password);
}
path方式入参
//path方式入参
@ApiOperation(value = "获取用户2",notes = "获取用户接口2-path方式入参")
@GetMapping("/getUser/{name}/{password}")
@ApiImplicitParams({
@ApiImplicitParam(name = "name",value = "账户",required = true,paramType = "path"),
@ApiImplicitParam(name = "password",value = "密码",required = true,paramType = "path")
})
public User getUser2(@PathVariable("name") String name,@PathVariable("password")String password){
return new User(name,password);
}
header方式入参
//header方式入参
@ApiOperation(value = "获取用户3",notes = "获取用户接口3-header方式入参")
@GetMapping("/getUser3")
@ApiImplicitParams({
@ApiImplicitParam(name = "name",value = "账户",required = true,paramType = "header"),
@ApiImplicitParam(name = "password",value = "密码",required = true,paramType = "header")
})
public User getUser3(@RequestHeader String name,@RequestHeader String password){
return new User(name,password);
}
单件上传入参
文件上传时要用@ApiImplicitParams @ApiImplicitParam @ApiParam作用在方法上作为入参@RequestPart用在参数上,用于将“multipart/form-data”请求的一部分与方法参数相关联的注释
//单件上传入参
@ApiOperation(value = "文件上传1",notes = "文件上传-单文件")
@ApiImplicitParams({
@ApiImplicitParam(name = "uploadFile", paramType="form", value = "上传文件", dataType="uploadFile", required = true)
})
@PostMapping(value = "/upload1", headers = "content-type=multipart/form-data")
public String upload(@RequestPart("uploadFile") MultipartFile uploadFile, HttpSession session, HttpServletRequest req){
String originalFilename = uploadFile.getOriginalFilename();
//若文件名为空则返回到上传页
if (!StringUtils.hasText(originalFilename)) {
return "originalFilename is error";
}
//上传路径保存设置
//String uploadPath = session.getServletContext().getRealPath("/uploadFile/");
System.out.println("fileSavePath====="+fileSavePath);
File file1 = new File(fileSavePath);
if (!file1.exists()) {
file1.mkdirs();
}
try {
uploadFile.transferTo(new File(file1,originalFilename));
} catch (IOException e) {
e.printStackTrace();
return "uploadFile is error!";
}
return req.getScheme()+"://"+req.getServerName()+":"+req.getServerPort()+"/workspace_idea01/uploadFile/"+originalFilename;
}
多件上传入参
多个文件上传时,swagger只能测试单文件上传,需要用postman或Apifox等工具测试
@ApiOperation(value = "文件上传2",notes = "文件上传-多文件")
@PostMapping(value = "/upload2",consumes = "multipart/*", headers = "content-type=multipart/form-data")
public ArrayList upload2(@ApiParam(name = "uploadFile",value = "上传文件",required = true,allowMultiple = true) MultipartFile[] uploadFile, HttpSession session, HttpServletRequest req){
String originalFilename ="";
//若文件名为空则返回到上传页
if (!StringUtils.hasText(originalFilename)) {
System.out.println("originalFilename is error");
}
ArrayList<String> filePathList=new ArrayList();
System.out.println("fileSavePath====="+fileSavePath);
File file1 = new File(fileSavePath);
if (!file1.exists()) {
file1.mkdirs();
}
for (MultipartFile file: uploadFile) {
originalFilename = file.getOriginalFilename();
if (!StringUtils.hasText(originalFilename)) {
System.out.println("originalFilename is error");
}
try {
file.transferTo(new File(file1,originalFilename));
filePathList.add(req.getScheme()+"://"+req.getServerName()+":"+req.getServerPort()+"/workspace_idea01/uploadFile/"+originalFilename);
} catch (IOException e) {
e.printStackTrace();
System.out.println("uploadFile is error!");
}
}
return filePathList;
}
通过reuestbody传递数据等方式
//通过reuestbody传递数据等方式
@ApiOperation(value = "测试requestBody", notes = "测试requestBody")
@ApiImplicitParams({
@ApiImplicitParam(paramType="query", name="userId", value="用户id", dataTypeClass = Integer.class, required = true),
@ApiImplicitParam(paramType="body", name = "body",dataType = "string", example = "", required = false)
})
@PostMapping(value="/command",produces = {"application/json;charset=UTF-8"})
public String getHttpInfo(@RequestBody User user, Integer userId) throws IOException {
//InputStream in = request.getInputStream();
// TODO. LOGIC
return user.toString();
}
- 也可以从request流中取值
public String getHttpInfo(HttpServletRequest request, Integer userId) throws IOException { InputStream in = request.getInputStream(); }
既有文件,又有参数
@ApiOperation(value = "文件上传3",notes = "文件上传-携带参数")
@ApiImplicitParams({
@ApiImplicitParam(name = "uploadFile", paramType="form", value = "上传文件", dataType="uploadFile", required = true),
@ApiImplicitParam(name = "id", paramType="query", value = "参数id", dataTypeClass= Integer.class, required = true)
})
@PostMapping(value = "/upload3", headers = "content-type=multipart/form-data")
public String upload3(@RequestPart("uploadFile") MultipartFile uploadFile,Integer id, HttpServletRequest req){
String originalFilename = uploadFile.getOriginalFilename();
//若文件名为空则返回到上传页
if (!StringUtils.hasText(originalFilename)) {
return "originalFilename is error";
}
//上传路径保存设置
//String uploadPath = session.getServletContext().getRealPath("/uploadFile/");
System.out.println("fileSavePath====="+fileSavePath);
File file1 = new File(fileSavePath);
if (!file1.exists()) {
file1.mkdirs();
}
try {
uploadFile.transferTo(new File(file1,originalFilename));
} catch (IOException e) {
e.printStackTrace();
return "uploadFile is error!";
}
return req.getScheme()+"://"+req.getServerName()+":"+req.getServerPort()+"/workspace_idea01/uploadFile/"+originalFilename+"&id="+id;
}
1.7.4 定义接口响应
- 定义接口响应,即查看接口文档的人能够知道接口返回的数据的意义。
1.7.4.1 响应是实体类
- 只要在接口请求参数上使用
@ApiModel
来标注类,如果接口返回了这个类,那么这个类上的说明也会作为响应的说明:
@ApiOperation(value = "返回实体对象",notes = "返回实体对象描述user")
@PostMapping("/getUser4")
public User getUser4(@RequestBody User user){
return user;
}
1.7.4.2 响应非实体类
- swagger无法对非实体类的响应进行详细说明,只能标注响应码等信息。是通过
@ApiResponses
和@ApiResponse
来实现的。
@ApiOperation(value = "返回非实体",notes = "返回非实体描述Stirng")
@PostMapping("/getUser5")
@ApiResponses({
@ApiResponse(code = 200,message = "请求-响应成功"),
@ApiResponse(code = 404,message = "页面异常"),
})
public String getUser5(@RequestBody User user){
return user.toString();
}
1.8 Swagger UI增强
- 作为Swagger UI的衍生,可以使用第三方提供了一些Swagger UI增强,如swagger-bootstrap-ui
1.8.1 使用
- 补充导入swagger-bootstrap-ui,前面的swagger-ui不变
<!--1.9.6会出NoClassDefFoundError: com/google/common/base/Function环境问题-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.8.7</version>
</dependency>
- 在swagger配置类中增加注解
@EnableSwaggerBootstrapUI
:
@Configuration // 标明是配置类
//@EnableSwagger2 //开启swagger2功能 供3.0以下使用,swagger老版本
@EnableOpenApi
//@Profile({"dev","test"})
@ConditionalOnProperty(name = "swagger.enable",havingValue = "true")
@EnableSwaggerBootstrapUI
public class SwaggerConfig {
...
}
- 访问API:
http://localhost:8080/doc.html
,可预览到基于bootstarp的Swagger UI界面。
-
基于BootstrapUI的swagger支持指定
form-data
或x-www-form-urlencoded
-
支持复制单个API文档和导出全部API文档:
- 整合Spring Security注意
在Spring Boot整合Spring Security和Swagger的时候,需要配置拦截的路径和放行的路径,注意是放行以下几个路径。
.antMatchers("/swagger**/**").permitAll()
.antMatchers("/webjars/**").permitAll()
.antMatchers("/v2/**").permitAll()
.antMatchers("/doc.html").permitAll() // 如果你用了bootstarp的Swagger UI界面,加一个这个。
1.8.2 对于token的处理
-
在swagger中只支持了简单的调试,但对于一些接口,我们测试的时候可能需要把token信息写到header中
-
办法如下:
-
- 在Swagger BootstrapUI,可以在“文档管理”中增加全局参数,这包括了添加header参数。
- 在swagger配置类中增加全局参数配置
@Bean public Docket docket(Environment environment){ RequestParameterBuilder builder = new RequestParameterBuilder(); RequestParameter requestParameter = builder.name("token").description("令牌").in(ParameterType.HEADER).required(false).build(); List<RequestParameter> globalRequestParameters = new ArrayList<>(); globalRequestParameters.add(requestParameter); //设置要显示的Swagger环境 Profiles profiles = Profiles.of("dev", "test"); //通过environment.acceptsProfiles配置文件中设置的环境来判断是否在设定的环境中 boolean flag = environment.acceptsProfiles(profiles); return new Docket(DocumentationType.OAS_30)// DocumentationType.OAS_30 固定的,代表swagger3.0 .groupName("分组1") // 如果配置多个文档的时候,那么需要配置groupName来分组标识 .apiInfo(apiInfo()) .enable(flag) .select() // select()函数返回一个ApiSelectorBuilder实例,用来控制接口被swagger做成文档 .apis(RequestHandlerSelectors.basePackage("com.example.controller"))// 用于指定扫描哪个包下的接口 //paths 指定扫描路径 PathSelectors.ant("/app/**")在controller包下,请求路径是/app/**可以扫描到 .paths(PathSelectors.any())// 选择所有的API,如果你想只为部分API生成文档,可以配置这里 .build().globalRequestParameters(globalRequestParameters); //建造者模式 }
- 使用
@ApiImplicitParams
来额外标注一个请求头参数,例如:
@ApiOperation(value = "获取用户5",notes = "获取用户接口5-带token的接口")
@GetMapping("/getUser5")
@ApiImplicitParams({
@ApiImplicitParam(name = "name",value = "账户",required = true,paramType = "query"),
@ApiImplicitParam(name = "password",value = "密码",required = true,paramType = "query"),
@ApiImplicitParam(name = "token",value = "令牌",required = true,paramType = "header"),
})
public User getUser5(String name,String password){
return new User(name,password);
}
- 整合了权限管理,可以给swagger加上权限管理
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/123871.html