Getting Started With MVC 1.0 (JSR 371)

Getting Started With MVC 1.0 (JSR 371)


In this tutorial we will create a simple web application using MVC 1.0 (JSR 371), ThymeleafH2 database, JPA and Thorntail (Wildfly Swarm).
MVC 1.0 is based on JAX-RS and integrates with existing Java EE technologies like CDI and Bean Validation.

Tools You Will Need
Maven 3.3+
Your favorite IDE. I'm using NetBeans
JDK 1.8+

WildFly Swarm Project Generator
Go to http://wildfly-swarm.io/generator/ and follow the steps below to generate a new project.



Enter the Details as Follows

Group ID: com.kodnito
Artifact ID: javaee-mvc-example
Dependencies: JPA, EJB, JAX-RS, MVC 

Click Generate Project to generate and download your project.
Next, Unzip the downloaded zip file and import it into your favorite IDE.
Open the pom.xml and add two more dependencies to the file.


<dependency>
    <groupId>org.mvc-spec.ozark.ext</groupId>
    <artifactId>ozark-thymeleaf</artifactId>
    <version>1.0.0-m03</version>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.196</version>
    <scope>runtime</scope>
</dependency>

We added Thymeleaf and H2 database dependencies to our application.
Your pom.xml should look like this :


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.kodnito</groupId>
    <artifactId>javaee-mvc-example</artifactId>
    <name>javaee-mvc-example</name>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <version.thorntail>2.1.0.Final</version.thorntail>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <failOnMissingWebXml>false</failOnMissingWebXml>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>io.thorntail</groupId>
                <artifactId>bom-all</artifactId>
                <version>${version.thorntail}</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <finalName>demo</finalName>
        <plugins>
            <plugin>
                <groupId>io.thorntail</groupId>
                <artifactId>thorntail-maven-plugin</artifactId>
                <version>${version.thorntail}</version>
        
                <executions>
                    <execution>
                        <goals>
                            <goal>package</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.mvc-spec.ozark.ext</groupId>
            <artifactId>ozark-thymeleaf</artifactId>
            <version>1.0.0-m03</version>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.196</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.thorntail</groupId>
            <artifactId>jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>io.thorntail</groupId>
            <artifactId>ejb</artifactId>
        </dependency>
        <dependency>
            <groupId>io.thorntail</groupId>
            <artifactId>jaxrs</artifactId>
        </dependency>
        <dependency>
            <groupId>io.thorntail</groupId>
            <artifactId>mvc</artifactId>
        </dependency>
    </dependencies>
</project>


In project directory run the following command to download the dependencies.


$ mvn install


Persistence XML
Inside src/main/resources/META-INF/ create persistence.xml and add the following

persistence.xml


<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
             xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
    <persistence-unit name="h2" transaction-type="JTA">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <class>com.kodnito.javaeemvcexample.model.Todo</class>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
            <property name="hibernate.connection.driver_class" value="org.h2.Driver" />
            <property name="hibernate.hbm2ddl.auto" value="update" />
        </properties>
    </persistence-unit>
</persistence>


persistence.xml is the standard configuration file for JPA and it has to be included in the META-INF directory
The persistence.xml file defines what provider to be used, the name of the persistence unit, how classes should be mapped to database tables.

Entity
Create a new java class called Todo.java inside src/main/java/com/kodnito/javaeemvcexample/model/ and add the following

Todo.java


package com.kodnito.javaeemvcexample.model;


import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

@Entity
@Table(name = "todos")
@NamedQuery(name = "Todo.findAll", query = "SELECT t FROM Todo t")
public class Todo {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String task;
    private String description;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getTask() {
        return task;
    }

    public void setTask(String task) {
        this.task = task;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

}


@Entity annotation indicates that it is a JPA entity
@Table annotation is used to name the table in the database
@NamedQuery annotation defines query with a name
@Id annotation is used to define the primary key and the Id property is also annotated with @GeneratedValue to indicate that the Id should be generated automatically.

Create a new java class called TodoForm.java inside src/main/java/com/kodnito/javaeemvcexample/form/ package and add the following

TodoForm.java


package com.kodnito.javaeemvcexample.form;

import javax.mvc.binding.MvcBinding;
import javax.ws.rs.FormParam;

public class TodoForm {
    
    @FormParam("id")
    private String id;

    @FormParam("task")
    private String task;

    @FormParam("description")
    private String description;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getTask() {
        return task;
    }

    public void setTask(String task) {
        this.task = task;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

}


Here we use @FormParam annotation to map HTML form parameters to attributes on TodoForm class.

Controller
Create a new java class called TodoController.java inside src/main/java/com/kodnito/javaeemvcexample/controller/ package and add the following

TodoController.java


package com.kodnito.javaeemvcexample.controller;

import com.kodnito.javaeemvcexample.form.TodoForm;
import com.kodnito.javaeemvcexample.model.Todo;
import java.util.List;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.mvc.Models;
import javax.mvc.annotation.Controller;
import javax.mvc.annotation.View;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.validation.Valid;
import javax.ws.rs.BeanParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;


@Controller
@Stateless
@Path("/todo")
public class TodoController {

    @PersistenceContext
    EntityManager em;

