简易社团管理系统(jsp+servlet+三件套+未完成)_jsp社团管理系统-程序员宅基地

技术标签: css  java  Powered by 金山文档  servlet  html  javascript  

今天来复盘一下快过去两个月的课程设计,主要要求是设计并创建不少于20个jsp页面,并实现数据库交互与用户交互功能,由于社团管理系统涉及“学生”“老师”“系统管理员”三类型用户,所以需要实现的功能范围还蛮大的,较为完善的只有管理员模块

基于此,本文适合那些还在学习并使用jsp技术并要求学生进行本地web端开发的学校的学生学习,主要目的是作者(大二学生)对自己的技术复盘与开发分享。(都2022年了真的还有人在用jsp作web开发吗...)

  1. 项目概况

1.1 整体结构

先介绍一下整个项目用到的IDE与结构

  • 项目的编译环境是MySQL5.0,可视化工具使用的是SQLyog,使用IDEA编译器,这几个软件网上都能搜到

  • 服务器使用apache-tomcat-8.5.83,jdk版本为1.8,网上都有资源,tomcat官方免费

  • 使用了jstl和standard两个jar包,主要用于date类型值显示问题,后面会提到

  • 后端数据库交互集成进了mybatis-3.4.6和mysql-connnector-java-8.0.25两个jar包

  • servlet技术实现使用了servlet-api一个jar包

以上的几个jar包都可以在搜索引擎上搜到下载资源,如果搜不到私信我

1.2 页面组成

所有页面结构由jap和html混合组成,几乎90%以上的样式表存放在css用link导入,,95%以上的js存放在js文件夹中(放在哪里无所谓,与jsp放在同级主要是路径写着不那么麻烦)

解释一下文件夹的命名规则:用单词缩写进行命名,有些是驼峰命名,有写首字母也大写了,是为了与其他同名或几乎同名的文件作以区分

缩写含义

  • BM:Back-office management--后台管理

  • Com:complaint--投诉

  • del:deal--处理

  • Tea:teacher--教师

  • Stu:student--学生

  • infor:information--信息

  • Act:activity--活动

  • Soc:Societies--社团

  • Pre:President--社长

1.3 集成声明

登录页为html+css实现,前端页面属于网络上开源资源集成过来的,原文地址:

前端酷炫效果之那些漂亮的登录界面

学生个人管理页为html+css+js实现,前端页面属网络上开源资源集成,原文地址:

Web大学生网页作业成品 基于HTML+CSS+JavaScript个人简历介绍 学生个人网站作业设计代做 学生个人网页设计作品

后台管理员页面和注册页均为html+css实现的侧边栏分页,前端页面属网络上开源资源集成,原文地址暂时找不到了,后期找到了注明...

其他页面均为个人原创,包括后端逻辑实现,源码搬运请告知

2. 功能实现

2.1 index主页(静态)

主页没什么好说的,直接贴图吧

唯一需要提一下的是导航栏,是仿原神官网导航栏的样式,利用css清除无序列表的基本样式后float得到的结果,左半边放置学校、项目logo和游客功能btn,右半边放置教师、管理员登录以及学生注册的btn(这块的逻辑有问题,高校社团管理系统应当是只给本校学生开放,不应该允许陌生用户自行注册)

此外,按钮用css实现了一个动态下压效果,给按钮绑定活动状态就行

页面结构源码:

<%--
  Created by IntelliJ IDEA.
  User: 谢xx
  Date: 2022/12/30
  Time: 16:51
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>    //jsp预定义
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>欢迎使用高校社团管理系统</title>
  <link rel="stylesheet" href="./css/index.css" type="text/css">
  <link rel="icon" href="./img/avatar.jpg" sizes="32x32"/>
</head>
<body>
<div class="header">
  <ul class="tabbar">
    <image src="./img/index1.png" alt="西安建筑科技大学" style="width: 30px;height: 30px; float: left;padding-left: 20px;padding-top:11px;padding-right: 10px;"/>
    <image src="./img/LOGO.PNG" alt="Societies Center" style="width: 30px;height: 30px; float: left;padding-left: 20px;padding-top:11px;padding-right: 20px;"/>
    <li><a href="#">社团展示</a></li>
    <li><a href="rule.jsp">规章制度</a></li>
    <li><a href="#">学管风采</a></li>
    <li><a href="Complaint.jsp">投诉社团</a></li>
    <li><a href="Forus.jsp">联系开发者</a></li>
    <li style="float: right;"><a href="enroll.jsp">学生注册</a></li>
    <li style="float: right;"><a href="Log_Manage.jsp">管理员登录</a></li>
    <li style="float: right;"><a href="Log_Tea.jsp">教师登录</a></li>
  </ul>
</div>

<div class="body">
  <div class="title">Societies Center<br/>高校社团管理系统</div>

  <div class="goon">
    <a href="Log_Stu.jsp"><button class="goon_a">立即进入</button></a>
  </div>

  <div class="footer">
    <p style="text-align: center; font-size: 15px;">信管xxxx&nbsp;&nbsp;|&nbsp;&nbsp;谢xx&nbsp;&nbsp;|&nbsp;&nbsp;2022年web课程设计&nbsp;&nbsp;</p>    //作者信息
  </div>
</div>
</body>
</html>

样式表:

@charset "UTF-8";

/*初始化盒子边框*/
* {
    padding: 0px;
    margin: 0px;
}

.header{
    width: 100%;
    height: 50px;
    background-color:#556B2F;
    opacity: 0.5;
}

.header .tabbar li{
    padding: 10px 20px;
    padding-top: 15px;
    float: left;
    list-style: none;
    color: #fff;
}

.header .tabbar a{
    text-decoration: none; /* 去除默认的下划线 */
    outline: none;    /* 去除旧版浏览器的点击后的外虚线框 */
    color: #fff;
}

.header .tabbar li:hover {
    border-bottom:4px solid #fff;
}

.header .tabbar a:hover{
    color:gold;
    opacity: 0.5;
}

.body{
    width: 100%;
    height: 590px;
    background-image: url(../img/index2.png);
    background-repeat: no-repeat;
}

.body .footer{
    width: 100%;
    height: 25px;
    background-color: grey;
    opacity: 0.5;
    position:fixed;
    bottom:0;
}

.body .title{
    width: 500px;
    height: 50px;
    font-size: 50px;
    font-family: 华文中宋;
    font-weight: 700;
    padding-left: 33%;
    padding-top: 170px;
}

.body .goon{
    padding-left: 45%;
    padding-top: 120px;
}

.body .goon .goon_a{
    display: inline-block;
    padding: 15px 25px;
    font-size: 24px;
    cursor: pointer;
    text-align: center;   
    text-decoration: none;
    outline: none;
    color: #fff;
    background-color: #4CAF50;
    border: none;
    border-radius: 15px;
    box-shadow: 0 9px #999;
}

.body .goon .goon_a:hover{
    background-color: #3e8e41;
}

.body .goon .goon_a:active{
    background-color: #3e8e41;
    box-shadow: 0 5px #666;
    transform: translateY(4px);
}

2.2 登录功能模块

2.2.1 前端页面实现

前面提到页面是集成的,此处就不再赘述,直接上图

相比原文,此页做了一点小改变:

  1. 在左上角加了返回按钮,用于用户误触或其他情况发生时给用户提供返回index主页的通道

  1. 在密码下方加入span标签,用于在用户用户名或密码输入出问题的时候进行红色字体提醒

页面结构源码:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page language="java" pageEncoding="UTF-8"%>
<%request.setCharacterEncoding ("UTF-8");%>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>用户登录</title>
    <link href="./css/Log.css" rel="stylesheet" type="text/css"/>
    <link rel="icon" href="./img/avatar.jpg" sizes="32x32"/>
