【SpringBoot】学生信息录入和查阅的前后端分离的小项目,SpringBoot+React+MySQL,手把手教学

 运行效果

【SpringBoot】学生信息录入和查阅的前后端分离的小项目,SpringBoot+React+MySQL,手把手教学

 【SpringBoot】学生信息录入和查阅的前后端分离的小项目,SpringBoot+React+MySQL,手把手教学

点击录入,下方的状态会变成数据更新成功。

 【SpringBoot】学生信息录入和查阅的前后端分离的小项目,SpringBoot+React+MySQL,手把手教学

【SpringBoot】学生信息录入和查阅的前后端分离的小项目,SpringBoot+React+MySQL,手把手教学

 刷新student_db数据库,发现学生数据被录入数据库并成功获取展示到花名册页面。

【SpringBoot】学生信息录入和查阅的前后端分离的小项目,SpringBoot+React+MySQL,手把手教学

 运行演示完,写一下这个小项目的步骤。

新建数据库student_db,在该数据库下新建表stu_tb

CREATE TABLE `stu_tb` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(32) DEFAULT NULL,
  `major` varchar(128) DEFAULT NULL,
  `birthday` date DEFAULT NULL,
  `gender` varchar(4) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3

【SpringBoot】学生信息录入和查阅的前后端分离的小项目,SpringBoot+React+MySQL,手把手教学

 新建SpringBoot项目

【SpringBoot】学生信息录入和查阅的前后端分离的小项目,SpringBoot+React+MySQL,手把手教学

 【SpringBoot】学生信息录入和查阅的前后端分离的小项目,SpringBoot+React+MySQL,手把手教学

【SpringBoot】学生信息录入和查阅的前后端分离的小项目,SpringBoot+React+MySQL,手把手教学

 配置项目

打开项目根目录下的pom.xml文件,配置项目基本和其他依赖。

【SpringBoot】学生信息录入和查阅的前后端分离的小项目,SpringBoot+React+MySQL,手把手教学

依赖:如果报红需要reimport

【SpringBoot】学生信息录入和查阅的前后端分离的小项目,SpringBoot+React+MySQL,手把手教学

<dependencies>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>


		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>

		<dependency>
			<groupId>javax.persistence</groupId>
			<artifactId>persistence-api</artifactId>
			<version>1.0</version>
		</dependency>


		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

打开resource目录下的application.properties文件,开始配置数据库信息。

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/student_db?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=你的数据库用户名,默认root
spring.datasource.password=你的数据库密码

开始写后端代码

model

新建一个包,model,在model包下新建一个类Student,

在写好类的私有属性后,快捷键alt+insert自动生成getter 和setter方法,自动生成重写toString方法。加上注解,自动导包。

最后,你的Student.java代码如下:

package com.liulei.stuinfo.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.time.LocalDate;

@Entity
@Table(name = "stu_tb")
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column
    private Integer id;

    @Column
    private String name;

    @Column
    private String major;

    @Column
    private LocalDate birthday;

    @Column
    private String gender;

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", major='" + major + '\'' +
                ", birthday=" + birthday +
                ", gender='" + gender + '\'' +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getMajor() {
        return major;
    }

    public void setMajor(String major) {
        this.major = major;
    }

    public LocalDate getBirthday() {
        return birthday;
    }

    public void setBirthday(LocalDate birthday) {
        this.birthday = birthday;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }
}

dao

StudentDAO.java

package com.liulei.stuinfo.dao;

import com.liulei.stuinfo.model.Student;

import java.util.List;

public interface StudentDAO {
    List<Student> get();

    Student get(int id);

    void save(Student student);

    void delete(int id);
}

StudentDAOImpl.java

package com.liulei.stuinfo.dao;

import com.liulei.stuinfo.model.Student;
import org.hibernate.Session;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import javax.persistence.EntityManager;
import java.util.List;

@Repository
public class StudentDAOImpl implements StudentDAO{
    @Autowired
    private EntityManager entityManager;