    @Inject
    Models models;

    @GET
    @View("todo/all-todos.html")
    public void getAllTodos() {
        List<Todo> allTodos = em.createNamedQuery("Todo.findAll", Todo.class).getResultList();
        models.put("todos", allTodos);
    }

    @GET
    @Path("/create")
    public String getCreateTodoForm() {
        return "todo/create-todo.html";
    }

    @POST
    @Path("/create")
    public String create(@BeanParam TodoForm todoForm) {
        Todo newTodo = new Todo();
        newTodo.setDescription(todoForm.getDescription());
        newTodo.setTask(todoForm.getTask());
        
        em.persist(newTodo);
        
        return "redirect:/todo";
    }
    
    @GET
    @Path("/update/{id}")
    @View("todo/update-todo.html")
    public void getUpdateTodoForm(@PathParam("id") Long id) {
        Todo todo = em.find(Todo.class, id);
        
        models.put("todo", todo);
    }
    
    @POST
    @Path("/update")
    public String update(@BeanParam TodoForm todoForm) {        
        Todo getTodo = em.find(Todo.class, Long.parseLong(todoForm.getId()));
        
        getTodo.setDescription(todoForm.getDescription());
        getTodo.setTask(todoForm.getTask());
        
        em.merge(getTodo);
        
        return "redirect:/todo";
    }
    
    @GET
    @Path("/delete/{id}")
    public String deleteTodo(@PathParam("id") Long id) {
        Todo todo = em.find(Todo.class, id);
        
        if (!em.contains(todo)) {
            todo = em.merge(todo);
        }

        em.remove(todo);
        return "redirect:/todo";
    }

}


getAllTodos() method retrieves all the todos from the database and return the entire list.
getCreateTodoForm() method will render the create todo form.
create() method will create Todo Object in the database.
getUpdateTodoForm method will render the update todo form.
update() method will update existing Todo Object in the database.
delete() method will find the Todo Object in the database and delete it.

@Controller annotation defines a controller class.
@Path annotation identifies the URI path to which the resource responds.
We inject the Models map to put dynamic content to our views.
Because TodoForm fields are annotated with @FormParam, we can use @BeanParam annotation to inject TodoForm class.
@View annotation is used to define the view name.
@GET annotation maps /todo HTTP GET request to getAll() method, which will retrieve all the todos from the database and return the entire list.
Parameters are accessed with the @PathParam annotation.
@POST annotation is for handling HTTP POST request and it is meant to create a new resource or update an existing resource.

Views
Inside src/main/webapp/WEB-INF/views/todo create all-todos.html and add the following :

all-todos.html


<!DOCTYPE html>
<html>
    <head>
        <title>TODO supply a title</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <h1>My Todos</h1>

        <table>
            <tr>
                <th>Task</th>
                <th>Description</th>
                <th>Edit</th>
                <th>Delete</th>
            </tr>
            <tr th:each="todo: ${todos}">
                <td th:text="${todo.task}"></td>
                <td th:text="${todo.description}"></td>
                <td><a th:href="@{/todo/update/{id}/(id=${todo.id})}" >Edit</a></td>
                <td><a th:href="@{/todo/delete/{id}/(id=${todo.id})}" >Delete</a></td>
            </tr>
        </table>
    </body>
</html>


Here we are iterating over the list of todos using Thymeleaf th:each.

 Inside src/main/webapp/WEB-INF/views/todo create create-todo.html and add the following :

create-todo.html


<!DOCTYPE html>
<html>
    <head>
        <title>TODO supply a title</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>

        <form action="/todo/create" method="post">
            <p>Title: <input type="text" name="task" /></p>
            <p>Content: 
                <input type="text" name="description" /></p>

            <p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
        </form>
    </body>
</html>






Inside src/main/webapp/WEB-INF/views/todo create update-todo.html and add the following :

update-todo.html


<!DOCTYPE html>
<html>
    <head>
        <title>TODO supply a title</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <form action="#" th:action="@{/todo/update}" th:object="${todo}" method="post">
            <input type="hidden" name="id" th:value="*{id}" th:field="*{id}"/>
            <p>Title: <input type="text" th:value="*{task}" th:field="*{task}" name="task" /></p>
            <p>Content: 
                <input type="text" th:value="*{description}" th:field="*{description}" name="description"/></p>

            <p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
        </form>

    </body>
</html>



Your project structure should look like this

$ tree .
.
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── kodnito
    │   │           └── javaeemvcexample
    │   │               ├── controller
    │   │               │   └── TodoController.java
    │   │               ├── form
    │   │               │   └── TodoForm.java
    │   │               ├── model
    │   │               │   └── Todo.java
    │   │               └── rest
    │   │                   └── RestApplication.java
    │   ├── resources
    │   │   └── META-INF
    │   │       └── persistence.xml
    │   └── webapp
    │       └── WEB-INF
    │           └── views
    │               └── todo
    │                   ├── all-todos.html
    │                   ├── create-todo.html
    │                   └── update-todo.html
    └── test
        └── java

In project directory type the following command to run the application.


$ mvn package thorntail:run


Visit mvc-spec.org to learn more about MVC API.



Share this: