Как настроить Джерси с помощью Spring, используя только аннотации

У меня есть веб-приложение Servlet 3.0, которое использует Spring и Jersey. В настоящее время он настроен с использованием SpringServlet, настроенного в качестве фильтра в web.xml, а классы ресурсов аннотированы как @Path и @Component. Вот фрагмент web.xml:

<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>

Эта настройка работает, но я действительно хочу настроить ее только с аннотациями - без конфигурации web.xml. Моей первой попыткой было удалить указанную выше конфигурацию SpringServlet и создать класс, который расширяет Application. Вот фрагмент этого:

@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);
    }
}

Это работает в том, что ресурсы JAX-RS зарегистрированы, и я могу нажать на них по их URL-адресам, но они выдают NullPointerException, когда они пытаются использовать свои свойства автопроводки ... это имеет смысл, потому что я предполагаю, что ресурсы сейчас загружаются Джерси и не являются бобами, управляемыми Spring, поэтому нет автопроводки.

Несмотря на немало поисков, я не могу найти способ загрузки ресурсов Джерси как бинов Spring только с аннотациями. Есть ли такой способ? Я действительно не хочу писать кучу кода для ресурсов, чтобы вручную извлекать контекст Spring и вызывать DI, если я могу помочь.

Если только аннотации не будут работать, тогда я смогу использовать конфигурацию фильтра в web.xml, если смогу указать Application класс для загрузки вместо списка пакетов для сканирования. Если я смогу избавиться от списка пакетов и просто указать экземпляр класса Application, тогда я буду доволен.

Очевидно, было бы замечательно, если бы кто-то имел для меня однозначный ответ, но я также был бы благодарен за любые указания или подсказки, где еще я мог бы искать или что-то попробовать.

Спасибо, Matt

7 голосов | спросил Doughnuts 6 FebruaryEurope/MoscowbWed, 06 Feb 2013 09:10:24 +0400000000amWed, 06 Feb 2013 09:10:24 +040013 2013, 09:10:24

5 ответов


0

Ниже приведена часть моего приложения, которое использует Servlet 3.0, Spring, Jersey 1.8 и не имеет веб-файла.

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");
    }
}

}

ответил Igor Bljahhin 6 MarpmThu, 06 Mar 2014 16:57:34 +04002014-03-06T16:57:34+04:0004 2014, 16:57:34
0

Мне не удалось достичь идеального результата, но я смог добиться определенного прогресса, поэтому я опубликую здесь, если это поможет кому-то еще. Я смог использовать Spring Servlet, чтобы указать класс своего приложения, тем самым удалив список пакетов из web.xml.

Требуемые изменения web.xml находятся в параметрах инициализации (отображение фильтра не отображается, но все еще требуется):

<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>

А затем в классе приложения мне пришлось немного изменить способ вызова супер-конструктора:

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);
}

Все еще не совсем то, что я делал после этого, но, по крайней мере, это добавляет немного конфигурации в код Java и из файла web.xml, что важно для меня, поскольку я пытаюсь скрыть эту деталь.

ответил Doughnuts 19 FebruaryEurope/MoscowbTue, 19 Feb 2013 05:04:47 +0400000000amTue, 19 Feb 2013 05:04:47 +040013 2013, 05:04:47
0

На ум приходят два варианта (не каламбур).

  1. Возможно, вы могли бы расширить SpringServlet своим собственным классом и добавить в него соответствующие аннотации сервлета 3.0.
  2. В соответствии с вашим подходом переключение с SpringServlet на Application, вы можете решить проблему отсутствия автопроводки, включив переплетение байт-кода во время сборки Spring или во время загрузки. Это позволяет Spring вводить объекты, созданные в любом месте, а не только объекты, созданные Spring. См. «Использование AspectJ для введения зависимости доменные объекты со Spring ".
ответил Ryan Stewart 19 FebruaryEurope/MoscowbTue, 19 Feb 2013 06:05:32 +0400000000amTue, 19 Feb 2013 06:05:32 +040013 2013, 06:05:32
0

Прежде всего, в контейнере сервлета 3.0 вам не нужен web.xml.

Но с помощью Jersey 2.0 вы можете установить флажок для сканирования всего веб-приложения на наличие аннотированных ресурсов:

<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>

Spring будет включен автоматически, если вы включите этот jar-файл:

    <dependency>
        <groupId>org.glassfish.jersey.ext</groupId>
        <artifactId>jersey-spring3</artifactId>
        <version>2.3.1</version>
    </dependency>
ответил rustyx 16 +04002013-10-16T11:33:57+04:00312013bEurope/MoscowWed, 16 Oct 2013 11:33:57 +0400 2013, 11:33:57
0

Я использовал Джерси с моим ранее сделанным проектом с использованием SpringMVC. Мой код основан на Официальная документация Spring .

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");

}
}

Классы конфигурации в config.package:

// 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

// 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;
    }
}
ответил Camilo Sampedro 26 Jam1000000amTue, 26 Jan 2016 02:08:48 +030016 2016, 02:08:48

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132