Oct 1, 2014

Simplifying JavaScript/HTML5 Rich Clients with Java EE

Simplifying JavaScript/HTML5 Rich Clients with Java EE 

JEE7 Angular CRUD Demo
JavaOne 2014 - CON6170
Johannes Weigend

This year at the JavaOne 2014 in San Francisco I did a session together with Geertjan Wielenga. The session was about combining JavaScript/HTML5 Clients with JavaEE. I developed live a JEE7 based CRUD application with an AngularJS frontend. In the linked video you can see every step of the live programming demo: 
JavaOne2014-JEE7-Angular-CRUD

The source is available on Github: https://github.com/jweigend/JEEAngularCRUD.
It contains the customer list, detail, update and delete functionality.
Customer List
It is a simple CRUD Singlepage HTML5 Application developed with NetBeans 8, Glassfish 4.1 and AngularJS. We use a JEE REST Server Backend and a HTML/JS Frontend. The HTML Frontend communicates with REST Services. The Server is stateless. 

In the first step I developed a  REST Backend for JavaDB by using NetBeans, Maven and Glassfish. In the second step I developed a HTML5 Frontend with the Yeoman Angular Generator and showed debugging and development of a Angular Single Page Application
Finally everything was put together in a single Deployment Unit by adding the HTML5 Application as a Maven Resource using the Maven WAR-Plugin.

If you want to repeat the demo by yourself follow these steps:


Step 1: Customer JEE7 REST Server

  • Create a new Maven based Web Application in NetBeans: 
    • Project->New->Maven->Web Application 
  • Use the „Create REST Services from Database“ Wizard to create REST Services direct by connecting to the sample database and choose the Customer table to generate your services.
  • Test the „Count“ Service by clicking the method in the Projects/Webservices Section
  • Create a „Cross Origin Resource Sharing Filter (CORS)“ in NetBeans to make sure the external HTML5 app can access our Webservice (After step 3 - the filter could be later removed for production).
Thats all. Amazing. Thats a perfect starting point for rapid prototyping. Since most enterprises have JEE Application Servers this Application will also meet enterprise requirements. Now we are ready to develop the HTML5 Client.


Step 2: Customer HTML5 AngularJS Client

Use the yo angular generator to generate a Angular HTML5 application. 

yo angular

Prerequisite: Make sure Yeoman is installed. 

$> grunt serve  #opens the browser and shows the generated page


After successful generation you can use grunt to show the generated sources in your browser. „grunt serve“ starts a simple NodeJS server which is a good first test.
We are ready to open the generated project in NetBeans. We use the „HTML Project from existing sources“ type of project.
The NetBeans project has some errors because the generated structure is not direct supported. The problem here is that the downloaded bower dependencies are one directory lower than the index.html file. This is currently not supported by the Netbeans toolchain.
We can fix this easily be changing the directory in the .bowerrc file from bower-components to app/bower-components.
After successful editing of the bower component file we kann download the bower libraries by clicking „bower install“ direct to the app directory in the project tree.
Now we have professional template for our project. The template uses Grunt as build automation tool. It uses bower as library download tool. It has the standard angular structure with unit tests and integration tests.
We now want to have two views. A list view to display the list of customers. A detail view to update or create a single customer. With the Yeoman generator we can create the two views inclusive the corresponding controllers. The reference to the controller code is automatically added to the index.html page.

yo angular:route customer-list
yo angular:route customer-detail

To make a first test we edit customer-list.html to loop over the generated array in the controller.
<div ng-repeat="thing in awesomeThings">
    {{ thing }}    
</div>

We change the awesomeThings array of string to an array of customer objects which contains a name and an email property. 

// customer-list.js
$scope.customers = [{
                    name: "Johannes Weigend",
                    email: "johannes.weigend@weigend.de"
                }, {
                    name: "Jonathan Weigend",
                    email: "jonathan.weigend@weigend.de"
                }];

// customer-list.html 
<tr ng-repeat="customer in customers">
                <td>{{ customer.name }}</td>
                <td>{{ customer.email }}</td>


The complete HTML Code for the customer-list view looks like this:

// customer-list.html
<div class="col-xs-12">
    <h1>Customers</h1>
    <table class="table table-striped table-condensed">
        <thead>
            <tr>
                <th style="min-width: 80px;">First name</th>
                <th style="min-width: 80px;">Last name</th>
                <th style="width:20px;">&nbsp;</th>
                <th style="width:20px;">&nbsp;</th>
            </tr>
        </thead>
        <tbody>
            <tr ng-repeat="customer in customers">
                <td>{{ customer.name }}</td>
                <td>{{ customer.email }}</td>
                <td><a class="btn btn-small btn-primary">edit</a></td>
                <td><a class="btn btn-small btn-danger">delete</a></td>
            </tr>
        </tbody>
    </table>
    <a class="btn btn-default">create new customer</a>
</div>

Now we are ready to connect the UI with our REST service. 

First create a customer-svc factory. 

$ yo angular:factory customer-svc

We have to change the generated customer-svc.js file to return a angular resource object to access our webservice. 

// customer-svc.js
angular.module('customerServices', ['ngResource'])
        .factory('customerSvc', ['$resource',
            function ($resource) {
                return $resource(
                        'http://localhost:8080/customerserver/webresources/com.javaone.customerserver.customer/:customerId:id',
                        {},
                        {}
                        });
            }]);

We also have to add the new module „customerServices“ to our list of module dependencies of our application. Otherwise the module will not be accessible in our controller.

// app.js
angular
  .module('demoClientApp', [
    'ngAnimate',
    'ngCookies',
    'ngResource',
    'ngRoute',
    'ngSanitize',
    'ngTouch', 
    'customerServices'
  ])

We change now the customer list controller to use the Customer Service instead of an hard coded array.

// customer-list.js

$scope.customers = customerSvc.query();


Step 3: Putting HTML5 Client direct into the WAR Webapplication Archive

To include the HTML Project in our JEE Webapp we use the Maven WAR Plugin:

// pom.xml
<plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-war-plugin</artifactId>
     <version>2.3</version>
     <configuration>
         <failOnMissingWebXml>false</failOnMissingWebXml>
         <webResources>
            <resource>
                <!-- this is relative to the pom.xml directory -->
                <directory>../CustomerClient/app</directory>
            </resource>
         </webResources>
     </configuration>
</plugin>

After new Maven build and deployment the page shows up when you start the Glassfish

Customer List View
To create the Update/Create dialog nothing special is needed. If you have this running it should be easy to extend the example as you wish.

Customer Create View
Customer Update View

Johannes Weigend





4 comments:

  1. Do you have source code in github.com or bitbucket.com this example ?

    ReplyDelete
    Replies
    1. I found the source code here https://github.com/jweigend/JEEAngularCRUD

      Delete
  2. how do i deploy the angular bit on glass fish with my java app?

    ReplyDelete
  3. Nice post it is very useful for me.
    Each and every year we are providing Cheap and best students project at Madurai.

    ReplyDelete