You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Mustache模板中基于operationId实现ServiceImpl条件逻辑生成?

问题与解决方案

问题描述

通过继承AbstractJavaCodegen自定义代码生成器,使用Mustache模板生成Java应用的ServiceImpl.java文件时,遇到以下问题:

  • 需求是根据Swagger规范中定义的operationId(可选值:createOrder、patchOrder、deleteOrder、retrieveOrder、listOrder),让每个方法体内仅包含对应操作的逻辑
  • 当前生成的所有方法会包含所有操作的逻辑,不符合预期
  • 此前尝试在preprocessOpenAPI中预处理数据,但因将属性放到全局additionalProperties中,导致所有方法都能读取到所有操作标记,未达到效果

解决方案

方案1:直接通过Mustache模板条件逻辑实现(无需修改Codegen代码)

利用OpenAPI Generator内置的Mustache条件辅助函数{{#is}},直接在模板中判断当前方法的operationId,仅渲染对应逻辑块。

修改后的Mustache模板:

{{#operations}}
public class {{classname}}ServiceImpl implements {{classname}}Service {

{{#operation}}
@Override
public ResponseEntity<{{>returnTypes}}> {{operationId}}({{#allParams}}{{>optionalDataType}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}) {

 {{#is operationId "createOrder"}}
 // Logic for createOrder operation
 {{/is}}

 {{#is operationId "patchOrder"}}
 // Logic for patchOrder operation
 {{/is}}

 {{#is operationId "deleteOrder"}}
 // Logic for deleteOrder operation
 {{/is}}

 {{#is operationId "retrieveOrder"}}
 // Logic for retrieveOrder operation
 {{/is}}

 {{#is operationId "listOrder"}}
 // Logic for listOrder operation
 {{/is}}

return new ResponseEntity<>(HttpStatus.OK);
}  
{{/operation}}
}

方案2:自定义Codegen预处理(修正原代码逻辑)

原代码的问题是将操作标记放到了全局的additionalProperties中,导致所有方法都能读取到所有标记。正确的做法是将标记添加到单个Operation对象的扩展属性中,这样每个方法只会读取到自身对应的标记。

修正后的preprocessOpenAPI代码:

@Override
public void preprocessOpenAPI(OpenAPI openAPI) {
    super.preprocessOpenAPI(openAPI);
    
    // 保留原有枚举配置、标题、端口处理逻辑
    if (!interfaceOnly && SPRING_BOOT.equals(library) && containsEnums()) {
        supportingFiles.add(new SupportingFile("converter.mustache",
            (sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator), "EnumConverterConfiguration.java"));
    }
    if (!additionalProperties.containsKey(TITLE)) {
        String title = openAPI.getInfo().getTitle();
        if (title != null) {
            title = title.trim().replace(" ", "-");
            if (title.toUpperCase(Locale.ROOT).endsWith("API")) {
                title = title.substring(0, title.length() - 3);
            }
            this.title = camelize(sanitizeName(title), LOWERCASE_FIRST_LETTER);
        }
        additionalProperties.put(TITLE, this.title);
    }
    if (!additionalProperties.containsKey(SERVER_PORT)) {
        final URL url = URLPathUtils.getServerURL(openAPI, serverVariableOverrides());
        additionalProperties.put(SERVER_PORT, URLPathUtils.getPort(url, 8080));
    }

    // 核心修正:将操作标记绑定到单个Operation的扩展属性
    if (openAPI.getPaths() != null) {
        for (final Map.Entry<String, PathItem> entry : openAPI.getPaths().entrySet()) {
            final PathItem path = entry.getValue();
            if (path.readOperations() != null) {
                for (final Operation operation : path.readOperations()) {
                    String operationId = operation.getOperationId();
                    // 先清除可能存在的旧扩展属性
                    operation.getExtensions().remove("x-create-operation");
                    operation.getExtensions().remove("x-patch-operation");
                    operation.getExtensions().remove("x-delete-operation");
                    operation.getExtensions().remove("x-retrieve-operation");
                    operation.getExtensions().remove("x-list-operation");

                    // 根据operationId添加对应扩展属性
                    if (operationId.startsWith("create")) {
                        operation.addExtension("x-create-operation", Boolean.TRUE);
                    } else if (operationId.startsWith("patch")) {
                        operation.addExtension("x-patch-operation", Boolean.TRUE);
                    } else if (operationId.startsWith("delete")) {
                        operation.addExtension("x-delete-operation", Boolean.TRUE);
                    } else if (operationId.startsWith("retrieve")) {
                        operation.addExtension("x-retrieve-operation", Boolean.TRUE);
                    } else if (operationId.startsWith("list")) {
                        operation.addExtension("x-list-operation", Boolean.TRUE);
                    }

                    // 保留原有标签处理逻辑
                    if (operation.getTags() != null) {
                        final List<Map<String, String>> tags = new ArrayList<>();
                        for (final String tag : operation.getTags()) {
                            final Map<String, String> value = new HashMap<>();
                            value.put("tag", tag);
                            tags.add(value);
                        }
                        if (!operation.getTags().isEmpty()) {
                            operation.setTags(Collections.singletonList(operation.getTags().get(0)));
                        }
                        operation.addExtension("x-tags", tags);
                    }
                }
            }
        }
    }
}

对应修改Mustache模板中的标记引用(添加x-前缀,匹配扩展属性):

{{#operations}}
public class {{classname}}ServiceImpl implements {{classname}}Service {

{{#operation}}
@Override
public ResponseEntity&lt;{{&gt;returnTypes}}&gt; {{operationId}}({{#allParams}}{{&gt;optionalDataType}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}) {

 {{#x-create-operation}}
 // Logic for createOrder operation
 {{/x-create-operation}}

 {{#x-patch-operation}}
 // Logic for patchOrder operation
 {{/x-patch-operation}}

 {{#x-delete-operation}}
 // Logic for deleteOrder operation
 {{/x-delete-operation}}

 {{#x-retrieve-operation}}
 // Logic for retrieveOrder operation
 {{/x-retrieve-operation}}

 {{#x-list-operation}}
 // Logic for listOrder operation
 {{/x-list-operation}}

return new ResponseEntity&lt;&gt;(HttpStatus.OK);
}  
{{/operation}}
}

总结

  • 方案1更轻量化,无需修改Codegen代码,直接通过模板条件判断即可实现需求
  • 方案2适合需要对Operation做更复杂自定义处理的场景,确保每个方法仅能访问自身对应的操作标记

内容的提问来源于stack exchange,提问作者Ankit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 19:54:49