2013-02-06 13 views
7

Tôi có ứng dụng web Servlet 3.0 sử dụng cả Spring và Jersey. Tôi hiện đã thiết lập nó bằng cách sử dụng SpringServlet được cấu hình như một bộ lọc trong tệp web.xml và các lớp tài nguyên được chú thích với cả hai @Path@Component. Dưới đây là đoạn mã web.xml:Cách định cấu hình Jersey bằng Spring chỉ sử dụng chú thích

<filter> 
    <filter-name>jersey-serlvet</filter-name> 
    <filter-class> 
     com.sun.jersey.spi.spring.container.servlet.SpringServlet 
    </filter-class> 
    <init-param> 
     <param-name> 
      com.sun.jersey.config.property.packages 
     </param-name> 
     <param-value>com.foo;com.bar</param-value> 
    </init-param> 
    <init-param> 
     <param-name>com.sun.jersey.config.feature.FilterForwardOn404</param-name> 
     <param-value>true</param-value> 
    </init-param> 
</filter> 

<filter-mapping> 
    <filter-name>jersey-serlvet</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 

Thiết lập này hoạt động, nhưng tôi thực sự muốn thiết lập chỉ với chú thích - không có cấu hình web.xml. Nỗ lực đầu tiên của tôi là xóa cấu hình SpringServlet ở trên và tạo một lớp mở rộng Application. Dưới đây là một đoạn rằng:

@ApplicationPath("/*") 
public class MyApplication extends PackagesResourceConfig { 

    public MyApplication() { 
     super("com.foo;com.bar"); 

     HashMap<String, Object> settings = new HashMap<String, Object>(1); 
     settings.put(ServletContainer.FEATURE_FILTER_FORWARD_ON_404, true); 
     this.setPropertiesAndFeatures(settings); 
    } 
} 

này hoạt động trong đó các nguồn lực JAX-RS được đăng ký và tôi có thể nhấn họ tại URL của họ, nhưng họ ném NullPointerExceptions khi họ cố gắng và sử dụng tài sản autowired của họ ... điều này làm cho cảm giác bởi vì tôi đoán các nguồn tài nguyên hiện đang được Jersey tải và không phải là các bean được quản lý mùa xuân, do đó không có autowiring.

Mặc dù một chút công bằng tìm kiếm xung quanh tôi không thể tìm thấy bất kỳ cách nào để tải các tài nguyên Jersey như các hạt Spring chỉ với các chú thích. Có cách nào không? Tôi không thực sự muốn phải viết một loạt mã để các tài nguyên tự tìm nạp bối cảnh Spring và gọi DI nếu tôi có thể trợ giúp nó.

Nếu chú thích chỉ không hoạt động, thì tôi có thể sống với cấu hình bộ lọc trong web.xml nếu tôi có thể chỉ định lớp Application để tải thay vì danh sách các gói cần quét. Nếu tôi có thể loại bỏ danh sách gói trong đó và chỉ cần chỉ định một cá thể lớp Application thì tôi sẽ có nội dung.

Rõ ràng nó sẽ là tuyệt vời nếu ai đó có câu trả lời dứt khoát cho tôi nhưng tôi cũng biết ơn về bất kỳ gợi ý hay gợi ý nào về nơi tôi có thể tìm hoặc những thứ để thử.

Cảm ơn, Matt

Trả lời

1

tôi đã không thể có được kết quả lý tưởng của tôi, nhưng tôi đã có thể thực hiện một số tiến bộ, vì vậy tôi sẽ đăng ở đây trong trường hợp nó giúp bất cứ ai khác. Tôi đã có thể sử dụng Spring Servlet để chỉ định lớp ứng dụng của tôi, do đó loại bỏ danh sách gói khỏi tệp web.xml.

Những thay đổi web.xml cần là trong params init (ánh xạ bộ lọc không được hiển thị nhưng vẫn bắt buộc):

<filter> 
    <filter-name>jersey-serlvet</filter-name> 
    <filter-class> 
     com.sun.jersey.spi.spring.container.servlet.SpringServlet 
    </filter-class> 
    <init-param> 
     <param-name>javax.ws.rs.Application</param-name> <!-- Specify application class here --> 
     <param-value>com.foo.MyApplication</param-value> 
    </init-param> 
</filter> 

Và sau đó trong lớp ứng dụng tôi đã phải thay đổi cách tôi gọi là siêu constructor hơi:

