0.8

0.8

实训答辩(2)

学生信息管理系统#

系统功能描述#

学生信息管理系统是基于B/S 模式开发的系统。系统包括学生、教师和管理员三种角色,同时也可以自定义添加用户,并且在管理员的权限下,通过分配权限这一功能能够对用户权限管理实现精准化、在一定程度上保证了学生信息管理系统的安全性。

学生#

  • 学生可以查看班级同学的相关信息密码等隐私因素已加密,非管理员用户无权查看),可以对自身信息进行修改或删除自己的记录并新增一条关于自己的个人信息记录

    image-20230607144747923

  • 学生可以查看教师团队以及相关班级,了解到有哪些班级来上课,哪些老师任教等相关信息

    image-20230607144804949

教师#

  • 教师可以查看班级学生的相关信息,可以对班级学生相关信息进行增删改查(包括修改登陆密码等),在一定程度上能够优化学生的登陆体验

    image-20230607145207165

  • 教师可以查看同行老师的授课情况以及自己对应的授课班级,并且对同行老师的相关信息做一些了解

    image-20230607145514877

  • 老师可以对操作行为进行历史操作查询,在一定程度上能够追踪溯源,提升系统的稳定性和安全性

    image-20230607145634278

超级管理员#

  • 超级管理员拥有老师和学生的全部功能,在此基础上,超级管理员还拥有菜单管理的功能,支持通过Tree的形式对整个管理系统进行垂直式浏览,方便系统的维护

image-20230607145812395

  • 超级管理员可以对字典进行管理,通过后台管理系统,管理员能够详细的了解到字典标识、字典类型、字典值、创建时间、更新时间等,支持增删改查

image-20230607150051720

  • 本项目支持二次开发,如管理员有一定需求,可以通过开发中心模块对本系统进行二次开发

    image-20230607150159203

系统功能模块图#

img

系统数据库设计#

sys_action_log.sql#

记录管理系统的操作日志

image-20230607150621161

sys_dept.sql#

用于存放部门管理相关数据

image-20230607150722949

sys_dict.sql#

用于存放菜单管理相关数据

image-20230607150840705

sys_file.sql#

用于存放上传头像相关数据

image-20230607150919947

sys_menu.sql#

用于存放系统菜单相关数据

image-20230607150954229

sys_role.sql#

用于存放系统角色相关数据

image-20230607151042959

sys_role_menu.sql#

用于存放系统角色 id相关数据

image-20230607151135548

sys_user.sql#

用于存放系统用户相关数据

image-20230607151209710

sys_user_role.sql#

用于存放系统用户 id相关数据

image-20230607151245779

系统的具体实现#

整体功能模块图#

image-20230607151523622

登录模块#

H5 页面图#

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="/common/template :: header(~{::title},~{::link},~{::style})">
    <title>TIMO登录</title>
    <link rel="stylesheet" type="text/css" th:href="@{/css/login.css}">
</head>
<body class="layui-layout-login">
<div class="login-bg">
    <div class="cover"></div>
</div>
<div class="login-content" th:th:classappend="${isCaptcha} ? 'captcha'">
    <h1 class="login-box-title"><i class="fa fa-fw fa-user"></i>登录</h1>
    <form class="layui-form" th:action="@{/login}" method="post">
        <div class="layui-form-item">
            <label class="layui-icon layui-icon-username" for="username"></label>
            <input class="layui-input" type="text" name="username" id="username" placeholder="用户名">
        </div>
        <div class="layui-form-item">
            <label class="layui-icon layui-icon-password" for="password"></label>
            <input class="layui-input" type="password" name="password" id="password" placeholder="密码">
        </div>
        <div th:if="${isCaptcha}" class="layui-form-item captcha-item">
            <label class="layui-icon layui-icon-vercode"></label>
            <input class="layui-input" type="text" name="captcha" autocomplete="off" placeholder="验证码">
            <img class="captcha-img" th:src="@{/captcha}" />
        </div>
        <div class="layui-form-item">
            <input type="checkbox" name="rememberMe" title="记住我" lay-skin="primary">
            <a class="layui-layout-right forget-password" href="javascript:alert('请联系超级管理员!')">忘记密码?</a>
        </div>
        <button type="submit" class="layui-btn layui-btn-fluid ajax-login"><i class="fa fa-sign-in fa-lg fa-fw"></i> 登录</button>
    </form>
    <div class="layui-layer-loading login-page-loading"><div class="layui-layer-content"></div></div>
