Remove filter in web.xml in jetty - maven

I have configured jetty to run my web application using the jetty maven. Jetty is supposed to be a light alternative for development and therefore it doesn't need all the stuff that is in web.xml. More specifically, I want to remove a filter in web.xml.
I tried to use the overrideDescriptor configuration property, but this only allows me to override the web.xml, not replace it. Therefore, the filter is still there.
Any ideas how I can remove the filter without modifying the original web.xml file?

Since there is no answer, I'll post my solution, which is not perfect.
<!-- Jetty configuration -->
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>8.1.5.v20120716</version>
<configuration>
<webApp>
<descriptor>src/main/webapp/mock-web.xml</descriptor>
[...]
</webApp>
[...]
</configuration>
</plugin>
The downside of this approach is that you have to maintain two almost identical web.xml files. I have not found a solution that will allow me override the original web.xml file and remove a listener.

You could replace the filter-class to a PassThroughFilter in the override-web.xml:
public class PassThroughFilter implements Filter{
#Override
public void init(FilterConfig filterConfig) throws ServletException {}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(request, response);
}
#Override
public void destroy() {}
}
<filter>
<filter-name>OriginalFilter</filter-name>
<filter-class>mypackage.PassThroughFilter</filter-class>
</filter>

A powerful solution would be to use 2 XML entities in your web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE document [
<!ENTITY webEntity1 SYSTEM 'webEntity1.xml'>
<!ENTITY webEntity2 SYSTEM 'webEntity2.xml'>
]>
<web-app>
&webEntity1;
&webEntity2;
</web-app>
And only 1 of them in a custom-web.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE document [
<!ENTITY webEntity1 SYSTEM 'webEntity1.xml'>
]>
<web-app>
&webEntity1;
</web-app>
That way, in webEntity1.xml you would declare your shared servlets, filters, mappings and in webEntity2.xml only the filter that you don't want to use in Jetty.
Then you would configure the jetty plugin like this:
<configuration>
...
<webApp>
...
<descriptor>${project.basedir}/src/main/webapp/WEB-INF/custom-web.xml</descriptor>
</webApp>
...
</configuration>
I just added a section to my jetty plugin wiki page.

Related

How to make awesome font work in Spring Boot with PrimeFaces

I have sample Spring Boot project for PrimeFaces and looking for a way to make awesomefont to work as shown in PF Showcase.
So I created awesomefont-test.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Awesomefont Test</title>
</h:head>
<h:body>
<p:commandButton value="Edit" icon="fa fa-fw fa-edit" type="button"/>
</h:body>
</html>
and the result is (no icon)
I tried several things:
1.) web.xml
I created web.xml and I tried to put it next to faces-config.xml (which is in jsf-primefaces-spring-boot/src/main/resources/META-INF/).
I tried to put it to jsf-primefaces-spring-boot/src/main/resources/WEB-INF/ not working too.
I do not know how to check it is read.
content:
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<context-param>
<param-name>primefaces.FONT_AWESOME</param-name>
<param-value>true</param-value>
</context-param>
</web-app>
2.) SpringBootServletInitializer
package com.codenotfound.primefaces;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.support.SpringBootServletInitializer;
#SpringBootApplication
public class SpringPrimeFacesApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(SpringPrimeFacesApplication.class, args);
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.setInitParameter("primefaces.FONT_AWESOME", "true");
super.onStartup(servletContext);
}
}
source: How to set context-param in spring-boot
3.) application.properties
From same source I tried to set property in application.properties
server.context_parameters.primefaces.FONT_AWESOME=true
also I tried variant with
server.servlet.context-parameters.primefaces.FONT_AWESOME=true
4.) webjars
This is a workaround, I just wanted to give it a try.
I also tried to add webjars dependencies (and modify xhtml) as described here - http://www.littlebigextra.com/add-bootstrap-css-jquery-to-springboot-mvc/
but none of those approaches worked for me.
After defining the dependency in pom.xml:
<dependency>
<groupId>org.webjars</groupId>
<artifactId>font-awesome</artifactId>
<version>4.7.0</version>
</dependency>
You need to add config into application.yml:
jsf:
primefaces:
FONT_AWESOME: true
or if use application.properties add:
jsf.primefaces.FONT_AWESOME=true
You don't need to create a web xml, just add the dependency and in your application.properties add this:
jsf.primefaces.font-awesome=true
And if you what to configure a theme add this:
jsf.primefaces.theme= theme-name

