JAX-RS CRUD Application using Vue.js and RESTEasy

Let’s check in this tutorial how to build a  JAX-RS CRUD application (on the top of WildFly application server) using Vue.js and Axios as Front End.

Let’s start with some basic concepts about Vue.js: in a nutshell, Vue.js is a system that enables us to declaratively render data to the DOM using straightforward template syntax. Example:

<div id="app">
  {{ message }}
</div>
new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue.js!'
  }
})

Assumed that you have imported the Javascript library for Vue:

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

Then, the above code will print in the div element an “Hello world” message.

Vue, however, doesn’t have a built-in HTTP request library. The recommended approach is to use Axios to interact with REST APIs. Axios is a promise-based HTTP client for making Ajax requests, and will work great for our purposes. It provides a simple and rich API that can easily wrap a basic CRUD REST Service.

Let’s build our example, starting from the REST Service.

Building the CRUD JAX-RS Service

Our JAX-RS Service will let us Create, Read, Update and Delete a list of Customer objects. So let’s add the Model object Customer to a standard Java EE project:

@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;

    public Long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

}

The interaction with the Customer object is done through a CustomerRepository Class which follows here:

import javax.enterprise.context.ApplicationScoped;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
import javax.ws.rs.WebApplicationException;


@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(Long id, String name, String surname) {

        Customer customerToUpdate = findCustomerById(id);
        customerToUpdate.setName(name);
        customerToUpdate.setSurname(surname);
    }
    @Transactional
    public void createCustomer(Customer customer) {

        entityManager.persist(customer);

    }
    @Transactional
    public void deleteCustomer(Long customerId) {

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


}

It is worth notice that, since the Repository is a CDI bean and not an EJB (which is by default a Transactional component), we need to specify the @Transactional annotation on the top of methods that execute a Transaction. Next on the list is the CustomerEndpoint class, which exposes to the Front-End a set of GET/POST/PUT and DELETE HTTP methods:

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.ws.rs.*;
import javax.ws.rs.core.Response;
import java.util.List;


@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) {
        customerRepository.createCustomer(customer);
        return Response.status(201).build();
    }

    @PUT
    public Response update(@QueryParam("id") Long id, @QueryParam("name") String name, @QueryParam("surname") String surname) {
        customerRepository.updateCustomer(id,name,surname);
        return Response.status(204).build();
    }
    @DELETE
    public Response delete(@QueryParam("id") Long customerId) {
        customerRepository.deleteCustomer(customerId);
        return Response.status(204).build();
    }

}

The last Class we need to add is a JaxRsActivator which sets the Web context for the REST Service, activating it as well:

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;


@ApplicationPath("/rest")
public class JaxRsActivator extends Application {
   /* class body intentionally left blank */
}

Our example application will run against the default H2 Database which is provided in WildFly, so our persistence.xml will reference the ExampleDS Datasource for this purpose:

<persistence version="2.1"
             xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="
        http://xmlns.jcp.org/xml/ns/persistence
        http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <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>

Within the folder resources we can add as well an import.sql script to have some Customer objects already available:

INSERT INTO customer (id, name, surname) VALUES ( nextval('customerId_seq'), 'Homer','Simpson');
INSERT INTO customer (id, name, surname) VALUES ( nextval('customerId_seq'), 'Bart','Simpson');

In order to build our projects, we can use the super-lean Jakarta EE dependency, which follows here:

<dependencies>
    <dependency>
      <groupId>jakarta.platform</groupId>
      <artifactId>jakarta.jakartaee-api</artifactId>
      <version>8.0.0</version>
      <scope>provided</scope>
    </dependency>
</dependencies>

Finally, in order to force the Web context to be independent from the artifactId, we have added a jboss-web.xml which dictates the Web context to be “vuejs-demo”:

<jboss-web>  
    <context-root>vuejs-demo</context-root>  
</jboss-web>  

Here is the Project tree:

src
└── main
    ├── java
    │   └── com
    │       └── mastertheboss
    │           └── jaxrs
    │               ├── CustomerEndpoint.java
    │               ├── CustomerException.java
    │               ├── Customer.java
    │               ├── CustomerRepository.java
    │               └── JaxRsActivator.java
    ├── resources
    │   ├── import.sql
    │   └── META-INF
    │       └── persistence.xml
    └── webapp
        ├── index.html
        └── WEB-INF
            ├── beans.xml
            └── jboss-web.xml

Coding the Vue.js Front-End

Now let’s code the Vue.js layer. For this purpose, we have added a single index.html page in our project. To get started, we obviously need to import the required libraries:

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.min.js"></script>

And now for the rest of the page:

<body>
<h3>JAX-RS Demo (WildFly) with VueJS</h3>
<div id="app">

    <table class="blueTable">
        <thead >
        <tr>
            <th>#</th>
            <th>Name</th>
            <th>Surname</th>
            <th>Delete</th>
            <th>Update</th>
        </tr>
        </thead>
        <tbody>
        <tr v-for="user in users" :key="user.id">
            <td>{{user.id}}</td>
            <td>{{user.name}}</td>
            <td>{{user.surname}}</td>
            <td>  <button class="button"  @click="deleteUser(user.id)">Delete</button></td>
            <td>  <button class="button"  @click="updateUser(user.id)">Update</button></td>
        </tr>
        </tbody>
    </table>
    <br/>
    <div>
        <form name="form" >
            <input type="text" placeholder="Name" v-model="name" size="60"/><br/>
            <input type="text" placeholder="Surname" v-model="surname" size="60"/><br/>
            <input type="submit" value="Save" @click="createUser"/><br/>
        </form>
    </div>
</div>


<script>


new Vue({
    el: "#app",
    data() {
        return {
            users: []
        }
    },
    methods: {


        updateUser: function(id) {

                axios.put("/vuejs-demo/rest/customers?id="+id+"&name="+this.name+"&surname="+this.surname)
                .then(response => {
                    this.listUsers()
                })
                this.name='';
                this.surname='';
        },

        deleteUser: function(id) {

                axios.delete("/vuejs-demo/rest/customers?id="+id)
                .then(response => {
                    this.listUsers()
                })
        },

        createUser: function() {

          var user = {
                // name and surname should exist in [data] or [computed] section
                name: this.name,
                surname: this.surname
              };


            axios.post("/vuejs-demo/rest/customers",  user)
                .then(response => {
                    this.listUsers()
                })


        },
        listUsers: function() {
            axios.get("/vuejs-demo/rest/customers", {

                })
                .then(response => {
                    this.users = response.data
                })
        }
    },
    mounted: function() {

       this.listUsers()
    }


})
</script>

The above code should be pretty intuitive. We have bootstrapped Vue.js definind three things:

  • A variable of type array called data which contains the list of Customer objects
  • A set of methods, to manage HTTP CRUD actions
  • We have mounted a function that fires up when the page loads. This function simply loads the listUsers method to fill our Table
That's all!

Running the project

Start WildFly application server using any available configuration:

standalone.sh

Then, as our project includes the WildFly Maven plugin (check the source code below), we can simply run it as follows:

mvn install wildfly:deploy

Here is our simple JAX-RS CRUD Example in action:

Let's check in this tutorial how to build a CRUD JAX-RS application (on the top of WildFly application server) using Vue.js and Axios as Front End.

By entering Name and Surname in the text field and clicking on Save a new Customer will be added. On the other hand, if you click on Update, the corresponding customer will be updated with the content of your text field. Obviosuly Delete evicts the Customer on that row.

In the next tutorial, we will show how to transform our Java EE application in a Quarkus application in a matter of minutes! Stay tuned!

You can check the source code for this tutorial here:

https://github.com/fmarchioni/mastertheboss/tree/master/web/vuejs-demo

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