</div>
<script th:replace="/common/template :: script"></script>
<script th:src="@{/js/login.js}" charset="utf-8"></script>
</body>
</html>

js 核心代码#

if(window.top!==window.self){window.top.location=window.location};
layui.use(['element'], function () {
    var $ = layui.jquery;
    $(document).on('click', '.captcha-img', function () {
        var src = this.src.split("?")[0];
        this.src = src + "?" + Math.random();
    });
    $(document).on('click', '.ajax-login', function (e) {
        e.preventDefault();
        var form = $(this).parents("form");
        var url = form.attr("action");
        var serializeArray = form.serializeArray();
        $.post(url, serializeArray, function (result) {
            if(result.code !== 200){
                $('.captcha-img').click();
            }
            $.fn.Messager(result);
        });
    });
    $('.layui-layer-loading').hide();
});

css 样式表#

@charset "UTF-8";
.layui-layout-login .login-bg{
    background-color: #e7e7e7;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: -1;
}
.layui-layout-login .login-bg .cover{
    background-color: #009688;
    height: 50%;
}
.layui-layout-login .login-content{
    width:250px;
    position: absolute;
    top: 50%;
    left: 50%;
    transform:translate(-50%,-50%);
    background-color: #ffffff;
    padding: 40px;
    padding-top: 32px;
    -webkit-box-shadow: 0px 3px 20px 3px rgba(0, 0, 0, 0.15);
    box-shadow: 0px 3px 20px 3px rgba(0, 0, 0, 0.15);
}
.layui-layout-login .login-content.captcha{
    width:300px;
    padding-bottom: 38px;
}
.layui-layout-login .login-content.captcha .captcha-item .layui-icon{
    font-size: 16px;
}
.layui-layout-login .login-content.captcha .captcha-item .layui-input{
    float: left;
    width: 180px;
}
.layui-layout-login .login-content.captcha .captcha-item .captcha-img{
    float: right;
    height: 38px;
    cursor: pointer;
}
.layui-layout-login .login-box-title{
    font-size: 26px;
    margin-bottom: 20px;
    text-align: center;
    color: #444444;
}
.layui-layout-login .layui-form-item{
    position: relative;
    margin-bottom: 20px;
    min-height: 18px;
}
.layui-layout-login .layui-form-item label{
    position: absolute;
    top:0;
    left: 0;
    font-size: 18px;
    width: 38px;
    line-height: 38px;
    text-align: center;
    color: #999999;
}
.layui-layout-login .layui-form-item input[type=text],
.layui-layout-login .layui-form-item input[type=password]{
    padding-left: 36px;
    border: 1px solid #ddd;
    transition: all 0s;
    -webkit-transition: all 0s;
}
.layui-layout-login .layui-form-item .layui-form-checkbox{
    margin-top: 0;
}
.layui-layout-login .layui-form-item .layui-form-checkbox .layui-icon{
    width: 14px;
    height: 14px;
    top: 1px;
    line-height: 14px;
}
.layui-layout-login .layui-form-item .layui-form-checkbox[lay-skin=primary]:hover i {
    border-color: #009688;
}
.layui-layout-login .layui-form-item .layui-form-checked[lay-skin=primary] i{
    border-color: #009688;
    background-color: #009688;
}
.layui-layout-login .layui-form-item .forget-password{
    color: #009688;
}
.layui-layout-login .login-page-loading {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 0!important;
    background-color: rgba(255, 255, 255, 0.3)!important;
}

业务代码#

package com.linln.admin.system.controller;

import com.linln.common.config.properties.ProjectProperties;
import com.linln.common.data.URL;
import com.linln.common.enums.ResultEnum;
import com.linln.common.exception.ResultException;
import com.linln.common.utils.CaptchaUtil;
import com.linln.common.utils.ResultVoUtil;
import com.linln.common.utils.SpringContextUtil;
import com.linln.common.vo.ResultVo;
import com.linln.component.actionLog.action.UserAction;
import com.linln.component.actionLog.annotation.ActionLog;
import com.linln.component.shiro.ShiroUtil;
import com.linln.modules.system.domain.User;
import com.linln.modules.system.service.RoleService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author 小懒虫
 * @date 2018/8/14
 */
