Hello Java programmers, if you want to learn Spring Boot and Reactjs and
looking for a full-stack Java example then you have come to the right place.
Earlier, I have shared the best Spring Boot courses, books, and best reactjs courses as well as many courses to learn full-stack development in Java and
become a full-stack java developer. In this tutorial, we will look at creating an application that is capable
of creating, deleting, updating, and retrieving functions using the Spring
Boot, React, and H2 Database. Here we create a School Classroom Application
that can insert, update, delete and search students. The frontend of the
application is developed using reactjs and also the backend is developed
using spring boot. Here, the communication between the two platforms will be
done using the REST APIs.
Tools and technologies which is used in this application.
-
You can use any IDE to develop the backend(spring boot) and the frontend
of the application.
- Server: Apache Tomcat
- Spring Boot 2
- Reactjs
- H2 Database
So let's create the spring boot backend of the system first.
The Spring Boot Application
Here, the REST API is used to communicate with the frontend(angular) of
the application. Before you start programming, you need to have a better
structure of the project. So below is the project structure which is
used in this application.
This application is used to store some data in the in-memory database of
H2 and fetch those data. So below are the maven dependencies in the
pom.xml file which is used in this example.
<?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.6.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.student</groupId>
<artifactId>crudapp</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>crudapp</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</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-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
The Application.properties file
SpringApplication will load properties from application.properties files in the following locations and add them to the Spring Environment:
1. config subdirectory of the current directory.
2. The current directory
3. A classpath /config package
4. The classpath root
Below is the used applicaiton.properties file in this Student Crud application.
server.port=8090
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
spring.datasource.url=jdbc:h2:mem:cmpe172
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
JPA Entity Class
Below is the used JPA entity class in this application. This is responsible for modeling Students.
package com.student.crudapp.model;
import javax.persistence.*;
@Entity
@Table(name = "STUDENT")
public class Student {
@Column(name = "id")
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
@Column(name = "name")
private String name;
@Column(name = "email")
private String email;
@Column(name = "grade")
private String grade;
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 getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getGrade() {
return grade;
}
public void setGrade(String grade) {
this.grade = grade;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", grade='" + grade + '\'' +
'}';
}
}
The StudentRepository Interface
As we need to stick with the crud functionality of our system, we need
to configure our Spring Data repository, StudentRepository interface as a Crud repository as
below.
package com.student.crudapp.repository;
import com.student.crudapp.model.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface StudentRepository extends JpaRepository<Student, Integer> {
List<Student> findAll();
Student findById(int id);
}
The StudentController Class
Below is the StudentController class which is used in the application.
There, we implement the addStudent, findStudent, getAllStudents,
updateStudent and deleteStudent methods which are communicating with the
H2 database in order to store them in the in-memory database.
package com.student.crudapp.controller;
import com.student.crudapp.model.Student;
import com.student.crudapp.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Controller
@CrossOrigin(origins = "http://localhost:8090")
public class StudentController {
@Autowired
StudentRepository studentRepository;
//check the api's working correctly api
@RequestMapping(value="/ping", method=RequestMethod.GET)
@ResponseBody
public String healthCheck() {
return "This is working well";
}
@RequestMapping(value="/students", method=RequestMethod.GET)
@ResponseBody
public List<Student> getAllStudents() {
return studentRepository.findAll();
}
@RequestMapping(value="/student", method=RequestMethod.POST)
@ResponseBody
public Student addStudent(Student student) {
return studentRepository.save(student);
}
@RequestMapping(value="/findstudent", method = RequestMethod.GET)
@ResponseBody
public Student findStudent(@RequestParam("studentId") int studentId) {
return studentRepository.findById(studentId);
}
@RequestMapping(value= "/updatestudent", method = RequestMethod.GET)
@ResponseBody
public Student updateStudent(@RequestBody Student student){
return studentRepository.save(student);
}
@RequestMapping(value="/deletestudent", method = RequestMethod.GET)
@ResponseBody
public int deleteStudent(@RequestParam("studentId") int studentId) {
return studentRepository.deleteById(studentId);
}
}
In the above controller, we used the @CrossOrigin annotation, in order to enable Cross-Origin Resource Sharing (CORS) on the server.
You think this is unncessary, but the thing is we're deploying our Angular frontend to http://localhost:4200, and our Boot backend to http://localhost:8090, the browser would otherwise deny requests from one to the other. the server.
So below are the created API's in order to deal with frontend of the application.
1. Add a new Student (POST request)
http://localhost:8090/student
{
"name": "Test",
"email": "test@gmail.com",
"grade": "05"
}
2. Get all students (GET request)
http://localhost:8090/students
3. Find specific student(GET request)
http://localhost:8090/findstudent?studentId=1
4. Update student(GET Request)
http://localhost:8090/updatestudent
{
"id": 1,
"name": "Testupdated",
"email": "testupdated@gmail.com",
"grade": "05"
}
5. Delete student(GET request)
http://localhost:8090/deletestudent?studentId=1
Here is the screenshot of the H2 database that we have created.
So now the backend of the application is completed, then let's focus on the
frontend of the application, which we use
reactjs
to develop our application.
The Reactjs Application.
Before going into frontend development, we need to look at what is
reactjs. Who develops this and what advantages that you can get by using
this to develop your applications.
React is a front-end JavaScript library for creating user interfaces using
UI components that is free and open-source. It is maintained by Meta and a
community of individual developers and companies. React can be used as a
base in the development of single-page or mobile applications.
Advantages of using Reactjs
1. Easy to learn and use - React is easy
to learn and easy to use and comes with a good supply of documentation,
tutorials, and training resources.
2. Reusable Component - Components are
wonderful and React is based on them. You start with small things, which
you use to build bigger things, which you use to build apps.
3. The virtual DOM - React solves this by
using a virtual DOM. This is, as the name implies, a virtual
representation of the DOM. Any new view changes are first performed on the
virtual DOM, which lives in memory and not on your screen.
4. Easy to write with JSX - JSX produces
React “elements” and has a number of side benefits, including helping
prevent injection attacks.
So let's create our application. Before that, you need to make sure that,
In your computer, you have the nodejs.
Creating React App is a comfortable environment for learning React, and is
the best way to start building a new single-page application in React.
$ npx create-react-app
react-frontend
This command will initiate the project with all the node modules.
$ cd
react-frontend
This will navigate to your project folder.
$ npm start
This will start the project and it will run on default port 3000. You can
access the created project using the http://localhost:3000/
Reactjs Project Structure.
The project structure of our Student Management Application is given
above.
React Application Entry Point
After the app creation process completes, navigate into the app directory
and install Bootstrap, cookie support for React, React Router, and
Reactstrap. Modify app/src/App.js to use the following code that calls to
routing to other pages.
import
React
from
'react';
import
logo
from
'./logo.svg';
import
'./App.css';
import {BrowserRouter
as
Router,
Route,
Switch}
from
'react-router-dom'
import
ListStudentComponent
from
'./components/ListStudentComponent';
import
HeaderComponent
from
'./components/HeaderComponent';
import
FooterComponent
from
'./components/FooterComponent';
import
CreateStudentComponent
from
'./components/CreateStudentComponent';
import
UpdateStudentComponent
from
'./components/UpdateStudentComponent';
import
ViewStudentComponent
from
'./components/ViewStudentComponent';
function
App() {
return (
<div>
<Router>
<HeaderComponent
/>
<div
className="container">
<Switch>
<Route
path =
"/"
exact
component =
{ListStudentComponent}></Route>
<Route
path =
"/students"
component
= {ListStudentComponent}></Route>
<Route
path =
"/add-student/:id"
component
= {CreateStudentComponent}></Route>
<Route
path =
"/view-student/:id"
component
= {ViewStudentComponent}></Route>
<Route
path =
"/update-student/:id"
component
= {UpdateStudentComponent}></Route>
</Switch>
</div>
<FooterComponent
/>
</Router>
</div>
);
}
export
default
App;
Build Components
React is all about components, and you don’t want to render everything in
your main App, so create the following components and populate them with
javascript.
- CreateStudentComponent.jsx
- FooterComponent.jsx
- HeaderComponent.jsx
- ListStudentComponent.jsx
- UpdateStudentComponent.jsx
- ViewStudentComponent.jsx
CreateStudentComponent.jsx
The CreateStudentComponent.jsx file looks like below.
import
React, {
Component }
from
'react'
import
StudentService
from
'../services/StudentService';
class
CreateStudentComponent
extends
Component {
constructor(props) {
super(props)
this.state
= {
// step 2
id:
this.props.match.params.id,
name:
'',
email:
'',
grade:
''
}
this.changeNameHandler
= this.changeNameHandler.bind(this);
this.changeEmailHandler
= this.changeEmailHandler.bind(this);
this.changeGradeHandler
= this.changeGradeHandler.bind(this);
this.saveOrUpdateStudent
= this.saveOrUpdateStudent.bind(this);
}
// step 3
componentDidMount(){
// step 4
if(this.state.id
=== '_add'){
return
}else{
StudentService.getStudentById(this.state.id).then( (res)
=>{
let
student =
res.data;
this.setState({
name:
student.name,
email:
student.email,
grade :
student.grade
});
});
}
}
saveOrUpdateStudent = (e) => {
e.preventDefault();
let
student = {name:
this.state.name,
email:
this.state.email,
grade:
this.state.grade};
console.log('Student => ' +
JSON.stringify(student));
// step 5
if(this.state.id
=== '_add'){
StudentService.createStudent(student).then(res
=>{
this.props.history.push('/students');
});
}else{
StudentService.updateStudent(student,
this.state.id).then( res
=> {
this.props.history.push('/students');
});
}
}
changeNameHandler=
(event)
=> {
this.setState({name:
event.target.value});
}
changeGradeHandler=
(event)
=> {
this.setState({grade:
event.target.value});
}
changeEmailHandler=
(event)
=> {
this.setState({email:
event.target.value});
}
cancel(){
this.props.history.push('/students');
}
getTitle(){
if(this.state.id
=== '_add'){
return
<h3
className="text-center">Add Student</h3>
}else{
return
<h3
className="text-center">Update Student</h3>
}
}
render() {
return (
<div>
<br></br>
<div
className =
"container">
<div
className =
"row">
<div
className =
"card col-md-6 offset-md-3 offset-md-3">
{
this.getTitle()
}
<div
className =
"card-body">
<form>
<div
className =
"form-group">
<label> Name:
</label>
<input
placeholder="Name"
name="Name"
className="form-control"
value={this.state.name}
onChange={this.changeNameHandler}/>
</div>
<div
className =
"form-group">
<label> Email:
</label>
<input
placeholder="Email Address"
name="email"
className="form-control"
value={this.state.email}
onChange={this.changeEmailHandler}/>
</div>
<div
className =
"form-group">
<label> Grade:
</label>
<input
placeholder="Grade" name="grade"
className="form-control"
value={this.state.grade}
onChange={this.changeGradeHandler}/>
</div>
<button
className="btn btn-success"
onClick={this.saveOrUpdateStudent}>Save</button>
<button
className="btn btn-danger"
onClick={this.cancel.bind(this)}
style={{marginLeft:
"10px"}}>Cancel</button>
</form>
</div>
</div>
</div>
</div>
</div>
)
}
}
export
default
CreateStudentComponent
This file is used to create new students by sending the user data to the
backend of the system.
ListStudentComponent.jsx
In reactjs, all the things are made out of components. Here, also we have a
ListStudentComponent.jsx to display the students.
import
React, {
Component }
from
'react'
import
StudentService
from
'../services/StudentService'
class
ListStudentComponent
extends
Component {
constructor(props) {
super(props)
this.state
= {
students: []
}
this.addStudent
= this.addStudent.bind(this);
this.editStudent
= this.editStudent.bind(this);
this.deleteStudent
= this.deleteStudent.bind(this);
}
deleteStudent(id){
StudentService.deleteStudent(id).then( res
=> {
this.setState({students:
this.state
.students .filter(student
=>
student.id
!== id)});
});
}
viewStudent(id){
this.props.history.push(`/view-student/${id}`);
}
editStudent(id){
this.props.history.push(`/add-student/${id}`);
}
componentDidMount(){
StudentService.getStudent().then((res) => {
this.setState({ students:
res.data});
});
}
addStudent(){
this.props.history.push('/add-student/_add');
}
render() {
return (
<div>
<h2
className="text-center">Students List</h2>
<div
className =
"row">
<button
className="btn btn-primary"
onClick={this.addStudent}> Add Student</button>
</div>
<br></br>
<div
className =
"row">
<table
className =
"table table-striped table-bordered">
<thead>
<tr>
<th> Student Name</th>
<th> Student Email</th>
<th> Student Grade</th>
<th> Actions</th>
</tr>
</thead>
<tbody>
{
this.state.students.map(
student
=>
<tr
key =
{student.id}>
<td>
{
student.firstName}
</td>
<td>
{student.lastName}</td>
<td>
{student.emailId}</td>
<td>
<button
onClick={
() =>
this.editStudent(student.id)}
className="btn btn-info">Update
</button>
<button
style={{marginLeft:
"10px"}}
onClick={
() =>
this.deleteStudent(student.id)}
className="btn btn-danger">Delete
</button>
<button
style={{marginLeft:
"10px"}}
onClick={
() =>
this.viewStudent(student.id)}
className="btn btn-info">View
</button>
</td>
</tr>
)
}
</tbody>
</table>
</div>
</div>
)
}
}
export
default
ListStudentComponent
UpdateStudentComponent.jsx
This is the file that we used to update a record in the student management
application. The records will be sent to the API and will
update.
import
React, {
Component }
from
'react'
import
StudentService
from
'../services/StudentService';
class
UpdateStudentComponent
extends
Component {
constructor(props) {
super(props)
this.state
= {
id:
this.props.match.params.id,
name:
'',
email:
'',
grade:
''
}
this.changeNameHandler
= this.changeFirstNameHandler.bind(this);
this.changeEmailHandler
= this.changeEmailHandler.bind(this);
this.changeGradeHandler
= this.changeGradeHandler.bind(this);
this.updateStudent
= this.updateStudent.bind(this);
}
componentDidMount(){
StudentService.getStudentById(this.state.id).then( (res)
=>{
let
student =
res.data;
this.setState({name:
student.name,
email:
student.email,
grade :
student.grade
});
});
}
updateStudent =
(e)
=> {
e.preventDefault();
let
student = {name:
this.state.name,
email:
this.state.email,
grade:
this.state.grade};
console.log('student => ' +
JSON.stringify(student));
console.log('id => ' +
JSON.stringify(this.state.id));
StudentService.updateStudent(student,
this.state.id).then( res
=> {
this.props.history.push('/students');
});
}
changeNameHandler=
(event)
=> {
this.setState({name:
event.target.value});
}
changeGradeHandler=
(event)
=> {
this.setState({grade:
event.target.value});
}
changeEmailHandler=
(event)
=> {
this.setState({emailId:
event.target.value});
}
cancel(){
this.props.history.push('/students');
}
render() {
return (
<div>
<br></br>
<div
className =
"container">
<div
className =
"row">
<div
className =
"card col-md-6 offset-md-3 offset-md-3">
<h3
className="text-center">Update Employee</h3>
<div
className =
"card-body">
<form>
<div
className =
"form-group">
<label> Name:
</label>
<input
placeholder="First Name"
name="firstName"
className="form-control"
value={this.state.firstName}
onChange={this.changeNameHandler}/>
</div>
<div
className =
"form-group">
<label> Email Id:
</label>
<input
placeholder="Email Address"
name="emailId"
className="form-control"
value={this.state.emailId}
onChange={this.changeEmailHandler}/>
</div>
<div
className =
"form-group">
<label> Grade:
</label>
<input
placeholder="Last Name"
name="lastName"
className="form-control"
value={this.state.lastName}
onChange={this.changeLastNameHandler}/>
</div>
<button
className="btn btn-success"
onClick={this.updateStudent}>Save</button>
<button
className="btn btn-danger"
onClick={this.cancel.bind(this)}
style={{marginLeft:
"10px"}}>Cancel</button>
</form>
</div>
</div>
</div>
</div>
</div>
)
}
}
export
default
UpdateStudentComponent
This will help to update a student record.
ViewStudentComponent.jsx
This will help to view one student out of many students.
import
React, {
Component }
from
'react'
import
StudentService
from
'../services/StudentService'
class
ViewStudentComponent
extends
Component {
constructor(props) {
super(props)
this.state
= {
id:
this.props.match.params.id,
students: {}
}
}
componentDidMount(){
StudentService.getStudentById(this.state.id).then( res
=> {
this.setState({students:
res.data});
})
}
render() {
return (
<div>
<br></br>
<div
className =
"card col-md-6 offset-md-3">
<h3
className =
"text-center"> View Student Details</h3>
<div
className =
"card-body">
<div
className =
"row">
<label> Student Name:
</label>
<div>
{
this.state.students.name
}</div>
</div>
<div
className =
"row">
<label> Student Email :
</label>
<div>
{
this.state.students.email
}</div>
</div>
<div
className =
"row">
<label> Student Grade:
</label>
<div>
{
this.state.students.grade
}</div>
</div>
</div>
</div>
</div>
)
}
}
export
default
ViewStudentComponent
FooterComponent.jsx and HeaderComponent.jsx
These files are used to customize the screen of the Student Management
Application. These files are displayed below.
FooterComponent.jsx
import
React, {
Component }
from
'react'
class
FooterComponent
extends
Component {
constructor(props) {
super(props)
this.state
= {
}
}
render() {
return (
<div>
<footer
className =
"footer">
<span
className="text-muted">All Rights Reserved</span>
</footer>
</div>
)
}
}
export
default
FooterComponent
HeaderComponent.jsx
import
React, {
Component }
from
'react'
class
HeaderComponent
extends
Component {
constructor(props) {
super(props)
this.state
= {
}
}
render() {
return (
<div>
<header>
<nav
className="navbar navbar-expand-md navbar-dark bg-dark">
<div><a
href=""
className="navbar-brand">Student Management
Application</a></div>
</nav>
</header>
</div>
)
}
}
export
default
HeaderComponent
API Integration
This is a file that is used to integrate our test our application.
This file has all the API calls which are used to communicate with our
backend of the system.(Spring boot)
import
axios
from
'axios';
const
STUDENT_API_BASE_URL =
"http://localhost:8090";
class
StudentService {
getStudent(){
return
axios.get(STUDENT_API_BASE_URL);
}
createStudent(student){
return
axios.post(STUDENT_API_BASE_URL+'/student', student);
}
getStudentById(studentId){
return
axios.get(STUDENT_API_BASE_URL +
'/findstudent' +
studentId);
}
updateStudent(student, studentId){
return
axios.put(STUDENT_API_BASE_URL +
'/updatestudent' +
studentId,
student);
}
deleteStudent(studentId){
return
axios.delete(STUDENT_API_BASE_URL +
'/deletestudent' +
studentId);
}
}
export
default
new
StudentService()
Interfaces of the project.
The interfaces of the project are given below.
Now we know how to use Spring Boot React CRUD to create a CRUD app that
communicates with an H2 database. We also look at client-server architecture
for REST APIs using Spring Web MVC and Spring Data JPA, as well as the
structure of a React project for creating a front-end app that makes HTTP
queries and consumes replies. So hope to see you in the next tutorial with
another interesting topic.
Other
Java and Spring Tutorial you may like
-
How to update an entity using Spring Data JPA? (example)
-
20 Spring Boot Interview Questions with answers (questions)
-
What is @Conditional annotation in Spring? (conditional example)
-
How Spring MVC works internally? (answer)
-
Spring Data JPA @Query Example (query example)
-
10 Advanced Spring Boot Courses for Java developers (courses)
-
Spring Data JPA Repository Example in Java (JpaReposistory example)
-
20+ Spring MVC Interview Questions for Programmers (answer)
-
13 Spring Boot Actuator Interview questions (boot questions)
-
Difference between @Autowired and @Inject in Spring? (answer)
-
Top 5 Frameworks Java Developer Should Know (frameworks)
-
Difference between @RequestParam and @PathVariable in Spring (answer)
-
Top 7 Courses to learn Microservices in Java (courses)
-
How to use @Bean in Spring framework (Example)
-
How to fix No property type found in Spring Data JPA? [Solution]
-
5 Spring Cloud annotations Java programmer should learn (cloud)
-
Top 5 Courses to Learn and Master Spring Cloud (courses)
-
5 Courses to Learn Spring Security for Java programmers (courses)
-
10 Spring MVC annotations Java developer should know (annotations)
-
@SpringBootApplication vs. @EnableAutoConfiguration? (answer)
-
15 Spring Boot Interview Questions for Java Developers (questions)
-
Difference between
@Component,
@Service, and
@Controller
in Spring (answer)
Thanks for reading this article so far. If you find this full-stack
Spring Boot and Reactjs tutorial and example,
then please share it with your friends and colleagues. If you have any
questions or feedback, then please drop a note.
P. S. - If you are a Spring Boot beginner and want to learn the
Spring Boot framework from scratch and look for some of the best online
resources, you can also check out these
best Spring Boot courses for Java developers. This list contains free Udemy and Pluralsight courses to learn Spring Boot
from scratch.
1 comment :
The source code is in a very terrible format. StudentService Where do you mention/create this service in the tutorial? There are a lot of topics that aren't explained.
Post a Comment