若依开源1.1.1发布

This commit is contained in:
RuoYi 2018-04-23 00:00:29 +08:00
commit 262ee25d8e
453 changed files with 66923 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target/

202
LICENSE Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2018 RuoYi All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
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.

51
README.md Normal file
View File

@ -0,0 +1,51 @@
## 平台简介
一直想做一款后台管理系统看了很多优秀的开源项目但是发现没有合适自己的。于是利用空闲休息时间开始自己写一套后台系统。如此有了若依管理系统。她可以用于所有的Web应用程序如网站管理后台网站会员中心CMSCRMOA。所有前端后台代码封装过后十分精简易上手出错概率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。
寓意:你若不离不弃,我必生死相依
## 内置功能
1. 用户管理:用户是系统操作者。
2. 部门管理:配置系统组织机构。
3. 岗位管理:岗位是用户所属职务。
4. 菜单管理:配置系统菜单(支持控制到按钮)。
5. 角色管理:角色菜单权限分配。
6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。
7. 操作日志:系统操作日志记录(含异常)。
8. 登录日志:系统登录情况记录(含异常)。
9. 在线用户:当前系统中活跃用户状态监控。
10. 定时任务:在线添加、修改和删除任务调度(含执行日志)。
11. 代码生成:生成包括 java、html、js、xml、sql
12. 连接池监视监视当期系统数据库连接池状态可进行分析SQL找出系统性能瓶颈。
## 系统演示
![登录界面](https://static.oschina.net/uploads/space/2018/0301/160757_fnZP_1438828.png)
![首页](https://static.oschina.net/uploads/space/2018/0301/221159_e9GB_1438828.png)
![操作日志](https://static.oschina.net/uploads/space/2018/0303/011028_xWoa_1438828.png)
![部门管理](https://static.oschina.net/uploads/space/2018/0311/235903_p5W6_1438828.png)
![用户管理](https://static.oschina.net/uploads/space/2018/0315/005844_Qduc_1438828.png)
![用户修改](https://static.oschina.net/uploads/space/2018/0403/234316_tMEP_1438828.png)
![部门选择](https://static.oschina.net/uploads/space/2018/0315/005851_bFzg_1438828.png)
![角色修改](https://static.oschina.net/uploads/space/2018/0310/164644_Jsre_1438828.png)
![菜单修改](https://static.oschina.net/uploads/space/2018/0311/235934_lHXI_1438828.png)
![岗位管理](https://static.oschina.net/uploads/space/2018/0403/234336_BqKh_1438828.png)
![调度日志](https://static.oschina.net/uploads/space/2018/0407/173459_d28s_1438828.png)
![代码生成](https://static.oschina.net/uploads/space/2018/0413/172629_IQ1C_1438828.png)
## 若依交流群
QQ群 [![加入QQ群](https://img.shields.io/badge/QQ群-1389287-blue.svg)](http://shang.qq.com/wpa/qunwpa?idkey=9a7d9f3274e4bfbf7e40e4a485ff6dc2adbeee8086ce39e40667ed4387414f12) 或 [![加入QQ群](https://img.shields.io/badge/QQ群-1389287-blue.svg)](https://jq.qq.com/?_wv=1027&k=5ONbr1w),推荐点击按钮入群,当然如果无法成功操作,请自行搜索群号`1389287`进行添加

170
doc/quartz.sql Normal file
View File

@ -0,0 +1,170 @@
-- ----------------------------
-- 1、存储每一个已配置的 jobDetail 的详细信息
-- ----------------------------
drop table if exists QRTZ_JOB_DETAILS;
create table QRTZ_JOB_DETAILS (
sched_name varchar(120) not null,
job_name varchar(200) not null,
job_group varchar(200) not null,
description varchar(250) null,
job_class_name varchar(250) not null,
is_durable varchar(1) not null,
is_nonconcurrent varchar(1) not null,
is_update_data varchar(1) not null,
requests_recovery varchar(1) not null,
job_data blob null,
primary key (sched_name,job_name,job_group)
) engine=innodb default charset=utf8;
-- ----------------------------
-- 2、 存储已配置的 Trigger 的信息
-- ----------------------------
drop table if exists QRTZ_TRIGGERS;
create table QRTZ_TRIGGERS (
sched_name varchar(120) not null,
trigger_name varchar(200) not null,
trigger_group varchar(200) not null,
job_name varchar(200) not null,
job_group varchar(200) not null,
description varchar(250) null,
next_fire_time bigint(13) null,
prev_fire_time bigint(13) null,
priority integer null,
trigger_state varchar(16) not null,
trigger_type varchar(8) not null,
start_time bigint(13) not null,
end_time bigint(13) null,
calendar_name varchar(200) null,
misfire_instr smallint(2) null,
job_data blob null,
primary key (sched_name,trigger_name,trigger_group),
foreign key (sched_name,job_name,job_group) references QRTZ_JOB_DETAILS(sched_name,job_name,job_group)
) engine=innodb default charset=utf8;
-- ----------------------------
-- 3、 存储简单的 Trigger包括重复次数间隔以及已触发的次数
-- ----------------------------
drop table if exists QRTZ_SIMPLE_TRIGGERS;
create table QRTZ_SIMPLE_TRIGGERS (
sched_name varchar(120) not null,
trigger_name varchar(200) not null,
trigger_group varchar(200) not null,
repeat_count bigint(7) not null,
repeat_interval bigint(12) not null,
times_triggered bigint(10) not null,
primary key (sched_name,trigger_name,trigger_group),
foreign key (sched_name,trigger_name,trigger_group) references QRTZ_TRIGGERS(sched_name,trigger_name,trigger_group)
) engine=innodb default charset=utf8;
-- ----------------------------
-- 4、 存储 Cron Trigger包括 Cron 表达式和时区信息
-- ----------------------------
drop table if exists QRTZ_CRON_TRIGGERS;
create table QRTZ_CRON_TRIGGERS (
sched_name varchar(120) not null,
trigger_name varchar(200) not null,
trigger_group varchar(200) not null,
cron_expression varchar(200) not null,
time_zone_id varchar(80),
primary key (sched_name,trigger_name,trigger_group),
foreign key (sched_name,trigger_name,trigger_group) references QRTZ_TRIGGERS(sched_name,trigger_name,trigger_group)
) engine=innodb default charset=utf8;
-- ----------------------------
-- 5、 Trigger 作为 Blob 类型存储(用于 Quartz 用户用 JDBC 创建他们自己定制的 Trigger 类型JobStore 并不知道如何存储实例的时候)
-- ----------------------------
drop table if exists QRTZ_BLOB_TRIGGERS;
create table QRTZ_BLOB_TRIGGERS (
sched_name varchar(120) not null,
trigger_name varchar(200) not null,
trigger_group varchar(200) not null,
blob_data blob null,
primary key (sched_name,trigger_name,trigger_group),
foreign key (sched_name,trigger_name,trigger_group) references QRTZ_TRIGGERS(sched_name,trigger_name,trigger_group)
) engine=innodb default charset=utf8;
-- ----------------------------
-- 6、 以 Blob 类型存储存放日历信息, quartz可配置一个日历来指定一个时间范围
-- ----------------------------
drop table if exists QRTZ_CALENDARS;
create table QRTZ_CALENDARS (
sched_name varchar(120) not null,
calendar_name varchar(200) not null,
calendar blob not null,
primary key (sched_name,calendar_name)
) engine=innodb default charset=utf8;
-- ----------------------------
-- 7、 存储已暂停的 Trigger 组的信息
-- ----------------------------
drop table if exists QRTZ_PAUSED_TRIGGER_GRPS;
create table QRTZ_PAUSED_TRIGGER_GRPS (
sched_name varchar(120) not null,
trigger_group varchar(200) not null,
primary key (sched_name,trigger_group)
) engine=innodb default charset=utf8;
-- ----------------------------
-- 8、 存储与已触发的 Trigger 相关的状态信息,以及相联 Job 的执行信息
-- ----------------------------
drop table if exists QRTZ_FIRED_TRIGGERS;
create table QRTZ_FIRED_TRIGGERS (
sched_name varchar(120) not null,
entry_id varchar(95) not null,
trigger_name varchar(200) not null,
trigger_group varchar(200) not null,
instance_name varchar(200) not null,
fired_time bigint(13) not null,
sched_time bigint(13) not null,
priority integer not null,
state varchar(16) not null,
job_name varchar(200) null,
job_group varchar(200) null,
is_nonconcurrent varchar(1) null,
requests_recovery varchar(1) null,
primary key (sched_name,entry_id)
) engine=innodb default charset=utf8;
-- ----------------------------
-- 9、 存储少量的有关 Scheduler 的状态信息,假如是用于集群中,可以看到其他的 Scheduler 实例
-- ----------------------------
drop table if exists QRTZ_SCHEDULER_STATE;
create table QRTZ_SCHEDULER_STATE (
sched_name varchar(120) not null,
instance_name varchar(200) not null,
last_checkin_time bigint(13) not null,
checkin_interval bigint(13) not null,
primary key (sched_name,instance_name)
) engine=innodb default charset=utf8;
-- ----------------------------
-- 10、 存储程序的悲观锁的信息(假如使用了悲观锁)
-- ----------------------------
drop table if exists QRTZ_LOCKS;
create table QRTZ_LOCKS (
sched_name varchar(120) not null,
lock_name varchar(40) not null,
primary key (sched_name,lock_name)
) engine=innodb default charset=utf8;
drop table if exists QRTZ_SIMPROP_TRIGGERS;
create table QRTZ_SIMPROP_TRIGGERS (
sched_name varchar(120) not null,
trigger_name varchar(200) not null,
trigger_group varchar(200) not null,
str_prop_1 varchar(512) null,
str_prop_2 varchar(512) null,
str_prop_3 varchar(512) null,
int_prop_1 int null,
int_prop_2 int null,
long_prop_1 bigint null,
long_prop_2 bigint null,
dec_prop_1 numeric(13,4) null,
dec_prop_2 numeric(13,4) null,
bool_prop_1 varchar(1) null,
bool_prop_2 varchar(1) null,
primary key (sched_name,trigger_name,trigger_group),
foreign key (sched_name,trigger_name,trigger_group) references QRTZ_TRIGGERS(sched_name,trigger_name,trigger_group)
) engine=innodb default charset=utf8;
commit;

504
doc/ry_20180423.sql Normal file
View File

@ -0,0 +1,504 @@
-- ----------------------------
-- 1、部门表
-- ----------------------------
drop table if exists sys_dept;
create table sys_dept (
dept_id int(11) not null auto_increment comment '部门id',
parent_id int(11) default 0 comment '父部门id',
dept_name varchar(30) default '' comment '部门名称',
order_num int(4) default 0 comment '显示顺序',
leader varchar(20) default '' comment '负责人',
phone varchar(20) default '' comment '联系电话',
email varchar(20) default '' comment '邮箱',
status int(1) default 0 comment '部门状态:0正常,1停用',
create_by varchar(64) default '' comment '创建者',
create_time timestamp comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time timestamp comment '更新时间',
primary key (dept_id)
) engine=innodb auto_increment=200 default charset=utf8 comment = '部门表';
-- ----------------------------
-- 初始化-部门表数据
-- ----------------------------
insert into sys_dept values(100, 0, '若依集团', 0, '马云', '15011112221', 'ry@qq.com', 0, 'admin', '2018-03-01', 'ry', '2018-03-01');
insert into sys_dept values(101, 100, '研发部门', 1, '马研', '15011112222', 'ry@qq.com', 0, 'admin', '2018-03-01', 'ry', '2018-03-01');
insert into sys_dept values(102, 100, '市场部门', 2, '马市', '15011112223', 'ry@qq.com', 0, 'admin', '2018-03-01', 'ry', '2018-03-01');
insert into sys_dept values(103, 100, '测试部门', 3, '马测', '15011112224', 'ry@qq.com', 0, 'admin', '2018-03-01', 'ry', '2018-03-01');
insert into sys_dept values(104, 100, '财务部门', 4, '马财', '15011112225', 'ry@qq.com', 1, 'admin', '2018-03-01', 'ry', '2018-03-01');
insert into sys_dept values(105, 100, '运维部门', 5, '马运', '15011112226', 'ry@qq.com', 1, 'admin', '2018-03-01', 'ry', '2018-03-01');
insert into sys_dept values(106, 101, '研发一部', 1, '马一', '15011112227', 'ry@qq.com', 0, 'admin', '2018-03-01', 'ry', '2018-03-01');
insert into sys_dept values(107, 101, '研发二部', 2, '马二', '15011112228', 'ry@qq.com', 1, 'admin', '2018-03-01', 'ry', '2018-03-01');
insert into sys_dept values(108, 102, '市场一部', 1, '马一', '15011112229', 'ry@qq.com', 0, 'admin', '2018-03-01', 'ry', '2018-03-01');
insert into sys_dept values(109, 102, '市场二部', 2, '马二', '15011112210', 'ry@qq.com', 1, 'admin', '2018-03-01', 'ry', '2018-03-01');
-- ----------------------------
-- 2、用户信息表
-- ----------------------------
drop table if exists sys_user;
create table sys_user (
user_id int(11) not null auto_increment comment '用户ID',
dept_id int(20) default null comment '部门ID',
login_name varchar(30) default '' comment '登录账号',
user_name varchar(30) default '' comment '用户昵称',
email varchar(100) default '' comment '用户邮箱',
phonenumber varchar(20) default '' comment '手机号码',
password varchar(100) default '' comment '密码',
salt varchar(100) default '' comment '盐加密',
user_type char(1) default 'N' comment '类型:Y默认用户,N非默认用户',
status int(1) default 0 comment '帐号状态:0正常,1禁用',
refuse_des varchar(500) default '' comment '拒绝登录描述',
create_by varchar(64) default '' comment '创建者',
create_time timestamp comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time timestamp comment '更新时间',
primary key (user_id)
) engine=innodb auto_increment=100 default charset=utf8 comment = '用户信息表';
-- ----------------------------
-- 初始化-用户信息表数据
-- ----------------------------
insert into sys_user values(1, 106, 'admin', '若依', 'yzz_ivy@163.com', '15088888888', '29c67a30398638269fe600f73a054934', '111111', 'Y', 0, '维护中', 'admin', '2018-03-01', 'ry', '2018-03-01');
insert into sys_user values(2, 108, 'ry', '若依', 'ry@163.com', '15288888888', '8e6d98b90472783cc73c17047ddccf36', '222222', 'N', 1, '锁定中', 'admin', '2018-03-01', 'ry', '2018-03-01');
-- ----------------------------
-- 3、岗位信息表
-- ----------------------------
drop table if exists sys_post;
create table sys_post
(
post_id int(11) not null auto_increment comment '岗位ID',
post_code varchar(64) not null comment '岗位编码',
post_name varchar(100) not null comment '岗位名称',
post_sort int(4) not null comment '显示顺序',
status int(1) not null comment '状态0正常 1停用',
create_by varchar(64) default '' comment '创建者',
create_time timestamp comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time timestamp comment '更新时间',
remark varchar(500) default '' comment '备注',
primary key (post_id)
) engine=innodb default charset=utf8 comment = '岗位信息表';
-- ----------------------------
-- 初始化-岗位信息表数据
-- ----------------------------
insert into sys_post values(1, 'ceo', '董事长', 1, 0, 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_post values(2, 'se', '项目经理', 2, 0, 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_post values(3, 'hr', '人力资源', 3, 0, 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_post values(4, 'user', '普通员工', 4, 0, 'admin', '2018-03-01', 'ry', '2018-03-01', '');
-- ----------------------------
-- 4、角色信息表
-- ----------------------------
drop table if exists sys_role;
create table sys_role (
role_id int(10) not null auto_increment comment '角色ID',
role_name varchar(30) not null comment '角色名称',
role_key varchar(100) not null comment '角色权限字符串',
role_sort int(10) not null comment '显示顺序',
status int(1) default 0 comment '角色状态:0正常,1禁用',
create_by varchar(64) default '' comment '创建者',
create_time timestamp comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time timestamp comment '更新时间',
remark varchar(500) default '' comment '备注',
primary key (role_id)
) engine=innodb auto_increment=100 default charset=utf8 comment = '角色信息表';
-- ----------------------------
-- 初始化-角色信息表数据
-- ----------------------------
insert into sys_role values('1', '管理员', 'admin', 1, 0, 'admin', '2018-03-01', 'ry', '2018-03-01', '管理员');
insert into sys_role values('2', '普通角色', 'common', 2, 0, 'admin', '2018-03-01', 'ry', '2018-03-01', '普通角色');
-- ----------------------------
-- 5、菜单权限表
-- ----------------------------
drop table if exists sys_menu;
create table sys_menu (
menu_id int(11) not null auto_increment comment '菜单ID',
menu_name varchar(50) not null comment '菜单名称',
parent_id int(11) default 0 comment '父菜单ID',
order_num int(4) default null comment '显示顺序',
url varchar(200) default '' comment '请求地址',
menu_type char(1) default '' comment '类型:M目录,C菜单,F按钮',
visible int(1) default 0 comment '菜单状态:0显示,1隐藏',
perms varchar(100) default '' comment '权限标识',
icon varchar(100) default '' comment '菜单图标',
create_by varchar(64) default '' comment '创建者',
create_time timestamp comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time timestamp comment '更新时间',
remark varchar(500) default '' comment '备注',
primary key (menu_id)
) engine=innodb auto_increment=1000 default charset=utf8 comment = '菜单权限表';
-- ----------------------------
-- 初始化-菜单信息表数据
-- ----------------------------
-- 一级菜单
insert into sys_menu values('1', '系统管理', '0', '1', '#', 'M', '0', '', 'fa fa-gear', 'admin', '2018-03-01', 'ry', '2018-03-01', '系统管理目录');
insert into sys_menu values('2', '系统监控', '0', '2', '#', 'M', '0', '', 'fa fa-video-camera', 'admin', '2018-03-01', 'ry', '2018-03-01', '系统监控目录');
insert into sys_menu values('3', '系统工具', '0', '3', '#', 'M', '0', '', 'fa fa-bars', 'admin', '2018-03-01', 'ry', '2018-03-01', '系统工具目录');
-- 二级菜单
insert into sys_menu values('4', '用户管理', '1', '1', '/system/user', 'C', '0', 'system:user:view', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '用户管理菜单');
insert into sys_menu values('5', '角色管理', '1', '2', '/system/role', 'C', '0', 'system:role:view', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '角色管理菜单');
insert into sys_menu values('6', '菜单管理', '1', '3', '/system/menu', 'C', '0', 'system:menu:view', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '菜单管理菜单');
insert into sys_menu values('7', '部门管理', '1', '4', '/system/dept', 'C', '0', 'system:dept:view', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '部门管理菜单');
insert into sys_menu values('8', '岗位管理', '1', '5', '/system/post', 'C', '0', 'system:post:view', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '岗位管理菜单');
insert into sys_menu values('9', '字典管理', '1', '6', '/system/dict', 'C', '0', 'system:dict:view', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '字典管理菜单');
insert into sys_menu values('10', '参数设置', '1', '7', '/system/config', 'C', '0', 'system:config:view', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '参数设置菜单');
insert into sys_menu values('11', '操作日志', '2', '1', '/monitor/operlog', 'C', '0', 'monitor:operlog:view', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '操作日志菜单');
insert into sys_menu values('12', '登录日志', '2', '2', '/monitor/logininfor', 'C', '0', 'monitor:logininfor:view', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '登录日志菜单');
insert into sys_menu values('13', '在线用户', '2', '3', '/monitor/online', 'C', '0', 'monitor:online:view', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '在线用户菜单');
insert into sys_menu values('14', '定时任务', '2', '4', '/monitor/job', 'C', '0', 'monitor:job:view', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '定时任务菜单');
insert into sys_menu values('15', '数据监控', '2', '5', '/monitor/data', 'C', '0', 'monitor:data:view', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '数据监控菜单');
insert into sys_menu values('16', '表单构建', '3', '1', '/tool/build', 'C', '0', 'tool:build:view', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '表单构建菜单');
insert into sys_menu values('17', '代码生成', '3', '2', '/tool/gen', 'C', '0', 'tool:gen:view', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '代码生成菜单');
-- 用户管理按钮
insert into sys_menu values('18', '用户查询', '4', '1', '#', 'F', '0', 'system:user:list', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('19', '用户新增', '4', '2', '#', 'F', '0', 'system:user:add', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('20', '用户修改', '4', '3', '#', 'F', '0', 'system:user:edit', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('21', '用户删除', '4', '4', '#', 'F', '0', 'system:user:remove', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('22', '用户保存', '4', '5', '#', 'F', '0', 'system:user:save', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('23', '批量删除', '4', '6', '#', 'F', '0', 'system:user:batchRemove', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('24', '重置密码', '4', '7', '#', 'F', '0', 'system:user:resetPwd', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
-- 角色管理按钮
insert into sys_menu values('25', '角色查询', '5', '1', '#', 'F', '0', 'system:role:list', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('26', '角色新增', '5', '2', '#', 'F', '0', 'system:role:add', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('27', '角色修改', '5', '3', '#', 'F', '0', 'system:role:edit', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('28', '角色删除', '5', '4', '#', 'F', '0', 'system:role:remove', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('29', '角色保存', '5', '5', '#', 'F', '0', 'system:role:save', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('30', '批量删除', '5', '6', '#', 'F', '0', 'system:role:batchRemove', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
-- 菜单管理按钮
insert into sys_menu values('31', '菜单查询', '6', '1', '#', 'F', '0', 'system:menu:list', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('32', '菜单新增', '6', '2', '#', 'F', '0', 'system:menu:add', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('33', '菜单修改', '6', '3', '#', 'F', '0', 'system:menu:edit', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('34', '菜单删除', '6', '4', '#', 'F', '0', 'system:menu:remove', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('35', '菜单保存', '6', '5', '#', 'F', '0', 'system:menu:save', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
-- 部门管理按钮
insert into sys_menu values('36', '部门查询', '7', '1', '#', 'F', '0', 'system:dept:list', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('37', '部门新增', '7', '2', '#', 'F', '0', 'system:dept:add', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('38', '部门修改', '7', '3', '#', 'F', '0', 'system:dept:edit', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('39', '部门删除', '7', '4', '#', 'F', '0', 'system:dept:remove', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('40', '部门保存', '7', '5', '#', 'F', '0', 'system:dept:save', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
-- 岗位管理按钮
insert into sys_menu values('41', '岗位查询', '8', '1', '#', 'F', '0', 'system:post:list', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('42', '岗位新增', '8', '2', '#', 'F', '0', 'system:post:add', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('43', '岗位修改', '8', '3', '#', 'F', '0', 'system:post:edit', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('44', '岗位删除', '8', '4', '#', 'F', '0', 'system:post:remove', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('45', '岗位保存', '8', '5', '#', 'F', '0', 'system:post:save', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('46', '批量删除', '8', '6', '#', 'F', '0', 'system:post:batchRemove', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
-- 字典管理按钮
insert into sys_menu values('47', '字典查询', '9', '1', '#', 'F', '0', 'system:dict:list', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('48', '字典新增', '9', '2', '#', 'F', '0', 'system:dict:add', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('49', '字典修改', '9', '3', '#', 'F', '0', 'system:dict:edit', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('50', '字典删除', '9', '4', '#', 'F', '0', 'system:dict:remove', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('51', '字典保存', '9', '5', '#', 'F', '0', 'system:dict:save', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('52', '批量删除', '9', '6', '#', 'F', '0', 'system:dict:batchRemove', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
-- 操作日志按钮
insert into sys_menu values('53', '操作查询', '11', '1', '#', 'F', '0', 'monitor:operlog:list', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('54', '批量删除', '11', '2', '#', 'F', '0', 'monitor:operlog:batchRemove', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('55', '详细信息', '11', '3', '#', 'F', '0', 'monitor:operlog:detail', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
-- 登录日志按钮
insert into sys_menu values('56', '登录查询', '12', '1', '#', 'F', '0', 'monitor:logininfor:list', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('57', '批量删除', '12', '2', '#', 'F', '0', 'monitor:logininfor:batchRemove', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
-- 在线用户按钮
insert into sys_menu values('58', '在线查询', '13', '1', '#', 'F', '0', 'monitor:online:list', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('59', '批量强退', '13', '2', '#', 'F', '0', 'monitor:online:batchForceLogout', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('60', '单条强退', '13', '3', '#', 'F', '0', 'monitor:online:forceLogout', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
-- 定时任务按钮
insert into sys_menu values('61', '任务查询', '14', '1', '#', 'F', '0', 'monitor:job:list', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('62', '任务新增', '14', '2', '#', 'F', '0', 'monitor:job:add', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('63', '任务修改', '14', '3', '#', 'F', '0', 'monitor:job:edit', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('64', '任务删除', '14', '4', '#', 'F', '0', 'monitor:job:remove', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('65', '任务保存', '14', '5', '#', 'F', '0', 'monitor:job:save', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('66', '状态修改', '14', '6', '#', 'F', '0', 'monitor:job:changeStatus', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('67', '批量删除', '14', '7', '#', 'F', '0', 'monitor:job:batchRemove', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
-- 代码生成按钮
insert into sys_menu values('68', '生成查询', '16', '1', '#', 'F', '0', 'tool:gen:list', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_menu values('69', '生成代码', '16', '2', '#', 'F', '0', 'tool:gen:code', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '');
-- ----------------------------
-- 6、用户和角色关联表 用户N-1角色
-- ----------------------------
drop table if exists sys_user_role;
create table sys_user_role (
user_id int(11) not null comment '用户ID',
role_id int(11) not null comment '角色ID',
primary key(user_id, role_id)
) engine=innodb default charset=utf8 comment = '用户和角色关联表';
-- ----------------------------
-- 初始化-用户和角色关联表数据
-- ----------------------------
insert into sys_user_role values ('1', '1');
insert into sys_user_role values ('2', '2');
-- ----------------------------
-- 7、角色和菜单关联表 角色1-N菜单
-- ----------------------------
drop table if exists sys_role_menu;
create table sys_role_menu (
role_id int(11) not null comment '角色ID',
menu_id int(11) not null comment '菜单ID',
primary key(role_id, menu_id)
) engine=innodb default charset=utf8 comment = '角色和菜单关联表';
-- ----------------------------
-- 初始化-角色和菜单关联表数据
-- ----------------------------
insert into sys_role_menu values ('1', '1');
insert into sys_role_menu values ('1', '2');
insert into sys_role_menu values ('1', '3');
insert into sys_role_menu values ('1', '4');
insert into sys_role_menu values ('1', '5');
insert into sys_role_menu values ('1', '6');
insert into sys_role_menu values ('1', '7');
insert into sys_role_menu values ('1', '8');
insert into sys_role_menu values ('1', '9');
insert into sys_role_menu values ('1', '10');
insert into sys_role_menu values ('1', '11');
insert into sys_role_menu values ('1', '12');
insert into sys_role_menu values ('1', '13');
insert into sys_role_menu values ('1', '14');
insert into sys_role_menu values ('1', '15');
insert into sys_role_menu values ('1', '16');
insert into sys_role_menu values ('1', '17');
insert into sys_role_menu values ('1', '18');
insert into sys_role_menu values ('1', '19');
insert into sys_role_menu values ('1', '20');
insert into sys_role_menu values ('1', '21');
insert into sys_role_menu values ('1', '22');
insert into sys_role_menu values ('1', '23');
insert into sys_role_menu values ('1', '24');
insert into sys_role_menu values ('1', '25');
insert into sys_role_menu values ('1', '26');
insert into sys_role_menu values ('1', '27');
insert into sys_role_menu values ('1', '28');
insert into sys_role_menu values ('1', '29');
insert into sys_role_menu values ('1', '30');
insert into sys_role_menu values ('1', '31');
insert into sys_role_menu values ('1', '32');
insert into sys_role_menu values ('1', '33');
insert into sys_role_menu values ('1', '34');
insert into sys_role_menu values ('1', '35');
insert into sys_role_menu values ('1', '36');
insert into sys_role_menu values ('1', '37');
insert into sys_role_menu values ('1', '38');
insert into sys_role_menu values ('1', '39');
insert into sys_role_menu values ('1', '40');
insert into sys_role_menu values ('1', '41');
insert into sys_role_menu values ('1', '42');
insert into sys_role_menu values ('1', '43');
insert into sys_role_menu values ('1', '44');
insert into sys_role_menu values ('1', '45');
insert into sys_role_menu values ('1', '46');
insert into sys_role_menu values ('1', '47');
insert into sys_role_menu values ('1', '48');
insert into sys_role_menu values ('1', '49');
insert into sys_role_menu values ('1', '50');
insert into sys_role_menu values ('1', '51');
insert into sys_role_menu values ('1', '52');
insert into sys_role_menu values ('1', '53');
insert into sys_role_menu values ('1', '54');
insert into sys_role_menu values ('1', '55');
insert into sys_role_menu values ('1', '56');
insert into sys_role_menu values ('1', '57');
insert into sys_role_menu values ('1', '58');
insert into sys_role_menu values ('1', '59');
insert into sys_role_menu values ('1', '60');
insert into sys_role_menu values ('1', '61');
insert into sys_role_menu values ('1', '62');
insert into sys_role_menu values ('1', '63');
insert into sys_role_menu values ('1', '64');
insert into sys_role_menu values ('1', '65');
insert into sys_role_menu values ('1', '66');
insert into sys_role_menu values ('1', '67');
insert into sys_role_menu values ('1', '68');
insert into sys_role_menu values ('1', '69');
-- ----------------------------
-- 8、用户与岗位关联表 用户1-N岗位
-- ----------------------------
drop table if exists sys_user_post;
create table sys_user_post
(
user_id varchar(64) not null comment '用户ID',
post_id varchar(64) not null comment '岗位ID',
primary key (user_id, post_id)
) engine=innodb default charset=utf8 comment = '用户与岗位关联表';
-- ----------------------------
-- 初始化-用户与岗位关联表数据
-- ----------------------------
insert into sys_user_post values ('1', '1');
insert into sys_user_post values ('2', '2');
-- ----------------------------
-- 9、操作日志记录
-- ----------------------------
drop table if exists sys_oper_log;
create table sys_oper_log (
oper_id int(11) not null auto_increment comment '日志主键',
title varchar(50) default '' comment '模块标题',
action varchar(100) default '' comment '功能请求',
method varchar(100) default '' comment '方法名称',
channel varchar(20) default '' comment '来源渠道',
login_name varchar(50) default '' comment '登录账号',
dept_name varchar(50) default '' comment '部门名称',
oper_url varchar(255) default '' comment '请求URL',
oper_ip varchar(30) default '' comment '主机地址',
oper_param varchar(255) default '' comment '请求参数',
status int(1) default 0 comment '操作状态 0正常 1异常',
error_msg varchar(2000) default '' comment '错误消息',
oper_time timestamp comment '操作时间',
primary key (oper_id)
) engine=innodb auto_increment=100 default charset=utf8 comment = '操作日志记录';
insert into sys_oper_log values(1, '监控管理', '在线用户-强退用户', 'com.ruoyi.project.monitor.online.controller.UserOnlineController()', 'web', 'admin', '研发部门', 'delete.do?id=1', '127.0.0.1', 'JSON参数', 0, '错误描述', '2018-03-01');
-- ----------------------------
-- 10、字典类型表
-- ----------------------------
drop table if exists sys_dict_type;
create table sys_dict_type
(
dict_id int(11) not null auto_increment comment '字典主键',
dict_name varchar(100) default '' comment '字典名称',
dict_type varchar(100) default '' comment '字典类型',
status int(1) default 0 comment '状态0正常 1禁用',
create_by varchar(64) default '' comment '创建者',
create_time timestamp comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time timestamp comment '更新时间',
remark varchar(500) default '' comment '备注',
primary key (dict_id),
unique (dict_type)
) engine=innodb auto_increment=100 default charset=utf8 comment = '字典类型表';
insert into sys_dict_type values(1, '银行列表', 'sys_bank_code', 0, 'admin', '2018-03-01', 'ry', '2018-03-01', '银行数据列表');
insert into sys_dict_type values(2, '支付通道', 'sys_pay_code', 0, 'admin', '2018-03-01', 'ry', '2018-03-01', '支付通道列表');
-- ----------------------------
-- 11、字典数据表
-- ----------------------------
drop table if exists sys_dict_data;
create table sys_dict_data
(
dict_code int(11) not null auto_increment comment '字典编码',
dict_sort int(4) default 0 comment '字典排序',
dict_label varchar(100) default '' comment '字典标签',
dict_value varchar(100) default '' comment '字典键值',
dict_type varchar(100) default '' comment '字典类型',
status int(1) default 0 comment '状态0正常 1禁用',
create_by varchar(64) default '' comment '创建者',
create_time timestamp comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time timestamp comment '更新时间',
remark varchar(500) default '' comment '备注',
primary key (dict_code)
) engine=innodb auto_increment=100 default charset=utf8 comment = '字典数据表';
insert into sys_dict_data values(1, 1, '工商银行', '01', 'sys_bank_code', 0, 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_dict_data values(2, 2, '建设银行', '02', 'sys_bank_code', 0, 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_dict_data values(3, 3, '农业银行', '03', 'sys_bank_code', 0, 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_dict_data values(4, 4, '光大银行', '04', 'sys_bank_code', 0, 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_dict_data values(5, 5, '兴业银行', '05', 'sys_bank_code', 0, 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_dict_data values(6, 6, '中国银行', '06', 'sys_bank_code', 0, 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_dict_data values(7, 7, '平安银行', '07', 'sys_bank_code', 0, 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_dict_data values(8, 8, '招商银行', '08', 'sys_bank_code', 0, 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_dict_data values(9, 1, '微信支付', 'WX', 'sys_pay_code', 0, 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_dict_data values(10, 2, '支付宝', 'ZFB', 'sys_pay_code', 0, 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_dict_data values(11, 3, 'QQ支付', 'JD', 'sys_pay_code', 0, 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_dict_data values(12, 4, '京东支付', 'QQ', 'sys_pay_code', 0, 'admin', '2018-03-01', 'ry', '2018-03-01', '');
-- ----------------------------
-- 12、系统访问记录
-- ----------------------------
drop table if exists sys_logininfor;
create table sys_logininfor (
info_id int(11) not null auto_increment comment '访问ID',
login_name varchar(50) default '' comment '登录账号',
ipaddr varchar(50) default '' comment '登录IP地址',
browser varchar(50) default '' comment '浏览器类型',
os varchar(50) default '' comment '操作系统',
status int(1) default 0 comment '登录状态 0成功 1失败',
msg varchar(255) default '' comment '提示消息',
login_time timestamp comment '访问时间',
primary key (info_id)
) engine=innodb auto_increment=100 default charset=utf8 comment = '系统访问记录';
insert into sys_logininfor values(1, 'admin', '127.0.0.1', 'Chrome 45', 'Windows 7', 0, '登录成功' ,'2018-03-01');
-- ----------------------------
-- 13、在线用户记录
-- ----------------------------
drop table if exists sys_user_online;
create table sys_user_online (
sessionId varchar(50) default '' comment '用户会话id',
login_name varchar(50) default '' comment '登录账号',
dept_name varchar(50) default '' comment '部门名称',
ipaddr varchar(50) default '' comment '登录IP地址',
browser varchar(50) default '' comment '浏览器类型',
os varchar(50) default '' comment '操作系统',
status varchar(10) default '' comment '在线状态on_line在线off_line离线',
start_timestsamp timestamp comment 'session创建时间',
last_access_time timestamp comment 'session最后访问时间',
expire_time int(5) default 0 comment '超时时间,单位为分钟',
primary key (sessionId)
) engine=innodb default charset=utf8 comment = '在线用户记录';
insert into sys_user_online(sessionId, login_name, dept_name, ipaddr, browser, os, status, start_timestsamp, last_access_time)
values('c3b252c3-2229-4be4-a5f7-7aba4b0c314c', 'admin', '研发部门', '127.0.0.1', 'Chrome 45', 'Windows 7', 'on_line', '2018-03-01', '2018-03-01');
-- ----------------------------
-- 14、定时任务调度表
-- ----------------------------
drop table if exists sys_job;
create table sys_job (
job_id int(11) not null auto_increment comment '任务ID',
job_name varchar(64) default '' comment '任务名称',
job_group varchar(64) default '' comment '任务组名',
method_name varchar(500) default '' comment '任务方法',
params varchar(200) default '' comment '方法参数',
cron_expression varchar(255) default '' comment 'cron执行表达式',
status int(1) default 0 comment '状态0正常 1暂停',
create_by varchar(64) default '' comment '创建者',
create_time timestamp comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time timestamp comment '更新时间',
remark varchar(500) default '' comment '备注信息',
primary key (job_id, job_name, job_group)
) engine=innodb auto_increment=100 default charset=utf8 comment = '定时任务调度表';
insert into sys_job values(1, 'ryTask', '系统默认(无参)', 'ryNoParams', '', '0/10 * * * * ?', 1, 'admin', '2018-03-01', 'ry', '2018-03-01', '');
insert into sys_job values(2, 'ryTask', '系统默认(有参)', 'ryParams', 'ry', '0/20 * * * * ?', 1, 'admin', '2018-03-01', 'ry', '2018-03-01', '');
-- ----------------------------
-- 15、定时任务调度日志表
-- ----------------------------
drop table if exists sys_job_log;
create table sys_job_log (
job_log_id int(11) not null auto_increment comment '任务日志ID',
job_name varchar(64) not null comment '任务名称',
job_group varchar(64) not null comment '任务组名',
method_name varchar(500) comment '任务方法',
params varchar(200) default '' comment '方法参数',
job_message varchar(500) comment '日志信息',
is_exception int(1) default 0 comment '是否异常',
exception_info text comment '异常信息',
create_time timestamp comment '创建时间',
primary key (job_log_id)
) engine=innodb default charset=utf8 comment = '定时任务调度日志表';

225
pom.xml Normal file
View File

@ -0,0 +1,225 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ruoyi</groupId>
<artifactId>RuoYi</artifactId>
<version>1.1.1</version>
<packaging>jar</packaging>
<name>RuoYi</name>
<description>若依管理系统</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
<relativePath />
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<shiro.version>1.3.2</shiro.version>
<thymeleaf-extras-shiro.version>1.2.1</thymeleaf-extras-shiro.version>
<mybatis-spring-boot-starter.version>1.1.1</mybatis-spring-boot-starter.version>
<fastjson.version>1.2.31</fastjson.version>
<druid.version>1.0.28</druid.version>
<commons.lang3.version>3.6</commons.lang3.version>
<bitwalker.version>1.19</bitwalker.version>
<lombok.version>1.16.18</lombok.version>
<mybatisplus-spring-boot-starter.version>1.0.4</mybatisplus-spring-boot-starter.version>
<velocity.version>1.7</velocity.version>
<quartz.version>2.3.0</quartz.version>
</properties>
<dependencies>
<!-- SpringBoot 核心包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- SpringBoot 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- SpringBoot 拦截器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- SpringBoot Web容器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringBoot集成thymeleaf模板 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- thymeleaf网页解析 -->
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
</dependency>
<!-- Mysql驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- SpringBoot集成mybatis框架 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot-starter.version}</version>
</dependency>
<!-- pagehelper 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.3</version>
</dependency>
<!--阿里数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<!--常用工具类 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons.lang3.version}</version>
</dependency>
<!--io常用工具类 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<!--Shiro核心框架 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<!-- Shiro使用Srping框架 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<!-- Shiro使用EhCache缓存框架 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
<!-- thymeleaf模板引擎和shiro框架的整合 -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>${thymeleaf-extras-shiro.version}</version>
</dependency>
<!-- 阿里JSON解析器 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- 解析客户端操作系统、浏览器等 -->
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
<version>${bitwalker.version}</version>
</dependency>
<!--Spring框架基本的核心工具-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!-- 定时任务 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>${quartz.version}</version>
<exclusions>
<exclusion>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--velocity代码生成使用模板 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>${velocity.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>public</id>
<name>aliyun nexus</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>public</id>
<name>aliyun nexus</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>

View File

@ -0,0 +1,33 @@
package com.ruoyi;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
/**
* 启动程序
*
* @author ruoyi
*/
@SpringBootApplication
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class })
@MapperScan("com.ruoyi.project.*.*.dao")
public class RuoYiApplication
{
public static void main(String[] args)
{
SpringApplication.run(RuoYiApplication.class, args);
System.out.println("(♥◠‿◠)ノ゙ 若依启动成功 ლ(´ڡ`ლ)゙ \n" +
" .-------. ____ __ \n" +
" | _ _ \\ \\ \\ / / \n" +
" | ( ' ) | \\ _. / ' \n" +
" |(_ o _) / _( )_ .' \n" +
" | (_,_).' __ ___(_ o _)' \n" +
" | |\\ \\ | || |(_,_)' \n" +
" | | \\ `' /| `-' / \n" +
" | | \\ / \\ / \n" +
" ''-' `'-' `-..-' ");
}
}

View File

@ -0,0 +1,41 @@
package com.ruoyi.common.constant;
/**
* 通用常量信息
*
* @author ruoyi
*/
public class CommonConstant
{
/**
* 通用成功标识
*/
public static final String SUCCESS = "0";
/**
* 通用失败标识
*/
public static final String FAIL = "1";
/**
* 登录成功
*/
public static final String LOGIN_SUCCESS = "Success";
/**
* 注销
*/
public static final String LOGOUT = "Logout";
/**
* 登录失败
*/
public static final String LOGIN_FAIL = "Error";
/**
* 自动去除表前缀
*/
public static String AUTO_REOMVE_PRE = "true";
}

View File

@ -0,0 +1,46 @@
package com.ruoyi.common.constant;
import java.util.HashMap;
import java.util.Map;
/**
* 通用Map数据
*
* @author ruoyi
*/
public class CommonMap
{
/** 状态编码转换 */
public static Map<String, String> javaTypeMap = new HashMap<String, String>();
static
{
initJavaTypeMap();
}
/**
* 返回状态映射
*/
public static void initJavaTypeMap()
{
javaTypeMap.put("tinyint", "Integer");
javaTypeMap.put("smallint", "Integer");
javaTypeMap.put("mediumint", "Integer");
javaTypeMap.put("int", "Integer");
javaTypeMap.put("integer", "integer");
javaTypeMap.put("bigint", "Long");
javaTypeMap.put("float", "Float");
javaTypeMap.put("double", "Double");
javaTypeMap.put("decimal", "BigDecimal");
javaTypeMap.put("bit", "Boolean");
javaTypeMap.put("char", "String");
javaTypeMap.put("varchar", "String");
javaTypeMap.put("tinytext", "String");
javaTypeMap.put("text", "String");
javaTypeMap.put("mediumtext", "String");
javaTypeMap.put("longtext", "String");
javaTypeMap.put("date", "String");
javaTypeMap.put("datetime", "String");
javaTypeMap.put("timestamp", "String");
}
}

View File

@ -0,0 +1,39 @@
package com.ruoyi.common.constant;
/**
* 任务调度通用常量
*
* @author ruoyi
*/
public interface ScheduleConstants
{
/**
* 任务调度参数key
*/
public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY";
public enum Status
{
/**
* 正常
*/
NORMAL(0),
/**
* 暂停
*/
PAUSE(1);
private int value;
private Status(int value)
{
this.value = value;
}
public int getValue()
{
return value;
}
}
}

View File

@ -0,0 +1,40 @@
package com.ruoyi.common.constant;
/**
* Shiro通用常量
*
* @author ruoyi
*/
public interface ShiroConstants
{
/**
* 当前登录的用户
*/
public static final String CURRENT_USER = "currentUser";
/**
* 用户名
*/
public static final String CURRENT_USERNAME = "username";
/**
* 消息key
*/
public static String MESSAGE = "message";
/**
* 错误key
*/
public static String ERROR = "errorMsg";
/**
* 编码格式
*/
public static String ENCODING = "UTF-8";
/**
* 当前在线会话
*/
public String ONLINE_SESSION = "online_session";
}

View File

@ -0,0 +1,39 @@
package com.ruoyi.common.constant;
/**
* 用户常量信息
*
* @author ruoyi
*/
public class UserConstants
{
/** 正常状态 */
public static final int NORMAL = 0;
/** 异常状态 */
public static final int EXCEPTION = 1;
/** 用户封禁状态 */
public static final int USER_BLOCKED = 1;
/** 角色封禁状态 */
public static final int ROLE_BLOCKED = 1;
/**
* 用户名长度限制
*/
public static final int USERNAME_MIN_LENGTH = 2;
public static final int USERNAME_MAX_LENGTH = 10;
/** 名称是否唯一的返回结果码 */
public final static String NAME_UNIQUE = "0";
public final static String NAME_NOT_UNIQUE = "1";
/**
* 密码长度限制
*/
public static final int PASSWORD_MIN_LENGTH = 5;
public static final int PASSWORD_MAX_LENGTH = 20;
}

View File

@ -0,0 +1,105 @@
package com.ruoyi.common.exception.base;
import org.springframework.util.StringUtils;
import com.ruoyi.common.utils.MessageUtils;
/**
* 基础异常
*
* @author ruoyi
*/
public class BaseException extends RuntimeException
{
private static final long serialVersionUID = 1L;
/**
* 所属模块
*/
private String module;
/**
* 错误码
*/
private String code;
/**
* 错误码对应的参数
*/
private Object[] args;
/**
* 错误消息
*/
private String defaultMessage;
public BaseException(String module, String code, Object[] args, String defaultMessage)
{
this.module = module;
this.code = code;
this.args = args;
this.defaultMessage = defaultMessage;
}
public BaseException(String module, String code, Object[] args)
{
this(module, code, args, null);
}
public BaseException(String module, String defaultMessage)
{
this(module, null, null, defaultMessage);
}
public BaseException(String code, Object[] args)
{
this(null, code, args, null);
}
public BaseException(String defaultMessage)
{
this(null, null, null, defaultMessage);
}
@Override
public String getMessage()
{
String message = null;
if (!StringUtils.isEmpty(code))
{
message = MessageUtils.message(code, args);
}
if (message == null)
{
message = defaultMessage;
}
return message;
}
public String getModule()
{
return module;
}
public String getCode()
{
return code;
}
public Object[] getArgs()
{
return args;
}
public String getDefaultMessage()
{
return defaultMessage;
}
@Override
public String toString()
{
return this.getClass() + "{" + "module='" + module + '\'' + ", message='" + getMessage() + '\'' + '}';
}
}

View File

@ -0,0 +1,32 @@
package com.ruoyi.common.exception.base;
/**
* Dao异常
*
* @author ruoyi
*/
public class DaoException extends RuntimeException
{
private static final long serialVersionUID = 1L;
/**
* 错误消息
*/
private String defaultMessage;
public DaoException(String defaultMessage)
{
this.defaultMessage = defaultMessage;
}
public String getDefaultMessage()
{
return defaultMessage;
}
@Override
public String toString()
{
return this.getClass() + "{" + "message='" + getMessage() + '\'' + '}';
}
}

View File

@ -0,0 +1,18 @@
package com.ruoyi.common.exception.user;
/**
* 角色锁定异常类
*
* @author ruoyi
*/
public class RoleBlockedException extends UserException
{
private static final long serialVersionUID = 1L;
public RoleBlockedException(String reason)
{
super("role.blocked", new Object[] { reason });
}
}

View File

@ -0,0 +1,16 @@
package com.ruoyi.common.exception.user;
/**
* 用户锁定异常类
*
* @author ruoyi
*/
public class UserBlockedException extends UserException
{
private static final long serialVersionUID = 1L;
public UserBlockedException(String reason)
{
super("user.blocked", new Object[] { reason });
}
}

View File

@ -0,0 +1,20 @@
package com.ruoyi.common.exception.user;
import com.ruoyi.common.exception.base.BaseException;
/**
* 用户信息异常类
*
* @author ruoyi
*/
public class UserException extends BaseException
{
private static final long serialVersionUID = 1L;
public UserException(String code, Object[] args)
{
super("user", code, args, null);
}
}

View File

@ -0,0 +1,17 @@
package com.ruoyi.common.exception.user;
/**
* 用户不存在异常类
*
* @author ruoyi
*/
public class UserNotExistsException extends UserException
{
private static final long serialVersionUID = 1L;
public UserNotExistsException()
{
super("user.not.exists", null);
}
}

View File

@ -0,0 +1,17 @@
package com.ruoyi.common.exception.user;
/**
* 用户密码不正确或不符合规范异常类
*
* @author ruoyi
*/
public class UserPasswordNotMatchException extends UserException
{
private static final long serialVersionUID = 1L;
public UserPasswordNotMatchException()
{
super("user.password.not.match", null);
}
}

View File

@ -0,0 +1,16 @@
package com.ruoyi.common.exception.user;
/**
* 用户错误记数异常类
*
* @author ruoyi
*/
public class UserPasswordRetryLimitCountException extends UserException
{
private static final long serialVersionUID = 1L;
public UserPasswordRetryLimitCountException(int retryLimitCount, String password)
{
super("user.password.retry.limit.count", new Object[] { retryLimitCount, password });
}
}

View File

@ -0,0 +1,16 @@
package com.ruoyi.common.exception.user;
/**
* 用户错误最大次数异常类
*
* @author ruoyi
*/
public class UserPasswordRetryLimitExceedException extends UserException
{
private static final long serialVersionUID = 1L;
public UserPasswordRetryLimitExceedException(int retryLimitCount)
{
super("user.password.retry.limit.exceed", new Object[] { retryLimitCount });
}
}

View File

@ -0,0 +1,65 @@
package com.ruoyi.common.utils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 时间工具类
*
* @author ruoyi
*/
public class DateUtils
{
public static final String DEFAULT_YYYYMMDD = "yyyyMMddHHmmss";
public static final String DEFAULT_YYYY_MM_DD = "yyyy-MM-dd HH:mm:ss";
/**
* 获取当前日期, 默认格式为yyyy-MM-dd
*
* @return String
*/
public static String getDate()
{
return dateTimeNow("yyyy-MM-dd");
}
public static final String dateTimeStr()
{
return dateTimeNow(DEFAULT_YYYY_MM_DD);
}
public static final String dateTimeNow()
{
return dateTimeNow(DEFAULT_YYYYMMDD);
}
public static final String dateTimeNow(final String format)
{
return dateTime(format, new Date());
}
public static final String dateTime(final Date date)
{
return dateTime(DEFAULT_YYYYMMDD, date);
}
public static final String dateTime(final String format, final Date date)
{
return new SimpleDateFormat(format).format(date);
}
public static final Date dateTime(final String format, final String ts)
{
try
{
return new SimpleDateFormat(format).parse(ts);
}
catch (ParseException e)
{
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,42 @@
package com.ruoyi.common.utils;
import javax.servlet.http.HttpServletRequest;
/**
* 获取IP方法
*
* @author ruoyi
*/
public class IpUtils
{
public static String getIpAddr(HttpServletRequest request)
{
if (request == null)
{
return "unknown";
}
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getHeader("X-Forwarded-For");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getHeader("X-Real-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
{
ip = request.getRemoteAddr();
}
return ip;
}
}

View File

@ -0,0 +1,136 @@
package com.ruoyi.common.utils;
import com.alibaba.fastjson.JSON;
import org.apache.shiro.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Map;
/**
* 处理并记录日志文件
*
* @author ruoyi
*/
public class LogUtils
{
public static final Logger ERROR_LOG = LoggerFactory.getLogger("sys-error");
public static final Logger ACCESS_LOG = LoggerFactory.getLogger("sys-access");
/**
* 记录访问日志 [username][jsessionid][ip][accept][UserAgent][url][params][Referer]
*
* @param request
*/
public static void logAccess(HttpServletRequest request)
{
String username = getUsername();
String jsessionId = request.getRequestedSessionId();
String ip = IpUtils.getIpAddr(request);
String accept = request.getHeader("accept");
String userAgent = request.getHeader("User-Agent");
String url = request.getRequestURI();
String params = getParams(request);
StringBuilder s = new StringBuilder();
s.append(getBlock(username));
s.append(getBlock(jsessionId));
s.append(getBlock(ip));
s.append(getBlock(accept));
s.append(getBlock(userAgent));
s.append(getBlock(url));
s.append(getBlock(params));
s.append(getBlock(request.getHeader("Referer")));
getAccessLog().info(s.toString());
}
/**
* 记录异常错误 格式 [exception]
*
* @param message
* @param e
*/
public static void logError(String message, Throwable e)
{
String username = getUsername();
StringBuilder s = new StringBuilder();
s.append(getBlock("exception"));
s.append(getBlock(username));
s.append(getBlock(message));
ERROR_LOG.error(s.toString(), e);
}
/**
* 记录页面错误 错误日志记录 [page/eception][username][statusCode][errorMessage][servletName][uri][exceptionName][ip][exception]
*
* @param request
*/
public static void logPageError(HttpServletRequest request)
{
String username = getUsername();
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
String message = (String) request.getAttribute("javax.servlet.error.message");
String uri = (String) request.getAttribute("javax.servlet.error.request_uri");
Throwable t = (Throwable) request.getAttribute("javax.servlet.error.exception");
if (statusCode == null)
{
statusCode = 0;
}
StringBuilder s = new StringBuilder();
s.append(getBlock(t == null ? "page" : "exception"));
s.append(getBlock(username));
s.append(getBlock(statusCode));
s.append(getBlock(message));
s.append(getBlock(IpUtils.getIpAddr(request)));
s.append(getBlock(uri));
s.append(getBlock(request.getHeader("Referer")));
StringWriter sw = new StringWriter();
while (t != null)
{
t.printStackTrace(new PrintWriter(sw));
t = t.getCause();
}
s.append(getBlock(sw.toString()));
getErrorLog().error(s.toString());
}
public static String getBlock(Object msg)
{
if (msg == null)
{
msg = "";
}
return "[" + msg.toString() + "]";
}
protected static String getParams(HttpServletRequest request)
{
Map<String, String[]> params = request.getParameterMap();
return JSON.toJSONString(params);
}
protected static String getUsername()
{
return (String) SecurityUtils.getSubject().getPrincipal();
}
public static Logger getAccessLog()
{
return ACCESS_LOG;
}
public static Logger getErrorLog()
{
return ERROR_LOG;
}
}

View File

@ -0,0 +1,51 @@
package com.ruoyi.common.utils;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.http.HttpServletRequest;
/**
* Map通用处理方法
*
* @author ruoyi
*/
public class MapDataUtil
{
public static Map<String, Object> convertDataMap(HttpServletRequest request)
{
Map<String, String[]> properties = request.getParameterMap();
Map<String, Object> returnMap = new HashMap<String, Object>();
Iterator<?> entries = properties.entrySet().iterator();
Map.Entry<?, ?> entry;
String name = "";
String value = "";
while (entries.hasNext())
{
entry = (Entry<?, ?>) entries.next();
name = (String) entry.getKey();
Object valueObj = entry.getValue();
if (null == valueObj)
{
value = "";
}
else if (valueObj instanceof String[])
{
String[] values = (String[]) valueObj;
for (int i = 0; i < values.length; i++)
{
value = values[i] + ",";
}
value = value.substring(0, value.length() - 1);
}
else
{
value = valueObj.toString();
}
returnMap.put(name, value);
}
return returnMap;
}
}

View File

@ -0,0 +1,27 @@
package com.ruoyi.common.utils;
import org.springframework.context.MessageSource;
import com.ruoyi.common.utils.spring.SpringUtils;
/**
* 获取i18n资源文件
*
* @author ruoyi
*/
public class MessageUtils
{
/**
* 根据消息键和参数 获取消息 委托给spring messageSource
*
* @param code 消息键
* @param args 参数
* @return
*/
public static String message(String code, Object... args)
{
MessageSource messageSource = SpringUtils.getBean(MessageSource.class);
return messageSource.getMessage(code, args, null);
}
}

View File

@ -0,0 +1,54 @@
package com.ruoyi.common.utils;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
/**
* 客户端工具类
*
* @author ruoyi
*/
public class ServletUtils
{
/**
* 获取request对象
*/
public static HttpServletRequest getHttpServletRequest()
{
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
}
/**
* 是否是Ajax异步请求
*/
public static boolean isAjaxRequest(HttpServletRequest request)
{
String accept = request.getHeader("accept");
if (accept != null && accept.indexOf("application/json") != -1)
{
return true;
}
String xRequestedWith = request.getHeader("X-Requested-With");
if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1)
{
return true;
}
String uri = request.getRequestURI();
if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml"))
{
return true;
}
String ajax = request.getParameter("__ajax");
if (StringUtils.inStringIgnoreCase(ajax, "json", "xml"))
{
return true;
}
return false;
}
}

View File

@ -0,0 +1,301 @@
package com.ruoyi.common.utils;
import java.util.Collection;
import java.util.Map;
import org.apache.commons.lang.text.StrBuilder;
/**
* 字符串工具类
*
* @author ruoyi
*/
public class StringUtils
{
/** 空字符串 */
private static final String NULLSTR = "";
/**
* 获取参数不为空值
*
* @param value defaultValue 要判断的value
* @return value 返回值
*/
public static <T> T nvl(T value, T defaultValue)
{
return value != null ? value : defaultValue;
}
/**
* * 判断一个Collection是否为空 包含ListSetQueue
*
* @param coll 要判断的Collection
* @return true为空 false非空
*/
public static boolean isEmpty(Collection<?> coll)
{
return isNull(coll) || coll.isEmpty();
}
/**
* * 判断一个Collection是否非空包含ListSetQueue
*
* @param coll 要判断的Collection
* @return true非空 false
*/
public static boolean isNotEmpty(Collection<?> coll)
{
return !isEmpty(coll);
}
/**
* * 判断一个对象数组是否为空
*
* @param objects 要判断的对象数组
** @return true为空 false非空
*/
public static boolean isEmpty(Object[] objects)
{
return isNull(objects) || (objects.length == 0);
}
/**
* * 判断一个对象数组是否非空
*
* @param objects 要判断的对象数组
* @return true非空 false
*/
public static boolean isNotEmpty(Object[] objects)
{
return !isEmpty(objects);
}
/**
* * 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true为空 false非空
*/
public static boolean isEmpty(Map<?, ?> map)
{
return isNull(map) || map.isEmpty();
}
/**
* * 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true非空 false
*/
public static boolean isNotEmpty(Map<?, ?> map)
{
return !isEmpty(map);
}
/**
* * 判断一个字符串是否为空串
*
* @param str String
* @return true为空 false非空
*/
public static boolean isEmpty(String str)
{
return isNull(str) || NULLSTR.equals(str.trim());
}
/**
* * 判断一个字符串是否为非空串
*
* @param str String
* @return true非空串 false空串
*/
public static boolean isNotEmpty(String str)
{
return !isEmpty(str);
}
/**
* * 判断一个对象是否为空
*
* @param object Object
* @return true为空 false非空
*/
public static boolean isNull(Object object)
{
return object == null;
}
/**
* * 判断一个对象是否非空
*
* @param object Object
* @return true非空 false
*/
public static boolean isNotNull(Object object)
{
return !isNull(object);
}
/**
* * 判断一个对象是否是数组类型Java基本型别的数组
*
* @param object 对象
* @return true是数组 false不是数组
*/
public static boolean isArray(Object object)
{
return isNotNull(object) && object.getClass().isArray();
}
/**
* 去空格
*/
public static String trim(String str)
{
return (str == null ? "" : str.trim());
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @return 结果
*/
public static String substring(final String str, int start)
{
if (str == null)
{
return NULLSTR;
}
if (start < 0)
{
start = str.length() + start;
}
if (start < 0)
{
start = 0;
}
if (start > str.length())
{
return NULLSTR;
}
return str.substring(start);
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @param end 结束
* @return 结果
*/
public static String substring(final String str, int start, int end)
{
if (str == null)
{
return NULLSTR;
}
if (end < 0)
{
end = str.length() + end;
}
if (start < 0)
{
start = str.length() + start;
}
if (end > str.length())
{
end = str.length();
}
if (start > end)
{
return NULLSTR;
}
if (start < 0)
{
start = 0;
}
if (end < 0)
{
end = 0;
}
return str.substring(start, end);
}
public static String uncapitalize(String str)
{
int strLen;
if (str == null || (strLen = str.length()) == 0)
{
return str;
}
return new StrBuilder(strLen).append(Character.toLowerCase(str.charAt(0))).append(str.substring(1)).toString();
}
/**
* 是否包含字符串
*
* @param str 验证字符串
* @param strs 字符串组
* @return 包含返回true
*/
public static boolean inStringIgnoreCase(String str, String... strs)
{
if (str != null && strs != null)
{
for (String s : strs)
{
if (str.equalsIgnoreCase(trim(s)))
{
return true;
}
}
}
return false;
}
/**
* 将下划线大写方式命名的字符串转换为驼峰式如果转换前的下划线大写方式命名的字符串为空则返回空字符串 例如HELLO_WORLD->HelloWorld
*
* @param name 转换前的下划线大写方式命名的字符串
* @return 转换后的驼峰式命名的字符串
*/
public static String convertToCamelCase(String name)
{
StringBuilder result = new StringBuilder();
// 快速检查
if (name == null || name.isEmpty())
{
// 没必要转换
return "";
}
else if (!name.contains("_"))
{
// 不含下划线仅将首字母大写
return name.substring(0, 1).toUpperCase() + name.substring(1);
}
// 用下划线将原始字符串分割
String[] camels = name.split("_");
for (String camel : camels)
{
// 跳过原始字符串中开头结尾的下换线或双重下划线
if (camel.isEmpty())
{
continue;
}
// 首字母大写
result.append(camel.substring(0, 1).toUpperCase());
result.append(camel.substring(1).toLowerCase());
}
return result.toString();
}
}

View File

@ -0,0 +1,71 @@
package com.ruoyi.common.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.common.constant.CommonConstant;
import com.ruoyi.common.utils.security.ShiroUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.project.monitor.logininfor.domain.Logininfor;
import com.ruoyi.project.monitor.logininfor.service.LogininforServiceImpl;
import eu.bitwalker.useragentutils.UserAgent;
/**
* 记录用户日志信息
*
* @author ruoyi
*/
public class SystemLogUtils
{
private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user");
/**
* 记录格式 [ip][用户名][操作][错误消息]
* <p/>
* 注意操作如下 loginError 登录失败 loginSuccess 登录成功 passwordError 密码错误 changePassword 修改密码 changeStatus 修改状态
*
* @param username
* @param op
* @param msg
* @param args
*/
public static void log(String username, String status, String msg, Object... args)
{
StringBuilder s = new StringBuilder();
s.append(LogUtils.getBlock(ShiroUtils.getIp()));
s.append(LogUtils.getBlock(username));
s.append(LogUtils.getBlock(status));
s.append(LogUtils.getBlock(msg));
sys_user_logger.info(s.toString(), args);
if (CommonConstant.LOGIN_SUCCESS.equals(status) || CommonConstant.LOGOUT.equals(status))
{
saveOpLog(username, msg, CommonConstant.SUCCESS);
}
else if (CommonConstant.LOGIN_FAIL.equals(status))
{
saveOpLog(username, msg, CommonConstant.FAIL);
}
}
public static void saveOpLog(String username, String message, String status)
{
UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getHttpServletRequest().getHeader("User-Agent"));
// 获取客户端操作系统
String os = userAgent.getOperatingSystem().getName();
// 获取客户端浏览器
String browser = userAgent.getBrowser().getName();
LogininforServiceImpl logininforService = SpringUtils.getBean(LogininforServiceImpl.class);
Logininfor logininfor = new Logininfor();
logininfor.setLoginName(username);
logininfor.setStatus(status);
logininfor.setIpaddr(ShiroUtils.getIp());
logininfor.setBrowser(browser);
logininfor.setOs(os);
logininfor.setMsg(message);
logininforService.insertLogininfor(logininfor);
}
}

View File

@ -0,0 +1,145 @@
package com.ruoyi.common.utils;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.ruoyi.project.system.menu.domain.Menu;
/**
* 权限数据处理
*
* @author ruoyi
*/
public class TreeUtils
{
/**
* 根据父节点的ID获取所有子节点
*
* @param list 分类表
* @param typeId 传入的父节点ID
* @return String
*/
public static List<Menu> getChildPerms(List<Menu> list, int praentId)
{
List<Menu> returnList = new ArrayList<Menu>();
for (Iterator<Menu> iterator = list.iterator(); iterator.hasNext();)
{
Menu t = (Menu) iterator.next();
// 根据传入的某个父节点ID,遍历该父节点的所有子节点
if (t.getParentId() == praentId)
{
recursionFn(list, t);
returnList.add(t);
}
}
return returnList;
}
/**
* 递归列表
*
* @param list
* @param Menu
*/
private static void recursionFn(List<Menu> list, Menu t)
{
// 得到子节点列表
List<Menu> childList = getChildList(list, t);
t.setChildren(childList);
for (Menu tChild : childList)
{
if (hasChild(list, tChild))
{
// 判断是否有子节点
Iterator<Menu> it = childList.iterator();
while (it.hasNext())
{
Menu n = (Menu) it.next();
recursionFn(list, n);
}
}
}
}
/**
* 得到子节点列表
*/
private static List<Menu> getChildList(List<Menu> list, Menu t)
{
List<Menu> tlist = new ArrayList<Menu>();
Iterator<Menu> it = list.iterator();
while (it.hasNext())
{
Menu n = (Menu) it.next();
if (n.getParentId().longValue() == t.getMenuId().longValue())
{
tlist.add(n);
}
}
return tlist;
}
List<Menu> returnList = new ArrayList<Menu>();
/**
* 根据父节点的ID获取所有子节点
*
* @param list 分类表
* @param typeId 传入的父节点ID
* @param prefix 子节点前缀
*/
public List<Menu> getChildPerms(List<Menu> list, int typeId, String prefix)
{
if (list == null)
{
return null;
}
for (Iterator<Menu> iterator = list.iterator(); iterator.hasNext();)
{
Menu node = (Menu) iterator.next();
// 根据传入的某个父节点ID,遍历该父节点的所有子节点
if (node.getParentId() == typeId)
{
recursionFn(list, node, prefix);
}
// 遍历所有的父节点下的所有子节点
/*
* if (node.getParentId()==0) { recursionFn(list, node); }
*/
}
return returnList;
}
private void recursionFn(List<Menu> list, Menu node, String p)
{
// 得到子节点列表
List<Menu> childList = getChildList(list, node);
if (hasChild(list, node))
{
// 判断是否有子节点
returnList.add(node);
Iterator<Menu> it = childList.iterator();
while (it.hasNext())
{
Menu n = (Menu) it.next();
n.setMenuName(p + n.getMenuName());
recursionFn(list, n, p + p);
}
}
else
{
returnList.add(node);
}
}
/**
* 判断是否有子节点
*/
private static boolean hasChild(List<Menu> list, Menu t)
{
return getChildList(list, t).size() > 0 ? true : false;
}
}

View File

@ -0,0 +1,50 @@
package com.ruoyi.common.utils.security;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import com.ruoyi.project.system.user.domain.User;
/**
* shiro 工具类
*
* @author ruoyi
*/
public class ShiroUtils
{
public static Subject getSubjct()
{
return SecurityUtils.getSubject();
}
public static void logout()
{
getSubjct().logout();
}
public static User getUser()
{
return (User) getSubjct().getPrincipal();
}
public static Long getUserId()
{
return getUser().getUserId().longValue();
}
public static String getLoginName()
{
return getUser().getLoginName();
}
public static String getIp()
{
return getSubjct().getSession().getHost();
}
public static String getSessionId()
{
return String.valueOf(getSubjct().getSession().getId());
}
}

View File

@ -0,0 +1,102 @@
package com.ruoyi.common.utils.spring;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
/**
* spring工具类 方便在非spring管理环境中获取bean
*
* @author ruoyi
*/
@Component
public final class SpringUtils implements BeanFactoryPostProcessor
{
/** Spring应用上下文环境 */
private static ConfigurableListableBeanFactory beanFactory;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
{
SpringUtils.beanFactory = beanFactory;
}
/**
* 获取对象
*
* @param name
* @return Object 一个以所给名字注册的bean的实例
* @throws org.springframework.beans.BeansException
*
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) throws BeansException
{
return (T) beanFactory.getBean(name);
}
/**
* 获取类型为requiredType的对象
*
* @param clz
* @return
* @throws org.springframework.beans.BeansException
*
*/
public static <T> T getBean(Class<T> clz) throws BeansException
{
T result = (T) beanFactory.getBean(clz);
return result;
}
/**
* 如果BeanFactory包含一个与所给名称匹配的bean定义则返回true
*
* @param name
* @return boolean
*/
public static boolean containsBean(String name)
{
return beanFactory.containsBean(name);
}
/**
* 判断以给定名字注册的bean定义是一个singleton还是一个prototype 如果与给定名字相应的bean定义没有被找到将会抛出一个异常NoSuchBeanDefinitionException
*
* @param name
* @return boolean
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*
*/
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException
{
return beanFactory.isSingleton(name);
}
/**
* @param name
* @return Class 注册对象的类型
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*
*/
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException
{
return beanFactory.getType(name);
}
/**
* 如果给定的bean名字在bean定义中有别名则返回这些别名
*
* @param name
* @return
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
*
*/
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException
{
return beanFactory.getAliases(name);
}
}

View File

@ -0,0 +1,171 @@
package com.ruoyi.framework.aspectj;
import java.lang.reflect.Method;
import java.util.Map;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.security.ShiroUtils;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.project.monitor.operlog.domain.OperLog;
import com.ruoyi.project.monitor.operlog.service.IOperLogService;
import com.ruoyi.project.system.user.domain.User;
/**
* 操作日志记录处理
*
* @author ruoyi
*/
@Aspect
@Component
public class LogAspect
{
private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
@Autowired
private IOperLogService operLogService;
// 配置织入点
@Pointcut("@annotation(com.ruoyi.framework.aspectj.lang.annotation.Log)")
public void logPointCut()
{
}
/**
* 前置通知 用于拦截操作
*
* @param joinPoint 切点
*/
@AfterReturning(pointcut = "logPointCut()")
public void doBefore(JoinPoint joinPoint)
{
handleLog(joinPoint, null);
}
/**
* 拦截异常操作
*
* @param joinPoint
* @param e
*/
@AfterThrowing(value = "logPointCut()", throwing = "e")
public void doAfter(JoinPoint joinPoint, Exception e)
{
handleLog(joinPoint, e);
}
private void handleLog(JoinPoint joinPoint, Exception e)
{
try
{
// 获得注解
Log controllerLog = getAnnotationLog(joinPoint);
if (controllerLog == null)
{
return;
}
// 获取当前的用户
User currentUser = ShiroUtils.getUser();
// *========数据库日志=========*//
OperLog operLog = new OperLog();
operLog.setStatus(UserConstants.NORMAL);
// 请求的地址
String ip = ShiroUtils.getIp();
operLog.setOperIp(ip);
operLog.setOperUrl(ServletUtils.getHttpServletRequest().getRequestURI());
if (currentUser != null)
{
operLog.setLoginName(currentUser.getLoginName());
operLog.setDeptName(currentUser.getDept().getDeptName());
}
if (e != null)
{
operLog.setStatus(UserConstants.EXCEPTION);
operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
}
// 设置方法名称
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
operLog.setMethod(className + "." + methodName + "()");
// 处理设置注解上的参数
getControllerMethodDescription(controllerLog, operLog);
// 保存数据库
operLogService.insertOperlog(operLog);
}
catch (Exception exp)
{
// 记录本地异常日志
log.error("==前置通知异常==");
log.error("异常信息:{}", exp.getMessage());
exp.printStackTrace();
}
}
/**
* 获取注解中对方法的描述信息 用于Controller层注解
*
* @param joinPoint 切点
* @return 方法描述
* @throws Exception
*/
public static void getControllerMethodDescription(Log log, OperLog operLog) throws Exception
{
// 设置action动作
operLog.setAction(log.action());
// 设置标题
operLog.setTitle(log.title());
// 设置channel
operLog.setChannel(log.channel());
// 是否需要保存request参数和值
if (log.isSaveRequestData())
{
// 获取参数的信息传入到数据库中
setRequestValue(operLog);
}
}
/**
* 获取请求的参数放到log中
*
* @param operLog
* @param request
*/
private static void setRequestValue(OperLog operLog)
{
Map<String, String[]> map = ServletUtils.getHttpServletRequest().getParameterMap();
String params = JSONObject.toJSONString(map);
operLog.setOperParam(StringUtils.substring(params, 0, 255));
}
/**
* 是否存在注解如果存在就获取
*/
private static Log getAnnotationLog(JoinPoint joinPoint) throws Exception
{
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null)
{
return method.getAnnotation(Log.class);
}
return null;
}
}

View File

@ -0,0 +1,32 @@
package com.ruoyi.framework.aspectj.lang.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;
/**
* 自定义操作日志记录注解
*
* @author ruoyi
*
*/
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log
{
/** 模块 */
String title() default "";
/** 功能 */
String action() default "";
/** 渠道 */
String channel() default "web";
/** 是否保存请求的参数 */
boolean isSaveRequestData() default true;
}

View File

@ -0,0 +1,34 @@
package com.ruoyi.framework.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* 通用配置
*
* @author ruoyi
*/
@Configuration
public class BaseConfig extends WebMvcConfigurerAdapter
{
/**
* 首页地址
*/
@Value("${shiro.user.indexUrl}")
private String indexUrl;
/**
* 默认首页的设置当输入域名是可以自动跳转到默认指定的网页
*/
@Override
public void addViewControllers(ViewControllerRegistry registry)
{
registry.addViewController("/").setViewName("forward:" + indexUrl);
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
super.addViewControllers(registry);
}
}

View File

@ -0,0 +1,159 @@
package com.ruoyi.framework.config;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
/**
* Druid数据库信息配置加载
*
* @author ruoyi
*/
@Configuration
public class DruidConfig
{
private static final Logger log = LoggerFactory.getLogger(DruidConfig.class);
@Value("${spring.datasource.url}")
private String dbUrl;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.driverClassName}")
private String driverClassName;
@Value("${spring.datasource.initialSize}")
private int initialSize;
@Value("${spring.datasource.minIdle}")
private int minIdle;
@Value("${spring.datasource.maxActive}")
private int maxActive;
@Value("${spring.datasource.maxWait}")
private int maxWait;
@Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
private int timeBetweenEvictionRunsMillis;
@Value("${spring.datasource.minEvictableIdleTimeMillis}")
private int minEvictableIdleTimeMillis;
@Value("${spring.datasource.validationQuery}")
private String validationQuery;
@Value("${spring.datasource.testWhileIdle}")
private boolean testWhileIdle;
@Value("${spring.datasource.testOnBorrow}")
private boolean testOnBorrow;
@Value("${spring.datasource.testOnReturn}")
private boolean testOnReturn;
@Value("${spring.datasource.poolPreparedStatements}")
private boolean poolPreparedStatements;
@Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}")
private int maxPoolPreparedStatementPerConnectionSize;
@Value("${spring.datasource.filters}")
private String filters;
@Value("{spring.datasource.connectionProperties}")
private String connectionProperties;
@Bean(initMethod = "init", destroyMethod = "close") /** 声明其为Bean实例 */
@Primary /** 在同样的DataSource中首先使用被标注的DataSource */
public DataSource dataSource()
{
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(this.dbUrl);
datasource.setUsername(username);
datasource.setPassword(password);
datasource.setDriverClassName(driverClassName);
/** configuration */
datasource.setInitialSize(initialSize);
datasource.setMinIdle(minIdle);
datasource.setMaxActive(maxActive);
datasource.setMaxWait(maxWait);
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
datasource.setValidationQuery(validationQuery);
datasource.setTestWhileIdle(testWhileIdle);
datasource.setTestOnBorrow(testOnBorrow);
datasource.setTestOnReturn(testOnReturn);
datasource.setPoolPreparedStatements(poolPreparedStatements);
datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
try
{
datasource.setFilters(filters);
}
catch (SQLException e)
{
log.error("druid configuration initialization filter", e);
}
datasource.setConnectionProperties(connectionProperties);
return datasource;
}
/**
* 注册一个StatViewServlet 相当于在web.xml中声明了一个servlet
*/
@Bean
public ServletRegistrationBean druidServlet()
{
ServletRegistrationBean reg = new ServletRegistrationBean();
reg.setServlet(new StatViewServlet());
reg.addUrlMappings("/monitor/druid/*");
/** 白名单 */
// reg.addInitParameter("allow", "10.211.61.45,127.0.0.1,123.207.20.136");
/** IP黑名单(共同存在时deny优先于allow) */
// reg.addInitParameter("deny", "10.211.61.4");
/** 是否能够重置数据 禁用HTML页面上的“Reset All”功能 */
reg.addInitParameter("resetEnable", "false");
return reg;
}
/**
* 注册一个filterRegistrationBean 相当于在web.xml中声明了一个Filter
*/
@Bean
public FilterRegistrationBean filterRegistrationBean()
{
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
/** 添加过滤规则. */
filterRegistrationBean.addUrlPatterns("/*");
/** 监控选项滤器 */
filterRegistrationBean.addInitParameter("DruidWebStatFilter", "/*");
/** 添加不需要忽略的格式信息. */
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/monitor/druid/*");
/** 配置profileEnable能够监控单个url调用的sql列表 */
filterRegistrationBean.addInitParameter("profileEnable", "true");
/** 当前的cookie的用户 */
filterRegistrationBean.addInitParameter("principalCookieName", "USER_COOKIE");
/** 当前的session的用户 */
filterRegistrationBean.addInitParameter("principalSessionName", "USER_SESSION");
return filterRegistrationBean;
}
}

View File

@ -0,0 +1,71 @@
package com.ruoyi.framework.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 读取代码生成相关配置
*
* @author ruoyi
*/
@Component
@ConfigurationProperties(prefix = "gen")
public class GenConfig
{
/** 作者 */
public static String author;
/** 生成包路径 */
public static String packageName;
/** 自动去除表前缀默认是true */
public static String autoRemovePre;
/** 表前缀(类名不会包含表前缀) */
public static String tablePrefix;
public static String getAuthor()
{
return author;
}
public static void setAuthor(String author)
{
GenConfig.author = author;
}
public static String getPackageName()
{
return packageName;
}
public static void setPackageName(String packageName)
{
GenConfig.packageName = packageName;
}
public static String getAutoRemovePre()
{
return autoRemovePre;
}
public static void setAutoRemovePre(String autoRemovePre)
{
GenConfig.autoRemovePre = autoRemovePre;
}
public static String getTablePrefix()
{
return tablePrefix;
}
public static void setTablePrefix(String tablePrefix)
{
GenConfig.tablePrefix = tablePrefix;
}
@Override
public String toString()
{
return "GenConfig [getClass()=" + getClass() + ", hashCode()=" + hashCode() + ", toString()=" + super.toString()
+ "]";
}
}

View File

@ -0,0 +1,47 @@
package com.ruoyi.framework.config;
import java.util.Locale;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
/**
* 资源文件配置加载
*
* @author ruoyi
*/
@Configuration
@Component
public class I18nConfig extends WebMvcConfigurerAdapter
{
@Bean
public LocaleResolver localeResolver()
{
SessionLocaleResolver slr = new SessionLocaleResolver();
// 默认语言
slr.setDefaultLocale(Locale.SIMPLIFIED_CHINESE);
return slr;
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor()
{
LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
// 参数名
lci.setParamName("lang");
return lci;
}
@Override
public void addInterceptors(InterceptorRegistry registry)
{
registry.addInterceptor(localeChangeInterceptor());
}
}

View File

@ -0,0 +1,52 @@
package com.ruoyi.framework.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 读取项目相关配置
*
* @author ruoyi
*/
@Component
@ConfigurationProperties(prefix = "ruoyi")
public class RuoYiConfig
{
/** 项目名称 */
private String name;
/** 版本 */
private String version;
/** 版权年份 */
private String copyrightYear;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getVersion()
{
return version;
}
public void setVersion(String version)
{
this.version = version;
}
public String getCopyrightYear()
{
return copyrightYear;
}
public void setCopyrightYear(String copyrightYear)
{
this.copyrightYear = copyrightYear;
}
}

View File

@ -0,0 +1,56 @@
package com.ruoyi.framework.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import javax.sql.DataSource;
import java.util.Properties;
/**
* 定时任务配置
*
* @author ruoyi
*
*/
@Configuration
public class ScheduleConfig
{
@Bean
public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource)
{
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setDataSource(dataSource);
// quartz参数
Properties prop = new Properties();
prop.put("org.quartz.scheduler.instanceName", "RuoyiScheduler");
prop.put("org.quartz.scheduler.instanceId", "AUTO");
// 线程池配置
prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
prop.put("org.quartz.threadPool.threadCount", "20");
prop.put("org.quartz.threadPool.threadPriority", "5");
// JobStore配置
prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
// 集群配置
prop.put("org.quartz.jobStore.isClustered", "true");
prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1");
prop.put("org.quartz.jobStore.misfireThreshold", "12000");
prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
factory.setQuartzProperties(prop);
factory.setSchedulerName("RuoyiScheduler");
// 延时启动
factory.setStartupDelay(1);
factory.setApplicationContextSchedulerContextKey("applicationContextKey");
// 可选QuartzScheduler
// 启动时更新己存在的Job这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
factory.setOverwriteExistingJobs(true);
// 设置自动启动默认为true
factory.setAutoStartup(true);
return factory;
}
}

View File

@ -0,0 +1,283 @@
package com.ruoyi.framework.config;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.Filter;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.ruoyi.framework.shiro.realm.UserRealm;
import com.ruoyi.framework.shiro.session.OnlineSessionDAO;
import com.ruoyi.framework.shiro.session.OnlineSessionFactory;
import com.ruoyi.framework.shiro.web.filter.LogoutFilter;
import com.ruoyi.framework.shiro.web.filter.online.OnlineSessionFilter;
import com.ruoyi.framework.shiro.web.filter.sync.SyncOnlineSessionFilter;
import com.ruoyi.framework.shiro.web.session.OnlineWebSessionManager;
import com.ruoyi.framework.shiro.web.session.SpringSessionValidationScheduler;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
/**
* 权限配置加载
*
* @author ruoyi
*/
@Configuration
public class ShiroConfig
{
public static final String PREMISSION_STRING = "perms[\"{0}\"]";
// Session超时时间单位为毫秒默认30分钟
@Value("${shiro.session.expireTime}")
private int expireTime;
// 相隔多久检查一次session的有效性单位毫秒默认就是10分钟
@Value("${shiro.session.validationInterval}")
private int validationInterval;
// 登录地址
@Value("${shiro.user.loginUrl}")
private String loginUrl;
// 权限认证失败地址
@Value("${shiro.user.unauthorizedUrl}")
private String unauthorizedUrl;
/**
* 缓存管理器 使用Ehcache实现
*/
@Bean
public EhCacheManager getEhCacheManager()
{
EhCacheManager em = new EhCacheManager();
em.setCacheManagerConfigFile("classpath:ehcache/ehcache-shiro.xml");
return em;
}
/**
* 自定义Realm
*/
@Bean
public UserRealm userRealm(EhCacheManager cacheManager)
{
UserRealm userRealm = new UserRealm();
userRealm.setCacheManager(cacheManager);
return userRealm;
}
/**
* 自定义sessionDAO会话
*/
@Bean
public OnlineSessionDAO sessionDAO()
{
OnlineSessionDAO sessionDAO = new OnlineSessionDAO();
return sessionDAO;
}
/**
* 自定义sessionFactory会话
*/
@Bean
public OnlineSessionFactory sessionFactory()
{
OnlineSessionFactory sessionFactory = new OnlineSessionFactory();
return sessionFactory;
}
/**
* 自定义sessionFactory调度器
*/
@Bean
public SpringSessionValidationScheduler sessionValidationScheduler()
{
SpringSessionValidationScheduler sessionValidationScheduler = new SpringSessionValidationScheduler();
// 相隔多久检查一次session的有效性单位毫秒默认就是10分钟
sessionValidationScheduler.setSessionValidationInterval(validationInterval * 60 * 1000);
// 设置会话验证调度器进行会话验证时的会话管理器
sessionValidationScheduler.setSessionManager(sessionValidationManager());
return sessionValidationScheduler;
}
/**
* 会话管理器
*/
@Bean
public OnlineWebSessionManager sessionValidationManager()
{
OnlineWebSessionManager manager = new OnlineWebSessionManager();
// 加入缓存管理器
manager.setCacheManager(getEhCacheManager());
// 删除过期的session
manager.setDeleteInvalidSessions(true);
// 设置全局session超时时间
manager.setGlobalSessionTimeout(expireTime * 60 * 1000);
// 是否定时检查session
manager.setSessionValidationSchedulerEnabled(true);
// 自定义SessionDao
manager.setSessionDAO(sessionDAO());
// 自定义sessionFactory
manager.setSessionFactory(sessionFactory());
return manager;
}
/**
* 会话管理器
*/
@Bean
public OnlineWebSessionManager sessionManager()
{
OnlineWebSessionManager manager = new OnlineWebSessionManager();
// 加入缓存管理器
manager.setCacheManager(getEhCacheManager());
// 删除过期的session
manager.setDeleteInvalidSessions(true);
// 设置全局session超时时间
manager.setGlobalSessionTimeout(expireTime * 60 * 1000);
// 定义要使用的无效的Session定时调度器
manager.setSessionValidationScheduler(sessionValidationScheduler());
// 是否定时检查session
manager.setSessionValidationSchedulerEnabled(true);
// 自定义SessionDao
manager.setSessionDAO(sessionDAO());
// 自定义sessionFactory
manager.setSessionFactory(sessionFactory());
return manager;
}
/**
* 安全管理器
*/
@Bean
public SecurityManager securityManager(UserRealm userRealm)
{
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 设置realm.
securityManager.setRealm(userRealm);
// 注入缓存管理器;
securityManager.setCacheManager(getEhCacheManager());
// session管理器
securityManager.setSessionManager(sessionManager());
return securityManager;
}
/**
* 退出过滤器
*/
public LogoutFilter logoutFilter()
{
LogoutFilter logoutFilter = new LogoutFilter();
logoutFilter.setLoginUrl(loginUrl);
return logoutFilter;
}
/**
* Shiro过滤器配置
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager)
{
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// Shiro的核心安全接口,这个属性是必须的
shiroFilterFactoryBean.setSecurityManager(securityManager);
// 身份认证失败则跳转到登录页面的配置
shiroFilterFactoryBean.setLoginUrl(loginUrl);
// 权限认证失败则跳转到指定页面
shiroFilterFactoryBean.setUnauthorizedUrl(unauthorizedUrl);
// Shiro连接约束配置即过滤链的定义
LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
// 对静态资源设置匿名访问
filterChainDefinitionMap.put("/favicon.ico**", "anon");
filterChainDefinitionMap.put("/ruoyi.png**", "anon");
filterChainDefinitionMap.put("/css/**", "anon");
filterChainDefinitionMap.put("/docs/**", "anon");
filterChainDefinitionMap.put("/fonts/**", "anon");
filterChainDefinitionMap.put("/img/**", "anon");
filterChainDefinitionMap.put("/js/**", "anon");
filterChainDefinitionMap.put("/ajax/**", "anon");
filterChainDefinitionMap.put("/ruoyi/**", "anon");
filterChainDefinitionMap.put("/druid/**", "anon");
// 不需要拦截的访问
filterChainDefinitionMap.put("/login", "anon");
// 退出 logout地址shiro去清除session
filterChainDefinitionMap.put("/logout", "logout");
// 系统权限列表
// filterChainDefinitionMap.putAll(SpringUtils.getBean(IMenuService.class).selectPermsAll());
Map<String, Filter> filters = new LinkedHashMap<>();
filters.put("onlineSession", onlineSessionFilter());
filters.put("syncOnlineSession", syncOnlineSessionFilter());
// 注销成功则跳转到指定页面
filters.put("logout", logoutFilter());
shiroFilterFactoryBean.setFilters(filters);
// 所有请求需要认证
filterChainDefinitionMap.put("/**", "authc");
// 系统请求记录当前会话
filterChainDefinitionMap.put("/main", "onlineSession,syncOnlineSession");
filterChainDefinitionMap.put("/system/**", "onlineSession,syncOnlineSession");
filterChainDefinitionMap.put("/monitor/**", "onlineSession,syncOnlineSession");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
/**
* 自定义在线用户处理过滤器
*/
@Bean
public OnlineSessionFilter onlineSessionFilter()
{
OnlineSessionFilter onlineSessionFilter = new OnlineSessionFilter();
onlineSessionFilter.setLoginUrl(loginUrl);
return onlineSessionFilter;
}
/**
* 自定义在线用户同步过滤器
*/
@Bean
public SyncOnlineSessionFilter syncOnlineSessionFilter()
{
SyncOnlineSessionFilter syncOnlineSessionFilter = new SyncOnlineSessionFilter();
return syncOnlineSessionFilter;
}
/**
* 开启Shiro代理
*/
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator()
{
DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
proxyCreator.setProxyTargetClass(true);
return proxyCreator;
}
/**
* thymeleaf模板引擎和shiro框架的整合
*/
@Bean
public ShiroDialect shiroDialect()
{
return new ShiroDialect();
}
/**
* 开启Shiro注解通知器
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
@Qualifier("securityManager") SecurityManager securityManager)
{
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}

View File

@ -0,0 +1,265 @@
package com.ruoyi.framework.mybatis;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;
import javax.xml.bind.PropertyException;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.executor.statement.BaseStatementHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
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.reflection.MetaObject;
import org.apache.ibatis.reflection.property.PropertyTokenizer;
import org.apache.ibatis.scripting.xmltags.ForEachSqlNode;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.web.page.PageUtilEntity;
/**
* 拦截需要分页SQL
*
* @author ruoyi
*/
@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class, Integer.class }) })
public class ExecutorPageMethodInterceptor implements Interceptor
{
private static String dialect = ""; // 数据库方言
private static String pageSqlId = ""; // mapper.xml中需要拦截的ID(正则匹配)
@Override
public Object intercept(Invocation ivk) throws Throwable
{
// TODO Auto-generated method stub
if (ivk.getTarget() instanceof RoutingStatementHandler)
{
RoutingStatementHandler statementHandler = (RoutingStatementHandler) ivk.getTarget();
BaseStatementHandler delegate = (BaseStatementHandler) ReflectHelper.getValueByFieldName(statementHandler,
"delegate");
MappedStatement mappedStatement = (MappedStatement) ReflectHelper.getValueByFieldName(delegate,
"mappedStatement");
if (mappedStatement.getId().matches(pageSqlId))
{ // 拦截需要分页的SQL
BoundSql boundSql = delegate.getBoundSql();
Object parameterObject = boundSql.getParameterObject();// 分页SQL<select>中parameterType属性对应的实体参数即Mapper接口中执行分页方法的参数,该参数不得为空
if (parameterObject == null)
{
throw new NullPointerException("parameterObject尚未实例化");
}
else
{
Connection connection = (Connection) ivk.getArgs()[0];
String sql = boundSql.getSql();
// String countSql = "select count(0) from (" + sql+ ") as tmp_count"; //记录统计
String countSql = "select count(0) from (" + sql + ") tmp_count"; // 记录统计 == oracle as 报错(SQL
// command not properly ended)
PreparedStatement countStmt = connection.prepareStatement(countSql);
BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(), countSql,
boundSql.getParameterMappings(), parameterObject);
setParameters(countStmt, mappedStatement, countBS, parameterObject);
ResultSet rs = countStmt.executeQuery();
int count = 0;
if (rs.next())
{
count = rs.getInt(1);
}
rs.close();
countStmt.close();
// System.out.println(count);
PageUtilEntity pageUtilEntity = null;
if (parameterObject instanceof PageUtilEntity)
{
// 参数就是Page实体
pageUtilEntity = (PageUtilEntity) parameterObject;
pageUtilEntity.setEntityOrField(true);
pageUtilEntity.setTotalResult(count);
}
else
{
// 参数为某个实体该实体拥有Page属性
Field pageField = ReflectHelper.getFieldByFieldName(parameterObject, "PageUtilEntity");
if (pageField != null)
{
pageUtilEntity = (PageUtilEntity) ReflectHelper.getValueByFieldName(parameterObject, "PageUtilEntity");
if (pageUtilEntity == null)
{
pageUtilEntity = new PageUtilEntity();
}
pageUtilEntity.setEntityOrField(false);
pageUtilEntity.setTotalResult(count);
ReflectHelper.setValueByFieldName(parameterObject, "PageUtilEntity", pageUtilEntity); // 通过反射对实体对象设置分页对象
}
else
{
throw new NoSuchFieldException(
parameterObject.getClass().getName() + "不存在 pageUtilEntity 属性!");
}
}
String pageSql = generatePageSql(sql, pageUtilEntity);
ReflectHelper.setValueByFieldName(boundSql, "sql", pageSql); // 将分页sql语句反射回BoundSql.
}
}
}
return ivk.proceed();
}
/**
* 对SQL参数(?)设值,参考org.apache.ibatis.executor.parameter.DefaultParameterHandler
*
* @param ps
* @param mappedStatement
* @param boundSql
* @param parameterObject
* @throws SQLException
*/
@SuppressWarnings("unchecked")
private void setParameters(PreparedStatement ps, MappedStatement mappedStatement, BoundSql boundSql,
Object parameterObject) throws SQLException
{
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null)
{
Configuration configuration = mappedStatement.getConfiguration();
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
MetaObject metaObject = parameterObject == null ? null : configuration.newMetaObject(parameterObject);
for (int i = 0; i < parameterMappings.size(); i++)
{
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT)
{
Object value;
String propertyName = parameterMapping.getProperty();
PropertyTokenizer prop = new PropertyTokenizer(propertyName);
if (parameterObject == null)
{
value = null;
}
else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass()))
{
value = parameterObject;
}
else if (boundSql.hasAdditionalParameter(propertyName))
{
value = boundSql.getAdditionalParameter(propertyName);
}
else if (propertyName.startsWith(ForEachSqlNode.ITEM_PREFIX)
&& boundSql.hasAdditionalParameter(prop.getName()))
{
value = boundSql.getAdditionalParameter(prop.getName());
if (value != null)
{
value = configuration.newMetaObject(value)
.getValue(propertyName.substring(prop.getName().length()));
}
}
else
{
value = metaObject == null ? null : metaObject.getValue(propertyName);
}
@SuppressWarnings("rawtypes")
TypeHandler typeHandler = parameterMapping.getTypeHandler();
if (typeHandler == null)
{
throw new ExecutorException("There was no TypeHandler found for parameter " + propertyName
+ " of statement " + mappedStatement.getId());
}
typeHandler.setParameter(ps, i + 1, value, parameterMapping.getJdbcType());
}
}
}
}
/**
* 根据数据库方言生成特定的分页sql
*
* @param sql
* @param page
* @return
*/
private String generatePageSql(String sql, PageUtilEntity pageUtilEntity)
{
if (pageUtilEntity != null && StringUtils.isNotEmpty(dialect))
{
StringBuffer pageSql = new StringBuffer();
if ("mysql".equals(dialect))
{
pageSql.append(sql);
if(StringUtils.isNotEmpty(pageUtilEntity.getOrderByColumn()))
{
pageSql.append(" order by " + pageUtilEntity.getOrderByColumn() + " " + pageUtilEntity.getIsAsc());
}
pageSql.append(" limit " + pageUtilEntity.getPage() + "," + pageUtilEntity.getSize());
}
else if ("oracle".equals(dialect))
{
pageSql.append("select * from (select tmp_tb.*,ROWNUM row_id from (");
pageSql.append(sql);
// pageSql.append(") as tmp_tb where ROWNUM<=");
pageSql.append(") tmp_tb where ROWNUM<=");
pageSql.append(pageUtilEntity.getPage() + pageUtilEntity.getSize());
pageSql.append(") where row_id>");
pageSql.append(pageUtilEntity.getPage());
}
return pageSql.toString();
}
else
{
return sql;
}
}
@Override
public Object plugin(Object arg0)
{
return Plugin.wrap(arg0, this);
}
@Override
public void setProperties(Properties p)
{
dialect = p.getProperty("dialect");
if (StringUtils.isEmpty(dialect))
{
try
{
throw new PropertyException("dialect property is not found!");
}
catch (PropertyException e)
{
e.printStackTrace();
}
}
pageSqlId = p.getProperty("pageSqlId");
if (StringUtils.isEmpty(pageSqlId))
{
try
{
throw new PropertyException("pageSqlId property is not found!");
}
catch (PropertyException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

View File

@ -0,0 +1,92 @@
package com.ruoyi.framework.mybatis;
import java.lang.reflect.Field;
/**
* 拦截需要分页SQL 反射工具
*
* @author ruoyi
*/
public class ReflectHelper
{
/**
* 获取obj对象fieldName的Field
*
* @param obj
* @param fieldName
* @return
*/
public static Field getFieldByFieldName(Object obj, String fieldName)
{
for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass())
{
try
{
return superClass.getDeclaredField(fieldName);
}
catch (NoSuchFieldException e)
{
}
}
return null;
}
/**
* 获取obj对象fieldName的属性值
*
* @param obj
* @param fieldName
* @return
* @throws SecurityException
* @throws NoSuchFieldException
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
public static Object getValueByFieldName(Object obj, String fieldName)
throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException
{
Field field = getFieldByFieldName(obj, fieldName);
Object value = null;
if (field != null)
{
if (field.isAccessible())
{
value = field.get(obj);
}
else
{
field.setAccessible(true);
value = field.get(obj);
field.setAccessible(false);
}
}
return value;
}
/**
* 设置obj对象fieldName的属性值
*
* @param obj
* @param fieldName
* @param value
* @throws SecurityException
* @throws NoSuchFieldException
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
public static void setValueByFieldName(Object obj, String fieldName, Object value)
throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException
{
Field field = obj.getClass().getDeclaredField(fieldName);
if (field.isAccessible())
{
field.set(obj, value);
}
else
{
field.setAccessible(true);
field.set(obj, value);
field.setAccessible(false);
}
}
}

View File

@ -0,0 +1,111 @@
package com.ruoyi.framework.shiro.realm;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.ruoyi.common.exception.user.RoleBlockedException;
import com.ruoyi.common.exception.user.UserBlockedException;
import com.ruoyi.common.exception.user.UserNotExistsException;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.exception.user.UserPasswordRetryLimitExceedException;
import com.ruoyi.common.utils.security.ShiroUtils;
import com.ruoyi.framework.shiro.service.LoginService;
import com.ruoyi.project.system.menu.service.IMenuService;
import com.ruoyi.project.system.role.service.IRoleService;
import com.ruoyi.project.system.user.domain.User;
/**
* 自定义Realm 处理登录 权限
*
* @author ruoyi
*/
public class UserRealm extends AuthorizingRealm
{
private static final Logger log = LoggerFactory.getLogger(UserRealm.class);
@Autowired
private IMenuService menuService;
@Autowired
private IRoleService roleService;
@Autowired
private LoginService loginService;
/**
* 授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0)
{
Long userId = ShiroUtils.getUserId();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// 角色加入AuthorizationInfo认证对象
info.setRoles(roleService.selectRoleKeys(userId));
// 权限加入AuthorizationInfo认证对象
info.setStringPermissions(menuService.selectPermsByUserId(userId));
return info;
}
/**
* 登录认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException
{
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String username = upToken.getUsername();
String password = "";
if (upToken.getPassword() != null)
{
password = new String(upToken.getPassword());
}
User user = null;
try
{
user = loginService.login(username, password);
}
catch (UserNotExistsException e)
{
throw new UnknownAccountException(e.getMessage(), e);
}
catch (UserPasswordNotMatchException e)
{
throw new IncorrectCredentialsException(e.getMessage(), e);
}
catch (UserPasswordRetryLimitExceedException e)
{
throw new ExcessiveAttemptsException(e.getMessage(), e);
}
catch (UserBlockedException e)
{
throw new LockedAccountException(e.getMessage(), e);
}
catch (RoleBlockedException e)
{
throw new LockedAccountException(e.getMessage(), e);
}
catch (Exception e)
{
log.info("对用户[" + username + "]进行登录验证..验证未通过{}", e.getMessage());
throw new AuthenticationException(e.getMessage(), e);
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
return info;
}
}

View File

@ -0,0 +1,78 @@
package com.ruoyi.framework.shiro.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import com.ruoyi.common.constant.CommonConstant;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.exception.user.UserBlockedException;
import com.ruoyi.common.exception.user.UserNotExistsException;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.SystemLogUtils;
import com.ruoyi.project.system.user.domain.User;
import com.ruoyi.project.system.user.service.IUserService;
/**
* 登录校验方法
*
* @author ruoyi
*/
@Component
public class LoginService
{
@Autowired
private PasswordService passwordService;
@Autowired
private IUserService userService;
/**
* 登录
*/
public User login(String username, String password)
{
// 用户名或密码为空 错误
if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password))
{
SystemLogUtils.log(username, CommonConstant.LOGIN_FAIL, MessageUtils.message("not.null"));
throw new UserNotExistsException();
}
// 密码如果不在指定范围内 错误
if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
|| password.length() > UserConstants.PASSWORD_MAX_LENGTH)
{
SystemLogUtils.log(username, CommonConstant.LOGIN_FAIL, MessageUtils.message("user.password.not.match"));
throw new UserPasswordNotMatchException();
}
// 用户名不在指定范围内 错误
if (username.length() < UserConstants.USERNAME_MIN_LENGTH
|| username.length() > UserConstants.USERNAME_MAX_LENGTH)
{
SystemLogUtils.log(username, CommonConstant.LOGIN_FAIL, MessageUtils.message("user.password.not.match"));
throw new UserPasswordNotMatchException();
}
// 查询用户信息
User user = userService.selectUserByName(username);
if (user == null)
{
SystemLogUtils.log(username, CommonConstant.LOGIN_FAIL, MessageUtils.message("user.not.exists"));
throw new UserNotExistsException();
}
passwordService.validate(user, password);
if (UserConstants.USER_BLOCKED == user.getStatus())
{
SystemLogUtils.log(username, CommonConstant.LOGIN_FAIL, MessageUtils.message("user.blocked", user.getRefuseDes()));
throw new UserBlockedException(user.getRefuseDes());
}
SystemLogUtils.log(username, CommonConstant.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
return user;
}
}

View File

@ -0,0 +1,91 @@
package com.ruoyi.framework.shiro.service;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.PostConstruct;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.ruoyi.common.constant.CommonConstant;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.exception.user.UserPasswordRetryLimitExceedException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.SystemLogUtils;
import com.ruoyi.project.system.user.domain.User;
/**
* 登录密码方法
*
* @author ruoyi
*/
@Component
public class PasswordService
{
@Autowired
private CacheManager cacheManager;
private Cache<String, AtomicInteger> loginRecordCache;
@Value(value = "${user.password.maxRetryCount}")
private String maxRetryCount;
@PostConstruct
public void init()
{
loginRecordCache = cacheManager.getCache("loginRecordCache");
}
public void validate(User user, String password)
{
String loginName = user.getLoginName();
AtomicInteger retryCount = loginRecordCache.get(loginName);
if (retryCount == null)
{
retryCount = new AtomicInteger(0);
loginRecordCache.put(loginName, retryCount);
}
if (retryCount.incrementAndGet() > Integer.valueOf(maxRetryCount).intValue())
{
SystemLogUtils.log(loginName, CommonConstant.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.exceed", maxRetryCount));
throw new UserPasswordRetryLimitExceedException(Integer.valueOf(maxRetryCount).intValue());
}
if (!matches(user, password))
{
SystemLogUtils.log(loginName, CommonConstant.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.count", retryCount, password));
loginRecordCache.put(loginName, retryCount);
throw new UserPasswordNotMatchException();
}
else
{
clearLoginRecordCache(loginName);
}
}
public boolean matches(User user, String newPassword)
{
return user.getPassword().equals(encryptPassword(user.getLoginName(), newPassword, user.getSalt()));
}
public void clearLoginRecordCache(String username)
{
loginRecordCache.remove(username);
}
public String encryptPassword(String username, String password, String salt)
{
return new Md5Hash(username + password + salt).toHex().toString();
}
public static void main(String[] args)
{
System.out.println(new PasswordService().encryptPassword("admin", "admin123", "111111"));
System.out.println(new PasswordService().encryptPassword("ry", "admin123", "222222"));
}
}

View File

@ -0,0 +1,31 @@
package com.ruoyi.framework.shiro.service;
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Component;
/**
* RuoYi首创 js调用 thymeleaf 实现按钮权限可见性
*
* @author ruoyi
*/
@Component
public class PermissionService
{
public String hasPermi(String permission)
{
return isPermittedOperator(permission) ? "" : "hidden";
}
private boolean isPermittedOperator(String permission)
{
if (SecurityUtils.getSubject().isPermitted(permission))
{
return true;
}
else
{
return false;
}
}
}

View File

@ -0,0 +1,115 @@
package com.ruoyi.framework.shiro.session;
import java.io.Serializable;
import java.util.Date;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import com.ruoyi.project.monitor.online.domain.OnlineSession;
import com.ruoyi.project.monitor.online.domain.UserOnline;
import com.ruoyi.project.monitor.online.service.IUserOnlineService;
/**
* 针对自定义的ShiroSession的db操作
*
* @author ruoyi
*/
public class OnlineSessionDAO extends EnterpriseCacheSessionDAO
{
/**
* 同步session到数据库的周期 单位为毫秒默认1分钟
*/
@Value("${shiro.session.dbSyncPeriod}")
private int dbSyncPeriod;
/**
* 上次同步数据库的时间戳
*/
private static final String LAST_SYNC_DB_TIMESTAMP = OnlineSessionDAO.class.getName() + "LAST_SYNC_DB_TIMESTAMP";
@Autowired
private IUserOnlineService onlineService;
@Autowired
private OnlineSessionFactory onlineSessionFactory;
public OnlineSessionDAO()
{
super();
}
public OnlineSessionDAO(long expireTime)
{
super();
}
/**
* 根据会话ID获取会话
*
* @param sessionId 会话ID
* @return ShiroSession
*/
@Override
protected Session doReadSession(Serializable sessionId)
{
UserOnline userOnline = onlineService.selectOnlineById(String.valueOf(sessionId));
if (userOnline == null)
{
return null;
}
return onlineSessionFactory.createSession(userOnline);
}
/**
* 更新会话如更新会话最后访问时间/停止会话/设置超时时间/设置移除属性等会调用
*/
public void syncToDb(OnlineSession onlineSession)
{
Date lastSyncTimestamp = (Date) onlineSession.getAttribute(LAST_SYNC_DB_TIMESTAMP);
if (lastSyncTimestamp != null)
{
boolean needSync = true;
long deltaTime = onlineSession.getLastAccessTime().getTime() - lastSyncTimestamp.getTime();
if (deltaTime < dbSyncPeriod * 60 * 1000)
{
// 时间差不足 无需同步
needSync = false;
}
boolean isGuest = onlineSession.getUserId() == null || onlineSession.getUserId() == 0L;
// session 数据变更了 同步
if (isGuest == false && onlineSession.isAttributeChanged())
{
needSync = true;
}
if (needSync == false)
{
return;
}
}
onlineSession.setAttribute(LAST_SYNC_DB_TIMESTAMP, onlineSession.getLastAccessTime());
// 更新完后 重置标识
if (onlineSession.isAttributeChanged())
{
onlineSession.resetAttributeChanged();
}
onlineService.saveOnline(UserOnline.fromOnlineSession(onlineSession));
}
/**
* 当会话过期/停止如用户退出时属性等会调用
*/
@Override
protected void doDelete(Session session)
{
OnlineSession onlineSession = (OnlineSession) session;
if (null == onlineSession)
{
return;
}
onlineSession.setStatus(OnlineSession.OnlineStatus.off_line);
onlineService.deleteOnlineById(String.valueOf(onlineSession.getId()));
}
}

View File

@ -0,0 +1,58 @@
package com.ruoyi.framework.shiro.session;
import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.SessionContext;
import org.apache.shiro.session.mgt.SessionFactory;
import org.apache.shiro.web.session.mgt.WebSessionContext;
import org.springframework.stereotype.Component;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.IpUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.project.monitor.online.domain.OnlineSession;
import com.ruoyi.project.monitor.online.domain.UserOnline;
import eu.bitwalker.useragentutils.UserAgent;
/**
* 自定义sessionFactory会话
*
* @author ruoyi
*/
@Component
public class OnlineSessionFactory implements SessionFactory
{
public Session createSession(UserOnline userOnline)
{
OnlineSession onlineSession = userOnline.getSession();
if (StringUtils.isNotNull(onlineSession) && onlineSession.getId() == null)
{
onlineSession.setId(userOnline.getSessionId());
}
return userOnline.getSession();
}
@Override
public Session createSession(SessionContext initData)
{
OnlineSession session = new OnlineSession();
if (initData != null && initData instanceof WebSessionContext)
{
WebSessionContext sessionContext = (WebSessionContext) initData;
HttpServletRequest request = (HttpServletRequest) sessionContext.getServletRequest();
if (request != null)
{
UserAgent userAgent = UserAgent
.parseUserAgentString(ServletUtils.getHttpServletRequest().getHeader("User-Agent"));
// 获取客户端操作系统
String os = userAgent.getOperatingSystem().getName();
// 获取客户端浏览器
String browser = userAgent.getBrowser().getName();
session.setHost(IpUtils.getIpAddr(request));
session.setBrowser(browser);
session.setOs(os);
}
}
return session;
}
}

View File

@ -0,0 +1,86 @@
package com.ruoyi.framework.shiro.web.filter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.shiro.session.SessionException;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.common.constant.CommonConstant;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.SystemLogUtils;
import com.ruoyi.common.utils.security.ShiroUtils;
import com.ruoyi.project.system.user.domain.User;
/**
* 退出过滤器
*
* @author ruoyi
*/
public class LogoutFilter extends org.apache.shiro.web.filter.authc.LogoutFilter
{
private static final Logger log = LoggerFactory.getLogger(LogoutFilter.class);
/**
* 退出后重定向的地址
*/
private String loginUrl;
public String getLoginUrl()
{
return loginUrl;
}
public void setLoginUrl(String loginUrl)
{
this.loginUrl = loginUrl;
}
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception
{
try
{
Subject subject = getSubject(request, response);
String redirectUrl = getRedirectUrl(request, response, subject);
try
{
User user = (User) ShiroUtils.getSubjct().getPrincipal();
if (StringUtils.isNotNull(user))
{
String loginName = user.getLoginName();
// 记录用户退出日志
SystemLogUtils.log(loginName, CommonConstant.LOGOUT, MessageUtils.message("user.logout.success"));
}
// 退出登录
subject.logout();
}
catch (SessionException ise)
{
log.error("logout fail.", ise);
}
issueRedirect(request, response, redirectUrl);
}
catch (Exception e)
{
log.debug("Encountered session exception during logout. This can generally safely be ignored.", e);
}
return false;
}
/**
* 退出跳转URL
*/
@Override
protected String getRedirectUrl(ServletRequest request, ServletResponse response, Subject subject)
{
String url = getLoginUrl();
if (StringUtils.isNotEmpty(url))
{
return url;
}
return super.getRedirectUrl(request, response, subject);
}
}

View File

@ -0,0 +1,97 @@
package com.ruoyi.framework.shiro.web.filter.online;
import java.io.IOException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import com.ruoyi.common.constant.ShiroConstants;
import com.ruoyi.common.utils.security.ShiroUtils;
import com.ruoyi.framework.shiro.session.OnlineSessionDAO;
import com.ruoyi.project.monitor.online.domain.OnlineSession;
import com.ruoyi.project.system.user.domain.User;
/**
* 自定义访问控制
*
* @author ruoyi
*/
public class OnlineSessionFilter extends AccessControlFilter
{
/**
* 强制退出后重定向的地址
*/
@Value("${shiro.user.loginUrl}")
private String loginUrl;
@Autowired
private OnlineSessionDAO onlineSessionDAO;
/**
* 表示是否允许访问mappedValue就是[urls]配置中拦截器参数部分如果允许访问返回true否则false
*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
throws Exception
{
Subject subject = getSubject(request, response);
if (subject == null || subject.getSession() == null)
{
return true;
}
Session session = onlineSessionDAO.readSession(subject.getSession().getId());
if (session != null && session instanceof OnlineSession)
{
OnlineSession onlineSession = (OnlineSession) session;
request.setAttribute(ShiroConstants.ONLINE_SESSION, onlineSession);
// 把user对象设置进去
boolean isGuest = onlineSession.getUserId() == null || onlineSession.getUserId() == 0L;
if (isGuest == true)
{
User user = ShiroUtils.getUser();
if (user != null)
{
onlineSession.setUserId(user.getUserId());
onlineSession.setLoginName(user.getLoginName());
onlineSession.setDeptName(user.getDept().getDeptName());
onlineSession.markAttributeChanged();
}
}
if (onlineSession.getStatus() == OnlineSession.OnlineStatus.off_line)
{
return false;
}
}
return true;
}
/**
* 表示当访问拒绝时是否已经处理了如果返回true表示需要继续处理如果返回false表示该拦截器实例已经处理了将直接返回即可
*/
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception
{
Subject subject = getSubject(request, response);
if (subject != null)
{
subject.logout();
}
saveRequestAndRedirectToLogin(request, response);
return true;
}
// 跳转到登录页
@Override
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException
{
WebUtils.issueRedirect(request, response, loginUrl);
}
}

View File

@ -0,0 +1,42 @@
package com.ruoyi.framework.shiro.web.filter.sync;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.shiro.web.filter.PathMatchingFilter;
import org.springframework.beans.factory.annotation.Autowired;
import com.ruoyi.common.constant.ShiroConstants;
import com.ruoyi.framework.shiro.session.OnlineSessionDAO;
import com.ruoyi.project.monitor.online.domain.OnlineSession;
/**
* 同步Session数据到Db
*
* @author ruoyi
*/
public class SyncOnlineSessionFilter extends PathMatchingFilter
{
@Autowired
private OnlineSessionDAO onlineSessionDAO;
/**
* 同步会话数据到DB 一次请求最多同步一次 防止过多处理 需要放到Shiro过滤器之前
*
* @param request
* @param response
* @return
* @throws Exception
*/
@Override
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception
{
OnlineSession session = (OnlineSession) request.getAttribute(ShiroConstants.ONLINE_SESSION);
// 如果session stop了 也不同步
// session停止时间如果stopTimestamp不为null则代表已停止
if (session != null && session.getUserId() != null && session.getStopTimestamp() == null)
{
onlineSessionDAO.syncToDb(session);
}
return true;
}
}

View File

@ -0,0 +1,155 @@
package com.ruoyi.framework.shiro.web.session;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.shiro.session.ExpiredSessionException;
import org.apache.shiro.session.InvalidSessionException;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.DefaultSessionKey;
import org.apache.shiro.session.mgt.SessionKey;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.common.constant.ShiroConstants;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.project.monitor.online.domain.OnlineSession;
import com.ruoyi.project.monitor.online.domain.UserOnline;
import com.ruoyi.project.monitor.online.service.UserOnlineServiceImpl;
/**
* 主要是在此如果会话的属性修改了 就标识下其修改了 然后方便 OnlineSessionDao同步
*
* @author ruoyi
*/
public class OnlineWebSessionManager extends DefaultWebSessionManager
{
private static final Logger log = LoggerFactory.getLogger(OnlineWebSessionManager.class);
@Override
public void setAttribute(SessionKey sessionKey, Object attributeKey, Object value) throws InvalidSessionException
{
super.setAttribute(sessionKey, attributeKey, value);
if (value != null && needMarkAttributeChanged(attributeKey))
{
OnlineSession s = (OnlineSession) doGetSession(sessionKey);
s.markAttributeChanged();
}
}
private boolean needMarkAttributeChanged(Object attributeKey)
{
if (attributeKey == null)
{
return false;
}
String attributeKeyStr = attributeKey.toString();
// 优化 flash属性没必要持久化
if (attributeKeyStr.startsWith("org.springframework"))
{
return false;
}
if (attributeKeyStr.startsWith("javax.servlet"))
{
return false;
}
if (attributeKeyStr.equals(ShiroConstants.CURRENT_USERNAME))
{
return false;
}
return true;
}
@Override
public Object removeAttribute(SessionKey sessionKey, Object attributeKey) throws InvalidSessionException
{
Object removed = super.removeAttribute(sessionKey, attributeKey);
if (removed != null)
{
OnlineSession s = (OnlineSession) doGetSession(sessionKey);
s.markAttributeChanged();
}
return removed;
}
/**
* 验证session是否有效 用于删除过期session
*/
@Override
public void validateSessions()
{
if (log.isInfoEnabled())
{
log.info("invalidation sessions...");
}
int invalidCount = 0;
int timeout = (int) this.getGlobalSessionTimeout();
Date expiredDate = DateUtils.addMilliseconds(new Date(), 0 - timeout);
UserOnlineServiceImpl userOnlineService = SpringUtils.getBean(UserOnlineServiceImpl.class);
List<UserOnline> userOnlineList = userOnlineService.selectOnlineByExpired(expiredDate);
// 批量过期删除
List<String> needOfflineIdList = new ArrayList<String>();
for (UserOnline userOnline : userOnlineList)
{
try
{
SessionKey key = new DefaultSessionKey(userOnline.getSessionId());
Session session = retrieveSession(key);
if (session != null)
{
throw new InvalidSessionException();
}
}
catch (InvalidSessionException e)
{
if (log.isDebugEnabled())
{
boolean expired = (e instanceof ExpiredSessionException);
String msg = "Invalidated session with id [" + userOnline.getSessionId() + "]"
+ (expired ? " (expired)" : " (stopped)");
log.debug(msg);
}
invalidCount++;
needOfflineIdList.add(userOnline.getSessionId());
}
}
if (needOfflineIdList.size() > 0)
{
try
{
userOnlineService.batchDeleteOnline(needOfflineIdList);
}
catch (Exception e)
{
log.error("batch delete db session error.", e);
}
}
if (log.isInfoEnabled())
{
String msg = "Finished invalidation session.";
if (invalidCount > 0)
{
msg += " [" + invalidCount + "] sessions were stopped.";
}
else
{
msg += " No sessions were stopped.";
}
log.info(msg);
}
}
@Override
protected Collection<Session> getActiveSessions()
{
throw new UnsupportedOperationException("getActiveSessions method not supported");
}
}

View File

@ -0,0 +1,141 @@
package com.ruoyi.framework.shiro.web.session;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.apache.shiro.session.mgt.DefaultSessionManager;
import org.apache.shiro.session.mgt.SessionValidationScheduler;
import org.apache.shiro.session.mgt.ValidatingSessionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 自定义任务调度器完成
*
* @author ruoyi
*/
public class SpringSessionValidationScheduler implements SessionValidationScheduler
{
private static final Logger log = LoggerFactory.getLogger(SpringSessionValidationScheduler.class);
public static final long DEFAULT_SESSION_VALIDATION_INTERVAL = DefaultSessionManager.DEFAULT_SESSION_VALIDATION_INTERVAL;
/**
* 定时器用于处理超时的挂起请求也用于连接断开时的重连
*/
private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
private volatile boolean enabled = false;
/**
* The session manager used to validate sessions.
*/
private ValidatingSessionManager sessionManager;
/**
* The session validation interval in milliseconds.
*/
private long sessionValidationInterval = DEFAULT_SESSION_VALIDATION_INTERVAL;
/**
* Default constructor.
*/
public SpringSessionValidationScheduler()
{
}
/**
* Constructor that specifies the session manager that should be used for validating sessions.
*
* @param sessionManager the <tt>SessionManager</tt> that should be used to validate sessions.
*/
public SpringSessionValidationScheduler(ValidatingSessionManager sessionManager)
{
this.sessionManager = sessionManager;
}
public void setSessionManager(ValidatingSessionManager sessionManager)
{
this.sessionManager = sessionManager;
}
@Override
public boolean isEnabled()
{
return this.enabled;
}
/**
* Specifies how frequently (in milliseconds) this Scheduler will call the
* {@link org.apache.shiro.session.mgt.ValidatingSessionManager#validateSessions()
* ValidatingSessionManager#validateSessions()} method.
*
* <p>
* Unless this method is called, the default value is {@link #DEFAULT_SESSION_VALIDATION_INTERVAL}.
*
* @param sessionValidationInterval
*/
public void setSessionValidationInterval(long sessionValidationInterval)
{
this.sessionValidationInterval = sessionValidationInterval;
}
/**
* Starts session validation by creating a spring PeriodicTrigger.
*/
@Override
public void enableSessionValidation()
{
enabled = true;
if (log.isDebugEnabled())
{
log.debug("Scheduling session validation job using Spring Scheduler with "
+ "session validation interval of [" + sessionValidationInterval + "]ms...");
}
try
{
executorService.scheduleAtFixedRate(new Runnable()
{
@Override
public void run()
{
if (enabled)
{
sessionManager.validateSessions();
}
}
}, 1000, sessionValidationInterval, TimeUnit.MILLISECONDS);
this.enabled = true;
if (log.isDebugEnabled())
{
log.debug("Session validation job successfully scheduled with Spring Scheduler.");
}
}
catch (Exception e)
{
if (log.isErrorEnabled())
{
log.error(
"Error starting the Spring Scheduler session validation job. Session validation may not occur.",
e);
}
}
}
@Override
public void disableSessionValidation()
{
if (log.isDebugEnabled())
{
log.debug("Stopping Spring Scheduler session validation job...");
}
this.enabled = false;
}
}

View File

@ -0,0 +1,71 @@
package com.ruoyi.framework.web.controller;
import java.util.List;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.security.ShiroUtils;
import com.ruoyi.framework.web.page.PageDomain;
import com.ruoyi.framework.web.page.PageUtilEntity;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.framework.web.support.TableSupport;
import com.ruoyi.project.system.user.domain.User;
/**
* web层通用数据处理
*
* @author ruoyi
*/
public class BaseController
{
/**
* 获取请求分页数据
*/
public PageUtilEntity getPageUtilEntity()
{
PageUtilEntity pageUtilEntity = TableSupport.buildPageRequest();
return pageUtilEntity;
}
/**
* 设置请求分页数据
*/
protected void setPageInfo(Object obj)
{
PageDomain page = (PageDomain) obj;
if (StringUtils.isNotEmpty(page.getPageNum()) && StringUtils.isNotEmpty(page.getPageSize()))
{
int pageNum = Integer.valueOf(page.getPageNum());
int pageSize = Integer.valueOf(page.getPageSize());
String orderBy = page.getOrderBy();
PageHelper.startPage(pageNum, pageSize, orderBy);
}
}
/**
* 响应请求分页数据
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
protected TableDataInfo getDataTable(List<?> list)
{
TableDataInfo rspData = new TableDataInfo();
rspData.setRows(list);
rspData.setTotal(new PageInfo(list).getTotal());
return rspData;
}
public User getUser()
{
return ShiroUtils.getUser();
}
public Long getUserId()
{
return getUser().getUserId();
}
public String getLoginName()
{
return getUser().getLoginName();
}
}

View File

@ -0,0 +1,207 @@
package com.ruoyi.framework.web.dao;
import java.util.List;
import javax.annotation.Resource;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import com.ruoyi.framework.web.page.PageUtilEntity;
import com.ruoyi.framework.web.page.TableDataInfo;
/**
* 数据DAO层通用数据处理
*
* @author ruoyi
*/
public class DynamicObjectBaseDao
{
@Resource(name = "sqlSessionTemplate")
private SqlSessionTemplate sqlSessionTemplate;
/**
* 保存对象
*
* @param str mapper 节点
* @param obj 对象
* @return 结果
* @throws Exception
*/
public int save(String str, Object obj)
{
return sqlSessionTemplate.insert(str, obj);
}
/**
* 批量更新
*
* @param str mapper 节点
* @param obj 对象
* @return 结果
* @throws Exception
*/
public int batchSave(String str, List<?> objs)
{
return sqlSessionTemplate.insert(str, objs);
}
/**
* 修改对象
*
* @param str mapper 节点
* @param obj 对象
* @return 结果
* @throws Exception
*/
public int update(String str, Object obj)
{
return sqlSessionTemplate.update(str, obj);
}
/**
* 批量更新
*
* @param str mapper 节点
* @param obj 对象
* @return 结果
* @throws Exception
*/
public void batchUpdate(String str, List<?> objs) throws Exception
{
SqlSessionFactory sqlSessionFactory = sqlSessionTemplate.getSqlSessionFactory();
// 批量执行器
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
try
{
if (objs != null)
{
for (int i = 0, size = objs.size(); i < size; i++)
{
sqlSession.update(str, objs.get(i));
}
sqlSession.flushStatements();
sqlSession.commit();
sqlSession.clearCache();
}
}
finally
{
sqlSession.close();
}
}
/**
* 批量删除 根据对象
*
* @param str mapper 节点
* @param obj 对象
* @return 结果
* @throws Exception
*/
public int batchDelete(String str, List<?> objs) throws Exception
{
return sqlSessionTemplate.delete(str, objs);
}
/**
* 批量删除 根据数组
*
* @param str mapper 节点
* @param obj 对象
* @return 结果
* @throws Exception
*/
public int batchDelete(String str, Long[] objs)
{
return sqlSessionTemplate.delete(str, objs);
}
/**
* 删除对象
*
* @param str mapper 节点
* @param obj 对象
* @return 结果
* @throws Exception
*/
public int delete(String str, Object obj)
{
return sqlSessionTemplate.delete(str, obj);
}
/**
* 查找单条对象
*
* @param str mapper 节点
* @param obj 对象
* @return 结果
* @throws Exception
*/
public <T> T findForObject(String str, Object obj)
{
return sqlSessionTemplate.selectOne(str, obj);
}
/**
* 查找总数
*
* @param str mapper 节点
* @param obj 对象
* @return 结果
* @throws Exception
*/
public int count(String str, Object obj)
{
return sqlSessionTemplate.selectOne(str, obj);
}
/**
* 查找对象 - 无条件
*
* @param str mapper 节点
* @param obj 对象
* @return 结果
* @throws Exception
*/
public <E> List<E> findForList(String str)
{
return sqlSessionTemplate.selectList(str);
}
/**
* 查找对象 - 有条件
*
* @param str mapper 节点
* @param obj 对象
* @return 结果
* @throws Exception
*/
public <E> List<E> findForList(String str, Object obj)
{
return sqlSessionTemplate.selectList(str, obj);
}
/**
* 自定义分页方法
*
* @param str mapper 节点
* @param obj 对象
* @return 结果
* @throws Exception
*/
public TableDataInfo findForList(String str, PageUtilEntity pageUtilEntity)
{
List<?> pageList = sqlSessionTemplate.selectList(str, pageUtilEntity);
TableDataInfo tableDataInfo = new TableDataInfo(pageList, pageUtilEntity.getTotalResult());
return tableDataInfo;
}
public Object findForMap(String str, Object obj, String key, String value) throws Exception
{
return sqlSessionTemplate.selectMap(str, obj, key);
}
}

View File

@ -0,0 +1,64 @@
package com.ruoyi.framework.web.domain;
import java.util.HashMap;
import java.util.Map;
/**
* 返回数据通用处理
*
* @author ruoyi
*/
public class JSON extends HashMap<String, Object>
{
private static final long serialVersionUID = 1L;
public JSON()
{
put("code", 0);
put("msg", "操作成功");
}
public static JSON error()
{
return error(1, "操作失败");
}
public static JSON error(String msg)
{
return error(500, msg);
}
public static JSON error(int code, String msg)
{
JSON json = new JSON();
json.put("code", code);
json.put("msg", msg);
return json;
}
public static JSON ok(String msg)
{
JSON json = new JSON();
json.put("msg", msg);
return json;
}
public static JSON ok(Map<String, Object> map)
{
JSON json = new JSON();
json.putAll(map);
return json;
}
public static JSON ok()
{
return new JSON();
}
@Override
public JSON put(String key, Object value)
{
super.put(key, value);
return this;
}
}

View File

@ -0,0 +1,61 @@
package com.ruoyi.framework.web.exception;
import org.apache.shiro.authz.AuthorizationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import com.ruoyi.framework.web.domain.JSON;
/**
* 自定义异常处理器
*
* @author ruoyi
*/
@RestControllerAdvice
public class DefaultExceptionHandler
{
private static final Logger log = LoggerFactory.getLogger(DefaultExceptionHandler.class);
/**
* 权限校验失败
*/
@ExceptionHandler(AuthorizationException.class)
public JSON handleAuthorizationException(AuthorizationException e)
{
log.error(e.getMessage(), e);
return JSON.error("您没有数据的权限,请联系管理员添加");
}
/**
* 请求方式不支持
*/
@ExceptionHandler({ HttpRequestMethodNotSupportedException.class })
public JSON handleException(HttpRequestMethodNotSupportedException e)
{
log.error(e.getMessage(), e);
return JSON.error("不支持' " + e.getMethod() + "'请求");
}
/**
* 拦截未知的运行时异常
*/
@ExceptionHandler(RuntimeException.class)
public JSON notFount(RuntimeException e)
{
log.error("运行时异常:", e);
return JSON.error("运行时异常:" + e.getMessage());
}
/**
* 系统异常
*/
@ExceptionHandler(Exception.class)
public JSON handleException(Exception e)
{
log.error(e.getMessage(), e);
return JSON.error("服务器错误,请联系管理员");
}
}

View File

@ -0,0 +1,82 @@
package com.ruoyi.framework.web.page;
import com.ruoyi.common.utils.StringUtils;
/**
* 分页数据
*
* @author ruoyi
*/
public class PageDomain
{
/** 当前记录起始索引 */
private String pageNum;
/** 每页显示记录数 */
private String pageSize;
/** 排序列 */
private String orderByColumn;
/** 排序的方向 "desc" 或者 "asc". */
private String isAsc;
/** 搜索值 */
private String searchValue;
public String getOrderBy()
{
if (StringUtils.isEmpty(orderByColumn))
{
return "";
}
return orderByColumn + " " + isAsc;
}
public String getPageNum()
{
return pageNum;
}
public void setPageNum(String pageNum)
{
this.pageNum = pageNum;
}
public String getPageSize()
{
return pageSize;
}
public void setPageSize(String pageSize)
{
this.pageSize = pageSize;
}
public String getOrderByColumn()
{
return orderByColumn;
}
public void setOrderByColumn(String orderByColumn)
{
this.orderByColumn = orderByColumn;
}
public String getIsAsc()
{
return isAsc;
}
public void setIsAsc(String isAsc)
{
this.isAsc = isAsc;
}
public String getSearchValue()
{
return searchValue;
}
public void setSearchValue(String searchValue)
{
this.searchValue = searchValue;
}
}

View File

@ -0,0 +1,109 @@
package com.ruoyi.framework.web.page;
import java.util.Map;
/**
* 表格请求参数封装
*
* @author ruoyi
*/
public class PageUtilEntity
{
/** 当前记录起始索引 */
private int page;
/** 每页显示记录数 */
private int size;
/** 排序列 */
private String orderByColumn;
/** 排序的方向 "desc" 或者 "asc". */
private String isAsc;
/** true:需要分页的地方传入的参数就是Page实体false:需要分页的地方传入的参数所代表的实体拥有Page属性 */
private boolean entityOrField;
/** 总记录数 */
private int totalResult;
/** 搜索值 */
private String searchValue;
/** 请求参数 */
protected Map<String, Object> reqMap;
public int getPage()
{
return page;
}
public void setPage(int page)
{
this.page = page;
}
public int getSize()
{
return size;
}
public void setSize(int size)
{
this.size = size;
}
public String getOrderByColumn()
{
return orderByColumn;
}
public void setOrderByColumn(String orderByColumn)
{
this.orderByColumn = orderByColumn;
}
public String getIsAsc()
{
return isAsc;
}
public void setIsAsc(String isAsc)
{
this.isAsc = isAsc;
}
public boolean isEntityOrField()
{
return entityOrField;
}
public void setEntityOrField(boolean entityOrField)
{
this.entityOrField = entityOrField;
}
public int getTotalResult()
{
return totalResult;
}
public void setTotalResult(int totalResult)
{
this.totalResult = totalResult;
}
public String getSearchValue()
{
return searchValue;
}
public void setSearchValue(String searchValue)
{
this.searchValue = searchValue;
}
public Map<String, Object> getReqMap()
{
return reqMap;
}
public void setReqMap(Map<String, Object> reqMap)
{
this.reqMap = reqMap;
}
}

View File

@ -0,0 +1,58 @@
package com.ruoyi.framework.web.page;
import java.io.Serializable;
import java.util.List;
/**
* 表格分页数据对象
*
* @author ruoyi
*/
public class TableDataInfo implements Serializable
{
private static final long serialVersionUID = 1L;
/** 总记录数 */
private long total;
/** 列表数据 */
private List<?> rows;
/**
* 表格数据对象
*/
public TableDataInfo()
{
}
/**
* 分页
*
* @param list 列表数据
* @param total 总记录数
*/
public TableDataInfo(List<?> list, int total)
{
this.rows = list;
this.total = total;
}
public long getTotal()
{
return total;
}
public void setTotal(long total)
{
this.total = total;
}
public List<?> getRows()
{
return rows;
}
public void setRows(List<?> rows)
{
this.rows = rows;
}
}

View File

@ -0,0 +1,37 @@
package com.ruoyi.framework.web.support;
import javax.servlet.http.HttpServletRequest;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.MapDataUtil;
import com.ruoyi.framework.web.page.PageUtilEntity;
/**
* 表格数据处理
*
* @author ruoyi
*/
public class TableSupport
{
/**
* 封装分页对象
*/
public static PageUtilEntity getPageUtilEntity()
{
HttpServletRequest request = ServletUtils.getHttpServletRequest();
PageUtilEntity pageUtilEntity = new PageUtilEntity();
pageUtilEntity.setPage(Integer.valueOf(request.getParameter("offset")));
pageUtilEntity.setSize(Integer.valueOf(request.getParameter("limit")));
pageUtilEntity.setOrderByColumn(request.getParameter("sort"));
pageUtilEntity.setIsAsc(request.getParameter("order"));
pageUtilEntity.setSearchValue(request.getParameter("search"));
pageUtilEntity.setReqMap(MapDataUtil.convertDataMap(request));
return pageUtilEntity;
}
public static PageUtilEntity buildPageRequest()
{
return getPageUtilEntity();
}
}

View File

@ -0,0 +1,26 @@
package com.ruoyi.project.monitor.druid;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.ruoyi.framework.web.controller.BaseController;
/**
* druid 监控
*
* @author ruoyi
*/
@Controller
@RequestMapping("/monitor/data")
public class DruidController extends BaseController
{
private String prefix = "/monitor/druid";
@RequiresPermissions("monitor:data:view")
@GetMapping()
public String index()
{
return "redirect:" + prefix + "/index";
}
}

View File

@ -0,0 +1,146 @@
package com.ruoyi.project.monitor.job.controller;
import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.JSON;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.project.monitor.job.domain.Job;
import com.ruoyi.project.monitor.job.service.IJobService;
/**
* 调度任务信息操作处理
*
* @author ruoyi
*/
@Controller
@RequestMapping("/monitor/job")
public class JobController extends BaseController
{
private String prefix = "monitor/job";
@Autowired
private IJobService jobService;
@RequiresPermissions("monitor:job:view")
@GetMapping()
public String job()
{
return prefix + "/job";
}
@RequiresPermissions("monitor:job:list")
@GetMapping("/list")
@ResponseBody
public TableDataInfo list(Job job)
{
setPageInfo(job);
List<Job> list = jobService.selectJobList(job);
return getDataTable(list);
}
/**
* 删除
*/
@Log(title = "监控管理", action = "定时任务-删除调度")
@RequiresPermissions("monitor:job:remove")
@RequestMapping("/remove/{jobId}")
@ResponseBody
public JSON remove(@PathVariable("jobId") Long jobId)
{
Job job = jobService.selectJobById(jobId);
if (job == null)
{
return JSON.error("调度任务不存在");
}
if (jobService.deleteJob(job) > 0)
{
return JSON.ok();
}
return JSON.error();
}
@Log(title = "监控管理", action = "定时任务-批量删除")
@RequiresPermissions("monitor:job:batchRemove")
@PostMapping("/batchRemove")
@ResponseBody
public JSON batchRemove(@RequestParam("ids[]") Long[] ids)
{
try
{
jobService.batchDeleteJob(ids);
return JSON.ok();
}
catch (Exception e)
{
e.printStackTrace();
return JSON.error(e.getMessage());
}
}
/**
* 任务调度状态修改
*/
@Log(title = "监控管理", action = "定时任务-状态修改")
@RequiresPermissions("monitor:job:changeStatus")
@PostMapping("/changeStatus")
@ResponseBody
public JSON changeStatus(Job job)
{
if (jobService.changeStatus(job) > 0)
{
return JSON.ok();
}
return JSON.error();
}
/**
* 新增调度
*/
@Log(title = "监控管理", action = "定时任务-新增调度")
@RequiresPermissions("monitor:job:add")
@GetMapping("/add")
public String add(Model model)
{
return prefix + "/add";
}
/**
* 修改调度
*/
@Log(title = "监控管理", action = "定时任务-修改调度")
@RequiresPermissions("monitor:job:edit")
@GetMapping("/edit/{jobId}")
public String edit(@PathVariable("jobId") Long jobId, Model model)
{
Job job = jobService.selectJobById(jobId);
model.addAttribute("job", job);
return prefix + "/edit";
}
/**
* 保存调度
*/
@Log(title = "监控管理", action = "定时任务-保存调度")
@RequiresPermissions("monitor:job:save")
@PostMapping("/save")
@ResponseBody
public JSON save(Job job)
{
if (jobService.saveJobCron(job) > 0)
{
return JSON.ok();
}
return JSON.error();
}
}

View File

@ -0,0 +1,89 @@
package com.ruoyi.project.monitor.job.controller;
import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.JSON;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.project.monitor.job.domain.JobLog;
import com.ruoyi.project.monitor.job.service.IJobLogService;
/**
* 调度日志操作处理
*
* @author ruoyi
*/
@Controller
@RequestMapping("/monitor/jobLog")
public class JobLogController extends BaseController
{
private String prefix = "monitor/job";
@Autowired
private IJobLogService jobLogService;
@RequiresPermissions("monitor:job:view")
@GetMapping()
public String jobLog()
{
return prefix + "/jobLog";
}
@RequiresPermissions("monitor:job:list")
@GetMapping("/list")
@ResponseBody
public TableDataInfo list(JobLog jobLog)
{
setPageInfo(jobLog);
List<JobLog> list = jobLogService.selectJobLogList(jobLog);
return getDataTable(list);
}
/**
* 调度日志删除
*/
@Log(title = "监控管理", action = "定时任务-删除调度日志")
@RequiresPermissions("monitor:job:remove")
@RequestMapping("/remove/{jobLogId}")
@ResponseBody
public JSON remove(@PathVariable("jobLogId") Long jobLogId)
{
JobLog jobLog = jobLogService.selectJobLogById(jobLogId);
if (jobLog == null)
{
return JSON.error("调度任务不存在");
}
if (jobLogService.deleteJobLogById(jobLogId) > 0)
{
return JSON.ok();
}
return JSON.error();
}
@Log(title = "监控管理", action = "定时任务-批量删除日志")
@RequiresPermissions("monitor:job:batchRemove")
@PostMapping("/batchRemove")
@ResponseBody
public JSON batchRemove(@RequestParam("ids[]") Long[] ids)
{
try
{
jobLogService.batchDeleteJoblog(ids);
return JSON.ok();
}
catch (Exception e)
{
e.printStackTrace();
return JSON.error(e.getMessage());
}
}
}

View File

@ -0,0 +1,69 @@
package com.ruoyi.project.monitor.job.dao;
import java.util.List;
import com.ruoyi.project.monitor.job.domain.Job;
/**
* 调度任务信息 数据层
*
* @author ruoyi
*/
public interface IJobDao
{
/**
* 查询调度任务日志集合
*
* @param job 调度信息
* @return 操作日志集合
*/
public List<Job> selectJobList(Job job);
/**
* 查询所有调度任务
*
* @return 调度任务列表
*/
public List<Job> selectJobAll();
/**
* 通过调度ID查询调度任务信息
*
* @param jobId 调度ID
* @return 角色对象信息
*/
public Job selectJobById(Long jobId);
/**
* 通过调度ID删除调度任务信息
*
* @param jobId 调度ID
* @return 结果
*/
public int deleteJobById(Job job);
/**
* 批量删除调度任务信息
*
* @param ids 需要删除的数据ID
* @return 结果
*/
public int batchDeleteJob(Long[] ids);
/**
* 修改调度任务信息
*
* @param job 调度任务信息
* @return 结果
*/
public int updateJob(Job job);
/**
* 新增调度任务信息
*
* @param job 调度任务信息
* @return 结果
*/
public int insertJob(Job job);
}

View File

@ -0,0 +1,54 @@
package com.ruoyi.project.monitor.job.dao;
import java.util.List;
import com.ruoyi.project.monitor.job.domain.JobLog;
/**
* 调度任务日志信息 数据层
*
* @author ruoyi
*/
public interface IJobLogDao
{
/**
* 获取quartz调度器日志的计划任务
*
* @param jobLog 调度日志信息
* @return 调度任务日志集合
*/
public List<JobLog> selectJobLogList(JobLog jobLog);
/**
* 通过调度任务日志ID查询调度信息
*
* @param jobLogId 调度任务日志ID
* @return 调度任务日志对象信息
*/
public JobLog selectJobLogById(Long jobLogId);
/**
* 新增任务日志
*
* @param jobLog 调度日志信息
* @return 结果
*/
public int insertJobLog(JobLog jobLog);
/**
* 批量删除调度日志信息
*
* @param ids 需要删除的数据ID
* @return 结果
*/
public int batchDeleteJobLog(Long[] ids);
/**
* 删除任务日志
*
* @param jobId 调度日志ID
* @return 结果
*/
public int deleteJobLogById(Long jobId);
}

View File

@ -0,0 +1,169 @@
package com.ruoyi.project.monitor.job.domain;
import java.io.Serializable;
import com.ruoyi.framework.web.page.PageDomain;
/**
* 定时任务调度信息 sys_job
*
* @author ruoyi
*/
public class Job extends PageDomain implements Serializable
{
private static final long serialVersionUID = 1L;
/** 任务ID */
private Long jobId;
/** 任务名称 */
private String jobName;
/** 任务组名 */
private String jobGroup;
/** 任务方法 */
private String methodName;
/** 方法参数 */
private String params;
/** cron执行表达式 */
private String cronExpression;
/** 状态0正常 1暂停 */
private int status;
/** 创建者 */
private String createBy;
/** 创建时间 */
private String createTime;
/** 更新时间 */
private String updateTime;
/** 更新者 */
private String updateBy;
/** 备注 */
private String remark;
public Long getJobId()
{
return jobId;
}
public void setJobId(Long jobId)
{
this.jobId = jobId;
}
public String getJobName()
{
return jobName;
}
public void setJobName(String jobName)
{
this.jobName = jobName;
}
public String getJobGroup()
{
return jobGroup;
}
public void setJobGroup(String jobGroup)
{
this.jobGroup = jobGroup;
}
public String getMethodName()
{
return methodName;
}
public void setMethodName(String methodName)
{
this.methodName = methodName;
}
public String getParams()
{
return params;
}
public void setParams(String params)
{
this.params = params;
}
public String getCronExpression()
{
return cronExpression;
}
public void setCronExpression(String cronExpression)
{
this.cronExpression = cronExpression;
}
public int getStatus()
{
return status;
}
public void setStatus(int status)
{
this.status = status;
}
public String getCreateBy()
{
return createBy;
}
public void setCreateBy(String createBy)
{
this.createBy = createBy;
}
public String getCreateTime()
{
return createTime;
}
public void setCreateTime(String createTime)
{
this.createTime = createTime;
}
public String getUpdateTime()
{
return updateTime;
}
public void setUpdateTime(String updateTime)
{
this.updateTime = updateTime;
}
public String getUpdateBy()
{
return updateBy;
}
public void setUpdateBy(String updateBy)
{
this.updateBy = updateBy;
}
public String getRemark()
{
return remark;
}
public void setRemark(String remark)
{
this.remark = remark;
}
@Override
public String toString()
{
return "Job [jobId=" + jobId + ", jobName=" + jobName + ", jobGroup=" + jobGroup + ", methodName=" + methodName
+ ", params=" + params + ", cronExpression=" + cronExpression + ", status=" + status + ", createBy="
+ createBy + ", createTime=" + createTime + ", updateTime=" + updateTime + ", updateBy=" + updateBy
+ ", remark=" + remark + "]";
}
}

View File

@ -0,0 +1,130 @@
package com.ruoyi.project.monitor.job.domain;
import java.util.Date;
import com.ruoyi.framework.web.page.PageDomain;
/**
* 定时任务调度日志信息 sys_job_log
*
* @author ruoyi
*/
public class JobLog extends PageDomain
{
/** ID */
private Integer jobLogId;
/** 任务名称 */
private String jobName;
/** 任务组名 */
private String jobGroup;
/** 任务方法 */
private String methodName;
/** 方法参数 */
private String params;
/** 日志信息 */
private String jobMessage;
/** 是否异常 */
private int isException;
/** 异常信息 */
private String exceptionInfo;
/** 创建时间 */
private Date createTime;
public Integer getJobLogId()
{
return jobLogId;
}
public void setJobLogId(Integer jobLogId)
{
this.jobLogId = jobLogId;
}
public String getJobName()
{
return jobName;
}
public void setJobName(String jobName)
{
this.jobName = jobName;
}
public String getJobGroup()
{
return jobGroup;
}
public void setJobGroup(String jobGroup)
{
this.jobGroup = jobGroup;
}
public String getMethodName()
{
return methodName;
}
public void setMethodName(String methodName)
{
this.methodName = methodName;
}
public String getParams()
{
return params;
}
public void setParams(String params)
{
this.params = params;
}
public String getJobMessage()
{
return jobMessage;
}
public void setJobMessage(String jobMessage)
{
this.jobMessage = jobMessage;
}
public int getIsException()
{
return isException;
}
public void setIsException(int isException)
{
this.isException = isException;
}
public String getExceptionInfo()
{
return exceptionInfo;
}
public void setExceptionInfo(String exceptionInfo)
{
this.exceptionInfo = exceptionInfo;
}
public Date getCreateTime()
{
return createTime;
}
public void setCreateTime(Date createTime)
{
this.createTime = createTime;
}
@Override
public String toString()
{
return "JobLog [jobLogId=" + jobLogId + ", jobName=" + jobName + ", jobGroup=" + jobGroup + ", methodName="
+ methodName + ", params=" + params + ", jobMessage=" + jobMessage + ", isException=" + isException
+ ", exceptionInfo=" + exceptionInfo + ", createTime=" + createTime + "]";
}
}

View File

@ -0,0 +1,53 @@
package com.ruoyi.project.monitor.job.service;
import java.util.List;
import com.ruoyi.project.monitor.job.domain.JobLog;
/**
* 定时任务调度日志信息信息 服务层
*
* @author ruoyi
*/
public interface IJobLogService
{
/**
* 获取quartz调度器日志的计划任务
*
* @param jobLog 调度日志信息
* @return 调度任务日志集合
*/
public List<JobLog> selectJobLogList(JobLog jobLog);
/**
* 通过调度任务日志ID查询调度信息
*
* @param jobLogId 调度任务日志ID
* @return 调度任务日志对象信息
*/
public JobLog selectJobLogById(Long jobLogId);
/**
* 新增任务日志
*
* @param jobLog 调度日志信息
*/
public void addJobLog(JobLog jobLog);
/**
* 批量删除调度日志信息
*
* @param ids 需要删除的数据ID
* @return 结果
*/
public int batchDeleteJoblog(Long[] ids);
/**
* 删除任务日志
*
* @param jobId 调度日志ID
* @return 结果
*/
public int deleteJobLogById(Long jobId);
}

View File

@ -0,0 +1,101 @@
package com.ruoyi.project.monitor.job.service;
import java.util.List;
import com.ruoyi.project.monitor.job.domain.Job;
/**
* 定时任务调度信息信息 服务层
*
* @author ruoyi
*/
public interface IJobService
{
/**
* 获取quartz调度器的计划任务
*
* @param job 调度信息
* @return 调度任务集合
*/
public List<Job> selectJobList(Job job);
/**
* 通过调度任务ID查询调度信息
*
* @param jobId 调度任务ID
* @return 调度任务对象信息
*/
public Job selectJobById(Long jobId);
/**
* 暂停任务
*
* @param job 调度信息
* @return 结果
*/
public int pauseJob(Job job);
/**
* 恢复任务
*
* @param job 调度信息
* @return 结果
*/
public int resumeJob(Job job);
/**
* 删除任务后所对应的trigger也将被删除
*
* @param job 调度信息
* @return 结果
*/
public int deleteJob(Job job);
/**
* 批量删除调度信息
*
* @param ids 需要删除的数据ID
* @return 结果
*/
public void batchDeleteJob(Long[] ids);
/**
* 任务调度状态修改
*
* @param job 调度信息
* @return 结果
*/
public int changeStatus(Job job);
/**
* 立即运行任务
*
* @param job 调度信息
* @return 结果
*/
public int triggerJob(Job job);
/**
* 新增任务表达式
*
* @param job 调度信息
* @return 结果
*/
public int addJobCron(Job job);
/**
* 更新任务的时间表达式
*
* @param job 调度信息
* @return 结果
*/
public int updateJobCron(Job job);
/**
* 保存任务的时间表达式
*
* @param job 调度信息
* @return 结果
*/
public int saveJobCron(Job job);
}

View File

@ -0,0 +1,79 @@
package com.ruoyi.project.monitor.job.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.project.monitor.job.dao.IJobLogDao;
import com.ruoyi.project.monitor.job.domain.JobLog;
/**
* 定时任务调度日志信息 服务层
*
* @author ruoyi
*/
@Service("jobLogService")
public class JobLogServiceImpl implements IJobLogService
{
@Autowired
private IJobLogDao jobLogDao;
/**
* 获取quartz调度器日志的计划任务
*
* @param jobLog 调度日志信息
* @return 调度任务日志集合
*/
@Override
public List<JobLog> selectJobLogList(JobLog jobLog)
{
return jobLogDao.selectJobLogList(jobLog);
}
/**
* 通过调度任务日志ID查询调度信息
*
* @param jobId 调度任务日志ID
* @return 调度任务日志对象信息
*/
@Override
public JobLog selectJobLogById(Long jobLogId)
{
return jobLogDao.selectJobLogById(jobLogId);
}
/**
* 新增任务日志
*
* @param jobLog 调度日志信息
*/
@Override
public void addJobLog(JobLog jobLog)
{
jobLogDao.insertJobLog(jobLog);
}
/**
* 批量删除调度日志信息
*
* @param ids 需要删除的数据ID
* @return 结果
*/
@Override
public int batchDeleteJoblog(Long[] ids)
{
return jobLogDao.batchDeleteJobLog(ids);
}
/**
* 删除任务日志
*
* @param jobId 调度日志ID
*/
@Override
public int deleteJobLogById(Long jobId)
{
return jobLogDao.deleteJobLogById(jobId);
}
}

View File

@ -0,0 +1,236 @@
package com.ruoyi.project.monitor.job.service;
import java.util.List;
import javax.annotation.PostConstruct;
import org.quartz.CronTrigger;
import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.common.constant.ScheduleConstants;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.security.ShiroUtils;
import com.ruoyi.project.monitor.job.dao.IJobDao;
import com.ruoyi.project.monitor.job.domain.Job;
import com.ruoyi.project.monitor.job.util.ScheduleUtils;
/**
* 定时任务调度信息 服务层
*
* @author ruoyi
*/
@Service("jobService")
public class JobServiceImpl implements IJobService
{
@Autowired
private Scheduler scheduler;
@Autowired
private IJobDao jobDao;
/**
* 项目启动时初始化定时器
*/
@PostConstruct
public void init()
{
List<Job> jobList = jobDao.selectJobAll();
for (Job job : jobList)
{
CronTrigger cronTrigger = ScheduleUtils.getCronTrigger(scheduler, job.getJobId());
// 如果不存在则创建
if (cronTrigger == null)
{
ScheduleUtils.createScheduleJob(scheduler, job);
}
else
{
ScheduleUtils.updateScheduleJob(scheduler, job);
}
}
}
/**
* 获取quartz调度器的计划任务列表
*
* @param job 调度信息
* @return
*/
@Override
public List<Job> selectJobList(Job job)
{
return jobDao.selectJobList(job);
}
/**
* 通过调度任务ID查询调度信息
*
* @param jobId 调度任务ID
* @return 调度任务对象信息
*/
@Override
public Job selectJobById(Long jobId)
{
return jobDao.selectJobById(jobId);
}
/**
* 暂停任务
*
* @param job 调度信息
*/
@Override
public int pauseJob(Job job)
{
job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
job.setUpdateBy(ShiroUtils.getLoginName());
int rows = jobDao.updateJob(job);
if (rows > 0)
{
ScheduleUtils.pauseJob(scheduler, job.getJobId());
}
return rows;
}
/**
* 恢复任务
*
* @param job 调度信息
*/
@Override
public int resumeJob(Job job)
{
job.setStatus(ScheduleConstants.Status.NORMAL.getValue());
job.setUpdateBy(ShiroUtils.getLoginName());
int rows = jobDao.updateJob(job);
if (rows > 0)
{
ScheduleUtils.resumeJob(scheduler, job.getJobId());
}
return rows;
}
/**
* 删除任务后所对应的trigger也将被删除
*
* @param job 调度信息
*/
@Override
public int deleteJob(Job job)
{
int rows = jobDao.deleteJobById(job);
if (rows > 0)
{
ScheduleUtils.deleteScheduleJob(scheduler, job.getJobId());
}
return rows;
}
/**
* 批量删除调度信息
*
* @param ids 需要删除的数据ID
* @return 结果
*/
@Override
public void batchDeleteJob(Long[] ids)
{
for (Long jobId : ids)
{
Job job = jobDao.selectJobById(jobId);
deleteJob(job);
}
}
/**
* 任务调度状态修改
*
* @param job 调度信息
*/
@Override
public int changeStatus(Job job)
{
int rows = 0;
int status = job.getStatus();
if (status == 0)
{
rows = resumeJob(job);
}
else if (status == 1)
{
rows = pauseJob(job);
}
return rows;
}
/**
* 立即运行任务
*
* @param job 调度信息
*/
@Override
public int triggerJob(Job job)
{
int rows = jobDao.updateJob(job);
if (rows > 0)
{
ScheduleUtils.run(scheduler, job);
}
return rows;
}
/**
* 新增任务
*
* @param job 调度信息 调度信息
*/
@Override
public int addJobCron(Job job)
{
job.setCreateBy(ShiroUtils.getLoginName());
job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
int rows = jobDao.insertJob(job);
if (rows > 0)
{
ScheduleUtils.createScheduleJob(scheduler, job);
}
return rows;
}
/**
* 更新任务的时间表达式
*
* @param job 调度信息
*/
@Override
public int updateJobCron(Job job)
{
int rows = jobDao.updateJob(job);
if (rows > 0)
{
ScheduleUtils.updateScheduleJob(scheduler, job);
}
return rows;
}
/**
* 保存任务的时间表达式
*
* @param job 调度信息
*/
@Override
public int saveJobCron(Job job)
{
Long jobId = job.getJobId();
int rows = 0;
if (StringUtils.isNotNull(jobId))
{
rows = updateJobCron(job);
}
else
{
rows = addJobCron(job);
}
return rows;
}
}

View File

@ -0,0 +1,24 @@
package com.ruoyi.project.monitor.job.task;
import org.springframework.stereotype.Component;
/**
* 定时任务调度测试
*
* @author ruoyi
*/
@Component("ryTask")
public class RyTask
{
public void ryParams(String params)
{
System.out.println("执行有参方法:" + params);
}
public void ryNoParams()
{
System.out.println("执行无参方法");
}
}

View File

@ -0,0 +1,75 @@
package com.ruoyi.project.monitor.job.util;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;
import com.ruoyi.common.constant.ScheduleConstants;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.project.monitor.job.domain.Job;
import com.ruoyi.project.monitor.job.domain.JobLog;
import com.ruoyi.project.monitor.job.service.IJobLogService;
/**
* 定时任务
*
* @author ruoyi
*
*/
public class ScheduleJob extends QuartzJobBean
{
private static final Logger log = LoggerFactory.getLogger(ScheduleJob.class);
private ExecutorService service = Executors.newSingleThreadExecutor();
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException
{
Job job = (Job) context.getMergedJobDataMap().get(ScheduleConstants.JOB_PARAM_KEY);
IJobLogService jobLogService = (IJobLogService) SpringUtils.getBean(IJobLogService.class);
JobLog jobLog = new JobLog();
jobLog.setJobName(job.getJobName());
jobLog.setJobGroup(job.getJobGroup());
jobLog.setMethodName(job.getMethodName());
jobLog.setParams(job.getParams());
jobLog.setCreateTime(new Date());
long startTime = System.currentTimeMillis();
try
{
// 执行任务
log.info("任务开始执行 - 名称:{} 方法:{}", job.getJobName(), job.getMethodName());
ScheduleRunnable task = new ScheduleRunnable(job.getJobName(), job.getMethodName(), job.getParams());
Future<?> future = service.submit(task);
future.get();
long times = System.currentTimeMillis() - startTime;
// 任务状态 0成功 1失败
jobLog.setIsException(0);
jobLog.setJobMessage(job.getJobName() + " 总共耗时:" + times + "毫秒");
log.info("任务执行结束 - 名称:{} 耗时:{} 毫秒", job.getJobName(), times);
}
catch (Exception e)
{
log.info("任务执行失败 - 名称:{} 方法:{}", job.getJobName(), job.getMethodName());
log.error("任务执行异常 - ", e);
long times = System.currentTimeMillis() - startTime;
jobLog.setJobMessage(job.getJobName() + " 总共耗时:" + times + "毫秒");
// 任务状态 0成功 1失败
jobLog.setIsException(1);
jobLog.setExceptionInfo(e.toString());
}
finally
{
jobLogService.addJobLog(jobLog);
}
}
}

View File

@ -0,0 +1,59 @@
package com.ruoyi.project.monitor.job.util;
import java.lang.reflect.Method;
import org.springframework.util.ReflectionUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
/**
* 执行定时任务
*
* @author ruoyi
*
*/
public class ScheduleRunnable implements Runnable
{
private Object target;
private Method method;
private String params;
public ScheduleRunnable(String beanName, String methodName, String params)
throws NoSuchMethodException, SecurityException
{
this.target = SpringUtils.getBean(beanName);
this.params = params;
if (StringUtils.isNotEmpty(params))
{
this.method = target.getClass().getDeclaredMethod(methodName, String.class);
}
else
{
this.method = target.getClass().getDeclaredMethod(methodName);
}
}
@Override
public void run()
{
try
{
ReflectionUtils.makeAccessible(method);
if (StringUtils.isNotEmpty(params))
{
method.invoke(target, params);
}
else
{
method.invoke(target);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,193 @@
package com.ruoyi.project.monitor.job.util;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.common.constant.ScheduleConstants;
import com.ruoyi.project.monitor.job.domain.Job;
/**
* 定时任务工具类
*
* @author ruoyi
*
*/
public class ScheduleUtils
{
private static final Logger log = LoggerFactory.getLogger(ScheduleUtils.class);
private final static String JOB_NAME = "TASK_";
/**
* 获取触发器key
*/
public static TriggerKey getTriggerKey(Long jobId)
{
return TriggerKey.triggerKey(JOB_NAME + jobId);
}
/**
* 获取jobKey
*/
public static JobKey getJobKey(Long jobId)
{
return JobKey.jobKey(JOB_NAME + jobId);
}
/**
* 获取表达式触发器
*/
public static CronTrigger getCronTrigger(Scheduler scheduler, Long jobId)
{
try
{
return (CronTrigger) scheduler.getTrigger(getTriggerKey(jobId));
}
catch (SchedulerException e)
{
log.error(e.getMessage());
}
return null;
}
/**
* 创建定时任务
*/
public static void createScheduleJob(Scheduler scheduler, Job job)
{
try
{
// 构建job信息
JobDetail jobDetail = JobBuilder.newJob(ScheduleJob.class).withIdentity(getJobKey(job.getJobId())).build();
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
// 按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(job.getJobId())).withSchedule(scheduleBuilder).build();
// 放入参数运行时的方法可以获取
jobDetail.getJobDataMap().put(ScheduleConstants.JOB_PARAM_KEY, job);
scheduler.scheduleJob(jobDetail, trigger);
// 暂停任务
if (job.getStatus() == ScheduleConstants.Status.PAUSE.getValue())
{
pauseJob(scheduler, job.getJobId());
}
}
catch (SchedulerException e)
{
log.error(e.getMessage());
}
}
/**
* 更新定时任务
*/
public static void updateScheduleJob(Scheduler scheduler, Job job)
{
try
{
TriggerKey triggerKey = getTriggerKey(job.getJobId());
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
CronTrigger trigger = getCronTrigger(scheduler, job.getJobId());
// 按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
// 参数
trigger.getJobDataMap().put(ScheduleConstants.JOB_PARAM_KEY, job);
scheduler.rescheduleJob(triggerKey, trigger);
// 暂停任务
if (job.getStatus() == ScheduleConstants.Status.PAUSE.getValue())
{
pauseJob(scheduler, job.getJobId());
}
}
catch (SchedulerException e)
{
log.error(e.getMessage());
}
}
/**
* 立即执行任务
*/
public static void run(Scheduler scheduler, Job job)
{
try
{
// 参数
JobDataMap dataMap = new JobDataMap();
dataMap.put(ScheduleConstants.JOB_PARAM_KEY, job);
scheduler.triggerJob(getJobKey(job.getJobId()), dataMap);
}
catch (SchedulerException e)
{
log.error(e.getMessage());
}
}
/**
* 暂停任务
*/
public static void pauseJob(Scheduler scheduler, Long jobId)
{
try
{
scheduler.pauseJob(getJobKey(jobId));
}
catch (SchedulerException e)
{
log.error(e.getMessage());
}
}
/**
* 恢复任务
*/
public static void resumeJob(Scheduler scheduler, Long jobId)
{
try
{
scheduler.resumeJob(getJobKey(jobId));
}
catch (SchedulerException e)
{
log.error(e.getMessage());
}
}
/**
* 删除定时任务
*/
public static void deleteScheduleJob(Scheduler scheduler, Long jobId)
{
try
{
scheduler.deleteJob(getJobKey(jobId));
}
catch (SchedulerException e)
{
log.error(e.getMessage());
}
}
}

View File

@ -0,0 +1,63 @@
package com.ruoyi.project.monitor.logininfor.controller;
import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.JSON;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.project.monitor.logininfor.domain.Logininfor;
import com.ruoyi.project.monitor.logininfor.service.ILogininforService;
/**
* 系统访问记录
*
* @author ruoyi
*/
@Controller
@RequestMapping("/monitor/logininfor")
public class LogininforController extends BaseController
{
private String prefix = "monitor/logininfor";
@Autowired
private ILogininforService logininforService;
@RequiresPermissions("monitor:logininfor:view")
@GetMapping()
public String logininfor()
{
return prefix + "/logininfor";
}
@RequiresPermissions("monitor:logininfor:list")
@GetMapping("/list")
@ResponseBody
public TableDataInfo list(Logininfor logininfor)
{
setPageInfo(logininfor);
List<Logininfor> list = logininforService.selectLogininforList(logininfor);
return getDataTable(list);
}
@RequiresPermissions("monitor:logininfor:batchRemove")
@Log(title = "监控管理", action = "登录日志-批量删除")
@PostMapping("/batchRemove")
@ResponseBody
public JSON batchRemove(@RequestParam("ids[]") Long[] ids)
{
int rows = logininforService.batchDeleteLogininfor(ids);
if (rows > 0)
{
return JSON.ok();
}
return JSON.error();
}
}

View File

@ -0,0 +1,35 @@
package com.ruoyi.project.monitor.logininfor.dao;
import java.util.List;
import com.ruoyi.project.monitor.logininfor.domain.Logininfor;
/**
* 系统访问日志情况信息 数据层
*
* @author ruoyi
*/
public interface ILogininforDao
{
/**
* 新增系统登录日志
*
* @param logininfor 访问日志对象
*/
public void insertLogininfor(Logininfor logininfor);
/**
* 查询系统登录日志集合
*
* @param logininfor 访问日志对象
* @return 登录记录集合
*/
public List<Logininfor> selectLogininforList(Logininfor logininfor);
/**
* 批量删除系统登录日志
*
* @param ids 需要删除的数据
* @return
*/
public int batchDeleteLogininfor(Long[] ids);
}

View File

@ -0,0 +1,117 @@
package com.ruoyi.project.monitor.logininfor.domain;
import java.util.Date;
import com.ruoyi.framework.web.page.PageDomain;
/**
* 系统访问日志情况信息 sys_logininfor
*
* @author ruoyi
*/
public class Logininfor extends PageDomain
{
/** ID */
private Integer infoId;
/** 用户账号 */
private String loginName;
/** 登录状态 0成功 1失败 */
private String status;
/** 登录IP地址 */
private String ipaddr;
/** 浏览器类型 */
private String browser;
/** 操作系统 */
private String os;
/** 提示消息 */
private String msg;
/** 访问时间 */
private Date loginTime;
public Integer getInfoId()
{
return infoId;
}
public void setInfoId(Integer infoId)
{
this.infoId = infoId;
}
public String getLoginName()
{
return loginName;
}
public void setLoginName(String loginName)
{
this.loginName = loginName;
}
public String getStatus()
{
return status;
}
public void setStatus(String status)
{
this.status = status;
}
public String getIpaddr()
{
return ipaddr;
}
public void setIpaddr(String ipaddr)
{
this.ipaddr = ipaddr;
}
public String getBrowser()
{
return browser;
}
public void setBrowser(String browser)
{
this.browser = browser;
}
public String getOs()
{
return os;
}
public void setOs(String os)
{
this.os = os;
}
public String getMsg()
{
return msg;
}
public void setMsg(String msg)
{
this.msg = msg;
}
public Date getLoginTime()
{
return loginTime;
}
public void setLoginTime(Date loginTime)
{
this.loginTime = loginTime;
}
@Override
public String toString()
{
return "Logininfor [infoId=" + infoId + ", loginName=" + loginName + ", status=" + status + ", ipaddr=" + ipaddr
+ ", browser=" + browser + ", os=" + os + ", msg=" + msg + ", loginTime=" + loginTime + "]";
}
}

View File

@ -0,0 +1,36 @@
package com.ruoyi.project.monitor.logininfor.service;
import java.util.List;
import com.ruoyi.project.monitor.logininfor.domain.Logininfor;
/**
* 系统访问日志情况信息 服务层
*
* @author ruoyi
*/
public interface ILogininforService
{
/**
* 新增系统登录日志
*
* @param logininfor 访问日志对象
*/
public void insertLogininfor(Logininfor logininfor);
/**
* 查询系统登录日志集合
*
* @param logininfor 访问日志对象
* @return 登录记录集合
*/
public List<Logininfor> selectLogininforList(Logininfor logininfor);
/**
* 批量删除系统登录日志
*
* @param ids 需要删除的数据
* @return
*/
public int batchDeleteLogininfor(Long[] ids);
}

View File

@ -0,0 +1,55 @@
package com.ruoyi.project.monitor.logininfor.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.project.monitor.logininfor.dao.ILogininforDao;
import com.ruoyi.project.monitor.logininfor.domain.Logininfor;
/**
* 系统访问日志情况信息 服务层处理
*
* @author ruoyi
*/
@Service("logininforService")
public class LogininforServiceImpl implements ILogininforService
{
@Autowired
private ILogininforDao logininforDao;
/**
* 新增系统登录日志
*
* @param logininfor 访问日志对象
*/
@Override
public void insertLogininfor(Logininfor logininfor)
{
logininforDao.insertLogininfor(logininfor);
}
/**
* 查询系统登录日志集合
*
* @param logininfor 访问日志对象
* @return 登录记录集合
*/
@Override
public List<Logininfor> selectLogininforList(Logininfor logininfor)
{
return logininforDao.selectLogininforList(logininfor);
}
/**
* 批量删除系统登录日志
*
* @param ids 需要删除的数据
* @return
*/
@Override
public int batchDeleteLogininfor(Long[] ids)
{
return logininforDao.batchDeleteLogininfor(ids);
}
}

View File

@ -0,0 +1,103 @@
package com.ruoyi.project.monitor.online.controller;
import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.shiro.session.OnlineSessionDAO;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.JSON;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.project.monitor.online.domain.OnlineSession;
import com.ruoyi.project.monitor.online.domain.UserOnline;
import com.ruoyi.project.monitor.online.service.IUserOnlineService;
/**
* 在线用户监控
*
* @author ruoyi
*/
@Controller
@RequestMapping("/monitor/online")
public class UserOnlineController extends BaseController
{
private String prefix = "monitor/online";
@Autowired
private IUserOnlineService userOnlineService;
@Autowired
private OnlineSessionDAO onlineSessionDAO;
@RequiresPermissions("monitor:online:view")
@GetMapping()
public String online()
{
return prefix + "/online";
}
@RequiresPermissions("monitor:online:list")
@GetMapping("/list")
@ResponseBody
public TableDataInfo list(UserOnline userOnline)
{
setPageInfo(userOnline);
List<UserOnline> list = userOnlineService.selectUserOnlineList(userOnline);
return getDataTable(list);
}
@RequiresPermissions("monitor:online:batchForceLogout")
@Log(title = "监控管理", action = "在线用户-批量强退用户")
@PostMapping("/batchForceLogout")
@ResponseBody
public JSON batchForceLogout(@RequestParam("ids[]") String[] ids)
{
for (String sessionId : ids)
{
UserOnline online = userOnlineService.selectOnlineById(sessionId);
if (online == null)
{
return JSON.error("用户已下线");
}
OnlineSession onlineSession = (OnlineSession) onlineSessionDAO.readSession(online.getSessionId());
if (onlineSession == null)
{
return JSON.error("用户已下线");
}
onlineSession.setStatus(OnlineSession.OnlineStatus.off_line);
online.setStatus(OnlineSession.OnlineStatus.off_line);
userOnlineService.saveOnline(online);
}
return JSON.ok();
}
@RequiresPermissions("monitor:online:forceLogout")
@Log(title = "监控管理", action = "在线用户-强退用户")
@RequestMapping("/forceLogout/{sessionId}")
@ResponseBody
public JSON forceLogout(@PathVariable("sessionId") String sessionId)
{
UserOnline online = userOnlineService.selectOnlineById(sessionId);
if (online == null)
{
return JSON.error("用户已下线");
}
OnlineSession onlineSession = (OnlineSession) onlineSessionDAO.readSession(online.getSessionId());
if (onlineSession == null)
{
return JSON.error("用户已下线");
}
onlineSession.setStatus(OnlineSession.OnlineStatus.off_line);
online.setStatus(OnlineSession.OnlineStatus.off_line);
userOnlineService.saveOnline(online);
return JSON.ok();
}
}

View File

@ -0,0 +1,52 @@
package com.ruoyi.project.monitor.online.dao;
import java.util.List;
import com.ruoyi.project.monitor.online.domain.UserOnline;
/**
* 在线用户 数据层
*
* @author ruoyi
*/
public interface IUserOnlineDao
{
/**
* 通过会话序号查询信息
*
* @param sessionId 会话ID
* @return 在线用户信息
*/
public UserOnline selectOnlineById(String sessionId);
/**
* 通过会话序号删除信息
*
* @param sessionId 会话ID
* @return 在线用户信息
*/
public int deleteOnlineById(String sessionId);
/**
* 保存会话信息
*
* @param online 会话信息
* @return 结果
*/
public int saveOnline(UserOnline online);
/**
* 查询会话集合
*
* @param userOnline 会话参数
* @return 会话集合
*/
public List<UserOnline> selectUserOnlineList(UserOnline userOnline);
/**
* 查询过期会话集合
*
* @param lastAccessTime 过期时间
* @return 会话集合
*/
public List<UserOnline> selectOnlineByExpired(String lastAccessTime);
}

View File

@ -0,0 +1,155 @@
package com.ruoyi.project.monitor.online.domain;
import org.apache.shiro.session.mgt.SimpleSession;
/**
* 在线用户会话属性
*
* @author ruoyi
*/
public class OnlineSession extends SimpleSession
{
private static final long serialVersionUID = 1L;
/** 用户ID */
private Long userId;
/** 用户名称 */
private String loginName;
/** 部门名称 */
private String deptName;
/** 登录IP地址 */
private String host;
/** 浏览器类型 */
private String browser;
/** 操作系统 */
private String os;
/** 在线状态 */
private OnlineStatus status = OnlineStatus.on_line;
/** 属性是否改变 优化session数据同步 */
private transient boolean attributeChanged = false;
@Override
public String getHost()
{
return host;
}
@Override
public void setHost(String host)
{
this.host = host;
}
public String getBrowser()
{
return browser;
}
public void setBrowser(String browser)
{
this.browser = browser;
}
public String getOs()
{
return os;
}
public void setOs(String os)
{
this.os = os;
}
public Long getUserId()
{
return userId;
}
public void setUserId(Long userId)
{
this.userId = userId;
}
public String getLoginName()
{
return loginName;
}
public void setLoginName(String loginName)
{
this.loginName = loginName;
}
public String getDeptName()
{
return deptName;
}
public void setDeptName(String deptName)
{
this.deptName = deptName;
}
public OnlineStatus getStatus()
{
return status;
}
public void setStatus(OnlineStatus status)
{
this.status = status;
}
public void markAttributeChanged()
{
this.attributeChanged = true;
}
public void resetAttributeChanged()
{
this.attributeChanged = false;
}
public boolean isAttributeChanged()
{
return attributeChanged;
}
@Override
public void setAttribute(Object key, Object value)
{
super.setAttribute(key, value);
}
@Override
public Object removeAttribute(Object key)
{
return super.removeAttribute(key);
}
public static enum OnlineStatus
{
/** 用户状态 */
on_line("在线"), off_line("离线");
private final String info;
private OnlineStatus(String info)
{
this.info = info;
}
public String getInfo()
{
return info;
}
}
}

View File

@ -0,0 +1,186 @@
package com.ruoyi.project.monitor.online.domain;
import java.util.Date;
import com.ruoyi.framework.web.page.PageDomain;
import com.ruoyi.project.monitor.online.domain.OnlineSession.OnlineStatus;
/**
* 当前在线会话 sys_user_online
*
* @author ruoyi
*/
public class UserOnline extends PageDomain
{
/** 用户会话id */
private String sessionId;
/** 部门名称 */
private String deptName;
/** 登录名称 */
private String loginName;
/** 登录IP地址 */
private String ipaddr;
/** 浏览器类型 */
private String browser;
/** 操作系统 */
private String os;
/** session创建时间 */
private Date startTimestamp;
/** session最后访问时间 */
private Date lastAccessTime;
/** 超时时间,单位为分钟 */
private Long expireTime;
/** 在线状态 */
private OnlineStatus status = OnlineStatus.on_line;
/** 备份的当前用户会话 */
private OnlineSession session;
/**
* 设置session对象
*/
public static final UserOnline fromOnlineSession(OnlineSession session)
{
UserOnline online = new UserOnline();
online.setSessionId(String.valueOf(session.getId()));
online.setDeptName(session.getDeptName());
online.setLoginName(session.getLoginName());
online.setStartTimestamp(session.getStartTimestamp());
online.setLastAccessTime(session.getLastAccessTime());
online.setExpireTime(session.getTimeout());
online.setIpaddr(session.getHost());
online.setBrowser(session.getBrowser());
online.setOs(session.getOs());
online.setStatus(session.getStatus());
online.setSession(session);
return online;
}
public String getSessionId()
{
return sessionId;
}
public void setSessionId(String sessionId)
{
this.sessionId = sessionId;
}
public String getDeptName()
{
return deptName;
}
public void setDeptName(String deptName)
{
this.deptName = deptName;
}
public String getLoginName()
{
return loginName;
}
public void setLoginName(String loginName)
{
this.loginName = loginName;
}
public String getIpaddr()
{
return ipaddr;
}
public void setIpaddr(String ipaddr)
{
this.ipaddr = ipaddr;
}
public String getBrowser()
{
return browser;
}
public void setBrowser(String browser)
{
this.browser = browser;
}
public String getOs()
{
return os;
}
public void setOs(String os)
{
this.os = os;
}
public Date getStartTimestamp()
{
return startTimestamp;
}
public void setStartTimestamp(Date startTimestamp)
{
this.startTimestamp = startTimestamp;
}
public Date getLastAccessTime()
{
return lastAccessTime;
}
public void setLastAccessTime(Date lastAccessTime)
{
this.lastAccessTime = lastAccessTime;
}
public Long getExpireTime()
{
return expireTime;
}
public void setExpireTime(Long expireTime)
{
this.expireTime = expireTime;
}
public OnlineStatus getStatus()
{
return status;
}
public void setStatus(OnlineStatus status)
{
this.status = status;
}
public OnlineSession getSession()
{
return session;
}
public void setSession(OnlineSession session)
{
this.session = session;
}
@Override
public String toString()
{
return "UserOnline [sessionId=" + sessionId + ", deptName=" + deptName + ", loginName=" + loginName
+ ", ipaddr=" + ipaddr + ", browser=" + browser + ", os=" + os + ", startTimestamp=" + startTimestamp
+ ", lastAccessTime=" + lastAccessTime + ", expireTime=" + expireTime + ", status=" + status
+ ", session=" + session + "]";
}
}

View File

@ -0,0 +1,67 @@
package com.ruoyi.project.monitor.online.service;
import java.util.Date;
import java.util.List;
import com.ruoyi.project.monitor.online.domain.UserOnline;
/**
* 在线用户 服务层
*
* @author ruoyi
*/
public interface IUserOnlineService
{
/**
* 通过会话序号查询信息
*
* @param sessionId 会话ID
* @return 在线用户信息
*/
public UserOnline selectOnlineById(String sessionId);
/**
* 通过会话序号删除信息
*
* @param sessionId 会话ID
* @return 在线用户信息
*/
public void deleteOnlineById(String sessionId);
/**
* 通过会话序号删除信息
*
* @param sessions 会话ID集合
* @return 在线用户信息
*/
public void batchDeleteOnline(List<String> sessions);
/**
* 保存会话信息
*
* @param online 会话信息
*/
public void saveOnline(UserOnline online);
/**
* 查询会话集合
*
* @param userOnline 分页参数
* @return 会话集合
*/
public List<UserOnline> selectUserOnlineList(UserOnline userOnline);
/**
* 强退用户
*
* @param sessionId 会话ID
*/
public void forceLogout(String sessionId);
/**
* 查询会话集合
*
* @param expiredDate 有效期
* @return 会话集合
*/
public List<UserOnline> selectOnlineByExpired(Date expiredDate);
}

View File

@ -0,0 +1,124 @@
package com.ruoyi.project.monitor.online.service;
import java.util.Date;
import java.util.List;
import org.apache.shiro.session.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.framework.shiro.session.OnlineSessionDAO;
import com.ruoyi.project.monitor.online.dao.IUserOnlineDao;
import com.ruoyi.project.monitor.online.domain.UserOnline;
/**
* 在线用户 服务层处理
*
* @author ruoyi
*/
@Service("userOnlineService")
public class UserOnlineServiceImpl implements IUserOnlineService
{
@Autowired
private IUserOnlineDao userOnlineDao;
@Autowired
private OnlineSessionDAO onlineSessionDAO;
/**
* 通过会话序号查询信息
*
* @param sessionId 会话ID
* @return 在线用户信息
*/
@Override
public UserOnline selectOnlineById(String sessionId)
{
return userOnlineDao.selectOnlineById(sessionId);
}
/**
* 通过会话序号删除信息
*
* @param sessionId 会话ID
* @return 在线用户信息
*/
@Override
public void deleteOnlineById(String sessionId)
{
UserOnline userOnline = selectOnlineById(sessionId);
if (userOnline != null)
{
userOnlineDao.deleteOnlineById(sessionId);
}
}
/**
* 通过会话序号删除信息
*
* @param sessions 会话ID集合
* @return 在线用户信息
*/
@Override
public void batchDeleteOnline(List<String> sessions)
{
for (String sessionId : sessions)
{
UserOnline userOnline = selectOnlineById(sessionId);
if (userOnline != null)
{
userOnlineDao.deleteOnlineById(sessionId);
}
}
}
/**
* 保存会话信息
*
* @param online 会话信息
*/
@Override
public void saveOnline(UserOnline online)
{
userOnlineDao.saveOnline(online);
}
/**
* 查询会话集合
*
* @param pageUtilEntity 分页参数
*/
@Override
public List<UserOnline> selectUserOnlineList(UserOnline userOnline)
{
return userOnlineDao.selectUserOnlineList(userOnline);
}
/**
* 强退用户
*
* @param sessionId 会话ID
*/
@Override
public void forceLogout(String sessionId)
{
Session session = onlineSessionDAO.readSession(sessionId);
if (session == null)
{
return;
}
session.setTimeout(1000);
userOnlineDao.deleteOnlineById(sessionId);
}
/**
* 查询会话集合
*
* @param online 会话信息
*/
@Override
public List<UserOnline> selectOnlineByExpired(Date expiredDate)
{
String lastAccessTime = DateUtils.dateTime("yyyy-MM-dd HH:mm:ss", expiredDate);
return userOnlineDao.selectOnlineByExpired(lastAccessTime);
}
}

View File

@ -0,0 +1,74 @@
package com.ruoyi.project.monitor.operlog.controller;
import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.JSON;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.project.monitor.operlog.domain.OperLog;
import com.ruoyi.project.monitor.operlog.service.IOperLogService;
/**
* 操作日志记录
*
* @author ruoyi
*/
@Controller
@RequestMapping("/monitor/operlog")
public class OperlogController extends BaseController
{
private String prefix = "monitor/operlog";
@Autowired
private IOperLogService operLogService;
@RequiresPermissions("monitor:operlog:view")
@GetMapping()
public String operlog()
{
return prefix + "/operlog";
}
@RequiresPermissions("monitor:operlog:list")
@GetMapping("/list")
@ResponseBody
public TableDataInfo list(OperLog operLog)
{
setPageInfo(operLog);
List<OperLog> list = operLogService.selectOperLogList(operLog);
return getDataTable(list);
}
@RequiresPermissions("monitor:operlog:batchRemove")
@Log(title = "监控管理", action = "操作日志-批量删除")
@PostMapping("/batchRemove")
@ResponseBody
public JSON batchRemove(@RequestParam("ids[]") Long[] ids)
{
int rows = operLogService.batchDeleteOperLog(ids);
if (rows > 0)
{
return JSON.ok();
}
return JSON.error();
}
@RequiresPermissions("monitor:operlog:detail")
@GetMapping("/detail/{operId}")
public String detail(@PathVariable("operId") Long deptId, Model model)
{
OperLog operLog = operLogService.selectOperLogById(deptId);
model.addAttribute("operLog", operLog);
return prefix + "/detail";
}
}

View File

@ -0,0 +1,43 @@
package com.ruoyi.project.monitor.operlog.dao;
import java.util.List;
import com.ruoyi.project.monitor.operlog.domain.OperLog;
/**
* 操作日志 数据层
*
* @author ruoyi
*/
public interface IOperLogDao
{
/**
* 新增操作日志
*
* @param operLog 操作日志对象
*/
public void insertOperlog(OperLog operLog);
/**
* 查询系统操作日志集合
*
* @param operLog 操作日志对象
* @return 操作日志集合
*/
public List<OperLog> selectOperLogList(OperLog operLog);
/**
* 批量删除系统操作日志
*
* @param ids 需要删除的数据
* @return 结果
*/
public int batchDeleteOperLog(Long[] ids);
/**
* 查询操作日志详细
*
* @param operId 操作ID
* @return 操作日志对象
*/
public OperLog selectOperLogById(Long operId);
}

View File

@ -0,0 +1,179 @@
package com.ruoyi.project.monitor.operlog.domain;
import java.util.Date;
import com.ruoyi.framework.web.page.PageDomain;
/**
* 操作日志记录 oper_log
*
* @author ruoyi
*/
public class OperLog extends PageDomain
{
/** 日志主键 */
private Integer operId;
/** 模块标题 */
private String title;
/** 功能请求 */
private String action;
/** 请求方法 */
private String method;
/** 来源渠道 */
private String channel;
/** 操作员名称 */
private String loginName;
/** 部门名称 */
private String deptName;
/** 请求url */
private String operUrl;
/** 操作地址 */
private String operIp;
/** 请求参数 */
private String operParam;
/** 状态0正常 1异常 */
private int status;
/** 错误消息 */
private String errorMsg;
/** 操作时间 */
private Date operTime;
public Integer getOperId()
{
return operId;
}
public void setOperId(Integer operId)
{
this.operId = operId;
}
public String getTitle()
{
return title;
}
public void setTitle(String title)
{
this.title = title;
}
public String getAction()
{
return action;
}
public void setAction(String action)
{
this.action = action;
}
public String getMethod()
{
return method;
}
public void setMethod(String method)
{
this.method = method;
}
public String getChannel()
{
return channel;
}
public void setChannel(String channel)
{
this.channel = channel;
}
public String getLoginName()
{
return loginName;
}
public void setLoginName(String loginName)
{
this.loginName = loginName;
}
public String getDeptName()
{
return deptName;
}
public void setDeptName(String deptName)
{
this.deptName = deptName;
}
public String getOperUrl()
{
return operUrl;
}
public void setOperUrl(String operUrl)
{
this.operUrl = operUrl;
}
public String getOperIp()
{
return operIp;
}
public void setOperIp(String operIp)
{
this.operIp = operIp;
}
public String getOperParam()
{
return operParam;
}
public void setOperParam(String operParam)
{
this.operParam = operParam;
}
public int getStatus()
{
return status;
}
public void setStatus(int status)
{
this.status = status;
}
public String getErrorMsg()
{
return errorMsg;
}
public void setErrorMsg(String errorMsg)
{
this.errorMsg = errorMsg;
}
public Date getOperTime()
{
return operTime;
}
public void setOperTime(Date operTime)
{
this.operTime = operTime;
}
@Override
public String toString()
{
return "OperLog [operId=" + operId + ", title=" + title + ", action=" + action + ", method=" + method
+ ", channel=" + channel + ", loginName=" + loginName + ", deptName=" + deptName + ", operUrl="
+ operUrl + ", operIp=" + operIp + ", operParam=" + operParam + ", status=" + status + ", errorMsg="
+ errorMsg + ", operTime=" + operTime + "]";
}
}

View File

@ -0,0 +1,43 @@
package com.ruoyi.project.monitor.operlog.service;
import java.util.List;
import com.ruoyi.project.monitor.operlog.domain.OperLog;
/**
* 操作日志 服务层
*
* @author ruoyi
*/
public interface IOperLogService
{
/**
* 新增操作日志
*
* @param operLog 操作日志对象
*/
public void insertOperlog(OperLog operLog);
/**
* 查询系统操作日志集合
*
* @param operLog 操作日志对象
* @return 操作日志集合
*/
public List<OperLog> selectOperLogList(OperLog operLog);
/**
* 批量删除系统操作日志
*
* @param ids 需要删除的数据
* @return 结果
*/
public int batchDeleteOperLog(Long[] ids);
/**
* 查询操作日志详细
*
* @param operId 操作ID
* @return 操作日志对象
*/
public OperLog selectOperLogById(Long operId);
}

View File

@ -0,0 +1,66 @@
package com.ruoyi.project.monitor.operlog.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.project.monitor.operlog.dao.IOperLogDao;
import com.ruoyi.project.monitor.operlog.domain.OperLog;
/**
* 操作日志 服务层处理
*
* @author ruoyi
*/
@Service("operLogService")
public class OperLogServiceImpl implements IOperLogService
{
@Autowired
private IOperLogDao operLogDao;
/**
* 新增操作日志
*
* @param operLog 操作日志对象
*/
@Override
public void insertOperlog(OperLog operLog)
{
operLogDao.insertOperlog(operLog);
}
/**
* 查询系统操作日志集合
*
* @param operLog 操作日志对象
* @return 操作日志集合
*/
@Override
public List<OperLog> selectOperLogList(OperLog operLog)
{
return operLogDao.selectOperLogList(operLog);
}
/**
* 批量删除系统操作日志
*
* @param ids 需要删除的数据
* @return
*/
@Override
public int batchDeleteOperLog(Long[] ids)
{
return operLogDao.batchDeleteOperLog(ids);
}
/**
* 查询操作日志详细
*
* @param operId 操作ID
* @return 操作日志对象
*/
@Override
public OperLog selectOperLogById(Long operId)
{
return operLogDao.selectOperLogById(operId);
}
}

View File

@ -0,0 +1,151 @@
package com.ruoyi.project.system.dept.controller;
import java.util.List;
import java.util.Map;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.web.domain.JSON;
import com.ruoyi.project.system.dept.domain.Dept;
import com.ruoyi.project.system.dept.service.IDeptService;
/**
* 部门信息
*
* @author ruoyi
*/
@Controller
@RequestMapping("/system/dept")
public class DeptController
{
private String prefix = "system/dept";
@Autowired
private IDeptService deptService;
@RequiresPermissions("system:dept:view")
@GetMapping()
public String dept()
{
return prefix + "/dept";
}
@RequiresPermissions("system:dept:list")
@GetMapping("/list")
@ResponseBody
public List<Dept> list()
{
List<Dept> deptList = deptService.selectDeptAll();
return deptList;
}
/**
* 修改
*/
@Log(title = "系统管理", action = "部门管理-修改部门")
@RequiresPermissions("system:dept:edit")
@GetMapping("/edit/{deptId}")
public String edit(@PathVariable("deptId") Long deptId, Model model)
{
Dept dept = deptService.selectDeptById(deptId);
model.addAttribute("dept", dept);
return prefix + "/edit";
}
/**
* 新增
*/
@Log(title = "系统管理", action = "部门管理-新增部门")
@RequiresPermissions("system:dept:add")
@GetMapping("/add/{parentId}")
public String add(@PathVariable("parentId") Long parentId, Model model)
{
Dept dept = deptService.selectDeptById(parentId);
model.addAttribute("dept", dept);
return prefix + "/add";
}
/**
* 保存
*/
@Log(title = "系统管理", action = "部门管理-保存部门")
@RequiresPermissions("system:dept:save")
@PostMapping("/save")
@ResponseBody
public JSON save(Dept dept)
{
if (deptService.saveDept(dept) > 0)
{
return JSON.ok();
}
return JSON.error();
}
/**
* 删除
*/
@Log(title = "系统管理", action = "部门管理-删除部门")
@RequiresPermissions("system:dept:remove")
@GetMapping("/remove/{deptId}")
@ResponseBody
public JSON remove(@PathVariable("deptId") Long deptId)
{
if (deptService.selectDeptCount(deptId) > 0)
{
return JSON.error(1, "存在下级部门,不允许删除");
}
if (deptService.checkDeptExistUser(deptId))
{
return JSON.error(1, "部门存在用户,不允许删除");
}
if (deptService.deleteDeptById(deptId) > 0)
{
return JSON.ok();
}
return JSON.error();
}
/**
* 校验部门名称
*/
@PostMapping("/checkDeptNameUnique")
@ResponseBody
public String checkDeptNameUnique(Dept dept)
{
String uniqueFlag = "0";
if (dept != null)
{
uniqueFlag = deptService.checkDeptNameUnique(dept);
}
return uniqueFlag;
}
/**
* 选择部门树
*/
@GetMapping("/selectDeptTree/{deptId}")
public String selectDeptTree(@PathVariable("deptId") Long deptId, Model model)
{
model.addAttribute("treeName", deptService.selectDeptById(deptId).getDeptName());
return prefix + "/tree";
}
/**
* 加载部门列表树
*/
@GetMapping("/treeData")
@ResponseBody
public List<Map<String, Object>> treeData()
{
List<Map<String, Object>> tree = deptService.selectDeptTree();
return tree;
}
}

View File

@ -0,0 +1,75 @@
package com.ruoyi.project.system.dept.dao;
import java.util.List;
import com.ruoyi.project.system.dept.domain.Dept;
/**
* 部门管理 数据层
*
* @author ruoyi
*/
public interface IDeptDao
{
/**
* 查询部门人数
*
* @param dept 部门信息
* @return 结果
*/
public int selectDeptCount(Dept dept);
/**
* 查询部门是否存在用户
*
* @param deptId 部门ID
* @return 结果
*/
public int checkDeptExistUser(Long deptId);
/**
* 查询部门管理集合
*
* @return 所有部门信息
*/
public List<Dept> selectDeptAll();
/**
* 删除部门管理信息
*
* @param deptId 部门ID
* @return 结果
*/
public int deleteDeptById(Long deptId);
/**
* 新增部门信息
*
* @param dept 部门信息
* @return 结果
*/
public int insertDept(Dept dept);
/**
* 修改部门信息
*
* @param dept 部门信息
* @return 结果
*/
public int updateDept(Dept dept);
/**
* 根据部门ID查询信息
*
* @param deptId 部门ID
* @return 部门信息
*/
public Dept selectDeptById(Long deptId);
/**
* 校验部门名称是否唯一
*
* @param deptName 部门名称
* @return 结果
*/
public Dept checkDeptNameUnique(String deptName);
}

View File

@ -0,0 +1,176 @@
package com.ruoyi.project.system.dept.domain;
/**
* 部门对象 sys_dept
*
* @author ruoyi
*/
public class Dept
{
/** 部门ID */
private Long deptId;
/** 父部门ID */
private Long parentId;
/** 部门名称 */
private String deptName;
/** 显示顺序 */
private String orderNum;
/** 负责人 */
private String leader;
/** 联系电话 */
private String phone;
/** 邮箱 */
private String email;
/** 部门状态:0正常,1停用 */
private int status;
/** 父部门名称 */
private String parentName;
/** 创建者 */
private String createBy;
/** 创建时间 */
private String createTime;
/** 更新者 */
private String updateBy;
/** 更新时间 */
private String updateTime;
public Long getDeptId()
{
return deptId;
}
public void setDeptId(Long deptId)
{
this.deptId = deptId;
}
public Long getParentId()
{
return parentId;
}
public void setParentId(Long parentId)
{
this.parentId = parentId;
}
public String getDeptName()
{
return deptName;
}
public void setDeptName(String deptName)
{
this.deptName = deptName;
}
public String getOrderNum()
{
return orderNum;
}
public void setOrderNum(String orderNum)
{
this.orderNum = orderNum;
}
public String getLeader()
{
return leader;
}
public void setLeader(String leader)
{
this.leader = leader;
}
public String getPhone()
{
return phone;
}
public void setPhone(String phone)
{
this.phone = phone;
}
public String getEmail()
{
return email;
}
public void setEmail(String email)
{
this.email = email;
}
public int getStatus()
{
return status;
}
public void setStatus(int status)
{
this.status = status;
}
public String getParentName()
{
return parentName;
}
public void setParentName(String parentName)
{
this.parentName = parentName;
}
public String getCreateBy()
{
return createBy;
}
public void setCreateBy(String createBy)
{
this.createBy = createBy;
}
public String getCreateTime()
{
return createTime;
}
public void setCreateTime(String createTime)
{
this.createTime = createTime;
}
public String getUpdateBy()
{
return updateBy;
}
public void setUpdateBy(String updateBy)
{
this.updateBy = updateBy;
}
public String getUpdateTime()
{
return updateTime;
}
public void setUpdateTime(String updateTime)
{
this.updateTime = updateTime;
}
@Override
public String toString()
{
return "Dept [deptId=" + deptId + ", parentId=" + parentId + ", deptName=" + deptName + ", orderNum=" + orderNum
+ ", leader=" + leader + ", phone=" + phone + ", email=" + email + ", status=" + status
+ ", parentName=" + parentName + ", createBy=" + createBy + ", createTime=" + createTime + ", updateBy="
+ updateBy + ", updateTime=" + updateTime + "]";
}
}

View File

@ -0,0 +1,150 @@
package com.ruoyi.project.system.dept.service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.security.ShiroUtils;
import com.ruoyi.project.system.dept.dao.IDeptDao;
import com.ruoyi.project.system.dept.domain.Dept;
/**
* 部门管理 服务实现
*
* @author ruoyi
*/
@Repository("deptService")
public class DeptServiceImpl implements IDeptService
{
@Autowired
private IDeptDao deptDao;
/**
* 查询部门管理集合
*
* @return 所有部门信息
*/
@Override
public List<Dept> selectDeptAll()
{
return deptDao.selectDeptAll();
}
/**
* 查询部门管理树
*
* @return 所有部门信息
*/
@Override
public List<Map<String, Object>> selectDeptTree()
{
List<Map<String, Object>> trees = new ArrayList<Map<String, Object>>();
List<Dept> deptList = deptDao.selectDeptAll();
for (Dept dept : deptList)
{
Map<String, Object> deptMap = new HashMap<String, Object>();
deptMap.put("id", dept.getDeptId());
deptMap.put("pId", dept.getParentId());
deptMap.put("name", dept.getDeptName());
trees.add(deptMap);
}
return trees;
}
/**
* 查询部门人数
*
* @param parentId 部门ID
* @return 结果
*/
@Override
public int selectDeptCount(Long parentId)
{
Dept dept = new Dept();
dept.setParentId(parentId);
return deptDao.selectDeptCount(dept);
}
/**
* 查询部门是否存在用户
*
* @param deptId 部门ID
* @return 结果 true 存在 false 不存在
*/
@Override
public boolean checkDeptExistUser(Long deptId)
{
int result = deptDao.checkDeptExistUser(deptId);
return result > 0 ? true : false;
}
/**
* 删除部门管理信息
*
* @param deptId 部门ID
* @return 结果
*/
@Override
public int deleteDeptById(Long deptId)
{
return deptDao.deleteDeptById(deptId);
}
/**
* 保存部门信息
*
* @param dept 部门信息
* @return 结果
*/
@Override
public int saveDept(Dept dept)
{
if (StringUtils.isNotNull(dept.getDeptId()))
{
dept.setUpdateBy(ShiroUtils.getLoginName());
return deptDao.updateDept(dept);
}
else
{
dept.setCreateBy(ShiroUtils.getLoginName());
return deptDao.insertDept(dept);
}
}
/**
* 根据部门ID查询信息
*
* @param deptId 部门ID
* @return 部门信息
*/
@Override
public Dept selectDeptById(Long deptId)
{
return deptDao.selectDeptById(deptId);
}
/**
* 校验部门名称是否唯一
*
* @param dept 部门信息
* @return 结果
*/
@Override
public String checkDeptNameUnique(Dept dept)
{
Long deptId = dept.getDeptId();
Dept info = deptDao.checkDeptNameUnique(dept.getDeptName());
if (StringUtils.isNotNull(info) && StringUtils.isNotNull(info.getDeptId())
&& info.getDeptId().longValue() != deptId.longValue())
{
return UserConstants.NAME_NOT_UNIQUE;
}
return UserConstants.NAME_UNIQUE;
}
}

View File

@ -0,0 +1,77 @@
package com.ruoyi.project.system.dept.service;
import java.util.List;
import java.util.Map;
import com.ruoyi.project.system.dept.domain.Dept;
/**
* 部门管理 服务层
*
* @author ruoyi
*/
public interface IDeptService
{
/**
* 查询部门管理集合
*
* @return 所有部门信息
*/
public List<Dept> selectDeptAll();
/**
* 查询部门管理树
*
* @return 所有部门信息
*/
public List<Map<String, Object>> selectDeptTree();
/**
* 查询部门人数
*
* @param parentId 父部门ID
* @return 结果
*/
public int selectDeptCount(Long parentId);
/**
* 查询部门是否存在用户
*
* @param deptId 部门ID
* @return 结果 true 存在 false 不存在
*/
public boolean checkDeptExistUser(Long deptId);
/**
* 删除部门管理信息
*
* @param deptId 部门ID
* @return 结果
*/
public int deleteDeptById(Long deptId);
/**
* 保存部门信息
*
* @param dept 部门信息
* @return 结果
*/
public int saveDept(Dept dept);
/**
* 根据部门ID查询信息
*
* @param deptId 部门ID
* @return 部门信息
*/
public Dept selectDeptById(Long deptId);
/**
* 校验部门名称是否唯一
*
* @param dept 部门信息
* @return 结果
*/
public String checkDeptNameUnique(Dept dept);
}

View File

@ -0,0 +1,127 @@
package com.ruoyi.project.system.dict.controller;
import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.JSON;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.project.system.dict.domain.DictData;
import com.ruoyi.project.system.dict.service.IDictDataService;
/**
* 数据字典信息
*
* @author ruoyi
*/
@Controller
@RequestMapping("/system/dict/data")
public class DictDataController extends BaseController
{
private String prefix = "system/dict/data";
@Autowired
private IDictDataService dictDataService;
@RequiresPermissions("system:dict:view")
@GetMapping()
public String dictData()
{
return prefix + "/data";
}
@GetMapping("/list")
@RequiresPermissions("system:dict:list")
@ResponseBody
public TableDataInfo list(DictData dictData)
{
setPageInfo(dictData);
List<DictData> list = dictDataService.selectDictDataList(dictData);
return getDataTable(list);
}
/**
* 修改字典类型
*/
@Log(title = "系统管理", action = "字典管理-修改字典数据")
@RequiresPermissions("system:dict:edit")
@GetMapping("/edit/{dictCode}")
public String edit(@PathVariable("dictCode") Long dictCode, Model model)
{
DictData dict = dictDataService.selectDictDataById(dictCode);
model.addAttribute("dict", dict);
return prefix + "/edit";
}
/**
* 新增字典类型
*/
@Log(title = "系统管理", action = "字典管理-新增字典数据")
@RequiresPermissions("system:dict:add")
@GetMapping("/add/{dictType}")
public String add(@PathVariable("dictType") String dictType, Model model)
{
model.addAttribute("dictType", dictType);
return prefix + "/add";
}
/**
* 保存字典类型
*/
@Log(title = "系统管理", action = "字典管理-保存字典数据")
@RequiresPermissions("system:dict:save")
@PostMapping("/save")
@ResponseBody
public JSON save(DictData dict)
{
if (dictDataService.saveDictData(dict) > 0)
{
return JSON.ok();
}
return JSON.error();
}
/**
* 删除
*/
@Log(title = "系统管理", action = "字典管理-删除字典数据")
@RequiresPermissions("system:dict:remove")
@RequestMapping("/remove/{dictCode}")
@ResponseBody
public JSON remove(@PathVariable("dictCode") Long dictCode)
{
DictData dictData = dictDataService.selectDictDataById(dictCode);
if (dictData == null)
{
return JSON.error("字典数据不存在");
}
if (dictDataService.deleteDictDataById(dictCode) > 0)
{
return JSON.ok();
}
return JSON.error();
}
@Log(title = "系统管理", action = "字典类型-批量删除")
@RequiresPermissions("system:dict:batchRemove")
@PostMapping("/batchRemove")
@ResponseBody
public JSON batchRemove(@RequestParam("ids[]") Long[] ids)
{
int rows = dictDataService.batchDeleteDictData(ids);
if (rows > 0)
{
return JSON.ok();
}
return JSON.error();
}
}

View File

@ -0,0 +1,156 @@
package com.ruoyi.project.system.dict.controller;
import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.JSON;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.project.system.dict.domain.DictType;
import com.ruoyi.project.system.dict.service.IDictTypeService;
/**
* 数据字典信息
*
* @author ruoyi
*/
@Controller
@RequestMapping("/system/dict")
public class DictTypeController extends BaseController
{
private String prefix = "system/dict/type";
@Autowired
private IDictTypeService dictTypeService;
@RequiresPermissions("system:dict:view")
@GetMapping()
public String dictType()
{
return prefix + "/type";
}
@GetMapping("/list")
@RequiresPermissions("system:dict:list")
@ResponseBody
public TableDataInfo list(DictType dictType)
{
setPageInfo(dictType);
List<DictType> list = dictTypeService.selectDictTypeList(dictType);
return getDataTable(list);
}
/**
* 修改字典类型
*/
@Log(title = "系统管理", action = "字典管理-修改字典类型")
@RequiresPermissions("system:dict:edit")
@GetMapping("/edit/{dictId}")
public String edit(@PathVariable("dictId") Long dictId, Model model)
{
DictType dict = dictTypeService.selectDictTypeById(dictId);
model.addAttribute("dict", dict);
return prefix + "/edit";
}
/**
* 新增字典类型
*/
@Log(title = "系统管理", action = "字典管理-新增字典类型")
@RequiresPermissions("system:dict:add")
@GetMapping("/add")
public String add()
{
return prefix + "/add";
}
/**
* 保存字典类型
*/
@Log(title = "系统管理", action = "字典管理-保存字典类型")
@RequiresPermissions("system:dict:save")
@PostMapping("/save")
@ResponseBody
public JSON save(DictType dict)
{
if (dictTypeService.saveDictType(dict) > 0)
{
return JSON.ok();
}
return JSON.error();
}
/**
* 删除
*/
@Log(title = "系统管理", action = "字典管理-删除字典类型")
@RequiresPermissions("system:dict:remove")
@RequestMapping("/remove/{dictId}")
@ResponseBody
public JSON remove(@PathVariable("dictId") Long dictId)
{
DictType dictType = dictTypeService.selectDictTypeById(dictId);
if (dictType == null)
{
return JSON.error("字典不存在");
}
if (dictTypeService.deleteDictTypeById(dictId) > 0)
{
return JSON.ok();
}
return JSON.error();
}
@Log(title = "系统管理", action = "字典类型-批量删除")
@RequiresPermissions("system:dict:batchRemove")
@PostMapping("/batchRemove")
@ResponseBody
public JSON batchRemove(@RequestParam("ids[]") Long[] ids)
{
int rows = dictTypeService.batchDeleteDictType(ids);
if (rows > 0)
{
return JSON.ok();
}
return JSON.error();
}
/**
* 查询字典详细
*/
@Log(title = "系统管理", action = "字典管理-查询字典数据")
@RequiresPermissions("system:dict:list")
@GetMapping("/detail/{dictId}")
public String detail(@PathVariable("dictId") Long dictId, Model model)
{
DictType dict = dictTypeService.selectDictTypeById(dictId);
model.addAttribute("dict", dict);
return "system/dict/data/data";
}
/**
* 校验字典类型
*/
@PostMapping("/checkDictTypeUnique")
@ResponseBody
public String checkDictTypeUnique(DictType dictType)
{
String uniqueFlag = "0";
if (dictType != null)
{
uniqueFlag = dictTypeService.checkDictTypeUnique(dictType);
}
return uniqueFlag;
}
}

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