, , ,

This is the 4th part of my tutorial series on building a web application using Spring Boot.  In the the last part of the series, we looked at setting up Spring Data JPA for database persistence. In the second part of the series we looked at using Thymeleaf for building the web pages. And we started off in the first part looking at using the Spring Initializr to start our Spring Boot project.

In this part of the series, we tie everything together to provide a working Spring Boot web application. An application which will display data from the database, and allow you to create new records, update existing records, and delete selected records too.

Spring MVC

In this part of my tutorial series for Spring Boot, we’re going to look at setting up a Spring MVC controller to support CRUD operations against the database.

MVC stands for Model, View, Controller. The MVC design pattern is probably the most popular design pattern used when writing code to generate dynamic web content. This design pattern is not limited to Java nor Spring. The MVC design pattern has been applied in Javascript, PHP, .NET, Python, and many other programming languages. The MVC pattern is popular because it does a great job of separating concerns, and leads you to a clean, maintainable, and easy to understand code base.

MVC Overview


Model refers to a data model, or some type of data structure. For example a web page showing a list of products, the ‘model’ would contain a list of product data.


The view layer, in Java frequently a JSP. This will take data from the Model and render the view.


I like to describe the controller as a traffic cop. It will take an incoming request, decide what to do with it, then direct the resulting action. For example, the controller could get a view product request. It will direct a service to get the product data, then direct to the product view and provide the ‘model’ (product data) to the view.

Single Responsibility Principle Applied to MVC

Frequently when dealing with legacy code, I see a lot of leakage between the layers. JSP pages making database calls. Controllers building database connection pools. On one legacy application I recently worked with the JSP pages and controllers were littered with static method calls, which ultimately made a call to an Oracle database. Because of this, the application was impossible to run outside of the application server. The code was so tightly coupled, there were no unit tests in what is a very large code case. Why? You can’t run any of the code under JUnit because of all the embedded static method calls.

In an MVC application each component has a specific function in life. You should be able to unit test your controllers. Using Mocks, you should be able to unit test that your controller returns the proper model, and makes the proper decisions.

CRUD Operations with Spring MVC

CRUD is a common acronym for Create, Read, Update, and Delete. In the last part of the series, we looked at creating a CRUD repository using Spring Data JPA. In this post, we’ll look at setting up the Spring MVC controller for the corresponding CRUD operations. We’ll continue using the Product class we previously used.


The Create operation is a two step operation. The first step needs to display the create form, the second needs to do the save of the form post.

Here is the controller code for displaying the create product form.

The @RequestMapping  annotation maps the url ‘product/new’ to this controller action. Our controller method is taking in the model attribute. This is the ‘model’ being returned to the view layer.

You can see in the code, we are returning an empty product class to the view. This is more of a trick to re-use the view code for both the Create and Update form. By providing a empty Product object, we reduce the likelihood of null pointer errors when rendering the view. You can either provide an empty object to the model, or do a lot of null checking in the view. From experience, I’ve found this simpler.

Our create view is going to have a form post. We need a controller action to handle this.

In this controller method, we’re handing the form post. The @RequestMapping annotation says to take the ‘url’ ‘product’ and the HTTP request method of POST to map it to this controller method. You can see how we’re asking for a Product object as input to the controller method. One of the cool things about Spring MVC is that it will take your form parameters and automatically bind them to a Product object. The object is automatically created and passed into your controller method. The Spring Framework saves you from the mundane work of parsing out HTTP request parameters.

You can see how we’re using a product service to handle the persistence. This is just a facade to the Spring Data JPA repository we created in the last post. I’m going to skip over the persistence code here. You’ll be able to find it in github. I want you to notice how I’m writing to an interface. The controller doesn’t know about persistence. It does not need to. Storing data is not the job of the controller. Maybe that method is using JDBC. Maybe it is calling a web service. Maybe it’s using JMS. Might be using AQMP. The controller does not care. The controller code does not need to care. This is a great example of decoupling code. Too often I see legacy code where the controllers are doing way too much.

On the last line of the saveProduct method, you can see I’m returning a string with “redirect”. This tells Spring after the save action to redirect to the view to show the created item. This example just show the ‘happy path’ – where everything happens as it should. In a more robust controller you’d have logic not only for the happy path, but to redirect to the create form if validations were to fail.


In Read operations, the client is going to tell you what it wants. In our case, the client will give us an Id value, and we’ll return the corresponding Product.

