So erstellen Sie eine Anwendung mit Spring Boot und ReactJS
In diesem Beitrag werde ich zeigen, wie wir eine Anwendung mit Spring Boot und ReactJS erstellen können.
Wir werden ReactJS für das Frontend und Spring Boot für die Handhabung der Geschäftslogik im Backend verwenden. Als Datenbank verwenden wir MySQL. Die Anwendung, die wir erstellen, ist eine Anwendung für Aufgabenlisten.
Wir werden die folgenden Anweisungen in diesem Beitrag behandeln:
- Richten Sie die Spring Boot-Anwendung ein
- MySQL-Datenbank einrichten
- Details der Spring Boot-Anwendung
- ReactJS installieren und Frontend einrichten
- Testen Sie die Anwendung in der lokalen Umgebung
Spring Boot-Anwendung einrichten
Normalerweise verwende ich https://start.spring.io/, um eine Boilerplate-Spring-Boot-Anwendung mit den erforderlichen Abhängigkeiten einzurichten. Als Teil dieses Projekts werden wir spring-data-jpa
verwenden , spring-data-rest
, jdbc
, und web
Abhängigkeiten. Unsere Gradle-Datei sieht wie folgt aus:
plugins {
id 'org.springframework.boot' version '2.3.1.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
id 'java'
}
group = 'com.betterjavacode.'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-data-rest'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-web'
runtimeOnly 'mysql:mysql-connector-java'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
test {
useJUnitPlatform()
}
Sobald wir das Projekt unter https://start.spring.io erstellt haben, können wir es herunterladen und in IntelliJ oder Eclipse importieren.
MySQL-Datenbank einrichten
Für die To-Do-Listenanwendung benötigen wir eine Datenbank und eine einzelne Tabelle. Diese Demo ist eine Barebone-Anwendung, daher haben wir keinen Anmelde- oder Registrierungsbildschirm.
Da wir von unserer Spring Boot-Anwendung aus eine Verbindung zur Datenbank herstellen, müssen wir unsere application.properties einrichten wie folgt:
spring.datasource.url=jdbc:mysql://127.0.0.1/todolist?autoReconnect=true&useSSL=false
spring.datasource.username = sa
spring.datasource.password=********
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
spring.datasource.hikari.connection-test-query=SELECT 1
Sie können GUI verwenden, um sich mit Ihrer MySQL-Datenbank zu verbinden, ich bevorzuge normalerweise den Befehlszeilen-Ansatz.
Nachdem Sie sich über die Befehlszeile bei Ihrer MySQL-Datenbank angemeldet haben, erstellen Sie eine Datenbank für unsere Anwendung.
create database todolist
Wir erstellen eine Datenbanktabelle task
.
create table task (id int(6) unsigned not null auto_increment, taskname varchar(100) not null, duedate date default null, status int(1), primary key(id));
Wir können entweder einige Daten einfügen lassen oder unsere Homepage der Anwendung haben, die das Formular zum Einfügen der Daten zeigt.
Details der Spring Boot-Anwendung
Zuerst erstellen wir eine Modellklasse für task
. Diese Klasse sieht wie folgt aus:
package com.betterjavacode.demo.models;
import com.fasterxml.jackson.annotation.JsonFormat;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
@Entity(name="Task")
@Table(name="task")
public class Task implements Serializable
{
private static final long serialVersionUID = 1L;
public Task()
{
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="id", nullable = false)
private int id;
@Column(name = "taskname", nullable=false)
private String taskname;
@Column(name = "duedate")
@JsonFormat(pattern="yyyy-MM-dd")
private Date dueDate;
@Column(name = "status")
private String status;
@Override
public String toString()
{
return "Task = { id = " + id + ", taskname = " + taskname + ", duedate = " + dueDate
+ ", status = " + status + "}";
}
public int getId ()
{
return id;
}
public void setId (int id)
{
this.id = id;
}
public String getTaskname ()
{
return taskname;
}
public void setTaskname (String taskname)
{
this.taskname = taskname;
}
public Date getDueDate ()
{
return dueDate;
}
public void setDueDate (Date dueDate)
{
this.dueDate = dueDate;
}
public String getStatus ()
{
return status;
}
public void setStatus (String status)
{
this.status = status;
}
}
In dieser Entwicklung werden wir einen Controller haben, der unseren Rest-Service handhabt, und einen Manager, der die Business-Layer-Logik handhabt.
Die Implementierung des Managers sieht wie folgt aus:
package com.betterjavacode.demo.managers;
import com.betterjavacode.demo.models.Task;
import com.betterjavacode.demo.repositories.TaskRepository;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import java.util.Optional;
public class TaskManagerImpl implements TaskManager
{
@Autowired
private TaskRepository taskRepository;
@Override
public Task createTask (Task task)
{
Task t = taskRepository.save(task);
return t;
}
@Override
public Task updateTask (Task task)
{
Task t = taskRepository.save(task);
return t;
}
@Override
public Task getTask (int id)
{
Optional task = taskRepository.findById(id);
return task.get();
}
@Override
public List getAllTasks ()
{
List tasks = (List) taskRepository.findAll();
return tasks;
}
@Override
public void deleteTask (int id)
{
taskRepository.deleteById(id);
}
}
Und unsere RestController
wird wie folgt aussehen:
package com.betterjavacode.demo.controllers;
import com.betterjavacode.demo.managers.TaskManager;
import com.betterjavacode.demo.models.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "http://localhost:8080")
public class TaskController
{
@Autowired
private TaskManager taskManager;
@GetMapping("/tasks")
public List get()
{
return taskManager.getAllTasks();
}
@PostMapping("/task")
public Task save(@RequestBody Task task)
{
return taskManager.createTask(task);
}
@GetMapping("/task/{id}")
public Task get(@PathVariable int id)
{
return taskManager.getTask(id);
}
@DeleteMapping("/task/{id}")
public String delete(@PathVariable int id)
{
taskManager.deleteTask(id);
return "Task with id " + id + " removed";
}
}
Jetzt können wir diese REST-APIs über POSTMAN testen. Ich werde das nicht zeigen, aber wenn Sie interessiert sind, können Sie postman herunterladen.
ReactJS installieren und Frontend einrichten
Für die Frontend-Benutzeroberfläche verwenden wir ReactJS. Wenige Dinge, die Sie benötigen, um ReactJS zu verwenden, sind npm, nodejs und create-react-app.
Sobald Sie diese drei Komponenten installiert haben, können wir ReactJS für unsere aktuelle Spring Boot-Anwendung verwenden.
Wechseln Sie in der Befehlszeile in das Stammverzeichnis, in dem sich die Spring Boot-Anwendung befindet. Erstellen Sie mit dem folgenden Befehl eine Reaktions-App:
npx create-react-app frontend
Wenn Sie in frontend
gehen Verzeichnis auf der Befehlszeile, können Sie das Frontend starten und es zeigt Ihnen den Standardbildschirm der ReactJS-Anwendung.
Um sicherzustellen, dass die Anwendung reibungslos funktioniert, benötigen wir einige Bibliotheken. Wir werden sie wie folgt installieren:
npm install react-router
npm install @material-ui/core
npm install @material-ui/icons
react-router
ist eine Standardbibliothek von React, die Ihre Benutzeroberfläche mit der URL synchron hält, dynamische Routenanpassung, Standortwechsel und Funktionen zur Handhabung von Lazy Code bereitstellt.
core
und icons
sind Bibliotheken für Frontend-Komponenten.
Wir werden einen Proxy in package.json
hinzufügen damit wir keine ganze URL schreiben müssen, wenn wir die Back-End-API aufrufen.
proxy: http://localhost:8080
Sehen wir uns nun die Komponentendateien an.
- App.jsIn dieser Datei definieren wir unsere App-Route mit React Router.
AddTask
dient als Homepage. Wir leiten einen Benutzer zur Ansichtsseite weiter, um eine Aufgabenliste anzuzeigen.
import React, {Component} from 'react';
import AddTask from "./Component/AddTask";
import { Route,BrowserRouter as Router} from 'react-router-dom';
import Table from "./Component/Table"
class App extends Component{
render(){
return(
);
}
}
export default App;
2. AddTask.js
Dies wird der Eintrag unserer Bewerbung sein. In dieser Datei haben wir ein Formular zum Hinzufügen einer Aufgabe. Sobald der Benutzer alle erforderlichen Informationen eingegeben hat, senden wir eine POST-Anforderung an den serverseitigen Code. Diese Datei sieht wie folgt aus:
import React from "react";
import Avatar from "@material-ui/core/Avatar";
import Button from "@material-ui/core/Button";
import CssBaseline from "@material-ui/core/CssBaseline";
import TextField from "@material-ui/core/TextField";
import { Link } from "react-router-dom";
import Grid from "@material-ui/core/Grid";
import GroupIcon from "@material-ui/icons/Group";
import Typography from "@material-ui/core/Typography";
import { makeStyles } from "@material-ui/core/styles";
import Container from "@material-ui/core/Container";
const useStyles = makeStyles(theme => ({
paper: {
marginTop: theme.spacing(7),
display: "flex",
flexDirection: "column",
alignItems: "center"
},
avatar: {
margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main
},
form: {
width: "100%", // Fix IE 11 issue.
marginTop: theme.spacing(3)
},
submit: {
margin: theme.spacing(3, 0, 2)
},
textField: {
marginLeft: theme.spacing(1),
marginRight: theme.spacing(1),
width: "100%"
}
}));
export default function AddTask(){
const classes = useStyles();
const[firstLoad, setLoad] = React.useState(true);
const [selectedDate, setSelectedDate] = React.useState(
new Date()
);
const [taskname, setTaskname] = React.useState("Write Code");
const [status, setStatus] = React.useState("Active");
const handleDateChange = event => setSelectedDate(event.target.value);
const handleTasknameChange = event => setTaskname(event.target.value);
const handleStatusChange = event => setStatus(event.target.value);
const [message, setMessage] = React.useState("Nothing saved in the session");
async function sampleFunc(toInput){
const response = await fetch("/api/task",{
method : "POST",
cache : "no-cache",
credentials : "include",
headers : {
"Content-Type":"application/json"
},
redirect : "follow",
referrerPolicy: "no-referrer", // no-referrer, *client
body: JSON.stringify(toInput)
});
let body = await response.json();
//console.log(body.id);
setMessage(body.id ? "Data successfully updated" : "Data updation failed");
}
const handleSubmit = variables => {
const toInput = {taskname,status, dueDate:selectedDate};
sampleFunc(toInput);
setTaskname("");
setStatus("");
};
if(firstLoad){
setLoad(false);
}
return(
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.paper}>
<GroupIcon />
</Avatar>
<Typography component="h1" variant="h5">
Tasks
</Typography>
<form className={classes.form} noValidate>
<Grid container spacing={2}>
<Grid item xs={12}>
<TextField
variant = "outlined"
required
fullWidth
id="taskname"
value={taskname.text}
label="Taskname"
name="taskname"
autoComplete="taskname"
onChange={handleTasknameChange}
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
autoComplete="status"
name="status"
variant="outlined"
required
fullWidth
value={status.text}
id="status"
label="Status"
onChange={handleStatusChange}
/>
</Grid>
<Grid item xs={12}>
<TextField
id="date"
label="Due Date"
type="date"
defaultValue={""}
className={classes.textField}
InputLabelProps={{
shrink: true
}}
onChange={handleDateChange}
/>
</Grid>
</Grid>
<Button
// type="submit"
fullWidth
variant="contained"
color="primary"
preventDefault
className={classes.submit}
onClick={handleSubmit}
>
Save
</Button>
<Grid container justify="center">
<Grid item>
<Link to="/view">View Tasks</Link>
</Grid>
</Grid>
</form>
<Typography style={{ margin: 7 }} variant="body1">
Status: {message}
</Typography>
</div>
</Container> );
}
3. Tabelle.js
In dieser Datei erhalten wir die Liste der Aufgaben aus unserer Datenbanktabelle über einen API-Aufruf an die Spring Boot-REST-API. Außerdem werden alle Einträge in Tabellenform angezeigt.
import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import TableContainer from "@material-ui/core/TableContainer";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import Paper from "@material-ui/core/Paper";
import Avatar from "@material-ui/core/Avatar";
import GroupIcon from "@material-ui/icons/Group";
import { Link } from "react-router-dom";
import Typography from "@material-ui/core/Typography";
import CircularProgress from "@material-ui/core/CircularProgress";
const useStyles = makeStyles(theme => ({
table: {
minWidth: 600
},
avatar: {
margin: theme.spacing(1),
backgroundColor: theme.palette.secondary.main
},
paper: {
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
margin: `10px`,
height: "100%",
width: "99%",
marginTop: theme.spacing(7)
},
link: {
color: "rgba(0,0,0,0.65)",
textDecoration: "none",
marginLeft: "10%",
alignSelf: "flex-start",
"&:hover": {
color: "rgba(0,0,0,1)"
}
}
}));
export default function SimpleTable() {
const classes = useStyles();
const [data, upDateData] = React.useState([]);
const [firstLoad, setLoad] = React.useState(true);
let isLoading = true;
async function sampleFunc() {
let response = await fetch("/api/tasks");
let body = await response.json();
upDateData(body);
}
if (firstLoad) {
sampleFunc();
setLoad(false);
}
if (data.length > 0) isLoading = false;
return (
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<GroupIcon />
</Avatar>
<Typography component="h1" variant="h5">
All Tasks
</Typography>
{isLoading ? (
<CircularProgress />
) : (
<TableContainer
style={{ width: "80%", margin: "0 10px" }}
component={Paper}
>
<Table className={classes.table} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell align="center">No.</TableCell>
<TableCell align="center">Taskname</TableCell>
<TableCell align="center">Status</TableCell>
<TableCell align="center">Due Date</TableCell>
</TableRow>
</TableHead>
<TableBody>
{data?.map(row => (
<TableRow key={row.taskname}>
<TableCell align="center">{row.id}</TableCell>
<TableCell align="center">{row.taskname}</TableCell>
<TableCell align="center">{row.status}</TableCell>
<TableCell align="center">{row.dueDate}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
)}
<Link className={classes.link} to="/">
{" "}
<Typography align="left">
← Head back to save data
</Typography>{" "}
</Link>
</div>
);
}
Mit dieser Änderung schließen wir die meisten unserer Codeänderungen auf der Frontend- und Backend-Seite ab.
Testen Sie die Anwendung in der lokalen Umgebung
Um die Anwendung jetzt auszuführen, starten Sie die Spring Boot-Anwendung entweder über die Befehlszeile oder in Ihrem Editor
Um das Frontend zu starten, verwenden Sie den folgenden Befehl aus dem Frontend-Ordner:
npm start
Dadurch wird der lokale Host wie folgt am Port 3000 gestartet:
Wenn ich jetzt auf View Tasks
klicke , komme ich zur Liste der Aufgaben wie folgt:
Schlussfolgerung
In diesem Beitrag haben wir gezeigt, wie man eine Anwendung mit Spring Boot und ReactJS erstellt. Sie können mir auf Twitter folgen, wenn Sie Fragen haben. Der Code dafür ist im Github-Repository verfügbar. Wenn Sie nach einer ähnlichen Anwendung mit AngularJS suchen, können Sie meinen Beitrag hier besuchen.
Referenzen
- ReactJS – ReactJS-Startseite
- Spring Boot und ReactJS – Spring Boot und ReactJS