Ebooks

Java MVC tutorial

Java MVC tutorial is an introductory tutorial to Java MVC framework. We create a simple web application with Java MVC and deploy it on Tomcat and Glassfish.

MVC

Model Miew Controller (MVC) architectural pattern separates an application into three parts: a model, a view, and a controller. The model represents the data in the application, the view is the visual representation of the data, and the controller processes and responds to events, typically user actions, and may invoke changes on the model. The idea is to separate the data access and business logic from data presentation and user interaction, by introducing an intermediate component: the controller.

Java MVC

Java MVC is a specification (JSR-371) for a new Java action-based web framework. It is an alternative to the traditional component-based JSF. The MVC API is layered on top of JAX-RS and integrates with existing Java EE technologies like CDI and Bean Validation. Eclipse Ozark is an implementation of Java MVC. It currently contains support for RESTEasy, Jersey, and Apache CXF.

A MVC controller is a JAX-RS resource method decorated by @Controller. MVC controllers are responsible for combining data models and views (templates) to produce web application pages. A model carries data that is displayed in the view. Models are created with @Named annotation or by injecting Models interface.

A view defines the structure of the output page and can refer to one or more models. It is the responsibility of a view engine to render a view by extracting the information in the models and producing the output page.

Java MVC example in Tomcat

We create a simple web application with Java MVC and deploy it on Tomcat. From the JAX-RS libraries, we chose Jersey.

$ tree
.
├── nb-configuration.xml
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── zetcode
    │   │           ├── conf
    │   │           │   └── ApplicationConfig.java
    │   │           ├── controller
    │   │           │   └── HelloController.java
    │   │           └── model
    │   │               └── Message.java
    │   ├── resources
    │   └── webapp
    │       ├── index.html
    │       ├── META-INF
    │       │   └── context.xml
    │       └── WEB-INF
    │           ├── beans.xml
    │           └── views
    │               └── hello.jsp
    └── test
        └── java

This is the project structure.

pom.xml
<?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/xsd/maven-4.0.0.xsd">
    
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>JavaMvcTomcatEx</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>JavaMvcTomcatEx</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.glassfish.jersey</groupId>
                <artifactId>jersey-bom</artifactId>
                <version>2.26</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>    
    
    <dependencies>
        
        <dependency>
            <groupId>org.glassfish.jersey.inject</groupId>
            <artifactId>jersey-hk2</artifactId>
        </dependency>            
        
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet</artifactId>
        </dependency>

        <dependency>
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-server</artifactId>
        </dependency>       
        
        <dependency>
            <groupId>org.glassfish.jersey.ext.cdi</groupId>
            <artifactId>jersey-cdi1x</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.glassfish.jersey.ext</groupId>
            <artifactId>jersey-bean-validation</artifactId>
        </dependency>

        <dependency>
            <groupId>javax.enterprise</groupId>
            <artifactId>cdi-api</artifactId>
            <version>2.0-EDR1</version>
        </dependency>
        
        <dependency>
            <groupId>org.jboss.weld.servlet</groupId>
            <artifactId>weld-servlet-shaded</artifactId>
            <version>3.0.2.Final</version>
        </dependency>              
        
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.2.2.Final</version>
        </dependency>     
        
        <dependency>
            <groupId>javax.mvc</groupId>
            <artifactId>javax.mvc-api</artifactId>
            <version>1.0-pr</version>
        </dependency>
        
        <dependency>
            <groupId>org.mvc-spec.ozark</groupId>
            <artifactId>ozark-core</artifactId>
            <version>1.0.0-m03</version>
        </dependency>        
        
        <dependency>
            <groupId>org.mvc-spec.ozark</groupId>
            <artifactId>ozark-jersey</artifactId>
            <version>1.0.0-m03</version>
        </dependency>          
        
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>

        </plugins>
    </build>

</project>

In order to run Java MVC on Tomcat, we need to include several dependencies for Java MVC, Jersey, Bean Validation, and CDI.

context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/JavaMvcTomcatEx">

    <Resource name="BeanManager" 
              auth="Container"
              type="javax.enterprise.inject.spi.BeanManager"
              factory="org.jboss.weld.resources.ManagerObjectFactory" />
    
</Context>

In the Tomcat's context.xml file, we define the context path and register Weld's BeanManager factory.

beans.xml
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
       bean-discovery-mode="all">
    
</beans>

In the WEB-INF directory, we have an empty beans.xml file. It is a deployment descriptor for CDI. It can be used for configuring interceptors, decorators, and other things. Even if we do no configurations, we need to add an empty beans.xml for registering CDI.

ApplicationConfig.java
package com.zetcode.conf;

import com.zetcode.controller.HelloController;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("mvc")
public class ApplicationConfig extends Application {

    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> set = new HashSet<>();
        set.add(HelloController.class);
        return set;
    }
}

ApplicationConfig is the application configuration class. It is possible to omit the web.xml file since Servlet 3.0. In Jersey, we create a configuration class that extends the abstract Application and use the @ApplicationPath annotation. The Application defines the components of a JAX-RS application and supplies additional meta-data. Here we register resource classes, providers, or properties the application needs.

set.add(HelloController.class);

We register the HelloController.

Message.java
package com.zetcode.model;

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named("message")
@RequestScoped
public class Message {
    
    private String text;

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

This is a model class. It holds data for the view. The @Named annotation gives a model a name. We will refer to the model in the view. The @RequestScoped makes the model valid for the life of the request.

HelloController.java
package com.zetcode.controller;

import com.zetcode.model.Message;
import javax.inject.Inject;
import javax.mvc.annotation.Controller;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

@Path("hello")
@Controller
public class HelloController {

    @Inject
    private Message message;

    @GET
    public String hello() {
        
        message.setText("Today is a sunny day");
        
        return "hello.jsp";
    }
}

A class decorated with a @Controller is a Java MVC controller. With @Path, it is bound to the hello path segment.

@Inject
private Message message;

With @Inject, we inject the model object. It carries data from the controller to the view.

@GET
public String hello() {
    
    message.setText("Today is a sunny day");
    
    return "hello.jsp";
}

The hello() method reacts to a GET request. It sets data to the model and returns a view. A string returned from a controller method is interpreted as a view path. The view engine's default directory for views is WEB-INF/views.

hello.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        <p>
           The message: ${message.text}
        </p>
    </body>
</html>

This is the view. It displays the data with the ${} syntax.

index.html
<!DOCTYPE html>
<html>
    <head>
        <title>Home Page</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <p>
            <a href="mvc/hello">Get message</a>
        </p>
    </body>
</html>

This is a home page. It contains a link to call the controller.

Java MVC example in Glassfish

To run the example on Glassfish, we do not need the context.xml file and we need the following three dependencies:

<dependencies>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-web-api</artifactId>
        <version>7.0</version>
        <scope>provided</scope>
    </dependency>
    
    <dependency>
        <groupId>javax.mvc</groupId>
        <artifactId>javax.mvc-api</artifactId>
        <version>1.0-pr</version>
    </dependency>
    <dependency>
        <groupId>org.mvc-spec.ozark</groupId>
        <artifactId>ozark-jersey</artifactId>
        <version>1.0.0-m03</version>
    </dependency>    
</dependencies>

Glasfish already contains many libraries that are not present in Tomca. No other modifications are necessary.

In this tutorial, we have introduced the Java MVC framework. You might also be interested in the related tutorials: Java tutorial, Java MVC Thymeleaf tutorial, Introduction to Play, Introduction to Stripes, or Java Spark tutorial.