    @Override
    public List<Student> get() {
        Session currSession = entityManager.unwrap(Session.class);
        Query<Student> query = currSession.createQuery("from Student", Student.class);
        List<Student> list = query.getResultList();
        return list;
    }

    @Override
    public Student get(int id) {
        Session currSession = entityManager.unwrap(Session.class);
        Student stu = currSession.get(Student.class, id);
        return stu;
    }

    @Override
    public void save(Student Student) {
        Session currSession = entityManager.unwrap(Session.class);
        currSession.saveOrUpdate(Student);
    }

    @Override
    public void delete(int id) {
        Session currSession = entityManager.unwrap(Session.class);
        Student stu = currSession.get(Student.class, id);
        currSession.delete(stu);
    }
}

service

StudentService.java

package com.liulei.stuinfo.service;

import com.liulei.stuinfo.model.Student;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

public interface StudentService {

    @Transactional
    List<Student> get();

    @Transactional
    Student get(int id);

    @Transactional
    void save(Student student);

    @Transactional
    void delete(int id);
}

StudentServiceImpl.java

package com.liulei.stuinfo.service;

import com.liulei.stuinfo.dao.StudentDAO;
import com.liulei.stuinfo.model.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
public class StudentServiceImpl implements StudentService{

    @Autowired
    private StudentDAO studentDao;

    @Transactional
    @Override
    public List<Student> get() {
        return studentDao.get();
    }

    @Transactional
    @Override
    public Student get(int id) {
        return studentDao.get(id);
    }

    @Transactional
    @Override
    public void save(Student student) {
        studentDao.save(student);

    }

    @Transactional
    @Override
    public void delete(int id) {
        studentDao.delete(id);

    }
}

controller

StudentController.java
package com.liulei.stuinfo.controller;

import com.liulei.stuinfo.model.Student;
import com.liulei.stuinfo.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api")
public class StudentController {

    @Autowired
    private StudentService studentService;

    @GetMapping("/student")
    public List<Student> get() {
        return studentService.get();
    }

    @PostMapping("/student")
    public Student save(@RequestBody Student student) {
        studentService.save(student);
        return student;
    }

    @GetMapping("/student/{id}")
    public Student get(@PathVariable int id) {
        return studentService.get(id);
    }

    @DeleteMapping("/student/{id}")
    public String delete(@PathVariable int id) {
        studentService.delete(id);
        return "Student removed with id "+id;

    }

    @PutMapping("/student")
    public Student update(@RequestBody Student student) {
        studentService.save(student);
        return student;
    }
}
StuinfoApplication.java无需修改

接着开始写前端代码-React

在工作区目录执行create-react-app stuinfo创建React项目

cd stuinfo进入到项目根目录,

【SpringBoot】学生信息录入和查阅的前后端分离的小项目,SpringBoot+React+MySQL,手把手教学

再在components建立AddStudent.js用以录入学生信息的界面,本项目前端样式用的@material-ui,

需要提前添加到依赖中:yarn add 

