8 min read

In this article by Alex Antonov, the author of the book Spring Boot Cookbook – Second Edition, learn to use and configure spring resources and build your own Spring-based application using Spring Boot.

In this article, you will learn about the following topics:

  • Configuring route matching patterns
  • Configuring custom static path mappings
  • Adding custom connectors

(For more resources related to this topic, see here.)

Introduction

We will look into enhancing our web application by doing behavior tuning, configuring the custom routing rules and patterns, adding additional static asset paths, and adding and modifying servlet container connectors and other properties, such as enabling SSL.

Configuring route matching patterns

When we build web applications, it is not always the case that a default, out-of-the-box, mapping configuration is applicable. At times, we want to create our RESTful URLs that contain characters such as . (dot), which Spring treats as a delimiter defining format, like path.xml, or we might not want to recognize a trailing slash, and so on. Conveniently, Spring provides us with a way to get this accomplished with ease.

Let’s imagine that the ISBN format does allow the use of dots to separate the book number from the revision with a pattern looking like [isbn-number].[revision].

How to do it…

We will configure our application to not use the suffix pattern match of .* and not to strip the values after the dot when parsing the parameters. Let’s perform the following steps:

  1. Let’s add the necessary configuration to our WebConfiguration class with the following content:
    @Override
    public void
      configurePathMatch(PathMatchConfigurer configurer) {
      configurer.setUseSuffixPatternMatch(false).
        setUseTrailingSlashMatch(true);
    }
    
  2. Start the application by running ./gradlew clean bootRun.
  3. Let’s open http://localhost:8080/books/978-1-78528-415-1.1 in the browser to see the following results:

  4. If we enter the correct ISBN, we will see a different result, as shown in the following screenshot:

How it works…

Let’s look at what we did in detail. The configurePathMatch(PathMatchConfigurer configurer) method gives us an ability to set our own behavior in how we want Spring to match the request URL path to the controller parameters:

  • configurer.setUseSuffixPatternMatch(false): This method indicates that we don’t want to use the .* suffix so as to strip the trailing characters after the last dot. This translates into Spring parsing out 978-1-78528-415-1.1 as an {isbn} parameter for BookController. So, http://localhost:8080/books/978-1-78528-415-1.1 and http://localhost:8080/books/978-1-78528-415-1 will become different URLs.
  • configurer.setUseTrailingSlashMatch(true): This method indicates that we want to use the trailing / in the URL as a match, as if it were not there. This effectively makes http://localhost:8080/books/978-1-78528-415-1 the same as http://localhost:8080/books/978-1-78528-415-1/.

If you want to do further configuration on how the path matching takes place, you can provide your own implementation of PathMatcher and UrlPathHelper, but these will be required in the most extreme and custom-tailored situations and are not generally recommended.

Configuring custom static path mappings

It is possible to control how our web application deals with static assets and the files that exist on the filesystem or are bundled in the deployable archive.

Let’s say that we want to expose our internal application.properties file via the static web URL of http://localhost:8080/internal/application.properties from our application. To get started with this, proceed with the steps in the next section.

