飞道的博客

实用!JavaWeb学生选课信息管理系统(数据报表、打印、批量删除等)!

437人阅读  评论(0)

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">
            &nbsp;&nbsp;&nbsp;&nbsp;<img src="static/picture/home.png">&nbsp;&nbsp;>&nbsp;&nbsp;信息查询&nbsp;&nbsp;>&nbsp;&nbsp;个人信息
        </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}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</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
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场