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

news2024/10/6 0:12:50

此文章适用于 学生管理系统成绩管理系统在线考试系统图书管理系统 等,提供源码下载。
技术架构: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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1857361.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java医院绩效考核系统源码:医院绩效考核的发展趋势、医院绩效考核的具体方法

java医院绩效考核系统源码&#xff1a;医院绩效考核的发展趋势、医院绩效考核的具体方法 医疗机构绩效考核是对医疗机构绩效进行评估和分析的一项重要工作。它对医疗机构的发展起到了重要的指导和推动作用。本文将会分析国际上医院绩效考核的发展趋势以及医院绩效考核的具体方…

全国青少年信息素养大赛图形化编程复赛小高组真题-附答案

2023年全国青少年信息素养大赛图形化编程复赛小高组真题 题目总数&#xff1a;6 总分数&#xff1a;100 编程题 第 1 题 问答题 编程实现&#xff1a; 按下空格&#xff0c;背景会随机变化&#xff0c;如果变成沙漠背景&#xff0c;骆驼就会出现。 具体要求&#x…

【C++】继承(定义、菱形继承、虚拟继承)

&#x1f308;个人主页&#xff1a;秦jh_-CSDN博客&#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/qinjh_/category_12575764.html?spm1001.2014.3001.5482 ​ 目录 继承的概念 继承定义 定义格式 继承关系和访问限定符 继承基类成员访问方式的变化 基类和…

【WEB前端2024】3D智体编程:乔布斯3D纪念馆-第46课-使用json文件

【WEB前端2024】3D智体编程&#xff1a;乔布斯3D纪念馆-第45课-使用头像 使用dtns.network德塔世界&#xff08;开源的智体世界引擎&#xff09;&#xff0c;策划和设计《乔布斯超大型的开源3D纪念馆》的系列教程。dtns.network是一款主要由JavaScript编写的智体世界引擎&…

Java版ERP管理系统源码解析:利用Spring Cloud Alibaba和Spring Boot实现微服务架构

在当今数字化浪潮的推动下&#xff0c;企业对于高效、稳定且易于扩展的管理系统需求日益增长。为了满足这一需求&#xff0c;我们精心打造了一款基于Java技术的鸿鹄ERP&#xff08;Enterprise Resource Planning&#xff09;管理系统。该系统充分利用了Spring Cloud Alibaba、S…

C# Web控件与数据感应之数据返写

目录 关于数据返写 准备视图 范例运行环境 ControlInducingFieldName 方法 设计与实现 如何根据 ID 查找控件 FindControlEx 方法 调用示例 小结 关于数据返写 数据感应也即数据捆绑&#xff0c;是一种动态的&#xff0c;Web控件与数据源之间的交互&#xff0c;数据…

达梦数据守护集群脑裂恢复

集群环境参考上篇 达梦数据守护集群部署 https://blog.csdn.net/qq_25045631/article/details/139900164 集群发散脑裂时&#xff0c;监视器显示如下&#xff0c;实例GRP1_RT_01发生脑裂 1. 关闭DW环境 因为Global守护类型的守护进程&#xff0c;会自动将数据库实例切换到O…

MySQL集群高可用架构之MySQL InnoDB Cluste

今天我将详细的为大家介绍Centos 7.5 基于 MySQL 5.7的 InnoDB Cluster 多节点高可用集群环境部署的相关知识&#xff0c;希望大家能够从中收获多多&#xff01;如有帮助&#xff0c;请点在看、转发支持一波&#xff01;&#xff01;&#xff01; 一、MySQL InnoDB Cluster 介…

【 华为OD机试】信号发射和接收(C++ Java JavaScript Python)

题目 题目描述 有一个二维的天线矩阵,每根天线可以向其他天线发射信号,也能接收其他天线的信号,为了简化起见,我们约定每根天线只能向东和向南发射信号,换言之,每根天线只能接收东向或南向的信号。 每根天线有自己的高度anth,每根天线的高度存储在一个二维数组中,各个天…

Web框架简介

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 如果你要从零开始建立了一些网站&#xff0c;可能会注意到你不得不反复解决一些类似的问题。这样做是令人厌烦的&#xff0c;并且违反了良好编程的核…

