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可以減少開發時間,提高生產力,同時也提升了代碼質量。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。