全网最详细的SpringBoot管理系统开发教程

此文章适用于 学生管理系统成绩管理系统在线考试系统图书管理系统 等,提供源码下载。

在这里插入图片描述技术架构:Java + SpringBoot + Vue3 + MySQL

一、项目搭建

1.1 开发工具

2024年了,我们就不考虑Eclipse了好吧,直接下载IDEA社区版。
下载地址:https://www.jetbrains.com/idea/download/other.html

1.2 环境配置

1.2.1 JDK

(1)下载JDK1.8 windows64位安装版:https://tool4j.com/files/software/jdk-8u102-windows-x64.exe
(2)安装及环境变量配置:https://blog.csdn.net/i_for/article/details/131128502

1.2.2 Maven

(1)下载Maven3.6.3:https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.zip
(2)配置教程:https://www.cnblogs.com/yu-si/p/14586626.html

1.2.3 MySQL

安装配置教程:https://blog.csdn.net/fattigers/article/details/135558127

1.2.4 NodeJs

下载Nodejs16.20.2:https://nodejs.org/dist/v16.20.2/node-v16.20.2-x64.msi
安装教程:没什么特别的步骤,无脑下一步即可,会自动配置好环境变量

1.3 模板工程下载

在这里插入图片描述

目前后台管理系统用的比较多的模板工程一般是若依,或者是基于若依改造而来的,虽然若依这套框架存在很多问题,但是对于初学者或者小公司来说,确实可以减少很多工作量,还是有可取之处的。
博主使用的模板工程是:youlai-boot,并进行了优化,删除了大量冗余代码,更易于初学者使用,有需要的可以通过Gitee下载。

前端项目地址:https://gitee.com/dwp1216/boot4j_ui.git
后台项目地址:https://gitee.com/dwp1216/boot4j.git

二、数据库表设计

基础工程所需的数据库表SQL文件已经放在项目根目录 /src/resources/sql 下了。
系统内置表如下:

create table sys_menu
(
  id          bigint auto_increment
  primary key,
  parent_id   bigint                  not null comment '父菜单ID',
  tree_path   varchar(255)            null comment '父节点ID路径',
  name        varchar(64)  default '' not null comment '菜单名称',
  type        tinyint                 not null comment '菜单类型(1:菜单 2:目录 3:外链 4:按钮)',
  path        varchar(128) default '' null comment '路由路径(浏览器地址栏路径)',
  component   varchar(128)            null comment '组件路径(vue页面完整路径,省略.vue后缀)',
  perm        varchar(128)            null comment '权限标识',
  visible     tinyint(1)   default 1  not null comment '显示状态(1-显示;0-隐藏)',
  sort        int          default 0  null comment '排序',
  icon        varchar(64)  default '' null comment '菜单图标',
  redirect    varchar(128)            null comment '跳转路径',
  create_time datetime                null comment '创建时间',
  update_time datetime                null comment '更新时间',
  always_show tinyint                 null comment '【目录】只有一个子路由是否始终显示(1:是 0:否)',
  keep_alive  tinyint                 null comment '【菜单】是否开启页面缓存(1:是 0:否)'
)
    comment '菜单管理' charset = utf8mb3;

create table sys_role
(
  id        bigint auto_increment comment '主键id'
  primary key,
  role_code varchar(100)                       null comment '角色标识',
  role_name varchar(100)                       null comment '角色名称',
  remark    varchar(255)                       null comment '描述',
  create_by varchar(100)                       null comment '创建人',
  create_at datetime default CURRENT_TIMESTAMP null comment '创建时间',
  update_by varchar(100)                       null comment '修改人',
  update_at datetime                           null on update CURRENT_TIMESTAMP comment '修改时间'
)
    comment '系统管理-角色信息表' collate = utf8mb4_bin;

