Views

MVC Application using Spring Boot and JSP

MVC Application using Spring Boot and JSP
Page content

In this article, I will be developing a Model-View-Controller (MVC) application using Spring Boot, H2 Database and Java Server Pages (JSP).

Spring Boot Framework will serve as back-end(created in Microservice Using Spring Boot, Hibernate and H2 Database, same code will be reused with few modifications).

I will be using the same Relational Database known as H2 Database, for persisting(storing) the data, used in the above mentioned project.

Java Server Pages (JSP) will be the User Interface (UI) for this application.

If you have no time to read this article, but want to try the code for yourself, GitHub location is provided here. Go ahead and clone the code.


Overview

We will build a MVC application using Spring Boot, H2 Database and Java Server Pages (JSP) for a Todo Task Application in that:

  • Each Todo Task has id, title, description, creation date, due date, status and comments.
  • User can Create New Task, Update Existing Task, View All Tasks as List, View a Task and Delete a Task.

What is Model-View-Controller (MVC) Architecture?

Model designs based on MVC Architecture follow the MVC Design Pattern and they separate the Application Logic from the User Interface (UI) when designing the software. As the name implies MVC Pattern has three layers, which are:

  • Model– Represents the Business Layer of the Application
  • View– Defines the Presentation Layer of the Application
  • Controller– Manages the Flow of the Application

mvc-architecture.jpeg
MVC Architecture

In the Java Programming Context, the Model consists of simple Java Classes(POJO - Plain Old Java Object classes), the View displays the data, usually the UI layer and the Controller consists of Servlets or Business Logic.

The Model Layer

In the MVC Design Pattern, the Model is the Data Layer which defines the Business Logic of the System and also represents the State of the Application. The Model Objects retrieve and store the State of the Model in a Database. Through this Layer, we apply Rules to Data, which eventually represents the concepts our application manages.

The View Layer

This Layer of the MVC Design Pattern represents the Output of the Application or User Interface (UI). It displays the data fetched from the Model Layer by the Controller and presents the data to the user whenever asked for. It receives all the information it needs from the Controller and it does not need to interact with the Business Layer directly.

The Controller Layer

The Controller is like an Interface between Model and View. It receives the user requests from the View Layer and processes them, including the necessary validations. The requests are then sent to Model Layer for Data Processing. Once they are processed, the data is again sent back to the Controller and then displayed on the View Layer.

The MVC Architecture provides an altogether new level of modularity to your code which makes it a lot more readable and maintainable.


Prerequisites

There are some prerequisites that are required for creating the Microservice Spring Boot Application.

Familiarity with Technology and Frameworks

It is assumed that you have prior basic knowledge or familiarity with Java Technology, Java Server Pages (JSP), Spring, Spring Boot, Hibernate Frameworks, working with RDBMS databases and basic SQL commands, because I will not be covering the basics of these in this article.

If you are not familiar, then it is advised to get the basic knowledge of these before continuing.

JDK 1.8+

Download the latest version of the Java JDK (1.17 is the latest LTS version, at the time of writing this article) from here. Click on the downloaded .exe and complete the installation.

Since it is an Oracle Proprietary product you will need to sign-in/create Oracle Account, before downloading.

Integrated Development Environment (IDE) for Code Development

You can use any IDE of your choice. I will be using the IntelliJ IDEA Community Edition.

If you wish to use the IntelliJ IDEA Community Edition, download the latest version from here.

Click on the downloaded .exe and complete the installation.

Webserver– Tomcat is embedded in the Spring Boot application and can be used as Webserver for running this project.

Project Management Tool (Maven)– Maven is embedded in the Spring Boot application and can be used for building and managing the Spring Boot project.


Adding JSP to Spring Boot Project

We will be updating the Microservice Application already created in Microservice Using Spring Boot, Hibernate and H2 Database. We will make the necessary changes to add Java Server Pages (JSP) , as a View Layer to this application.

