I map all requests to /* to a specific servlet.
My static content is hidden by this configuration.
How can i allow access to specific files (such as crossdomain.xml)?
When you map /* to a specific servlet, all requests will be forwarded to that servlet, unless you provide a more explicit mapping to another servlet.
That is, if you have /* mapped to ServletA, and /static/* mapped to ServletB, then following Servlets will get called.
http://localhost:8080/abc.jpg -> ServletA
http://localhost:8080/static/abc.jpg -> ServletB
http://localhost:8080/xyz/abc.jpg -> ServletA
So one option you have is to write a Servlet to handle the static content, which will grab the file and return it as response. You can map that servlet to a prefixed by something like /static/*. This requires that all URL references to your static files to be updated to contain this '/static' part.
If that is not feasible for you, then probably you can use the same servlet, but mapped to multiple URL patterns (probably by extension) as follows.
<servlet>
<servlet-name>static-servlet</servlet-name>
<servlet-class>xxx.yyy.StaticServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>static-servlet</servlet-name>
<url-pattern>*.xml</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>static-servlet</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
If you want this to be fine-grained to the level of each file, you can map the servlet to your file URL as well.
Cookbook:
Map your controller Servlet on a more specific url-pattern like /app/*.
Put all the static content in a specific folder like /static.
Create a Filter which is mapped on /* which transparently continues the chain for any /static requests and dispatches other requests to /app.
So, in a nutshell:
<filter>
<filter-name>filter</filter-name>
<filter-class>com.example.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>controller</servlet-name>
<servlet-class>com.example.Controller</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>controller</servlet-name>
<url-pattern>/pages/*</url-pattern>
</servlet-mapping>
with the following in filter's doFilter():
String uri = ((HttpServletRequest) request).getRequestURI();
if (uri.startsWith("/static/")) {
chain.doFilter(request, response); // Goes to default servlet.
} else {
request.getRequestDispatcher("/app" + uri).forward(request, response);
}
No, you do not end up with extra /app path in the URL. It's fully transparent. Make if necessary "/static" and/or "/app" an <init-param> of the filter.
And one more(a direct) servlet mapping like this<servlet-mapping><servlet-name>StaticContentServlet</servlet-name><url-pattern>/crossdomain.xml</url-pattern></servlet-mapping>
probably you can put your static content under different URL like /static/* and then map this URL to a Servlet which responds with the static content.
Related
I am having difficulty getting requests mapped to the correct servlet when the servlet-mapping url-pattern uses a wildcard. I want all requests that begin with "/profile-api" to be mapped to a new REST service I'll be writing soon.
From web.xml:
<!-- default servlet -->
<servlet-mapping>
<servlet-name>professional</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- profile api -->
<servlet-mapping>
<servlet-name>profile-api</servlet-name>
<url-pattern>/profile-api/*</url-pattern>
</servlet-mapping>
Pseudo-code from the controller that allows a third-party system to update a user's "email communication opt-in status" (OptinResponse is a domain class that will ultimately be transformed to JSON and returned to caller):
#Controller
#RequestMapping("/profile-api")
public class ProfileAPIController {
#RequestMapping(method = RequestMethod.GET, value="/setoptin/{userID}")
public #ResponseBody OptinResponse setOptinStatus(#PathVariable String userID) {
return new OptinResponse("200", "Successfully set optin status for user: " + userID);
}
}
I would expect a request to "{localhost}/profile-api/setoptin/12345" to be correctly routed to the ProfileAPIController, but it is not.
Changing the servlet-mapping url-pattern to be more specific but still generic also fails:
<servlet-mapping>
<servlet-name>profile-api</servlet-name>
<url-pattern>/profile-api/setoptin/*</url-pattern>
</servlet-mapping>
The ONLY way I have been able to get my request routed as intended is to include the full, exact path:
<servlet-mapping>
<servlet-name>profile-api</servlet-name>
<url-pattern>/profile-api/setoptin/12345</url-pattern>
</servlet-mapping>
Obviously, that's unacceptable, as the user id must be variable.
In all cases, the request is instead mapped to the default "professional" servlet. I have tried reordering the servlet-mapping nodes to no avail. I have "alwaysUseFullPath" set to "true" in the AnnotationMethodHandlerAdapter bean in the servlet config (but have tried it as "false", too). I feel as though I'm overlooking something simple, but can't see the forest for the trees.
I have a Servlet Filter and due to my business logic Filter uses some variables that are initializing in when servlet's method init() invoke. So the question is: is any possibility to init filter after servlet. My Web.xml is next:
...
<servlet>
<servlet-name>CommonsServlet</servlet-name>
<servlet-class>com.promptlink.dslib.gwt.common.server.rpc.CommonsServletImpl</servlet-class>
</servlet>
...
<filter>
<filter-name>CommonServletFilter</filter-name>
<filter-class>com.promptlink.dslib.gwt.common.server.httpListeners.CommonServletFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CommonServletFilter</filter-name>
<url-pattern>/*</url-pattern>
<servlet-name>CommonsServletImpl</servlet-name>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
...
Maybe is any way to configure filter not in xml? I've heart that it is possible to add filter to ServletContext, but i need to add a mapping to filter too
Filters are initialized before servlets, see here for the details.
But you can create a ServletContextListener which is loaded at application startup before any filter or servlet, initialize your variables in the listener, and let your serlvets and filters then use the already initialized variables.
The listener can also add your servlets and filters programmatically, see ServletContext.addFilter() and ServletContext.addServlet().
I know that I can set init params for a jsp page using web.xml. For example
<servlet>
<servlet-name>init</servlet-name>
<jsp-file>/init.jsp</jsp-file>
<init-param>
<param-name>test</param-name>
<param-value>me</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>init</servlet-name>
<url-pattern>/init.jsp</url-pattern>
</servlet-mapping>
then in my init.jsp I can get the init params using getServletContext.getInitParameter..
However, I am using WebSevlet 3.0 annotations and I can't see equivalent jsp-file annotation. I am looking for something along these lines
#WebServlet(initParams=#WebInitParam(name="hello", value = "hello"),description = "A Simple Servlet", urlPatterns = { "/init.jsp" })
where I can use jsp-file annotation. So I need to set the jsp init params without using web.xml.
I know you said without using a web.xml - but you could still use a web.xml file with annotations - and just use it for the parameters - define the init params as a context-param. That would set the parameter for the whole application...
<context-param>
<param-name>someParameter</param-name>
<param-value>someValue</param-value>
</context-param>
Then in your code - reference it in the same way as above :
getServletContext.getInitParameter("someParameter");
I am trying to run two Servlet-class in a single web.xml but its not working, each servlet-class works fine independently.
web.xml:
<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>transformWsdlLocations</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-ws</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>240</session-timeout>
</session-config>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-ws-servlet.xml
/WEB-INF/health-page-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>health-page</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>health-page</servlet-name>
<url-pattern>/health.htm</url-pattern>
</servlet-mapping>
Do let me know if you can figure something wrong that i am doing.
I tried the below link but it doesnt work for me
Can I use Spring MVC and Spring WS in one single application?
This isn't going to work. The one which is mapped on /* overtakes all requests. You need to map it on / instead so that it will only intercept on requests which are not matched by all other existing servlets (including the JSP servlet which is implicitly mapped on *.jsp and all "normal" static resources like CSS/JS/image files!). See also Difference between / and /* in servlet mapping url pattern.
If being able to serve static resources is also required, then better map it on a more specific URL pattern like /ws/* and create a Filter which checks the request URI and then forwards accordingly. That filter can in turn safely be mapped on /*. See also this answer for a more concrete code example: How to access static resources when mapping a global front controller servlet on /*.
I am using Java configuration in my project and following code works fine for the same purpose:
public class Initializer implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(ApplicationConfiguration.class);
ctx.setServletContext(servletContext);
MessageDispatcherServlet messageDispatcherServlet = new MessageDispatcherServlet();
messageDispatcherServlet.setApplicationContext(ctx);
messageDispatcherServlet.setTransformWsdlLocations(true);
Dynamic dynamic = servletContext.addServlet("messageDispatcherServlet", messageDispatcherServlet);
dynamic.addMapping("/ws/*");
dynamic.setLoadOnStartup(1);
dynamic = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
dynamic.addMapping("/");
dynamic.setLoadOnStartup(1);
}
}
you have a mapping for /* in the spring-ws section which is getting the request. you need to
come up with a different strategy... Try putting the /health.htm before the /* mapping.
Thanks to everyone in advance,
I am trying to access any context parameters in the web.xml from within a servlet filter. Below is a portion from my web.xml file. I have verified that the context-param node is accessible via a jsp page using out.print(getServletContext().getInitParameter("error"));.
<filter>
<filter-name>prePost</filter-name>
<filter-class>MyFilter</filter-class>
<init_param>
<param_name>error</param_name>
<param_value>/test.jsp</param_value>
</init_param>
<filter-mapping>
<filter-name>prePost</filter-name>
<url-pattern>*.jsp</url-pattern>
<context-param>
<description>Error Handler</description>
<param-name>error</param-name>
<param-value>/test.jsp</param-value>
In my filters doFilter when I output this.filterConfig.getInitParameter("error"), I always get null. In my filters init() I am setting this.filterConfig with the passed in FilterConfig.
Thanks,
Sam
You're using underscores rather than hyphens for "param-name" and "param-value". Your config should look like this:
<init-param>
<param-name>error</param-name>
<param-value>/test.jsp</param-value>
</init-param>