Spring Framework 5 and EhCache 3.5

I tried to use EhCache 3.5 caching features in our web application based on Spring Boot 2/Spring Framework 5.
I added EHCache dependency:
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<version>1.0.0</version>
</dependency>
Then created ehcache.xml file in src/main/resources folder:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"
monitoring="autodetect" dynamicConfig="true">
<cache name="orders" maxElementsInMemory="100"
eternal="false" overflowToDisk="false"
memoryStoreEvictionPolicy="LFU" copyOnRead="true"
copyOnWrite="true" />
</ehcache>
Spring 5 reference guide does't mention EHCache usage, Spring 4 reference guide states: "Ehcache 3.x is fully JSR-107 compliant and no dedicated support is required for it."
So I created controller OrderController and REST endpoint:
#Cacheable("orders")
#GetMapping(path = "/{id}")
public Order findById(#PathVariable int id) {
return orderRepository.findById(id);
}
Spring Boot configuration:
#SpringBootApplication
#EnableCaching
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
But when I call this endpoint I get an exception:
Cannot find cache named 'orders' for Builder[public org.Order org.OrderController.findById(int)] caches=[orders] | key='' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless='' | sync='false'
Then I tried to use example from Spring Framework 4:
#Bean
public CacheManager cacheManager() {
return new EhCacheCacheManager(ehCacheCacheManager().getObject());
}
#Bean
public EhCacheManagerFactoryBean ehCacheCacheManager() {
EhCacheManagerFactoryBean cmfb = new EhCacheManagerFactoryBean();
cmfb.setConfigLocation(new ClassPathResource("ehcache.xml"));
cmfb.setShared(true);
return cmfb;
}
But it doesn't compile because of exception:
The type net.sf.ehcache.CacheManager cannot be resolved. It is indirectly referenced from required .class file
Please, advise.
There is a mix of things here. Ehcache 3, which you are using, is used with Spring through JCache.
Which is why you need to use spring.cache.jcache.config=classpath:ehcache.xml.
Then, your Ehcache configuration is indeed an Ehcache 2 configuration. So is the EhCacheCacheManager. For JCache, you should use JCacheCacheManager. But in fact, you don't even need it with an ehcache.xml.
Here are the steps to make it work
Step 1: Set the correct dependencies. Note that you don't need to specify any version as they are provided by the parent pom dependency management. javax.cache is now version 1.1.
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
</dependency>
Step 2: Add an ehcache.xml file in src/main/resources. An example below.
<?xml version="1.0" encoding="UTF-8"?>
<config
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:jsr107='http://www.ehcache.org/v3/jsr107'
xmlns='http://www.ehcache.org/v3'
xsi:schemaLocation="
http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.5.xsd
http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.5.xsd">
<service>
<jsr107:defaults enable-management="false" enable-statistics="true"/>
</service>
<cache alias="value">
<resources>
<heap unit="entries">2000</heap>
</resources>
</cache>
</config>
Step 3: An application.properties with this line is needed to find the ehcache.xml
spring.cache.jcache.config=classpath:ehcache.xml
Note that since JCache is found in the classpath, Spring Cache will pick it as the cache provider. So there's no need to specify spring.cache.type=jcache.
Step 4: Enable caching like you did
#SpringBootApplication
#EnableCaching
public class Cache5Application {
private int value = 0;
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(Cache5Application.class, args);
Cache5Application app = context.getBean(Cache5Application.class);
System.out.println(app.value());
System.out.println(app.value());
}
#Cacheable("value")
public int value() {
return value++;
}
}
You need to force it to use ehcache version 2
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.3</version>
</dependency>
To use ehcache 3:
Here is the application:
#SpringBootApplication
#EnableCaching
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Here is the application.yml
spring:
cache:
ehcache:
config: ehcache.xml
Here a service with a counter for testing
#Service
public class OrderService {
public static int counter=0;
#Cacheable("orders")
public Order findById(Long id) {
counter++;
return new Order(id, "desc_" + id);
}
}
Here is a test to prove it is using the cache:
#RunWith(SpringRunner.class)
#SpringBootTest
public class OrderServiceTest {
#Autowired
private OrderService orderService;
#Test
public void getHello() throws Exception {
orderService.findById(1l);
assertEquals(1, OrderService.counter);
orderService.findById(1l);
assertEquals(1, OrderService.counter);
orderService.findById(2l);
assertEquals(2, OrderService.counter);
}
}
See here for working example.
I made additional research. The following configuration isn't picked up by Spring Boot(from application.properties):
spring.cache.ehcache.config=classpath:ehcache.xml
So I created jcache.xml and also put into src/main/resource folder:
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='http://www.ehcache.org/v3'
xsi:schemaLocation="
http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd">
<cache alias="orders">
<key-type>org.springframework.cache.interceptor.SimpleKey</key-type>
<value-type>java.util.Collections$SingletonList</value-type>
<heap unit="entries">200</heap>
</cache>
</config>
Then I changed setting in application.properties to
spring.cache.jcache.config=classpath:jcache.xml
Now Spring Caching works correctly. However it's still a question how to pick up ehcache.xml
Facing the same issue.
My ehcache.xml looks like
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='http://www.ehcache.org/v3'
xmlns:jsr107='http://www.ehcache.org/v3/jsr107'
xsi:schemaLocation="
http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd
http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd">
<service>
<jsr107:defaults>
<jsr107:cache name="vehicles" template="heap-cache" />
</jsr107:defaults>
</service>
<cache-template name="heap-cache">
<heap unit="entries">20</heap>
</cache-template>
</config>
Have configured spring.cache.jcache.config=classpath:ehcache.xml in application.properties
Have #EnableCaching on my application class.
Have #CacheResult on my service implementation.
#CacheResult(cacheName = "vehicles") public VehicleDetail
getVehicle(#CacheKey String vehicleId) throws VehicleServiceException
Do NOTE that I do not have a CacheManager bean.
Would be really helpful if someone can point out what am I missing.
hmm.. changing ehcache.xml to, did the trick ..
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='http://www.ehcache.org/v3'
xmlns:jsr107='http://www.ehcache.org/v3/jsr107'
xsi:schemaLocation="
http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd
http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd">
<service>
<jsr107:defaults enable-management="true"
enable-statistics="true" />
</service>
<cache alias="vehicles" uses-template="heap-cache" />
<cache-template name="heap-cache">
<heap unit="entries">20</heap>
</cache-template>
</config>

ServletContextParameterFactoryBean without web.xml

I´m using spring boot on a project. On that project I need to import an applicationContext.xml from another project, like the following code:
#SpringBootApplication
#EnableSwagger
#EnableEntityLinks
#ImportResource("classpath:applicationContext.xml")
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
#Bean
public CurieProvider curieProvider() {
return new DefaultCurieProvider("pm", new UriTemplate("http://www.xpto.com/docs/pm/rels/{rel}"));
}
}
One of the beans on applicationContext.xml has the following aspect:
<bean id="configLocation" class="org.springframework.web.context.support.ServletContextParameterFactoryBean">
<property name="initParamName">
<value>propertiesLocation</value>
</property>
</bean>
Now, I want to define the propertiesLocation without using a web.xml with the following:
<context-param>
<description>
</description>
<param-name>propertiesLocation</param-name>
<param-value>file:/a/b/c/application.properties</param-value>
</context-param>
I tried all the solutions that I found but without sucess (for instance How to set context-param in spring-boot). When I build the project, it always complain about the missing propertiesLocation. Is there any solution that does not involve a web.xml or modifications to the applicationContext.xml?
When I try to do a "mvn spring-boot:run", it fails with a IllegalArgumentException:
java.lang.IllegalArgumentException: Resource must not be null
at org.springframework.util.Assert.notNull(Assert.java:112)
at org.springframework.core.io.support.EncodedResource.<init>(EncodedResource.java:82)
at org.springframework.core.io.support.EncodedResource.<init>(EncodedResource.java:67)
at org.springframework.core.io.support.PropertiesLoaderSupport.loadProperties(PropertiesLoaderSupport.java:175)
at org.springframework.core.io.support.PropertiesLoaderSupport.mergeProperties(PropertiesLoaderSupport.java:156)
at org.springframework.beans.factory.config.PropertyResourceConfigurer.postProcessBeanFactory(PropertyResourceConfigurer.java:80)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:265)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:162)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:606)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:462)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:957)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:946)
at com.nsn.oss.pm.api.MyApplication.main(MyApplication.java:28)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.boot.maven.RunMojo$LaunchRunner.run(RunMojo.java:418)
at java.lang.Thread.run(Thread.java:724)
Another project that I'm using as guidance uses the following web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>portal</display-name>
<context-param>
<description></description>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:/datasourceContext.xml
classpath:/applicationContext.xml
classpath:/aopContext.xml
classpath:/mailContext.xml
</param-value>
</context-param>
<context-param>
<description>
</description>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:/log4j.properties</param-value>
</context-param>
<context-param>
<description>
</description>
<param-name>propertiesLocation</param-name>
<param-value>file:/a/b/c/application.properties</param-value>
</context-param>
...
So, I'm trying to configure my project like the above without the web.xml
Don't use the ServletContextParameterFactoryBean. Newer version of spring use a PropertySourcePlaceholderConfigurer. So instead use a #Value("${propertiesLocation}") which will depending on the location will use the servlet context or not to lookup the property. So if you can remove it, added advantage is that you could use system properties to override properties from the servlet context (or define them in JNDI for instance).
If you really want to configure it adding it to the application.properties should be enough. But I would strongly urge you to remove the bean all together.
A final solution is to simply override the bean with a #Bean method. Which should give you the advantage of using PropertySources.
#Autowired
private Environment env;
#Bean
public String configLocation() {
return env.getRequiredProperty("propertiesLocation");
}

