Skip to content

Lab 12 - Order Navigation

Goal

Now that you've displayed all the orders, let's add links so you can view the details of each order.

Make Thymeleaf Reloading Easier

To make it easier to see changes without explicitly restarting the application, make sure you have the following two properties in the application.properties file:

spring.thymeleaf.mode: HTML
spring.thymeleaf.cache: false

If you don't have that file, create it in the /resources directory.

Once you have that set up, anytime you rebuild the project by doing CMD + F9, Spring and Thymeleaf will reload any changed files.

A. Create a Root (Home) Page

  1. Copy the following into a Test class called WebIntegrationTest and make sure it's in the src/test folder.

    package com.welltestedlearning.cvm;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    import org.springframework.test.web.servlet.MockMvc;
    
    import static org.hamcrest.Matchers.containsString;
    import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    @AutoConfigureMockMvc
    public class WebIntegrationTest {
    
      @Autowired
      private MockMvc mockMvc;
    
      @Test
      public void homePageExists() throws Exception {
        mockMvc.perform(get("/index.html"))
               .andExpect(status().isOk())
               .andExpect(content().string(containsString("<title>Coffee</title>")));
      }
    }
    
  2. Run it and it should fail.

  3. Create a new HTML page named index.html and place it in the /src/main/resources/static directory:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Coffee</title>
    </head>
    <body>
    <h1>Welcome to the Coffee Vending Machine.</h1>
    <br/>
    <div><a href="/coffee-order">View all coffee orders</a></div>
    </body>
    </html>
    
  4. Run the WebIntegrationTest from above and it should pass.

  5. Also verify it by going to http://localhost:8080/ and trying out the link.

In this section, you'll use the th:href tag to create links to view a specific order page.

Thymeleaf URL Syntax Reference

You can find the docs for the Thymeleaf URL (href) Syntax here: http://www.thymeleaf.org/doc/articles/standardurlsyntax.html

Background

You'll update the all-coffee-orders.html template to add a link (aka "anchor" or "href") surrounding the order's name that will link to the details page for that order.

With normal static HTML, a link looks like this: <a href="/coffee-order/1">Megan</a> for Megan's order.

We want to generate a link that will point to /coffee-order/1 for an order with an ID of 1, and link to /coffee-order/5 for an order with an ID of 5.

Parameterize Example

Thymeleaf URL Syntax Reference

Thymeleaf docs for variable replacement is here: http://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#using-and-displaying-variables

As an example, to produce a link to a product page using its Product SKU (similar to an ID), we would use the @{} expression, with an embedded ${} variable expression like this:

<a th:href="@{/product/{id}(id=${product.sku})}">Product</a>

This can seem complicated, so let's look at the two steps that Thymeleaf does to complete the transformation:

  1. the ${product.sku} is the SKU property from the product object (i.e., Thymeleaf does a product.getSku()), and (id=${...}) means assign that property value to a temporary variable id.

  2. The /product/{id} (which is a URI template) then gets the {id} replaced at runtime from the temporary id variable from step 1.

So, if ${product.sku} is 2, then Thymeleaf will transform /product/{id} to the URL /product/2 and the href would look like this:

<a href="/product/2">Product</a>

Since we want each order name cell to have both the name of the order and a link, we'll need to pull the th:text out of the <td> tag and into a <span>.

The HTML that we want to be generated for order #1 that has the name Megan would be:

<td><a href="/coffee-order/1"><span>Megan</span></a></td>
  1. Open the all-coffee-orders.html template and use the example from above and translate it into the appropriate Thymeleaf attributes.

  2. Go to localhost:8080/ and then click on View all coffee orders

  3. Verify that clicking on a name link takes you to the specific page for that order.


Once you've completed the above steps,
check in with the instructor to review your code.


Bonus

  1. You can use the "pre-processing" syntax to generate the href, which for this particular use case is easier:

    th:href="@{/coffee-order/__${coffeeOrder.id}__}"

In case you're interested, the documentation for the pre-processing syntax is here: http://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#preprocessing


Once you've completed the above steps,
check in with the instructor to review your code.