基于SpringBoot的高校信息管理系统

一、视频展示

https://www.bilibili.com/video/BV1pU4y1J7wc

二、项目介绍

1、技术与工具

开发工具 IntelliJ IDEA
数据库 MySQL 5.7
前端技术 Jquery 、 Bootstrap 、echarts、thymeleaf
后台技术 SpringBoot、MyBatis

2、项目目录介绍

 具体介绍如下:

(1)程序代码的存放目录——src下的java

component 登录拦截器
config 静态资源拦截
controller 负责在页面和程序之间传输数据的,做页面的跳转
dao 负责对数据向数据库增删改查的操作
entity 实体类。一般与数据库中的属性值基本保持一致
service 负责业务模块的应用逻辑设计
utils 工具包。包括验证码、分页插件等

(2)资源文件的存放目录——resources

Mapper 存放Mabtis的映射文件
static 存放静态资源文件,包括图片、css文件、js文件
tempaltes 存放前端所有的页面。

(3)测试类的目录——test 

扫描二维码关注公众号,回复: 13289087 查看本文章

(4)maven的配置文件——pom.xml 

三、关键技术

1、分页插件

需求:系统中的数据可能会有多条。当数据量较少的时候可以在一页上展示,但是如果数据量很大,则应该使用分页的方式来显示数据。

(1)分页插件的依赖包

        <!--分页插件-->
		<dependency>
			<groupId>com.github.pagehelper</groupId>
			<artifactId>pagehelper</artifactId>
			<version>4.1.6</version>
		</dependency>

(2)分页插件的工具类

Page类

public class Page {

    private int start; //开始页数
    private int count; //每页显示个数
    private int total; //总个数
    private String param; //参数

    private static final int defaultCount = 5; //默认每页显示5条

    public int getStart() {
        return start;
    }
    public void setStart(int start) {
        this.start = start;
    }
    public int getCount() {
        return count;
    }
    public void setCount(int count) {
        this.count = count;
    }

    public Page (){
        count = defaultCount;
    }
    public Page(int start, int count) {
        this();
        this.start = start;
        this.count = count;
    }

    public boolean isHasPreviouse(){
        if(start==0)
            return false;
        return true;
    }
    public boolean isHasNext(){
        if(start==getLast())
            return false;
        return true;
    }

    public int getTotalPage(){
        int totalPage;
        // 假设总数是50,是能够被5整除的,那么就有10页
        if (0 == total % count)
            totalPage = total /count;
            // 假设总数是51,不能够被5整除的,那么就有11页
        else
            totalPage = total / count + 1;

        if(0==totalPage)
            totalPage = 1;
        return totalPage;

    }

    public int getLast(){
        int last;
        // 假设总数是50,是能够被5整除的,那么最后一页的开始就是45
        if (0 == total % count)
            last = total - count;
            // 假设总数是51,不能够被5整除的,那么最后一页的开始就是50
        else
            last = total - total % count;
        last = last<0?0:last;
        return last;
    }

    @Override
    public String toString() {
        return "Page [start=" + start + ", count=" + count + ", total=" + total + ", getStart()=" + getStart()
                + ", getCount()=" + getCount() + ", isHasPreviouse()=" + isHasPreviouse() + ", isHasNext()="
                + isHasNext() + ", getTotalPage()=" + getTotalPage() + ", getLast()=" + getLast() + "]";
    }
    public int getTotal() {
        return total;
    }
    public void setTotal(int total) {
        this.total = total;
    }
    public String getParam() {
        return param;
    }
    public void setParam(String param) {
        this.param = param;
    }

}

PageHelperConfig类

@Configuration
public class PageHelperConfig {
 
    @Bean
    public PageHelper pageHelper() {
        PageHelper pageHelper = new PageHelper();
        Properties p = new Properties();
        p.setProperty("offsetAsPageNum", "true");
        p.setProperty("rowBoundsWithCount", "true");
        p.setProperty("reasonable", "true");
        pageHelper.setProperties(p);
        return pageHelper;
    }
}

(3)分页插件在业务逻辑中的使用方式

以查询所有学生信息为例演示分页插件的使用:

@RequestMapping("/studentList")
    public String studentList(Model model, Page page, String classNo){
        //分页插件
        PageHelper.offsetPage(page.getStart(),page.getCount());
        //结果集
        List<Student> studentList = new ArrayList<>();
        //如果班级号为空,则表明是查询所有学生信息的请求,反之则是根据班级号查询该班所有学生信息
        if(classNo != null){
            studentList = studentService.selectByCondition("", "", classNo);
        }else{
            studentList = studentService.selectAll();
        }
        //根据学号得到每个学生的选课数
        for (Student student : studentList){
            List<String> stringList = studentService.selectClassCount(student.getStuNo());
            student.setClassCount(stringList.size());
        }
        //得到记录总数
        int total = (int) new PageInfo<>(studentList).getTotal();
        //设置页的总数
        page.setTotal(total);
        //向页面返回数据
        model.addAttribute("page",page);
        model.addAttribute("studentList", studentList);
        return "student/student";
    }

(4)页面显示

<table class="table table-striped table-bordered text-center" style="margin-top:80px" th:if="${studentList != null}">
							<thead>
								<tr>
									<th class="text-center">头像</th>
									<th class="text-center">学号</th>
									<th class="text-center">姓名</th>
									<th class="text-center">性别</th>
									<th class="text-center">班级</th>
									<th class="text-center">手机号</th>
									<th class="text-center">选课数量</th>
									<th class="text-center">操作</th>
								</tr>
							</thead>
							<tbody>
								<tr th:each="student : ${studentList}">
									<td><img th:src="@{${student.icon}}" alt="点击查看头像" class="img-circle" style="width: 30px; height: 30px;"></td>
									<td th:text="${student.stuNo}"></td>
									<td th:text="${student.name}"></td>
									<td th:text="${student.gender==0} ? '女' : '男'"></td>
									<td th:text="${student.classNo}"></td>
									<td th:text="${student.phone}"></td>
									<td><a th:href="@{/curriculum/curriculumList(stuNo=${student.stuNo})}">[[${student.classCount}]]</span></a></td>
									<td>
										<a th:href="@{/student/studentDetail(id=${student.id})}"><span class="glyphicon glyphicon-pencil"
														 style="margin-right:10px"></span></a>
										<a th:href="@{/student/deleteStudent(id=${student.id})}"><span class="glyphicon glyphicon-trash"></span></a>
									</td>
								</tr>
							</tbody>
						</table>
						<div class="row text-center" th:if="${studentList != null}">
							<div class="col-sm-6 col-sm-offset-2">
								<ul class="pagination">
									<li><a th:href="@{/student/studentList(start = 0)}" aria-label="Previous"><span aria-hidden="true">上一页</span></a></li>
									<li th:each="number:${#numbers.sequence(1,page.totalPage)}"><a th:href="@{/student/studentList(start=${(number-1)*page.count})}" th:text="${number}"></a></li>
									<li><a  th:href="@{/student/studentList(start=${page.last})}" aria-label="Next"><span aria-hidden="true">下一页</span></a></li>
								</ul>
							</div>

						</div>

2、用户头像的上传与存储

需求:学生的个人信息中包含了头像,上传的头像存储在本地目录。同样,在页面也需显示出来。

 (1)页面上传头像

<form class="form-horizontal " th:action="@{/student/addStudent}" enctype="multipart/form-data" method="post">
			<div class="form-group"  style="margin-top: 10px;">
				<label for="exampleInputFile"  class="col-sm-3 control-label col-sm-offset-1">头像</label>
				<div class="col-sm-8">
					<div class="custom-file">
						<input type="file"  name="file" class="custom-file-input" id="exampleInputFile">
					</div>
				</div>
			</div>
...
</form>

(2)存储头像