Update pom.xml

  • We need to package the project as a war file, because by default pom.xml would package the project into jar and when using JSP files with Spring Boot, we cannot use jar for packaging the project because, JSP files are placed in WEB-INF folder which is available outside the resources folder and will not be packaged in the jar.
<packaging>war</packaging>
  • Add the following dependencies to the pom.xml for JSP to be processed.
 1<dependency>
 2	<groupId>org.apache.tomcat.embed</groupId>
 3	<artifactId>tomcat-embed-jasper</artifactId>
 4	<scope>provided</scope>
 5</dependency>
 6<dependency>
 7	<groupId>javax.servlet</groupId>
 8	<artifactId>jstl</artifactId>
 9	<scope>provided</scope>
10</dependency>

Update /src/main/resources/application.properties

  • For processing of JSP files.
1spring.mvc.view.prefix=/WEB-INF/jsp/
2spring.mvc.view.suffix=.jsp

These prefix and suffix will inform the Application Server to process the JSP files from respective location.

Create a new folder /src/main/webapp/WEB-INF/jsp/

  • Make sure to keep all the JSP files in this folder, in order for application server to process them.

Update the existing Controller = controller.TodoController

  • Remove all the RequestMappings(like @GetMapping, @PostMapping, @PutMapping, @DeleteMapping) from this class, since it is serving as only Intermediary Controller class.
 1@RestController
 2public class TodoController implements TodoApplicationConstants {
 3
 4    @Autowired
 5    private TodoService todoService;
 6
 7    public ResponseEntity<List<Tasks>> getAllTasks() {
 8        try {
 9            List<Tasks> tasksList = todoService.findAll();
10            return new ResponseEntity<>(tasksList, HttpStatus.OK);
11        } catch (Exception ex) {
12            return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
13        }
14    }
15
16    public ResponseEntity<Tasks> getTasksById(@PathVariable("id") long id) {
17        Optional<Tasks> task = todoService.findById(id);
18        if (task.isPresent()) {
19            return new ResponseEntity<>(task.get(), HttpStatus.OK);
20        } else {
21            return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
22        }
23    }
24
25    public ResponseEntity<HttpStatus> deleteTaskById(@PathVariable("id") long id) {
26        try {
27            if(todoService.deleteById(id))
28                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
29            else
30                return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
31        } catch (Exception ex) {
32            return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
33        }
34    }
35
36    public ResponseEntity<Tasks> updateTaskItem(@RequestBody Tasks task) {
37        task = todoService.createOrUpdate(task);
38        return new ResponseEntity<>(task, HttpStatus.OK);
39    }
40
41    public ResponseEntity<Tasks> createTodoTask(@RequestBody Tasks task) {
42        task = todoService.createOrUpdate(task);
43        return new ResponseEntity<>(task, HttpStatus.CREATED);
44    }
45
46    public ResponseEntity<List<String>> getTaskStatus() {
47        List<String> taskStatusList = todoService.getTodoStatusAsList();
48        return new ResponseEntity<>(taskStatusList, HttpStatus.OK);
49    }
50}

