发布 4.1.0

This commit is contained in:
疯狂的狮子li 2022-04-24 14:09:19 +08:00
parent 2cf283b8c6
commit d5520817bd
146 changed files with 7725 additions and 1893 deletions

View File

@ -1,4 +1,4 @@
### 使用版本
### 使用版本(未按照模板填写直接删除)
### 问题描述

View File

@ -4,8 +4,8 @@
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/blob/master/LICENSE)
[![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
<br>
[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-4.0.1-success.svg)](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus)
[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-2.5-blue.svg)]()
[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-4.1.0-success.svg)](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus)
[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-2.6-blue.svg)]()
[![JDK-8+](https://img.shields.io/badge/JDK-8-green.svg)]()
[![JDK-11](https://img.shields.io/badge/JDK-11-green.svg)]()
@ -25,6 +25,9 @@
| 容器框架 | Undertow | [Undertow官网](https://undertow.io/) | 基于 XNIO 的高性能容器 |
| 权限认证框架 | Sa-Token、Jwt | [Sa-Token官网](https://sa-token.dev33.cn/) | 强解耦、强扩展 |
| 关系数据库 | MySQL | [MySQL官网](https://dev.mysql.com/) | 适配 8.X 最低 5.7 |
| 关系数据库 | Oracle | [Oracle官网](https://www.oracle.com/cn/database/) | 适配 11g 12c |
| 关系数据库 | PostgreSQL | [PostgreSQL官网](https://www.postgresql.org/) | 适配 13 14 |
| 关系数据库 | SQLServer | [SQLServer官网](https://docs.microsoft.com/zh-cn/sql/sql-server) | 适配 2017 2019 |
| 缓存数据库 | Redis | [Redis官网](https://redis.io/) | 适配 6.X 最低 4.X |
| 数据库框架 | Mybatis-Plus | [Mybatis-Plus文档](https://baomidou.com/guide/) | 快速 CRUD 增加开发效率 |
| 数据库框架 | p6spy | [p6spy官网](https://p6spy.readthedocs.io/) | 更强劲的 SQL 分析 |

54
pom.xml
View File

@ -6,46 +6,49 @@
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-vue-plus</artifactId>
<version>4.0.1</version>
<version>4.1.0</version>
<name>RuoYi-Vue-Plus</name>
<url>https://gitee.com/JavaLionLi/RuoYi-Vue-Plus</url>
<description>RuoYi-Vue-Plus后台管理系统</description>
<properties>
<ruoyi-vue-plus.version>4.0.1</ruoyi-vue-plus.version>
<spring-boot.version>2.6.4</spring-boot.version>
<ruoyi-vue-plus.version>4.1.0</ruoyi-vue-plus.version>
<spring-boot.version>2.6.7</spring-boot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
<spring-boot.mybatis>2.2.0</spring-boot.mybatis>
<druid.version>1.2.8</druid.version>
<knife4j.version>3.0.3</knife4j.version>
<swagger-annotations.version>1.5.22</swagger-annotations.version>
<poi.version>4.1.2</poi.version>
<commons-compress.version>1.21</commons-compress.version>
<easyexcel.version>3.0.5</easyexcel.version>
<cglib.version>3.3.0</cglib.version>
<velocity.version>2.3</velocity.version>
<satoken.version>1.29.0</satoken.version>
<mybatis-plus.version>3.5.1</mybatis-plus.version>
<p6spy.version>3.9.1</p6spy.version>
<hutool.version>5.7.21</hutool.version>
<okhttp.version>4.9.2</okhttp.version>
<spring-boot-admin.version>2.6.2</spring-boot-admin.version>
<redisson.version>3.16.8</redisson.version>
<hutool.version>5.7.22</hutool.version>
<okhttp.version>4.9.3</okhttp.version>
<spring-boot-admin.version>2.6.6</spring-boot-admin.version>
<redisson.version>3.17.0</redisson.version>
<lock4j.version>2.2.1</lock4j.version>
<dynamic-ds.version>3.5.0</dynamic-ds.version>
<dynamic-ds.version>3.5.1</dynamic-ds.version>
<tlog.version>1.3.6</tlog.version>
<xxl-job.version>2.3.0</xxl-job.version>
<!-- jdk11 缺失依赖 jaxb-->
<jaxb.version>3.0.1</jaxb.version>
<!-- 统一 guava 版本 解决隐式漏洞问题 -->
<guava.version>30.0-jre</guava.version>
<!-- OSS 配置 -->
<qiniu.version>7.9.3</qiniu.version>
<qiniu.version>7.9.5</qiniu.version>
<aliyun.oss.version>3.14.0</aliyun.oss.version>
<qcloud.cos.version>5.6.68</qcloud.cos.version>
<minio.version>8.3.7</minio.version>
<qcloud.cos.version>5.6.72</qcloud.cos.version>
<minio.version>8.3.8</minio.version>
<!-- docker 配置 -->
<docker.registry.url>localhost</docker.registry.url>
@ -109,6 +112,13 @@
<version>${poi.version}</version>
</dependency>
<!-- 修复poi漏洞 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>${commons-compress.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
@ -125,12 +135,6 @@
</exclusions>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>${cglib.version}</version>
</dependency>
<!-- velocity代码生成使用模板 -->
<dependency>
<groupId>org.apache.velocity</groupId>
@ -222,6 +226,20 @@
<groupId>com.yomahub</groupId>
<artifactId>tlog-web-spring-boot-starter</artifactId>
<version>${tlog.version}</version>
<exclusions>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
<exclusion>
<artifactId>dom4j</artifactId>
<groupId>dom4j</groupId>
</exclusion>
<exclusion>
<artifactId>commons-beanutils</artifactId>
<groupId>commons-beanutils</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.0.1</version>
<version>4.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-extend</artifactId>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>ruoyi-extend</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.0.1</version>
<version>4.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>

View File

@ -4,14 +4,12 @@
<parent>
<artifactId>ruoyi-extend</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.0.1</version>
<version>4.1.0</version>
</parent>
<artifactId>ruoyi-xxl-job-admin</artifactId>
<packaging>jar</packaging>
<properties>
<mybatis-spring-boot-starter.version>2.1.4</mybatis-spring-boot-starter.version>
<mysql-connector-java.version>8.0.23</mysql-connector-java.version>
</properties>
<dependencyManagement>
@ -62,13 +60,12 @@
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot-starter.version}</version>
<version>${spring-boot.mybatis}</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-java.version}</version>
</dependency>
<dependency>

View File

@ -11,7 +11,7 @@ cd ruoyi-ui
npm install
# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
npm install --registry=https://registry.npm.taobao.org
npm install --registry=https://registry.npmmirror.com
# 启动服务
npm run dev

View File

@ -1,12 +1,12 @@
@echo off
echo.
echo [信息] 安装Web工程生成node_modules文件。
echo [<EFBFBD><EFBFBD>Ϣ] <20><>װWeb<65><62><EFBFBD>̣<EFBFBD><CCA3><EFBFBD><EFBFBD><EFBFBD>node_modules<65>ļ<EFBFBD><C4BC><EFBFBD>
echo.
%~d0
cd %~dp0
cd ..
npm install --registry=https://registry.npm.taobao.org
npm install --registry=https://registry.npmmirror.com
pause
pause

View File

@ -1,6 +1,6 @@
{
"name": "ruoyi-vue-plus",
"version": "4.0.1",
"version": "4.1.0",
"description": "RuoYi-Vue-Plus后台管理系统",
"author": "LionLi",
"license": "MIT",
@ -41,13 +41,13 @@
"clipboard": "2.0.8",
"core-js": "3.19.1",
"echarts": "4.9.0",
"element-ui": "2.15.6",
"element-ui": "2.15.8",
"file-saver": "2.0.5",
"fuse.js": "6.4.3",
"highlight.js": "9.18.5",
"js-beautify": "1.13.0",
"js-cookie": "3.0.1",
"jsencrypt": "3.2.1",
"jsencrypt": "3.0.0-rc.1",
"nprogress": "0.2.0",
"quill": "1.3.7",
"screenfull": "5.0.2",

View File

@ -3,14 +3,17 @@ import request from '@/utils/request'
// 查询生成表数据
export function listTable(query) {
return request({
headers: { 'datasource': localStorage.getItem("dataName") },
url: '/tool/gen/list',
method: 'get',
params: query
})
}
// 查询db数据库列表
export function listDbTable(query) {
return request({
headers: { 'datasource': localStorage.getItem("dataName") },
url: '/tool/gen/db/list',
method: 'get',
params: query
@ -20,6 +23,7 @@ export function listDbTable(query) {
// 查询表详细信息
export function getGenTable(tableId) {
return request({
headers: { 'datasource': localStorage.getItem("dataName") },
url: '/tool/gen/' + tableId,
method: 'get'
})
@ -28,6 +32,7 @@ export function getGenTable(tableId) {
// 修改代码生成信息
export function updateGenTable(data) {
return request({
headers: { 'datasource': localStorage.getItem("dataName") },
url: '/tool/gen',
method: 'put',
data: data
@ -37,6 +42,7 @@ export function updateGenTable(data) {
// 导入表
export function importTable(data) {
return request({
headers: { 'datasource': localStorage.getItem("dataName") },
url: '/tool/gen/importTable',
method: 'post',
params: data
@ -46,6 +52,7 @@ export function importTable(data) {
// 预览生成代码
export function previewTable(tableId) {
return request({
headers: { 'datasource': localStorage.getItem("dataName") },
url: '/tool/gen/preview/' + tableId,
method: 'get'
})
@ -54,6 +61,7 @@ export function previewTable(tableId) {
// 删除表数据
export function delTable(tableId) {
return request({
headers: { 'datasource': localStorage.getItem("dataName") },
url: '/tool/gen/' + tableId,
method: 'delete'
})
@ -62,6 +70,7 @@ export function delTable(tableId) {
// 生成代码(自定义路径)
export function genCode(tableName) {
return request({
headers: { 'datasource': localStorage.getItem("dataName") },
url: '/tool/gen/genCode/' + tableName,
method: 'get'
})
@ -70,6 +79,7 @@ export function genCode(tableName) {
// 同步数据库
export function synchDb(tableName) {
return request({
headers: { 'datasource': localStorage.getItem("dataName") },
url: '/tool/gen/synchDb/' + tableName,
method: 'get'
})

View File

@ -7,6 +7,10 @@
position: relative;
}
.sidebarHide {
margin-left: 0!important;
}
.sidebar-container {
-webkit-transition: width .28s;
transition: width 0.28s;

View File

@ -41,6 +41,7 @@
<script>
import { getToken } from "@/utils/auth";
import { delOss } from "@/api/system/oss";
export default {
name: "FileUpload",
@ -89,9 +90,7 @@ export default {
const list = Array.isArray(val) ? val : this.value.split(',');
//
this.fileList = list.map(item => {
if (typeof item === "string") {
item = { name: item, url: item };
}
item = { name: item.name, url: item.url, ossId: item.ossId };
item.uid = item.uid || new Date().getTime() + temp++;
return item;
});
@ -153,12 +152,12 @@ export default {
//
handleUploadSuccess(res, file) {
if (res.code === 200) {
this.uploadList.push({ name: res.data.fileName, url: res.data.url });
this.uploadList.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId });
if (this.uploadList.length === this.number) {
this.fileList = this.fileList.concat(this.uploadList);
this.uploadList = [];
this.number = 0;
this.$emit("input", this.listToString(this.fileList));
this.$emit("input", this.fileList);
this.$modal.closeLoading();
}
} else {
@ -168,26 +167,20 @@ export default {
},
//
handleDelete(index) {
let ossId = this.fileList[index].ossId;
delOss(ossId);
this.fileList.splice(index, 1);
this.$emit("input", this.listToString(this.fileList));
this.$emit("input", this.fileList);
},
//
getFileName(name) {
// url
if (name.lastIndexOf("/") > -1) {
return name.slice(name.lastIndexOf("/") + 1);
} else {
return "";
return name;
}
},
//
listToString(list, separator) {
let strs = "";
separator = separator || ",";
for (let i in list) {
strs += list[i].url + separator;
}
return strs != "" ? strs.substr(0, strs.length - 1) : "";
},
},
};
</script>

View File

@ -44,6 +44,7 @@
<script>
import { getToken } from "@/utils/auth";
import { delOss } from "@/api/system/oss";
export default {
props: {
@ -92,9 +93,8 @@ export default {
const list = Array.isArray(val) ? val : this.value.split(',');
//
this.fileList = list.map(item => {
if (typeof item === "string") {
item = { name: item, url: item };
}
// name使ossId
item = { name: item.ossId, url: item.url, ossId: item.ossId };
return item;
});
} else {
@ -117,19 +117,21 @@ export default {
handleRemove(file, fileList) {
const findex = this.fileList.map(f => f.name).indexOf(file.name);
if(findex > -1) {
let ossId = this.fileList[findex].ossId;
delOss(ossId);
this.fileList.splice(findex, 1);
this.$emit("input", this.listToString(this.fileList));
this.$emit("input", this.fileList);
}
},
//
handleUploadSuccess(res) {
if (res.code == 200) {
this.uploadList.push({ name: res.data.fileName, url: res.data.url });
this.uploadList.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId });
if (this.uploadList.length === this.number) {
this.fileList = this.fileList.concat(this.uploadList);
this.uploadList = [];
this.number = 0;
this.$emit("input", this.listToString(this.fileList));
this.$emit("input", this.fileList);
this.$modal.closeLoading();
}
} else {
@ -182,15 +184,6 @@ export default {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
},
//
listToString(list, separator) {
let strs = "";
separator = separator || ",";
for (let i in list) {
strs += list[i].url + separator;
}
return strs != '' ? strs.substr(0, strs.length - 1) : '';
}
}
};
</script>

View File

@ -30,13 +30,14 @@
<script>
import { constantRoutes } from "@/router";
//
const hideList = ['/index', '/user/profile'];
export default {
data() {
return {
//
visibleNumber: 5,
//
isFrist: false,
// index
currentIndex: undefined
};
@ -71,7 +72,7 @@ export default {
for (var item in router.children) {
if (router.children[item].parentPath === undefined) {
if(router.path === "/") {
router.children[item].path = "/redirect/" + router.children[item].path;
router.children[item].path = "/" + router.children[item].path;
} else {
if(!this.ishttp(router.children[item].path)) {
router.children[item].path = router.path + "/" + router.children[item].path;
@ -87,22 +88,16 @@ export default {
//
activeMenu() {
const path = this.$route.path;
let activePath = this.defaultRouter();
if (path.lastIndexOf("/") > 0) {
let activePath = path;
if (path !== undefined && path.lastIndexOf("/") > 0 && hideList.indexOf(path) === -1) {
const tmpPath = path.substring(1, path.length);
activePath = "/" + tmpPath.substring(0, tmpPath.indexOf("/"));
} else if ("/index" == path || "" == path) {
if (!this.isFrist) {
this.isFrist = true;
} else {
activePath = "index";
}
}
var routes = this.activeRoutes(activePath);
if (routes.length === 0) {
activePath = this.currentIndex || this.defaultRouter()
this.activeRoutes(activePath);
this.$store.dispatch('app/toggleSideBarHide', false);
} else if(!this.$route.children) {
activePath = path;
this.$store.dispatch('app/toggleSideBarHide', true);
}
this.activeRoutes(activePath);
return activePath;
},
},
@ -121,29 +116,21 @@ export default {
const width = document.body.getBoundingClientRect().width / 3;
this.visibleNumber = parseInt(width / 85);
},
//
defaultRouter() {
let router;
Object.keys(this.routers).some((key) => {
if (!this.routers[key].hidden) {
router = this.routers[key].path;
return true;
}
});
return router;
},
//
handleSelect(key, keyPath) {
this.currentIndex = key;
const route = this.routers.find(item => item.path === key);
if (this.ishttp(key)) {
// http(s)://
window.open(key, "_blank");
} else if (key.indexOf("/redirect") !== -1) {
// /redirect
this.$router.push({ path: key.replace("/redirect", "") });
} else if (!route || !route.children) {
//
this.$router.push({ path: key });
this.$store.dispatch('app/toggleSideBarHide', true);
} else {
//
this.activeRoutes(key);
this.$store.dispatch('app/toggleSideBarHide', false);
}
},
//
@ -159,7 +146,6 @@ export default {
if(routes.length > 0) {
this.$store.commit("SET_SIDEBAR_ROUTERS", routes);
}
return routes;
},
ishttp(url) {
return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1

View File

@ -41,7 +41,7 @@
<el-divider/>
<h3 class="drawer-title">系统布局配置</h3>
<div class="drawer-item">
<span>开启 TopNav</span>
<el-switch v-model="topNav" class="drawer-switch" />
@ -108,6 +108,7 @@ export default {
value: val
})
if (!val) {
this.$store.dispatch('app/toggleSideBarHide', false);
this.$store.commit("SET_SIDEBAR_ROUTERS", this.$store.state.permission.defaultRoutes);
}
}

View File

@ -21,7 +21,11 @@ export default {
}
if (title) {
vnodes.push(<span slot='title'>{(title)}</span>)
if (title.length > 5) {
vnodes.push(<span slot='title' title={(title)}>{(title)}</span>)
} else {
vnodes.push(<span slot='title'>{(title)}</span>)
}
}
return vnodes
}

View File

@ -1,8 +1,8 @@
<template>
<div :class="classObj" class="app-wrapper" :style="{'--current-color': theme}">
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
<sidebar class="sidebar-container"/>
<div :class="{hasTagsView:needTagsView}" class="main-container">
<sidebar v-if="!sidebar.hide" class="sidebar-container" />
<div :class="{hasTagsView:needTagsView,sidebarHide:sidebar.hide}" class="main-container">
<div :class="{'fixed-header':fixedHeader}">
<navbar />
<tags-view v-if="needTagsView" />
@ -101,6 +101,10 @@ export default {
width: calc(100% - 54px);
}
.sidebarHide .fixed-header {
width: 100%;
}
.mobile .fixed-header {
width: 100%;
}

View File

@ -38,7 +38,10 @@ export default {
method: 'get',
url: url,
responseType: 'blob',
headers: { 'Authorization': 'Bearer ' + getToken() }
headers: {
'Authorization': 'Bearer ' + getToken(),
'datasource': localStorage.getItem("dataName")
}
}).then(async (res) => {
const isLogin = await blobValidate(res.data);
if (isLogin) {

View File

@ -55,10 +55,10 @@ export default {
return store.dispatch('tagsView/delOthersViews', obj || router.currentRoute);
},
// 添加tab页签
openPage(title, url) {
openPage(title, url, params) {
var obj = { path: url, meta: { title: title } }
store.dispatch('tagsView/addView', obj);
return router.push(url);
return router.push({ path: url, query: params });
},
// 修改tab页签
updatePage(obj) {

View File

@ -164,7 +164,14 @@ export const dynamicRoutes = [
}
]
// 防止连续点击多次路由报错
let routerPush = Router.prototype.push;
Router.prototype.push = function push(location) {
return routerPush.call(this, location).catch(err => err)
}
export default new Router({
base: process.env.VUE_APP_CONTEXT_PATH,
mode: 'history', // 去掉url中的#
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes

View File

@ -3,7 +3,8 @@ import Cookies from 'js-cookie'
const state = {
sidebar: {
opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
withoutAnimation: false
withoutAnimation: false,
hide: false
},
device: 'desktop',
size: Cookies.get('size') || 'medium'
@ -11,6 +12,9 @@ const state = {
const mutations = {
TOGGLE_SIDEBAR: state => {
if (state.sidebar.hide) {
return false;
}
state.sidebar.opened = !state.sidebar.opened
state.sidebar.withoutAnimation = false
if (state.sidebar.opened) {
@ -30,6 +34,9 @@ const mutations = {
SET_SIZE: (state, size) => {
state.size = size
Cookies.set('size', size)
},
SET_SIDEBAR_HIDE: (state, status) => {
state.sidebar.hide = status
}
}
@ -45,6 +52,9 @@ const actions = {
},
setSize({ commit }, size) {
commit('SET_SIZE', size)
},
toggleSideBarHide({ commit }, status) {
commit('SET_SIDEBAR_HIDE', status)
}
}

View File

@ -22,12 +22,7 @@ const permission = {
state.defaultRoutes = constantRoutes.concat(routes)
},
SET_TOPBAR_ROUTES: (state, routes) => {
// 顶部导航菜单默认添加统计报表栏指向首页
const index = [{
path: 'index',
meta: { title: '统计报表', icon: 'dashboard' }
}]
state.topbarRouters = routes.concat(index);
state.topbarRouters = routes
},
SET_SIDEBAR_ROUTERS: (state, routes) => {
state.sidebarRouters = routes

View File

@ -51,7 +51,7 @@ const user = {
return new Promise((resolve, reject) => {
getInfo().then(res => {
const user = res.data.user
const avatar = user.avatar == "" ? require("@/assets/images/profile.jpg") : user.avatar;
const avatar = (user.avatar == "" || user.avatar == null) ? require("@/assets/images/profile.jpg") : user.avatar;
if (res.data.roles && res.data.roles.length > 0) { // 验证返回的roles是否是一个非空数组
commit('SET_ROLES', res.data.roles)
commit('SET_PERMISSIONS', res.data.permissions)

View File

@ -39,14 +39,24 @@
v-hasPermi="['demo:tree:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="el-icon-sort"
size="mini"
@click="toggleExpandAll"
>展开/折叠</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table
v-if="refreshTable"
v-loading="loading"
:data="treeList"
row-key="id"
default-expand-all
:default-expand-all="isExpandAll"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
>
<el-table-column label="父id" prop="parentId" />
@ -54,12 +64,12 @@
<el-table-column label="用户id" align="center" prop="userId" />
<el-table-column label="树节点名" align="center" prop="treeName" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<template #default="scope">
<el-button
size="mini"
type="text"
@ -135,6 +145,10 @@ export default {
title: "",
//
open: false,
//
isExpandAll: true,
//
refreshTable: true,
//
daterangeCreateTime: [],
//
@ -233,6 +247,14 @@ export default {
this.open = true;
this.title = "添加测试树表";
},
/** 展开/折叠操作 */
toggleExpandAll() {
this.refreshTable = false;
this.isExpandAll = !this.isExpandAll;
this.$nextTick(() => {
this.refreshTable = true;
});
},
/** 修改按钮操作 */
handleUpdate(row) {
this.loading = true;

View File

@ -8,9 +8,12 @@
<br/>
* 前端开发框架 VueElement UI<br/>
* 后端开发框架 Spring Boot<br/>
* 容器框架 Undertow 基于 Netty 的高性能容器<br/>
* 权限认证框架 Spring SecurityJwt 支持多终端认证系统<br/>
* 容器框架 Undertow 基于 XNIO 的高性能容器<br/>
* 权限认证框架 Sa-TokenJwt 支持多终端认证系统<br/>
* 关系数据库 MySQL 适配 8.X 最低 5.7<br/>
* 关系数据库 Oracle 适配 11g 12c<br/>
* 关系数据库 PostgreSQL 适配 13 14<br/>
* 关系数据库 SQLServer 适配 2017 2019<br/>
* 缓存数据库 Redis 适配 6.X 最低 4.X<br/>
* 数据库框架 Mybatis-Plus 快速 CRUD 增加开发效率<br/>
* 数据库框架 p6spy 更强劲的 SQL 分析<br/>
@ -19,11 +22,11 @@
* Redis客户端 Redisson 性能强劲API丰富<br/>
* 分布式限流 Redisson 全局请求IP集群ID 多种限流<br/>
* 分布式锁 Lock4j 注解锁工具锁 多种多样<br/>
* 分布式幂等 Lock4j 基于分布式锁实现<br/>
* 分布式幂等 Redisson 拦截重复提交<br/>
* 分布式日志 TLog 支持跟踪链路日志记录性能分析链路排查<br/>
* 分布式任务调度 Xxl-Job 高性能 高可靠 易扩展<br/>
* 文件存储 Minio 本地存储<br/>
* 文件存储 七牛阿里腾讯 云存储<br/>
* 分布式文件存储 Minio 本地存储<br/>
* 分布式云存储 七牛阿里腾讯 云存储<br/>
* 监控框架 SpringBoot-Admin 全方位服务监控<br/>
* 校验框架 Validation 增强接口安全性 严谨性<br/>
* Excel框架 Alibaba EasyExcel 性能优异 扩展性强<br/>
@ -56,6 +59,14 @@
@click="goTarget('https://github.com/JavaLionLi/RuoYi-Vue-Plus')"
>访问GitHub</el-button
>
<el-button
type="primary"
size="mini"
icon="el-icon-cloudy"
plain
@click="goTarget('https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages?sort_id=4106467&doc_id=1469725')"
>更新日志</el-button
>
</p>
</el-col>
@ -94,634 +105,6 @@
</el-col>
</el-row>
<el-divider />
<el-row :gutter="20">
<el-col :xs="24" :sm="24" :md="12" :lg="8">
<el-card class="update-log">
<div slot="header" class="clearfix">
<span>更新日志</span>
</div>
<el-collapse accordion>
<el-collapse-item title="v4.0.1 - 2022-03-01">
<ol>
<li>update 图片上传 文件上传 支持并发上传</li>
<li>update 组件ImageUpload支持多图同时选择上传</li>
<li>udpate 组件fileUpload支持多文件同时选择上传</li>
<li>update springboot 2.6.3 => 2.6.4</li>
<li>update hutool 5.7.20 => 5.7.21</li>
<li>update qiniu 7.9.2 => 7.9.3</li>
<li>update minio 8.3.5 => 8.3.7</li>
<li>update 优化 R 默认返回 msg</li>
<li>update 增加 用户注册 用户类型默认值</li>
<li>update 增加用户登出日志</li>
<li>update 更新 多用户多设备的注释说明</li>
<li>update 优化 是否为管理员的判断</li>
<li>update 优化 页面若未匹配到字典标签则返回原字典值</li>
<li>update 调整用户登录 将日志调整到最后 防止获取不到用户警告</li>
<li>update 优化随机数生成方式 避免容易生成两个相同随机数的问题</li>
<li>fix 修复代码生成 基于路径生成 路径为空问题</li>
<li>fix 恢复误删 @Async 注解线程池配置类</li>
<li>fix 修复 minio 适配 https 导致的问题</li>
<li>fix 修复分页组件请求两次问题</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v4.0.0 - 2022-02-18">
<ol>
<li>[重大更新] 重写项目整体结构 数据处理下沉至Mapper符合MVC规范 减少循环依赖</li>
<li>[重磅更新] 主分支与satoken分支合并 权限统一使用 sa-token</li>
<li>[重磅更新] 适配升级 SpringBoot 2.6</li>
<li>[重磅更新] EasyExcel大版本升级3.X</li>
<li>[重磅更新] 移除链式调用注解 因链式调用不符合java规范 导致很多问题</li>
<li>[重磅更新] 增加 轻量级 分布式队列 支持</li>
<li>[重磅更新] 增加 数据脱敏注解 使用序列化控制脱敏 支持多种表达式</li>
<li>[重磅更新] 重构 使用 Spring 简化 oss 模块代码</li>
<li>[重磅更新] 重构 调整返回类型为 R 精简 Controller 代码</li>
<li>update springboot 2.5.8 => 2.6.3</li>
<li>update mybatis-plus 3.4.3.4 => 3.5.1</li>
<li>update maven-jar-plugin 3.2.0 => 3.2.2</li>
<li>update maven-war-plugin 3.2.0 => 3.2.2</li>
<li>update maven-compiler-plugin 3.1 => 3.9.0</li>
<li>update hutool 5.7.18 => 5.7.20</li>
<li>update springboot-admin 2.6.0 => 2.6.2</li>
<li>update redisson 3.16.7 => 3.16.8</li>
<li>update qiniu 7.9.0 => 7.9.2</li>
<li>update aliyun 3.13.1 => 3.14.0</li>
<li>update qcloud 5.6.58 => 5.6.68</li>
<li>update minio 8.3.4 => 8.3.5</li>
<li>update 用户管理部门查询选择节点后分页参数初始</li>
<li>update 防重复提交标识组合key + url + header</li>
<li>update 接口文档增加 basic 账号密码验证</li>
<li>update 用户修改减少一次角色列表关联查询</li>
<li>update 优化部门修改缩放后出现的错位问题</li>
<li>update 指定 maven 资源过滤为具体文件 防止错误过滤</li>
<li>update hutool 引入改为 bom 依赖项引入</li>
<li>update 降低开发环境 redis连接池数量</li>
<li>update 升级 springboot 2.6.X 解决 springfox 兼容性问题</li>
<li>update 优化多用户体系处理 更名 LoginUtils LoginHelper 支持 LoginUser 多级缓存</li>
<li>update 优化加载字典缓存数据</li>
<li>update 数据库更改 对接多用户体系</li>
<li>update 移除掉 StringUtils 语义不明确的api方法 使用特定工具替换</li>
<li>update 优化登录注册在接口通过`@Validated`注解进行数据基础校验</li>
<li>update 优化 查询登录用户数据 统一走缓存</li>
<li>update 优化 redisson 配置 去除掉不常用的配置 使用默认配置</li>
<li>update 用户访问控制时校验数据权限防止越权</li>
<li>update 修改用户注册报未登录警告</li>
<li>update 调整oss预览开关 使用前端直接调用更改配置参数</li>
<li>update 使用 satoken 自带的 BCrypt 工具 替换 Security 加密工具 减少依赖</li>
<li>update 优化 TreeBuildUtils 工具 使用反射自动获取顶级父id</li>
<li>update 使用 hutool Dict 优化 JsonUtils 防止类型解析异常</li>
<li>update 优化代码生成 使用新 JsonUtils.parseMap 方法</li>
<li>update 更新 所有 oss 均支持 https 配置</li>
<li>add 增加 RedisUtils 工具 hasKey 检查key存在方法</li>
<li>add 增加 监控中心 自定义事件通知</li>
<li>add 增加 3.X update 4.0 更新sql</li>
<li>fix 修复登录失效后多次请求提示多次弹窗问题</li>
<li>fix 修复 StringUtils 通配符匹配无效</li>
<li>fix 修复选项卡点击右键刷新丢失参数问题</li>
<li>fix 修复 数据权限 缓存方法名错误问题</li>
<li>fix 修复自定义组件`file-upload`无法显示第一个文件列表显示的文件比实际文件少一个的问题</li>
<li>fix 修复因升级 sa-token 导致 doLogin 无法获取 token 问题</li>
<li>fix 修复分页组件请求两次问题</li>
<li>remove 移除过期代码 分页工具相关</li>
<li>remove 移除过期代码 多数据源切换</li>
<li>remove 移除过期代码 数据权限</li>
<li>3.X 版本进入维护阶段 不进行更新 只修复bug 持续维护到2022年10月</li>
<li>4.X 版本公测将近一个月 大部分bug已修复 官网主分支更改为 4.X 版本 推荐使用</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.5.0 - 2021-12-28">
<ol>
<li>[重大更新] 重写数据权限实现</li>
<li>[重磅更新] 重构分页 简化使用</li>
<li>[重磅更新] 用户登录 支持校验错误次数锁定登录</li>
<li>[重磅更新] 增加 jdbc 批处理参数 大幅提升批量操作性能 对原生语句与 MP 均有效</li>
<li>update springboot 2.5.7 => 2.5.8 升级预防 log4j2 问题</li>
<li>update springboot-admin 2.5.4 => 2.5.5</li>
<li>update hutool 5.7.16 => 5.7.18</li>
<li>update redisson 3.16.4 => 3.16.7</li>
<li>update dynamic-ds 3.4.1 => 3.5.0</li>
<li>update qiniu 7.8.0 => 7.9.0</li>
<li>update minio 8.3.3 => 8.3.4</li>
<li>update tlog 1.3.4 => 1.3.6 启用 tlog 自动配置</li>
<li>update clipboard 2.0.6 => 2.0.8</li>
<li>update 多数据源切换标注过期 3.6.0 移除 推荐使用原生注解</li>
<li>update 通用权限服务 迁移回 ruoyi-framework 模块</li>
<li>update 使用 hutool-jwt 替换老旧 jjwt 依赖</li>
<li>update 调整 OSS 表字段内容长度</li>
<li>update LoginUser 增加角色缓存 优化角色权限代码</li>
<li>update 使用 Cglib 重构 BeanCopyUtils 性能优异</li>
<li>update 禁止所有工具类实例化 优化代码书写规范</li>
<li>update 优化查询用户的角色组岗位组代码</li>
<li>update 更新 RedisUtils 返回客户端实例</li>
<li>update 修改 健康检查权限 改为用户放行 提高安全性</li>
<li>update hutool 工具 改为单包引入 减少无用依赖</li>
<li>update ServicePlusImpl 功能 下沉到 BaseMapperPlus</li>
<li>update 去除 jdk17 标签 由于很多组件还未适配 导致一些问题</li>
<li>udpate 代码生成预览支持复制内容</li>
<li>update 用户导入提示溢出则显示滚动条</li>
<li>update 路由支持单独配置菜单或角色权限</li>
<li>update 优化web拦截器 使用原生接口处理 默认非生产环境开启</li>
<li>update 调整监控依赖 common 迁移到 framework</li>
<li>add 新增 Vue3 分支 代码生成模板(由于组件还未完善 仅供学习)</li>
<li>add 增加 RedisUtils 注册监听器方法</li>
<li>add 增加 自定义 Xss 校验注解 用户导入增加 Bean 校验</li>
<li>add oss下载增加 loading </li>
<li>add 新增图片预览组件</li>
<li>add 集成compression-webpack-plugin插件实现打包Gzip压缩</li>
<li>add 新增 SqlUtils 检查关键字方法</li>
<li>fix 修复 集群雪花id重复问题 使用网卡信息绑定生成</li>
<li>fix 修复 count 语法异常</li>
<li>fix 修复更改密码问题</li>
<li>fix 修复sql关键字处理 防止解析器报错</li>
<li>fix 修复 TreeBuildUtils 顶节点不为 0 问题</li>
<li>fix 修复 SysOssConfig 主键类型错误</li>
<li>fix 修复代码生成 导出注解错误</li>
<li>fix 修复 redisson 集群模式 路径未匹配协议头问题</li>
<li>fix 修复打包后字体图标偶现的乱码问题</li>
<li>fix 修复版本差异导致的懒加载报错问题</li>
<li>fix 修复代码生成字典组重复问题</li>
<li>remove 删除 jjwt 无用依赖</li>
<li>remove 移除过期 用户导入</li>
<li>remove 移除过期工具 DictUtils</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.4.0 - 2021-11-29">
<ol>
<li>update [重磅更新] 重构 Excel 导入 支持 Validator 校验 支持自定义监听器</li>
<li>update [重磅更新] Validator 校验框架支持国际化</li>
<li>update springboot 2.5.6 => 2.5.7</li>
<li>update hutool 5.7.15 => 5.7.16</li>
<li>update okhttp 4.9.1 => 4.9.2</li>
<li>update spring-boot-admin 2.5.2 => 2.5.4</li>
<li>update redisson 3.16.3 => 3.16.4</li>
<li>update tlog 1.3.3 => 1.3.4</li>
<li>update axios 0.21.0 => 0.24.0</li>
<li>update core-js 3.8.1 => 3.19.1</li>
<li>update js-cookie 2.2.1 => 3.0.1</li>
<li>update velocity 1.7 => 2.3</li>
<li>update 升级 docker 基础镜像</li>
<li>update 基于 hutool 封装树构建工具 重构部门与菜单树结构返回</li>
<li>update 减少使用特定数据库函数</li>
<li>update 配置应用前缀路径 改为配置文件统一配置</li>
<li>update 升级 swagger 配置 使用 knife4j 增强模式</li>
<li>update 监控中心 集成监控客户端 实现自监控</li>
<li>update 调度中心 集成监控客户端 注册到监控中心</li>
<li>update 优化 tab 对象简化页签操作</li>
<li>update 解耦 LoginUser SysUser 强关联</li>
<li>update 更新 RepeatSubmit 注解 aop 处理 针对特殊参数进行过滤</li>
<li>update DictUtils 字典工具类 标记过期 3.5.0 版本移除 使用 DictService 代替</li>
<li>update 抽象 DictService 通用 字典服务</li>
<li>update 抽象 ConfigService 通用 参数配置服务</li>
<li>update 基于 DictService 重构 Excel 内字典查询功能</li>
<li>update OSS 模块 整体重命名 消除歧义</li>
<li>update 更新 redis.conf 存储策略 aof rdb 配置参数</li>
<li>update 初始化数据转移到 ApplicationRunner 统一处理</li>
<li>update 优化时间查询语句</li>
<li>add 增加 框架缓存懒加载 开关</li>
<li>add 新增 监控中心 Bean 初始化 startup trace 监控插件</li>
<li>add 增加 ValidatorUtils 校验框架工具 用于在非 Controller 的地方校验对象</li>
<li>fix 修复 SysOssSysOssConfig 未继承 BaseEntity 基础实体问题</li>
<li>fix 修复 xxl-job-admin 部署问题</li>
<li>fix 修复 回显数据字典键值修正</li>
<li>fix 修复 Linux 清除临时目录 导致上传找不到目录报错问题</li>
<li>fix 修复通用实体 传参无法接收问题</li>
<li>fix 修复 SysLoginController 接口文档书写错误问题</li>
<li>fix 修复 用户逻辑删除 差异问题</li>
<li>fix 修复 OSS 七牛云 token 过期未刷新问题</li>
<li>fix 修复 分页工具 排序字段 null 处理</li>
<li>fix 修复 用户导入字典使用错误</li>
<li>fix 修复 关闭 xss 功能导致可重复读 RepeatableFilter 失效</li>
<li>fix 修复 使用 this.$options.data 报错问题</li>
<li>fix 修复 代码生成复选框字典遗漏问题</li>
<li>fix 修复 重复提交不生效问题 由于概念不同 使用 RedisUtils 重构</li>
<li>fix 修复 OSS 工厂 未实例化服务更新加载问题</li>
<li>remove 移除 quartz 相关代码与依赖</li>
<li>remove 移除 feign 相关代码与依赖</li>
<li>remove 移除 MybatisPlusRedisCache 二级缓存</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.3.0 - 2021-10-29">
<ol>
<li>add [重磅更新] 增加分布式日志框架 TLog</li>
<li>add [重磅更新] 增加分布式任务调度系统 Xxl-Job</li>
<li>add [重大更新] 增加 ruoyi-job 任务调度模块(基于xxl-job)</li>
<li>update [重大更新]全业务 增加 接口文档注解 格式化代码</li>
<li>update springboot 2.5.5 => 2.5.6</li>
<li>update springboot-admin 2.5.1 => 2.5.2</li>
<li>update element-ui 2.15.5 => 2.15.6</li>
<li>update hutool 5.7.13 => 5.7.15</li>
<li>update qcloud.cos 5.6.55 => 5.6.58</li>
<li>update minio 8.3.0 => 8.3.3</li>
<li>update 更新 element 2.15.6 表格样式</li>
<li>update 优化 代码生成常量 关于 BO VO 注释</li>
<li>update 优化代码生成 导入表 列表返回 主键默认选中</li>
<li>update MybatisPlusRedisCache 标记过期 推荐使用 spring-cache</li>
<li>update Quartz 标记过期 推荐迁移至新框架 xxl-job</li>
<li>update Feign 标记过期</li>
<li>update 前端增加默认国际化参数</li>
<li>update 更新 Admin 监控 注释 避免错误使用</li>
<li>update Admin 监控增加日志文件输出</li>
<li>update 优化 xxl-job-admin 增加格式化日志输出与 docker 镜像</li>
<li>update 更新 xxl-job 执行器开关功能</li>
<li>update 代码生成 改为生成抽象实体</li>
<li>update 代码生成 搜索框 更新文本域生成 用于模糊查询</li>
<li>update 通用数据注入改为适配通用实体类</li>
<li>update 使用路由懒加载提升页面响应速度</li>
<li>update 迁移所有脚本文件至 script 目录</li>
<li>update swagger 组顺序配置</li>
<li>update sql 文件更新 xxljob 控制台菜单</li>
<li>update 前端增加 任务调度中心页面与环境及 nginx 配置</li>
<li>update 合并 oss.sql 至主 sql</li>
<li>update 补全国际化文件(英文)</li>
<li>update 更新关于全局路径设置与文档链接</li>
<li>update 删除无用 setUsername 使用自动注入</li>
<li>update RedisUtils 更新删除 hash 数据方法</li>
<li>fix 修复 多数据源 aop 语法错误</li>
<li>fix 修复 子菜单无 query 参数问题</li>
<li>fix 修复 oss 配置删除时删除缓存 bug</li>
<li>fix 修复无权限获取请求头 download-filename 导致文件名为空问题</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.2.0 - 2021-9-28">
<ol>
<li>update [重大改动]接口文档 支持分组配置</li>
<li>update [重大改动]security 路径配置抽取到配置文件</li>
<li>update [重大改动] framework system 模块 解耦 调整依赖结构 解决依赖冲突</li>
<li>update [重大改动]重写 防重提交实现 使用分布式锁 解决并发问题 压测通过</li>
<li>update springboot 2.5.4 => 2.5.5 bugfix版本</li>
<li>update mybatis-plus 3.4.3.3 => 3.4.3.4 bugfix版本</li>
<li>update redisson 3.16.2 => 3.16.3 bugfix版本</li>
<li>update easyexcel 2.2.10 => 2.2.11</li>
<li>update hutool 5.7.11 => 5.7.13</li>
<li>update file-saver 2.0.4 => 2.0.5</li>
<li>update dart-sass 1.32.0 => 1.32.13</li>
<li>update sass-loader 10.1.0 => 10.1.1</li>
<li>update 优化代码生成 根据MP生成特性 调整导入表结构默认值合理化</li>
<li>update 将所有 云存储字样 改为 对象存储 避免误解</li>
<li>update 更新 @Cacheable 错误用法 注意事项</li>
<li>update 优化 AddressUtils 空校验处理</li>
<li>update 菜单管理支持配置路由参数</li>
<li>update 优化aop语法 使用spring自动注入注解</li>
<li>update 使用 Redisson 限流工具 重写限流实现</li>
<li>update 使用 vue-data-dict 简化数据字典使用</li>
<li>update 增加日志注解新增是否保存响应参数开关</li>
<li>update 用户未登录日志改为 warn 级别</li>
<li>update OSS模块 关于下载403报错信息优化</li>
<li>update 更新 Actuator prod 默认暴漏端点 增加暴漏 logfile 日志端点</li>
<li>update 默认适配jdk11 测试 jdk17 无异常</li>
<li>update 封装通用下载方法简化下载使用</li>
<li>add 新增通用方法简化模态/缓存使用</li>
<li>add 增加 限流演示案例</li>
<li>add 增加 redis redisson 集群配置</li>
<li>fix Cron表达式生成器关闭时销毁避免再次打开时存在上一次修改的数据</li>
<li>fix 全局限流key会多出一个"-" 将其移动到IP后面 去除多余的空格</li>
<li>fix 修复多主键代码生成bug</li>
<li>fix 修复 @Cacheable @DataScope 冲突问题</li>
<li>fix 修复代码生成页面数据编辑保存之后总是跳转第一页的问题</li>
<li>remove 移除过期工具 RedisCache</li>
<li>remove 移除无用配置类 ServerConfig</li>
<li>remove 移除 SysUser 无用字段 salt</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.1.0 - 2021-9-7">
<ol>
<li>add [重大改动] 过期 RedisCache 新增 RedisUtils 工具类 新增 发布订阅功能 更灵巧便于使用</li>
<li>add [重大改动] 新增 saveOrUpdateAll 方法 可完美替代 saveOrUpdateBatch 高性能</li>
<li>update [重大改动] 重写 InsertAll 方法实现 可完美替代 saveBatch 秒级插入上万数据</li>
<li>update [重大改动] 更改OSS上传通用路径生成 按照年月日分三级目录</li>
<li>update [重大改动] MP字段验证策略更改为 NOT_NULL 个别特殊字段使用注解单独处理</li>
<li>update [重大改动] 所有业务适配 RedisUtils 新工具</li>
<li>update springboot 2.5.3 => 2.5.4</li>
<li>update spring-boot-admin 2.5.0 => 2.5.1</li>
<li>update mybatis-plus 3.4.3 => 3.4.3.3 适配升级 (包含不兼容升级)</li>
<li>update aliyun.oss 3.13.0 => 3.13.1</li>
<li>update qcloud.cos 5.6.47 => 5.6.51</li>
<li>update hutool 5.7.9 => 5.7.11</li>
<li>update maven-jar-plugin 3.1.1 => 3.2.0</li>
<li>update feign-okhttp 11.2 => 11.6</li>
<li>update redisson 3.16.1 => 3.16.2</li>
<li>add 优化 docker 增加 redis 配置文件</li>
<li>add 新增暗色菜单风格主题</li>
<li>add 菜单&部门新增展开/折叠功能</li>
<li>add 页签右键按钮添加图标 页签新增关闭左侧</li>
<li>update 优化 OSS 模块与上传组件 异常处理</li>
<li>update 更新 jackson 配置 支持 LocalDateTime 全局格式化</li>
<li>update 优化 使用权限工具 获取用户信息</li>
<li>update 自定义可拖动弹窗宽度指令</li>
<li>update 重构 将下载excel工具提取到全局</li>
<li>update 定时任务对检查异常进行事务回滚</li>
<li>update 优化spy配置文件为 UTF8编码 解决中文注释乱码问题</li>
<li>update 修改时检查用户数据权限范围</li>
<li>update 解决 logout 写死 无法扩展路径问题</li>
<li>update 优化代码生成 导入与同步 批处理效率</li>
<li>update 修改时检查用户数据权限范围</li>
<li>update 修改代码生成字典回显样式</li>
<li>update 修改数据字典回显</li>
<li>update 优化验证码配置 使用泛型 防止错误输入</li>
<li>update 优化全局线程池配置 使用泛型 防止错误输入</li>
<li>update 使用 MP 全局配置分页溢出</li>
<li>update 代码生成器 导入表时查询 新创建表的优先排序在前面</li>
<li>update 定时任务支持在线生成cron表达式</li>
<li>update 自定义弹层溢出滚动样式</li>
<li>update 优化分页工具排序处理</li>
<li>update 优化 oss配置 使用发布订阅工具 刷新配置</li>
<li>update 代码生成 查询数据库列表 按照时间倒序</li>
<li>update 使用MP自行判断数据库类型</li>
<li>fix 修复保存配置主题颜色失效问题</li>
<li>fix 修复 导出雪花id excel失真问题</li>
<li>fix 修复 druid 监控 集群模式下 无法路由到同一台服务器问题</li>
<li>fix 解决搜索校验不通过问题</li>
<li>fix 修复定时器工具编写错误问题</li>
<li>fix 修复 minio perfix 问题</li>
<li>fix 修复 富文本图片路径错误问题</li>
<li>fix 修复 OSS配置清空被过滤问题</li>
<li>fix 修复 excel 导入与 class 未对应问题</li>
<li>fix 修复字典组件值为整形不显示问题</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.0.0 - 2021-8-18">
<ol>
<li>add [重大更新]重写 OSS 模块相关实现 支持动态配置(页面配置)</li>
<li>add [重大更新]增加 jackson 超出 JS 最大数值自动转字符串(雪花id序列化)处理</li>
<li>add [重大更新]重写 防重提交拦截器 支持全局与注解自定义 拦截时间配置配置 优化逻辑</li>
<li>add [重大更新]新增是否开启用户注册功能</li>
<li>add [重大更新]增加 easyexcel 工具类</li>
<li>add [重大更新]集成 性能分析插件 p6spy 更强劲的 SQL 分析</li>
<li>add [重大更新]增加 完整国际化解决方案</li>
<li>add [重大更新]支持自定义注解实现接口限流</li>
<li>update feign-okhttp 11.0 => 11.2</li>
<li>update okhttp 3.19.4 => 4.9.1</li>
<li>update minio 8.2.0 => 8.3.0</li>
<li>update hutool 5.7.6 => 5.7.7</li>
<li>update element-ui 2.15.2 => 2.15.5</li>
<li>update springboot admin 2.4.3 => 2.5.0 (新增 Quartz 专属监控页)</li>
<li>add 增加 admin 监控客户端开关</li>
<li>add 增加 国际化演示demo</li>
<li>update 更新软件架构图</li>
<li>update 优化XSS跨站脚本过滤</li>
<li>update 优化BLOB下载时清除URL对象引用</li>
<li>update 更新 防重提交拦截器 demo演示案例</li>
<li>update 日常字符串校验 统一重构到 StringUtils 便于维护扩展</li>
<li>update 修改 自动注入器 用户未登录异常拦截抛出警告 返回Null</li>
<li>update 重构 统一使用 流工具下载</li>
<li>update 重写 所有业务导出 适配easyexcel工具</li>
<li>update 移动文件存储业务到 system 模块</li>
<li>update 代码生成模板 适配新excel导出</li>
<li>update Actuator 配置 移动到全局配置</li>
<li>update 统一镜像时区配置 移除主机时间映射</li>
<li>update 更改多数据源框架更清晰的依赖名</li>
<li>update 更新 阿里云 maven源 新地址</li>
<li>update 补全基础实体 文档注解</li>
<li>update 代码生成文档注解 增加必填判断配置</li>
<li>update 注入器 insert 增加 update 字段处理</li>
<li>update 默认首页使用keep-alive缓存</li>
<li>fix 生产minio回显问题</li>
<li>fix 修复角色分配用户页面接收参数与传递参数类型不一致导致的错误</li>
<li>fix 修复代码生成 删除按钮报错 loading 不取消问题</li>
<li>fix 解决登录后浏览器后台Breadcrumb组件报错</li>
<li>fix 修复DictUtils方法报错</li>
<li>fix 头像上传 未走OSS存储问题</li>
<li>fix oss列表 jpeg 不回显问题</li>
<li>fix 修复操作日志根据状态查询异常问题</li>
<li>remove 移除原生excel工具</li>
<li>remove 移除通用上传下载接口与配置</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v2.6.0 - 2021-7-28">
<ol>
<li>add [重大新增] 增加 OSS 对象存储模块</li>
<li>remove [重大改动] 删除 自带通用上传 接口 使用OSS模块替换<li>
<li>update [重大改动] 重写VO转换 支持深拷贝 将VO类抽象到 ServicePlus 泛型处理<li>
<li>update [重大改动] 多BO合并 使用分组校验 生成BO代码<li>
<li>update [重大改动] 重构 IServicePlus 功能 增加 BeanCopyUtils 深拷贝工具<li>
<li>update springboot 2.4.9 => 2.5.3<li>
<li>update hutool 5.7.4 => 5.7.6<li>
<li>update minio 8.2.2 => 8.3.0<li>
<li>update docker plugin 1.2.0 => 1.2.2<li>
<li>update redisson 3.16.0 => 3.16.1<li>
<li>update datasource 3.4.0 => 3.4.1<li>
<li>update element-ui 2.15.2 => 2.15.3<li>
<li>add 演示Demo增加自定义分页接口案例</li>
<li>add 角色&菜单新增字段属性提示信息</li>
<li>update 更新druid配置 独立配置更明显</li>
<li>update 顶部菜单排除隐藏的默认路由</li>
<li>update 富文本新增上传文件大小限制</li>
<li>update 导入用户样式调整</li>
<li>update 顶部菜单样式调整</li>
<li>update 密码框新增显示切换密码图标</li>
<li>update 内链设置meta信息</li>
<li>update 跳转路由高亮相对应的菜单栏</li>
<li>fix 修复多数据源druid全局配置缩进错误 引起无效配置问题</li>
<li>fix 修复定时任务日志执行状态显示</li>
<li>fix 修复 授权角色空数据问题</li>
<li>fix 修复 DictData 删除逻辑问题</li>
<li>fix 修复任意账户越权漏洞</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v2.5.2 - 2021-7-19">
<ol>
<li>update 优化代码生成器注释格式</li>
<li>fix 回滚代码生成 批处理优化</li>
<li>fix 代码生成 queryType 重复勾选数据库无默认值问题</li>
<li>fix 修复接口单参数校验无效问题</li>
<li>fix 代码生成 queryType >= <= 标识符错误问题</li>
<li>fix 修复代码生成字典问题</li>
<li>fix 修复 thread-pool: enabled 配置不生效问题</li>
<li>remove 删除无用文档与脚本</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v2.5.1 - 2021-7-13">
<ol>
<li>update 验证码开关 转移到表 参数管理 </li>
<li>update 使用hutool重构 判断是否url</li>
<li>fix 修复 docker业务集群部署与文件上传的问题</li>
<li>fix 修复代码生成同步表结构id冲突问题</li>
<li>fix 修复代码生成选择字典 无法取消问题</li>
<li>fix 修复代码生成字典为null问题</li>
<li>fix 图片上传 多图时无法删除相应图片修复</li>
<li>remove 删除富文本video事件</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v2.5.0 - 2021-7-12">
<ol>
<li>update springboot 2.4.7 => 2.4.8</li>
<li>update knife4j 3.0.2 => 3.0.3</li>
<li>update hutool 5.7.2 => 5.7.4</li>
<li>update spring-boot-admin 2.4.1 => 2.4.3</li>
<li>update redisson 3.15.2 => 3.16.0</li>
<li>add 增加 docker 编排 shell 脚本</li>
<li>add 增加 feign 熔断 自定义结构体解析方法 demo 注释</li>
<li>add 用户管理新增分配角色功能</li>
<li>add 角色管理新增分配用户功能</li>
<li>add 增加spring-cache演示案例</li>
<li>update 独立 springboot-admin 监控到扩展模块项目</li>
<li>update springboot-admin 监控 增加用户登录权限管理</li>
<li>update 优化代码生成器 批量导入</li>
<li>update 优化 增加MP注入异常拦截</li>
<li>update 关闭默认二级缓存 推荐使用 spring-cache 注解手动缓存</li>
<li>update FileUpload ImageUpload组件 支持多图片上传</li>
<li>update 优化中英文语言配置</li>
<li>update 规范maven写法</li>
<li>fix redis获取map属性bug修复</li>
<li>fix 修复 按钮loading 后端500卡死问题</li>
<li>fix 相对路径下载问题</li>
<li>fix 修复 hutool 工具返回结果不一致问题</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v2.4.0 - 2021-6-24">
<ol>
<li>update springboot 2.3.11 => 2.4.7</li>
<li>update springboot-admin 2.3.1 => 2.4.1</li>
<li>update feign 2.2.6 => 3.0.3</li>
<li>update hutool 5.6.7 => 5.7.2</li>
<li>update 多数据源替换成dynamic-datasource</li>
<li>update 适配 jdk11</li>
<li>update 集成 Lock4j 分布式锁</li>
<li>update 移除 fastjson 增加 jackson 工具类 重写相关业务</li>
<li>update 优化 异步工厂重写 使用 spring 异步处理</li>
<li>update 全局挂载字典标签组件</li>
<li>update 日志列表支持排序操作</li>
<li>update 更新 feign demo 更清晰的用法</li>
<li>update 更新多数据源演示案例</li>
<li>add 增加 ServicePlusImpl 自动以实现类 重写移除事务注解方法 防止多数据源失效</li>
<li>add 增加 自定义 批量insert方法</li>
<li>add 增加 Swagger3 用法示例</li>
<li>fix 修复地址ip地址特殊回环问题</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v2.3.2 - 2021-6-11">
<ol>
<li>add redis锁工具类编写</li>
<li>update spring-cache 整合 redisson</li>
<li>update MybatisPlus整合Redis二级缓存</li>
<li>update swagger 升级为 3.0.0 使用 OAS_30 协议</li>
<li>update 优化 代码生成器 增加表单防重注解</li>
<li>update 优化 锁切面代码 key到常量类</li>
<li>fix 修复相对路径上传异常问题</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v2.3.1 - 2021-6-4">
<ol>
<li>add 增加 redisson 分布式锁 注解与demo案例</li>
<li>add 增加 Oracle 分支</li>
<li>update 优化 redis 空密码兼容性</li>
<li>update 优化前端代码生成按钮增加 loading</li>
<li>fix 修复 redisson 不能批量删除的bug</li>
<li>fix 修复表单构建选择下拉选择控制台报错问题</li>
<li>fix 修复 vo 代码生成 主键列表显示 重复生成bug</li>
<li>fix 修复上传路径 win 打包编译为 win 路径, linux 报错bug</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v2.3.0 - 2021-6-1">
<ol>
<li>add 升级 luttuce redisson 性能更强 工具更全</li>
<li>add 增加测试数据sql文件</li>
<li>add 增加demo模块 单表演示案例(包含数据权限)</li>
<li>update 完美修复 数据权限功能(支持单表多表过滤)</li>
<li>update 优化代码生成模板</li>
<li>update 优化 system 模块 批量操作性能</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v2.2.1 - 2021-5-29">
<ol>
<li>add 增加 security 权限框架 @Async 异步注解配置</li>
<li>update 优化dataScope参数防止注入</li>
<li>update 优化参数&字典缓存操作</li>
<li>update 增加修改包名文档</li>
<li>update 文档增加演示图例</li>
<li>fix 修复部门类sql符号错误</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v2.2.0 - 2021-5-25">
<ol>
<li>同步升级 RuoYi-Vue 3.5.0</li>
<li>add 增加验证码开关</li>
<li>add 新增IE浏览器版本过低提示页面</li>
<li>update 升级druid到最新版本v1.2.6</li>
<li>update 升级fastjson到最新版1.2.76</li>
<li>update 修改bo加入判断是否设置必填再加载必填注解</li>
<li>update 生成vue模板导出按钮点击后添加遮罩</li>
<li>update Redis设置HashKey序列化</li>
<li>update 优化Redis序列化配置</li>
<li>fix 修复代码生成器中表字段取消必填无法更新问题</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v2.1.2 - 2021-5-21">
<ol>
<li>update springboot 升级 2.3.11</li>
<li>update mybatis-plus 升级 3.4.3 分页Plus对象适配更新</li>
<li>update 验证码生成更新为无符号整数计算</li>
<li>update 请求响应对象 分页对象 结构修改 适配接口文档配置</li>
<li>update swagger增加请求前缀</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v2.1.1 - 2021-5-19">
<ol>
<li>update 配置统一提取为 properties 配置类</li>
<li>update 分页工具 删除过期方法</li>
<li>update admin 实时监控日志 改为保留一天</li>
<li>fix 修复swagger开关无法控制关闭问题</li>
<li>fix maven install 异常</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v2.1.0 - 2021-5-17">
<ol>
<li>update knife4j升级3.0.2</li>
<li>update 增强分页工具兼容性</li>
<li>update 通用Service接口 增加自定义vo转换函数</li>
<li>remove 移除ruoyi自带服务监控(Admin已全部包含)</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v2.0.0 - 2021-5-15">
<ol>
<li>springboot 升级 2.3.10 依赖全面升级适配</li>
<li>add 增加分页工具</li>
<li>add 增加 增强Mapper 增强Service 重写业务适配</li>
<li>add 代码生成器 增加校验注解</li>
<li>update 代码生成器修改为MP分页</li>
<li>update 使用 MP 分页工具 重构业务</li>
<li>update 重写文档介绍</li>
<li>remove 移除 pagehelper 分页工具</li>
<li>fix 修复代码生成 数据权限问题</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v1.0.2 - 2021-5-13">
<ol>
<li>update 更新整合打包文档 重新排版</li>
<li>fix vue与boot整合打包与admin页面路由冲突</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v1.0.1 - 2021-5-11">
<ol>
<li>update 更新banner</li>
<li>update 配置转移到 yml 文件 统一管理</li>
<li>update 上传媒体类型添加视频格式</li>
<li>update 树级结构更新子节点使用replaceFirst</li>
<li>update 删除操作日志记录日志</li>
<li>fix 修正导入表权限标识</li>
<li>fix 文件上传时报错</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v1.0.0 - 2021-5-10">
<ol>
<li>RuoYi-Vue-Plus 后台管理系统正式发布</li>
<li>ORM框架 使用 Mybatis-Plus 3.4.2 简化CRUD</li>
<li>Bean简化 使用 Lombok 简化 get set toString 等等</li>
<li>容器改动 Tomcat 改为 并发性能更好的 undertow</li>
<li>所有原生功能使用 Mybatis-Plus Lombok 重写</li>
<li>代码生成模板 改为适配 Mybatis-Plus 的代码</li>
<li>代码生成模板 拆分出Vo,QueryBo,AddBo,EditBo等领域对象</li>
<li>项目修改为 maven多环境配置</li>
<li>swagger 修改为 knife4j</li>
<li>集成 Hutool 5.X 并重写RuoYi部分功能</li>
<li>集成 Feign 接口化管理 Http 请求(如三方请求 支付,短信,推送等)</li>
<li>集成 spring-boot-admin 全方位监控</li>
<li>增加demo模块示例(给不会增加模块的小伙伴做参考)</li>
</ol>
</el-collapse-item>
</el-collapse>
</el-card>
</el-col>
</el-row>
</div>
</template>
@ -731,7 +114,7 @@ export default {
data() {
return {
//
version: "4.0.1",
version: "4.1.0",
};
},
methods: {

View File

@ -1,12 +1,11 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="登录地址" prop="ipaddr">
<el-input
v-model="queryParams.ipaddr"
placeholder="请输入登录地址"
clearable
size="small"
style="width: 240px;"
@keyup.enter.native="handleQuery"
/>
@ -16,7 +15,6 @@
v-model="queryParams.userName"
placeholder="请输入用户名称"
clearable
size="small"
style="width: 240px;"
@keyup.enter.native="handleQuery"
/>
@ -26,7 +24,6 @@
v-model="queryParams.status"
placeholder="登录状态"
clearable
size="small"
style="width: 240px"
>
<el-option
@ -40,7 +37,6 @@
<el-form-item label="登录时间">
<el-date-picker
v-model="dateRange"
size="small"
style="width: 240px"
value-format="yyyy-MM-dd"
type="daterange"

View File

@ -1,12 +1,11 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="68px">
<el-form-item label="登录地址" prop="ipaddr">
<el-input
v-model="queryParams.ipaddr"
placeholder="请输入登录地址"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
@ -15,7 +14,6 @@
v-model="queryParams.userName"
placeholder="请输入用户名称"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>

View File

@ -1,12 +1,11 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="系统模块" prop="title">
<el-input
v-model="queryParams.title"
placeholder="请输入系统模块"
clearable
size="small"
style="width: 240px;"
@keyup.enter.native="handleQuery"
/>
@ -16,7 +15,6 @@
v-model="queryParams.operName"
placeholder="请输入操作人员"
clearable
size="small"
style="width: 240px;"
@keyup.enter.native="handleQuery"
/>
@ -26,7 +24,6 @@
v-model="queryParams.businessType"
placeholder="操作类型"
clearable
size="small"
style="width: 240px"
>
<el-option
@ -42,7 +39,6 @@
v-model="queryParams.status"
placeholder="操作状态"
clearable
size="small"
style="width: 240px"
>
<el-option
@ -56,7 +52,6 @@
<el-form-item label="操作时间">
<el-date-picker
v-model="dateRange"
size="small"
style="width: 240px"
value-format="yyyy-MM-dd"
type="daterange"

View File

@ -1,12 +1,11 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="参数名称" prop="configName">
<el-input
v-model="queryParams.configName"
placeholder="请输入参数名称"
clearable
size="small"
style="width: 240px"
@keyup.enter.native="handleQuery"
/>
@ -16,13 +15,12 @@
v-model="queryParams.configKey"
placeholder="请输入参数键名"
clearable
size="small"
style="width: 240px"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="系统内置" prop="configType">
<el-select v-model="queryParams.configType" placeholder="系统内置" clearable size="small">
<el-select v-model="queryParams.configType" placeholder="系统内置" clearable>
<el-option
v-for="dict in dict.type.sys_yes_no"
:key="dict.value"
@ -34,7 +32,6 @@
<el-form-item label="创建时间">
<el-date-picker
v-model="dateRange"
size="small"
style="width: 240px"
value-format="yyyy-MM-dd"
type="daterange"

View File

@ -1,17 +1,16 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
<el-form-item label="部门名称" prop="deptName">
<el-input
v-model="queryParams.deptName"
placeholder="请输入部门名称"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="部门状态" clearable size="small">
<el-select v-model="queryParams.status" placeholder="部门状态" clearable>
<el-option
v-for="dict in dict.type.sys_normal_disable"
:key="dict.value"

View File

@ -1,8 +1,8 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="字典名称" prop="dictType">
<el-select v-model="queryParams.dictType" size="small">
<el-select v-model="queryParams.dictType">
<el-option
v-for="item in typeOptions"
:key="item.dictId"
@ -16,12 +16,11 @@
v-model="queryParams.dictLabel"
placeholder="请输入字典标签"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="数据状态" clearable size="small">
<el-select v-model="queryParams.status" placeholder="数据状态" clearable>
<el-option
v-for="dict in dict.type.sys_normal_disable"
:key="dict.value"

View File

@ -1,12 +1,11 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="字典名称" prop="dictName">
<el-input
v-model="queryParams.dictName"
placeholder="请输入字典名称"
clearable
size="small"
style="width: 240px"
@keyup.enter.native="handleQuery"
/>
@ -16,7 +15,6 @@
v-model="queryParams.dictType"
placeholder="请输入字典类型"
clearable
size="small"
style="width: 240px"
@keyup.enter.native="handleQuery"
/>
@ -26,7 +24,6 @@
v-model="queryParams.status"
placeholder="字典状态"
clearable
size="small"
style="width: 240px"
>
<el-option
@ -40,7 +37,6 @@
<el-form-item label="创建时间">
<el-date-picker
v-model="dateRange"
size="small"
style="width: 240px"
value-format="yyyy-MM-dd"
type="daterange"

View File

@ -1,17 +1,16 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
<el-form-item label="菜单名称" prop="menuName">
<el-input
v-model="queryParams.menuName"
placeholder="请输入菜单名称"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="菜单状态" clearable size="small">
<el-select v-model="queryParams.status" placeholder="菜单状态" clearable>
<el-option
v-for="dict in dict.type.sys_normal_disable"
:key="dict.value"
@ -208,7 +207,7 @@
</el-col>
<el-col :span="12" v-if="form.menuType == 'C'">
<el-form-item>
<el-input v-model="form.query" placeholder="请输入路由参数" maxlength="255" />
<el-input v-model="form.queryParam" placeholder="请输入路由参数" maxlength="255" />
<span slot="label">
<el-tooltip content='访问路由的默认传递参数,如:`{"id": 1, "name": "ry"}`' placement="top">
<i class="el-icon-question"></i>

View File

@ -1,12 +1,11 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="公告标题" prop="noticeTitle">
<el-input
v-model="queryParams.noticeTitle"
placeholder="请输入公告标题"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
@ -15,12 +14,11 @@
v-model="queryParams.createBy"
placeholder="请输入操作人员"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="类型" prop="noticeType">
<el-select v-model="queryParams.noticeType" placeholder="公告类型" clearable size="small">
<el-select v-model="queryParams.noticeType" placeholder="公告类型" clearable>
<el-option
v-for="dict in dict.type.sys_notice_type"
:key="dict.value"

View File

@ -1,12 +1,11 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="岗位编码" prop="postCode">
<el-input
v-model="queryParams.postCode"
placeholder="请输入岗位编码"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
@ -15,12 +14,11 @@
v-model="queryParams.postName"
placeholder="请输入岗位名称"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="岗位状态" clearable size="small">
<el-select v-model="queryParams.status" placeholder="岗位状态" clearable>
<el-option
v-for="dict in dict.type.sys_normal_disable"
:key="dict.value"

View File

@ -1,12 +1,11 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" v-show="showSearch" :inline="true">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
<el-form-item label="用户名称" prop="userName">
<el-input
v-model="queryParams.userName"
placeholder="请输入用户名称"
clearable
size="small"
style="width: 240px"
@keyup.enter.native="handleQuery"
/>
@ -16,7 +15,6 @@
v-model="queryParams.phonenumber"
placeholder="请输入手机号码"
clearable
size="small"
style="width: 240px"
@keyup.enter.native="handleQuery"
/>

View File

@ -1,12 +1,11 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" v-show="showSearch" :inline="true">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
<el-form-item label="角色名称" prop="roleName">
<el-input
v-model="queryParams.roleName"
placeholder="请输入角色名称"
clearable
size="small"
style="width: 240px"
@keyup.enter.native="handleQuery"
/>
@ -16,7 +15,6 @@
v-model="queryParams.roleKey"
placeholder="请输入权限字符"
clearable
size="small"
style="width: 240px"
@keyup.enter.native="handleQuery"
/>
@ -26,7 +24,6 @@
v-model="queryParams.status"
placeholder="角色状态"
clearable
size="small"
style="width: 240px"
>
<el-option
@ -40,7 +37,6 @@
<el-form-item label="创建时间">
<el-date-picker
v-model="dateRange"
size="small"
style="width: 240px"
value-format="yyyy-MM-dd"
type="daterange"

View File

@ -1,13 +1,12 @@
<template>
<!-- 授权用户 -->
<el-dialog title="选择用户" :visible.sync="visible" width="800px" top="5vh" append-to-body>
<el-form :model="queryParams" ref="queryForm" :inline="true">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true">
<el-form-item label="用户名称" prop="userName">
<el-input
v-model="queryParams.userName"
placeholder="请输入用户名称"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
@ -16,7 +15,6 @@
v-model="queryParams.phonenumber"
placeholder="请输入手机号码"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>

View File

@ -27,13 +27,12 @@
</el-col>
<!--用户数据-->
<el-col :span="20" :xs="24">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="用户名称" prop="userName">
<el-input
v-model="queryParams.userName"
placeholder="请输入用户名称"
clearable
size="small"
style="width: 240px"
@keyup.enter.native="handleQuery"
/>
@ -43,7 +42,6 @@
v-model="queryParams.phonenumber"
placeholder="请输入手机号码"
clearable
size="small"
style="width: 240px"
@keyup.enter.native="handleQuery"
/>
@ -53,7 +51,6 @@
v-model="queryParams.status"
placeholder="用户状态"
clearable
size="small"
style="width: 240px"
>
<el-option
@ -67,7 +64,6 @@
<el-form-item label="创建时间">
<el-date-picker
v-model="dateRange"
size="small"
style="width: 240px"
value-format="yyyy-MM-dd"
type="daterange"

View File

@ -1,13 +1,12 @@
<template>
<!-- 导入表 -->
<el-dialog title="导入表" :visible.sync="visible" width="800px" top="5vh" append-to-body>
<el-form :model="queryParams" ref="queryForm" :inline="true">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true">
<el-form-item label="表名称" prop="tableName">
<el-input
v-model="queryParams.tableName"
placeholder="请输入表名称"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
@ -16,7 +15,6 @@
v-model="queryParams.tableComment"
placeholder="请输入表描述"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>

View File

@ -1,12 +1,19 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="数据源" prop="dataName">
<el-input
v-model="queryParams.dataName"
placeholder="请输入数据源名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="表名称" prop="tableName">
<el-input
v-model="queryParams.tableName"
placeholder="请输入表名称"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
@ -15,14 +22,12 @@
v-model="queryParams.tableComment"
placeholder="请输入表描述"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker
v-model="dateRange"
size="small"
style="width: 240px"
value-format="yyyy-MM-dd"
type="daterange"
@ -220,7 +225,8 @@ export default {
pageNum: 1,
pageSize: 10,
tableName: undefined,
tableComment: undefined
tableComment: undefined,
dataName: "master"
},
//
preview: {
@ -232,6 +238,7 @@ export default {
};
},
created() {
localStorage.setItem("dataName", this.queryParams.dataName);
this.getList();
},
activated() {
@ -255,6 +262,7 @@ export default {
},
/** 搜索按钮操作 */
handleQuery() {
localStorage.setItem("dataName", this.queryParams.dataName);
this.queryParams.pageNum = 1;
this.getList();
},
@ -321,7 +329,9 @@ export default {
/** 修改按钮操作 */
handleEditTable(row) {
const tableId = row.tableId || this.ids[0];
this.$router.push({ path: '/tool/gen-edit/index/' + tableId, query: { pageNum: this.queryParams.pageNum } });
const tableName = row.tableName || this.tableNames[0];
const params = { pageNum: this.queryParams.pageNum };
this.$tab.openPage("修改[" + tableName + "]生成配置", '/tool/gen-edit/index/' + tableId, params);
},
/** 删除按钮操作 */
handleDelete(row) {

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.0.1</version>
<version>4.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
@ -62,16 +62,26 @@
<artifactId>swagger-annotations</artifactId>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
</dependency>
<!-- Mysql驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- Oracle -->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
</dependency>
<!-- PostgreSql -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<!-- SqlServer -->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
</dependency>
<!-- Sa-Token 权限认证, 在线文档http://sa-token.dev33.cn/ -->
<dependency>
@ -234,6 +244,10 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>

View File

@ -22,8 +22,8 @@ public @interface RepeatSubmit {
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
/**
* 提示消息
* 提示消息 支持国际化 格式为 {code}
*/
String message() default "不允许重复提交,请稍候再试";
String message() default "{repeat.submit.message}";
}

View File

@ -65,12 +65,12 @@ public interface Constants {
/**
* 登录用户 redis key
*/
public static final String LOGIN_TOKEN_KEY = "Authorization:login:token:";
String LOGIN_TOKEN_KEY = "Authorization:login:token:";
/**
* 在线用户 redis key
*/
public static final String ONLINE_TOKEN_KEY = "online_tokens:";
String ONLINE_TOKEN_KEY = "online_tokens:";
/**
* 防重提交 redis key

View File

@ -22,11 +22,21 @@ public interface UserConstants {
*/
String EXCEPTION = "1";
/**
* 用户正常状态
*/
String USER_NORMAL = "0";
/**
* 用户封禁状态
*/
String USER_DISABLE = "1";
/**
* 角色正常状态
*/
String ROLE_NORMAL = "0";
/**
* 角色封禁状态
*/
@ -62,6 +72,16 @@ public interface UserConstants {
*/
String NO_FRAME = "1";
/**
* 菜单正常状态
*/
String MENU_NORMAL = "0";
/**
* 菜单停用状态
*/
String MENU_DISABLE = "1";
/**
* 菜单类型目录
*/

View File

@ -16,7 +16,7 @@ import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)
public class TreeEntity extends BaseEntity {
public class TreeEntity<T> extends BaseEntity {
private static final long serialVersionUID = 1L;
@ -38,6 +38,6 @@ public class TreeEntity extends BaseEntity {
*/
@TableField(exist = false)
@ApiModelProperty(value = "子部门")
private List<?> children = new ArrayList<>();
private List<T> children = new ArrayList<>();
}

View File

@ -24,7 +24,7 @@ import javax.validation.constraints.Size;
@EqualsAndHashCode(callSuper = true)
@TableName("sys_dept")
@ApiModel("部门业务对象")
public class SysDept extends TreeEntity {
public class SysDept extends TreeEntity<SysDept> {
private static final long serialVersionUID = 1L;
/**
@ -47,7 +47,7 @@ public class SysDept extends TreeEntity {
*/
@ApiModelProperty(value = "显示顺序")
@NotNull(message = "显示顺序不能为空")
private Long orderNum;
private Integer orderNum;
/**
* 负责人

View File

@ -42,7 +42,7 @@ public class SysDictData extends BaseEntity {
*/
@ApiModelProperty(value = "字典排序")
@ExcelProperty(value = "字典排序")
private Long dictSort;
private Integer dictSort;
/**
* 字典标签

View File

@ -14,6 +14,7 @@ import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
/**
@ -53,6 +54,7 @@ public class SysDictType extends BaseEntity {
@ExcelProperty(value = "字典类型")
@NotBlank(message = "字典类型不能为空")
@Size(min = 0, max = 100, message = "字典类型类型长度不能超过100个字符")
@Pattern(regexp = "^[a-z][a-z0-9_]*$", message = "字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)")
private String dictType;
/**

View File

@ -1,8 +1,8 @@
package com.ruoyi.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.ruoyi.common.core.domain.TreeEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ -23,7 +23,7 @@ import javax.validation.constraints.Size;
@EqualsAndHashCode(callSuper = true)
@TableName("sys_menu")
@ApiModel("菜单权限业务对象")
public class SysMenu extends TreeEntity {
public class SysMenu extends TreeEntity<SysMenu> {
/**
* 菜单ID
@ -45,7 +45,7 @@ public class SysMenu extends TreeEntity {
*/
@ApiModelProperty(value = "显示顺序")
@NotNull(message = "显示顺序不能为空")
private Long orderNum;
private Integer orderNum;
/**
* 路由地址
@ -65,8 +65,7 @@ public class SysMenu extends TreeEntity {
* 路由参数
*/
@ApiModelProperty(value = "路由参数")
@TableField("`query`")
private String query;
private String queryParam;
/**
* 是否为外链0是 1否
@ -103,6 +102,7 @@ public class SysMenu extends TreeEntity {
* 权限字符串
*/
@ApiModelProperty(value = "权限字符串")
@JsonInclude(JsonInclude.Include.NON_NULL)
@Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符")
private String perms;

View File

@ -16,6 +16,7 @@ import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
/**
@ -62,8 +63,8 @@ public class SysRole extends BaseEntity {
*/
@ApiModelProperty(value = "角色排序")
@ExcelProperty(value = "角色排序")
@NotBlank(message = "显示顺序不能为空")
private String roleSort;
@NotNull(message = "显示顺序不能为空")
private Integer roleSort;
/**
* 数据范围1所有数据权限2自定义数据权限3本部门数据权限4本部门及以下数据权限5仅本人数据权限
@ -77,13 +78,13 @@ public class SysRole extends BaseEntity {
* 菜单树选择项是否关联显示 0父子不互相关联显示 1父子互相关联显示
*/
@ApiModelProperty(value = "菜单树选择项是否关联显示( 0父子不互相关联显示 1父子互相关联显示")
private boolean menuCheckStrictly;
private Boolean menuCheckStrictly;
/**
* 部门树选择项是否关联显示0父子不互相关联显示 1父子互相关联显示
*/
@ApiModelProperty(value = "部门树选择项是否关联显示0父子不互相关联显示 1父子互相关联显示 ")
private boolean deptCheckStrictly;
private Boolean deptCheckStrictly;
/**
* 角色状态0正常 1停用
@ -135,5 +136,4 @@ public class SysRole extends BaseEntity {
public boolean isAdmin() {
return UserConstants.ADMIN_ID.equals(this.roleId);
}
}

View File

@ -0,0 +1,33 @@
package com.ruoyi.common.core.domain.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* 短信登录对象
*
* @author Lion Li
*/
@Data
@ApiModel("短信登录对象")
public class SmsLoginBody {
/**
* 用户名
*/
@NotBlank(message = "{user.phonenumber.not.blank}")
@ApiModelProperty(value = "用户手机号")
private String phonenumber;
/**
* 用户密码
*/
@NotBlank(message = "{sms.code.not.blank}")
@ApiModelProperty(value = "短信验证码")
private String smsCode;
}

View File

@ -0,0 +1,24 @@
package com.ruoyi.common.core.domain.model;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
* 小程序登录用户身份权限
*
* @author Lion Li
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
public class XcxLoginUser extends LoginUser {
private static final long serialVersionUID = 1L;
/**
* openid
*/
private String openid;
}

View File

@ -0,0 +1,49 @@
package com.ruoyi.common.enums;
import com.ruoyi.common.utils.StringUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 数据库类型
*
* @author Lion Li
*/
@Getter
@AllArgsConstructor
public enum DataBaseType {
/**
* MySQL
*/
MY_SQL("MySQL"),
/**
* Oracle
*/
ORACLE("Oracle"),
/**
* PostgreSQL
*/
POSTGRE_SQL("PostgreSQL"),
/**
* SQL Server
*/
SQL_SERVER("Microsoft SQL Server");
private final String type;
public static DataBaseType find(String databaseProductName) {
if (StringUtils.isBlank(databaseProductName)) {
return null;
}
for (DataBaseType type : values()) {
if (type.getType().equals(databaseProductName)) {
return type;
}
}
return null;
}
}

View File

@ -21,7 +21,12 @@ public enum DeviceType {
/**
* app端
*/
APP("app");
APP("app"),
/**
* 小程序端
*/
XCX("xcx");
private final String device;
}

View File

@ -0,0 +1,39 @@
package com.ruoyi.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 登录类型
*
* @author Lion Li
*/
@Getter
@AllArgsConstructor
public enum LoginType {
/**
* 密码登录
*/
PASSWORD("user.password.retry.limit.exceed", "user.password.retry.limit.count"),
/**
* 短信登录
*/
SMS("sms.code.retry.limit.exceed", "sms.code.retry.limit.count"),
/**
* 小程序登录
*/
XCX("", "");
/**
* 登录重试超出限制提示
*/
final String retryLimitExceed;
/**
* 登录重试限制计数提示
*/
final String retryLimitCount;
}

View File

@ -1,26 +0,0 @@
package com.ruoyi.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 线程池 拒绝策略 泛型
*
* @author Lion Li
*/
@Getter
@AllArgsConstructor
public enum ThreadPoolRejectedPolicy {
CALLER_RUNS_POLICY("调用方执行", ThreadPoolExecutor.CallerRunsPolicy.class),
DISCARD_OLDEST_POLICY("放弃最旧的", ThreadPoolExecutor.DiscardOldestPolicy.class),
DISCARD_POLICY("丢弃", ThreadPoolExecutor.DiscardPolicy.class),
ABORT_POLICY("中止", ThreadPoolExecutor.AbortPolicy.class);
private final String name;
private final Class<? extends RejectedExecutionHandler> clazz;
}

View File

@ -0,0 +1,72 @@
package com.ruoyi.common.helper;
import cn.hutool.core.convert.Convert;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.ruoyi.common.enums.DataBaseType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.spring.SpringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
/**
* 数据库助手
*
* @author Lion Li
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class DataBaseHelper {
private static final DynamicRoutingDataSource DS = SpringUtils.getBean(DynamicRoutingDataSource.class);
/**
* 获取当前数据库类型
*/
public static DataBaseType getDataBaseType() {
DataSource dataSource = DS.determineDataSource();
try (Connection conn = dataSource.getConnection()) {
DatabaseMetaData metaData = conn.getMetaData();
String databaseProductName = metaData.getDatabaseProductName();
return DataBaseType.find(databaseProductName);
} catch (SQLException e) {
throw new ServiceException(e.getMessage());
}
}
public static boolean isMySql() {
return DataBaseType.MY_SQL == getDataBaseType();
}
public static boolean isOracle() {
return DataBaseType.ORACLE == getDataBaseType();
}
public static boolean isPostgerSql() {
return DataBaseType.POSTGRE_SQL == getDataBaseType();
}
public static boolean isSqlServer() {
return DataBaseType.SQL_SERVER == getDataBaseType();
}
public static String findInSet(Object var1, String var2) {
DataBaseType dataBasyType = getDataBaseType();
String var = Convert.toStr(var1);
if (dataBasyType == DataBaseType.SQL_SERVER) {
// charindex(',100,' , ',0,100,101,') <> 0
return "charindex('," + var + ",' , ','+" + var2 + "+',') <> 0";
} else if (dataBasyType == DataBaseType.POSTGRE_SQL) {
// (select position(',100,' in ',0,100,101,')) <> 0
return "(select position('," + var + ",' in ','||" + var2 + "||',')) <> 0";
} else if (dataBasyType == DataBaseType.ORACLE) {
// instr(',0,100,101,' , ',100,') <> 0
return "instr(','||" + var2 + "||',' , '," + var + ",') <> 0";
}
// find_in_set(100 , '0,100,101')
return "find_in_set(" + var + " , " + var2 + ") <> 0";
}
}

View File

@ -1,15 +1,20 @@
package com.ruoyi.common.utils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.SimpleCache;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.extra.cglib.CglibUtil;
import cn.hutool.core.util.StrUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.cglib.core.Converter;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* bean深拷贝工具(基于 cglib 性能优异)
@ -37,7 +42,8 @@ public class BeanCopyUtils {
if (ObjectUtil.isNull(desc)) {
return null;
}
return CglibUtil.copy(source, desc);
final V target = ReflectUtil.newInstanceIfPossible(desc);
return copy(source, target);
}
/**
@ -54,7 +60,8 @@ public class BeanCopyUtils {
if (ObjectUtil.isNull(desc)) {
return null;
}
CglibUtil.copy(source, desc);
BeanCopier beanCopier = BeanCopierCache.INSTANCE.get(source.getClass(), desc.getClass(), null);
beanCopier.copy(source, desc, null);
return desc;
}
@ -72,7 +79,11 @@ public class BeanCopyUtils {
if (CollUtil.isEmpty(sourceList)) {
return CollUtil.newArrayList();
}
return CglibUtil.copyList(sourceList, () -> ReflectUtil.newInstanceIfPossible(desc));
return sourceList.stream().map(source -> {
V target = ReflectUtil.newInstanceIfPossible(desc);
copy(source, target);
return target;
}).collect(Collectors.toList());
}
/**
@ -81,11 +92,12 @@ public class BeanCopyUtils {
* @param bean 数据来源实体
* @return map对象
*/
@SuppressWarnings("unchecked")
public static <T> Map<String, Object> copyToMap(T bean) {
if (ObjectUtil.isNull(bean)) {
return null;
}
return CglibUtil.toMap(bean);
return BeanMap.create(bean);
}
/**
@ -102,7 +114,8 @@ public class BeanCopyUtils {
if (ObjectUtil.isNull(beanClass)) {
return null;
}
return CglibUtil.toBean(map, beanClass);
T bean = ReflectUtil.newInstanceIfPossible(beanClass);
return mapToBean(map, bean);
}
/**
@ -119,6 +132,54 @@ public class BeanCopyUtils {
if (ObjectUtil.isNull(bean)) {
return null;
}
return CglibUtil.fillBean(map, bean);
BeanMap.create(bean).putAll(map);
return bean;
}
/**
* BeanCopier属性缓存<br>
* 缓存用于防止多次反射造成的性能问题
*
* @author Looly
* @since 5.4.1
*/
public enum BeanCopierCache {
/**
* BeanCopier属性缓存单例
*/
INSTANCE;
private final SimpleCache<String, BeanCopier> cache = new SimpleCache<>();
/**
* 获得类与转换器生成的key在{@link BeanCopier}的Map中对应的元素
*
* @param srcClass 源Bean的类
* @param targetClass 目标Bean的类
* @param converter 转换器
* @return Map中对应的BeanCopier
*/
public BeanCopier get(Class<?> srcClass, Class<?> targetClass, Converter converter) {
final String key = genKey(srcClass, targetClass, converter);
return cache.get(key, () -> BeanCopier.create(srcClass, targetClass, converter != null));
}
/**
* 获得类与转换器生成的key
*
* @param srcClass 源Bean的类
* @param targetClass 目标Bean的类
* @param converter 转换器
* @return 属性名和Map映射的key
*/
private String genKey(Class<?> srcClass, Class<?> targetClass, Converter converter) {
final StringBuilder key = StrUtil.builder()
.append(srcClass.getName()).append('#').append(targetClass.getName());
if(null != converter){
key.append('#').append(converter.getClass().getName());
}
return key.toString();
}
}
}

View File

@ -22,17 +22,17 @@ import java.util.Date;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
public static String YYYY = "yyyy";
public static final String YYYY = "yyyy";
public static String YYYY_MM = "yyyy-MM";
public static final String YYYY_MM = "yyyy-MM";
public static String YYYY_MM_DD = "yyyy-MM-dd";
public static final String YYYY_MM_DD = "yyyy-MM-dd";
public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
private static String[] parsePatterns = {
private static final String[] PARSE_PATTERNS = {
"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
@ -55,27 +55,27 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
return dateTimeNow(YYYY_MM_DD);
}
public static final String getTime() {
public static String getTime() {
return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
}
public static final String dateTimeNow() {
public static String dateTimeNow() {
return dateTimeNow(YYYYMMDDHHMMSS);
}
public static final String dateTimeNow(final String format) {
public static String dateTimeNow(final String format) {
return parseDateToStr(format, new Date());
}
public static final String dateTime(final Date date) {
public static String dateTime(final Date date) {
return parseDateToStr(YYYY_MM_DD, date);
}
public static final String parseDateToStr(final String format, final Date date) {
public static String parseDateToStr(final String format, final Date date) {
return new SimpleDateFormat(format).format(date);
}
public static final Date dateTime(final String format, final String ts) {
public static Date dateTime(final String format, final String ts) {
try {
return new SimpleDateFormat(format).parse(ts);
} catch (ParseException e) {
@ -86,7 +86,7 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
/**
* 日期路径 即年// 如2018/08/08
*/
public static final String datePath() {
public static String datePath() {
Date now = new Date();
return DateFormatUtils.format(now, "yyyy/MM/dd");
}
@ -94,7 +94,7 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
/**
* 日期路径 即年// 如20180808
*/
public static final String dateTime() {
public static String dateTime() {
Date now = new Date();
return DateFormatUtils.format(now, "yyyyMMdd");
}
@ -107,7 +107,7 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
return null;
}
try {
return parseDate(str.toString(), parsePatterns);
return parseDate(str.toString(), PARSE_PATTERNS);
} catch (ParseException e) {
return null;
}
@ -124,8 +124,7 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
/**
* 计算相差天数
*/
public static int differentDaysByMillisecond(Date date1, Date date2)
{
public static int differentDaysByMillisecond(Date date1, Date date2) {
return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
}

View File

@ -45,7 +45,7 @@ public class TestBatchController extends BaseController {
List<TestDemo> list = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
TestDemo testDemo = new TestDemo();
testDemo.setOrderNum(-1L);
testDemo.setOrderNum(-1);
testDemo.setTestKey("批量新增");
testDemo.setValue("测试新增");
list.add(testDemo);
@ -65,7 +65,7 @@ public class TestBatchController extends BaseController {
List<TestDemo> list = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
TestDemo testDemo = new TestDemo();
testDemo.setOrderNum(-1L);
testDemo.setOrderNum(-1);
testDemo.setTestKey("批量新增");
testDemo.setValue("测试新增");
list.add(testDemo); }

View File

@ -117,7 +117,7 @@ public class TestDemoController extends BaseController {
@ApiOperation("新增测试单表")
@SaCheckPermission("demo:demo:add")
@Log(title = "测试单表", businessType = BusinessType.INSERT)
@RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS, message = "不允许重复提交")
@RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS, message = "{repeat.submit.message}")
@PostMapping()
public R<Void> add(@RequestBody TestDemoBo bo) {
// 使用校验工具对标 @Validated(AddGroup.class) 注解

View File

@ -39,7 +39,7 @@ public class TestDemo extends BaseEntity {
* 排序号
*/
@OrderBy(asc = false, sort = 1)
private Long orderNum;
private Integer orderNum;
/**
* key键

View File

@ -17,7 +17,7 @@ import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("test_tree")
public class TestTree extends TreeEntity {
public class TestTree extends TreeEntity<TestTree> {
private static final long serialVersionUID = 1L;

View File

@ -21,7 +21,7 @@ import javax.validation.constraints.NotNull;
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel("测试树表业务对象")
public class TestTreeBo extends TreeEntity {
public class TestTreeBo extends TreeEntity<TestTreeBo> {
/**
* 主键

View File

@ -3,6 +3,7 @@ package com.ruoyi.framework.aspectj;
import com.ruoyi.common.annotation.RateLimiter;
import com.ruoyi.common.enums.LimitType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.redis.RedisUtils;
import lombok.extern.slf4j.Slf4j;
@ -37,7 +38,7 @@ public class RateLimiterAspect {
}
long number = RedisUtils.rateLimiter(combineKey, rateType, count, time);
if (number == -1) {
throw new ServiceException("访问过于频繁,请稍候再试");
throw new ServiceException(MessageUtils.message("rate.limiter.message"));
}
log.info("限制令牌 => {}, 剩余令牌 => {}, 缓存key => '{}'", count, number, combineKey);
} catch (ServiceException e) {

View File

@ -5,15 +5,18 @@ import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.SecureUtil;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.redis.RedisUtils;
import com.ruoyi.framework.config.properties.RepeatSubmitProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@ -27,7 +30,7 @@ import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* 防止重复提交
* 防止重复提交(参考美团GTIS防重系统)
*
* @author Lion Li
*/
@ -37,12 +40,12 @@ import java.util.concurrent.TimeUnit;
@Component
public class RepeatSubmitAspect {
private final RepeatSubmitProperties repeatSubmitProperties;
private static final ThreadLocal<String> KEY_CACHE = new ThreadLocal<>();
@Before("@annotation(repeatSubmit)")
public void doBefore(JoinPoint point, RepeatSubmit repeatSubmit) throws Throwable {
// 如果注解不为0 则使用注解数值
long interval = repeatSubmitProperties.getInterval();
long interval = 0;
if (repeatSubmit.interval() > 0) {
interval = repeatSubmit.timeUnit().toMillis(repeatSubmit.interval());
}
@ -64,11 +67,45 @@ public class RepeatSubmitAspect {
String key = RedisUtils.getCacheObject(cacheRepeatKey);
if (key == null) {
RedisUtils.setCacheObject(cacheRepeatKey, "", interval, TimeUnit.MILLISECONDS);
KEY_CACHE.set(cacheRepeatKey);
} else {
throw new ServiceException(repeatSubmit.message());
String message = repeatSubmit.message();
if (StringUtils.startsWith(message, "{") && StringUtils.endsWith(message, "}")) {
message = MessageUtils.message(StringUtils.substring(message, 1, message.length() - 1));
}
throw new ServiceException(message);
}
}
/**
* 处理完请求后执行
*
* @param joinPoint 切点
*/
@AfterReturning(pointcut = "@annotation(repeatSubmit)", returning = "jsonResult")
public void doAfterReturning(JoinPoint joinPoint, RepeatSubmit repeatSubmit, Object jsonResult) {
if (jsonResult instanceof R) {
R<?> r = (R<?>) jsonResult;
if (r.getCode() == R.SUCCESS) {
return;
}
RedisUtils.deleteObject(KEY_CACHE.get());
KEY_CACHE.remove();
}
}
/**
* 拦截异常操作
*
* @param joinPoint 切点
* @param e 异常
*/
@AfterThrowing(value = "@annotation(repeatSubmit)", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, RepeatSubmit repeatSubmit, Exception e) {
RedisUtils.deleteObject(KEY_CACHE.get());
KEY_CACHE.remove();
}
/**
* 参数拼装
*/

View File

@ -18,10 +18,10 @@ import java.awt.*;
@Configuration
public class CaptchaConfig {
private final int width = 160;
private final int height = 60;
private final Color background = Color.PINK;
private final Font font = new Font("Arial", Font.BOLD, 48);
private static final int WIDTH = 160;
private static final int HEIGHT = 60;
private static final Color BACKGROUND = Color.PINK;
private static final Font FONT = new Font("Arial", Font.BOLD, 48);
/**
* 圆圈干扰验证码
@ -29,9 +29,9 @@ public class CaptchaConfig {
@Lazy
@Bean
public CircleCaptcha circleCaptcha() {
CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(width, height);
captcha.setBackground(background);
captcha.setFont(font);
CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(WIDTH, HEIGHT);
captcha.setBackground(BACKGROUND);
captcha.setFont(FONT);
return captcha;
}
@ -41,9 +41,9 @@ public class CaptchaConfig {
@Lazy
@Bean
public LineCaptcha lineCaptcha() {
LineCaptcha captcha = CaptchaUtil.createLineCaptcha(width, height);
captcha.setBackground(background);
captcha.setFont(font);
LineCaptcha captcha = CaptchaUtil.createLineCaptcha(WIDTH, HEIGHT);
captcha.setBackground(BACKGROUND);
captcha.setFont(FONT);
return captcha;
}
@ -53,9 +53,9 @@ public class CaptchaConfig {
@Lazy
@Bean
public ShearCaptcha shearCaptcha() {
ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(width, height);
captcha.setBackground(background);
captcha.setFont(font);
ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(WIDTH, HEIGHT);
captcha.setBackground(BACKGROUND);
captcha.setFont(FONT);
return captcha;
}

View File

@ -53,8 +53,7 @@ public class RedisConfig extends CachingConfigurerSupport {
Config config = new Config();
config.setThreads(redissonProperties.getThreads())
.setNettyThreads(redissonProperties.getNettyThreads())
.setCodec(JsonJacksonCodec.INSTANCE)
.setTransportMode(redissonProperties.getTransportMode());
.setCodec(JsonJacksonCodec.INSTANCE);
RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig();
if (ObjectUtil.isNotNull(singleServerConfig)) {
@ -65,8 +64,6 @@ public class RedisConfig extends CachingConfigurerSupport {
.setDatabase(redisProperties.getDatabase())
.setPassword(StringUtils.isNotBlank(redisProperties.getPassword()) ? redisProperties.getPassword() : null)
.setTimeout(singleServerConfig.getTimeout())
.setRetryAttempts(singleServerConfig.getRetryAttempts())
.setRetryInterval(singleServerConfig.getRetryInterval())
.setClientName(singleServerConfig.getClientName())
.setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout())
.setSubscriptionConnectionPoolSize(singleServerConfig.getSubscriptionConnectionPoolSize())
@ -87,11 +84,8 @@ public class RedisConfig extends CachingConfigurerSupport {
.setConnectTimeout(((Long) redisProperties.getTimeout().toMillis()).intValue())
.setPassword(StringUtils.isNotBlank(redisProperties.getPassword()) ? redisProperties.getPassword() : null)
.setTimeout(clusterServersConfig.getTimeout())
.setRetryAttempts(clusterServersConfig.getRetryAttempts())
.setRetryInterval(clusterServersConfig.getRetryInterval())
.setClientName(clusterServersConfig.getClientName())
.setIdleConnectionTimeout(clusterServersConfig.getIdleConnectionTimeout())
.setPingConnectionInterval(clusterServersConfig.getPingConnectionInterval())
.setSubscriptionConnectionPoolSize(clusterServersConfig.getSubscriptionConnectionPoolSize())
.setMasterConnectionMinimumIdleSize(clusterServersConfig.getMasterConnectionMinimumIdleSize())
.setMasterConnectionPoolSize(clusterServersConfig.getMasterConnectionPoolSize())
@ -144,8 +138,6 @@ public class RedisConfig extends CachingConfigurerSupport {
* threads: 16
* # Netty线程池数量
* nettyThreads: 32
* # 传输模式
* transportMode: "NIO"
* # 集群配置
* clusterServersConfig:
* # 客户端名称
@ -160,14 +152,8 @@ public class RedisConfig extends CachingConfigurerSupport {
* slaveConnectionPoolSize: 64
* # 连接空闲超时单位毫秒
* idleConnectionTimeout: 10000
* # ping连接间隔
* pingConnectionInterval: 1000
* # 命令等待超时单位毫秒
* timeout: 3000
* # 如果尝试在此限制之内发送成功则开始启用 timeout 计时
* retryAttempts: 3
* # 命令重试发送时间间隔单位毫秒
* retryInterval: 1500
* # 发布和订阅连接池大小
* subscriptionConnectionPoolSize: 50
* # 读取模式

View File

@ -5,7 +5,7 @@ import cn.dev33.satoken.interceptor.SaRouteInterceptor;
import cn.dev33.satoken.jwt.StpLogicJwtForStyle;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpLogic;
import cn.hutool.core.util.ObjectUtil;
import cn.dev33.satoken.stp.StpUtil;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.framework.config.properties.SecurityProperties;
import lombok.RequiredArgsConstructor;
@ -43,15 +43,17 @@ public class SaTokenConfig implements WebMvcConfigurer {
.match("/**")
// 排除下不需要拦截的
.notMatch(securityProperties.getExcludes())
// 对未排除的路径进行检查
.check(() -> {
Long userId = LoginHelper.getUserId();
if (ObjectUtil.isNotNull(userId)) {
// 有效率影响 用于临时测试
// if (log.isDebugEnabled()) {
// log.debug("剩余有效时间: {}", StpUtil.getTokenTimeout());
// log.debug("临时有效时间: {}", StpUtil.getTokenActivityTimeout());
// }
}
// 检查是否登录 是否有token
StpUtil.checkLogin();
// 有效率影响 用于临时测试
// if (log.isDebugEnabled()) {
// log.debug("剩余有效时间: {}", StpUtil.getTokenTimeout());
// log.debug("临时有效时间: {}", StpUtil.getTokenActivityTimeout());
// }
});
}) {
@SuppressWarnings("all")

View File

@ -1,7 +1,6 @@
package com.ruoyi.framework.config;
import com.ruoyi.common.utils.Threads;
import com.ruoyi.common.utils.reflect.ReflectUtils;
import com.ruoyi.framework.config.properties.ThreadPoolProperties;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -10,7 +9,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
@ -23,6 +21,11 @@ import java.util.concurrent.ThreadPoolExecutor;
@Configuration
public class ThreadPoolConfig {
/**
* 核心线程数 = cpu 核心数 + 1
*/
private final int core = Runtime.getRuntime().availableProcessors() + 1;
@Autowired
private ThreadPoolProperties threadPoolProperties;
@ -30,12 +33,11 @@ public class ThreadPoolConfig {
@ConditionalOnProperty(prefix = "thread-pool", name = "enabled", havingValue = "true")
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setMaxPoolSize(threadPoolProperties.getMaxPoolSize());
executor.setCorePoolSize(threadPoolProperties.getCorePoolSize());
executor.setMaxPoolSize(core);
executor.setCorePoolSize(core * 2);
executor.setQueueCapacity(threadPoolProperties.getQueueCapacity());
executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds());
RejectedExecutionHandler handler = ReflectUtils.newInstance(threadPoolProperties.getRejectedExecutionHandler().getClazz());
executor.setRejectedExecutionHandler(handler);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
@ -44,7 +46,7 @@ public class ThreadPoolConfig {
*/
@Bean(name = "scheduledExecutorService")
protected ScheduledExecutorService scheduledExecutorService() {
return new ScheduledThreadPoolExecutor(threadPoolProperties.getCorePoolSize(),
return new ScheduledThreadPoolExecutor(core,
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
new ThreadPoolExecutor.CallerRunsPolicy()) {
@Override

View File

@ -4,7 +4,6 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import org.redisson.config.ReadMode;
import org.redisson.config.SubscriptionMode;
import org.redisson.config.TransportMode;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ -30,11 +29,6 @@ public class RedissonProperties {
*/
private int nettyThreads;
/**
* 传输模式
*/
private TransportMode transportMode;
/**
* 单机服务配置
*/
@ -79,16 +73,6 @@ public class RedissonProperties {
*/
private int timeout;
/**
* 如果尝试在此限制之内发送成功则开始启用 timeout 计时
*/
private int retryAttempts;
/**
* 命令重试发送时间间隔单位毫秒
*/
private int retryInterval;
/**
* 发布和订阅连接池大小
*/
@ -130,26 +114,11 @@ public class RedissonProperties {
*/
private int idleConnectionTimeout;
/**
* ping超时
*/
private int pingConnectionInterval;
/**
* 命令等待超时单位毫秒
*/
private int timeout;
/**
* 如果尝试在此限制之内发送成功则开始启用 timeout 计时
*/
private int retryAttempts;
/**
* 命令重试发送时间间隔单位毫秒
*/
private int retryInterval;
/**
* 发布和订阅连接池大小
*/

View File

@ -1,22 +0,0 @@
package com.ruoyi.framework.config.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 重复提交 配置属性
*
* @author Lion Li
*/
@Data
@Component
@ConfigurationProperties(prefix = "repeat-submit")
public class RepeatSubmitProperties {
/**
* 间隔时间(毫秒)
*/
private int interval;
}

View File

@ -1,6 +1,5 @@
package com.ruoyi.framework.config.properties;
import com.ruoyi.common.enums.ThreadPoolRejectedPolicy;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ -20,16 +19,6 @@ public class ThreadPoolProperties {
*/
private boolean enabled;
/**
* 核心线程池大小
*/
private int corePoolSize;
/**
* 最大可创建的线程数
*/
private int maxPoolSize;
/**
* 队列最大长度
*/
@ -40,9 +29,4 @@ public class ThreadPoolProperties {
*/
private int keepAliveSeconds;
/**
* 线程池对拒绝任务(无线程可用)的处理策略
*/
private ThreadPoolRejectedPolicy rejectedExecutionHandler;
}

View File

@ -53,7 +53,7 @@ public class UserActionListener implements SaTokenListener {
dto.setUserName(user.getUsername());
dto.setDeptName(user.getDeptName());
RedisUtils.setCacheObject(Constants.ONLINE_TOKEN_KEY + tokenValue, dto, tokenConfig.getTimeout(), TimeUnit.SECONDS);
log.info("user doLogin, useId:{}, token:{}", loginId, tokenValue);
log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue);
} else if (userType == UserType.APP_USER) {
// app端 自行根据业务编写
}
@ -65,7 +65,7 @@ public class UserActionListener implements SaTokenListener {
@Override
public void doLogout(String loginType, Object loginId, String tokenValue) {
RedisUtils.deleteObject(Constants.ONLINE_TOKEN_KEY + tokenValue);
log.info("user doLogout, useId:{}, token:{}", loginId, tokenValue);
log.info("user doLogout, userId:{}, token:{}", loginId, tokenValue);
}
/**
@ -74,7 +74,7 @@ public class UserActionListener implements SaTokenListener {
@Override
public void doKickout(String loginType, Object loginId, String tokenValue) {
RedisUtils.deleteObject(Constants.ONLINE_TOKEN_KEY + tokenValue);
log.info("user doLogoutByLoginId, useId:{}, token:{}", loginId, tokenValue);
log.info("user doLogoutByLoginId, userId:{}, token:{}", loginId, tokenValue);
}
/**
@ -83,7 +83,7 @@ public class UserActionListener implements SaTokenListener {
@Override
public void doReplaced(String loginType, Object loginId, String tokenValue) {
RedisUtils.deleteObject(Constants.ONLINE_TOKEN_KEY + tokenValue);
log.info("user doReplaced, useId:{}, token:{}", loginId, tokenValue);
log.info("user doReplaced, userId:{}, token:{}", loginId, tokenValue);
}
/**

View File

@ -9,9 +9,17 @@ import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* sa-token 权限管理实现类
*
* @author Lion Li
*/
@Component
public class SaInterfaceImpl implements StpInterface {
public class SaPermissionImpl implements StpInterface {
/**
* 获取菜单权限列表
*/
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
LoginUser loginUser = LoginHelper.getLoginUser();
@ -19,11 +27,14 @@ public class SaInterfaceImpl implements StpInterface {
if (userType == UserType.SYS_USER) {
return new ArrayList<>(loginUser.getMenuPermission());
} else if (userType == UserType.APP_USER) {
// app端权限返回 自行根据业务编写
// 其他端 自行根据业务编写
}
return new ArrayList<>();
}
/**
* 获取角色权限列表
*/
@Override
public List<String> getRoleList(Object loginId, String loginType) {
LoginUser loginUser = LoginHelper.getLoginUser();
@ -31,7 +42,7 @@ public class SaInterfaceImpl implements StpInterface {
if (userType == UserType.SYS_USER) {
return new ArrayList<>(loginUser.getRolePermission());
} else if (userType == UserType.APP_USER) {
// app端权限返回 自行根据业务编写
// 其他端 自行根据业务编写
}
return new ArrayList<>();
}

View File

@ -9,7 +9,9 @@ import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.exception.DemoModeException;
import com.ruoyi.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
@ -71,6 +73,31 @@ public class GlobalExceptionHandler {
return R.fail(e.getMessage());
}
/**
* 主键或UNIQUE索引数据重复异常
*/
@ExceptionHandler(DuplicateKeyException.class)
public R<Void> handleDuplicateKeyException(DuplicateKeyException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
log.error("请求地址'{}',数据库中已存在记录'{}'", requestURI, e.getMessage());
return R.fail("数据库中已存在该记录,请联系管理员确认");
}
/**
* Mybatis系统异常 通用处理
*/
@ExceptionHandler(MyBatisSystemException.class)
public R<Void> handleCannotFindDataSourceException(MyBatisSystemException e, HttpServletRequest request) {
String requestURI = request.getRequestURI();
String message = e.getMessage();
if (message.contains("CannotFindDataSourceException")) {
log.error("请求地址'{}', 未找到数据源", requestURI);
return R.fail("未找到数据源,请联系管理员确认");
}
log.error("请求地址'{}', Mybatis系统异常", requestURI, e);
return R.fail(message);
}
/**
* 业务异常
*/

View File

@ -5,13 +5,12 @@ import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.IoUtil;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.generator.domain.GenTable;
import com.ruoyi.generator.domain.GenTableColumn;
import com.ruoyi.generator.service.IGenTableColumnService;
import com.ruoyi.generator.service.IGenTableService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@ -38,7 +37,6 @@ import java.util.Map;
public class GenController extends BaseController {
private final IGenTableService genTableService;
private final IGenTableColumnService genTableColumnService;
/**
* 查询代码生成列表
@ -55,11 +53,11 @@ public class GenController extends BaseController {
*/
@ApiOperation("修改代码生成业务")
@SaCheckPermission("tool:gen:query")
@GetMapping(value = "/{talbleId}")
public R<Map<String, Object>> getInfo(@PathVariable Long talbleId) {
GenTable table = genTableService.selectGenTableById(talbleId);
@GetMapping(value = "/{tableId}")
public R<Map<String, Object>> getInfo(@PathVariable Long tableId) {
GenTable table = genTableService.selectGenTableById(tableId);
List<GenTable> tables = genTableService.selectGenTableAll();
List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(talbleId);
List<GenTableColumn> list = genTableService.selectGenTableColumnListByTableId(tableId);
Map<String, Object> map = new HashMap<String, Object>();
map.put("info", table);
map.put("rows", list);
@ -82,10 +80,10 @@ public class GenController extends BaseController {
*/
@ApiOperation("查询数据表字段列表")
@SaCheckPermission("tool:gen:list")
@GetMapping(value = "/column/{talbleId}")
@GetMapping(value = "/column/{tableId}")
public TableDataInfo<GenTableColumn> columnList(Long tableId) {
TableDataInfo<GenTableColumn> dataInfo = new TableDataInfo<>();
List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(tableId);
List<GenTableColumn> list = genTableService.selectGenTableColumnListByTableId(tableId);
dataInfo.setRows(list);
dataInfo.setTotal(list.size());
return dataInfo;

View File

@ -150,6 +150,12 @@ public class GenTable extends BaseEntity {
@TableField(exist = false)
private String treeName;
/*
* 菜单id列表
*/
@TableField(exist = false)
private List<Long> menuIds;
/**
* 上级菜单ID字段
*/

View File

@ -8,7 +8,7 @@ import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.utils.StringUtils;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.apache.ibatis.type.JdbcType;
import javax.validation.constraints.NotBlank;
@ -42,7 +42,7 @@ public class GenTableColumn extends BaseEntity {
/**
* 列描述
*/
@TableField(updateStrategy = FieldStrategy.IGNORED)
@TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
private String columnComment;
/**
@ -64,43 +64,43 @@ public class GenTableColumn extends BaseEntity {
/**
* 是否主键1是
*/
@TableField(updateStrategy = FieldStrategy.IGNORED)
@TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
private String isPk;
/**
* 是否自增1是
*/
@TableField(updateStrategy = FieldStrategy.IGNORED)
@TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
private String isIncrement;
/**
* 是否必填1是
*/
@TableField(updateStrategy = FieldStrategy.IGNORED)
@TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
private String isRequired;
/**
* 是否为插入字段1是
*/
@TableField(updateStrategy = FieldStrategy.IGNORED)
@TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
private String isInsert;
/**
* 是否编辑字段1是
*/
@TableField(updateStrategy = FieldStrategy.IGNORED)
@TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
private String isEdit;
/**
* 是否列表字段1是
*/
@TableField(updateStrategy = FieldStrategy.IGNORED)
@TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
private String isList;
/**
* 是否查询字段1是
*/
@TableField(updateStrategy = FieldStrategy.IGNORED)
@TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
private String isQuery;
/**

View File

@ -16,26 +16,13 @@ import java.util.List;
@InterceptorIgnore(dataPermission = "true")
public interface GenTableMapper extends BaseMapperPlus<GenTableMapper, GenTable, GenTable> {
Page<GenTable> selectPageGenTableList(@Param("page") Page<GenTable> page, @Param("genTable") GenTable genTable);
Page<GenTable> selectPageDbTableList(@Param("page") Page<GenTable> page, @Param("genTable") GenTable genTable);
/**
* 查询业务列表
*
* @param genTable 业务信息
* @return 业务集合
*/
List<GenTable> selectGenTableList(GenTable genTable);
/**
* 查询据库列表
*
* @param genTable 业务信息
* @param genTable 查询条件
* @return 数据库表集合
*/
List<GenTable> selectDbTableList(GenTable genTable);
Page<GenTable> selectPageDbTableList(@Param("page") Page<GenTable> page, @Param("genTable") GenTable genTable);
/**
* 查询据库列表

View File

@ -1,68 +0,0 @@
package com.ruoyi.generator.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.generator.domain.GenTableColumn;
import com.ruoyi.generator.mapper.GenTableColumnMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
/**
* 业务字段 服务层实现
*
* @author Lion Li
*/
@RequiredArgsConstructor
@Service
public class GenTableColumnServiceImpl implements IGenTableColumnService {
private final GenTableColumnMapper baseMapper;
/**
* 查询业务字段列表
*
* @param tableId 业务字段编号
* @return 业务字段集合
*/
@Override
public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId) {
return baseMapper.selectList(new LambdaQueryWrapper<GenTableColumn>()
.eq(GenTableColumn::getTableId, tableId)
.orderByAsc(GenTableColumn::getSort));
}
/**
* 新增业务字段
*
* @param genTableColumn 业务字段信息
* @return 结果
*/
@Override
public int insertGenTableColumn(GenTableColumn genTableColumn) {
return baseMapper.insert(genTableColumn);
}
/**
* 修改业务字段
*
* @param genTableColumn 业务字段信息
* @return 结果
*/
@Override
public int updateGenTableColumn(GenTableColumn genTableColumn) {
return baseMapper.updateById(genTableColumn);
}
/**
* 删除业务字段对象
*
* @param ids 需要删除的数据ID
* @return 结果
*/
@Override
public int deleteGenTableColumnByIds(String ids) {
return baseMapper.deleteBatchIds(Arrays.asList(ids.split(",")));
}
}

View File

@ -3,8 +3,13 @@ package com.ruoyi.generator.service;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.GenConstants;
@ -28,7 +33,6 @@ import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.ByteArrayOutputStream;
import java.io.File;
@ -46,6 +50,7 @@ import java.util.zip.ZipOutputStream;
*
* @author Lion Li
*/
@DS("#header.datasource")
@Slf4j
@RequiredArgsConstructor
@Service
@ -54,6 +59,19 @@ public class GenTableServiceImpl implements IGenTableService {
private final GenTableMapper baseMapper;
private final GenTableColumnMapper genTableColumnMapper;
/**
* 查询业务字段列表
*
* @param tableId 业务字段编号
* @return 业务字段集合
*/
@Override
public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId) {
return genTableColumnMapper.selectList(new LambdaQueryWrapper<GenTableColumn>()
.eq(GenTableColumn::getTableId, tableId)
.orderByAsc(GenTableColumn::getSort));
}
/**
* 查询业务信息
*
@ -69,38 +87,27 @@ public class GenTableServiceImpl implements IGenTableService {
@Override
public TableDataInfo<GenTable> selectPageGenTableList(GenTable genTable, PageQuery pageQuery) {
Page<GenTable> page = baseMapper.selectPageGenTableList(pageQuery.build(), genTable);
Page<GenTable> page = baseMapper.selectPage(pageQuery.build(), this.buildGenTableQueryWrapper(genTable));
return TableDataInfo.build(page);
}
private QueryWrapper<GenTable> buildGenTableQueryWrapper(GenTable genTable) {
Map<String, Object> params = genTable.getParams();
QueryWrapper<GenTable> wrapper = Wrappers.query();
wrapper.like(StringUtils.isNotBlank(genTable.getTableName()), "lower(table_name)", StringUtils.lowerCase(genTable.getTableName()))
.like(StringUtils.isNotBlank(genTable.getTableComment()), "lower(table_comment)", StringUtils.lowerCase(genTable.getTableComment()))
.between(params.get("beginTime") != null && params.get("endTime") != null,
"create_time", params.get("beginTime"), params.get("endTime"));
return wrapper;
}
@Override
public TableDataInfo<GenTable> selectPageDbTableList(GenTable genTable, PageQuery pageQuery) {
Page<GenTable> page = baseMapper.selectPageDbTableList(pageQuery.build(), genTable);
return TableDataInfo.build(page);
}
/**
* 查询业务列表
*
* @param genTable 业务信息
* @return 业务集合
*/
@Override
public List<GenTable> selectGenTableList(GenTable genTable) {
return baseMapper.selectGenTableList(genTable);
}
/**
* 查询据库列表
*
* @param genTable 业务信息
* @return 数据库表集合
*/
@Override
public List<GenTable> selectDbTableList(GenTable genTable) {
return baseMapper.selectDbTableList(genTable);
}
/**
* 查询据库列表
*
@ -129,7 +136,6 @@ public class GenTableServiceImpl implements IGenTableService {
* @return 结果
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void updateGenTable(GenTable genTable) {
String options = JsonUtils.toJsonString(genTable.getParams());
genTable.setOptions(options);
@ -148,7 +154,6 @@ public class GenTableServiceImpl implements IGenTableService {
* @return 结果
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteGenTableByIds(Long[] tableIds) {
List<Long> ids = Arrays.asList(tableIds);
baseMapper.deleteBatchIds(ids);
@ -161,7 +166,6 @@ public class GenTableServiceImpl implements IGenTableService {
* @param tableList 导入表列表
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void importGenTable(List<GenTable> tableList) {
String operName = LoginHelper.getUsername();
try {
@ -198,6 +202,12 @@ public class GenTableServiceImpl implements IGenTableService {
Map<String, String> dataMap = new LinkedHashMap<>();
// 查询表信息
GenTable table = baseMapper.selectGenTableById(tableId);
Snowflake snowflake = IdUtil.getSnowflake();
List<Long> menuIds = new ArrayList<>();
for (int i = 0; i < 6; i++) {
menuIds.add(snowflake.nextId());
}
table.setMenuIds(menuIds);
// 设置主子表信息
setSubTable(table);
// 设置主键列信息
@ -275,7 +285,6 @@ public class GenTableServiceImpl implements IGenTableService {
* @param tableName 表名称
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void synchDb(String tableName) {
GenTable table = baseMapper.selectGenTableByName(tableName);
List<GenTableColumn> tableColumns = table.getColumns();
@ -299,9 +308,8 @@ public class GenTableServiceImpl implements IGenTableService {
column.setQueryType(prevColumn.getQueryType());
}
if (StringUtils.isNotEmpty(prevColumn.getIsRequired()) && !column.isPk()
&& (column.isInsert() || column.isEdit())
&& ((column.isUsableColumn()) || (!column.isSuperColumn())))
{
&& (column.isInsert() || column.isEdit())
&& ((column.isUsableColumn()) || (!column.isSuperColumn()))) {
// 如果是(新增/修改&非主键/非忽略及父属性)继续保留必填/显示类型选项
column.setIsRequired(prevColumn.getIsRequired());
column.setHtmlType(prevColumn.getHtmlType());
@ -345,6 +353,12 @@ public class GenTableServiceImpl implements IGenTableService {
private void generatorCode(String tableName, ZipOutputStream zip) {
// 查询表信息
GenTable table = baseMapper.selectGenTableByName(tableName);
Snowflake snowflake = IdUtil.getSnowflake();
List<Long> menuIds = new ArrayList<>();
for (int i = 0; i < 6; i++) {
menuIds.add(snowflake.nextId());
}
table.setMenuIds(menuIds);
// 设置主子表信息
setSubTable(table);
// 设置主键列信息
@ -477,3 +491,4 @@ public class GenTableServiceImpl implements IGenTableService {
return genPath + File.separator + VelocityUtils.getFileName(template, table);
}
}

View File

@ -1,44 +0,0 @@
package com.ruoyi.generator.service;
import com.ruoyi.generator.domain.GenTableColumn;
import java.util.List;
/**
* 业务字段 服务层
*
* @author Lion Li
*/
public interface IGenTableColumnService {
/**
* 查询业务字段列表
*
* @param tableId 业务字段编号
* @return 业务字段集合
*/
List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId);
/**
* 新增业务字段
*
* @param genTableColumn 业务字段信息
* @return 结果
*/
int insertGenTableColumn(GenTableColumn genTableColumn);
/**
* 修改业务字段
*
* @param genTableColumn 业务字段信息
* @return 结果
*/
int updateGenTableColumn(GenTableColumn genTableColumn);
/**
* 删除业务字段信息
*
* @param ids 需要删除的数据ID
* @return 结果
*/
int deleteGenTableColumnByIds(String ids);
}

View File

@ -3,6 +3,7 @@ package com.ruoyi.generator.service;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.generator.domain.GenTable;
import com.ruoyi.generator.domain.GenTableColumn;
import java.util.List;
import java.util.Map;
@ -14,11 +15,13 @@ import java.util.Map;
*/
public interface IGenTableService {
TableDataInfo<GenTable> selectPageGenTableList(GenTable genTable, PageQuery pageQuery);
TableDataInfo<GenTable> selectPageDbTableList(GenTable genTable, PageQuery pageQuery);
/**
* 查询业务字段列表
*
* @param tableId 业务字段编号
* @return 业务字段集合
*/
List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId);
/**
* 查询业务列表
@ -26,7 +29,7 @@ public interface IGenTableService {
* @param genTable 业务信息
* @return 业务集合
*/
List<GenTable> selectGenTableList(GenTable genTable);
TableDataInfo<GenTable> selectPageGenTableList(GenTable genTable, PageQuery pageQuery);
/**
* 查询据库列表
@ -34,7 +37,7 @@ public interface IGenTableService {
* @param genTable 业务信息
* @return 数据库表集合
*/
List<GenTable> selectDbTableList(GenTable genTable);
TableDataInfo<GenTable> selectPageDbTableList(GenTable genTable, PageQuery pageQuery);
/**
* 查询据库列表

View File

@ -5,6 +5,8 @@ import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.generator.config.GenConfig;
import com.ruoyi.generator.domain.GenTable;
import com.ruoyi.generator.domain.GenTableColumn;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.RegExUtils;
import java.util.Arrays;
@ -14,6 +16,7 @@ import java.util.Arrays;
*
* @author ruoyi
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class GenUtils {
/**

View File

@ -1,6 +1,8 @@
package com.ruoyi.generator.util;
import com.ruoyi.common.constant.Constants;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.velocity.app.Velocity;
import java.util.Properties;
@ -10,6 +12,7 @@ import java.util.Properties;
*
* @author ruoyi
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class VelocityInitializer {
/**

View File

@ -5,11 +5,14 @@ import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.common.constant.GenConstants;
import com.ruoyi.common.helper.DataBaseHelper;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.generator.domain.GenTable;
import com.ruoyi.generator.domain.GenTableColumn;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.velocity.VelocityContext;
import java.util.*;
@ -19,6 +22,7 @@ import java.util.*;
*
* @author ruoyi
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class VelocityUtils {
/**
@ -135,7 +139,15 @@ public class VelocityUtils {
templates.add("vm/java/serviceImpl.java.vm");
templates.add("vm/java/controller.java.vm");
templates.add("vm/xml/mapper.xml.vm");
templates.add("vm/sql/sql.vm");
if (DataBaseHelper.isOracle()) {
templates.add("vm/sql/oracle/sql.vm");
} else if (DataBaseHelper.isPostgerSql()) {
templates.add("vm/sql/postgres/sql.vm");
} else if (DataBaseHelper.isSqlServer()) {
templates.add("vm/sql/sqlserver/sql.vm");
} else {
templates.add("vm/sql/sql.vm");
}
templates.add("vm/js/api.js.vm");
if (GenConstants.TPL_CRUD.equals(tplCategory)) {
templates.add("vm/vue/index.vue.vm");

View File

@ -12,11 +12,14 @@ import java.io.InputStream;
*/
public interface IOssStrategy {
/**
* 创建存储桶
*/
void createBucket();
/**
* 获取服务商类型
* @return
* @return 对象存储服务商枚举
*/
OssEnumd getServiceType();
@ -25,6 +28,7 @@ public interface IOssStrategy {
*
* @param data 文件字节数组
* @param path 文件路径包含文件名
* @param contentType 文件类型
* @return 返回http地址
*/
UploadResult upload(byte[] data, String path, String contentType);
@ -41,6 +45,7 @@ public interface IOssStrategy {
*
* @param data 文件字节数组
* @param suffix 后缀
* @param contentType 文件类型
* @return 返回http地址
*/
UploadResult uploadSuffix(byte[] data, String suffix, String contentType);
@ -50,6 +55,7 @@ public interface IOssStrategy {
*
* @param inputStream 字节流
* @param path 文件路径包含文件名
* @param contentType 文件类型
* @return 返回http地址
*/
UploadResult upload(InputStream inputStream, String path, String contentType);
@ -59,6 +65,7 @@ public interface IOssStrategy {
*
* @param inputStream 字节流
* @param suffix 后缀
* @param contentType 文件类型
* @return 返回http地址
*/
UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType);

View File

@ -60,5 +60,10 @@ public abstract class AbstractOssStrategy implements IOssStrategy {
@Override
public abstract UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType);
/**
* 获取域名访问链接
*
* @return 域名访问链接
*/
public abstract String getEndpointLink();
}

View File

@ -79,6 +79,8 @@ public class MinioOssStrategy extends AbstractOssStrategy {
@Override
public UploadResult upload(InputStream inputStream, String path, String contentType) {
try {
// 解决 inputStream.available() socket 下传输延迟问题 导致获取数值不精确
Thread.sleep(1000);
minioClient.putObject(PutObjectArgs.builder()
.bucket(properties.getBucketName())
.object(path)

View File

@ -1,6 +1,5 @@
package com.ruoyi.system.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.core.domain.BaseEntity;
@ -20,7 +19,7 @@ public class SysOss extends BaseEntity {
/**
* 对象存储主键
*/
@TableId(value = "oss_id", type = IdType.AUTO)
@TableId(value = "oss_id")
private Long ossId;
/**

View File

@ -14,6 +14,7 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
/**
@ -60,8 +61,8 @@ public class SysPost extends BaseEntity {
*/
@ApiModelProperty(value = "岗位排序")
@ExcelProperty(value = "岗位排序")
@NotBlank(message = "显示顺序不能为空")
private String postSort;
@NotNull(message = "显示顺序不能为空")
private Integer postSort;
/**
* 状态0正常 1停用

View File

@ -1,5 +1,7 @@
package com.ruoyi.system.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.ruoyi.common.annotation.DataColumn;
import com.ruoyi.common.annotation.DataPermission;
import com.ruoyi.common.core.domain.entity.SysDept;
@ -18,13 +20,13 @@ public interface SysDeptMapper extends BaseMapperPlus<SysDeptMapper, SysDept, Sy
/**
* 查询部门管理数据
*
* @param dept 部门信息
* @param queryWrapper 查询条件
* @return 部门信息集合
*/
@DataPermission({
@DataColumn(key = "deptName", value = "d.dept_id")
@DataColumn(key = "deptName", value = "dept_id")
})
List<SysDept> selectDeptList(SysDept dept);
List<SysDept> selectDeptList(@Param(Constants.WRAPPER) Wrapper<SysDept> queryWrapper);
/**
* 根据角色ID查询部门树信息
@ -35,12 +37,4 @@ public interface SysDeptMapper extends BaseMapperPlus<SysDeptMapper, SysDept, Sy
*/
List<Long> selectDeptListByRoleId(@Param("roleId") Long roleId, @Param("deptCheckStrictly") boolean deptCheckStrictly);
/**
* 修改子元素关系
*
* @param depts 子元素
* @return 结果
*/
int updateDeptChildren(@Param("depts") List<SysDept> depts);
}

View File

@ -1,5 +1,9 @@
package com.ruoyi.system.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
@ -23,10 +27,10 @@ public interface SysMenuMapper extends BaseMapperPlus<SysMenuMapper, SysMenu, Sy
/**
* 根据用户查询系统菜单列表
*
* @param menu 菜单信息
* @param queryWrapper 查询条件
* @return 菜单列表
*/
List<SysMenu> selectMenuListByUserId(SysMenu menu);
List<SysMenu> selectMenuListByUserId(@Param(Constants.WRAPPER) Wrapper<SysMenu> queryWrapper);
/**
* 根据用户ID查询权限
@ -41,7 +45,14 @@ public interface SysMenuMapper extends BaseMapperPlus<SysMenuMapper, SysMenu, Sy
*
* @return 菜单列表
*/
List<SysMenu> selectMenuTreeAll();
default List<SysMenu> selectMenuTreeAll() {
LambdaQueryWrapper<SysMenu> lqw = new LambdaQueryWrapper<SysMenu>()
.in(SysMenu::getMenuType, UserConstants.TYPE_DIR, UserConstants.TYPE_MENU)
.eq(SysMenu::getStatus, UserConstants.MENU_NORMAL)
.orderByAsc(SysMenu::getParentId)
.orderByAsc(SysMenu::getOrderNum);
return this.selectList(lqw);
}
/**
* 根据用户ID查询菜单

View File

@ -1,5 +1,7 @@
package com.ruoyi.system.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.annotation.DataColumn;
import com.ruoyi.common.annotation.DataPermission;
@ -19,18 +21,18 @@ public interface SysRoleMapper extends BaseMapperPlus<SysRoleMapper, SysRole, Sy
@DataPermission({
@DataColumn(key = "deptName", value = "d.dept_id")
})
Page<SysRole> selectPageRoleList(@Param("page") Page<SysRole> page, @Param("role") SysRole role);
Page<SysRole> selectPageRoleList(@Param("page") Page<SysRole> page, @Param(Constants.WRAPPER) Wrapper<SysRole> queryWrapper);
/**
* 根据条件分页查询角色数据
*
* @param role 角色信息
* @param queryWrapper 查询条件
* @return 角色数据集合信息
*/
@DataPermission({
@DataColumn(key = "deptName", value = "d.dept_id")
})
List<SysRole> selectRoleList(SysRole role);
List<SysRole> selectRoleList(@Param(Constants.WRAPPER) Wrapper<SysRole> queryWrapper);
/**
* 根据用户ID查询角色

View File

@ -1,5 +1,7 @@
package com.ruoyi.system.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.annotation.DataColumn;
import com.ruoyi.common.annotation.DataPermission;
@ -20,43 +22,43 @@ public interface SysUserMapper extends BaseMapperPlus<SysUserMapper, SysUser, Sy
@DataColumn(key = "deptName", value = "d.dept_id"),
@DataColumn(key = "userName", value = "u.user_id")
})
Page<SysUser> selectPageUserList(@Param("page") Page<SysUser> page, @Param("user") SysUser user);
Page<SysUser> selectPageUserList(@Param("page") Page<SysUser> page, @Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
/**
* 根据条件分页查询用户列表
*
* @param sysUser 用户信息
* @param queryWrapper 查询条件
* @return 用户信息集合信息
*/
@DataPermission({
@DataColumn(key = "deptName", value = "d.dept_id"),
@DataColumn(key = "userName", value = "u.user_id")
})
List<SysUser> selectUserList(SysUser sysUser);
List<SysUser> selectUserList(@Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
/**
* 根据条件分页查询已配用户角色列表
*
* @param user 用户信息
* @param queryWrapper 查询条件
* @return 用户信息集合信息
*/
@DataPermission({
@DataColumn(key = "deptName", value = "d.dept_id"),
@DataColumn(key = "userName", value = "u.user_id")
})
Page<SysUser> selectAllocatedList(@Param("page") Page<SysUser> page, @Param("user") SysUser user);
Page<SysUser> selectAllocatedList(@Param("page") Page<SysUser> page, @Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
/**
* 根据条件分页查询未分配用户角色列表
*
* @param user 用户信息
* @param queryWrapper 查询条件
* @return 用户信息集合信息
*/
@DataPermission({
@DataColumn(key = "deptName", value = "d.dept_id"),
@DataColumn(key = "userName", value = "u.user_id")
})
Page<SysUser> selectUnallocatedList(@Param("page") Page<SysUser> page, @Param("user") SysUser user);
Page<SysUser> selectUnallocatedList(@Param("page") Page<SysUser> page, @Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
/**
* 通过用户名查询用户
@ -66,6 +68,14 @@ public interface SysUserMapper extends BaseMapperPlus<SysUserMapper, SysUser, Sy
*/
SysUser selectUserByUserName(String userName);
/**
* 通过手机号查询用户
*
* @param phonenumber 手机号
* @return 用户对象信息
*/
SysUser selectUserByPhonenumber(String phonenumber);
/**
* 通过用户ID查询用户
*

View File

@ -3,6 +3,8 @@ package com.ruoyi.system.mapper;
import com.ruoyi.common.core.mapper.BaseMapperPlus;
import com.ruoyi.system.domain.SysUserRole;
import java.util.List;
/**
* 用户与角色关联表 数据层
*
@ -10,4 +12,6 @@ import com.ruoyi.system.domain.SysUserRole;
*/
public interface SysUserRoleMapper extends BaseMapperPlus<SysUserRoleMapper, SysUserRole, SysUserRole> {
List<Long> selectUserIdsByRoleId(Long roleId);
}

View File

@ -24,7 +24,7 @@ public interface ISysOssConfigService {
/**
* 查询单个
*/
SysOssConfigVo queryById(Integer ossConfigId);
SysOssConfigVo queryById(Long ossConfigId);
/**
* 查询列表

View File

@ -48,6 +48,14 @@ public interface ISysUserService {
*/
SysUser selectUserByUserName(String userName);
/**
* 通过手机号查询用户
*
* @param phonenumber 手机号
* @return 用户对象信息
*/
SysUser selectUserByPhonenumber(String phonenumber);
/**
* 通过用户ID查询用户
*

Some files were not shown because too many files have changed in this diff Show More