@Controller
public class LoginController implements ErrorController {

    @Autowired
    private RoleService roleService;

    /**
     * 跳转到登录页面
     */
    @GetMapping("/login")
    public String toLogin(Model model) {
        ProjectProperties properties = SpringContextUtil.getBean(ProjectProperties.class);
        model.addAttribute("isCaptcha", properties.isCaptchaOpen());
        return "/login";
    }

    /**
     * 实现登录
     */
    @PostMapping("/login")
    @ResponseBody
    @ActionLog(key = UserAction.USER_LOGIN, action = UserAction.class)
    public ResultVo login(String username, String password, String captcha, String rememberMe) {
        // 判断账号密码是否为空
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            throw new ResultException(ResultEnum.USER_NAME_PWD_NULL);
        }

        // 判断验证码是否正确
        ProjectProperties properties = SpringContextUtil.getBean(ProjectProperties.class);
        if (properties.isCaptchaOpen()) {
            Session session = SecurityUtils.getSubject().getSession();
            String sessionCaptcha = (String) session.getAttribute("captcha");
            if (StringUtils.isEmpty(captcha) || StringUtils.isEmpty(sessionCaptcha)
                    || !captcha.toUpperCase().equals(sessionCaptcha.toUpperCase())) {
                throw new ResultException(ResultEnum.USER_CAPTCHA_ERROR);
            }
            session.removeAttribute("captcha");
        }

        // 1.获取Subject主体对象
        Subject subject = SecurityUtils.getSubject();

        // 2.封装用户数据
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);

        // 3.执行登录,进入自定义Realm类中
        try {
            // 判断是否自动登录
            if (rememberMe != null) {
                token.setRememberMe(true);
            } else {
                token.setRememberMe(false);
            }
            subject.login(token);

            // 判断是否拥有后台角色
            User user = ShiroUtil.getSubject();
            if (roleService.existsUserOk(user.getId())) {
                return ResultVoUtil.success("登录成功", new URL("/"));
            } else {
                SecurityUtils.getSubject().logout();
                return ResultVoUtil.error("您不是后台管理员!");
            }
        } catch (LockedAccountException e) {
            return ResultVoUtil.error("该账号已被冻结");
        } catch (AuthenticationException e) {
            return ResultVoUtil.error("用户名或密码错误");
        }
    }

    /**
     * 验证码图片
     */
    @GetMapping("/captcha")
    public void captcha(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //设置响应头信息,通知浏览器不要缓存
        response.setHeader("Expires", "-1");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "-1");
        response.setContentType("image/jpeg");

        // 获取验证码
        String code = CaptchaUtil.getRandomCode();
        // 将验证码输入到session中,用来验证
        request.getSession().setAttribute("captcha", code);
        // 输出到web页面
        ImageIO.write(CaptchaUtil.genCaptcha(code), "jpg", response.getOutputStream());
    }

    /**
     * 退出登录
     */
    @GetMapping("/logout")
    public String logout() {
        SecurityUtils.getSubject().logout();
        return "redirect:/login";
    }

    /**
     * 权限不足页面
     */
    @GetMapping("/noAuth")
    public String noAuth() {
        return "/system/main/noAuth";
    }

    /**
     * 处理错误页面
     */
    @RequestMapping("${server.error.path:${error.path:/error}}")
    public String handleError(Model model, HttpServletRequest request) {
        Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
        String errorMsg = "好像出错了呢!";
        if (statusCode == 404) {
            errorMsg = "页面找不到了!好像是去火星了~";
        }

        model.addAttribute("statusCode", statusCode);
        model.addAttribute("msg", errorMsg);
        return "/system/main/error";
    }
}

运行截图#

image-20230607151835654

image-20230607151851037

用户模块#

定义#

用户模块包括管理员登陆,学生登陆,教师登陆功能,不同用户选择不同身份登入系统享有不同权限,同时对密码等信息进行加密,非管理员无法查看其他用户信息,通过分配权限这一功能能够对用户权限管理实现精准化、在一定程度上保证了学生信息管理系统的安全性,学生可以查看班级同学的相关信息(密码等隐私因素已加密,非管理员用户无权查看),可以对自身信息进行修改或删除自己的记录并新增一条关于自己的个人信息记录。

功能介绍#

