Develop a REST application using Jakarta EE and AngularJS

In this tutorial, we will walk through the process of developing an AngularJS frontend for a REST server application. AngularJS is a popular JavaScript framework that simplifies the development of dynamic web applications. We will assume that you have basic knowledge of HTML, CSS, and JavaScript.

Prerequisites

  • Basic knowledge of HTML, CSS, and JavaScript.
  • JDK and a Java Application Server such as WildFly

To keep this tutorial simple, we will not install Node Package Manager (npm) to bootstrap our AngularJS project. We do recommend to use it if you want to advance your AngularJS skills.

Do I need NPM to develop Angular JS applications?

Using the npm package manager is not mandatory but it provides several advantages for managing dependencies and building AngularJS applications. Npm simplifies dependency management by allowing you to specify dependencies and their versions in a package.json file. It also integrates well with version control systems and offers module resolution for organized code. Finally, npm enables the use of build tools and task runners for automation and optimization. Overall, npm enhances development workflow, maintainability, and collaboration in AngularJS projects.

Coding the Back end REST Application

Firstly, we will code our REST Application which will expose a set of CRUD (Create, Read, Update and Delete) methods to manage an Entity Class.

Therefore, let’s begin from the Entity Customer Class which follows here:

@Entity
@NamedQuery(name = "Customers.findAll",
        query = "SELECT c FROM Customer c ORDER BY c.id")
public class Customer {
    @Id
    @SequenceGenerator(
            name = "customerSequence",
            sequenceName = "customerId_seq",
            allocationSize = 1,
            initialValue = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "customerSequence")
    private Long id;
    @Column(length = 40)
    private String name;
    @Column(length = 40)
    private String surname;

    // Getters/Setters omitted for brevity

}

To manage our Entity application we will add a Repository Class which is a CDI Bean with a set of @Transactional methods and one method to fetch the list of Customers:

@ApplicationScoped
public class CustomerRepository {

    @PersistenceContext
    private EntityManager entityManager;

    public List<Customer> findAll() {
        return entityManager.createNamedQuery("Customers.findAll", Customer.class)
                .getResultList();
    }

    public Customer findCustomerById(Long id) {

        Customer customer = entityManager.find(Customer.class, id);

        if (customer == null) {
            throw new WebApplicationException("Customer with id of " + id + " does not exist.", 404);
        }
        return customer;
    }
    @Transactional
    public void updateCustomer(Customer customer) {

        Customer customerToUpdate = findCustomerById(customer.getId());
        customerToUpdate.setName(customer.getName());
        customerToUpdate.setSurname(customer.getSurname());
    }
    @Transactional
    public Customer createCustomer(Customer customer) {

        entityManager.persist(customer);
        entityManager.flush(); // Ensures the ID is populated after persistence
        return customer;

    }
    @Transactional
    public void deleteCustomer(Long customerId) {

        Customer c = findCustomerById(customerId);
        entityManager.remove(c);
    }


}

Finally, all the Service methods are mapped by a REST Endpoint which produces and consumes JSON Content:

@Path("customers")
@ApplicationScoped
@Produces("application/json")
@Consumes("application/json")
public class CustomerEndpoint {

    @Inject CustomerRepository customerRepository;

    @GET
    public List<Customer> getAll() {
        return customerRepository.findAll();
    }

    @POST
    public Response create(Customer customer) {

        Customer c =  customerRepository.createCustomer(customer);
        return Response.status(201).entity(customer).build();
    }
    
    @PUT
    public Response update(Customer customer) {
        customerRepository.updateCustomer(customer);         
        return Response.status(204).build();
    }
    @DELETE
    public Response delete(@QueryParam("id") Long customerId) {
        customerRepository.deleteCustomer(customerId);
        return Response.status(204).build();
    }

}

Connecting the Back end to the Datasource

This simple REST Application will connect to the application server’s default Datasource, which is for WildFly the H2 Database available at the JNDI Binding java:jboss/datasources/ExampleDS

<persistence xmlns="https://jakarta.ee/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_1.xsd"
             version="3.1">
             
    <persistence-unit name="primary">
        <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
        <properties>
            <!-- Properties for Hibernate -->
            <property name="hibernate.hbm2ddl.auto" value="create-drop" />
            <property name="hibernate.show_sql" value="false" />
        </properties>
    </persistence-unit>
</persistence>           

Coding the AngularJS Front end

Our front end includes just a single inde.xhtml page which contains an AngularJS Controller that manages access to the REST Endpoint. Here is the index.html page:

<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
    <meta charset="UTF-8">
    <title>Customer Management</title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
</head>
<body ng-controller="CustomerController">

    <h1>Customer Management</h1>

    <form ng-submit="createCustomer()">
        <input type="text" ng-model="newCustomer.name" placeholder="Name" required>
        <input type="text" ng-model="newCustomer.surname" placeholder="Surname" required>
        <button type="submit">Create</button>
    </form>

    <table>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Surname</th>
            <th>Actions</th>
        </tr>
        <tr ng-repeat="customer in customers">
            <td>{{customer.id}}</td>
            <td>{{customer.name}}</td>
            <td>{{customer.surname}}</td>
            <td>
                <button ng-click="editCustomer(customer)">Edit</button>
                <button ng-click="deleteCustomer(customer.id)">Delete</button>
            </td>
        </tr>
    </table>

    <form ng-show="isEditing" ng-submit="updateCustomer()">
        <input type="text" ng-model="editedCustomer.name" required>
        <input type="text" ng-model="editedCustomer.surname" required>
        <button type="submit">Update</button>
        <button ng-click="cancelEditing()">Cancel</button>
    </form>

    <script>
        var app = angular.module('myApp', []);

        app.controller('CustomerController', function($scope, $http) {
            $scope.customers = [];
            $scope.newCustomer = {};
            $scope.editedCustomer = {};
            $scope.isEditing = false;

            // Fetch all customers
            $http.get('rest/customers')
                .then(function(response) {
                    $scope.customers = response.data;
                });

            // Create a new customer
            $scope.createCustomer = function() {
            $http.post('rest/customers', $scope.newCustomer)
                .then(function(response) {
                    $scope.customers.push(response.data);
                    $scope.newCustomer = {};
                });
        };


            // Edit a customer
            $scope.editCustomer = function(customer) {
                $scope.isEditing = true;
                $scope.editedCustomer = angular.copy(customer);
            };

            // Update a customer
            $scope.updateCustomer = function() {
            $http.put('rest/customers', $scope.editedCustomer)
                .then(function(response) {
                    $scope.isEditing = false;
                    // Reload all customers
                    $http.get('rest/customers')
                        .then(function(response) {
                            $scope.customers = response.data;
                        });
                });
};


            // Delete a customer
            $scope.deleteCustomer = function(customerId) {
                $http.delete('rest/customers?id=' + customerId)
                    .then(function(response) {
                        var index = $scope.customers.findIndex(function(customer) {
                            return customer.id === customerId;
                        });
                        $scope.customers.splice(index, 1);
                    });
            };

            // Cancel editing
            $scope.cancelEditing = function() {
                $scope.isEditing = false;
            };
        });
    </script>

</body>
</html>

the Angular controller CustomerController contains several methods that handle different functionalities of the customer management application. Here’s an explanation of each method:

  1. createCustomer(): This method is invoked when the form is submitted to create a new customer. It sends an HTTP POST request to the 'rest/customers' endpoint, passing the newCustomer object. Upon successful response, it adds the newly created customer to the customers array and resets the newCustomer object.
  2. editCustomer(customer): This method is triggered when the “Edit” button is clicked for a customer. It sets the isEditing flag to true and makes a copy of the selected customer object, storing it in editedCustomer. This enables editing the customer’s details.
  3. updateCustomer(): This method is executed when the form for updating a customer is submitted. It sends an HTTP PUT request to the 'rest/customers' endpoint, updating the customer details with the editedCustomer object. Upon successful response, it sets isEditing to false and reloads all customers by making an HTTP GET request to 'rest/customers'.
  4. deleteCustomer(customerId): When the “Delete” button is clicked for a customer, this method is called. It sends an HTTP DELETE request to the 'rest/customers' endpoint, passing the customerId as a query parameter. Upon successful response, it finds the index of the deleted customer in the customers array and removes it using splice().
  5. cancelEditing(): This method is triggered when the “Cancel” button is clicked during editing. It sets isEditing to false, canceling the editing mode.

These methods utilize the $http service to make HTTP requests to interact with the REST server and update the application’s data accordingly. They are responsible for creating, editing, updating, and deleting customers, as well as fetching the initial list of customers from the server.

Running and Testing our application

We can deploy the application on WildFly with a simple set of Maven goals:

mvn install wildfly:deploy

And then you can access the index.html page at: http://localhost:8080/jaxrs-demo/

angularjs rest service integration

The Create button will let you add another Customer Entity through the AngularJS Controller and the REST Service. The Edit and Delete Buttons will let you modify or delete an existing one.

Conclusion

In conclusion, by integrating AngularJS as the frontend framework for your Jakarta EE REST application, you can deliver a modern and engaging user experience, streamline data communication, and build a robust full-stack web application. So, go ahead and start building your AngularJS frontend to complement your Jakarta EE backend and unlock the full potential of your REST application.

Source code: https://github.com/fmarchioni/mastertheboss/tree/master/jax-rs/angular

Found the article helpful? if so please follow us on Socials