Read by Id

You can see in our controller method, the Request Mapping is using ‘product’ with a id value in squigglies. This identifies that portion of the url path as an ‘id; value.

Now, we’re using a new annotation @Pathvariable to inject the id value from the url path into our controller as the ID variable. Again, we’re accepting the model variable into our controller. We’re asking the product service to get the product, and the result is appended to the model object, which is returned to the view. The controller method returns a string to indicate which view to render.

List All

A common method is also to provide a list view. Normally, you’re going to want to add paging or some type of filter. However, in this example, we just want to show a simple example of listing products from the database.

We’ve mapped this controller method to the URL ‘/products’. We ask the product service for a list of all products and append it to the model attribute “products”. The controller method returns the string ‘products’ to tell Spring MVC to render the products view.


Updates are actions against existing entities. Updates are similar to create actions, where we have two controller actions involved. With a create, we’re showing a form for a new item, while an update is going to be populated with data from an existing item. While this is very similar to the create action, we typically will want a separate controller action to show the edit form to capture the data for the update.

The good news, functionally the save and view of the saved item is the same as the create action.

Here is our save method once more:

You can see we’re using Spring to bind the form post parameters to a Product object, then calling the product service to save the item. Then just like in the save method of the create process, we want to view the saved product, so we redirect to the show product view.


There’s a few different ways to implement a delete action. One of the easiest is to use a url with the ID for the delete action. This can then be implemented on the web forms as a simple URL to click on. Below is the controller action for the delete action.

This method will take in the id value from the URL and pass it to the delete method of the product service. Since we’re not creating or updating a product, a typical course of action is to return to the list view. In this example, we redirect to the products view to show the user a list of products.

Summary of CRUD Operations

At this point we’ve covered the necessary controller actions to support CRUD operations on an entity. You can see these operations work in conjunction with the Spring Data JPA methods we looked at in the previous post on Spring Data JPA. I’m using a Facade Service to mask the Spring Data JPA implementation. We’ll take a look at the Facade in the next section.

Spring Framework 5
Become a Spring Framework Guru! Click Here to learn more about my online course Spring Framework 5: Beginner to Guru!

Spring Facade Service

You can see in the controller methods above, there is no dependency on the persistence layer. The controller is completely unaware of how data is being persisted. This is exactly as it should be. Too often I see legacy code where the controller is interacting with the database directly. This is a very poor coding practice. It makes your code tightly coupled and hard to maintain.

Code to an Interface

When using Spring to develop applications it is always best to develop to an interface, especially when leveraging the benefits of dependency injection.  To support our controller actions, I wrote the following interface.


Notice how this interface is rather generic? Can you tell how data is being persisted? JDBC? Spring Data JPA? Web Service? JMS? This is what decoupling is about. At this point, the answer is all of the above. We just need to provide the appropriate implementation.

Spring Data JPA Product Service Implementation

In the last post of this series, we looked at using Spring Data JPA. Now we need an implementation of the Product Service which will use the Spring Data JPA repositories.

Spring Data JPA Repository

We’ll need to inject an instance of the Spring Data JPA repository into the implementation of our product service. You can do so by declaring a property for the repository and annotating the setter method with the @Autowired  annotation.

List Products

Using Spring Data JPA, it becomes trivial to list all the products for our application. While we did not actually create a findAll()  method on the repository we defined, we inherited by extending the CrudRepository  in Spring Data JPA. This is one of many handy features of Spring Data JPA. It’s going to provide us an implementation of the findAll()  method, which we do not need to write code for.

Get Product (Read)

To fetch a product by its id value, again, we can leverage a method implemented for us by Spring Data JPA.

Save Product (Create / Update)

Spring Data JPA also provides us an implementation of a save method for saving entities. We use this method in creating and updating products in our web application.

Delete Product (Delete)

Finally, in our CRUD operations, Spring Data JPA provides us an implementation of a delete method. Spring Data JPA overloads the delete method, accepting just the ID value, or the entity itself. For our purposes, we are using the ID value to delete the desired entity.

Summary of Spring Data JPA Usage

In this example, we implemented the CRUD operations using a CrudRepository supplied by Spring Data JPA. If you look at the code you will see all we did was extend the Spring Data JPA CrudRepository to create our Product Repository. We did not define, nor implement an additional methods. We’re not declaring transactions. We’re not writing any SQL. I hope you can see the simplicity and time saving using tools like Spring Data JPA can bring you.