学生管理系统的用户模块是指用于管理系统中用户账户和权限的模块,主要包括以下功能:

  1. 用户注册:新用户可以通过注册功能在系统中创建账户,填写必填信息如用户名,密码等。同时,可以根据需要填写其他个人信息如姓名,联系方式等。
  2. 用户登录:已注册用户可以通过登录功能进入系统,使用自己的账号和密码进行身份验证。登录成功后,用户即可使用系统中的其他功能。
  3. 用户信息管理:已登录用户可以查看和修改自己的个人信息,如修改联系方式等。
  4. 权限管理:系统管理员可以对不同用户的权限进行设置,包括用户的操作权限和数据访问权限等。管理员可以根据需求设置不同的权限等级,以保证系统的安全性和数据的保密性。
  5. 用户查询:已登录用户可以使用系统中提供的查询功能,查询自己的个人信息和相关记录,如成绩查询,选课记录等。
  6. 用户注销:已登录用户可以通过注销功能退出系统,保护自己的账户安全。

核心代码 (实现类)#

package com.linln.modules.system.domain;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.linln.common.enums.StatusEnum;
import com.linln.common.utils.StatusUtil;
import com.linln.component.excel.annotation.Excel;
import com.linln.component.excel.enums.ExcelType;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

@Data
@Entity
@Table(name = "sys_user")
@ToString(exclude = {"dept", "roles"})
@EqualsAndHashCode(exclude = {"dept", "roles"})
@EntityListeners(AuditingEntityListener.class)
@SQLDelete(sql = "update sys_user" + StatusUtil.SLICE_DELETE)
@Where(clause = StatusUtil.NOT_DELETE)
@Excel("用户数据")
public class User implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Excel(value = "用户ID", type = ExcelType.EXPORT)
    private Long id;
    @Excel("用户名")
    private String username;
    @JsonIgnore
    private String password;
    @JsonIgnore
    private String salt;
    @Excel("昵称")
    private String nickname;
    private String picture;
    @Excel(value = "性别", dict = "USER_SEX")
    private Byte sex;
    @Excel("手机号码")
    private String phone;
    @Excel("电子邮箱")
    private String email;
    @CreatedDate
    @Excel("创建时间")
    private Date createDate;
    @LastModifiedDate
    @Excel("更新时间")
    private Date updateDate;
    @Excel("备注")
    private String remark;
    @Excel(value = "状态", dict = "DATA_STATUS")
    private Byte status = StatusEnum.OK.getCode();

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "dept_id")
    @JsonIgnore
    private Dept dept;

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "sys_user_role",
            joinColumns = @JoinColumn(name = "user_id"),
            inverseJoinColumns = @JoinColumn(name = "role_id"))
    @JsonIgnore
    private Set<Role> roles = new HashSet<>(0);
}

核心代码 (接口)#

package com.linln.modules.system.repository;

import com.linln.modules.system.domain.Dept;
import com.linln.modules.system.domain.User;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

import java.util.List;

public interface UserRepository extends BaseRepository<User, Long>, JpaSpecificationExecutor<User> {

    /**
     * 根据用户名查询用户数据
     * @param username 用户名
     * @return 用户数据
     */
    public User findByUsername(String username);

    /**
     * 根据用户名查询用户数据,且排查指定ID的用户
     * @param username 用户名
     * @param id 排除的用户ID
     * @return 用户数据
     */
    public User findByUsernameAndIdNot(String username, Long id);

    /**
     * 查找多个相应部门的用户列表
     * @param dept 部门对象
     * @return 用户列表
     */
    public List<User> findByDept(Dept dept);

    /**
     * 删除多条数据
     * @param ids ID列表
     * @return 影响行数
     */
    public Integer deleteByIdIn(List<Long> ids);
}

运行截图#

image-20230608085049154

菜单模块#

定义#

学生管理系统的菜单模块是指系统中提供的菜单栏,用于方便用户浏览和使用系统中的各个功能模块,