</head>
<body>
    <div class="container">
        <div style="float: left;">
            <a href="index.jsp">
                <img src="./img/Log1.png" style="float: left; width: 50px; height: 50px; padding-left: 50px; padding-top: 20px;">
            </a>
        </div>
        <div class="login-wrapper">
            <div class="header">登录</div>
            <form class="form-wrapper" action="stulogin" method="post" id="stuLoginForm">
                <input type="text" id="stuname" name="stuname" placeholder="用户名" class="input-item" value="${stuMassageMoudle.stuobject.stuName}">
                <input type="password" id="stupassword" name="stupassword" placeholder="密码" class="input-item"  value="${stuMassageMoudle.stuobject.stuPassword}">
                <span id="stumsg" style="font-size: 12px;color: red">${stuMassageMoudle.stumsg}</span> </br>    //此处的${}是从消息模型中获取数据实现数据回显
                <button class="btn" type="button" id="stuLoginBtn">登录</button>
            </form>
            <div class="msg">
                没有账户?
                <a href="enroll.jsp">注册</a>
            </div>
        </div>
    </div>
</body>

<script>
    /**
     * 学生登录前端验证
     */
    $("#stuLoginBtn").click(function (){
        //获取用户填入的用户名和密码的值
        let stuname = $("#stuname").val();
        let stupassword = $("#stupassword").val();

        //判断姓名是否为空
        if (isEmpty(stuname)){
            //如果姓名为空,则提醒用户(给span标签赋值),然后return
            $("#stumsg").html("用户名不可为空")
            return;
        }

        //判断密码是否为空
        if (isEmpty(stupassword)){
            //如果密码为空,则提醒用户
            $("#stumsg").html("密码不可为空")
            return;
        }

        //如果都不为空,则提交表单
        $("#stuLoginForm").submit();
    })

    /**
     * 判断字符串是否为空
     *      如果为空返回true,如果不为空返回false
     * @param str
     * @returns {boolean}
     */
    function isEmpty(str){
        if(str == null || str.trim() == ""){
            return true;
        }
        return false;
    }
</script>

</html>

样式表:

@charset "UTF-8";

