A DispatcherType can be associated with a Java Servlet Filter to limit its scope. From ServletRequest.getDispatcherType() API doc:
The dispatcher type of a request is used by the container to select the filters that need to be applied to the request: Only filters with matching dispatcher type and url patterns will be applied.
The initial dispatcher type of a request is defined as DispatcherType.REQUEST. The dispatcher type of a request dispatched via RequestDispatcher.forward(ServletRequest, ServletResponse) or RequestDispatcher.include(ServletRequest, ServletResponse) is given as DispatcherType.FORWARD or DispatcherType.INCLUDE, respectively, while the dispatcher type of an asynchronous request dispatched via one of the AsyncContext.dispatch() methods is given as DispatcherType.ASYNC. Finally, the dispatcher type of a request dispatched to an error page by the container's error handling mechanism is given as DispatcherType.ERROR.
Example
In this example, we will create a Filter which will only be invoked for DispatcherType.ERROR .
A Servlet
@WebServlet(name = "currencyRateServlet", urlPatterns = {"/app/*"})
public class AppServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
PrintWriter writer = resp.getWriter();
DispatcherType dispatcherType = req.getDispatcherType();
String requestURI = req.getRequestURI();
writer.write(String.format("response at %s, DispatcherType: %s%n", requestURI, dispatcherType));
if (requestURI.endsWith("test")) {
writer.println("AppServlet response at: " + requestURI);
} else {
int i = 10 / 0;//throwing exception
}
}
}
As seen above, our AppServlet can throw an exception, so let's create an error mapping in web.xml:
src/main/webapp/WEB-INF/web.xml<?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_1.xsd" version="3.1">
<error-page>
<location>/error-handlers/default-error-handler</location>
</error-page>
</web-app>
Also check out Servlet Error Handling tutorial.
The error handler Servlet
@WebServlet(name = "errorHandlerServlet",
urlPatterns = {"/error-handlers/default-error-handler"})
public class ErrorHandlerServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
PrintWriter writer = resp.getWriter();
writer.println("Error Handler Servlet:");
resp.getWriter().printf("dispatcherType: %s%n", req.getDispatcherType());
}
}
The Filter
@WebFilter(filterName = "errorFilter",
urlPatterns = "/*",
dispatcherTypes = {DispatcherType.ERROR})
public class ErrorFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(req, resp);
PrintWriter writer = resp.getWriter();
writer.println("In the filter:");
Exception exception = (Exception) req.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
writer.printf("exception: %s%n", exception);
Integer code = (Integer) req.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
writer.printf("status_code: %s%n", code);
String requestUri = (String) req.getAttribute(RequestDispatcher.ERROR_REQUEST_URI);
resp.getWriter().printf("request_uri: %s%n", requestUri);
resp.getWriter().printf("dispatcherType: %s%n", req.getDispatcherType());
}
@Override
public void destroy() {
}
}
To try examples, run embedded tomcat (configured in pom.xml of example project below):
mvn tomcat7:run-war
Output
As seen above, our filter did not invoke. It will only be invoked if there's an error.
Let's try an URI not mapped to our app servlet:
Notes
Specifying DispatcherType in web.xml
In case if we are doing xml based configuration rather than annotation one:
....
<filter-mapping>
<filter-name>errorFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
...
We can use multiple <dispatcher> within <filter-mapping>.
Setting DispatcherType during dynamic filter registration
@WebListener
public class MyContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
FilterRegistration.Dynamic fr = sce.getServletContext()
.addFilter("errorFilter", ErrorFilter.class);
EnumSet<DispatcherType> dts = EnumSet.of(DispatcherType.ERROR);
fr.addMappingForUrlPatterns(dts, false, "/*");
}
.....
}
Check out Servlet Dynamic registration tutorial and other example as well.
Example ProjectDependencies and Technologies Used: - javax.servlet-api 3.1.0 Java Servlet API
- JDK 1.8
- Maven 3.3.9
|