1、效果图
2、项目阐述
该项目是模拟学生选课信息的管理系统,用户类型有三种,分别是管理员、教师、学生。学生入校注册后需统一记录学生个人基本信息,对于面向学生开设的相关课程需要记录每门课程的基本信息,每个任课教师规定其可主讲三门课程,学生选课时系统将相应的选课信息记录入库,考试结束后教师需在相应的选课记录中补上考试成绩,管理员可查看所有用户信息,同时查看一系列的数据报表。
- 由于代码量较多,就不放上完整代码啦,若有需要可评论交流联系或者私信博主哦O(∩_∩)O
- 该项目的所有页面样式,布局等均由博主自主编写
- 本文不涉及前端页面编写知识
3、开发环境
- 编译软件:IntelliJ IDEA 2019
- 页面设计软件:Adobe Dreamweaver CC 2019
- 数据库:MySQL 8.0
- 数据库操作工具:Navicat Premium 12
- 服务器:Tomcat 9.0.37
- 环境:jdk1.8
4、功能开发
4.1、登录
- 用户类型选择
- 登录
由于项目分为三个类型的用户,即管理员、教师、学生,因此在进入系统前须先选择相应的用户类型。
- 如何区分用户类型?
答:当用户选择完类型后,将对应的value值设置为session域对象值,session域可简单理解为只要浏览器未关闭,session域对象就会一直存在。但是在Tomcat中,域对象的生命周期默认为30分钟,即若30分钟内客户端没有再发送请求,则会超时从而自动销毁session域中相应的对象。
/**
* 登录
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
String type = userService.queryTypeByUsername(username);
String typeChoose = String.valueOf(req.getSession().getAttribute("UserType"));
User user = userService.login(new User(username, password, null, type));
//判断用户类型及账号密码是否成功匹配
if (type.equalsIgnoreCase(typeChoose) == false){
System.out.println("登录失败");
req.setAttribute("username",username);
req.setAttribute("tip","不存在此"+typeChoose+"用户");
req.getRequestDispatcher("/page/user/login.jsp").forward(req,resp);
}else if (user==null){
System.out.println("登录失败");
req.setAttribute("username",username);
req.setAttribute("tip","用户名或密码错误");
req.getRequestDispatcher("/page/user/login.jsp").forward(req,resp);
}
else {
System.out.println("登录成功");
req.setAttribute("username",username);
if (typeChoose.equalsIgnoreCase("student")){
req.getSession().setAttribute("stuNum",username);
req.getRequestDispatcher("/page/student/index.jsp").forward(req,resp);
}else if (typeChoose.equalsIgnoreCase("system")){
req.getSession().setAttribute("systemNum",username);
req.getRequestDispatcher("/page/system/index.jsp").forward(req,resp);
}else if (typeChoose.equalsIgnoreCase("teacher")){
req.getSession().setAttribute("teacherNum",username);
req.getRequestDispatcher("/page/teacher/index.jsp").forward(req,resp);
}
}
}
4.2、学生模块
4.2.1、个人信息查询
个人信息查询功能的实现,只需将数据库中对应的信息读取即可。通过Servlet调用Service层,Service层再去调用DAO层,DAO层与数据库交互获取该用户信息,并逐层返回,最后由Servlet发送数据并跳转到相应的Jsp页面。
- 由于功能逻辑不复杂,此处就贴jsp页面的代码啦
- 涉及知识点:JSTL(JSP标准标签库)
<%--
自我介绍
--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!doctype html>
<html>
<head>
<%@include file="/common/head.jsp" %>
<title>index</title>
<link rel="stylesheet" type="text/css" href="css/common.css">
<link rel="stylesheet" type="text/css" href="css/introduction.css">
</head>
<body>
<%@include file="/common/header_student.jsp" %>
<section>
<%@include file="/common/menu_student.jsp" %>
<div class="info">
<div class="address">
<img src="static/picture/home.png"> > 信息查询 > 个人信息
</div>
<div class="introduction">
<%-- 头像--%>
<div class="intr-first">
<div class="head-image">
<img class="face_image" src="static/picture/6.jpg">
</div>
</div>
<%-- 学生信息遍历--%>
<div class="intr-second">
<c:forEach var="info" items="${requestScope.info}">
<div class="subassemble">
<label class="sub-1">${info.key} </label>
<label class="sub-2">${info.value}</label>
</div>
</c:forEach>
</div>
</div>
</div>
</section>
</body>
</html>
4.2.2、 选课
学生选课会有两种情况,一是处于选课时间,二是未在选课时间段。并且此处的限制是只选择一门课,不可多选。
- 如何确定是否为选课时间?
答:选课开启是由管理员开启的,即可以设置一个servletContext域对象,当管理员开启选课时,则该域对象的值为true,若关闭则为false。当学生点击选课时,对应的Servlet先获取servletContext域对象并进行判断,若为true,则代表处在选课时间段,反之。
/**
* 设置是否是选课时间
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void isChooseTime(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String isChecked = req.getParameter("isChecked");
if (isChecked!=null && isChecked.equals("true")){
req.getServletContext().setAttribute("isTime",isChecked);
}
req.getRequestDispatcher("/page/system/systemSetting.jsp").forward(req,resp);
}
- 如何限定只选一门课?
答:使用JQuery为选课图标绑定一个点击事件,当点击选课时先获取已选列表的数据对象,若已存在对象,即不为null,则说明已选一门课,则alert()提示并返回false阻止点击事件。
<script type="text/javascript">
$(function () {
//选课
$(".choose").click(function () {
var b = ${
requestScope.isChoose.cno};
if (b != null) {
alert("已选一门功课!请先退选!");
return false;
}
});
//退课
$(".delete").click(function () {
return confirm("确定删除已选课程吗?");
})
})
</script>
4.3、教师模块
4.3.1、分数录入
- 教师只可录入其所教课程的成绩
- 录入方式,在这里我使用的是input组件,直接进行录入,录入后修改对应的数据库数据,并把input组件的默认值改成新的成绩
4.4、管理员模块
4.4.1 信息管理
管理员可以查看所有信息,同时对信息进行增删查改的操作
-
信息查询
-
添加信息
-
信息修改
-
添加信息的方式?
答:在项目中,通过css编写“添加信息”组件,实现下拉动画效果,当点击添加信息时,会在当前页面下方弹出一个添加框,填入一系列信息并点击确定,将信息更新到数据库中,并再由Servlet跳转回当前信息查询页面。
4.4.2、数据报表
项目中的数据报表使用Echarts图表,关于Echarts图表的使用方式在博主首页噢!先给大家看看效果o( ̄▽ ̄)o
5、其他小技巧
5.1、实现打印功能
打印功能可以使用第三方插件,或者直接调用window.print()方法打印,window.print()的好处是使用方便,只需要直接调用即可,但缺点是直接调用的话不能打印像Echarts的图表,还有一些css样式也需要重新设置。总结下来,若只是为了简单的打印网页,没有其他样式要求,则可直接使用window.print(),若对打印样式有需求,则需使用第三方插件。
- 利用 window.print() 打印指定部分的内容
在要打印的内容前面一行加上“< !–startprint-- >”,最后一行后面加上“< !–endprint-- >”,再给一个如button组件绑定下方的doPrint()事件即可。
function doPrint() {
bdhtml=window.document.body.innerHTML;
sprnstr="<!--startprint-->"; //开始打印标识字符串有17个字符
eprnstr="<!--endprint-->"; //结束打印标识字符串
prnhtml=bdhtml.substr(bdhtml.indexOf(sprnstr)+17); //从开始打印标识之后的内容
prnhtml=prnhtml.substring(0,prnhtml.indexOf(eprnstr)); //截取开始标识和结束标识之间的内容
window.document.body.innerHTML=prnhtml; //把需要打印的指定内容赋给body.innerHTML
window.print(); //调用浏览器的打印功能打印指定区域
window.document.body.innerHTML=bdhtml;//重新给页面内容赋值
return false;
}
5.2、数据输入约束性
- 尽可能地使用下拉列表组件(select-option),避免了手动输入数据时数据不合法。
- 使用JS正则表达式辅助判断数据的合法
function check() {
var options=$("#searchType option:selected").val();
var val = $("#searchInfo").val();
var number = /^\+?[1-9][0-9]*$/;//数字
if (options == "cno" || options == "priorId" || options == "credit"){
if (number.test(val))//判断输入的是否为数字
return true;
else{
alert("内容输入错误!")
return false;
}
}
return true;
}
5.3、全选\全不选
- 在Jsp上使用type为checkbox的input组件,再给其添加绑定事件(如下)
//全选/全不选
$("#checkAll").click(function () {
let checked = document.getElementById("checkAll").checked;
if (checked==true){
<c:forEach items="${requestScope.CourseMap}" var="entry">
document.getElementById("${entry.value.id}").checked=true;
</c:forEach>
}else if (checked==false){
<c:forEach items="${requestScope.CourseMap}" var="entry">
document.getElementById("${entry.value.id}").checked=false;
</c:forEach>
}
})
5.4、批量删除
- 获取当前Jsp中已选中的数据编号,并将所有编号以一个字符(如s)作为连接,将其连接成一段字符串,再把该字符串传送到Servlet中,再在Service层对字符串以“s”作为分隔符,将字符串分割后再逐一对每一个数据进行操作。
//批量删除
$(".deleteAll").click(function () {
let array = new Array();
<c:forEach items="${requestScope.CourseMap}" var="entry">
if (document.getElementById("${entry.value.id}").checked==true){
array.push("${entry.value.id}");
}
</c:forEach>
let allcno=array[0];
for (let i = 1; i < array.length; i++) {
allcno += "s"+array[i];
}
if (array[0]!=null){
let b = confirm("确定删除课程号"+allcno+"吗?");
if (b==true){
location.href="http://localhost:8080/StudentsInfoSystem/systemCourseServlet?action=deleteMoreCourse&allcno="+allcno;
}
}
})
5.5、模糊查询
- 模糊查询这里以MySQL为例,主要使用“LIKE”关键词,如要查询学号中带有10的学生,只需要输入“10”即可,具体DAO层语句如下:
/**
* 通过学号查询所有学生信息
* @return
*/
public List<Student> queryAllBySno(String sno){
String sql="select * from student where sno like ?";
return queryForList(Student.class,sql,sno);
}
6、总结
- 项目开发使用了三层架构,即“Web视图层-Service业务层-Dao持久层”,分层的目的是为了解耦,即降低代码耦合度,便于后期的维护。
- 建议多使用工厂模式创建实例化对象,这样便于当底层数据库有所变动时,只需DAO层变动,无需每一个页面都进行修改,大大降低了工作量。
- 要有封装的思想,把重复的,常用的语句进行封装,再调用,这样代码看起来更加清楚整洁,而且修改方便。
谢谢看完的你!有帮助记得点个赞噢!有问题可随时评论或者私信博主交流!!o( ̄▽ ̄)o
转载:https://blog.csdn.net/ttbro/article/details/112510668