功能#

  1. 菜单项分类:系统中的各个功能模块可以按照不同的分类进行归类,如学生信息管理、教师信息管理、课程管理、成绩管理等,方便用户查找和使用。
  2. 菜单项排序:系统中的菜单项可以按照用户的使用频率或者重要程度进行排序,让用户更加方便地找到需要使用的功能。
  3. 菜单项展开:系统中可以提供菜单项展开和折叠功能,当某一分类下的菜单项过多时,可以折叠部分菜单项,以减少用户的视觉负担。
  4. 菜单项图标:系统中的菜单项可以添加图标,方便用户根据图标识别功能,提高用户的使用体验。
  5. 菜单项权限控制:对于不同的用户,系统中的菜单项的显示和可用性可能会有所不同,需要根据用户的权限进行控制,以保证系统的安全性和数据的保密性。
  6. 菜单项搜索:当系统中的菜单项过多时,用户可以使用菜单项搜索功能,通过输入关键词或者名称来搜索需要的功能模块,提高用户的使用效率。
  7. 菜单项快捷键:对于某些经常使用的功能模块,系统可以为其设置快捷键,让用户通过键盘操作快速进入对应的功能模块,提高用户的使用效率。
  8. 菜单项定制:系统中的菜单项可以根据用户需要进行定制,用户可以将自己经常使用的菜单项添加到快捷菜单中,方便快速访问。
  9. 菜单项国际化:对于一些国际化的学生管理系统,菜单项还可以根据用户的语言环境进行自动切换,提高跨国使用的便利性和用户体验。
  10. 菜单项分组:对于一些大型的学生管理系统,菜单项可以按照不同的分组进行分类,如学生管理、教师管理、课程管理等,以便于用户管理和使用。
  11. 菜单项扩展:当学生管理系统需要添加新的功能模块时,菜单模块可以提供扩展功能,让管理员能够方便地添加新的菜单项和功能模块。

核心代码 (实现类)#

package com.linln.modules.system.domain;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.linln.common.enums.StatusEnum;
import com.linln.common.utils.StatusUtil;
import lombok.*;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
import org.hibernate.annotations.Where;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.io.Serializable;
import java.util.*;

@Data
@Entity
@Table(name = "sys_menu")
@ToString(exclude = {"roles", "createBy", "updateBy"})
@EqualsAndHashCode(exclude = {"roles", "createBy", "updateBy"})
@EntityListeners(AuditingEntityListener.class)
@Where(clause = StatusUtil.NOT_DELETE)
public class Menu implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long pid;
    private String pids;
    private String title;
    private String url;
    private String perms;
    private String icon;
    private Byte type;
    private Integer sort;
    private String remark;
    @CreatedDate
    private Date createDate;
    @LastModifiedDate
    private Date updateDate;
    @CreatedBy
    @ManyToOne(fetch = FetchType.LAZY)
    @NotFound(action = NotFoundAction.IGNORE)
    @JoinColumn(name = "create_by")
    @JsonIgnore
    private User createBy;
    @LastModifiedBy
    @ManyToOne(fetch = FetchType.LAZY)
    @NotFound(action = NotFoundAction.IGNORE)
    @JoinColumn(name = "update_by")
    @JsonIgnore
    private User updateBy;
    private Byte status = StatusEnum.OK.getCode();

    @ManyToMany(mappedBy = "menus")
    @JsonIgnore
    private Set<Role> roles = new HashSet<>(0);

    @Transient
    @JsonIgnore
    private Map<Long, Menu> children = new HashMap<>();

    public Menu(){

    }

    public Menu(Long id, String title, String pids) {
        this.id = id;
        this.title = title;
        this.pids = pids;
    }

    public void setPids(String pids) {
        if (pids.startsWith(",")){
            pids = pids.substring(1);
        }
        this.pids = pids;
    }
}

核心代码 (接口)#

package com.linln.modules.system.repository;

import com.linln.common.constant.StatusConst;
import com.linln.modules.system.domain.Menu;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

public interface MenuRepository extends BaseRepository<Menu, Long> {

    /**
     * 查找多个菜单
     * @param ids id列表
     * @return 菜单列表
     */
    public List<Menu> findByIdIn(List<Long> ids);

    /**
     * 查找响应状态的菜单
     * @param sort 排序对象
     * @param status 数据状态
     * @return 菜单列表
     */
    public List<Menu> findAllByStatus(Sort sort, Byte status);

    /**
     * 查询菜单URL
     * @param url id列表
     * @return 菜单信息
     */
    public Menu findByUrl(String url);

    /**
     * 根据父ID查找子菜单
     * @param pids pid列表
     * @param status 数据状态
     * @return 菜单列表
     */
    public List<Menu> findByPidsLikeAndStatus(String pids, Byte status);

