CustomMenu

Thursday, February 20, 2014

Spring MVC 4 - Thymeleaf CRUD - Part 4

This is the fourth and last part of a series on moving our simple Spring MVC 4 CRUD application from JSP to Thymeleaf.  The first part of the series can be found at Spring MVC 4 - Thymeleaf CRUD - Part 1.  In part one, simple list functionality was built.  In part two we created the "add" functionality on the list page.  In part three we created the update/edit functionality and linked to it from the list page.  In this part we will create the delete functionality and link to it from the list page.

1. The first step is to modify the StrategyController HTTP-GET method for deleting a strategy. The old and new versions of the relevant HTTP-GET method are shown below.

The old method simply deleted the strategy. The new method is structured around a confirmation page, that uses a new request parameter called "phase" to direct method processing. Initially, the delete page is displayed with the read-only details of the strategy ("stage" phase).  On this page a user can either confirm the deletion ("confirm" phase), or cancel the deletion ("cancel" phase). Both of these actions will result in the user being returned to the list page.
    
@RequestMapping(value="/delete/{id}", method=RequestMethod.GET)
public ModelAndView deleteStrategy(@PathVariable Integer id) {
    ModelAndView modelAndView = new ModelAndView("home");
    strategyService.deleteStrategy(id);
    String message = "Strategy was successfully deleted.";
    modelAndView.addObject("message", message);
    return modelAndView;
}
@RequestMapping(value="/delete", method=RequestMethod.GET)
public ModelAndView deleteStrategyPage(@RequestParam(value="id", required=true) Integer id, 
        @RequestParam(value="phase", required=true) String phase) {

    Strategy strategy = strategyService.getStrategy(id);
    ModelAndView modelAndView = null;

    if (phase.equals("stage")) {
        modelAndView = new ModelAndView("strategy-delete");
        StrategyDTO strategyDTO = StrategyMapper.getDTO(strategy);
        String message = "Strategy " + strategy.getId() + " queued for display.";
        modelAndView.addObject("strategyDTO",strategyDTO);
        modelAndView.addObject("message", message);
    }

    if (phase.equals("confirm")) {
        modelAndView = new ModelAndView("redirect:/strategy/list");
        strategyService.deleteStrategy(id);
        String message = "Strategy " + strategy.getId() + " was successfully deleted";
        modelAndView.addObject("message", message);
    }

    if (phase.equals("cancel")) {
        modelAndView = new ModelAndView("redirect:/strategy/list");
        String message = "Strategy delete was cancelled.";
        modelAndView.addObject("message", message);
    }

    return modelAndView;
}

2.  The second step is to create the html page for deleting the strategy.  We will call this page strategy-delete.html, and the full file is shown below.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
 xmlns:th="http://www.thymeleaf.org">
<head th:fragment="header">
    <meta charset="utf-8" />
 <link type="text/css" rel="stylesheet" href="../../resources/css/style.css" th:href="@{/resources/css/style.css}"/>
 <title th:text="#{strategy.delete.page.title}">Title</title>
</head>
<body>
<h1 data-th-text="#{strategy.delete.head.title}">temp heading</h1>
 <table class="box-table-a">
  <tr>
   <td data-th-text="#{strategy.list.id.label}">Temp id</td>
   <td data-th-text="${strategyDTO.id}">
   </td>
  </tr>
  <tr>
   <td data-th-text="#{strategy.list.type.label}">Temp type</td>
   <td data-th-text="${strategyDTO.type}">
   </td>
  </tr>
  <tr>
   <td data-th-text="#{strategy.list.name.label}">Temp name</td>
   <td data-th-text="${strategyDTO.name}">
   </td>
  </tr>
  <tr>
            <td><a href="#" data-th-href="@{/strategy/delete(id=${strategyDTO.id},phase=confirm)}">
             <button type="button" data-th-text="#{delete.button.label}">Delete</button></a>
            </td>
            <td><a href="#" data-th-href="@{/strategy/delete(id=${strategyDTO.id},phase=cancel)}">
             <button type="button" data-th-text="#{cancel.button.label}">Cancel</button></a>
            </td>
  </tr>
 </table>