Create a new Controller Class = controller.TodoViewController

  • This is the Controller Class that will be receiving the requests from JSP and hence it will have all the RequestMappings(like @GetMapping, @PostMapping, @PutMapping, @DeleteMapping).
 1@RestController
 2public class TodoViewController implements TodoApplicationConstants {
 3
 4    @Autowired
 5    private TodoController todoController;
 6
 7    @GetMapping
 8    public ModelAndView gotoHome(ModelMap model) {
 9        model.put("todoList", todoController.getAllTasks().getBody());
10        return new ModelAndView("index");
11    }
12
13    @GetMapping("/singleItemView/{action}/{todoId}")
14    public ModelAndView goToSingleItemView(ModelMap model, @PathVariable("action") String action, @PathVariable("todoId") Long todoId){
15        Tasks todoItem = Tasks.builder().title("").description("").dueDate(null).status("").build();
16        if(todoId > 0) {
17            todoItem = todoController.getTasksById(todoId).getBody();
18        }
19        model.put("todoItem", todoItem);
20        model.put("action",action);
21        model.put("todoStatus",todoController.getTaskStatus().getBody());
22        return new ModelAndView("singleItemPage");
23    }
24
25    @PostMapping("/create")
26    public void sendToCreate(ModelMap model, @RequestBody Tasks todoItem) {
27        todoController.createTodoTask(todoItem);
28        gotoHome(model);
29    }
30
31    @PutMapping("/update")
32    public void sendToUpdate(ModelMap model, @RequestBody Tasks todoItem) {
33        todoController.updateTaskItem(todoItem);
34        gotoHome(model);
35    }
36
37    @DeleteMapping("/deleteById/{id}")
38    public void sendToDeleteById(ModelMap model, @PathVariable long id) {
39        todoController.deleteTaskById(id);
40        gotoHome(model);
41    }
42}

Create new JSP file= /src/main/webapp/WEB-INF/jsp/index.jsp

  • This is the Homepage for the application.
  • This will contain List of Tasks with options to View/Edit/Delete.
  • New Task can also be created from this page.
 1<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
 2<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
 3
 4<html lang="en">
 5<head>
 6    <meta charset="UTF-8">
 7    <title>To do Tracker</title>
 8    <!-- Latest compiled and minified CSS -->
 9    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
