mirror of
https://github.com/dromara/RuoYi-Vue-Plus.git
synced 2025-09-19 09:46:39 +08:00
同步 dev 分支
This commit is contained in:
parent
3e5b850e25
commit
03c459e5a3
14
README.md
14
README.md
@ -2,6 +2,8 @@
|
|||||||
[](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus)
|
[](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus)
|
||||||
[](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/blob/master/LICENSE)
|
[](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/blob/master/LICENSE)
|
||||||
[](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
|
[](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
|
||||||
|
[]()
|
||||||
|
[]()
|
||||||
|
|
||||||
基于 RuoYi-Vue 集成 Mybatis-Plus Lombok Hutool 等便捷开发工具 适配重写相关业务 便于开发 定期与 RuoYi-Vue 同步
|
基于 RuoYi-Vue 集成 Mybatis-Plus Lombok Hutool 等便捷开发工具 适配重写相关业务 便于开发 定期与 RuoYi-Vue 同步
|
||||||
* 前端开发框架 Vue、Element UI
|
* 前端开发框架 Vue、Element UI
|
||||||
@ -16,9 +18,15 @@
|
|||||||
* 监控框架 spring-boot-admin 全方位服务监控
|
* 监控框架 spring-boot-admin 全方位服务监控
|
||||||
* 校验框架 validation 增强接口安全性 严谨性
|
* 校验框架 validation 增强接口安全性 严谨性
|
||||||
* 文档框架 knife4j 美化接口文档
|
* 文档框架 knife4j 美化接口文档
|
||||||
|
* 序列化框架 统一使用 jackson 高效可靠
|
||||||
* 代码生成器 一键生成前后端代码
|
* 代码生成器 一键生成前后端代码
|
||||||
|
* 多数据源框架 dynamic-datasource 支持主从与多种类数据库异构
|
||||||
|
* Redis客户端 采用 Redisson 性能更强
|
||||||
|
* 分布式锁 Lock4j 注解锁、工具锁 多种多样
|
||||||
|
|
||||||
## 参考文档
|
## 参考文档
|
||||||
|
|
||||||
|
使用框架前请仔细阅读文档重点注意事项
|
||||||
[参考文档 Wiki](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages)
|
[参考文档 Wiki](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus/wikis/pages)
|
||||||
|
|
||||||
## 修改RuoYi功能
|
## 修改RuoYi功能
|
||||||
@ -34,7 +42,10 @@
|
|||||||
* 集成 Feign 接口化管理 Http 请求(如三方请求 支付,短信,推送等)
|
* 集成 Feign 接口化管理 Http 请求(如三方请求 支付,短信,推送等)
|
||||||
* 移除 自带服务监控 改为 spring-boot-admin 全方位监控
|
* 移除 自带服务监控 改为 spring-boot-admin 全方位监控
|
||||||
* 增加 demo 模块示例(给不会增加模块的小伙伴做参考)
|
* 增加 demo 模块示例(给不会增加模块的小伙伴做参考)
|
||||||
* 增加 redisson 支持分布式锁 功能更强大
|
* 增加 redisson 高性能 Redis 客户端
|
||||||
|
* 移除 fastjson 统一使用 jackson 序列化
|
||||||
|
* 集成 dynamic-datasource 多数据源(默认支持MySQL,其他种类需自行适配)
|
||||||
|
* 集成 Lock4j 实现分布式 注解锁、工具锁 多种多样
|
||||||
|
|
||||||
### 代码改动
|
### 代码改动
|
||||||
|
|
||||||
@ -46,6 +57,7 @@
|
|||||||
* 项目修改为 maven多环境配置
|
* 项目修改为 maven多环境配置
|
||||||
* 项目配置修改为 application.yml 统一管理
|
* 项目配置修改为 application.yml 统一管理
|
||||||
* 数据权限修改为 适配支持单表、多表
|
* 数据权限修改为 适配支持单表、多表
|
||||||
|
* 使用 redisson 实现分布式锁注解与工具类
|
||||||
* 使用 redisson 实现 spring-cache 整合
|
* 使用 redisson 实现 spring-cache 整合
|
||||||
* 增加 mybatis-plus 二级缓存 redis 存储
|
* 增加 mybatis-plus 二级缓存 redis 存储
|
||||||
|
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# 页面标题
|
||||||
|
VUE_APP_TITLE = RuoYi-Vue-Plus后台管理系统
|
||||||
|
|
||||||
# 开发环境配置
|
# 开发环境配置
|
||||||
ENV = 'development'
|
ENV = 'development'
|
||||||
|
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# 页面标题
|
||||||
|
VUE_APP_TITLE = RuoYi-Vue-Plus后台管理系统
|
||||||
|
|
||||||
# 生产环境配置
|
# 生产环境配置
|
||||||
ENV = 'production'
|
ENV = 'production'
|
||||||
|
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# 页面标题
|
||||||
|
VUE_APP_TITLE = RuoYi-Vue-Plus后台管理系统
|
||||||
|
|
||||||
NODE_ENV = production
|
NODE_ENV = production
|
||||||
|
|
||||||
# 测试环境配置
|
# 测试环境配置
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
"clipboard": "2.0.6",
|
"clipboard": "2.0.6",
|
||||||
"core-js": "3.8.1",
|
"core-js": "3.8.1",
|
||||||
"echarts": "4.9.0",
|
"echarts": "4.9.0",
|
||||||
"element-ui": "2.15.0",
|
"element-ui": "2.15.2",
|
||||||
"file-saver": "2.0.4",
|
"file-saver": "2.0.4",
|
||||||
"fuse.js": "6.4.3",
|
"fuse.js": "6.4.3",
|
||||||
"highlight.js": "9.18.5",
|
"highlight.js": "9.18.5",
|
||||||
@ -55,6 +55,7 @@
|
|||||||
"vue": "2.6.12",
|
"vue": "2.6.12",
|
||||||
"vue-count-to": "1.0.13",
|
"vue-count-to": "1.0.13",
|
||||||
"vue-cropper": "0.5.5",
|
"vue-cropper": "0.5.5",
|
||||||
|
"vue-meta": "^2.4.0",
|
||||||
"vue-router": "3.4.9",
|
"vue-router": "3.4.9",
|
||||||
"vuedraggable": "2.24.3",
|
"vuedraggable": "2.24.3",
|
||||||
"vuex": "3.6.0"
|
"vuex": "3.6.0"
|
||||||
|
@ -6,6 +6,14 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'App'
|
name: 'App',
|
||||||
|
metaInfo() {
|
||||||
|
return {
|
||||||
|
title: this.$store.state.settings.dynamicTitle && this.$store.state.settings.title,
|
||||||
|
titleTemplate: title => {
|
||||||
|
return title ? `${title} - ${process.env.VUE_APP_TITLE}` : process.env.VUE_APP_TITLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
53
ruoyi-ui/src/api/demo/demo.js
Normal file
53
ruoyi-ui/src/api/demo/demo.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询测试单表列表
|
||||||
|
export function listDemo(query) {
|
||||||
|
return request({
|
||||||
|
url: '/demo/demo/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询测试单表详细
|
||||||
|
export function getDemo(id) {
|
||||||
|
return request({
|
||||||
|
url: '/demo/demo/' + id,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增测试单表
|
||||||
|
export function addDemo(data) {
|
||||||
|
return request({
|
||||||
|
url: '/demo/demo',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改测试单表
|
||||||
|
export function updateDemo(data) {
|
||||||
|
return request({
|
||||||
|
url: '/demo/demo',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除测试单表
|
||||||
|
export function delDemo(id) {
|
||||||
|
return request({
|
||||||
|
url: '/demo/demo/' + id,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出测试单表
|
||||||
|
export function exportDemo(query) {
|
||||||
|
return request({
|
||||||
|
url: '/demo/demo/export',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
@ -1,53 +0,0 @@
|
|||||||
import request from '@/utils/request'
|
|
||||||
|
|
||||||
// 查询测试列表
|
|
||||||
export function listTest(query) {
|
|
||||||
return request({
|
|
||||||
url: '/demo/test/list',
|
|
||||||
method: 'get',
|
|
||||||
params: query
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查询测试详细
|
|
||||||
export function getTest(id) {
|
|
||||||
return request({
|
|
||||||
url: '/demo/test/' + id,
|
|
||||||
method: 'get'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 新增测试
|
|
||||||
export function addTest(data) {
|
|
||||||
return request({
|
|
||||||
url: '/demo/test',
|
|
||||||
method: 'post',
|
|
||||||
data: data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改测试
|
|
||||||
export function updateTest(data) {
|
|
||||||
return request({
|
|
||||||
url: '/demo/test',
|
|
||||||
method: 'put',
|
|
||||||
data: data
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除测试
|
|
||||||
export function delTest(id) {
|
|
||||||
return request({
|
|
||||||
url: '/demo/test/' + id,
|
|
||||||
method: 'delete'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 导出测试
|
|
||||||
export function exportTest(query) {
|
|
||||||
return request({
|
|
||||||
url: '/demo/test/export',
|
|
||||||
method: 'get',
|
|
||||||
params: query
|
|
||||||
})
|
|
||||||
}
|
|
@ -105,6 +105,15 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media ( max-width : 768px) {
|
||||||
|
.pagination-container .el-pagination > .el-pagination__jump {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.pagination-container .el-pagination > .el-pagination__sizes {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.el-table .fixed-width .el-button--mini {
|
.el-table .fixed-width .el-button--mini {
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
|
51
ruoyi-ui/src/components/DictTag/index.vue
Normal file
51
ruoyi-ui/src/components/DictTag/index.vue
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<template v-for="(item, index) in options">
|
||||||
|
<template v-if="values.includes(item.dictValue)">
|
||||||
|
<span
|
||||||
|
v-if="item.listClass == 'default' || item.listClass == ''"
|
||||||
|
:key="item.dictValue"
|
||||||
|
:index="index"
|
||||||
|
:class="item.cssClass"
|
||||||
|
>{{ item.dictLabel }}</span
|
||||||
|
>
|
||||||
|
<el-tag
|
||||||
|
v-else
|
||||||
|
:key="item.dictValue"
|
||||||
|
:index="index"
|
||||||
|
:type="item.listClass == 'primary' ? '' : item.listClass"
|
||||||
|
:class="item.cssClass"
|
||||||
|
>
|
||||||
|
{{ item.dictLabel }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "DictTag",
|
||||||
|
props: {
|
||||||
|
options: {
|
||||||
|
type: Array,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
value: [String, Array],
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
values() {
|
||||||
|
if (this.value) {
|
||||||
|
return Array.isArray(this.value) ? this.value : [this.value];
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.el-tag + .el-tag {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -6,6 +6,7 @@
|
|||||||
:page-size.sync="pageSize"
|
:page-size.sync="pageSize"
|
||||||
:layout="layout"
|
:layout="layout"
|
||||||
:page-sizes="pageSizes"
|
:page-sizes="pageSizes"
|
||||||
|
:pager-count="pagerCount"
|
||||||
:total="total"
|
:total="total"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
@size-change="handleSizeChange"
|
@size-change="handleSizeChange"
|
||||||
@ -38,6 +39,11 @@ export default {
|
|||||||
return [10, 20, 30, 50]
|
return [10, 20, 30, 50]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// 移动端页码按钮的数量端默认值5
|
||||||
|
pagerCount: {
|
||||||
|
type: Number,
|
||||||
|
default: document.body.clientWidth < 992 ? 5 : 7
|
||||||
|
},
|
||||||
layout: {
|
layout: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'total, sizes, prev, pager, next, jumper'
|
default: 'total, sizes, prev, pager, next, jumper'
|
||||||
|
36
ruoyi-ui/src/components/iFrame/index.vue
Normal file
36
ruoyi-ui/src/components/iFrame/index.vue
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<template>
|
||||||
|
<div v-loading="loading" :style="'height:' + height">
|
||||||
|
<iframe
|
||||||
|
:src="src"
|
||||||
|
frameborder="no"
|
||||||
|
style="width: 100%; height: 100%"
|
||||||
|
scrolling="auto"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
src: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
height: document.documentElement.clientHeight - 94.5 + "px;",
|
||||||
|
loading: true,
|
||||||
|
url: this.src
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted: function () {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.loading = false;
|
||||||
|
}, 300);
|
||||||
|
const that = this;
|
||||||
|
window.onresize = function temp() {
|
||||||
|
that.height = document.documentElement.clientHeight - 94.5 + "px;";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
@ -62,6 +62,11 @@
|
|||||||
<el-switch v-model="sidebarLogo" class="drawer-switch" />
|
<el-switch v-model="sidebarLogo" class="drawer-switch" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="drawer-item">
|
||||||
|
<span>动态标题</span>
|
||||||
|
<el-switch v-model="dynamicTitle" class="drawer-switch" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<el-divider/>
|
<el-divider/>
|
||||||
|
|
||||||
<el-button size="small" type="primary" plain icon="el-icon-document-add" @click="saveSetting">保存配置</el-button>
|
<el-button size="small" type="primary" plain icon="el-icon-document-add" @click="saveSetting">保存配置</el-button>
|
||||||
@ -129,6 +134,17 @@ export default {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
dynamicTitle: {
|
||||||
|
get() {
|
||||||
|
return this.$store.state.settings.dynamicTitle
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.dispatch('settings/changeSetting', {
|
||||||
|
key: 'dynamicTitle',
|
||||||
|
value: val
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
themeChange(val) {
|
themeChange(val) {
|
||||||
@ -160,6 +176,7 @@ export default {
|
|||||||
"tagsView":${this.tagsView},
|
"tagsView":${this.tagsView},
|
||||||
"fixedHeader":${this.fixedHeader},
|
"fixedHeader":${this.fixedHeader},
|
||||||
"sidebarLogo":${this.sidebarLogo},
|
"sidebarLogo":${this.sidebarLogo},
|
||||||
|
"dynamicTitle":${this.dynamicTitle},
|
||||||
"sideTheme":"${this.sideTheme}",
|
"sideTheme":"${this.sideTheme}",
|
||||||
"theme":"${this.theme}"
|
"theme":"${this.theme}"
|
||||||
}`
|
}`
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
<div class="sidebar-logo-container" :class="{'collapse':collapse}" :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBg : variables.menuLightBg }">
|
<div class="sidebar-logo-container" :class="{'collapse':collapse}" :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBg : variables.menuLightBg }">
|
||||||
<transition name="sidebarLogoFade">
|
<transition name="sidebarLogoFade">
|
||||||
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
|
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
|
||||||
<img v-if="logo" :src="logo" class="sidebar-logo">
|
<img v-if="logo" :src="logo" class="sidebar-logo" />
|
||||||
<h1 v-else class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.sidebarTitle : variables.sidebarLightTitle }">{{ title }} </h1>
|
<h1 v-else class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.sidebarTitle : variables.sidebarLightTitle }">{{ title }} </h1>
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link v-else key="expand" class="sidebar-logo-link" to="/">
|
<router-link v-else key="expand" class="sidebar-logo-link" to="/">
|
||||||
<img v-if="logo" :src="logo" class="sidebar-logo">
|
<img v-if="logo" :src="logo" class="sidebar-logo" />
|
||||||
<h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.sidebarTitle : variables.sidebarLightTitle }">{{ title }} </h1>
|
<h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.sidebarTitle : variables.sidebarLightTitle }">{{ title }} </h1>
|
||||||
</router-link>
|
</router-link>
|
||||||
</transition>
|
</transition>
|
||||||
|
@ -18,8 +18,12 @@ import { getDicts } from "@/api/system/dict/data";
|
|||||||
import { getConfigKey } from "@/api/system/config";
|
import { getConfigKey } from "@/api/system/config";
|
||||||
import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, download, handleTree } from "@/utils/ruoyi";
|
import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, download, handleTree } from "@/utils/ruoyi";
|
||||||
import Pagination from "@/components/Pagination";
|
import Pagination from "@/components/Pagination";
|
||||||
// 自定义表格工具扩展
|
// 自定义表格工具组件
|
||||||
import RightToolbar from "@/components/RightToolbar"
|
import RightToolbar from "@/components/RightToolbar"
|
||||||
|
// 字典标签组件
|
||||||
|
import DictTag from '@/components/DictTag'
|
||||||
|
// 头部标签组件
|
||||||
|
import VueMeta from 'vue-meta'
|
||||||
|
|
||||||
// 全局方法挂载
|
// 全局方法挂载
|
||||||
Vue.prototype.getDicts = getDicts
|
Vue.prototype.getDicts = getDicts
|
||||||
@ -45,10 +49,12 @@ Vue.prototype.msgInfo = function (msg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 全局组件挂载
|
// 全局组件挂载
|
||||||
|
Vue.component('DictTag', DictTag)
|
||||||
Vue.component('Pagination', Pagination)
|
Vue.component('Pagination', Pagination)
|
||||||
Vue.component('RightToolbar', RightToolbar)
|
Vue.component('RightToolbar', RightToolbar)
|
||||||
|
|
||||||
Vue.use(permission)
|
Vue.use(permission)
|
||||||
|
Vue.use(VueMeta)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If you don't want to use mock-server
|
* If you don't want to use mock-server
|
||||||
|
@ -12,6 +12,7 @@ const whiteList = ['/login', '/auth-redirect', '/bind', '/register']
|
|||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
NProgress.start()
|
NProgress.start()
|
||||||
if (getToken()) {
|
if (getToken()) {
|
||||||
|
to.meta.title && store.dispatch('settings/setTitle', to.meta.title)
|
||||||
/* has token*/
|
/* has token*/
|
||||||
if (to.path === '/login') {
|
if (to.path === '/login') {
|
||||||
next({ path: '/' })
|
next({ path: '/' })
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
title: 'RuoYi-Vue-Plus后台管理系统',
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 侧边栏主题 深色主题theme-dark,浅色主题theme-light
|
* 侧边栏主题 深色主题theme-dark,浅色主题theme-light
|
||||||
*/
|
*/
|
||||||
@ -31,6 +29,11 @@ module.exports = {
|
|||||||
*/
|
*/
|
||||||
sidebarLogo: true,
|
sidebarLogo: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否显示动态标题
|
||||||
|
*/
|
||||||
|
dynamicTitle: false,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {string | array} 'production' | ['production', 'development']
|
* @type {string | array} 'production' | ['production', 'development']
|
||||||
* @description Need show err logs component.
|
* @description Need show err logs component.
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
import variables from '@/assets/styles/element-variables.scss'
|
import variables from '@/assets/styles/element-variables.scss'
|
||||||
import defaultSettings from '@/settings'
|
import defaultSettings from '@/settings'
|
||||||
|
|
||||||
const { sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo } = defaultSettings
|
const { sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle } = defaultSettings
|
||||||
|
|
||||||
const storageSetting = JSON.parse(localStorage.getItem('layout-setting')) || ''
|
const storageSetting = JSON.parse(localStorage.getItem('layout-setting')) || ''
|
||||||
const state = {
|
const state = {
|
||||||
|
title: '',
|
||||||
theme: storageSetting.theme || variables.theme,
|
theme: storageSetting.theme || variables.theme,
|
||||||
sideTheme: storageSetting.sideTheme || sideTheme,
|
sideTheme: storageSetting.sideTheme || sideTheme,
|
||||||
showSettings: showSettings,
|
showSettings: showSettings,
|
||||||
topNav: storageSetting.topNav === undefined ? topNav : storageSetting.topNav,
|
topNav: storageSetting.topNav === undefined ? topNav : storageSetting.topNav,
|
||||||
tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView,
|
tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView,
|
||||||
fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader,
|
fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader,
|
||||||
sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo
|
sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo,
|
||||||
|
dynamicTitle: storageSetting.dynamicTitle === undefined ? dynamicTitle : storageSetting.dynamicTitle
|
||||||
}
|
}
|
||||||
const mutations = {
|
const mutations = {
|
||||||
CHANGE_SETTING: (state, { key, value }) => {
|
CHANGE_SETTING: (state, { key, value }) => {
|
||||||
@ -22,8 +24,13 @@ const mutations = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
|
// 修改布局设置
|
||||||
changeSetting({ commit }, data) {
|
changeSetting({ commit }, data) {
|
||||||
commit('CHANGE_SETTING', data)
|
commit('CHANGE_SETTING', data)
|
||||||
|
},
|
||||||
|
// 设置网页标题
|
||||||
|
setTitle({ commit }, title) {
|
||||||
|
state.title = title
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,15 +19,6 @@
|
|||||||
@keyup.enter.native="handleQuery"
|
@keyup.enter.native="handleQuery"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="版本" prop="version">
|
|
||||||
<el-input
|
|
||||||
v-model="queryParams.version"
|
|
||||||
placeholder="请输入版本"
|
|
||||||
clearable
|
|
||||||
size="small"
|
|
||||||
@keyup.enter.native="handleQuery"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="创建时间">
|
<el-form-item label="创建时间">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="daterangeCreateTime"
|
v-model="daterangeCreateTime"
|
||||||
@ -40,33 +31,6 @@
|
|||||||
end-placeholder="结束日期"
|
end-placeholder="结束日期"
|
||||||
></el-date-picker>
|
></el-date-picker>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="删除标志" prop="deleted">
|
|
||||||
<el-input
|
|
||||||
v-model="queryParams.deleted"
|
|
||||||
placeholder="请输入删除标志"
|
|
||||||
clearable
|
|
||||||
size="small"
|
|
||||||
@keyup.enter.native="handleQuery"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="父id" prop="parentId">
|
|
||||||
<el-input
|
|
||||||
v-model="queryParams.parentId"
|
|
||||||
placeholder="请输入父id"
|
|
||||||
clearable
|
|
||||||
size="small"
|
|
||||||
@keyup.enter.native="handleQuery"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="排序号" prop="orderNum">
|
|
||||||
<el-input
|
|
||||||
v-model="queryParams.orderNum"
|
|
||||||
placeholder="请输入排序号"
|
|
||||||
clearable
|
|
||||||
size="small"
|
|
||||||
@keyup.enter.native="handleQuery"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||||
@ -81,7 +45,7 @@
|
|||||||
icon="el-icon-plus"
|
icon="el-icon-plus"
|
||||||
size="mini"
|
size="mini"
|
||||||
@click="handleAdd"
|
@click="handleAdd"
|
||||||
v-hasPermi="['demo:test:add']"
|
v-hasPermi="['demo:demo:add']"
|
||||||
>新增</el-button>
|
>新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
@ -92,7 +56,7 @@
|
|||||||
size="mini"
|
size="mini"
|
||||||
:disabled="single"
|
:disabled="single"
|
||||||
@click="handleUpdate"
|
@click="handleUpdate"
|
||||||
v-hasPermi="['demo:test:edit']"
|
v-hasPermi="['demo:demo:edit']"
|
||||||
>修改</el-button>
|
>修改</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
@ -103,7 +67,7 @@
|
|||||||
size="mini"
|
size="mini"
|
||||||
:disabled="multiple"
|
:disabled="multiple"
|
||||||
@click="handleDelete"
|
@click="handleDelete"
|
||||||
v-hasPermi="['demo:test:remove']"
|
v-hasPermi="['demo:demo:remove']"
|
||||||
>删除</el-button>
|
>删除</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
@ -112,27 +76,34 @@
|
|||||||
plain
|
plain
|
||||||
icon="el-icon-download"
|
icon="el-icon-download"
|
||||||
size="mini"
|
size="mini"
|
||||||
|
:loading="exportLoading"
|
||||||
@click="handleExport"
|
@click="handleExport"
|
||||||
v-hasPermi="['demo:test:export']"
|
v-hasPermi="['demo:demo:export']"
|
||||||
>导出</el-button>
|
>导出</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="testList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="demoList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="主键" align="center" prop="id" v-if="false"/>
|
<el-table-column label="主键" align="center" prop="id" v-if="false"/>
|
||||||
|
<el-table-column label="部门id" align="center" prop="deptId" />
|
||||||
|
<el-table-column label="用户id" align="center" prop="userId" />
|
||||||
|
<el-table-column label="排序号" align="center" prop="orderNum" />
|
||||||
<el-table-column label="key键" align="center" prop="testKey" />
|
<el-table-column label="key键" align="center" prop="testKey" />
|
||||||
<el-table-column label="值" align="center" prop="value" />
|
<el-table-column label="值" align="center" prop="value" />
|
||||||
<el-table-column label="版本" align="center" prop="version" />
|
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
|
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="删除标志" align="center" prop="deleted" />
|
<el-table-column label="创建人" align="center" prop="createBy" />
|
||||||
<el-table-column label="父id" align="center" prop="parentId" />
|
<el-table-column label="更新时间" align="center" prop="updateTime" width="180">
|
||||||
<el-table-column label="排序号" align="center" prop="orderNum" />
|
<template slot-scope="scope">
|
||||||
|
<span>{{ parseTime(scope.row.updateTime, '{y}-{m}-{d}') }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="更新人" align="center" prop="updateBy" />
|
||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button
|
<el-button
|
||||||
@ -140,14 +111,14 @@
|
|||||||
type="text"
|
type="text"
|
||||||
icon="el-icon-edit"
|
icon="el-icon-edit"
|
||||||
@click="handleUpdate(scope.row)"
|
@click="handleUpdate(scope.row)"
|
||||||
v-hasPermi="['demo:test:edit']"
|
v-hasPermi="['demo:demo:edit']"
|
||||||
>修改</el-button>
|
>修改</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
size="mini"
|
size="mini"
|
||||||
type="text"
|
type="text"
|
||||||
icon="el-icon-delete"
|
icon="el-icon-delete"
|
||||||
@click="handleDelete(scope.row)"
|
@click="handleDelete(scope.row)"
|
||||||
v-hasPermi="['demo:test:remove']"
|
v-hasPermi="['demo:demo:remove']"
|
||||||
>删除</el-button>
|
>删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -161,30 +132,35 @@
|
|||||||
@pagination="getList"
|
@pagination="getList"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 添加或修改测试对话框 -->
|
<!-- 添加或修改测试单表对话框 -->
|
||||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||||
|
<el-form-item label="部门id" prop="deptId">
|
||||||
|
<el-input v-model="form.deptId" placeholder="请输入部门id" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="用户id" prop="userId">
|
||||||
|
<el-input v-model="form.userId" placeholder="请输入用户id" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="排序号" prop="orderNum">
|
||||||
|
<el-input v-model="form.orderNum" placeholder="请输入排序号" />
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="key键" prop="testKey">
|
<el-form-item label="key键" prop="testKey">
|
||||||
<el-input v-model="form.testKey" placeholder="请输入key键" />
|
<el-input v-model="form.testKey" placeholder="请输入key键" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="值" prop="value">
|
<el-form-item label="值" prop="value">
|
||||||
<el-input v-model="form.value" placeholder="请输入值" />
|
<el-input v-model="form.value" placeholder="请输入值" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="版本" prop="version">
|
<el-form-item label="创建时间" prop="createTime">
|
||||||
<el-input v-model="form.version" placeholder="请输入版本" />
|
<el-date-picker clearable size="small"
|
||||||
</el-form-item>
|
v-model="form.createTime"
|
||||||
<el-form-item label="删除标志" prop="deleted">
|
type="datetime"
|
||||||
<el-input v-model="form.deleted" placeholder="请输入删除标志" />
|
value-format="yyyy-MM-dd HH:mm:ss"
|
||||||
</el-form-item>
|
placeholder="选择创建时间">
|
||||||
<el-form-item label="父id" prop="parentId">
|
</el-date-picker>
|
||||||
<el-input v-model="form.parentId" placeholder="请输入父id" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="排序号" prop="orderNum">
|
|
||||||
<el-input v-model="form.orderNum" placeholder="请输入排序号" />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div slot="footer" class="dialog-footer">
|
<div slot="footer" class="dialog-footer">
|
||||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||||
<el-button @click="cancel">取 消</el-button>
|
<el-button @click="cancel">取 消</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
@ -192,16 +168,20 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { listTest, getTest, delTest, addTest, updateTest, exportTest } from "@/api/demo/test";
|
import { listDemo, getDemo, delDemo, addDemo, updateDemo, exportDemo } from "@/api/demo/demo";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Test",
|
name: "Demo",
|
||||||
components: {
|
components: {
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
//按钮loading
|
||||||
|
buttonLoading: false,
|
||||||
// 遮罩层
|
// 遮罩层
|
||||||
loading: true,
|
loading: true,
|
||||||
|
// 导出遮罩层
|
||||||
|
exportLoading: false,
|
||||||
// 选中数组
|
// 选中数组
|
||||||
ids: [],
|
ids: [],
|
||||||
// 非单个禁用
|
// 非单个禁用
|
||||||
@ -212,8 +192,8 @@ export default {
|
|||||||
showSearch: true,
|
showSearch: true,
|
||||||
// 总条数
|
// 总条数
|
||||||
total: 0,
|
total: 0,
|
||||||
// 测试表格数据
|
// 测试单表表格数据
|
||||||
testList: [],
|
demoList: [],
|
||||||
// 弹出层标题
|
// 弹出层标题
|
||||||
title: "",
|
title: "",
|
||||||
// 是否显示弹出层
|
// 是否显示弹出层
|
||||||
@ -226,16 +206,18 @@ export default {
|
|||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
testKey: undefined,
|
testKey: undefined,
|
||||||
value: undefined,
|
value: undefined,
|
||||||
version: undefined,
|
|
||||||
createTime: undefined,
|
createTime: undefined,
|
||||||
deleted: undefined,
|
|
||||||
parentId: undefined,
|
|
||||||
orderNum: undefined
|
|
||||||
},
|
},
|
||||||
// 表单参数
|
// 表单参数
|
||||||
form: {},
|
form: {},
|
||||||
// 表单校验
|
// 表单校验
|
||||||
rules: {
|
rules: {
|
||||||
|
testKey: [
|
||||||
|
{ required: true, message: "key键不能为空", trigger: "blur" }
|
||||||
|
],
|
||||||
|
value: [
|
||||||
|
{ required: true, message: "值不能为空", trigger: "blur" }
|
||||||
|
],
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -243,7 +225,7 @@ export default {
|
|||||||
this.getList();
|
this.getList();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/** 查询测试列表 */
|
/** 查询测试单表列表 */
|
||||||
getList() {
|
getList() {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.queryParams.params = {};
|
this.queryParams.params = {};
|
||||||
@ -251,8 +233,8 @@ export default {
|
|||||||
this.queryParams.params["beginCreateTime"] = this.daterangeCreateTime[0];
|
this.queryParams.params["beginCreateTime"] = this.daterangeCreateTime[0];
|
||||||
this.queryParams.params["endCreateTime"] = this.daterangeCreateTime[1];
|
this.queryParams.params["endCreateTime"] = this.daterangeCreateTime[1];
|
||||||
}
|
}
|
||||||
listTest(this.queryParams).then(response => {
|
listDemo(this.queryParams).then(response => {
|
||||||
this.testList = response.rows;
|
this.demoList = response.rows;
|
||||||
this.total = response.total;
|
this.total = response.total;
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
});
|
});
|
||||||
@ -266,13 +248,17 @@ export default {
|
|||||||
reset() {
|
reset() {
|
||||||
this.form = {
|
this.form = {
|
||||||
id: undefined,
|
id: undefined,
|
||||||
|
deptId: undefined,
|
||||||
|
userId: undefined,
|
||||||
|
orderNum: undefined,
|
||||||
testKey: undefined,
|
testKey: undefined,
|
||||||
value: undefined,
|
value: undefined,
|
||||||
version: undefined,
|
version: undefined,
|
||||||
createTime: undefined,
|
createTime: undefined,
|
||||||
deleted: undefined,
|
createBy: undefined,
|
||||||
parentId: undefined,
|
updateTime: undefined,
|
||||||
orderNum: undefined
|
updateBy: undefined,
|
||||||
|
delFlag: undefined
|
||||||
};
|
};
|
||||||
this.resetForm("form");
|
this.resetForm("form");
|
||||||
},
|
},
|
||||||
@ -297,30 +283,35 @@ export default {
|
|||||||
handleAdd() {
|
handleAdd() {
|
||||||
this.reset();
|
this.reset();
|
||||||
this.open = true;
|
this.open = true;
|
||||||
this.title = "添加测试";
|
this.title = "添加测试单表";
|
||||||
},
|
},
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
handleUpdate(row) {
|
handleUpdate(row) {
|
||||||
|
this.loading = true;
|
||||||
this.reset();
|
this.reset();
|
||||||
const id = row.id || this.ids
|
const id = row.id || this.ids
|
||||||
getTest(id).then(response => {
|
getDemo(id).then(response => {
|
||||||
|
this.loading = false;
|
||||||
this.form = response.data;
|
this.form = response.data;
|
||||||
this.open = true;
|
this.open = true;
|
||||||
this.title = "修改测试";
|
this.title = "修改测试单表";
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
submitForm() {
|
submitForm() {
|
||||||
this.$refs["form"].validate(valid => {
|
this.$refs["form"].validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
|
this.buttonLoading = true;
|
||||||
if (this.form.id != null) {
|
if (this.form.id != null) {
|
||||||
updateTest(this.form).then(response => {
|
updateDemo(this.form).then(response => {
|
||||||
|
this.buttonLoading = false;
|
||||||
this.msgSuccess("修改成功");
|
this.msgSuccess("修改成功");
|
||||||
this.open = false;
|
this.open = false;
|
||||||
this.getList();
|
this.getList();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
addTest(this.form).then(response => {
|
addDemo(this.form).then(response => {
|
||||||
|
this.buttonLoading = false;
|
||||||
this.msgSuccess("新增成功");
|
this.msgSuccess("新增成功");
|
||||||
this.open = false;
|
this.open = false;
|
||||||
this.getList();
|
this.getList();
|
||||||
@ -332,13 +323,15 @@ export default {
|
|||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
handleDelete(row) {
|
handleDelete(row) {
|
||||||
const ids = row.id || this.ids;
|
const ids = row.id || this.ids;
|
||||||
this.$confirm('是否确认删除测试编号为"' + ids + '"的数据项?', "警告", {
|
this.$confirm('是否确认删除测试单表编号为"' + ids + '"的数据项?', "警告", {
|
||||||
confirmButtonText: "确定",
|
confirmButtonText: "确定",
|
||||||
cancelButtonText: "取消",
|
cancelButtonText: "取消",
|
||||||
type: "warning"
|
type: "warning"
|
||||||
}).then(function() {
|
|
||||||
return delTest(ids);
|
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
this.loading = true;
|
||||||
|
return delDemo(ids);
|
||||||
|
}).then(() => {
|
||||||
|
this.loading = false;
|
||||||
this.getList();
|
this.getList();
|
||||||
this.msgSuccess("删除成功");
|
this.msgSuccess("删除成功");
|
||||||
})
|
})
|
||||||
@ -346,14 +339,16 @@ export default {
|
|||||||
/** 导出按钮操作 */
|
/** 导出按钮操作 */
|
||||||
handleExport() {
|
handleExport() {
|
||||||
const queryParams = this.queryParams;
|
const queryParams = this.queryParams;
|
||||||
this.$confirm('是否确认导出所有测试数据项?', "警告", {
|
this.$confirm('是否确认导出所有测试单表数据项?', "警告", {
|
||||||
confirmButtonText: "确定",
|
confirmButtonText: "确定",
|
||||||
cancelButtonText: "取消",
|
cancelButtonText: "取消",
|
||||||
type: "warning"
|
type: "warning"
|
||||||
}).then(function() {
|
}).then(() => {
|
||||||
return exportTest(queryParams);
|
this.exportLoading = true;
|
||||||
|
return exportDemo(queryParams);
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
this.download(response.msg);
|
this.download(response.msg);
|
||||||
|
this.exportLoading = false;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -53,7 +53,7 @@
|
|||||||
<li>JWT</li>
|
<li>JWT</li>
|
||||||
<li>MyBatis</li>
|
<li>MyBatis</li>
|
||||||
<li>Druid</li>
|
<li>Druid</li>
|
||||||
<li>Fastjson</li>
|
<li>Jackson</li>
|
||||||
<li>...</li>
|
<li>...</li>
|
||||||
</ul>
|
</ul>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
@ -1,26 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-loading="loading" :style="'height:'+ height">
|
<i-frame :src="url" />
|
||||||
<iframe :src="src" frameborder="no" style="width: 100%;height: 100%" scrolling="auto" />
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
import iFrame from "@/components/iFrame/index";
|
||||||
export default {
|
export default {
|
||||||
name: "Druid",
|
name: "Druid",
|
||||||
|
components: { iFrame },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
src: process.env.VUE_APP_BASE_API + "/druid/login.html",
|
url: process.env.VUE_APP_BASE_API + "/druid/login.html"
|
||||||
height: document.documentElement.clientHeight - 94.5 + "px;",
|
|
||||||
loading: true
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted: function() {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.loading = false;
|
|
||||||
}, 230);
|
|
||||||
const that = this;
|
|
||||||
window.onresize = function temp() {
|
|
||||||
that.height = document.documentElement.clientHeight - 94.5 + "px;";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -91,17 +91,17 @@
|
|||||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
|
<el-table ref="tables" v-loading="loading" :data="list" @selection-change="handleSelectionChange" :default-sort="defaultSort" @sort-change="handleSortChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="访问编号" align="center" prop="infoId" />
|
<el-table-column label="访问编号" align="center" prop="infoId" />
|
||||||
<el-table-column label="用户名称" align="center" prop="userName" />
|
<el-table-column label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']" />
|
||||||
<el-table-column label="登录地址" align="center" prop="ipaddr" width="130" :show-overflow-tooltip="true" />
|
<el-table-column label="登录地址" align="center" prop="ipaddr" width="130" :show-overflow-tooltip="true" />
|
||||||
<el-table-column label="登录地点" align="center" prop="loginLocation" :show-overflow-tooltip="true" />
|
<el-table-column label="登录地点" align="center" prop="loginLocation" :show-overflow-tooltip="true" />
|
||||||
<el-table-column label="浏览器" align="center" prop="browser" />
|
<el-table-column label="浏览器" align="center" prop="browser" :show-overflow-tooltip="true" />
|
||||||
<el-table-column label="操作系统" align="center" prop="os" />
|
<el-table-column label="操作系统" align="center" prop="os" />
|
||||||
<el-table-column label="登录状态" align="center" prop="status" :formatter="statusFormat" />
|
<el-table-column label="登录状态" align="center" prop="status" :formatter="statusFormat" />
|
||||||
<el-table-column label="操作信息" align="center" prop="msg" />
|
<el-table-column label="操作信息" align="center" prop="msg" />
|
||||||
<el-table-column label="登录日期" align="center" prop="loginTime" width="180">
|
<el-table-column label="登录日期" align="center" prop="loginTime" sortable="custom" :sort-orders="['descending', 'ascending']" width="180">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<span>{{ parseTime(scope.row.loginTime) }}</span>
|
<span>{{ parseTime(scope.row.loginTime) }}</span>
|
||||||
</template>
|
</template>
|
||||||
@ -143,6 +143,8 @@ export default {
|
|||||||
statusOptions: [],
|
statusOptions: [],
|
||||||
// 日期范围
|
// 日期范围
|
||||||
dateRange: [],
|
dateRange: [],
|
||||||
|
// 默认排序
|
||||||
|
defaultSort: {prop: 'loginTime', order: 'descending'},
|
||||||
// 查询参数
|
// 查询参数
|
||||||
queryParams: {
|
queryParams: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
@ -183,13 +185,20 @@ export default {
|
|||||||
resetQuery() {
|
resetQuery() {
|
||||||
this.dateRange = [];
|
this.dateRange = [];
|
||||||
this.resetForm("queryForm");
|
this.resetForm("queryForm");
|
||||||
|
this.$refs.tables.sort(this.defaultSort.prop, this.defaultSort.order)
|
||||||
this.handleQuery();
|
this.handleQuery();
|
||||||
},
|
},
|
||||||
// 多选框选中数据
|
/** 多选框选中数据 */
|
||||||
handleSelectionChange(selection) {
|
handleSelectionChange(selection) {
|
||||||
this.ids = selection.map(item => item.infoId)
|
this.ids = selection.map(item => item.infoId)
|
||||||
this.multiple = !selection.length
|
this.multiple = !selection.length
|
||||||
},
|
},
|
||||||
|
/** 排序触发事件 */
|
||||||
|
handleSortChange(column, prop, order) {
|
||||||
|
this.queryParams.orderByColumn = column.prop;
|
||||||
|
this.queryParams.isAsc = column.order;
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
handleDelete(row) {
|
handleDelete(row) {
|
||||||
const infoIds = row.infoId || this.ids;
|
const infoIds = row.infoId || this.ids;
|
||||||
|
@ -107,17 +107,17 @@
|
|||||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
|
<el-table ref="tables" v-loading="loading" :data="list" @selection-change="handleSelectionChange" :default-sort="defaultSort" @sort-change="handleSortChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="日志编号" align="center" prop="operId" />
|
<el-table-column label="日志编号" align="center" prop="operId" />
|
||||||
<el-table-column label="系统模块" align="center" prop="title" />
|
<el-table-column label="系统模块" align="center" prop="title" />
|
||||||
<el-table-column label="操作类型" align="center" prop="businessType" :formatter="typeFormat" />
|
<el-table-column label="操作类型" align="center" prop="businessType" :formatter="typeFormat" />
|
||||||
<el-table-column label="请求方式" align="center" prop="requestMethod" />
|
<el-table-column label="请求方式" align="center" prop="requestMethod" />
|
||||||
<el-table-column label="操作人员" align="center" prop="operName" />
|
<el-table-column label="操作人员" align="center" prop="operName" width="100" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']" />
|
||||||
<el-table-column label="主机" align="center" prop="operIp" width="130" :show-overflow-tooltip="true" />
|
<el-table-column label="操作地址" align="center" prop="operIp" width="130" :show-overflow-tooltip="true" />
|
||||||
<el-table-column label="操作地点" align="center" prop="operLocation" :show-overflow-tooltip="true" />
|
<el-table-column label="操作地点" align="center" prop="operLocation" :show-overflow-tooltip="true" />
|
||||||
<el-table-column label="操作状态" align="center" prop="status" :formatter="statusFormat" />
|
<el-table-column label="操作状态" align="center" prop="status" :formatter="statusFormat" />
|
||||||
<el-table-column label="操作日期" align="center" prop="operTime" width="180">
|
<el-table-column label="操作日期" align="center" prop="operTime" sortable="custom" :sort-orders="['descending', 'ascending']" width="180">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<span>{{ parseTime(scope.row.operTime) }}</span>
|
<span>{{ parseTime(scope.row.operTime) }}</span>
|
||||||
</template>
|
</template>
|
||||||
@ -216,6 +216,8 @@ export default {
|
|||||||
statusOptions: [],
|
statusOptions: [],
|
||||||
// 日期范围
|
// 日期范围
|
||||||
dateRange: [],
|
dateRange: [],
|
||||||
|
// 默认排序
|
||||||
|
defaultSort: {prop: 'operTime', order: 'descending'},
|
||||||
// 表单参数
|
// 表单参数
|
||||||
form: {},
|
form: {},
|
||||||
// 查询参数
|
// 查询参数
|
||||||
@ -266,13 +268,20 @@ export default {
|
|||||||
resetQuery() {
|
resetQuery() {
|
||||||
this.dateRange = [];
|
this.dateRange = [];
|
||||||
this.resetForm("queryForm");
|
this.resetForm("queryForm");
|
||||||
|
this.$refs.tables.sort(this.defaultSort.prop, this.defaultSort.order)
|
||||||
this.handleQuery();
|
this.handleQuery();
|
||||||
},
|
},
|
||||||
// 多选框选中数据
|
/** 多选框选中数据 */
|
||||||
handleSelectionChange(selection) {
|
handleSelectionChange(selection) {
|
||||||
this.ids = selection.map(item => item.operId)
|
this.ids = selection.map(item => item.operId)
|
||||||
this.multiple = !selection.length
|
this.multiple = !selection.length
|
||||||
},
|
},
|
||||||
|
/** 排序触发事件 */
|
||||||
|
handleSortChange(column, prop, order) {
|
||||||
|
this.queryParams.orderByColumn = column.prop;
|
||||||
|
this.queryParams.isAsc = column.order;
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
/** 详细按钮操作 */
|
/** 详细按钮操作 */
|
||||||
handleView(row) {
|
handleView(row) {
|
||||||
this.open = true;
|
this.open = true;
|
||||||
|
@ -86,10 +86,19 @@
|
|||||||
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="字典编码" align="center" prop="dictCode" />
|
<el-table-column label="字典编码" align="center" prop="dictCode" />
|
||||||
<el-table-column label="字典标签" align="center" prop="dictLabel" />
|
<el-table-column label="字典标签" align="center" prop="dictLabel">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span v-if="scope.row.listClass == '' || scope.row.listClass == 'default'">{{scope.row.dictLabel}}</span>
|
||||||
|
<el-tag v-else :type="scope.row.listClass == 'primary' ? '' : scope.row.listClass">{{scope.row.dictLabel}}</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column label="字典键值" align="center" prop="dictValue" />
|
<el-table-column label="字典键值" align="center" prop="dictValue" />
|
||||||
<el-table-column label="字典排序" align="center" prop="dictSort" />
|
<el-table-column label="字典排序" align="center" prop="dictSort" />
|
||||||
<el-table-column label="状态" align="center" prop="status" :formatter="statusFormat" />
|
<el-table-column label="状态" align="center" prop="status">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<dict-tag :options="statusOptions" :value="scope.row.status"/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
|
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
@ -136,9 +145,22 @@
|
|||||||
<el-form-item label="数据键值" prop="dictValue">
|
<el-form-item label="数据键值" prop="dictValue">
|
||||||
<el-input v-model="form.dictValue" placeholder="请输入数据键值" />
|
<el-input v-model="form.dictValue" placeholder="请输入数据键值" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="样式属性" prop="cssClass">
|
||||||
|
<el-input v-model="form.cssClass" placeholder="请输入样式属性" />
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="显示排序" prop="dictSort">
|
<el-form-item label="显示排序" prop="dictSort">
|
||||||
<el-input-number v-model="form.dictSort" controls-position="right" :min="0" />
|
<el-input-number v-model="form.dictSort" controls-position="right" :min="0" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="回显样式" prop="listClass">
|
||||||
|
<el-select v-model="form.listClass">
|
||||||
|
<el-option
|
||||||
|
v-for="item in listClassOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="状态" prop="status">
|
<el-form-item label="状态" prop="status">
|
||||||
<el-radio-group v-model="form.status">
|
<el-radio-group v-model="form.status">
|
||||||
<el-radio
|
<el-radio
|
||||||
@ -190,6 +212,33 @@ export default {
|
|||||||
title: "",
|
title: "",
|
||||||
// 是否显示弹出层
|
// 是否显示弹出层
|
||||||
open: false,
|
open: false,
|
||||||
|
// 数据标签回显样式
|
||||||
|
listClassOptions: [
|
||||||
|
{
|
||||||
|
value: "default",
|
||||||
|
label: "默认"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "primary",
|
||||||
|
label: "主要"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "success",
|
||||||
|
label: "成功"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "info",
|
||||||
|
label: "信息"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "warning",
|
||||||
|
label: "警告"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "danger",
|
||||||
|
label: "危险"
|
||||||
|
}
|
||||||
|
],
|
||||||
// 状态数据字典
|
// 状态数据字典
|
||||||
statusOptions: [],
|
statusOptions: [],
|
||||||
// 类型数据字典
|
// 类型数据字典
|
||||||
@ -250,10 +299,6 @@ export default {
|
|||||||
this.loading = false;
|
this.loading = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
// 数据状态字典翻译
|
|
||||||
statusFormat(row, column) {
|
|
||||||
return this.selectDictLabel(this.statusOptions, row.status);
|
|
||||||
},
|
|
||||||
// 取消按钮
|
// 取消按钮
|
||||||
cancel() {
|
cancel() {
|
||||||
this.open = false;
|
this.open = false;
|
||||||
@ -265,6 +310,8 @@ export default {
|
|||||||
dictCode: undefined,
|
dictCode: undefined,
|
||||||
dictLabel: undefined,
|
dictLabel: undefined,
|
||||||
dictValue: undefined,
|
dictValue: undefined,
|
||||||
|
cssClass: undefined,
|
||||||
|
listClass: 'default',
|
||||||
dictSort: 0,
|
dictSort: 0,
|
||||||
status: "0",
|
status: "0",
|
||||||
remark: undefined
|
remark: undefined
|
||||||
|
@ -123,7 +123,11 @@
|
|||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="状态" align="center" prop="status" :formatter="statusFormat" />
|
<el-table-column label="状态" align="center" prop="status">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<dict-tag :options="statusOptions" :value="scope.row.status"/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
|
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
@ -257,10 +261,6 @@ export default {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
// 字典状态字典翻译
|
|
||||||
statusFormat(row, column) {
|
|
||||||
return this.selectDictLabel(this.statusOptions, row.status);
|
|
||||||
},
|
|
||||||
// 取消按钮
|
// 取消按钮
|
||||||
cancel() {
|
cancel() {
|
||||||
this.open = false;
|
this.open = false;
|
||||||
|
@ -210,7 +210,7 @@
|
|||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="用户昵称" prop="nickName">
|
<el-form-item label="用户昵称" prop="nickName">
|
||||||
<el-input v-model="form.nickName" placeholder="请输入用户昵称" />
|
<el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
@ -234,12 +234,12 @@
|
|||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
|
<el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
|
||||||
<el-input v-model="form.userName" placeholder="请输入用户名称" />
|
<el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item v-if="form.userId == undefined" label="用户密码" prop="password">
|
<el-form-item v-if="form.userId == undefined" label="用户密码" prop="password">
|
||||||
<el-input v-model="form.password" placeholder="请输入用户密码" type="password" />
|
<el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -440,7 +440,8 @@ export default {
|
|||||||
{ required: true, message: "用户昵称不能为空", trigger: "blur" }
|
{ required: true, message: "用户昵称不能为空", trigger: "blur" }
|
||||||
],
|
],
|
||||||
password: [
|
password: [
|
||||||
{ required: true, message: "用户密码不能为空", trigger: "blur" }
|
{ required: true, message: "用户密码不能为空", trigger: "blur" },
|
||||||
|
{ min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' }
|
||||||
],
|
],
|
||||||
email: [
|
email: [
|
||||||
{
|
{
|
||||||
@ -545,7 +546,7 @@ export default {
|
|||||||
},
|
},
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
handleQuery() {
|
handleQuery() {
|
||||||
this.queryParams.page = 1;
|
this.queryParams.pageNum = 1;
|
||||||
this.getList();
|
this.getList();
|
||||||
},
|
},
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
@ -592,7 +593,10 @@ export default {
|
|||||||
handleResetPwd(row) {
|
handleResetPwd(row) {
|
||||||
this.$prompt('请输入"' + row.userName + '"的新密码', "提示", {
|
this.$prompt('请输入"' + row.userName + '"的新密码', "提示", {
|
||||||
confirmButtonText: "确定",
|
confirmButtonText: "确定",
|
||||||
cancelButtonText: "取消"
|
cancelButtonText: "取消",
|
||||||
|
closeOnClickModal: false,
|
||||||
|
inputPattern: /^.{5,20}$/,
|
||||||
|
inputErrorMessage: "用户密码长度必须介于 5 和 20 之间",
|
||||||
}).then(({ value }) => {
|
}).then(({ value }) => {
|
||||||
resetUserPwd(row.userId, value).then(response => {
|
resetUserPwd(row.userId, value).then(response => {
|
||||||
this.msgSuccess("修改成功,新密码是:" + value);
|
this.msgSuccess("修改成功,新密码是:" + value);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-form ref="form" :model="user" :rules="rules" label-width="80px">
|
<el-form ref="form" :model="user" :rules="rules" label-width="80px">
|
||||||
<el-form-item label="用户昵称" prop="nickName">
|
<el-form-item label="用户昵称" prop="nickName">
|
||||||
<el-input v-model="user.nickName" />
|
<el-input v-model="user.nickName" maxlength="30" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="手机号码" prop="phonenumber">
|
<el-form-item label="手机号码" prop="phonenumber">
|
||||||
<el-input v-model="user.phonenumber" maxlength="11" />
|
<el-input v-model="user.phonenumber" maxlength="11" />
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<el-select v-model="info.tplCategory" @change="tplSelectChange">
|
<el-select v-model="info.tplCategory" @change="tplSelectChange">
|
||||||
<el-option label="单表(增删改查)" value="crud" />
|
<el-option label="单表(增删改查)" value="crud" />
|
||||||
<el-option label="树表(增删改查)" value="tree" />
|
<el-option label="树表(增删改查)" value="tree" />
|
||||||
<el-option label="主子表(增删改查)" value="sub" />
|
<!-- <el-option label="主子表(增删改查)" value="sub" />-->
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
@ -1,26 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-loading="loading" :style="'height:'+ height">
|
<i-frame :src="url" />
|
||||||
<iframe :src="src" frameborder="no" style="width: 100%;height: 100%" scrolling="auto" />
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
import iFrame from "@/components/iFrame/index";
|
||||||
export default {
|
export default {
|
||||||
name: "Swagger",
|
name: "Swagger",
|
||||||
|
components: { iFrame },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
src: process.env.VUE_APP_BASE_API + "/doc.html",
|
url: process.env.VUE_APP_BASE_API + "/doc.html"
|
||||||
height: document.documentElement.clientHeight - 94.5 + "px;",
|
|
||||||
loading: true
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted: function() {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.loading = false;
|
|
||||||
}, 230);
|
|
||||||
const that = this;
|
|
||||||
window.onresize = function temp() {
|
|
||||||
that.height = document.documentElement.clientHeight - 94.5 + "px;";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const defaultSettings = require('./src/settings.js')
|
|
||||||
|
|
||||||
function resolve(dir) {
|
function resolve(dir) {
|
||||||
return path.join(__dirname, dir)
|
return path.join(__dirname, dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
const name = defaultSettings.title || 'RuoYi-Vue-Plus后台管理系统' // 标题
|
const name = process.env.VUE_APP_TITLE || 'RuoYi-Vue-Plus后台管理系统' // 网页标题
|
||||||
|
|
||||||
const port = process.env.port || process.env.npm_config_port || 80 // 端口
|
const port = process.env.port || process.env.npm_config_port || 80 // 端口
|
||||||
|
|
||||||
|
@ -14,23 +14,24 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<ruoyi-vue-plus.version>2.3.2</ruoyi-vue-plus.version>
|
<ruoyi-vue-plus.version>2.3.2</ruoyi-vue-plus.version>
|
||||||
<spring-boot.version>2.3.11.RELEASE</spring-boot.version>
|
<spring-boot.version>2.4.7</spring-boot.version>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
<java.version>1.8</java.version>
|
<java.version>1.8</java.version>
|
||||||
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
|
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
|
||||||
<druid.version>1.2.6</druid.version>
|
<druid.version>1.2.6</druid.version>
|
||||||
<knife4j.version>3.0.2</knife4j.version>
|
<knife4j.version>3.0.2</knife4j.version>
|
||||||
<fastjson.version>1.2.76</fastjson.version>
|
|
||||||
<poi.version>4.1.2</poi.version>
|
<poi.version>4.1.2</poi.version>
|
||||||
<velocity.version>1.7</velocity.version>
|
<velocity.version>1.7</velocity.version>
|
||||||
<jwt.version>0.9.1</jwt.version>
|
<jwt.version>0.9.1</jwt.version>
|
||||||
<mybatis-plus.version>3.4.3</mybatis-plus.version>
|
<mybatis-plus.version>3.4.3</mybatis-plus.version>
|
||||||
<hutool.version>5.5.8</hutool.version>
|
<hutool.version>5.7.2</hutool.version>
|
||||||
<feign.version>2.2.6.RELEASE</feign.version>
|
<feign.version>3.0.3</feign.version>
|
||||||
<feign-okhttp.version>11.0</feign-okhttp.version>
|
<feign-okhttp.version>11.0</feign-okhttp.version>
|
||||||
<spring-boot-admin.version>2.3.1</spring-boot-admin.version>
|
<spring-boot-admin.version>2.4.1</spring-boot-admin.version>
|
||||||
<redisson.version>3.15.2</redisson.version>
|
<redisson.version>3.15.2</redisson.version>
|
||||||
|
<lock4j.version>2.2.1</lock4j.version>
|
||||||
|
<datasource.version>3.4.0</datasource.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<!-- 依赖声明 -->
|
<!-- 依赖声明 -->
|
||||||
@ -168,13 +169,6 @@
|
|||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- 阿里JSON解析器 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.alibaba</groupId>
|
|
||||||
<artifactId>fastjson</artifactId>
|
|
||||||
<version>${fastjson.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- excel工具 -->
|
<!-- excel工具 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.poi</groupId>
|
<groupId>org.apache.poi</groupId>
|
||||||
@ -213,6 +207,13 @@
|
|||||||
<artifactId>javax.servlet-api</artifactId>
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- dynamic-datasource 多数据源-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
|
||||||
|
<version>${datasource.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||||
@ -273,6 +274,11 @@
|
|||||||
<artifactId>redisson-spring-boot-starter</artifactId>
|
<artifactId>redisson-spring-boot-starter</artifactId>
|
||||||
<version>${redisson.version}</version>
|
<version>${redisson.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>lock4j-redisson-spring-boot-starter</artifactId>
|
||||||
|
<version>${lock4j.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
@ -377,6 +383,45 @@
|
|||||||
<logging.level>warn</logging.level>
|
<logging.level>warn</logging.level>
|
||||||
</properties>
|
</properties>
|
||||||
</profile>
|
</profile>
|
||||||
|
|
||||||
|
<!-- jdk多版本配置 -->
|
||||||
|
<profile>
|
||||||
|
<id>jdk8</id>
|
||||||
|
<activation>
|
||||||
|
<activeByDefault>true</activeByDefault>
|
||||||
|
<jdk>1.8</jdk>
|
||||||
|
</activation>
|
||||||
|
<properties>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
</properties>
|
||||||
|
</profile>
|
||||||
|
<profile>
|
||||||
|
<id>jdk11</id>
|
||||||
|
<activation>
|
||||||
|
<jdk>11</jdk>
|
||||||
|
</activation>
|
||||||
|
<properties>
|
||||||
|
<java.version>11</java.version>
|
||||||
|
<jaxb.version>3.0.1</jaxb.version>
|
||||||
|
</properties>
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<!-- jdk11 缺失依赖 jaxb-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.xml.bind</groupId>
|
||||||
|
<artifactId>jaxb-impl</artifactId>
|
||||||
|
<version>${jaxb.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<!--jaxb-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.xml.bind</groupId>
|
||||||
|
<artifactId>jaxb-impl</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</profile>
|
||||||
</profiles>
|
</profiles>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -2,7 +2,6 @@ package com.ruoyi;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 启动程序
|
* 启动程序
|
||||||
@ -10,7 +9,7 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
|||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
|
@SpringBootApplication
|
||||||
public class RuoYiApplication
|
public class RuoYiApplication
|
||||||
{
|
{
|
||||||
public static void main(String[] args)
|
public static void main(String[] args)
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
package com.ruoyi.common.annotation;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分布式锁(注解模式,不推荐使用,最好用锁的工具类)
|
|
||||||
*
|
|
||||||
* @author shenxinquan
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Target({ElementType.METHOD})
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public @interface RedisLock {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 锁过期时间 默认30秒
|
|
||||||
*/
|
|
||||||
int expireTime() default 30;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 锁key值
|
|
||||||
*/
|
|
||||||
String key() default "redisLockKey";
|
|
||||||
}
|
|
@ -127,6 +127,11 @@ public class Constants
|
|||||||
*/
|
*/
|
||||||
public static final String RESOURCE_PREFIX = "/profile";
|
public static final String RESOURCE_PREFIX = "/profile";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RMI 远程方法调用
|
||||||
|
*/
|
||||||
|
public static final String LOOKUP_RMI = "rmi://";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 资源映射路径 前缀
|
* 资源映射路径 前缀
|
||||||
*/
|
*/
|
||||||
|
@ -2,14 +2,8 @@ package com.ruoyi.common.core.controller;
|
|||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
import com.ruoyi.common.utils.DateUtils;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.web.bind.WebDataBinder;
|
|
||||||
import org.springframework.web.bind.annotation.InitBinder;
|
|
||||||
|
|
||||||
import java.beans.PropertyEditorSupport;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* web层通用数据处理
|
* web层通用数据处理
|
||||||
@ -20,23 +14,6 @@ public class BaseController
|
|||||||
{
|
{
|
||||||
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
|
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||||
|
|
||||||
/**
|
|
||||||
* 将前台传递过来的日期格式的字符串,自动转化为Date类型
|
|
||||||
*/
|
|
||||||
@InitBinder
|
|
||||||
public void initBinder(WebDataBinder binder)
|
|
||||||
{
|
|
||||||
// Date 类型转换
|
|
||||||
binder.registerCustomEditor(Date.class, new PropertyEditorSupport()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void setAsText(String text)
|
|
||||||
{
|
|
||||||
setValue(DateUtils.parseDate(text));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 响应返回结果
|
* 响应返回结果
|
||||||
*
|
*
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.ruoyi.common.core.domain;
|
package com.ruoyi.common.core.domain;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
@ -30,14 +29,12 @@ public class BaseEntity implements Serializable
|
|||||||
private String createBy;
|
private String createBy;
|
||||||
|
|
||||||
/** 创建时间 */
|
/** 创建时间 */
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
|
||||||
private Date createTime;
|
private Date createTime;
|
||||||
|
|
||||||
/** 更新者 */
|
/** 更新者 */
|
||||||
private String updateBy;
|
private String updateBy;
|
||||||
|
|
||||||
/** 更新时间 */
|
/** 更新时间 */
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
|
||||||
private Date updateTime;
|
private Date updateTime;
|
||||||
|
|
||||||
/** 备注 */
|
/** 备注 */
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package com.ruoyi.common.core.mybatisplus;
|
package com.ruoyi.common.core.mybatisplus.cache;
|
||||||
|
|
||||||
import cn.hutool.extra.spring.SpringUtil;
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
import com.ruoyi.common.core.redis.RedisCache;
|
import com.ruoyi.common.core.redis.RedisCache;
|
@ -1,6 +1,9 @@
|
|||||||
package com.ruoyi.common.core.page;
|
package com.ruoyi.common.core.mybatisplus.core;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定义 Mapper 接口, 实现 自定义扩展
|
* 自定义 Mapper 接口, 实现 自定义扩展
|
||||||
@ -9,4 +12,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
|||||||
* @since 2021-05-13
|
* @since 2021-05-13
|
||||||
*/
|
*/
|
||||||
public interface BaseMapperPlus<T> extends BaseMapper<T> {
|
public interface BaseMapperPlus<T> extends BaseMapper<T> {
|
||||||
|
|
||||||
|
int insertAll(@Param("list") Collection<T> batchList);
|
||||||
|
|
||||||
}
|
}
|
@ -1,9 +1,10 @@
|
|||||||
package com.ruoyi.common.core.page;
|
package com.ruoyi.common.core.mybatisplus.core;
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.ruoyi.common.core.page.PagePlus;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -182,7 +183,6 @@ public interface IServicePlus<T> extends IService<T> {
|
|||||||
*
|
*
|
||||||
* @param page 翻页对象
|
* @param page 翻页对象
|
||||||
* @param queryWrapper 实体对象封装操作类
|
* @param queryWrapper 实体对象封装操作类
|
||||||
* @param kClass vo类型
|
|
||||||
*/
|
*/
|
||||||
default <K> PagePlus<T, K> pageVo(PagePlus<T, K> page, Wrapper<T> queryWrapper, Class<K> kClass) {
|
default <K> PagePlus<T, K> pageVo(PagePlus<T, K> page, Wrapper<T> queryWrapper, Class<K> kClass) {
|
||||||
PagePlus<T, K> result = getBaseMapper().selectPage(page, queryWrapper);
|
PagePlus<T, K> result = getBaseMapper().selectPage(page, queryWrapper);
|
||||||
@ -210,7 +210,6 @@ public interface IServicePlus<T> extends IService<T> {
|
|||||||
* 无条件翻页查询
|
* 无条件翻页查询
|
||||||
*
|
*
|
||||||
* @param page 翻页对象
|
* @param page 翻页对象
|
||||||
* @param kClass vo类型
|
|
||||||
*/
|
*/
|
||||||
default <K> PagePlus<T, K> pageVo(PagePlus<T, K> page, Class<K> kClass) {
|
default <K> PagePlus<T, K> pageVo(PagePlus<T, K> page, Class<K> kClass) {
|
||||||
return pageVo(page, Wrappers.emptyWrapper(), kClass);
|
return pageVo(page, Wrappers.emptyWrapper(), kClass);
|
||||||
@ -226,5 +225,21 @@ public interface IServicePlus<T> extends IService<T> {
|
|||||||
return pageVo(page, Wrappers.emptyWrapper(), convertor);
|
return pageVo(page, Wrappers.emptyWrapper(), convertor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default boolean saveBatch(Collection<T> entityList) {
|
||||||
|
return saveBatch(entityList, DEFAULT_BATCH_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default boolean saveOrUpdateBatch(Collection<T> entityList) {
|
||||||
|
return saveOrUpdateBatch(entityList, DEFAULT_BATCH_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default boolean updateBatchById(Collection<T> entityList) {
|
||||||
|
return updateBatchById(entityList, DEFAULT_BATCH_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean saveAll(Collection<T> entityList);
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,90 @@
|
|||||||
|
package com.ruoyi.common.core.mybatisplus.core;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.ClassUtils;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.ResolvableType;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IServicePlus 实现类
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public class ServicePlusImpl<M extends BaseMapperPlus<T>, T> extends ServiceImpl<M, T> implements IServicePlus<T> {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected M baseMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public M getBaseMapper() {
|
||||||
|
return baseMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected Class<T> entityClass = currentModelClass();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<T> getEntityClass() {
|
||||||
|
return entityClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Class<T> mapperClass = currentMapperClass();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<T> currentMapperClass() {
|
||||||
|
return (Class<T>) this.getResolvableType().as(ServicePlusImpl.class).getGeneric(0).getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<T> currentModelClass() {
|
||||||
|
return (Class<T>) this.getResolvableType().as(ServicePlusImpl.class).getGeneric(1).getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ResolvableType getResolvableType() {
|
||||||
|
return ResolvableType.forClass(ClassUtils.getUserClass(getClass()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单条执行性能差
|
||||||
|
*
|
||||||
|
* {@link #saveAll(Collection)}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
@Override
|
||||||
|
public boolean saveBatch(Collection<T> entityList, int batchSize) {
|
||||||
|
return super.saveBatch(entityList, batchSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean saveOrUpdate(T entity) {
|
||||||
|
return super.saveOrUpdate(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单条执行性能差
|
||||||
|
*
|
||||||
|
* {@link #saveAll(Collection)}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
@Override
|
||||||
|
public boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize) {
|
||||||
|
return super.saveOrUpdateBatch(entityList, batchSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean updateBatchById(Collection<T> entityList, int batchSize) {
|
||||||
|
return super.updateBatchById(entityList, batchSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean saveAll(Collection<T> entityList) {
|
||||||
|
return baseMapper.insertAll(entityList) == entityList.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
package com.ruoyi.common.core.mybatisplus.methods;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
|
||||||
|
import org.apache.ibatis.mapping.MappedStatement;
|
||||||
|
import org.apache.ibatis.mapping.SqlSource;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.TableInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单sql批量插入
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
public class InsertAll extends AbstractMethod {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
|
||||||
|
final String sql = "<script>insert into %s %s values %s</script>";
|
||||||
|
final String fieldSql = prepareFieldSql(tableInfo);
|
||||||
|
final String valueSql = prepareValuesSqlForMysqlBatch(tableInfo);
|
||||||
|
final String sqlResult = String.format(sql, tableInfo.getTableName(), fieldSql, valueSql);
|
||||||
|
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);
|
||||||
|
return this.addInsertMappedStatement(mapperClass, modelClass, "insertAll", sqlSource, new NoKeyGenerator(), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String prepareFieldSql(TableInfo tableInfo) {
|
||||||
|
StringBuilder fieldSql = new StringBuilder();
|
||||||
|
if (StrUtil.isNotBlank(tableInfo.getKeyColumn())) {
|
||||||
|
fieldSql.append(tableInfo.getKeyColumn()).append(",");
|
||||||
|
}
|
||||||
|
tableInfo.getFieldList().forEach(x -> fieldSql.append(x.getColumn()).append(","));
|
||||||
|
fieldSql.delete(fieldSql.length() - 1, fieldSql.length());
|
||||||
|
fieldSql.insert(0, "(");
|
||||||
|
fieldSql.append(")");
|
||||||
|
return fieldSql.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String prepareValuesSqlForMysqlBatch(TableInfo tableInfo) {
|
||||||
|
final StringBuilder valueSql = new StringBuilder();
|
||||||
|
valueSql.append("<foreach collection=\"list\" item=\"item\" index=\"index\" open=\"(\" separator=\"),(\" close=\")\">");
|
||||||
|
if (StrUtil.isNotBlank(tableInfo.getKeyColumn())) {
|
||||||
|
valueSql.append("#{item.").append(tableInfo.getKeyProperty()).append("},");
|
||||||
|
}
|
||||||
|
tableInfo.getFieldList().forEach(x -> valueSql.append("#{item.").append(x.getProperty()).append("},"));
|
||||||
|
valueSql.delete(valueSql.length() - 1, valueSql.length());
|
||||||
|
valueSql.append("</foreach>");
|
||||||
|
return valueSql.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,39 +0,0 @@
|
|||||||
package com.ruoyi.common.core.page;
|
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import lombok.*;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分页数据
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@NoArgsConstructor
|
|
||||||
@Accessors(chain = true)
|
|
||||||
public class PageDomain
|
|
||||||
{
|
|
||||||
/** 当前记录起始索引 */
|
|
||||||
private Integer pageNum;
|
|
||||||
|
|
||||||
/** 每页显示记录数 */
|
|
||||||
private Integer pageSize;
|
|
||||||
|
|
||||||
/** 排序列 */
|
|
||||||
private String orderByColumn;
|
|
||||||
|
|
||||||
/** 排序的方向desc或者asc */
|
|
||||||
private String isAsc = "asc";
|
|
||||||
|
|
||||||
public String getOrderBy()
|
|
||||||
{
|
|
||||||
if (StrUtil.isEmpty(orderByColumn))
|
|
||||||
{
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return StrUtil.toUnderlineCase(orderByColumn) + " " + isAsc;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
package com.ruoyi.common.core.page;
|
|
||||||
|
|
||||||
import com.ruoyi.common.utils.ServletUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 表格数据处理
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class TableSupport
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 当前记录起始索引
|
|
||||||
*/
|
|
||||||
public static final String PAGE_NUM = "pageNum";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 每页显示记录数
|
|
||||||
*/
|
|
||||||
public static final String PAGE_SIZE = "pageSize";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 排序列
|
|
||||||
*/
|
|
||||||
public static final String ORDER_BY_COLUMN = "orderByColumn";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 排序的方向 "desc" 或者 "asc".
|
|
||||||
*/
|
|
||||||
public static final String IS_ASC = "isAsc";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 封装分页对象
|
|
||||||
*/
|
|
||||||
public static PageDomain getPageDomain()
|
|
||||||
{
|
|
||||||
PageDomain pageDomain = new PageDomain();
|
|
||||||
pageDomain.setPageNum(ServletUtils.getParameterToInt(PAGE_NUM));
|
|
||||||
pageDomain.setPageSize(ServletUtils.getParameterToInt(PAGE_SIZE));
|
|
||||||
pageDomain.setOrderByColumn(ServletUtils.getParameter(ORDER_BY_COLUMN));
|
|
||||||
pageDomain.setIsAsc(ServletUtils.getParameter(IS_ASC));
|
|
||||||
return pageDomain;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PageDomain buildPageRequest()
|
|
||||||
{
|
|
||||||
return getPageDomain();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,170 +0,0 @@
|
|||||||
package com.ruoyi.common.core.redis;
|
|
||||||
|
|
||||||
import cn.hutool.core.lang.Assert;
|
|
||||||
import cn.hutool.core.lang.Validator;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import org.redisson.api.RCountDownLatch;
|
|
||||||
import org.redisson.api.RLock;
|
|
||||||
import org.redisson.api.RedissonClient;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* redis 锁管理类
|
|
||||||
*
|
|
||||||
* @author shenxinquan
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class RedisLockManager {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RedissonClient redissonClient;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通用锁
|
|
||||||
*/
|
|
||||||
private final static Integer BASE_LOCK = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 公平锁
|
|
||||||
*/
|
|
||||||
private final static Integer FAIR_LOCK = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 存放当前线程获取锁的类型
|
|
||||||
*/
|
|
||||||
private final ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取锁
|
|
||||||
*/
|
|
||||||
private RLock getLock(String key, Integer lockType) {
|
|
||||||
Assert.isTrue(StrUtil.isNotBlank(key), "key不能为空");
|
|
||||||
threadLocal.set(lockType);
|
|
||||||
RLock lock;
|
|
||||||
if (BASE_LOCK.equals(lockType)) {
|
|
||||||
lock = redissonClient.getLock(key);
|
|
||||||
} else if (FAIR_LOCK.equals(lockType)) {
|
|
||||||
lock = redissonClient.getFairLock(key);
|
|
||||||
} else {
|
|
||||||
throw new RuntimeException("锁不存在!");
|
|
||||||
}
|
|
||||||
return lock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取锁(不用设置超时时间,一直等待)
|
|
||||||
*/
|
|
||||||
public boolean getLock(String key) {
|
|
||||||
RLock lock = getLock(key, BASE_LOCK);
|
|
||||||
return lock.tryLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置过期时间
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @param time 过期时间
|
|
||||||
* @param expireUnit 时间单位
|
|
||||||
*/
|
|
||||||
public boolean getLock(String key, long time, TimeUnit expireUnit) {
|
|
||||||
Assert.isTrue(time > 0, "过期时间必须大于0");
|
|
||||||
Assert.isTrue(Validator.isNotEmpty(expireUnit), "时间单位不能为空");
|
|
||||||
RLock lock = getLock(key, BASE_LOCK);
|
|
||||||
try {
|
|
||||||
return lock.tryLock(time, expireUnit);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置过期时间
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @param waitTime 获取锁等待时间
|
|
||||||
* @param leaseTime 保留锁的时间
|
|
||||||
* @param expireUnit 时间单位
|
|
||||||
*/
|
|
||||||
public boolean getLock(String key, long waitTime, long leaseTime, TimeUnit expireUnit) {
|
|
||||||
Assert.isTrue(waitTime > 0, "获取锁等待时间必须大于0");
|
|
||||||
Assert.isTrue(leaseTime > 0, "保留锁的时间必须大于0");
|
|
||||||
Assert.isTrue(Validator.isNotEmpty(expireUnit), "时间单位不能为空");
|
|
||||||
RLock lock = getLock(key, BASE_LOCK);
|
|
||||||
try {
|
|
||||||
return lock.tryLock(waitTime, leaseTime, expireUnit);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取计数器锁
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @param count countDownLatch 的数量
|
|
||||||
*/
|
|
||||||
public RCountDownLatch getCountDownLatch(String key, long count) {
|
|
||||||
Assert.isTrue(count >= 0, "count数量必须大于等于0");
|
|
||||||
RCountDownLatch rCountDownLatch = redissonClient.getCountDownLatch(key);
|
|
||||||
rCountDownLatch.trySetCount(count);
|
|
||||||
return rCountDownLatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取公平锁
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @param waitTime 获取锁等待时间
|
|
||||||
* @param leaseTime 持有锁的时间
|
|
||||||
* @param expireUnit 时间单位
|
|
||||||
* @return
|
|
||||||
* @throws InterruptedException
|
|
||||||
*/
|
|
||||||
public boolean getFairLock(String key, long waitTime, long leaseTime, TimeUnit expireUnit) {
|
|
||||||
Assert.isTrue(waitTime > 0, "获取锁等待时间必须大于0");
|
|
||||||
Assert.isTrue(leaseTime > 0, "保留锁的时间必须大于0");
|
|
||||||
Assert.isTrue(Validator.isNotEmpty(expireUnit), "时间单位不能为空");
|
|
||||||
RLock lock = getLock(key, FAIR_LOCK);
|
|
||||||
try {
|
|
||||||
return lock.tryLock(waitTime, leaseTime, expireUnit);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取公平锁
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @param leaseTime 持有锁的时间
|
|
||||||
* @param expireUnit 时间单位
|
|
||||||
*/
|
|
||||||
public boolean getFairLock(String key, long leaseTime, TimeUnit expireUnit) {
|
|
||||||
Assert.isTrue(leaseTime > 0, "保留锁的时间必须大于0");
|
|
||||||
Assert.isTrue(Validator.isNotEmpty(expireUnit), "时间单位不能为空");
|
|
||||||
RLock lock = getLock(key, FAIR_LOCK);
|
|
||||||
try {
|
|
||||||
return lock.tryLock(leaseTime, expireUnit);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 释放锁(统一释放)
|
|
||||||
*/
|
|
||||||
public void unLock(String key) {
|
|
||||||
Integer lockType = threadLocal.get();
|
|
||||||
RLock lock = getLock(key, lockType);
|
|
||||||
lock.unlock();
|
|
||||||
threadLocal.remove();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +1,25 @@
|
|||||||
package com.ruoyi.common.enums;
|
package com.ruoyi.common.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据源
|
* 数据源
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
public enum DataSourceType
|
@AllArgsConstructor
|
||||||
{
|
public enum DataSourceType {
|
||||||
/**
|
/**
|
||||||
* 主库
|
* 主库
|
||||||
*/
|
*/
|
||||||
MASTER,
|
MASTER("master"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从库
|
* 从库
|
||||||
*/
|
*/
|
||||||
SLAVE
|
SLAVE("slave");
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final String source;
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
package com.ruoyi.common.filter;
|
package com.ruoyi.common.filter;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import cn.hutool.core.io.IoUtil;
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import javax.servlet.ReadListener;
|
import javax.servlet.ReadListener;
|
||||||
import javax.servlet.ServletInputStream;
|
import javax.servlet.ServletInputStream;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletRequestWrapper;
|
import javax.servlet.http.HttpServletRequestWrapper;
|
||||||
import com.ruoyi.common.utils.http.HttpHelper;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建可重复读取inputStream的request
|
* 构建可重复读取inputStream的request
|
||||||
@ -26,7 +28,7 @@ public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper
|
|||||||
request.setCharacterEncoding("UTF-8");
|
request.setCharacterEncoding("UTF-8");
|
||||||
response.setCharacterEncoding("UTF-8");
|
response.setCharacterEncoding("UTF-8");
|
||||||
|
|
||||||
body = HttpHelper.getBodyString(request).getBytes("UTF-8");
|
body = IoUtil.readUtf8(request.getInputStream()).getBytes(StandardCharsets.UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package com.ruoyi.common.filter;
|
package com.ruoyi.common.filter;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.IoUtil;
|
||||||
import cn.hutool.core.lang.Validator;
|
import cn.hutool.core.lang.Validator;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.http.HtmlUtil;
|
import cn.hutool.http.HtmlUtil;
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
|
||||||
@ -13,6 +13,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
import javax.servlet.http.HttpServletRequestWrapper;
|
import javax.servlet.http.HttpServletRequestWrapper;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* XSS过滤处理
|
* XSS过滤处理
|
||||||
@ -57,7 +58,7 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 为空,直接返回
|
// 为空,直接返回
|
||||||
String json = IOUtils.toString(super.getInputStream(), "utf-8");
|
String json = IoUtil.read(super.getInputStream(), StandardCharsets.UTF_8);
|
||||||
if (Validator.isEmpty(json))
|
if (Validator.isEmpty(json))
|
||||||
{
|
{
|
||||||
return super.getInputStream();
|
return super.getInputStream();
|
||||||
@ -65,7 +66,8 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper
|
|||||||
|
|
||||||
// xss过滤
|
// xss过滤
|
||||||
json = HtmlUtil.cleanHtmlTag(json).trim();
|
json = HtmlUtil.cleanHtmlTag(json).trim();
|
||||||
final ByteArrayInputStream bis = new ByteArrayInputStream(json.getBytes("utf-8"));
|
|
||||||
|
final ByteArrayInputStream bis = IoUtil.toStream(json, StandardCharsets.UTF_8);
|
||||||
return new ServletInputStream()
|
return new ServletInputStream()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
|
101
ruoyi/src/main/java/com/ruoyi/common/utils/JsonUtils.java
Normal file
101
ruoyi/src/main/java/com/ruoyi/common/utils/JsonUtils.java
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
package com.ruoyi.common.utils;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Validator;
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON 工具类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public class JsonUtils {
|
||||||
|
|
||||||
|
private static ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化 objectMapper 属性
|
||||||
|
* <p>
|
||||||
|
* 通过这样的方式,使用 Spring 创建的 ObjectMapper Bean
|
||||||
|
*
|
||||||
|
* @param objectMapper ObjectMapper 对象
|
||||||
|
*/
|
||||||
|
public static void init(ObjectMapper objectMapper) {
|
||||||
|
JsonUtils.objectMapper = objectMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toJsonString(Object object) {
|
||||||
|
if (Validator.isEmpty(object)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return objectMapper.writeValueAsString(object);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T parseObject(String text, Class<T> clazz) {
|
||||||
|
if (StrUtil.isEmpty(text)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return objectMapper.readValue(text, clazz);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T parseObject(byte[] bytes, Class<T> clazz) {
|
||||||
|
if (ArrayUtil.isEmpty(bytes)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return objectMapper.readValue(bytes, clazz);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T parseObject(String text, TypeReference<T> typeReference) {
|
||||||
|
if (StrUtil.isBlank(text)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return objectMapper.readValue(text, typeReference);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Map<String, T> parseMap(String text) {
|
||||||
|
if (StrUtil.isBlank(text)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return objectMapper.readValue(text, new TypeReference<Map<String, T>>() {});
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> List<T> parseArray(String text, Class<T> clazz) {
|
||||||
|
if (StrUtil.isEmpty(text)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return objectMapper.readValue(text, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -70,19 +70,30 @@ public class PageUtils {
|
|||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> Page<T> buildPage() {
|
||||||
|
return buildPage(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建 MP 普通分页对象
|
* 构建 MP 普通分页对象
|
||||||
* @param <T> domain 实体
|
* @param <T> domain 实体
|
||||||
* @return 分页对象
|
* @return 分页对象
|
||||||
*/
|
*/
|
||||||
public static <T> Page<T> buildPage() {
|
public static <T> Page<T> buildPage(String defaultOrderByColumn, String defaultIsAsc) {
|
||||||
Integer pageNum = ServletUtils.getParameterToInt(PAGE_NUM, DEFAULT_PAGE_NUM);
|
Integer pageNum = ServletUtils.getParameterToInt(PAGE_NUM, DEFAULT_PAGE_NUM);
|
||||||
Integer pageSize = ServletUtils.getParameterToInt(PAGE_SIZE, DEFAULT_PAGE_SIZE);
|
Integer pageSize = ServletUtils.getParameterToInt(PAGE_SIZE, DEFAULT_PAGE_SIZE);
|
||||||
String orderByColumn = ServletUtils.getParameter(ORDER_BY_COLUMN);
|
String orderByColumn = ServletUtils.getParameter(ORDER_BY_COLUMN, defaultOrderByColumn);
|
||||||
String isAsc = ServletUtils.getParameter(IS_ASC);
|
String isAsc = ServletUtils.getParameter(IS_ASC, defaultIsAsc);
|
||||||
|
// 兼容前端排序类型
|
||||||
|
if ("ascending".equals(isAsc)) {
|
||||||
|
isAsc = "asc";
|
||||||
|
} else if ("descending".equals(isAsc)) {
|
||||||
|
isAsc = "desc";
|
||||||
|
}
|
||||||
Page<T> page = new Page<>(pageNum, pageSize);
|
Page<T> page = new Page<>(pageNum, pageSize);
|
||||||
if (StrUtil.isNotBlank(orderByColumn)) {
|
if (StrUtil.isNotBlank(orderByColumn)) {
|
||||||
String orderBy = SqlUtil.escapeOrderBySql(orderByColumn);
|
String orderBy = SqlUtil.escapeOrderBySql(orderByColumn);
|
||||||
|
orderBy = StrUtil.toUnderlineCase(orderBy);
|
||||||
if ("asc".equals(isAsc)) {
|
if ("asc".equals(isAsc)) {
|
||||||
page.addOrder(OrderItem.asc(orderBy));
|
page.addOrder(OrderItem.asc(orderBy));
|
||||||
} else if ("desc".equals(isAsc)) {
|
} else if ("desc".equals(isAsc)) {
|
||||||
|
@ -2,6 +2,9 @@ package com.ruoyi.common.utils;
|
|||||||
|
|
||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.extra.servlet.ServletUtil;
|
||||||
|
import cn.hutool.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.context.request.RequestAttributes;
|
import org.springframework.web.context.request.RequestAttributes;
|
||||||
import org.springframework.web.context.request.RequestContextHolder;
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
@ -10,72 +13,64 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 客户端工具类
|
* 客户端工具类
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
public class ServletUtils
|
public class ServletUtils extends ServletUtil {
|
||||||
{
|
|
||||||
/**
|
/**
|
||||||
* 获取String参数
|
* 获取String参数
|
||||||
*/
|
*/
|
||||||
public static String getParameter(String name)
|
public static String getParameter(String name) {
|
||||||
{
|
|
||||||
return getRequest().getParameter(name);
|
return getRequest().getParameter(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取String参数
|
* 获取String参数
|
||||||
*/
|
*/
|
||||||
public static String getParameter(String name, String defaultValue)
|
public static String getParameter(String name, String defaultValue) {
|
||||||
{
|
|
||||||
return Convert.toStr(getRequest().getParameter(name), defaultValue);
|
return Convert.toStr(getRequest().getParameter(name), defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取Integer参数
|
* 获取Integer参数
|
||||||
*/
|
*/
|
||||||
public static Integer getParameterToInt(String name)
|
public static Integer getParameterToInt(String name) {
|
||||||
{
|
|
||||||
return Convert.toInt(getRequest().getParameter(name));
|
return Convert.toInt(getRequest().getParameter(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取Integer参数
|
* 获取Integer参数
|
||||||
*/
|
*/
|
||||||
public static Integer getParameterToInt(String name, Integer defaultValue)
|
public static Integer getParameterToInt(String name, Integer defaultValue) {
|
||||||
{
|
|
||||||
return Convert.toInt(getRequest().getParameter(name), defaultValue);
|
return Convert.toInt(getRequest().getParameter(name), defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取request
|
* 获取request
|
||||||
*/
|
*/
|
||||||
public static HttpServletRequest getRequest()
|
public static HttpServletRequest getRequest() {
|
||||||
{
|
|
||||||
return getRequestAttributes().getRequest();
|
return getRequestAttributes().getRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取response
|
* 获取response
|
||||||
*/
|
*/
|
||||||
public static HttpServletResponse getResponse()
|
public static HttpServletResponse getResponse() {
|
||||||
{
|
|
||||||
return getRequestAttributes().getResponse();
|
return getRequestAttributes().getResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取session
|
* 获取session
|
||||||
*/
|
*/
|
||||||
public static HttpSession getSession()
|
public static HttpSession getSession() {
|
||||||
{
|
|
||||||
return getRequest().getSession();
|
return getRequest().getSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ServletRequestAttributes getRequestAttributes()
|
public static ServletRequestAttributes getRequestAttributes() {
|
||||||
{
|
|
||||||
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
|
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
|
||||||
return (ServletRequestAttributes) attributes;
|
return (ServletRequestAttributes) attributes;
|
||||||
}
|
}
|
||||||
@ -87,17 +82,13 @@ public class ServletUtils
|
|||||||
* @param string 待渲染的字符串
|
* @param string 待渲染的字符串
|
||||||
* @return null
|
* @return null
|
||||||
*/
|
*/
|
||||||
public static String renderString(HttpServletResponse response, String string)
|
public static String renderString(HttpServletResponse response, String string) {
|
||||||
{
|
try {
|
||||||
try
|
response.setStatus(HttpStatus.HTTP_OK);
|
||||||
{
|
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||||
response.setStatus(200);
|
response.setCharacterEncoding(StandardCharsets.UTF_8.toString());
|
||||||
response.setContentType("application/json");
|
|
||||||
response.setCharacterEncoding("utf-8");
|
|
||||||
response.getWriter().print(string);
|
response.getWriter().print(string);
|
||||||
}
|
} catch (IOException e) {
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -108,31 +99,32 @@ public class ServletUtils
|
|||||||
*
|
*
|
||||||
* @param request
|
* @param request
|
||||||
*/
|
*/
|
||||||
public static boolean isAjaxRequest(HttpServletRequest request)
|
public static boolean isAjaxRequest(HttpServletRequest request) {
|
||||||
{
|
|
||||||
String accept = request.getHeader("accept");
|
String accept = request.getHeader("accept");
|
||||||
if (accept != null && accept.indexOf("application/json") != -1)
|
if (accept != null && accept.indexOf("application/json") != -1) {
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
String xRequestedWith = request.getHeader("X-Requested-With");
|
String xRequestedWith = request.getHeader("X-Requested-With");
|
||||||
if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1)
|
if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1) {
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
String uri = request.getRequestURI();
|
String uri = request.getRequestURI();
|
||||||
if (StrUtil.equalsAnyIgnoreCase(uri, ".json", ".xml"))
|
if (StrUtil.equalsAnyIgnoreCase(uri, ".json", ".xml")) {
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
String ajax = request.getParameter("__ajax");
|
String ajax = request.getParameter("__ajax");
|
||||||
if (StrUtil.equalsAnyIgnoreCase(ajax, "json", "xml"))
|
if (StrUtil.equalsAnyIgnoreCase(ajax, "json", "xml")) {
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getClientIP() {
|
||||||
|
return getClientIP(getRequest());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.ruoyi.common.utils.file;
|
package com.ruoyi.common.utils.file;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.FileUtil;
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
|
||||||
@ -14,85 +15,10 @@ import java.nio.charset.StandardCharsets;
|
|||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
public class FileUtils extends org.apache.commons.io.FileUtils
|
public class FileUtils extends FileUtil
|
||||||
{
|
{
|
||||||
public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
|
public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
|
||||||
|
|
||||||
/**
|
|
||||||
* 输出指定文件的byte数组
|
|
||||||
*
|
|
||||||
* @param filePath 文件路径
|
|
||||||
* @param os 输出流
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static void writeBytes(String filePath, OutputStream os) throws IOException
|
|
||||||
{
|
|
||||||
FileInputStream fis = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
File file = new File(filePath);
|
|
||||||
if (!file.exists())
|
|
||||||
{
|
|
||||||
throw new FileNotFoundException(filePath);
|
|
||||||
}
|
|
||||||
fis = new FileInputStream(file);
|
|
||||||
byte[] b = new byte[1024];
|
|
||||||
int length;
|
|
||||||
while ((length = fis.read(b)) > 0)
|
|
||||||
{
|
|
||||||
os.write(b, 0, length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (os != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
os.close();
|
|
||||||
}
|
|
||||||
catch (IOException e1)
|
|
||||||
{
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (fis != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
fis.close();
|
|
||||||
}
|
|
||||||
catch (IOException e1)
|
|
||||||
{
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除文件
|
|
||||||
*
|
|
||||||
* @param filePath 文件
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static boolean deleteFile(String filePath)
|
|
||||||
{
|
|
||||||
boolean flag = false;
|
|
||||||
File file = new File(filePath);
|
|
||||||
// 路径为文件且不为空则进行删除
|
|
||||||
if (file.isFile() && file.exists())
|
|
||||||
{
|
|
||||||
file.delete();
|
|
||||||
flag = true;
|
|
||||||
}
|
|
||||||
return flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件名称验证
|
* 文件名称验证
|
||||||
*
|
*
|
||||||
@ -142,7 +68,7 @@ public class FileUtils extends org.apache.commons.io.FileUtils
|
|||||||
if (agent.contains("MSIE"))
|
if (agent.contains("MSIE"))
|
||||||
{
|
{
|
||||||
// IE浏览器
|
// IE浏览器
|
||||||
filename = URLEncoder.encode(filename, "utf-8");
|
filename = URLEncoder.encode(filename, StandardCharsets.UTF_8.toString());
|
||||||
filename = filename.replace("+", " ");
|
filename = filename.replace("+", " ");
|
||||||
}
|
}
|
||||||
else if (agent.contains("Firefox"))
|
else if (agent.contains("Firefox"))
|
||||||
@ -153,12 +79,12 @@ public class FileUtils extends org.apache.commons.io.FileUtils
|
|||||||
else if (agent.contains("Chrome"))
|
else if (agent.contains("Chrome"))
|
||||||
{
|
{
|
||||||
// google浏览器
|
// google浏览器
|
||||||
filename = URLEncoder.encode(filename, "utf-8");
|
filename = URLEncoder.encode(filename, StandardCharsets.UTF_8.toString());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 其它浏览器
|
// 其它浏览器
|
||||||
filename = URLEncoder.encode(filename, "utf-8");
|
filename = URLEncoder.encode(filename, StandardCharsets.UTF_8.toString());
|
||||||
}
|
}
|
||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
package com.ruoyi.common.utils.http;
|
|
||||||
|
|
||||||
import cn.hutool.core.exceptions.ExceptionUtil;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.servlet.ServletRequest;
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通用http工具封装
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class HttpHelper
|
|
||||||
{
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(HttpHelper.class);
|
|
||||||
|
|
||||||
public static String getBodyString(ServletRequest request)
|
|
||||||
{
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
BufferedReader reader = null;
|
|
||||||
try (InputStream inputStream = request.getInputStream())
|
|
||||||
{
|
|
||||||
reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
|
|
||||||
String line = "";
|
|
||||||
while ((line = reader.readLine()) != null)
|
|
||||||
{
|
|
||||||
sb.append(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
LOGGER.warn("getBodyString出现问题!");
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (reader != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
reader.close();
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
LOGGER.error(ExceptionUtil.getMessage(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,262 +0,0 @@
|
|||||||
package com.ruoyi.common.utils.http;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.net.ConnectException;
|
|
||||||
import java.net.SocketTimeoutException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLConnection;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
import javax.net.ssl.HostnameVerifier;
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
|
||||||
import javax.net.ssl.SSLContext;
|
|
||||||
import javax.net.ssl.SSLSession;
|
|
||||||
import javax.net.ssl.TrustManager;
|
|
||||||
import javax.net.ssl.X509TrustManager;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import com.ruoyi.common.constant.Constants;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通用http发送方法
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class HttpUtils
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 向指定 URL 发送GET方法的请求
|
|
||||||
*
|
|
||||||
* @param url 发送请求的 URL
|
|
||||||
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
|
|
||||||
* @return 所代表远程资源的响应结果
|
|
||||||
*/
|
|
||||||
public static String sendGet(String url, String param)
|
|
||||||
{
|
|
||||||
return sendGet(url, param, Constants.UTF8);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 向指定 URL 发送GET方法的请求
|
|
||||||
*
|
|
||||||
* @param url 发送请求的 URL
|
|
||||||
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
|
|
||||||
* @param contentType 编码类型
|
|
||||||
* @return 所代表远程资源的响应结果
|
|
||||||
*/
|
|
||||||
public static String sendGet(String url, String param, String contentType)
|
|
||||||
{
|
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
BufferedReader in = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
String urlNameString = url + "?" + param;
|
|
||||||
log.info("sendGet - {}", urlNameString);
|
|
||||||
URL realUrl = new URL(urlNameString);
|
|
||||||
URLConnection connection = realUrl.openConnection();
|
|
||||||
connection.setRequestProperty("accept", "*/*");
|
|
||||||
connection.setRequestProperty("connection", "Keep-Alive");
|
|
||||||
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
|
|
||||||
connection.connect();
|
|
||||||
in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));
|
|
||||||
String line;
|
|
||||||
while ((line = in.readLine()) != null)
|
|
||||||
{
|
|
||||||
result.append(line);
|
|
||||||
}
|
|
||||||
log.info("recv - {}", result);
|
|
||||||
}
|
|
||||||
catch (ConnectException e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
catch (SocketTimeoutException e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (in != null)
|
|
||||||
{
|
|
||||||
in.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 向指定 URL 发送POST方法的请求
|
|
||||||
*
|
|
||||||
* @param url 发送请求的 URL
|
|
||||||
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
|
|
||||||
* @return 所代表远程资源的响应结果
|
|
||||||
*/
|
|
||||||
public static String sendPost(String url, String param)
|
|
||||||
{
|
|
||||||
PrintWriter out = null;
|
|
||||||
BufferedReader in = null;
|
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
String urlNameString = url;
|
|
||||||
log.info("sendPost - {}", urlNameString);
|
|
||||||
URL realUrl = new URL(urlNameString);
|
|
||||||
URLConnection conn = realUrl.openConnection();
|
|
||||||
conn.setRequestProperty("accept", "*/*");
|
|
||||||
conn.setRequestProperty("connection", "Keep-Alive");
|
|
||||||
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
|
|
||||||
conn.setRequestProperty("Accept-Charset", "utf-8");
|
|
||||||
conn.setRequestProperty("contentType", "utf-8");
|
|
||||||
conn.setDoOutput(true);
|
|
||||||
conn.setDoInput(true);
|
|
||||||
out = new PrintWriter(conn.getOutputStream());
|
|
||||||
out.print(param);
|
|
||||||
out.flush();
|
|
||||||
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
|
|
||||||
String line;
|
|
||||||
while ((line = in.readLine()) != null)
|
|
||||||
{
|
|
||||||
result.append(line);
|
|
||||||
}
|
|
||||||
log.info("recv - {}", result);
|
|
||||||
}
|
|
||||||
catch (ConnectException e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
catch (SocketTimeoutException e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (out != null)
|
|
||||||
{
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
if (in != null)
|
|
||||||
{
|
|
||||||
in.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException ex)
|
|
||||||
{
|
|
||||||
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String sendSSLPost(String url, String param)
|
|
||||||
{
|
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
String urlNameString = url + "?" + param;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
log.info("sendSSLPost - {}", urlNameString);
|
|
||||||
SSLContext sc = SSLContext.getInstance("SSL");
|
|
||||||
sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());
|
|
||||||
URL console = new URL(urlNameString);
|
|
||||||
HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
|
|
||||||
conn.setRequestProperty("accept", "*/*");
|
|
||||||
conn.setRequestProperty("connection", "Keep-Alive");
|
|
||||||
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
|
|
||||||
conn.setRequestProperty("Accept-Charset", "utf-8");
|
|
||||||
conn.setRequestProperty("contentType", "utf-8");
|
|
||||||
conn.setDoOutput(true);
|
|
||||||
conn.setDoInput(true);
|
|
||||||
|
|
||||||
conn.setSSLSocketFactory(sc.getSocketFactory());
|
|
||||||
conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
|
|
||||||
conn.connect();
|
|
||||||
InputStream is = conn.getInputStream();
|
|
||||||
BufferedReader br = new BufferedReader(new InputStreamReader(is));
|
|
||||||
String ret = "";
|
|
||||||
while ((ret = br.readLine()) != null)
|
|
||||||
{
|
|
||||||
if (ret != null && !"".equals(ret.trim()))
|
|
||||||
{
|
|
||||||
result.append(new String(ret.getBytes("ISO-8859-1"), "utf-8"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.info("recv - {}", result);
|
|
||||||
conn.disconnect();
|
|
||||||
br.close();
|
|
||||||
}
|
|
||||||
catch (ConnectException e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
catch (SocketTimeoutException e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class TrustAnyTrustManager implements X509TrustManager
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void checkClientTrusted(X509Certificate[] chain, String authType)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void checkServerTrusted(X509Certificate[] chain, String authType)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public X509Certificate[] getAcceptedIssuers()
|
|
||||||
{
|
|
||||||
return new X509Certificate[] {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class TrustAnyHostnameVerifier implements HostnameVerifier
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public boolean verify(String hostname, SSLSession session)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +1,23 @@
|
|||||||
package com.ruoyi.common.utils.ip;
|
package com.ruoyi.common.utils.ip;
|
||||||
|
|
||||||
|
import cn.hutool.core.net.NetUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import cn.hutool.http.HtmlUtil;
|
||||||
|
import cn.hutool.http.HttpUtil;
|
||||||
import com.ruoyi.common.config.RuoYiConfig;
|
import com.ruoyi.common.config.RuoYiConfig;
|
||||||
import com.ruoyi.common.constant.Constants;
|
import com.ruoyi.common.constant.Constants;
|
||||||
import com.ruoyi.common.utils.http.HttpUtils;
|
import com.ruoyi.common.utils.JsonUtils;
|
||||||
import org.slf4j.Logger;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取地址类
|
* 获取地址类
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
public class AddressUtils
|
@Slf4j
|
||||||
{
|
public class AddressUtils {
|
||||||
private static final Logger log = LoggerFactory.getLogger(AddressUtils.class);
|
|
||||||
|
|
||||||
// IP地址查询
|
// IP地址查询
|
||||||
public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp";
|
public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp";
|
||||||
@ -23,31 +25,28 @@ public class AddressUtils
|
|||||||
// 未知地址
|
// 未知地址
|
||||||
public static final String UNKNOWN = "XX XX";
|
public static final String UNKNOWN = "XX XX";
|
||||||
|
|
||||||
public static String getRealAddressByIP(String ip)
|
public static String getRealAddressByIP(String ip) {
|
||||||
{
|
|
||||||
String address = UNKNOWN;
|
String address = UNKNOWN;
|
||||||
// 内网不查询
|
// 内网不查询
|
||||||
if (IpUtils.internalIp(ip))
|
ip = "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : HtmlUtil.cleanHtmlTag(ip);
|
||||||
{
|
if (NetUtil.isInnerIP(ip)) {
|
||||||
return "内网IP";
|
return "内网IP";
|
||||||
}
|
}
|
||||||
if (RuoYiConfig.isAddressEnabled())
|
if (RuoYiConfig.isAddressEnabled()) {
|
||||||
{
|
try {
|
||||||
try
|
String rspStr = HttpUtil.createGet(IP_URL)
|
||||||
{
|
.body("ip=" + ip + "&json=true", Constants.GBK)
|
||||||
String rspStr = HttpUtils.sendGet(IP_URL, "ip=" + ip + "&json=true", Constants.GBK);
|
.execute()
|
||||||
if (StrUtil.isEmpty(rspStr))
|
.body();
|
||||||
{
|
if (StrUtil.isEmpty(rspStr)) {
|
||||||
log.error("获取地理位置异常 {}", ip);
|
log.error("获取地理位置异常 {}", ip);
|
||||||
return UNKNOWN;
|
return UNKNOWN;
|
||||||
}
|
}
|
||||||
JSONObject obj = JSONObject.parseObject(rspStr);
|
Map<String, String> obj = JsonUtils.parseMap(rspStr);
|
||||||
String region = obj.getString("pro");
|
String region = obj.get("pro");
|
||||||
String city = obj.getString("city");
|
String city = obj.get("city");
|
||||||
return String.format("%s %s", region, city);
|
return String.format("%s %s", region, city);
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
log.error("获取地理位置异常 {}", ip);
|
log.error("获取地理位置异常 {}", ip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,196 +0,0 @@
|
|||||||
package com.ruoyi.common.utils.ip;
|
|
||||||
|
|
||||||
import cn.hutool.core.lang.Validator;
|
|
||||||
import cn.hutool.http.HtmlUtil;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取IP方法
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class IpUtils
|
|
||||||
{
|
|
||||||
public static String getIpAddr(HttpServletRequest request)
|
|
||||||
{
|
|
||||||
if (request == null)
|
|
||||||
{
|
|
||||||
return "unknown";
|
|
||||||
}
|
|
||||||
String ip = request.getHeader("x-forwarded-for");
|
|
||||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
|
|
||||||
{
|
|
||||||
ip = request.getHeader("Proxy-Client-IP");
|
|
||||||
}
|
|
||||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
|
|
||||||
{
|
|
||||||
ip = request.getHeader("X-Forwarded-For");
|
|
||||||
}
|
|
||||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
|
|
||||||
{
|
|
||||||
ip = request.getHeader("WL-Proxy-Client-IP");
|
|
||||||
}
|
|
||||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
|
|
||||||
{
|
|
||||||
ip = request.getHeader("X-Real-IP");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
|
|
||||||
{
|
|
||||||
ip = request.getRemoteAddr();
|
|
||||||
}
|
|
||||||
return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : HtmlUtil.cleanHtmlTag(ip);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean internalIp(String ip)
|
|
||||||
{
|
|
||||||
byte[] addr = textToNumericFormatV4(ip);
|
|
||||||
return internalIp(addr) || "127.0.0.1".equals(ip);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean internalIp(byte[] addr)
|
|
||||||
{
|
|
||||||
if (Validator.isNull(addr) || addr.length < 2)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
final byte b0 = addr[0];
|
|
||||||
final byte b1 = addr[1];
|
|
||||||
// 10.x.x.x/8
|
|
||||||
final byte SECTION_1 = 0x0A;
|
|
||||||
// 172.16.x.x/12
|
|
||||||
final byte SECTION_2 = (byte) 0xAC;
|
|
||||||
final byte SECTION_3 = (byte) 0x10;
|
|
||||||
final byte SECTION_4 = (byte) 0x1F;
|
|
||||||
// 192.168.x.x/16
|
|
||||||
final byte SECTION_5 = (byte) 0xC0;
|
|
||||||
final byte SECTION_6 = (byte) 0xA8;
|
|
||||||
switch (b0)
|
|
||||||
{
|
|
||||||
case SECTION_1:
|
|
||||||
return true;
|
|
||||||
case SECTION_2:
|
|
||||||
if (b1 >= SECTION_3 && b1 <= SECTION_4)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case SECTION_5:
|
|
||||||
switch (b1)
|
|
||||||
{
|
|
||||||
case SECTION_6:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将IPv4地址转换成字节
|
|
||||||
*
|
|
||||||
* @param text IPv4地址
|
|
||||||
* @return byte 字节
|
|
||||||
*/
|
|
||||||
public static byte[] textToNumericFormatV4(String text)
|
|
||||||
{
|
|
||||||
if (text.length() == 0)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] bytes = new byte[4];
|
|
||||||
String[] elements = text.split("\\.", -1);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
long l;
|
|
||||||
int i;
|
|
||||||
switch (elements.length)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
l = Long.parseLong(elements[0]);
|
|
||||||
if ((l < 0L) || (l > 4294967295L)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
bytes[0] = (byte) (int) (l >> 24 & 0xFF);
|
|
||||||
bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
|
|
||||||
bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
|
|
||||||
bytes[3] = (byte) (int) (l & 0xFF);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
l = Integer.parseInt(elements[0]);
|
|
||||||
if ((l < 0L) || (l > 255L)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
bytes[0] = (byte) (int) (l & 0xFF);
|
|
||||||
l = Integer.parseInt(elements[1]);
|
|
||||||
if ((l < 0L) || (l > 16777215L)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
bytes[1] = (byte) (int) (l >> 16 & 0xFF);
|
|
||||||
bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
|
|
||||||
bytes[3] = (byte) (int) (l & 0xFF);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
for (i = 0; i < 2; ++i)
|
|
||||||
{
|
|
||||||
l = Integer.parseInt(elements[i]);
|
|
||||||
if ((l < 0L) || (l > 255L)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
bytes[i] = (byte) (int) (l & 0xFF);
|
|
||||||
}
|
|
||||||
l = Integer.parseInt(elements[2]);
|
|
||||||
if ((l < 0L) || (l > 65535L)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
bytes[2] = (byte) (int) (l >> 8 & 0xFF);
|
|
||||||
bytes[3] = (byte) (int) (l & 0xFF);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
for (i = 0; i < 4; ++i)
|
|
||||||
{
|
|
||||||
l = Integer.parseInt(elements[i]);
|
|
||||||
if ((l < 0L) || (l > 255L)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
bytes[i] = (byte) (int) (l & 0xFF);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (NumberFormatException e)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getHostIp()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return InetAddress.getLocalHost().getHostAddress();
|
|
||||||
}
|
|
||||||
catch (UnknownHostException e)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
return "127.0.0.1";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getHostName()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return InetAddress.getLocalHost().getHostName();
|
|
||||||
}
|
|
||||||
catch (UnknownHostException e)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
return "未知";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,44 +1,33 @@
|
|||||||
package com.ruoyi.common.utils.reflect;
|
package com.ruoyi.common.utils.reflect;
|
||||||
|
|
||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
import com.ruoyi.common.utils.DateUtils;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.commons.lang3.Validate;
|
|
||||||
import org.apache.poi.ss.usermodel.DateUtil;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Date;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
|
* 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
public class ReflectUtils
|
public class ReflectUtils extends ReflectUtil {
|
||||||
{
|
|
||||||
private static final String SETTER_PREFIX = "set";
|
private static final String SETTER_PREFIX = "set";
|
||||||
|
|
||||||
private static final String GETTER_PREFIX = "get";
|
private static final String GETTER_PREFIX = "get";
|
||||||
|
|
||||||
private static final String CGLIB_CLASS_SEPARATOR = "$$";
|
|
||||||
|
|
||||||
private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 调用Getter方法.
|
* 调用Getter方法.
|
||||||
* 支持多级,如:对象名.对象名.方法
|
* 支持多级,如:对象名.对象名.方法
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <E> E invokeGetter(Object obj, String propertyName)
|
public static <E> E invokeGetter(Object obj, String propertyName) {
|
||||||
{
|
|
||||||
Object object = obj;
|
Object object = obj;
|
||||||
for (String name : StringUtils.split(propertyName, "."))
|
for (String name : StrUtil.split(propertyName, ".")) {
|
||||||
{
|
String getterMethodName = GETTER_PREFIX + StrUtil.upperFirst(name);
|
||||||
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
|
object = invoke(object, getterMethodName);
|
||||||
object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
|
|
||||||
}
|
}
|
||||||
return (E) object;
|
return (E) object;
|
||||||
}
|
}
|
||||||
@ -47,360 +36,19 @@ public class ReflectUtils
|
|||||||
* 调用Setter方法, 仅匹配方法名。
|
* 调用Setter方法, 仅匹配方法名。
|
||||||
* 支持多级,如:对象名.对象名.方法
|
* 支持多级,如:对象名.对象名.方法
|
||||||
*/
|
*/
|
||||||
public static <E> void invokeSetter(Object obj, String propertyName, E value)
|
public static <E> void invokeSetter(Object obj, String propertyName, E value) {
|
||||||
{
|
|
||||||
Object object = obj;
|
Object object = obj;
|
||||||
String[] names = StringUtils.split(propertyName, ".");
|
List<String> names = StrUtil.split(propertyName, ".");
|
||||||
for (int i = 0; i < names.length; i++)
|
for (int i = 0; i < names.size(); i++) {
|
||||||
{
|
if (i < names.size() - 1) {
|
||||||
if (i < names.length - 1)
|
String getterMethodName = GETTER_PREFIX + StrUtil.upperFirst(names.get(i));
|
||||||
{
|
object = invoke(object, getterMethodName);
|
||||||
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
|
} else {
|
||||||
object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
|
String setterMethodName = SETTER_PREFIX + StrUtil.upperFirst(names.get(i));
|
||||||
}
|
Method method = getMethodByName(object.getClass(), setterMethodName);
|
||||||
else
|
invoke(object, method, value);
|
||||||
{
|
|
||||||
String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
|
|
||||||
invokeMethodByName(object, setterMethodName, new Object[] { value });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <E> E getFieldValue(final Object obj, final String fieldName)
|
|
||||||
{
|
|
||||||
Field field = getAccessibleField(obj, fieldName);
|
|
||||||
if (field == null)
|
|
||||||
{
|
|
||||||
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
E result = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
result = (E) field.get(obj);
|
|
||||||
}
|
|
||||||
catch (IllegalAccessException e)
|
|
||||||
{
|
|
||||||
logger.error("不可能抛出的异常{}", e.getMessage());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
|
|
||||||
*/
|
|
||||||
public static <E> void setFieldValue(final Object obj, final String fieldName, final E value)
|
|
||||||
{
|
|
||||||
Field field = getAccessibleField(obj, fieldName);
|
|
||||||
if (field == null)
|
|
||||||
{
|
|
||||||
// throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
|
|
||||||
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
field.set(obj, value);
|
|
||||||
}
|
|
||||||
catch (IllegalAccessException e)
|
|
||||||
{
|
|
||||||
logger.error("不可能抛出的异常: {}", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 直接调用对象方法, 无视private/protected修饰符.
|
|
||||||
* 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用.
|
|
||||||
* 同时匹配方法名+参数类型,
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <E> E invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
|
|
||||||
final Object[] args)
|
|
||||||
{
|
|
||||||
if (obj == null || methodName == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Method method = getAccessibleMethod(obj, methodName, parameterTypes);
|
|
||||||
if (method == null)
|
|
||||||
{
|
|
||||||
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return (E) method.invoke(obj, args);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
|
|
||||||
throw convertReflectionExceptionToUnchecked(msg, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 直接调用对象方法, 无视private/protected修饰符,
|
|
||||||
* 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
|
|
||||||
* 只匹配函数名,如果有多个同名函数调用第一个。
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <E> E invokeMethodByName(final Object obj, final String methodName, final Object[] args)
|
|
||||||
{
|
|
||||||
Method method = getAccessibleMethodByName(obj, methodName, args.length);
|
|
||||||
if (method == null)
|
|
||||||
{
|
|
||||||
// 如果为空不报错,直接返回空。
|
|
||||||
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 类型转换(将参数数据类型转换为目标方法参数类型)
|
|
||||||
Class<?>[] cs = method.getParameterTypes();
|
|
||||||
for (int i = 0; i < cs.length; i++)
|
|
||||||
{
|
|
||||||
if (args[i] != null && !args[i].getClass().equals(cs[i]))
|
|
||||||
{
|
|
||||||
if (cs[i] == String.class)
|
|
||||||
{
|
|
||||||
args[i] = Convert.toStr(args[i]);
|
|
||||||
if (StringUtils.endsWith((String) args[i], ".0"))
|
|
||||||
{
|
|
||||||
args[i] = StringUtils.substringBefore((String) args[i], ".0");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cs[i] == Integer.class)
|
|
||||||
{
|
|
||||||
args[i] = Convert.toInt(args[i]);
|
|
||||||
}
|
|
||||||
else if (cs[i] == Long.class)
|
|
||||||
{
|
|
||||||
args[i] = Convert.toLong(args[i]);
|
|
||||||
}
|
|
||||||
else if (cs[i] == Double.class)
|
|
||||||
{
|
|
||||||
args[i] = Convert.toDouble(args[i]);
|
|
||||||
}
|
|
||||||
else if (cs[i] == Float.class)
|
|
||||||
{
|
|
||||||
args[i] = Convert.toFloat(args[i]);
|
|
||||||
}
|
|
||||||
else if (cs[i] == Date.class)
|
|
||||||
{
|
|
||||||
if (args[i] instanceof String)
|
|
||||||
{
|
|
||||||
args[i] = DateUtils.parseDate(args[i]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
args[i] = DateUtil.getJavaDate((Double) args[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cs[i] == boolean.class || cs[i] == Boolean.class)
|
|
||||||
{
|
|
||||||
args[i] = Convert.toBool(args[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (E) method.invoke(obj, args);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
|
|
||||||
throw convertReflectionExceptionToUnchecked(msg, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
|
|
||||||
* 如向上转型到Object仍无法找到, 返回null.
|
|
||||||
*/
|
|
||||||
public static Field getAccessibleField(final Object obj, final String fieldName)
|
|
||||||
{
|
|
||||||
// 为空不报错。直接返回 null
|
|
||||||
if (obj == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Validate.notBlank(fieldName, "fieldName can't be blank");
|
|
||||||
for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Field field = superClass.getDeclaredField(fieldName);
|
|
||||||
makeAccessible(field);
|
|
||||||
return field;
|
|
||||||
}
|
|
||||||
catch (NoSuchFieldException e)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
|
|
||||||
* 如向上转型到Object仍无法找到, 返回null.
|
|
||||||
* 匹配函数名+参数类型。
|
|
||||||
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
|
|
||||||
*/
|
|
||||||
public static Method getAccessibleMethod(final Object obj, final String methodName,
|
|
||||||
final Class<?>... parameterTypes)
|
|
||||||
{
|
|
||||||
// 为空不报错。直接返回 null
|
|
||||||
if (obj == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Validate.notBlank(methodName, "methodName can't be blank");
|
|
||||||
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
|
|
||||||
makeAccessible(method);
|
|
||||||
return method;
|
|
||||||
}
|
|
||||||
catch (NoSuchMethodException e)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
|
|
||||||
* 如向上转型到Object仍无法找到, 返回null.
|
|
||||||
* 只匹配函数名。
|
|
||||||
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
|
|
||||||
*/
|
|
||||||
public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum)
|
|
||||||
{
|
|
||||||
// 为空不报错。直接返回 null
|
|
||||||
if (obj == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Validate.notBlank(methodName, "methodName can't be blank");
|
|
||||||
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())
|
|
||||||
{
|
|
||||||
Method[] methods = searchType.getDeclaredMethods();
|
|
||||||
for (Method method : methods)
|
|
||||||
{
|
|
||||||
if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum)
|
|
||||||
{
|
|
||||||
makeAccessible(method);
|
|
||||||
return method;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
|
|
||||||
*/
|
|
||||||
public static void makeAccessible(Method method)
|
|
||||||
{
|
|
||||||
if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
|
|
||||||
&& !method.isAccessible())
|
|
||||||
{
|
|
||||||
method.setAccessible(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
|
|
||||||
*/
|
|
||||||
public static void makeAccessible(Field field)
|
|
||||||
{
|
|
||||||
if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())
|
|
||||||
|| Modifier.isFinal(field.getModifiers())) && !field.isAccessible())
|
|
||||||
{
|
|
||||||
field.setAccessible(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处
|
|
||||||
* 如无法找到, 返回Object.class.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <T> Class<T> getClassGenricType(final Class clazz)
|
|
||||||
{
|
|
||||||
return getClassGenricType(clazz, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
|
|
||||||
* 如无法找到, 返回Object.class.
|
|
||||||
*/
|
|
||||||
public static Class getClassGenricType(final Class clazz, final int index)
|
|
||||||
{
|
|
||||||
Type genType = clazz.getGenericSuperclass();
|
|
||||||
|
|
||||||
if (!(genType instanceof ParameterizedType))
|
|
||||||
{
|
|
||||||
logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType");
|
|
||||||
return Object.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
|
|
||||||
|
|
||||||
if (index >= params.length || index < 0)
|
|
||||||
{
|
|
||||||
logger.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
|
|
||||||
+ params.length);
|
|
||||||
return Object.class;
|
|
||||||
}
|
|
||||||
if (!(params[index] instanceof Class))
|
|
||||||
{
|
|
||||||
logger.debug(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
|
|
||||||
return Object.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (Class) params[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Class<?> getUserClass(Object instance)
|
|
||||||
{
|
|
||||||
if (instance == null)
|
|
||||||
{
|
|
||||||
throw new RuntimeException("Instance must not be null");
|
|
||||||
}
|
|
||||||
Class clazz = instance.getClass();
|
|
||||||
if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR))
|
|
||||||
{
|
|
||||||
Class<?> superClass = clazz.getSuperclass();
|
|
||||||
if (superClass != null && !Object.class.equals(superClass))
|
|
||||||
{
|
|
||||||
return superClass;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return clazz;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将反射时的checked exception转换为unchecked exception.
|
|
||||||
*/
|
|
||||||
public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e)
|
|
||||||
{
|
|
||||||
if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
|
|
||||||
|| e instanceof NoSuchMethodException)
|
|
||||||
{
|
|
||||||
return new IllegalArgumentException(msg, e);
|
|
||||||
}
|
|
||||||
else if (e instanceof InvocationTargetException)
|
|
||||||
{
|
|
||||||
return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException());
|
|
||||||
}
|
|
||||||
return new RuntimeException(msg, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,67 +1,17 @@
|
|||||||
package com.ruoyi.common.utils.spring;
|
package com.ruoyi.common.utils.spring;
|
||||||
|
|
||||||
import cn.hutool.core.lang.Validator;
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
import org.springframework.aop.framework.AopContext;
|
import org.springframework.aop.framework.AopContext;
|
||||||
import org.springframework.beans.BeansException;
|
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
|
||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.context.ApplicationContextAware;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* spring工具类 方便在非spring管理环境中获取bean
|
* spring工具类
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware
|
public final class SpringUtils extends SpringUtil {
|
||||||
{
|
|
||||||
/** Spring应用上下文环境 */
|
|
||||||
private static ConfigurableListableBeanFactory beanFactory;
|
|
||||||
|
|
||||||
private static ApplicationContext applicationContext;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
|
|
||||||
{
|
|
||||||
SpringUtils.beanFactory = beanFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
|
|
||||||
{
|
|
||||||
SpringUtils.applicationContext = applicationContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取对象
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
* @return Object 一个以所给名字注册的bean的实例
|
|
||||||
* @throws org.springframework.beans.BeansException
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <T> T getBean(String name) throws BeansException
|
|
||||||
{
|
|
||||||
return (T) beanFactory.getBean(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取类型为requiredType的对象
|
|
||||||
*
|
|
||||||
* @param clz
|
|
||||||
* @return
|
|
||||||
* @throws org.springframework.beans.BeansException
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static <T> T getBean(Class<T> clz) throws BeansException
|
|
||||||
{
|
|
||||||
T result = (T) beanFactory.getBean(clz);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
|
* 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
|
||||||
@ -69,46 +19,36 @@ public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationC
|
|||||||
* @param name
|
* @param name
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public static boolean containsBean(String name)
|
public static boolean containsBean(String name) {
|
||||||
{
|
return getBeanFactory().containsBean(name);
|
||||||
return beanFactory.containsBean(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
|
* 判断以给定名字注册的bean定义是一个singleton还是一个prototype。
|
||||||
|
* 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name
|
||||||
* @return boolean
|
* @return boolean
|
||||||
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException
|
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
|
||||||
{
|
return getBeanFactory().isSingleton(name);
|
||||||
return beanFactory.isSingleton(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param name
|
* @param name
|
||||||
* @return Class 注册对象的类型
|
* @return Class 注册对象的类型
|
||||||
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException
|
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
|
||||||
{
|
return getBeanFactory().getType(name);
|
||||||
return beanFactory.getType(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 如果给定的bean名字在bean定义中有别名,则返回这些别名
|
* 如果给定的bean名字在bean定义中有别名,则返回这些别名
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name
|
||||||
* @return
|
|
||||||
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException
|
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
|
||||||
{
|
return getBeanFactory().getAliases(name);
|
||||||
return beanFactory.getAliases(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -118,29 +58,8 @@ public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationC
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <T> T getAopProxy(T invoker)
|
public static <T> T getAopProxy(T invoker) {
|
||||||
{
|
|
||||||
return (T) AopContext.currentProxy();
|
return (T) AopContext.currentProxy();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前的环境配置,无配置返回null
|
|
||||||
*
|
|
||||||
* @return 当前的环境配置
|
|
||||||
*/
|
|
||||||
public static String[] getActiveProfiles()
|
|
||||||
{
|
|
||||||
return applicationContext.getEnvironment().getActiveProfiles();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前的环境配置,当有多个环境配置时,只获取第一个
|
|
||||||
*
|
|
||||||
* @return 当前的环境配置
|
|
||||||
*/
|
|
||||||
public static String getActiveProfile()
|
|
||||||
{
|
|
||||||
final String[] activeProfiles = getActiveProfiles();
|
|
||||||
return Validator.isNotEmpty(activeProfiles) ? activeProfiles[0] : null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import io.swagger.annotations.ApiModelProperty;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import javax.validation.constraints.NotBlank;
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,4 +40,8 @@ public class TestDemoAddBo {
|
|||||||
@NotBlank(message = "值不能为空")
|
@NotBlank(message = "值不能为空")
|
||||||
private String value;
|
private String value;
|
||||||
|
|
||||||
|
/** 创建时间 */
|
||||||
|
@ApiModelProperty("创建时间")
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package com.ruoyi.demo.controller;
|
package com.ruoyi.demo.controller;
|
||||||
|
|
||||||
import com.ruoyi.common.annotation.RedisLock;
|
import com.baomidou.lock.LockInfo;
|
||||||
|
import com.baomidou.lock.LockTemplate;
|
||||||
|
import com.baomidou.lock.annotation.Lock4j;
|
||||||
|
import com.baomidou.lock.executor.RedissonLockExecutor;
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
import com.ruoyi.common.core.redis.RedisLockManager;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.cache.annotation.Cacheable;
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
@ -10,7 +12,7 @@ import org.springframework.web.bind.annotation.GetMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.time.LocalTime;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -24,44 +26,47 @@ import java.util.concurrent.TimeUnit;
|
|||||||
public class RedisLockController {
|
public class RedisLockController {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private RedisLockManager redisLockManager;
|
private LockTemplate lockTemplate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* #p0 标识取第一个参数为redis锁的key
|
* 测试lock4j 注解
|
||||||
*/
|
*/
|
||||||
@GetMapping("/testLock1")
|
@Lock4j(keys = {"#key"})
|
||||||
@RedisLock(expireTime = 10, key = "#p0")
|
@GetMapping("/testLock4j")
|
||||||
public AjaxResult<String> testLock1(String key, String value) {
|
public AjaxResult<String> testLock4j(String key,String value){
|
||||||
|
System.out.println("start:"+key+",time:"+ LocalTime.now().toString());
|
||||||
try {
|
try {
|
||||||
// 同时请求排队
|
Thread.sleep(10000);
|
||||||
// Thread.sleep(5000);
|
|
||||||
// 锁超时测试
|
|
||||||
Thread.sleep(11000);
|
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
System.out.println("end :"+key+",time:"+LocalTime.now().toString());
|
||||||
return AjaxResult.success("操作成功",value);
|
return AjaxResult.success("操作成功",value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 测试锁工具类
|
* 测试lock4j 工具
|
||||||
*/
|
*/
|
||||||
@GetMapping("/testLock2")
|
@GetMapping("/testLock4jLockTemaplate")
|
||||||
public AjaxResult<Void> testLock(String key, Long time) {
|
public AjaxResult<String> testLock4jLockTemaplate(String key,String value){
|
||||||
|
final LockInfo lockInfo = lockTemplate.lock(key, 30000L, 5000L, RedissonLockExecutor.class);
|
||||||
|
if (null == lockInfo) {
|
||||||
|
throw new RuntimeException("业务处理中,请稍后再试");
|
||||||
|
}
|
||||||
|
// 获取锁成功,处理业务
|
||||||
try {
|
try {
|
||||||
boolean flag = redisLockManager.getLock(key, time, TimeUnit.SECONDS);
|
try {
|
||||||
if (flag) {
|
Thread.sleep(8000);
|
||||||
log.info("获取锁成功: " + key);
|
|
||||||
Thread.sleep(3000);
|
|
||||||
redisLockManager.unLock(key);
|
|
||||||
log.info("释放锁成功: " + key);
|
|
||||||
} else {
|
|
||||||
log.error("获取锁失败: " + key);
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
log.error(e.getMessage());
|
//
|
||||||
}
|
}
|
||||||
return AjaxResult.success();
|
System.out.println("执行简单方法1 , 当前线程:" + Thread.currentThread().getName());
|
||||||
|
} finally {
|
||||||
|
//释放锁
|
||||||
|
lockTemplate.releaseLock(lockInfo);
|
||||||
|
}
|
||||||
|
//结束
|
||||||
|
return AjaxResult.success("操作成功",value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
package com.ruoyi.demo.controller;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.ruoyi.common.core.controller.BaseController;
|
||||||
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
|
import com.ruoyi.demo.domain.TestDemo;
|
||||||
|
import com.ruoyi.demo.service.ITestDemoService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试批量方法
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
* @date 2021-05-30
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/demo/batch")
|
||||||
|
public class TestBatchController extends BaseController {
|
||||||
|
|
||||||
|
private final ITestDemoService iTestDemoService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增批量方法
|
||||||
|
*/
|
||||||
|
@PostMapping()
|
||||||
|
public AjaxResult<Void> add() {
|
||||||
|
List<TestDemo> list = new ArrayList<>();
|
||||||
|
for (int i = 0; i < 1000; i++) {
|
||||||
|
list.add(new TestDemo().setOrderNum(-1L).setTestKey("批量新增").setValue("测试新增"));
|
||||||
|
}
|
||||||
|
return toAjax(iTestDemoService.saveAll(list) ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改批量方法
|
||||||
|
*/
|
||||||
|
@DeleteMapping()
|
||||||
|
public AjaxResult<Void> edit() {
|
||||||
|
return toAjax(iTestDemoService.remove(new LambdaQueryWrapper<TestDemo>()
|
||||||
|
.eq(TestDemo::getOrderNum, -1L)) ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
package com.ruoyi.demo.domain;
|
package com.ruoyi.demo.domain;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.*;
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
@ -23,8 +25,11 @@ public class TestDemo implements Serializable {
|
|||||||
private static final long serialVersionUID=1L;
|
private static final long serialVersionUID=1L;
|
||||||
|
|
||||||
|
|
||||||
/** 主键 */
|
/**
|
||||||
|
* 主键
|
||||||
|
*/
|
||||||
@TableId(value = "id")
|
@TableId(value = "id")
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
/** 部门id */
|
/** 部门id */
|
||||||
@ -64,7 +69,6 @@ public class TestDemo implements Serializable {
|
|||||||
private String updateBy;
|
private String updateBy;
|
||||||
|
|
||||||
/** 删除标志 */
|
/** 删除标志 */
|
||||||
@TableLogic
|
|
||||||
private Long delFlag;
|
private Long delFlag;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
package com.ruoyi.demo.domain;
|
package com.ruoyi.demo.domain;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.*;
|
import com.baomidou.mybatisplus.annotation.*;
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.math.BigDecimal;
|
|
||||||
import com.ruoyi.common.annotation.Excel;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 测试树表对象 test_tree
|
* 测试树表对象 test_tree
|
||||||
@ -26,6 +27,7 @@ public class TestTree implements Serializable {
|
|||||||
|
|
||||||
/** 主键 */
|
/** 主键 */
|
||||||
@TableId(value = "id")
|
@TableId(value = "id")
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
/** 父id */
|
/** 父id */
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.ruoyi.demo.feign;
|
package com.ruoyi.demo.feign;
|
||||||
|
|
||||||
|
import com.ruoyi.demo.feign.constant.FeignTestConstant;
|
||||||
import com.ruoyi.demo.feign.fallback.FeignTestFallback;
|
import com.ruoyi.demo.feign.fallback.FeignTestFallback;
|
||||||
import org.springframework.cloud.openfeign.FeignClient;
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
@ -7,10 +8,15 @@ import org.springframework.web.bind.annotation.RequestParam;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* feign测试service
|
* feign测试service
|
||||||
*
|
* 规范接口 Service 无感调用
|
||||||
|
* 常量管理请求路径 更加规范
|
||||||
|
* 自定义容错处理 安全可靠
|
||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
@FeignClient(name = "baidu",url = "http://www.baidu.com",fallback = FeignTestFallback.class)
|
@FeignClient(
|
||||||
|
name = FeignTestConstant.BAIDU_NAME,
|
||||||
|
url = FeignTestConstant.BAIDU_URL,
|
||||||
|
fallback = FeignTestFallback.class)
|
||||||
public interface FeignTestService {
|
public interface FeignTestService {
|
||||||
|
|
||||||
@GetMapping("/s")
|
@GetMapping("/s")
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.ruoyi.demo.feign.constant;
|
||||||
|
|
||||||
|
public class FeignTestConstant {
|
||||||
|
|
||||||
|
public static final String BAIDU_NAME = "baidu";
|
||||||
|
|
||||||
|
public static final String BAIDU_URL = "http://www.baidu.com";
|
||||||
|
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package com.ruoyi.demo.mapper;
|
package com.ruoyi.demo.mapper;
|
||||||
|
|
||||||
import com.ruoyi.common.core.mybatisplus.MybatisPlusRedisCache;
|
import com.ruoyi.common.core.mybatisplus.cache.MybatisPlusRedisCache;
|
||||||
import com.ruoyi.common.core.page.BaseMapperPlus;
|
import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus;
|
||||||
import com.ruoyi.demo.domain.TestDemo;
|
import com.ruoyi.demo.domain.TestDemo;
|
||||||
import org.apache.ibatis.annotations.CacheNamespace;
|
import org.apache.ibatis.annotations.CacheNamespace;
|
||||||
|
|
||||||
@ -11,6 +11,7 @@ import org.apache.ibatis.annotations.CacheNamespace;
|
|||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
* @date 2021-05-30
|
* @date 2021-05-30
|
||||||
*/
|
*/
|
||||||
|
// 如使需切换数据源 请勿使用缓存 会造成数据不一致现象
|
||||||
@CacheNamespace(implementation = MybatisPlusRedisCache.class, eviction = MybatisPlusRedisCache.class)
|
@CacheNamespace(implementation = MybatisPlusRedisCache.class, eviction = MybatisPlusRedisCache.class)
|
||||||
public interface TestDemoMapper extends BaseMapperPlus<TestDemo> {
|
public interface TestDemoMapper extends BaseMapperPlus<TestDemo> {
|
||||||
|
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
package com.ruoyi.demo.mapper;
|
package com.ruoyi.demo.mapper;
|
||||||
|
|
||||||
import com.ruoyi.common.core.mybatisplus.MybatisPlusRedisCache;
|
import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus;
|
||||||
import com.ruoyi.common.core.page.BaseMapperPlus;
|
|
||||||
import com.ruoyi.demo.domain.TestTree;
|
import com.ruoyi.demo.domain.TestTree;
|
||||||
import org.apache.ibatis.annotations.CacheNamespace;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 测试树表Mapper接口
|
* 测试树表Mapper接口
|
||||||
@ -11,7 +9,7 @@ import org.apache.ibatis.annotations.CacheNamespace;
|
|||||||
* @author Lion Li
|
* @author Lion Li
|
||||||
* @date 2021-05-30
|
* @date 2021-05-30
|
||||||
*/
|
*/
|
||||||
@CacheNamespace(implementation = MybatisPlusRedisCache.class, eviction = MybatisPlusRedisCache.class)
|
//@CacheNamespace(implementation = MybatisPlusRedisCache.class, eviction = MybatisPlusRedisCache.class)
|
||||||
public interface TestTreeMapper extends BaseMapperPlus<TestTree> {
|
public interface TestTreeMapper extends BaseMapperPlus<TestTree> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import com.ruoyi.demo.vo.TestDemoVo;
|
|||||||
import com.ruoyi.demo.bo.TestDemoQueryBo;
|
import com.ruoyi.demo.bo.TestDemoQueryBo;
|
||||||
import com.ruoyi.demo.bo.TestDemoAddBo;
|
import com.ruoyi.demo.bo.TestDemoAddBo;
|
||||||
import com.ruoyi.demo.bo.TestDemoEditBo;
|
import com.ruoyi.demo.bo.TestDemoEditBo;
|
||||||
import com.ruoyi.common.core.page.IServicePlus;
|
import com.ruoyi.common.core.mybatisplus.core.IServicePlus;
|
||||||
import com.ruoyi.common.core.page.TableDataInfo;
|
import com.ruoyi.common.core.page.TableDataInfo;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -18,6 +18,7 @@ import java.util.List;
|
|||||||
* @date 2021-05-30
|
* @date 2021-05-30
|
||||||
*/
|
*/
|
||||||
public interface ITestDemoService extends IServicePlus<TestDemo> {
|
public interface ITestDemoService extends IServicePlus<TestDemo> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询单个
|
* 查询单个
|
||||||
* @return
|
* @return
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package com.ruoyi.demo.service;
|
package com.ruoyi.demo.service;
|
||||||
|
|
||||||
import com.ruoyi.common.core.page.IServicePlus;
|
import com.ruoyi.common.core.mybatisplus.core.IServicePlus;
|
||||||
import com.ruoyi.demo.bo.TestTreeAddBo;
|
import com.ruoyi.demo.bo.TestTreeAddBo;
|
||||||
import com.ruoyi.demo.bo.TestTreeEditBo;
|
import com.ruoyi.demo.bo.TestTreeEditBo;
|
||||||
import com.ruoyi.demo.bo.TestTreeQueryBo;
|
import com.ruoyi.demo.bo.TestTreeQueryBo;
|
||||||
|
@ -4,8 +4,8 @@ import cn.hutool.core.bean.BeanUtil;
|
|||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
||||||
import com.ruoyi.common.annotation.DataScope;
|
import com.ruoyi.common.annotation.DataScope;
|
||||||
|
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
|
||||||
import com.ruoyi.common.core.page.PagePlus;
|
import com.ruoyi.common.core.page.PagePlus;
|
||||||
import com.ruoyi.common.core.page.TableDataInfo;
|
import com.ruoyi.common.core.page.TableDataInfo;
|
||||||
import com.ruoyi.common.utils.PageUtils;
|
import com.ruoyi.common.utils.PageUtils;
|
||||||
@ -29,7 +29,7 @@ import java.util.Map;
|
|||||||
* @date 2021-05-30
|
* @date 2021-05-30
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class TestDemoServiceImpl extends ServiceImpl<TestDemoMapper, TestDemo> implements ITestDemoService {
|
public class TestDemoServiceImpl extends ServicePlusImpl<TestDemoMapper, TestDemo> implements ITestDemoService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TestDemoVo queryById(Long id) {
|
public TestDemoVo queryById(Long id) {
|
||||||
|
@ -4,8 +4,8 @@ import cn.hutool.core.bean.BeanUtil;
|
|||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
||||||
import com.ruoyi.common.annotation.DataScope;
|
import com.ruoyi.common.annotation.DataScope;
|
||||||
|
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
|
||||||
import com.ruoyi.demo.bo.TestTreeAddBo;
|
import com.ruoyi.demo.bo.TestTreeAddBo;
|
||||||
import com.ruoyi.demo.bo.TestTreeEditBo;
|
import com.ruoyi.demo.bo.TestTreeEditBo;
|
||||||
import com.ruoyi.demo.bo.TestTreeQueryBo;
|
import com.ruoyi.demo.bo.TestTreeQueryBo;
|
||||||
@ -26,13 +26,14 @@ import java.util.Map;
|
|||||||
* @date 2021-05-30
|
* @date 2021-05-30
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class TestTreeServiceImpl extends ServiceImpl<TestTreeMapper, TestTree> implements ITestTreeService {
|
public class TestTreeServiceImpl extends ServicePlusImpl<TestTreeMapper, TestTree> implements ITestTreeService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TestTreeVo queryById(Long id) {
|
public TestTreeVo queryById(Long id) {
|
||||||
return getVoById(id, TestTreeVo.class);
|
return getVoById(id, TestTreeVo.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @DataSource(DataSourceType.SLAVE) // 切换从库查询
|
||||||
@DataScope(isUser = true)
|
@DataScope(isUser = true)
|
||||||
@Override
|
@Override
|
||||||
public List<TestTreeVo> queryList(TestTreeQueryBo bo) {
|
public List<TestTreeVo> queryList(TestTreeQueryBo bo) {
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
package com.ruoyi.demo.vo;
|
package com.ruoyi.demo.vo;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||||
import com.ruoyi.common.annotation.Excel;
|
import com.ruoyi.common.annotation.Excel;
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
|
||||||
@ -21,8 +23,13 @@ public class TestDemoVo {
|
|||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/** 主键 */
|
/**
|
||||||
|
* 主键
|
||||||
|
* 如果是自定义id 或者 雪花id
|
||||||
|
* 需要增加序列化为字符串注解 因为Long到前端会失真
|
||||||
|
*/
|
||||||
@ApiModelProperty("主键")
|
@ApiModelProperty("主键")
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
/** 部门id */
|
/** 部门id */
|
||||||
@ -52,7 +59,7 @@ public class TestDemoVo {
|
|||||||
|
|
||||||
/** 创建时间 */
|
/** 创建时间 */
|
||||||
@Excel(name = "创建时间" , width = 30, dateFormat = "yyyy-MM-dd")
|
@Excel(name = "创建时间" , width = 30, dateFormat = "yyyy-MM-dd")
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
// @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
@ApiModelProperty("创建时间")
|
@ApiModelProperty("创建时间")
|
||||||
private Date createTime;
|
private Date createTime;
|
||||||
|
|
||||||
@ -63,7 +70,7 @@ public class TestDemoVo {
|
|||||||
|
|
||||||
/** 更新时间 */
|
/** 更新时间 */
|
||||||
@Excel(name = "更新时间" , width = 30, dateFormat = "yyyy-MM-dd")
|
@Excel(name = "更新时间" , width = 30, dateFormat = "yyyy-MM-dd")
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
// @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
@ApiModelProperty("更新时间")
|
@ApiModelProperty("更新时间")
|
||||||
private Date updateTime;
|
private Date updateTime;
|
||||||
|
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
package com.ruoyi.demo.vo;
|
package com.ruoyi.demo.vo;
|
||||||
|
|
||||||
import com.ruoyi.common.annotation.Excel;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||||
|
import com.ruoyi.common.annotation.Excel;
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
|
||||||
@ -23,6 +26,7 @@ public class TestTreeVo {
|
|||||||
|
|
||||||
/** 主键 */
|
/** 主键 */
|
||||||
@ApiModelProperty("主键")
|
@ApiModelProperty("主键")
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
/** 父id */
|
/** 父id */
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
package com.ruoyi.framework.aspectj;
|
package com.ruoyi.framework.aspectj;
|
||||||
|
|
||||||
import cn.hutool.core.lang.Validator;
|
import cn.hutool.core.lang.Validator;
|
||||||
|
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
|
||||||
import com.ruoyi.common.annotation.DataSource;
|
import com.ruoyi.common.annotation.DataSource;
|
||||||
import com.ruoyi.framework.datasource.DynamicDataSourceContextHolder;
|
|
||||||
import org.aspectj.lang.ProceedingJoinPoint;
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
import org.aspectj.lang.annotation.Around;
|
import org.aspectj.lang.annotation.Around;
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
import org.aspectj.lang.annotation.Pointcut;
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
import org.aspectj.lang.reflect.MethodSignature;
|
import org.aspectj.lang.reflect.MethodSignature;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.core.annotation.AnnotationUtils;
|
import org.springframework.core.annotation.AnnotationUtils;
|
||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@ -22,49 +20,40 @@ import java.util.Objects;
|
|||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
@Aspect
|
@Aspect
|
||||||
@Order(1)
|
@Order(-500)
|
||||||
@Component
|
@Component
|
||||||
public class DataSourceAspect
|
public class DataSourceAspect {
|
||||||
{
|
|
||||||
protected Logger logger = LoggerFactory.getLogger(getClass());
|
|
||||||
|
|
||||||
@Pointcut("@annotation(com.ruoyi.common.annotation.DataSource)"
|
@Pointcut("@annotation(com.ruoyi.common.annotation.DataSource)"
|
||||||
+ "|| @within(com.ruoyi.common.annotation.DataSource)")
|
+ "|| @within(com.ruoyi.common.annotation.DataSource)")
|
||||||
public void dsPointCut()
|
public void dsPointCut() {
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Around("dsPointCut()")
|
@Around("dsPointCut()")
|
||||||
public Object around(ProceedingJoinPoint point) throws Throwable
|
public Object around(ProceedingJoinPoint point) throws Throwable {
|
||||||
{
|
|
||||||
DataSource dataSource = getDataSource(point);
|
DataSource dataSource = getDataSource(point);
|
||||||
|
|
||||||
if (Validator.isNotNull(dataSource))
|
if (Validator.isNotNull(dataSource)) {
|
||||||
{
|
DynamicDataSourceContextHolder.poll();
|
||||||
DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());
|
String source = dataSource.value().getSource();
|
||||||
|
DynamicDataSourceContextHolder.push(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try {
|
||||||
{
|
|
||||||
return point.proceed();
|
return point.proceed();
|
||||||
}
|
} finally {
|
||||||
finally
|
|
||||||
{
|
|
||||||
// 销毁数据源 在执行方法之后
|
// 销毁数据源 在执行方法之后
|
||||||
DynamicDataSourceContextHolder.clearDataSourceType();
|
DynamicDataSourceContextHolder.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取需要切换的数据源
|
* 获取需要切换的数据源
|
||||||
*/
|
*/
|
||||||
public DataSource getDataSource(ProceedingJoinPoint point)
|
public DataSource getDataSource(ProceedingJoinPoint point) {
|
||||||
{
|
|
||||||
MethodSignature signature = (MethodSignature) point.getSignature();
|
MethodSignature signature = (MethodSignature) point.getSignature();
|
||||||
DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);
|
DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);
|
||||||
if (Objects.nonNull(dataSource))
|
if (Objects.nonNull(dataSource)) {
|
||||||
{
|
|
||||||
return dataSource;
|
return dataSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,16 +2,14 @@ package com.ruoyi.framework.aspectj;
|
|||||||
|
|
||||||
import cn.hutool.core.lang.Validator;
|
import cn.hutool.core.lang.Validator;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.ruoyi.common.annotation.Log;
|
import com.ruoyi.common.annotation.Log;
|
||||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||||
import com.ruoyi.common.enums.BusinessStatus;
|
import com.ruoyi.common.enums.BusinessStatus;
|
||||||
import com.ruoyi.common.enums.HttpMethod;
|
import com.ruoyi.common.enums.HttpMethod;
|
||||||
|
import com.ruoyi.common.utils.JsonUtils;
|
||||||
import com.ruoyi.common.utils.ServletUtils;
|
import com.ruoyi.common.utils.ServletUtils;
|
||||||
import com.ruoyi.common.utils.ip.IpUtils;
|
|
||||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
import com.ruoyi.common.utils.spring.SpringUtils;
|
||||||
import com.ruoyi.framework.manager.AsyncManager;
|
import com.ruoyi.framework.web.service.AsyncService;
|
||||||
import com.ruoyi.framework.manager.factory.AsyncFactory;
|
|
||||||
import com.ruoyi.framework.web.service.TokenService;
|
import com.ruoyi.framework.web.service.TokenService;
|
||||||
import com.ruoyi.system.domain.SysOperLog;
|
import com.ruoyi.system.domain.SysOperLog;
|
||||||
import org.aspectj.lang.JoinPoint;
|
import org.aspectj.lang.JoinPoint;
|
||||||
@ -32,7 +30,6 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -93,10 +90,10 @@ public class LogAspect
|
|||||||
SysOperLog operLog = new SysOperLog();
|
SysOperLog operLog = new SysOperLog();
|
||||||
operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
|
operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
|
||||||
// 请求的地址
|
// 请求的地址
|
||||||
String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
|
String ip = ServletUtils.getClientIP();
|
||||||
operLog.setOperIp(ip);
|
operLog.setOperIp(ip);
|
||||||
// 返回参数
|
// 返回参数
|
||||||
operLog.setJsonResult(JSON.toJSONString(jsonResult));
|
operLog.setJsonResult(JsonUtils.toJsonString(jsonResult));
|
||||||
|
|
||||||
operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());
|
operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());
|
||||||
if (loginUser != null)
|
if (loginUser != null)
|
||||||
@ -118,7 +115,7 @@ public class LogAspect
|
|||||||
// 处理设置注解上的参数
|
// 处理设置注解上的参数
|
||||||
getControllerMethodDescription(joinPoint, controllerLog, operLog);
|
getControllerMethodDescription(joinPoint, controllerLog, operLog);
|
||||||
// 保存数据库
|
// 保存数据库
|
||||||
AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
|
SpringUtils.getBean(AsyncService.class).recordOper(operLog);
|
||||||
}
|
}
|
||||||
catch (Exception exp)
|
catch (Exception exp)
|
||||||
{
|
{
|
||||||
@ -194,19 +191,16 @@ public class LogAspect
|
|||||||
*/
|
*/
|
||||||
private String argsArrayToString(Object[] paramsArray)
|
private String argsArrayToString(Object[] paramsArray)
|
||||||
{
|
{
|
||||||
String params = "";
|
StringBuilder params = new StringBuilder();
|
||||||
if (paramsArray != null && paramsArray.length > 0)
|
if (paramsArray != null && paramsArray.length > 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < paramsArray.length; i++)
|
for (Object o : paramsArray) {
|
||||||
{
|
if (Validator.isNotNull(o) && !isFilterObject(o)) {
|
||||||
if (Validator.isNotNull(paramsArray[i]) && !isFilterObject(paramsArray[i]))
|
params.append(JsonUtils.toJsonString(o)).append(" ");
|
||||||
{
|
|
||||||
Object jsonObj = JSON.toJSON(paramsArray[i]);
|
|
||||||
params += jsonObj.toString() + " ";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return params.trim();
|
return params.toString().trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -226,17 +220,15 @@ public class LogAspect
|
|||||||
else if (Collection.class.isAssignableFrom(clazz))
|
else if (Collection.class.isAssignableFrom(clazz))
|
||||||
{
|
{
|
||||||
Collection collection = (Collection) o;
|
Collection collection = (Collection) o;
|
||||||
for (Iterator iter = collection.iterator(); iter.hasNext();)
|
for (Object value : collection) {
|
||||||
{
|
return value instanceof MultipartFile;
|
||||||
return iter.next() instanceof MultipartFile;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Map.class.isAssignableFrom(clazz))
|
else if (Map.class.isAssignableFrom(clazz))
|
||||||
{
|
{
|
||||||
Map map = (Map) o;
|
Map map = (Map) o;
|
||||||
for (Iterator iter = map.entrySet().iterator(); iter.hasNext();)
|
for (Object value : map.entrySet()) {
|
||||||
{
|
Map.Entry entry = (Map.Entry) value;
|
||||||
Map.Entry entry = (Map.Entry) iter.next();
|
|
||||||
return entry.getValue() instanceof MultipartFile;
|
return entry.getValue() instanceof MultipartFile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,139 +0,0 @@
|
|||||||
package com.ruoyi.framework.aspectj;
|
|
||||||
|
|
||||||
|
|
||||||
import com.ruoyi.common.annotation.RedisLock;
|
|
||||||
import com.ruoyi.common.constant.Constants;
|
|
||||||
import com.ruoyi.common.core.redis.RedisLockManager;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.aspectj.lang.ProceedingJoinPoint;
|
|
||||||
import org.aspectj.lang.annotation.Around;
|
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
|
||||||
import org.aspectj.lang.annotation.Pointcut;
|
|
||||||
import org.aspectj.lang.reflect.MethodSignature;
|
|
||||||
import org.redisson.api.RLock;
|
|
||||||
import org.redisson.api.RedissonClient;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.core.annotation.Order;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分布式锁(注解实现版本)
|
|
||||||
*
|
|
||||||
* @author shenxinquan
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Aspect
|
|
||||||
@Order(9)
|
|
||||||
@Component
|
|
||||||
public class RedisLockAspect {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RedisLockManager redisLockManager;
|
|
||||||
|
|
||||||
@Pointcut("@annotation(com.ruoyi.common.annotation.RedisLock)")
|
|
||||||
public void annotationPointcut() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Around("annotationPointcut()")
|
|
||||||
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
|
|
||||||
// 获得当前访问的class
|
|
||||||
Class<?> className = joinPoint.getTarget().getClass();
|
|
||||||
// 获得访问的方法名
|
|
||||||
String methodName = joinPoint.getSignature().getName();
|
|
||||||
// 得到方法的参数的类型
|
|
||||||
Class<?>[] argClass = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
|
|
||||||
Object[] args = joinPoint.getArgs();
|
|
||||||
String key = "";
|
|
||||||
// 默认30秒过期时间
|
|
||||||
int expireTime = 30;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 得到访问的方法对象
|
|
||||||
Method method = className.getMethod(methodName, argClass);
|
|
||||||
method.setAccessible(true);
|
|
||||||
// 判断是否存在@RedisLock注解
|
|
||||||
if (method.isAnnotationPresent(RedisLock.class)) {
|
|
||||||
RedisLock annotation = method.getAnnotation(RedisLock.class);
|
|
||||||
key = getRedisKey(args, annotation.key());
|
|
||||||
expireTime = getExpireTime(annotation);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException("redis分布式锁注解参数异常", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 声明锁名称
|
|
||||||
key = Constants.REDIS_LOCK_KEY + key;
|
|
||||||
Object res;
|
|
||||||
try {
|
|
||||||
if (redisLockManager.getLock(key, expireTime, TimeUnit.SECONDS)) {
|
|
||||||
log.info("lock => key : " + key + " , ThreadName : " + Thread.currentThread().getName());
|
|
||||||
try {
|
|
||||||
res = joinPoint.proceed();
|
|
||||||
return res;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} finally {
|
|
||||||
redisLockManager.unLock(key);
|
|
||||||
log.info("unlock => key : " + key + " , ThreadName : " + Thread.currentThread().getName());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new RuntimeException("redis分布式锁注解参数异常");
|
|
||||||
}
|
|
||||||
} catch (IllegalMonitorStateException e) {
|
|
||||||
log.error("lock timeout => key : " + key + " , ThreadName : " + Thread.currentThread().getName());
|
|
||||||
throw new RuntimeException("lock timeout => key : " + key);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new Exception("redis分布式未知异常", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getExpireTime(RedisLock annotation) {
|
|
||||||
return annotation.expireTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getRedisKey(Object[] args, String primalKey) {
|
|
||||||
if (args.length == 0) {
|
|
||||||
return primalKey;
|
|
||||||
}
|
|
||||||
// 获取#p0...集合
|
|
||||||
List<String> keyList = getKeyParsList(primalKey);
|
|
||||||
for (String keyName : keyList) {
|
|
||||||
int keyIndex = Integer.parseInt(keyName.toLowerCase().replace("#p", ""));
|
|
||||||
Object parValue = args[keyIndex];
|
|
||||||
primalKey = primalKey.replace(keyName, String.valueOf(parValue));
|
|
||||||
}
|
|
||||||
return primalKey.replace("+", "").replace("'", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取key中#p0中的参数名称
|
|
||||||
*/
|
|
||||||
private static List<String> getKeyParsList(String key) {
|
|
||||||
List<String> listPar = new ArrayList<>();
|
|
||||||
if (key.contains("#")) {
|
|
||||||
int plusIndex = key.substring(key.indexOf("#")).indexOf("+");
|
|
||||||
int indexNext = 0;
|
|
||||||
String parName;
|
|
||||||
int indexPre = key.indexOf("#");
|
|
||||||
if (plusIndex > 0) {
|
|
||||||
indexNext = key.indexOf("#") + plusIndex;
|
|
||||||
parName = key.substring(indexPre, indexNext);
|
|
||||||
} else {
|
|
||||||
parName = key.substring(indexPre);
|
|
||||||
}
|
|
||||||
listPar.add(parName.trim());
|
|
||||||
key = key.substring(indexNext + 1);
|
|
||||||
if (key.contains("#")) {
|
|
||||||
listPar.addAll(getKeyParsList(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listPar;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -2,6 +2,8 @@ package com.ruoyi.framework.config;
|
|||||||
|
|
||||||
import com.ruoyi.common.exception.CustomException;
|
import com.ruoyi.common.exception.CustomException;
|
||||||
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
|
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
|
import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
|
||||||
import org.springframework.scheduling.annotation.EnableAsync;
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
@ -9,7 +11,7 @@ import org.springframework.security.concurrent.DelegatingSecurityContextExecutor
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 异步配置
|
* 异步配置
|
||||||
@ -20,13 +22,16 @@ import java.util.concurrent.Executors;
|
|||||||
@Configuration
|
@Configuration
|
||||||
public class AsyncConfig extends AsyncConfigurerSupport {
|
public class AsyncConfig extends AsyncConfigurerSupport {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("scheduledExecutorService")
|
||||||
|
private ScheduledExecutorService scheduledExecutorService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 异步执行需要使用权限框架自带的包装线程池 保证权限信息的传递
|
* 异步执行需要使用权限框架自带的包装线程池 保证权限信息的传递
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Executor getAsyncExecutor() {
|
public Executor getAsyncExecutor() {
|
||||||
return new DelegatingSecurityContextExecutorService(
|
return new DelegatingSecurityContextExecutorService(scheduledExecutorService);
|
||||||
Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,28 +1,14 @@
|
|||||||
package com.ruoyi.framework.config;
|
package com.ruoyi.framework.config;
|
||||||
|
|
||||||
import java.io.IOException;
|
import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
|
||||||
import java.util.HashMap;
|
import com.alibaba.druid.util.Utils;
|
||||||
import java.util.Map;
|
|
||||||
import javax.servlet.Filter;
|
|
||||||
import javax.servlet.FilterChain;
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.ServletRequest;
|
|
||||||
import javax.servlet.ServletResponse;
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Primary;
|
|
||||||
import com.alibaba.druid.pool.DruidDataSource;
|
import javax.servlet.*;
|
||||||
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
|
import java.io.IOException;
|
||||||
import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
|
|
||||||
import com.alibaba.druid.util.Utils;
|
|
||||||
import com.ruoyi.common.enums.DataSourceType;
|
|
||||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
|
||||||
import com.ruoyi.framework.config.properties.DruidProperties;
|
|
||||||
import com.ruoyi.framework.datasource.DynamicDataSource;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* druid 配置多数据源
|
* druid 配置多数据源
|
||||||
@ -30,53 +16,7 @@ import com.ruoyi.framework.datasource.DynamicDataSource;
|
|||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
public class DruidConfig
|
public class DruidConfig {
|
||||||
{
|
|
||||||
@Bean
|
|
||||||
@ConfigurationProperties("spring.datasource.druid.master")
|
|
||||||
public DataSource masterDataSource(DruidProperties druidProperties)
|
|
||||||
{
|
|
||||||
DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
|
|
||||||
return druidProperties.dataSource(dataSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConfigurationProperties("spring.datasource.druid.slave")
|
|
||||||
@ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
|
|
||||||
public DataSource slaveDataSource(DruidProperties druidProperties)
|
|
||||||
{
|
|
||||||
DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
|
|
||||||
return druidProperties.dataSource(dataSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean(name = "dynamicDataSource")
|
|
||||||
@Primary
|
|
||||||
public DynamicDataSource dataSource(DataSource masterDataSource)
|
|
||||||
{
|
|
||||||
Map<Object, Object> targetDataSources = new HashMap<>();
|
|
||||||
targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
|
|
||||||
setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");
|
|
||||||
return new DynamicDataSource(masterDataSource, targetDataSources);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置数据源
|
|
||||||
*
|
|
||||||
* @param targetDataSources 备选数据源集合
|
|
||||||
* @param sourceName 数据源名称
|
|
||||||
* @param beanName bean名称
|
|
||||||
*/
|
|
||||||
public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
DataSource dataSource = SpringUtils.getBean(beanName);
|
|
||||||
targetDataSources.put(sourceName, dataSource);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 去除监控页面底部的广告
|
* 去除监控页面底部的广告
|
||||||
|
@ -1,71 +0,0 @@
|
|||||||
package com.ruoyi.framework.config;
|
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
|
||||||
import com.fasterxml.jackson.databind.JavaType;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.fasterxml.jackson.databind.type.TypeFactory;
|
|
||||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
|
||||||
import org.springframework.data.redis.serializer.SerializationException;
|
|
||||||
import com.alibaba.fastjson.parser.ParserConfig;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redis使用FastJson序列化
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
|
|
||||||
{
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private ObjectMapper objectMapper = new ObjectMapper();
|
|
||||||
|
|
||||||
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
|
|
||||||
|
|
||||||
private Class<T> clazz;
|
|
||||||
|
|
||||||
static
|
|
||||||
{
|
|
||||||
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FastJson2JsonRedisSerializer(Class<T> clazz)
|
|
||||||
{
|
|
||||||
super();
|
|
||||||
this.clazz = clazz;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte[] serialize(T t) throws SerializationException
|
|
||||||
{
|
|
||||||
if (t == null)
|
|
||||||
{
|
|
||||||
return new byte[0];
|
|
||||||
}
|
|
||||||
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T deserialize(byte[] bytes) throws SerializationException
|
|
||||||
{
|
|
||||||
if (bytes == null || bytes.length <= 0)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String str = new String(bytes, DEFAULT_CHARSET);
|
|
||||||
|
|
||||||
return JSON.parseObject(str, clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setObjectMapper(ObjectMapper objectMapper)
|
|
||||||
{
|
|
||||||
Assert.notNull(objectMapper, "'objectMapper' must not be null");
|
|
||||||
this.objectMapper = objectMapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected JavaType getJavaType(Class<?> clazz)
|
|
||||||
{
|
|
||||||
return TypeFactory.defaultInstance().constructType(clazz);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
package com.ruoyi.framework.config;
|
package com.ruoyi.framework.config;
|
||||||
|
|
||||||
import feign.*;
|
import feign.*;
|
||||||
import feign.hystrix.HystrixFeign;
|
|
||||||
import okhttp3.ConnectionPool;
|
import okhttp3.ConnectionPool;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||||
@ -35,11 +34,6 @@ public class FeignConfig {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
public Feign.Builder feignBuilder() {
|
|
||||||
return HystrixFeign.builder();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public Contract feignContract() {
|
public Contract feignContract() {
|
||||||
return new SpringMvcContract();
|
return new SpringMvcContract();
|
||||||
|
@ -30,7 +30,7 @@ public class FilterConfig {
|
|||||||
FilterRegistrationBean registration = new FilterRegistrationBean();
|
FilterRegistrationBean registration = new FilterRegistrationBean();
|
||||||
registration.setDispatcherTypes(DispatcherType.REQUEST);
|
registration.setDispatcherTypes(DispatcherType.REQUEST);
|
||||||
registration.setFilter(new XssFilter());
|
registration.setFilter(new XssFilter());
|
||||||
registration.addUrlPatterns(StrUtil.split(xssProperties.getUrlPatterns(), ","));
|
registration.addUrlPatterns(StrUtil.splitToArray(xssProperties.getUrlPatterns(), ","));
|
||||||
registration.setName("xssFilter");
|
registration.setName("xssFilter");
|
||||||
registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
|
registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
|
||||||
Map<String, String> initParameters = new HashMap<String, String>();
|
Map<String, String> initParameters = new HashMap<String, String>();
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
package com.ruoyi.framework.config;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||||
|
import com.ruoyi.common.utils.JsonUtils;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* jackson 配置
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Configuration
|
||||||
|
public class JacksonConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public BeanPostProcessor objectMapperBeanPostProcessor() {
|
||||||
|
return new BeanPostProcessor() {
|
||||||
|
@Override
|
||||||
|
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||||
|
if (!(bean instanceof ObjectMapper)) {
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
ObjectMapper objectMapper = (ObjectMapper) bean;
|
||||||
|
// 全局配置序列化返回 JSON 处理
|
||||||
|
SimpleModule simpleModule = new SimpleModule();
|
||||||
|
simpleModule.addSerializer(LocalDateTime.class, LocalDateTimeSerializer.INSTANCE);
|
||||||
|
simpleModule.addDeserializer(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE);
|
||||||
|
objectMapper.registerModule(simpleModule);
|
||||||
|
objectMapper.setTimeZone(TimeZone.getDefault());
|
||||||
|
JsonUtils.init(objectMapper);
|
||||||
|
log.info("初始化 jackson 配置");
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -2,15 +2,21 @@ package com.ruoyi.framework.config;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.DbType;
|
import com.baomidou.mybatisplus.annotation.DbType;
|
||||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||||
|
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
|
||||||
|
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
|
||||||
|
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
|
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||||
|
import com.ruoyi.common.core.mybatisplus.methods.InsertAll;
|
||||||
import com.ruoyi.framework.mybatisplus.CreateAndUpdateMetaObjectHandler;
|
import com.ruoyi.framework.mybatisplus.CreateAndUpdateMetaObjectHandler;
|
||||||
import org.mybatis.spring.annotation.MapperScan;
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mybatis-plus配置类
|
* mybatis-plus配置类
|
||||||
*
|
*
|
||||||
@ -94,10 +100,17 @@ public class MybatisPlusConfig {
|
|||||||
* sql注入器配置
|
* sql注入器配置
|
||||||
* https://baomidou.com/guide/sql-injector.html
|
* https://baomidou.com/guide/sql-injector.html
|
||||||
*/
|
*/
|
||||||
// @Bean
|
@Bean
|
||||||
// public ISqlInjector sqlInjector() {
|
public ISqlInjector sqlInjector() {
|
||||||
// return new DefaultSqlInjector();
|
return new DefaultSqlInjector() {
|
||||||
// }
|
@Override
|
||||||
|
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
|
||||||
|
List<AbstractMethod> methodList = super.getMethodList(mapperClass);
|
||||||
|
methodList.add(new InsertAll());
|
||||||
|
return methodList;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TenantLineInnerInterceptor 多租户插件
|
* TenantLineInnerInterceptor 多租户插件
|
||||||
|
@ -29,9 +29,6 @@ public class ResourcesConfig implements WebMvcConfigurer
|
|||||||
{
|
{
|
||||||
/** 本地文件上传路径 */
|
/** 本地文件上传路径 */
|
||||||
registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + RuoYiConfig.getProfile() + "/");
|
registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + RuoYiConfig.getProfile() + "/");
|
||||||
|
|
||||||
/** swagger配置 */
|
|
||||||
registry.addResourceHandler("/swagger-ui/**").addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,7 +50,7 @@ public class ResourcesConfig implements WebMvcConfigurer
|
|||||||
CorsConfiguration config = new CorsConfiguration();
|
CorsConfiguration config = new CorsConfiguration();
|
||||||
config.setAllowCredentials(true);
|
config.setAllowCredentials(true);
|
||||||
// 设置访问源地址
|
// 设置访问源地址
|
||||||
config.addAllowedOrigin("*");
|
config.addAllowedOriginPattern("*");
|
||||||
// 设置访问源请求头
|
// 设置访问源请求头
|
||||||
config.addAllowedHeader("*");
|
config.addAllowedHeader("*");
|
||||||
// 设置访问源请求方法
|
// 设置访问源请求方法
|
||||||
|
@ -112,7 +112,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
|
|||||||
.antMatchers("/profile/**").anonymous()
|
.antMatchers("/profile/**").anonymous()
|
||||||
.antMatchers("/common/download**").anonymous()
|
.antMatchers("/common/download**").anonymous()
|
||||||
.antMatchers("/common/download/resource**").anonymous()
|
.antMatchers("/common/download/resource**").anonymous()
|
||||||
.antMatchers("/swagger-ui.html").anonymous()
|
.antMatchers("/doc.html").anonymous()
|
||||||
.antMatchers("/swagger-resources/**").anonymous()
|
.antMatchers("/swagger-resources/**").anonymous()
|
||||||
.antMatchers("/webjars/**").anonymous()
|
.antMatchers("/webjars/**").anonymous()
|
||||||
.antMatchers("/*/api-docs").anonymous()
|
.antMatchers("/*/api-docs").anonymous()
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
package com.ruoyi.framework.config.properties;
|
|
||||||
|
|
||||||
import com.alibaba.druid.pool.DruidDataSource;
|
|
||||||
import lombok.Data;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* druid 配置属性
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Configuration
|
|
||||||
@ConfigurationProperties(prefix = "spring.datasource.druid")
|
|
||||||
public class DruidProperties {
|
|
||||||
|
|
||||||
/** 初始连接数 */
|
|
||||||
private int initialSize;
|
|
||||||
/** 最小连接池数量 */
|
|
||||||
private int minIdle;
|
|
||||||
/** 最大连接池数量 */
|
|
||||||
private int maxActive;
|
|
||||||
/** 配置获取连接等待超时的时间 */
|
|
||||||
private int maxWait;
|
|
||||||
/** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */
|
|
||||||
private int timeBetweenEvictionRunsMillis;
|
|
||||||
/** 配置一个连接在池中最小生存的时间,单位是毫秒 */
|
|
||||||
private int minEvictableIdleTimeMillis;
|
|
||||||
/** 配置一个连接在池中最大生存的时间,单位是毫秒 */
|
|
||||||
private int maxEvictableIdleTimeMillis;
|
|
||||||
/** 配置检测连接是否有效 */
|
|
||||||
private String validationQuery;
|
|
||||||
/** 初始连接数 */
|
|
||||||
private boolean testWhileIdle;
|
|
||||||
/** 初始连接数 */
|
|
||||||
private boolean testOnBorrow;
|
|
||||||
/** 初始连接数 */
|
|
||||||
private boolean testOnReturn;
|
|
||||||
|
|
||||||
public DruidDataSource dataSource(DruidDataSource datasource) {
|
|
||||||
datasource.setInitialSize(initialSize);
|
|
||||||
datasource.setMaxActive(maxActive);
|
|
||||||
datasource.setMinIdle(minIdle);
|
|
||||||
datasource.setMaxWait(maxWait);
|
|
||||||
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
|
|
||||||
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
|
|
||||||
datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);
|
|
||||||
datasource.setValidationQuery(validationQuery);
|
|
||||||
datasource.setTestWhileIdle(testWhileIdle);
|
|
||||||
datasource.setTestOnBorrow(testOnBorrow);
|
|
||||||
datasource.setTestOnReturn(testOnReturn);
|
|
||||||
return datasource;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
package com.ruoyi.framework.datasource;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 动态数据源
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class DynamicDataSource extends AbstractRoutingDataSource
|
|
||||||
{
|
|
||||||
public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources)
|
|
||||||
{
|
|
||||||
super.setDefaultTargetDataSource(defaultTargetDataSource);
|
|
||||||
super.setTargetDataSources(targetDataSources);
|
|
||||||
super.afterPropertiesSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Object determineCurrentLookupKey()
|
|
||||||
{
|
|
||||||
return DynamicDataSourceContextHolder.getDataSourceType();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
package com.ruoyi.framework.datasource;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 数据源切换处理
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class DynamicDataSourceContextHolder
|
|
||||||
{
|
|
||||||
public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
|
|
||||||
* 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
|
|
||||||
*/
|
|
||||||
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置数据源的变量
|
|
||||||
*/
|
|
||||||
public static void setDataSourceType(String dsType)
|
|
||||||
{
|
|
||||||
log.info("切换到{}数据源", dsType);
|
|
||||||
CONTEXT_HOLDER.set(dsType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得数据源的变量
|
|
||||||
*/
|
|
||||||
public static String getDataSourceType()
|
|
||||||
{
|
|
||||||
return CONTEXT_HOLDER.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清空数据源变量
|
|
||||||
*/
|
|
||||||
public static void clearDataSourceType()
|
|
||||||
{
|
|
||||||
CONTEXT_HOLDER.remove();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +1,16 @@
|
|||||||
package com.ruoyi.framework.interceptor;
|
package com.ruoyi.framework.interceptor;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import com.ruoyi.common.annotation.RepeatSubmit;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import com.ruoyi.common.utils.JsonUtils;
|
||||||
|
import com.ruoyi.common.utils.ServletUtils;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.method.HandlerMethod;
|
import org.springframework.web.method.HandlerMethod;
|
||||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import com.ruoyi.common.annotation.RepeatSubmit;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import com.ruoyi.common.utils.ServletUtils;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 防止重复提交拦截器
|
* 防止重复提交拦截器
|
||||||
@ -32,7 +33,7 @@ public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter
|
|||||||
if (this.isRepeatSubmit(request))
|
if (this.isRepeatSubmit(request))
|
||||||
{
|
{
|
||||||
AjaxResult ajaxResult = AjaxResult.error("不允许重复提交,请稍后再试");
|
AjaxResult ajaxResult = AjaxResult.error("不允许重复提交,请稍后再试");
|
||||||
ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult));
|
ServletUtils.renderString(response, JsonUtils.toJsonString(ajaxResult));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
package com.ruoyi.framework.interceptor.impl;
|
package com.ruoyi.framework.interceptor.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.IoUtil;
|
||||||
import cn.hutool.core.lang.Validator;
|
import cn.hutool.core.lang.Validator;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import com.ruoyi.common.constant.Constants;
|
import com.ruoyi.common.constant.Constants;
|
||||||
import com.ruoyi.common.core.redis.RedisCache;
|
import com.ruoyi.common.core.redis.RedisCache;
|
||||||
import com.ruoyi.common.filter.RepeatedlyRequestWrapper;
|
import com.ruoyi.common.filter.RepeatedlyRequestWrapper;
|
||||||
import com.ruoyi.common.utils.http.HttpHelper;
|
import com.ruoyi.common.utils.JsonUtils;
|
||||||
import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;
|
import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@ -22,6 +24,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
|
public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
|
||||||
{
|
{
|
||||||
@ -56,13 +59,17 @@ public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
|
|||||||
if (request instanceof RepeatedlyRequestWrapper)
|
if (request instanceof RepeatedlyRequestWrapper)
|
||||||
{
|
{
|
||||||
RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
|
RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
|
||||||
nowParams = HttpHelper.getBodyString(repeatedlyRequest);
|
try {
|
||||||
|
nowParams = IoUtil.readUtf8(repeatedlyRequest.getInputStream());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("读取流出现问题!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// body参数为空,获取Parameter的数据
|
// body参数为空,获取Parameter的数据
|
||||||
if (Validator.isEmpty(nowParams))
|
if (Validator.isEmpty(nowParams))
|
||||||
{
|
{
|
||||||
nowParams = JSONObject.toJSONString(request.getParameterMap());
|
nowParams = JsonUtils.toJsonString(request.getParameterMap());
|
||||||
}
|
}
|
||||||
Map<String, Object> nowDataMap = new HashMap<String, Object>();
|
Map<String, Object> nowDataMap = new HashMap<String, Object>();
|
||||||
nowDataMap.put(REPEAT_PARAMS, nowParams);
|
nowDataMap.put(REPEAT_PARAMS, nowParams);
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
package com.ruoyi.framework.manager;
|
|
||||||
|
|
||||||
import java.util.TimerTask;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import com.ruoyi.common.utils.Threads;
|
|
||||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 异步任务管理器
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class AsyncManager
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 操作延迟10毫秒
|
|
||||||
*/
|
|
||||||
private final int OPERATE_DELAY_TIME = 10;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 异步操作任务调度线程池
|
|
||||||
*/
|
|
||||||
private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 单例模式
|
|
||||||
*/
|
|
||||||
private AsyncManager(){}
|
|
||||||
|
|
||||||
private static AsyncManager me = new AsyncManager();
|
|
||||||
|
|
||||||
public static AsyncManager me()
|
|
||||||
{
|
|
||||||
return me;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行任务
|
|
||||||
*
|
|
||||||
* @param task 任务
|
|
||||||
*/
|
|
||||||
public void execute(TimerTask task)
|
|
||||||
{
|
|
||||||
executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 停止任务线程池
|
|
||||||
*/
|
|
||||||
public void shutdown()
|
|
||||||
{
|
|
||||||
Threads.shutdownAndAwaitTermination(executor);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,39 +1,41 @@
|
|||||||
package com.ruoyi.framework.manager;
|
package com.ruoyi.framework.manager;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import com.ruoyi.common.utils.Threads;
|
||||||
import org.slf4j.LoggerFactory;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.annotation.PreDestroy;
|
import javax.annotation.PreDestroy;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 确保应用退出时能关闭后台线程
|
* 确保应用退出时能关闭后台线程
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
|
@Slf4j(topic = "sys-user")
|
||||||
@Component
|
@Component
|
||||||
public class ShutdownManager
|
public class ShutdownManager {
|
||||||
{
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger("sys-user");
|
@Autowired
|
||||||
|
@Qualifier("scheduledExecutorService")
|
||||||
|
private ScheduledExecutorService scheduledExecutorService;
|
||||||
|
|
||||||
@PreDestroy
|
@PreDestroy
|
||||||
public void destroy()
|
public void destroy() {
|
||||||
{
|
|
||||||
shutdownAsyncManager();
|
shutdownAsyncManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 停止异步执行任务
|
* 停止异步执行任务
|
||||||
*/
|
*/
|
||||||
private void shutdownAsyncManager()
|
private void shutdownAsyncManager() {
|
||||||
{
|
try {
|
||||||
try
|
log.info("====关闭后台任务任务线程池====");
|
||||||
{
|
Threads.shutdownAndAwaitTermination(scheduledExecutorService);
|
||||||
logger.info("====关闭后台任务任务线程池====");
|
} catch (Exception e) {
|
||||||
AsyncManager.me().shutdown();
|
log.error(e.getMessage(), e);
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
logger.error(e.getMessage(), e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,111 +0,0 @@
|
|||||||
package com.ruoyi.framework.manager.factory;
|
|
||||||
|
|
||||||
import cn.hutool.http.useragent.UserAgent;
|
|
||||||
import cn.hutool.http.useragent.UserAgentUtil;
|
|
||||||
import com.ruoyi.common.constant.Constants;
|
|
||||||
import com.ruoyi.common.utils.ServletUtils;
|
|
||||||
import com.ruoyi.common.utils.ip.AddressUtils;
|
|
||||||
import com.ruoyi.common.utils.ip.IpUtils;
|
|
||||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
|
||||||
import com.ruoyi.system.domain.SysLogininfor;
|
|
||||||
import com.ruoyi.system.domain.SysOperLog;
|
|
||||||
import com.ruoyi.system.service.ISysLogininforService;
|
|
||||||
import com.ruoyi.system.service.ISysOperLogService;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.TimerTask;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 异步工厂(产生任务用)
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class AsyncFactory
|
|
||||||
{
|
|
||||||
private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 记录登录信息
|
|
||||||
*
|
|
||||||
* @param username 用户名
|
|
||||||
* @param status 状态
|
|
||||||
* @param message 消息
|
|
||||||
* @param args 列表
|
|
||||||
* @return 任务task
|
|
||||||
*/
|
|
||||||
public static TimerTask recordLogininfor(final String username, final String status, final String message,
|
|
||||||
final Object... args)
|
|
||||||
{
|
|
||||||
final UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent"));
|
|
||||||
final String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
|
|
||||||
return new TimerTask()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
String address = AddressUtils.getRealAddressByIP(ip);
|
|
||||||
StringBuilder s = new StringBuilder();
|
|
||||||
s.append(getBlock(ip));
|
|
||||||
s.append(address);
|
|
||||||
s.append(getBlock(username));
|
|
||||||
s.append(getBlock(status));
|
|
||||||
s.append(getBlock(message));
|
|
||||||
// 打印信息到日志
|
|
||||||
sys_user_logger.info(s.toString(), args);
|
|
||||||
// 获取客户端操作系统
|
|
||||||
String os = userAgent.getOs().getName();
|
|
||||||
// 获取客户端浏览器
|
|
||||||
String browser = userAgent.getBrowser().getName();
|
|
||||||
// 封装对象
|
|
||||||
SysLogininfor logininfor = new SysLogininfor();
|
|
||||||
logininfor.setUserName(username);
|
|
||||||
logininfor.setIpaddr(ip);
|
|
||||||
logininfor.setLoginLocation(address);
|
|
||||||
logininfor.setBrowser(browser);
|
|
||||||
logininfor.setOs(os);
|
|
||||||
logininfor.setMsg(message);
|
|
||||||
// 日志状态
|
|
||||||
if (Constants.LOGIN_SUCCESS.equals(status) || Constants.LOGOUT.equals(status))
|
|
||||||
{
|
|
||||||
logininfor.setStatus(Constants.SUCCESS);
|
|
||||||
}
|
|
||||||
else if (Constants.LOGIN_FAIL.equals(status))
|
|
||||||
{
|
|
||||||
logininfor.setStatus(Constants.FAIL);
|
|
||||||
}
|
|
||||||
// 插入数据
|
|
||||||
SpringUtils.getBean(ISysLogininforService.class).insertLogininfor(logininfor);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 操作日志记录
|
|
||||||
*
|
|
||||||
* @param operLog 操作日志信息
|
|
||||||
* @return 任务task
|
|
||||||
*/
|
|
||||||
public static TimerTask recordOper(final SysOperLog operLog)
|
|
||||||
{
|
|
||||||
return new TimerTask()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
// 远程查询操作地点
|
|
||||||
operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
|
|
||||||
SpringUtils.getBean(ISysOperLogService.class).insertOperlog(operLog);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getBlock(Object msg)
|
|
||||||
{
|
|
||||||
if (msg == null)
|
|
||||||
{
|
|
||||||
msg = "";
|
|
||||||
}
|
|
||||||
return "[" + msg.toString() + "]";
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,8 +2,8 @@ package com.ruoyi.framework.security.handle;
|
|||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.http.HttpStatus;
|
import cn.hutool.http.HttpStatus;
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
|
import com.ruoyi.common.utils.JsonUtils;
|
||||||
import com.ruoyi.common.utils.ServletUtils;
|
import com.ruoyi.common.utils.ServletUtils;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
@ -30,6 +30,6 @@ public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, S
|
|||||||
{
|
{
|
||||||
int code = HttpStatus.HTTP_UNAUTHORIZED;
|
int code = HttpStatus.HTTP_UNAUTHORIZED;
|
||||||
String msg = StrUtil.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI());
|
String msg = StrUtil.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI());
|
||||||
ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(code, msg)));
|
ServletUtils.renderString(response, JsonUtils.toJsonString(AjaxResult.error(code, msg)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,12 @@ package com.ruoyi.framework.security.handle;
|
|||||||
|
|
||||||
import cn.hutool.core.lang.Validator;
|
import cn.hutool.core.lang.Validator;
|
||||||
import cn.hutool.http.HttpStatus;
|
import cn.hutool.http.HttpStatus;
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.ruoyi.common.constant.Constants;
|
import com.ruoyi.common.constant.Constants;
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||||
|
import com.ruoyi.common.utils.JsonUtils;
|
||||||
import com.ruoyi.common.utils.ServletUtils;
|
import com.ruoyi.common.utils.ServletUtils;
|
||||||
import com.ruoyi.framework.manager.AsyncManager;
|
import com.ruoyi.framework.web.service.AsyncService;
|
||||||
import com.ruoyi.framework.manager.factory.AsyncFactory;
|
|
||||||
import com.ruoyi.framework.web.service.TokenService;
|
import com.ruoyi.framework.web.service.TokenService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@ -26,29 +25,29 @@ import java.io.IOException;
|
|||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler
|
public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler {
|
||||||
{
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private TokenService tokenService;
|
private TokenService tokenService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AsyncService asyncService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退出处理
|
* 退出处理
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
|
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
|
||||||
throws IOException, ServletException
|
throws IOException, ServletException {
|
||||||
{
|
|
||||||
LoginUser loginUser = tokenService.getLoginUser(request);
|
LoginUser loginUser = tokenService.getLoginUser(request);
|
||||||
if (Validator.isNotNull(loginUser))
|
if (Validator.isNotNull(loginUser)) {
|
||||||
{
|
|
||||||
String userName = loginUser.getUsername();
|
String userName = loginUser.getUsername();
|
||||||
// 删除用户缓存记录
|
// 删除用户缓存记录
|
||||||
tokenService.delLoginUser(loginUser.getToken());
|
tokenService.delLoginUser(loginUser.getToken());
|
||||||
// 记录用户退出日志
|
// 记录用户退出日志
|
||||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, "退出成功"));
|
asyncService.recordLogininfor(userName, Constants.LOGOUT, "退出成功", request);
|
||||||
}
|
}
|
||||||
ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(HttpStatus.HTTP_OK, "退出成功")));
|
ServletUtils.renderString(response, JsonUtils.toJsonString(AjaxResult.error(HttpStatus.HTTP_OK, "退出成功")));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,96 @@
|
|||||||
|
package com.ruoyi.framework.web.service;
|
||||||
|
|
||||||
|
import cn.hutool.http.useragent.UserAgent;
|
||||||
|
import cn.hutool.http.useragent.UserAgentUtil;
|
||||||
|
import com.ruoyi.common.constant.Constants;
|
||||||
|
import com.ruoyi.common.utils.ServletUtils;
|
||||||
|
import com.ruoyi.common.utils.ip.AddressUtils;
|
||||||
|
import com.ruoyi.system.domain.SysLogininfor;
|
||||||
|
import com.ruoyi.system.domain.SysOperLog;
|
||||||
|
import com.ruoyi.system.service.ISysLogininforService;
|
||||||
|
import com.ruoyi.system.service.ISysOperLogService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步工厂(产生任务用)
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
@Slf4j(topic = "sys-user")
|
||||||
|
@Async
|
||||||
|
@Component
|
||||||
|
public class AsyncService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISysLogininforService iSysLogininforService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISysOperLogService iSysOperLogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录登录信息
|
||||||
|
*
|
||||||
|
* @param username 用户名
|
||||||
|
* @param status 状态
|
||||||
|
* @param message 消息
|
||||||
|
* @param args 列表
|
||||||
|
*/
|
||||||
|
public void recordLogininfor(final String username, final String status, final String message,
|
||||||
|
HttpServletRequest request, final Object... args) {
|
||||||
|
final UserAgent userAgent = UserAgentUtil.parse(request.getHeader("User-Agent"));
|
||||||
|
final String ip = ServletUtils.getClientIP(request);
|
||||||
|
|
||||||
|
String address = AddressUtils.getRealAddressByIP(ip);
|
||||||
|
StringBuilder s = new StringBuilder();
|
||||||
|
s.append(getBlock(ip));
|
||||||
|
s.append(address);
|
||||||
|
s.append(getBlock(username));
|
||||||
|
s.append(getBlock(status));
|
||||||
|
s.append(getBlock(message));
|
||||||
|
// 打印信息到日志
|
||||||
|
log.info(s.toString(), args);
|
||||||
|
// 获取客户端操作系统
|
||||||
|
String os = userAgent.getOs().getName();
|
||||||
|
// 获取客户端浏览器
|
||||||
|
String browser = userAgent.getBrowser().getName();
|
||||||
|
// 封装对象
|
||||||
|
SysLogininfor logininfor = new SysLogininfor();
|
||||||
|
logininfor.setUserName(username);
|
||||||
|
logininfor.setIpaddr(ip);
|
||||||
|
logininfor.setLoginLocation(address);
|
||||||
|
logininfor.setBrowser(browser);
|
||||||
|
logininfor.setOs(os);
|
||||||
|
logininfor.setMsg(message);
|
||||||
|
// 日志状态
|
||||||
|
if (Constants.LOGIN_SUCCESS.equals(status) || Constants.LOGOUT.equals(status)) {
|
||||||
|
logininfor.setStatus(Constants.SUCCESS);
|
||||||
|
} else if (Constants.LOGIN_FAIL.equals(status)) {
|
||||||
|
logininfor.setStatus(Constants.FAIL);
|
||||||
|
}
|
||||||
|
// 插入数据
|
||||||
|
iSysLogininforService.insertLogininfor(logininfor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作日志记录
|
||||||
|
*
|
||||||
|
* @param operLog 操作日志信息
|
||||||
|
*/
|
||||||
|
public void recordOper(final SysOperLog operLog) {
|
||||||
|
// 远程查询操作地点
|
||||||
|
operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
|
||||||
|
iSysOperLogService.insertOperlog(operLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getBlock(Object msg) {
|
||||||
|
if (msg == null) {
|
||||||
|
msg = "";
|
||||||
|
}
|
||||||
|
return "[" + msg.toString() + "]";
|
||||||
|
}
|
||||||
|
}
|
@ -11,10 +11,7 @@ import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
|
|||||||
import com.ruoyi.common.utils.DateUtils;
|
import com.ruoyi.common.utils.DateUtils;
|
||||||
import com.ruoyi.common.utils.MessageUtils;
|
import com.ruoyi.common.utils.MessageUtils;
|
||||||
import com.ruoyi.common.utils.ServletUtils;
|
import com.ruoyi.common.utils.ServletUtils;
|
||||||
import com.ruoyi.common.utils.ip.IpUtils;
|
|
||||||
import com.ruoyi.framework.config.properties.CaptchaProperties;
|
import com.ruoyi.framework.config.properties.CaptchaProperties;
|
||||||
import com.ruoyi.framework.manager.AsyncManager;
|
|
||||||
import com.ruoyi.framework.manager.factory.AsyncFactory;
|
|
||||||
import com.ruoyi.system.service.ISysUserService;
|
import com.ruoyi.system.service.ISysUserService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
@ -24,6 +21,7 @@ import org.springframework.security.core.Authentication;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录校验方法
|
* 登录校验方法
|
||||||
@ -48,6 +46,9 @@ public class SysLoginService
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ISysUserService userService;
|
private ISysUserService userService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AsyncService asyncService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录验证
|
* 登录验证
|
||||||
*
|
*
|
||||||
@ -59,16 +60,17 @@ public class SysLoginService
|
|||||||
*/
|
*/
|
||||||
public String login(String username, String password, String code, String uuid)
|
public String login(String username, String password, String code, String uuid)
|
||||||
{
|
{
|
||||||
|
HttpServletRequest request = ServletUtils.getRequest();
|
||||||
if(captchaProperties.getEnabled()) {
|
if(captchaProperties.getEnabled()) {
|
||||||
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
|
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
|
||||||
String captcha = redisCache.getCacheObject(verifyKey);
|
String captcha = redisCache.getCacheObject(verifyKey);
|
||||||
redisCache.deleteObject(verifyKey);
|
redisCache.deleteObject(verifyKey);
|
||||||
if (captcha == null) {
|
if (captcha == null) {
|
||||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
|
asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"), request);
|
||||||
throw new CaptchaExpireException();
|
throw new CaptchaExpireException();
|
||||||
}
|
}
|
||||||
if (!code.equalsIgnoreCase(captcha)) {
|
if (!code.equalsIgnoreCase(captcha)) {
|
||||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
|
asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"), request);
|
||||||
throw new CaptchaException();
|
throw new CaptchaException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,16 +86,16 @@ public class SysLoginService
|
|||||||
{
|
{
|
||||||
if (e instanceof BadCredentialsException)
|
if (e instanceof BadCredentialsException)
|
||||||
{
|
{
|
||||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
|
asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"), request);
|
||||||
throw new UserPasswordNotMatchException();
|
throw new UserPasswordNotMatchException();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
|
asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage(), request);
|
||||||
throw new CustomException(e.getMessage());
|
throw new CustomException(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
|
asyncService.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"), request);
|
||||||
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
|
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
|
||||||
recordLoginInfo(loginUser.getUser());
|
recordLoginInfo(loginUser.getUser());
|
||||||
// 生成token
|
// 生成token
|
||||||
@ -105,7 +107,7 @@ public class SysLoginService
|
|||||||
*/
|
*/
|
||||||
public void recordLoginInfo(SysUser user)
|
public void recordLoginInfo(SysUser user)
|
||||||
{
|
{
|
||||||
user.setLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
|
user.setLoginIp(ServletUtils.getClientIP());
|
||||||
user.setLoginDate(DateUtils.getNowDate());
|
user.setLoginDate(DateUtils.getNowDate());
|
||||||
user.setUpdateBy(user.getUserName());
|
user.setUpdateBy(user.getUserName());
|
||||||
userService.updateUserProfile(user);
|
userService.updateUserProfile(user);
|
||||||
|
@ -9,7 +9,6 @@ import com.ruoyi.common.core.domain.model.LoginUser;
|
|||||||
import com.ruoyi.common.core.redis.RedisCache;
|
import com.ruoyi.common.core.redis.RedisCache;
|
||||||
import com.ruoyi.common.utils.ServletUtils;
|
import com.ruoyi.common.utils.ServletUtils;
|
||||||
import com.ruoyi.common.utils.ip.AddressUtils;
|
import com.ruoyi.common.utils.ip.AddressUtils;
|
||||||
import com.ruoyi.common.utils.ip.IpUtils;
|
|
||||||
import com.ruoyi.framework.config.properties.TokenProperties;
|
import com.ruoyi.framework.config.properties.TokenProperties;
|
||||||
import io.jsonwebtoken.Claims;
|
import io.jsonwebtoken.Claims;
|
||||||
import io.jsonwebtoken.Jwts;
|
import io.jsonwebtoken.Jwts;
|
||||||
@ -131,7 +130,7 @@ public class TokenService {
|
|||||||
*/
|
*/
|
||||||
public void setUserAgent(LoginUser loginUser) {
|
public void setUserAgent(LoginUser loginUser) {
|
||||||
UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent"));
|
UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent"));
|
||||||
String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
|
String ip = ServletUtils.getClientIP();
|
||||||
loginUser.setIpaddr(ip);
|
loginUser.setIpaddr(ip);
|
||||||
loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
|
loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
|
||||||
loginUser.setBrowser(userAgent.getBrowser().getName());
|
loginUser.setBrowser(userAgent.getBrowser().getName());
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package com.ruoyi.generator.mapper;
|
package com.ruoyi.generator.mapper;
|
||||||
|
|
||||||
import com.ruoyi.common.core.page.BaseMapperPlus;
|
import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus;
|
||||||
import com.ruoyi.generator.domain.GenTableColumn;
|
import com.ruoyi.generator.domain.GenTableColumn;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.ruoyi.generator.mapper;
|
package com.ruoyi.generator.mapper;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.ruoyi.common.core.page.BaseMapperPlus;
|
import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus;
|
||||||
import com.ruoyi.generator.domain.GenTable;
|
import com.ruoyi.generator.domain.GenTable;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.ruoyi.generator.service;
|
package com.ruoyi.generator.service;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
|
||||||
import com.ruoyi.generator.domain.GenTableColumn;
|
import com.ruoyi.generator.domain.GenTableColumn;
|
||||||
import com.ruoyi.generator.mapper.GenTableColumnMapper;
|
import com.ruoyi.generator.mapper.GenTableColumnMapper;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@ -15,7 +15,7 @@ import java.util.List;
|
|||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class GenTableColumnServiceImpl extends ServiceImpl<GenTableColumnMapper, GenTableColumn> implements IGenTableColumnService {
|
public class GenTableColumnServiceImpl extends ServicePlusImpl<GenTableColumnMapper, GenTableColumn> implements IGenTableColumnService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询业务字段列表
|
* 查询业务字段列表
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user