2014-11-13 15 views
6

Tôi đang sử dụng các thành phần sau trong dự án REST của back-end của tôi:SwaggerSpringMvcPlugin không làm việc trên Spring MVC

  • Spring MVC: 4.1.2.RELEASE (mới nhất)
  • Hibernate4 Object Mapper: 2.4.3 (mới nhất)
  • Swagger: 0.9.1 (mới nhất)
  • JavaEE-web-api: 7.0 (servlet 3,1)

tôi đang sử dụng cấu hình đậu XML dựa và tôi đã có thể để có được các thiết lập cơ bản với Swagger và chạy, bằng cách sử dụng sau đây trong tập tin cấu hình mùa xuân XML:

<mvc:annotation-driven/> <!-- Required so swagger-springmvc can access spring's RequestMappingHandlerMapping --> 

<bean class="com.mangofactory.swagger.configuration.SpringSwaggerConfig" /> 

sau đó tôi nhân bản repo Swagger-UI GIT từ https://github.com/wordnik/swagger-ui và sao chép của thư mục quận để tôi /webapp/docs thư mục. Sau khi làm như vậy tôi đã có thể sử dụng giao diện người dùng JS dựa trên URL sau:

http://localhost:9090/docs/index.html (works so far). 

Vấn đề là không ai trong số các thử nút làm việc, có thể được sử dụng để tương tác với REST API của bạn sử dụng JSON trực tiếp. Lý do mà nó không làm việc là nó không lấy đúng cơ sở url đường để nói chuyện với các bộ điều khiển của tôi:

http://localhost:9090/rest/addresses (actual controller location) 
http://localhost:9090/addresses (swagger's attempt to talk to the API) 

Sau khi một số nghiên cứu trực tuyến Tôi phát hiện ra rằng tôi có lẽ tốt hơn đi cho cách tiếp cận linh hoạt hơn sử dụng SwaggerSpringMvcPlugin như được ghi trên https://github.com/martypitt/swagger-springmvc.

Đây là vênh vang lớp cấu hình tập tin của tôi:

@Configuration 
@EnableSwagger 
public class MySwaggerConfig { 

    private SpringSwaggerConfig springSwaggerConfig; 

    @Autowired 
    public void setSpringSwaggerConfig(SpringSwaggerConfig springSwaggerConfig) { 
     this.springSwaggerConfig = springSwaggerConfig; 
    } 

    @Bean 
    public SwaggerSpringMvcPlugin customImplementation(){ 
     return new SwaggerSpringMvcPlugin(this.springSwaggerConfig) 
       .includePatterns(".*"); 
    } 
} 

này là đầy đủ mùa xuân xml MVC tập tin của tôi:

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:context="http://www.springframework.org/schema/context" 
     xmlns:p="http://www.springframework.org/schema/p" 
     xmlns:util="http://www.springframework.org/schema/util" 
     xmlns:mvc="http://www.springframework.org/schema/mvc" 
     xmlns="http://www.springframework.org/schema/beans" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans 
          http://www.springframework.org/schema/beans/spring-beans.xsd 
          http://www.springframework.org/schema/context 
          http://www.springframework.org/schema/context/spring-context.xsd 
          http://www.springframework.org/schema/util 
          http://www.springframework.org/schema/util/spring-util.xsd 
          http://www.springframework.org/schema/mvc 
          http://www.springframework.org/schema/mvc/spring-mvc.xsd"> 

    <context:component-scan base-package="be.exampley.backend.web.rest"/> 

    <bean id="hibernateAwareObjectMapper" class="be.example.backend.util.HibernateAwareObjectMapper"/> 

    <mvc:annotation-driven> 
     <mvc:message-converters> 
      <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" 
        p:prettyPrint="true" 
        p:supportedMediaTypes-ref="supportedMediaTypes" 
        p:objectMapper-ref="hibernateAwareObjectMapper"/> 
     </mvc:message-converters> 
    </mvc:annotation-driven> 

    <util:list id="supportedMediaTypes"> 
     <value>application/json</value> 
     <value>text/plain</value> 
    </util:list> 

    <context:annotation-config/> 

    <mvc:default-servlet-handler/> 

    <context:property-placeholder location="classpath:swagger.properties"/> 

    <bean name="swaggerConfig" class="be.example.backend.configuration.MySwaggerConfig"/> 

</beans> 

Một chiết xuất của bộ phận có liên quan từ web của tôi. xml tệp:

<servlet> 
    <servlet-name>restServlet</servlet-name> 
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
    <init-param> 
     <param-name>contextConfigLocation</param-name> 
     <param-value>WEB-INF/spring/mvc-rest-config.xml</param-value> 
    </init-param> 
    <load-on-startup>1</load-on-startup> 
</servlet> 

<servlet-mapping> 
    <servlet-name>restServlet</servlet-name> 
    <url-pattern>/rest/*</url-pattern> 
</servlet-mapping> 

Đây là tệp swagger.properties của tôi, không được tính đến vì lý do nào đó.

documentation.services.basePath=/rest/ 
documentation.services.version=2.0 

Các stacktrace tôi nhận được trong suốt quá trình khởi động:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mySwaggerConfig': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void be.example.backend.configuration.MySwaggerConfig.setSpringSwaggerConfig(com.mangofactory.swagger.configuration.SpringSwaggerConfig); nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.mangofactory.swagger.configuration.SpringSwaggerConfig': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.util.List com.mangofactory.swagger.configuration.SpringSwaggerConfig.handlerMappings; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping] found for dependency [collection of org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} 
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1204) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476) 
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302) 
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:725) 
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757) 
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480) 
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403) 
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306) 
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106) 
    at org.eclipse.jetty.server.handler.ContextHandler.callContextInitialized(ContextHandler.java:798) 
    at org.eclipse.jetty.servlet.ServletContextHandler.callContextInitialized(ServletContextHandler.java:444) 
    at org.eclipse.jetty.server.handler.ContextHandler.startContext(ContextHandler.java:789) 
    at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:294) 
    at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1341) 
    at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1334) 
    at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:741) 
    at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:497) 
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) 
    at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132) 
    at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114) 
    at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61) 
    at org.eclipse.jetty.server.handler.ContextHandlerCollection.doStart(ContextHandlerCollection.java:163) 
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) 
    at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132) 
    at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114) 
    at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61) 
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) 
    at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132) 
    at org.eclipse.jetty.server.Server.start(Server.java:387) 
    at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114) 
    at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61) 
    at org.eclipse.jetty.server.Server.doStart(Server.java:354) 
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) 
    at org.eclipse.jetty.runner.Runner.run(Runner.java:509) 
    at org.eclipse.jetty.runner.Runner.main(Runner.java:557) 
... 
Caused by: 
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping] found for dependency [collection of org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1261) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:961) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:904) 
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:527) 
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87) 
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1204) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476) 
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302) 
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1081) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1006) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:904) 
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:600) 
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87) 
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1204) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476) 
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302) 
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:725) 
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757) 
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480) 
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403) 
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306) 
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106) 
    at org.eclipse.jetty.server.handler.ContextHandler.callContextInitialized(ContextHandler.java:798) 
    at org.eclipse.jetty.servlet.ServletContextHandler.callContextInitialized(ServletContextHandler.java:444) 
    at org.eclipse.jetty.server.handler.ContextHandler.startContext(ContextHandler.java:789) 
    at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:294) 
    at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1341) 
    at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1334) 
    at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:741) 
    at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:497) 
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) 
    at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132) 
    at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114) 
    at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61) 
    at org.eclipse.jetty.server.handler.ContextHandlerCollection.doStart(ContextHandlerCollection.java:163) 
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) 
    at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132) 
    at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114) 
    at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61) 
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) 
    at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132) 
    at org.eclipse.jetty.server.Server.start(Server.java:387) 
    at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114) 
    at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61) 
    at org.eclipse.jetty.server.Server.doStart(Server.java:354) 
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) 
    at org.eclipse.jetty.runner.Runner.run(Runner.java:509) 
    at org.eclipse.jetty.runner.Runner.main(Runner.java:557) 

Tôi đọc ở đâu đó rằng Không đậu vòng loại org ... RequestMappingHandlerMapping dấu vết cho thấy tôi có thể bỏ lỡ MVC: chú thích-driven trong XML của tôi, nhưng đây không phải là trường hợp.

Tôi đã tìm kiếm hàng giờ để tìm giải pháp nhưng không thành công cho đến nay. Thực tế là trong cấu hình cơ bản của nó (sử dụng SpringSwaggerConfig), nó hoạt động được 90% (bên cạnh việc dùng thử nút ...), khiến tôi không muốn bỏ cuộc. Nó thực sự có vẻ rất mát mẻ và là một cách tốt để ghi lại API của bạn.

Vì vậy, nếu có ai đó có thể giúp tôi về điều này, tôi sẽ rất biết ơn. Đá vênh vang!

Kind regards, Bart

Trả lời

6

tôi đã có thể vấp ngã khi vấn đề sau đây: "Không đậu phù hợp đã được tìm thấy để tự động nối dây" cho RequestMappingHandlerMapping: http://forum.spring.io/forum/spring-projects/web/112154-unable-to-autowire-requestmappinghandlermapping-in-controller

Trong khi có nghĩa là tôi đã chuyển sang Cấu hình dựa trên Java để thay thế XML của tôi. Điều này giải quyết vấn đề autowire là tốt. Dưới đây là giải pháp của tôi cho tham chiếu của người khác, bao gồm việc thay đổi apiResourcePrefix và sử dụng tệp swagger.properties để cấu hình bên ngoài.

My web.xml file:

<context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value>classpath:spring/business.xml</param-value> 
</context-param> 

<servlet> 
    <servlet-name>restServlet</servlet-name> 
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
    <init-param> 
     <param-name>contextClass</param-name> 
     <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value> 
    </init-param> 
    <init-param> 
     <param-name>contextConfigLocation</param-name> 
     <param-value>be.example.backend.configuration.MvcConfig</param-value> 
    </init-param> 
    <load-on-startup>1</load-on-startup> 
</servlet> 

<servlet-mapping> 
    <servlet-name>restServlet</servlet-name> 
    <url-pattern>/rest/*</url-pattern> 
</servlet-mapping> 

My bussiness.xml như bối cảnh ứng dụng gốc:

<context:annotation-config/> 
<context:component-scan base-package="be.example.backend"/> 
... 

My MvcConfig.java như tập tin cấu hình MVC:

@EnableWebMvc 
@ComponentScan(basePackages = {"be.example.backend"}) 
@Configuration 
public class MvcConfig extends WebMvcConfigurerAdapter { 

    @Override 
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { 
     List<MediaType> supportedMediaTypes = new ArrayList<>(); 
     supportedMediaTypes.add(MediaType.APPLICATION_JSON); 
     supportedMediaTypes.add(MediaType.TEXT_PLAIN); 

     MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); 
     converter.setObjectMapper(new HibernateAwareObjectMapper()); 
     converter.setPrettyPrint(true); 
     converter.setSupportedMediaTypes(supportedMediaTypes); 
     converters.add(converter); 

     super.configureMessageConverters(converters); 
    } 
} 

My SwaggerConfig.java như tập tin cấu hình vênh vang:

@EnableWebMvc 
@EnableSwagger 
@PropertySource("classpath:swagger.properties") 
@ComponentScan(basePackages = {"be.example.backend"}) 
@Configuration 
public class SwaggerConfig implements ServletContextAware { 

    @Autowired 
    private Environment environment; 

    private SpringSwaggerConfig springSwaggerConfig; 

    private ServletContext servletContext; 

    @Autowired 
    public void setSpringSwaggerConfig(SpringSwaggerConfig springSwaggerConfig) { 
     this.springSwaggerConfig = springSwaggerConfig; 
    } 

    @Bean 
    public SwaggerSpringMvcPlugin customImplementation() { 
     RelativeSwaggerPathProvider relativeSwaggerPathProvider = new RelativeSwaggerPathProvider(servletContext); 
     relativeSwaggerPathProvider.setApiResourcePrefix(environment.getProperty("swagger.resource_prefix")); 
     return new SwaggerSpringMvcPlugin(this.springSwaggerConfig) 
       .pathProvider(relativeSwaggerPathProvider); 
    } 


    @Override 
    public void setServletContext(ServletContext servletContext) { 
     this.servletContext = servletContext; 
    } 
} 

swagger.properties My thuộc tính bên ngoài file:

swagger.resource_prefix=rest 

Giải pháp này làm việc cho tôi và bây giờ tôi có thể tận hưởng những tính năng vênh vang thông qua swagger-ui.

Hy vọng người khác cũng có thể sử dụng nó!

1

Tôi có chính xác cùng một ngoại lệ

org.springframework.beans.factory.BeanCreationException: 
    Error creating bean with name 'mySwaggerConfig': Injection of autowired dependencies failed; 
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: 
public void be.example.backend.configuration.MySwaggerConfig.setSpringSwaggerConfig 
(com.mangofactory.swagger.configuration.SpringSwaggerConfig) 

trong thử nghiệm của tôi. Root casue là chú thích không chính xác. Thử nghiệm của tôi đã được chú thích với @Tích hợp, thay vì bằng @WebIntegrationTest.

Đối với mã sản xuất, đảm bảo bạn @Configuration được chú thích với @EnableWebMvc