    /**
     * 获取排序最大值
     * @param pid 父菜单ID
     * @return 最大值
     */
    @Query("select max(sort) from Menu m where m.pid = ?1 and m.status <> " + StatusConst.DELETE)
    public Integer findSortMax(long pid);

    /**
     * 根据父级菜单ID获取本级全部菜单
     * @param sort 排序对象
     * @param pid 父菜单ID
     * @param notId 需要排除的菜单ID
     * @return 菜单列表
     */
    public List<Menu> findByPidAndIdNot(Sort sort, long pid, long notId);

    /**
     * 取消菜单与角色之间的关系
     * @param id 菜单ID
     * @return 影响行数
     */
    @Modifying
    @Transactional
    @Query(value = "DELETE FROM sys_role_menu WHERE menu_id = ?1", nativeQuery = true)
    public Integer cancelRoleJoin(Long id);
}

运行截图#

image-20230608085516770

部门模块#

定义#

学生管理系统的部门模块是指用于管理系统中部门信息的模块。

功能#

  1. 部门信息维护:系统管理员可以通过部门模块添加、编辑和删除部门信息,包括部门名称、描述、负责人等信息。
  2. 部门人员管理:管理员可以在部门模块中添加、编辑和删除部门人员信息,包括姓名、职位、联系方式等信息。同时,管理员可以将一个或多个人员分配到一个或多个部门中。
  3. 部门权限管理:管理员可以通过部门模块为每个部门设置相应的权限,包括访问权限和操作权限等。这样可以保证部门之间的数据安全和隔离。
  4. 部门数据查询:已登录用户可以使用部门模块提供的查询功能,查询自己所在的部门信息和相关记录,如部门人员信息、部门项目进度等。
  5. 部门报表生成:通过部门模块,管理员可以生成部门相关的报表,如人员结构报表、项目进度报表等。这些报表可以帮助管理员更好地了解和管理部门的情况。
  6. 部门协作:通过部门模块,不同部门之间可以进行协作,例如共享文件、交流信息、合作开展项目等,以提高工作效率和协同能力。
  7. 部门日志记录:通过部门模块,系统可以记录部门相关的操作日志,包括部门信息的添加、编辑和删除,以便于管理员了解部门的操作历史和追溯问题。

核心代码 (实现类)#

package com.linln.modules.system.domain;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.linln.common.enums.StatusEnum;
import com.linln.common.utils.StatusUtil;
import lombok.Data;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
import org.hibernate.annotations.Where;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;

@Data
@Entity
@Table(name = "sys_dept")
@EntityListeners(AuditingEntityListener.class)
@Where(clause = StatusUtil.NOT_DELETE)
public class Dept implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    /** 部门名称 */
    private String title;

    /** 父级编号 */
    private Long pid;

    /** 所有父级编号 */
    private String pids;

    /** 排序 */
    private Integer sort;

    /** 备注 */
    private String remark;

    /** 创建时间 */
    @CreatedDate
    private Date createDate;

    /** 更新时间 */
    @LastModifiedDate
    private Date updateDate;

    /** 创建者 */
    @CreatedBy
    @ManyToOne(fetch = FetchType.LAZY)
    @NotFound(action = NotFoundAction.IGNORE)
    @JoinColumn(name = "create_by")
    @JsonIgnore
    private User createBy;

    /** 更新者 */
    @LastModifiedBy
    @ManyToOne(fetch = FetchType.LAZY)
    @NotFound(action = NotFoundAction.IGNORE)
    @JoinColumn(name = "update_by")
    @JsonIgnore
    private User updateBy;

    /** 数据状态 */
    private Byte status = StatusEnum.OK.getCode();
}

核心代码 (接口)#

package com.linln.modules.system.repository;

import com.linln.common.constant.StatusConst;
import com.linln.modules.system.domain.Dept;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.Query;

import java.util.List;

public interface DeptRepository extends BaseRepository<Dept, Long> {

    /**
     * 查找多个部门
     * @param ids id列表
     * @return 部门列表
     */
    public List<Dept> findByIdIn(List<Long> ids);

    /**
     * 获取排序最大值
     * @param pid 父部门ID
     * @return 最大值
     */
    @Query("select max(sort) from Menu m where m.pid = ?1 and m.status <> " + StatusConst.DELETE)
    public Integer findSortMax(long pid);

