BMS是一个后台管理系统,基于经典技术组合(Spring Boot、Apache、Shiro、MyBatis、Thymeleaf)主要目的是通过项目系统的学习运用,将公司以及社会发展需要同专业知识结合,注重专注业务,降低技术难度,从而节省人力成本,缩短项目周期,提高软件安全质量。
Spring Boot、Apache、Shiro、MyBatis、Thymeleaf
1、系统环境
Java EE 8
Servlet 3.0
Apache Maven 3
2、主框架
Spring Boot 2.2.x
Spring Framework 5.2.x
Apache Shiro 1.7
3、持久层
Apache MyBatis 3.5.x
Hibernate Validation 6.0.x
Alibaba Druid 1.2.x
4、视图层
Bootstrap 3.3.7
Thymeleaf 3.0.x
开发要求:
JDK >= 1.8
MySQL >= 5.7
Maven >= 3.0
Idea、Navicat、Typora、Postman、Apifox(国产)、Google
数据库
完全响应式布局(支持电脑、平板、手机等所有主流设备)
强大的一键生成功能(包括控制器、模型、视图、菜单等)
支持多数据源,简单配置即可实现切换。
支持按钮及数据权限,可自定义部门数据权限。
对常用js插件进行二次封装,使js代码变得简洁,更加易维护
完善的XSS防范及脚本过滤,彻底杜绝XSS攻击
Maven多项目依赖,模块及插件分项目,尽量松耦合,方便模块升级、增减模块。
国际化支持,服务端及客户端支持
完善的日志记录体系简单注解即可实现
支持服务监控,数据监控,缓存监控功能。
打包工程文件
在主项目的bin目录下执行package.bat打包Web工程,生成war/jar包文件。
然后会在项目下生成target文件夹包含war或jar
提示
多模块版本会生成在admin模块下target文件夹
部署工程文件
1、jar部署方式
使用命令行执行:java –jar XXX.jar 或者执行脚本:run.bat
2、war部署方式
主项目的pom.xml中的packaging修改为war,放入tomcat服务器webapps
<packaging>war</packaging>
提示
多模块版本在admin模块下修改pom.xml
SpringBoot去除内嵌Tomcat(PS:此步骤不重要,因为不排除也能在容器中部署war)
<!-- 多模块排除内置tomcat -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 单应用排除内置tomcat -->
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
如果提示当前权限不足,无法写入文件请检查application.yml中的profile路径或logback.xml中的log.path路径是否有可读可写操作权限
com.bms
├── common // 工具类
│ └── annotation // 自定义注解
│ └── config // 全局配置
│ └── constant // 通用常量
│ └── core // 核心控制
│ └── enums // 通用枚举
│ └── exception // 通用异常
│ └── json // JSON数据处理
│ └── utils // 通用类处理
│ └── xss // XSS过滤处理
├── framework // 框架核心
│ └── aspectj // 注解实现
│ └── config // 系统配置
│ └── datasource // 数据权限
│ └── interceptor // 拦截器
│ └── manager // 异步处理
│ └── shiro // 权限控制
│ └── web // 前端控制
├── bms-generator // 代码生成(不用可移除)
├── bms-system // 系统代码
├── bms-admin // 后台服务
├── bms-xxxxxx // 其他自定义功能模块
application.yml
# 项目相关配置
bms:
# 名称
name: lowkey
# 版本
version: 4.6.0
# 版权年份
copyrightYear: 2022
# 实例演示开关
demoEnabled: true
# 文件路径 示例( Windows配置D:/lowkey/uploadPath,Linux配置 /home/lowkey/uploadPath)
profile: D:/BMS/uploadPath
# 获取ip地址开关
addressEnabled: false
# 开发环境配置
server:
# 服务器的HTTP端口,默认为80
port: 80
servlet:
# 应用的访问路径
context-path: /
tomcat:
# tomcat的URI编码
uri-encoding: UTF-8
# tomcat最大线程数,默认为200
max-threads: 800
# Tomcat启动初始化的线程数,默认值25
min-spare-threads: 30
# 日志配置
logging:
level:
com.ruoyi: debug
org.springframework: warn
# 用户配置
user:
password:
# 密码错误{maxRetryCount}次锁定10分钟
maxRetryCount: 5
# Spring配置
spring:
# 模板引擎
thymeleaf:
mode: HTML
encoding: utf-8
# 禁用缓存
cache: false
# 资源信息
messages:
# 国际化资源文件路径
basename: static/i18n/messages
jackson:
time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
profiles:
active: druid
# 文件上传
servlet:
multipart:
# 单个文件大小
max-file-size: 10MB
# 设置总上传的文件大小
max-request-size: 20MB
# 服务模块
devtools:
restart:
# 热部署开关
enabled: true
# MyBatis
mybatis:
# 搜索指定包别名
typeAliasesPackage: com.bms.domain
# 配置mapper的扫描,找到所有的mapper.xml映射文件
mapperLocations: classpath*:mapper/**/*Mapper.xml
# 加载全局的配置文件
configLocation: classpath:mybatis/mybatis-config.xml
# PageHelper分页插件
pagehelper:
helperDialect: mysql
reasonable: true
supportMethodsArguments: true
params: count=countSql
# Shiro
shiro:
user:
# 登录地址
loginUrl: /login
# 权限认证失败地址
unauthorizedUrl: /unauth
# 首页地址
indexUrl: /index
# 验证码开关
captchaEnabled: true
# 验证码类型 math 数组计算 char 字符
captchaType: math
cookie:
# 设置Cookie的域名 默认空,即当前访问的域名
domain:
# 设置cookie的有效访问路径
path: /
# 设置HttpOnly属性
httpOnly: true
# 设置Cookie的过期时间,天为单位
maxAge: 30
# 设置密钥,务必保持唯一性(生成方式,直接拷贝到main运行即可)KeyGenerator keygen = KeyGenerator.getInstance("AES"); SecretKey deskey = keygen.generateKey(); System.out.println(Base64.encodeToString(deskey.getEncoded()));
cipherKey: zSyK5Kp6PZAAjlT+eeNMlg==
session:
# Session超时时间,-1代表永不过期(默认30分钟)
expireTime: 30
# 同步session到数据库的周期(默认1分钟)
dbSyncPeriod: 1
# 相隔多久检查一次session的有效性,默认就是10分钟
validationInterval: 10
# 同一个用户最大会话数,比如2的意思是同一个账号允许最多同时两个人登录(默认-1不限制)
maxSession: -1
# 踢出之前登录的/之后登录的用户,默认踢出之前登录的用户
kickoutAfter: false
# 防止XSS攻击
xss:
# 过滤开关
enabled: true
# 排除链接(多个用逗号分隔)
excludes: /system/notice/*
# 匹配链接
urlPatterns: /system/*,/monitor/*,/tool/*
# Swagger配置
swagger:
# 是否开启swagger
enabled: true
数据源配置 application-druid.yml
# 数据源配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
druid:
# 主库数据源
master:
url: jdbc:mysql://localhost:3306/bms?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: 123456
# 从库数据源
slave:
# 从数据源开关/默认关闭
enabled: false
url:
username:
password:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/*
# 控制台管理用户名和密码
login-username:
login-password:
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true
代码生成配置 generator.yml
# 代码生成
gen:
# 作者
author: lowkey
# 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool
packageName: com.bms.system
# 自动去除表前缀,默认是false
autoRemovePre: false
# 表前缀(生成类名不会包含表前缀,多个用逗号分隔)
tablePrefix: sys_
1、介绍
Spring Boot
是一款开箱即用框架,提供各种默认配置来简化项目配置。让我们的Spring
应用变的更轻量化、更快的入门。 在主程序执行main
函数就可以运行。你也可以打包你的应用为jar
并通过使用java -jar
来运行你的Web应用。它遵循"约定优先于配置"的原则, 使用SpringBoot
只需很少的配置,大部分的时候直接使用默认的配置即可。同时可以与Spring Cloud
的微服务无缝结合。
提示
Spring Boot2.x
版本环境要求必须是jdk8
或以上版本,服务器Tomcat8
或以上版本
2、优点
1、介绍
Apache Shiro是Java的一个安全框架。Shiro可以帮助我们完成:认证、授权、加密、会话管理、与Web集成、缓存等。其不仅可以用在 JavaSE环境,也可以用在 JavaEE 环境。
2、优点
3、特性
Authentication
身份认证/登录,验证用户是不是拥有相应的身份
Authorization
授权,即验证权限,验证某个已认证的用户是否拥有某个权限,即判断用户是否能做事情 SessionManagement
会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中
Cryptography
加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储
Caching
缓存,比如用户登录后,其用户信息,拥有的角色/权限不必每次去查,提高效率
Concurrency
Shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去
Testing
提供测试支持
RunAs
允许一个用户假装为另一个用户(如果他们允许)的身份进行访问
RememberMe
记住我,这是非常常见的功能,即一次登录后,下次再来的话不用登录了
4、架构
Subject
主体,代表了当前的“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫, 机器人等;即一个抽象概念;所有Subject都绑定到SercurityManager,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者
SecurityManage
安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且它管理着所有Subject; 可以看出它是Shiro的核心,它负责与后边介绍的其他组件进行交互
Realm
域,Shiro从Realm获取安全数据(如用户,角色,权限),就是说SecurityManager要验证用户身份, 那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以有1个或多个Realm,我们一般在应用中都需要实现自己的Realm
SessionManager
如果写过Servlet就应该知道Session的概念,Session需要有人去管理它的生命周期,这个组件就是SessionManager
SessionDAO
DAO大家都用过,数据库访问对象,用于会话的CRUD,比如我们想把Session保存到数据库,那么可以实现自己的SessionDAO,也可以写入缓存,以提高性能
CacheManager
缓存控制器,来管理如用户,角色,权限等的缓存的;因为这些数据基本上很少去改变,放到缓存中后可以提高访问的性能
应用代码通过Subject来进行认证和授权,而Subject又委托给SecurityManager; 我们需要给Shrio的SecurityManager注入Realm,从而让SecurityManager能得到合法的用户及其权限进行判断,Shiro不提供维护用户/权限,而是通过Realm让开发人员自己注入。
Shiro不会去维护用户,维护权限;这些需要自己去设计/提供;然后通过响应的接口注入给Shiro即可
1、介绍
Thymeleaf是一个用于Web和独立Java环境的模板引擎,能够处理HTML、XML、JavaScript、CSS甚至纯文本。能轻易的与Spring MVC等Web框架进行集成作为Web应用的模板引擎。 与其它模板引擎(比如FreeMaker)相比,Thymeleaf最大的特点是能够直接在浏览器中打开并正确显示模板页面,而不需要启动整个Web应用(更加方便前后端分离,比如方便类似VUE前端设计页面),抛弃JSP吧。 Thymeleaf 3.0是一个完全彻底重构的模板引擎,极大的减少内存占用和提升性能和并发性,避免v2.1版因大量的输出标记的集合产生的资源占用。 Thymeleaf 3.0放弃了大多数面向DOM的处理机制,变成了一个基于事件的模板处理器,它通过处理模板标记或文本并立即生成其输出,甚至在新事件之前响应模板解析器/缓存事件。Thymeleaf是Spring Boot官方的推荐使用模板。
2、优点
bootstrap
的轻量级表格插件bootstrap-tablemybatis
的轻量级分页插件pageHelper前后端分页实现流程
var options = {
url: prefix + "/list",
columns: [{
field: 'id',
title: '主键'
},
{
field: 'name',
title: '名称'
}]
};
$.table.init(options);
自定义查询条件参数(特殊情况提前设置查询条件下使用)
var options = {
url: prefix + "/list",
queryParams: queryParams,
columns: [{
field: 'id',
title: '主键'
},
{
field: 'name',
title: '名称'
}]
};
$.table.init(options);
function queryParams(params) {
var search = $.table.queryParams(params);
search.userName = $("#userName").val();
return search;
}
@PostMapping("/list")
@ResponseBody
public TableDataInfo list(User user)
{
startPage(); // 此方法配合前端完成自动分页
List<User> list = userService.selectUserList(user);
return getDataTable(list);
}
selectPostById
莫名其妙的分页。例如下面这段代码startPage();
List<User> list;
if(user != null){
list = userService.selectUserList(user);
} else {
list = new ArrayList<User>();
}
Post post = postService.selectPostById(1L);
return getDataTable(list);
原因分析:这种情况下由于user
存在null
的情况,就会导致pageHelper
生产了一个分页参数,但是没有被消费,这个参数就会一直保留在这个线程上。 当这个线程再次被使用时,就可能导致不该分页的方法去消费这个分页参数,这就产生了莫名其妙的分页。
上面这个代码,应该写成下面这个样子才能保证安全。
List<User> list;
if(user != null){
startPage();
list = userService.selectUserList(user);
} else {
list = new ArrayList<User>();
}
Post post = postService.selectPostById(1L);
return getDataTable(list);
startPage
方法。也没有正常分页。例如下面这段代码startPage();
Post post = postService.selectPostById(1L);
List<User> list = userService.selectUserList(user);
return getDataTable(list);
原因分析:只对该语句以后的第一个查询(Select)
语句得到的数据进行分页。
上面这个代码,应该写成下面这个样子才能正常分页。
Post post = postService.selectPostById(1L);
startPage();
List<User> list = userService.selectUserList(user);
return getDataTable(list);
注意
如果改为其他数据库需修改配置application.yml
文件中的属性helperDialect=你的数据库
在实际开发中经常需要使用导入导出功能来加快数据的操作。在项目中可以使用注解来完成此项功能。 在需要被导入导出的实体类属性添加@Excel
注解,目前支持参数如下:
注解参数说明
参数 | 类型 | 默认值 | 描述 |
---|---|---|---|
sort | int | Integer.MAX_VALUE | 导出时在excel中排序,值越小越靠前 |
name | String | 空 | 导出到Excel中的名字 |
dateFormat | String | 空 | 日期格式, 如: yyyy-MM-dd |
dictType | String | 空 | 如果是字典类型,请设置字典的type值 (如: sys_user_sex) |
readConverterExp | String | 空 | 读取内容转表达式 (如: 0=男,1=女,2=未知) |
separator | String | , | 分隔符,读取字符串组内容 |
scale | int | -1 | BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化) |
roundingMode | int | BigDecimal.ROUND_HALF_EVEN | BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN |
columnType | Enum | Type.STRING | 导出类型(0数字 1字符串 2图片) |
height | String | 14 | 导出时在excel中每个列的高度 单位为字符 |
width | String | 16 | 导出时在excel中每个列的宽 单位为字符 |
suffix | String | 空 | 文字后缀,如% 90 变成90% |
defaultValue | String | 空 | 当值为空时,字段的默认值 |
prompt | String | 空 | 提示信息 |
combo | String | Null | 设置只能选择不能输入的列内容 |
targetAttr | String | 空 | 另一个类中的属性名称,支持多级获取,以小数点隔开 |
isStatistics | boolean | false | 是否自动统计数据,在最后追加一行统计数据总和 |
type | Enum | Type.ALL | 字段类型(0:导出导入;1:仅导出;2:仅导入) |
align | Enum | Type.AUTO | 导出字段对齐方式(0:默认;1:靠左;2:居中;3:靠右) |
handler | Class | ExcelHandlerAdapter.class | 自定义数据处理器 |
args | String[] | {} | 自定义数据处理器参数 |
1、前端调用封装好的方法$.table.init
,传入后台exportUrl
var options = {
exportUrl: prefix + "/export",
columns: [{
field: 'id',
title: '主键'
},
{
field: 'name',
title: '名称'
}]
};
$.table.init(options);
2、添加导出按钮事件
<a class="btn btn-warning" onclick="$.table.exportExcel()">
<i class="fa fa-download"></i> 导出
</a>
3、在实体变量上添加@Excel
注解
@Excel(name = "用户序号", prompt = "用户编号")
private Long userId;
@Excel(name = "用户名称")
private String userName;
@Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知")
private String sex;
@Excel(name = "用户头像", cellType = ColumnType.IMAGE)
private String avatar;
@Excel(name = "帐号状态", dictType = "sys_normal_disable")
private String status;
@Excel(name = "最后登陆时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date loginDate
文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态
文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境
文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn
文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker
文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机
文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk
文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入
文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。 Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。
文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动
文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计
文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;gt;Jni-&amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图
文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法