概述
当我们使用Swagger生成验证时,通常会依赖基本规范。然而,有时我们需要添加Spring自定义验证注解。本文将指导如何在关注OpenAPI服务器生成器而不是约束验证器的情况下,利用这些验证来创建模型和REST API。
安装设置
我们将使用之前Baeldung教程中的内容,从OpenAPI 3.0.0规范生成一个服务器:从OpenAPI 3.0.0定义生成服务器。接下来,我们会添加一些自定义验证注解,并引入所有必要的依赖。
PetStore API OpenAPI定义
假设我们有一个PetStore API的OpenAPI定义,并需要为REST API和描述的模型(Pet)添加自定义验证。
3.1. API模型的自定义验证
为了创建宠物,我们需要让Swagger使用我们的自定义验证注解检查宠物名称是否大写。因此,为了本教程,我们将这个验证命名为Capitalized。
请查看下面示例中的x-constraints规范,它将告诉Swagger我们需要生成不同于已知类型的另一种注解:
openapi: 3.0.1
info:
version: "1.0"
title: PetStore
paths:
/pets:
post:
#.. post described here
components:
schemas:
Pet:
type: object
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
x-constraints: "Capitalized(required = true)"
tag:
type: string
3.2. REST API端点的自定义验证
同样,我们会在描述查找所有以特定名称的宠物的端点时采用相同的方法。为了演示目的,假设我们的系统对大小写敏感,所以我们将再次为name输入参数添加x-constraints验证:
/pets:
# post defined here
get:
tags:
- pet
summary: Finds Pets by name
description: 'Find pets by name'
operationId: findPetsByTags
parameters:
- name: name
in: query
schema:
type: string
description: Tags to filter by
required: true
x-constraints: "Capitalized(required = true)"
responses:
'200':
description: default response
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Pet'
'400':
description: Invalid tag value
4. 创建Capitalized
注解
为了强制执行自定义验证,我们需要创建一个确保功能的注解。
首先,我们创建一个接口——@Capitalized
:
@Documented
@Constraint(validatedBy = {Capitalized.class})
@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Capitalized{
String message() default "Name should be capitalized.";
boolean required() default true;
// default annotation methods
}
请注意,我们为了演示目的添加了required
方法,稍后会解释。
接下来,我们需要添加CapitalizedValidator
,这是上面@Constraint
注解中引用的:
public class CapitalizedValidator implements ConstraintValidator<Capitalized, String> {
@Override
public boolean isValid(String nameField, ConstraintValidatorContext context) {
// validation code here
}
}
5. 生成验证注解
5.1. 指定Mustache模板目录
为了在模型中生成带有@Capitalized
验证的注解,我们需要特定的Mustache模板,告诉Swagger在模型中生成它。
因此,在OpenAPI生成插件中,在<configuration>...</configuration>
标签内,我们需要添加一个模板目录:
<plugin>
//...
<executions>
<execution>
<configuration
//...
<templateDirectory>
${project.basedir}/src/main/resources/openapi/templates
</templateDirectory>
//...
</configuration>
</execution>
</executions>
//...
</plugin>
5.2. 添加Mustache Bean验证配置
在这个章节中,我们将配置Mustache模板来生成验证规范。为了提供更多的细节,我们将修改[beanValidationCore.mustache](https://raw.githubusercontent.com/swagger-api/swagger-codegen/master/modules/swagger-codegen/src/main/resources/Java/beanValidationCore.mustache)
、[model.mustache](https://github.com/swagger-api/swagger-codegen/blob/master/modules/swagger-codegen/src/main/resources/Java/model.mustache)
和[api.muctache](https://github.com/swagger-api/swagger-codegen/blob/master/modules/swagger-codegen/src/main/resources/Java/api.mustache)
文件,以成功生成代码。
首先,需要在swagger-codegen
模块的[beanValidationCore.mustache](https://raw.githubusercontent.com/swagger-api/swagger-codegen/master/modules/swagger-codegen/src/main/resources/Java/beanValidationCore.mustache)
中添加供应商扩展规范:
{{{ vendorExtensions.x-constraints }}}
其次,如果我们的注解具有内部属性,如@Capitalized(required = "true")
,则需要在[beanValidationCore.mustache](https://raw.githubusercontent.com/swagger-api/swagger-codegen/master/modules/swagger-codegen/src/main/resources/Java/beanValidationCore.mustache)
文件的第二行指定特定模式:
{{#required}}@Capitalized(required="{{{pattern}}}") {{/required}}
接着,我们需要更改[model.mustache](https://github.com/swagger-api/swagger-codegen/blob/master/modules/swagger-codegen/src/main/resources/Java/model.mustache)
规范,使其包含必要的导入。例如,我们将导入@Capitalized
注解和Capitalized.*
。导入应在model.mustache
的package
标签之后:
{{#imports}}import {{import}}; {{/imports}} import
com.baeldung.openapi.petstore.validator.CapitalizedValidator;
import com.baeldung.openapi.petstore.validator.Capitalized;
最后,为了使注解生成到API中,我们需要在[api.mustache](https://github.com/swagger-api/swagger-codegen/blob/master/modules/swagger-codegen/src/main/resources/Java/api.mustache)
文件中添加@Capitalized
注解的导入。
{{#imports}}import {{import}}; {{/imports}} import
com.baeldung.openapi.petstore.validator.Capitalized;
此外,[api.mustache](https://github.com/swagger-api/swagger-codegen/blob/master/modules/swagger-codegen/src/main/resources/Java/api.mustache)
依赖于[cookieParams.mustache](https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator/src/main/resources/JavaSpring/cookieParams.mustache)
文件。因此,我们需要将其添加到openapi/templates
目录中。
6. 生成源代码
最后,我们可以使用生成的代码。至少运行mvn generate-sources
,这将生成模型:
public class Pet {
@JsonProperty("id")
private Long id = null;
@JsonProperty("name")
private String name = null;
// other parameters
@Schema(required = true, description = "")
@Capitalized public String getName() { return name; } // default getters and setter }
同时也会生成API:
default ResponseEntity<List<Pet>> findPetsByTags(
@Capitalized(required = true)
@ApiParam(value = "Tags to filter by")
@Valid @RequestParam(value = "name", required = false) String name) {
// default generated code here
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
7. 使用curl
测试
启动应用后,我们将运行一些curl
命令进行测试。
另外,请注意,违反约束会抛出ConstraintViolationException
。异常需要通过@ControllerAdvice
正确处理,返回400 Bad Request状态。
7.1. 测试Pet
模型验证
这个Pet
模型的名称是小写的,因此应用程序应该返回400 Bad Request:
curl -X 'POST' \
'http://localhost:8080/pet' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"id": 1,
"name": "rockie"
}'
7.2. 测试查找Pet
API
同样,因为名称是小写的,应用程序也应该返回400 Bad Request:
curl -I http://localhost:8080/pets/name="rockie"
8. 总结
在这篇教程中,我们学习了如何在实现REST API服务器的同时,启用Spring自定义约束验证器的生成。
一如既往,代码可以在GitHub上找到。