ZetCode

Introduction to Spring web applications

last modified July 13, 2020

In this tutorial, we are going to create simple web applications in Spring. Three web applications are created; each of the applications is configured in a different way.

In our Spring web applications, we use Spring 5 and Thymeleaf 3.

Spring is a popular Java application framework. Spring Boot is an effort to create stand-alone, production-grade Spring based applications with minimal effort.

There are three basic approaches to configure a Spring web application:

Traditionally, Spring has used XML files to configure applications. Later, a new approach was created where the configuration is done in the Java configuration classes. Spring Boot autoconfiguration magic is the latest approach to configure Spring web applications.

Spring web application configuration with XML

In the first example, we create a Spring web application configured in XML files.

pom.mxl
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           └───controller
│   │                   HomeController.java
│   ├───resources
│   └───webapp
│       │   index.html
│       └───WEB-INF
│           │   spring-servlet.xml
│           │   web.xml
│           └───templates
│                   showMessage.html
└───test
    └───java

This is the project structure.

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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.zetcode</groupId>
    <artifactId>springwebfirst</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.25</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>        

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
            <version>3.0.11.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf</artifactId>
            <version>3.0.11.RELEASE</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>

        </plugins>
    </build>

</project>

This is the Maven build file. We have the following dependencies: slf4j-api, and slf4j-simple for logging, javax.servlet-api for Java Servlet technology, thymeleaf-spring5 and thymeleaf for the Thymeleaf template engine, and spring-webmvc for creating Spring Web MVC applications.

The maven-war-plugin creates web archives (WAR).

WEB-INF/spring-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context.xsd 
    http://www.springframework.org/schema/mvc 
    http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.zetcode"/>
    <mvc:annotation-driven/>
    <mvc:default-servlet-handler/>

    <bean id="templateResolver" 
            class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
        <property name="prefix" value="/WEB-INF/templates/"/>
        <property name="suffix" value=".html"/>
        <property name="templateMode" value="HTML"/>
    </bean>

    <bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
        <property name="templateEngine" ref="templateEngine"/>
    </bean>

    <bean id="templateEngine" class="org.thymeleaf.spring5.SpringTemplateEngine">
        <property name="templateResolver" ref="templateResolver"/>
    </bean>

</beans>

The spring-servlet.xml configures the Spring web application. It enables component scanning, Spring web annotations (@Controller) and configures the Thymeleaf template.

<context:component-scan base-package="com.zetcode" />

This tells Spring where to look for classes with @Controller, @Repository, @Service, @Component annotations and register them. In our case, we have a controller with the @Controller annotation.

<mvc:annotation-driven/>

The <mvc:annotation-driven/> enables web based Spring annotations.

<mvc:default-servlet-handler/>

We need this tag to enable static HTML files. We have one static index.html for the home page.

<bean id="templateResolver" 
        class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
    <property name="prefix" value="/WEB-INF/templates/"/>
    <property name="suffix" value=".html"/>
    <property name="templateMode" value="HTML"/>
</bean>

<bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
    <property name="templateEngine" ref="templateEngine"/>
</bean>

<bean id="templateEngine" class="org.thymeleaf.spring5.SpringTemplateEngine">
    <property name="templateResolver" ref="templateResolver"/>
</bean>

These lines configure Thymeleaf with a template engine, template view resolver, and a template resolver. In the template resolver we specify where the templates are located and their extensions.

WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
            http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
            version="4.0">
    
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>      
    
    <servlet>
        <servlet-name>spring</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>    
    
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
</web-app>

In the web.xml file, we set up the Spring DispatcherServlet and choose the welcome file. The DispatcherServlet is the Spring's front controller. The servlet is mapped to the URL having *.html extension.

com/zetcode/controller/HomeController.java
package com.zetcode.controller;

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

@Controller
public class HomeController {

    @GetMapping("/message")
    public String message() {

        return "showMessage";
    }
}

HTTP requests are handled by a controller. It prepares a model and returns a view. The returned showMessage string is mapped to the showMessage.html file located in the WEB-INF/templates/ directory.

WEB-INF/templates/showMessage.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Message</title>
</head>
<body>

<p>
    Hello there
</p>

</body>
</html>

The showMessage.html file displays a message.