How to do it…

  1. Let’s add a new method, addResourceHandlers, to the WebConfiguration class with the following content:
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/internal/**").addResourceLocations("classpath:/");
    }
  2. Start the application by running ./gradlew clean bootRun.
  3. Let’s open http://localhost:8080/internal/application.properties in the browser to see the following results:

How it works…

The method that we overrode, addResourceHandlers(ResourceHandlerRegistry registry), is another configuration method from WebMvcConfigurer, which gives us an ability to define custom mappings for static resource URLs and connect them with the resources on the filesystem or application classpath. In our case, we defined a mapping of anything that is being accessed via the / internal URL to be looked for in classpath:/ of our application. (For production environment, you probably don’t want to expose the entire classpath as a static resource!) So, let’s take a detailed look at what we did, as follows:

  • registry.addResourceHandler(“/internal/**”): This method adds a resource handler to the registry to handle our static resources, and it returns ResourceHandlerRegistration to us, which can be used to further configure the mapping in a chained fashion. /internal/** is a path pattern that will be used to match against the request URL using PathMatcher. We have seen how PathMatcher can be configured in the previous example but, by default, an AntPathMatcher implementation is used. We can configure more than one URL pattern to be matched to a particular resource location.
  • addResourceLocations(“classpath:/”):This method is called on the newly created instance of ResourceHandlerRegistration, and it defines the directories where the resources should be loaded from. These should be valid filesystems or classpath directories, and there can be more than one entered. If multiple locations are provided, they will be checked in the order in which they were entered.
  • setCachePeriod (Integer cachePeriod): Using this method, we can also configure a caching interval for the given resource by adding custom connectors.

Another very common scenario in the enterprise application development and deployment is to run the application with two separate HTTP port connectors: one for HTTP and the other for HTTPS.

Adding custom connectors

Another very common scenario in the enterprise application development and deployment is to run the application with two separate HTTP port connectors: one for HTTP and the other for HTTPS.

Getting ready

For this recipe, we will undo the changes that we implemented in the previous example. In order to create an HTTPS connector, we will need a few things; but, most importantly, we will need to generate a certificate keystore that is used to encrypt and decrypt the SSL communication with the browser.

If you are using Unix or Mac, you can do it by running the following command:

$JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA

On Windows, this can be achieved via the following code:

"%JAVA_HOME%binkeytool" -genkey -alias tomcat -keyalg RSA

During the creation of the keystore, you should enter the information that is appropriate to you, including passwords, name, and so on. For the purpose of this book, we will use the default password: changeit. Once the execution is complete, a newly generated keystore file will appear in your home directory under the name .keystore.

You can find more information about preparing the certificate keystore at https://tomcat.apache.org/tomcat-8.0-doc/ssl-howto.html#Prepare_the_Certificate_Keystore.

How to do it…

With the keystore creation complete, we will need to create a separate properties file in order to store our configuration for the HTTPS connector, such as port and others. After that, we will create a configuration property binding object and use it to configure our new connector. Perform the following steps:

  1. First, we will create a new properties file named tomcat.https.properties in the src/main/resources directory from the root of our project with the following content:
    custom.tomcat.https.port=8443
    custom.tomcat.https.secure=true
    custom.tomcat.https.scheme=https
    custom.tomcat.https.ssl=true
    custom.tomcat.https.keystore=${user.home}/.keystore
    custom.tomcat.https.keystore-password=changeit
  2. Next, we will create a nested static class named TomcatSslConnectorProperties in our WebConfiguration, with the following content:
    @ConfigurationProperties(prefix = "custom.tomcat.https")
    public static class TomcatSslConnectorProperties {
      private Integer port;
      private Boolean ssl= true;
      private Boolean secure = true;
      private String scheme = "https";
      private File keystore;
      private String keystorePassword;
      //Skipping getters and setters to save space, but we do need them
    
      public void configureConnector(Connector connector) {
        if (port != null)
          connector.setPort(port);
        if (secure != null)
          connector.setSecure(secure);
        if (scheme != null)
          connector.setScheme(scheme);
        if (ssl!= null)
          connector.setProperty("SSLEnabled", ssl.toString());
        if (keystore!= null &&keystore.exists()) {
          connector.setProperty("keystoreFile", 
            keystore.getAbsolutePath());
          connector.setProperty("keystorePassword",         keystorePassword);
        }
      }
    }
  3. Now, we will need to add our newly created tomcat.http.properties file as a Spring Boot property source and enable TomcatSslConnectorProperties to be bound. This can be done by adding the following code right above the class declaration of the WebConfiguration class:
    @Configuration
    @PropertySource("classpath:/tomcat.https.properties")
    @EnableConfigurationProperties(WebConfiguration.TomcatSslConnectorProperties.class)
    public class WebConfiguration extends 
      WebMvcConfigurerAdapter {...}
  4. Finally, we will need to create an EmbeddedServletContainerFactory Spring bean where we will add our HTTPS connector. We will do that by adding the following code to the WebConfiguration class:
    @Bean
    public EmbeddedServletContainerFactory servletContainer(TomcatSslConnectorProperties properties) {
      TomcatEmbeddedServletContainerFactory tomcat = new 
        TomcatEmbeddedServletContainerFactory();
        tomcat.addAdditionalTomcatConnectors(
            createSslConnector(properties));
        return tomcat;
      }
    
    private Connector 
      createSslConnector(TomcatSslConnectorProperties 
        properties) {
        Connector connector = new Connector();
        properties.configureConnector(connector);
        return connector;
    }
  5. Start the application by running ./gradlew clean bootRun.
  6. Let’s open https://localhost:8443/internal/tomcat.https.properties in the browser to see the following results:

Summary

In this article, you learned how to fine-tune the behavior of a web application. This article has given a small gist about custom routes, asset paths, and amending routing patterns. You also learned how to add more connectors to the servlet container.

Resources for Article:


Further resources on this subject:


LEAVE A REPLY

Please enter your comment!
Please enter your name here