/*初始化盒子边框*/
* {
    margin: 0;
    padding: 0;
}
html {
    height: 100%;
}
body {
    height: 100%;
}
.container {
    height: 100%;
    background-image: linear-gradient(to right, #fbc2eb, #a6c1ee);
}

.login-wrapper {
    background-color: #fff;
    width: 358px;
    height: 588px;
    border-radius: 15px;
    padding: 0 50px;
    position: relative;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
}
.header {
    font-size: 38px;
    font-weight: bold;
    text-align: center;
    line-height: 200px;
}
.input-item {
    display: block;
    width: 100%;
    margin-bottom: 20px;
    border: 0;
    padding: 10px;
    border-bottom: 1px solid rgb(128, 125, 125);
    font-size: 15px;
    outline: none;
}
.input-item:placeholder {
    text-transform: uppercase;
}
.btn {
    text-align: center;
    padding: 10px;
    width: 100%;
    margin-top: 40px;
    background-image: linear-gradient(to right, #a6c1ee, #fbc2eb);
    color: #fff;
}

//设置鼠标悬停时的按钮样式
.btn:hover{
    background-color: #3e8e41;
}

//设置按钮激活时的样式
.btn:active{
    background-color: #3e8e41;
    box-shadow: 0 5px #666;
    transform: translateY(4px);
}
.msg {
    text-align: center;
    line-height: 88px;
}
a {
    text-decoration-line: none;
    color: #abc1ee;
}

2.2.2 后端逻辑功能实现(以学生登录为例)

登录模块相较于其他模块不同的是登录功能使用servlet实现,其他数据的渲染都是jsp页内访问并操作数据库实现的,利用servlet的好处是教师登录与管理员登录界面可以完全复用(偷懒.jpg)。而使用servlet进行数据操作就要知道servlet到底是干嘛的(

这里就不过多赘述,有需要的可以看看下面两篇文章:

菜鸟教程——servlet简介

JavaWeb——Servlet(全网最详细教程包括Servlet源码分析)

本文的servlet相关文件架构为:

利用分层思想将整个servlet登录分为三大层:controller层、service层、mapper层

主要任务分别是:

controller:接受客户端请求、调用service层方法、将消息模型对象设置到request作用域中实现回显

service:非空判断、调用mapper通过用户名查询数据库中对应对象、判断是否存在该用户

mapper:定义接口、集成mybatis、操作数据库

其他文件夹及其主要任务:

entity实体类:存放需要使用的对象或JavaBean实体

test测试类:用于定义测试类或测试方法

util工具类:存放整个项目通用的方法或类

(1)controller层

先在全局范围内实例化service层方法:

private StuService studentService = new StuService();

然后开始写与客户端的交互响应:

  1. 在接收响应之前要用setCharacterEncoding()方法对接受到的参数重新设置编码(前端表单POST提交时默认以ISO编码方式提交,如果后端编码格式不是ISO格式的话此处要重新设置格式)

  1. 利用getParameter()方法将请求实例化

  1. 调用service层并返回消息模型对象(此处idea会报错,因为service层和entity实体类还没有写,可以先去service层中定义一个空函数、在去entity实体类文件中创建一个对象类)

  1. 判断消息模型的状态码,并对前端页面进行操作,如果状态码为成功则把用户信息存到session中,重定向到个人信息页面;如果失败,把用户信息定义到session中并跳转回登录页面,将用户刚刚输入的信息渲染到前端页面上实现回显

源码如下:

package com.xxxx.controller;

import com.xxxx.entity.vo.StuMassageMoudle;
import com.xxxx.service.StuService;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//idea会自动导入外部包,以上不需要自行操作

@WebServlet("/stulogin")    //此处括号中的内容一定要哏前端表单提交的目标地址一致
public class StuServlet extends HttpServlet {

    //实例化StudentService对象
    private StuService studentService = new StuService();

    /**
     * 学生登录功能
     */
    @Override
    protected void service(HttpServletRequest request , HttpServletResponse response) throws ServletException , IOException{

        //设置接收的请求编码格式
        request.setCharacterEncoding("Utf-8");

        //接收客户端的请求(接收参数,学生用户名和学生密码)
        String stuname = request.getParameter("stuname");
        String stupassword = request.getParameter("stupassword");

        //调用service层对象,返回消息模型对象
        StuMassageMoudle stuMassageMoudle = studentService.stuLogin(stuname,stupassword);

        //判断消息模型的状态码
        if (stuMassageMoudle.getStucode() == 1){    //成功
            //将用户信息存到session中,重定向到学生个人信息管理页
            request.getSession().setAttribute("student",stuMassageMoudle.getStuobject());
            response.sendRedirect("stuManage.jsp");
        }else {     //失败
            //将消息模型设置到session中,跳转回Log_Stu.jsp登录页
            request.setAttribute("stuMassageMoudle",stuMassageMoudle);
            request.getRequestDispatcher("Log_Stu.jsp").forward(request,response);
        }
    }
}
(2)entity实体类

entity实体类主要用于存放JavaBean对象的信息,并提供方法供后端进行获取或修改数据,由于学生注册时需要多种信息,从数据库中获取的数据也是这些,所以此处也对应存放这些信息(但由于本项目中仅有登录模块用到servlet,所以对象中有东西有好多几乎是浪费的)

学生类源码如下:

package com.xxxx.entity;

import java.util.Date;

/**
 * Student实体类
 */
public class Student {
    private Integer stuId;      //学生帐号
    private Integer stuNumber;  //学生学号
    private String stuName;     //学生姓名
    private String stuPassword; //学生密码
    private String stuEmail;    //学生邮箱
    private Integer stuPhone;   //学生电话号码
    private Date stuBirthDay;   //学生生日

    //以下是一些set和get方法,idea中有快捷键,是啥我忘了...有需要的可以上网查查,但也可以自己敲
    public Integer getStuId() {
        return stuId;
    }

    public void setStuId(Integer stuId) {
        this.stuId = stuId;
    }

    public Integer getStuNumber() {
        return stuNumber;
    }

    public void setStuNumber(Integer stuNumber) {
        this.stuNumber = stuNumber;
    }

    public String getStuName() {
        return stuName;
    }

    public void setStuName(String stuName) {
        this.stuName = stuName;
    }

    public String getStuPassword() {
        return stuPassword;
    }

    public void setStuPassword(String stuPassword) {
        this.stuPassword = stuPassword;
    }

    public String getStuEmail() {
        return stuEmail;
    }

    public void setStuEmail(String stuEmail) {
        this.stuEmail = stuEmail;
    }

    public Integer getStuPhone() {
        return stuPhone;
    }

    public void setStuPhone(Integer stuPhone) {
        this.stuPhone = stuPhone;
    }

    public Date getStuBirthDay() {
        return stuBirthDay;
    }

    public void setStuBirthDay(Date stuBirthDay) {
        this.stuBirthDay = stuBirthDay;
    }
}

将消息模型单独存放在vo文件夹中,主要需要状态码以判断登录是否成功、提示信息以告知用户登录失败原因、回显对象以存放用户名密码三个变量,源码如下:

package com.xxxx.entity.vo;

/**
 * 消息模型对象(用来做数据响应)
 *      状态码
 *          1=成功;0=失败
 *      提示信息
 *          字符串
 *      回显数据
 *          object对象
 */
public class MassageMoudle {

    private Integer code = 1;   //状态码
    private String msg = "成功!";     //提示信息
    private Object object;  //回显对象

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getObject() {
        return object;
    }

    public void setObject(Object object) {
        this.object = object;
    }
}
(3)service层

由于service层是一些逻辑的实现,比较难懂的话可以试着debug以下,跟着数据一步一步走一遍

  1. 实例化消息模型

  1. 先将前端接收到的用户名和密码放到student消息模型对象中

  1. 在后端进行提交参数的非空判断,如果为空就设置状态码和提示信息,并return消息模型对象(这么做主要是为了培养后端进行非空判断的习惯,做后端的时候永远不要相信前端的非空判断,万一没做呢...)

  1. 调用mapper层的非空判断,在数据库中根据用户名查询学生对象,并将数据库中拿过来的信息存放在学生类中

  1. 判断是否从数据库拿到信息了,如果没拿到证明数据库中没有这个用户名对应的对象,也就是没注册(也有可能是因为数据库连接的问题没拿到,所以在mapper层连接数据库的时候就要用一个测试类去测试连接情况),设置状态码和提示信息,并且将用户输入的用户名回显到前端

  1. 如果从数据库拿到信息了,就把从前端传过来的密码与从数据库拿到的密码作比较,如果不一致还是退回到登录页,如果一致再允许登录并跳转到个人信息管理页

源码如下:

package com.xxxx.service;

import com.xxxx.entity.Student;
import com.xxxx.entity.vo.StuMassageMoudle;
import com.xxxx.mapper.StudentMapper;
import com.xxxx.util.GetSqlSession;
import com.xxxx.util.StringUtil;
import org.apache.ibatis.session.SqlSession;

public class StuService {

    /**
     * 学生登录功能
     * @param stuname
     * @param stupassword
     * @return
     */

    public StuMassageMoudle stuLogin(String stuname , String stupassword) {

        StuMassageMoudle stuMassageMoudle = new StuMassageMoudle();

        //回显数据
        Student stu = new Student();
        stu.setStuName(stuname);
        stu.setStuPassword(stupassword);
        stuMassageMoudle.setStuobject(stu);

        //参数的非空判断
        if (StringUtil.isEmpty(stuname) || StringUtil.isEmpty(stupassword)){    //调用工具类,判断字符串是否为空
            //将状态码、提示信息、回显数据设置到学生消息模型对象中
            stuMassageMoudle.setStucode(0);
            stuMassageMoudle.setStumsg("用户姓名和密码不能为空!");
            return stuMassageMoudle;
        }

        //调用mapper层的非空判断,通过学生用户名查询学生对象
        SqlSession stusession = GetSqlSession.createSqlSession();    //调用工具类,创建数据库会话
        StudentMapper studentMapper = stusession.getMapper(StudentMapper.class);
        Student student = studentMapper.queryStuByName(stuname);    //调用mapper层id为queryStuByName的操作

        //判断用户对象是否为空
        if (student == null){
            //将状态码、提示信息、回显数据设置到学生消息模型对象中
            stuMassageMoudle.setStucode(0);
            stuMassageMoudle.setStumsg("用户不存在!");
            return stuMassageMoudle;
        }

        //将数据库中的数据与从前端拿到的密码作比较
        if (!stupassword.equals(student.getStuPassword())){
            //如果不相等,将状态码、提示信息、回显数据设置到学生消息模型对象中
            stuMassageMoudle.setStucode(0);
            stuMassageMoudle.setStumsg("用户密码不正确!");
            return stuMassageMoudle;
        }

        //登录成功,将用户信息设置到学生消息模型中
        stuMassageMoudle.setStuobject(student);

        return stuMassageMoudle;
    }
}

这里没有用else,代码是顺序执行的,满足if的条件就执行,如果所有if都不满足就执行最后一个return,但这样写一定要看好,所有if一定要包含所有可能的登录失败的情况,如果遗漏一个就会造成登录模块的重大bug

(4)mapper层

mapper层主要分为两个部分,一个是xml文件配置数据库操作,一个是创建接口类供service层调用

StudentMapper.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">
<!-- 首先来解析 namespace; 命名空间,此属性通常用来映射Dao(Mapper)层接口,-->
<mapper namespace="com.xxxx.mapper.StudentMapper">
    <!-- id:对应Dao(Mapper)层接口方法名 parameterType: 指定输入参数类型 -->
    <!-- useGeneratedKeys="true”把新增加的主键赋值到自己定义的keyProperty (id)中 -->
    <select id="queryStuByName" parameterType="String" resultType="com.xxxx.entity.Student">
        select * from tb_stu where stuName = #{stuName}
    </select>
</mapper>

StudentMapper接口类文件源码:

package com.xxxx.mapper;

import com.xxxx.entity.Student;

/**
 * Student接口类
 */
public interface StudentMapper {
    public Student queryStuByName(String stuName);
}

mapper层相当于是逻辑层与数据库的中间件,数据库的配置要在全局完成,不同的servlet功能模块要用不同的接口层方法进行操作,全局的DB配置后面会说

(5)用test类测试能否从数据库拿到数据

原理:在test类内部创建数据库会话,并调用对应的mapper层方法,自己写一个用户名字符串拿去数据库检验(这个用户名对应的对象一定要是提前在数据库中创建好的,否则怎么可能拿得到数据),如果成功,把这个对象输出到控制台

源码

package com.xxxx.test;

import com.xxxx.entity.Student;
import com.xxxx.entity.Teacher;
import com.xxxx.entity.User;
import com.xxxx.mapper.StudentMapper;
import com.xxxx.mapper.TeacherMapper;
import com.xxxx.mapper.UserMapper;
import com.xxxx.util.GetSqlSession;
import org.apache.ibatis.session.SqlSession;

/**
 * 测试能否从数据库拿到数据
 */
public class Test {
    public static void main(String[] args) {
        //获取sqlSession对象
        SqlSession session = GetSqlSession.createSqlSession();    //调用GetSqlSession工具类
        //得到对应的mapper
        TeacherMapper teacherMapper = session.getMapper(TeacherMapper.class);    //要测试哪个mapper层就写哪个mapper层的名字
        //调用方法,返回用户对象
        Teacher teacher = teacherMapper.queryTeaByName("qjj");    //此处一定要写数据库中有的
        System.out.println(teacher);
    }
}
(6)util工具类

大家也可以发现,在test类中使用到了GetSqlSession、在service层中使用到了GetSqlSession和isEmpty这两个类方法,是因为我们在开发过程中发现这两个方法可以复用,于是直接在until工具类中写了这两个方法的实现逻辑,其他层直接调用就好,大大提高了开发效率

GetSqlSession工具类源码:

package com.xxxx.util;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

public class GetSqlSession {
    /**
     * 获取SqlSession对象
     * @return
     */
    public static SqlSession createSqlSession() {

        SqlSessionFactory sqlSessionFactory = null;
        InputStream input = null;
        SqlSession session = null;

        try {
            // 获得mybatis的环境配置文件
            String resource = "mybatis-config.xml";
            // 以流的方式获取recource(mybatis的环境配置文件)
            input = Resources.getResourceAsStream(resource);
            // 创建会话工厂
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(input);
            // 通过工厂得到SqlSession
            session = sqlSessionFactory.openSession();
            return session;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 测试能否创建数据库会话
     * @param args
     */
    public static void main(String[] args) {
        System.out.println(createSqlSession());
    }
}

创建数据库会话的代码是固定的,可以直接复制,最下面是检查会话是否创建成功的方法, 在idea中可以单独run这个方法

StringUtil工具类源码:

package com.xxxx.util;

/**
 * 字符串工具类
 */
public class StringUtil {

    /**
     * 判断字符串是否为空
     *      如果为空返回true,如果不为空返回false
     * @param str
     * @return
     */
    public static boolean isEmpty(String str){
        if(str == null || "".equals(str.trim())){
            return  true;
        }
        return false;
    }
}
(7)全局配置

mybatis配置源码:(文件名mybatis-config.xml)

<?xml version="1.0" encoding="UTF-8"?>    //该xml文件的版本与编码格式
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <properties resource="mysql.properties"/>

    <environments default="development">
        <environment id="development">
            <!--
            transactionManager用来配置事务管理
            type中使用JDBC代表mybatis进行事务管理
            type中使用Manager代表mybatis不进行事务管理
            如果与spring进行整合的情况下,type中可以使用Manager选项
            让spring来参与事务管理
            -->
            <transactionManager type="JDBC" />
            <!--
                dataSource用来配置数据库连接
                UNPOOLED代表底层不使用连接池,每次都需要创建一个新的连接
                用完后再释放该连接;会有一些基础属性设置:
                driver url username password
                defaultTransactionIsolationLevel(默认连接事务隔离级别)
                defaultNetworkTimeout(连接超时时间)
                POOLED代表使用连接池,每次从连接池中获取连接
                当资源关闭时将连接返回连接池;
                在正式项目中仍然会切换成第三方的连接池,例如C3p0;
            -->
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
        <!--        根据需要的生产或测试环境配置不同的数据库进行数据切换-->
        <!--        <environment id="produce">-->
        <!--            <transactionManager type=""></transactionManager>-->
        <!--            <dataSource type=""></dataSource>-->
        <!--        </environment>-->
    </environments>

    <!--    mapper映射器-->
    <mappers>
        <!--        <mapper resource="com/bestapply/dao/ProductMapper.xml"/>-->
        <!--        如果使用package需要注意一定要使用接口-->
        <!--        且接口的命名一定要和对应mapper的命名一致-->
        <package name="com.xxxx.mapper"/>
    </mappers>

</configuration>

mysql配置源码:(文件名mysql.properties)

driver=com.mysql.cj.jdbc.Driver    //你的数据库驱动
url=jdbc:mysql://localhost:3306/web_keshe?serverTimezone=UTC&useSSL=false&useUnicode=true/useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=true
username=root    //你的数据库用户名
password=        //你的数据库密码

2.3 注册模块

注意:从注册模块开始,后续其他功能的实现都是利用jsp页内调用数据库实现的,如果需要提交数据实现功能的会提交给一个处理jsp页,该jsp页只进行数据操作,不渲染页面,jsp页面操作数据完毕后转回一级页面进行数据渲染。本项目最多使用了两级jsp处理页。

2.3.1 前端展示

直接上图:

此页主要涉及到insert数据和跳转两个功能,跳转没什么好说的,insert数据马上说。

昵称框内提示说(暂仅支持英文)是因为在首次做这个功能时insert到数据库中的数据成了乱码,登陆时数据回显和个人信息管理页的用户名渲染都是乱码,只有当用户名是英文的时候才是正常的。后来这个问题在项目中被解决了,主要原因时表单提交数据时默认ISO编码格式,而jsp在接收数据时又忘了重设编码格式,就导致了到处都是乱码,现在这个项目的代码是支持中文用户名的。

页面架构源码:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page language="java" pageEncoding="UTF-8"%>
<%request.setCharacterEncoding ("UTF-8");%>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>学生注册</title>
    <link href="./css/enroll.css" rel="stylesheet" type="text/css"/>
    <link rel="icon" href="./img/avatar.jpg" sizes="32x32"/>
</head>

<body>
    <div class="rg_layout">
        <div class="rg_left">
            <p>新用户注册</p>
            <p>USER REGISTER</p>
        </div>
        <div class="rg_center">
            <div class="rg_form">
                <form action="enrollDo.jsp" method="post">
                    <table>
                        <tr>
                            <td class="td_title" colspan="2">欢迎使用高校社团管理系统</td>
                        </tr>
                        <tr class="td_null">
                        </tr>
                        <tr>
                            <td class="td_left"><label for="stunumber">学号</label></td>
                            <td class="td_right"><input type="text" name="stunumber" id="stunumber" placeholder="请输入学号">
                            </td>
                        </tr>
                        <tr>
                            <td class="td_left"><label for="stupassword">密码</label></td>
                            <td class="td_right"><input type="stupassword" name="stupassword" id="stupassword"
                                    placeholder="请输入密码"></td>
                        </tr>
                        <tr>
                            <td class="td_left"><label for="stuemail">Email</label></td>
                            <td class="td_right"><input type="email" name="stuemail" id="stuemail" placeholder="请输入邮箱"></td>
                        </tr>
                        <tr>
                            <td class="td_left"><label for="stuname">设置昵称</label></td>
                            <td class="td_right"><input type="text" name="stuname" id="stuname" placeholder="请输入昵称(暂仅支持英文)"></td>
                        </tr>
                        <tr>
                            <td class="td_left"><label for="stuphone">手机号</label></td>
                            <td class="td_right"><input type="text" name="stuphone" id="stuphone" placeholder="请输入手机号"></td>
                        </tr>
                        <tr>
                            <td class="td_left"><label>性别</label></td>
                            <td class="td_right"><input type="radio" name="gender" value="male">男
                                <input type="radio" name="gender" value="female">女
                            </td>
                        </tr>
                        <tr>
                            <td class="td_left"><label for="stubirthday">出生日期</label></td>
                            <td class="td_right"><input type="date" name="stubirthday" id="stubirthday" value="2001-01-01"></td>
                        </tr>
                        <tr class="td_null">
                        </tr>
                        <tr>
                            <td colspan="2" align="center"><input type="submit" id="btn_sub" value="注册"></td>
                        </tr>
                    </table>
                </form>
            </div>
        </div>
        <div class="rg_right">
            <p>已有账号?<a href="Log_Stu.jsp">立即登录</a></p>
        </div>
    </div>
</body>

</html>

样式表:

@charset "UTF-8";

*{
    margin: 0px;
    padding: 0px;
    box-sizing: border-box;
}
body{
    background: url("../img/enroll1.jpg") no-repeat;
    background-size: 100%;
}
.rg_layout{
    width: 900px;
    height: 500px;
    border: 5px solid #EEEEEE;
    background-color: white;
    /*让div水平居中*/
    margin: auto;
    margin-top: 15px;
    opacity: 0.8;
}
.rg_left{
    float: left;
    margin: 15px;
    width: 20%;
}
.rg_left > p:first-child{
    color: #FFD026;
    font-size: 20px;
}
.rg_left > p:last-child{
    color: #A6A6A6;
}
.rg_center{
    /*border: 1px solid red;*/
    float: left;
    width: 450px;
    /*margin: 15px;*/
}
.rg_right{
    float: right;
    margin: 15px;
}
.rg_right > p:first-child{
    font-size: 15px;
}
.rg_right p a {
    color: pink;
}
.td_title{
    width: 100px;
    text-align: center;
    height: 45px;
    font-size: 30px;
}
.td_null{
    width: 100px;
    text-align: center;
    height: 20px;
}
.td_left{
    width: 100px;
    text-align: right;
    height: 45px;
}
.td_right{
    padding-left: 50px;
}
#stunumber,#stuname,#stupassword,#stuemail,#stuname,#stuphone,#checkcode,#stubirthday{
    width: 251px;
    height: 32px;
    border: 1px solid #A6A6A6;
    /*设置边框圆角*/
    border-radius: 5px;
    padding-left: 10px ;
}
#checkcode{
    width: 110px;
}
#img_check{
    height: 32px;
    /*设置垂直居中*/
    vertical-align: middle;
}
#btn_sub{
    width: 150px;
    height: 40px;
    background-color: #FFD026;
    border: 1px solid #FFD026;
}

2.3.2 数据功能实现

由于本项目注册模块未进行前端验证,所以如果有需要用这个项目代码的朋友注意一下将前端验证一下用户名和密码为非空,否则会出现问题(一般用户正常使用的情况下不会出现这种极端情况)

  1. 设置接受的数据的编码格式

  1. 接收前端传过来的数据

  1. 与数据库建立连接,创建状态,并执行SQL语句

  1. 进行用户名重复验证

  1. 创建结果集对象(select因为不用向前端渲染数据,所以用不上result对象,其他操作会用到)

  1. while输出结果集对象(如果没有创建的话就不存在这一步)

  1. 关闭状态、关闭数据库连接、关闭结果集对象

  1. 提示用户注册成功

jsp处理页面源码:

<%--
  Created by IntelliJ IDEA.
  User: 谢XX
  Date: 2023/1/2
  Time: 13:17
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" import="java.sql.*" %>
<%@ page language="java" pageEncoding="UTF-8"%>
<%request.setCharacterEncoding ("UTF-8");%>
<html>
<head>
    <link rel="icon" href="./img/avatar.jpg" sizes="32x32"/>
    <title>提示</title>
</head>
<body>

<%
    String stunumber = request.getParameter("stunumber");   //学生学号
    String stupassword = request.getParameter("stupassword");   //学生密码
    String stuemail = request.getParameter("stuemail");   //学生邮箱
    String stuname = request.getParameter("stuname");   //学生姓名
    String stuphone = request.getParameter("stuphone");   //学生联系电话
    String stubirthday = request.getParameter("stubirthday");   //学生生日
    String stumsg1 = "未知错误,请联系管理员!";
%>

<%
    // JDBC driver name and database URL
    final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver";
    final String DB_URL = "jdbc:mysql://localhost:3306/web_keshe?serverTimezone=UTC&useSSL=false&useUnicode=true/useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=true";

    //  Database credentials
    final String USER = "root";
    final String PASS = "";
%>

<%
    Connection conn = null;
    Statement stmt = null;
    PreparedStatement pst = null;
    ResultSet rs = null;
    try{
        //STEP 2: Register JDBC driver
        Class.forName(JDBC_DRIVER);

        //STEP 3: Open a connection
        System.out.println("Connecting to database...");
        conn = DriverManager.getConnection(DB_URL,USER,PASS);

        //STEP 4: Execute a query
        System.out.println("Creating statement...");
        stmt = conn.createStatement();
        String sql , sql1 = null;
        sql1 = "SELECT stuId FROM tb_stu WHERE stuName = \""+stuname+"\";";
        pst = conn.prepareStatement(sql1);
        rs = pst.executeQuery();
        String rs_stuID = null;
        while(rs.next()){      //这里必须循环遍历
            rs_stuID = rs.getString("stuId");//返回一条记录
            System.out.println(rs_stuID );
        }
        if ( rs_stuID == null){     //判断用户名是否重复
            sql = "INSERT INTO tb_stu (stuNumber, stuName, stuPassword ,stuEmail ,stuPhone ,stuBirthDay)VALUES ('"+stunumber+"', '"+stuname+"', '"+stupassword+"', '"+stuemail+"' ,'"+stuphone+"' ,'"+stubirthday+"');";
            stmt.execute(sql);
            stumsg1 = "注册成功!请返回登录";
        }else {
            stumsg1 = "注册失败!用户名已存在,请更换用户名后重试";
        }

        //STEP 6: Clean-up environment
        stmt.close();
        conn.close();
%>
<script>
    alert("<%=stumsg1%>")
    window.location.href="Log_Stu.jsp"
</script>
<%
    }catch(SQLException se){
        //Handle errors for JDBC
        se.printStackTrace();
    }catch(Exception e){
        //Handle errors for Class.forName
        e.printStackTrace();
    }finally{
        //finally block used to close resources
        try{
            if(stmt!=null)
                stmt.close();
        }catch(SQLException se2){
        }// nothing we can do
        try{
            if(conn!=null)
                conn.close();
        }catch(SQLException se){
            se.printStackTrace();
        }//end finally try
    }//end try
    System.out.println("Goodbye!");
%>
</body>

</html>

2.4 投诉社团模块

先说一下投诉社团的逻辑:游客或学生或教师都可以投诉,且是匿名投诉,利用表单存储到数据库中,管理员后台可以看见每一个投诉的投诉信息,根据投诉信息找到对应社团负责人,处理好投诉中描述的问题后点击“已解决”将该问题从所有投诉列表中移除。

2.4.1 前端展示

所以前端仅需要一个表单传递数据,后端仅需要一个jsp页面select数据,再加上一个删除实例的按钮就能完成。

前端页面展示:

社团名称下拉框按逻辑应该是有多少社团就下拉展示多少社团,但是因为技术问题没做出来,最后改成了填写框。

前端结构源代码:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>投诉社团</title>
    <link href="./css/Complaint.css" rel="stylesheet" type="text/css"/>
    <link rel="icon" href="./img/avatar.jpg" sizes="32x32"/>
</head>

<body>
    <!-- 返回主页图标 -->
    <div style="float: left;padding-top: -5px;padding-left: 60px;">
        <a href="index.jsp">
            <img src="./img/Complaint.png" style="float: left; width: 50px; height: 50px;">
        </a>
    </div>

    <!-- 投诉表单主体 -->
    <div class="Content-Main">
        <div class="Content-Main1">
            <h1>投诉社团</h1>
        </div>
        <form action="ComplaintDo.jsp" method="post" class="form-report">
            <label>
                <span>社团名称:</span>
                <textarea style="height: 23px;" id="societies_name" name="societies_name" placeholder="请填写社团名称"></textarea>
            </label>

            <label>
                <span>投诉原因:</span>
                <select name="select2" class="select2" id="select2">
                    <option value="涉及诈骗">涉及诈骗</option>
                    <option value="加收社费">加收社费</option>
                    <option value="违规举办活动">违规举办活动</option>
                    <option value="泄露社员信息">泄露社员信息</option>
                    <option value="其他违规行为">其他违规行为</option>
                </select>
            </label>

            <label>
                <span>问题描述:</span>
                <textarea id="describe" name="describe" placeholder="详细填写举报理由,有利于审核,不得少于8个字"></textarea>
            </label>

            <label>
                <span>投诉作证:</span>
                <textarea id="url" name="url" placeholder="请上传作证至百度网盘,将文件共享链接填在此处"></textarea>
            </label>
            
            <label>
                <span>您的联系方式:</span>
                <textarea id="email" name="email" placeholder="请务必填写正确的邮箱地址或联系电话"></textarea>
            </label>

            <label>
                <span>备注:</span>
                <input type="text" id="verifiation code">
            </label>
            <label>
                <input type="submit" class="button" value="确定">
            </label>
        </form>
    </div>
</body>

</html>

样式表源代码:

@charset "UTF-8";

.Content-Main {
    max-width: 500px;
    margin: auto;
    margin-top: 50px;
    padding: 20px 30px 20px 30px;
    font: 12px "Helvetica Neue", Helvetica, Arial, sans-serif;
    text-shadow: 1px 1px 1px #FFF;
    border: 1px solid #DDD;
    border-radius: 5px;
    color: #888;
    background: #FFF;
}

.Content-Main h1 {
    display: block;
    padding: 0px 0px 10px 40px;
    margin: -10px -30px 30px -30px;
    font: 25px "Helvetica Neue", Helvetica, Arial, sans-serif;
    border-bottom: 1px solid #DADADA;
    color: #888;
}

.Content-Main h1>span {
    display: block;
    font-size: 11px;
}

.Content-Main label {
    display: block;
    margin: 0px 0px 5px;
}

.Content-Main label>span {
    float: left;
    width: 20%;
    padding-right: 10px;
    margin-top: 10px;
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-weight: bold;
    text-align: right;
    color: #333;
}

.Content-Main input[type="text"],
.Content-Main textarea {
    width: 70%;
    height: 20px;
    padding: 5px 0px 5px 5px;
    margin-bottom: 16px;
    margin-right: 6px;
    margin-top: 0px;
    line-height: 15px;
    border-radius: 4px;
    border: 1px solid #CCC;
    color: #888;
    -webkit-border-radius: 4px;
    -moz-border-radius: 4px;
    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
    -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
    resize: none;
}

.select1 {
    width: 71%;
    height: 35px;
    margin-bottom: 16px;
    margin-right: 6px;
    margin-top: 0px;
    line-height: 15px;
    padding: 5px 0px 5px 5px;
    border-radius: 4px;
    border: 1px solid #CCC;
    color: #888;
    -webkit-border-radius: 4px;
    -moz-border-radius: 4px;
    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
    -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}

.select2 {
    width: 25%;
    height: auto;
    padding-top: 0px;
    padding-bottom: 3px;
    padding-left: 1px;
    margin-top: 0px;
    margin-bottom: 10px;
    border-radius: 4px;
    border: 1px solid #CCC;
    color: #888;
    -webkit-border-radius: 4px;
    -moz-border-radius: 4px;
    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
    -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}

.Content-Main textarea {
    width: 70%;
    height: 100px;
    padding: 5px 0px 0px 5px;
}

#societies_name{
    width: 150px;
    height: 20px;
}