public MyApplication() { 
    super("com.foo", "com.bar"); // Pass in packages as separate params 

    HashMap<String, Object> settings = new HashMap<String, Object>(1); 
    settings.put(ServletContainer.FEATURE_FILTER_FORWARD_ON_404, true); 
    this.setPropertiesAndFeatures(settings); 
} 

Vẫn không chính xác những gì tôi đã sau nhưng ít nhất này kéo một chút cấu hình hơn vào mã Java và ra khỏi web.xml, đó là quan trọng đối với tôi khi tôi đang cố gắng để che giấu chi tiết này.

1

Hai tùy chọn cần lưu ý (không có ý định chơi chữ).

  1. Có thể bạn có thể mở rộng SpringServlet bằng lớp của riêng mình và thêm chú thích servlet 3.0 thích hợp vào nó.
  2. Đi cùng với cách tiếp cận của bạn để chuyển từ SpringServlet sang lớp Application, bạn có thể giải quyết vấn đề không tự động bằng cách bật thời gian tải hoặc thời gian tải bytecode của Spring.Điều đó cho phép Spring chèn các đối tượng được khởi tạo bởi bất cứ nơi nào thay vì chỉ các đối tượng được tạo bởi Spring. Xem "Using AspectJ to dependency inject domain objects with Spring".
1

Trước hết, trong thùng chứa servlet 3.0 bạn không thực sự cần web.xml.

Nhưng với Jersey 2.0, bạn có thể thiết lập một lá cờ để quét các ứng dụng web toàn cho nguồn chú thích:

<listener> 
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
</listener> 

<servlet> 
    <servlet-name>jersey</servlet-name> 
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> 
    <init-param> 
     <param-name>jersey.config.servlet.provider.webapp</param-name> 
     <param-value>true</param-value> 
    </init-param> 
    <load-on-startup>1</load-on-startup> 
</servlet> 

mùa xuân sẽ được kích hoạt tự động nếu bạn bao gồm jar này:

<dependency> 
     <groupId>org.glassfish.jersey.ext</groupId> 
     <artifactId>jersey-spring3</artifactId> 
     <version>2.3.1</version> 
    </dependency> 
+0

Cám ơn câu trả lời của bạn, nhưng tôi đang sử dụng Jersey 1 và tôi không có bất kỳ sự cố khi nhận tài nguyên Jersey được tải và chạy. Vấn đề là tôi muốn họ quản lý bởi Spring vì vậy tôi nhận được autowiring. – Doughnuts

+0

Ok, trong trường hợp đó, đây không phải là giải pháp cho bạn. Nhưng chỉ để được rõ ràng: điều này cho phép mùa xuân autowiring. – rustyx

2

Dưới đây là một phần của ứng dụng của tôi, sử dụng Servlet 3.0, Spring, Jersey 1.8 và không có web.xml:

public class WebAppInitializer implements WebApplicationInitializer { 

@Override 
public void onStartup(ServletContext servletContext) throws ServletException { 
    final AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); 
    context.setConfigLocation("com.myapp.config"); 

    final FilterRegistration.Dynamic characterEncodingFilter = servletContext.addFilter("characterEncodingFilter", new CharacterEncodingFilter()); 
    characterEncodingFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*"); 
    characterEncodingFilter.setInitParameter("encoding", "UTF-8"); 
    characterEncodingFilter.setInitParameter("forceEncoding", "true"); 

    final FilterRegistration.Dynamic springSecurityFilterChain = servletContext.addFilter("springSecurityFilterChain", new DelegatingFilterProxy()); 
    springSecurityFilterChain.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*"); 

    servletContext.addListener(new ContextLoaderListener(context)); 
    servletContext.setInitParameter("spring.profiles.default", "production"); 

    final SpringServlet servlet = new SpringServlet(); 

    final ServletRegistration.Dynamic appServlet = servletContext.addServlet("appServlet", servlet); 
    appServlet.setInitParameter("com.sun.jersey.config.property.packages", "com.myapp.api"); 
    appServlet.setInitParameter("com.sun.jersey.spi.container.ContainerRequestFilters", "com.myapp.api.SizeLimitFilter"); 
    appServlet.setLoadOnStartup(1); 

    final Set<String> mappingConflicts = appServlet.addMapping("/api/*"); 

    if (!mappingConflicts.isEmpty()) { 
     throw new IllegalStateException("'appServlet' cannot be mapped to '/' under Tomcat versions <= 7.0.14"); 
    } 
} 

}

0

