Java学生管理系统项目Springboot+vue
错误说明
1.因为使用的是Mybatics 在dao层遗漏了@Mapper标注 导致Services层使用 @Autowired private DaoStuTable daostu;时出现daostu为null,也就是说DaoStuTable 对象没有成功通过依赖注入方式注入到 StuManagement 类
解决方法:在Dao接口处加上@Mapper注解
2.vue中报错 error ‘fetchstudent’ is not defined
原因是 Vue 组件中,因为在 created 钩子函数中直接调用fetchstudent,但是 fetchstudent 方法实际上是定义在 Vue 实例的 methods 对象中的。在 Vue 实例的方法中,需要使用 this 来引用当前的 Vue 实例,从而访问 methods 中定义的方法。
解决方法:
3.前端出现类型错误,因为设置students:[]为数组 而此次根据学号查询只有一个结果 所以需要将this.students=Respose.data改为this.students=[Respose.data]
4.前后端写数据是用的变量名称要一致,例如这个 后端返回的数据名为sno,而这里设置为studentsno,这就导致在使用时出现问题
5.进行增加操作时 从前端向后端发送数据时,后端的方法的参数要使用@RequestBody 这样才能将json数据用实体类接收
细节问题
1.对于要从请求路径上获取数据 例如下面图片,需要在请求路径中携带参数,可以使用@PathVariable注解
原理:在 Spring Web(特别是 Spring MVC 或 Spring Boot)中,@PathVariable 注解的作用是将 URI 路径中的动态部分提取为方法参数。通常,路径中的变量部分是由 {} 括起来的,@PathVariable 允许你将这些路径参数绑定到控制器方法的参数上。使用 @PathVariable 注解后,Spring 会自动从 URL 中提取 {id} 部分并将其绑定到控制器方法的 id 参数。
2.实体类的成员变量不是所有字段都必须有
如果数据库查询返回的字段多于实体类的成员变量,MyBatis 会 忽略 不匹配的字段。只有实体类中定义的字段会被填充,其他字段会被跳过。查询结果字段多于实体类字段时,MyBatis 不会报错,它只是不会处理那些在实体类中没有对应成员变量的字段。
3.注意前端Element UI 只支持vue2
项目目录结构
前端:
后端:
源码
前端
StudentPage.vue
<template>
<div style="width:68%;margin: auto;">
<div style="margin-top: 20px;">
<h1>学生管理系统</h1>
</div>
<el-row :gutter="20">
<!-- 输入框占据一半空间 -->
<el-col :span="6">
<el-input
v-model="inputValue_sno"
placeholder="请输入学号"
clearable>
</el-input>
</el-col>
<!-- 按钮占据一半空间 -->
<el-col :span="4">
<el-row>
<el-button type="primary" @click="SearchBysno">查询</el-button>
</el-row>
</el-col>
<el-col :span="6">
<el-input
v-model="inputValue_sname"
placeholder="请输入姓名"
clearable>
</el-input>
</el-col>
<!-- 按钮占据一半空间 -->
<el-col :span="4">
<el-row>
<el-button type="primary" @click="SearchByName">查询</el-button>
</el-row>
</el-col>
<el-col :span="4">
<el-row>
<el-button type="primary" @click="handleClick2">增加学生</el-button>
</el-row>
</el-col>
</el-row>
<!-- 添加间隔 -->
<div style="height: 15px;"></div>
<el-table :data="students" border style="width: 100%">
<el-table-column fixed prop="id" label="序号" width="50">
</el-table-column>
<el-table-column prop="sno" label="学号" width="100">
</el-table-column>
<el-table-column prop="sname" label="姓名" width="100">
</el-table-column>
<el-table-column prop="major" label="专业" width="200">
</el-table-column>
<el-table-column prop="grades" label="绩点" width="100">
</el-table-column>
<el-table-column prop="email" label="邮箱" width="200">
</el-table-column>
<el-table-column prop="tel" label="电话" width="200">
</el-table-column>
<el-table-column fixed="right" label="操作" width="100">
<template slot-scope="scope">
<el-button @click="handleClick1(scope.row)" type="text" size="small">修改</el-button>
<el-button @click="del(scope.row)" type="text" size="small">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog title="增加学生信息" :visible.sync="addDialogVisible" width="35%">
<el-form :model="addStudentForm">
<!-- 第一行:学号和姓名 -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="学号">
<el-input v-model="addStudentForm.studentsno" autocomplete="off"></el-input>
</el-form-item>
</el-col>
<el-col :span="10" :offset="2">
<el-form-item label="姓名">
<el-input v-model="addStudentForm.sname" autocomplete="off"></el-input>
</el-form-item>
</el-col>
</el-row>
<!--第二行:专业和绩点 -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="专业">
<el-input v-model="addStudentForm.major" autocomplete="off"></el-input>
</el-form-item>
</el-col>
<el-col :span="10" :offset="2">
<el-form-item label="绩点">
<el-input v-model="addStudentForm.grades" autocomplete="off"></el-input>
</el-form-item>
</el-col>
</el-row>
<!-- 第三行:邮箱和电话 -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="邮箱">
<el-input v-model="addStudentForm.email" autocomplete="off"></el-input>
</el-form-item>
</el-col>
<el-col :span="10" :offset="2">
<el-form-item label="电话">
<el-input v-model="addStudentForm.tel" autocomplete="off"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="addDialogVisible = false">取消</el-button>
<el-button type="primary" @click="addsubmit">提交</el-button>
</span>
</el-dialog>
<el-dialog title="修改学生信息" :visible.sync="updateDialogVisible" width="35%">
<el-form :model="studentForm">
<!-- 第一行:学号和姓名 -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="学号">
<el-input v-model="studentForm.sno" autocomplete="off"></el-input>
</el-form-item>
</el-col>
<el-col :span="10" :offset="2">
<el-form-item label="姓名">
<el-input v-model="studentForm.sname" autocomplete="off"></el-input>
</el-form-item>
</el-col>
</el-row>
<!--第二行:专业和绩点 -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="专业">
<el-input v-model="studentForm.major" autocomplete="off"></el-input>
</el-form-item>
</el-col>
<el-col :span="10" :offset="2">
<el-form-item label="绩点">
<el-input v-model="studentForm.grades" autocomplete="off"></el-input>
</el-form-item>
</el-col>
</el-row>
<!-- 第三行:邮箱和电话 -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="邮箱">
<el-input v-model="studentForm.email" autocomplete="off"></el-input>
</el-form-item>
</el-col>
<el-col :span="10" :offset="2">
<el-form-item label="电话">
<el-input v-model="studentForm.tel" autocomplete="off"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="updateDialogVisible = false">取消</el-button>
<el-button type="primary" @click="updatesubmit">提交</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import axios from 'axios';
import { Message } from 'element-ui';
export default {
data() {
return {
students:[],
userId:null,
addDialogVisible: false, // 添加对话框可见性状态
updateDialogVisible: false, // 修改对话框可见性状态
studentForm: { // 表单数据模型
id: null,
sno: null,
sname: null,
major:null,
grades: null,
email: null,
tel: null
},
addStudentForm: {// 增加表单数据模型
sno: null,
sname: null,
major:null,
grades: null,
email: null,
tel: null
},
message: "",
inputValue_sno: '', // 根据学号查询内容
inputValue_sname: '', // 根据姓名模糊查询内容
};
},
//钩子函数
created(){
this.fetchstudent();
},
methods: {
fetchstudent() {
console.log("Fetching students...");
axios.get('http://localhost:8080/stu/getallstu')
.then(Response => {
this.students=Response.data;
})
.catch(error => {
console.error('Error fetching students:', error); // 处理错误
});
},
SearchBysno(){
console.log("Searching by sno...");
axios.get(`http://localhost:8080/stu/getstubysno/${this.inputValue_sno}`)
.then(Response => {
this.students = [Response.data];
console.log("返回数据为:");
console.log(this.students);
})
.catch(error => {
console.error('Error searching by sno:', error); // 处理错误
});
},
SearchByName(){
axios.get(`http://localhost:8080/stu/getstubyname/${this.inputValue_sname}`)
.then(Response => {
if(Array.isArray(Response.data)){
this.students = Response.data;
}else{
this.students = [Response.data];
}
console.log("返回数据为:");
console.log(this.students);
})
.catch(error => {
console.error('Error searching by sno:', error); // 处理错误
});
},
//修改
handleClick1(row){
console.log("Modifying student...");
console.log(row); // 查看打印的 row 对象中是否包含学号字段
this.studentForm = { ...row }; // 初始化表单数据为当前行数据
this.updateDialogVisible = true; // 显示对话框
},
//增加
handleClick2(){
this.addDialogVisible = true; // 显示对话框
this.addStudentForm = { // 初始化表单数据
studentsno: '',
sname: '',
major: '',
grades: '',
email: '',
tel: ''
};
},
updatesubmit() {
console.log("Submitting grade:", this.studentForm);
axios.put(`http://localhost:8080/stu/update`,
{
id: this.studentForm.id,
sno: this.studentForm.sno,
sname: this.studentForm.sname,
major: this.studentForm.major,
grades: this.studentForm.grades,
email: this.studentForm.email,
tel: this.studentForm.tel,
})
.then(()=> {
this.message = "修改成功";
this.updateDialogVisible = false; // 关闭对话框
this.fetchstudent(); // 刷新成绩列表
this.clearForm(); // 清空表单
})
.catch(error => {
console.error("Error updating grade:", error);
this.message = "成绩录入失败"; // 显示错误信息
});
},
addsubmit() {
console.log(this.addStudentForm);
//console.log("Submitting grade:", this.studentForm.id);
axios.post(`http://localhost:8080/stu/add`,
{"sno": this.addStudentForm.studentsno,
"sname": this.addStudentForm.sname,
"major": this.addStudentForm.major,
"grades": this.addStudentForm.grades,
"email": this.addStudentForm.email,
"tel": this.addStudentForm.tel,
})
.then(()=> {
this.message = "添加成功";
this.addDialogVisible = false; // 关闭对话框
this.fetchstudent(); // 刷新成绩列表
this.clearForm(); // 清空表单
})
.catch(error => {
console.error("Error updating grade:", error);
this.message = "添加失败"; // 显示错误信息
});
},
//删除的方法
del(row){
console.log("Deleting student...");
console.log(this.studentForm);
this.studentForm = { ...row }; // 初始化表单数据为当前行数据
axios.post("http://localhost:8080/stu/delete",{
id: this.studentForm.id
})
.then(()=> {
this.message = "删除成功";
Message.success("删除成功"); // 使用 Message 显示成功消息
this.fetchstudent(); // 刷新成绩列表
this.clearForm(); // 清空表单
})
.catch(error => {
console.error("Error deleting student:", error);
this.message = "删除失败"; // 显示错误信息
});
},
clearForm() {
this.grade = {
studentId: null,
courseId: null,
regular_score: 0,
exam_score: 0,
weight: 0.3
};
}
},
};
</script>
<style scoped>
.message {
margin-top: 10px;
color: green;
}
</style>
App.vue
<template>
<router-view></router-view>
</template>
<script setup lang="ts">
</script>
<style>
</style>
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
//import store from './store'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.config.productionTip = false
Vue.use(ElementUI);
new Vue({
router,
//store,
render: h => h(App)
}).$mount('#app')
router目录下的index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/student',
name: 'student',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/StudentPage.vue')
}
]
const router = new VueRouter({
routes
})
export default router
后端
Pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.nike</groupId>
<artifactId>stu_mangement</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>stu_mangement</name>
<description>stu_mangement</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter-test</artifactId>
<version>3.0.4</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Application.properties
spring.application.name=stu_mangement
# 连接数据库
spring.datasource.url=jdbc:mysql://localhost:3306/stu?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
//解决跨域问题
spring.web.cors.allow-credentials=true
spring.web.cors.allowed-origins=http://localhost:8083
spring.web.cors.allowed-methods=GET,POST,PUT,DELETE,OPTIONS
spring.web.cors.allowed-headers=*
StudentManagementController.java
package cn.nike.stu_mangement.cotroller;
import cn.nike.stu_mangement.entity.Stu;
import cn.nike.stu_mangement.services.StuManagement;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/stu")
@CrossOrigin(origins = "http://localhost:8081")
public class StuMangementController {
@Autowired
StuManagement stuManagement;
@RequestMapping("/getallstu")
public List<Stu>GetAllStu(){
List<Stu> students=stuManagement.QueryAllStu();
if(students==null){
System.out.println("Controller--students is null");
return null;
}
//students.forEach(student->System.out.println(student));
return students;
}
@RequestMapping("/getstubyid/{id}")
public Stu GetStuById(@PathVariable int id){
return stuManagement.QueryStuById(id);
}
@RequestMapping("/getstubysno/{sno}")
public Stu GetStuBySno(@PathVariable String sno){
return stuManagement.QueryStuBysno(sno);
}
@RequestMapping("/getstubyname/{name}")
public List<Stu> GetStuByName(@PathVariable String name){
return stuManagement.QueryStuByName(name);
}
@RequestMapping(value="/add" ,method = RequestMethod.POST)
public void AddStu(@RequestBody Stu stu) throws Exception {
stuManagement.addStu(stu);
System.out.println("添加成功");
}
@PutMapping("/update")
public void UpdateStu(@RequestBody Stu stu) throws Exception {
System.out.println(stu);
stuManagement.updateStu(stu);
}
@RequestMapping("/delete")
public void deleteStu(@RequestBody Stu stu) throws Exception {
System.out.println("到达后端");
System.out.println(stu);
int id=stu.getId();
stuManagement.deleteStu(id);
}
}
Service层
StuManagement.java
package cn.nike.stu_mangement.services;
import cn.nike.stu_mangement.dao.DaoStuTable;
import cn.nike.stu_mangement.entity.Stu;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.concurrent.ExecutionException;
@Service
public class StuManagement {
@Autowired
private DaoStuTable daostu;
public List<Stu> QueryAllStu() {
return daostu.getAllStu();
}
public Stu QueryStuById(int id) {
return daostu.getStuById(id);
}
public List<Stu>QueryStuByName(String stuName) {
return daostu.getStuByName(stuName);
}
public Stu QueryStuBysno(String sno) {
return daostu.getStuBySno(sno);
}
public void addStu(Stu stu) throws Exception{
//if(daostu.insertStu(stu.getSno(),stu.getSname(),stu.getGrades(),stu.getMajor(),stu.getEmail(),stu.getTel()))
if(!daostu.insertStu(stu))throw new Exception("插入失败!");
}
public void updateStu(Stu stu) throws Exception{
if(!daostu.updateStu(stu))throw new Exception("修改失败");
}
public void deleteStu(int id) throws Exception{
if(!daostu.deleteStu(id))throw new Exception("删除失败!");
}
}
dao层
这是个接口
DaoStuTable.java
package cn.nike.stu_mangement.dao;
import cn.nike.stu_mangement.entity.Stu;
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
@Mapper
public interface DaoStuTable {
//各种查询操作
@Select("select * from stu where id=#{id}")
public Stu getStuById(int id);
@Select("select * from stu where sno=#{sno}")
public Stu getStuBySno(String sno);
@Select("select * from stu ")
public List<Stu> getAllStu();
@Select("select * from stu where sname like concat('%',#{name},'%')")
public List<Stu> getStuByName(String name);
//各种添加操作
@Insert("insert into stu(sno,sname,major,grades,email,tel) values (#{sno},#{sname},#{major},#{grades},#{email},#{tel})")
public boolean insertStu( Stu stu);
//修改
@Update("update stu set sno= #{sno},sname=#{sname},major=#{major},grades=#{grades},email=#{email},tel=#{tel} where id=#{id}")
public boolean updateStu(Stu stu);
@Delete("delete from stu where id=#{id}")
public boolean deleteStu(int id);
}
实体:
Stu.java
package cn.nike.stu_mangement.entity;
public class Stu {
private int id;
private String sno;
private String sname;
private String major;
private double grades;
private String email;
private String tel;
public Stu() {}
public Stu(int id, String sno,String sname, String major, double grades, String email, String tel) {
this.id = id;
this.sno = sno;
this.sname = sname;
this.major = major;
this.grades = grades;
this.email = email;
this.tel = tel;
}
public String getSno() {
return sno;
}
public void setSno(String sno) {
this.sno = sno;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public double getGrades() {
return grades;
}
public void setGrades(double grades) {
this.grades = grades;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
@Override
public String toString() {
return "Stu [id=" + id + ",sno="+sno+", sname=" + sname + ", major="+ major +
", grades=" + grades + ", email=" + email + ", tel=" + tel + "]";
}
}
建表SQL语句:
create table stu
(
id int auto_increment comment '序号'
primary key,
sno varchar(60) null comment '学号',
sname varchar(40) not null comment '姓名',
major varchar(50) null comment '专业',
grades double null comment '绩点',
email varchar(60) null comment '邮箱',
tel varchar(60) null comment '电话'
);