Thymeleaf Fragments

Thymeleaf fragments are a very powerful feature of Thymeleaf. They allow you to define repeatable chunks of code for your website. Once you define a Thymeleaf fragment, you can reuse it in other Thymeleaf templates. This works great for components you wish to reuse across your web pages.

In developing the Spring Boot Web Application, I found two uses for Thymeleaf templates. The first was common includes of the CSS, Javascript. The second was for a common menu I wanted to display at the top of each web page.


Below is the Thymeleaf Fragment I’m using for the HTML header includes. You can see its a normal HTML document, using Thymeleaf tags to define the resources for a page.



For our Spring Boot Web Application, I chose to use the Bootstrap CSS framework. I’m big fan of Bootstrap. It’s easy to use, and its components look great. Bootstrap CSS has a menu component which I chose to use for the menu system.

In this Thymeleaf fragment, I’m providing the Bootstrap CSS menu I want to place at the top of all my pages. I also have a section to show my Spring Boot logo on each page.


Including Thymeleaf Fragments


Previously, we defined an index page for our Spring Boot web application. You can apply Thymeleaf templates through the use of HTML comments. By doing this, you preserve the ability of the document to be viewed in the browser. You will be able to see the document okay in your browser, but the fragment portions will be omitted. The fragments are only included when the Thymeleaf template is rendered by Spring.

Remember, Spring will be reading the Thymeleaf templates, then producing output based upon the Thymeleaf directives.


You can see how our index page is very simple now. While this is a very lean HTML document, when Spring renders it at run time, you will see HTML looking like this:

Actual HTML Rendered to Browser

Notice how Thymeleaf and Spring have merged the contents of the index.html document and the two Thymeleaf fragment documents? Now you have pure HTML, and Thymeleaf tags are not rendered to the HTML content sent to the browser.

The index.html Thymeleaf template will show this page in your browser.

Thymeleaf Index page

Thymeleaf Views for CRUD Application

Show Product

Showing a product is one of the simpler operations under Spring MVC and Thymeleaf. Our controller returned a product object to the model and bound it to the property ‘product’.  Now we can use the typical name-dot-property syntax to access properties of the product object.

This Thymeleaf tag:

Will get text from the description property of the product object and replace the ‘description’ text in the paragraph HTML tag.

Here is the full Thymeleaf template for showing a product:


The show product Thymeleaf template will show this page:

Thymeleaf Show Product Page

List Products

The list view is a little trickier because now we have a list of products to iterate over. Luckily, Thymeleaf makes this very easy to do.

Here is a snippet showing how to iterate over a list of products.

You can see the syntax of this Thymeleaf tag is similar to a for-each loop in Java.

Our controller added a list of products to the ‘products’ property to the model, which we pass to the Thymeleaf tag. The variable name we are assigning to the iterator is ‘product’.

The body of the each tag will be rendered once for each product in the list of products.

Here is the complete Thymeleaf template used for showing a list of products.


Here is the Thymeleaf list products page:

Thymeleaf List Products

Create / Update Product

We can use the same HTML form for creating and updating products. A little trick is to have your controller method return an empty object to the view for the create option, and the existing object for the update option. By doing this you don’t need to worry about null objects on the view layer. For a new object, the null properties show up blank. For existing objects, non-null properties will get populated into the form fields.

The following line sets up the form in Thymeleaf.

The “th:object” tag binds the product object to the form. Thus, you only use the property names on the form fields. No need to qualify the object name too.

The “th:action” tag maps the form action to the ‘/product’ url. And we specify to use the HTML post action for the form.

Here is the controller action this maps back to:

Notice how we’ve assigned the url ‘product’ and method POST in the request mapping.

This next step is critical for your updates to work properly. All entities have an ID value. This is not accessible for the user to edit, but it still needs to be included to the post back to the server, so Spring / Hibernate can find the correct entity to update. If this is missing, there is no way to distinguish between and update and a create. If the ID property is missing from the form post, Spring Data JPA will think it’s a new item and create a new entity.

The way to handle this is through the use of hidden form fields. In this snippet, we’re assigning hidden fields for the Id and version values. (A best practice in Hibernate is to use a version property to detect conflicting updates.)

Here is the complete product form.


Here is the Thymeleaf product form.

Thymeleaf Product Form

Spring Framework 5
Click here to learn about my online course Spring Framework 5: Beginner to Guru!


