JeecgBoot 2.3 里程碑版本发布,支持微服务和单体自由切换、提供新行编辑表格JVXETable

This commit is contained in:
zhangdaiscott
2020-09-13 18:23:23 +08:00
parent c5f055d004
commit 024272eb7c
533 changed files with 187550 additions and 36942 deletions

View File

@ -1,5 +1,4 @@
/target/
/.idea/
*.iml
jeecg-boot-module-demo
rebel.xml

View File

@ -1,7 +1,7 @@
Jeecg-Boot 低代码开发平台
===============
当前最新版本: 2.2.1发布日期20200713
当前最新版本: 2.3发布日期20200914
## 后端技术架构

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,54 +0,0 @@
-- ----author:scott--------date:20200602-------for: 字典表字段禁止为空------
ALTER TABLE `sys_dict_item`
MODIFY COLUMN `item_text` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '字典项文本' AFTER `dict_id`,
MODIFY COLUMN `item_value` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '字典项值' AFTER `item_text`;
ALTER TABLE `sys_dict`
MODIFY COLUMN `dict_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '字典名称' AFTER `id`,
MODIFY COLUMN `dict_code` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '字典编码' AFTER `dict_name`;
-- ----author:scott--------date:20200602-------for: 字典表字段禁止为空------
-- author:taoyan--------date:20200619-------for: 同步定时任务
INSERT INTO `sys_quartz_job`(`id`, `create_by`, `create_time`, `del_flag`, `update_by`, `update_time`, `job_class_name`, `cron_expression`, `parameter`, `description`, `status`) VALUES ('1273896435116408834', 'admin', '2020-06-19 16:32:31', 0, 'admin', '2020-06-19 20:08:20', 'org.jeecg.modules.quartz.job.AsyncJob', '0/1 * * * * ? *', NULL, '同步任务', -1);
-- author:taoyan--------date:20200619-------for: 同步定时任务
-- author:lvdandan--------date:20200703-------for: 角色授权、二级部门授权添加操作时间及操作ip
ALTER TABLE `sys_role_permission`
MODIFY COLUMN `data_rule_ids` varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '数据权限ids' AFTER `permission_id`,
ADD COLUMN `operate_date` datetime COMMENT '操作时间' AFTER `data_rule_ids`,
ADD COLUMN `operate_ip` varchar(20) COMMENT '操作ip' AFTER `operate_date`;
ALTER TABLE `sys_depart_role_permission`
MODIFY COLUMN `data_rule_ids` varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '数据权限ids' AFTER `permission_id`,
ADD COLUMN `operate_date` datetime DEFAULT NULL COMMENT '操作时间' AFTER `data_rule_ids`,
ADD COLUMN `operate_ip` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '操作ip' AFTER `operate_date`;
-- author:lvdandan--------date:20200703-------for: 角色授权、二级部门授权添加操作时间及操作ip
-- author:lvdandan--------date:20200707-------for: 添加图片裁剪
INSERT INTO `sys_permission`(`id`, `parent_id`, `name`, `url`, `component`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_route`, `is_leaf`, `keep_alive`, `hidden`, `description`, `status`, `del_flag`, `rule_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `internal_or_external`) VALUES ('1280464606292099074', '2a470fc0c3954d9dbb61de6d80846549', '图片裁剪', '/jeecg/ImagCropper', 'jeecg/ImagCropper', NULL, NULL, 1, NULL, '1', 9.00, 0, NULL, 1, 1, 0, 0, NULL, '1', 0, 0, 'admin', '2020-07-07 19:32:06', NULL, NULL, 0);
-- author:lvdandan--------date:20200707-------for: 添加图片裁剪菜单
-- author:taoyan--------date:20200707-------for: 多租户
ALTER TABLE `sys_user`
ADD COLUMN `rel_tenant_ids` varchar(100) NULL COMMENT '多租户标识' AFTER `depart_ids`;
INSERT INTO `sys_permission`(`id`, `parent_id`, `name`, `url`, `component`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_route`, `is_leaf`, `keep_alive`, `hidden`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`) VALUES ('1280350452934307841', 'd7d6e2e4e2934f2c9385a623fd98c6f3', '租户管理', '/isys/tenant', 'system/TenantList', NULL, NULL, 1, NULL, '1', 99.00, 0, NULL, 1, 1, 0, 0, NULL, 'admin', '2020-07-07 11:58:30', NULL, NULL, 0, 0, '1', 0);
DROP TABLE IF EXISTS `sys_tenant`;
CREATE TABLE `sys_tenant` (
`id` int(5) NOT NULL COMMENT '租户编码',
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '租户名称',
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
`create_by` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人',
`begin_date` datetime(0) NULL DEFAULT NULL COMMENT '开始时间',
`end_date` datetime(0) NULL DEFAULT NULL COMMENT '结束时间',
`status` int(1) NULL DEFAULT NULL COMMENT '状态 1正常 0冻结',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '多租户信息表' ROW_FORMAT = Dynamic;
INSERT INTO `sys_dict`(`id`, `dict_name`, `dict_code`, `description`, `del_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `type`) VALUES ('1280401766745718786', '租户状态', 'tenant_status', '租户状态', 0, 'admin', '2020-07-07 15:22:25', NULL, NULL, 0);
INSERT INTO `sys_dict_item`(`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1280401815068295170', '1280401766745718786', '正常', '1', '', 1, 1, 'admin', '2020-07-07 15:22:36', NULL, NULL);
INSERT INTO `sys_dict_item`(`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1280401847607705602', '1280401766745718786', '冻结', '0', '', 1, 1, 'admin', '2020-07-07 15:22:44', NULL, NULL);
-- author:taoyan--------date:20200707-------for: 多租户

View File

@ -0,0 +1,116 @@
-- author:sunjianlei--------date:20200721------for: 新增JVXETable示例菜单 --------
INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`) VALUES ('1285157614715457537', '2a470fc0c3954d9dbb61de6d80846549', 'JVXETable示例', '/jeecg/j-vxe-table-demo', 'jeecg/JVXETableDemo', '1', NULL, NULL, '1', NULL, '1', '10', '0', NULL, '1', '0', '0', NULL, 'admin', '2020-07-20 18:20:27', 'admin', '2020-07-20 18:20:36', '0', '0', '1', '0');
-- author:sunjianlei--------date:20200721------for: 新增JVXETable示例菜单 --------
-- author:sunjianlei--------date:20200727------for: 新增JVXETable示例菜单 --------
-- 删除旧菜单
DELETE FROM `sys_permission` WHERE (`id`='1285157614715457537');
DELETE FROM `sys_role_permission` WHERE (`permission_id`='1285157614715457537');
-- 添加新菜单
INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`) VALUES ('1287715272999944193', '2a470fc0c3954d9dbb61de6d80846549', 'JVXETable示例', '/jeecg/j-vxe-table-demo', 'layouts/RouteView', '1', NULL, NULL, '1', NULL, '1', '10', '0', '', '0', '0', '0', NULL, 'admin', '2020-07-27 19:43:40', 'admin', '2020-07-27 19:47:19', '0', '0', '1', '0');
INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`) VALUES ('1287715783966834689', '1287715272999944193', '普通示例', '/jeecg/j-vxe-table-demo/normal', 'jeecg/JVXETableDemo', '1', NULL, NULL, '1', NULL, '1', '1', '0', NULL, '1', '0', '0', NULL, 'admin', '2020-07-27 19:45:42', NULL, NULL, '0', '0', '1', '0');
INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`) VALUES ('1287716451494510593', '1287715272999944193', '布局模板', '/jeecg/j-vxe-table-demo/layout', 'jeecg/JVxeDemo/layout-demo/Index', '1', NULL, NULL, '1', NULL, '1', '2', '0', NULL, '1', '0', '0', NULL, 'admin', '2020-07-27 19:48:21', NULL, NULL, '0', '0', '1', '0');
INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`) VALUES ('1287718919049691137', '1287715272999944193', '即时保存', '/jeecg/j-vxe-table-demo/jsbc', 'jeecg/JVxeDemo/demo/JSBCDemo', '1', NULL, NULL, '1', NULL, '1', '3', '0', NULL, '1', '0', '0', NULL, 'admin', '2020-07-27 19:57:36', 'admin', '2020-07-27 20:03:37', '0', '0', '1', '0');
INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`) VALUES ('1287718938179911682', '1287715272999944193', '弹出子表', '/jeecg/j-vxe-table-demo/tczb', 'jeecg/JVxeDemo/demo/PopupSubTable', '1', NULL, NULL, '1', NULL, '1', '4', '0', NULL, '1', '0', '0', NULL, 'admin', '2020-07-27 19:57:41', 'admin', '2020-07-27 20:03:47', '0', '0', '1', '0');
INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`) VALUES ('1287718956957810689', '1287715272999944193', '无痕刷新', '/jeecg/j-vxe-table-demo/whsx', 'jeecg/JVxeDemo/demo/SocketReload', '1', NULL, NULL, '1', NULL, '1', '5', '0', NULL, '1', '0', '0', NULL, 'admin', '2020-07-27 19:57:44', 'admin', '2020-07-27 20:03:57', '0', '0', '1', '0');
-- author:sunjianlei--------date:20200727------for: 新增JVXETable示例菜单 --------
DROP TABLE IF EXISTS `sys_gateway_route`;
CREATE TABLE `sys_gateway_route` (
`id` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '服务名',
`uri` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '服务地址',
`predicates` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '断言',
`filters` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '过滤器',
`retryable` int(3) NULL DEFAULT NULL COMMENT '是否重试:0-否 1-是',
`strip_prefix` int(3) NULL DEFAULT NULL COMMENT '是否忽略前缀0-否 1-是',
`persist` int(3) NULL DEFAULT NULL COMMENT '是否为保留数据:0-否 1-是',
`show_api` int(3) NULL DEFAULT NULL COMMENT '是否在接口文档中展示:0-否 1-是',
`status` int(3) NULL DEFAULT NULL COMMENT '状态:0-无效 1-有效',
`create_by` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人',
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建日期',
`update_by` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新人',
`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新日期',
`sys_org_code` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '所属部门',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
-- author:taoyan--------date:20200815---for: gateway 路由配置管理
-- author:liusq--------date:20200904---for: 新增字段
ALTER TABLE `sys_user`
ADD COLUMN `client_id` varchar(64) NULL COMMENT '设备ID' AFTER `rel_tenant_ids`;
-- author:liusq--------date:20200904---for:新增字段
-- author:taoyan--------date:20200723--------for: online权限改造
-- ----------------------------
-- Table structure for onl_auth_data
-- ----------------------------
DROP TABLE IF EXISTS `onl_auth_data`;
CREATE TABLE `onl_auth_data` (
`id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键',
`cgform_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'online表ID',
`rule_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '规则名',
`rule_column` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '规则列',
`rule_operator` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '规则条件 大于小于like',
`rule_value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '规则值',
`status` int(1) NULL DEFAULT NULL COMMENT '1有效 0无效',
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
`create_by` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人',
`update_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新人',
`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新日期',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for onl_auth_page
-- ----------------------------
DROP TABLE IF EXISTS `onl_auth_page`;
CREATE TABLE `onl_auth_page` (
`id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT ' 主键',
`cgform_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'online表id',
`code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '字段名/按钮编码',
`type` int(1) NULL DEFAULT NULL COMMENT '1字段 2按钮',
`control` int(1) NULL DEFAULT NULL COMMENT '3可编辑 5可见(仅支持两种状态值3,5)',
`page` int(1) NULL DEFAULT NULL COMMENT '3列表 5表单(仅支持两种状态值3,5)',
`status` int(1) NULL DEFAULT NULL COMMENT '1有效 0无效',
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
`create_by` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人',
`update_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新人',
`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新日期',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Table structure for onl_auth_relation
-- ----------------------------
DROP TABLE IF EXISTS `onl_auth_relation`;
CREATE TABLE `onl_auth_relation` (
`id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`role_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '角色id',
`auth_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '权限id',
`type` int(1) NULL DEFAULT NULL COMMENT '1字段 2按钮 3数据权限',
`cgform_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'online表单ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- author:taoyan--------date:20200723--------for: online权限改造
-- author:liusq----date:20200909----for: 更新大屏表单模版url ------------
-- 生产销售监控 --
update sys_permission set url='{{ window._CONFIG[\'domianURL\'] }}/test/bigScreen/templat/index1' where id='1205098241075453953';
-- 智慧物流监控 --
update sys_permission set url='{{ window._CONFIG[\'domianURL\'] }}/test/bigScreen/templat/index2' where id='1205306106780364802';
-- author:liusq----date:20200909----for: 更新大屏表单模版url ------------

View File

@ -0,0 +1,51 @@
#### 镜像上传
# 仓库私服: 81.70.17.111:5000
# 第一步上传镜像到docker仓库
#docker tag jeecg-boot-mysql 81.70.17.111:5000/jeecg-boot-mysql:1.1
#docker tag jeecg-boot-system 81.70.17.111:5000/jeecg-boot-system:1.0
#docker tag nginxhtml:jeecgboot 81.70.17.111:5000/nginxhtml:1.2
#docker push 81.70.17.111:5000/jeecg-boot-mysql:1.1
#docker push 81.70.17.111:5000/jeecg-boot-system:1.0
#docker push 81.70.17.111:5000/nginxhtml:1.2
# 第二步将此yml文件上传服务器执行启动命令 docker-compose -f ./docker-compose-server.yml up
version: '2'
services:
jeecg-boot-mysql:
image: 81.70.17.111:5000/jeecg-boot-mysql:1.0
environment:
MYSQL_ROOT_PASSWORD: root
restart: always
container_name: jeecg-boot-mysql
command:
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--explicit_defaults_for_timestamp=true
--lower_case_table_names=1
--max_allowed_packet=128M
ports:
- 3306:3306
jeecg-boot-redis:
image: redis:5.0
ports:
- 6379:6379
restart: always
container_name: jeecg-boot-redis
jeecg-boot-system:
image: 81.70.17.111:5000/jeecg-boot-system:1.0
restart: always
container_name: jeecg-boot-system
volumes:
- /data/config:/jeecg-boot/config
ports:
- 8080:8080
jeecg-boot-nginx:
image: 81.70.17.111:5000/nginxhtml
restart: always
container_name: jeecg-boot-nginx
ports:
- 80:80

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jeecg-boot-base-api</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>2.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jeecg-system-cloud-api</artifactId>
<dependencies>
<!-- spring-cloud begin -->
<!-- nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- sentinel 熔断限流 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- spring-cloud end -->
</dependencies>
<dependencyManagement>
<dependencies>
<!-- spring-cloud-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>

View File

@ -0,0 +1,396 @@
package org.jeecg.common.system.api;
import com.alibaba.fastjson.JSONObject;
import org.jeecg.common.api.CommonAPI;
import org.jeecg.common.api.dto.OnlineAuthDTO;
import org.jeecg.common.api.dto.message.*;
import org.jeecg.common.constant.ServiceNameConstants;
import org.jeecg.common.system.api.factory.SysBaseAPIFallbackFactory;
import org.jeecg.common.system.vo.*;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
import java.util.Set;
/**
* 相比较local版
* 去掉了一些方法:
* addLog getDatabaseType queryAllDepart
* queryAllUser(Wrapper wrapper) queryAllUser(String[] userIds, int pageNo, int pageSize)
* 修改了一些方法:
* createLog
* sendSysAnnouncement 只保留了一个,其余全部干掉
*
* cloud接口数量43 local35 common9 额外一个特殊queryAllRole一个当两个用
*/
@Component
@FeignClient(contextId = "sysBaseRemoteApi", value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = SysBaseAPIFallbackFactory.class)
public interface ISysBaseAPI extends CommonAPI {
/**
* 1发送系统消息
* @param message 使用构造器赋值参数 如果不设置category(消息类型)则默认为2 发送系统消息
*/
@PostMapping("/sys/api/sendSysAnnouncement")
void sendSysAnnouncement(@RequestBody MessageDTO message);
/**
* 2发送消息 附带业务参数
* @param message 使用构造器赋值参数
*/
@PostMapping("/sys/api/sendBusAnnouncement")
void sendBusAnnouncement(@RequestBody BusMessageDTO message);
/**
* 3通过模板发送消息
* @param message 使用构造器赋值参数
*/
@PostMapping("/sys/api/sendTemplateAnnouncement")
void sendTemplateAnnouncement(@RequestBody TemplateMessageDTO message);
/**
* 4通过模板发送消息 附带业务参数
* @param message 使用构造器赋值参数
*/
@PostMapping("/sys/api/sendBusTemplateAnnouncement")
void sendBusTemplateAnnouncement(@RequestBody BusTemplateMessageDTO message);
/**
* 5通过消息中心模板生成推送内容
* @param templateDTO 使用构造器赋值参数
* @return
*/
@PostMapping("/sys/api/parseTemplateByCode")
String parseTemplateByCode(@RequestBody TemplateDTO templateDTO);
/**
* 6根据用户id查询用户信息
* @param id
* @return
*/
@GetMapping("/sys/api/getUserById")
LoginUser getUserById(@RequestParam("id") String id);
/**
* 7通过用户账号查询角色集合
* @param username
* @return
*/
@GetMapping("/sys/api/getRolesByUsername")
List<String> getRolesByUsername(@RequestParam("username") String username);
/**
* 8通过用户账号查询部门集合
* @param username
* @return 部门 id
*/
@GetMapping("/sys/api/getDepartIdsByUsername")
List<String> getDepartIdsByUsername(@RequestParam("username") String username);
/**
* 9通过用户账号查询部门 name
* @param username
* @return 部门 name
*/
@GetMapping("/sys/api/getDepartNamesByUsername")
List<String> getDepartNamesByUsername(@RequestParam("username") String username);
/**
* 10获取数据字典
* @param code
* @return
*/
@GetMapping("/sys/api/queryDictItemsByCode")
List<DictModel> queryDictItemsByCode(@RequestParam("code") String code);
/** 11查询所有的父级字典按照create_time排序 */
@GetMapping("/sys/api/queryAllDict")
List<DictModel> queryAllDict();
/**
* 12查询所有分类字典
* @return
*/
@GetMapping("/sys/api/queryAllDSysCategory")
List<SysCategoryModel> queryAllDSysCategory();
/**
* 13获取表数据字典
* @param table
* @param text
* @param code
* @return
*/
@GetMapping("/sys/api/queryTableDictItemsByCode")
List<DictModel> queryTableDictItemsByCode(@RequestParam("table") String table, @RequestParam("text") String text, @RequestParam("code") String code);
/**
* 14查询所有部门 作为字典信息 id -->value,departName -->text
* @return
*/
@GetMapping("/sys/api/queryAllDepartBackDictModel")
List<DictModel> queryAllDepartBackDictModel();
/**
* 15根据业务类型 busType 及业务 busId 修改消息已读
*/
@GetMapping("/sys/api/updateSysAnnounReadFlag")
public void updateSysAnnounReadFlag(@RequestParam("busType") String busType, @RequestParam("busId")String busId);
/**
* 16查询表字典 支持过滤数据
* @param table
* @param text
* @param code
* @param filterSql
* @return
*/
@GetMapping("/sys/api/queryFilterTableDictInfo")
List<DictModel> queryFilterTableDictInfo(@RequestParam("table") String table, @RequestParam("text") String text, @RequestParam("code") String code, @RequestParam("filterSql") String filterSql);
/**
* 17查询指定table的 text code 获取字典包含text和value
* @param table
* @param text
* @param code
* @param keyArray
* @return
*/
@Deprecated
@GetMapping("/sys/api/queryTableDictByKeys")
public List<String> queryTableDictByKeys(@RequestParam("table") String table, @RequestParam("text") String text, @RequestParam("code") String code, @RequestParam("keyArray") String[] keyArray);
/**
* 18查询所有用户 返回ComboModel
* @return
*/
@GetMapping("/sys/api/queryAllUserBackCombo")
public List<ComboModel> queryAllUserBackCombo();
/**
* 19分页查询用户 返回JSONObject
* @return
*/
@GetMapping("/sys/api/queryAllUser")
public JSONObject queryAllUser(@RequestParam(name="userIds",required=false)String userIds, @RequestParam(name="pageNo",required=false) Integer pageNo,@RequestParam(name="pageSize",required=false) int pageSize);
/**
* 20获取所有角色 带参
* roleIds 默认选中角色
* @return
*/
@GetMapping("/sys/api/queryAllRole")
public List<ComboModel> queryAllRole(@RequestParam(name = "roleIds",required = false)String[] roleIds);
/**
* 21通过用户账号查询角色Id集合
* @param username
* @return
*/
@GetMapping("/sys/api/getRoleIdsByUsername")
public List<String> getRoleIdsByUsername(@RequestParam("username")String username);
/**
* 22通过部门编号查询部门id
* @param orgCode
* @return
*/
@GetMapping("/sys/api/getDepartIdsByOrgCode")
public String getDepartIdsByOrgCode(@RequestParam("orgCode")String orgCode);
/**
* 23查询所有部门
* @return
*/
@GetMapping("/sys/api/getAllSysDepart")
public List<SysDepartModel> getAllSysDepart();
/**
* 24查找父级部门
* @param departId
* @return
*/
@GetMapping("/sys/api/getParentDepartId")
DictModel getParentDepartId(@RequestParam("departId")String departId);
/**
* 25根据部门Id获取部门负责人
* @param deptId
* @return
*/
@GetMapping("/sys/api/getDeptHeadByDepId")
public List<String> getDeptHeadByDepId(@RequestParam("deptId") String deptId);
/**
* 26给指定用户发消息
* @param userIds
* @param cmd
*/
@GetMapping("/sys/api/sendWebSocketMsg")
public void sendWebSocketMsg(@RequestParam("userIds")String[] userIds, @RequestParam("cmd") String cmd);
/**
* 27根据id获取所有参与用户
* userIds
* @return
*/
@GetMapping("/sys/api/queryAllUserByIds")
public List<LoginUser> queryAllUserByIds(@RequestParam("userIds") String[] userIds);
/**
* 28将会议签到信息推动到预览
* userIds
* @return
* @param userId
*/
@GetMapping("/sys/api/meetingSignWebsocket")
void meetingSignWebsocket(@RequestParam("userId")String userId);
/**
* 29根据name获取所有参与用户
* userNames
* @return
*/
@GetMapping("/sys/api/queryUserByNames")
List<LoginUser> queryUserByNames(@RequestParam("userNames")String[] userNames);
/**
* 30获取用户的角色集合
* @param username
* @return
*/
@GetMapping("/sys/api/getUserRoleSet")
Set<String> getUserRoleSet(@RequestParam("username")String username);
/**
* 31获取用户的权限集合
* @param username
* @return
*/
@GetMapping("/sys/api/getUserPermissionSet")
Set<String> getUserPermissionSet(@RequestParam("username") String username);
/**
* 32判断是否有online访问的权限
* @param onlineAuthDTO
* @return
*/
@PostMapping("/sys/api/hasOnlineAuth")
boolean hasOnlineAuth(@RequestBody OnlineAuthDTO onlineAuthDTO);
/**
* 33通过部门id获取部门全部信息
*/
@GetMapping("/sys/api/selectAllById")
SysDepartModel selectAllById(@RequestParam("id") String id);
/**
* 34根据用户id查询用户所属公司下所有用户ids
* @param userId
* @return
*/
@GetMapping("/sys/api/queryDeptUsersByUserId")
List<String> queryDeptUsersByUserId(@RequestParam("userId") String userId);
//---
/**
* 35查询用户角色信息
* @param username
* @return
*/
@GetMapping("/sys/api/queryUserRoles")
Set<String> queryUserRoles(@RequestParam("username")String username);
/**
* 36查询用户权限信息
* @param username
* @return
*/
@GetMapping("/sys/api/queryUserAuths")
Set<String> queryUserAuths(@RequestParam("username")String username);
/**
* 37根据 id 查询数据库中存储的 DynamicDataSourceModel
*
* @param dbSourceId
* @return
*/
@GetMapping("/sys/api/getDynamicDbSourceById")
DynamicDataSourceModel getDynamicDbSourceById(@RequestParam("dbSourceId") String dbSourceId);
/**
* 38根据 code 查询数据库中存储的 DynamicDataSourceModel
*
* @param dbSourceCode
* @return
*/
@GetMapping("/sys/api/getDynamicDbSourceByCode")
DynamicDataSourceModel getDynamicDbSourceByCode(@RequestParam("dbSourceCode") String dbSourceCode);
/**
* 39根据用户账号查询用户信息 CommonAPI中定义
* @param username
*/
@GetMapping("/sys/api/getUserByName")
LoginUser getUserByName(@RequestParam("username") String username);
/**
* 40字典表的 翻译
* @param table
* @param text
* @param code
* @param key
* @return
*/
@GetMapping("/sys/api/translateDictFromTable")
String translateDictFromTable(@RequestParam("table") String table, @RequestParam("text") String text, @RequestParam("code") String code, @RequestParam("key") String key);
/**
* 41普通字典的翻译
* @param code
* @param key
* @return
*/
@GetMapping("/sys/api/translateDict")
String translateDict(@RequestParam("code") String code, @RequestParam("key") String key);
/**
* 42查询数据权限
* @return
*/
@GetMapping("/sys/api/queryPermissionDataRule")
List<SysPermissionDataRuleModel> queryPermissionDataRule(@RequestParam("component") String component, @RequestParam("requestPath")String requestPath, @RequestParam("username") String username);
/**
* 43查询用户信息
* @param username
* @return
*/
@GetMapping("/sys/api/getCacheUser")
SysUserCacheInfo getCacheUser(@RequestParam("username") String username);
/**
* 36根据多个用户账号(逗号分隔),查询返回多个用户信息
* @param usernames
* @return
*/
@GetMapping("/sys/api/queryUsersByUsernames")
List<JSONObject> queryUsersByUsernames(String usernames);
/**
* 37根据多个部门编码(逗号分隔),查询返回多个部门信息
* @param orgCodes
* @return
*/
@GetMapping("/sys/api/queryDepartsByOrgcodes")
List<JSONObject> queryDepartsByOrgcodes(String orgCodes);
}

View File

@ -0,0 +1,17 @@
package org.jeecg.common.system.api.factory;
import feign.hystrix.FallbackFactory;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.api.fallback.SysBaseAPIFallback;
import org.springframework.stereotype.Component;
@Component
public class SysBaseAPIFallbackFactory implements FallbackFactory<ISysBaseAPI> {
@Override
public ISysBaseAPI create(Throwable throwable) {
SysBaseAPIFallback fallback = new SysBaseAPIFallback();
fallback.setCause(throwable);
return fallback;
}
}

View File

@ -0,0 +1,248 @@
package org.jeecg.common.system.api.fallback;
import com.alibaba.fastjson.JSONObject;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.dto.OnlineAuthDTO;
import org.jeecg.common.api.dto.message.*;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.vo.*;
import java.util.List;
import java.util.Set;
@Slf4j
public class SysBaseAPIFallback implements ISysBaseAPI {
@Setter
private Throwable cause;
@Override
public void sendSysAnnouncement(MessageDTO message) {
log.error("发送消息失败 {}", cause);
}
@Override
public void sendBusAnnouncement(BusMessageDTO message) {
log.error("发送消息失败 {}", cause);
}
@Override
public void sendTemplateAnnouncement(TemplateMessageDTO message) {
log.error("发送消息失败 {}", cause);
}
@Override
public void sendBusTemplateAnnouncement(BusTemplateMessageDTO message) {
log.error("发送消息失败 {}", cause);
}
@Override
public String parseTemplateByCode(TemplateDTO templateDTO) {
log.error("通过模板获取消息内容失败 {}", cause);
return null;
}
@Override
public LoginUser getUserById(String id) {
return null;
}
@Override
public List<String> getRolesByUsername(String username) {
return null;
}
@Override
public List<String> getDepartIdsByUsername(String username) {
return null;
}
@Override
public List<String> getDepartNamesByUsername(String username) {
return null;
}
@Override
public List<DictModel> queryDictItemsByCode(String code) {
return null;
}
@Override
public List<DictModel> queryAllDict() {
return null;
}
@Override
public List<SysCategoryModel> queryAllDSysCategory() {
return null;
}
@Override
public List<DictModel> queryTableDictItemsByCode(String table, String text, String code) {
return null;
}
@Override
public List<DictModel> queryAllDepartBackDictModel() {
return null;
}
@Override
public void updateSysAnnounReadFlag(String busType, String busId) {
}
@Override
public List<DictModel> queryFilterTableDictInfo(String table, String text, String code, String filterSql) {
return null;
}
@Override
public List<String> queryTableDictByKeys(String table, String text, String code, String[] keyArray) {
log.error("queryTableDictByKeys查询失败 {}", cause);
return null;
}
@Override
public List<ComboModel> queryAllUserBackCombo() {
return null;
}
@Override
public JSONObject queryAllUser(String userIds, Integer pageNo, int pageSize) {
return null;
}
@Override
public List<ComboModel> queryAllRole(String[] roleIds) {
log.error("获取角色信息失败 {}", cause);
return null;
}
@Override
public List<String> getRoleIdsByUsername(String username) {
return null;
}
@Override
public String getDepartIdsByOrgCode(String orgCode) {
return null;
}
@Override
public List<SysDepartModel> getAllSysDepart() {
return null;
}
@Override
public DictModel getParentDepartId(String departId) {
return null;
}
@Override
public List<String> getDeptHeadByDepId(String deptId) {
return null;
}
@Override
public void sendWebSocketMsg(String[] userIds, String cmd) {
}
@Override
public List<LoginUser> queryAllUserByIds(String[] userIds) {
return null;
}
@Override
public void meetingSignWebsocket(String userId) {
}
@Override
public List<LoginUser> queryUserByNames(String[] userNames) {
return null;
}
@Override
public Set<String> getUserRoleSet(String username) {
return null;
}
@Override
public Set<String> getUserPermissionSet(String username) {
return null;
}
@Override
public boolean hasOnlineAuth(OnlineAuthDTO onlineAuthDTO) {
return false;
}
@Override
public SysDepartModel selectAllById(String id) {
return null;
}
@Override
public List<String> queryDeptUsersByUserId(String userId) {
return null;
}
@Override
public Set<String> queryUserRoles(String username) {
return null;
}
@Override
public Set<String> queryUserAuths(String username) {
return null;
}
@Override
public DynamicDataSourceModel getDynamicDbSourceById(String dbSourceId) {
return null;
}
@Override
public DynamicDataSourceModel getDynamicDbSourceByCode(String dbSourceCode) {
return null;
}
@Override
public LoginUser getUserByName(String username) {
return null;
}
@Override
public String translateDictFromTable(String table, String text, String code, String key) {
return null;
}
@Override
public String translateDict(String code, String key) {
return null;
}
@Override
public List<SysPermissionDataRuleModel> queryPermissionDataRule(String component, String requestPath, String username) {
return null;
}
@Override
public SysUserCacheInfo getCacheUser(String username) {
log.error("获取用户信息失败 {}", cause);
return null;
}
@Override
public List<JSONObject> queryUsersByUsernames(String usernames) {
return null;
}
@Override
public List<JSONObject> queryDepartsByOrgcodes(String orgCodes) {
return null;
}
}

View File

@ -0,0 +1,70 @@
package org.jeecg.config;
import feign.Feign;
import feign.Logger;
import feign.RequestInterceptor;
import feign.codec.Encoder;
import feign.form.spring.SpringFormEncoder;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.constant.CommonConstant;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
@Slf4j
@Configuration
public class FeignConfig {
@Bean
public RequestInterceptor requestInterceptor() {
return requestTemplate -> {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (null != attributes) {
HttpServletRequest request = attributes.getRequest();
log.info("Feign request: {}", request.getRequestURI());
// 将token信息放入header中
requestTemplate.header(CommonConstant.X_ACCESS_TOKEN, request.getHeader(CommonConstant.X_ACCESS_TOKEN));
}
};
}
/**
* Feign 客户端的日志记录默认级别为NONE
* Logger.Level 的具体级别如下:
* NONE不记录任何信息
* BASIC仅记录请求方法、URL以及响应状态码和执行时间
* HEADERS除了记录 BASIC级别的信息外还会记录请求和响应的头信息
* FULL记录所有请求与响应的明细包括头信息、请求体、元数据
*/
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
/**
* Feign支持文件上传
* @param messageConverters
* @return
*/
@Bean
@Primary
@Scope("prototype")
public Encoder multipartFormEncoder(ObjectFactory<HttpMessageConverters> messageConverters) {
return new SpringFormEncoder(new SpringEncoder(messageConverters));
}
}

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jeecg-boot-base-api</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>2.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jeecg-system-local-api</artifactId>
</project>

View File

@ -0,0 +1,278 @@
package org.jeecg.common.system.api;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.jeecg.common.api.CommonAPI;
import org.jeecg.common.api.dto.OnlineAuthDTO;
import org.jeecg.common.api.dto.message.*;
import org.jeecg.common.system.vo.*;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
/**
* @Description 底层共通业务API提供其他独立模块调用
* @Author scott
* @Date 2019-4-20
* @Version V1.0
*/
public interface ISysBaseAPI extends CommonAPI {
/**
* 1发送系统消息
* @param message 使用构造器赋值参数 如果不设置category(消息类型)则默认为2 发送系统消息
*/
void sendSysAnnouncement(MessageDTO message);
/**
* 2发送消息 附带业务参数
* @param message 使用构造器赋值参数
*/
void sendBusAnnouncement(BusMessageDTO message);
/**
* 3通过模板发送消息
* @param message 使用构造器赋值参数
*/
void sendTemplateAnnouncement(TemplateMessageDTO message);
/**
* 4通过模板发送消息 附带业务参数
* @param message 使用构造器赋值参数
*/
void sendBusTemplateAnnouncement(BusTemplateMessageDTO message);
/**
* 5通过消息中心模板生成推送内容
* @param templateDTO 使用构造器赋值参数
* @return
*/
String parseTemplateByCode(TemplateDTO templateDTO);
/**
* 6根据用户id查询用户信息
* @param id
* @return
*/
LoginUser getUserById(String id);
/**
* 7通过用户账号查询角色集合
* @param username
* @return
*/
List<String> getRolesByUsername(String username);
/**
* 8通过用户账号查询部门集合
* @param username
* @return 部门 id
*/
List<String> getDepartIdsByUsername(String username);
/**
* 9通过用户账号查询部门 name
* @param username
* @return 部门 name
*/
List<String> getDepartNamesByUsername(String username);
/**
* 10获取数据字典
* @param code
* @return
*/
public List<DictModel> queryDictItemsByCode(String code);
/** 11查询所有的父级字典按照create_time排序 */
public List<DictModel> queryAllDict();
/**
* 12查询所有分类字典
* @return
*/
public List<SysCategoryModel> queryAllDSysCategory();
/**
* 13获取表数据字典
* @param table
* @param text
* @param code
* @return
*/
List<DictModel> queryTableDictItemsByCode(String table, String text, String code);
/**
* 14查询所有部门 作为字典信息 id -->value,departName -->text
* @return
*/
public List<DictModel> queryAllDepartBackDictModel();
/**
* 15根据业务类型及业务id修改消息已读
* @param busType
* @param busId
*/
public void updateSysAnnounReadFlag(String busType, String busId);
/**
* 16查询表字典 支持过滤数据
* @param table
* @param text
* @param code
* @param filterSql
* @return
*/
public List<DictModel> queryFilterTableDictInfo(String table, String text, String code, String filterSql);
/**
* 17查询指定table的 text code 获取字典包含text和value
* @param table
* @param text
* @param code
* @param keyArray
* @return
*/
@Deprecated
public List<String> queryTableDictByKeys(String table, String text, String code, String[] keyArray);
/**
* 18查询所有用户 返回ComboModel
* @return
*/
public List<ComboModel> queryAllUserBackCombo();
/**
* 19分页查询用户 返回JSONObject
* @return
*/
public JSONObject queryAllUser(String userIds, Integer pageNo, Integer pageSize);
/**
* 20获取所有角色
* @return
*/
public List<ComboModel> queryAllRole();
/**
* 21获取所有角色 带参
* roleIds 默认选中角色
* @return
*/
public List<ComboModel> queryAllRole(String[] roleIds );
/**
* 22通过用户账号查询角色Id集合
* @param username
* @return
*/
public List<String> getRoleIdsByUsername(String username);
/**
* 23通过部门编号查询部门id
* @param orgCode
* @return
*/
public String getDepartIdsByOrgCode(String orgCode);
/**
* 24查询所有部门
* @return
*/
public List<SysDepartModel> getAllSysDepart();
/**
* 25查找父级部门
* @param departId
* @return
*/
DictModel getParentDepartId(String departId);
/**
* 26根据部门Id获取部门负责人
* @param deptId
* @return
*/
public List<String> getDeptHeadByDepId(String deptId);
/**
* 27给指定用户发消息
* @param userIds
* @param cmd
*/
public void sendWebSocketMsg(String[] userIds, String cmd);
/**
* 28根据id获取所有参与用户
* userIds
* @return
*/
public List<LoginUser> queryAllUserByIds(String[] userIds);
/**
* 29将会议签到信息推动到预览
* userIds
* @return
* @param userId
*/
void meetingSignWebsocket(String userId);
/**
* 30根据name获取所有参与用户
* userNames
* @return
*/
List<LoginUser> queryUserByNames(String[] userNames);
/**
* 31获取用户的角色集合
* @param username
* @return
*/
Set<String> getUserRoleSet(String username);
/**
* 32获取用户的权限集合
* @param username
* @return
*/
Set<String> getUserPermissionSet(String username);
/**
* 33判断是否有online访问的权限
* @param onlineAuthDTO
* @return
*/
boolean hasOnlineAuth(OnlineAuthDTO onlineAuthDTO);
/**
* 34通过部门id获取部门全部信息
*/
SysDepartModel selectAllById(String id);
/**
* 35根据用户id查询用户所属公司下所有用户ids
* @param userId
* @return
*/
List<String> queryDeptUsersByUserId(String userId);
/**
* 36根据多个用户账号(逗号分隔),查询返回多个用户信息
* @param usernames
* @return
*/
List<JSONObject> queryUsersByUsernames(String usernames);
/**
* 37根据多个部门编码(逗号分隔),查询返回多个部门信息
* @param orgCodes
* @return
*/
List<JSONObject> queryDepartsByOrgcodes(String orgCodes);
}

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jeecg-boot-parent</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>2.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jeecg-boot-base-api</artifactId>
<packaging>pom</packaging>
<modules>
<module>jeecg-system-local-api</module>
<module>jeecg-system-cloud-api</module>
</modules>
<dependencies>
<dependency>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-base-common</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,15 +1,15 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>jeecg-boot-base-common</artifactId>
<parent>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-parent</artifactId>
<version>2.2.1</version>
<version>2.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jeecg-boot-base-common</artifactId>
<repositories>
<repository>
<id>aliyun</id>
@ -28,5 +28,267 @@
</snapshots>
</repository>
</repositories>
<properties>
<java.version>1.8</java.version>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<mybatis-plus.version>3.3.2</mybatis-plus.version>
<druid.version>1.1.17</druid.version>
<jwt.version>0.9.1</jwt.version>
<commons.version>2.6</commons.version>
<aliyun-java-sdk-dysmsapi.version>1.0.0</aliyun-java-sdk-dysmsapi.version>
<aliyun.oss.version>3.6.0</aliyun.oss.version>
<guava.version>26.0-jre</guava.version>
</properties>
<dependencies>
<!--集成springmvc框架并实现自动配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- commons -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons.version}</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>${commons.version}</version>
</dependency>
<!-- freemarker -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<!-- 动态数据源 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>2.5.4</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
<scope>runtime</scope>
</dependency>
<!-- sqlserver-->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>sqljdbc4</artifactId>
<version>4.0</version>
</dependency>
<!-- oracle驱动 -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3</version>
<scope>runtime</scope>
</dependency>
<!-- postgresql驱动 -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.6</version>
<scope>runtime</scope>
</dependency>
<!-- Quartz定时任务 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<!--JWT-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.7.0</version>
</dependency>
<!--shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.5.3</version>
</dependency>
<!-- shiro-redis -->
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>3.1.0</version>
<exclusions>
<exclusion>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-re</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<exclusions>
<exclusion>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Swagger API文档 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.6</version>
</dependency>
<!-- # 增加两个配置解决 NumberFormatException -->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.5.22</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.5.22</version>
</dependency>
<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- 代码生成器 -->
<!-- 如下载失败,请参考此文档 http://doc.jeecg.com/1273965 -->
<dependency>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>codegenerate</artifactId>
<version>1.2.2</version>
</dependency>
<!-- AutoPoi Excel工具类-->
<dependency>
<groupId>org.jeecgframework</groupId>
<artifactId>autopoi-web</artifactId>
<version>1.2.1</version>
<exclusions>
<exclusion>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.3.8</version>
</dependency>
<!-- mini文件存储服务 -->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<!-- 阿里云短信 -->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>${aliyun-java-sdk-dysmsapi.version}</version>
</dependency>
<!-- aliyun oss -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>${aliyun.oss.version}</version>
</dependency>
<!-- 第三方登录 -->
<dependency>
<groupId>com.xkcoding.justauth</groupId>
<artifactId>justauth-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,84 @@
package org.jeecg.common.api;
import org.jeecg.common.system.vo.DynamicDataSourceModel;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.system.vo.SysPermissionDataRuleModel;
import org.jeecg.common.system.vo.SysUserCacheInfo;
import java.util.List;
import java.util.Set;
public interface CommonAPI {
/**
* 1查询用户角色信息
* @param username
* @return
*/
Set<String> queryUserRoles(String username);
/**
* 2查询用户权限信息
* @param username
* @return
*/
Set<String> queryUserAuths(String username);
/**
* 3根据 id 查询数据库中存储的 DynamicDataSourceModel
*
* @param dbSourceId
* @return
*/
DynamicDataSourceModel getDynamicDbSourceById(String dbSourceId);
/**
* 4根据 code 查询数据库中存储的 DynamicDataSourceModel
*
* @param dbSourceCode
* @return
*/
DynamicDataSourceModel getDynamicDbSourceByCode(String dbSourceCode);
/**
* 5根据用户账号查询用户信息
* @param username
* @return
*/
public LoginUser getUserByName(String username);
/**
* 6字典表的 翻译
* @param table
* @param text
* @param code
* @param key
* @return
*/
String translateDictFromTable(String table, String text, String code, String key);
/**
* 7普通字典的翻译
* @param code
* @param key
* @return
*/
String translateDict(String code, String key);
/**
* 8查询数据权限
* @return
*/
List<SysPermissionDataRuleModel> queryPermissionDataRule(String component, String requestPath, String username);
/**
* 9查询用户信息
* @param username
* @return
*/
SysUserCacheInfo getCacheUser(String username);
}

View File

@ -0,0 +1,30 @@
package org.jeecg.common.api.dto;
import lombok.Data;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
/**
* 文件下载
* cloud api 用到的接口传输对象
*/
@Data
public class FileDownDTO implements Serializable {
private static final long serialVersionUID = 6749126258686446019L;
private String filePath;
private String uploadpath;
private String uploadType;
private HttpServletResponse response;
public FileDownDTO(){}
public FileDownDTO(String filePath, String uploadpath, String uploadType,HttpServletResponse response){
this.filePath = filePath;
this.uploadpath = uploadpath;
this.uploadType = uploadType;
this.response = response;
}
}

View File

@ -0,0 +1,55 @@
package org.jeecg.common.api.dto;
import lombok.Data;
import org.springframework.web.multipart.MultipartFile;
import java.io.Serializable;
/**
* 文件上传
* cloud api 用到的接口传输对象
*/
@Data
public class FileUploadDTO implements Serializable {
private static final long serialVersionUID = -4111953058578954386L;
private MultipartFile file;
private String bizPath;
private String uploadType;
private String customBucket;
public FileUploadDTO(){
}
/**
* 简单上传 构造器1
* @param file
* @param bizPath
* @param uploadType
*/
public FileUploadDTO(MultipartFile file,String bizPath,String uploadType){
this.file = file;
this.bizPath = bizPath;
this.uploadType = uploadType;
}
/**
* 申明桶 文件上传 构造器2
* @param file
* @param bizPath
* @param uploadType
* @param customBucket
*/
public FileUploadDTO(MultipartFile file,String bizPath,String uploadType,String customBucket){
this.file = file;
this.bizPath = bizPath;
this.uploadType = uploadType;
this.customBucket = customBucket;
}
}

View File

@ -0,0 +1,68 @@
package org.jeecg.common.api.dto;
import lombok.Data;
import org.jeecg.common.system.vo.LoginUser;
import java.io.Serializable;
import java.util.Date;
/**
* 日志对象
* cloud api 用到的接口传输对象
*/
@Data
public class LogDTO implements Serializable {
private static final long serialVersionUID = 8482720462943906924L;
/**内容*/
private String logContent;
/**日志类型(0:操作日志;1:登录日志;2:定时任务) */
private Integer logType;
/**操作类型(1:添加;2:修改;3:删除;) */
private Integer operateType;
/**登录用户 */
private LoginUser loginUser;
private String id;
private String createBy;
private Date createTime;
private Long costTime;
private String ip;
/**请求参数 */
private String requestParam;
/**请求类型*/
private String requestType;
/**请求路径*/
private String requestUrl;
/**请求方法 */
private String method;
/**操作人用户名称*/
private String username;
/**操作人用户账户*/
private String userid;
public LogDTO(){
}
public LogDTO(String logContent, Integer logType, Integer operatetype){
this.logContent = logContent;
this.logType = logType;
this.operateType = operatetype;
}
public LogDTO(String logContent, Integer logType, Integer operatetype, LoginUser loginUser){
this.logContent = logContent;
this.logType = logType;
this.operateType = operatetype;
this.loginUser = loginUser;
}
}

View File

@ -0,0 +1,41 @@
package org.jeecg.common.api.dto;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* online 拦截器权限判断
* cloud api 用到的接口传输对象
*/
@Data
public class OnlineAuthDTO implements Serializable {
private static final long serialVersionUID = 1771827545416418203L;
/**
* 用户名
*/
private String username;
/**
* 可能的请求地址
*/
private List<String> possibleUrl;
/**
* online开发的菜单地址
*/
private String onlineFormUrl;
public OnlineAuthDTO(){
}
public OnlineAuthDTO(String username, List<String> possibleUrl, String onlineFormUrl){
this.username = username;
this.possibleUrl = possibleUrl;
this.onlineFormUrl = onlineFormUrl;
}
}

View File

@ -0,0 +1,43 @@
package org.jeecg.common.api.dto.message;
import lombok.Data;
import java.io.Serializable;
/**
* 带业务参数的消息
*/
@Data
public class BusMessageDTO extends MessageDTO implements Serializable {
private static final long serialVersionUID = 9104793287983367669L;
/**
* 业务类型
*/
private String busType;
/**
* 业务id
*/
private String busId;
public BusMessageDTO(){
}
/**
* 构造 带业务参数的消息
* @param fromUser
* @param toUser
* @param title
* @param msgContent
* @param msgCategory
* @param busType
* @param busId
*/
public BusMessageDTO(String fromUser, String toUser, String title, String msgContent, String msgCategory, String busType, String busId){
super(fromUser, toUser, title, msgContent, msgCategory);
this.busId = busId;
this.busType = busType;
}
}

View File

@ -0,0 +1,45 @@
package org.jeecg.common.api.dto.message;
import lombok.Data;
import java.io.Serializable;
import java.util.Map;
/**
* 带业务参数的模板消息
*/
@Data
public class BusTemplateMessageDTO extends TemplateMessageDTO implements Serializable {
private static final long serialVersionUID = -4277810906346929459L;
/**
* 业务类型
*/
private String busType;
/**
* 业务id
*/
private String busId;
public BusTemplateMessageDTO(){
}
/**
* 构造 带业务参数的模板消息
* @param fromUser
* @param toUser
* @param title
* @param templateParam
* @param templateCode
* @param busType
* @param busId
*/
public BusTemplateMessageDTO(String fromUser, String toUser, String title, Map<String, String> templateParam, String templateCode, String busType, String busId){
super(fromUser, toUser, title, templateParam, templateCode);
this.busId = busId;
this.busType = busType;
}
}

View File

@ -0,0 +1,69 @@
package org.jeecg.common.api.dto.message;
import lombok.Data;
import org.jeecg.common.constant.CommonConstant;
import java.io.Serializable;
/**
* 普通消息
*/
@Data
public class MessageDTO implements Serializable {
private static final long serialVersionUID = -5690444483968058442L;
/**
* 发送人(用户登录账户)
*/
protected String fromUser;
/**
* 发送给(用户登录账户)
*/
protected String toUser;
/**
* 消息主题
*/
protected String title;
/**
* 消息内容
*/
protected String content;
/**
* 消息类型 1:消息 2:系统消息
*/
protected String category;
public MessageDTO(){
}
/**
* 构造器1 系统消息
*/
public MessageDTO(String fromUser,String toUser,String title, String content){
this.fromUser = fromUser;
this.toUser = toUser;
this.title = title;
this.content = content;
//默认 都是2系统消息
this.category = CommonConstant.MSG_CATEGORY_2;
}
/**
* 构造器2 支持设置category 1:消息 2:系统消息
*/
public MessageDTO(String fromUser,String toUser,String title, String content, String category){
this.fromUser = fromUser;
this.toUser = toUser;
this.title = title;
this.content = content;
this.category = category;
}
}

View File

@ -0,0 +1,37 @@
package org.jeecg.common.api.dto.message;
import lombok.Data;
import java.io.Serializable;
import java.util.Map;
/**
* 消息模板dto
*/
@Data
public class TemplateDTO implements Serializable {
private static final long serialVersionUID = 5848247133907528650L;
/**
* 模板编码
*/
protected String templateCode;
/**
* 模板参数
*/
protected Map<String, String> templateParam;
/**
* 构造器 通过设置模板参数和模板编码 作为参数获取消息内容
*/
public TemplateDTO(String templateCode, Map<String, String> templateParam){
this.templateCode = templateCode;
this.templateParam = templateParam;
}
public TemplateDTO(){
}
}

View File

@ -0,0 +1,48 @@
package org.jeecg.common.api.dto.message;
import lombok.Data;
import java.io.Serializable;
import java.util.Map;
/**
* 模板消息
*/
@Data
public class TemplateMessageDTO extends TemplateDTO implements Serializable {
private static final long serialVersionUID = 411137565170647585L;
/**
* 发送人(用户登录账户)
*/
protected String fromUser;
/**
* 发送给(用户登录账户)
*/
protected String toUser;
/**
* 消息主题
*/
protected String title;
public TemplateMessageDTO(){
}
/**
* 构造器1 发模板消息用
*/
public TemplateMessageDTO(String fromUser, String toUser,String title, Map<String, String> templateParam, String templateCode){
super(templateCode, templateParam);
this.fromUser = fromUser;
this.toUser = toUser;
this.title = title;
}
}

View File

@ -33,7 +33,7 @@ public class OaWpsModel implements Serializable {
/**
* id
*/
@TableId(type = IdType.ID_WORKER_STR)
@TableId(type = IdType.ASSIGN_ID)
@ApiModelProperty(value = "id")
private String id;
/**

View File

@ -1,6 +1,8 @@
package org.jeecg.common.api.vo;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.jeecg.common.constant.CommonConstant;
@ -58,8 +60,8 @@ public class Result<T> implements Serializable {
this.success = true;
return this;
}
@Deprecated
public static Result<Object> ok() {
Result<Object> r = new Result<Object>();
r.setSuccess(true);
@ -67,7 +69,8 @@ public class Result<T> implements Serializable {
r.setMessage("成功");
return r;
}
@Deprecated
public static Result<Object> ok(String msg) {
Result<Object> r = new Result<Object>();
r.setSuccess(true);
@ -75,7 +78,8 @@ public class Result<T> implements Serializable {
r.setMessage(msg);
return r;
}
@Deprecated
public static Result<Object> ok(Object data) {
Result<Object> r = new Result<Object>();
r.setSuccess(true);
@ -83,6 +87,31 @@ public class Result<T> implements Serializable {
r.setResult(data);
return r;
}
public static<T> Result<T> OK() {
Result<T> r = new Result<T>();
r.setSuccess(true);
r.setCode(CommonConstant.SC_OK_200);
r.setMessage("成功");
return r;
}
public static<T> Result<T> OK(T data) {
Result<T> r = new Result<T>();
r.setSuccess(true);
r.setCode(CommonConstant.SC_OK_200);
r.setResult(data);
return r;
}
public static<T> Result<T> OK(String msg, T data) {
Result<T> r = new Result<T>();
r.setSuccess(true);
r.setCode(CommonConstant.SC_OK_200);
r.setMessage(msg);
r.setResult(data);
return r;
}
public static Result<Object> error(String msg) {
return error(CommonConstant.SC_INTERNAL_SERVER_ERROR_500, msg);
@ -108,4 +137,8 @@ public class Result<T> implements Serializable {
public static Result<Object> noauth(String msg) {
return error(CommonConstant.SC_JEECG_NO_AUTHZ, msg);
}
@JsonIgnore
private String onlTable;
}

View File

@ -0,0 +1,269 @@
package org.jeecg.common.aspect;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.PropertyFilter;
import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.JoinPoint;
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.jeecg.common.api.dto.LogDTO;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.enums.ModuleType;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.IPUtils;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
/**
* 系统日志,切面处理类
*
* @Author scott
* @email jeecgos@163.com
* @Date 2018年1月14日
*/
@Aspect
@Component
public class AutoLogAspect {
@Resource
private BaseCommonService baseCommonService;
@Pointcut("@annotation(org.jeecg.common.aspect.annotation.AutoLog)")
public void logPointCut() {
}
@Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
long beginTime = System.currentTimeMillis();
//执行方法
Object result = point.proceed();
//执行时长(毫秒)
long time = System.currentTimeMillis() - beginTime;
//保存日志
saveSysLog(point, time, result);
return result;
}
private void saveSysLog(ProceedingJoinPoint joinPoint, long time, Object obj) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
LogDTO dto = new LogDTO();
AutoLog syslog = method.getAnnotation(AutoLog.class);
if(syslog != null){
//update-begin-author:taoyan date:
String content = syslog.value();
if(syslog.module()== ModuleType.ONLINE){
content = getOnlineLogContent(obj, content);
}
//注解上的描述,操作日志内容
dto.setLogType(syslog.logType());
dto.setLogContent(content);
}
//请求的方法名
String className = joinPoint.getTarget().getClass().getName();
String methodName = signature.getName();
dto.setMethod(className + "." + methodName + "()");
//设置操作类型
if (dto.getLogType() == CommonConstant.LOG_TYPE_2) {
dto.setOperateType(getOperateType(methodName, syslog.operateType()));
}
//获取request
HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
//请求的参数
dto.setRequestParam(getReqestParams(request,joinPoint));
//设置IP地址
dto.setIp(IPUtils.getIpAddr(request));
//获取登录用户信息
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
if(sysUser!=null){
dto.setUserid(sysUser.getUsername());
dto.setUsername(sysUser.getRealname());
}
//耗时
dto.setCostTime(time);
dto.setCreateTime(new Date());
//保存系统日志
baseCommonService.addLog(dto);
}
/**
* 获取操作类型
*/
private int getOperateType(String methodName,int operateType) {
if (operateType > 0) {
return operateType;
}
if (methodName.startsWith("list")) {
return CommonConstant.OPERATE_TYPE_1;
}
if (methodName.startsWith("add")) {
return CommonConstant.OPERATE_TYPE_2;
}
if (methodName.startsWith("edit")) {
return CommonConstant.OPERATE_TYPE_3;
}
if (methodName.startsWith("delete")) {
return CommonConstant.OPERATE_TYPE_4;
}
if (methodName.startsWith("import")) {
return CommonConstant.OPERATE_TYPE_5;
}
if (methodName.startsWith("export")) {
return CommonConstant.OPERATE_TYPE_6;
}
return CommonConstant.OPERATE_TYPE_1;
}
/**
* @Description: 获取请求参数
* @author: scott
* @date: 2020/4/16 0:10
* @param request: request
* @param joinPoint: joinPoint
* @Return: java.lang.String
*/
private String getReqestParams(HttpServletRequest request, JoinPoint joinPoint) {
String httpMethod = request.getMethod();
String params = "";
if ("POST".equals(httpMethod) || "PUT".equals(httpMethod) || "PATCH".equals(httpMethod)) {
Object[] paramsArray = joinPoint.getArgs();
// java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
// https://my.oschina.net/mengzhang6/blog/2395893
Object[] arguments = new Object[paramsArray.length];
for (int i = 0; i < paramsArray.length; i++) {
if (paramsArray[i] instanceof ServletRequest || paramsArray[i] instanceof ServletResponse || paramsArray[i] instanceof MultipartFile) {
//ServletRequest不能序列化从入参里排除否则报异常java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
//ServletResponse不能序列化 从入参里排除否则报异常java.lang.IllegalStateException: getOutputStream() has already been called for this response
continue;
}
arguments[i] = paramsArray[i];
}
//update-begin-author:taoyan date:20200724 for:日志数据太长的直接过滤掉
PropertyFilter profilter = new PropertyFilter() {
@Override
public boolean apply(Object o, String name, Object value) {
if(value!=null && value.toString().length()>500){
return false;
}
return true;
}
};
params = JSONObject.toJSONString(arguments, profilter);
//update-end-author:taoyan date:20200724 for:日志数据太长的直接过滤掉
} else {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
// 请求的方法参数值
Object[] args = joinPoint.getArgs();
// 请求的方法参数名称
LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
String[] paramNames = u.getParameterNames(method);
if (args != null && paramNames != null) {
for (int i = 0; i < args.length; i++) {
params += " " + paramNames[i] + ": " + args[i];
}
}
}
return params;
}
/**
* online日志内容拼接
* @param obj
* @param content
* @return
*/
private String getOnlineLogContent(Object obj, String content){
if (Result.class.isInstance(obj)){
Result res = (Result)obj;
String msg = res.getMessage();
String tableName = res.getOnlTable();
if(oConvertUtils.isNotEmpty(tableName)){
content+=",表名:"+tableName;
}
if(res.isSuccess()){
content+= ","+(oConvertUtils.isEmpty(msg)?"操作成功":msg);
}else{
content+= ","+(oConvertUtils.isEmpty(msg)?"操作失败":msg);
}
}
return content;
}
/* private void saveSysLog(ProceedingJoinPoint joinPoint, long time, Object obj) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
SysLog sysLog = new SysLog();
AutoLog syslog = method.getAnnotation(AutoLog.class);
if(syslog != null){
//update-begin-author:taoyan date:
String content = syslog.value();
if(syslog.module()== ModuleType.ONLINE){
content = getOnlineLogContent(obj, content);
}
//注解上的描述,操作日志内容
sysLog.setLogContent(content);
sysLog.setLogType(syslog.logType());
}
//请求的方法名
String className = joinPoint.getTarget().getClass().getName();
String methodName = signature.getName();
sysLog.setMethod(className + "." + methodName + "()");
//设置操作类型
if (sysLog.getLogType() == CommonConstant.LOG_TYPE_2) {
sysLog.setOperateType(getOperateType(methodName, syslog.operateType()));
}
//获取request
HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
//请求的参数
sysLog.setRequestParam(getReqestParams(request,joinPoint));
//设置IP地址
sysLog.setIp(IPUtils.getIpAddr(request));
//获取登录用户信息
LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
if(sysUser!=null){
sysLog.setUserid(sysUser.getUsername());
sysLog.setUsername(sysUser.getRealname());
}
//耗时
sysLog.setCostTime(time);
sysLog.setCreateTime(new Date());
//保存系统日志
sysLogService.save(sysLog);
}*/
}

View File

@ -1,31 +1,29 @@
package org.jeecg.modules.system.aspect;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
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.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.Dict;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.system.service.ISysDictService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
package org.jeecg.common.aspect;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
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.jeecg.common.api.CommonAPI;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.Dict;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* @Description: 字典aop类
@ -37,8 +35,10 @@ import lombok.extern.slf4j.Slf4j;
@Component
@Slf4j
public class DictAspect {
@Autowired
private ISysDictService dictService;
private CommonAPI commonAPI;
// 定义切点Pointcut
@Pointcut("execution(public * org.jeecg.modules..*.*Controller.*(..))")
public void excudeService() {
@ -146,11 +146,10 @@ public class DictAspect {
}
if (!StringUtils.isEmpty(table)){
log.debug("--DictAspect------dicTable="+ table+" ,dicText= "+text+" ,dicCode="+code);
tmpValue= dictService.queryTableDictTextByKey(table,text,code,k.trim());
tmpValue= commonAPI.translateDictFromTable(table,text,code,k.trim());
}else {
tmpValue = dictService.queryDictTextByKey(code, k.trim());
tmpValue = commonAPI.translateDict(code, k.trim());
}
if (tmpValue != null) {
if (!"".equals(textValue.toString())) {
textValue.append(",");

View File

@ -0,0 +1,119 @@
package org.jeecg.common.aspect;
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.jeecg.common.api.CommonAPI;
import org.jeecg.common.aspect.annotation.PermissionData;
import org.jeecg.common.system.util.JeecgDataAutorUtils;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.SysPermissionDataRuleModel;
import org.jeecg.common.system.vo.SysUserCacheInfo;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.List;
/**
* 数据权限切面处理类
* 当被请求的方法有注解PermissionData时,会在往当前request中写入数据权限信息
* @Date 2019年4月10日
* @Version: 1.0
*/
@Aspect
@Component
@Slf4j
public class PermissionDataAspect {
@Autowired
private CommonAPI commonAPI;
@Pointcut("@annotation(org.jeecg.common.aspect.annotation.PermissionData)")
public void pointCut() {
}
@Around("pointCut()")
public Object arround(ProceedingJoinPoint point) throws Throwable{
HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
PermissionData pd = method.getAnnotation(PermissionData.class);
String component = pd.pageComponent();
String requestMethod = request.getMethod();
String requestPath = request.getRequestURI().substring(request.getContextPath().length());
requestPath = filterUrl(requestPath);
log.info("拦截请求 >> "+requestPath+";请求类型 >> "+requestMethod);
String username = JwtUtil.getUserNameByToken(request);
//查询数据权限信息
//TODO 微服务情况下也得支持缓存机制
List<SysPermissionDataRuleModel> dataRules = commonAPI.queryPermissionDataRule(component, requestPath, username);
if(dataRules!=null && dataRules.size()>0) {
//临时存储
JeecgDataAutorUtils.installDataSearchConditon(request, dataRules);
//TODO 微服务情况下也得支持缓存机制
SysUserCacheInfo userinfo = commonAPI.getCacheUser(username);
JeecgDataAutorUtils.installUserInfo(request, userinfo);
}
return point.proceed();
}
private String filterUrl(String requestPath){
String url = "";
if(oConvertUtils.isNotEmpty(requestPath)){
url = requestPath.replace("\\", "/");
url = requestPath.replace("//", "/");
if(url.indexOf("//")>=0){
url = filterUrl(url);
}
/*if(url.startsWith("/")){
url=url.substring(1);
}*/
}
return url;
}
/**
* 获取请求地址
* @param request
* @return
*/
private String getJgAuthRequsetPath(HttpServletRequest request) {
String queryString = request.getQueryString();
String requestPath = request.getRequestURI();
if(oConvertUtils.isNotEmpty(queryString)){
requestPath += "?" + queryString;
}
if (requestPath.indexOf("&") > -1) {// 去掉其他参数(保留一个参数) 例如loginController.do?login
requestPath = requestPath.substring(0, requestPath.indexOf("&"));
}
if(requestPath.indexOf("=")!=-1){
if(requestPath.indexOf(".do")!=-1){
requestPath = requestPath.substring(0,requestPath.indexOf(".do")+3);
}else{
requestPath = requestPath.substring(0,requestPath.indexOf("?"));
}
}
requestPath = requestPath.substring(request.getContextPath().length() + 1);// 去掉项目路径
return filterUrl(requestPath);
}
private boolean moHuContain(List<String> list,String key){
for(String str : list){
if(key.contains(str)){
return true;
}
}
return false;
}
}

View File

@ -1,12 +1,9 @@
package org.jeecg.common.aspect.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.enums.ModuleType;
import java.lang.annotation.*;
/**
* 系统日志注解
@ -40,4 +37,10 @@ public @interface AutoLog {
* @return 1查询2添加3修改4删除
*/
int operateType() default 0;
/**
* 模块类型 默认为common
* @return
*/
ModuleType module() default ModuleType.COMMON;
}

View File

@ -7,6 +7,11 @@ package org.jeecg.common.constant;
*/
public interface CacheConstant {
/**
* 缓存用户jwt
*/
public static final String SYS_USERS_CACHE_JWT = "sys:cache:user:jwt";
/**
* 字典信息缓存
*/
@ -15,6 +20,7 @@ public interface CacheConstant {
* 表字典信息缓存
*/
public static final String SYS_DICT_TABLE_CACHE = "sys:cache:dictTable";
public static final String SYS_DICT_TABLE_BY_KEYS_CACHE = SYS_DICT_TABLE_CACHE + "ByKeys";
/**
* 数据权限配置缓存
@ -48,4 +54,14 @@ public interface CacheConstant {
*/
public static final String SYS_DYNAMICDB_CACHE = "sys:cache:dbconnect:dynamic:";
/**
* gateway路由缓存
*/
public static final String GATEWAY_ROUTES = "geteway_routes";
/**
* gateway路由 reload key
*/
public static final String ROUTE_JVM_RELOAD_TOPIC = "gateway_jvm_route_reload_topic";
}

View File

@ -257,6 +257,16 @@ public interface CommonConstant {
*/
public static final String IM_SOCKET_TYPE = "chatMessage";
/**
* 在线聊天 是否开启默认添加好友 1是 0否
*/
public static final String IM_DEFAULT_ADD_FRIEND = "1";
/**
* 在线聊天 用户好友缓存前缀
*/
public static final String IM_PREFIX_USER_FRIEND_CACHE = "im_prefix_user_friend_";
/**
* 考勤补卡业务状态 1同意 2不同意
*/
@ -277,4 +287,17 @@ public interface CommonConstant {
*/
public static final String WPS_TYPE_1="1";
public static final String WPS_TYPE_2="2";
public final static String X_ACCESS_TOKEN = "X-Access-Token";
/**
* 多租户 请求头
*/
public final static String TENANT_ID = "tenant_id";
/**
* 微服务读取配置文件属性 服务地址
*/
public final static String CLOUD_SERVER_KEY = "spring.cloud.nacos.discovery.server-addr";
}

View File

@ -0,0 +1,33 @@
/*
*
* * Copyright (c) 2019-2020, 冷冷 (wangiegie@gmail.com).
* * <p>
* * Licensed under the GNU Lesser General Public License 3.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* * <p>
* * https://www.gnu.org/licenses/lgpl.html
* * <p>
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package org.jeecg.common.constant;
/**
* @author scott
* @date 2019年05月18日
* 服务名称
*/
public interface ServiceNameConstants {
/**
* 系统管理 admin
*/
String SYSTEM_SERVICE = "jeecg-system";
}

View File

@ -0,0 +1,30 @@
package org.jeecg.common.constant;
/**
* VXESocket 常量
*/
public class VXESocketConst {
/**
* 消息类型
*/
public static final String TYPE = "type";
/**
* 消息数据
*/
public static final String DATA = "data";
/**
* 消息类型:心跳检测
*/
public static final String TYPE_HB = "heart_beat";
/**
* 消息类型:通用数据传递
*/
public static final String TYPE_CSD = "common_send_date";
/**
* 消息类型更新vxe table数据
*/
public static final String TYPE_UVT = "update_vxe_table";
}

View File

@ -22,10 +22,18 @@ public enum CgformEnum {
* 多表
*/
ERP(2, "erp", "/jeecg/code-template-online", "erp.onetomany", "ERP风格"),
/**
* 多表jvxe风格
* */
JVXE_TABLE(2, "jvxe", "/jeecg/code-template-online", "jvxe.onetomany", "JVXE风格"),
/**
* 多表(内嵌子表风格)
*/
INNER_TABLE(2, "innerTable", "/jeecg/code-template-online", "inner-table.onetomany", "内嵌子表风格"),
/**
* 多表tab风格
* */
TAB(2, "tab", "/jeecg/code-template-online", "tab.onetomany", "Tab风格"),
/**
* 树形列表
*/
@ -55,9 +63,10 @@ public enum CgformEnum {
/**
* 构造器
*
* @param type
* @param code
* @param templatePath
* @param type 类型 1/单表 2/一对多 3/树
* @param code 模板编码
* @param templatePath 模板路径
* @param stylePath 模板子路径
* @param note
*/
CgformEnum(int type, String code, String templatePath, String stylePath, String note) {

View File

@ -0,0 +1,17 @@
package org.jeecg.common.constant.enums;
/**
* 日志按模块分类
*/
public enum ModuleType {
/**
* 普通
*/
COMMON,
/**
* online
*/
ONLINE;
}

View File

@ -1,336 +0,0 @@
package org.jeecg.common.system.api;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import org.jeecg.common.system.vo.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
/**
* @Description: 底层共通业务API提供其他独立模块调用
* @Author: scott
* @Date:2019-4-20
* @Version:V1.0
*/
public interface ISysBaseAPI {
/**
* 日志添加
* @param LogContent 内容
* @param logType 日志类型(0:操作日志;1:登录日志;2:定时任务)
* @param operatetype 操作类型(1:添加;2:修改;3:删除;)
*/
void addLog(String LogContent, Integer logType, Integer operatetype);
/**
* 根据用户账号查询用户信息
* @param username
* @return
*/
public LoginUser getUserByName(String username);
/**
* 根据用户id查询用户信息
* @param id
* @return
*/
public LoginUser getUserById(String id);
/**
* 通过用户账号查询角色集合
* @param username
* @return
*/
public List<String> getRolesByUsername(String username);
/**
* 通过用户账号查询部门集合
* @param username
* @return 部门 id
*/
List<String> getDepartIdsByUsername(String username);
/**
* 通过用户账号查询部门 name
* @param username
* @return 部门 name
*/
List<String> getDepartNamesByUsername(String username);
/**
* 获取当前数据库类型
* @return
* @throws Exception
*/
public String getDatabaseType() throws SQLException;
/**
* 获取数据字典
* @param code
* @return
*/
public List<DictModel> queryDictItemsByCode(String code);
/** 查询所有的父级字典按照create_time排序 */
public List<DictModel> queryAllDict();
/**
* 查询所有分类字典
* @return
*/
public List<SysCategoryModel> queryAllDSysCategory();
/**
* 获取表数据字典
* @param table
* @param text
* @param code
* @return
*/
List<DictModel> queryTableDictItemsByCode(String table, String text, String code);
/**
* 查询所有部门 作为字典信息 id -->value,departName -->text
* @return
*/
public List<DictModel> queryAllDepartBackDictModel();
/**
* 查询所有部门,拼接查询条件
* @return
*/
List<JSONObject> queryAllDepart(Wrapper wrapper);
/**
* 发送系统消息
* @param fromUser 发送人(用户登录账户)
* @param toUser 发送给(用户登录账户)
* @param title 消息主题
* @param msgContent 消息内容
*/
public void sendSysAnnouncement(String fromUser,String toUser,String title, String msgContent);
/**
* 发送系统消息
* @param fromUser 发送人(用户登录账户)
* @param toUser 发送给(用户登录账户)
* @param title 通知标题
* @param map 模板参数
* @param templateCode 模板编码
*/
public void sendSysAnnouncement(String fromUser, String toUser,String title, Map<String, String> map, String templateCode);
/**
*
* @param fromUser 发送人(用户登录账户)
* @param toUser 发送给(用户登录账户)
* @param title 通知标题
* @param map 模板参数
* @param templateCode 模板编码
* @param busType 业务类型
* @param busId 业务id
*/
public void sendSysAnnouncement(String fromUser, String toUser,String title, Map<String, String> map, String templateCode,String busType,String busId);
/**
* 通过消息中心模板,生成推送内容
*
* @param templateCode 模板编码
* @param map 模板参数
* @return
*/
public String parseTemplateByCode(String templateCode, Map<String, String> map);
/**
* 发送系统消息
* @param fromUser 发送人(用户登录账户)
* @param toUser 发送给(用户登录账户)
* @param title 消息主题
* @param msgContent 消息内容
* @param setMsgCategory 消息类型 1:消息2:系统消息
*/
public void sendSysAnnouncement(String fromUser, String toUser, String title, String msgContent, String setMsgCategory);
/**queryTableDictByKeys
* 发送系统消息
* @param fromUser 发送人(用户登录账户)
* @param toUser 发送给(用户登录账户)
* @param title 消息主题
* @param msgContent 消息内容
* @param setMsgCategory 消息类型 1:消息2:系统消息
* @param busType 业务类型
* @param busId 业务id
*/
public void sendSysAnnouncement(String fromUser, String toUser, String title, String msgContent, String setMsgCategory,String busType,String busId);
/**
* 根据业务类型及业务id修改消息已读
* @param busType
* @param busId
*/
public void updateSysAnnounReadFlag(String busType,String busId);
/**
* 查询表字典 支持过滤数据
* @param table
* @param text
* @param code
* @param filterSql
* @return
*/
public List<DictModel> queryFilterTableDictInfo(String table, String text, String code, String filterSql);
/**
* 查询指定table的 text code 获取字典包含text和value
* @param table
* @param text
* @param code
* @param keyArray
* @return
*/
@Deprecated
public List<String> queryTableDictByKeys(String table, String text, String code, String[] keyArray);
/**
* 获取所有有效用户
* @return
*/
public List<ComboModel> queryAllUser();
/**
* 获取所有有效用户 带参
* userIds 默认选中用户
* @return
*/
public JSONObject queryAllUser(String[] userIds, int pageNo, int pageSize);
/**
* 获取所有有效用户 拼接查询条件
*
* @return
*/
List<JSONObject> queryAllUser(Wrapper wrapper);
/**
* 获取所有角色
* @return
*/
public List<ComboModel> queryAllRole();
/**
* 获取所有角色 带参
* roleIds 默认选中角色
* @return
*/
public List<ComboModel> queryAllRole(String[] roleIds );
/**
* 通过用户账号查询角色Id集合
* @param username
* @return
*/
public List<String> getRoleIdsByUsername(String username);
/**
* 通过部门编号查询部门id
* @param orgCode
* @return
*/
public String getDepartIdsByOrgCode(String orgCode);
/**
* 查询上一级部门
* @param departId
* @return
*/
public DictModel getParentDepartId(String departId);
/**
* 查询所有部门
* @return
*/
public List<SysDepartModel> getAllSysDepart();
/**
* 根据 id 查询数据库中存储的 DynamicDataSourceModel
*
* @param dbSourceId
* @return
*/
DynamicDataSourceModel getDynamicDbSourceById(String dbSourceId);
/**
* 根据 code 查询数据库中存储的 DynamicDataSourceModel
*
* @param dbSourceCode
* @return
*/
DynamicDataSourceModel getDynamicDbSourceByCode(String dbSourceCode);
/**
* 根据部门Id获取部门负责人
* @param deptId
* @return
*/
public List<String> getDeptHeadByDepId(String deptId);
/**
* 文件上传
* @param file 文件
* @param bizPath 自定义路径
* @param uploadType 上传方式
* @return
*/
public String upload(MultipartFile file,String bizPath,String uploadType);
/**
* 文件上传 自定义桶
* @param file
* @param bizPath
* @param uploadType
* @param customBucket
* @return
*/
public String upload(MultipartFile file,String bizPath,String uploadType,String customBucket);
/**
* 文档管理文件下载预览
* @param filePath
* @param uploadpath
* @param response
*/
public void viewAndDownload(String filePath, String uploadpath, String uploadType,HttpServletResponse response);
/**
* 给指定用户发消息
* @param userIds
* @param cmd
*/
public void sendWebSocketMsg(String[] userIds, String cmd);
/**
* 根据id获取所有参与用户
* userIds
* @return
*/
public List<LoginUser> queryAllUserByIds(String[] userIds);
/**
* 将会议签到信息推动到预览
* userIds
* @return
* @param userId
*/
void meetingSignWebsocket(String userId);
/**
* 根据name获取所有参与用户
* userNames
* @return
*/
List<LoginUser> queryUserByNames(String[] userNames);
}

View File

@ -26,7 +26,7 @@ public class JeecgEntity implements Serializable {
private static final long serialVersionUID = 1L;
/** ID */
@TableId(type = IdType.ID_WORKER_STR)
@TableId(type = IdType.ASSIGN_ID)
@ApiModelProperty(value = "ID")
private java.lang.String id;
/** 创建人 */

View File

@ -1,382 +0,0 @@
package org.jeecg.common.system.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.util.CommonUtils;
import org.jeecg.common.util.RestUtil;
import org.jeecg.common.util.TokenUtils;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
/**
* <p>
* 用户表 前端控制器
* </p>
*
* @Author scott
* @since 2018-12-20
*/
@Slf4j
@RestController
@RequestMapping("/sys/common")
public class CommonController {
@Autowired
private ISysBaseAPI sysBaseAPI;
@Value(value = "${jeecg.path.upload}")
private String uploadpath;
/**
* 本地local miniominio 阿里alioss
*/
@Value(value="${jeecg.uploadType}")
private String uploadType;
/**
* @Author 政辉
* @return
*/
@GetMapping("/403")
public Result<?> noauth() {
return Result.error("没有权限,请联系管理员授权");
}
/**
* 文件上传统一方法
* @param request
* @param response
* @return
*/
@PostMapping(value = "/upload")
public Result<?> upload(HttpServletRequest request, HttpServletResponse response) {
Result<?> result = new Result<>();
String savePath = "";
String bizPath = request.getParameter("biz");
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
MultipartFile file = multipartRequest.getFile("file");// 获取上传文件对象
if(oConvertUtils.isEmpty(bizPath)){
if(CommonConstant.UPLOAD_TYPE_OSS.equals(uploadType)){
//未指定目录,则用阿里云默认目录 upload
bizPath = "upload";
//result.setMessage("使用阿里云文件上传时,必须添加目录!");
//result.setSuccess(false);
//return result;
}else{
bizPath = "";
}
}
if(CommonConstant.UPLOAD_TYPE_LOCAL.equals(uploadType)){
//针对jeditor编辑器如何使 lcaol模式采用 base64格式存储
String jeditor = request.getParameter("jeditor");
if(oConvertUtils.isNotEmpty(jeditor)){
result.setMessage(CommonConstant.UPLOAD_TYPE_LOCAL);
result.setSuccess(true);
return result;
}else{
savePath = this.uploadLocal(file,bizPath);
}
}else{
savePath = sysBaseAPI.upload(file,bizPath,uploadType);
}
if(oConvertUtils.isNotEmpty(savePath)){
result.setMessage(savePath);
result.setSuccess(true);
}else {
result.setMessage("上传失败!");
result.setSuccess(false);
}
return result;
}
/**
* 本地文件上传
* @param mf 文件
* @param bizPath 自定义路径
* @return
*/
private String uploadLocal(MultipartFile mf,String bizPath){
try {
String ctxPath = uploadpath;
String fileName = null;
File file = new File(ctxPath + File.separator + bizPath + File.separator );
if (!file.exists()) {
file.mkdirs();// 创建文件根目录
}
String orgName = mf.getOriginalFilename();// 获取文件名
orgName = CommonUtils.getFileName(orgName);
if(orgName.indexOf(".")!=-1){
fileName = orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.indexOf("."));
}else{
fileName = orgName+ "_" + System.currentTimeMillis();
}
String savePath = file.getPath() + File.separator + fileName;
File savefile = new File(savePath);
FileCopyUtils.copy(mf.getBytes(), savefile);
String dbpath = null;
if(oConvertUtils.isNotEmpty(bizPath)){
dbpath = bizPath + File.separator + fileName;
}else{
dbpath = fileName;
}
if (dbpath.contains("\\")) {
dbpath = dbpath.replace("\\", "/");
}
return dbpath;
} catch (IOException e) {
log.error(e.getMessage(), e);
}
return "";
}
// @PostMapping(value = "/upload2")
// public Result<?> upload2(HttpServletRequest request, HttpServletResponse response) {
// Result<?> result = new Result<>();
// try {
// String ctxPath = uploadpath;
// String fileName = null;
// String bizPath = "files";
// String tempBizPath = request.getParameter("biz");
// if(oConvertUtils.isNotEmpty(tempBizPath)){
// bizPath = tempBizPath;
// }
// String nowday = new SimpleDateFormat("yyyyMMdd").format(new Date());
// File file = new File(ctxPath + File.separator + bizPath + File.separator + nowday);
// if (!file.exists()) {
// file.mkdirs();// 创建文件根目录
// }
// MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
// MultipartFile mf = multipartRequest.getFile("file");// 获取上传文件对象
// String orgName = mf.getOriginalFilename();// 获取文件名
// fileName = orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.indexOf("."));
// String savePath = file.getPath() + File.separator + fileName;
// File savefile = new File(savePath);
// FileCopyUtils.copy(mf.getBytes(), savefile);
// String dbpath = bizPath + File.separator + nowday + File.separator + fileName;
// if (dbpath.contains("\\")) {
// dbpath = dbpath.replace("\\", "/");
// }
// result.setMessage(dbpath);
// result.setSuccess(true);
// } catch (IOException e) {
// result.setSuccess(false);
// result.setMessage(e.getMessage());
// log.error(e.getMessage(), e);
// }
// return result;
// }
/**
* 预览图片&下载文件
* 请求地址http://localhost:8080/common/static/{user/20190119/e1fe9925bc315c60addea1b98eb1cb1349547719_1547866868179.jpg}
*
* @param request
* @param response
*/
@GetMapping(value = "/static/**")
public void view(HttpServletRequest request, HttpServletResponse response) {
// ISO-8859-1 ==> UTF-8 进行编码转换
String imgPath = extractPathFromPattern(request);
if(oConvertUtils.isEmpty(imgPath) || imgPath=="null"){
return;
}
// 其余处理略
InputStream inputStream = null;
OutputStream outputStream = null;
try {
imgPath = imgPath.replace("..", "");
if (imgPath.endsWith(",")) {
imgPath = imgPath.substring(0, imgPath.length() - 1);
}
String filePath = uploadpath + File.separator + imgPath;
File file = new File(filePath);
if(!file.exists()){
response.setStatus(404);
throw new RuntimeException("文件不存在..");
}
response.setContentType("application/force-download");// 设置强制下载不打开
response.addHeader("Content-Disposition", "attachment;fileName=" + new String(file.getName().getBytes("UTF-8"),"iso-8859-1"));
inputStream = new BufferedInputStream(new FileInputStream(filePath));
outputStream = response.getOutputStream();
byte[] buf = new byte[1024];
int len;
while ((len = inputStream.read(buf)) > 0) {
outputStream.write(buf, 0, len);
}
response.flushBuffer();
} catch (IOException e) {
log.error("预览文件失败" + e.getMessage());
response.setStatus(404);
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
}
}
// /**
// * 下载文件
// * 请求地址http://localhost:8080/common/download/{user/20190119/e1fe9925bc315c60addea1b98eb1cb1349547719_1547866868179.jpg}
// *
// * @param request
// * @param response
// * @throws Exception
// */
// @GetMapping(value = "/download/**")
// public void download(HttpServletRequest request, HttpServletResponse response) throws Exception {
// // ISO-8859-1 ==> UTF-8 进行编码转换
// String filePath = extractPathFromPattern(request);
// // 其余处理略
// InputStream inputStream = null;
// OutputStream outputStream = null;
// try {
// filePath = filePath.replace("..", "");
// if (filePath.endsWith(",")) {
// filePath = filePath.substring(0, filePath.length() - 1);
// }
// String localPath = uploadpath;
// String downloadFilePath = localPath + File.separator + filePath;
// File file = new File(downloadFilePath);
// if (file.exists()) {
// response.setContentType("application/force-download");// 设置强制下载不打开            
// response.addHeader("Content-Disposition", "attachment;fileName=" + new String(file.getName().getBytes("UTF-8"),"iso-8859-1"));
// inputStream = new BufferedInputStream(new FileInputStream(file));
// outputStream = response.getOutputStream();
// byte[] buf = new byte[1024];
// int len;
// while ((len = inputStream.read(buf)) > 0) {
// outputStream.write(buf, 0, len);
// }
// response.flushBuffer();
// }
//
// } catch (Exception e) {
// log.info("文件下载失败" + e.getMessage());
// // e.printStackTrace();
// } finally {
// if (inputStream != null) {
// try {
// inputStream.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
// if (outputStream != null) {
// try {
// outputStream.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
// }
//
// }
/**
* @功能pdf预览Iframe
* @param modelAndView
* @return
*/
@RequestMapping("/pdf/pdfPreviewIframe")
public ModelAndView pdfPreviewIframe(ModelAndView modelAndView) {
modelAndView.setViewName("pdfPreviewIframe");
return modelAndView;
}
/**
* 把指定URL后的字符串全部截断当成参数
* 这么做是为了防止URL中包含中文或者特殊字符/等)时,匹配不了的问题
* @param request
* @return
*/
private static String extractPathFromPattern(final HttpServletRequest request) {
String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
String bestMatchPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
return new AntPathMatcher().extractPathWithinPattern(bestMatchPattern, path);
}
/**
* 中转HTTP请求解决跨域问题
*
* @param url 必填:请求地址
* @return
*/
@RequestMapping("/transitRESTful")
public Result transitRESTful(@RequestParam("url") String url, HttpServletRequest request) {
try {
ServletServerHttpRequest httpRequest = new ServletServerHttpRequest(request);
// 中转请求method、body
HttpMethod method = httpRequest.getMethod();
JSONObject params;
try {
params = JSON.parseObject(JSON.toJSONString(httpRequest.getBody()));
} catch (Exception e) {
params = new JSONObject();
}
// 中转请求问号参数
JSONObject variables = JSON.parseObject(JSON.toJSONString(request.getParameterMap()));
variables.remove("url");
// 在 headers 里传递Token
String token = TokenUtils.getTokenByRequest(request);
HttpHeaders headers = new HttpHeaders();
headers.set("X-Access-Token", token);
// 发送请求
String httpURL = URLDecoder.decode(url, "UTF-8");
ResponseEntity<String> response = RestUtil.request(httpURL, method, headers , variables, params, String.class);
// 封装返回结果
Result<Object> result = new Result<>();
int statusCode = response.getStatusCodeValue();
result.setCode(statusCode);
result.setSuccess(statusCode == 200);
String responseBody = response.getBody();
try {
// 尝试将返回结果转为JSON
Object json = JSON.parse(responseBody);
result.setResult(json);
} catch (Exception e) {
// 转成JSON失败直接返回原始数据
result.setResult(responseBody);
}
return result;
} catch (Exception e) {
log.debug("中转HTTP请求失败", e);
return Result.error(e.getMessage());
}
}
}

View File

@ -1,23 +1,26 @@
package org.jeecg.common.system.query;
import cn.hutool.core.util.ArrayUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.PropertyUtils;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.DataBaseConstant;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.util.JeecgDataAutorUtils;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.SysPermissionDataRuleModel;
import org.jeecg.common.util.CommonUtils;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.SqlInjectionUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecgframework.core.util.ApplicationContextUtil;
import org.springframework.util.NumberUtils;
import java.beans.PropertyDescriptor;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.text.ParseException;
@ -115,7 +118,26 @@ public class QueryGenerator {
if (judgedIsUselessField(name)|| !PropertyUtils.isReadable(searchObj, name)) {
continue;
}
Object value = PropertyUtils.getSimpleProperty(searchObj, name);
// update-begin--Author:taoyan Date:20200910 forissues/1671 如果字段加注解了@TableField(exist = false),不走DB查询-------
//如果字段加注解了@TableField(exist = false),不走DB查询
//TODO 存在缺陷,这个写法 clazz.getDeclaredField(name) 获取不到继承的父实体字段
try {
if (oConvertUtils.isNotEmpty(value)) {
Field field = searchObj.getClass().getDeclaredField(name);
if (field != null) {
TableField tableField = field.getAnnotation(TableField.class);
if (tableField != null && tableField.exist() == false) {
continue;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
// update-end--Author:taoyan Date:20200910 forissues/1671 如果字段加注解了@TableField(exist = false),不走DB查询 -------
//数据权限查询
if(ruleMap.containsKey(name)) {
addRuleToQueryWrapper(ruleMap.get(name), name, origDescriptors[i].getPropertyType(), queryWrapper);
@ -140,7 +162,6 @@ public class QueryGenerator {
//判断单值 参数带不同标识字符串 走不同的查询
//TODO 这种前后带逗号的支持分割后模糊查询需要否 使多选字段的查询生效
Object value = PropertyUtils.getSimpleProperty(searchObj, name);
if (null != value && value.toString().startsWith(COMMA) && value.toString().endsWith(COMMA)) {
String multiLikeval = value.toString().replace(",,", COMMA);
String[] vals = multiLikeval.substring(1, multiLikeval.length()).split(COMMA);
@ -446,9 +467,14 @@ public class QueryGenerator {
queryWrapper.in(name, (Object[])value.toString().split(","));
}else if(value instanceof String[]) {
queryWrapper.in(name, (Object[]) value);
}
//update-begin-author:taoyan date:20200909 for:【bug】in 类型多值查询 不适配postgresql #1671
else if(value.getClass().isArray()) {
queryWrapper.in(name, (Object[])value);
}else {
queryWrapper.in(name, value);
}
//update-end-author:taoyan date:20200909 for:【bug】in 类型多值查询 不适配postgresql #1671
break;
case LIKE:
queryWrapper.like(name, value);
@ -498,6 +524,30 @@ public class QueryGenerator {
}
return ruleMap;
}
/**
* 获取请求对应的数据权限规则
* @return
*/
public static Map<String, SysPermissionDataRuleModel> getRuleMap(List<SysPermissionDataRuleModel> list) {
Map<String, SysPermissionDataRuleModel> ruleMap = new HashMap<String, SysPermissionDataRuleModel>();
if(list==null){
list =JeecgDataAutorUtils.loadDataSearchConditon();
}
if(list != null&&list.size()>0){
if(list.get(0)==null){
return ruleMap;
}
for (SysPermissionDataRuleModel rule : list) {
String column = rule.getRuleColumn();
if(QueryRuleEnum.SQL_RULES.getValue().equals(rule.getRuleConditions())) {
column = SQL_RULES_COLUMN+rule.getId();
}
ruleMap.put(column, rule);
}
}
return ruleMap;
}
private static void addRuleToQueryWrapper(SysPermissionDataRuleModel dataRule, String name, Class propertyType, QueryWrapper<?> queryWrapper) {
QueryRuleEnum rule = QueryRuleEnum.getByValue(dataRule.getRuleConditions());
@ -525,10 +575,7 @@ public class QueryGenerator {
}
public static String converRuleValue(String ruleValue) {
String value = JwtUtil.getSessionData(ruleValue);
if(oConvertUtils.isEmpty(value)) {
value = JwtUtil.getUserSystemData(ruleValue,null);
}
String value = JwtUtil.getUserSystemData(ruleValue,null);
return value!= null ? value : ruleValue;
}
@ -728,8 +775,7 @@ public class QueryGenerator {
/**
* 根据权限相关配置生成相关的SQL 语句
* @param searchObj
* @param parameterMap
* @param clazz
* @return
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
@ -771,8 +817,8 @@ public class QueryGenerator {
/**
* 根据权限相关配置 组装mp需要的权限
* @param searchObj
* @param parameterMap
* @param queryWrapper
* @param clazz
* @return
*/
public static void installAuthMplus(QueryWrapper<?> queryWrapper,Class<?> clazz) {
@ -847,17 +893,7 @@ public class QueryGenerator {
* 获取系统数据库类型
*/
private static String getDbType(){
if(oConvertUtils.isNotEmpty(DB_TYPE)){
return DB_TYPE;
}
try {
ISysBaseAPI sysBaseAPI = ApplicationContextUtil.getContext().getBean(ISysBaseAPI.class);
DB_TYPE = sysBaseAPI.getDatabaseType();
return DB_TYPE;
} catch (Exception e) {
e.printStackTrace();
}
return DB_TYPE;
return CommonUtils.getDatabaseType();
}
}

View File

@ -75,11 +75,28 @@ public class JeecgDataAutorUtils {
request.setAttribute(MENU_DATA_AUTHOR_RULE_SQL,sql);
}
}
/**
* 将用户信息存到request
* @param request
* @param userinfo
*/
public static synchronized void installUserInfo(HttpServletRequest request, SysUserCacheInfo userinfo) {
request.setAttribute(SYS_USER_INFO, userinfo);
}
/**
* 将用户信息存到request
* @param userinfo
*/
public static synchronized void installUserInfo(SysUserCacheInfo userinfo) {
SpringContextUtils.getHttpServletRequest().setAttribute(SYS_USER_INFO, userinfo);
}
/**
* 从request获取用户信息
* @return
*/
public static synchronized SysUserCacheInfo loadUserInfo() {
return (SysUserCacheInfo) SpringContextUtils.getHttpServletRequest().getAttribute(SYS_USER_INFO);

View File

@ -174,10 +174,15 @@ public class JwtUtil {
}
//替换为系统用户所拥有的所有机构编码
else if (key.equals(DataBaseConstant.SYS_MULTI_ORG_CODE)|| key.toLowerCase().equals(DataBaseConstant.SYS_MULTI_ORG_CODE_TABLE)) {
if(user.isOneDepart()) {
returnValue = user.getSysMultiOrgCode().get(0);
}else {
returnValue = Joiner.on(",").join(user.getSysMultiOrgCode());
if(user==null){
//TODO 暂时使用用户登录部门,存在逻辑缺陷,不是用户所拥有的部门
returnValue = sysUser.getOrgCode();
}else{
if(user.isOneDepart()) {
returnValue = user.getSysMultiOrgCode().get(0);
}else {
returnValue = Joiner.on(",").join(user.getSysMultiOrgCode());
}
}
}
//替换为当前系统时间(年月日)

View File

@ -113,4 +113,7 @@ public class LoginUser {
/**多租户id配置编辑用户的时候设置*/
private String relTenantIds;
/**设备id uniapp推送用*/
private String clientId;
}

View File

@ -1,14 +1,23 @@
package org.jeecg.common.util;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.DataBaseConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.oss.OssBootUtil;
import org.jeecgframework.poi.util.PoiPublicUtil;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.sql.DataSource;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
@Slf4j
public class CommonUtils {
public static String uploadOnlineImage(byte[] data,String basePath,String bizPath,String uploadType){
@ -61,4 +70,81 @@ public class CommonUtils {
fileName = fileName.replace("=","").replace(",","").replace("&","").replace("#", "");
return fileName;
}
}
/**
* 统一全局上传
* @Return: java.lang.String
*/
public static String upload(MultipartFile file, String bizPath, String uploadType) {
String url = "";
if(CommonConstant.UPLOAD_TYPE_MINIO.equals(uploadType)){
url = MinioUtil.upload(file,bizPath);
}else{
url = OssBootUtil.upload(file,bizPath);
}
return url;
}
/**
* 统一全局上传 带桶
* @Return: java.lang.String
*/
public static String upload(MultipartFile file, String bizPath, String uploadType, String customBucket) {
String url = "";
if(CommonConstant.UPLOAD_TYPE_MINIO.equals(uploadType)){
url = MinioUtil.upload(file,bizPath,customBucket);
}else{
url = OssBootUtil.upload(file,bizPath,customBucket);
}
return url;
}
/** 当前系统数据库类型 */
private static String DB_TYPE = "";
public static String getDatabaseType() {
if(oConvertUtils.isNotEmpty(DB_TYPE)){
return DB_TYPE;
}
DataSource dataSource = SpringContextUtils.getApplicationContext().getBean(DataSource.class);
try {
return getDatabaseTypeByDataSource(dataSource);
} catch (SQLException e) {
//e.printStackTrace();
log.warn(e.getMessage());
return "";
}
}
/**
* 获取数据库类型
* @param dataSource
* @return
* @throws SQLException
*/
private static String getDatabaseTypeByDataSource(DataSource dataSource) throws SQLException{
if("".equals(DB_TYPE)) {
Connection connection = dataSource.getConnection();
try {
DatabaseMetaData md = connection.getMetaData();
String dbType = md.getDatabaseProductName().toLowerCase();
if(dbType.indexOf("mysql")>=0) {
DB_TYPE = DataBaseConstant.DB_TYPE_MYSQL;
}else if(dbType.indexOf("oracle")>=0) {
DB_TYPE = DataBaseConstant.DB_TYPE_ORACLE;
}else if(dbType.indexOf("sqlserver")>=0||dbType.indexOf("sql server")>=0) {
DB_TYPE = DataBaseConstant.DB_TYPE_SQLSERVER;
}else if(dbType.indexOf("postgresql")>=0) {
DB_TYPE = DataBaseConstant.DB_TYPE_POSTGRESQL;
}else {
throw new JeecgBootException("数据库类型:["+dbType+"]不识别!");
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}finally {
connection.close();
}
}
return DB_TYPE;
}
}

View File

@ -6,8 +6,12 @@ public enum DySmsEnum {
LOGIN_TEMPLATE_CODE("SMS_175435174","JEECG","code"),
FORGET_PASSWORD_TEMPLATE_CODE("SMS_175435174","JEECG","code"),
REGISTER_TEMPLATE_CODE("SMS_175430166","JEECG","code");
REGISTER_TEMPLATE_CODE("SMS_175430166","JEECG","code"),
/**会议通知*/
MEET_NOTICE_TEMPLATE_CODE("SMS_201480469","H5活动之家","username,title,minute,time"),
/**我的计划通知*/
PLAN_NOTICE_TEMPLATE_CODE("SMS_201470515","H5活动之家","username,title,time");
/**
* 短信模板编码
*/

View File

@ -1,5 +1,6 @@
package org.jeecg.common.util;
import org.jeecg.config.StaticConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -57,6 +58,12 @@ public class DySmsHelper {
//可自助调整超时时间
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
System.setProperty("sun.net.client.defaultReadTimeout", "10000");
//update-begin-authortaoyan date:20200811 for:配置类数据获取
StaticConfig staticConfig = SpringContextUtils.getBean(StaticConfig.class);
setAccessKeyId(staticConfig.getAccessKeyId());
setAccessKeySecret(staticConfig.getAccessKeySecret());
//update-end-authortaoyan date:20200811 for:配置类数据获取
//初始化acsClient,暂不支持region化
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);

View File

@ -3,8 +3,8 @@ package org.jeecg.common.util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.jeecg.common.api.CommonAPI;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
@ -35,32 +35,32 @@ public class TokenUtils {
/**
* 验证Token
*/
public static boolean verifyToken(HttpServletRequest request, ISysBaseAPI sysBaseAPI, RedisUtil redisUtil) {
public static boolean verifyToken(HttpServletRequest request, CommonAPI commonAPI, RedisUtil redisUtil) {
log.info(" -- url --" + request.getRequestURL());
String token = getTokenByRequest(request);
if (StringUtils.isBlank(token)) {
throw new AuthenticationException("token不能为空!");
throw new AuthenticationException("Token不能为空!");
}
// 解密获得username用于和数据库进行对比
String username = JwtUtil.getUsername(token);
if (username == null) {
throw new AuthenticationException("token非法无效!");
throw new AuthenticationException("Token非法无效!");
}
// 查询用户信息
LoginUser user = sysBaseAPI.getUserByName(username);
LoginUser user = commonAPI.getUserByName(username);
if (user == null) {
throw new AuthenticationException("用户不存在!");
}
// 判断用户状态
if (user.getStatus() != 1) {
throw new AuthenticationException("账号已锁定,请联系管理员!");
throw new AuthenticationException("账号已锁定,请联系管理员!");
}
// 校验token是否超时失效 & 或者账号密码是否错误
if (!jwtTokenRefresh(token, username, user.getPassword(), redisUtil)) {
throw new AuthenticationException("Token失效请重新登录!");
throw new AuthenticationException("Token失效请重新登录");
}
return true;
}
@ -95,4 +95,34 @@ public class TokenUtils {
return false;
}
/**
* 验证Token
*/
public static boolean verifyToken(String token, CommonAPI commonAPI, RedisUtil redisUtil) {
if (StringUtils.isBlank(token)) {
throw new AuthenticationException("token不能为空!");
}
// 解密获得username用于和数据库进行对比
String username = JwtUtil.getUsername(token);
if (username == null) {
throw new AuthenticationException("token非法无效!");
}
// 查询用户信息
LoginUser user = commonAPI.getUserByName(username);
if (user == null) {
throw new AuthenticationException("用户不存在!");
}
// 判断用户状态
if (user.getStatus() != 1) {
throw new AuthenticationException("账号已被锁定,请联系管理员!");
}
// 校验token是否超时失效 & 或者账号密码是否错误
if (!jwtTokenRefresh(token, username, user.getPassword(), redisUtil)) {
throw new AuthenticationException("Token失效请重新登录!");
}
return true;
}
}

View File

@ -1,8 +1,8 @@
package org.jeecg.common.util.dynamic.db;
import com.alibaba.druid.pool.DruidDataSource;
import org.jeecg.common.api.CommonAPI;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.vo.DynamicDataSourceModel;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.SpringContextUtils;
@ -37,8 +37,8 @@ public class DataSourceCachePool {
if (getRedisTemplate().hasKey(redisCacheKey)) {
return (DynamicDataSourceModel) getRedisTemplate().opsForValue().get(redisCacheKey);
}
ISysBaseAPI sysBaseAPI = SpringContextUtils.getBean(ISysBaseAPI.class);
DynamicDataSourceModel dbSource = sysBaseAPI.getDynamicDbSourceByCode(dbKey);
CommonAPI commonAPI = SpringContextUtils.getBean(CommonAPI.class);
DynamicDataSourceModel dbSource = commonAPI.getDynamicDbSourceByCode(dbKey);
if (dbSource != null) {
getRedisTemplate().opsForValue().set(redisCacheKey, dbSource);
}

View File

@ -1,14 +1,12 @@
package org.jeecg.common.util.jsonschema;
import com.alibaba.fastjson.JSONObject;
import org.jeecg.common.system.vo.DictModel;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.jeecg.common.system.vo.DictModel;
import com.alibaba.fastjson.JSONObject;
/**
* 验证通用属性
*/
@ -161,7 +159,7 @@ public abstract class CommonProperty implements Serializable{
JSONObject ui = JSONObject.parseObject(str);
json.put("ui", ui);
}
if (StringUtils.isNotBlank(defVal)) {
if (defVal!=null && defVal.length()>0) {
json.put("defVal", defVal);
}
return json;

View File

@ -593,7 +593,7 @@ public class oConvertUtils {
* @return
*/
public static<F,T> List<T> entityListToModelList(List<F> fromList, Class<T> tClass){
if(fromList.isEmpty() || fromList == null){
if(fromList == null || fromList.isEmpty()){
return null;
}
List<T> tList = new ArrayList<>();

View File

@ -0,0 +1,28 @@
package org.jeecg.config;
import org.jeecgframework.core.util.ApplicationContextUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author: Scott
* @Date: 2018/2/7
* @description: autopoi 配置类
*/
@Configuration
public class AutoPoiConfig {
/**
* excel注解字典参数支持(导入导出字典值,自动翻译)
* 举例: @Excel(name = "性别", width = 15, dicCode = "sex")
* 1、导出的时候会根据字典配置把值1,2翻译成男、女;
* 2、导入的时候会把男、女翻译成1,2存进数据库;
* @return
*/
@Bean
public ApplicationContextUtil applicationContextUtil() {
return new org.jeecgframework.core.util.ApplicationContextUtil();
}
}

View File

@ -0,0 +1,22 @@
package org.jeecg.config;
import org.jeecg.common.constant.CommonConstant;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* 跨域配置加载条件
*/
public class CorsFilterCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Object object = context.getEnvironment().getProperty(CommonConstant.CLOUD_SERVER_KEY);
//如果没有服务注册发现的配置 说明是单体应用 则加载跨域配置 返回true
if(object==null){
return true;
}
return false;
}
}

View File

@ -6,6 +6,10 @@ import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
/**
* 优雅的http请求方式RestTemplate
* @Return:
*/
@Configuration
public class RestTemplateConfig {

View File

@ -1,15 +1,14 @@
package org.jeecg.config;
import org.jeecg.common.util.DySmsHelper;
import org.jeecg.modules.message.handle.impl.EmailSendMsgHandle;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
/**
* 设置静态参数初始化
*/
@Configuration
@Component
@Data
public class StaticConfig {
@Value("${jeecg.sms.accessKeyId}")
@ -22,10 +21,11 @@ public class StaticConfig {
private String emailFrom;
@Bean
/*@Bean
public void initStatic() {
DySmsHelper.setAccessKeyId(accessKeyId);
DySmsHelper.setAccessKeySecret(accessKeySecret);
EmailSendMsgHandle.setEmailFrom(emailFrom);
}
DySmsHelper.setAccessKeyId(accessKeyId);
DySmsHelper.setAccessKeySecret(accessKeySecret);
EmailSendMsgHandle.setEmailFrom(emailFrom);
}*/
}

View File

@ -0,0 +1,135 @@
package org.jeecg.config;
import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrapUI;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.constant.CommonConstant;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @Author scott
*/
@Slf4j
@Configuration
@EnableSwagger2
@EnableSwaggerBootstrapUI
@ConditionalOnProperty(name = "swagger.enable", havingValue = "true")
public class Swagger2Config implements WebMvcConfigurer {
/**
*
* 显示swagger-ui.html文档展示页还必须注入swagger资源
*
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
/**
* swagger2的配置文件这里可以配置swagger2的一些基本的内容比如扫描的包等等
*
* @return Docket
*/
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
//此包路径下的类,才生成接口文档
.apis(RequestHandlerSelectors.basePackage("org.jeecg.modules"))
//加了ApiOperation注解的类才生成接口文档
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build()
.securitySchemes(Collections.singletonList(securityScheme()))
.securityContexts(securityContexts());
//.globalOperationParameters(setHeaderToken());
}
/***
* oauth2配置
* 需要增加swagger授权回调地址
* http://localhost:8888/webjars/springfox-swagger-ui/o2c.html
* @return
*/
@Bean
SecurityScheme securityScheme() {
return new ApiKey(CommonConstant.X_ACCESS_TOKEN, CommonConstant.X_ACCESS_TOKEN, "header");
}
/**
* JWT token
* @return
*/
private List<Parameter> setHeaderToken() {
ParameterBuilder tokenPar = new ParameterBuilder();
List<Parameter> pars = new ArrayList<>();
tokenPar.name(CommonConstant.X_ACCESS_TOKEN).description("token").modelRef(new ModelRef("string")).parameterType("header").required(false).build();
pars.add(tokenPar.build());
return pars;
}
/**
* api文档的详细信息函数,注意这里的注解引用的是哪个
*
* @return
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
// //大标题
.title("Jeecg-Boot 后台服务API接口文档")
// 版本号
.version("1.0")
// .termsOfServiceUrl("NO terms of service")
// 描述
.description("后台API接口")
// 作者
.contact("JEECG团队")
.license("The Apache License, Version 2.0")
.licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
.build();
}
/**
* 新增 securityContexts 保持登录状态
*/
private List<SecurityContext> securityContexts() {
return new ArrayList(
Collections.singleton(SecurityContext.builder()
.securityReferences(defaultAuth())
.forPaths(PathSelectors.regex("^(?!auth).*$"))
.build())
);
}
private List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
return new ArrayList(
Collections.singleton(new SecurityReference(CommonConstant.X_ACCESS_TOKEN, authorizationScopes)));
}
}

View File

@ -0,0 +1,66 @@
package org.jeecg.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Spring Boot 2.0 解决跨域问题
*
* @Author qinfeng
*
*/
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Value("${jeecg.path.upload}")
private String upLoadPath;
@Value("${jeecg.path.webapp}")
private String webAppPath;
@Value("${spring.resource.static-locations}")
private String staticLocations;
/**
* 静态资源的配置 - 使得可以从磁盘中读取 Html、图片、视频、音频等
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations("file:" + upLoadPath + "//", "file:" + webAppPath + "//")
.addResourceLocations(staticLocations.split(","));
}
/**
* 方案一: 默认访问根路径跳转 doc.html页面 swagger文档页面
* 方案二: 访问根路径改成跳转 index.html页面 (简化部署方案: 可以把前端打包直接放到项目的 webapp上面的配置
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("doc.html");
}
@Bean
@Conditional(CorsFilterCondition.class)
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
final CorsConfiguration corsConfiguration = new CorsConfiguration();
//是否允许请求带有验证信息
corsConfiguration.setAllowCredentials(true);
// 允许访问的客户端域名
corsConfiguration.addAllowedOrigin("*");
// 允许服务端访问的客户端请求头
corsConfiguration.addAllowedHeader("*");
// 允许访问的方法名,GET POST等
corsConfiguration.addAllowedMethod("*");
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
}

View File

@ -14,5 +14,5 @@ public class WebSocketConfig {
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}

View File

@ -1,25 +1,19 @@
package org.jeecg.config.mybatis;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.Properties;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.binding.MapperMethod.ParamMap;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.plugin.*;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.system.entity.SysUser;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.Properties;
/**
* mybatis拦截器自动注入创建人创建时间修改人修改时间

View File

@ -1,8 +1,8 @@
package org.jeecg.config;
package org.jeecg.config.mybatis;
import com.baomidou.mybatisplus.core.parser.ISqlParser;
import com.baomidou.mybatisplus.core.parser.ISqlParserFilter;
import com.baomidou.mybatisplus.core.parser.SqlParserHelper;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser;
@ -11,12 +11,8 @@ import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.expression.operators.relational.InExpression;
import net.sf.jsqlparser.schema.Column;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.reflection.MetaObject;
import org.jeecg.config.mybatis.JeecgTenantParser;
import org.jeecg.modules.system.util.TenantContext;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -41,8 +37,13 @@ public class MybatisPlusConfig {
* 有哪些表需要做多租户 这些表需要添加一个字段 字段名和tenant_field对应的值一样
*/
private static final List<String> tenantTable = new ArrayList<String>();
/**
* ddl 关键字 判断不走多租户的sql过滤
*/
private static final List<String> DDL_KEYWORD = new ArrayList<String>();
static {
tenantTable.add("jee_bug_danbiao");
DDL_KEYWORD.add("alter");
}
/**
@ -51,6 +52,16 @@ public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor().setLimit(-1);
//多租户配置 配置后每次执行sql会走一遍他的转化器 如果不需要多租户功能 可以将其注释
tenantConfig(paginationInterceptor);
return paginationInterceptor;
}
/**
* 多租户的配置
* @param paginationInterceptor
*/
private void tenantConfig(PaginationInterceptor paginationInterceptor){
/*
* 测试多租户 SQL 解析处理拦截器<br>
* 这里固定写成住户 1 实际情况你可以从cookie读取因此数据看不到 麻花藤 这条记录 注意观察 SQL <br>
@ -99,15 +110,25 @@ public class MybatisPlusConfig {
paginationInterceptor.setSqlParserFilter(new ISqlParserFilter() {
@Override
public boolean doFilter(MetaObject metaObject) {
MappedStatement ms = SqlParserHelper.getMappedStatement(metaObject);
// 过滤自定义查询此时无租户信息约束 麻花藤 出现
if ("com.baomidou.springboot.mapper.UserMapper.selectListBySQL".equals(ms.getId())) {
return true;
String sql = (String) metaObject.getValue(PluginUtils.DELEGATE_BOUNDSQL_SQL);
for(String tableName: tenantTable){
String sql_lowercase = sql.toLowerCase();
if(sql_lowercase.indexOf(tableName.toLowerCase())>=0){
for(String key: DDL_KEYWORD){
if(sql_lowercase.indexOf(key)>=0){
return true;
}
}
return false;
}
}
return false;
/*if ("mapper路径.方法名".equals(ms.getId())) {
//使用这种判断也可以避免走此过滤器
return true;
}*/
return true;
}
});
return paginationInterceptor;
}
// /**
// * mybatis-plus SQL执行效率插件生产环境可以关闭

View File

@ -0,0 +1,25 @@
package org.jeecg.config.mybatis;
import lombok.extern.slf4j.Slf4j;
/**
* 多租户 tenant_id存储器
*/
@Slf4j
public class TenantContext {
private static ThreadLocal<String> currentTenant = new ThreadLocal<>();
public static void setTenant(String tenant) {
log.debug(" setting tenant to " + tenant);
currentTenant.set(tenant);
}
public static String getTenant() {
return currentTenant.get();
}
public static void clear(){
currentTenant.remove();
}
}

View File

@ -1,4 +1,4 @@
package org.jeecg.config;
package org.jeecg.config.oss;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.util.MinioUtil;

View File

@ -5,8 +5,11 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 云存储 配置
*/
@Configuration
public class OssBootConfiguration {
public class OssConfiguration {
@Value("${jeecg.oss.endpoint}")
private String endpoint;

View File

@ -1,16 +1,14 @@
package org.jeecg.config;
import java.lang.reflect.Method;
import java.time.Duration;
import java.util.Arrays;
import javax.annotation.Resource;
package org.jeecg.config.redis;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.constant.CacheConstant;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
@ -18,20 +16,20 @@ import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping;
import org.springframework.data.redis.serializer.*;
import javax.annotation.Resource;
import java.time.Duration;
import static java.util.Collections.singletonMap;
/**
* 开启缓存支持
* @Return:
*/
@Slf4j
@EnableCaching
@Configuration
@EnableCaching // 开启缓存支持
public class RedisConfig extends CachingConfigurerSupport {
@Resource
@ -65,6 +63,7 @@ public class RedisConfig extends CachingConfigurerSupport {
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
log.info(" --- redis config init --- ");
// 设置序列化
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
@ -95,7 +94,7 @@ public class RedisConfig extends CachingConfigurerSupport {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(6));
RedisCacheConfiguration redisCacheConfiguration = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
// 以锁写入的方式创建RedisCacheWriter对象
//RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(factory);
// 创建默认缓存配置对象

View File

@ -1,7 +1,7 @@
package org.jeecg.modules.shiro.authc;
package org.jeecg.config.shiro;
import org.apache.shiro.authc.AuthenticationToken;
/**
* @Author Scott
* @create 2018-07-12 15:19

View File

@ -0,0 +1,309 @@
package org.jeecg.config.shiro;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.IRedisManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisClusterManager;
import org.crazycake.shiro.RedisManager;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.shiro.filters.JwtFilter;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.util.StringUtils;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import javax.annotation.Resource;
import javax.servlet.Filter;
import java.util.*;
/**
* @author: Scott
* @date: 2018/2/7
* @description: shiro 配置类
*/
@Slf4j
@Configuration
public class ShiroConfig {
@Value("${jeecg.shiro.excludeUrls}")
private String excludeUrls;
@Resource
LettuceConnectionFactory lettuceConnectionFactory;
@Autowired
private Environment env;
/**
* Filter Chain定义说明
*
* 1、一个URL可以配置多个Filter使用逗号分隔
* 2、当设置多个过滤器时全部验证通过才视为通过
* 3、部分过滤器可指定参数如permsroles
*/
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 拦截器
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
if(oConvertUtils.isNotEmpty(excludeUrls)){
String[] permissionUrl = excludeUrls.split(",");
for(String url : permissionUrl){
filterChainDefinitionMap.put(url,"anon");
}
}
//cas验证登录
filterChainDefinitionMap.put("/cas/client/validateLogin", "anon");
// 配置不会被拦截的链接 顺序判断
filterChainDefinitionMap.put("/sys/randomImage/**", "anon"); //登录验证码接口排除
filterChainDefinitionMap.put("/sys/checkCaptcha", "anon"); //登录验证码接口排除
filterChainDefinitionMap.put("/sys/login", "anon"); //登录接口排除
filterChainDefinitionMap.put("/sys/mLogin", "anon"); //登录接口排除
filterChainDefinitionMap.put("/sys/logout", "anon"); //登出接口排除
filterChainDefinitionMap.put("/thirdLogin/**", "anon"); //第三方登录
filterChainDefinitionMap.put("/sys/getEncryptedString", "anon"); //获取加密串
filterChainDefinitionMap.put("/sys/sms", "anon");//短信验证码
filterChainDefinitionMap.put("/sys/phoneLogin", "anon");//手机登录
filterChainDefinitionMap.put("/sys/user/checkOnlyUser", "anon");//校验用户是否存在
filterChainDefinitionMap.put("/sys/user/register", "anon");//用户注册
filterChainDefinitionMap.put("/sys/user/querySysUser", "anon");//根据手机号获取用户信息
filterChainDefinitionMap.put("/sys/user/phoneVerification", "anon");//用户忘记密码验证手机号
filterChainDefinitionMap.put("/sys/user/passwordChange", "anon");//用户更改密码
filterChainDefinitionMap.put("/auth/2step-code", "anon");//登录验证码
filterChainDefinitionMap.put("/sys/common/static/**", "anon");//图片预览 &下载文件不限制token
//filterChainDefinitionMap.put("/sys/common/view/**", "anon");//图片预览不限制token
//filterChainDefinitionMap.put("/sys/common/download/**", "anon");//文件下载不限制token
filterChainDefinitionMap.put("/sys/common/pdf/**", "anon");//pdf预览
filterChainDefinitionMap.put("/generic/**", "anon");//pdf预览需要文件
filterChainDefinitionMap.put("/", "anon");
filterChainDefinitionMap.put("/doc.html", "anon");
filterChainDefinitionMap.put("/**/*.js", "anon");
filterChainDefinitionMap.put("/**/*.css", "anon");
filterChainDefinitionMap.put("/**/*.html", "anon");
filterChainDefinitionMap.put("/**/*.svg", "anon");
filterChainDefinitionMap.put("/**/*.pdf", "anon");
filterChainDefinitionMap.put("/**/*.jpg", "anon");
filterChainDefinitionMap.put("/**/*.png", "anon");
filterChainDefinitionMap.put("/**/*.ico", "anon");
// update-begin--Author:sunjianlei Date:20190813 for排除字体格式的后缀
filterChainDefinitionMap.put("/**/*.ttf", "anon");
filterChainDefinitionMap.put("/**/*.woff", "anon");
filterChainDefinitionMap.put("/**/*.woff2", "anon");
// update-begin--Author:sunjianlei Date:20190813 for排除字体格式的后缀
filterChainDefinitionMap.put("/druid/**", "anon");
filterChainDefinitionMap.put("/swagger-ui.html", "anon");
filterChainDefinitionMap.put("/swagger**/**", "anon");
filterChainDefinitionMap.put("/webjars/**", "anon");
filterChainDefinitionMap.put("/v2/**", "anon");
// update-begin--Author:sunjianlei Date:20190813 for表单设计器不要一次性全排除
filterChainDefinitionMap.put("/desform/index/**", "anon");
filterChainDefinitionMap.put("/desform/ext/**", "anon");
filterChainDefinitionMap.put("/desform/add/**", "anon");
filterChainDefinitionMap.put("/desform/view/**", "anon");
filterChainDefinitionMap.put("/desform/edit/**", "anon");
filterChainDefinitionMap.put("/desform/detail/**", "anon");
// update-end--Author:sunjianlei Date:20190813 for表单设计器不要一次性全排除
//报表设计器排除
filterChainDefinitionMap.put("/design/report/**", "anon");
filterChainDefinitionMap.put("/**/*.js.map", "anon");
filterChainDefinitionMap.put("/**/*.css.map", "anon");
//在线文档管理
filterChainDefinitionMap.put("/filemanage/**", "anon");
//在线聊天排除
filterChainDefinitionMap.put("/oa/im/**", "anon");
filterChainDefinitionMap.put("/im/dist/**", "anon");
//大屏设计器排除
filterChainDefinitionMap.put("/jmreport/bigscreen/**", "anon");
filterChainDefinitionMap.put("/test/bigScreen/**", "anon");
filterChainDefinitionMap.put("/bigscreen/**", "anon");
//测试示例
//filterChainDefinitionMap.put("/test/jeecgDemo/html", "anon"); //模板页面
//filterChainDefinitionMap.put("/test/jeecgDemo/redis/**", "anon"); //redis测试
//流程模块组件请求
// filterChainDefinitionMap.put("/act/process/**", "anon");
// filterChainDefinitionMap.put("/act/task/**", "anon");
// filterChainDefinitionMap.put("/act/model/**", "anon");
// 流程图请求地址
filterChainDefinitionMap.put("/act/task/traceImage", "anon");
filterChainDefinitionMap.put("/act/process/processPic", "anon");
filterChainDefinitionMap.put("/act/process/downProcessXml", "anon");
filterChainDefinitionMap.put("/act/process/resource", "anon");
filterChainDefinitionMap.put("/service/editor/**", "anon");
filterChainDefinitionMap.put("/service/model/**", "anon");
filterChainDefinitionMap.put("/service/model/**/save", "anon");
filterChainDefinitionMap.put("/editor-app/**", "anon");
filterChainDefinitionMap.put("/diagram-viewer/**", "anon");
filterChainDefinitionMap.put("/modeler.html", "anon");
filterChainDefinitionMap.put("/designer", "anon");
filterChainDefinitionMap.put("/designer/**", "anon");
filterChainDefinitionMap.put("/plug-in/**", "anon");
//排除Online请求
filterChainDefinitionMap.put("/auto/cgform/**", "anon");
//FineReport报表
filterChainDefinitionMap.put("/ReportServer**", "anon");
//websocket排除
filterChainDefinitionMap.put("/websocket/**", "anon");
filterChainDefinitionMap.put("/newsWebsocket/**", "anon");
//我的聊天排除
filterChainDefinitionMap.put("/oa/im/**","anon");
filterChainDefinitionMap.put("/im/dist/**","anon");
filterChainDefinitionMap.put("/eoaSocket/**","anon");
// VXE Table WebSocket 排除前端vxe组件无痕刷新功能
filterChainDefinitionMap.put("/vxeSocket/**", "anon");
//wps
filterChainDefinitionMap.put("/v1/**","anon");
//公文路径部分拦截
filterChainDefinitionMap.put("/officialdoc/oaOfficialdocTemp/editByFiledId","anon");
filterChainDefinitionMap.put("/officialdoc/oaOfficialdocOrgancode/getTemp","anon");
filterChainDefinitionMap.put("/officialdoc/oaOfficialdocTemp/getTempByFileId","anon");
filterChainDefinitionMap.put("/officialdoc/oaOfficialdocTemp/updateNameByFileId","anon");
//ureport报表拦截排除
filterChainDefinitionMap.put("/ureport/**","anon");
//插件商城排除
filterChainDefinitionMap.put("/pluginMall/**","anon");
// 添加自己的过滤器并且取名为jwt
Map<String, Filter> filterMap = new HashMap<String, Filter>(1);
//如果cloudServer为空 则说明是单体 需要加载跨域配置
Object cloudServer = env.getProperty(CommonConstant.CLOUD_SERVER_KEY);
filterMap.put("jwt", new JwtFilter(cloudServer==null));
shiroFilterFactoryBean.setFilters(filterMap);
// <!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边
filterChainDefinitionMap.put("/**", "jwt");
// 未授权界面返回JSON
shiroFilterFactoryBean.setUnauthorizedUrl("/sys/common/403");
shiroFilterFactoryBean.setLoginUrl("/sys/common/403");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean("securityManager")
public DefaultWebSecurityManager securityManager(ShiroRealm myRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
/*
* 关闭shiro自带的session详情见文档
* http://shiro.apache.org/session-management.html#SessionManagement-
* StatelessApplications%28Sessionless%29
*/
DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
securityManager.setSubjectDAO(subjectDAO);
//自定义缓存实现,使用redis
securityManager.setCacheManager(redisCacheManager());
return securityManager;
}
/**
* 下面的代码是添加注解支持
* @return
*/
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
/**
* 解决重复代理问题 github#994
* 添加前缀判断 不匹配 任何Advisor
*/
defaultAdvisorAutoProxyCreator.setUsePrefix(true);
defaultAdvisorAutoProxyCreator.setAdvisorBeanNamePrefix("_no_advisor");
return defaultAdvisorAutoProxyCreator;
}
@Bean
public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
/**
* cacheManager 缓存 redis实现
* 使用的是shiro-redis开源插件
*
* @return
*/
public RedisCacheManager redisCacheManager() {
log.info("===============(1)创建缓存管理器RedisCacheManager");
RedisCacheManager redisCacheManager = new RedisCacheManager();
redisCacheManager.setRedisManager(redisManager());
//redis中针对不同用户缓存(此处的id需要对应user实体中的id字段,用于唯一标识)
redisCacheManager.setPrincipalIdFieldName("id");
//用户权限信息缓存时间
redisCacheManager.setExpire(200000);
return redisCacheManager;
}
/**
* 配置shiro redisManager
* 使用的是shiro-redis开源插件
*
* @return
*/
@Bean
public IRedisManager redisManager() {
log.info("===============(2)创建RedisManager,连接Redis..");
IRedisManager manager;
// redis 单机支持,在集群为空,或者集群无机器时候使用 add by jzyadmin@163.com
if (lettuceConnectionFactory.getClusterConfiguration() == null || lettuceConnectionFactory.getClusterConfiguration().getClusterNodes().isEmpty()) {
RedisManager redisManager = new RedisManager();
redisManager.setHost(lettuceConnectionFactory.getHostName());
redisManager.setPort(lettuceConnectionFactory.getPort());
redisManager.setTimeout(0);
if (!StringUtils.isEmpty(lettuceConnectionFactory.getPassword())) {
redisManager.setPassword(lettuceConnectionFactory.getPassword());
}
manager = redisManager;
}else{
// redis 集群支持,优先使用集群配置 add by jzyadmin@163.com
RedisClusterManager redisManager = new RedisClusterManager();
Set<HostAndPort> portSet = new HashSet<>();
lettuceConnectionFactory.getClusterConfiguration().getClusterNodes().forEach(node -> portSet.add(new HostAndPort(node.getHost() , node.getPort())));
JedisCluster jedisCluster = new JedisCluster(portSet);
redisManager.setJedisCluster(jedisCluster);
manager = redisManager;
}
return manager;
}
}

View File

@ -0,0 +1,183 @@
package org.jeecg.config.shiro;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.jeecg.common.api.CommonAPI;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Set;
/**
* @Description: 用户登录鉴权和获取用户授权
* @Author: Scott
* @Date: 2019-4-23 8:13
* @Version: 1.1
*/
@Component
@Slf4j
public class ShiroRealm extends AuthorizingRealm {
@Lazy
@Resource
private CommonAPI commonAPI;
@Lazy
@Resource
private RedisUtil redisUtil;
/**
* 必须重写此方法不然Shiro会报错
*/
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof JwtToken;
}
/**
* 权限信息认证(包括角色以及权限)是用户访问controller的时候才进行验证(redis存储的此处权限信息)
* 触发检测用户权限时才会调用此方法例如checkRole,checkPermission
*
* @param principals 身份信息
* @return AuthorizationInfo 权限信息
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
log.info("===============Shiro权限认证开始============ [ roles、permissions]==========");
String username = null;
if (principals != null) {
LoginUser sysUser = (LoginUser) principals.getPrimaryPrincipal();
username = sysUser.getUsername();
}
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// 设置用户拥有的角色集合比如“admin,test”
Set<String> roleSet = commonAPI.queryUserRoles(username);
System.out.println(roleSet.toString());
info.setRoles(roleSet);
// 设置用户拥有的权限集合比如“sys:role:add,sys:user:add”
Set<String> permissionSet = commonAPI.queryUserAuths(username);
info.addStringPermissions(permissionSet);
System.out.println(permissionSet);
log.info("===============Shiro权限认证成功==============");
return info;
}
/**
* 用户信息认证是在用户进行登录的时候进行验证(不存redis)
* 也就是说验证用户输入的账号和密码是否正确,错误抛出异常
*
* @param auth 用户登录的账号密码信息
* @return 返回封装了用户信息的 AuthenticationInfo 实例
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
log.debug("===============Shiro身份认证开始============doGetAuthenticationInfo==========");
String token = (String) auth.getCredentials();
if (token == null) {
log.info("————————身份认证失败——————————IP地址: "+ oConvertUtils.getIpAddrByRequest(SpringContextUtils.getHttpServletRequest()));
throw new AuthenticationException("token为空!");
}
// 校验token有效性
LoginUser loginUser = this.checkUserTokenIsEffect(token);
return new SimpleAuthenticationInfo(loginUser, token, getName());
}
/**
* 校验token的有效性
*
* @param token
*/
public LoginUser checkUserTokenIsEffect(String token) throws AuthenticationException {
// 解密获得username用于和数据库进行对比
String username = JwtUtil.getUsername(token);
if (username == null) {
throw new AuthenticationException("token非法无效!");
}
// 查询用户信息
log.debug("———校验token是否有效————checkUserTokenIsEffect——————— "+ token);
LoginUser loginUser = (LoginUser) redisUtil.get(CacheConstant.SYS_USERS_CACHE_JWT+":"+token);
//TODO 当前写法导致两个小时操作中token过期
//如果redis缓存用户信息为空则通过接口获取用户信息,避免超过两个小时操作中token过期
if(loginUser==null){
loginUser = commonAPI.getUserByName(username);
}
if (loginUser == null) {
throw new AuthenticationException("用户不存在!");
}
// 判断用户状态
if (loginUser.getStatus() != 1) {
throw new AuthenticationException("账号已被锁定,请联系管理员!");
}
// 校验token是否超时失效 & 或者账号密码是否错误
if (!jwtTokenRefresh(token, username, loginUser.getPassword())) {
throw new AuthenticationException("Token失效请重新登录!");
}
return loginUser;
}
/**
* JWTToken刷新生命周期 (实现: 用户在线操作不掉线功能)
* 1、登录成功后将用户的JWT生成的Token作为k、v存储到cache缓存里面(这时候k、v值一样)缓存有效期设置为Jwt有效时间的2倍
* 2、当该用户再次请求时通过JWTFilter层层校验之后会进入到doGetAuthenticationInfo进行身份验证
* 3、当该用户这次请求jwt生成的token值已经超时但该token对应cache中的k还是存在则表示该用户一直在操作只是JWT的token失效了程序会给token对应的k映射的v值重新生成JWTToken并覆盖v值该缓存生命周期重新计算
* 4、当该用户这次请求jwt在生成的token值已经超时并在cache中不存在对应的k则表示该用户账户空闲超时返回用户信息已失效请重新登录。
* 注意: 前端请求Header中设置Authorization保持不变校验有效性以缓存中的token为准。
* 用户过期时间 = Jwt有效时间 * 2。
*
* @param userName
* @param passWord
* @return
*/
public boolean jwtTokenRefresh(String token, String userName, String passWord) {
String cacheToken = String.valueOf(redisUtil.get(CommonConstant.PREFIX_USER_TOKEN + token));
if (oConvertUtils.isNotEmpty(cacheToken)) {
// 校验token有效性
if (!JwtUtil.verify(cacheToken, userName, passWord)) {
String newAuthorization = JwtUtil.sign(userName, passWord);
// 设置超时时间
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, newAuthorization);
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME *2 / 1000);
log.info("——————————用户在线操作更新token保证不掉线—————————jwtTokenRefresh——————— "+ token);
}
//update-begin--Author:scott Date:20191005 for解决每次请求都重写redis中 token缓存问题
// else {
// // 设置超时时间
// redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, cacheToken);
// redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 1000);
// }
//update-end--Author:scott Date:20191005 for解决每次请求都重写redis中 token缓存问题
return true;
}
return false;
}
/**
* 清除当前用户的权限认证缓存
*
* @param principals 权限信息
*/
@Override
public void clearCache(PrincipalCollection principals) {
super.clearCache(principals);
}
}

View File

@ -0,0 +1,92 @@
package org.jeecg.config.shiro.filters;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.config.mybatis.TenantContext;
import org.jeecg.config.shiro.JwtToken;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Description: 鉴权登录拦截器
* @Author: Scott
* @Date: 2018/10/7
**/
@Slf4j
public class JwtFilter extends BasicHttpAuthenticationFilter {
private boolean allowOrigin = true;
public JwtFilter(){}
public JwtFilter(boolean allowOrigin){
this.allowOrigin = allowOrigin;
}
/**
* 执行登录认证
*
* @param request
* @param response
* @param mappedValue
* @return
*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
try {
executeLogin(request, response);
return true;
} catch (Exception e) {
throw new AuthenticationException("Token失效请重新登录", e);
}
}
/**
*
*/
@Override
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String token = httpServletRequest.getHeader(CommonConstant.X_ACCESS_TOKEN);
JwtToken jwtToken = new JwtToken(token);
// 提交给realm进行登入如果错误他会抛出异常并被捕获
getSubject(request, response).login(jwtToken);
// 如果没有抛出异常则代表登入成功返回true
return true;
}
/**
* 对跨域提供支持
*/
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
if(allowOrigin){
httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
//update-begin-author:scott date:20200907 for:issues/I1TAAP 前后端分离shiro过滤器配置引起的跨域问题
// 是否允许发送Cookie默认Cookie不包括在CORS请求之中。设为true时表示服务器允许Cookie包含在请求中。
httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
//update-end-author:scott date:20200907 for:issues/I1TAAP 前后端分离shiro过滤器配置引起的跨域问题
}
// 跨域时会首先发送一个option请求这里我们给option请求直接返回正常状态
if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
httpServletResponse.setStatus(HttpStatus.OK.value());
return false;
}
//update-begin-author:taoyan date:20200708 for:多租户用到
String tenant_id = httpServletRequest.getHeader(CommonConstant.TENANT_ID);
TenantContext.setTenant(tenant_id);
//update-end-author:taoyan date:20200708 for:多租户用到
return super.preHandle(request, response);
}
}

View File

@ -0,0 +1,67 @@
package org.jeecg.config.shiro.filters;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import lombok.extern.slf4j.Slf4j;
/**
* @Author Scott
* @create 2019-02-01 15:56
* @desc 鉴权请求URL访问权限拦截器
*/
@Slf4j
public class ResourceCheckFilter extends AccessControlFilter {
private String errorUrl;
public String getErrorUrl() {
return errorUrl;
}
public void setErrorUrl(String errorUrl) {
this.errorUrl = errorUrl;
}
/**
* 表示是否允许访问 如果允许访问返回true否则false
*
* @param servletRequest
* @param servletResponse
* @param o 表示写在拦截器中括号里面的字符串 mappedValue 就是 [urls] 配置中拦截器参数部分
* @return
* @throws Exception
*/
@Override
protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {
Subject subject = getSubject(servletRequest, servletResponse);
String url = getPathWithinApplication(servletRequest);
log.info("当前用户正在访问的 url => " + url);
return subject.isPermitted(url);
}
/**
* onAccessDenied表示当访问拒绝时是否已经处理了 如果返回 true 表示需要继续处理; 如果返回 false
* 表示该拦截器实例已经处理了,将直接返回即可。
*
* @param servletRequest
* @param servletResponse
* @return
* @throws Exception
*/
@Override
protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
log.info("当 isAccessAllowed 返回 false 的时候,才会执行 method onAccessDenied ");
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.sendRedirect(request.getContextPath() + this.errorUrl);
// 返回 false 表示已经处理,例如页面跳转啥的,表示不在走以下的拦截器了(如果还有配置的话)
return false;
}
}

View File

@ -0,0 +1,16 @@
package org.jeecg.modules.base.mapper;
import com.baomidou.mybatisplus.annotation.SqlParser;
import org.apache.ibatis.annotations.Param;
import org.jeecg.common.api.dto.LogDTO;
public interface BaseCommonMapper {
/**
* 保存日志
* @param dto
*/
@SqlParser(filter=true)
void saveLog(@Param("dto")LogDTO dto);
}

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.jeecg.modules.base.mapper.BaseCommonMapper">
<!-- 保存日志11 -->
<insert id="saveLog" parameterType="Object">
insert into sys_log (id, log_type, log_content, method, operate_type, request_param, ip, userid, username, cost_time, create_time)
values(
#{dto.id,jdbcType=VARCHAR},
#{dto.logType,jdbcType=INTEGER},
#{dto.logContent,jdbcType=VARCHAR},
#{dto.method,jdbcType=VARCHAR},
#{dto.operateType,jdbcType=INTEGER},
#{dto.requestParam,jdbcType=VARCHAR},
#{dto.ip,jdbcType=VARCHAR},
#{dto.userid,jdbcType=VARCHAR},
#{dto.username,jdbcType=VARCHAR},
#{dto.costTime,jdbcType=BIGINT},
#{dto.createTime,jdbcType=TIMESTAMP}
)
</insert>
</mapper>

View File

@ -0,0 +1,34 @@
package org.jeecg.modules.base.service;
import org.jeecg.common.api.dto.LogDTO;
import org.jeecg.common.system.vo.LoginUser;
/**
* common接口
*/
public interface BaseCommonService {
/**
* 保存日志
* @param logDTO
*/
void addLog(LogDTO logDTO);
/**
* 保存日志
* @param LogContent
* @param logType
* @param operateType
* @param user
*/
void addLog(String LogContent, Integer logType, Integer operateType, LoginUser user);
/**
* 保存日志
* @param LogContent
* @param logType
* @param operateType
*/
void addLog(String LogContent, Integer logType, Integer operateType);
}

View File

@ -0,0 +1,78 @@
package org.jeecg.modules.base.service.impl;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.dto.LogDTO;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.modules.base.mapper.BaseCommonMapper;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.system.vo.SysPermissionDataRuleModel;
import org.jeecg.common.system.vo.SysUserCacheInfo;
import org.jeecg.common.util.IPUtils;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
@Service
public class BaseCommonServiceImpl implements BaseCommonService {
@Resource
private BaseCommonMapper baseCommonMapper;
@Override
public void addLog(LogDTO logDTO) {
if(oConvertUtils.isEmpty(logDTO.getId())){
logDTO.setId(String.valueOf(IdWorker.getId()));
}
baseCommonMapper.saveLog(logDTO);
}
@Override
public void addLog(String logContent, Integer logType, Integer operatetype, LoginUser user) {
LogDTO sysLog = new LogDTO();
sysLog.setId(String.valueOf(IdWorker.getId()));
//注解上的描述,操作日志内容
sysLog.setLogContent(logContent);
sysLog.setLogType(logType);
sysLog.setOperateType(operatetype);
try {
//获取request
HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
//设置IP地址
sysLog.setIp(IPUtils.getIpAddr(request));
} catch (Exception e) {
sysLog.setIp("127.0.0.1");
}
//获取登录用户信息
if(user==null){
try {
user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
} catch (Exception e) {
//e.printStackTrace();
}
}
if(user!=null){
sysLog.setUserid(user.getUsername());
sysLog.setUsername(user.getRealname());
}
sysLog.setCreateTime(new Date());
//保存系统日志
baseCommonMapper.saveLog(sysLog);
}
@Override
public void addLog(String logContent, Integer logType, Integer operateType) {
addLog(logContent, logType, operateType, null);
}
}

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jeecg-boot-parent</artifactId>
<groupId>org.jeecgframework.boot</groupId>
<version>2.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jeecg-boot-module-demo</artifactId>
<dependencies>
<dependency>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-base-common</artifactId>
</dependency>
<dependency>
<groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-system-local-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,20 @@
//package org.jeecg;
//
//import org.springframework.boot.SpringApplication;
//import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
//import org.springframework.boot.autoconfigure.SpringBootApplication;
//import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
//import org.springframework.cloud.openfeign.EnableFeignClients;
//
//import java.net.UnknownHostException;
//
//@SpringBootApplication
//@EnableDiscoveryClient
//@EnableFeignClients
//@EnableAutoConfiguration(exclude={org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class})
//public class JeecgDemoApplication {
//
// public static void main(String[] args) throws UnknownHostException {
// SpringApplication.run(JeecgDemoApplication.class, args);
// }
//}

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