#url {
    width: 70%;
    height: auto;
    padding: 5px 0px 25px 5px;
}

#describe {
    width: 70%;
    height: auto;
    padding: 5px 0px 80px 5px;
}

#email {
    width: 70%;
    height: auto;
    padding: 5px 0px 5px 5px;
}

#verifiation code {
    width: 20px;
    height: auto;
}

.button {
    padding: 10px 25px 10px 25px;
    margin-left: 111px;
    border-radius: 4px;
    border: 1px solid #CCC;
    background: #FFF;
    color: #333;
}

.button:hover {
    color: #333;
    background-color: #EBEBEB;
    border-color: #ADADAD;
}

2.4.2 数据功能实现

由于此页面是表单收集用户填入的收据,所以要增加一个处理页与数据库作数据交互(insert数据)

处理页源代码:

<%--
  Created by IntelliJ IDEA.
  User: 谢XX
  Date: 2023/1/3
  Time: 16:16
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" import="java.sql.*"%>
<%@ page language="java" pageEncoding="UTF-8"%>
<%request.setCharacterEncoding ("UTF-8");%>
<html>
<head>
    <title>提示</title>
</head>
<body>

<%
    String comSocName = request.getParameter("societies_name");
    String comCause = request.getParameter("select2");
    String comIssue = request.getParameter("describe");
    String comProof = request.getParameter("url");
    String comPerson = request.getParameter("email");
    String comRemark = request.getParameter("verifiation code");
