Brief Introduction
这个项目是一个大学生信息管理系统,提供用户级别的登录注册资料管理,信息查询,信息修改(管理员权利),简单的数据可视化分析等功能,也有基本的安全性保障
代码已经上传github
https://github.com/21503882/studentinfossh
Release Notes
v1.0.0 - 2019.5.19
StuInfoAdmin-v1.0.0 的一切准备工作似乎都已到位。发布之弦,一触即发。 不枉近百个日日夜夜与之为伴。因小而大,因弱而强。
无论它能走多远,抑或如何支撑?至少我曾倾注全心,无怨无悔
v1.1.0 - 2019.7.27
版本1.1.0,更新如下内容 :
优化数据表结构,对原有的表的部分字段进行了修改,并增加了title和grade两个表
优化sql语句效率
优化前端查询界面及查询方式,使其更加全面,对用户友好
更新登录界面记住密码的cookie设置
更新邮箱验证码服务,增加了验证码有效时间
优化源代码结构,增强了规范性和可拓展性
v1.2.0 - 2019.9.12 (Current Version)
目前版本为v1.2.0,更新如下内容 :
修复了前端编辑添加弹窗在不同分辨率客户机上的显示大小问题
新增Redis技术,用以缓存用户名密码,用户错误登录次数限制,邮箱验证码等等
新增连续输错用户名密码超过一定次数后的限制时间
更改了邮箱验证码有效时间的实现方式,由服务端java实现改为redis过期时间实现
提升了服务端的安全性和新增异常处理机制,用aop实现入参的校验,对不合法的请求及其参数值用日志记录,并抛出异常
优化了util包等源代码的结构,增强了可拓展性
对Redis和SpringAOP不太熟的同学,下载v1.1.0版本足够学习或完成课设了~
v2.0.0 (//TODO)
使用SpringBoot重构SSM,Thymeleaf重构JSP,提高项目的实用性及扩展性,尽情期待哟~
Technologies Used
前端
前端框架 : layui
数据可视化框架 : echarts
后端
IOC容器 : Spring
MVC框架 : SpringMVC
ORM框架 : Mybatis
缓存技术:Redis
数据库:Mysql
日志框架 : Log4j
安全框架 : Shiro
Project Structure
├─database // 数据库相关文件
│ ├─design // 数据库设计
│ │ └─1
│ └─sql // 数据库初始化脚本文件
├─git_screenshot // 存放README.md 中的图片
├─src // 项目源代码目录
│ ├─main //源代码目录
│ │ ├─java
│ │ │ └─com
│ │ │ └─jzy // java代码目录
│ │ │ ├─controller // 控制层
│ │ │ ├─dao // 持久层
│ │ │ ├─dto // 传输对象
│ │ │ ├─entity // 实体类
│ │ │ ├─interceptor // 拦截器
│ │ │ ├─log // 日志管理
│ │ │ ├─service // 服务层
│ │ │ │ └─impl // 服务层接口实现
│ │ │ └─util // 工具方法
│ │ ├─resources // 资源文件目录
│ │ │ └─com
│ │ │ └─jzy
│ │ │ └─mapper // mybatis对dao接口的xml实现
│ │ └─webapp // tomcat前端文件目录
│ │ ├─static // 静态资源
│ │ │ ├─custom // 自定义静态资源
│ │ │ └─plugins // 插件类静态资源
│ │ └─WEB-INF
│ │ └─page // jsp页面目录
│ └─test // 测试代码目录
├─README.md // help
└─pom.xml // maven依赖
Quick Start
1 : 项目开发环境
IDE : IntelliJ IDEA 2018.1.7
项目构建工具 : Maven 3.x
数据库 : Mysql 8.0.13
Redis:Redis server 3.2.100
JDK版本 : jdk 1.8
Tomcat版本 : Tomcat 8.x
2 : 项目的初始构建
在你的Mysql中,运行我提供的database/sql/init.sql 文件(注意mysql版本与sql脚本中部分代码的兼容性), 成功会创建名为mydatabase2的数据库,以及user、student、teacher、class、major、college、title、grade八个表
数据库物理模型如下 :
Snipaste_2019-07-17_09-48-36
进入src/main/resources修改dbconfig.properties配置文件,把数据库主机、端口、用户名和密码,改为你本地的
进入src/main/resources修改redis.properties配置文件,把数据库主机、端口、用户名和密码,改为你本地的
进入src/main/resources查看log4j.properties,如果有必要可以修改日志输出路径,目前在D盘下,你可选择不修改跳过此步
使用 IntelliJ IDEA 导入项目,选择Maven项目选项,一路点击next,即可将项目所需依赖导入。若有无法引入的依赖,可能是因为maven版本不同或是该依赖已过时不存在于现有maven仓库中,请前往maven官网映入最新的该类型依赖
Snipaste_2019-07-17_08-47-37
Snipaste_2019-07-17_08-49-48
在 IntelliJ IDEA 中,配置我们的 Tomcat, 然后把使用Maven构建好的项目添加到Tomcat中,操作比较简单,相关方法可以参考百度
运行项目,进入用户登录页面
Snipaste_2019-05-04_08-02-50
登录账户/密码(你也可以自行注册一个账户登录哟)
管理员账户:000000000000/admin1
学生账户:516030910429/123456
教师账户:1000000001/123456
Detailed Functions
用户服务
登录:如上文图所示
注册
Snipaste_2019-05-04_08-11-21
忘记密码后的重置密码(含发送邮箱验证码)
Snipaste_2019-05-04_08-12-27
登录进入主页
Snipaste_2019-09-12_10-35-03
修改基本资料
Snipaste_2019-07-04_08-19-12
修改密码
Snipaste_2019-07-17_09-23-03
修改绑定邮箱
Snipaste_2019-07-17_09-30-38
信息查询
学生信息查询
查询所有信息
Snipaste_2019-07-17_09-31-05
根据登录用户的用户名(应以学号注册)查询当前个人的学籍信息,若注册时未以真实学号注册,则无法查询到。
Snipaste_2019-07-17_09-32-12
模糊查询搜索
Snipaste_2019-07-17_09-32-47
教师信息查询:类似学生信息查询,图略
班级信息查询:类似学生信息查询,图略
专业&学院信息查询:类似学生信息查询,图略
信息修改
学生信息修改
此功能必须以管理员用户身份登录,否则会跳转至异常页面
Snipaste_2019-05-04_08-32-13
编辑信息
Snipaste_2019-07-17_09-33-51
添加
Snipaste_2019-07-17_09-34-24
单条、多条删除
Snipaste_2019-07-17_09-34-56
教师信息修改:类似学生信息修改,图略
班级信息修改:类似学生信息修改,图略
专业&学院信息修改:类似学生信息修改,图略
拓展功能
学生男女比可视化
Snipaste_2019-07-17_09-36-37
学生人数比可视化
Snipaste_2019-07-17_09-37-17
Snipaste_2019-07-26_17-10-43
师资力量可视化
package com.springmvc.controller;
import com.springmvc.dto.other.EmailVerifyCode;
import com.springmvc.dto.other.senior.StudentPercentBySex;
import com.springmvc.entity.College;
import com.springmvc.entity.User;
import com.springmvc.interceptor.Token;
import com.springmvc.util.Constants;
import com.springmvc.util.SetCookie;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author JinZhiyun
* @ClassName OtherController
* @Description 其他一些请求的控制类
* @Date 2019/6/6 13:09
* @Version 1.0
**/
@Controller
public class OtherController extends BaseController {
/**
* @author JinZhiyun
* @Description 定向到主页index.jsp,并返回用户model
* @Date 16:48 2019/7/25
* @Param []
* @return org.springframework.web.servlet.ModelAndView
**/
@RequestMapping("/index")
public ModelAndView index() {
User user = userService.updateUserSession(session);
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject(Constants.USER_MODEL, user);
modelAndView.setViewName("index");
return modelAndView;
}
/**
* @return java.lang.String
* @Author JinZhiyun
* @Description 定向到登录页面login.jsp
* @Date 9:25 2019/4/19
* @Param []
**/
@RequestMapping("/login")
public String login() {
return "user/login";
}
/**
* @return java.lang.String
* @Author JinZhiyun
* @Description 注销并定向到登录页面login.jsp
* @Date 9:36 2019/4/19
* @Param []
**/
@RequestMapping("/logout")
public String logout() {
userService.deleteUserSession(session);
return "user/login";
}
/**
* @author JinZhiyun
* @Description 测试登录成功与否的ajax交互
* @Date 16:49 2019/7/25
* @Param [user, remember]
* @return java.util.Map
**/
@RequestMapping("/loginTest")
@ResponseBody //直接返回 json 数据
public Map
Map
User userSessionInfo = userService.selectUserByNameAndPassword(user.getUserName(), user.getUserPassword());
if (userSessionInfo == null) {
map.put("data", "resultFail");
} else {
map.put("data", "resultSuccess");
//登录成功设置session
session.setAttribute(Constants.USERINFO_SESSION, userSessionInfo);
//记住密码存cookie
SetCookie.setUserLoginCookie(user.getUserName(), user.getUserPassword(), remember, request, response);
}
return map;
}
/**
* @return java.lang.String
* @Author JinZhiyun
* @Description 定向到注册页面reg.jsp
* @Date 9:37 2019/4/19
* @Param []
**/
@RequestMapping("/reg")
public String reg() {
return "user/reg";
}
/**
* @return java.util.Map
* @Author JinZhiyun
* @Description 判断注册成功与否的ajax交互
* @Date 9:39 2019/4/19
* @Param [user]
**/
@RequestMapping("/regTest")
@ResponseBody
public Map
Map
map.put("data", userService.insertUserRegInfo(user));
return map;
}
/**
* @return java.lang.String
* @Author JinZhiyun
* @Description 定向到忘记密码页面forget.jsp
* @Date 9:37 2019/4/19
* @Param []
**/
@RequestMapping("/forget")
@Token(save = true)
public String forget() {
return "user/forget";
}
/**
* @return java.util.Map
* @author JinZhiyun
* @Description 发送验证码的ajax交互
* @Date 8:46 2019/6/6
* @Param [user]
**/
@RequestMapping("/sendVerifyCodeToEmail")
@ResponseBody
public Map
Map
EmailVerifyCode emailVerifyCode = otherService.sendVerifyCodeToEmail(user.getUserEmail());
session.setAttribute(Constants.EMAILVERIFYCODE_SESSION, emailVerifyCode);
map.put("msg", "sendSuccess");
return map;
}
/**
* @return java.util.Map
* @author JinZhiyun
* @Description 检测验证码是否正确的ajax交互
* @Date 8:58 2019/6/6
* @Param [emailVerifyCode, user]
**/
@RequestMapping("/emailVerifyCodeTest")
@ResponseBody
public Map
Map
if (userService.selectUserByEmail(user.getUserEmail()) == null) {
map.put("data", "emailUnregistered");
} else if (!otherService.ifValidEmailVerifyCode(emailVerifyCode, session)) {
map.put("data", "verifyCodeWrong");
} else {
session.setAttribute(Constants.USEREMAIL_SESSION, user.getUserEmail());
map.put("data", "verifyCodeCorrect");
}
return map;
}
/**
* @return java.util.Map
* @Author JinZhiyun
* @Description 重置密码的ajax交互
* @Date 9:46 2019/4/19
* @Param [user]
**/
@RequestMapping("/resetPassword")
@Token(remove = true)
@ResponseBody
public Map
Map
String userEmail = (String) session.getAttribute(Constants.USEREMAIL_SESSION);
if (userEmail != null && userEmail != "") {
userService.updateResetPasswordByEmail(userEmail, user.getUserPassword());
map.put("data", "resetPasswordSuccess");
}
return map;
}
/*=================以上为非登录下的请求,在LoginInterceptor中应该排除==================*/
/**
* @return java.lang.String
* @Author JinZhiyun
* @Description 定向到无修改权限提示页面error.jsp
* @Date 13:17 2019/5/3
* @Param []
**/
@RequestMapping("/error")
public String error() {
return "tips/error";
}
/**
* @return java.lang.String
* @Author JinZhiyun
* @Description 定向到控制台console.jsp
* @Date 9:58 2019/5/3
* @Param []
**/
@RequestMapping("/console")
public String console() {
return "home/console";
}
/**
* @return java.util.Map
* @Author JinZhiyun
* @Description 性别比可视化ajax
* @Date 18:54 2019/5/5
* @Param [stuCollegeName, stuMajorName, stuClassName]
**/
@RequestMapping("/findSexPercent")
@ResponseBody
public Map
, @RequestParam(value = "major", required = false) String stuMajorName
, @RequestParam(value = "class", required = false) String stuClassName) {
Map
StudentPercentBySex studentPercent = otherService.selectStuTotalBySex(stuCollegeName, stuMajorName, stuClassName);
map.put(Constants.STUDENT_PERCENT_BY_SEX, studentPercent);
return map;
}
/**
* @return java.lang.String
* @Author JinZhiyun
* @Description 重定向到echarts可视化性别比饼图
* @Date 12:18 2019/5/5
* @Param []
**/
@RequestMapping("/senior/stuSex")
public String sex() {
return "senior/student/stuSex";
}
/**
* @return java.lang.String
* @Author JinZhiyun
* @Description 重定向到echarts可视化学生数柱状图
* @Date 19:37 2019/5/5
* @Param []
**/
@RequestMapping("/senior/stuNum")
public String stuNum() {
return "senior/student/stuNum";
}
/**
* @return java.util.Map
* @author JinZhiyun
* @Description 学生人数比可视化ajax
* @Date 19:00 2019/7/21
* @Param [collegeName, majorName, type]
**/
@RequestMapping("/findPersonTotalPercentByCommonName")
@ResponseBody
public Map
, @RequestParam(value = "major", required = false) String majorName, @RequestParam(value = "type", required = false) String type) {
Map
List> list = otherService.proSelectStuTotalByCollegeOrMajorName(type, collegeName, majorName);
map.put("commonName", list.get(0));
map.put("total", list.get(1));
return map;
}
/**
* @author JinZhiyun
* @Description 本硕博比可视化ajax
* @Date 17:40 2019/7/23
* @Param [collegeName, type]
* @return java.util.Map
**/
@RequestMapping("/findStuTotalByDegreeAndCollege")
@ResponseBody
public Map
Map
map.put("dimensions", new ArrayList
/**
* @author JinZhiyun
* @Description 重定向到师资力量echarts可视化
* @Date 17:42 2019/7/23
* @Param []
* @return java.lang.String
**/
@RequestMapping("/senior/teaPower")
public String teaPower() {
return "senior/teacher/teaPower";
}
/**
* @author JinZhiyun
* @Description 师资力量可视化ajax
* @Date 18:45 2019/7/24
* @Param [collegeName, majorName, type]
* @return java.util.Map
**/
@RequestMapping("/findTeaTotalGroupByTitle")
@ResponseBody
public Map
, @RequestParam(value = "major", required = false) String majorName,@RequestParam(value = "type", required = false) String type) {
return otherService.transTeaTotalToValidJSON(type,collegeName,majorName);
}
}
代码已经上传github,下载地址: https://github.com/21503882/studentinfossh
————————————————