我有一个使用Spring和Jersey的Servlet 3.0 Web应用程序。我目前使用在web.xml中配置为过滤器的SpringServlet以及使用@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上点击它们,但是当他们尝试使用他们的自动装配属性时会抛出NullPointerExceptions ...这是有道理的,因为我猜测资源现在由泽西岛加载并且不是Spring托管bean,因此没有自动装配。
尽管有一些搜索,我找不到任何方式将Jersey资源加载为仅带注释的Spring bean。 有没有这样的方式?我真的不想为资源编写一堆代码来手动获取Spring上下文并在我可以帮助时调用DI。
如果仅注释不起作用,那么如果我可以指定要加载的Application
类而不是要扫描的包列表,那么我可以使用web.xml中的过滤器配置。如果我可以删除那里的包列表并只指定一个Application
类实例,那么我就会满足。
显然如果有人对我有明确的答案会很好,但我也会感激任何我可以看到的东西或尝试的东西。
谢谢, 马特
答案 0 :(得分:2)
以下是我的应用程序的一部分,它使用Servlet 3.0,Spring,Jersey 1.8,它没有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");
}
}
}
答案 1 :(得分:1)
我无法获得理想的结果,但我已经取得了一些进展,所以我会在这里发布,以防它帮助其他人。我能够使用Spring Servlet来指定我的应用程序类,从而从web.xml中删除包列表。
所需的web.xml更改位于init params中(过滤器映射未显示但仍需要):
<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,这对我来说很重要,因为我试图隐藏这些细节。
答案 2 :(得分:1)
有两种选择可供选择(没有双关语)。
SpringServlet
并为其添加适当的servlet 3.0注释。SpringServlet
切换到Application
类的方法,您可以通过启用Spring构建时或加载时字节码编织来解决无自动装配问题。这使Spring能够注入由任何地方实例化的对象,而不仅仅是Spring创建的对象。见"Using AspectJ to dependency inject domain objects with Spring"。答案 3 :(得分:1)
首先,在servlet 3.0容器中,您并不需要web.xml
。
但是使用Jersey 2.0,您可以设置一个标志来扫描整个Web应用程序以获取带注释的资源:
<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>
如果包含此jar,将自动启用Spring:
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring3</artifactId>
<version>2.3.1</version>
</dependency>
答案 4 :(得分:0)
我使用Jersey和我之前使用SpringMVC制作的项目。我的代码基于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");
}
}
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;
}
}
答案 5 :(得分:0)
这是一个完整的示例。首先-不要使用任何web.xml。仅使用下面的代码。
其他资源:
@Path("hello")
public class HelloResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public Response hello() {
String output = "Hello World!";
return Response.status(200).entity(output).build();
}
}
其他应用程序(在程序包名称中注明“核心”)
@ApplicationPath("rest")
public class RestApplication extends javax.ws.rs.core.Application {
public RestApplication() {
}
@Override public Set<Class<?>> getClasses() {
return Set.of(
HelloResource.class
);
}
}
Spring Web配置。
@Configuration
@EnableWebMvc
@ComponentScan(basePackageClasses = {
})
public class WebConfig implements WebMvcConfigurer {
private static final Logger logger = LoggerFactory.getLogger(WebConfig.class);
@Autowired
private ApplicationContext applicationContext;
public WebConfig() {
}
}
Spring初始化器
//This @Order is required!!!
@Order(Ordered.HIGHEST_PRECEDENCE)
public class MyWebInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
var ctx = new AnnotationConfigWebApplicationContext();
//spring WebMvcConfigurer
ctx.register(WebConfig.class);
ctx.setServletContext(servletContext);
//Spring servlet
var servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping("/");
// Register Jersey 2.0 servlet
ServletRegistration.Dynamic jerseyServlet = servletContext.addServlet("jerseyServlet",
"org.glassfish.jersey.servlet.ServletContainer");
//note "javax.ws.rs.Application" doesn't have "core"
jerseyServlet.setInitParameter("javax.ws.rs.Application", RestApplication.class.getName());
jerseyServlet.addMapping("/rest/*");
jerseyServlet.setLoadOnStartup(1);
}
}
上运行