10        integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
11        crossorigin="anonymous">
12
13    <script type="text/javascript">
14        var fullPath = window.location.href;
15        var ctx= "${pageContext.request.contextPath}";
16        apiURL = fullPath.substring(0, fullPath.indexOf(ctx)) + ctx;
17        var http = new XMLHttpRequest();
18
19        function redirectToSingleView(action, id) {
20            window.location.href = apiURL+"/singleItemView/"+action+"/"+id;
21        }
22
23        function deleteById(id) {
24            http.open("DELETE", apiURL+"/deleteById/"+id, true);
25            http.send();
26           window.location.reload();
27        }
28    </script>
29</head>
30<body>
31	<div class="container" align="center">
32		<h1>To do Tracker Application</h1>
33	    <button class="btn btn-success" onclick=redirectToSingleView('edit','0')>CREATE</button></a>
34    </div>
35	<table class='table-striped' border='1' align="center">
36        <thead>
37            <tr>
38                <th>Title</th>
39                <th>Description</th>
40                <th>Due Date</th>
41                <th>Status</th>
42                <th>No. Of Comments</th>
43                <th>View</th>
44                <th>Edit</th>
45                <th>Delete</th>
46            </tr>
47        </thead>
48        <tbody>
49            <c:forEach items="${todoList}" var="tasks">
50                <tr>
51                    <td>${tasks.title}</td>
52                    <td>${tasks.description}</td>
53                    <td>
54                        <fmt:parseDate  value="${tasks.dueDate}"  type="date" pattern="yyyy-MM-dd" var="parsedDate" />
55                        <fmt:formatDate value="${parsedDate}" type="date" pattern="dd-MMM-yyyy" />
56                    </td>
57                    <td>${tasks.status}</td>
58                    <td align="center">${tasks.todoTaskCommentsSet.size()}</td>
59                    <td>
60                        <button class="btn btn-success" onclick=redirectToSingleView('view','${tasks.systemTasksId}')>VIEW</button>
61                    </td>
62                    <td>
63                        <button class="btn btn-success" onclick=redirectToSingleView('edit','${tasks.systemTasksId}')>EDIT</button>
64                    </td>
65                    <td>
66                        <button class="btn btn-warning" onclick=deleteById('${tasks.systemTasksId}')>DELETE</button>
67                    </td>
68                </tr>
69            </c:forEach>
70        </tbody>
71    </table>
72</body>
73</html>
  1. Create one more JSP file= /src/main/webapp/WEB-INF/jsp/singleItemPage.jsp
  • When user clicks on View/Edit/Create on the Homepage, they are redirected to this page.
  • This page will display details about the single task.
  • User can either View/Edit the existing task or Create the new Task, depending on the chosen action.
  1<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
  2<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
  3<%@ page import="org.json.*" %>
  4
  5<html lang="en">
  6<head>
  7    <meta charset="UTF-8">
  8    <title>To do Tracker</title>
  9    <!-- Latest compiled and minified CSS -->
 10    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
 11        integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
 12        crossorigin="anonymous">
 13
 14    <script type="text/javascript">
 15        function submit(id) {
 16            var jsonObj = {};
 17            jsonObj['systemTasksId']=id;
 18            jsonObj['title']=document.getElementById('title').value;
 19            jsonObj['description']=document.getElementById('description').value;
 20            jsonObj['dueDate']=document.getElementById('dueDate').value;
 21            jsonObj['status']=document.getElementById('status').value;
 22
 23            var fullPath = window.location.href;
 24            var ctx= "${pageContext.request.contextPath}";
 25            apiURL = fullPath.substring(0, fullPath.indexOf(ctx)) + ctx;
 26            var http = new XMLHttpRequest();
 27
 28            if(id > 0) {
 29                var jsonCommentsArray=[];
 30                var jsonCommentsObj={};
 31                jsonCommentsObj["taskComments"]= document.getElementById('taskComments').value;
 32                jsonCommentsArray.push(jsonCommentsObj);
 33                jsonObj["todoTaskCommentsSet"] = jsonCommentsArray;
 34                http.open("PUT", apiURL+"/update", true);
 35            } else {
 36                http.open("POST", apiURL+"/create", true);
 37            }
 38            http.setRequestHeader("Content-type","application/json");
 39            http.send(JSON.stringify(jsonObj));
 40            window.location.href = apiURL;
 41        }
 42
 43        function addNewComments(){
 44            var lTable = document.getElementById("commentsTable");
 45            lTable.style.display = (lTable.style.display == "table") ? "none" : "table";
 46        }
 47    </script>
 48</head>
 49<body>
 50	<div class="container" align="center">
 51		<h1>To do Tracker Application</h1>
 52
 53        <table class='table-striped' border='1' align="center">
 54            <tbody>
 55                <tr>
 56                    <th>Title</th>
 57                    <td>
 58                        <c:if test="${action == 'view'}">${todoItem.title}</c:if>
 59                        <c:if test="${action == 'edit'}"><input type="text" name='title' id='title' value='${todoItem.title}' size="35" /></c:if>
 60                    </td>
 61                </tr><tr>
 62                    <th>Description</th>
 63                    <td>
 64                        <c:if test="${action == 'view'}">${todoItem.description}</c:if>
 65                        <c:if test="${action == 'edit'}"><textarea name='description' id='description' rows="3" cols="38">${todoItem.description}</textarea></c:if>
 66                    </td>
 67                </tr><tr>
 68                     <th>Creation Date</th>
 69                     <td>
 70                         <fmt:parseDate  value="${todoItem.creationDate}"  type="date" pattern="yyyy-MM-dd" var="parsedDate" />
 71                         <fmt:formatDate value="${parsedDate}" type="date" pattern="dd-MMM-yyyy" />
 72                     </td>
 73                </tr><tr>
 74                    <th>Due Date</th>
 75                    <td>
 76                        <c:if test="${action == 'view'}">
 77                            <fmt:parseDate  value="${todoItem.dueDate}"  type="date" pattern="yyyy-MM-dd" var="parsedDate" />
 78                            <fmt:formatDate value="${parsedDate}" type="date" pattern="dd-MMM-yyyy" />
 79                        </c:if>
 80                        <c:if test="${action == 'edit'}"><input type="date" name='dueDate' id='dueDate' value='${todoItem.dueDate}'/></c:if>
 81                    </td>
 82                </tr><tr>
 83                    <th>Status</th>
 84                    <td>
 85                        <c:if test="${action == 'view'}">${todoItem.status}</c:if>
 86                        <c:if test="${action == 'edit'}">
 87                            <select name='status' id='status' value='${todoItem.status}'>
 88                                <option value="">--Select Status--</option>
 89                                <c:forEach items="${todoStatus}" var="status">
 90                                    <option value="${status}"
 91                                        ${status == todoItem.status ? 'selected="selected"' : ''}>${status}
 92                                  </option>
 93                                </c:forEach>
 94                            </select>
 95                        </c:if>
 96                    </td>
 97                </tr><tr>
 98                    <c:if test="${todoItem.systemTasksId > 0}">
 99                        <th>Comments</th>