    /**
     * 根据父ID查找子孙部门
     * @param pids pid列表
     * @param status 数据状态
     * @return 部门列表
     */
    public List<Dept> findByPidsLikeAndStatus(String pids, Byte status);

    /**
     * 根据父级部门ID获取本级全部部门
     * @param sort 排序对象
     * @param pid 父部门ID
     * @param notId 需要排除的部门ID
     * @return 部门列表
     */
    public List<Dept> findByPidAndIdNot(Sort sort, long pid, long notId);
}


运行截图#

image-20230608085533710

日志模块#

定义#

学生管理系统的日志模块是指用于记录系统中各种操作的日志信息

功能#

  1. 日志记录:系统管理员可以通过日志模块记录系统中的各种操作,例如用户登录、数据修改、系统设置等,以便于管理员了解系统的运行情况和问题。
  2. 日志查询:已登录用户可以使用日志模块提供的查询功能,查询自己或其他用户的操作记录,以便于了解自己或其他用户的操作历史和行为。
  3. 日志分析:通过日志模块,管理员可以对系统中的操作日志进行分析,以便于了解系统的使用情况和问题。例如,可以对用户的登录次数、数据修改次数等进行统计分析,以便于评估系统的安全性和稳定性。
  4. 日志备份:为了保证系统数据的安全性,日志模块可以提供备份功能,定期备份系统中的操作日志,以便于在系统出现问题时进行数据恢复和追溯操作历史。
  5. 日志报表生成:通过日志模块,管理员可以生成系统操作日志的报表,以便于管理和分析操作记录。报表可以按照不同的时间段、用户、操作类型等进行分类和统计分析。
  6. 日志审计:通过日志模块,管理员可以对系统中的操作日志进行审计,以便于发现和解决潜在的安全问题和漏洞。
  7. 日志过滤:通过日志模块,管理员可以根据不同的关键词进行过滤,以便于筛选出特定的操作记录。例如,可以根据用户姓名、操作类型、时间范围等进行过滤。
  8. 日志安全:为了保证日志记录的安全性和隐私性,日志模块可以提供一些安全措施,如加密、权限控制等,以防止未经授权的用户进行非法操作和篡改操作记录。

核心代码(实现类)#

package com.linln.modules.system.domain;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;

@Data
@Entity
@Table(name="sys_action_log")
@EntityListeners(AuditingEntityListener.class)
public class ActionLog implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private Byte type;
    private String ipaddr;
    private String clazz;
    private String method;
    private String model;
    private Long recordId;
    @Lob @Column(columnDefinition="TEXT")
    private String message;
    @CreatedDate
    private Date createDate;
    @ManyToOne(fetch=FetchType.LAZY)
    @NotFound(action=NotFoundAction.IGNORE)
    @JoinColumn(name="oper_by")
    @JsonIgnore
    private User operBy;
    private String operName;

    public ActionLog(){}
    /**
     * 封装日志对象
     * @param name 日志名称
     * @param message 日志消息
     */
    public ActionLog(String name, String message){
        this.name = name;
        this.message = message;
    }
}

核心代码 (接口)#

package com.linln.modules.system.repository;

import com.linln.modules.system.domain.ActionLog;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface ActionLogRepository extends JpaRepository<ActionLog, Long> {

    /**
     * 根据模型和数据ID查询日志列表
     * @param model 模型(表名)
     * @param recordId 数据ID
     * @return 日志列表
     */
    public List<ActionLog> findByModelAndRecordId(String model, Long recordId);
}

运行截图#

image-20230608085724889

实训总结#

Spring Boot是一个开源框架,旨在简化Java应用程序的创建、部署、运行。它的主要目的是快速构建生产级的应用程序,减少配置文件的数量,简化配置过程。通过使用Spring Boot,开发人员可以快速构建 Web 应用程序,使用其内置的Tomcat服务器,不需要手动配置任何东西,可以立即启动。

实训中,我们学习了如何使用Spring Boot构建Web应用程序,包括如何使用Spring MVC构建RESTful Web服务,如何使用Spring Data JPA进行数据持久化,如何使用Thymeleaf渲染HTML模板,以及如何使用Spring Security提供安全性。

总的来说,Spring Boot是一个非常强大的框架,它的简化配置和快速开发特性被广泛应用于Web开发领域。对于开发人员来说,使用Spring Boot可以减少开发时间,提高生产力,同时也提升了代码质量。

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。