Springboot (Java)
- Install Java and Maven:
- 1- TAKE CARE OF THE DATABASE FIRST!:
- 2 - Create a new maven project:
- 3- Connecting the database to the backend:
- 4- If everything is OK, it should compile…:
- 5- Model (i.e. Student.java):
- 6- Repository (i.e. Classroom.java):
- 7- Controller (i.e. SchoolController.java):
- 8- REST-Controller is now READY!:
- 9- Now let’s create the MVC-Controller. (i.e. SchoolRenderer.java):
- 10- Now it’s time to implement the front-end:
Install Java and Maven:
sudo apt install default-jdk #Check version with: java -version
sudo apt install maven #Check version with: mvn --version
1- TAKE CARE OF THE DATABASE FIRST!:
An empty database & an user with enough privileges (SELECT INSERT UPDATE DELETE) will be enough
sudo apt install mysql-server #Installing MySQL
sudo mysql_secure_installation #Wizard to improve security.
systemctl status mysql #If inactive: systemctl start mysql. Runs at localhost:3306
sudo mysql #Enters MySQL CLI. Check from which port it's running: SHOW VARIABLES LIKE 'port';
#same as: CREATE SCHEMA schemaname; To view all databases: SHOW DATABASES;
CREATE DATABASE databasename;
#to view all users: SELECT USER, HOST from mysql.user;
CREATE USER 'username'@'localhost' IDENTIFIED BY 'enterPasswordHere';
#view all grants: SHOW GRANTS FOR 'username'@'localhost'; | note: *.* == allDatabases.allTables
GRANT INSERT, SELECT, UPDATE, DELETE ON databasename.* to 'username'@'localhost';
New user can now access MySQL like this:
mysql -u username -p #A password-prompt will ensue. For now, 'databasename' should be empty. Check with: USE databasename; SHOW TABLES;
2 - Create a new maven project:
Use the Springboot Initializr. Try this one out!
(i.e. Language: Java|Project: Maven|Spring Boot: 2.7.13|Packaging: Jar|Java: 11)
Working with current setup: Java version: 11.0.19 | Apache Maven 3.6.3
Include these dependencies:
Spring Web #Uses Apache Tomcat as the default embedded container.
MySQL Driver #MySQL JDBC driver (Appears in 'pom.xml' as: 'mysql-connector-j').
Spring Data JPA #Automates creation of tables and columns.
Thymeleaf #Server-side Java template engine
Upon un-Zipping the file, a “pom.xml” will be found at the “root of the project”.
3- Connecting the database to the backend:
From the “root of the project”, locate this file:
src/main/resources/application.properties
Add these lines to that configuration file:
#Or: spring.datasource.url=jdbc:mysql://localhost:3306/databasename?useSSL=false&serverTimezone=UTC
spring.datasource.url=jdbc:mysql://localhost:3306/databasename #replace 'databasename'!
spring.datasource.username=userNameHere #replace 'userNameHere'!
spring.datasource.password=enterPasswordHere #replace with user's password!
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver #Keep the same
spring.jpa.hibernate.ddl-auto=update #Keep the same
4- If everything is OK, it should compile…:
mvn clean package #Or: mvn clean test | mvn clean install
java -jar target/PROJECT.jar #Or, in cases where you have a 'main' method: java -cp target/PROJECT.jar com.project.Main
It should run on localhost:8080
now let’s work on the REST-API itself. it’s made up of a CONTROLLER that interacts with a database through a REPOSITORY of MODELs. To put it simple: “API’s repository” = “database table”; “API model” = “database entry/row”. The end user accesses the back-end through the “API’s controller”, which is a series of mappings of: URL end-points + functions. To code the following classes, use this directory:
cd src/main/java/PROJECT/
5- Model (i.e. Student.java):
This class is an abstraction of database entry.
import javax.persistence.*;
//indicates this class is an entry in a database. A table modeled after this schema is created automatically if it doesn't yet exist.
@Entity
public class Student{
//indicates this variable is the 'primary key' and uniquely identifies each entry
@Id
//indicates each primary key will be automatically generated. End-user only needs to enter the other columns (name and age).
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
//indicates it's a field (column) in the database.
@Column
private String name;
@Column
private int age;
//getters and setters!
public long getId(){
return this.id;
}
public String getName(){
return this.name;
}
public int getAge(){
return this.age;
}
public void setId(int id){
this.id = id;
}
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
}
6- Repository (i.e. Classroom.java):
This class is an abstraction of a database table.
import org.springframework.data.jpa.repository.JpaRepository;
//i.e. This is a repository of 'Student' objects. Each uniquely identified by a 'Long' variable (i.e. id)
public interface Classroom extends JpaRepository<Student, Long>{}
7- Controller (i.e. SchoolController.java):
This class is what the end-user interacts with.
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.*;
@RestController
public class SchoolController{
@Autowired
private Classroom room; //Repository injection
@GetMapping(value="/")
public String homeScreen(){
return "Welcome!";
}
@GetMapping(value="/students")
public List<Student> getStudents(){
return room.findAll();
}
@PostMapping(value="/enroll")
public String enroll(@RequestBody Student scholar){
room.save(scholar);
return "New student added...";
}
@DeleteMapping(value="/remove/{id}")
public String removeStudent(@PathVariable long id){
Student selected = room.findById(id).get();
selected.delete(selected);
return "Student deleted";
}
@PutMapping(value="/edit")
public String editStudent(@PathVariable long id, @RequestBody Student scholar){
Student selected = room.findById(id).get();
selected.setName(scholar.getName());
selected.setAge(scholar.getAge());
room.save(selected);
return "Student edited...";
}
}
8- REST-Controller is now READY!:
Use Postman to send GET, POST, PUT, DELETE requests.
mvn clean package #Compile and test!
java -jar target/PROJECT.jar #or: java -cp target/PROJECT.jar com.company.project.Mainclass
If it’s up and running, go to: localhost:8080/
in postman, try:
POST localhost:8080/enroll Body>raw>JSON
{
"name": "John",
"age": 38
}
9- Now let’s create the MVC-Controller. (i.e. SchoolRenderer.java):
Thymeleaf is used by this class to render templates stored at ‘src/main/resources/templates/’ (i.e. index.html)
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
public class Renderer{
@GetMapping("/")
public String showIndexPage(){
return "jsform";
}
}
10- Now it’s time to implement the front-end:
I’ll leave the “(USER_INPUT)” retrieval up to you. What you need to know is the bread and butter; how to use the “fetch” API to send HTTP requests.
//--GET--
fetch("/students")
.then(response => response.json())
.then(data => {//i.e. 'data' is a list of Student-Objects//})
.catch(error => {console.log("Error: ", error)});
//--POST--
fetch("/enroll",
{
method:"POST",
headers:{"Content-Type":"application/json"}
body: JSON.stringify(USER_INPUT)
})
.catch(error => {console.log("Error: ", error)});
//--DELETE--
fetch(`/remove/${id}`,
{
method:"DELETE",
})
.catch(error => {console.log("Error: ", error)});
//--PUT--
fetch(`/edit/${id}`,
{
method: "PUT",
headers: {"Content-Type":"application/json"},
body: JSON.stringify(USER_INPUT)
})
.catch(error => {console.log("Error: ", error)});
Alternatively, you can use “async” and “await” for cleaner code:
//--GET--
async function fetchItems() {
try {
const response = await fetch('/enrolled');
const data = await response.json();
//handle request
} catch (error) {
console.error('Error:', error);
}
}
//--POST--
async function addStudent() {
try {
await fetch('/enroll', POSTmsg());
//handle request
} catch (error) {
console.error('Error:', error);
}
}
//--DELETE--
async function deleteStudent(each_id){
try {
await fetch(`/remove/${each_id}`, {method: 'DELETE'});
//handle request
} catch (error) {
console.error('Error:', error);
}
}
//--PUT--
async function updateStudent(each_id){
try{
await fetch(`/modify/${each_id}`, PUTmsg());
//handle request
} catch (error) {
console.error('Error:', error);
}
}