Skip to content

Instantly share code, notes, and snippets.

@bluekvirus
Created January 23, 2017 22:53
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save bluekvirus/29789fe8080e31d84f921241311e567d to your computer and use it in GitHub Desktop.
Save bluekvirus/29789fe8080e31d84f921241311e567d to your computer and use it in GitHub Desktop.
Develop a Jersey (Restful Web) Application using Hibernate and MariaDB

Develop a Jersey Application using Hibernate and MariaDB

@credit Yan Zhu (https://github.com/nina-zhu)

Introduction

Jersey is the most popular amongst Restful web service development. Latest Jersey 2.x version has been developed by Oracle/Glassfish team in accordance with JAX-RS 2.0 specification. Earlier Jersey 1.x version was developed and supported by Oracle/Sun team.

Latest Jersey release version is 2.25 see here and look documentation and API for details. We will implement a Jersey example in this article based on latest 2.x version.

In this article, we will use Hibernate's rich API to interact with MariaDB database or in general any ORM compliant database. We will create a complete user CRUD application, use MariaDB to store the users records.

Technology Used

  • MariaDB 5.5.52
  • Java 1.8
  • NetBeans IDE 8.2
  • Apache Tomcat 8.5.11
  • Apache Maven 3.3.9
  • Jersey-2.25
  • Jersey-mvc-mustache-2.25
  • Jersey-spring3-2.25
  • Spring framework-4.3.5.RELEASE
  • Hibernate-5.2.6.Final
  • mysql-connector-java-5.1.40

Set Up the MariaDB Server (on Ubuntu 14.04)

First we should set up the MariaDB server.

Install MariaDB

Install the packages from the repositories by typing:

sudo apt-get update
sudo apt-get install mariadb-server libmariadbclient-dev libssl-dev

You will be asked to select and confirm a password for the administrative MariaDB account.

Start MariaDB Server

Most likely, MariaDB is already started after installing, you can run following command to check:

ps -ef | grep mysql

If it is not started, start it manually by running:

sudo service mysql start

And to stop MariaDB server manually, run:

sudo service mysql stop

After installing MariaDB from Ubuntu's repositories, it will be started automatically when system boots up. If you want, you can disable its automatically starting by running:

sudo update-rc.d mysql disable

This will change S19mysql to K81mysql in /etc/rc[2-5].d directories, thus won't start MariaDB database server at boot time.

Perform Initial Configuration

Get MariaDB server started, you can then run through a simple security script to perform the necessary initial configuration:

sudo mysql_secure_installation

You'll be asked for the administrative password you set for MariaDB during installation. Afterwards, you'll be asked a series of questions. Besides the first question, asking you to choose another administrative password, select yes for each question.

With the installation and initial database configuration out of the way, we can move on to create our database and database user.

Create a Database and Database User

We can start by loggin into an interactive session with our database software by typing the following:

mysql -u root -p

You will be prompted for the administrative password you selected during installation. Afterwards, you will be given a prompt.

First, we will create a database for our Jersey project. Each project should have its own isolated database for security reasons. We will call our database "jersey". We'll set the default type for the database to UTF-8, which is what Jersey expects:

CREATE DATABASE jersey CHARACTER SET UTF8;

Remember to end all commands at an SQL prompt with a semicolon.

Next, we will create a database user which we will use to connect to and interact with the database. Set the password to something strong and secure (substitute and with your own ones):

CREATE USER <user>@localhost IDENTIFIED BY '<password>';

Now, all we need to do is give our database user access rights to the database we created (substitute to yours):

GRANT ALL PRIVILEGES ON jersey.* TO <user>@localhost;

Flush the changes so that they will be available during the current session:

FLUSH PRIVILEGES;

Exit the SQL prompt to get back to your regular shell session:

exit

Develop Jersey Application integrating with Hibernate

Now that our database is set up, we can start developing our Jersey application. Before that, we should first set up our development environment.

Install JDK 8

  1. Download "jdk-8u111-linux-x64.tar.gz" from http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
  2. Extract ("/usr/lib/jvm/" is my extracting destination, you can use yours)
$ sudo tar xzvf jdk-8u111-linux-x64.tar.gz -C /usr/lib/jvm/
  1. Set environment variables
$ sudo gedit /etc/profile

Add following lines

# Set Java environment
export JAVA_HOME=/usr/lib/jvm/jdk1.8.0_111
export JRE_HOME=$JAVA_HOME/jre
export CLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib
export PATH=$JAVA_HOME/bin:$PATH

Log out system and log in again. You can now use the java -version to check the Java version.

Install Apache Tomcat

  1. Download "apache-tomcat-8.5.11.tar.gz" from http://tomcat.apache.org/download-80.cgi
  2. Ensure JAVA_HOME environment variable is set and points to your JDK installation
$ echo $JAVA_HOME
  1. Extract distribution archive in any directory
$ tar xzvf apache-tomcat-8.5.11.tar.gz -C ~

Install NetBeans IDE

  1. Download the installer file from https://netbeans.org/downloads/, select the "IDE Language" and "Platform", download the "All" bundle, the file name is "netbeans-8.2-linux.sh"
  2. Make the installer file executable
$ chmod +x netbeans-8.2-linux.sh
  1. Run the installer
$ ./netbeans-8.2-linux.sh

Install Apache Maven

  1. Download "apache-maven-3.3.9-bin.tar.gz" from https://maven.apache.org/download.cgi
  2. Ensure JAVA_HOME environment variable is set and points to your JDK installation
$ echo $JAVA_HOME
  1. Extract distribution archive in any directory
$ tar xzvf apache-maven-3.3.9-bin.tar.gz -C ~
  1. Add the "bin" directory of the created directory "apache-maven-3.3.9" to the PATH environment variable
$ vi ~/.bashrc

Add following lines

export MAVEN_HOME=~/apache-maven-3.3.9
export PATH=$MAVEN_HOME/bin:$PATH

Exit terminal and open a new terminal, run

$ mvn -v

to confirm.

Create a JavaEE Web Application from Maven Archetype

Jersey provides a Maven archetype for creating web application skeletons. To create the new web application skeleton project, execute the following Maven command in the directory where the new project should reside:

$ mvn archetype:generate -DarchetypeArtifactId=jersey-quickstart-webapp -DarchetypeGroupId=org.glassfish.jersey.archetypes -DinteractiveMode=false -DgroupId=com.fortinet.experiment.jersey.examples -DartifactId=user_example -Dpackage=com.fortinet.experiment.jersey.examples.user_example -DarchetypeVersion=2.25

Feel free to adjust the "groupId", "package" and/or "artifactId" of your new web application project. Alternatively, you can change it by updating the new project "pom.xml" once it gets generated. Note: It may take a while on the first run, this is because Maven is downloading the most recent artifacts (plugin jars and other files) into your local repository. You may also need to execute the command a couple of times before it succeeds, this is because the remote server may time out before your downloads are complete.

Once the project generation from a Jersey maven archetype is successfully finished, you should see the new "user_example" project directory created in your current location. The directory contains a standard Maven project structure, let's have a look at it in NetBeans IDE. Open NetBeans IDE, click menu "File > Open Project...", choose the project you just generated, click "Open Project" button, the project is opened in NetBeans IDE. In "Files" window, we can see following project structure:

  • Project build and management configuration is described in the pom.xml located in the project root directory.
  • Project sources are located under src/main/java.
  • Project resources are located under src/main/resources.
  • Project web application files are located under src/main/webapp. There is a generated "MyResource.java" file under "src/main/java/com/fortinet/experiment/jersey/examples/user_example" folder, here we don't need it, thus delete it.

Mavenize required jars

Add "Jersey-2.25", "jersey-mvc-mustache-2.25", "Jersey-spring3-2.25", "Spring-4.3.5.RELEASE", "Hibernate-5.2.6.Final", "mysql-connector-java-5.1.40", etc. dependencies. To do this, change the generated "pom.xml" file content to following: pom.xml

<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.fortinet.experiment.jersey.examples</groupId>
    <artifactId>user_example</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>user_example</name>

    <build>
        <finalName>user_example</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven.compiler.version}</version>
                <inherited>true</inherited>
                <configuration>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.glassfish.jersey</groupId>
                <artifactId>jersey-bom</artifactId>
                <version>${jersey.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet-core</artifactId>
            <!-- use the following artifactId if you don't need servlet 2.x compatibility -->
            <!-- artifactId>jersey-container-servlet</artifactId -->
        </dependency>
        
        <!-- Jersey extension module providing support for Mustache templates -->
        <dependency>
            <groupId>org.glassfish.jersey.ext</groupId>
            <artifactId>jersey-mvc-mustache</artifactId>
        </dependency>
        
        <!-- Jersey extension module providing support for Spring 3 integration -->
        <dependency>
            <groupId>org.glassfish.jersey.ext</groupId>
            <artifactId>jersey-spring3</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-core</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-web</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-beans</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-aop</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.hibernate</groupId>
                    <artifactId>hibernate-validator</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        
        <!-- Spring Framework 4.x -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>
        
        <!-- Hibernate Core 5.2.x -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-ehcache</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.3.4.Final</version>
        </dependency>
        
        <!-- MySql-Connector -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
    </dependencies>
    
    <properties>
        <jersey.version>2.25</jersey.version>
        <spring.version>4.3.5.RELEASE</spring.version>
        <hibernate.version>5.2.6.Final</hibernate.version>
        <mysql.version>5.1.40</mysql.version>
        <compileSource>1.8</compileSource>
        <maven.compiler.version>3.6.0</maven.compiler.version>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
</project>

Initialize Database

New a file, named "init-db.sql", under "src/main/resources". Write following sql statements to create a table and insert a few records: init-db.sql

DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `id` INT(6) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(50) NOT NULL,
  `password` VARCHAR(50) NOT NULL,
  PRIMARY KEY (`id`)
);