create table sys_role_permission
(
  id            bigint auto_increment comment '主键id'
  primary key,
  resource_id   bigint                             null comment '资源ID',
  resource_type varchar(100) charset utf8mb4       null comment '资源类型(menu:菜单、btn:按钮、api:服务)',
  role_id       bigint                             null comment '角色ID',
  create_by     varchar(100) charset utf8mb4       null comment '创建人',
  create_at     datetime default CURRENT_TIMESTAMP null comment '创建时间',
  update_by     varchar(100) charset utf8mb4       null comment '修改人',
  update_at     datetime                           null on update CURRENT_TIMESTAMP comment '修改时间'
)
    comment '系统管理-角色权限表' collate = utf8mb4_bin;

create table sys_user
(
  id           bigint auto_increment comment '主键'
  primary key,
  user_id      bigint                              null comment '用户ID',
  account      varchar(255)                        null comment '账号',
  password     varchar(255)                        null comment '密码',
  role_id      bigint                              null comment '角色ID',
  created_date timestamp default CURRENT_TIMESTAMP null,
  updated_date datetime                            null on update CURRENT_TIMESTAMP comment '修改时间'
)
    comment '系统管理-用户信息表' charset = utf8mb4;

create table sys_user_detail
(
  id           bigint auto_increment comment '主键'
  primary key,
  user_id      bigint                              null comment '用户ID',
  username     varchar(255)                        null comment '用户名',
  avatar       varchar(255)                        null comment '头像',
  sex          varchar(10)                         null comment '性别:1-男、0-女、2-保密',
  age          int                                 null comment '年龄',
  region       varchar(255)                        null comment '地区',
  remark       varchar(255)                        null comment '简介',
  created_date timestamp default CURRENT_TIMESTAMP null,
  updated_date datetime                            null on update CURRENT_TIMESTAMP comment '修改时间',
  phone_num    varchar(255)                        null comment '手机号',
  email        varchar(255)                        null comment '邮箱'
)
    comment '系统管理-用户详情信息表' charset = utf8mb4;

在设计数据库表时,我们可以按如下思路来设计:

  1. 根据需求先设计出有哪些对象,一个对象就是一张表
  2. 对象之间的关联关系

(1) 如果是一对一、一对多的关系,就在对象表上增加另一个对象的ID字段来关联
(2) 如果是多对多的关系,建议使用单独的关系表来保存关联关系

  1. 对于比较通用的信息,建议使用更加通用的对象表来存储,例如文件信息表、用户消息表。

三、模板代码生成

表结构设计好以后,可通过 代码生成器 一键生成代码。image.png
复制或者上传sql文件,即可一键生成。
生成后点击下载,会下载一个zip压缩包,解压之后放到src/main/java目录下即可使用。

四、功能实现

4.1 登录认证功能

对于小型项目,我们可以使用Spring提供的 HandlerInterceptor拦截前端请求,进行登录认证。

  1. 首先创建一个拦截器类SecurityInterceptor:
import com.privacy.guard.util.UserPermission;
import com.privacy.guard.util.security.AuthUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

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

@Component
@Slf4j
public class SecurityInterceptor implements HandlerInterceptor {

    @Autowired
    private AuthUtil authUtil;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        return authUtil.verify(request);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {
        UserPermission.remove();
        UserPermission.removeToken();
    }

}
  1. AuthUtil 校验工具类:
import com.privacy.guard.util.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;

@Component
@Slf4j
public class AuthUtil {

    public boolean verify(HttpServletRequest request) {
        try {
            String token = request.getHeader("Authorization");
            if (token.startsWith("Bearer ")) {
                token = token.substring(7);
            }
            Long userId = JwtUtil.verify(token);
            Assert.notNull(userId, "Token不合法,请勿非法访问");
            return true;
        } catch (Exception e) {
            String requestURI = request.getRequestURI();
            log.error("鉴权未通过, 请求地址 = {}", requestURI, e);
            throw new RuntimeException(e.getMessage());
        }
    }

}
  1. JwtUtil 生成 Token 工具类:
import cn.hutool.json.JSONUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.InvalidClaimException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;

import java.util.Map;

@Slf4j
public class JwtUtil {

    private static final Algorithm key = Algorithm.HMAC256("abcdjhtsrgarehdgjheras");

