点击录入,下方的状态会变成数据更新成功。
刷新student_db数据库,发现学生数据被录入数据库并成功获取展示到花名册页面。
运行演示完,写一下这个小项目的步骤。
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
打开项目根目录下的pom.xml文件,配置项目基本和其他依赖。
依赖:如果报红需要reimport
<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包下新建一个类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; } }
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); } }
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); } }
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无需修改
在工作区目录执行create-react-app stuinfo创建React项目
cd stuinfo进入到项目根目录,
再在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"> ← 返回录入界面 </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