如何在 swagger codegen 中注入自定义 spring 验证?

2023-11-24

我们能够使用 openApi 文档并使用 spring swagger-codegen 生成 Java 输入类。此外,我们可以在为常见约束(如长度、强制等)生成输入时注入 javax.validation 注释。

我希望将其提升到下一个自定义级别,并能够使用与 Spring 的 @Constraint 注释连接的自定义验证注释来注释生成的输入类。这样我们就可以为我们的项目重用特定的验证。

我希望有一个开箱即用的解决方案。您使用自定义验证注释生成输入类的首选方法是什么?


我没有找到“开箱即用的解决方案”。但 openapi-generator 提供了一种通过编辑 Mustache 模板来修改生成代码的简单方法。这就是我解决与你完全相同的问题的方法。

基本上,我在 OpenAPI 规范中创建了自定义字段,其中指定了自定义约束注释(在我的例子中为 @EvenLong)。我将此字段称为“x-constraints”:

...
components:
  schemas:
    Pet:
      type: object
      required:
        - id
        - name
      properties:
        id:
          type: integer
          format: int64
          x-constraints: "@EvenLong"
        name:
          type: string
        tag:
          type: string
...

然后我告诉 openapi-generator 在哪里寻找我的自定义/修改的胡子模板。我使用 openapi-generator 作为 Maven 插件,因此我将 templateDirectory 属性添加到 pom.xml 中的插件定义中:

...
<plugin>
   <groupId>org.openapitools</groupId>
   <artifactId>openapi-generator-maven-plugin</artifactId>
   <version>4.3.1</version>
   <executions>
      <execution>
         <goals>
            <goal>generate</goal>
         </goals>
         <configuration>
            <inputSpec>
               ${project.basedir}/src/main/resources/openapi/specs/petstore.yaml
            </inputSpec>
            <templateDirectory>
              ${project.basedir}/src/main/resources/openapi/templates
            </templateDirectory>
            <generatorName>spring</generatorName>
            <apiPackage>sk.matusko.tutorial.openapicustomvalidations.api</apiPackage>
            <modelPackage>sk.matusko.tutorial.openapicustomvalidations.model</modelPackage>
            <configOptions>
               <interfaceOnly>true</interfaceOnly>
            </configOptions>
         </configuration>
      </execution>
   </executions>
</plugin>
...

最后我编辑了 2 个胡子模板这样我的 @EvenLong 注释就会出现在输出代码中。

您要做的就是从以下位置复制所需的文件https://github.com/OpenAPITools/openapi-generator/tree/v4.3.1/modules/openapi-generator/src/main/resources/JavaSpring到 ${project.basedir}/src/main/resources/openapi/templates (或您正在使用的任何目录),然后将更改添加到其中。

第一个胡子模板是beanValidationCore.mustache它从 x-constraints 字段渲染内容本身。

我添加了 {{vendorExtensions.x-constraints }} 所以 beanValidationCore.mustache 看起来像这样