</body>
</html>
This page is rendering the strategy details contained in the StrategyDTO object passed to this page.  The initial get request to the delete method will populate the DTO and pass it back to the page.  The page contains both delete and cancel buttons, with the backing data-th-href values dynamically generated for a given strategy id.  Lastly, each button has a unique phase value, so that get request for each button can be handled correctly by the HTTP-GET request to the delete method on the controller.

3. The last step before demoing the application is to modify the list page to correctly link to the delete page we just created.  The relevant section of code in the strategy-list.html file is shown below.  The only change that was made to this code was to add the data-th-href entry for the delete functionality.  As with "edit," the code will build a link for each strategy in the list, with the link containing the id of a given strategy.
<tr data-th-each="strategy : ${strategies}">
    <td data-th-text="${strategy.id}">1</td>
    <td data-th-text="${strategy.type}">Iron Butterfly</td>
    <td data-th-text="${strategy.name}">Triple Butter</td>
    <td><a href="#" data-th-href="@{/strategy/delete(id=${strategy.id},phase=stage)}">delete</a> | 
        <a href="#" data-th-href="@{/strategy/edit(id=${strategy.id})}">edit</a>
    </td>
</tr>

4. We can now run the application, navigate to the list page, and select delete on a strategy.  The screenshot below is the delete page for the second strategy.

When we select the delete button, the strategy is deleted and we are returned to the list page.  The delete strategy should no longer be displayed in the list.

In future posts we will look at integrating Twitter Bootstrap and integrating Spring Security.  After these steps are complete, we should be ready to start building out the trading system core.

Code at GitHub: https://github.com/dtr-trading/spring-ex04

Wednesday, February 19, 2014

Spring MVC 4 - Thymeleaf CRUD - Part 3

This is the third part of a series on moving our simple Spring MVC 4 CRUD application from JSP to Thymeleaf.  The first part of the series can be found at Spring MVC 4 - Thymeleaf CRUD - Part 1.  In part one, simple list functionality was built.  In part two we created the "add" functionality on the same page.  In this post we will create the update/edit functionality and link to it from the list page.

1. The first step is to modify the StrategyController HTTP-GET method for updating a strategy.  The old and new versions of the relevant HTTP-GET method are below.  The only difference is that the new method is passing the StrategyDTO object rather than the Strategy object to Thymeleaf.
    
@RequestMapping(value="/edit/{id}", method=RequestMethod.GET)
public ModelAndView editStrategyPage(@PathVariable Integer id) {
        ModelAndView modelAndView = new ModelAndView("strategy-edit");
        Strategy strategy = strategyService.getStrategy(id);
        modelAndView.addObject("strategy",strategy);
        return modelAndView;
    }
@RequestMapping(value="/edit", method=RequestMethod.GET)
public ModelAndView editStrategyPage(@RequestParam(value="id", required=true) Integer id) {
    ModelAndView modelAndView = new ModelAndView("strategy-edit");
    Strategy strategy = strategyService.getStrategy(id);
    StrategyDTO strategyDTO = StrategyMapper.getDTO(strategy);
    modelAndView.addObject("strategyDTO",strategyDTO);
    return modelAndView;
}

2. The second step is to modify the StrategyController HTTP-POST method for updating a strategy.  The old and new versions of the relevant HTTP-POST method are shown below.

As with the HTTP-GET method, the new method is using the StrategyDTO object rather than the Strategy object received from Thymeleaf.  In addition, this new method is receiving a parameter named "action" that indicates whether to "save" or "cancel" the update.  After the new method is finished, it will redirect the user to the list page.
    @RequestMapping(value="/edit/{id}", method=RequestMethod.POST)
    public ModelAndView edditingStrategy(@ModelAttribute Strategy strategy, @PathVariable Integer id) {
        ModelAndView modelAndView = new ModelAndView("home");
        strategyService.updateStrategy(strategy);
        String message = "Strategy was successfully edited.";
        modelAndView.addObject("message", message);
        return modelAndView;
    }
@RequestMapping(value="/edit", method=RequestMethod.POST)
public ModelAndView editingStrategy(@ModelAttribute StrategyDTO strategyDTO, 
        @RequestParam(value="action", required=true) String action) {

    ModelAndView modelAndView = new ModelAndView("redirect:/strategy/list");
    String message = null;

    if (action.equals("save")) {
        Strategy strategy = StrategyMapper.getStrategy(strategyDTO);
        strategyService.updateStrategy(strategy);
        message = "Strategy " + strategy.getId() + " was successfully edited";
        modelAndView.addObject("message", message);         
    }

    if (action.equals("cancel")) {
        message = "Strategy " + strategyDTO.getId() + " edit cancelled";
    }

    return modelAndView;
}

