Java >> Java Tutorial >  >> Tag >> Spring

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.

  1. 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">
          &#x2190; 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

  1. ReactJS – ReactJS-Startseite
  2. Spring Boot und ReactJS – Spring Boot und ReactJS


Java-Tag