Log into mysql client:

$ mysql -u root -p

Enter password then use database "jersey" that you created previously:

> use jersey;

Execute the sql file:

> source /<path to your location>/user_example/src/main/resources/init-db.sql;

Check the records:

> select * from users;

Exit client:

> exit

Develop the Web Application

web.xml

For any web application, entry point is web.xml which describes how the incoming http requests are served / processed.

This web.xml file describes,

  • Like any JavaEE web framework, register org.glassfish.jersey.servlet.ServletContainer with servlet container
  • Set <init-param> with <param-name> as "jersey.config.server.provider.packages" and <param-value> describing the qualified package name of the JAX-RS annotated Resource/Provider classes. In this example, "com.fortinet.experiment.jersey.examples.user_example.service"
  • Set <init-param> with <param-name> as "jersey.config.server.provider.classnames" and <param-value> describing the qualified class name of MustacheMvcFeature to use the capabilities of Jersey MVC templating support, here we use Mustache templating engine
  • Set <init-param> with <param-name> as "jersey.config.server.mvc.templateBasePath.mustache" and <param-value> as "templates" to configure the base path where Mustache templates are located
  • HTTP requests with URL pattern "/rest/*" will be sent to the registered servlet called "jersey-servlet" i.e. org.glassfish.jersey.servlet.ServletContainer
  • Register spring listener org.springframework.web.context.ContextLoaderListener
  • <context-param> with its attributes describes the location of the "spring-hibernate-jersey2.xml" file from where it has to be loaded. We will discuss briefly about this file
  • <welcome-file-list> files under this tag is the start-up page