index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
</head>
<body>
<p>
    <a href="message">Show message</a>
</p>
</body>
</html>

The index.html is a home page. It contains a link.

Spring web application configuration with Java config

In the second example, we create a Spring web application configured in Java config classes. In this example, web.xml and spring-servlet.xml are replaced with MyWebInitializer.java and WebConfig.java.

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           ├───config
│   │           │       MyWebInitializer.java
│   │           │       WebConfig.java
│   │           └───controller
│   │                   MyController.java
│   ├───resources
│   └───webapp
│       └───WEB-INF
│           └───templates
│                   index.html
│                   showMessage.html
└───test
    └───java

This is the project structure. The pom.xml file is the same as in the first example.

com/zetcode/config/WebConfig.java
package com.zetcode.config;

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.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public SpringResourceTemplateResolver templateResolver() {

        var templateResolver = new SpringResourceTemplateResolver();

        templateResolver.setApplicationContext(applicationContext);
        templateResolver.setPrefix("/WEB-INF/templates/");
        templateResolver.setSuffix(".html");

        return templateResolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine() {

        var templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver());
        templateEngine.setEnableSpringELCompiler(true);

        return templateEngine;
    }

    @Bean
    public ViewResolver viewResolver() {

        var resolver = new ThymeleafViewResolver();
        var registry = new ViewResolverRegistry(null, applicationContext);

        resolver.setTemplateEngine(templateEngine());
        registry.viewResolver(resolver);

        return resolver;
    }
}

The WebConfig.java is used instead of the spring-servlet.xml file. In the WebConfig, we enable Spring web annotations with @EnableWebMvc, enable component scanning with @ComponentScan and configure the Thymeleaf template engine.

com/zetcode/config/MyWebInitializer.java
package com.zetcode.config;

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

public class MyWebInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

The MyWebInitializer class is used instead of the web.xml file. We specify the name of the servlet configuration class.

com/zetcode/controller/MyController.java
package com.zetcode.controller;

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

@Controller
public class MyController {

    @GetMapping("/")
    public String index() {
        return "index";
    }

    @GetMapping("/message")
    public String message() {
        return "showMessage";
    }
}

This is the controller. We have mappings for the home page and for a showMessage page.

WEB-INF/templates/showMessage.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Message</title>
</head>
<body>
<p>Today is a sunny day!</p>
</body>
</html>

The showMessage.html file displays a message.

WEB-INF/templates/index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
</head>
<body>
<p>
    <a href="message.html">Show message</a>
</p>
</body>
</html>

The index.html is a home page. It contains a link.

Spring Boot web application

In the third example, we create a web application with Spring Boot. Spring Boot uses a different default approach. It uses JAR archives with an embedded web server.

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           └───controller
│   │                   MyController.java
│   └───resources
│       │   application.properties
│       ├───static
│       │       index.html
│       └───templates
│               showMessage.html
└───test
    └───java

This is the project structure.

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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.zetcode</groupId>
    <artifactId>springbootwebfirst</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.0.RELEASE</version>
    </parent>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

This is the Maven build file. The spring-boot-starter-web is a starter POM for building web, including RESTful, applications using Spring MVC. The spring-boot-starter-thymeleaf is a starter POM for Thymeleaf template engine.

Note that the packaging is set to JAR.

com/zetcode/controller/MyController.java
package com.zetcode.controller;

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

@Controller
public class MyController {

    @GetMapping("/message")
    public String message() {

        return "showMessage";
    }
}

This is the controller class for the Spring Boot web application. A controller is decorated with the @Controller annotation. The controller has one mapping. The mapping resolves to the showMessage.html template, which is located in the WEB-INF/templates directory.

com/zetcode/Application.java
package com.zetcode;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

The Application sets up the Spring Boot application.

WEB-INF/templates/showMessage.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Message</title>
</head>
<body>
<p>Today is a cold day</p>
</body>
</html>

The showMessage.html shows a simple message.

WEB-INF/static/index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Home page</title>
</head>
<body>
<p>
    <a href="message">Show message</a>
</p>
</body>
</html>

The index.html is the home page of the application containing a link. Static resources such as plain HTML files are put into static directory.

In this tutorial, we have created our first Spring web application.