    /**
     * 生成Token
     *
     * @return
     */
    public static String createToken(Long userId) {
        String sign = JWT.create()
        .withClaim("userId", userId)
        .sign(key);
        return sign;
    }

    /**
     * 验证Token
     *
     * @param jwtStr
     * @return
     */
    public static Long verify(String jwtStr) {
        JWTVerifier build = JWT.require(key).build();
        try {
            //验签
            DecodedJWT verify = build.verify(jwtStr);
            byte[] bytes = Base64.decodeBase64(verify.getPayload());
            String json = new String(bytes);
            return Long.parseLong(JSONUtil.toBean(json, Map.class).get("userId").toString());
        } catch (AlgorithmMismatchException e) {
            //算法错误
            log.error("加密算法和解密算法不一致");
        } catch (SignatureVerificationException e) {
            //验签失败,验签pwd密码错误
            log.error("解密密码错误");
        } catch (TokenExpiredException e) {
            //token过期
            log.error("Token过期");
        } catch (InvalidClaimException e) {
            //获取不到对应的负荷信息
            log.error("获取不到对应的负荷信息");
        } catch (Exception e) {
            log.error("未获取到正确的userId", e);
        }
        return null;
    }

}
  1. 然后创建一个WebConfig类,继承WebMvcConfigurer,实现请求拦截与过滤配置
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private SecurityInterceptor securityInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        /**
        * 所有 /api 开头的接口会被 securityInterceptor 拦截器拦截
        * 所有 /auth 开头的接口会被 securityInterceptor 拦截器拦截
        * 所有 /api/auth 开头的接口不会被拦截
        */
        registry.addInterceptor(securityInterceptor)
        .addPathPatterns("/api/**")
        .addPathPatterns("/auth/**")
        .excludePathPatterns("/api/auth/**");
    }

}

4.2 菜单权限控制

在模板工程中,我们已经定义好了菜单表的结构,根据用户权限,查询出用户具有的菜单集合,并进行组装,形成菜单树。(完整代码可下载源码查看)

/**
 * 获取路由列表
 */
@Override
public List<RouteVO> listRoutes() {
    SysUser user = userService.findByUserId(UserPermission.get());
    List<RouteBO> menuList = sysMenuMapper.listRoutes(user.getRoleId());
    return buildRoutes(Constants.ROOT_NODE_ID, menuList);
}

/**
 * 递归生成菜单路由层级列表
 *
 * @param parentId 父级ID
 * @param menuList 菜单列表
 * @return 路由层级列表
 */
private List<RouteVO> buildRoutes(Long parentId, List<RouteBO> menuList) {
    List<RouteVO> routeList = new ArrayList<>();
    for (RouteBO menu : menuList) {
        if (menu.getParentId().equals(parentId)) {
            RouteVO routeVO = toRouteVo(menu);
            List<RouteVO> children = buildRoutes(menu.getId(), menuList);
            if (!children.isEmpty()) {
                routeVO.setChildren(children);
            }
            routeList.add(routeVO);
        }
    }
    return routeList;
}

/**
 * 根据RouteBO创建RouteVO
 */
private RouteVO toRouteVo(RouteBO routeBO) {
    RouteVO routeVO = new RouteVO();
    String routeName = StringUtils.capitalize(StrUtil.toCamelCase(routeBO.getPath().replaceAll("-", "_")));  // 路由 name 需要驼峰,首字母大写
    routeVO.setName(routeName); // 根据name路由跳转 this.$router.push({name:xxx})
    routeVO.setPath(routeBO.getPath()); // 根据path路由跳转 this.$router.push({path:xxx})
    routeVO.setRedirect(routeBO.getRedirect());
    routeVO.setComponent(routeBO.getComponent());
    
    RouteVO.Meta meta = new RouteVO.Meta();
    meta.setTitle(routeBO.getName());
    meta.setIcon(routeBO.getIcon());
    meta.setRoles(routeBO.getRoles());
    meta.setHidden(StatusEnum.DISABLE.getValue().equals(routeBO.getVisible()));
    // 【菜单】是否开启页面缓存
    if (MenuTypeEnum.MENU.getValue().equals(routeBO.getType())
        && routeBO.getKeepAlive() != null && 1 == routeBO.getKeepAlive()) {
        meta.setKeepAlive(true);
    }
    // 【目录】只有一个子路由是否始终显示
    if (MenuTypeEnum.CATALOG.getValue().equals(routeBO.getType())
        && routeBO.getAlwaysShow() != null && 1 == routeBO.getAlwaysShow()) {
        meta.setAlwaysShow(true);
    }
    routeVO.setMeta(meta);
    return routeVO;
}

