Spring Boot REST API中的默认最大字符串长度?

x33g5p2x  于 2023-04-30  发布在  Spring
关注(0)|答案(2)|浏览(288)

我在OpenAPI 3中定义了一个REST API。0.1规范,使用Openapi Spring Code Generator生成Java类。
为防止滥用,除非另有规定,否则所有字符串字段的长度应限制在5000个字符。对于API规范中设置了maxLength的字段,这很有效,但大多数字段没有设置任何参数。
有没有一个好的解决方案来定义一个默认值,无论是在spec还是在Sping Boot 中(记住,模型类是在每次构建时从spec自动生成的)?
除了spring.servlet.multipart.max-request-size,我找不到任何东西,但是由于还有用于上传文件的端点,这不是一个可行的选择。
任何比手动将maxLength: 5000添加到几千个字段中更容易完成此任务的方法都是有帮助的。

nue99wik

nue99wik1#

问题

您已经确定需要在API中的所有String项上设置默认的maxLength。

溶液

使用提供的mustache模板可以轻松完成此操作。我告诉你

测试方案

我使用以下模式进行测试。

openapi: 3.0.3
info:
  title: My-API
  version: 0.0.1
servers:
  - url: 'https://{api}.{server}/{basePath}'
    variables:
      api:
        default: "mywebsite"
        description: "This is my website api"
      server:
        default: "production"
      basePath:
        default: "v2"
paths:
  /simpleValidationTest:
    get:
      operationId: setValue
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/testingStringValidation'
      summary: get modules
      tags:
        - Modules
components:
  schemas:
    testingStringValidation:
      type: object
      properties:
        validatedString:
          type: string
          maxLength: 25
        unvalidatedString:
          type: string
        unvalidatedInteger:
          type: integer
        validatedInteger:
          type: integer
          minimum: 2

此模式对字符串和整数都有验证和无验证。这将确保我们生成的模型应用预期的默认验证

胡子模板

Spring生成器有一个名为beanValidationCore.mustache的模板。此模板处理所有bean验证。此模板在此段中从pojo.mustache调用:

{{#beanValidation}}
{{>beanValidation}}
{{/useBeanValidation}}

这告诉模板引擎,如果它应该使用beanValidation({{#beanValidation}}),那么此时它将调用beanValidation模板({{>beanValidation}})。注意:>表示使用其他模板。
在我的简短测试中,这总是评估为true。我检查了文档,和it claimsuseBeanValidation默认为false。然而,看看代码,这显然不是真的。因此,我们需要做的就是更新beanValidationCore.mustache以提供默认值。通过在模板的第8行和第9行插入以下代码片段,可以轻松地完成此操作

minLength not set, maxLength not set
}}{{^minLength}}{{^maxLength}}{{#isString}}@Size(max = 5000) {{/isString}}{{/maxLength}}{{/minLength}}{{!

这将检查要验证的项是否为String。如果是,并且没有设置maxLength,那么它将对字段应用注解@Size(max = 5000)

生成代码

使用上面的API和新模板,我在pojo中得到了以下结果。

public class TestingStringValidation implements Serializable {

  private static final long serialVersionUID = 1L;

  @JsonProperty("validatedString")
  private String validatedString;

  @JsonProperty("unvalidatedString")
  private String unvalidatedString;

  @JsonProperty("unvalidatedInteger")
  private Integer unvalidatedInteger;

  @JsonProperty("validatedInteger")
  private Integer validatedInteger;

  public TestingStringValidation validatedString(String validatedString) {
    this.validatedString = validatedString;
    return this;
  }

  /**
   * Get validatedString
   * @return validatedString
  */
  @Size(max = 25) 
  @Schema(name = "validatedString", required = false)
  public String getValidatedString() {
    return validatedString;
  }

  public void setValidatedString(String validatedString) {
    this.validatedString = validatedString;
  }

  public TestingStringValidation unvalidatedString(String unvalidatedString) {
    this.unvalidatedString = unvalidatedString;
    return this;
  }

  /**
   * Get unvalidatedString
   * @return unvalidatedString
  */
  @Size(max = 5000) 
  @Schema(name = "unvalidatedString", required = false)
  public String getUnvalidatedString() {
    return unvalidatedString;
  }

  public void setUnvalidatedString(String unvalidatedString) {
    this.unvalidatedString = unvalidatedString;
  }

  public TestingStringValidation unvalidatedInteger(Integer unvalidatedInteger) {
    this.unvalidatedInteger = unvalidatedInteger;
    return this;
  }

  /**
   * Get unvalidatedInteger
   * @return unvalidatedInteger
  */
  
  @Schema(name = "unvalidatedInteger", required = false)
  public Integer getUnvalidatedInteger() {
    return unvalidatedInteger;
  }

  public void setUnvalidatedInteger(Integer unvalidatedInteger) {
    this.unvalidatedInteger = unvalidatedInteger;
  }

  public TestingStringValidation validatedInteger(Integer validatedInteger) {
    this.validatedInteger = validatedInteger;
    return this;
  }

  /**
   * Get validatedInteger
   * minimum: 2
   * @return validatedInteger
  */
  @Min(2) 
  @Schema(name = "validatedInteger", required = false)
  public Integer getValidatedInteger() {
    return validatedInteger;
  }

  public void setValidatedInteger(Integer validatedInteger) {
    this.validatedInteger = validatedInteger;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    TestingStringValidation testingStringValidation = (TestingStringValidation) o;
    return Objects.equals(this.validatedString, testingStringValidation.validatedString) &&
        Objects.equals(this.unvalidatedString, testingStringValidation.unvalidatedString) &&
        Objects.equals(this.unvalidatedInteger, testingStringValidation.unvalidatedInteger) &&
        Objects.equals(this.validatedInteger, testingStringValidation.validatedInteger);
  }

  @Override
  public int hashCode() {
    return Objects.hash(validatedString, unvalidatedString, unvalidatedInteger, validatedInteger);
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("class TestingStringValidation {\n");
    sb.append("    validatedString: ").append(toIndentedString(validatedString)).append("\n");
    sb.append("    unvalidatedString: ").append(toIndentedString(unvalidatedString)).append("\n");
    sb.append("    unvalidatedInteger: ").append(toIndentedString(unvalidatedInteger)).append("\n");
    sb.append("    validatedInteger: ").append(toIndentedString(validatedInteger)).append("\n");
    sb.append("}");
    return sb.toString();
  }

  /**
   * Convert the given object to string with each line indented by 4 spaces
   * (except the first line).
   */
  private String toIndentedString(Object o) {
    if (o == null) {
      return "null";
    }
    return o.toString().replace("\n", "\n    ");
  }
}

您会注意到,唯一具有默认验证的字段是unvalidatedString。这应该正是你所期望的。

最后一点

Mustache模板功能非常强大,有很多可用字段。您可以通过在globalProperties中启用debugModels: "true"来检查这些字段。这将产生类似于以下内容的输出:

{
      "openApiType" : "string",
      "baseName" : "unvalidatedString",
      "getter" : "getUnvalidatedString",
      "setter" : "setUnvalidatedString",
      "dataType" : "String",
      "datatypeWithEnum" : "String",
      "name" : "unvalidatedString",
      "defaultValueWithParam" : " = data.unvalidatedString;",
      "baseType" : "String",
      "jsonSchema" : "{\r\n  \"type\" : \"string\"\r\n}",
      "exclusiveMinimum" : false,
      "exclusiveMaximum" : false,
      "required" : false,
      "deprecated" : false,
      "hasMoreNonReadOnly" : false,
      "isPrimitiveType" : true,
      "isModel" : false,
      "isContainer" : false,
      "isString" : true,
      "isNumeric" : false,
      "isInteger" : false,
      "isShort" : false,
      "isLong" : false,
      "isUnboundedInteger" : false,
      "isNumber" : false,
      "isFloat" : false,
      "isDouble" : false,
      "isDecimal" : false,
      "isByteArray" : false,
      "isBinary" : false,
      "isFile" : false,
      "isBoolean" : false,
      "isDate" : false,
      "isDateTime" : false,
      "isUuid" : false,
      "isUri" : false,
      "isEmail" : false,
      "isNull" : false,
      "isFreeFormObject" : false,
      "isAnyType" : false,
      "isArray" : false,
      "isMap" : false,
      "isEnum" : false,
      "isInnerEnum" : false,
      "isEnumRef" : false,
      "isReadOnly" : false,
      "isWriteOnly" : false,
      "isNullable" : false,
      "isSelfReference" : false,
      "isCircularReference" : false,
      "isDiscriminator" : false,
      "isNew" : false,
      "vars" : [ ],
      "requiredVars" : [ ],
      "vendorExtensions" : { },
      "hasValidation" : false,
      "isInherited" : false,
      "nameInCamelCase" : "UnvalidatedString",
      "nameInSnakeCase" : "UNVALIDATED_STRING",
      "uniqueItems" : false,
      "isXmlAttribute" : false,
      "isXmlWrapped" : false,
      "additionalPropertiesIsAnyType" : false,
      "hasVars" : false,
      "hasRequired" : false,
      "hasDiscriminatorWithNonEmptyMapping" : false,
      "hasMultipleTypes" : false,
      "schemaIsFromAdditionalProperties" : false,
      "isBooleanSchemaTrue" : false,
      "isBooleanSchemaFalse" : false,
      "datatype" : "String",
      "isEnumOrRef" : false,
      "iexclusiveMaximum" : false,
      "hasItems" : false

输出中的任何布尔值都可以在模板中被检查并用作条件,而任何非布尔值都可以直接检索和使用。您可以利用这一点进一步自定义对象的输出。
祝你好运。

xvw2m8pv

xvw2m8pv2#

在open-api中定义一个新的组件lengthLimitedString在您的情况下是否可行。json/yml并在请求中使用它。body对象定义为schema $ref?这样,验证将内置到生成的代码中,对调用客户端可见,并将包含在任何生成的客户端代码中。
这可以在open-api中实现。json/yml,全局查找和替换字符串。

相关问题