Something I always end up needing to reference is building a new application from scratch. It seems like it’s just not something I ever need to do that often. So here is a guide on how to get a very basic “Hello World!” Spring 4 application with a Thymeleaf view resolver with absolutely no XML.

The Source

First things first, I put the source used in the examples together in a Github repository.

https://github.com/kgengler/basic-spring-web-application

If you just want to start with that, all you need to do is clone the repository and build with your preferred tool. I’ve included configurations for both Maven, and Gradle.

The Container

It seems like every guide I find on the Internet nowadays for spring ALWAYS uses Spring Boot. While Spring Boot is a great project, some of use still deploy to application containers like Wildfly or tc Server. I still like to use Tomcat for basic things. Basically, pick your poison and make sure you have it set up and running according to your given application server’s installation instructions.

The Build Tool

Gradle seems to be really popular now, but I seem to always reach for Maven still. Either way, I’ve detailed both below as it doesn’t really matter.

Maven

Maven uses an XML configuration to set up the project. In your project directory, create a file pom.xml. Put the following configuration in your pom.xml file.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.kylegengler</groupId>
    <artifactId>BasicWebApp</artifactId>
    <version>1.0.0</version>
    
    <!-- Tell maven to build this as a war -->
    <packaging>war</packaging>

    <build>

        <!-- Set the final artifact name of the project -->
        <finalName>${project.artifactId}</finalName>
        <plugins>

            <!-- Allow the build to pass without a web.xml -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>

            <!-- Compile for Java 8 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <!-- Project Dependencies -->
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring4</artifactId>
            <version>3.0.3.RELEASE</version>
        </dependency>
    </dependencies>
</project>

To build the project you will run

mvn clean package

The resulting file will be the target/BasicWebApp.war

Gradle

Gradle uses Groovy to write its configuration. In your project root directory, create a file build.gradle. Use the below configuration

// Build a war
apply plugin: 'war'

group = 'com.kylegengler'
version = '1.0.0'

description = "A Basic Spring Application"

// Build for Java 8
sourceCompatibility = 1.8
targetCompatibility = 1.8

// Set the final name for the artifact
war {
    archiveName 'BasicWebApp.war'
}

repositories {
     mavenCentral()
}

// Declare the project dependencies
dependencies {
    compile group: 'org.springframework', name: 'spring-webmvc', version:'4.3.6.RELEASE'
    compile group: 'org.thymeleaf', name: 'thymeleaf-spring4', version:'3.0.3.RELEASE'
}

To build the application you will run:

gradle clean war

The resulting file will be available at build/libs/BasicWebApp.war.

The Web App Configuration

Traditionally Java applications will use a web.xml for their configuration. Now with servlet 3.0+ environments, we can write out the configuration in Java.

package com.kylegengler.basic;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

/**
 * This class configures the web application. This replaces the traditional
 * web.xml file in servlet 3.0+ environments.
 * 
 * @author kyle
 */
public class WebApplicationConfiguration extends AbstractAnnotationConfigDispatcherServletInitializer {

    /**
     * Specify the root configuration classes. This is used for the business
     * logic, and persistence classes. Since this application is just a basic
     * "Hello World!" application, we'll be omitting it here.
     */
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    /**
     * Configuration classes for the servlet environment. This would include the
     * Controllers and view resolvers.
     */
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { ServletConfiguration.class };
    }

    /**
     * Specify the url mappings that will be handled by the servlet.
     */
    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}

The magic here is that by extending the AbstractAnnotationConfigDispatcherServletInitializer class, this file will be picked up automatically by the Servlet contatiner and used to initialize the application.

The Servlet Configuration

Here is where we configure the Spring Dispatcher Servlet. This is also where you would configure the controllers, and view resolvers.

package com.kylegengler.basic;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.thymeleaf.spring4.SpringTemplateEngine;
import org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring4.view.ThymeleafViewResolver;
import org.thymeleaf.templatemode.TemplateMode;

/**
 * Configure the Spring dispatcher servlet
 * 
 * The configuration annotation designates this as a Spring configuration.
 * EnableWebMvc - tells spring to import and set up any configuration needed for
 * the controllers and any other mvc components. ComponentScan - Tells spring
 * the base package(s) to scan on the classpath for any spring @Components, or
 * any of its derivitives such as @Service, @Controller, or @Repository
 *
 * This file will specify any @Beans that need to be managed by the Spring IoC
 * container for Dependency Injection
 *
 * @author kyle
 */
@Configuration
@EnableWebMvc
@ComponentScan({ "com.kylegengler" })
public class ServletConfiguration extends WebMvcConfigurerAdapter {

    @Autowired
    private ApplicationContext ctx;

    /**
     * Set up the template resolver. This will look for templates in the
     * /WEB-INF/templates directory, ending with html. This is used to find the
     * template files needed to generate the view
     */
    @Bean
    public SpringResourceTemplateResolver templateResolver() {
        SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
        templateResolver.setApplicationContext(ctx);
        templateResolver.setPrefix("/WEB-INF/templates/");
        templateResolver.setSuffix(".html");
        templateResolver.setTemplateMode(TemplateMode.HTML);
        templateResolver.setCacheable(true);
        return templateResolver;
    }

    /**
     * The engine used to render the view using the template file and model.
     */
    @Bean
    public SpringTemplateEngine templateEngine() {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver());
        templateEngine.setEnableSpringELCompiler(true);
        return templateEngine;
    }

    /**
     * The view resolver receives the name of the view, and is responsible for
     * creating the corresponding View object to go with that view. It ties
     * together the Controller logic and template engine.
     */
    @Bean
    public ThymeleafViewResolver viewResolver() {
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setTemplateEngine(templateEngine());
        return viewResolver;
    }

}

The Controller

This is where we create a basic Controller that will be picked up by Spring’s classpath scanning, and managed by the IoC container.

package com.kylegengler.basic;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * Set up a simple controller for the application
 * 
 * @author kyle
 */
@Controller
public class IndexController {

    /**
     * This will use the template at /WEB-INF/templates/index.html for the root
     * and /home url paths.
     */
    @RequestMapping({ "/", "/home" })
    public String getIndex() {
        return "index";
    }
}

The Template

Now we just need to create the template file that will be used by Thymeleaf to generate the view. As shown in the controller, this will use the /WEB-INF/templates/index.html file.

<!DOCTYPE html>
<html>
<head>
    <title>Hello World!</title>
</head>
<body>
    <h1>Hello World!</h1>
    <p th:text="${#dates.format(#dates.createNow(), 'dd MMM yyyy HH:mm')}">Current Timestamp</p>
</body>
</html>

The Deployment

Build the application using your preferred build tool and deploy the resulting war to the application server. For Tomcat, you can just copy it into the webapps directory. Once the application is deployed you can hit the / or /home paths of the servlet. For Tomcat this might be http://localhost:8080/BasicWebApp/.

And you should see:

Basic Web App Home