%>

<%
    // JDBC driver name and database URL
    final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver";
    final String DB_URL = "jdbc:mysql://localhost:3306/web_keshe?serverTimezone=UTC&useSSL=false&useUnicode=true/useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=true";

    //  Database credentials
    final String USER = "root";
    final String PASS = "";
%>
<div>投诉失败,请返回刷新页面后重新输入</div>
<a href="Complaint.jsp"><button>确定</button></a>
<%
    Connection conn = null;
    Statement stmt = null;
    try{
        //STEP 2: Register JDBC driver
        Class.forName(JDBC_DRIVER);

        //STEP 3: Open a connection
        System.out.println("Connecting to database...");
        conn = DriverManager.getConnection(DB_URL,USER,PASS);

        //STEP 4: Execute a query
        System.out.println("Creating statement...");
        stmt = conn.createStatement();
        String sql;
        sql = "INSERT INTO tb_soc_com (comSocName, comCause, comIssue ,comProof ,comPerson ,comRemark)VALUES ('"+comSocName+"', '"+comCause+"', '"+comIssue+"', '"+comProof+"' ,'"+comPerson+"' ,'"+comRemark+"');";
        stmt.execute(sql);

        //STEP 6: Clean-up environment
        stmt.close();
        conn.close();
%>
<script>
    alert("投诉成功,感谢您对西建大学生活动的监督!")
    window.location.href="index.jsp"
</script>
<%
    }catch(SQLException se){
        //Handle errors for JDBC
        se.printStackTrace();
    }catch(Exception e){
        //Handle errors for Class.forName
        e.printStackTrace();
    }finally{
        //finally block used to close resources
        try{
            if(stmt!=null)
                stmt.close();
        }catch(SQLException se2){
        }// nothing we can do
        try{
            if(conn!=null)
                conn.close();
        }catch(SQLException se){
            se.printStackTrace();
        }//end finally try
    }//end try
    System.out.println("Goodbye!");
