将Swagger服务器存根添加到现有的Spring应用程序中

13

如何将由Swagger Codegen生成的服务器存根最佳地插入到现有的Spring MVC应用程序中?

我首先尝试使用petstore stubs示例。

我的Spring配置是由Java编写的,看起来像这样:

public class SpringConfigurationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] { ApplicationContext.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] { WebMvcContext.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

    // ... onStartup etc.

}

WebMvcConfigurationSupport:

@Configuration
@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
@PropertySource({ "classpath:config.properties", "file:${CONFIGDIR}/config.properties" })
@ComponentScan(useDefaultFilters = false, basePackages = { "com.yyy", "com.xxx" }, includeFilters = { @Filter(type = FilterType.ANNOTATION, value = Controller.class) })
public class WebMvcContext extends WebMvcConfigurationSupport {

    // ... beans etc.
}

应用上下文:

@Configuration
@EnableAsync
@EnableScheduling
@EnableMBeanExport
@Import({SecurityConfig.class, GeneralDBConfiguration.class})
@ComponentScan(useDefaultFilters = true, basePackages = { "com.yyy", "com.xxx" }, excludeFilters = { @Filter(type = FilterType.ANNOTATION, value = {Controller.class, Configuration.class/*, Aspect.class*/}) })
public class ApplicationContext implements AsyncConfigurer {

    // beans etc.

}

我该如何将io.swagger.configuration包中的配置类部分包含到我的现有应用程序中?

更多细节如下:

我遇到的问题之一是,如果我在我的应用程序中指定了一个maven依赖项来使用宠物店存根(通过从spring-mvc-j8-async目录运行mvn install:install-file ...安装到本地):

    <dependency>
        <groupId>io.swagger</groupId>
        <artifactId>swagger-spring-mvc-server</artifactId>
        <version>1.0.0</version>
    </dependency>

然后我的Spring应用程序找到了两个AbstractAnnotationConfigDispatcherServletInitializer(一个来自我的应用程序,另一个来自swagger-spring-mvc-server中的io.swagger.configuration.WebApplication),并且无法加载它们-导致以下异常:

无法使用名称'dispatcher'注册servlet。检查是否有另一个已注册相同名称的servlet。

我猜另一种表达我的问题的方式是,如何使用swagger-codegen生成的服务器存根?看起来我不能直接依赖于开箱即用的maven软件包...


1
看起来你正在使用Spring MVC堆栈而不是Max-Es堆栈。我建议使用spring-mvc示例。 - Dilip Krishnan
@DilipKrishnan 你所说的max-Es是什么意思?我正在尝试集成的宠物商店存根是spring-mvc-j8-async存根--实际上,io.swagger.configuration包与“普通”的spring-mvc存根中的一个完全相同。 - jlb
那是一个打字错误,我想说的是JAX-RS。其他示例我不确定(我写了Spring MVC版本)。肯定缺少@enableSwagger2注释。 - Dilip Krishnan
@DilipKrishnan 谢谢 - 非常感谢。不过我认为我正在与一个更大的问题作斗争 - 请参见问题末尾添加的附加部分。 - jlb
为什么不使用Springfox? - ali akbar azizkhani
显示剩余2条评论
1个回答

7

我知道这篇文章比较老,但我遇到了很多问题,我收集的信息可能对其他人有用,直到生成器文档得到改进。

此说明是为了使用 openapi-generator-maven-plugin 从 OpenApi 3.0.0 规范生成并使用 spring-mvc 服务器存根。

  1. 不要使用 swagger-codegen,而要使用 openapi-generator: https://github.com/OpenAPITools/openapi-generator(分叉的原因在此处: https://github.com/OpenAPITools/openapi-generator/blob/master/docs/qna.md

  2. 为服务器部分创建单独的项目/模块,并配置maven插件。

<build>
    <plugins>
        <plugin>
            <groupId>org.openapitools</groupId>
            <artifactId>openapi-generator-maven-plugin</artifactId>
            <version>3.3.4</version>
            <executions>
                <execution>
                    <goals>
                        <goal>generate</goal>
                    </goals>
                    <configuration>
                        <skipIfSpecIsUnchanged>true</skipIfSpecIsUnchanged>
                        <inputSpec>${engine-openapi-spec.location}</inputSpec>
                        <output>${project.build.directory}/generated-sources/openapi</output>
                        <generatorName>spring</generatorName>
                        <library>spring-mvc</library>
                        <apiPackage>eu.dorsum.swift.engine.service.api</apiPackage>
                        <modelPackage>eu.dorsum.swift.engine.service.model</modelPackage>
                        <generateApis>true</generateApis>
                        <generateApiDocumentation>false</generateApiDocumentation>
                        <generateApiTests>false</generateApiTests>
                        <generateModels>true</generateModels>
                        <generateModelDocumentation>false</generateModelDocumentation>
                        <generateModelTests>false</generateModelTests>
                        <generateSupportingFiles>true</generateSupportingFiles>
                        <configOptions>
                            <sourceFolder>src/main/java</sourceFolder>
                            <java8>true</java8>
                            <dateLibrary>java8</dateLibrary>
                            <useTags>true</useTags>
                            <configPackage>eu.dorsum.swift.engine.appconfig</configPackage>
                            <interfaceOnly>false</interfaceOnly>
                            <delegatePattern>true</delegatePattern>
                        </configOptions>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

