For a WebApp, I need to serve all .js, .css and all images from corresponding folders in my web app development tree ./js, ./css, ... through a default handling.
So any URL like
http://www.example.com/js/x.js
should be served straight from the static files in the war.
The main servlet should deal with all requests that are not for the above.
I need to be able to process requests like
http://www.example.com/PROJ/ELEM/WHATEVER
with the same unique main servlet.
So I thought I'd do this in the web.xml:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/css/*,/js/*,/WEB-INF/*</url-pattern>
</servlet-mapping>
and map the main servlet like this to make some JSTL mods in a JSP file:
#WebServlet(urlPatterns="/*")
public class Main extends HttpServlet {
protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
request.setAttribute("test", "ok");
request.getRequestDispatcher("/WEB-INF/index.jsp")
.forward(request, response);
}
}
When I do this I end up in a recursive loop.
Is there a way to achieve this?
Here is the explanation with same problem.
http://www.kuligowski.pl/java/rest-style-urls-and-url-mapping-for-static-content-apache-tomcat,5
This is what already happens. There is a 'default servlet' that handles any request that isn't specifically mapped to an installed servlet.
A simple variation on Rahul Jain's answer. You could do what spring MVC does for static resources : DispatcherServlet is a catch all, and it is configured to delegate to default servlet for a number or url. This may be interesting for a catch all servlet because it is often designed as a front controller that delegates actual serving to other controllers (be them servlets or not).
You can simply give the prefixes of urls that should serve static resources in a comma separated string in a context param of name static_path_prefixes and put that in your servlet :
String[] staticPathPrefixes;
RequestDispatcher defaultDispatcher;
#Override
protected void service(HttpServletRequest hsr, HttpServletResponse hsr1) throws ServletException, IOException {
String path = hsr.getServletPath();
for (String url: staticPathPrefixes) {
if (path.startsWith(url)) {
defaultDispatcher.forward(hsr, hsr1);
return;
}
}
super.service(hsr, hsr1);
}
#Override
public void init() throws ServletException {
String urls = getServletConfig().getInitParameter("static_path_prefixes");
staticPathPrefixes = urls.split(" *, *");
defaultDispatcher = getServletConfig().getServletContext().
getNamedDispatcher("default");
}
Related
How to make jersey and #webservlet working together ?
jersey ResourceConfig:
#ApplicationPath("/*")
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
register(Greetings.class);
}
}
jersey Resource registered in resourceConfig:
#Path("/login")
public class Greetings {
#GET
public Response getHelloGreeting(#Context HttpServletRequest httpRequest) {
System.out.println("In the Greetings resource");
String url= "http://"+httpRequest.getServerName()+":"+httpRequest.getServerPort()+httpRequest.getContextPath();
String newURL = url+"/login.jsp";
System.out.println(newURL);
return Response.seeOther(URI.create(newURL)).build();
}
}
web servlet
#WebServlet(name = "LoginServlet", urlPatterns = { "/hello" })
public class LoginServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletContext servletContext = getServletContext();
System.out.println("inside login servlet");
request.getRequestDispatcher("/login.jsp").forward(request, response);
System.out.println("request forwarded");
}
//other functions not important so deleted
}
Case 1: on accessing this
http://localhost:8088/ResponseFilterweb/login
console logs:
In the Greetings resource
http://localhost:8088/ResponseFilterweb/login.jsp (no ui comes)
on accessing this
http://localhost:8088/ResponseFilterweb/hello
(nothing happens 404 error)
Case 2: Changing application config resource path:
#ApplicationPath("/auth")
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
register(Greetings.class);
}
}
on accessing this
http://localhost:8088/ResponseFilterweb/auth/login
In the Greetings resource
http://localhost:8088/ResponseFilterweb/login.jsp (Ui comes)
on accessing this
http://localhost:8088/ResponseFilterweb/hello
inside login servlet (Ui comes)
userid is
Encoded string
request forwarded
doubts:
don't know why login.jsp is blocked in the first case:
why http://localhost:8088/ResponseFilterweb/login not showing any ui .. i think it should come ?
why http://localhost:8088/ResponseFilterweb/hello not showing any ui ?
If you were using web.xml, this or this would be your solution, but since you're not, this might be your only option. The problem is that when you use /* as the servlet mapping for Jersey, it hogs up all the requests. So the request to /hello would go to Jersey and not the LoginServlet. What those solutions I linked to do is cause Jersey to forward the request if it can't find it within the Jersey application. The other solution is to just change the servlet mapping to something like /api/* (which is pretty common), then you would just prefix your API requests with /api.
Using asterisk (*) won't work using #ApplicationPath
If you use /*, then you're making it too greedy and saying it should match everything all the time, and the default servlet will never be invoked
Use #ApplicationPath("/") instead
If you use /, then you're replacing the container's default servlet
Basically I have servlet named forward. When a request is made to it, it forwards the request to a .html file like this:
#WebServlet("/forward")
public class forward extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("/videos/forward.html").forward(request, response);
return;
}
}
The problem is that when I test this on eclipse when a request is made to this servlet, it responds with the link as localhost/videos/forward.html
But then when I deployed it with name com.war Now when a request is made to it, it responds with localhost/com/videos/forward.html
How can I make the requestDispatcher to respond with localhost/videos/forward.html and not as localhost/com/videos/forward.html
No you cannot. Forwarding is a request made to the servlet container to pass control to another servlet in same servlet context. A JSP page in indeed implemented as a servlet, but a HTML is just a ressource, so you cannot forward to it.
But you can redirect to it. A redirection works by sending a special response telling the browser that it should go to that other URL. As it works at browser level, you can redirect to a HTML page or even to a completely different site.
You can use the sendRedirect method from HttpServletResponse to initiate a redirection from a servlet:
#WebServlet("/forward")
public class forward extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.sendRedirect("/videos/forward.html");
return;
}
}
Just write
response.sendRedirect(pagename.html)
Yes, u can.
use:
RequestDispatcher r = req.getRequestDispatcher(String arg);
I want some concrete filter to be applied for all urls except for one concrete (i.e. for /* except for /specialpath).
Is there a possibility to do that?
sample code:
<filter>
<filter-name>SomeFilter</filter-name>
<filter-class>org.somproject.AFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SomeFilter</filter-name>
<url-pattern>/*</url-pattern> <!-- the question is: how to modify this line? -->
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
The standard Servlet API doesn't support this facility. You may want either to use a rewrite-URL filter for this like Tuckey's one (which is much similar Apache HTTPD's mod_rewrite), or to add a check in the doFilter() method of the Filter listening on /*.
String path = ((HttpServletRequest) request).getRequestURI();
if (path.startsWith("/specialpath/")) {
chain.doFilter(request, response); // Just continue chain.
} else {
// Do your business stuff here for all paths other than /specialpath.
}
You can if necessary specify the paths-to-be-ignored as an init-param of the filter so that you can control it in the web.xml anyway. You can get it in the filter as follows:
private String pathToBeIgnored;
public void init(FilterConfig config) {
pathToBeIgnored = config.getInitParameter("pathToBeIgnored");
}
If the filter is part of 3rd party API and thus you can't modify it, then map it on a more specific url-pattern, e.g. /otherfilterpath/* and create a new filter on /* which forwards to the path matching the 3rd party filter.
String path = ((HttpServletRequest) request).getRequestURI();
if (path.startsWith("/specialpath/")) {
chain.doFilter(request, response); // Just continue chain.
} else {
request.getRequestDispatcher("/otherfilterpath" + path).forward(request, response);
}
To avoid that this filter will call itself in an infinite loop you need to let it listen (dispatch) on REQUEST only and the 3rd party filter on FORWARD only.
See also:
How to prevent static resources from being handled by front controller servlet which is mapped on /*
How to handle static content in Spring MVC?
I used an approach described by Eric Daugherty: I created a special servlet that always answers with 403 code and put its mapping before the general one.
Mapping fragment:
<servlet>
<servlet-name>generalServlet</servlet-name>
<servlet-class>project.servlet.GeneralServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>specialServlet</servlet-name>
<servlet-class>project.servlet.SpecialServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>specialServlet</servlet-name>
<url-pattern>/resources/restricted/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>generalServlet</servlet-name>
<url-pattern>/resources/*</url-pattern>
</servlet-mapping>
And the servlet class:
public class SpecialServlet extends HttpServlet {
public SpecialServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.sendError(HttpServletResponse.SC_FORBIDDEN);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.sendError(HttpServletResponse.SC_FORBIDDEN);
}
}
This approach works when you want to prevent a certain filter and all the following ones. It should work well if you eg. want to serve some content as static resources within your servlet container instead of letting your application logic (through a filter like GuiceFilter):
Map the folder with your static resource files to the default servlet. Create a servlet filter and put it before the GuiceFilter in your web.xml. In your created filter, you can separate between forwarding some requests to the GuiceFilter and others directly to the dispatcher. Example follows...
web.xml
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/static/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>StaticResourceFilter</filter-name>
<filter-class>com.project.filter.StaticResourceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>StaticResourceFilter</filter-name>
<url-pattern>/static/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
StaticResourceFilter.class
public class StaticResourceFilter implements Filter {
private final static Logger LOGGER = LoggerFactory.getLogger(StaticResourceFilter.class);
private static final String RESOURCE_PATH = "/static/";
#Override
public void init(final FilterConfig filterConfig) throws ServletException {
LOGGER.info("StaticResourceFilter initialized");
}
#Override
public void doFilter(final ServletRequest request, final ServletResponse response,
final FilterChain chain) throws IOException, ServletException {
String path = ((HttpServletRequest) request).getServletPath();
if (path.toLowerCase().startsWith(RESOURCE_PATH)) {
request.getRequestDispatcher(path).forward(request, response);
} else {
chain.doFilter(request, response);
}
}
#Override
public void destroy() {
LOGGER.info("StaticResourceFilter destroyed");
}
}
Unfortunately if you just want to skip a single step in the filter chain while keeping those that follows, this will not work.
I don't think you can, the only other configuration alternative is to enumerate the paths that you want to be filtered, so instead of /* you could add some for /this/* and /that/* etc, but that won't lead to a sufficient solution when you have alot of those paths.
What you can do is add a parameter to the filter providing an expression (like a regular expression) which is used to skip the filter functionality for the paths matched.
The servlet container will still call your filter for those url's but you will have better control over the configuration.
Edit
Now that you mention you have no control over the filter, what you could do is either inherit from that filter calling super methods in its methods except when the url path you want to skip is present and follow the filter chain like #BalusC proposed, or build a filter which instantiates your filter and delegates under the same circumstances. In both cases the filter parameters would include both the expression parameter you add and those of the filter you inherit from or delegate to.
The advantage of building a delegating filter (a wrapper) is that you can add the filter class of the wrapped filter as parameter and reuse it in other situations like this one.
I also Had to filter based on the URL pattern(/{servicename}/api/stats/)in java code .
if (path.startsWith("/{servicename}/api/statistics/")) {
validatingAuthToken(((HttpServletRequest) request).getHeader("auth_token"));
filterChain.doFilter(request, response);
}
But its bizarre, that servlet doesn't support url pattern other than (/*), This should be a very common case for servlet API's !
I have encounterd the same issue, but I find a anwser showing below.
web.xml
<!-- set this param value for the filter-->
<init-param>
<param-name>freePages</param-name>
<param-value>
MainFrame.jsp;
</param-value>
</init-param>
filter.java
strFreePages = config.getInitParameter("freePages"); //get the exclue pattern from config file
isFreePage(strRequestPage) //decide the exclude path
this way you don't have to harass the concrete Filter class.
If for any reason you cannot change the original filter mapping ("/*" in my case) and you are dispatching to an unchangeable third-party filter, you can find useful the following:
Intercept the path to be bypassed
Skip to and execute the last ring of the filter chain (the servlet itself)
The skipping is done via reflection, inspecting the container instances in debug mode
The following works in Weblogic 12.1.3:
import org.apache.commons.lang3.reflect.FieldUtils;
import javax.servlet.Filter;
[...]
#Override
public void doFilter(ServletRequest request, ServletRespons response, FilterChain chain) throws IOException, ServletException {
String path = ((HttpServletRequest) request).getRequestURI();
if(!bypassSWA(path)){
swpFilterHandler.doFilter(request, response, chain);
} else {
try {
((Filter) (FieldUtils.readField(
(FieldUtils.readField(
(FieldUtils.readField(chain, "filters", true)), "last", true)), "item", true)))
.doFilter(request, response, chain);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
I was able to handle this in Spring 2 as following
private boolean isInPath(ServletRequest request) {
String PATH_TO_VALIDATE = "/path/";
String path = ((HttpServletRequest) request).getRequestURI();
return path != null && path.toLowerCase().contains(PATH_TO_VALIDATE);
}
This is what I want to do :
A servlet is called.Before a servlet is called , the request is intercepted by a filter. Filter gets some details out from the request,sets them as an attribute and the forwards it to a servlet via chain.doFilter(request,response). Request finally reaches the servlet. Servlet gets the attribute set by the filter before and sets a new attribute by another name. Then it forwards it to some jsp page where the page gets the attribute and processes it.
How do I do this ? I know how to write a filter and a servlet but how do I forward it to a jsp page from the servlet or is there any other way to achieve this ?
You can use the RequestDispatcher.forward method from your servlet:
public class YourServlet extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
RequestDispatcher rd = getServletConfig().getServletContext()
.getRequestDispatcher("/yourJsp.jsp");
rd.forward(request, response);
}
}
See also javaee 5 tutorial
EDIT: I've tested this approach on tomcat 7 examples:
I've enabled the example timing filter
I've invoked the servletToJsp example (in this example a servlet forwards to a jsp)
Everything works perfectly. The filter does his job and there are no exceptions.
You should have specified from the start that you had a problem and provide stacktrace, etc.
Regarding the question in the comments:
why not request.getRequestDispatcher ?
In the example I provided makes no difference as I'm calling an absolute path. The request.getRequestDispatcher is useful when dealing with relative paths. See this SO question.
EDIT 2:
I'm attaching the sources with the filter, servlet and jsp.
Filter:
package tests.filters;
import javax.servlet.*;
import java.io.IOException;
public final class ExampleFilter implements Filter {
private String attribute = null;
private FilterConfig filterConfig = null;
#Override
public void destroy() {
this.attribute = null;
this.filterConfig = null;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
if (attribute != null)
request.setAttribute(attribute, this);
long startTime = System.currentTimeMillis();
chain.doFilter(request, response);
long stopTime = System.currentTimeMillis();
filterConfig.getServletContext().log
(this.toString() + ": " + (stopTime - startTime) +
" milliseconds");
}
#Override
public void init(FilterConfig fConfig) throws ServletException {
this.filterConfig = fConfig;
this.attribute = fConfig.getInitParameter("attribute");
}
#Override
public String toString() {
if (filterConfig == null)
return ("TimingFilter()");
StringBuilder sb = new StringBuilder("TimingFilter(");
sb.append(filterConfig);
sb.append(")");
return (sb.toString());
}
}
Servlet:
package tests.servlets;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ServletToJsp extends HttpServlet {
private static final long serialVersionUID = 1L;
#Override
public void doGet (HttpServletRequest request,
HttpServletResponse response) {
try {
request.setAttribute ("servletName", "servletToJsp");
getServletConfig().getServletContext().getRequestDispatcher(
"/jsp/jsp-to-servlet/hello.jsp").forward(request, response);
} catch (Exception ex) {
ex.printStackTrace ();
}
}
}
JSP:
<html>
<body bgcolor="white">
<h1>
I have been invoked by
<% out.print (request.getAttribute("servletName").toString()); %> Servlet.
</h1>
</html>
web.xml
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0"
metadata-complete="true">
<filter>
<filter-name>Timing Filter</filter-name>
<filter-class>tests.filters.ExampleFilter</filter-class>
<init-param>
<param-name>attribute</param-name>
<param-value>tests.filters.ExampleFilter</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Timing Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>ServletToJsp</servlet-name>
<servlet-class>tests.servlets.ServletToJsp</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletToJsp</servlet-name>
<url-pattern>/servletToJsp</url-pattern>
</servlet-mapping>
</web-app>
I also provide a download link that contains the example packaged as a war: http://goo.gl/GaV5w (7 days availability)
Just copy the file in your tomcat 7 webapps directory and call from your browser: http://localhost:8080/webapp-javaee6-1.0-SNAPSHOT/servletToJsp. You'll see in the logs/localhost.currentDate.log file that the filter prints the processing time and the jsp display its content.
I can't do anything more to convince you that this approach works and your problem (if you have one) is in other place.
Yes when we give the wild-card. It means that for any request the filter will
first intercept the request. You can practically imagine this scenario in a
full fledge web application where you need to introduce security. In most simplest
form you will write a Security filter which will authorized your user. So you can
give the mapping as generic so that for every request first your security filter is
invoked. You get IllegalState exception when you have already committed the response.
Is your code working fine? Please post your code if it is not working still.
HTH,
Ben
I have a url-mapping in my web.xml such that requests for a specific url x.pt gets mapped to a Servlet say Servlet1. In the service() of this servlet I check if the request has some specific parameter.
If so, the call is delegated to another servlet Servlet2 by instantiating it and calling its service method.
public void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
// if the call is for some special events (request has some specific parameter)
if (req.getParameter(conditionCheck()) {
doPost(req, res);
} else {
// Report parsing
}
}
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
try {
// instantiate Servlet2 object
servlet2.init(this.getServletConfig());
servlet2.service(req, res);
servlet2.destroy();
} catch (Exception e) {
LOG.error("Unable to execute event", e);
}
}
The browser returns some JSON text when the request is for special events( i.e. to Servlet2)
Do let me know if I need to do something extra for getting response of Servlet2 to the brwoser.
Thanks in advance!
You can forward your request using RequestDispacher:
RequestDispatcher rd = getServletContext().getRequestDispatcher(destination);
rd.forward(request, response);
As Kris says, I'd expect a RequestDispatcher to work, but I'm always uncomfortable when I see a servlet being called directly like this. Do you have the opportunity to move the logic that is provided by servlet2 into a separate object that both servlet1 and servlet2 can call upon? If you can, I think it'll give you a better, more easily testable solution.