-
Notifications
You must be signed in to change notification settings - Fork 24
进阶教程
注解 | 注解字段 | 是否支持 | 作用描述 | 备注 |
---|---|---|---|---|
@RequestMapping | value/path | 支持 | 绑定一个或多个 url | |
@RequestMapping | method | 支持 | 限制请求的 HTTP 方法类型 | |
@RequestMapping | consumes | 不支持 | 限制请求 Content-Type必须被此字段包含,否则抛出异常 | |
@RequestMapping | produces | 不支持 | 限制请求 Accept 必须与此字段对应,否则抛出异常 | |
@GetMapping | 同 @RequestMapping | 支持 | @RequestMapping + 限制方法类型为 GET | |
@PostMapping | 同 @RequestMapping | 支持 | @RequestMapping + 限制方法类型为 POST | |
@PutMapping | 同 @RequestMapping | 支持 | @RequestMapping + 限制方法类型为 PUT | |
@DeleteMapping | 同 @RequestMapping | 支持 | @RequestMapping + 限制方法类型为 DELETE | |
@RequestBody | 无 | 支持 | 修饰的参数在一系列操作下可与HTTP 请求 Body 映射 | 插件读取后会将除此之外的参数拼接到 url 上,请求示例则展示为 json 格式 |
@RequestParam | value/name | 支持 | 覆盖参数变量名 | |
@RequestParam | required | 支持 | 指定是否必填,默认为 true |
本插件支持读取注释 / 注解信息来生成文档,因为 Swagger 用户比较多,考虑到最小成本改造,注解采用的正是 Swagger 这一套,注释则是自己随便定义了一些 tag,具体见下表格!
注解 | 注解字段 | 对应注释 | 作用说明 | 备注 |
---|---|---|---|---|
@Api | tags | #tags 或 @tags | 接口分组名称 | 插件将此字段信息用于两处(批量生成时的按类分组生成的文档文件名/Postman 文件夹名称) |
@Api | description | 不带注释 tag 部分连起来(可换行)或@description | 接口分组描述 | 分组描述用不上,因此我将其作为 tags 的备用,无 tags 字段时,使用此字段。具体逻辑见代码 (cn.gudqs7.plugins.docer.pojo.annotation.CommentInfo#getItemName) |
@Api | hidden | #hidden 或 @hidden | 隐藏此类下所有接口 | 即跳过此类下所有接口,不生成(但类上直接右键时会忽略此字段,毕竟都指名道姓了,再忽略就不合理了! |
@ApiOperation | value | 不带注释 tag 部分连起来(可换行) | 接口名称(接口简述) | |
@ApiOperation | notes | #notes 或 @notes | 接口详细描述 | |
@ApiOperation | hidden | #hidden 或 @hidden | 隐藏该接口 | 即跳过此接口,不生成(但方法上直接右键时会忽略此字段,毕竟都指名道姓了,再忽略就不合理了! |
@ApiOperation | tags | 不支持 | 覆盖 Controller 上 @Api 的 tags 字段,将接口分组 | 暂不支持,个人无这个需求,目前分组逻辑是类下的为一组,放到同一个文件下,不同包下不同文件夹。(主要目前代码逻辑要支持改动挺大的) |
@ApiOperation | 其他字段 | 不支持 | ||
@ApiParam | name | 不支持 | 覆盖变量名 | Swagger 本身无法对 MVC 规则变动,一般需搭配 @RequestParam,而本插件是支持 @RequestParam 的 |
@ApiParam | value | @param 后面非 tagKey=tagValue 部分 | 字段描述 | |
@ApiParam | required | @param xxx required | 字段是否必填 | 默认为 required=false,可写为 required=true,也可直接写为 required |
@ApiParam | example | @param xxx example=yyy | 字段示例值,字段默认值 | |
@ApiParam | hidden | @param xxx hidden | 隐藏改字段 | 写法同 required,凡是 bool 值均如此 |
@ApiModel | value | 类注释中非 tag 部分(可换行) | 类的简述 | |
@ApiModel | description | 不支持 | 类的描述 | 暂不支持,后续考虑加上吧,用处不大。 |
@ApiModelProperty | value | 字段注释中非 tag 部分(可换行) | ||
@ApiModelProperty | notes | #notes 或 @notes | ||
@ApiModelProperty | example | #example 或 @example | ||
@ApiModelProperty | required | #required 或 @required | 值为 true 或 false,由于默认值为 false,因此希望指定为 true 时,可省略值不填,即 @required == @required true(所有bool类型都如此) | |
@ApiModelProperty | hidden | #hidden 或 @hidden | 同上 | |
@ApiModelProperty | name | 不支持 | 覆盖字段变量名 | 暂不支持,考虑到目前没遇到前后的名称风格不一致的情况(前端无话语权),暂时就这样吧! |
虽然提到了注解,但更多时候,我都是增加注释来完善文档的,毕竟注解的侵入性较高,还需要增加依赖 jar。
可能你已经注意到了,上面的表格对应注释总是有两种写法,但他们其实只有前缀不同。
我在代码中解析时,两个符号都会判断,等同对待,因此任一种写法都是 OK 的。
之所以会加一个#
开头,主要是考虑大部分同学并不知道(我也不知道)如何设置自定义注释 tag,以确保 IDEA 某条规则解析时不会以警告处理。而#
,反而不会触发这条报警规则!
虽然你有注解,但我偏喜欢用注释来生成文档,此时需要使用此注解来告诉插件,使用注释而忽略注解!
之所以这么设计,是因为我虽然更偏爱注释,但也知道大部分注释都是不完整的,而注解则一般较为完整;因此设计优先级时,存在注解则优先使用注解的信息;
于是,我们需要一种方式来提高注释的优先级;此时我便想到了 CSS 的!important
,于是添加了这个注解。
该注释值为true/false
,一般写作#important
即可。
该注释支持位置如下:类上,字段上,方法上,参数中(即@param
这行,注意参数的注释以xx=xx
格式,不同于其他三处写法)
若您的接口有多个返回状态码,一般为错误码;
您可使用@code 50001 错误信息xxxx
来描述这个状态,若有多个,则多写几行即可!
请看一个示例:
/**
* 新增一个用户
*
* @param createUserRequest 用户信息
* @return 操作是否成功
* #hiddenResponse totalCount
* #code 10001 用户昵称已存在
* #code 10002 用户年龄范围无效, 即用户年龄需在0~200之间的数字
*/
@PostMapping("/createUser")
public BaseResponse<Boolean> createUser(CreateUserRequest createUserRequest) {
return BaseResponse.success();
}
生成文档如下图,将多出一段 Code 含义信息表格
友情提示,该功能 Swagger 也支持,请翻到看下面注解篇查看!
有时候,部分数据传输类被多个接口复用,但某个接口可能不需要某个字段(不论入参出参),此时我们可以使用
@hiddenRequest
和@hiddenResponse
来排除字段;
类似的,你也可以使用@onlyRequest
和@onlyResponse
来指定仅需要的字段。
其中request
后缀指代入参,response
后缀指代出参。
另外,排除和仅包含只能出现一个,否则排除优先级更高,另一个则不会起作用。
关于出参,用法比较确定,毕竟只有一个返回值,以此为根对象,指定字段非常方便;如上个示例中我就隐藏了totalCount
这个分页相关的出参,其为返回类型下的一个字段;也可以使用data.xxx
这种格式,通过.
来指定多层结构下的字段。
而入参,我采用的方式是以Spring MVC
的解析方式为准,即若所有参数以application/x-www-form-urlencoded
方式绑定,则表单中的组件名称与变量名称对应;
且当参数为对象类型时,其下的字段与表单中组件名称一致,而不是带有参数的变量名为前缀;如上个示例中,createUserRequest
这个变量就是如此。
总计就是不带有参数变量名为前缀的写法。
这与knife4j
定义的@ApiOperationSupport
注解中includeParameters,ignoreParameters
并不相同;
不过您不用担心,我在程序中已经做了处理,使用其注解时,按照knife4j
的写法来即可,插件依然能正确识别。
两个注释作用一样,
@date
的优先级高;
此注释只能用于字段上。
示例:
/**
* 开始时间(精度为天)
* @json yyyy-MM-dd
* @data yyyy-MM-dd
*/
private Date startTime;
生成的文档的结果如下:
{
"startTime": "2022-05-29"
}
此注释依据
@JsonFormat
和@DateTimeFormat
注解字段pattern
演化而来,因此使用注解也会识别,都存在时,注解优先级高!(@important
此时无效)
如题,添加注释后,生成的 Postman 请求下,返回示例将不生成!
此注释可用于类上,方法上,方法上优先级高(就近原则)。
您可通过
@guid
来指定示例值为一个 GUID;
使用@random
来指定字符串示例值的生成时随机的(有字段描述时,非随机,此时可用注释指定为随机,无字段描述时,默认随机);
这两个注释仅适用于字符串类型的字段;
此注释可用于,方法参数上,字段上。
-
@ApiResponse
的code
和message
分别对应 Code 和 含义 -
@ApiResponses
则用于包含多个@ApiResponse
- 注意此注解仅
knife4j
拥有。 - 上面有提到,
knife4j
的写法是包含参数变量作为前缀的,和我注释的写法是不一样的,请不要混淆两者! -
knife4j
仅支持入参,不支持出参,而我的注释是均支持,您可以在注解的基础上,使用注释来设置出参,这样是可以生效的。(这点适用于绝大多数更多注释)
-
@JsonFormat
的pattern
字段值与注释@json
对应。 -
@DateTimeFormat
的pattern
字段值与注释@date
对应。
-
@NotNull / @NotEmpty / @NotBlank
:包含此三个任意一个注解的字段或参数,其是否必填会被设置为 true。 -
@Length
:包含此注解时,其字段max / min
指定了字符长度最大值和最小值,其他参考信息列会多出相应的描述。 -
@Range / @Min / @Max
:指定了数字的范围,其他参考信息列会多出相应的描述。
以上的 Hibernate validator 注解均支持在参数上或字段上。
直接在项目上右键(或某个目录/某个类/任意多选亦可),然后点击 Export Api Interface to Postman
的按钮,如下图
生成的结果文件在文档跟目录(一般为项目路径/api-doc)下 postman 目录下,有个 xxx.postman_collection.json
,然后在 Postman 导入界面选择此文件即可。
导出到 Postman 有两种模式
- 离线模式,生成文件到 postman 目录下。
- 在线模式,通过配置文件指定 Postman 的 Api Key,可直接通过 api 生成到你的 workspace 下(但无法控制生成到哪个 workspace 下,Postman 提供的 Api 不够完善的问题。)
另外,当仅选择一个类右键时,会根据此类为标识来生成新的 Collection(默认以项目名或在配置文件中指定);
这样做的好处是,不会因为调试某个类把原来的 Collection 覆盖掉。
双击 Shift
进入 Search Everywhere
后切换到 Api,或使用快捷键 Ctrl + \
或 Ctrl + Alt + N
进入如下图界面。
此时您可通过 url 或接口描述来搜索并跳转到该接口。
以下展示后缀的使用方法,但使用智能上下文得到的效果是类似的,只是个人认为后缀效率更高一丢丢!
下面演示所使用的基础类
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class Foo {
private Integer testInt;
private Long testLong;
private Float testFloat;
private Double testDouble;
private Boolean testBoolean;
}
public void usage01() {
// 用法1, 生成所有 set 方法, 带默认值, 通过 postfix
Foo foo = new Foo();
// 取消下面的注释, 光标位于 allset 后面, 按下 Tab 键
// foo.allset
// 即可得到下面结果, 且 foo.allset 会自动消失
foo.setTestInt(0);
foo.setTestLong(0L);
foo.setTestFloat(0f);
foo.setTestDouble(0D);
foo.setTestBoolean(false);
}
public void usage03() {
// 用法3, 生成所有 get 方法, 通过 postfix
Foo foo = new Foo();
// 取消下面的注释, 光标位于 allget 后面, 按下 Tab 键
// foo.allget
// 即可得到下面结果, 且 foo.allget 会自动消失
Integer testInt = foo.getTestInt();
Long testLong = foo.getTestLong();
Float testFloat = foo.getTestFloat();
Double testDouble = foo.getTestDouble();
Boolean testBoolean = foo.getTestBoolean();
}
public void usage04() {
// 用法4, 生成所有 set 方法, 通过 builder, 通过 postfix
// 取消下面的注释, 光标位于 allbuilder 后面, 按下 Tab 键
// Foo.builder().allbuilder
// 即可得到下面结果
Foo foo = Foo.builder()
.testInt(0)
.testLong(0L)
.testFloat(0f)
.testDouble(0D)
.testBoolean(false)
.build();
}
public void usage05() {
// 用法5, 将 src 的数据赋值给 dest, 常用于两个不同类直接进行 convert(需字段名称相同), 通过 postfix
Foo src = new Foo();
Foo dest = new Foo();
// 取消下面的注释, 光标位于 convert 后面, 按下 Tab 键
// dest.setTestInt(src.getTestInt());.convert
// 即可得到下面结果
dest.setTestInt(src.getTestInt());
dest.setTestLong(src.getTestLong());
dest.setTestFloat(src.getTestFloat());
dest.setTestDouble(src.getTestDouble());
dest.setTestBoolean(src.getTestBoolean());
}
public Foo usage09(Foo src) {
// 用法9 通过在方法名称上触发 Show Context Actions, 快捷键(如 Alt + Enter 或右键菜单选择)
// 可看到 Generate Convert,选中后生成下面注释里的内容(不包含 return null;)
// Foo foo = new Foo();
// foo.setTestInt(src.getTestInt());
// foo.setTestLong(src.getTestLong());
// foo.setTestFloat(src.getTestFloat());
// foo.setTestDouble(src.getTestDouble());
// foo.setTestBoolean(src.getTestBoolean());
// return foo;
return null;
}
上面这些代码在示例代码块的
cn.gudqs.example.genset.GenerateSetterAndGetterUsage
下。
欢迎 Clone 体验。