Mastering Spring framework 5, Part 1: Spring MVC

Build a Java web application using Spring MVC with Spring Boot

1 2 3 Page 3
Page 3 of 3

Listing 7. widget.html


<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <title>Widget Details</title>
    <link href="../static/css/bootstrap.min.css" th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
</head>
<body>
    <div class="container">
        <ol class="breadcrumb">
            <li><a href="#" th:href="${'/widgets'}">Home</a></li>
        </ol>
        <div class="row"><h2>Widget Details</h2></div>
        <form class="form-horizontal">
            <div class="form-group">
                <label class="col-sm-2 control-label">ID:</label>
                <div class="col-sm-10">
                    <p class="form-control-static" th:text="${widget.id}">Widget ID</p>
                </div>
            </div>
            <div class="form-group">
                <label class="col-sm-2 control-label">Name:</label>
                <div class="col-sm-10">
                    <p class="form-control-static" th:text="${widget.name}">Widget Name</p>
                </div>
            </div>
            <div class="form-group">
                <label class="col-sm-2 control-label">Description:</label>
                <div class="col-sm-10">
                    <p class="form-control-static" th:text="${widget.description}">Widget Description</p>
                </div>
            </div>
            <div class="form-group">
                <div class="col-sm-offset-2 col-sm-10">
                    <a href="#" class="btn btn-default" th:href="${'/widget/edit/' + widget.id}">Edit</a>
                </div>
            </div>
        </form>
    </div>
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="../static/js/bootstrap.min.js" th:src="@{/js/bootstrap.min.js}"></script>
</body>
</html>

Aside from the Bootstrap markup, this HTML file shows the three widget fields in paragraph elements using the th:text Thymeleaf attribute with the ${widget.propertyName} notation. If you are not familiar with Bootstrap, don't let the form trick you into thinking this is a proper HTML form that accepts fields; it is just a layout paradigm. You can see sample Bootstrap forms here.

The only other two things I added are:

  • A breadcrumb that allows the user to navigate back to the homepage (widget list), using an anchor tag with the th:href attribute that points to the /widgets page.
  • A button (disguised as an anchor tag but rendered as a button using the Bootstrap class btn btn-default CSS) with a th:href attribute pointing to ${'/widget/edit' + widget.id}. This notation performs a String concatenation of /widget/edit/ with the ID of the widget, resulting in something like /widget/edit/1.

An example of this page is shown in Figure 5.

jw springmvc5 fig05 Steven Haines

Figure 5. Widget edit page

If the user presses the Edit button, the editWidget method is called:


    @GetMapping("/widget/edit/{id}")
    public String editWidget(@PathVariable Long id, Model model) {
        model.addAttribute("widget", widgetRepository.findById(id).orElse(new Widget()));
        return "widgetform";
    }

This method maps to the /widget/edit/{id} URI, retrieves the widget from the database, sets it as the model's "widget" attribute, and tells Spring to render it using the "widgetform.html" Thymeleaf template, shown in Listing 8.

Listing 8. widgetform.html


<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Create/Edit Widget</title>
    <link href="../static/css/bootstrap.min.css" th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
</head>
<body>
<h2>Create / Edit Widget</h2>
<div class="container">
    <form th:object="${widget}" th:action="@{/widget}" method="post">
        <input type="hidden" th:field="*{id}" />
        <div class="form-group">
            <label>Name</label>
            <input type="text" th:field="*{name}" class="form-control" placeholder="Name">
        </div>
        <div class="form-group">
            <label>Description</label>
            <input type="text" th:field="*{description}" class="form-control" placeholder="Description">
        </div>
        <button type="submit" class="btn btn-default">Submit</button>
    </form>
</div>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="../static/js/bootstrap.min.js" th:src="@{/js/bootstrap.min.js}"></script>
</body>
</html>

This template introduces a proper Thymeleaf form. To build a form with Thymeleaf, you specify the object that the form is operating on, using the th:object attribute of the form, and then you can access that object's properties using th:field attribute in form elements. These field attributes are accessed using the "*{propertyName}" notation, which refers back to the form's object. In this example, we define a hidden text field to hold the ID (we don't want the user changing the primary key in the database) and we add the name and description fields. At the end of the document we add a submit button, which submits the form to the th:action, which points to "@{/widget}". Notice that we use the @ symbol to reference locations and the $ symbol to reference model objects.

We are able to leverage the "widgetform" for both creating new Widgets and editing existing Widgets by adding an empty Widget object in the newWidget method:


    @GetMapping("/widget/new")
    public String newWidget(Model model) {
        model.addAttribute("widget", new Widget());
        return "widgetform";
    }

Because we pass an empty Widget object through the "widget" model attribute, the form will not fail if a Widget is not present. This allows us to reuse the same form both for creating and editing widgets.

Now that we have our controller and templates defined, we're ready to run the application. To run a Spring Boot application, execute the following Maven command:

mvn spring-boot:run

You should see Spring start Tomcat, create an embedded H2 database with the name testdb and then show a summary of the URI mappings for your WidgetController.

To see your application in action, open a browser to the following URL:

http://localhost:8080/widgets

When you are ready to release and run your application in production, you can build your project with the standard mvn clean install and then run the resultant executable JAR file:


$ mvn clean install
$ java -jar target/spring5mvc-example-0.0.1-SNAPSHOT.jar

Conclusion

Spring MVC is the traditional Spring framework library for building Java web applications. This article introduced you to Spring MVC web development using Spring Boot, Spring Initializr, and the Thymeleaf view rendering engine.

There's lots more to learn about Spring framework 5! Look for the second half of this article, featuring Spring 5's reactive programming library, Spring WebFlux.

1 2 3 Page 3
Page 3 of 3