Spring Injection with Servlets: NoSuchBean

New to Spring, and working with Spring 3.2.5 trying to get injection to work with a servlet in a vanilla web app (i.e., it's not a Spring MVC web app - it's a pre-existing app I'm extending using the Spring framework). The container is Tomcat 7.0.47.
My problem is that I'm getting NoSuchBeanDefinitionException errors (No bean named 'MyServlet' is defined) when I hit the servlet. There are no errors at startup, so at least one of my beans (the ServiceImplementation bean) is getting successfully instantiated. The problem appears to be with finding the HttpRequestHandler-derived bean (MyServlet) when a new HTTP request comes in.
The full stack trace for the exception is:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'MyServlet' is defined
org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:570)
org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1114)
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:279)
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1121)
org.springframework.web.context.support.HttpRequestHandlerServlet.init(HttpRequestHandlerServlet.java:58)
com.random.webapp.MySpringServlet.init(Unknown Source)
javax.servlet.GenericServlet.init(GenericServlet.java:160)
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
java.lang.Thread.run(Thread.java:662)
I followed this pattern for my setup:
http://andykayley.blogspot.com/2008/06/how-to-inject-spring-beans-into.html
...with one minor (I think) twist. I have a class derived from HttpRequestHandlerServlet so that I can override the init method with some application-specific stuff. The extension class looks like this:
public class MySpringServlet extends HttpRequestHandlerServlet
{
public void init() throws ServletException
{
super.init();
appSpecificInit();
}
}
The servlet I want injected looks like this:
public class MyServlet implements HttpRequestHandler
{
private IService _service = null;
public void setService( IService theService ) {
_service = theService;
}
#Override
public void handleRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
_service.DoSomething();
}
}
The implementation I want it injected with looks like this:
public class ServiceImplementation implements IService
{
#Override
public void DoSomething()
{
// some code goes here
}
}
These are the relevant entries in web.xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml /WEB-INF/implementation.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.random.webapp.MySpringServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/myservlet/*</url-pattern>
</servlet-mapping>
</web-app>
This is the applicationContext.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="MyServlet" class="com.random.webapp.MyServlet">
<property name="Service" ref="ServiceImplementation" />
</bean>
</beans>
...and this is what implementation.xml looks like:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="ServiceImplementation" class="com.random.webapp.ServiceImplementation">
</bean>
</beans>
I've been back and forth between the web.xml, applicationContext.xml, and implementation.xml files to double and triple check my configuration, and I don't see anything wrong with any of them, but I'm obviously missing something.
Anyone have any ideas?
The exception you are getting
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'MyServlet' is defined
occurs in the init() method of the HttpRequestHandlerServlet which tries to load a delegate HttpRequestHandler object from your context based on the name you give the HttpRequestHandlerServlet in your web.xml
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.random.webapp.MySpringServlet</servlet-class>
</servlet>
In the configuration above, that would be MyServlet. Although it appears you have it correct in
<bean id="MyServlet" class="com.random.webapp.MyServlet">
<property name="Service" ref="ServiceImplementation" />
</bean>
make sure you are loading the correct context file as declared here
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml /WEB-INF/implementation.xml</param-value>
</context-param>

Can SpringMVC be configured to process all requests, but exclude static content directories?

If I map my spring application to process all incoming requests ('/*'), then requests for static content return 404's. For example, a request for "myhost.com/css/global.css" would return a 404, even though the resource exists as Spring intercepts the request.
The alternative is to map SpringMVC to a subdirectory (for example '/home/'), but in this case, you must pass this directory in all links within the application. Is there a way to map SpringMVC to '/' and exclude a set of directories from processing?
My current web.xml configuration is:
<servlet>
<servlet-name>springApp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springApp</servlet-name>
<url-pattern>/home/*</url-pattern>
</servlet-mapping>
Idealy I would like to have the mapping be something like the following:
<servlet-mapping>
<servlet-name>springApp</servlet-name>
<url-pattern>/*</url-pattern>
<exclude>/css/*,/js/*</exclude>
</servlet-mapping>
Is this type of thing possible?
NOTE: this answer applies to Spring 3.0.4+ ONLY
(BTW, this question has also been dealt with here: Spring serving static content with mvc:resources, invalid xsd)
Check out the Spring mvc-showcase project in the Spring subversion samples repository. It shows exactly what you want to do, namely that you can delineate static resources which will not be processed by the DisapatcherServlet. See file /mvc-showcase/src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml. Here's a snippet of how I handle these exclusions, where the JS, CSS, and images are in the app context root (with the MVC namespace mapped to mvc:
<!-- resources exclusions from servlet mapping -->
<mvc:resources mapping="/css/**" location="/css/" />
<mvc:resources mapping="/images/**" location="/images/" />
<mvc:resources mapping="/js/**" location="/js/" />
I solved by serving static content through the 'default' servlet, that just serve the content to the client. So my web.xml looks like this:
<servlet>
<servlet-name>MyApp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyApp</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping> <!-- The 'dynamic' content -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping> <!-- The 'static' content -->
Hope this helps.
If you want to do this with Spring only, it's possible but a bit messy:
You'll either need to use a SimpleUrlHandlerMapping for which you can explicitly specify URL patterns which should be mapped to controllers OR extend it to support "ignore" URLs like "css/**".
You'll need to write your own HttpRequestHandler implementation that would basically consist of "getServletContext().getRequestDsipatcher().include()" call to return the requested resource as is.
You'll have to register that handler as defaultHandler for the above SimpleUrlHandlerMapping.
Once all that is done, all requests that can't be mapped to your controllers will be forwarded to your HttpRequestHandler and served "as is".
Simplest way for me (if using a late enough version of Spring) is
<mvc:resources mapping="/**/*.js" location="/"/>
<mvc:resources mapping="/**/*.css" location="/"/>
...
One way to do it would be with Filters. You'd have to write a little bit of custom code but it's not bad. Here's an example if you don't want to pass *.css or *.js files to your Spring servlet:
web.xml:
<filter-mapping>
<filter-name>fileTypeFilter</filter-name>
<filter-class>foo.FileTypeFilter</filter-class>
<url-pattern>/*</url-pattern>
</filter-mapping>
Java class:
public class FileTypeFilter implements Filter {
public void init(FilterConfig conf) {
// init logic here
}
public void destroy() {
// release resources here
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
if(shouldExclude(req)) {
chain.doFilter(req, res);
//some logic so the request doesnt go to the servlet
//maybe you could just forward
//the request directly to the file getting accessed. not sure if that would work
}
//file should be passed to the servlet; you can do some logic here
//if you want
}
private boolean shouldExclude(ServletRequest req) {
if(req instanceof HttpServletRequest) {
HttpServletRequest hreq = (HttpServletRequest) req;
return (hreq.getRequestURI().endsWith(".css") ||
hreq.getRequestURI().endsWith(".js"));
}
return false;
}
}
I haven't tested this, but I think it will work.
EDIT: There's isn't any exclude functionality in the servlet spec. I don't think there is a good way to do this within Spring, but it essentially achieves the same thing in your post.
EDIT 2: If you want to be able to easily change what gets filtered, you could just use Spring to inject something into the Filter at runtime.
EDIT 3: I just realized if you forward directly to the file, it'll do the filter again and you'll get caught in an infinite loop. There might be another way to do this with filters, but I'm honestly not sure what it is.
What are you using to serve your static images?
If it's Apache then you could configure Apache to not pass css/js requests to your app server.
If you are using Tomcat you'd put something like this in your httpd.conf:
JkUnMount /*.css webapp
Where 'webapp' is the entry from your workers.properties.
Sorry I can't give you a pure Spring solution, but this is how I do it.
I got the same problem and here is how I solved it:
The following was added to the web.xml file:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
<url-pattern>*.css</url-pattern>
<url-pattern>*.ico</url-pattern>
<url-pattern>*.png</url-pattern>
<url-pattern>*.jpg</url-pattern>
<url-pattern>*.htc</url-pattern>
<url-pattern>*.gif</url-pattern>
<url-pattern>*.html</url-pattern>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
The following was added to the spring3 MVC servlet bean definition file (such as applicationContext.xml, the file that is configured in web.xml as the contextConfigLocation.):
<mvc:annotation-driven />
<mvc:default-servlet-handler />
Do you have a consistent extension(s) for the requests you want processed by the Spring dispatcher (I believe most of the Spring examples use a *.htm)? In that case, you could map to the extensions you wish to have processed which would bypass your css and js files.
Otherwise I'd agree with Nalandial, the Filter approach is probably the best work around at this point.
I use virtual URL path to retrieve the resource I need. Typically I use Spring MVC, so I couldn't have javascripts and css under /WEB-INF/views folder. I came up with this custom servlet to ONLY allow access to .js & .css files within /WEB-INF/views folder. In your case, if you move the /css folder and /js folder to a parent folder such as /resource then my solution will be applicable to you.
You can change the String url = "YOUR_RESOURCE_FOLDER"
So for example, virtual path can be something like http://www.mysite.com/resources/path/path/app.js
That will map to my /WEB-INF/views/path/path/app.js
web.xml
<servlet>
<servlet-name>ResourceDispatcherServlet</servlet-name>
<servlet-class>mywebapp.web.ResourceDispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ResourceDispatcherServlet</servlet-name>
<url-pattern>/resource/*</url-pattern>
</servlet-mapping>
servlet
public class ResourceDispatcherServlet extends HttpServlet {
public void init() throws ServletException {
}
public void doGet(HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException {
String servletPath = req.getServletPath(); // /resource
String pathInfo = req.getPathInfo(); // /path/path/app.js
String url = "/WEB-INF/views" + pathInfo;
String lastPath = StringUtil.substringAfterLast(pathInfo, "/");
String extension = StringUtil.substringAfterLast(lastPath, ".");
try {
RequestDispatcher dispatcher = null;
if (!StringUtil.isEmpty(extension) && ("js".equals(extension) || "css".equals(extension))) {
dispatcher = req.getRequestDispatcher(url);
}
if (dispatcher != null) {
dispatcher.include(req, rsp);
}
else {
rsp.sendError(404);
}
}
catch (Exception e) {
if (!rsp.isCommitted()) {
rsp.sendError(500);
}
}
}
}
If you are using Spring 3.0.4 and above you should use solution provided by atrain
Otherwise, you can do this simple thing:
perhaps you have following static directory structure you want to serve:
WebContent
|
WEB-INF
|
public
|
css
|
js
|
img
Eclipse Dynamic web projects by default generate following structure: WebContent/WEB-INF. Move the public folder out of your WEB-INF directory into WebContentdirectory.
On client side
refer your static files in following way:
<link rel="stylesheet" type="text/css" href="public/css/mystyles.css">
Here is my reference.
In my case everything was ok. But i have a problem in a Controller
that was my problem
#RequestMapping( method = RequestMethod.GET)
y change for this:
#RequestMapping(value = "/usuario", method = RequestMethod.GET)
and it works
look for a controller that has bad #RequestMappgin and change.
It's cleaner to use UrlRewriteFilter to redirect the request to your servlet, here an example of urlrewrite.xml
<urlrewrite>
<rule>
<from>^/img/(.*)$</from>
<to>/img/$1</to>
</rule>
<rule>
<from>^/js/(.*)$</from>
<to>/js/$1</to>
</rule>
<rule>
<from>^/css/(.*)$</from>
<to>/css/$1</to>
</rule>
<rule>
<from>^/(.*)$</from>
<to>/app/$1</to>
</rule>
<outbound-rule>
<from>/app/(.*)$</from>
<to>/$1</to>
</outbound-rule>
</urlrewrite>
NOTES:
It's important the last <rule> is in the bottom so img, js, css will be caught first
The <outbound-rule> is optional and is just to make the existing<c:url value="/app/some" /> render /some instead of /app/some
Usually, big websites prefer using another server only to handle static content.
Requests of static content goes to one server and dynamic goes to another (with spring, in this case).
In many cases, Nginx server (http://nginx.com/), a recent and very fast server.
But this is not trivial to do. A lot of configurations.

Resources