web.xml (under "src/main/webapp/WEB-INF")

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    
    <!-- Jersey Servlet -->
    <servlet>
        <servlet-name>jersey-servlet</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <!-- Register resources and providers -->
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>com.fortinet.experiment.jersey.examples.user_example.service</param-value>
        </init-param>
        <!-- Register and configure MvcFeature -->
        <init-param>
            <param-name>jersey.config.server.provider.classnames</param-name>
            <param-value>org.glassfish.jersey.server.mvc.mustache.MustacheMvcFeature</param-value>
        </init-param>
        <init-param>
            <param-name>jersey.config.server.mvc.templateBasePath.mustache</param-name>
            <param-value>templates</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>jersey-servlet</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
    
    <!-- Spring Listener -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    <!-- Load Spring context for registering beans within application context -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>WEB-INF/spring-hibernate-jersey2.xml</param-value>
    </context-param>
    
    <!-- Welcome File -->
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

Spring Application Context File

This Spring application context file describes,

  • <context:annotation-config /> to activate annotation on the registered beans within application context
  • <context:component-scan base-package=""/> tag scans all classes & sub-classes under the value of "base-package" attribute and register them with the Spring container
  • <tx:annotation-driven /> to turn ON transaction annotation on all DAO methods
  • bean with id="transactionManager" to inform Spring to take care of the database transaction. All methods annotated with @Transactional
  • bean with id="sessionFactory" defines hibernate properties to let it take care of database operations using Hibernate's rich API
  • bean with id="dataSource" defines values for "driverClassName", "url", "username" and "password" for MySql/MariaDB database Note: injection series between transactionManager, sessionFactory and dataSource