3. The next step is to create the html page for editing a strategy.  We will call this page strategy-edit.html, and the full file is shown below.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
 xmlns:th="http://www.thymeleaf.org">
<head data-th-fragment="header">
    <meta charset="utf-8" />
 <link type="text/css" rel="stylesheet" href="../../resources/css/style.css" th:href="@{/resources/css/style.css}"/>
 <title data-th-text="#{strategy.edit.page.title}">temp title</title>
</head>
<body>
<h1 data-th-text="#{strategy.edit.head.title}">temp heading</h1>
 <form action="#" data-th-action="@{/strategy/edit}" data-th-object="${strategyDTO}" method="post">
 <table class="box-table-a">
  <caption data-th-text="#{strategy.edit.form.title}">Add Title</caption>
  <tbody>
   <tr>
    <td data-th-text="#{strategy.list.type.label}">Temp Type</td>
    <td><input type="text" hidden="hidden" data-th-value="*{id}" data-th-field="*{id}" />
        <input type="text" data-th-value="*{type}" data-th-field="*{type}" /></td>
   </tr>
   <tr>
    <td data-th-text="#{strategy.list.name.label}">Temp Name</td>
    <td><input type="text" data-th-value="*{name}" data-th-field="*{name}" /></td>
   </tr>
   <tr>
    <td>
     <button type="submit" name="action" value="save" data-th-text="#{update.button.label}">save</button>
    </td>
    <td>
     <button type="submit" name="action" value="cancel" data-th-text="#{cancel.button.label}">cancel</button>
    </td>
   </tr>
  </tbody>
 </table>
 </form>
</body>
</html>
There are a few things to note on this page, but for the most part it is similar to the list page.  The form is associated with a POST action that will post the strategyDTO object back to the HTTP-POST edit method on the controller.

The strategyDTO object is received by the form with it's variables already populated by the HTTP-GET edit method call on the controller.  The values of these variables populate the corresponding data-th-value attributes in the form (e.g. *{name}).  These values pre-populate the fields in the form.  These form fields can then be changed (or not) by the user, with the values stored in the data-th-field attributes of the form.  When a button is selected, the data in the field attributes are stored in the strategyDTO object and the object is posted back to the controller for processing in the HTTP-POST edit method.

4. The last step before demoing the application is to modify the list page to correctly link to the edit page we just created.  The relevant section of code in the strategy-list.html file is shown below.  The only change that was made to this code was to add the data-th-href entry.  This code will build a link for each strategy in the list, with the link containing the id of a given strategy.
<tr data-th-each="strategy : ${strategies}">
    <td data-th-text="${strategy.id}">1</td>
    <td data-th-text="${strategy.type}">Iron Butterfly</td>
    <td data-th-text="${strategy.name}">Triple Butter</td>
    <td><a href="#" >delete</a> | 
        <a href="#" data-th-href="@{/strategy/edit(id=${strategy.id})}">edit</a>
    </td>
</tr>

5. We can now run the application, navigate to the list page, and select edit on a strategy.  The screenshot below is the edit page for the second strategy.

We then edit the strategy name.

And finally we select the update button and are returned to the list screen.  Our update should now be visible in the list.

If we had instead selected the cancel button, we would have been redirected to the list page with no updates having occurred.

In Part 4, we will create the delete functionality so that we can delete the strategies in the database.  There are links on the list page for this functionality, but these links are currently stubs.

Code at GitHub: https://github.com/dtr-trading/spring-ex04

Tuesday, February 18, 2014

Spring MVC 4 - Thymeleaf CRUD - Part 2

This is the second part of a series on moving a simple Spring MVC 4 CRUD application from JSP to Thymeleaf.  The first part of the series can be found at Spring MVC 4 - Thymeleaf CRUD - Part 1.  In part one, simple list functionality was built.  In this post we will create the "add" functionality on the same page.

1. The first step is to modify the StrategyController method for adding a strategy.  An http-get method will not be needed, so we can delete that method from the controller.  Here are the old and new versions of the relevant http-post method.  They are essentially the same except for the addition of the StrategyDTO created earlier, and redirecting the user to the list page after a strategy has been created.

