The problem I am trying to solve is that I want to check all incoming GET urls against a database. If the the url exist in the database it shall be passed to a certein controller. I'm using Spring 3.0.
First I tried to make an interceptor and add that to DefaultAnnotationsHandlerMapping. Turns out i couldn't modify the url in preHandle(). The plan was to modify the url in the request and then let an annotated controller handle the rest.
Next I tried to make a custom HandleMapping. I extended AbstractUrlHandlerMapping and made my own getHandlerInternal() that returns a String with the name of the Controller and this is working. But I'd prefer a solution where I can modify the url in the request and let an annotated controller handle it.
While writing this I got thinking that maybe a servlet filter is the most proper solution. If that's the case can I get Spring to inject an EntityManager into the filter? Any Spring class I can extend that makes this easier?
What's the most proper way to solve the problem in the first paragraph? If it's the servlet filter please give me some pointers on how to write it.
As has been pointed out by others, a standard servlet filter would do the job, but it's not a very spring-friendly solution - the filter is not managed by Spring, and so cannot be wired with Spring beans. The filter would need to fetch the spring beans programmatically, which isn't nice.
The trouble with modifying the URL of an existing request is that it rather breaks the servlet API model. HttpServletRequest
has multiple path- and URL-related methods that extract different parts of the original URL, and you'd have to make sure you somehow modified all of those values. The API just isn't designed for that, whether you use filters or interceptors.
SO rather than trying to subvert the API, my suggestion is you write a Spring controller that accepts the "old" path, and which forwards the request to the "new" path, based on the injected EntityManager
. The forwarding can happen by having the controller handler method return a InternalResourceView
with the "new" path. It's not strictly speaking a view you're forwarding to, but Spring won't know the difference. Alternatively, you can forward it directly using request.getRequestDispatcher(newPath).forward(request, response)
.
I realise this is an old thread, but instead I would suggest that you extend org.springframework.web.servlet.DispatcherServlet
something like this :
@Override
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
try {
RequestImpl req = RequestImpl.wrapRequest(request, response);
request = req;
response = req.getResponse();
} catch (Throwable t) {
//swallow }
super.doDispatch(request, response);
}
Then refer to this dispatcher in your web.xml as :
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>blah.com.MyDispatcher</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
Etc. It seems scary to extend the absolute core class of Spring MVC, but if you're old enough to remember, before the dark days of annotations, when real adults were still committing to the beautiful POJO framework we all loved, this is how you're meant to use Spring.
Maybe wrapping the servlet request and passing it to the filter chain.
...
MyHttpServletRequestWrapper wreq = new MyHttpServletRequestWrapper(request);
doFilter(wreq, response, chain);
...
The wrapper returns a modified URL when asked.
You could use a normal javax.servlet.Filter
and create a HttpServletRequest
-Wrapper that does the URL handling for you.