In this post we built upon the previous posts in this series on building a web application using Spring Boot to have a functional web application which performs CRUD operations against a single entity. At this point, you can checkout the project from Github and build it using Maven. Spring Boot will create an executable JAR, which you can run to demo the application. Spring Boot will run the application in an embedded Apache Tomcat instance and you will be able to see the application running at http://localhost:8080.

In the next part of this series, I’ll show you how to secure content using Spring Security.

Get The Source!

Like all of my tutorials, the source code for this post is available on GitHub here.



In the first part of this tutorial series for building a web application using Spring Boot, we looked at creating our Spring project using the Spring Initializr. This handy tool gave us a Spring project to work with, jump starting our development effort by creating the project structure and Maven dependencies for us.

In this post I am going to walk you through enabling rendering a webpage using Thymeleaf and Spring MVC.

Why Thymeleaf?

Traditionally, Spring MVC applications used Java Server Pages, or JSPs to generate html content. JSPs are a mature technology and has been around since the early days of Java. In terms of raw speed, JSPs are hard to beat too. But when you do not need the absolute raw speed of a JSP, you may want to consider alternatives to JSPs which help improve developer productivity.

JSPs offer an HTML ‘like’ syntax. Meaning its close, but not completely compatible with HTML. Thymeleaf on the other hand, aims to be a “Natural Template”. This means the Thymeleaf template file will open and display normally in a browser, while a JSP file does not.

I also have selfish reasons for using Thymeleaf in this tutorial on Spring Boot. I’ve never used it, and I thought it looked like a cool technology to try out.

Spring Framework 5
Become a Spring Framework Guru! Click here to learn about my Spring Framework 5: Beginner to Guru online course!

Thymeleaf Configuration and Spring Boot

If you were using just Spring MVC, you would need to configure the Thymeleaf template engine for use. That’s not so when you’re using Spring Boot, because we’ve included the dependency spring-boot-starter-thymeleaf in our Maven POM for the project, so Spring Boot will do some things automatically for us.

By default, Spring Boot configures the Thymeleaf template engine to read template files from /resources/templates .

Effectively, you as the developer just need to start making Thymeleaf templates and dropping them into  /resources/templates.

Thymeleaf Template

Let’s start with a very basic HTML file to show.

Thymeleaf Template – index.html

A few things I’d like to point out in the HTML:

  • Line 1 – Is the standard declaration for HTML 5
  • Line 2 – sets a XML Namespace for Thymeleaf. This is important as you start to use the Thymeleaf extensions.
  • Line 6 – Defines the character set for the HTML file.

Spring MVC Controller

The next step we need to take care of is creating a Spring MVC controller. Because we’ve included the dependency spring-boot-starter-web, Spring Boot automatically configured Spring MVC for us. We also get an embedded instance of Tomcat to run our application in too. This may sound simple, but it does take care of a lot of setup tasks that we would normally need to do if we were using Spring MVC without Spring Boot.

With using Spring Boot, we only need to define our controller class, nothing else. Like other things Spring Boot sets up sensible defaults for us.


At this point, we just need a very simple controller. We want to map the web root path (“/”) to the index template. A common convention used in Spring MVC is to return the string name of the template file, less the file extension. Thus to show the index.html file we defined above, our controller method needs to return the string ‘index’,

On Line 6, I’ve used the @Controller  annotation to make this class a Spring component and a Spring MVC controller. On line 9, you can see that I annotated the index()  method with a @RequestMapping  annotation. By doing this, I’ve configured the root path to this controller method.

Running the Example

If you’re using IntelliJ, you can go into the class SpringBootWebApplication  and right click on the main()  method, then click on run. This will run the Spring Boot application. Spring Boot will startup an embedded instance of Tomcat and deploy our application to it.

BUT – if you navigate to http://localhost:8080 via your browser, the port Tomcat is listening on, you will see this:

Basic Auth via Spring Security

So, what’s happening here? Because we added Spring Security into our build, Spring Boot has configured Spring Security for our use. The default behavior is to require basic auth for all endpoints. This is a good approach to secure everything by default, but it can trip you up if you’re not accustomed to working with Spring Security.

Spring Security Configuration

What we need to do, is tell Spring Security to allow all requests access to the root path. I’ll be covering Spring Security in additional detail in a future post,  but for now, we need to add a Spring Configuration class to allow us to configure Spring Security.