Recall that the StrategyDTO object was passed to the list page.  On the list page, this object will be the container that holds our strategy values to be added to the database.  The object containing the new strategy fields will be processed by the new method below.
    @RequestMapping(value="/add", method=RequestMethod.POST)
    public ModelAndView addingStrategy(@ModelAttribute Strategy strategy) {
        ModelAndView modelAndView = new ModelAndView("home");
        strategyService.addStrategy(strategy);
        String message = "Strategy was successfully added.";
        modelAndView.addObject("message", message);
        return modelAndView;
    }
    @RequestMapping(value="/add", method=RequestMethod.POST)
    public ModelAndView addingStrategy(@ModelAttribute StrategyDTO strategyDTO) {
        ModelAndView modelAndView = new ModelAndView("redirect:/strategy/list");
        Strategy strategy = StrategyMapper.getStrategy(strategyDTO);
        strategyService.addStrategy(strategy);
        String message = "Strategy " + strategy.getId() + " was successfully added";
        modelAndView.addObject("message", message);
        return modelAndView;
    }

2. Now the strategy-list.html page will need to be updated to have the "add" functionality added to the page.  The add functionality is contained in the form at the bottom of the html page.

In the form, the data-th-object is the dto object sent to the list page when the page was rendered.  The *{} fields are fields on this object that will be set to the values in the corresponding form fields.  The *{id} field is hidden because this value is generated by the database and is not a user entered value.  The new strategy-list.html page is show below.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:th="http://www.thymeleaf.org">
    
<head data-th-fragment="header">
    <meta charset="utf-8" />
    <link type="text/css" rel="stylesheet" href="../../resources/css/style.css" data-th-href="@{/resources/css/style.css}"/>
    <title data-th-text="#{strategy.list.page.title}">Title</title>
</head>

<body>
<div>
    <table class="box-table-a">
        <caption data-th-text="#{strategy.list.table.title}">Temp table title</caption>
        <thead>
            <tr>
                <th scope="col" data-th-text="#{strategy.list.id.label}">Temp ID</th>
                <th scope="col" data-th-text="#{strategy.list.type.label}">Temp Type</th>
                <th scope="col" data-th-text="#{strategy.list.name.label}">Temp Name</th>
                <th scope="col" data-th-text="#{strategy.list.actions.label}">Temp Action</th>
            </tr>
        </thead>
        <tbody>
            <tr data-th-each="strategy : ${strategies}">
                <td data-th-text="${strategy.id}">1</td>
                <td data-th-text="${strategy.type}">Iron Butterfly</td>
                <td data-th-text="${strategy.name}">Triple Butter</td>
                <td><a href="#" >delete</a> | 
                    <a href="#" >edit</a>
                </td>
            </tr>
            <tr data-th-remove="all">
                <td>2</td>
                <td>Iron Condor</td>
                <td>High Prob Hedged</td>
                <td><a href="#">delete</a> | <a href="#">edit</a></td>
            </tr>
        </tbody>
    </table>
 
 <form action="#" data-th-action="@{/strategy/add}" data-th-object="${strategyDTO}" method="post">
 <table class="box-table-a">
  <caption data-th-text="#{strategy.list.add.title}">Add Title</caption>
  <thead>
   <tr>
    <th data-th-text="#{strategy.list.type.label}">Type Label</th>
    <th data-th-text="#{strategy.list.name.label}">Name Label</th>
   </tr>
  </thead>
  <tbody>
   <tr>
    <td><input type="text" hidden="hidden" data-th-field="*{id}"/>
        <input type="text" data-th-field="*{type}"/></td>
    <td><input type="text" data-th-field="*{name}"/></td>
   </tr>
   <tr>
    <td>
     <button type="submit" data-th-text="#{add.button.label}">Action</button>
    </td>
    <td></td>
   </tr>
  </tbody>
 </table>
 </form>
</div>
</body>
</html>

3. Now, when you run the application on the server and go to the list page, you should see the screen below.

4. If you add some options trading strategies, the should show up in the list after selecting the "add" button.

In Part 3, we will create the update/edit functionality so that we can edit the strategies in the database.  There are links on the list page for this functionality, but these links are currently stubs.

Code at GitHub: https://github.com/dtr-trading/spring-ex04