五、源码下载

前端项目地址:https://gitee.com/dwp1216/boot4j_ui.git
后台项目地址:https://gitee.com/dwp1216/boot4j.git

  • 24
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本图书管理系统总体上分为前台页面显示和后台管理。 前台页面(即本书图书管理系统的首页)实现了公告的显示,图书查询,留言建议三大主要功能,有读者规则查看功能,师生们可以看到图书管理人员发布的最新公告信息,并可以查询自己感兴趣的图书,查看留言提议,用户登录后还有个人资料修改、个人借阅信息查询、个人违章信息查询等功能,也可以给学校的图书管理人员留言提议。 后台的页面则集成了图书管理中所需的功能,分成图书管理人员和系统管理人员,平时管理人员的工作都是在后台中完成的。前台是为了师生显示的。相对应的后台是针对学校图书管理人员,后台的页面都加密,如果不正常登录是进入不了后台管理页面的,后台图书管理人员功能包括:借阅图书、归还图书、借书记录显示与查找、还书记录显示与查找、公告增删改查;后台系统管理员功能包括:对书籍的增删改查、对书籍分类的增删改、对借阅证的增删改查、对借阅信息的显示与查找、对借阅规则的增删改、对图书管理员的增删改、对近期借阅书籍数量的折线图显示,以及对这些表格数据进行Excel表格的输出 共包含三个大模块:用户、图书管理员、系统管理员 一、用户模块 查看公告:能看到图书管理员发布的公告信息。 图书查看:分页显示,能看到图书总览,能通过图书编号、图书名称、作者、存放位置、图书描述进行模糊查询 个人违章信息(登录后):个人历史违章信息与查询 图书馆读者留言(登录后):对图书馆的建议,或对书籍的评价 查看借阅规则:不同的规则有不同的借阅限定数量、限定时间、超期费用 个人信息(登录后):对个人信息的查看与登录密码的修改 个人借阅信息(登录后):对个人借阅记录的分页查看与查询 二、图书管理员模块 借还图书:帮助用户借阅图书,并判断符不符合借阅规则、返还图书时判断有没有超期,超期则输出超期费用再归还 借阅报表:分页显示所有借阅记录、能进行查询和输出结果到excel公告管理:能添加编辑和删除公告 还书报表:分页显示所有未还的书籍,能通过借阅证号、图书编号、借阅日期、截止日期等条件进行模糊查询 个人信息修改:修改个人信息、密码等 三、系统管理员模块 书籍管理:分页,新添图书,设置图书各种信息,编辑删除,通过编号、书名、作者、描述等进行搜索,输出结果到excel,并且能查看该书籍被谁借阅过。 分类管理:分页显示,增删改书籍分类,书籍分类方便查阅整理 借阅证管理:分页显示所有借阅证,增删改查用户借阅证,查看该借阅证所有的借阅记录 借阅规则管理:能显示、编辑、删除所有借阅规则,借阅规则将决定该图书证能借阅什么图书馆的图书,能借多少本,能借多久以及超期每天的费用。 借阅信息查询:分页显示,能条件查询超期没还的,根据编号、借阅证号、书籍编号、借阅日期等进行模糊查询,输出结果到excel等,系统管理员只能查询,不能增删改借阅信息,这个操作由图书管理员操作。 图书管理员管理:对图书管理员进行增删改操作,但是不能修改原来的账号 图书借阅统计:通过折线图将图书馆近30天的每天借阅书籍数量直观的显示出来。 sql表 共有十张数据库表,书籍表、借书记录表、留言表、系统管理员表、借阅证表、图书管理管理员表书籍分类表、图书馆表、借阅规则表、公告表 书籍表 编号、姓名、作者、存放的图书馆、分类编号、存放位置、是否借出、书籍描述 借书记录表 编号、借阅证编号、书籍编号、借书日期、限制日期、归还日期、违规描述、处理人编号 留言表 编号、借阅证编号、留言内容、留言日期 系统管理员表 账号、密码 借阅证表 编号、密码、借阅者姓名、规则编号、状态(丢失、可用) 图书管理员表 编号、姓名、账号、密码、邮箱 书籍分类表 编号、分类名、分类描述 图书馆表 编号、图书馆名、描述 规则表 编号、限制借阅数量、限制借阅天数、图书超期每天费用 公告表 编号、标题、公告内容、发布日期
当前课程中博客项目的实战源码是我在 GitHub上开源项目 My-Blog,目前已有 3000 多个 star:本课程是一个 Spring Boot 技术栈的实战类课程,课程共分为 3 大部分,前面两个部分为基础环境准备和相关概念介绍,第三个部分是 Spring Boot 个人博客项目功能的讲解,通过本课程的学习,不仅仅让你掌握基本的 Spring Boot 开发能力以及 Spring Boot 项目的大部分开发使用场景,同时帮你提前甄别和处理掉将要遇到的技术难点,认真学完这个课程后,你将会对 Spring Boot 有更加深入而全面的了解,同时你也会得到一个大家都在使用的博客系统源码,你可以根据自己的需求和想法进行改造,也可以直接使用它来作为自己的个人网站,这个课程一定会给你带来巨大的收获。作者寄语本课程录制于 2020 年,代码基于 Spring Boot 2.x 版本。到目前为止,Spring Boot 技术栈也有一些版本升级,比如 Spring Boot 2.7 发版、Spring Boot 3.x 版本发布正式版本。对于这些情况,笔者会在本课程实战项目的开源仓库中创建不同的代码分支,保持实战项目的源码更新,保证读者朋友们不会学习过气的知识点。课程特色 课程内容紧贴 Spring Boot 技术栈,涵盖大部分 Spring Boot 使用场景。开发教程详细完整、文档资源齐全、实验过程循序渐进简单明了。实践项目页面美观且实用,交互效果完美。包含从零搭建项目、以及完整的后台管理系统和博客展示系统两个系统的功能开发流程。技术栈新颖且知识点丰富,学习后可以提升大家对于知识的理解和掌握,对于提升你的市场竞争力有一定的帮助。实战项目预览    
对于全网详细的VSCode教程,以下是一个简短的描述: 全网详细的VSCode教程应该包含以下内容:基本介绍、安装和设置、编辑器布局、常用快捷键、实用插件和扩展、调试功能、版本控制、代码片段等。 在基本介绍部分,应该详细介绍VSCode是什么,它的优点和特点,如何下载和安装等。 安装和设置部分应该涵盖不同操作系统上的安装步骤和注意事项。同时,还应该介绍不同配置选项,如主题、字体、缩进设置等。 编辑器布局部分应该解释各个面板和视图的作用,如侧边栏、编辑窗口、终端等。详细说明如何调整布局以优化工作流程。 常用快捷键部分应该列举常用的快捷键和相关操作,如快速打开文件、搜索、查看定义等。应该对不同功能区分操作系统进行说明。 实用插件和扩展部分应该介绍一些常见和有用的插件,如代码片段、代码格式化、调试器等。应该详细解释如何安装和使用这些插件。 调试功能部分应该详细介绍如何配置和使用调试器,包括设置断点、查看变量的值等。 版本控制部分应该介绍如何使用内置的版本控制工具,如Git,如何提交、推送和拉取代码等。 最后,代码片段部分应该教授如何创建和使用代码片段,以提高编码效率。 以上仅是对全网详细的VSCode教程的一些简要描述。当然,真正最详细教程可能比这个更加全面和详细,具体内容可能还包括更多高级功能和技巧。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值