spring boot
, , ,

This is the fifth part of my tutorial series on building a Spring Boot Web Application. We started off in the first part looking at using the Spring Initializr to start our Spring Boot project. In part 2, we configured Spring MVC and ThymeLeaf templates to display a basic web page. This was followed by part 3 where we setup the H2 database and Spring Data JPA and used them to persist data of our application to the database. In part 4, we consolidated everything to provide a working Spring Boot MVC Web Application capable of performing CRUD operations. We now have an application which displays data from the database, allows you to create new records, update existing records, and delete selected records too.

In part 5, we will use Spring Security to set up authentication and authorization in our application.

Spring Security, one of the most commonly used project in the Spring family of projects, provides a powerful and highly customizable authentication and authorization framework designed specifically to secure Java applications. In this part, I’ll show you how to setup Spring Security to secure our Spring Boot Web Application using the basic in-memory authentication provider.

Security Requirements

Our Spring Boot Web application in the current state is accessible to all users. Any user can create and view products, and also edit or delete them. Before we setup Spring Security to secure our application, let’s set few security requirements:

  • An anonymous user (user who doesn’t sign in) should be able to view the home page and product listing.
  • An authenticated user, in addition to the home page and product listing, should be able to view the details of a product.
  • An authenticated admin user, in addition to the above, should be able to create, update, and delete products.

Maven Dependencies

Spring Security is already listed as a dependency of our application in the Maven POM.

In the Maven Projects pane of IntelliJ we can see the additional dependencies of  Spring Security.

spring security dependencies in Maven

As we can see the Spring Security starter has brought in Spring AOP, Spring Security web, and Spring Security config, which in turn bring in Spring Security core.

Authentication and Authorization

Before we go deep, we need to understand what authentication and authorization means in Spring Security. Although both sound similar and it’s very easy to confuse them..

Authentication means ascertaining that somebody really is who they claim to be. Authentication is performed using different mechanisms. One simple and common mechanism is through user credentials in the form of user name and password. These are stored in some type back end data store, such as a SQL database. Others include LDAP, Single Sign-On (SSO), OpenID, and OAuth 2.0.

Authorization, on the other hand, defines what you are allowed to do. For example, an authenticated user may be authorized to view products but not to add or delete them.

Remember that authentication is “Who I am?” as a user to the system. While authorization is “You are either allowed or not to do this” from the system.

Securing URLs

In part 1, where we added Spring Security into our build, Spring Boot configured Spring Security to require Basic authentication for all endpoints. In part 2, we configured Spring Security to allow all requests access to the root path. We did this by creating a SecurityConfiguration class that extends the WebSecurityConfigurerAdapater class and overridden the configure() method. We will now update the same configure() method to define which URL paths should be secured and which should not.

Here is the the updated configure() method:

This security configuration will:

  • Allows all requests to the /, /products, /product/show/*, /console/** paths (Line 5)
  • Secures all other paths of the application to require authentication (Line 6)
  • Allows everyone to view a custom /login page specified by loginPage()(Line 8)
  • Permits all to make logout calls (Line 10)
  • Disables CSRF protection (Line 12)
  • Disables X-Frame-Options in Spring Security (Line 13) for access to H2 database console. By default, Spring Security will protect against CRSF attacks.

Note: Although this is not a production-level configuration, it should get us started with the basic in-memory authentication. I’ll revisit this part, when I discuss more advanced security configuration in my upcoming posts.

In the same SecurityConfiguration class, we will also autowire a configureGlobal() overridden method of WebSecurityConfigurerAdapter. At runtime, Spring will inject an AuthenticationManagerBuilder that we will use to configure the simplest, default in-memory authentication with two users. The complete code of the
SecurityConfiguration class is this.

SecurityConfiguration.java

In this code, Line 27 – Line 30 configures in-memory authentication with two users. The first user with the username user and a password user is assigned a role of USER. The second user with the username admin and a password admin is assigned a role of ADMIN.

The Login Page

Our application will have a login page to capture user credentials in the form of user name and password. The login page, a Thymeleaf template will be served whenever a request to /login is received. We will configure the request mapping in ProductController like this.

The code of the login template is this.

login.html

This is a standard Thymeleaf template that presents a form to capture a username and password and post them to /login. Spring Security provides a filter that intercepts that request and authenticates the user with our configured in-memory authentication provider. If authentication succeeds, the application displays the requested page. If authentication fails, the request is redirected to /login?error and the login page displays the appropriate error message (Line 10 – Line 12). Upon successfully signing out, our application is sent to /login?logout and the login page displays a sign out message (Line 13 – Line 17).

This is how the login page displays an error message on authentication failure.
Spring Security Login Error Message

Spring Security Integration in Thymeleaf

To integrate Spring Security in our Thymeleaf templates, we will use the Thymeleaf “extras” integration module for Spring Security. For this, we need to add a JAR dependency in our Maven POM like this.

The Thymeleaf “extras” module is not a part of the Thymeleaf core but fully supported by the Thymeleaf team. This module follows its own schema, and therefore we need to include its XML namespace in those templates that will use security features, like this.

Showing Content based on Role

One of our application requirement states that only authenticated users with the ADMIN role can create products. To address this, we will configure authorization in the header.html Thymeleaf fragment to display the Create Product link only to users with the ADMIN role. In this template, we will also display a welcome message with the user name to an authenticated user. The code of the header.html template file is this:

header.html

The Thymeleaf security extension provides the sec:authorize attribute that renders its content when the corresponding Spring Security expression evaluates to true.

In Line 16 we used the sec:authorize attribute to display the Create Product link only if the authenticated user has the ADMIN role. Observe that we are checking against ROLE_ADMIN instead of the ADMIN role. This is because of Spring Security’s internal feature of mapping a configured role to the role name prefixed with ROLE_. In Line 23 we again used the sec:authorize attribute to check whether the user is authenticated, and if so, displayed the name using the sec:authenticate attribute.

This is how the home page appears to authenticated users with USER and ADMIN roles.

Home Page View for USER Role
Home Page View for ADMIN Role

Our current Product Listing page rendered by the products.html template displays the View, Edit, and Delete links to all users. In this template, we will configure authorization:

  • To show the View, Edit, and Delete links to a user with ADMIN role
  • To show only the View link to a user with USER role
  • Not to show any links to an anonymous user who hasn’t signed in

The code of the products.html page is this.

products.html

In Line 16 the “Sign Out” form submits a POST to /logout. Upon successfully logging out it will redirect the user to /login?logout. The remaining authorization is performed using the sec:authorize attribute. The hasAnyRole('ROLE_USER','ROLE_ADMIN') expression on Line 30 and Line 39 evaluates to true if the user has either the ROLE_USER or ROLE_ADMIN.

With this configuration, the product listing page will appear to different roles like this.

Home Page View for Anonymous
Home Page View for USER Role
Home Page View for ADMIN Role
If you are wondering why the Sign Out Submit button is getting displayed as a link, it’s due to this CSS code I added to the guru.css stylesheet.

guru.css

The code of productshow.html and productform.html templates, except for the addition of the “Sign Out” form, remains the same.

productshow.html

productform.html

Finally, if any signed in user clicks on Sign Out in any one of the secured pages, the user is redirected to the login page with a message, like this.
Spring Security Log Out Message

free spring framework tutorialSummary

Spring Security is a very popular project in the Spring Framework family of projects. When you need to secure content in a Spring Boot web application, Spring Security is a natural ‘go to’ tool to use.

In this post, I’ve only scratched the surface of the capabilities of Spring Security. For example, I used the in-memory authentication provider for Spring Security. This a great tool to demonstrate how to configure Spring Security. But, you probably would not use an in-memory authentication provider in production. It’s actually fairly common to store user credentials in a database. In the next post of this series, I’ll explain how to setup a DAO authentication provider for Spring Security.

1
Share
spring boot
, ,

In my earlier Integration Testing with Spring and JUnit post, I discussed how to test a service bean facade with JUnit. I also posted a video, titled Testing Spring with JUnit on YouTube. In post, Spring Boot Web Application – Part 3 – Spring Data JPA, I showed how to test a Spring Data JPA repository of a Spring MVC application.

It has been more than a year now since I wrote these posts and posted the video. Since then, there’s been an exciting overhaul of testing support for Spring Boot MVC applications. The Spring Boot 1.4 release includes a number of exciting new testing features for our use.

In this post, I will look the new Spring MVC testing features. And I’ll show you how to put them to use.

Spring Boot 1.4 Testing Enhancements

In Spring Boot 1.3, there’s a lot of choices to write tests for a Spring MVC application. One option to set Spring MVC is shown in my earlier post here. In this post on Spring Boot 1.3, the @RunWith annotation with @ContextConfiguration is used to test for a business service façade, like this:

Another method I used in the post here is a combination of the @RunWith annotation with @SpringApplicationConfiguration to test a Spring Data JPA repository, like this:

There are several other approaches you can check in the official Spring blog here.

The testing approaches I used above are actually integration tests.  A pure unit test shouldn’t create and load Spring Context.

Spring Boot 1.4 replaces these various testing approaches that via a single @SpringBootTest annotation for regular integration tests.

Prior to Spring Boot 1.4, I found Spring was lacking a simplified unit testing approach. This is really no surprise. The Spring team is always creating. Spring and Spring Boot offers a number of testing options. Due to innvotation, the testing options have evolved over time. In Spring Boot 1.4, the Spring committers took some time to clean testing up. They gave us much simpler options to use for testing Spring Boot applications. For example, a simple approach to unit test a controller having @Autowired external services without having to load Spring Context was lacking. With Spring Boot 1.4, it’s now possible.

Another missing piece that Spring Boot 1.4 tackels, is the ability to test portions (slices) of code. This can be done without the need to fire up a server. And with out the need to load up the entire Spring Context. Spring Boot 1.4 does this through the new Test Slicing feature that is designed to set-up a narrow slice of the Spring Context. This makes testing single ‘slices’ much easier. You can now focus on testing specific slices of your application. For example:

For example:

  • MVC slice: Controller code through the @WebMvcTest annotation
  • JPA slice: Spring Data JPA repository code through the @DataJpaTest annotation
  • JSON slice: JSON serialization code through the @JsonTest annotation

This may not seem like much at first glance. But when you have a large application starting the Spring context in testing, it is time consuming. Context loads can really increase your build time.

Let’s start putting the new test features to use.

The Application Under Test

I wrote a series of posts on Spring MVC starting off from Spring Boot Web Application – Part 1 – Spring Initializer. In the last post of the series, Spring Boot Web Application – Part 4 – Spring MVC, I completed creating a Spring MVC application to perform Create, Read, Update, and Delete (CRUD) operations.

In this post, I’ll show you how to write tests for the controllers of the same Spring MVC application.

If you are new to Spring MVC, you should go through my series on Spring MVC starting here.

You can also download the source code of the application available on GitHub here to follow along this post.

It’s a pretty simple example of a Spring Boot MVC application consisting of the following primary components:

  • Product: The domain object, which is a JPA entity
  • IndexController: Returns the index.html Thymeleaf template for a GET request to the application root
  • ProductController: Contains number of actions methods that use ProductService to perform CRUD operations via the repository model
  • ProductRepository: A Spring Data JPA repository
  • ProductService: A business service façade interface
  • ProductServiceImpl: A business service façade implementation annotated with @Service

With the Spring Boot MVC application that will be under test in place, lets start by writing few tests for the controllers.

Maven Dependencies

The testing features we’re looking at were introduced in Spring Boot 1.4. The version of Spring Boot we’ll be using is 1.4.0.RELEASE.

Here is the complete Maven POM that we’ll use.

pom.xml

Unit Testing Spring MVC Controllers

MockMvc has been around since Spring 3.2. This providing a powerful way to mock Spring MVC for testing MVC web applications. Through MockMvc, you can send mock HTTP requests to a controller and test how the controller behaves without running the controller within a server. You can obtain a MockMvc instance through the following two methods of MockMvcBuilders:

  • standaloneSetup(): Registers one or more @Controller instances and allows programmatically configuring the Spring MVC infrastructure to build a MockMvc instance. This is similar to plain unit tests while also making it possible to focus tests around a single controller at a time.
  • webAppContextSetup(): Uses the fully initialized (refreshed) WebApplicationContext to build a MockMvc instance. This lets Spring load your controllers as well as their dependencies for a full-blown integration test.

Pro Tip: Whenever possible, I will try to use standaloneSetup() for my SpringMVC tests. Your tests will remain true unit tests and stay blazing fast!

This is the IndexController that we are going to test:

IndexController.java

For our purpose, we’re starting with standaloneSetup() to test this IndexController.

The test class is this.

IndexControllerTest.java

The test class above is a JUnit test. If you are new to JUnit, you should go through my series on unit testing with JUnit, starting from here. In the test class above, observe the new Spring Boot 1.4 test runner, named SpringRunner that we specified for @RunWith in Line 20. Under the hood, both SpringRunner and its predecessor SpringJUnit4ClassRunner are the same. SpringRunner is only the new name for SpringJUnit4ClassRunner – to just make it easy on the eyes.
In the @Before annotated method that runs before all @Test method, we programmatically constructed a MockMvc instance after registering the IndexController instance.

In the @Test method, we used the MockMvc instance to verify the following behavior of IndexController:

  • HTTP status code 200 is returned
  • The name of the returned view is index

Finally, by using andDo(print()), we get the following output on the console

Spring MockMvc IndexController Test Output

Testing the Spring MVC Slice

The unit test we wrote were for some basic expectations of the controller. Let’s write some more specific tests, this time to test ProductController. This time we’re going to use webAppContextSetup() to build MockMvc.

For a quick recap, the ProductController class is this.

ProductController.java

We will start by testing the behavior of ProductController.list() method. For a GET request to /product, we will perform the following verification:

  • The ProductService mock is not null
  • The HTTP status code 200 is returned
  • The returned content type is text/html;charset=UTF-8
  • The name of the returned view is products
  • The view contains the Spring Framework Guru string

Here is the test class.

ProductControllerTest.java

As we are testing the MVC slice of the application (testing whether the ProductController is working as expected), we used the @WebMvcTest annotation combined with @RunWith(SpringRunner.class).

As we planned to use webAppContextSetup() to build MockMvc, we @autowired WebApplicationContext in Line 6 – Line 7 to bring it into our test. Then in line 13, we passed WebApplicationContext as an argument to webAppContextSetup() to build the MockMvc instance.

Going back to the ProductController class under test, note that the controller class is @Autowired with ProductService. Therefore, we used the @MockBean annotation to define a Mockito mock for ProductService (Line 8 -Line 9) that will be passed to the controller. If you are new to mocking in unit tests, checkout my Mocking in Unit Tests with Mockito post.

Coming back to the test, in Line 17 we used the AssertJ library to assert that the ProductService mock is not null.

Note: Starting with Spring Boot 1.4, AssertJ comes out-of-the-box with Spring Boot to provide a fluent assertion API with a plan to replace JUnit’s  org.junit.Assert class.

From Line 19 – Line 23, it’s all about verifying our expectations. As you can see, a lot of static methods are being used in this test method, including static methods of MockMvcRequestBuilders ( get()), MockMvcResultMatchers ( status(), content(), and view()), MockMvcResultMatchers ( match()), and Hamcrest Matcher’s ( match()). The last two match() are similar and performs the same functions in our test. They exist together only to demonstrate the different approaches that can be used.

Our test method reads naturally. First it performs a

First it performs a GET request against /products. Then it expects that the request is successful ( isOk() asserts an HTTP 200 response code) and that the content type and name of the view is text/html;charset=UTF-8 and products respectively. Finally, it asserts that the view contains the Spring Framework Guru string.

When all the expectations pass, Line 24 prints the result out to the console.

The important thing to note here is that at no time is the application gets deployed to a server. The Tomcat container is not use. Instead the application runs within a mocked out Spring MVC to handle the HTTP request that we provided through the

Instead the application runs within a mocked out Spring MVC to handle the HTTP request that we provided through the MockMvc instance.

Here is the test result in the console.
Test output of ProductController.list()

The complete output of the test sent to console is this.

Testing Spring MVC Slice with @Autowired MockMvc

Now let’s test the behavior of showProduct() of ProductController. Instead of manually building MockMvc, we’ll use a @Autowired MockMvc in the test and let Spring create, configure, and provide a MockMvc for us.

This is how the test class now looks minus any @Test method implementations.

In the test class above, notice that we used the @Autowired annotation on MockMvc in Line 5 – Line 6 instead of building it manually.

An @Autowired MockMvc combined with @WebMvcTest(controllers = ProductController.class) gives us a fully configured MockMvc instance with Spring security configured to set up BASIC authentication.

At this point, if we run the ProductControllerTest.testList() test again, we’ll encounter an authentication error, like this.

We’re getting the 401 response because Spring Boot is auto-configuring Spring Security for us.

To disable the Spring Security auto-configuration, we can the MockMvc instance to disable security with @AutoConfigureMockMvc(secure=false) in Line 3.

Note, in the @Before method, we created and initialized a Product domain object that we will use in the @Test method.

The @Test method is this:

In the @Test method above:

  • Line 4: Performs an AssertJ assertion to test that the ProductService mock is not null.
  • Line 5: Uses Mockito to stub the getProductById() method on the ProductService mock to return the initialized Product instance
  • Line 8 to Line 15: Performs the following verifications for a GET request to product/{id}:
    • The HTTP status code 200 is returned
    • The name of the returned view is productshow
    • The view model contains a product attribute
    • The various properties of the product attribute matches against the values we used to initialize Product
  • Line 16: Returns the result as MvcResult
  • Line 19- Line 20: Uses AssertJ to assert that the content type of the response is
    text/html;charset=UTF-8
  • Line 22- Line 27: Uses JUnit assertions to assert that:
    • The response header that MvcResult returns as MockHttpServletResponse is not null
    • There is only one response header
    • The response header name is Content-Type
    • The response contains the Spring Framework Guru string
  • Line 29 -Line 30: Uses Mockito to verify that the getProductById() is called only once on the ProductService mock, and that no other methods of the ProductService mock are called during the test.

The complete test class is this:

ProductControllerTest.java

The complete output of the test sent to console is this:

Summary

The new @WebMVC used with MockBean allows creating powerful yet simple tests for your Spring MVC apps. Unlike the @SpringBootTest annotation, the @WebMvcTest annotation disables full auto-configuration. @WebMvcTest only auto-configures the Spring MVC infrastructure and limits scanned beans to @Controller, @ControllerAdvice, @JsonComponent, Filter, WebMvcConfigurer, and HandlerMethodArgumentResolver beans.

When you use @WebMvcTest, regular @Component, @Service, or @Repository beans will not be scanned – an important point to differentiate @WebMvcTest from a full-blown @SpringBootTest.

If you’re looking to load your full application configuration and use MockMVC, you should consider @SpringBootTest combined with @AutoConfigureMockMvc rather than @WebMvcTest. I will cover it in an upcoming post of this Spring MVC testing series. I will also help you to explore more about mocking services and JPA repositories with @MockBean combined with @DataJpaTest and @WebMvcTest, and also how to unit test RESTful controller’s GETs and POSTs using MockMvc and @JsonTest.

4
Share
spring boot

I was looking over Stackoverflow today, and saw a question about how to set response headers in Thymeleaf. The question was from a guy new to Thymeleaf, but accustomed to JSP.

The short answer, is you don’t. Setting response headers is a function of the controller, not of the templating engine.

In my experience as a Java developer, some of the worst code I’ve ever seen has been in JSP pages. I’ve seen absolutely awful stuff. Sadly, JSP allows, almost encourages poor development practices. Just because you can do something, does not mean you should do something. I can make a JDBC call directly from a JSP page. That does not mean I should make a JDBC call from a JSP page.

I expect people moving over to Thymeleaf from the JSP world will have issues from bad habits of poor coding practices. Thymeleaf is a template engine. Not a dumping ground for bad code.

thymeleaflogonameverysmall

In the video below, I step you through how to use Spring MVC to set a HTTP response header when using Thymeleaf. Following the video, is a code example.

Setting Response Headers in Spring MVC

Setting response headers in Spring MVC is simple. In your controller method, make the HttpServletResponse object an argument. Spring MVC will provide the method the response object, and then you can set the appropriate response headers.

 

1
Share
, ,

A real common task is to display a list of objects fetched from the database in a HTML table on a webpage. Thymeleaf has a handy tag which allows us to iterate over a list of objects, and generate HTML code to display a table row for each object. The HTML generated really does not “need” to be a table row, but this a very common use case. Thymeleaf will simply generate the template code contained within the HTML div tags.

Typically, in your Spring MVC controller you will get a list of objects, and bind it to a property which is returned to the view layer. Ideally, your controller should be unaware of the source of the list. Often the source is ultimately a database access through a Spring service injected into the controller.

 

Free Introduction to Spring Tutorial

Are you new to the Spring Framework? Checkout my Free Introduction to Spring Online Tutorial.

 

In the video example below, I show you how to get bind a list of Java objects to a property in the model returned to the Thymeleaf template engine. Then I show you how to iterate over the list to generate an HTML table. At the end of the demonstration, I run the example in Tomcat using Spring Boot and show you the HTML code generated by Thymeleaf.

 

0
Share
spring boot
, , ,

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

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.

View

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

Controller

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.

Create

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.

Read

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.

Update

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.

Delete

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.

Free Spring Tutorial

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.

ProductService.java

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

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.

Includes

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.

headerinc.html

Menu

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.

header.html

Including Thymeleaf Fragments

Example

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.

index.html

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:

productshow.html

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.

products.html

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.

productform.html

Here is the Thymeleaf product form.

Thymeleaf Product Form

Thymeleaf Spring Course
Want to learn more about Thymeleaf, check out my Thymeleaf Spring Course!

Conclusion

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.
&nbsp:

Free Introduction to Spring Tutorial

Are you new to the Spring Framework? Enroll in my free Introduction to Spring Course!

Get The Source!

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

Save

14
Share