数据库设计
因为教务系统主要分成了学生端,教师端,管理员端,因此需要创建三个表student,teacher,admin,表示三种角色。
-
student表:
-
teacher表:
-
admin表:
但是需要获取这个学生的课表信息,因此还需要创建一个course表,表示课程信息: -
course表:
此外,为了实现选课功能,我们需要保证那些课是需要选择的,所以,新建一个selectCourse表,用于存放开放选课的课程: -
selectCourse表
在管理员添加、修改学生信息的时候,如果我们需要修改学生的学院的,我们需要给出一个下拉框,所以我们需要创建academy表,表示不同的学院信息,同理我们需要创建major表,表示不同的专业信息。
-
major表:
-
academy表:
所以总的表有:
页面的设计
登录界面
为了使thymeleaf发生渲染作用,那么我们需要在对应的类上面使用的是@Controller注解,并且对应的方法上面不可以使用@ResponseBody注解,而不是@RestController注解(因为@RestController = @Controller + @ResponseBody)。一旦使用了@RestController或者@Controller + @ResponseBody注解,那么没有办法实现thymeleaf的渲染作用。
同时,如何来到登录界面之后,我们提交应该怎样获取登录用户的对应信息呢?此时我们将根据@RequestParam()注解,从而获取对应的信息,其中括号中的参数是我们想要获取的信息,这个参数需要和我们在template中的index中的名字需要一致。
@PostMapping("/user/login")
public String login(@RequestParam("username")String username,
@RequestParam("password")String password,
@RequestParam("identity")String identity,
Model model, HttpSession session) {
this.identity = identity;
//需要获取这个登录的用户名以及密码以及所勾选的角色(利用@RequestParam()就可以获得对应的参属信息
//登录成功之后,返回到主页面
//定义一个sql语句,然后返回一个对象
if(StringUtils.isEmpty(username)){
model.addAttribute("name","用户名不可以为空");
return "index";
}
if(StringUtils.isEmpty(password)){
model.addAttribute("password","登录密码不可以为空");
return "index";
}
String sql = "select password from " + identity + " where name = ?";
try{
String pass = jdbcTemplate.queryForObject(sql, String.class, new Object[]{username});
if(!password.equals(pass)){
model.addAttribute("password","用户密码错误");
return "index";
}else{
//session对象设置loginUser(自定义的),并且它的值为username
session.setAttribute("loginUser",username);
return "redirect:/dashboard";
}
}catch (EmptyResultDataAccessException e){
//学生为null,说明查无此人
model.addAttribute("msg","查无此人,请重新输入");
return "index";
}
}
但是看到上面的代码,为什么添加一个try-catch异常呢?代码并不会发生异常啊,然而,当我们输入的是表中不存在的数据的时候,本来需要返回查无此人的信息,但是如果没有try-catch,而仅仅靠if判断pass是否为空,从而得知当前的用户是否存在于数据库中是不可以,他会发生报错:`Incorrect result size: expected 1, actual 0`,这就是因为jdbcTemplate调用queryForObject的时候发生了报错。所以为了发生这样的错误,需要使用try-catch,一旦检测到适应空的数据,就会执行catch语句。
但是有一个bug没有解决,就是如果没有点击单选按钮的时候,就会发生了报错,具体原因还没有知道,如果有大佬知道的话,请指教哈!!!
提取公共部分
因为我们设计一个学生端的时候,有很多个选项,这时候我们需要提取一些公共部分,例如头部导航栏和侧边栏,因此我们定义了commons类,用来存放公共部分,然后利用thymelefat中的fragment来定义公共部分的名字,然后再对应的页面中插入这个公共部分即可。
<!--利用th:fragment来定义头部导航栏-->
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0" th:fragment="topbar">
<!--利用th:fragment来定义侧边栏这个公共部分-->
<nav class="col-md-2 d-none d-md-block bg-light sidebar" th:fragment="sidebar">
这时候我们利用th:replace或者th:insert在对应的页面中插入公共部分内容:
<!--利用th:insert插入公共部分的时候,需要使用的符号是~,并且括号中是对应html文件中的名字为topbar的
公共部分.所以这里是将resources下面的common文件夹下面的commons.html中的topbar插入-->
<div th:insert="~{common/commons::topbar}"></div>
<div th:insert="~{common/commons::sidebar}"></div>
此外还可以传递参数,从而实现点击侧边栏的某一项的时候实现高亮:
<!--当前在course.html界面,也就是点击了课程管理界面,此时我们需要这一项实现高亮-->
<div th:insert="~{common/commons::sidebar(active = 'course.html')></div>
那么根据上面的代码,我们来到common文件夹下面的commons.html侧边栏中的课程管理这一个功能,然后加上这个修饰:th:class="@{active=='course.html' ? 'nav-link active' : 'nav-link'}
,即如下所示:
<a th:class="${active == 'course.html' ? 'nav-link active' : 'nav-link'}" th:href="@{/getCourse}">
课程管理
</a>
个人信息的修改
对于个人信息的修改,我们首先需要获取这个人原本的信息,然后再对相应的信息进行修改,然后执行sql语句实现更新,所以我们通过url来到toUpdatePage这个方法中,通过执行sql语句,来获取当前登录用户原来的信息,然后将这些信息添加到model中,来到updateInformation.html界面,就会看到这个用户原来的信息表单,然后进行修改,点击提交之后,根据url来到updateInformation方法中,然后执行sql语句进行更新。值得注意的是,有可能会修改用户名字,所以需要通过session进行修改实现同步修改用户的名字。
@GetMapping("/updateInformation")
public String toUpdatePage(Model model,HttpSession session){
//获取当前需要修改的学生信息
Object loginUser = session.getAttribute("loginUser");//获取当前登录的用户
String sql = "select * from student where name = ?";
Student student = jdbcTemplate.queryForObject(sql,new Object[]{loginUser},new StudentMapper());
//System.out.println(student);//输出原来的学生信息
model.addAttribute("student",student);//将当前需要修改的学生获取,然后将其添加到前端页面
return "student/updateInformation";//来到template中的student包中的updateInformation.html
}
@PostMapping("/updateInformation")
public String updateInformation(Student student2,HttpSession session){
System.out.println(student2);//输出修改后的学生信息
//修改信息的时候,为了避免修改了学生的姓名,所以需要将session中的loginUser一并修改
String sql = "update student set " +
"stu_id = ?," +
"name = ?," +
"gender = ?," +
"birth = ?," +
"nationality = ?," +
"into_time = ?," +
"school_year = ?," +
"phone = ?," +
"address = ? " +
"where stu_id = ?";
jdbcTemplate.update(sql,new Object[]{
student2.getStu_id(),
student2.getName(),
student2.getGender(),
student2.getBirth(),
student2.getNationality(),
student2.getInto_time(),
student2.getSchool_year(),
student2.getPhone(),
student2.getAddress(),
student2.getStu_id()
});//调用update方法,可以执行增,删,改的操作
//如果需要修改登录用户的名字,那么虽然数据库修改成功了,但是前端页面也需要修改,所以需要
//修改session中的loginUser的值.
session.setAttribute("loginUser",student2.getName());
return "redirect:/person";//修改成功之后,重新返回到个人信息界面
}
值得注意的是,修改出生日期的时候,如果没有再配置文件中配置日期的输入格式,那么默认是’yyyy/MM/dd’的格式,此时,如果输入的是’yyyy-MM-dd’的话,那么就会发生报错,提示日期的个数有问题,提示信息的重点在于:Field error in object ‘student’ on field ‘birth’: rejected value [2001-05-25]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date' for property 'birth'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.util.Date] for value '2001-05-25'; nested exception is java.lang.IllegalArgumentException]
,所以我们需要在配置文件中指定日期的输入格式:
spring:
mvc:
format:
date:
指定之后,从而指定了日期的输入格式为’yyyy-MM-dd’,如果我们输入的是’yyyy/MM/dd’同样会发生上面的错误。
但是有一个问题没有解决的是:如果修改的日期是为:‘2001-08-30’,那么最后返回到数据库中信息为’2001-08-29’,最终显示再页面中的也是’2001-08-29’,如果有大佬知道的话,请指教哈!!!
课表查询
对于一个学生来说,如果这个学生修了这门课,所以就会有这一门课的成绩,所以需要再score表中查询这个学生的课程。一开始由于表没有考虑到这一点,就设计了course表,并且course表中含有stu_id这个列,但是后面才意识到一个课程可能会有很多学生修,所以不可能course中设置stu_id,然后这个课程只能对应一个学生,因此需要设置score表,这个表中含有course_id以及stu_id,通过stu_id,就可以知道他修的课程了。
成绩查询
如果这一门课程的成绩不合格,我们需要设置表格背景颜色为red,合格的话,则设置为blue.
一开始我是这样写的:
<tbody th:each="score:${scores}">
<tr th:if="${score.get('goal') < 60}" style="background-color: red">
<td th:text="${score.get('course_id')}"></td>
<td th:text="${score.get('course_name')}"></td>
<td th:text="${score.get('type') == 1 ? '必修' : '选修'}"></td>
<td th:text="${score.get('credit')}"></td>
<td th:text="${score.get('goal')}"></td>
</tr>
<tr th:if="${score.get('goal') >= 60}" style="background-color: lightblue">
<td th:text="${score.get('course_id')}"></td>
<td th:text="${score.get('course_name')}"></td>
<td th:text="${score.get('type') == 1 ? '必修' : '选修'}"></td>
<td th:text="${score.get('credit')}"></td>
<td th:text="${score.get('goal')}"></td>
</tr>
</tbody>
尽管也能够实现,如果th:if中的值是true,那么这一行是存在的,否则不会存在这一行,但是显然这样会有代码的冗余,那么我们需要怎样,才能够避免这种情况,后来才发现通过th:bgcolor来实现,
在tr中设计th:bgcolor="${score.get('goal') < 60 ? 'red' : 'lightblue'}"
,这样我们只要写一个<tr></tr>
就可以实现我们的目的了,所以修改后的代码为:
<tr th:bgcolor="${score.get('goal') < 60 ? 'red' : 'lightblue'}">
<td th:text="${score.get('course_id')}"></td>
<td th:text="${score.get('course_name')}"></td>
<td th:text="${score.get('type') == 1 ? '必修' : '选修'}"></td>
<td th:text="${score.get('credit')}"></td>
<td th:text="${score.get('goal')}"></td>
</tr>
源码地址:https://gitee.com/MyGit_Test/simple_teacing_system
项目有些简陋,而且也存在一些问题:
- 例如教师端希望录入成绩的时候,如何实现表格编辑,尽管我是用vue中的v-model进行了绑定,但是修改一行的时候,就会其他行的这一列。
- 管理员端修改学生的学院的时候,专业的下拉框并没有发生改变,我希望的是专业能够随着学院的改变而改变的,但是不知道怎样来实现这个目的。
- 课表中并没有实现我们日常中的表格形式,并不直观。
如果有大佬的话,请指教哈!!!