%>
</body>
</html>

2.5 管理员

管理员是三种用户类型中权限最高的用户,可以对社团信息进行增删改查,管理社长数据、教师数据、社团学生信息数据,进行活动审批(未做),处理社团投诉等等功能。

后台的界面涉及可以简易一点,管理员需要有自己的个人信息修改功能与后台退出功能,后台退出用js实现,逻辑功能处理页与上述jsp页面组成相同,此处只展示前端页面结构、修改社团信息与删除社团操作。

2.5.1 前端展示

管理员刚登陆需要有欢迎页面

具体的数据操作页面(以社团信息管理界面为例):

修改信息界面(以修改社团信息为例):

管理员前端页面结构源码:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>社团管理系统管理员后台</title>
    <link href="./css/BM_first.css" rel="stylesheet" type="text/css" />
    <link rel="icon" href="./img/avatar.jpg" sizes="32x32"/>
</head>

<body>
<!--顶部信息区-->
<header role="header">
    <div>
        <h1>高校社团后台管理系统</h1>
        <nav role="user">
            <ul>
                <li>欢迎管理员:<strong>${user.userName}</strong></li>
                <li><a href="Password_change.jsp?userName=${user.userName}" target="main">修改信息</a></li>
                <li><a href="javascript:void(0);" onclick="logout()">退出登录</a></li>
            </ul>
        </nav>
    </div>