100                        <c:if test="${action == 'edit' || todoItem.todoTaskCommentsSet.size() > 0}">
101                            <td>
102                                <table class='table-bordered'>
103                                    <thead>
104                                        <tr>
105                                            <th>Creation Date</th>
106                                            <th>Description</th>
107                                        </tr>
108                                    </thead>
109                                    <tbody>
110                                        <c:forEach var="comments" items="${todoItem.todoTaskCommentsSet}">
111                                            <tr>
112                                                <td>
113                                                    <fmt:parseDate value="${comments.creationDate}" type="date" pattern="yyyy-MM-dd" var="parsedDate" />
114                                                    <fmt:formatDate value="${parsedDate}" type="date" pattern="dd-MMM-yyyy" />
115                                                </td>
116                                                <td><c:out value="${comments.taskComments}"/></td>
117                                            </tr>
118                                        </c:forEach>
119                                    </tbody>
120                                </table>
121                                <c:if test="${action == 'edit'}">
122                                <button class="btn btn-success" onclick=addNewComments()>Add New Comments</button>
123                                <table class='table-bordered' id="commentsTable" style="display:none;">
124                                    <tbody>
125                                        <tr>
126                                            <th>Description</th>
127                                            <td><textarea name='description' id='taskComments' rows="3" cols="38"></textarea></td>
128                                        </tr>
129                                    </tbody>
130                                </table>
131                                </c:if>
132                            </td>
133                        </c:if>
134                    </c:if>
135                </tr>
136                <c:if test="${action == 'edit'}">
137                <tr>
138                    <td colspan="2" align="center">
139                        <button class="btn btn-success" onclick=submit(${todoItem.systemTasksId})>Submit</button>
140                    </td>
141                </tr>
142                </c:if>
143            </tbody>
144        </table>
145	</div>
146</body>
147</html>

Running the JSP Spring Boot Project

With these changes, we are ready to run the project.

Run the server using the Configuration settings as shown here.

When we start the project and go to browser and type http://localhost:8080/todo-app/tasks, we will see the index.html in action.

todo-tracker-home-page.jpeg
Todo Tracker Home Page

  • When you click on Create Button

    todo-tracker-create-page.jpeg
    Todo Tracker Create Page

  • Enter the values and Click on the Submit Button in the Create Page

    todo-tracker-home-page-2.jpeg
    Todo Tracker Home Page After Create

  • Click on View Button to go to the below page

    todo-tracker-view-page.jpeg
    Todo Tracker View Page

  • On the Home page, click on the Edit Button to get the Edit Page, where you can update the existing contents or add new comment.

    todo-tracker-edit-page.jpeg
    Todo Tracker Edit Page

  • On the Home page, click on Delete Button and delete the task.

    todo-tracker-home-page.jpeg
    Todo Tracker Home Page After Delete


Conclusion

With this setup, we have come to an end of this article and we have seen how we can developing a Model-View-Controller (MVC) Application using Spring Boot, H2 Database and Java Server Pages (JSP).

Complete code for this project can be found at GitHub here. Go ahead and clone it.

Instructions on how to clone and run the project are provided on the GitHub page.