spring-hibernate-jersey2.xml (substitute and with your database username and password)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
    
    <!-- to activate annotations in beans already registered in the application context -->
    <context:annotation-config />
    
    <!-- scans packages to find and register beans within the application context -->
    <context:component-scan base-package="com.fortinet.experiment.jersey.examples.user_example" />
    
    <!-- turn on spring transaction annotation -->
    <tx:annotation-driven transaction-manager="transactionManager" />
    
    <!-- Transaction Manager -->
    <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    
    <!-- Session Factory -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="annotatedClasses">
            <list>
                <value>com.fortinet.experiment.jersey.examples.user_example.model.User</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>
    </bean>
    
    <!-- dataSource configuration -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/jersey" />
        <property name="username" value="<user>" />
        <property name="password" value="<password>" />
    </bean>
    
</beans>

Model Class (POJO)

Model class User with three primitive attributes with their getter/setter. Also Hibernate POJO class is annotated describing the mapping between java property and database columns. @Entity: represents an object that can be persisted in the database and for this class should have no-arg constructor @Table: describes which table in the database to map with this class @Id: defines this is unique which means it represents primary key in the database table @GeneratedValue: this will be taken care by hibernate to define generator sequence @Column: tells to map this particular property to table column in the database Note: we can add attributes to the @Column annotation like name, length, nullable and unique

User.java

package com.fortinet.experiment.jersey.examples.user_example.model;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="users")
public class User implements Serializable {
    
    // member variables
    @Id
    @GeneratedValue
    @Column(name="id")
    private int id;
    
    @Column(name="name")
    private String name;
    
    @Column(name="password")
    private String password;
    
    // getters & setters
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}

URL Pattern

HTTP URL for any common web application is http://<server>:<port>/<root-context>/<from_here_application_specific_path>. In our example, we are going to deploy the war into Apache Tomcat server so our server and port are localhost and 8080 respectively. Context root is the project name i.e. "user_example". Initial path for this application is "http://localhost:8080/user_example". We have configured "/rest/*" as url-pattern for the "jersey-servlet" servlet in web.xml and at class-level path configured is "/users" using @Path annotation. Next respective path for each method annotated with @Path (method-level).

User Service

Defines basic CRUD operations for User service,

  • @GET - retrieve all users (get all users)
  • @POST - create/insert a new resource (add new user)
  • @GET - read/select internal resource representation based on the user id
  • @PUT - update/modify an internal resource representation (modify user)
  • @DELETE - delete/remove a resource (delete user)

Let's discuss @Produces, @Consumes and MediaType.

@Consumes Defines which MIME type is consumed by this method. For example, methods annotated with @Consumes(MediaType.APPLICATION_JSON) support JSON format. Note: When Content-Type is not specified in the header, then by default it expects request body in "application/x-www-form-urlencoded".

@Produces Defines which MIME type it will produce. For example, methods annotated with @Produces(MediaType.APPLICATION_JSON) produce response in JSON format. Note: @Produces can accept a list of types, in this case, when invoked it returns the response in the format which is the first string in the array. So, to get the response in the other format then set accept="" in the header.

Most widely used Media Types are

  • APPLICATION_XML
  • APPLICATION_JSON
  • TEXT_HTML
  • TEXT_PLAIN
  • TEXT_XML
  • APPLICATION_FORM_URLENCODED Note: Jersey doesn't inherit JAX-RS annotations, so we are annotating Resource/Provider classes and then defining qualified package name in web.xml.

UserService.java

package com.fortinet.experiment.jersey.examples.user_example.service;

import java.util.List;
import java.net.URI;
import javax.ws.rs.core.Response;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
//import javax.ws.rs.PUT;
//import javax.ws.rs.DELETE;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import org.glassfish.jersey.server.mvc.Viewable;
import org.glassfish.jersey.server.mvc.Template;

