Model-View-Controller Pattern

Model–view–controller (usually known as MVC) is a software design pattern that is commonly used for developing web applications. In fact, most web development frameworks (like SparkJava) support this design pattern by default (i.e. they expect you to follow it).

This pattern is used to separate application's concerns:

  • Model represents an object or JAVA POJO carrying data.
  • View represents the visualization of the data that model contains.
  • Controller is the bridge between the model and view. It controls the data flow into model object and updates the view whenever data changes.

In our application, we are building the Views using Apache Velocity templates. Add the following to your gradle's dependencies:

implementation 'com.sparkjava:spark-template-velocity:2.7.1'

So far, we have had three API endpoints, namely /, authors and addauthor, with three separate "views".

/ View

We currently have a homepage which only shows a simple message, let's improve it a little. Save the following file under src/main/resources/public/index.html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Welcome to MyBooks App</title>
</head>
<body>
<h1>Welcome to MyBooks App</h1>
<div class="divContents indexLinkWrapper">
<p><a class="content indexLink" href="/authors">Show all authors</a></p>
<p><a class="content indexLink" href="/addauthor">Add author</a></p>
</div>
</body>
</html>

authors view

Now, on to the authors page; add the following to src/main/resources/public/authors.vm:

<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>List of your favorite books' authors</title>
</head>
<body>
#if ($authors)
<h1>List of the authors of your favorite books:</h1>
<div class="divContents">
<ol>
<p>
#foreach($author in $authors )
<li class="content author"><i>$author.name</i> ($author.nationality) has published $author.numOfBooks books.</li>
#end
</p>
</ol>
</div>
#end
</body>
</html>

In particular, note:

#if ($authors)
.
.
.
#end

and the following:

#foreach($author in $authors )
<li class="content author"><i>$author.name</i> ($author.nationality) has published $author.numOfBooks books.</li>
#end

These are Velocity Template Language (VTL) statements. VTL provides an easy way to incorporate dynamic content in a web page. HTML pages are static meaning that their content is fixed, but quite often the content we'd like to present is dynamic. For example, in our authors view here, we'd like to list all the authors from the Authors table.

Using the above VTL statements, we show all the authors inside an ordered HTML list (i.e. <ol>), where each author is a list item (i.e. <li>). You can see that we iterate through authors and for each author in authors, we show author's name, nationality and numOfBooks e.g. Leo Tolstoy (Russian) has published 22 books. Now, comes the question where to get authors from? The answer is the Model. The dynamic data that we'd like to make a part of our view should be stored in the model objects: Controller does this!

Controller

We must tell our web server to route to authors view (i.e. page) when browser is pointed at http://localhost:7000/authors. Update the following routes in Server.main:

get("/", (req, res) -> {
Map<String, Object> model = new HashMap<String, Object>();
return new ModelAndView(model, "public/index.html");
}, new VelocityTemplateEngine());
get("/authors", (req, res) -> {
Map<String, Object> model = new HashMap<String, Object>();
model.put("authors", new Sql2oAuthorDao(sql2o).listAll());
return new ModelAndView(model, "public/authors.vm");
}, new VelocityTemplateEngine());

After running the WebServer, point your browser to http://localhost:7000/ on the homepage, click on the Show all authors link and you must be redirected to http://localhost:7000/authors where all authors from Authors table are listed.