Search code examples
javaspringspring-booturl-rewritingtomcat8

How do I add Tomcat rewrite valve to Spring Boot 2.0 application


I am trying to make use of Tomcat's rewrite valve in my Spring Boot app however cannot determine where to put the rewrite.conf in order to be loaded successfully.

I am using Spring Boot 2.0.3.RELEASE with Tomcat 8.5.31 and packaging the application as a fat jar.

I have configured the rewrite valve like so:

@Bean
public TomcatServletWebServerFactory containerFactory() {
    TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
    factory.addContextValves(new RewriteValve());

    return factory;
}

However, it appears to rely on a directory structure of /WEB-INF to load the rewrite.conf from, which being a fat jar, I don't currently have.

Has anybody found a solution to configure this without changing the application packaging structure to a WAR with a WEB-INF directory?


Solution

  • With spring boot 2 and tomcat embedded.

    First create rewrite.config file under resources directory like this resources/rewrite.config. This rule example for run routing react in my server side (react needs to redirect all routes to index.html)

    RewriteCond %{REQUEST_URI} !^.*\.(bmp|css|gif|htc|html?|ico|jpe?g|js|pdf|png|swf|txt|xml|svg|eot|woff|woff2|ttf|map)$
    RewriteRule ^(.*)$ /index.html [L]
    

    then create your own custom class for configure tomcat server like this:

    @Component
    public class CustomContainer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
    
        @Override
        public void customize(TomcatServletWebServerFactory factory) {
    
            final RewriteValve valve = new RewriteValve() {
    
                @Override
                protected synchronized void startInternal() throws LifecycleException {
                    super.startInternal();
    
                    try {
                        InputStream resource = new ClassPathResource("rewrite.config").getInputStream();
    
                        InputStreamReader resourceReader = new InputStreamReader(resource);
                        BufferedReader buffer = new BufferedReader(resourceReader);
    
                        parse(buffer);
    
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            };
    
            valve.setEnabled(true);
    
            factory.addContextValves(valve);
        }
    } 
    

    This custom class overrides starInternal method to implement how to retrieve the config file for parsing it and add that valve in context valves.

    This work fine for me :)