Thursday, 1 September 2011

Creating a custom filter in Spring

Adding a filter in spring is something that seems like it should be easy, but can be tricky if you get your configurations in a twist.

So here is how I added a really simple filter to my Spring application.

In my web.xml I added the following filter definition, alongside the other standard security and encoding ones:

 <filter>
  <filter-name>expiredPasswordFilter</filter-name>
  <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  <init-param>
    <param-name>targetBeanName</param-name>
    <param-value>expiredPasswordFilterBean</param-value>
  </init-param>
</filter>



The org.springframework.web.filter.DelegatingFilterProxy is the relevant filter type that allows you to then declare a targetBeanName value... which corresponds to a declaration we add in our applicationContext.xml, as so:

<bean name="expiredPasswordFilterBean" class="com.companyname.webapp.filter.ExpiredPasswordFilter"/>

With that connection set up, we now head back to the web.xml to define the mapping for our filter... separately from the above filter definition. In my case, this was enough:

 <filter-mapping>
  <filter-name>expiredPasswordFilter</filter-name>
  <url-pattern>*.html</url-pattern>
 </filter-mapping>


the filter name connects to the previous web.xml definition, and the url-pattern in my case was for the filter to be run on every request for a HTML path.

With that all in place, all I needed to do was declare the actual filter control class. This is defined in the applicationContext above as being at com.companyname.webapp.filter.ExpiredPasswordFilter, and the class looks a little like this:

com.companyname.webapp.filter.ExpiredPasswordFilter;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.filter.OncePerRequestFilter;

public class ExpiredPasswordFilter extends OncePerRequestFilter {

 protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws ServletException, IOException {
  
  /*
   *  This is where I did my user flag checking
   */
  
                chain.doFilter(req, res);
 }
}


The actual logic of the filter can be almost anything you want! But just make sure you call chain.doFilter(req, res); to invoke the next filter in the chain. This can be at any point throughout your code, and control is passed straight back to your filter once the chain has been executed, which can be useful for ensuring other security/authentication filters have been run before you do anything additional yourself.

19 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. I just ate a mountain of frustration with Spring, I am tired and I am frazzled. Reading your short and well written post I found a good workaround to get what I needed off the ground. Thank you so much for posting.

    Steve

    ReplyDelete
    Replies
    1. Same for me!

      I was unable to get the primefaces fileupload filter work propperly... In fact, it wasn't called at all!
      Now I just created a bean that extends the org.primefaces.webapp.filter.FileUploadFilter and use that filter instead ^^

      This post saved my day! Thanks a lot!

      Delete
    2. Thank you guys, it's always great to hear my ramblings are proving useful! Cheers for taking the time to leave your comments, and all the best with your projects in the future!!

      Simon

      Delete
  3. No worries Steve, I'm glad my post could help.

    Thank you for posting.

    ReplyDelete
  4. It's really Short and sweet description.

    Thanks for this blog.

    ReplyDelete
    Replies
    1. You're welcome. I'm glad you found it useful, and thank you for your comment.

      Delete
  5. This is just wonderful. I needed to redirect a user when session timeouts and your code just helped me.

    Thanks!

    ReplyDelete
    Replies
    1. Fantastic Rishab, glad it was of help.

      Thank you for your comment.

      Delete
  6. Do not forget to add the following listener

    org.springframework.web.context.ContextLoaderListener

    If missed you get this exception :
    java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?

    ReplyDelete
  7. Thanks For Your valuable posting, it was very informative.

    ReplyDelete
  8. "all I needed to do was declare the actual filter control class. This is defined in the applicationContext above as being at com.companyname.webapp.filter.ExpiredPasswordFilter",

    Are you defining the ExpiredPasswordFilter bean in the
    Dispatcher Servlet Application Context ("Web Layer Context", used for Controllers, Views, Resolvers used by Spring MVC)
    or
    in the "Root" Application context?

    Thank you for the very nice post.

    ReplyDelete
  9. I can't think in any cases I would want use the traditional filter instead of the spring interceptor.

    ReplyDelete
  10. but yeh, thanks for the tutorial it was useful anyway

    ReplyDelete
  11. Great article.. It worked for me..
    Thanks for sharing such a useful tutorial.. :)

    ReplyDelete
  12. The information you wish to give through this article is very informative. I have been waiting to read such wonderful piece of articles but was never lucky, but today I finally did become lucky because your article is just fabulous.
    http://www.redsqware.com/

    ReplyDelete
  13. It's really a short and beautiful description
    Thank you so much for posting.

    ReplyDelete
  14. Incredible points. Sound arguments. Keep up the great work.

    ReplyDelete