</header>
<!--圣杯二列布局-->
<main role="main">
    <!--主体内联框架区-->
    <article role="content">
        <iframe src="BM_welcome.jsp" name="main"></iframe>
        <footer role="copyright">
            <p><a href="#">信管2002 谢林希</a> 版权所有</p>
        </footer>
    </article>
    <!--左侧导航区-->
    <aside>
        <nav role="option">
            <ul>
                <li><h3>·&nbsp;导航列表</h3></li>
                <li><a href="Soc_infor_manage.jsp" target="main" class="active">社团信息管理</a></li>
                <li><a href="Act_apply.jsp" target="main">活动审批</a></li>
                <li><a href="Teacher_manage.jsp" target="main">指导教师管理</a></li>
                <li><a href="Pre_infor_manage.jsp" target="main">社长管理</a></li>
                <li><a href="Com_del.jsp" target="main">社团投诉管理</a></li>
                <li><a href="SocStu_infor_manage.jsp" target="main">社团学生管理</a></li>
            </ul>
        </nav>
    </aside>
</main>

<script>
    function logout() {
        if (window.confirm('是否退出?')) {
            window.location.href = 'index.jsp';
        } else {
            return false;
        }
    }
</script>
</body>

</html>

子页面结构源码(以社团信息展示页为例)

<%@ page contentType="text/html;charset=UTF-8" language="java" import="java.sql.*" %>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>社团信息管理</title>
    <link rel="stylesheet" href="./css/tb_show.css" type="text/css">
</head>
<body>
<%!
    public static final String DBDRIVER = "com.mysql.cj.jdbc.Driver";
    //    驱动路径
    public static final String DBURL = "jdbc:mysql://localhost:3306/web_keshe?serverTimezone=UTC&useSSL=false&useUnicode=true/useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=true";
    //    web_keshe数据库名
    public static final String DBUSER = "root";
    //    数据库用户名
    public static final String DBPASS = "";
    //    数据库密码
%>

<%
    /*这里的一下参数也可以去下面定义*/
    Connection conn = null;
    /*定义一个创建连接的变量,初始值设为空,当需要连接时,通过
    Connection conn=DriverManager.getConnection(URL,Username,Password);
    去创建连接, 方便后面关闭操作*/
    PreparedStatement pst = null;
    /*Statement和PreparedStatament的区别
    Statement执行查询调用方法executeQuery(sql)
    执行更删改调用方法executeUpdate(sql)
    PreparedStatement执行查询调用方法executeQuery()
    执行更删改调动方法executeUpdate()*/
    ResultSet rs = null;
%>
<%
    try {
        Class.forName(DBDRIVER);
        //注册驱动
        conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS);
        //获取链接
        request.setCharacterEncoding("utf-8");
        String sql_select = "select * from tb_soc";
        //获取操作数据库中的表对象
        pst = conn.prepareStatement(sql_select);
        rs = pst.executeQuery();
        //执行sql_select,获取结果集
%>
<table border="1" align="center">
    <tr>
        <td>社团编号</td>
        <td>社团名称</td>
        <td>社长学号</td>
        <td style="width: 120px">指导教师工号</td>
        <td>社团人数</td>
        <td>创立日期</td>
        <td style="width: 80px">星级</td>
        <td colspan="2" align="center">数据操作</td>
    </tr>
        <%
        while (rs.next()) {
            //处理结果
    %>
    <tr>
        <td><%= rs.getString("socNumber") %>
        </td>
        <td><%= rs.getString("socName")%>
        </td>
        <td><%= rs.getString("soc_PreNumber")%>
        </td>
        <td><%= rs.getString("soc_TeaNumber")%>
        </td>
        <td><%= rs.getString("socMemberNumber")%>
        </td>
        <td><%= rs.getString("socMadeDate")%>
        </td>
        <td><%= rs.getString("socStar")%>
        </td>
        <td>
            &nbsp;<button><a href="Soc_infor_manage_delete.jsp?socNumber=<%=rs.getString("socNumber")%>">注销社团</a></button>
        </td>
        <td>
            <button><a href="Soc_infor_manage_update.jsp?socNumber=<%=rs.getString("socNumber")%>">修改信息</a></button>
        </td>
    </tr>
        <%
            }
        } catch (Exception e) {
            System.out.println(e);
        }
    %>

    <tr style="margin-top: 20px;float: right">
        <td>
            <button><a href="Soc_infor_manage_new.jsp">新建社团</a></button>
        </td>
    </tr>

</body>
</html>

管理员页面样式表源码:

@charset "UTF-8";

/*********** 声明公共元素样式 ***********/
* {
    margin: 0;
    padding: 0;
}

body {
    background-color: #efefef;
}

li {
    list-style-type: none;
}

a {
    color: #000;
    text-decoration-line: none;
}

a:hover {
    color: brown;
    text-decoration-line: underline;
}