To accommodate the Spring Security configuration, I created a new package and added the SecurityConfiguration  class. By annotating the class with the @Configuration  annotation, I’m telling Spring this is a configuration class. When doing Java configuration for Spring Security, you need to extend the WebSecurityConfigurerAdapater  class and override the configure method.

Spring Boot and Package Scans

One quick note I want to call out here, the controller and configuration classes I’ve just defined are annotated Spring Components. Spring will only pick these up when their respective package is included in a component scan. A default behavior of Spring Boot when using the @SpringBootApplication annotation is to perform a package scan on its package (and all sub packages). Because my Spring Boot application resides in the package guru.springframework, the annotated Spring Components in the child packages are automatically found by Spring. If they were in a different package tree, I would need to explicitly tell Spring Boot to scan that package. This is important to know, and is something that could easily trip up a beginner with Spring Boot.

Example Web Page:

At this point in building our Spring Boot web application, we have not applied any styling to our Thymeleaf template file. Its pure simple, unstyled HTML.

unstyled spring boot web page

Managing Web Resources Under Spring Boot

At this point our Spring Boot Web application is working, in the sense it generate some HTML. But that’s not very realistic for today’s web applications. Any modern web application is going to have some web resources to manage. Web resources typically include:

  • CSS files.
  • Javascript assets
  • Images

Right now, our web page is very boring. Lets dress it up using Bootstrap CSS and JQuery.

Static Resources with Spring Boot

Spring Boot will automatically serve static resources from the path /resources/static. By a generally accepted convention, you will typically put CSS files in /resources/static/css, Javascript files in /resources/static/js, and images in resources/static/images. You could name the directories after /resources/static/ whatever you wish, this is just a convention you will likely see used and it helps you organize the static resources.

I like to add a CSS file for any overrides and customization I’ll need. I’m going to add an empty CSS file into /resources/static/css and then add it to the Thymeleaf template as follows:

Notice how the link tag has two href attributes? The first one in normal HTML will be used by the browser when the template is read from the file system. The second with the ‘th’ namespace is used by Thymeleaf when the template is rendered via Spring Boot. In this case a SPeL expression is being used to resolve the path of the static asset under Spring Boot, and this will be used as the path when the template is rendered by Spring Boot for the browser via a request through Tomcat.

This is what is meant when Thymeleaf is called a natural template engine. In this case, the CSS file is found for the HTML file via the relative path in the file system, then again when it’s deployed using a SPeL notation.

Spring Boot and WebJars

More than once I’ve copied all the files for Bootstrap CSS or JQuery into a resources folder, and then managed the lifecycle of their versions. This can be a manual and tedious process. WebJars is a very cool concept which which packages web assets into a JAR file for your use. The JAR s are available in public Maven repositories, making them build assets you can easily include in your project. (Did you know JAR files are just zip files, with the extension changed to JAR?)

Spring Boot supports WebJars out of the box. We just need to include the dependency in our Maven POM file for the project, then add it to our Thymeleaf template file.

We can declare the WebJar dependencies for Bootstrap CSS and JQuery by adding the following lines to our Maven POM file:

Now we can add the Bootstrap CSS and JQuery dependencies to our index.html file as follows:

Note: In this example I’m using a public CDN for the Bootstrap CSS and JQuery assets. By doing this I can preserve the natural templating of the Thymeleaf template file.

Spring Framework 5
Click here to learn more about my online course Spring Framework 5: Beginner to Guru!

Styling Our Example

Now that we have the Bootstrap CSS and JQuery resources loading with our Spring Boot web application, lets add a little Bootstrap styling to our index.html file.


Example web page:

spring boot web page


At this point in this tutorial series on building a Spring Boot web application using Spring Boot, we’ve shown you how to create a basic project using the Spring Initializr and setup support for Thymeleaf. You can see how Spring Boot has made some common sense choices for us, like configuring the Thymeleaf template engine for use with Spring MVC, defaulting the locations for static resources, and providing out of the box support for WebJars.

In our next post on Spring Boot, we will take a look at setting up the persistence layer with Spring Boot, H2 and Spring Data JPA.

Get The Code

I’ve committed the source code for this post to github. It is a Maven project which you can download and build. If you wish to learn more about the Spring Framework, I have a free introduction to Spring tutorial. You can sign up for this tutorial in the section below.

The source code for this post is available on github. You can download it here.


I went through the content of this post on YouTube video. You can check it out below.