yarn add @material-ui/core
yarn add @material-ui/icons
import React from "react";
import 'isomorphic-fetch';
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%",
    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 AddStudent() {
  const classes = useStyles();
  const [firstLoad, setLoad] = React.useState(true);

  const [selectedDate, setSelectedDate] = React.useState(
    new Date("1999-12-12T21:11:11")
  );
  const [name, setName] = React.useState("");
  const [major, setMajor] = React.useState("");
  const [gender, setGender] = React.useState("");

  const handleDateChange = date => setSelectedDate(date.target.value);
  const handleNameChange = event => setName(event.target.value);
  const handleMajorChange = event => setMajor(event.target.value);
  const handleGenderChange = event => setGender(event.target.value);

  const [message, setMessage] = React.useState("暂未保存任何内容");

  async function sampleFunc(toInput) {
    const response = await fetch("/api/student", {
      method: "POST", 
      mode: "cors", 
      cache: "no-cache", 
      credentials: "same-origin",
      headers: {
        "Content-Type": "application/json"
       
      },
      redirect: "follow", 
      referrerPolicy: "no-referrer",
      body: JSON.stringify(toInput) header
    });
    let body = await response.json();
    console.log(body.id);
    setMessage(body.id ? "数据更新成功" : "数据更新失败");
  }

  const handleSubmit = variables => {
    const toInput = { name, major, gender, birthday: selectedDate };
    sampleFunc(toInput);
    setName("");
    setMajor("");
    setGender("");
  };

  if (firstLoad) {
    // sampleFunc();
    setLoad(false);
  }

  return (
    <Container component="main" maxWidth="xs">
      <CssBaseline />
      <div className={classes.paper}>
        <Avatar className={classes.avatar}>
          <GroupIcon />
        </Avatar>
        <Typography component="h1" variant="h5">
          学生花名册
        </Typography>
        <form className={classes.form} noValidate>
          <Grid container spacing={2}>
            <Grid item xs={12}>
              <TextField
                variant="outlined"
                required
                fullWidth
                id="name"
                value={name}
                label="姓名"
                name="name"
                autoComplete="name"
                onChange={handleNameChange}
              />
            </Grid>
            <Grid item xs={12} sm={6}>
              <TextField
                autoComplete="major"
                name="major"
                variant="outlined"
                required
                fullWidth
                value={major}
                id="major"
                label="专业"
                onChange={handleMajorChange}
              />
            </Grid>
            <Grid item xs={12} sm={6}>
              <TextField
                variant="outlined"
                required
                fullWidth
                id="gender"
                value={gender}
                label="性别"
                name="gender"
                autoComplete="gender"
                onChange={handleGenderChange}
              />
            </Grid>
            <Grid item xs={12}>
              <TextField
                id="date"
                label="生日"
                type="date"
                defaultValue="1999-12-12"
                className={classes.textField}
                InputLabelProps={{
                  shrink: true
                }}
                onChange={handleDateChange}
              />
            </Grid>
          </Grid>
          <Button
            // type="submit"
            fullWidth
            variant="contained"
            color="primary"
            preventDefault
            className={classes.submit}
            onClick={handleSubmit}
          >
            录入
          </Button>

          <Grid container justify="center">
            <Grid item>
              <Link to="/view">查看学生花名册</Link>
            </Grid>
          </Grid>
        </form>
        <Typography style={{ margin: 7 }} variant="body1">
          状态: {message}
        </Typography>
      </div>
    </Container>
  );
}

再在components建立Table.js用以输出显示学生花名册

import React from "react";
import 'isomorphic-fetch';
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("http://localhost:8081/api/student");
    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">
        学生花名册
      </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">姓名</TableCell>
                <TableCell align="center">专业</TableCell>
                <TableCell align="center">性别</TableCell>
                <TableCell align="center">生日</TableCell>
              </TableRow>
            </TableHead>
            <TableBody>
              {data?.map(row => (
                <TableRow key={row.name}>
                  <TableCell align="center">{row.name}</TableCell>
                  <TableCell align="center">{row.major}</TableCell>
                  <TableCell align="center">{row.gender}</TableCell>
                  <TableCell align="center">{row.birthday}</TableCell>
                </TableRow>
              ))}
            </TableBody>
          </Table>
        </TableContainer>
      )}
      <Link className={classes.link} to="/">
        {" "}
        <Typography align="left">
          &#x2190; 返回录入界面
        </Typography>{" "}
      </Link>
    </div>
   ) );
}

再在App.js中引入上述组件

import React, { Component } from "react";
import AddStudent from "./components/AddStudent";
import { Route,Routes, BrowserRouter as Router } from "react-router-dom";
import Table from "./components/Table";

class App extends Component {
  render() {
    return (
      <Router>
        <Routes>
        <Route exact path="/" componet=<AddStudent/> />
        <Route exact path="/view" componet=<Table/> />
        </Routes>
      </Router>
    );
  }
}

export default App;

最后在index.js中引入App

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(
    <App />,
    document.getElementById('root')
 );

最后在项目根目录执行yarn start就可以启动项目了。在此之前需要先启动springboot的主程序类

StuinfoApplication
上一篇:Android Material Design系列之FloatingActionButton和Sna


下一篇:图书管理系统