/*********** 声明顶部样式 ***********/
header {
    background: linear-gradient(to top, lightgrey, #efefef);
    margin: 10px 20px;
    overflow: hidden;
    height: 60px;
    border-bottom-left-radius: 20px;
    border-bottom-right-radius: 6px;
}

header div {
    width: 100%;
    margin: auto;
}

header h1 {
    float: left;
    margin-left: 20px;
    font-weight: normal;
    line-height: 60px;
}

header nav {
    float: right;
    margin-right: 20px;
}

header nav ul li {
    float: left;
    padding-left: 30px;
    line-height: 80px;
}

/*********** 声明主体区样式 ***********/
/*侧边导航栏*/
main {
    width: 80%;
    /*内容区宽度*/
    height: 800px;
    margin: 30px auto 0;
    padding-left: 200px;
    overflow: hidden;
    /*布局参考线*/
    /*border: 1px solid red;*/
}

main article {
    float: left;
    /*布局参考色块*/
    /*background-color: #FD6FCF;*/
    width: 100%;
    min-height: 100%;
    background: linear-gradient(to bottom, lightgrey, #ededed);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);
    border-radius: 6px;
}

main aside {
    float: left;
    border-radius: 6px;
    background: linear-gradient(to left, lightgrey, #ededed);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);
    padding-bottom: 20px;
    width: 175px;
    margin-left: -100%;
    position: relative;
    left: -197px;
}

main aside nav li {
    line-height: 2rem;
}

main aside nav li:first-child,
main aside nav li a {
    padding: 10px 15px;
    display: block;
}

/*main aside nav li a.active{*/
/*    border-left: 3px solid brown !important;*/
/*    background: #efefef;*/
/*    padding-left: 15px;*/
/*    margin-left: -3px;*/
/*}*/
main aside nav li a:hover {
    border-left: 3px solid brown !important;
    background: #efefef;
    padding-left: 15px;
    margin-left: -3px;
}

main article iframe {
    min-width: 100%;
    min-height: 700px;
    margin: auto;
    border: none;
}

main article footer p {
    text-align: center;
}

子页面样式表源码(所有信息展示子页面复用):

@charset "UTF-8";

td{
    text-align: center;
}

a{
    text-decoration:none;
    color:#696969;
}

a:hover{
    color:#F4A460;
}

input[type="submit"]{
    color:#696969;
}

input[type="submit"]:hover{
    color:#F4A460;
}

input[type="button"]{
    color:#696969;
}

input[type="button"]:hover{
    color:#F4A460;
}

2.5.2 数据功能实现

(1)删除功能

删除功能基本集成在一个按钮中,在按下按钮时获取该按钮对应的实例的UID,并将该UID传递到数据处理页,数据处理页以该UID为例在数据库中删除数据。而且一般来说,在删除信息后要让用户看到信息总量的变化,也就是删除数据库信息之后要将剩余数据重新渲染到页面上,所以在jsp处理页以后要跳转到原来的jsp页面上,由于处理页不向用户展示,所以在删除以后用户能观察到删除的那条数据没了。

删除功能源码:

<%--
  Created by IntelliJ IDEA.
  User: 谢XX
  Date: 2023/1/4
  Time: 16:12
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" import="java.sql.*" %>
<html>
<head>
    <title>注销社团</title>
</head>
<body>
<%!
    public static final String DBDRIVER="com.mysql.cj.jdbc.Driver";
    public static final String DBURL="jdbc:mysql://localhost:3306/web_keshe?serverTimezone=UTC&useSSL=false&useUnicode=true/useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=true";
    public static final String DBUSER="root";
    public static final String DBPASS="";
%>
<%
    Connection conn=null;
    PreparedStatement pst=null;
    int rs=0;
    String socNumber=request.getParameter("socNumber");
%>

<%
    try{
        Class.forName(DBDRIVER);
        conn=DriverManager.getConnection(DBURL,DBUSER,DBPASS);
        String sql_delete="delete from tb_soc where socNumber="+socNumber+"";
        //获取要删除的此id的数据库信息
        pst=conn.prepareStatement(sql_delete);
        rs=pst.executeUpdate();
        if(rs!=0){
            System.out.println("删除成功");
%>
<jsp:forward page="Soc_infor_manage.jsp">
    <jsp:param name="socNumber" value="socNumber"/>
</jsp:forward>
<%
        }
    }
    catch(Exception e){
        System.out.println(e);
    }

%>
</body>
</html>
(2)修改社团信息

与删除功能相同,update操作也是整合在一个按钮中,但是不同的是点击数据更新操作按钮后,页面要跳转到另外一个页面,向用户展示修改前的各个信息,并将新信息写入数据库。

所以这就涉及到展示页和新数据处理页两个页面,这也就是刚才所提到的两级jsp处理页的情况。

更新展示页源码:

<%--
  Created by IntelliJ IDEA.
  User: 谢XX
  Date: 2023/1/4
  Time: 16:24
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" import="java.sql.*" %>
<html>
<head>
    <title>更新社团信息</title>
    <link rel="stylesheet" href="./css/tb_show.css" type="text/css">
    <link rel="stylesheet" href="./css/tb_show.css" type="text/css">
    <style>
        input{
            margin-bottom: 12px;
            margin-left: 12px;
        }
    </style>
</head>
<body>
<%!
    public static final String DBDRIVER = "com.mysql.cj.jdbc.Driver";
    public static final String DBURL = "jdbc:mysql://localhost:3306/web_keshe?serverTimezone=UTC&useSSL=false&useUnicode=true/useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=true";
    public static final String DBUSER = "root";
    public static final String DBPASS = "";
%>
<%
    Connection conn = null;
    PreparedStatement pst = null;
    ResultSet rs = null;
    String socNumber = null;
%>
<%
    try {
        Class.forName(DBDRIVER);
        conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS);
        request.setCharacterEncoding("utf-8");
        socNumber = request.getParameter("socNumber");
        String sql_update = "select * from tb_soc where socNumber='" +socNumber+ "'";
        //获取你要更新数据的id的数据库信息
        pst = conn.prepareStatement(sql_update);
        rs = pst.executeQuery();
        if (rs.next()) {
%>
<form action="Soc_infor_manage_updateDo.jsp?socNumber=<%=rs.getString("socNumber")%>" method="post">
    <%--切换到Teacher_Manage_updataDo.jsp,显示要更新的数据信息--%>
    &nbsp;社团编号:<br/><input type="text" value="<%=rs.getString("socNumber")%>" name="socNumber"><br/>
    &nbsp;社团名称: <br/><input type="text" value="<%=rs.getString("socName") %>" name="socName"><br/>
    &nbsp;社长学号: <br/><input type="text" value="<%=rs.getString("soc_PreNumber") %>" name="soc_PreNumber"><br/>
    &nbsp;指导教师工号: <br/><input type="text" value="<%=rs.getString("soc_TeaNumber") %>" name="soc_TeaNumber"><br/>
    &nbsp;社团人数: <br/><input type="text" value="<%=rs.getString("socMemberNumber") %>" name="socMemberNumber"><br/>
<%--    &nbsp;创立日期: <br/><input type="text" value="<%=rs.getString("socMadeDate") %>" name="socMadeDate"><br/>--%>
    &nbsp;星级: <br/><input type="text" value="<%=rs.getString("socStar") %>" name="socStar"><br/>
    <input type="submit" value="修改">&nbsp;&nbsp;&nbsp;&nbsp;
        <button><a href="Soc_infor_manage.jsp">取消</a></button>
    <br/>
    <br/>
    <div style="font-size: 10px;color: red">注:暂不支持修改社团创立日期</div>
</form>
<%
        }
    } catch (Exception e) {
        System.out.println(e);
    }
%>
</body>
</html>

更新处理页源码:

<%--
  Created by IntelliJ IDEA.
  User: 谢XX
  Date: 2023/1/4
  Time: 16:31
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" import="java.sql.*" %>
<html>
<head>
    <title>更新社团信息(执行)</title>
</head>
<body>
<%!
    public static final String DBDRIVER="com.mysql.cj.jdbc.Driver";
    public static final String DBURL="jdbc:mysql://localhost:3306/web_keshe?serverTimezone=UTC&useSSL=false&useUnicode=true/useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=true";
    public static final String DBUSER="root";
    public static final String DBPASS="";
%>
<%
    Connection conn=null;
    PreparedStatement pst=null;
    int rs=0;
    String socNumber=null;
    String socName=null;
    String soc_PreNumber=null;
    String soc_TeaNumber=null;
    String socMemberNumber=null;
    String socStar=null;
//    Date socMadeDate=null;
%>
<%
    try{

        Class.forName(DBDRIVER);
        conn=DriverManager.getConnection(DBURL,DBUSER,DBPASS);
        request.setCharacterEncoding("utf-8");
        socNumber=request.getParameter("socNumber");
        socName=request.getParameter("socName");
        soc_PreNumber=request.getParameter("soc_PreNumber");
        soc_TeaNumber=request.getParameter("soc_TeaNumber");
        socMemberNumber=request.getParameter("socMemberNumber");
        socStar=request.getParameter("socStar");
//        socMadeDate=request.getParameter("socMadeDate");

//        //string转Date
//        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//        Date socMadeDate1 = null;
//        try {
//            socMadeDate1 = (Date) sdf1.parse(socMadeDate);
//        }catch (Exception e){
//            e.printStackTrace();
//        }

        String sql_update="update tb_soc set socNumber='"+socNumber+"',socName='"+socName+"' ,soc_PreNumber='"+soc_PreNumber+"',soc_TeaNumber='"+soc_TeaNumber+"' ,socMemberNumber='"+socMemberNumber+"' ,socStar='"+socStar+"'where socNumber='"+socNumber+"'";
        pst=conn.prepareStatement(sql_update);
        rs=pst.executeUpdate();
        if(rs!=0){
            System.out.println("更新成功");
%>
<jsp:forward page="Soc_infor_manage.jsp"></jsp:forward>
<%--修改之后转到展示页面--%>
<%
        }
    }
    catch(Exception e){
        System.out.println(e);
    }

%>
</body>
</html>

3. 写在最后

(还有一个联系开发者没有提到,其中有一个省市县三级联动的下拉框,这个不难,只需要一个js文件就行,在项目文件里有)

写代码真的是一件枯燥又有趣的事情,这两个词语看起来很矛盾,但是又不矛盾。

枯燥是它时不时会蹦出来让自己好几个小时甚至好几天都无法让项目推进一丁点的无奈

有趣是真的做出来东西的时候那种激动和兴奋,即便做出来的东西不如trash

还是多敲代码吧,如果以后想找一份技术岗的工作,代码是实打实的hard ability

曾经听到的一句话:

现在敲的每一行代码,都是以后涨薪的基石

你我共勉!


项目及其源码已上传至GitHub个人仓库,有需要的uu自行获取哈(获取完整项目源码的话记得star一下)~

https://github.com/xielinxi123/Personal-warehouse.git

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/xlxnb666/article/details/129170857

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法