有两个配置需要注意一下。

2.a: 将 configOptions/configPackage 设置为你的应用程序根配置所在的包。这个选项会将你的配置包添加为额外的基础包到 OpenAPIUiConfiguration.java 的组件扫描中:@ComponentScan(basePackages = {"eu.dorsum.swift.engine.service.api", "eu.dorsum.swift.engine.appconfig"})。这是一种倒置的方法,刚开始你可能想让生成的 mvc 配置启动你现有的东西,但这是我找到的不需要对生成的代码进行修改的唯一方法。

2.b: 将 configOptions/delegatePattern 设置为 true。我很喜欢这个选项!这会生成一个额外的委托接口,你的服务器控制器可以实现它。生成的 ApiController 将所有服务调用委托给这个接口,因此你可以非常优雅地插入你的实现。在我的设置中,我有这样的链条:MessageApi(生成的接口)-> MessageApiController 实现 MessageApi(生成的 mvc 控制器)-> MessageApiDelegate(生成的接口)-> MessageService 实现 MessageApiDelegate(我对服务方法的实现)。

有了这两个配置,就没有必要修改生成的源代码了。如果 API 规范发生变化,则委派接口也会发生变化,你需要在 MessageService 中实现这些变化。

下面是我原来的帖子的更新,以更详细地解释服务实现如何与委托接口绑定。

由 openapi-gen 生成的源代码位于一个单独的 jar 模块中,其中只包含 swagger.yaml 和 pom.xml 作为检入的“源”。使用生成代码的模块是一个 war,它直接依赖于生成的 jar。服务实现在 war 中,并实现了 MessageApiDelegate 接口,该接口在生成的源代码中。

Spring 上下文从生成的代码中提取,并且你在 openapi-gen 配置中定义的 apiPackage 和 configPackage 将被添加为 @ComponentScan 在生成的 OpenAPIUiConfiguration.java 中的基础包,因此你的服务实现必须放在 apiPackages 中或其下。

这里有一个简化的结构,将这些部分组合在一起。

parent/
  swift-engin-service/ (generated jar module)
    swagger.yaml
    pom.xml
    target/generated-sources/openapi/src/main/java/eu/dorsum/swift/engine/
      appconfig/ (generated spring webmvc config)
        OpenAPIUiConfiguration.java
        WebApplication.java (brings up spring context by extending AbstractAnnotationConfigDispatcherServletInitializer)
      service/
        MessageApiController.java (@Controller, @RequestMapping etc.)
        MessageApiDelegate.java (implement this to get your service implementation plugged in the controller)
  swift-engine/ (war module, your code)
    pom.xml
    src/main/java/eu/dorsum/swift/engine/
      appconfig/
        EngineConfig.java (my spring config)
      service/api/ (must be the same as apiPackages property)
        MessageService.java (service implementation)

swift-engine/pom.xml的相关部分

<project>
    <packaging>war</packaging>

    <dependencies>
        <dependency>
            <groupId>eu.dorsum.core.java.swift-engine</groupId>
            <artifactId>swift-engine-service</artifactId>
        </dependency>
    </dependencies>
</project>

eu.dorsum.swift.engine.service.api.MessageService的相关部分

@Service
public class MessageService implements MessageApiDelegate {
    @Override
    public ResponseEntity<List<SwiftMessage>> listMessages(List<String> sorting, Integer pageStart, Integer pageSize, String filter) {
        // implementation
    }

    @Override
    public ResponseEntity<Void> updateMessage(SwiftMessage message) {
        // implementation
    }
}

eu.dorsum.swift.engine.appconfig.OpenAPIUiConfiguration的相关部分(生成的)

@Configuration
@ComponentScan(basePackages = {"eu.dorsum.swift.engine.service.api", "eu.dorsum.swift.engine.appconfig"})
@EnableWebMvc
public class OpenAPIUiConfiguration extends WebMvcConfigurerAdapter {
    ...
}

我似乎无法调用已实现的方法。尽管我的注释服务类实现了接口方法(默认),但仍然调用接口中的默认方法。是我这边缺少了什么吗? - Bass
很有可能是的 :) 你也使用spring-mvc吗? - Peter
我使用Spring 5.1.1和Peter。我尝试了不同的设置组合,其中一个是使用openapi与/或springboot,另一个是在同一模块中作为我的springmvc应用程序,所有这些都使用weblogic作为应用服务器。您是否有单独的openapi模块war文件?openapi模块如何“看到”MessageService,它们都在同一个模块中,我想知道?您能否也发布openapi模块的pom.xml?我正在使用open-api-generator-plugin 4.2.3。 - Bass
“delegatePattern”肯定是最重要的模式之一。在看到您的帖子之前,我已经考虑只生成接口了。非常感谢! - LionH
Bass,抱歉回复晚了,之前没找到时间回答。我编辑了我的回答并加入了详细信息,希望能有所帮助。 - Peter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接