import com.fortinet.experiment.jersey.examples.user_example.model.User;
import com.fortinet.experiment.jersey.examples.user_example.dao.UserDAO;

@Component
@Path("/users")
public class UserService {
    
    @Autowired
    private UserDAO userDAO;
    
    // Basic CRUD operations for User service
    
    // http://localhost:8080/user_example/rest/users/
    @GET
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces(MediaType.TEXT_HTML)
    @Template(name="/users")
    public List<User> getAllUsers() {
        return userDAO.getAll();
    }
    
    // http://localhost:8080/user_example/rest/users/showForm
    @GET
    @Path("showForm")
    @Produces(MediaType.TEXT_HTML)
    public Viewable showForm() {
        return new Viewable("/userForm");
    }
    
    // http://localhost:8080/user_example/rest/users/get/1
    @GET
    @Path("get/{id}")
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces(MediaType.TEXT_HTML)
    @Template(name="/userForm")
    public User getUser(@PathParam("id") int userId) {
        return userDAO.get(userId);
    }
    
    // http://localhost:8080/user_example/rest/users/add
    @POST
    @Path("add")
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces(MediaType.TEXT_HTML)
    @Template(name="/users")
    public List<User> createUser(@FormParam("username") String username,
                                 @FormParam("password") String password) {
        User newUser = new User();
        newUser.setName(username);
        newUser.setPassword(password);
        userDAO.insertNew(newUser);
        return getAllUsers();
    }
    
    // http://localhost:8080/user_example/rest/users/update
    @POST // should use @PUT
    @Path("update")
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces(MediaType.TEXT_HTML)
    @Template(name="/users")
    public List<User> updateUser(@FormParam("id") int userId,
                                 @FormParam("username") String username,
                                 @FormParam("password") String password) {
        User user = new User();
        user.setId(userId);
        user.setName(username);
        user.setPassword(password);
        userDAO.update(user);
        return getAllUsers();
    }
    
    // http://localhost:8080/user_example/rest/users/delete/1
    @GET // should use @DELETE
    @Path("delete/{id}")
    public Response deleteUser(@PathParam("id") int userId) throws Exception {
        User user = new User();
        user.setId(userId);
        userDAO.remove(user);
        return Response.temporaryRedirect(new URI("/user_example/rest/users")).build();
    }
}

Note: We should use @PUT for "updateUser" method and @DELETE for "deleteUser" method, here I use @POST and @GET respectively because I do not specify method in client page code (i.e. the template code), I just use the standard <form action="xxx"> and <a> link to send requests for simplicity.

DAO Layer

This DAO layer takes care of the database interaction i.e. uses Hibernate's rich API to interact with MySql/MariaDB database using MySQLDialect.

UserDAO.java

package com.fortinet.experiment.jersey.examples.user_example.dao;

import java.util.List;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import org.hibernate.Session;
import org.hibernate.SessionFactory;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.fortinet.experiment.jersey.examples.user_example.model.User;

@Repository("userDAO")
public class UserDAO {
    
    @Autowired
    private SessionFactory sessionFactory;

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
    
    @SuppressWarnings("unchecked")
    @Transactional
    public List<User> getAll() {
        Session session = sessionFactory.getCurrentSession();
        CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
        CriteriaQuery<User> criteriaQuery = criteriaBuilder.createQuery(User.class);
        Root<User> from = criteriaQuery.from(User.class);
        CriteriaQuery<User> select = criteriaQuery.select(from);
        TypedQuery<User> typedQuery = session.createQuery(select);
        List<User> users = typedQuery.getResultList();
        return users;
    }
    
    @Transactional
    public String insertNew(User user) {
        // insert into database & return primary key
        int userId = (Integer) sessionFactory.getCurrentSession().save(user);
        return "User information saved successfully with id " + userId;
    }
    
    @Transactional
    public User get(int userId) {
        User user = (User) sessionFactory.getCurrentSession().get(User.class, userId);
        return user;
    }
    
    @Transactional
    public String update(User user) {
        sessionFactory.getCurrentSession().update(user);
        return "User information updated successfully";
    }
    
    @Transactional
    public String remove(User user) {
        sessionFactory.getCurrentSession().delete(user);
        return "User information with id " + user.getId() + " deleted successfully";
    }
}

Add Templates

Create "templates" folder under "src/main/webapp", then create 2 templates for User service under "templates":

users.mustache

<!DOCTYPE html>
<html>
  <head>
    <title>Users</title>
    <style>
      .row {
        line-height: 2;
      }
      .header {
        font-weight: bold;
      }
      .col {
        float: left;
        width: 25%;
      }
      .toolbar {
        margin-bottom: 20px;
      }
      .info {
        font-style: italic;
      }
    </style>
  </head>
  <body>
    <h2>Users</h2>
    <div class="toolbar">
      <a href="/user_example/rest/users/showForm">Create New One</a>
    </div>
    <div>
      <div class="row header">
        <div class="col">ID</div>
        <div class="col">User Name</div>
        <div class="col">Password</div>
        <div class="col">Actions</div>
      </div>
      {{#.}}
      <div class="row">
        <div class="col">{{id}}</div>
        <div class="col">{{name}}</div>
        <div class="col">{{password}}</div>
        <div class="col">
          <a href="/user_example/rest/users/get/{{id}}">Edit</a>
          <a href="/user_example/rest/users/delete/{{id}}">Delete</a>
        </div>
      </div>
      {{/.}}
      {{^.}}
      <div class="info">Empty List</div>
      {{/.}}
    </div>
  </body>
</html>

userForm.mustache

<!DOCTYPE html>
<html>
  <head>
    <title>User Form</title>
    <style>
    .row {
      line-height: 2;
    }
    .row .label {
      float: left;
      width: 40%;
      text-align: right;
      margin-right: 20px;
    }
    .toolbar {
      text-align: center;
      margin-top: 30px;
    }
    </style>
  </head>
  <body>
    <h2>User Form</h2>
    <form action="{{^id}}/user_example/rest/users/add{{/id}}{{#id}}/user_example/rest/users/update{{/id}}" method="POST">
      <input type="hidden" name="id" value="{{id}}" />
      <div class="row">
        <div class="label">User Name</div>
        <div class="control">
          <input type="text" name="username" value="{{name}}" {{#name}}readonly{{/name}} />
        </div>
      </div>
      <div class="row">
        <div class="label">Password</div>
        <div class="control">
          <input type="text" name="password" value="{{password}}" />
        </div>
      </div>
      <div class="toolbar">
        <input type="submit" value="Save" />
        <a href="/user_example/rest/users">Cancel</a>
      </div>
    </form>
  </body>
</html>

Modify Welcome File

We've specified "index.jsp" as welcome file in "web.xml". The original "index.jsp" file is generated by archetype "jersey-quickstart-webapp", let's modify it a little to provide a link to the User service.

index.jsp

<html>
<body>
    <h2>Jersey RESTful Web Application!</h2>
    <p><a href="/user_example/rest/users">User Service</a>
    <p>Visit <a href="http://jersey.java.net">Project Jersey website</a>
    for more information on Jersey!
</body>
</html>

Build Project

Now, all the code is done, it is time to build this project using maven capability of NetBeans. Right click on "user_example" project to open context menu, select "Clean and Build" option. Maven will start building the project. You can see the output in NetBeans "Output" window.

Run Application in NetBeans

After building successfully, we can run the application in NetBeans.

First, we have to add Apache Tomcat server to NetBeans IDE. Go to "Services" window, right click "Servers" node, click "Add Server..." option, in dialog "Add Server Instance", choose server "Apache Tomcat or TomEE", click "Next>" button, specify the server location which is your Apache Tomcat installing location, enter the credentials (username, password) of an user in the manager role, check the checkbox "Create user if it does not exist" to create the user, click "Finish" button. You can see "Apache Tomcat or TomEE" under "Servers" node.

Then, we can run the application. Right click on "user_example" project, select "Run" as option, in the "Select deployment server" dialog, choose server "Apache Tomcat or TomEE", select option "Remember in Current IDE Session" to remember the deployment server in current IDE session so you don't have to select server every time you run the application. Click "OK" button.

After a while, your default browser will open page "http://localhost:8080/user_example/", what you see is the "index.jsp" page. You can test User service by clicking the "User Service" link.

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment