Creating a fullstack React/Material-UI DataGrid frontend data grid connected to a Java SpringBoot REST GET API backend with axios

The increase in popularity of Javascript and mobile devices has led to the rise of JS frameworks such as React, Angular and Vue and the development of single page applications (or SPAs) that are compatible across all devices from laptops to handphones. Whilst frontend development with Java (e.g. JSP, JSF) has taken more of a back seat, React apps running on node.js has become extremely popular. But Java still has an important role to play as a backend layer particularly in the field of providing REST services and this is due to the simplicity in creating Spring apps through the use of SpringBoot and the Spring Initializr website to quickly create default ready-made Spring template apps. However, backends are also increasingly being built by the Python/Django, RubyOnRails and PHP/Laravel stacks.

In this article, I will go through developing a Java SpringBoot backend REST API and then, creating a front-end React/Material-UI DataGrid grid table to connect to the SpringBoot backend using axios third-party connection tool. The Java backend will access a MySQL database and retrieve data making it available through a GET REST interface. Material UIs are very popular nowadays, not least because it is owned by Google, and for its simple and flat, minimalistic look. You can also look at using jqWidgets which provide a wide set of React components for your next generation ES6 app.

(For a node.js-ExpressJS-MongoDB (through mongoose) stack REST API backend with CRUD functionality accessed via a React-Data-Grid and Material-UI/DataGrid, please check out my recent article, Creating a CRUD node.js REST service backend with node.js, Express and MongoDB (mongoose) and a React-Data-Grid / Material-UI DataGrid frontend to access the service.

For a Python-Django REST API stack implementing HTTP GET, check out my other article, Creating a Python Django REST Service backend with Postgres database.)

The Backend

I start by downloading and installing MySQL on my Windows 10 laptop. With my trusty HeidiSQL, I start with creating my User table in the database:

CREATE TABLE `t_users` (

`id` INT(11) NOT NULL AUTO_INCREMENT,

`user_name` VARCHAR(255) NULL DEFAULT NULL,

`user_email` VARCHAR(255) NULL DEFAULT NULL,

`user_password` VARCHAR(255) NULL DEFAULT NULL,

`user_role` VARCHAR(255) NULL DEFAULT NULL,

`user_tel_no` VARCHAR(255) NULL DEFAULT NULL,

`login_date_time` DATETIME NULL DEFAULT NULL,

`entry_date_time` DATETIME NULL DEFAULT NULL,

`update_date_time` DATETIME NULL DEFAULT NULL,

`get_users` VARCHAR(255) NULL DEFAULT NULL,

PRIMARY KEY (`id`) USING BTREE,

INDEX `user_name` (`user_name`) USING BTREE,

INDEX `user_role` (`user_role`) USING BTREE

)

COLLATE=’utf8mb4_general_ci’

ENGINE=InnoDB

AUTO_INCREMENT=1

;

Now, lets create the SpringBoot backend.

I start with going to the Spring Initializr website and choosing a Maven project, the latest SpringBoot version, defining the package and app names, choosing a WAR file output and selecting Spring Web as a dependency. Note that when you choose Spring Web here, it automatically comes with Spring MVC and an embedded Tomcat server.

After clicking Generate, I will have downloaded a ZIP file containing the project template as generated by the Initializr website. I import this template into my Eclipse IDE and create a Dynamic Web Project project type. The next step is determining all the dependencies I will need to update my pom.xml file:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-parent</artifactId>

<version>2.4.2</version>

<relativePath/> <! — lookup parent from repository →

</parent>

<groupId>com.ezani</groupId>

<artifactId>restproject</artifactId>

<version>0.0.1-SNAPSHOT</version>

<packaging>war</packaging>

<name>restproject</name>

<description>REST backend</description>

<properties>

<java.version>15</java.version>

</properties>

<dependencies>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-jdbc</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-data-jpa</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-devtools</artifactId>

<scope>runtime</scope>

<optional>true</optional>

</dependency>

<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

<scope>runtime</scope>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-tomcat</artifactId>

<scope>provided</scope>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope>

</dependency>

</dependencies>

<build>

<plugins>

<plugin>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-maven-plugin</artifactId>

</plugin>

</plugins>

</build>

</project>

Note that I also added Spring JPA as a dependency and downloaded a Java JDBC Connector jar to connect to my MySQL database.

Here’s how my Project Explorer file folder structure looks like so far :

Having added Spring JPA as a dependency, I configure my application.properties file so that Spring Data is able to access my MySQL database:

I then create the User.java model class in my model folder as below:

package com.model;

import java.util.Date;
import java.util.*;
import java.time.LocalDateTime;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
@Table(name = “T_USERS”)
public class User {

@Id
@GeneratedValue
private Integer id;
private String userName;
private String userPassword;
private String userTelNo;
private String userEmail;
private String userRole;
private LocalDateTime loginDateTime;

//constructor
public User () {
this.userName = “”;
this.userPassword = “”;
this.userTelNo = “”;
this.userEmail = “”;
this.userRole = “”;
this.loginDateTime = null;
}

public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public String getUserTelNo() {
return userTelNo;
}
public void setUserTelNo(String userTelNo) {
this.userTelNo = userTelNo;
}
public String getUserEmail() {
return userEmail;
}
public void setUserEmail(String userEmail) {
this.userEmail = userEmail;
}
public String getUserRole() {
return userRole;
}
public void setUserRole(String userRole) {
this.userRole = userRole;
}
public LocalDateTime getLoginDateTime() {
return loginDateTime;
}
public void setLoginDateTime(LocalDateTime loginDateTime) {
this.loginDateTime = loginDateTime;
}
public String toString() {
return “Table T_USER_MS user”;
}

}

We bring in the Spring JPA repository through an interface class, so that we can use its default CRUD methods as follows:

package com.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import org.springframework.data.jpa.repository.Query;
import com.model.User;

@Repository
public interface UserRepository extends JpaRepository<User, Integer> {

}

Next, we create our User service class:

package com.service;

import java.util.List;

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

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;

import com.model.User;

@Service

@Transactional

public interface UserService {

public List<User> getUsers();

}

and implement it as below :

package com.service.impl;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.service.UserService;
import com.repository.UserRepository;
import com.model.User;

@Service
public class UserServiceImpl implements UserService {


@Autowired
UserRepository dao;

@Override
public List<User> getUsers() {
return dao.findAll();
}
}

Next, we head to the controller folder and create a Controller class which will handle the REST APIs :

package com.controller;

import java.util.List;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

import java.io.IOException;

import java.time.LocalDate;

import java.time.LocalDateTime;

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

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.CrossOrigin;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.ResponseBody;

import org.springframework.web.bind.annotation.RestController;

import org.springframework.web.servlet.ModelAndView;

import com.model.User;

import com.service.UserService;

@Controller

@CrossOrigin(origins = “*”)

@RequestMapping(value= “/”, method= RequestMethod.GET)

public class UserController {

@Autowired

UserService service;

//List all users API

@ResponseBody

@CrossOrigin(origins = “*”)

@RequestMapping(value= “/user/all”, method= RequestMethod.GET)

public List<User> getUsers() {

return service.getUsers();

}

}

Note that I have to include the @CrossOrigins annotation because I was going to use my React/Material-UI app running on node.js server on port 3000 to access my REST SpringBoot Java app running on port 8080, both on my local machine to avoid a CORS issue.

I check that it outputs the right data by running as a SpringBoot App and typing the REST API URL with “user/all” appended, and checking the JSON output:

With the SpringBoot app working properly and outputting the right data in the proper format, its time to head on to developing my frontend app using React, Material-UI DataGrid and axios.

The Frontend

npx create-react-app my-user-app
cd my-user-app
npm start

I also install yarn which allows me to manage my React packages easily as I know I’ll be downloading a number of packages later.

After installing React and checking that the sample React app is running properly on port 3000, I delete the sample coding inside the App.js file. I head to the Materials-UI website to install the DataGrid component which also installs the needed Materials-Core components. I then head over to the axios website using yarn to add this dependency to my React Material app. This axios dependency allows my React app to connect to REST API URLs through GET, PUT, FETCH calls, etc. (Note — Besides axios, you can also use admin on rest to connect to REST URLs).

Finally, after opening my Visual Code editor from my projects folder, I get the screen below:

Here is how my index.js file looks like:

My package.json file contains all the dependencies I need on my frontend app:

Finally, I concentrate on writing code within the App.js file to create a Material-UI Data Grid and use axios to connect (through AJAX) to my SpringBoot backend.

Here is the coding within the App.js file :

import React, {useState, useEffect} from “react”;

import { DataGrid } from ‘@material-ui/data-grid’;

export default function App() {

const [isLoaded,setIsLoaded] = useState(false);

const [rowData,setRowData] = useState([]);

useEffect(() => {

const axios = require(‘axios’).default;

axios

.get(‘http://localhost:8080/user/all')

.then((response) => {

setIsLoaded(true);

console.log(response.data);

setRowData(response.data);

response.data.forEach(user => {

});

});

}, []);

const columns = [

{ field: “id”, headerName: “ID”, width: 10 },

{ field: “userName”, headerName: “Name”, width: 170 },

{ field: “userTelNo”, headerName: “Tel No”, width: 70 },

{ field: “userEmail”, headerName: “EMail”, width: 100 },

{ field: “userRole”, headerName: “Role”, width: 100 },

];

return(

<div style={{ height: 400, width: ‘100%’ }}>

<div style={{ display: ‘flex’, height: ‘100%’ }}>

<div style={{ flexGrow: 1 }}>

<DataGrid

columns={columns}

rows={rowData}

id=”id”

pageSize={15}

/>

</div>

</div>

</div>

);

}

Note that I use the useEffect() and useState() methods as a hook to read and go through all the response data from the SpringBoot app which is coming in as an object array within the success portion of the AJAX call. I use setRowData(response.data) to populate the Material-UI Data Grid rows. The columns constant defines the column header descriptions as well as the size of each column. You must also add an id parameter within the DataGrid tag to identify the primary key column. For checking purposes, you can view that the data is coming in correctly from the SpringBoot backend using Watch and console.log via the browser Developer Tools (accessible through F12).

Finally, I can see that the Material-UI DataGrid is successfully populated with the data from the SpringBoot REST call as below:

(Note that the Material-UI Data Grid will initially not show any rows (although headers and columns are visible) as you have to include a CSS style to the data grid to allow the row height to be resized to show all the rows. For my data grid, I use the flexGrow style which is simple and easy to use and automatically grows and shrinks as the grid is populated with data.)

30+ years as a computer programmer. Started with Visual Basic, now doing Java, SpringBoot, React and .NET. Running my own software company at mysoftware2u.com

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store