Tôi đã sử dụng Jersey với dự án đã tạo trước đây của mình bằng SpringMVC. Tôi dựa trên mã của tôi trên Spring's official documentation.

public class WebAppInitializer implements WebApplicationInitializer { 

@Override 
public void onStartup(ServletContext servletContext) { 
    // Don't create the Listener that Jersey uses to create. 
    // There can only be one linstener 
    servletContext.setInitParameter("contextConfigLocation", "<NONE>"); 
    AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); 

    // Add app config packages 
    context.setConfigLocation("config.package"); 

    // Add listener to the context 
    servletContext.addListener(new ContextLoaderListener(context)); 

    // Replacing: 
    //  <servlet-name>ServletName</servlet-name> 
    //  <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class> 
    //  <init-param> 
    //   <param-name>com.sun.jersey.config.property.packages</param-name> 
    //   <param-value>webservices.packages</param-value> 
    //  </init-param> 
    //  <load-on-startup>1</load-on-startup> 
    AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext(); 

    ServletRegistration.Dynamic appServlet = servletContext.addServlet("ServletName", new DispatcherServlet(dispatcherContext)); 
    appServlet.setInitParameter("com.sun.jersey.config.property.packages", "org.sunnycake.aton.controller"); 
    appServlet.setLoadOnStartup(1); 
    appServlet.addMapping("/RootApp"); 

} 
} 

Các lớp cấu hình trong config.package là:

// Specifies that there will be bean methods annotated with @Bean tag 
// and will be managed by Spring 
@Configuration 

// Equivalent to context:component-scan base-package="..." in the xml, states 
// where to find the beans controlled by Spring 
@ComponentScan(basePackages = "config.package") 
public class AppConfig { 

    /** 
    * Where will the project views be. 
    * 
    * @return ViewResolver como el XML 
    */ 
    @Bean 
    public ViewResolver viewResolver() { 
     InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); 
     return viewResolver; 
    } 

} 

Hibernate cấu hình

// Specifies that there will be bean methods annotated with @Bean tag 
// and will be managed by Spring 
@Configuration 
// Equivalent to Spring's tx in the xml 
@EnableTransactionManagement 

// Equivalent to context:component-scan base-package="..." in the xml, states 
// where to find the beans controlled by Spring 
@ComponentScan({"config.package"}) 

// Here it can be stated some Spring properties with a properties file 
@PropertySource(value = {"classpath:aplicacion.properties"}) 
public class HibernateConfig { 

    /** 
    * Inyected by Spring based on the .properties file in the 
    * \@PropertySource tag. 
    */ 
    @Autowired 
    private Environment environment; 

    /** 
    * Here it's created a Session Factory, equivalent to the Spring's config file one. 
    * 
    * @return Spring Session factory 
    */ 
    @Bean 
    public LocalSessionFactoryBean sessionFactory() { 
     LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean(); 

     // Uses the datasource 
     sessionFactory.setDataSource(dataSource()); 

     // Indicates where are the POJOs (DTO) 
     sessionFactory.setPackagesToScan(new String[]{"dto.package"}); 
     // Se asignan las propiedades de Hibernate 
     sessionFactory.setHibernateProperties(hibernateProperties()); 

     return sessionFactory; 
    } 

    /** 
    * Propiedades de la base de datos (Según environment) 
    * 
    * @return Nuevo DataSource (Configuración de la base de datos) 
    */ 
    @Bean 
    public DataSource dataSource() { 
     DriverManagerDataSource dataSource = new DriverManagerDataSource(); 
     dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName")); 
     dataSource.setUrl(environment.getRequiredProperty("jdbc.url")); 
     dataSource.setUsername(environment.getRequiredProperty("jdbc.username")); 
     dataSource.setPassword(environment.getRequiredProperty("jdbc.password")); 
     return dataSource; 
    } 

    /** 
    * Hibernate properties 
    * 
    * @return Properties set with the configuration 
    */ 
    private Properties hibernateProperties() { 
     Properties properties = new Properties(); 
     // Dialect (Mysql, postgresql, ...) 
     properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect")); 
     // Show SQL query 
     properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql")); 
     properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql")); 
     return properties; 
    } 

    /** 
    * Inyected by sessionFactory 
    */ 
    @Bean 
    @Autowired 
    public HibernateTransactionManager transactionManager(SessionFactory s) { 
     HibernateTransactionManager txManager = new HibernateTransactionManager(); 
     txManager.setSessionFactory(s); 
     return txManager; 
    } 
}