Views: 0
在设计数据库表的时候,当有某个字段需要(具体看自己的业务)跟其他模块的信息有所关联的时候,或者这个字段是跟角色相关的(可能不同的角色对这个模块看到的信息或者行为不一样)时候,该字段就要考虑关联了,我们可以设计为
xxx_id
。
逻辑
选课入口:
学生登录系统后,可以看到可选课程列表(CourseService
提供数据)
每门课程会显示:课程名称、授课教师、剩余名额等信息
选课核心流程:
学生点击”选课”按钮时,系统会做两个重要检查:
- 检查课程是否已满(通过比较课程总人数
num
和已选人数alreadyNum
) - 检查该学生是否已经选过这门课(通过查询
choice
表)
选课成功的情况:
如果课程未满且学生未选过: 系统会在选课表(choice
)中新增一条记录
同时把该课程的已选人数+1(更新course
表)
选课失败的情况:
如果课程已满:提示”课程已经选满” 如果已经选过:提示”你已经选过这门课程”
关键代码位置:
选课逻辑主要在ChoiceService.java
的add()
方法
课程信息查询在CourseService.java
前端选课页面在Choice.vue
简单来说就是:选课前检查名额和重复选课,通过检查就记录选课信息并更新课程人数。
创建数据库
CREATE TABLE `choice` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '课程名称',
`teacher_id` int DEFAULT NULL COMMENT '授课教师',
`student_id` int DEFAULT NULL COMMENT '学生信息',
`course_id` int DEFAULT NULL COMMENT '课程ID',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='选课信息';
entity—Choice.java
创建实体类
public class Choice {
private Integer id;
private String name;
private Integer studentId;
private Integer teacherId;
private String teacherName;
private String studentName;
private Integer courseId;
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 Integer getStudentId() {
return studentId;
}
public void setStudentId(Integer studentId) {
this.studentId = studentId;
}
public Integer getTeacherId() {
return teacherId;
}
public void setTeacherId(Integer teacherId) {
this.teacherId = teacherId;
}
public String getTeacherName() {
return teacherName;
}
public void setTeacherName(String teacherName) {
this.teacherName = teacherName;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public Integer getCourseId() {
return courseId;
}
public void setCourseId(Integer courseId) {
this.courseId = courseId;
}
}
前端
Manager.vue
<el-menu-item index="/choice">
<el-icon><Reading /></el-icon>
<span>选课信息</span>
</el-menu-item>
index.js
{ path: 'choice', component: () => import('@/views/manager/Choice.vue')},
Choice.vue
<template>
<div>
<div class="card" style="margin-bottom: 5px;">
<el-input v-model="data.name" style="width: 300px; margin-right: 10px" placeholder="请输入课程名称查询"></el-input>
<el-button type="primary" @click="load">查询</el-button>
<el-button type="info" style="margin: 0 10px" @click="reset">重置</el-button>
</div>
<div class="card" style="margin-bottom: 5px">
<el-table :data="data.tableData" stripe>
<el-table-column label="课程名称" prop="name"></el-table-column>
<el-table-column label="授课教师" prop="teacherName"></el-table-column>
<el-table-column label="选课学生" prop="studentName"></el-table-column>
<el-table-column label="操作" align="center" width="160" v-if ="data.user.role === 'ADMIN'">
<template #default="scope" >
<el-button type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="card">
<el-pagination background layout="prev, pager, next" v-model:page-size="data.pageSize" v-model:current-page="data.pageNum" :total="data.total"/>
</div>
</div>
</template>
<script setup>
import request from "@/utils/request";
import {reactive} from "vue";
import {ElMessageBox, ElMessage} from "element-plus";
const data = reactive({
user: JSON.parse(localStorage.getItem('system-user') || '{}'),// 获取当前登录的用户信息
pageNum: 1,
pageSize: 10,
total: 0,
formVisible: false,
form: {},
tableData: [],
name: null,
collegeDate: [],// 用于存储学院信息
teacherDate: []// 用于存储教师信息
})
// 分页查询
const load = () => {
let teacherId = null// 用于存储教师id
if (data.user.role === 'TEACHER') {
teacherId = data.user.id// 如果是教师,就查询自己的课程信息
}
request.get('/choice/selectPage', {
params: {
pageNum: data.pageNum,
pageSize: data.pageSize,
name: data.name,
teacherId: teacherId,// 如果是教师,就查询自己的课程信息
}
}).then(res => {
data.tableData = res.data?.list
data.total = res.data?.total
})
}
// 删除
const handleDelete = (id) => {
ElMessageBox.confirm('删除后数据无法恢复,您确定删除吗?', '删除确认', { type: 'warning' }).then(res => {
request.delete('/choice/deleteById/' + id).then(res => {
if (res.code === '200') {
load()
ElMessage.success('操作成功')
} else {
ElMessage.error(res.msg)
}
})
}).catch(err => {})
}
// 重置
const reset = () => {
data.name = null
load()
}
const loadTeacher = () => {//查询所有教师信息
request.get('/teacher/selectAll').then(res => {//调用后端接口查询所有教师信息
if (res.code === '200') {//如果查询成功,将查询到的教师信息赋值给data.teacherDate
data.teacherDate = res.data
}else {//如果查询失败,提示用户
ElMessage.error(res.msg)
}
})
}
const loadCollege= () => {//查询所有学院信息
request.get('/college/selectAll').then(res => {//调用后端接口查询所有学院信息
if (res.code === '200') {//如果查询成功,将查询到的学院信息赋值给data.collegeDate
data.collegeDate = res.data
load()//查询课程信息
}else {//如果查询失败,提示用户
ElMessage.error(res.msg)
}
})
}
load()
loadCollege()
loadTeacher()
</script>
Course.vue
<template #default="scope" v-else>
<el-button type="primary" @click="ChoiceCouse(scope.row)" :disabled = "scope.row.num === scope.row.alreadyNum">选课</el-button>
<!--点击选课按钮的时候会触发选课方法,传入的参数是scope.row,也就是当前行的数据-->
</template>
const ChoiceCouse = (row) => {//选课
let courseData = JSON.parse(JSON.stringify(row))// 复制一份row的数据
courseData.studentId = data.user.id// 将学生id赋值给courseData.studentId
request.post('/choice/add', courseData).then(res => {//调用后端接口添加选课信息
if (res.code === '200') {
ElMessage.success('选课成功')
load() // 刷新课程列表
} else {//如果添加失败,提示用户
ElMessage.error(res.msg)
}
})
}
Controller— ChoiceController.java
/**
* 选课信息模块前端操作接口入口
* 拿到数据后,调用service层的方法,返回结果
* 前端调用接口时,需要传入参数,调用service层的方法,返回结果
**/
@RestController
@RequestMapping("/choice")
public class ChoiceController {
@Resource
// 注入ChoiceService
private ChoiceService choiceService;
/**
* 新增选课信息
* */
@PostMapping("/add")
public Result add(@RequestBody Course course) { // 修改参数类型为 Course
choiceService.add(course);
return Result.success();
}
/**
* 更新选课信息
*/
@PutMapping("/update")
public Result update(@RequestBody Choice choice) {
choiceService.updateById(choice);
return Result.success();
}
/**
* 删除选课信息
*/
@DeleteMapping("/deleteById/{id}")
public Result deleteById(@PathVariable Integer id) {
choiceService.deleteById(id);
return Result.success();
}
/**
* 分页查询
* */
@GetMapping("selectPage")
public Result selectPage(Choice choice,
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "5") Integer pageSize){
// 调用service层的方法,返回结果
PageInfo<Choice> pageInfo = choiceService.selectPage(choice,pageNum,pageSize);
// 总数
return Result.success(pageInfo);
}
/**
* 查询所有选课信息
*/
@GetMapping("/selectAll")
public Result selectAll(){
List<Choice> list = choiceService.selectAll();
return Result.success(list);
}
}
Service
ChoiceService.java
/**
* 选课模块业务逻辑接口
* 要把数据往数据库里存,调用mapper层的方法,返回结果
* 业务逻辑接口调用mapper层的方法,返回结果
*/
@Service
public class ChoiceService {
// 注入ChoiceMapper
@Resource
private ChoiceMapper choiceMapper;
@Resource
private CourseMapper courseMapper;
/**
* 新增选课
*/
public void add(Course course) {
//判断课程是否已经选满
if(course.getNum().equals(course.getAlreadyNum())){//如果课程已经选满,就抛出异常
throw new CustomException("课程已经选满");
}
//判断这个学生这门课程是否已经选过
List<Choice> list = choiceMapper.selectByStudentIdAndCourseId(course.getStudentId(),course.getId());
if(CollectionUtil.isNotEmpty(list)){
throw new CustomException("你已经选过这门课程");//如果已经选过这门课程,就抛出异常
}
//往选课信息表中插入数据
Choice choice = new Choice();//创建一个choice对象
choice.setStudentId(course.getStudentId());//设置学生id
choice.setCourseId(course.getId());//设置课程id
choice.setTeacherId(course.getTeacherId());//设置教师id
choice.setName(course.getName());//设置课程名称
choiceMapper.insert(choice);//往选课信息表中插入数据
//该门课程的已选人数加1
course.setAlreadyNum(course.getAlreadyNum()+1);//已选人数加1
courseMapper.updateById(course);//更新课程信息
}
/**
* 分页查询
*/
public PageInfo<Choice> selectPage(Choice choice,Integer pageNum, Integer pageSize) {
// ToDo 分页查询逻辑处理
// 1. 分页查询选课信息
// 2. 返回选课信息
// 3. 如果没有选课信息,返回空列表
// 4. 如果有选课信息,返回选课信息列表
List<Choice> list;//定义一个list集合
PageHelper.startPage(pageNum,pageSize);//分页查询
if(ObjectUtil.isNotEmpty(choice.getName())){//如果name不为空,就查询name对应的选课信息
list = choiceMapper.selectByName(choice.getName());//查询name对应的选课信息
}else{//如果name为空,就查询所有选课信息
list = choiceMapper.selectAll();//查询所有选课信息
}
return PageInfo.of(list);//返回选课信息列表
}
//根据id查询选课信息,返回一个choice对象
public void updateById(Choice choice) {//传入一个choice对象 前端传过来的choice对象
choiceMapper.updateById(choice);//更新选课信息
}
//根据id删除选课信息
public void deleteById(Integer id) {//传入一个id
choiceMapper.deleteById(id);//删除选课信息
}
//查询所有选课信息
public List<Choice> selectAll() {//返回一个list集合
return choiceMapper.selectAll();//返回所有选课信息
}
}
CourseService.java
/**
* 课程模块业务逻辑接口
* 要把数据往数据库里存,调用mapper层的方法,返回结果
* 业务逻辑接口调用mapper层的方法,返回结果
*/
@Service
public class CourseService {
// 注入CourseMapper
@Resource
private CourseMapper courseMapper;
/**
* 新增课程
*/
public void add(Course course) {
course.setAlreadyNum(0);//设置已选人数为0
courseMapper.insert(course);//调用mapper层的方法,返回结果
}
/**
* 分页查询
*/
public PageInfo<Course> selectPage(Course course,Integer pageNum, Integer pageSize) {
// ToDo 分页查询逻辑处理
// 1. 分页查询课程信息
// 2. 返回课程信息
// 3. 如果没有课程信息,返回空列表
// 4. 如果有课程信息,返回课程信息列表
List<Course> list;//定义一个list集合
PageHelper.startPage(pageNum,pageSize);//分页查询
//表示当前登录是教师
if(ObjectUtil.isNotEmpty(course.getTeacherId())){//如果teacherId不为空,就查询teacherId对应的课程信息
Integer teacherId = course.getTeacherId();
//如果name不为空,就查询name对应的课程信息,否则就查询所有课程信息
if (ObjectUtil.isNotEmpty(course.getName())) {//如果name不为空,就查询name对应的课程信息
list = courseMapper.selectByNameAndTeacherId(course.getName(),teacherId);
} else {//如果name为空,就查询所有课程信息
list = courseMapper.selectAllByTeacherId(teacherId);
}
}
else {
//如果name不为空,就查询name对应的课程信息,否则就查询所有课程信息
if (ObjectUtil.isNotEmpty(course.getName())) {//如果name不为空,就查询name对应的课程信息
list = courseMapper.selectByName(course.getName());
} else {//如果name为空,就查询所有课程信息
list = courseMapper.selectAll();
}
}
return PageInfo.of(list);//返回课程信息列表
}
//根据id查询课程信息,返回一个course对象
public void updateById(Course course) {//传入一个course对象
courseMapper.updateById(course);//调用mapper层的方法,返回结果
}
//根据id删除课程信息
public void deleteById(Integer id) {
courseMapper.deleteById(id);
}
//查询所有课程信息
public List<Course> selectAll() {
return courseMapper.selectAll();
}
}
Mapper
ChoiceMapper.java
注意:sql语句换行后面加空格
明确指定表名样MySQL就能明确知道我们要查询的是哪个表
@Mapper
public interface ChoiceMapper {
//新增
void insert(Choice choice);
//查询所有
@Select("select choice.*, course.name as courseName, teacher.name as teacherName, student.name as studentName " +
"from choice " +
"left join course on choice.course_id = course.id " +
"left join teacher on choice.teacher_id = teacher.id " +
"left join student on choice.student_id = student.id")
List<Choice> selectAll();
//根据name查询
@Select("select choice.*, course.name as courseName, teacher.name as teacherName,student.name as studentName " +
"from choice " +
"left join course on choice.course_id = course.id " +
"left join teacher on choice.teacher_id = teacher.id " +
"left join student on choice.student_id = student.id " +
"where choice.name like concat('%',#{name},'%')")
//查询所有专业信息,并且把专业信息对应的学院名称也查询出来,并且把专业信息对应的教师名称也查询出来,并且模糊查询
List<Choice> selectByName(String name);
//修改
void updateById(Choice choice);
//删除
@Delete("delete from choice where id = #{id}")
void deleteById(Integer id);
//根据name查询,并且根据teacherId查询 模糊查询
@Select("select choice.*, course.name as courseName, teacher.name as teacherName,student.name as studentName " +
"from choice " +
"left join course on choice.course_id = course.id " +
"left join teacher on choice.teacher_id = teacher.id " +
"left join student on choice.student_id = student.id " +
"where choice.name like concat('%',#{name},'%') and choice.teacher_id = #{teacherId}")
List<Choice> selectByNameAndTeacherId(@Param("name") String name, @Param("teacherId") Integer teacherId);
//根据teacherId查询,并且把专业信息对应的学院名称也查询出来,把专业信息对应的教师名称也查询出来
@Select("select choice.*, course.name as courseName,teacher.name as teacherName,student.name as studentName " +
"from choice " +
"left join course on choice.course_id = course.id " +
"left join teacher on choice.teacher_id = teacher.id " +
"left join student on choice.student_id = student.id " +
"where choice.teacher_id = #{teacherId}")
List<Choice> selectAllByTeacherId(Integer teacherId);
@Select("select * from choice where student_id = #{studentId} and course_id = #{courseId}")
List<Choice> selectByStudentIdAndCourseId(@Param("studentId") Integer studentId, @Param("courseId") Integer courseId);
@Select("select choice.*, teacher.name as teacherName,student.name as studentName " +
"from choice " +
"left join teacher on choice.teacher_id = teacher.id " +
"left join student on choice.student_id = student.id " +
"where choice.name like concat('%',#{name},'%') and student_id = #{studentId}")
List<Choice> selectByNameAndStudentId(@Param("name") String name, @Param("studentId") Integer studentId);
@Select("select choice.*, teacher.name as teacherName,student.name as studentName " +
"from choice " +
"left join teacher on choice.teacher_id = teacher.id " +
"left join student on choice.student_id = student.id " + // 这里添加空格
"where student_id = #{studentId} ") // 修改查询条件为student_id
List<Choice> selectAllByStudentId(Integer studentId);
}
ChoiceMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.ChoiceMapper">
<insert id="insert" parameterType="com.example.entity.Choice" useGeneratedKeys="true">
insert into choice (name, teacher_id, student_id,course_id)
values (#{name}, #{teacherId}, #{studentId},#{courseId})
</insert>
<update id="updateById" parameterType="com.example.entity.Choice">
update choice
set name = #{name},
student_id = #{studentId},
teacher_id = #{teacherId},
course_id = #{courseId}
where id = #{id}
-- 这里的id是实体类中的属性名,不是数据库中的字段名
</update>
</mapper>
这个算是整个系统里面最难,最重要的一个逻辑之一吧,一定要仔细看!!!好好消化