【系统架构设计师】四、嵌入式基础知识(软件|软件设计|硬件|式总线逻辑)

目录 一、嵌入式软件 1.1 嵌入式软件分类 1.2 板级支持包(BSP) 1.3 BootLoader 1.4 设备驱动程序 二、嵌入式软件设计 2.1 编码 2.2 交叉编译 2.3 交叉调试 三、嵌入式系统硬件的分类 3.1 根据用途分类 3.2 存储器分类 四、内&#xff08;外&#xff09;总线逻辑 …

苹果Mac系统安装adobe软件“无法打开install因为无法验证开发者”解决方法

对于大部分小伙伴&#xff0c;特别是从事视频后期、设计等专业的人来说&#xff0c;Adobe全家桶系列软件&#xff0c;相信都或多或少用过&#xff0c;比如Photoshop、Premiere、illustrator、Lightroom等等。这些软件不仅支持Windows系统&#xff0c;也完美适配于苹果Mac系统&a…

AcWing算法基础课笔记——动态规划之背包问题

背包问题 1. 01背包问题 解题思路&#xff1a; 题目 2. 01背包问题 - AcWing题库 代码 优化前&#xff1a; #include<iostream> #include<algorithm>using namespace std;const int N 1010;int n, m; int v[N], w[N]; int f[N][N];int main() {cin >> …

旋转机械振动信号特征提取(Python)

前缀 &#xff1a;将一维机械振动信号构造为训练集和测试集&#xff08;Python&#xff09; https://mp.weixin.qq.com/s/DTKjBo6_WAQ7bUPZEdB1TA import pandas as pd import numpy as np import scipy.io as sio import statistics_hamming from statistics_hamming import…

文华财经幅图指标公式大全源码

文华财经幅图指标公式大全源码下载&#xff1a; DIFF:EMA(CLOSE,55) - EMA(CLOSE,89),NODRAW; DEA: EMA(DIFF,9),NODRAW; MACD:2*(DIFF-DEA),NODRAW; DIFF1: EMA(CLOSE,12) - EMA(CLOSE,26),NODRAW; DEA1: EMA(DIFF1,9),NODRAW; MACD1:2*(DIFF1-DEA1),DOT,COLORYELLOW; DRAW…

Java | Leetcode Java题解之第188题买卖股票的最佳时机IV

题目&#xff1a; 题解&#xff1a; class Solution {public int maxProfit(int k, int[] prices) {if (prices.length 0) {return 0;}int n prices.length;k Math.min(k, n / 2);int[] buy new int[k 1];int[] sell new int[k 1];buy[0] -prices[0];sell[0] 0;for (…

【源码下载】宇宙星空

更多精彩内容尽在数字孪生平台&#xff0c;关注公众号【sky的数孪技术】&#xff0c;技术交流、源码下载请添加VX&#xff1a;digital_twin123 概述 用threejs和gsap实现的宇宙星空效果&#xff0c;访问 http://8.130.10.148:3000/digitaltwin/index.html&#xff0c;公众号后…

mybatis x插件的使用教程(详细)

MyBatisX 的主要功能 代码生成&#xff1a; 自动生成 MyBatis 的 Mapper、XML 配置文件和实体类&#xff0c;大大减少手工编写代码的工作量。 智能代码补全&#xff1a; 提供 SQL 语句和 MyBatis 配置的智能代码补全功能&#xff0c;使开发者能够更快地编写代码。 代码导航&…

怎样激励员工积极应用新版FMEA培训后的知识?

在快节奏的职场环境中&#xff0c;新版FMEA&#xff08;失效模式与影响分析&#xff09;的培训无疑是提升员工技能、优化工作流程的重要一环。然而&#xff0c;如何让员工积极地将所学知识应用于实际工作中&#xff0c;却是一个值得深入探讨的问题。下面&#xff0c;深圳天行健…

数据结构 —— 哈夫曼树

数据结构 —— 哈夫曼树 哈夫曼树定义构造算法特性应用 哈夫曼编码核心概念工作原理特点 我们今天来看哈夫曼树&#xff1a; 哈夫曼树 哈夫曼树&#xff08;Huffman Tree&#xff09;&#xff0c;是一种特殊的二叉树&#xff0c;由D.A. Huffman在1952年提出&#xff0c;主要用…