@RequestMapping("/addStudent")
    public String addStudent(RedirectAttributes attributes, Student student, MultipartFile file, String province, String city, String district){
        //学生头像
        String filePath = "D:/Java/项目/MyDo/schoolmanagement/src/main/resources/static/userImg";
        String fileName = file.getOriginalFilename();
        File targetFile = new File(filePath, fileName);
        targetFile.getParentFile().mkdirs();
        try {
            file.transferTo(targetFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
        student.setIcon("/userImg/"+fileName);
        //学生地址
        String address = province + ":" + city + ":" + district;
        student.setAddress(address);
        //插入数据库
        studentService.insertStudent(student);
        attributes.addFlashAttribute("msg", "添加成功");
        return "redirect:/student/studentList";
    }

(3)更换头像

@RequestMapping("/modifyStudent")
    public String modifyStudent(RedirectAttributes attributes, Student student, MultipartFile file, String province, String city, String district){
        //学生头像。如果页面提交过来的不为空,则替换,如果为空,则仍然是源头像
        if (!file.isEmpty()) {
            /**
             * 上传图片
             */
            //图像存放路径
            String filePath = "D:/Java/项目/MyDo/schoolmanagement/src/main/resources/static/userImg";
            //图片名称
            String fileName = file.getOriginalFilename();
            File targetFile = new File(filePath, fileName);
            //创建文件路径
            targetFile.getParentFile().mkdirs();
            targetFile.delete();
            try {
                file.transferTo(targetFile);
            } catch (IOException e) {
                e.printStackTrace();
            }
            student.setIcon("/userImg/"+fileName);
        }else {
            //设置源头像
            Student searchStudent = studentService.selectById(student.getId());
            student.setIcon(searchStudent.getIcon());
        }
        //学生地址
        String address = province + ":" + city + ":" + district;
        student.setAddress(address);
        studentService.updateStudent(student);
        attributes.addFlashAttribute("msg", "修改成功");
        return "redirect:/student/studentList";
    }

3、登录验证码

需求:在用户登陆系统时,需要输入验证码,并在后台完成验证。

 (1)页面逻辑

<div class="input-group mb-3">
                <img id="imgVerify" th:src="@{/getVerify}" alt="更换验证码" height="30" width="170"
                     onclick="getVerify(this);">
                <input type="tel" class="form-control" placeholder="验证码" maxlength="4" style="float:right;width: 40%;left: 0;margin-top: 14px;"
                       name="verifyInput" id="verify" onfocus="modifyLabel()">
            </div>
//获取验证码
    function getVerify() {
        $("#imgVerify").attr("src", '/getVerify?' + Math.random());//jquery方式
    }
   function modifyLabel(){
        $(".tip-area").css("display", "none");
    }

(2)工具类

RandomValidateCodeUtil类



import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;

public class RandomValidateCodeUtil {
 
 
    public static final String RANDOMCODEKEY= "RANDOMVALIDATECODEKEY";//放到session中的key
    private String randString = "0123456789";//随机产生只有数字的字符串 private String
    //private String randString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";//随机产生只有字母的字符串
    //private String randString = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";//随机产生数字与字母组合的字符串
    private int width = 95;// 图片宽
    private int height = 25;// 图片高
    private int lineSize = 40;// 干扰线数量
    private int stringNum = 4;// 随机产生字符数量
 
    private static final Logger logger = LoggerFactory.getLogger(RandomValidateCodeUtil.class);
 
    private Random random = new Random();
 
    /**
     * 获得字体
     */
    private Font getFont() {
        return new Font("Fixedsys", Font.CENTER_BASELINE, 18);
    }
 
    /**
     * 获得颜色
     */
    private Color getRandColor(int fc, int bc) {
        if (fc > 255)
            fc = 255;
        if (bc > 255)
            bc = 255;
        int r = fc + random.nextInt(bc - fc - 16);
        int g = fc + random.nextInt(bc - fc - 14);
        int b = fc + random.nextInt(bc - fc - 18);
        return new Color(r, g, b);
    }
 
    /**
     * 生成随机图片
     */
    public void getRandcode(HttpServletRequest request, HttpServletResponse response) {
        HttpSession session = request.getSession();
        // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
        Graphics g = image.getGraphics();// 产生Image对象的Graphics对象,改对象可以在图像上进行各种绘制操作
        g.fillRect(0, 0, width, height);//图片大小
        g.setFont(new Font("Times New Roman", Font.ROMAN_BASELINE, 18));//字体大小
        g.setColor(getRandColor(110, 133));//字体颜色
        // 绘制干扰线
        for (int i = 0; i <= lineSize; i++) {
            drowLine(g);
        }
        // 绘制随机字符
        String randomString = "";
        for (int i = 1; i <= stringNum; i++) {
            randomString = drowString(g, randomString, i);
        }
        logger.info(randomString);
        //将生成的随机字符串保存到session中
        session.removeAttribute(RANDOMCODEKEY);
        session.setAttribute(RANDOMCODEKEY, randomString);
        g.dispose();
        try {
            // 将内存中的图片通过流动形式输出到客户端
            ImageIO.write(image, "JPEG", response.getOutputStream());
        } catch (Exception e) {
            logger.error("将内存中的图片通过流动形式输出到客户端失败>>>>   ", e);
        }
 
    }
 
    /**
     * 绘制字符串
     */
    private String drowString(Graphics g, String randomString, int i) {
        g.setFont(getFont());
        g.setColor(new Color(random.nextInt(101), random.nextInt(111), random
                .nextInt(121)));
        String rand = String.valueOf(getRandomString(random.nextInt(randString
                .length())));
        randomString += rand;
        g.translate(random.nextInt(3), random.nextInt(3));
        g.drawString(rand, 13 * i, 16);
        return randomString;
    }
 
    /**
     * 绘制干扰线
     */
    private void drowLine(Graphics g) {
        int x = random.nextInt(width);
        int y = random.nextInt(height);
        int xl = random.nextInt(13);
        int yl = random.nextInt(15);
        g.drawLine(x, y, x + xl, y + yl);
    }
 
    /**
     * 获取随机的字符
     */
    public String getRandomString(int num) {
        return String.valueOf(randString.charAt(num));
    }
}

Picverigyaction类



import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@RestController
public class Picverifyaction {
    private final static Logger logger = LoggerFactory.getLogger(Picverifyaction.class);
 
    /**
     * 生成验证码
     */
    @RequestMapping(value = "/getVerify")
    public void getVerify(HttpServletRequest request, HttpServletResponse response) {
        try {
            response.setContentType("image/jpeg");//设置相应类型,告诉浏览器输出的内容为图片
            response.setHeader("Pragma", "No-cache");//设置响应头信息,告诉浏览器不要缓存此内容
            response.setHeader("Cache-Control", "no-cache");
            response.setDateHeader("Expire", 0);
            RandomValidateCodeUtil randomValidateCode = new RandomValidateCodeUtil();
            randomValidateCode.getRandcode(request, response);//输出验证码图片方法
        } catch (Exception e) {
            logger.error("获取验证码失败>>>>   ", e);
        }
    }
 

 
}

(3)登录处理

@PostMapping("/login")
    public ModelAndView login(User user, @RequestParam String verifyInput, HttpSession session, RedirectAttributes attributes){
        //验证码
        String random = (String) session.getAttribute("RANDOMVALIDATECODEKEY");
        ModelAndView mv = new ModelAndView();
        //验证码校验
        if (random == null) {
            System.out.println("验证码错误");
            mv.addObject("msg", "验证码错误");
            mv.setViewName("index");
            return mv;
        }
        //判断验证码是否相等
        if(random.equals(verifyInput)){
            //根据用户名和密码查询用户
            User loginUser = userService.selectByNameAndPwd(user);
            if(loginUser != null){
                //查询成功,判断身份是否相等
                if(loginUser.getIdentity() != user.getIdentity()){
                    //不相等,则提示信息
                    mv.addObject("msg", "你不是"+(user.getIdentity() == 1 ? "管理员" : "用户"));
                    mv.setViewName("index");
                }else{
                    //相等,登陆成功
                    // session.setAttribute("loginUsername", user.getName());
                    session.setAttribute("user", user);
                    mv.setViewName("main");
                }
            } else{
                //查询失败,提示未注册
                mv.addObject("msg", "当前用户未注册");
                mv.setViewName("index");
            }
        }else{
            //验证码错误。,返回登录页
            System.out.println("验证码错误");
            mv.addObject("msg", "验证码错误");
            mv.setViewName("index");
        }
        // mv.setViewName("main");
        return mv;
    }

4、Hutool导出数据

需求:页面显示了信息列表,如果需要导出列表数据,需要点击导出按钮。

(1)页面

<div class="text-center" style="display:block;margin-bottom: 20px;">
					<a class="btn btn-primary col-sm-1" style="margin-right:10px" th:href="@{/user/toPage(url='/teacher/addTeacher')}"><span class="glyphicon glyphicon-plus" style="margin-right: 10px;"></span>添加</a>
					<a class="btn btn-warning col-sm-1" th:href="@{/teacher/exportTeacherData}"><span class="glyphicon glyphicon-upload" style="margin-right: 10px;"></span>导出</a>
					<label class="pull-right" style="margin-right:20px"  th:if="${teacherList != null}">共有数据[[${page.total}]]条</label>

				</div>

(2)后台处理请求

    @RequestMapping("/exportTeacherData")
    public void exportTeacherData(HttpServletResponse response) throws UnsupportedEncodingException {
        //从数据库中查询到数据
        List<Teacher> teacherList = teacherService.selectAll();
        for(Teacher teacher : teacherList){
            teacher.setClassCount(curriculumService.selectByTeacherNo(teacher.getTeacherNo()).size());
        }
        // 通过工具类创建writer,默认创建xls格式
        ExcelWriter writer = ExcelUtil.getWriter();
        //自定义标题别名
        writer.addHeaderAlias("teacherNo", "教工号");
        writer.addHeaderAlias("name", "教师姓名");
        writer.addHeaderAlias("age", "年龄");
        writer.addHeaderAlias("gender", "性别(0 男 1 女)");
        writer.addHeaderAlias("professor", "职称");
        writer.addHeaderAlias("phone", "手机号");
        writer.addHeaderAlias("email", "邮箱");
        writer.addHeaderAlias("classCount", "带课数");
        //只导出设置了别名的列
        writer.setOnlyAlias(true);
        // 合并单元格后的标题行,使用默认标题样式
        writer.merge(7, "教师信息");
        // 一次性写出内容,使用默认样式,强制输出标题
        writer.write(teacherList, true);
        //out为OutputStream,需要写出到的目标流
        //response为HttpServletResponse对象
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        //dateString.xls是弹出下载对话框的文件名,用日期作为文件名称
        Date currentTime = new Date();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = formatter.format(currentTime);
        response.setHeader("Content-Disposition","attachment;filename="+dateString+".xls");
        ServletOutputStream out= null;
        try {
            out = response.getOutputStream();
            writer.flush(out, true);
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        finally {
            // 关闭writer,释放内存
            writer.close();
        }
        //此处记得关闭输出Servlet流
        IoUtil.close(out);
    }

5、webjars使用

(1)介绍

        WebJars是将客户端(浏览器)资源(JavaScript,Css等)打成jar包文件,以对资源进行统一依赖管理。WebJars的jar包部署在Maven中央仓库上。

(2)目的

统一管理静态资源

(3)实现方式(以Bootstrap、jquery、echart为例)

pom.xml

        <dependency>
			<groupId>org.webjars</groupId>
			<artifactId>bootstrap</artifactId>
			<version>3.3.5</version>
		</dependency>
		<dependency>
			<groupId>org.webjars</groupId>
			<artifactId>jquery</artifactId>
			<version>3.6.0</version>
		</dependency>
        <dependency>
			<groupId>org.webjars.bower</groupId>
			<artifactId>echarts</artifactId>
			<version>4.7.0</version>
		</dependency>

页面中使用:

		<!-- Bootstrap core CSS -->
		<link th:href="@{/webjars/bootstrap/3.3.5/css/bootstrap.css}" rel="stylesheet">
		<script th:src="@{/webjars/jquery/3.6.0/jquery.min.js}"></script>

		<script th:src="@{/webjars/bootstrap/3.3.5/js/bootstrap.js}"></script>
		<script th:src="@{/webjars/echarts/4.7.0/dist/echarts.js}"></script>

6、公共请求的页面跳转

需求:在后台逻辑中有的请求只是为了跳转页面,通过设置公共请求对这些跳转请求进行统一处理。如下:

    /**
     * 跳转至学生分析页面
     * @return
     */
    @RequestMapping("/studentAnalysis")
    public String studentScore(){
        return "/student/studentAnalysis";
    }

处理公共请求的映射方法:

/**
     * 公共请求的处理
     * @param request
     * @return
     */
    @RequestMapping(value = "/toPage",method = RequestMethod.GET)
    public  String toPage(HttpServletRequest request){
        //获取请求参数
        String url= request.getParameter("url");
        return  url;
    }

使用方式:在请求页面时携带url参数

教师页面:点击按钮,跳转至添加教师页面。

<a class="btn btn-primary col-sm-1" style="margin-right:10px" th:href="@{/user/toPage(url='/teacher/addTeacher')}"><span class="glyphicon glyphicon-plus" style="margin-right: 10px;"></span>添加</a>

顶部菜单栏的退出功能:

<ul class="dropdown-menu text-center">
                <li class="text-center" ><a href="#">修改密码</a></li>
                <li role="separator" class="divider"></li>
                <li class="text-center"><a th:href="@{/user/toPage(url='index')}">退出</a></li>
            </ul>

7、session的使用

需求:用户登陆成功之后,在顶部菜单栏显示欢迎XXX登录。

登录逻辑中的处理:

session.setAttribute("user", user);

 页面中使用session:

<li><a >欢迎[[${session.user.name}]]登录</a></li>

8、echarts与后台的交互

需求:对信息以图表化形式显示在页面上。

 (1)页面

<!DOCTYPE html>
<html lang="en"  xmlns:th="http://www.thymeleaf.org">
	<head>
		<meta charset="utf-8">
		<title>课程分析</title>
		<!-- Bootstrap core CSS -->
		<link th:href="@{/webjars/bootstrap/3.3.5/css/bootstrap.css}" rel="stylesheet">
		<script th:src="@{/webjars/jquery/3.6.0/jquery.min.js}"></script>

		<script th:src="@{/webjars/bootstrap/3.3.5/js/bootstrap.js}"></script>
		<script th:src="@{/webjars/echarts/4.7.0/dist/echarts.js}"></script>
	</head>
	<body>
		<!-- 导航 -->
		<div th:replace="commons/bar::topbar"></div>
		<!-- 主题内容 -->
		<div class="container-fluid">
			<div class="page-main">
				<ol class="breadcrumb">
					<li>课程信息</li>
					<li>课程分析</li>
				</ol>
				<div class="row">
					<div class="">
						<div id="leftGraph" style="height: 400px" class="col-sm-5 col-sm-offset-1"></div>
						<div id="rightGraph" style="height: 400px" class="col-sm-5 col-sm-offset-1"></div>
					</div>
				</div>

			</div>
		</div>
		</div>
		<div th:replace="commons/footer::footer"></div>
	</body>
`
	<script type="text/javascript">
		$(function () {
			$.ajax({
				type : "get",   //请求方式
				url : "http://localhost:8082/curriculumGrade",  //后端controller层路径
				contentType: 'application/json',
				success:function(data){

					var leftDom = document.getElementById("leftGraph");
					var leftChart = echarts.init(leftDom);
					var leftOption;
					leftOption = {
						title : {
							show:true,//显示策略,默认值true,可选为:true(显示) | false(隐藏)
							text: '课程等级',
						},
						xAxis: {
							type: 'category',
							data: data.names
						},
						yAxis: {
							type: 'value'
						},
						series: [{
							data: data.grades,
							type: 'bar',
							showBackground: true,
							backgroundStyle: {
								color: 'rgba(43, 114, 180, 0.2)'
							}
						}]
					};
					if (leftOption && typeof leftOption === 'object') {
						leftChart.setOption(leftOption);
					}
				},
				error:function(data){
					console.log("error")
					console.log(data)
				}
			})
			$.ajax({
				type : "get",   //请求方式
				url : "http://localhost:8082/curriculumTime",  //后端controller层路径
				contentType: 'application/json',
				success:function(data){
					console.log(data)
					var arr = [];
					for(var i=0; i < data.hours.length; i++){
						arr.push({"value":data.counts[i], "name":data.hours[i]});
					}
					console.log(arr);
					var rightDom = document.getElementById("rightGraph");
					var rightChart = echarts.init(rightDom);

					var rightOption;
					rightOption = {
						title: {
							text: '课时数量',
							left: 'center'
						},
						tooltip: {
							trigger: 'item'
						},
						legend: {
							orient: 'vertical',
							left: 'left',
						},
						series: [
							{
								name: '访问来源',
								type: 'pie',
								radius: '50%',
								data:arr,
								emphasis: {
									itemStyle: {
										shadowBlur: 10,
										shadowOffsetX: 0,
										shadowColor: 'rgba(0, 0, 0, 0.5)'
									}
								}
							}
						]
					};

					if (rightOption && typeof rightOption === 'object') {
						rightChart.setOption(rightOption);
					}
				},
				error:function(data){
					console.log("error")
					console.log(data)
				}


			})
		});

		

	</script>
</html>

(2)后台处理 

/**
     * 课程等级
     * @return
     */
    @RequestMapping("/curriculumGrade")
    public Map<String, Object> curriculumGrade(){
        List<Curriculum> curriculumList = curriculumService.selectAll();
        String[] names = new String[curriculumList.size()];
        int[] grades = new int[curriculumList.size()];
        int i = 0;
        for(Curriculum curriculum :curriculumList){
            names[i] = curriculum.getClassName();
            grades[i] = curriculum.getClassGrade();
            i++;
        }
        Map<String, Object> map = new HashMap<>();
        map.put("names", names);
        map.put("grades", grades);
        return map;
    }

    /**
     * 课程课时
     * @return
     */
    @RequestMapping("/curriculumTime")
    public Map<String, Object> curriculumTime(){
        List<Curriculum> curriculumList = curriculumService.selectAll();
        Map<Integer, Integer> myMap = new HashMap<>();
        for(Curriculum curriculum : curriculumList){
            if(myMap.containsKey(curriculum.getClassHour())){
                myMap.put(curriculum.getClassHour(), myMap.get(curriculum.getClassHour())+1);
            }else{
                myMap.put(curriculum.getClassHour(), 1);
            }
        }
        System.out.println(myMap);
        int[] hours = new int[myMap.size()];
        int[] counts = new int[myMap.size()];
        int i = 0;
        for (Map.Entry<Integer, Integer> entry : myMap.entrySet()) {
            hours[i] = entry.getKey();
            counts[i] = entry.getValue();
            i++;
        }
        Map<String, Object> map = new HashMap<>();
        map.put("hours", hours);
        map.put("counts", counts);
        return map;
    }

9、省市区三级联动

需求:添加学生的时候,选择学生的家庭住址

页面实现:

<div class="form-group" style="margin-top: 10px;">
				<label class="col-sm-3 control-label col-sm-offset-1">家庭住址</label>
				<div class="col-sm-8 form-inline">
					<div id="distpicker" >
						<div class="form-group col-sm-offset-1 col-sm-3" style="margin-right: 10px;">
							<label class="sr-only" for="province">Province</label>
							<select class="form-control" id="province" name="province"></select>
						</div>
						<div class="form-group  col-sm-offset-1  col-sm-3" >
							<label class="sr-only" for="city">City</label>
							<select class="form-control" id="city" name="city"></select>
						</div>
						<div class="form-group col-sm-offset-1  col-sm-3"  style="margin-right: 10px;">
							<label class="sr-only" for="district">District</label>
							<select class="form-control" id="district" name="district"></select>
						</div>
						<div class="form-group">
							<button class="btn btn-primary" id="reset" type="button">Reset</button>
						</div>
					</div>
				</div>
			</div>

<script src="/js/distpicker.data.js"></script>
<script src="/js/distpicker.js"></script>
<script>
var _distpicker = $('#distpicker');

	_distpicker.distpicker({
		province: '浙江省',
		city: '杭州市',
		district: '上城区'
	});

	$('#reset').click(function () {
		_distpicker.distpicker('reset');
	});
</script>

10、日期控件

需求:学生生日的选择通过日历控件。

 页面中的定义:

<div class="form-group" style="margin-top: 10px;">
    <label class="col-sm-3 control-label col-sm-offset-1">生日</label>
    <div class="col-sm-8 username-area">
        <input type="text" class="form-control" id="date" name="birth">
    </div>
</div>
$("#date").datetime({
		type: "date",
		value: [2019, 9, 31],
		success: function(res) {
			console.log(res)
		}
	})

 注:在省市区三级联动和日历控件中用了自定义的css以及一些js文件,可在源码中查看,这里不再罗列。

11、thymeleaf提取公共页面

需求:每个页面都有顶部菜单栏,因此提取作为公共部分,然后在所需引入即可。

topbar.html:

<!DOCTYPE html>
<html lang="en"  xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!-- 导航 -->
<nav class="navbar navbar-default navbar-static-top  navbar-inverse" th:fragment="topbar">
    <div class="navbar-header">
        <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#slide-left">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
        </button>
        <label  class="navbar-brand">高校人员信息管理</label>
    </div>
    <ul class="nav navbar-nav nav-menu" style="margin-right: 25px;">
        <li ><a th:href="@{/user/toPage/(url='/main')}">首页</a></li>
        <li class="dropdown">
            <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">学生培养
                <span class="caret"></span></a>
            <ul class="dropdown-menu text-center">
                <li class="text-center"><a th:href="@{/student/studentList}">学生列表</a></li>

                <li role="separator" class="divider"></li>
                <li class="text-center"><a th:href="@{/student/studentAnalysis}">学生分析</a></li>
            </ul>
        </li>
        <li class="dropdown">
            <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">教师风采
                <span class="caret"></span></a>
            <ul class="dropdown-menu text-center">
                <li class="text-center"><a th:href="@{/teacher/teacherList}">教师列表</a></li>
                <li role="separator" class="divider"></li>
                <li class="text-center"><a th:href="@{/teacher/teacherAnalysis}">教师分析</a></li>
            </ul>
        </li>
        <li class="dropdown">
            <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">课程信息
                <span class="caret"></span></a>
            <ul class="dropdown-menu text-center">
                <li class="text-center"><a th:href="@{/curriculum/curriculumList}">课程列表</a></li>
                <li role="separator" class="divider"></li>
                <li class="text-center"><a th:href="@{/curriculum/curriculumAnalysis}">课程分析</a></li>
            </ul>
        </li>
        <li class="dropdown">
            <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">班级信息
                <span class="caret"></span></a>
            <ul class="dropdown-menu text-center">
                <li class="text-center"><a th:href="@{/class/classAllList}">班级列表</a></li>
                <li role="separator" class="divider"></li>
                <li class="text-center"><a th:href="@{/class/classAnalysis}">班级分析</a></li>
            </ul>
        </li>
        <li><a href="">关于</a></li>

    </ul>

    <ul class="nav navbar-nav navbar-right pull-right" style="margin-right: 40px;">
        <li><a >欢迎[[${session.user.name}]]登录</a></li>
        <li class="dropdown">
            <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">我的
                <span class="caret"></span></a>
            <ul class="dropdown-menu text-center">
                <li class="text-center" ><a href="#">修改密码</a></li>
                <li role="separator" class="divider"></li>
                <li class="text-center"><a th:href="@{/user/toPage(url='index')}">退出</a></li>
            </ul>
        </li>
    </ul>

</nav>
</body>
</html>

footer.html:

<!DOCTYPE html>
<html lang="en"  xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>$Title$</title>
</head>
<body>
<footer class="footer" style="background-color:#1C1C1C;color:white;height:80px;line-height:30px" th:fragment="footer">
    <div class="container text-center">
        <p>版权所有:YHT China &nbsp;&nbsp;&nbsp;电话:029-12345678<br />地址:陕西省西安市 &nbsp;&nbsp;&nbsp; 邮编:123456</p>
    </div>
</footer>
</body>
</html>

这两个文件都在templates的commons文件下。

引入公共部分:

<div th:replace="commons/bar::topbar"></div>
<div th:replace="commons/footer::footer"></div>

12、MD5加密

需求:对用户的密码进行MD5加密,提高安全性。

(1)工具类MD5Utils

public class MD5Utils {
    public static String stringToMD5(String plainText) {
        byte[] secretBytes = null;
        try {
            secretBytes = MessageDigest.getInstance("md5").digest(
                    plainText.getBytes());
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("没有这个md5算法!");
        }
        String md5code = new BigInteger(1, secretBytes).toString(16);
        for (int i = 0; i < 32 - md5code.length(); i++) {
            md5code = "0" + md5code;
        }
        return md5code;
    }
}

(2)注册时MD5加密

 user.setPassword(MD5Utils.stringToMD5(user.getPassword()));

13、RedirectAttributes

需求:在重定向之后需要携带参数跳转页面。

如下:在添加班级之后将提示信息传递到classList页面。

/**
     * 添加班级信息
     * @param classEntity
     * @param attributes
     * @return
     */
    @RequestMapping("/addClass")
    public String addCurriculum(ClassEntity classEntity, RedirectAttributes attributes){
        //插入数据
        classService.insertClass(classEntity);
        attributes.addFlashAttribute("msg", "添加成功");
        return "redirect:/class/classAllList";
    }

四、总结

一定要仔细,特别是复制粘贴的时候。在这个项目中,其实出现的问题都是因为自己不仔细,所以才出现的。

五、代码地址

https://github.com/MyBestThought/schoolmanagement

欢迎大家指点!!!

猜你喜欢

转载自blog.csdn.net/weixin_47382783/article/details/119318208