<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4081042681428327092</id><updated>2011-12-27T07:40:42.530-05:00</updated><category term='Command Query Responsibility Separation'/><category term='Domain Driven Design'/><category term='pom'/><category term='DDD'/><category term='Spring'/><category term='Event Sourcing'/><category term='Polyglot'/><category term='Maven 3'/><category term='CQRS'/><category term='tuckey urlrewrite spring mvc'/><category term='Event'/><category term='Groovy'/><title type='text'>The Weekly Give</title><subtitle type='html'>All things Java, Spring, Groovy and Grails</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://mattgivney.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4081042681428327092/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://mattgivney.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Matt Givney</name><uri>http://www.blogger.com/profile/01367149444779607020</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/__V-Zstazg88/SwMCHR4y2kI/AAAAAAAAAB8/k4dckOVm-KE/S220/me.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>4</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4081042681428327092.post-4135514899641008698</id><published>2011-10-20T23:14:00.001-04:00</published><updated>2011-10-20T23:22:31.388-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Spring'/><title type='text'>Spring 3.1 @Profile and @PropertySource</title><content type='html'>Today, I'd like to go over a  cool new feature that the good folks at Spring are releasing as part of Spring 3.1...Profiles.&lt;br /&gt;&lt;br /&gt;I won't go into too much detail about how profiles work because SpringSource's Chris Beams has already done a good job of that already -&gt; &lt;a href="http://blog.springsource.com/2011/02/14/spring-3-1-m1-introducing-profile"&gt;Read about it here&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Instead, I'd like to take on a very simple use case where this feature will be VERY helpful. Most developers have run into a scenario where they needed to bootstrap their application with beans that are slightly different based on the environment. For example, a datasource might be different for dev, test and prod. With the help of Spring @Profile and the @Configuration classes, this is a complete snap to do now. Let's dive into the example.&lt;br /&gt;&lt;br /&gt;My project has two beans: CommonBean which is the same for all environments, and EnvBean which has environment specific configuration (in the real world, EnvBean could be a datasource, jms connectivity beans, etc..). The last wrinkle to this app is that my EnvBean requires environment specific properties as well. A very simple use-case, but complete enough to demo the new capabilities.&lt;br /&gt;&lt;br /&gt;Here's the source for my application beans:&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: java"&gt;&lt;![CDATA[public class EnvBean { private String message; public EnvBean(String message){  this.message = message; } public String getMessage(){ return this.message; } protected EnvBean(){}}public class CommonBean { private EnvBean envBean; public CommonBean(EnvBean eb){  this.envBean = eb; } public String getMessage(){ return envBean.getMessage(); } protected CommonBean(){}}]]&gt;&lt;/script&gt;&lt;br /&gt;You see they are simple Java POJOs. Now,  I create a per environment properties file for dev, test and prod with the properties, I am calling them &lt;env&gt;-app.properties.&lt;br /&gt;&lt;br /&gt;Now here's where @Profile comes into the picture. To distinguish the various environments, I create a common @Configuration class called AppBootstrap and a per environment @Configuration class to configure the EnvBean.&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: java"&gt;&lt;![CDATA[@Configuration@Profile(value="DEV")@PropertySource("classpath:/dev-app.properties")public class DevEnvConfig { @Autowired private Environment env;  @Bean public EnvBean simpleBean(){  EnvBean bean = new EnvBean(env.getProperty("service.message"));  return bean; } }@Configuration@Profile(value="TEST")@PropertySource("classpath:/test-app.properties")public class TestEnvConfig { @Autowired private Environment env;  @Bean public EnvBean simpleBean(){  EnvBean bean = new EnvBean(env.getProperty("service.message"));  return bean; }}@Configuration@Profile(value="PROD")@PropertySource("classpath:/prod-app.properties")public class ProdEnvConfig { @Autowired private Environment env; @Bean public EnvBean simpleBean(){  EnvBean bean = new EnvBean(env.getProperty("service.message"));  return bean; }}@Configurationpublic class AppBootstrap { @Autowired private EnvBean envBean; @Bean public CommonBean commonBean(){  CommonBean cb = new CommonBean(envBean);  return cb; }}]]&gt;&lt;/script&gt;&lt;br /&gt;That's it. Now my app is configured to have a different configuration PER environment. So I can run a test to prove this out:&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: java"&gt;&lt;![CDATA[public class Main { public static void main(String args[]){  Main m = new Main();  m.runDevExample();  m.runTestExample();  m.runProdExample(); } private void runProdExample() {  runGenericTest("PROD"); } private void runTestExample() {  runGenericTest("TEST"); } private void runDevExample() {  runGenericTest("DEV"); } private void runGenericTest(String profile){  AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();  ctx.getEnvironment().setActiveProfiles(profile);  ctx.scan("com.mattgivney.profiles.config");  ctx.refresh();  CommonBean cb = (CommonBean)ctx.getBean("commonBean");  print(profile,cb); } private void print(String env, CommonBean cb) {  System.out.println("==== Test result ====");  System.out.println(    String.format("running the %s test resulted in the message %s",env,cb.getMessage())); }}]]&gt;&lt;/script&gt;&lt;br /&gt;Voila! With each run*Example() test you will notice that the appropriate @Profile was invoked and the environment specific properties file was used to configure my EnvBean. &lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: java"&gt;&lt;![CDATA[==== Test result ====running the DEV test resulted in the message This is a dev message==== Test result ====running the TEST test resulted in the message This is a test message==== Test result ====running the PROD test resulted in the message This is a prod message]]&gt;&lt;/script&gt;&lt;br /&gt;Pretty slick new feature from the guys at Spring!  Did I mention, this whole thing was done with NO SPRING XML!!!&lt;br /&gt;&lt;br /&gt;If you want the source for this, you can grab it from Bitbucket =&gt; &lt;a href="https://bitbucket.org/mgivney/spring-3.1-profiles-example"&gt;click here&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;More to come and as always, I hope this helps! Cheers!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4081042681428327092-4135514899641008698?l=mattgivney.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattgivney.blogspot.com/feeds/4135514899641008698/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mattgivney.blogspot.com/2011/10/spring-31-profile-and-propertysource.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4081042681428327092/posts/default/4135514899641008698'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4081042681428327092/posts/default/4135514899641008698'/><link rel='alternate' type='text/html' href='http://mattgivney.blogspot.com/2011/10/spring-31-profile-and-propertysource.html' title='Spring 3.1 @Profile and @PropertySource'/><author><name>Matt Givney</name><uri>http://www.blogger.com/profile/01367149444779607020</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/__V-Zstazg88/SwMCHR4y2kI/AAAAAAAAAB8/k4dckOVm-KE/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4081042681428327092.post-6013597821220225854</id><published>2011-05-03T22:04:00.001-04:00</published><updated>2011-05-04T07:48:39.242-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Maven 3'/><category scheme='http://www.blogger.com/atom/ns#' term='pom'/><category scheme='http://www.blogger.com/atom/ns#' term='Groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='Polyglot'/><title type='text'>Maven 3 Polyglot Support</title><content type='html'>A while back I wrote a post where I created a little demo which used Groovy, Maven, JPA and Hibernate. The code is &lt;a href="https://bitbucket.org/mgivney/contact-mgr-hibernate-jpa/overview"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I was taking a look at the Maven 3's new polyglot POM support and decided to convert that application's build to use the Groovy DSL.  If you take a look at the &lt;a href="https://github.com/sonatype/polyglot-maven"&gt;Maven 3 Polyglot code&lt;/a&gt;, you will notice it is simply converting the Groovy DSL into the same POM object that would be created with the XML config. Still, it does make the configuration much more terse. Compared to the pom.xml, the pom.groovy is less than half as many lines. Moreover it just seems to be a bit cleaner and flows nicely. &lt;br /&gt;&lt;br /&gt;For example, where we would have declared a dependency in the pom.xml as:&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: xml"&gt;&lt;![CDATA[&lt;dependency&gt;  &lt;groupid&gt;junit&lt;/groupId&gt;  &lt;artifactid&gt;junit&lt;/artifactId&gt;  &lt;version&gt;3.8.1&lt;/version&gt;  &lt;scope&gt;test&lt;/scope&gt;&lt;/dependency&gt;]]&gt;&lt;/script&gt;&lt;br /&gt;You can do the same thing in the Groovy DSL as:&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: java"&gt;&lt;![CDATA[dependency('junit:junit:3.8.1:test')]]&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Before getting too excited about this new Polyglot support, there are a few cons. First, and perhaps a deal breaker for some would be tooling support. Eclipse doesn't support this form of configuration, so you'd have to use Maven eclipse .project/.classpath plugin in order to develop in Eclipse....yet another reason to code in Textmate ;P&lt;br /&gt;&lt;br /&gt;Second, as I said before, the DSL really only converts the config into the same POM object as the XML version would. You can't write executable Groovy code in the DSL unless you use the gmaven plugin. That's sort of a bummer. &lt;br /&gt;&lt;br /&gt;The DSL is nice and makes configuring a Maven project MUCH cleaner. I will most likely use it for Maven projects in the future. I have also heard great things about &lt;a href="http://www.gradle.org/"&gt;Gradle&lt;/a&gt;, and will take a look at that build tool next.&lt;br /&gt;&lt;br /&gt;In the meantime, if you want the code with the Polyglot Maven build, here's the &lt;a href="https://bitbucket.org/mgivney/contact-groovy-hibernate-maven3-polyglot"&gt;link&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4081042681428327092-6013597821220225854?l=mattgivney.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattgivney.blogspot.com/feeds/6013597821220225854/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mattgivney.blogspot.com/2011/05/maven-3-polyglot-support.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4081042681428327092/posts/default/6013597821220225854'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4081042681428327092/posts/default/6013597821220225854'/><link rel='alternate' type='text/html' href='http://mattgivney.blogspot.com/2011/05/maven-3-polyglot-support.html' title='Maven 3 Polyglot Support'/><author><name>Matt Givney</name><uri>http://www.blogger.com/profile/01367149444779607020</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/__V-Zstazg88/SwMCHR4y2kI/AAAAAAAAAB8/k4dckOVm-KE/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4081042681428327092.post-7353528430348610150</id><published>2010-10-19T14:15:00.004-04:00</published><updated>2010-11-09T16:46:23.370-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Event Sourcing'/><category scheme='http://www.blogger.com/atom/ns#' term='Event'/><category scheme='http://www.blogger.com/atom/ns#' term='Domain Driven Design'/><category scheme='http://www.blogger.com/atom/ns#' term='DDD'/><category scheme='http://www.blogger.com/atom/ns#' term='Command Query Responsibility Separation'/><category scheme='http://www.blogger.com/atom/ns#' term='CQRS'/><title type='text'>Event Sourcing</title><content type='html'>It's been a while since I made a blog posting so this one might be a little lengthy. Let's chat up Event Sourcing...&lt;br /&gt;&lt;br /&gt;What is Event Sourcing and why do I care?&lt;br /&gt;&lt;br /&gt;First off, Event Sourcing is not new. It has been around a long time, but the buzz around Command Query Responsibility Separation and DDD has pushed it back into the nerdy mainstream. The basic concept behind event sourcing is that we record state changes in the form of events, instead of the entire state of the object each time.&lt;br /&gt;&lt;br /&gt;Using this technique adds a few nice benefits too; First, a reliable audit log becomes a first class citizen in your architecture, and not an after-thought. Second the persistence code becomes remarkably simpler. Third, your event storage can be implemented by as many options as you can imagine (RDBMS, flat file, xml, Object DB, BigTable, CouchDB, etc). Finally, you can replay these events to create the state of an object at any point in time...which kicks up the cool many, many notches.&lt;br /&gt;&lt;br /&gt;Let's cover a little bit about one way you could implement event sourcing to persist and recreate a domain object. Before I begin, a little proviso to keep the bliki piranha at bay:  this code is taken from a Contact Manager sample app I am in the process of writing in java to demonstrate the CQRS architecture. It is definitely a work in progress. Before you say it, yes I am well aware that implementing a contact manager in CQRS is crazy over-architected ;} &lt;br /&gt;&lt;br /&gt;The code can be found on BitBucket &lt;a href="https://bitbucket.org/mgivney/contact-mgr-cqrs/src"&gt;here&lt;/a&gt; if you are interested in following along.&lt;br /&gt;&lt;br /&gt;With that out of the way, the first thing we should discuss is how to develop your domain objects to take advantage of Event Sourcing. This snippet comes from my Contact object, which is an aggregate root in my domain. Each of the methods that modify the state of my object, translate that state change into an Event. For example,&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: java"&gt;&lt;![CDATA[public void changeHomeAddress(final Address homeAddress){    Validate.notNull(homeAddress, "Home address cannot be null! Use remove instead.");    applyEvent( new HomeAddressChanged(this.identity, this.homeAddress));}]]&gt;&lt;/script&gt;&lt;br /&gt;The HomeAddressChanged object represents an Event. It is representative of the fact that the state of the address changed in my domain. Notice also that it is a past tense verb. This is important if you are trying to create DDD type UL. That said, DDD is out of scope for this posting, so let's move on.&lt;br /&gt;&lt;br /&gt;After you've made all of your state changes, it's time to save the entity. The Contacts object, which is an implementation of the Repository pattern, will pull the events generated by state changes from the Contact aggregate (1 to *), and store them in the event store. Finally, the markChangesCommitted() method clears the event cache in my contact object.&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: java"&gt;&lt;![CDATA[public void store(final Contact contact) {    final List&lt;event&gt; events = contact.getUncommittedChanges();    eventStore.storeEvents(contact.identity(), events, contact.version());    contact.markChangesCommitted();}]]&gt;&lt;/script&gt;&lt;br /&gt;The last part of persistence is saving these events in the event store. My example is *extra* simple because I am simply using an InMemoryEventStore, but your event store can literally be just about anything. I may do a separate post on the event store to delve into that topic a bit more.&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: java"&gt;&lt;![CDATA[public void storeEvents(UUID aggregateId, List&lt;event&gt; events, int expectedVersion) {      List&lt;storedevent&gt; committedEvents;      if(storedEvents.containsKey(aggregateId)){          committedEvents = storedEvents.get(aggregateId);      }else{          committedEvents = new LinkedList&lt;storedevent&gt;();      }      //a simple optimistic locking check      checkForStaleData(aggregateId, expectedVersion);      //load in the new events      for(Event event : events){         expectedVersion++;         committedEvents.add(new StoredEvent(event, expectedVersion));      }      storedEvents.put(aggregateId,committedEvents);  }]]&gt;&lt;/script&gt;&lt;br /&gt;A couple of key points. First, we ONLY ever insert into the event store, never update or delete. This is to preserve the lifecycle of the aggregate and build a solid audit trail. Second, it is very helpful if your aggregate has a identity that is unique throughout your enterprise. I chose a UUID for simplicity, but it isn't the only way to generate uniqueness. &lt;br /&gt;&lt;br /&gt;Ok, now we have a series of events in the event store, lets talk a bit about replaying events to recreate an aggregate. First step is to get the events for a given id. In my case, I just grab them out of the event store:&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: java"&gt;&lt;![CDATA[public List&lt;event&gt; sourceEvents(UUID aggregateId) {    final List&lt;event&gt; events = new LinkedList&lt;event&gt;();    if(storedEvents.containsKey(aggregateId)){        final List&lt;storedevent&gt; cachedEvents =                storedEvents.get(aggregateId);        for(StoredEvent e : cachedEvents){            events.add(e.getEvent());        }    }    return events;}]]&gt;&lt;/script&gt;&lt;br /&gt;Then I loop through this collection of events and in order, invoke the replay method of the aggregate to rebuild its state.&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: java"&gt;&lt;![CDATA[protected void replay(final Event event){    try{        Method m = getClass().getDeclaredMethod("replay", event.getClass());        m.invoke(this,event);    }catch(Exception e){        throw new ReplayFailureException("Failed to replay contact with id =&gt;" +                 this.identity, e);    }}protected void replay(final HomeAddressChanged event){    changeHomeAddress(event.getHomeAddress());}]]&gt;&lt;/script&gt;&lt;br /&gt;Notice the vanilla replay(Event event) method which uses Reflection to invoke the correct replay method for the type of event it is. This is not the most efficient way to build this functionality, but it is pretty darn simple to maintain, so I'm sticking with it for now. I'd be interested in hearing about other ways java folks have implemented this same piece without Reflection..perhaps an AOP implementation?&lt;br /&gt;&lt;br /&gt;So when this loop finishes, you have the aggregate back in the exact state it was in when you stored it last. Here's an example of testing the storage and then the replay:&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: java"&gt;&lt;![CDATA[protected Contact contact(){    final Contact c = new Contact(aggregateId,"Matt","Givney");    c.changeAIMHandle("captaincrunch");    c.changePhoneNumbers(phoneNumbers);    c.changeEmailAddresses(emailAddresses);    assertNotNull(repository);    return c;}@Testpublic void testStoreEventsShouldGenerateFourEvents(){    Contact c = contact();    repository.store(c);    //now lets confirm the all the appropriate events are stored    List&lt;event&gt; events = eventStore.sourceEvents(aggregateId);    assertEquals(4, events.size());    assertTrue(events.get(0) instanceof ContactCreated);    assertTrue(events.get(1) instanceof AIMHandleChanged);    assertTrue(events.get(2) instanceof PhoneNumbersChanged);    assertTrue(events.get(3) instanceof EmailAddressesChanged);}@Testpublic void testLoadContactByEventsShouldReplayContactToCurrentState(){    Contact c = contact();    repository.store(c);    final Contact contact = repository.load(aggregateId);    assertEquals(contact.getFirstName(), "Matt");    assertEquals(contact.getLastName(), "Givney");    assertEquals(contact.getEmailAddress(),emailAddresses);    assertEquals(contact.getPhoneNumbers(), phoneNumbers);}]]&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;That concludes this little ditty about Event Sourcing. In a future post, I will demonstrate different types EventStore implementations. When I am satisfied with my CQRS Demo I will also do a series of posts about that topic.&lt;br /&gt;&lt;br /&gt;If you are interested in CQRS, here are two great presentations by &lt;a href="http://skillsmatter.com/podcast/open-source-dot-net/greg-young-cqrs-event-sourcing-the-business-perspecive"&gt;Greg Young&lt;/a&gt; and &lt;a href="http://skillsmatter.com/podcast/open-source-dot-net/udi-dahan-command-query-responsibility-segregation/wd-21"&gt;Udi Dahan&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;That's it for now, I am interested to hear your experiences with Event Sourcing and ways I can tweak my code to make it more efficient or amp up the cool.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4081042681428327092-7353528430348610150?l=mattgivney.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattgivney.blogspot.com/feeds/7353528430348610150/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mattgivney.blogspot.com/2010/10/event-sourcing.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4081042681428327092/posts/default/7353528430348610150'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4081042681428327092/posts/default/7353528430348610150'/><link rel='alternate' type='text/html' href='http://mattgivney.blogspot.com/2010/10/event-sourcing.html' title='Event Sourcing'/><author><name>Matt Givney</name><uri>http://www.blogger.com/profile/01367149444779607020</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/__V-Zstazg88/SwMCHR4y2kI/AAAAAAAAAB8/k4dckOVm-KE/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4081042681428327092.post-5556897792903605504</id><published>2010-07-08T21:57:00.002-04:00</published><updated>2010-08-10T20:54:55.679-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tuckey urlrewrite spring mvc'/><title type='text'>How to URL Rewrite in Spring MVC</title><content type='html'>I am in the process of writing a Groovy based web app with Spring MVC and I wanted to use URL Rewriting. I scoured the boards for HOWTO's and from all my research Tuckey.org's URLRewrite is the best one out there. Here's a quick tutorial on how to set it up.&lt;br /&gt;&lt;br /&gt;First, you need to add the dependency to your pom:&lt;br /&gt;&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: xml"&gt;&lt;![CDATA[&lt;dependency&gt;    &lt;groupid&gt;org.tuckey&lt;/groupId&gt;    &lt;artifactid&gt;urlrewritefilter&lt;/artifactId&gt;    &lt;version&gt;3.1.0&lt;/version&gt;&lt;/dependency&gt;]]&gt;&lt;/script&gt;&lt;br /&gt;Next you need to map the URL Rewrite filter and your Spring Dispatcher servlet in your web.xml:&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: xml"&gt;&lt;![CDATA[&lt;filter&gt;    &lt;filter-name&gt;UrlRewriteFilter&lt;/filter-name&gt;    &lt;filter-class&gt;org.tuckey.web.filters.urlrewrite.UrlRewriteFilter&lt;/filter-class&gt;&lt;/filter&gt;&lt;filter-mapping&gt;    &lt;filter-name&gt;UrlRewriteFilter&lt;/filter-name&gt;    &lt;url-pattern&gt;/*&lt;/url-pattern&gt;&lt;/filter-mapping&gt;        &lt;context-param&gt;    &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;&lt;param-value&gt;/WEB-INF/applicationContext.xml&lt;/param-value&gt;&lt;/context-param&gt;&lt;listener&gt;    &lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;&lt;/listener&gt;&lt;servlet&gt;    &lt;servlet-name&gt;dispatcher&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;    &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;&lt;/servlet&gt;&lt;servlet-mapping&gt;    &lt;servlet-name&gt;dispatcher&lt;/servlet-name&gt;    &lt;url-pattern&gt;/web/*&lt;/url-pattern&gt;&lt;/servlet-mapping&gt;]]&gt;&lt;/script&gt;&lt;br /&gt;Then in src/main/webapp/WEB-INF you need to define a urlrewrite.xml. This file defines the filters for your webapp. For my app, I keep all JSP files under WEB-INF/jsp and use Spring's InternalResourceViewResolver to forward to them. This is great, except since my filter takes all request, I have to supply rules for the static files like html, javascript, css, images etc.&lt;br /&gt;&lt;br /&gt;Here's how you do that. In urlrewrite.xml add the following:&lt;br /&gt;&lt;script type="syntaxhighlighter" class="brush: xml"&gt;&lt;![CDATA[&lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.0//EN" "urlrewrite3.0.dtd"&gt;&lt;urlrewrite default-match-type="wildcard"&gt; &lt;rule&gt;  &lt;from&gt;/images/**&lt;/from&gt;  &lt;to&gt;/images/$1&lt;/to&gt; &lt;/rule&gt; &lt;rule&gt;  &lt;from&gt;/js/**&lt;/from&gt;  &lt;to&gt;/js/$1&lt;/to&gt; &lt;/rule&gt; &lt;rule&gt;  &lt;from&gt;/css/**&lt;/from&gt;  &lt;to&gt;/css/$1&lt;/to&gt; &lt;/rule&gt;        &lt;rule&gt;            &lt;from&gt;/html/**&lt;/from&gt;            &lt;to&gt;/html/$1&lt;/to&gt;        &lt;/rule&gt; &lt;rule&gt;  &lt;from&gt;/**&lt;/from&gt;  &lt;to&gt;/web/$1&lt;/to&gt; &lt;/rule&gt; &lt;outbound-rule&gt;  &lt;from&gt;/web/**&lt;/from&gt;  &lt;to&gt;/$1&lt;/to&gt; &lt;/outbound-rule&gt;&lt;/urlrewrite&gt;]]&gt;&lt;/script&gt;&lt;br /&gt;That's it, URL rewriting is enabled on your app. Now anytime someone hits a URL in your app like http://[server]:[port]/[context-root]/[controller]/[action] (depending on which &lt;a href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-handlermapping"&gt;HandlerMapping&lt;/a&gt; you use) the filter will forward the request to the dispatcher servlet and your appropriate controller. For anything that goes to /images /js /css or /html, they will be forwarded to those resources.&lt;br /&gt;&lt;br /&gt;I hope this is helpful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4081042681428327092-5556897792903605504?l=mattgivney.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattgivney.blogspot.com/feeds/5556897792903605504/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mattgivney.blogspot.com/2010/07/how-to-url-rewrite-in-spring-mvc.html#comment-form' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4081042681428327092/posts/default/5556897792903605504'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4081042681428327092/posts/default/5556897792903605504'/><link rel='alternate' type='text/html' href='http://mattgivney.blogspot.com/2010/07/how-to-url-rewrite-in-spring-mvc.html' title='How to URL Rewrite in Spring MVC'/><author><name>Matt Givney</name><uri>http://www.blogger.com/profile/01367149444779607020</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://1.bp.blogspot.com/__V-Zstazg88/SwMCHR4y2kI/AAAAAAAAAB8/k4dckOVm-KE/S220/me.jpg'/></author><thr:total>9</thr:total></entry></feed>