{{ vendorExtensions.x-constraints }}
{{#pattern}}@Pattern(regexp="{{{pattern}}}") {{/pattern}}{{!
minLength && maxLength set
}}{{#minLength}}{{#maxLength}}@Size(min={{minLength}},max={{maxLength}}) {{/maxLength}}{{/minLength}}{{!
minLength set, maxLength not
}}{{#minLength}}{{^maxLength}}@Size(min={{minLength}}) {{/maxLength}}{{/minLength}}{{!
minLength not set, maxLength set
}}{{^minLength}}{{#maxLength}}@Size(max={{maxLength}}) {{/maxLength}}{{/minLength}}{{!
@Size: minItems && maxItems set
}}{{#minItems}}{{#maxItems}}@Size(min={{minItems}},max={{maxItems}}) {{/maxItems}}{{/minItems}}{{!
@Size: minItems set, maxItems not
}}{{#minItems}}{{^maxItems}}@Size(min={{minItems}}) {{/maxItems}}{{/minItems}}{{!
@Size: minItems not set && maxItems set
}}{{^minItems}}{{#maxItems}}@Size(max={{maxItems}}) {{/maxItems}}{{/minItems}}{{!
@Email: useBeanValidation set && isEmail && java8 set
}}{{#useBeanValidation}}{{#isEmail}}{{#java8}}@javax.validation.constraints.Email{{/java8}}{{/isEmail}}{{/useBeanValidation}}{{!
@Email: performBeanValidation set && isEmail && not java8 set
}}{{#performBeanValidation}}{{#isEmail}}{{^java8}}@org.hibernate.validator.constraints.Email{{/java8}}{{/isEmail}}{{/performBeanValidation}}{{!
check for integer or long / all others=decimal type with @Decimal*
isInteger set
}}{{#isInteger}}{{#minimum}}@Min({{minimum}}){{/minimum}}{{#maximum}} @Max({{maximum}}) {{/maximum}}{{/isInteger}}{{!
isLong set
}}{{#isLong}}{{#minimum}}@Min({{minimum}}L){{/minimum}}{{#maximum}} @Max({{maximum}}L) {{/maximum}}{{/isLong}}{{!
Not Integer, not Long => we have a decimal value!
}}{{^isInteger}}{{^isLong}}{{#minimum}}@DecimalMin({{#exclusiveMinimum}}value={{/exclusiveMinimum}}"{{minimum}}"{{#exclusiveMinimum}},inclusive=false{{/exclusiveMinimum}}){{/minimum}}{{#maximum}} @DecimalMax({{#exclusiveMaximum}}value={{/exclusiveMaximum}}"{{maximum}}"{{#exclusiveMaximum}},inclusive=false{{/exclusiveMaximum}}) {{/maximum}}{{/isLong}}{{/isInteger}}

第二个胡子模板是模型.胡子它为从 openapi 规范生成的 java 模型呈现 java 导入。因此,我添加了验证器 java 包(其中 @EvenLong 所在)中所有类的导入。 添加导入 com.foo.bar.validators.*;模型.胡子。我的看起来像这样:

package {{package}};

import java.util.Objects;
{{#imports}}import {{import}};
{{/imports}}
import org.openapitools.jackson.nullable.JsonNullable;
{{#serializableModel}}
import java.io.Serializable;
{{/serializableModel}}
{{#useBeanValidation}}
import javax.validation.Valid;
import com.foo.bar.validators.*;
import javax.validation.constraints.*;
{{/useBeanValidation}}
{{#performBeanValidation}}
import org.hibernate.validator.constraints.*;
{{/performBeanValidation}}
{{#jackson}}
{{#withXml}}
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
{{/withXml}}
{{/jackson}}
{{#withXml}}
import javax.xml.bind.annotation.*;
{{/withXml}}
{{^parent}}
{{#hateoas}}
import org.springframework.hateoas.RepresentationModel;
{{/hateoas}}
{{/parent}}

{{#models}}
{{#model}}
{{#isEnum}}
{{>enumOuterClass}}
{{/isEnum}}
{{^isEnum}}
{{>pojo}}
{{/isEnum}}
{{/model}}
{{/models}}

就是这样!

这是我的详细教程https://bartko-mat.medium.com/openapi-generator-to-spring-boot-with-custom-java-validations-623381df9215和代码示例https://github.com/Matusko/open-api-custom-validations

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 swagger codegen 中注入自定义 spring 验证? 的相关文章

  • 带预览和进度栏的 Twitter Bootstrap 图像上传

    我如何使用 Twitter Bootstrap 上传带有预览和进度条的单个图像 目前 在保存图像之前 我看不到上传图像的任何预览或进度条 Jasny 的 Bootstrap 分支让您能够接近这一点 看文档 http jasny github
  • Javascript:在函数内调用函数时 window.location.href 不会重定向

    单击按钮时 window location href 会将浏览器重定向到 stackoverflow com 但在输入文本字段中按 Enter 键时不会将浏览器重定向到 stackoverflow com 尽管两个事件侦听器使用相同的函数
  • 如何在 Scala Play 框架中进行 Twitter 反向身份验证?

    我正在编写一个 play 应用程序 在 scala 中 并且正在尝试执行 twitter 此处概述的反向身份验证步骤 https dev twitter com docs ios using reverse auth https dev t
  • 使用 DataMapper 而不是 ActiveRecord [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 扩展Android应用程序类

    当我正在寻找从远程设备获取错误报告的解决方案时 就像 iOS 中的试飞应用程序一样 我发现了acra适用于 Android 设备here http code google com p acra wiki BasicSetup 在基本设置中
  • Turbolinks 访问的页面中缺少 hubspot 聊天界面,但可用于全页面刷新

    我想将 hubspot 聊天界面集成到我的 Rails 4 Turbolinks 应用程序中 我已将 Google 跟踪代码管理器配置为在每个页面加载事件中显示支持聊天界面 该界面工作正常 GTM 标签 自定义 html PROBLEM 当
  • 如何从 python 中的字符串中删除 ANSI 转义序列

    这是包含我的字符串的片段 ls r n x1b 00m x1b 01 31mexamplefile zip x1b 00m r n x1b 01 31m 该字符串是从我执行的 SSH 命令返回的 我无法使用当前状态下的字符串 因为它包含 A
  • 具有重复值的 Sqlite 列

    就说专栏吧aSQLite 数据库的非常重复 始终有相同的 4 个值 其他值可能稍后出现 但不同值的数量将少于 1000 个 VALUES hello world it s a shame to store this str many tim
  • Haskell:如何创建将函数应用于元组项的最通用函数

    这是一个个人练习 旨在更好地理解 Haskell 类型系统的局限性 我想创建最通用的函数 将某些函数应用于 2 条目元组中的每个条目 例如 applyToTuple fn a b fn a fn b 我试图让这个函数在以下每种情况下都起作用
  • Centos/Linux 将 logrotate 设置为所有日志的最大文件大小

    我们使用 logrotate 并且它每天运行 现在我们遇到了一些情况 日志显着增长 阅读 gigabaytes 并杀死我们的服务器 所以现在我们想为日志设置最大文件大小 我可以将其添加到 logrotate conf 中吗 size 50M
  • IIS 中的 WIX 和证书

    我正在尝试设置我的安装 以便使用 WIX 配置我的站点及其证书 我可以在 IIS 中查看证书并有权访问 cer 文件 这就是我对证书的了解 所以请简化任何答案 即我不知道我的 BinaryKey 是什么 该证书已安装在计算机上 理想情况下
  • Pandas 2 个字段中唯一值的数量

    我正在尝试查找覆盖 2 个字段的唯一值的数量 例如 一个典型的例子是姓氏和名字 我有一个数据框 当我执行以下操作时 我只获取每列的唯一字段数 在本例中为 最后一个 和 第一个 不是复合体 df Last Name First Name nu
  • 如何从Python枚举类中获取所有值?

    我正在使用 Enum4 库创建一个枚举类 如下所示 class Color Enum RED 1 BLUE 2 我要打印 1 2 作为某处的列表 我怎样才能实现这个目标 您可以执行以下操作 e value for e in Color
  • 如何使用 Microsoft Graph API 更新 MailboxSettings

    我想从不同的日历更新邮箱设置 如何构建可以通过 Microsoft Graph 更新 MailboxSetting 的请求 这是我的代码示例 但有例外 代码示例 User obj GraphServiceClient Users roomC
  • AngularJS 中的全局模拟对象用于 jasmine/karma 测试

    我有一个正在模拟进行单元测试的对象 基本上在我的测试文件中 我将其模拟如下 var mockObject mockMethod1 function return true mockMethod2 function return true b
  • 如何在 Firefox 插件上使用 jQuery 1.5.2+?

    首先 我创建了一个接收参数并返回 jQuery 的函数 例如 function getjQuery window jquery code window return window jQuery 但后来我收到了一封评论电子邮件 他们告诉我必须
  • 在着色器中旋转法线

    我有一个场景 其中有多个具有各自位置和旋转的模型 给定法线 着色器对每个像素应用简单的双向照明 那是我的顶点着色器 version 150 in vec3 position in vec3 normal in vec2 texcoord o
  • 在reactjs中停止超时?

    有没有办法可以杀死 摆脱 reactjs 中的超时 setTimeout function do something bind this 3000 通过某种点击或操作 我希望能够完全停止并结束超时 有没有办法做到这一点 谢谢 假设这种情况发
  • 使用 python/scipy 进行 voronoi 和 lloyd 松弛

    如何使用 Qhull 确定哪些 voronoi 单元 按索引 是 正确的 由 现有顶点 组成 我正在尝试使用 LLoyds 算法和 scipy spatial Voronoi 它是 Qhull 的包装器 生成的输入来执行约束松弛 就代码而言
  • 如何使用javascript取消设置变量? [复制]

    这个问题在这里已经有答案了 这是我到目前为止所尝试的 var nxt I am next window onscroll function var scr this pageYOffset if scr gt 400 console log

随机推荐

  • 在android中显示TextView而不是ImageView

    我想在图像视图上显示文本 我按照 Alesqui 的建议这样做 Android 文字覆盖图像 The preview in Android studio looks fine 但我的实际结果看起来像这样 上面有不必要的文本 我必须在执行期间
  • 在 Fortran 95 中将任意浮点字符串转换为实数

    在 fortran 中是否有任何简单的方法可以将任意浮点字符串转换为实数 想想类似的事情strtod 问题在于READ声明是所有浮点格式编辑描述符都需要显式宽度 到目前为止 我做出的最好的解决方法是这样的 pure function str
  • 有没有办法确定用户加入了哪些多用户会议 (MUCH)?

    我想知道是否有办法查询 XMPP 服务器 传递用户 JID 以找出该用户当前所在的聊天室 如果没有 我们可以查询 jabber 服务器来获取所有活动聊天室的列表吗 顺便说一句 我们正在运行支持多用户聊天的 ejabber 使用 java 库
  • 为什么我应该使用 Deque 而不是 Stack?

    我需要一个Stack我的用例的数据结构 我应该能够将项目推送到数据结构中 并且我只想从堆栈中检索最后一个项目 这堆栈的 JavaDoc says 一组更完整且一致的 LIFO 堆栈操作是 由 Deque 接口及其实现提供 应该 优先使用此类
  • 2x2 按钮网格布局

    我正在尝试创建一个包含 2x2 按钮网格 总共 4 个 的布局 我有以下内容 但它只在左上角创建按钮网格 我希望按钮网格填满整个屏幕
  • 设置输入框背景

    我必须创建一个具有以下背景的输入框 到目前为止 在我的代码中 我有下面的代码 但它没有显示 gt 执行此操作的正确程序是什么 我还必须制作此按钮的几个变体 如下所示 按钮黑色区域上的十字 我只是要使用 span 标记一个类并将图形设置为该类
  • 在 C++ 中从向量复制到向量

    我创建一个向量 A 并想使用以下方法复制到另一个类中的向量 B 这是正确的方法吗 向量A可能会被破坏 我在谷歌搜索 但没有找到好的解决方案和有意义的解释 感谢大家 void StateInit vector
  • Android 上的 OpenId

    我想让我的用户能够使用他们的 OpenId 登录我的 Android 应用程序 有一个像 StackOverflow 一样的文本字段 并要求用户在那里输入他的 OpenId 我环顾四周 但找不到任何允许我在 Android 上实现客户端 O
  • Laravel 5 Flysystem - 从远程磁盘下载文件

    我正在使用 Flysystem 在 Rackspace 上存储站点的文件 上传没问题 但无法弄清楚如何开始下载文件 这是我尝试过的 Storage disk rackspace return response gt download fil
  • 为什么追加documentFragment时需要使用cloneNode?

    我一直在考虑在 Backbone js 应用程序中使用 documentFragments 并且想知道为什么我看到在将 documentFragment 附加到父 DOM 元素时使用 cloneNode 的示例 可以看一个例子here 如果
  • jsr 关键字是什么意思?

    我正在查看一些 Java 代码 并且注意到以下内容 if foo bar baz qux i 0 jsr 433 javac 被它噎住了 说这不是一个语句 并且关键字后面应该有一个分号jsr 我做了一些谷歌搜索 我发现一些包含相同内容的代码
  • Heroku - 无法通过 Play Framework 应用程序设置 postgres 数据库?

    我正在尝试通过 Play Framework 应用程序在 heroku 上设置 postgres 数据库 但我不断收到有关 DATABASE URL 的错误 堆栈跟踪 gt Heroku receiving push gt Play 2 0
  • Flask 蓝图中的 render_template 使用其他蓝图的模板

    我有一个带有蓝图的 Flask 应用程序 每个蓝图都提供了一些模板 当我尝试渲染时index html第二个蓝图的模板 将渲染第一个蓝图的模板 为什么 blueprint2 会覆盖 blueprint1 的模板 如何渲染每个蓝图的模板 ap
  • Cordova Phonegap IOS 应用程序设置。捆绑可能吗?

    所以我是移动开发的新手 但我即将使用 HTML CSS JS 和 Cordova PhoneGap 3 完成我的第一个 IOS 应用程序 我试图允许用户通过 iPhone 的本机 设置 应用程序提供文本输入 灰色齿轮图标 我的应用程序将在
  • 如何更改闪存的起始地址?

    我正在使用 STM32F746ZG 和 FreeRTOS Flash的起始地址是0x08000000 但我想把它改成0x08040000 我通过谷歌搜索了这个问题 但没有找到解决方案 我更改了链接器脚本 如下所示 MEMORY RAM xr
  • 物化视图和表同名

    我有点理解物化视图并且以前曾与它们合作过 最近出现了一个问题 为什么特定报告没有显示最新数据 我调查了这个问题 显然 他们之前有一个加载了 crontab 的临时表 后来切换到了物化视图 当我使用以下查询查看数据库时 表名称已更改 SELE
  • 如何在wp7中设置可点击的文本块中的链接

    我有一个包含链接的文本框 文本中的内容是在运行时生成的 我的问题是文本内的链接不可单击 如何使文本块内的所有链接可单击 以便当我点击链接时它应该打开网络浏览器 在android中 我们可以使用自动链接来设置它 这样的选项在wp7或wp7 1
  • 如何使用动态 OR 语句构建 Linq 查询?

    以下代码 var dynamicQuery from a in context Users select a string args new string aa bb cc foreach string word in args dynam
  • 内部可变性如何影响缓存行为?

    我正在尝试创建一个struct这需要一个Path并根据需要从指定路径加载图像 这是我到目前为止所拥有的 extern crate image use std cell RefCell use std path Path use image
  • 如何在 swagger codegen 中注入自定义 spring 验证?

    我们能够使用 openApi 文档并使用 spring swagger codegen 生成 Java 输入类 此外 我们可以在为常见约束 如长度 强制等 生成输入时注入 javax validation 注释 我希望将其提升到下一个自定义