I'm using Tomcat 7 to serve some JAXRS services.
I also want to get a few static web pages to be served by the same application, using default servlet. This is how I define the mapping :
public void contextInitialized(ServletContextEvent sce) {
sce.getServletContext().getServletRegistrations().get("default").addMapping("/backoffice/*");
}
My problem is that the only way to access those static files is to use http://myserver.com/backoffice/index.html. I would like to access them just with http://myserver.com/backoffice
I do not define any mapping in web.xml file, just my main JAXRS application.
I've tried using welcome file list this way :
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
I did not find any workaround on this problem, and the way I define the mapping to default servlet is the only one I found working.
Thanks for help.
I can only think of two possibilities.
Define a servlet mapping in the web.xml to the html file or
Create a servlet, annotate it with #WebServlet and then in the doGet() method dispatch/redirect to the html file.
You could dynamically register the servlet if you prefered.
What I ended with :
In my ServletContextListener, I added :
public void contextInitialized(ServletContextEvent sce) {
String name = "backoffice-filter";
sce.getServletContext().addFilter(name, new StaticRedirectionFilter(basePath, targetPath));
sce.getServletContext().getFilterRegistrations().get(name).addMappingForUrlPatterns(null, false, pathDepart);
sce.getServletContext().getServletRegistrations().get("default").addMapping("/backoffice/*");
}
The class StaticRedirectionFilter :
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
String requestURI = request.getServletPath();
if (requestURI.equals(basePath)) {
HttpServletResponse response = (HttpServletResponse) res;
response.sendRedirect(request.getContextPath() + targetPath);
}
else {
chain.doFilter(req, res);
}
}
As Alex mentionned it, I could have done it with an annotation #WebFilter("/backoffice") abose the StaticRedirectionFilter class, but using the mapping in context seems better for reusability.
I also think it works before Servlet 3, even if I didn't try it.
Related
I've done my java web app in Java EE with HttpServlet and JSP. I normally map my Servlet like this:
#WebServlet(urlPatterns = "/main")
public class MainServlet extends HttpServlet{
I do my servlet stuff and would like to pass data to JSP file like this:
RequestDispatcher dispatcher = req.getRequestDispatcher("/main.jsp");
dispatcher.forward(req, resp);
The main.jsp is in my web app folder (I use IntelliJ Idea).
The question is, I've initially made my UI with Vaadin 8. Using following:
#Theme("mytheme")
#CDIUI("users")
#SuppressWarnings("serial")
public class Vaadin extends UI
and then override init.
Now I would like to add a single HttpServlet and override doGet and then call the dispatcher to forward data to jsp. Here's the problem adding Vaadin somehow broke the path to tsp, as jsp does not display, instead a standard vaadin
Request was not handled by any registered handler.
appears, I know the servlet was mapped properly as the servlet starts and does work, what does not work is the running the JSP file.
Can anyone advise?
It seems that you need to implement yet a WebFilter to process JSP. Your dispatcher forwards the request but it is then a request that is again handled by some filter by Vaadin I guess. Also I am not sure if you need any servlet and/or dispatcher (not sure what your actual use is).
Anyway, with WebFilter it is possible to intercept this processing. Check the following example
#WebFilter(filterName="jspFilter", urlPatterns="*")
public class JspFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
try {
HttpServletRequest hreq = (HttpServletRequest)request;
String path = hreq.getPathTranslated();
if(path.toLowerCase().endsWith(".jsp")) {
try(Writer writer = response.getWriter();
Reader reader = new FileReader(path) ) {
processJsp(reader, writer);
return;
} catch (Exception e) { /* TODO: handle exception */};
}
} catch (Exception e) { /* TODO: handle exception */};
chain.doFilter(request, response); // forward to filter chain by default
}
#Override public void destroy() {}
#Override public void init(FilterConfig filterConfig)
throws ServletException {}
}
This filter checks all request. If URI (here checked from translated/absolute path) is ending with .jsp it is processed with processJsp(reader, writer) that you might want to implement to do the forwarding to JSP parser or so.
I am learning JSP and Servlets. Consider the following code inside the doPost method of a Servlet which forwards a HTTP request to a JSP -
RequestDispatcher view = request.getRequestDispatcher("/MyWebApp/MvcView.jsp");
I wonder what will happen if someone wants this servlet to forward the request to another jsp instead of the one above ? Does one have to change this code manually every time in their application ? How can one free oneself of all this manual work ?
One simple solution is to set the url as a parameter for your servlet:
<servlet>
<servlet-name>YourServlet</servlet-name>
<servlet-class>com.you.YourServlet</servlet-class>
<init-param>
<param-name>url</param-name>
<param-value>/MyWebApp/MvcView.jsp</param-value>
</init-param>
</servlet>
and the in the servlet:
public class YourServlet {
protected String url = null;
public void init(ServletConfig servletConfig) throws ServletException {
this.url = servletConfig.getInitParameter("url");
}
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
RequestDispatcher view = request.getRequestDispatcher(url);
}
}
then there is no need to recompile servlet code to chage the url.
jsp:
<!DOCTYPE html>
<form action="/{insert your context here}/p/hello" method="post" enctype="multipart/form-data">
<input type="file" name="data">
<button>Go</button>
</form>
Servlet:
#WebServlet
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1;
#Override
protected void doPost( HttpServletRequest request, HttpServletResponse response )
throws IOException, ServletException {
if ( request.getPart( "data" ) != null ) {
response.getWriter().print( "It worked\n\n" );
} else {
response.getWriter().print( "IT IS NOT WORKING!\n\n" );
}
}
}
Filter
#WebFilter( filterName = "hello" )
public class HelloFilter implements Filter {
#Override
public void init( FilterConfig config ) throws ServletException {}
#Override
public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain )
throws IOException, ServletException {
request
.getRequestDispatcher( "/hello" )
.include( request, response );
request
.getRequestDispatcher( "/hello.jsp" )
.include( request, response );
}
#Override
public void destroy() {}
}
Listener
#WebListener
public class HelloListener implements ServletContextListener {
#Override
public void contextInitialized( ServletContextEvent event ) {
ServletContext context = event.getServletContext();
Dynamic hello = context.addServlet( "hello", HelloServlet.class );
hello.addMapping( "/hello" );
hello.setMultipartConfig( getMultiPartConfig() );
}
#Override
public void contextDestroyed( ServletContextEvent event ) {}
private MultipartConfigElement getMultiPartConfig() {
String location = "";
long maxFileSize = -1;
long maxRequestSize = -1;
int fileSizeThreshold = 0;
return new MultipartConfigElement(
location,
maxFileSize,
maxRequestSize,
fileSizeThreshold
);
}
}
My 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" xmlns:jsp="http://java.sun.com/xml/ns/javaee/jsp" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>{insert the context here}</display-name>
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<page-encoding>UTF-8</page-encoding>
</jsp-property-group>
</jsp-config>
<filter-mapping>
<filter-name>hello</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
When I submit the form I receive the output "IT IS NOT WORKING!" in the first line of the response. If I change the requested path from /{insert your context here}/p/hello to /{insert your context here}/hello it works, why?
Using:
JBoss EAP 6.1
I was able to reproduce the problem with Tomcat 7.0.30. The same problem was present whether I configured the "HelloServlet" dynamically or statically, using a #MultipartConfig annotation.
I also tested on Jetty version 8.1.13.v20130916, and it worked fine in both cases; /{context}/p/hello and /{context}/hello, without any modifications.
If you were to modify your HelloListener like this:
Dynamic hello = context.addServlet( "hello", HelloServlet.class );
hello.addMapping( "/hello" );
hello.addMapping( "/p/hello" );
hello.setMultipartConfig( getMultiPartConfig() );
it would work, but I suspect that defeats the purpose of what you are trying to do. Another option would be to modify your filter to add new mappings dynamically as required:
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// dynamically add mappings
ServletContext context = request.getServletContext();
ServletRegistration registration = context.getServletRegistration("hello");
registration.addMapping("/<dynamic path>/hello");
request.getRequestDispatcher("/hello").include(request, response);
request.getRequestDispatcher("/hello.jsp").include(request, response);
}
It seems like tomcat/jboss is only enabling multipart support for the request based on whether or not the original request path matches one of the servlets configured for multipart support, whereas it should be enabling support based on the path of the request it is currently handling (which might have been "included" by the RequestDispatcher.
It does seem like a tomcat/jboss bug, but you'd have to carefully read the servlet spec to find out, otherwise you could use Jetty instead.
I randomly came across this and what may be the answer to your dilemma at the same time. Given the annotations supplied, the page would be accessed with {insert your context here}/hello and not {insert your context here}/p/hello. Take a look at Multiple folders in Java EE 6 web pages. It is very similar and BalusC provides some great information. Hope that helps.
I'm trying to use WebFilter with JSF 2, but my filter not is working. The urlPattern is not recognized.
My Filter class:
#WebFilter(urlPatterns = {"/rws/*"})
public class AuthorizationFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
HttpSession session = req.getSession(true);
Object o = session.getAttribute("user");
HttpServletResponse res = (HttpServletResponse) response;
if(o == null)
res.sendRedirect(req.getContextPath() + "/login.xhtml");
else
chain.doFilter(request, response);
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void destroy() {
}
}
In my structure I want to protect all pages that are in the rws folder, but I could not configure the filter.
I've tried
# WebFilter ("/ rws / *")
# WebFilter ("/ faces / rws / *")
My filter never is executed!!
I noticed that the url does not change when I browse pages.
For example, the user opens the index.xhtml performs login and then redirects to page loginOk.xhtml.
LoginOk.xhtml page has links to pages that are in the folder rws.
When I click the link url does not change, ie, I'm browsing in a folder page rws but the url in the browser remains the same (http://jsftest.com:8080/TestePrimeFaces/faces/loginOK.xhtml). Is that the problem?
Used a commandLink as link, do not know if it is the most suitable.
Does anyone know where is the problem?
add "#Component" like this.
#Component
#WebFilter(urlPatterns = {"/rws/*"})
public class AuthorizationFilter implements Filter { ...
Servlet filters don't get triggered when you perform a non-redirect JSF navigation on postback. JSF navigation does namely by default not create a new HTTP request (which would trigger the filter), but it just changes the content of the HTTP response while still keeping the same HTTP request (that's also exactly why you don't see a change in browser's address bar).
Adding the FORWARD dispatcher to the filter mapping as some may suggest won't work as JSF on Facelets doesn't use RequestDispatcher#forward() unlike "plain" JSP/Servlet and many other MVC frameworks.
If you want to trigger the filter, just send a new request by a redirect.
So, instead of
public String login() {
// ...
return "home";
}
just do
public String login() {
// ...
return "home?faces-redirect=true";
}
If you worry about faces messages being lost due to the redirect, just make use of the flash scope.
See also:
What is the difference between redirect and navigation/forward and when to use what?
How to navigate in JSF? How to make URL reflect current page (and not previous one)
How to show faces message in the redirected page
I have a Spring MVC application which uses FreeMarker as View technology (But maybe the view technology doesn't really matter for my question). I need to intercept all exceptions which may get thrown during a request.
I have implemented a HandlerExceptionResolver but this resolver is only executed when the exception occurs within a controller. But when a controller returns a ModelAndView and the exception occurs while rendering the view (Because a variable was not found or something like this) then the exception resolver is not called and instead I get a stack trace in the browser window.
I also tried using an exception handler method within the controller which returns the view and annotated it with #ExceptionHandler but this also doesn't work (Most likely again because the exception is not thrown in the controller but in the view).
So is there some Spring mechanism where I can register an exception handler which captures view errors?
A word upfront: if you just need a "static" error page without much logic and model preparation, it should suffice to put a <error-page>-Tag in your web.xml (see below for an example).
Otherwise, there might be better ways to do this, but this works for us:
We use a servlet <filter> in the web.xml that catches all Exceptions and calls our custom ErrorHandler, the same we use inside the Spring HandlerExceptionResolver.
<filter>
<filter-name>errorHandlerFilter</filter-name>
<filter-class>org.example.filter.ErrorHandlerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>errorHandlerFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
The implementation looks essentially like this:
public class ErrorHandlerFilter implements Filter {
ErrorHandler errorHandler;
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
try {
filterChain.doFilter(request, response);
} catch (Exception ex) {
// call ErrorHandler and dispatch to error jsp
String errorMessage = errorHandler.handle(request, response, ex);
request.setAttribute("errorMessage", errorMessage);
request.getRequestDispatcher("/WEB-INF/jsp/error/dispatch-error.jsp").forward(request, response);
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
errorHandler = (ErrorHandler) WebApplicationContextUtils
.getRequiredWebApplicationContext(filterConfig.getServletContext())
.getBean("defaultErrorHandler");
}
// ...
}
I believe this should work pretty much the same for FreeMarker templates. Of course if your error view throws an error, you're more or less out of options.
To also catch errors like 404 and prepare the model for it, we use a filter that is mapped to the ERROR dispatcher:
<filter>
<filter-name>errorDispatcherFilter</filter-name>
<filter-class>org.example.filter.ErrorDispatcherFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>errorDispatcherFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
<error-page>
<error-code>404</error-code>
<location>/WEB-INF/jsp/error/dispatch-error.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/WEB-INF/jsp/error/dispatch-error.jsp</location>
</error-page>
The doFilter-Implementation looks like this:
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
// handle code(s)
final int code = (Integer) request.getAttribute("javax.servlet.error.status_code");
if (code == 404) {
final String uri = (String) request.getAttribute("javax.servlet.error.request_uri");
request.setAttribute("errorMessage", "The requested page '" + uri + "' could not be found.");
}
// notify chain
filterChain.doFilter(servletRequest, servletResponse);
}
You could extends the DispatcherServlet.
In your web.xml replace the generic DispatcherServlet for your own class.
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>com.controller.generic.DispatcherServletHandler</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
Later create your own class DispatcherServletHandler and extends from DispatcherServlet:
public class DispatcherServletHandler extends DispatcherServlet {
private static final String ERROR = "error";
private static final String VIEW_ERROR_PAGE = "/WEB-INF/views/error/view-error.jsp";
#Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
try{
super.doService(request, response);
} catch(Exception ex) {
request.setAttribute(ERROR, ex);
request.getRequestDispatcher(VIEW_ERROR_PAGE).forward(request, response);
}
}
}
And in that page we only have to show a message to the user.
Not sure if my solution works with the problem you're having. Ill just post the way i catch my exceptions to ensure no stack trace is show inside the browser:
I made an AbstractController class with a method that will handle a specific conflict like this:
public class AbstractController {
#ResponseStatus(HttpStatus.CONFLICT)
#ExceptionHandler({OptimisticLockingFailureException.class})
#ResponseBody
public void handleConflict() {
//Do something extra if you want
}
}
This way whenever an exception occurs the user will see a default HTTPResponse status. (eg. 404 Not Found etc..)
I extend this class on all my controller classes to make sure errors are redirected to the AbstractController. This way I don't need to use ExceptionHandler on a specific controller but I can add the globally to all my controllers. (by extending the AbstractController class).
Edit:
After another go on your question, I noticed you're getting errors in your view. Not sure if this way will catch that error..
Hope this helps!!