V3.0 项目Demo初始化

This commit is contained in:
seagull 2019-02-14 11:56:38 +08:00
parent fd698b613a
commit 74a23369d9
1749 changed files with 80770 additions and 203516 deletions

View File

@ -15,7 +15,6 @@
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
@ -23,6 +22,10 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk1.8.0_121"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="owner.project.facets" value="java"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@ -1,9 +1,8 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/main/resources=UTF-8
encoding//src/main/webapp/down.jsp=UTF-8
encoding//src/main/webapp/footer.jsp=UTF-8
encoding//src/main/webapp/head.jsp=UTF-8
encoding//src/main/webapp/index.jsp=UTF-8
encoding//src/main/resources/i18n/messages.properties=UTF-8
encoding//src/main/resources/static/css/main/style.min862f.css=UTF-8
encoding//src/main/resources/static/css/style.css=UTF-8
encoding//src/test/java=UTF-8
encoding/<project>=UTF-8

View File

@ -1,13 +1,13 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.7
org.eclipse.jdt.core.compiler.source=1.8

View File

@ -3,5 +3,5 @@
<fixed facet="wst.jsdt.web"/>
<installed facet="jst.web" version="3.0"/>
<installed facet="wst.jsdt.web" version="1.0"/>
<installed facet="java" version="1.7"/>
<installed facet="java" version="1.8"/>
</faceted-project>

View File

@ -0,0 +1,839 @@
-- ----------------------------
-- 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;
-- ----------------------------
-- 11、部门表
-- ----------------------------
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',
ancestors varchar(50) default '' comment '祖级列表',
dept_name varchar(30) default '' comment '部门名称',
order_num int(4) default 0 comment '显示顺序',
leader varchar(20) default null comment '负责人',
phone varchar(11) default null comment '联系电话',
email varchar(50) default null comment '邮箱',
status char(1) default '0' comment '部门状态0正常 1停用',
del_flag char(1) default '0' comment '删除标志0代表存在 2代表删除',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time datetime comment '更新时间',
primary key (dept_id)
) engine=innodb auto_increment=200 default charset=utf8 comment = '部门表';
-- ----------------------------
-- 初始化-部门表数据
-- ----------------------------
insert into sys_dept
values(100, 0, '0', 'LF总公司', 0, 'luckyframe', '15888888888', 'admin@luckyframe.cn', '0', '0', 'admin', '2019-02-13 10-27-32', 'admin', '2019-02-13 10-27-32');
insert into sys_dept
values(101, 100, '0,100', '深圳分公司', 1, 'luckyframe', '15888888888', 'admin@luckyframe.cn', '0', '0', 'admin', '2019-02-13 10-27-32', 'admin', '2019-02-13 10-27-32');
insert into sys_dept
values(102, 100, '0,100', '长沙分公司', 2, 'luckyframe', '15888888888', 'admin@luckyframe.cn', '0', '0', 'admin', '2019-02-13 10-27-32', 'admin', '2019-02-13 10-27-32');
insert into sys_dept
values(103, 101, '0,100,101', '研发部门', 1, 'luckyframe', '15888888888', 'admin@luckyframe.cn', '0', '0', 'admin', '2019-02-13 10-27-32', 'admin', '2019-02-13 10-27-32');
insert into sys_dept
values(104, 101, '0,100,101', '测试部门', 3, 'luckyframe', '15888888888', 'admin@luckyframe.cn', '0', '0', 'admin', '2019-02-13 10-27-32', 'admin', '2019-02-13 10-27-32');
insert into sys_dept
values(105, 101, '0,100,101', '运维部门', 5, 'luckyframe', '15888888888', 'admin@luckyframe.cn', '0', '0', 'admin', '2019-02-13 10-27-32', 'admin', '2019-02-13 10-27-32');
insert into sys_dept
values(106, 102, '0,100,102', '测试部门', 1, 'luckyframe', '15888888888', 'admin@luckyframe.cn', '0', '0', 'admin', '2019-02-13 10-27-32', 'admin', '2019-02-13 10-27-32');
insert into sys_dept
values(107, 102, '0,100,102', '研发部门', 2, 'luckyframe', '15888888888', 'admin@luckyframe.cn', '0', '0', 'admin', '2019-02-13 10-27-32', 'admin', '2019-02-13 10-27-32');
-- ----------------------------
-- 29、测试项目表
-- ----------------------------
drop table if exists sys_project;
create table sys_project (
project_id int(4) not null auto_increment comment '项目ID',
project_name varchar(50) not null comment '项目名称',
dept_id int(11) not null comment '归属部门',
project_sign varchar(10) default 'sign' not null comment '项目标识',
primary key (project_id)
) engine=innodb default charset=utf8 comment = '测试项目管理表';
-- ----------------------------
-- 初始化-测试项目表数据
-- ----------------------------
/*插入默认项目*/
insert into sys_project values (1, '接口测试项目', 104, 'ITT');
insert into sys_project values (2, 'UI测试项目', 106, 'UIT');
-- ----------------------------
-- 12、用户信息表
-- ----------------------------
drop table if exists sys_user;
create table sys_user (
user_id int(11) not null auto_increment comment '用户ID',
dept_id int(11) default null comment '部门ID',
login_name varchar(30) not null comment '登录账号',
user_name varchar(30) not null comment '用户昵称',
user_type varchar(2) default '00' comment '用户类型00系统用户',
email varchar(50) default '' comment '用户邮箱',
phonenumber varchar(11) default '' comment '手机号码',
sex char(1) default '0' comment '用户性别0男 1女 2未知',
avatar varchar(100) default '' comment '头像路径',
password varchar(50) default '' comment '密码',
salt varchar(20) default '' comment '盐加密',
status char(1) default '0' comment '帐号状态0正常 1停用',
del_flag char(1) default '0' comment '删除标志0代表存在 2代表删除',
login_ip varchar(50) default '' comment '最后登陆IP',
login_date datetime comment '最后登陆时间',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time datetime comment '更新时间',
remark varchar(500) default '' comment '备注',
primary key (user_id)
) engine=innodb auto_increment=100 default charset=utf8 comment = '用户信息表';
-- ----------------------------
-- 初始化-用户信息表数据
-- ----------------------------
insert into sys_user values(1, 103, 'admin', 'luckyframe', '00', 'ry@163.com', '15888888888', '1', '', '29c67a30398638269fe600f73a054934', '111111', '0', '0', '127.0.0.1', '2019-02-13 10-27-32', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '管理员');
insert into sys_user values(2, 105, 'luckyframe', 'luckyframe', '00', 'ry@qq.com', '15666666666', '1', '', '8e6d98b90472783cc73c17047ddccf36', '222222', '0', '0', '127.0.0.1', '2019-02-13 10-27-32', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '测试员');
-- ----------------------------
-- 13、岗位信息表
-- ----------------------------
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(50) not null comment '岗位名称',
post_sort int(4) not null comment '显示顺序',
status char(1) not null comment '状态0正常 1停用',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time datetime comment '更新时间',
remark varchar(500) default null comment '备注',
primary key (post_id)
) engine=innodb default charset=utf8 comment = '岗位信息表';
-- ----------------------------
-- 初始化-岗位信息表数据
-- ----------------------------
insert into sys_post values(1, 'PM', '项目经理', 1, '0', 'admin', '2019-02-13 10-27-32', 'admin', '2019-02-13 10-27-32', '');
insert into sys_post values(2, 'DE', '开发工程师', 2, '0', 'admin', '2019-02-13 10-27-32', 'admin', '2019-02-13 10-27-32', '');
insert into sys_post values(3, 'TM', '测试经理', 3, '0', 'admin', '2019-02-13 10-27-32', 'admin', '2019-02-13 10-27-32', '');
insert into sys_post values(4, 'TE', '测试工程师', 4, '0', 'admin', '2019-02-13 10-27-32', 'admin', '2019-02-13 10-27-32', '');
-- ----------------------------
-- 14、角色信息表
-- ----------------------------
drop table if exists sys_role;
create table sys_role (
role_id int(11) not null auto_increment comment '角色ID',
role_name varchar(30) not null comment '角色名称',
role_key varchar(100) not null comment '角色权限字符串',
role_sort int(4) not null comment '显示顺序',
data_scope char(1) default '1' comment '数据范围1全部数据权限 2自定数据权限',
status char(1) not null comment '角色状态0正常 1停用',
del_flag char(1) default '0' comment '删除标志0代表存在 2代表删除',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time datetime comment '更新时间',
remark varchar(500) default null comment '备注',
primary key (role_id)
) engine=innodb auto_increment=100 default charset=utf8 comment = '角色信息表';
-- ----------------------------
-- 初始化-角色信息表数据
-- ----------------------------
insert into sys_role values('1', '管理员', 'admin', 1, 1, '0', '0', 'admin', '2019-02-13 10-27-32', 'admin', '2019-02-13 10-27-32', '管理员');
insert into sys_role values('2', '普通角色', 'common', 2, 2, '0', '0', 'admin', '2019-02-13 10-27-32', 'admin', '2019-02-13 10-27-32', '普通角色');
-- ----------------------------
-- 15、菜单权限表
-- ----------------------------
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 0 comment '显示顺序',
url varchar(200) default '#' comment '请求地址',
menu_type char(1) default '' comment '菜单类型M目录 C菜单 F按钮',
visible char(1) default 0 comment '菜单状态0显示 1隐藏',
perms varchar(100) default null comment '权限标识',
icon varchar(100) default '#' comment '菜单图标',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time datetime comment '更新时间',
remark varchar(500) default '' comment '备注',
primary key (menu_id)
) engine=innodb auto_increment=2000 default charset=utf8 comment = '菜单权限表';
-- ----------------------------
-- 初始化-菜单信息表数据
-- ----------------------------
-- 一级菜单
insert into sys_menu values('1', '系统管理', '0', '1', '#', 'M', '0', '', 'fa fa-gear', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '系统管理目录');
insert into sys_menu values('2', '系统监控', '0', '2', '#', 'M', '0', '', 'fa fa-video-camera', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '系统监控目录');
insert into sys_menu values('3', '系统工具', '0', '3', '#', 'M', '0', '', 'fa fa-bars', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '系统工具目录');
-- 二级菜单
insert into sys_menu values('100', '用户管理', '1', '1', '/system/user', 'C', '0', 'system:user:view', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '用户管理菜单');
insert into sys_menu values('101', '角色管理', '1', '2', '/system/role', 'C', '0', 'system:role:view', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '角色管理菜单');
insert into sys_menu values('102', '菜单管理', '1', '3', '/system/menu', 'C', '0', 'system:menu:view', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '菜单管理菜单');
insert into sys_menu values('103', '部门管理', '1', '4', '/system/dept', 'C', '0', 'system:dept:view', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '部门管理菜单');
insert into sys_menu values('104', '项目管理', '1', '5', '/system/project', 'C', '0', 'system:project:view', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '项目管理菜单');
insert into sys_menu values('105', '岗位管理', '1', '6', '/system/post', 'C', '0', 'system:post:view', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '岗位管理菜单');
insert into sys_menu values('106', '字典管理', '1', '7', '/system/dict', 'C', '0', 'system:dict:view', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '字典管理菜单');
insert into sys_menu values('107', '参数设置', '1', '8', '/system/config', 'C', '0', 'system:config:view', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '参数设置菜单');
insert into sys_menu values('108', '通知公告', '1', '9', '/system/notice', 'C', '0', 'system:notice:view', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '通知公告菜单');
insert into sys_menu values('109', '日志管理', '1', '10', '#', 'M', '0', '', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '日志管理菜单');
insert into sys_menu values('110', '在线用户', '2', '1', '/monitor/online', 'C', '0', 'monitor:online:view', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '在线用户菜单');
insert into sys_menu values('111', '定时任务', '2', '2', '/monitor/job', 'C', '0', 'monitor:job:view', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '定时任务菜单');
insert into sys_menu values('112', '数据监控', '2', '3', '/monitor/data', 'C', '0', 'monitor:data:view', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '数据监控菜单');
insert into sys_menu values('113', '服务监控', '2', '3', '/monitor/server', 'C', '0', 'monitor:server:view', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '服务监控菜单');
insert into sys_menu values('114', '表单构建', '3', '1', '/tool/build', 'C', '0', 'tool:build:view', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '表单构建菜单');
insert into sys_menu values('115', '代码生成', '3', '2', '/tool/gen', 'C', '0', 'tool:gen:view', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '代码生成菜单');
insert into sys_menu values('116', '系统接口', '3', '3', '/tool/swagger', 'C', '0', 'tool:swagger:view', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '系统接口菜单');
-- 三级菜单
insert into sys_menu values('500', '操作日志', '108', '1', '/monitor/operlog', 'C', '0', 'monitor:operlog:view', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '操作日志菜单');
insert into sys_menu values('501', '登录日志', '108', '2', '/monitor/logininfor', 'C', '0', 'monitor:logininfor:view', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '登录日志菜单');
-- 用户管理按钮
insert into sys_menu values('1000', '用户查询', '100', '1', '#', 'F', '0', 'system:user:list', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1001', '用户新增', '100', '2', '#', 'F', '0', 'system:user:add', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1002', '用户修改', '100', '3', '#', 'F', '0', 'system:user:edit', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1003', '用户删除', '100', '4', '#', 'F', '0', 'system:user:remove', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1004', '用户导出', '100', '5', '#', 'F', '0', 'system:user:export', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1005', '用户导入', '100', '6', '#', 'F', '0', 'system:user:import', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1006', '重置密码', '100', '7', '#', 'F', '0', 'system:user:resetPwd', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
-- 角色管理按钮
insert into sys_menu values('1007', '角色查询', '101', '1', '#', 'F', '0', 'system:role:list', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1008', '角色新增', '101', '2', '#', 'F', '0', 'system:role:add', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1009', '角色修改', '101', '3', '#', 'F', '0', 'system:role:edit', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1010', '角色删除', '101', '4', '#', 'F', '0', 'system:role:remove', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1011', '角色导出', '101', '5', '#', 'F', '0', 'system:role:export', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
-- 菜单管理按钮
insert into sys_menu values('1012', '菜单查询', '102', '1', '#', 'F', '0', 'system:menu:list', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1013', '菜单新增', '102', '2', '#', 'F', '0', 'system:menu:add', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1014', '菜单修改', '102', '3', '#', 'F', '0', 'system:menu:edit', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1015', '菜单删除', '102', '4', '#', 'F', '0', 'system:menu:remove', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
-- 部门管理按钮
insert into sys_menu values('1016', '部门查询', '103', '1', '#', 'F', '0', 'system:dept:list', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1017', '部门新增', '103', '2', '#', 'F', '0', 'system:dept:add', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1018', '部门修改', '103', '3', '#', 'F', '0', 'system:dept:edit', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1019', '部门删除', '103', '4', '#', 'F', '0', 'system:dept:remove', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
-- 岗位管理按钮
insert into sys_menu values('1020', '岗位查询', '105', '1', '#', 'F', '0', 'system:post:list', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1021', '岗位新增', '105', '2', '#', 'F', '0', 'system:post:add', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1022', '岗位修改', '105', '3', '#', 'F', '0', 'system:post:edit', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1023', '岗位删除', '105', '4', '#', 'F', '0', 'system:post:remove', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1024', '岗位导出', '105', '5', '#', 'F', '0', 'system:post:export', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
-- 字典管理按钮
insert into sys_menu values('1025', '字典查询', '106', '1', '#', 'F', '0', 'system:dict:list', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1026', '字典新增', '106', '2', '#', 'F', '0', 'system:dict:add', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1027', '字典修改', '106', '3', '#', 'F', '0', 'system:dict:edit', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1028', '字典删除', '106', '4', '#', 'F', '0', 'system:dict:remove', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1029', '字典导出', '106', '5', '#', 'F', '0', 'system:dict:export', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
-- 参数设置按钮
insert into sys_menu values('1030', '参数查询', '107', '1', '#', 'F', '0', 'system:config:list', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1031', '参数新增', '107', '2', '#', 'F', '0', 'system:config:add', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1032', '参数修改', '107', '3', '#', 'F', '0', 'system:config:edit', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1033', '参数删除', '107', '4', '#', 'F', '0', 'system:config:remove', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1034', '参数导出', '107', '5', '#', 'F', '0', 'system:config:export', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
-- 通知公告按钮
insert into sys_menu values('1035', '公告查询', '108', '1', '#', 'F', '0', 'system:notice:list', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1036', '公告新增', '108', '2', '#', 'F', '0', 'system:notice:add', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1037', '公告修改', '108', '3', '#', 'F', '0', 'system:notice:edit', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1038', '公告删除', '108', '4', '#', 'F', '0', 'system:notice:remove', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
-- 操作日志按钮
insert into sys_menu values('1039', '操作查询', '500', '1', '#', 'F', '0', 'monitor:operlog:list', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1040', '操作删除', '500', '2', '#', 'F', '0', 'monitor:operlog:remove', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1041', '详细信息', '500', '3', '#', 'F', '0', 'monitor:operlog:detail', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1042', '日志导出', '500', '4', '#', 'F', '0', 'monitor:operlog:export', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
-- 登录日志按钮
insert into sys_menu values('1043', '登录查询', '501', '1', '#', 'F', '0', 'monitor:logininfor:list', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1044', '登录删除', '501', '2', '#', 'F', '0', 'monitor:logininfor:remove', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1045', '日志导出', '501', '3', '#', 'F', '0', 'monitor:logininfor:export', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
-- 在线用户按钮
insert into sys_menu values('1046', '在线查询', '110', '1', '#', 'F', '0', 'monitor:online:list', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1047', '批量强退', '110', '2', '#', 'F', '0', 'monitor:online:batchForceLogout', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1048', '单条强退', '110', '3', '#', 'F', '0', 'monitor:online:forceLogout', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
-- 定时任务按钮
insert into sys_menu values('1049', '任务查询', '111', '1', '#', 'F', '0', 'monitor:job:list', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1050', '任务新增', '111', '2', '#', 'F', '0', 'monitor:job:add', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1051', '任务修改', '111', '3', '#', 'F', '0', 'monitor:job:edit', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1052', '任务删除', '111', '4', '#', 'F', '0', 'monitor:job:remove', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1053', '状态修改', '111', '5', '#', 'F', '0', 'monitor:job:changeStatus', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1054', '任务详细', '111', '6', '#', 'F', '0', 'monitor:job:detail', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1055', '任务导出', '111', '7', '#', 'F', '0', 'monitor:job:export', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
-- 代码生成按钮
insert into sys_menu values('1056', '生成查询', '115', '1', '#', 'F', '0', 'tool:gen:list', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1057', '生成代码', '115', '2', '#', 'F', '0', 'tool:gen:code', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
-- 测试项目管理按钮
insert into sys_menu values('1058', '项目查询', '104', '1', '#', 'F', '0', 'system:project:list', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1059', '项目新增', '104', '2', '#', 'F', '0', 'system:project:add', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1060', '项目修改', '104', '3', '#', 'F', '0', 'system:project:edit', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_menu values('1061', '项目删除', '104', '4', '#', 'F', '0', 'system:project:remove', '#', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
-- ----------------------------
-- 16、用户和角色关联表 用户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');
-- ----------------------------
-- 17、角色和菜单关联表 角色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 ('2', '1');
insert into sys_role_menu values ('2', '2');
insert into sys_role_menu values ('2', '3');
insert into sys_role_menu values ('2', '100');
insert into sys_role_menu values ('2', '101');
insert into sys_role_menu values ('2', '102');
insert into sys_role_menu values ('2', '103');
insert into sys_role_menu values ('2', '104');
insert into sys_role_menu values ('2', '105');
insert into sys_role_menu values ('2', '106');
insert into sys_role_menu values ('2', '107');
insert into sys_role_menu values ('2', '108');
insert into sys_role_menu values ('2', '109');
insert into sys_role_menu values ('2', '110');
insert into sys_role_menu values ('2', '111');
insert into sys_role_menu values ('2', '112');
insert into sys_role_menu values ('2', '113');
insert into sys_role_menu values ('2', '114');
insert into sys_role_menu values ('2', '115');
insert into sys_role_menu values ('2', '116');
insert into sys_role_menu values ('2', '500');
insert into sys_role_menu values ('2', '501');
insert into sys_role_menu values ('2', '1000');
insert into sys_role_menu values ('2', '1001');
insert into sys_role_menu values ('2', '1002');
insert into sys_role_menu values ('2', '1003');
insert into sys_role_menu values ('2', '1004');
insert into sys_role_menu values ('2', '1005');
insert into sys_role_menu values ('2', '1006');
insert into sys_role_menu values ('2', '1007');
insert into sys_role_menu values ('2', '1008');
insert into sys_role_menu values ('2', '1009');
insert into sys_role_menu values ('2', '1010');
insert into sys_role_menu values ('2', '1011');
insert into sys_role_menu values ('2', '1012');
insert into sys_role_menu values ('2', '1013');
insert into sys_role_menu values ('2', '1014');
insert into sys_role_menu values ('2', '1015');
insert into sys_role_menu values ('2', '1016');
insert into sys_role_menu values ('2', '1017');
insert into sys_role_menu values ('2', '1018');
insert into sys_role_menu values ('2', '1019');
insert into sys_role_menu values ('2', '1020');
insert into sys_role_menu values ('2', '1021');
insert into sys_role_menu values ('2', '1022');
insert into sys_role_menu values ('2', '1023');
insert into sys_role_menu values ('2', '1024');
insert into sys_role_menu values ('2', '1025');
insert into sys_role_menu values ('2', '1026');
insert into sys_role_menu values ('2', '1027');
insert into sys_role_menu values ('2', '1028');
insert into sys_role_menu values ('2', '1029');
insert into sys_role_menu values ('2', '1030');
insert into sys_role_menu values ('2', '1031');
insert into sys_role_menu values ('2', '1032');
insert into sys_role_menu values ('2', '1033');
insert into sys_role_menu values ('2', '1034');
insert into sys_role_menu values ('2', '1035');
insert into sys_role_menu values ('2', '1036');
insert into sys_role_menu values ('2', '1037');
insert into sys_role_menu values ('2', '1038');
insert into sys_role_menu values ('2', '1039');
insert into sys_role_menu values ('2', '1040');
insert into sys_role_menu values ('2', '1041');
insert into sys_role_menu values ('2', '1042');
insert into sys_role_menu values ('2', '1043');
insert into sys_role_menu values ('2', '1044');
insert into sys_role_menu values ('2', '1045');
insert into sys_role_menu values ('2', '1046');
insert into sys_role_menu values ('2', '1047');
insert into sys_role_menu values ('2', '1048');
insert into sys_role_menu values ('2', '1049');
insert into sys_role_menu values ('2', '1050');
insert into sys_role_menu values ('2', '1051');
insert into sys_role_menu values ('2', '1052');
insert into sys_role_menu values ('2', '1053');
insert into sys_role_menu values ('2', '1054');
insert into sys_role_menu values ('2', '1055');
insert into sys_role_menu values ('2', '1056');
insert into sys_role_menu values ('2', '1057');
-- ----------------------------
-- 18、角色和项目关联表 角色1-N项目
-- ----------------------------
drop table if exists sys_role_project;
create table sys_role_project (
role_id int(11) not null comment '角色ID',
project_id int(11) not null comment '项目ID',
primary key(role_id, project_id)
) engine=innodb default charset=utf8 comment = '角色和项目关联表';
-- ----------------------------
-- 初始化-角色和项目关联表数据
-- ----------------------------
insert into sys_role_project values ('2', '1');
insert into sys_role_project values ('2', '2');
-- ----------------------------
-- 8、角色和部门关联表 角色1-N部门
-- ----------------------------
drop table if exists sys_role_dept;
create table sys_role_dept (
role_id int(11) not null comment '角色ID',
dept_id int(11) not null comment '部门ID',
primary key(role_id, dept_id)
) engine=innodb default charset=utf8 comment = '角色和部门关联表';
-- ----------------------------
-- 初始化-角色和部门关联表数据
-- ----------------------------
insert into sys_role_dept values ('2', '100');
insert into sys_role_dept values ('2', '101');
insert into sys_role_dept values ('2', '105');
-- ----------------------------
-- 19、用户与岗位关联表 用户1-N岗位
-- ----------------------------
drop table if exists sys_user_post;
create table sys_user_post
(
user_id int(11) not null comment '用户ID',
post_id int(11) 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');
-- ----------------------------
-- 20、操作日志记录
-- ----------------------------
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 '模块标题',
business_type int(2) default 0 comment '业务类型0其它 1新增 2修改 3删除',
method varchar(100) default '' comment '方法名称',
operator_type int(1) default 0 comment '操作类别0其它 1后台用户 2手机端用户',
oper_name varchar(50) default '' comment '操作人员',
dept_name varchar(50) default '' comment '部门名称',
oper_url varchar(255) default '' comment '请求URL',
oper_ip varchar(50) default '' comment '主机地址',
oper_location varchar(255) default '' comment '操作地点',
oper_param varchar(255) default '' comment '请求参数',
status int(1) default 0 comment '操作状态0正常 1异常',
error_msg varchar(2000) default '' comment '错误消息',
oper_time datetime comment '操作时间',
primary key (oper_id)
) engine=innodb auto_increment=100 default charset=utf8 comment = '操作日志记录';
-- ----------------------------
-- 21、字典类型表
-- ----------------------------
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 char(1) default '0' comment '状态0正常 1停用',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time datetime comment '更新时间',
remark varchar(500) default null 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_user_sex', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '用户性别列表');
insert into sys_dict_type values(2, '菜单状态', 'sys_show_hide', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '菜单状态列表');
insert into sys_dict_type values(3, '系统开关', 'sys_normal_disable', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '系统开关列表');
insert into sys_dict_type values(4, '任务状态', 'sys_job_status', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '任务状态列表');
insert into sys_dict_type values(5, '系统是否', 'sys_yes_no', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '系统是否列表');
insert into sys_dict_type values(6, '通知类型', 'sys_notice_type', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '通知类型列表');
insert into sys_dict_type values(7, '通知状态', 'sys_notice_status', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '通知状态列表');
insert into sys_dict_type values(8, '操作类型', 'sys_oper_type', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '操作类型列表');
insert into sys_dict_type values(9, '系统状态', 'sys_common_status', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '登录状态列表');
-- ----------------------------
-- 22、字典数据表
-- ----------------------------
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 '字典类型',
css_class varchar(100) default null comment '样式属性(其他样式扩展)',
list_class varchar(100) default null comment '表格回显样式',
is_default char(1) default 'N' comment '是否默认Y是 N否',
status char(1) default '0' comment '状态0正常 1停用',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time datetime comment '更新时间',
remark varchar(500) default null comment '备注',
primary key (dict_code)
) engine=innodb auto_increment=100 default charset=utf8 comment = '字典数据表';
insert into sys_dict_data values(1, 1, '', '0', 'sys_user_sex', '', '', 'Y', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '性别男');
insert into sys_dict_data values(2, 2, '', '1', 'sys_user_sex', '', '', 'N', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '性别女');
insert into sys_dict_data values(3, 3, '未知', '2', 'sys_user_sex', '', '', 'N', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '性别未知');
insert into sys_dict_data values(4, 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '显示菜单');
insert into sys_dict_data values(5, 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '隐藏菜单');
insert into sys_dict_data values(6, 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '正常状态');
insert into sys_dict_data values(7, 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '停用状态');
insert into sys_dict_data values(8, 1, '正常', '0', 'sys_job_status', '', 'primary', 'Y', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '正常状态');
insert into sys_dict_data values(9, 2, '暂停', '1', 'sys_job_status', '', 'danger', 'N', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '停用状态');
insert into sys_dict_data values(10, 1, '', 'Y', 'sys_yes_no', '', 'primary', 'Y', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '系统默认是');
insert into sys_dict_data values(11, 2, '', 'N', 'sys_yes_no', '', 'danger', 'N', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '系统默认否');
insert into sys_dict_data values(12, 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '通知');
insert into sys_dict_data values(13, 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '公告');
insert into sys_dict_data values(14, 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '正常状态');
insert into sys_dict_data values(15, 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '关闭状态');
insert into sys_dict_data values(16, 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '新增操作');
insert into sys_dict_data values(17, 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '修改操作');
insert into sys_dict_data values(18, 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '删除操作');
insert into sys_dict_data values(19, 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '授权操作');
insert into sys_dict_data values(20, 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '导出操作');
insert into sys_dict_data values(21, 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '导入操作');
insert into sys_dict_data values(22, 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '强退操作');
insert into sys_dict_data values(23, 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '生成操作');
insert into sys_dict_data values(24, 8, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '清空操作');
insert into sys_dict_data values(25, 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '正常状态');
insert into sys_dict_data values(26, 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '停用状态');
-- ----------------------------
-- 23、参数配置表
-- ----------------------------
drop table if exists sys_config;
create table sys_config (
config_id int(5) not null auto_increment comment '参数主键',
config_name varchar(100) default '' comment '参数名称',
config_key varchar(100) default '' comment '参数键名',
config_value varchar(100) default '' comment '参数键值',
config_type char(1) default 'N' comment '系统内置Y是 N否',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time datetime comment '更新时间',
remark varchar(500) default null comment '备注',
primary key (config_id)
) engine=innodb auto_increment=100 default charset=utf8 comment = '参数配置表';
insert into sys_config values(1, '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow' );
insert into sys_config values(2, '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '初始化密码 123456' );
-- ----------------------------
-- 24、系统访问记录
-- ----------------------------
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地址',
login_location varchar(255) default '' comment '登录地点',
browser varchar(50) default '' comment '浏览器类型',
os varchar(50) default '' comment '操作系统',
status char(1) default '0' comment '登录状态0成功 1失败',
msg varchar(255) default '' comment '提示消息',
login_time datetime comment '访问时间',
primary key (info_id)
) engine=innodb auto_increment=100 default charset=utf8 comment = '系统访问记录';
-- ----------------------------
-- 25、在线用户记录
-- ----------------------------
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地址',
login_location varchar(255) default '' comment '登录地点',
browser varchar(50) default '' comment '浏览器类型',
os varchar(50) default '' comment '操作系统',
status varchar(10) default '' comment '在线状态on_line在线off_line离线',
start_timestamp datetime comment 'session创建时间',
last_access_time datetime comment 'session最后访问时间',
expire_time int(5) default 0 comment '超时时间,单位为分钟',
primary key (sessionId)
) engine=innodb default charset=utf8 comment = '在线用户记录';
-- ----------------------------
-- 26、定时任务调度表
-- ----------------------------
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 '任务方法',
method_params varchar(50) default null comment '方法参数',
cron_expression varchar(255) default '' comment 'cron执行表达式',
misfire_policy varchar(20) default '3' comment '计划执行错误策略1立即执行 2执行一次 3放弃执行',
status char(1) default '0' comment '状态0正常 1暂停',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time datetime 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 * * * * ?', '3', '1', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
insert into sys_job values(2, 'ryTask', '系统默认(有参)', 'ryParams', 'luckyframe', '0/20 * * * * ?', '3', '1', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '');
-- ----------------------------
-- 27、定时任务调度日志表
-- ----------------------------
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 '任务方法',
method_params varchar(50) default null comment '方法参数',
job_message varchar(500) comment '日志信息',
status char(1) default '0' comment '执行状态0正常 1失败',
exception_info varchar(2000) default '' comment '异常信息',
create_time datetime comment '创建时间',
primary key (job_log_id)
) engine=innodb default charset=utf8 comment = '定时任务调度日志表';
-- ----------------------------
-- 28、通知公告表
-- ----------------------------
drop table if exists sys_notice;
create table sys_notice (
notice_id int(4) not null auto_increment comment '公告ID',
notice_title varchar(50) not null comment '公告标题',
notice_type char(1) not null comment '公告类型1通知 2公告',
notice_content varchar(2000) default null comment '公告内容',
status char(1) default '0' comment '公告状态0正常 1关闭',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',
update_by varchar(64) default '' comment '更新者',
update_time datetime comment '更新时间',
remark varchar(255) default null comment '备注',
primary key (notice_id)
) engine=innodb auto_increment=10 default charset=utf8 comment = '通知公告表';
-- ----------------------------
-- 初始化-公告信息表数据
-- ----------------------------
insert into sys_notice values('1', '温馨提醒2018-07-01 若依新版本发布啦', '2', '新版本内容', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '管理员');
insert into sys_notice values('2', '维护通知2018-07-01 若依系统凌晨维护', '1', '维护内容', '0', 'admin', '2019-02-13 10-27-32', 'luckyframe', '2019-02-13 10-27-32', '管理员');

542
pom.xml
View File

@ -1,378 +1,304 @@
<?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/maven-v4_0_0.xsd">
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.seagull</groupId>
<artifactId>LuckyFrameServer</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>LuckyFrameServer Maven Webapp</name>
<url>http://maven.apache.org</url>
<build>
<finalName>LuckyFrameServer</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
<groupId>com.luckyframe</groupId>
<artifactId>LuckyFrameWeb</artifactId>
<version>3.0</version>
<packaging>jar</packaging>
<name>LuckyFrameWeb</name>
<url>http://www.luckyframe.cn</url>
<description>LuckyFrame开源测试平台</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.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.4.0</shiro.version>
<thymeleaf.extras.shiro.version>2.0.0</thymeleaf.extras.shiro.version>
<mybatis.spring.boot.starter.version>1.3.2</mybatis.spring.boot.starter.version>
<pagehelper.spring.boot.starter.version>1.2.5</pagehelper.spring.boot.starter.version>
<fastjson.version>1.2.47</fastjson.version>
<druid.version>1.1.10</druid.version>
<commons.io.version>2.5</commons.io.version>
<commons.fileupload.version>1.3.3</commons.fileupload.version>
<bitwalker.version>1.19</bitwalker.version>
<lombok.version>1.16.18</lombok.version>
<velocity.version>1.7</velocity.version>
<kaptcha.version>2.3.2</kaptcha.version>
<swagger.version>2.7.0</swagger.version>
<jsoup.version>1.11.3</jsoup.version>
<poi.version>3.17</poi.version>
<oshi.version>3.9.1</oshi.version>
</properties>
<repositories>
<repository>
<id>maven-ali</id>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>fail</checksumPolicy>
</snapshots>
</repository>
</repositories>
<dependencies>
<!-- SpringBoot 核心包 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<!--
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
-->
</dependency>
<!-- SpringBoot 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- SpringBoot 拦截器 -->
<dependency>
<groupId>antlr</groupId>
<artifactId>antlr</artifactId>
<version>2.7.7</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- SpringBoot Web容器 -->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringBoot集成thymeleaf模板 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.10</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- spring-boot-devtools -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.4.0.Final</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!-- <dependency> <groupId>commons-attributes</groupId> <artifactId>commons-attributes-api</artifactId>
<version>2.2</version> </dependency> <dependency> <groupId>commons-attributes</groupId>
<artifactId>commons-attributes-compiler</artifactId> <version>2.2</version>
</dependency> -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-digester</groupId>
<artifactId>commons-digester</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>commons-discovery</groupId>
<artifactId>commons-discovery</artifactId>
<version>0.5</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.6</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.5.1</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>ejb3-persistence</artifactId>
<version>3.3.2.Beta1</version>
</dependency>
<dependency>
<groupId>net.sf.ezmorph</groupId>
<artifactId>ezmorph</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-hibernate3</artifactId>
<version>2.0.8</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.5.6-Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>1.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>5.3.4.Final</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.21.0-GA</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional> <!-- 表示依赖不会传递 -->
</dependency>
<!-- Mysql驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<!-- SpringBoot集成mybatis框架 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>1.8.6</version>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.spring.boot.starter.version}</version>
</dependency>
<!-- pagehelper 分页插件 -->
<dependency>
<groupId>opensymphony</groupId>
<artifactId>quartz-all</artifactId>
<version>1.6.2</version>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pagehelper.spring.boot.starter.version}</version>
</dependency>
<!--阿里数据库连接池 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-commonj</artifactId>
<version>1.8.6</version>
</dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<!--常用工具类 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-oracle</artifactId>
<version>1.8.6</version>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!--io常用工具类 -->
<dependency>
<groupId>org.w3c.css</groupId>
<artifactId>sac</artifactId>
<version>1.3</version>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons.io.version}</version>
</dependency>
<!--文件上传工具类 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.22</version>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons.fileupload.version}</version>
</dependency>
<!--Shiro核心框架 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.22</version>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<!-- Shiro使用Srping框架 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.18.RELEASE</version>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<!-- Shiro使用EhCache缓存框架 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.18.RELEASE</version>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
<!-- thymeleaf模板引擎和shiro框架的整合 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.18.RELEASE</version>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>${thymeleaf.extras.shiro.version}</version>
</dependency>
<!-- 阿里JSON解析器 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.18.RELEASE</version>
<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>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- 定时任务 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.18.RELEASE</version>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<exclusions>
<exclusion>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--velocity代码生成使用模板 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.18.RELEASE</version>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>${velocity.version}</version>
</dependency>
<!--验证码 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>4.3.18.RELEASE</version>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>${kaptcha.version}</version>
<exclusions>
<exclusion>
<artifactId>javax.servlet-api</artifactId>
<groupId>javax.servlet</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- swagger2-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument-tomcat</artifactId>
<version>4.3.18.RELEASE</version>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
</dependency>
<!-- swagger2-UI-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.18.RELEASE</version>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<!-- 获取系统信息 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>4.3.18.RELEASE</version>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
<version>${oshi.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.3.18.RELEASE</version>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>4.3.18.RELEASE</version>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
</dependency>
<!-- HTML解析器 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-struts</artifactId>
<version>3.2.18.RELEASE</version>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>${jsoup.version}</version>
</dependency>
<!-- excel工具 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork> <!-- 如果没有该配置devtools不会生效 -->
</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,27 @@
package com.luckyframe;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
/**
* 启动LuckyFrameWeb程序
* =================================================================
* 这是一个受限制的自由软件您不能在任何未经允许的前提下对程序代码进行修改和用于商业用途也不允许对程序代码修改后以任何形式任何目的的再发布
* 为了尊重作者的劳动成果LuckyFrame关键版权信息严禁篡改 有任何疑问欢迎联系作者讨论 QQ:1573584944 Seagull
* =================================================================
* @author Seagull
* @date 2019年2月12日
*/
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
@MapperScan("com.luckyframe.project.*.*.mapper")
public class LuckyFrameWebApplication
{
public static void main(String[] args)
{
// System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(LuckyFrameWebApplication.class, args);
System.out.println("LuckyFrameWeb启动成功......");
}
}

View File

@ -0,0 +1,22 @@
package com.luckyframe;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
/**
* 容器部署
* =================================================================
* 这是一个受限制的自由软件您不能在任何未经允许的前提下对程序代码进行修改和用于商业用途也不允许对程序代码修改后以任何形式任何目的的再发布
* 为了尊重作者的劳动成果LuckyFrame关键版权信息严禁篡改 有任何疑问欢迎联系作者讨论 QQ:1573584944 Seagull
* =================================================================
* @author Seagull
* @date 2019年2月12日
*/
public class LuckyFrameWebServletInitializer extends SpringBootServletInitializer
{
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
{
return application.sources(LuckyFrameWebApplication.class);
}
}

View File

@ -0,0 +1,49 @@
package com.luckyframe.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("number", "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("varchar2", "String");
javaTypeMap.put("tinytext", "String");
javaTypeMap.put("text", "String");
javaTypeMap.put("mediumtext", "String");
javaTypeMap.put("longtext", "String");
javaTypeMap.put("time", "Date");
javaTypeMap.put("date", "Date");
javaTypeMap.put("datetime", "Date");
javaTypeMap.put("timestamp", "Date");
}
}

View File

@ -0,0 +1,64 @@
package com.luckyframe.common.constant;
/**
* 通用常量信息
*
* @author ruoyi
*/
public class Constants
{
/**
* UTF-8 字符集
*/
public static final String UTF8 = "UTF-8";
/**
* 通用成功标识
*/
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";
/**
* 当前记录起始索引
*/
public static String PAGE_NUM = "pageNum";
/**
* 每页显示记录数
*/
public static String PAGE_SIZE = "pageSize";
/**
* 排序列
*/
public static String ORDER_BY_COLUMN = "orderByColumn";
/**
* 排序的方向 "desc" 或者 "asc".
*/
public static String IS_ASC = "isAsc";
}

View File

@ -0,0 +1,27 @@
package com.luckyframe.common.constant;
/**
* 权限通用常量
*
* @author ruoyi
*/
public class PermissionConstants
{
/** 新增权限 */
public static final String ADD_PERMISSION = "add";
/** 修改权限 */
public static final String EDIT_PERMISSION = "edit";
/** 删除权限 */
public static final String REMOVE_PERMISSION = "remove";
/** 导出权限 */
public static final String EXPORT_PERMISSION = "export";
/** 显示权限 */
public static final String VIEW_PERMISSION = "view";
/** 查询权限 */
public static final String LIST_PERMISSION = "list";
}

View File

@ -0,0 +1,49 @@
package com.luckyframe.common.constant;
/**
* 任务调度通用常量
*
* @author ruoyi
*/
public interface ScheduleConstants
{
public static final String TASK_CLASS_NAME = "__TASK_CLASS_NAME__";
public static final String TASK_PROPERTIES = "__TASK_PROPERTIES__";
/** 默认 */
public static final String MISFIRE_DEFAULT = "0";
/** 立即触发执行 */
public static final String MISFIRE_IGNORE_MISFIRES = "1";
/** 触发一次执行 */
public static final String MISFIRE_FIRE_AND_PROCEED = "2";
/** 不触发立即执行 */
public static final String MISFIRE_DO_NOTHING = "3";
public enum Status
{
/**
* 正常
*/
NORMAL("0"),
/**
* 暂停
*/
PAUSE("1");
private String value;
private Status(String value)
{
this.value = value;
}
public String getValue()
{
return value;
}
}
}

View File

@ -0,0 +1,64 @@
package com.luckyframe.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";
/**
* 验证码key
*/
public static final String CURRENT_CAPTCHA = "captcha";
/**
* 验证码开关
*/
public static final String CURRENT_ENABLED = "captchaEnabled";
/**
* 验证码开关
*/
public static final String CURRENT_TYPE = "captchaType";
/**
* 验证码
*/
public static final String CURRENT_VALIDATECODE = "validateCode";
/**
* 验证码错误
*/
public static final String CAPTCHA_ERROR = "captchaError";
}

View File

@ -0,0 +1,90 @@
package com.luckyframe.common.constant;
/**
* 用户常量信息
*
* @author ruoyi
*/
public class UserConstants
{
/** 正常状态 */
public static final String NORMAL = "0";
/** 异常状态 */
public static final String EXCEPTION = "1";
/** 用户封禁状态 */
public static final String USER_BLOCKED = "1";
/** 角色封禁状态 */
public static final String ROLE_BLOCKED = "1";
/** 部门正常状态 */
public static final String DEPT_NORMAL = "0";
/**
* 用户名长度限制
*/
public static final int USERNAME_MIN_LENGTH = 2;
public static final int USERNAME_MAX_LENGTH = 20;
/** 登录名称是否唯一的返回结果码 */
public final static String USER_NAME_UNIQUE = "0";
public final static String USER_NAME_NOT_UNIQUE = "1";
/** 手机号码是否唯一的返回结果 */
public final static String USER_PHONE_UNIQUE = "0";
public final static String USER_PHONE_NOT_UNIQUE = "1";
/** e-mail 是否唯一的返回结果 */
public final static String USER_EMAIL_UNIQUE = "0";
public final static String USER_EMAIL_NOT_UNIQUE = "1";
/** 部门名称是否唯一的返回结果码 */
public final static String DEPT_NAME_UNIQUE = "0";
public final static String DEPT_NAME_NOT_UNIQUE = "1";
/** 角色名称是否唯一的返回结果码 */
public final static String ROLE_NAME_UNIQUE = "0";
public final static String ROLE_NAME_NOT_UNIQUE = "1";
/** 岗位名称是否唯一的返回结果码 */
public final static String POST_NAME_UNIQUE = "0";
public final static String POST_NAME_NOT_UNIQUE = "1";
/** 角色权限是否唯一的返回结果码 */
public final static String ROLE_KEY_UNIQUE = "0";
public final static String ROLE_KEY_NOT_UNIQUE = "1";
/** 岗位编码是否唯一的返回结果码 */
public final static String POST_CODE_UNIQUE = "0";
public final static String POST_CODE_NOT_UNIQUE = "1";
/** 菜单名称是否唯一的返回结果码 */
public final static String MENU_NAME_UNIQUE = "0";
public final static String MENU_NAME_NOT_UNIQUE = "1";
/** 字典类型是否唯一的返回结果码 */
public final static String DICT_TYPE_UNIQUE = "0";
public final static String DICT_TYPE_NOT_UNIQUE = "1";
/** 参数键名是否唯一的返回结果码 */
public final static String CONFIG_KEY_UNIQUE = "0";
public final static String CONFIG_KEY_NOT_UNIQUE = "1";
/**
* 密码长度限制
*/
public static final int PASSWORD_MIN_LENGTH = 5;
public static final int PASSWORD_MAX_LENGTH = 20;
/**
* 手机号码格式限制
*/
public static final String MOBILE_PHONE_NUMBER_PATTERN = "^0{0,1}(13[0-9]|15[0-9]|14[0-9]|18[0-9])[0-9]{8}$";
/**
* 邮箱格式限制
*/
public static final String EMAIL_PATTERN = "^((([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+(\\.([a-z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(\\\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|\\d|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.)+(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])|(([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])([a-z]|\\d|-|\\.|_|~|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])*([a-z]|[\\u00A0-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF])))\\.?";
}

View File

@ -0,0 +1,24 @@
package com.luckyframe.common.exception;
/**
* 业务异常
*
* @author ruoyi
*/
public class BusinessException extends RuntimeException
{
private static final long serialVersionUID = 1L;
protected final String message;
public BusinessException(String message)
{
this.message = message;
}
@Override
public String getMessage()
{
return message;
}
}

View File

@ -0,0 +1,15 @@
package com.luckyframe.common.exception;
/**
* 演示模式异常
*
* @author ruoyi
*/
public class DemoModeException extends RuntimeException
{
private static final long serialVersionUID = 1L;
public DemoModeException()
{
}
}

View File

@ -0,0 +1,104 @@
package com.luckyframe.common.exception.base;
import org.springframework.util.StringUtils;
import com.luckyframe.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,19 @@
package com.luckyframe.common.exception.file;
import com.luckyframe.common.exception.base.BaseException;
/**
* 文件信息异常类
*
* @author ruoyi
*/
public class FileException extends BaseException
{
private static final long serialVersionUID = 1L;
public FileException(String code, Object[] args)
{
super("file", code, args, null);
}
}

View File

@ -0,0 +1,16 @@
package com.luckyframe.common.exception.file;
/**
* 文件名称超长限制异常类
*
* @author ruoyi
*/
public class FileNameLengthLimitExceededException extends FileException
{
private static final long serialVersionUID = 1L;
public FileNameLengthLimitExceededException(int defaultFileNameLength)
{
super("upload.filename.exceed.length", new Object[] { defaultFileNameLength });
}
}

View File

@ -0,0 +1,16 @@
package com.luckyframe.common.exception.file;
/**
* 文件名大小限制异常类
*
* @author ruoyi
*/
public class FileSizeLimitExceededException extends FileException
{
private static final long serialVersionUID = 1L;
public FileSizeLimitExceededException(long defaultMaxSize)
{
super("upload.exceed.maxSize", new Object[] { defaultMaxSize });
}
}

View File

@ -0,0 +1,71 @@
package com.luckyframe.common.exception.file;
import java.util.Arrays;
import org.apache.commons.fileupload.FileUploadException;
/**
* 文件上传 误异常类
*
* @author ruoyi
*/
public class InvalidExtensionException extends FileUploadException
{
private static final long serialVersionUID = 1L;
private String[] allowedExtension;
private String extension;
private String filename;
public InvalidExtensionException(String[] allowedExtension, String extension, String filename)
{
super("filename : [" + filename + "], extension : [" + extension + "], allowed extension : [" + Arrays.toString(allowedExtension) + "]");
this.allowedExtension = allowedExtension;
this.extension = extension;
this.filename = filename;
}
public String[] getAllowedExtension()
{
return allowedExtension;
}
public String getExtension()
{
return extension;
}
public String getFilename()
{
return filename;
}
public static class InvalidImageExtensionException extends InvalidExtensionException
{
private static final long serialVersionUID = 1L;
public InvalidImageExtensionException(String[] allowedExtension, String extension, String filename)
{
super(allowedExtension, extension, filename);
}
}
public static class InvalidFlashExtensionException extends InvalidExtensionException
{
private static final long serialVersionUID = 1L;
public InvalidFlashExtensionException(String[] allowedExtension, String extension, String filename)
{
super(allowedExtension, extension, filename);
}
}
public static class InvalidMediaExtensionException extends InvalidExtensionException
{
private static final long serialVersionUID = 1L;
public InvalidMediaExtensionException(String[] allowedExtension, String extension, String filename)
{
super(allowedExtension, extension, filename);
}
}
}

View File

@ -0,0 +1,34 @@
package com.luckyframe.common.exception.job;
/**
* 计划策略异常
*
* @author ruoyi
*/
public class TaskException extends Exception
{
private static final long serialVersionUID = 1L;
private Code code;
public TaskException(String msg, Code code)
{
this(msg, code, null);
}
public TaskException(String msg, Code code, Exception nestedEx)
{
super(msg, nestedEx);
this.code = code;
}
public Code getCode()
{
return code;
}
public enum Code
{
TASK_EXISTS, NO_TASK_EXISTS, TASK_ALREADY_STARTED, UNKNOWN, CONFIG_ERROR, TASK_NODE_NOT_AVAILABLE
}
}

View File

@ -0,0 +1,16 @@
package com.luckyframe.common.exception.user;
/**
* 验证码错误异常类
*
* @author ruoyi
*/
public class CaptchaException extends UserException
{
private static final long serialVersionUID = 1L;
public CaptchaException()
{
super("user.jcaptcha.error", null);
}
}

View File

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

View File

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

View File

@ -0,0 +1,16 @@
package com.luckyframe.common.exception.user;
/**
* 用户账号已被删除
*
* @author ruoyi
*/
public class UserDeleteException extends UserException
{
private static final long serialVersionUID = 1L;
public UserDeleteException()
{
super("user.password.delete", null);
}
}

View File

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

View File

@ -0,0 +1,16 @@
package com.luckyframe.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,408 @@
package com.luckyframe.common.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Date;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.poi.ss.usermodel.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.luckyframe.common.support.Convert;
import com.luckyframe.common.utils.DateUtils;
/**
* 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
*
* @author ruoyi
*/
@SuppressWarnings("rawtypes")
public class ReflectUtils
{
private static final String SETTER_PREFIX = "set";
private static final String GETTER_PREFIX = "get";
private static final String CGLIB_CLASS_SEPARATOR = "$$";
private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class);
/**
* 调用Getter方法.
* 支持多级对象名.对象名.方法
*/
@SuppressWarnings("unchecked")
public static <E> E invokeGetter(Object obj, String propertyName)
{
Object object = obj;
for (String name : StringUtils.split(propertyName, "."))
{
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
}
return (E) object;
}
/**
* 调用Setter方法, 仅匹配方法名
* 支持多级对象名.对象名.方法
*/
public static <E> void invokeSetter(Object obj, String propertyName, E value)
{
Object object = obj;
String[] names = StringUtils.split(propertyName, ".");
for (int i = 0; i < names.length; i++)
{
if (i < names.length - 1)
{
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
}
else
{
String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
invokeMethodByName(object, setterMethodName, new Object[] { value });
}
}
}
/**
* 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
*/
@SuppressWarnings("unchecked")
public static <E> E getFieldValue(final Object obj, final String fieldName)
{
Field field = getAccessibleField(obj, fieldName);
if (field == null)
{
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
return null;
}
E result = null;
try
{
result = (E) field.get(obj);
}
catch (IllegalAccessException e)
{
logger.error("不可能抛出的异常{}", e.getMessage());
}
return result;
}
/**
* 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
*/
public static <E> void setFieldValue(final Object obj, final String fieldName, final E value)
{
Field field = getAccessibleField(obj, fieldName);
if (field == null)
{
// throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
return;
}
try
{
field.set(obj, value);
}
catch (IllegalAccessException e)
{
logger.error("不可能抛出的异常: {}", e.getMessage());
}
}
/**
* 直接调用对象方法, 无视private/protected修饰符.
* 用于一次性调用的情况否则应使用getAccessibleMethod()函数获得Method后反复调用.
* 同时匹配方法名+参数类型
*/
@SuppressWarnings("unchecked")
public static <E> E invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
final Object[] args)
{
if (obj == null || methodName == null)
{
return null;
}
Method method = getAccessibleMethod(obj, methodName, parameterTypes);
if (method == null)
{
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
return null;
}
try
{
return (E) method.invoke(obj, args);
}
catch (Exception e)
{
String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
throw convertReflectionExceptionToUnchecked(msg, e);
}
}
/**
* 直接调用对象方法, 无视private/protected修饰符
* 用于一次性调用的情况否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
* 只匹配函数名如果有多个同名函数调用第一个
*/
@SuppressWarnings("unchecked")
public static <E> E invokeMethodByName(final Object obj, final String methodName, final Object[] args)
{
Method method = getAccessibleMethodByName(obj, methodName, args.length);
if (method == null)
{
// 如果为空不报错直接返回空
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
return null;
}
try
{
// 类型转换将参数数据类型转换为目标方法参数类型
Class<?>[] cs = method.getParameterTypes();
for (int i = 0; i < cs.length; i++)
{
if (args[i] != null && !args[i].getClass().equals(cs[i]))
{
if (cs[i] == String.class)
{
args[i] = Convert.toStr(args[i]);
if (StringUtils.endsWith((String) args[i], ".0"))
{
args[i] = StringUtils.substringBefore((String) args[i], ".0");
}
}
else if (cs[i] == Integer.class)
{
args[i] = Convert.toInt(args[i]);
}
else if (cs[i] == Long.class)
{
args[i] = Convert.toLong(args[i]);
}
else if (cs[i] == Double.class)
{
args[i] = Convert.toDouble(args[i]);
}
else if (cs[i] == Float.class)
{
args[i] = Convert.toFloat(args[i]);
}
else if (cs[i] == Date.class)
{
if (args[i] instanceof String)
{
args[i] = DateUtils.parseDate(args[i]);
}
else
{
args[i] = DateUtil.getJavaDate((Double) args[i]);
}
}
}
}
return (E) method.invoke(obj, args);
}
catch (Exception e)
{
String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
throw convertReflectionExceptionToUnchecked(msg, e);
}
}
/**
* 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
* 如向上转型到Object仍无法找到, 返回null.
*/
public static Field getAccessibleField(final Object obj, final String fieldName)
{
// 为空不报错直接返回 null
if (obj == null)
{
return null;
}
Validate.notBlank(fieldName, "fieldName can't be blank");
for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass())
{
try
{
Field field = superClass.getDeclaredField(fieldName);
makeAccessible(field);
return field;
}
catch (NoSuchFieldException e)
{
continue;
}
}
return null;
}
/**
* 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
* 如向上转型到Object仍无法找到, 返回null.
* 匹配函数名+参数类型
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethod(final Object obj, final String methodName,
final Class<?>... parameterTypes)
{
// 为空不报错直接返回 null
if (obj == null)
{
return null;
}
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())
{
try
{
Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
makeAccessible(method);
return method;
}
catch (NoSuchMethodException e)
{
continue;
}
}
return null;
}
/**
* 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
* 如向上转型到Object仍无法找到, 返回null.
* 只匹配函数名
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum)
{
// 为空不报错直接返回 null
if (obj == null)
{
return null;
}
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())
{
Method[] methods = searchType.getDeclaredMethods();
for (Method method : methods)
{
if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum)
{
makeAccessible(method);
return method;
}
}
}
return null;
}
/**
* 改变private/protected的方法为public尽量不调用实际改动的语句避免JDK的SecurityManager抱怨
*/
public static void makeAccessible(Method method)
{
if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
&& !method.isAccessible())
{
method.setAccessible(true);
}
}
/**
* 改变private/protected的成员变量为public尽量不调用实际改动的语句避免JDK的SecurityManager抱怨
*/
public static void makeAccessible(Field field)
{
if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())
|| Modifier.isFinal(field.getModifiers())) && !field.isAccessible())
{
field.setAccessible(true);
}
}
/**
* 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处
* 如无法找到, 返回Object.class.
*/
@SuppressWarnings("unchecked")
public static <T> Class<T> getClassGenricType(final Class clazz)
{
return getClassGenricType(clazz, 0);
}
/**
* 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
* 如无法找到, 返回Object.class.
*/
public static Class getClassGenricType(final Class clazz, final int index)
{
Type genType = clazz.getGenericSuperclass();
if (!(genType instanceof ParameterizedType))
{
logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType");
return Object.class;
}
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
if (index >= params.length || index < 0)
{
logger.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
+ params.length);
return Object.class;
}
if (!(params[index] instanceof Class))
{
logger.debug(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
return Object.class;
}
return (Class) params[index];
}
public static Class<?> getUserClass(Object instance)
{
if (instance == null)
{
throw new RuntimeException("Instance must not be null");
}
Class clazz = instance.getClass();
if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR))
{
Class<?> superClass = clazz.getSuperclass();
if (superClass != null && !Object.class.equals(superClass))
{
return superClass;
}
}
return clazz;
}
/**
* 将反射时的checked exception转换为unchecked exception.
*/
public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e)
{
if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
|| e instanceof NoSuchMethodException)
{
return new IllegalArgumentException(msg, e);
}
else if (e instanceof InvocationTargetException)
{
return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException());
}
return new RuntimeException(msg, e);
}
}

View File

@ -0,0 +1,88 @@
package com.luckyframe.common.support;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import com.luckyframe.common.utils.StringUtils;
/**
* 字符集工具类
*
* @author ruoyi
*
*/
public class CharsetKit
{
/** ISO-8859-1 */
public static final String ISO_8859_1 = "ISO-8859-1";
/** UTF-8 */
public static final String UTF_8 = "UTF-8";
/** GBK */
public static final String GBK = "GBK";
/** ISO-8859-1 */
public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1);
/** UTF-8 */
public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8);
/** GBK */
public static final Charset CHARSET_GBK = Charset.forName(GBK);
/**
* 转换为Charset对象
*
* @param charset 字符集为空则返回默认字符集
* @return Charset
*/
public static Charset charset(String charset)
{
return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset);
}
/**
* 转换字符串的字符集编码
*
* @param source 字符串
* @param srcCharset 源字符集默认ISO-8859-1
* @param destCharset 目标字符集默认UTF-8
* @return 转换后的字符集
*/
public static String convert(String source, String srcCharset, String destCharset)
{
return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset));
}
/**
* 转换字符串的字符集编码
*
* @param source 字符串
* @param srcCharset 源字符集默认ISO-8859-1
* @param destCharset 目标字符集默认UTF-8
* @return 转换后的字符集
*/
public static String convert(String source, Charset srcCharset, Charset destCharset)
{
if (null == srcCharset)
{
srcCharset = StandardCharsets.ISO_8859_1;
}
if (null == destCharset)
{
srcCharset = StandardCharsets.UTF_8;
}
if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset))
{
return source;
}
return new String(source.getBytes(srcCharset), destCharset);
}
/**
* @return 系统字符集编码
*/
public static String systemCharset()
{
return Charset.defaultCharset().name();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,93 @@
package com.luckyframe.common.support;
import com.luckyframe.common.utils.StringUtils;
/**
* 字符串格式化
*
* @author ruoyi
*/
public class StrFormatter
{
public static final String EMPTY_JSON = "{}";
public static final char C_BACKSLASH = '\\';
public static final char C_DELIM_START = '{';
public static final char C_DELIM_END = '}';
/**
* 格式化字符串<br>
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
* 如果想输出 {} 使用 \\转义 { 即可如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
* <br>
* 通常使用format("this is {} for {}", "a", "b") -> this is a for b<br>
* 转义{} format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
* 转义\ format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
*
* @param strPattern 字符串模板
* @param argArray 参数列表
* @return 结果
*/
public static String format(final String strPattern, final Object... argArray)
{
if (StringUtils.isEmpty(strPattern) || StringUtils.isEmpty(argArray))
{
return strPattern;
}
final int strPatternLength = strPattern.length();
// 初始化定义好的长度以获得更好的性能
StringBuilder sbuf = new StringBuilder(strPatternLength + 50);
int handledPosition = 0;
int delimIndex;// 占位符所在位置
for (int argIndex = 0; argIndex < argArray.length; argIndex++)
{
delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition);
if (delimIndex == -1)
{
if (handledPosition == 0)
{
return strPattern;
}
else
{ // 字符串模板剩余部分不再包含占位符加入剩余部分后返回结果
sbuf.append(strPattern, handledPosition, strPatternLength);
return sbuf.toString();
}
}
else
{
if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH)
{
if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH)
{
// 转义符之前还有一个转义符占位符依旧有效
sbuf.append(strPattern, handledPosition, delimIndex - 1);
sbuf.append(Convert.utf8Str(argArray[argIndex]));
handledPosition = delimIndex + 2;
}
else
{
// 占位符被转义
argIndex--;
sbuf.append(strPattern, handledPosition, delimIndex - 1);
sbuf.append(C_DELIM_START);
handledPosition = delimIndex + 1;
}
}
else
{
// 正常占位符
sbuf.append(strPattern, handledPosition, delimIndex);
sbuf.append(Convert.utf8Str(argArray[argIndex]));
handledPosition = delimIndex + 2;
}
}
}
// append the characters following the last {} pair.
// 加入最后一个占位符后所有的字符
sbuf.append(strPattern, handledPosition, strPattern.length());
return sbuf.toString();
}
}

View File

@ -0,0 +1,45 @@
package com.luckyframe.common.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONObject;
import com.luckyframe.common.utils.http.HttpUtils;
import com.luckyframe.framework.config.LuckyFrameConfig;
/**
* 获取地址类
*
* @author ruoyi
*/
public class AddressUtils
{
private static final Logger log = LoggerFactory.getLogger(AddressUtils.class);
public static final String IP_URL = "http://ip.taobao.com/service/getIpInfo.php";
public static String getRealAddressByIP(String ip)
{
String address = "XX XX";
// 内网不查询
if (IpUtils.internalIp(ip))
{
return "内网IP";
}
if (LuckyFrameConfig.isAddressEnabled())
{
String rspStr = HttpUtils.sendPost(IP_URL, "ip=" + ip);
if (StringUtils.isEmpty(rspStr))
{
log.error("获取地理位置异常 {}", ip);
return address;
}
JSONObject obj = JSONObject.parseObject(rspStr);
JSONObject data = obj.getObject("data", JSONObject.class);
String region = data.getString("region");
String city = data.getString("city");
address = region + " " + city;
}
return address;
}
}

View File

@ -0,0 +1,113 @@
package com.luckyframe.common.utils;
import java.math.BigDecimal;
/**
* 精确的浮点数运算
*
* @author ruoyi
*/
public class Arith
{
/** 默认除法运算精度 */
private static final int DEF_DIV_SCALE = 10;
/** 这个类不能实例化 */
private Arith()
{
}
/**
* 提供精确的加法运算
* @param v1 被加数
* @param v2 加数
* @return 两个参数的和
*/
public static double add(double v1, double v2)
{
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.add(b2).doubleValue();
}
/**
* 提供精确的减法运算
* @param v1 被减数
* @param v2 减数
* @return 两个参数的差
*/
public static double sub(double v1, double v2)
{
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.subtract(b2).doubleValue();
}
/**
* 提供精确的乘法运算
* @param v1 被乘数
* @param v2 乘数
* @return 两个参数的积
*/
public static double mul(double v1, double v2)
{
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.multiply(b2).doubleValue();
}
/**
* 提供相对精确的除法运算当发生除不尽的情况时精确到
* 小数点以后10位以后的数字四舍五入
* @param v1 被除数
* @param v2 除数
* @return 两个参数的商
*/
public static double div(double v1, double v2)
{
return div(v1, v2, DEF_DIV_SCALE);
}
/**
* 提供相对精确的除法运算当发生除不尽的情况时由scale参数指
* 定精度以后的数字四舍五入
* @param v1 被除数
* @param v2 除数
* @param scale 表示表示需要精确到小数点以后几位
* @return 两个参数的商
*/
public static double div(double v1, double v2, int scale)
{
if (scale < 0)
{
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
if (b1.compareTo(BigDecimal.ZERO) == 0)
{
return BigDecimal.ZERO.doubleValue();
}
return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 提供精确的小数位四舍五入处理
* @param v 需要四舍五入的数字
* @param scale 小数点后保留几位
* @return 四舍五入后的结果
*/
public static double round(double v, int scale)
{
if (scale < 0)
{
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b = new BigDecimal(Double.toString(v));
BigDecimal one = new BigDecimal("1");
return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
}
}

View File

@ -0,0 +1,155 @@
package com.luckyframe.common.utils;
import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.commons.lang3.time.DateFormatUtils;
/**
* 时间工具类
*
* @author ruoyi
*/
public class DateUtils extends org.apache.commons.lang3.time.DateUtils
{
public static String YYYY = "yyyy";
public static String YYYY_MM = "yyyy-MM";
public static String YYYY_MM_DD = "yyyy-MM-dd";
public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
private static String[] parsePatterns = {
"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
/**
* 获取当前Date型日期
*
* @return Date() 当前日期
*/
public static Date getNowDate()
{
return new Date();
}
/**
* 获取当前日期, 默认格式为yyyy-MM-dd
*
* @return String
*/
public static String getDate()
{
return dateTimeNow(YYYY_MM_DD);
}
public static final String getTime()
{
return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
}
public static final String dateTimeNow()
{
return dateTimeNow(YYYYMMDDHHMMSS);
}
public static final String dateTimeNow(final String format)
{
return parseDateToStr(format, new Date());
}
public static final String dateTime(final Date date)
{
return parseDateToStr(YYYY_MM_DD, date);
}
public static final String parseDateToStr(final String format, final Date date)
{
return new SimpleDateFormat(format).format(date);
}
public static final Date dateTime(final String format, final String ts)
{
try
{
return new SimpleDateFormat(format).parse(ts);
}
catch (ParseException e)
{
throw new RuntimeException(e);
}
}
/**
* 日期路径 即年// 如2018/08/08
*/
public static final String datePath()
{
Date now = new Date();
return DateFormatUtils.format(now, "yyyy/MM/dd");
}
/**
* 日期路径 即年// 如20180808
*/
public static final String dateTime()
{
Date now = new Date();
return DateFormatUtils.format(now, "yyyyMMdd");
}
/**
* 日期型字符串转化为日期 格式
*/
public static Date parseDate(Object str)
{
if (str == null)
{
return null;
}
try
{
return parseDate(str.toString(), parsePatterns);
}
catch (ParseException e)
{
return null;
}
}
/**
* 获取服务器启动时间
*/
public static Date getServerStartDate()
{
long time = ManagementFactory.getRuntimeMXBean().getStartTime();
return new Date(time);
}
/**
* 计算两个时间差
*/
public static String getDatePoor(Date endDate, Date nowDate)
{
long nd = 1000 * 24 * 60 * 60;
long nh = 1000 * 60 * 60;
long nm = 1000 * 60;
// long ns = 1000;
// 获得两个时间的毫秒时间差异
long diff = endDate.getTime() - nowDate.getTime();
// 计算差多少天
long day = diff / nd;
// 计算差多少小时
long hour = diff % nd / nh;
// 计算差多少分钟
long min = diff % nd % nh / nm;
// 计算差多少秒//输出结果
// long sec = diff % nd % nh % nm / ns;
return day + "" + hour + "小时" + min + "分钟";
}
}

View File

@ -0,0 +1,184 @@
package com.luckyframe.common.utils;
import java.net.InetAddress;
import java.net.UnknownHostException;
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 "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
}
public static boolean internalIp(String ip)
{
byte[] addr = textToNumericFormatV4(ip);
return internalIp(addr) || "127.0.0.1".equals(ip);
}
private static boolean internalIp(byte[] addr)
{
final byte b0 = addr[0];
final byte b1 = addr[1];
// 10.x.x.x/8
final byte SECTION_1 = 0x0A;
// 172.16.x.x/12
final byte SECTION_2 = (byte) 0xAC;
final byte SECTION_3 = (byte) 0x10;
final byte SECTION_4 = (byte) 0x1F;
// 192.168.x.x/16
final byte SECTION_5 = (byte) 0xC0;
final byte SECTION_6 = (byte) 0xA8;
switch (b0)
{
case SECTION_1:
return true;
case SECTION_2:
if (b1 >= SECTION_3 && b1 <= SECTION_4)
{
return true;
}
case SECTION_5:
switch (b1)
{
case SECTION_6:
return true;
}
default:
return false;
}
}
/**
* 将IPv4地址转换成字节
*
* @param text IPv4地址
* @return byte 字节
*/
public static byte[] textToNumericFormatV4(String text)
{
if (text.length() == 0)
{
return null;
}
byte[] bytes = new byte[4];
String[] elements = text.split("\\.", -1);
try
{
long l;
int i;
switch (elements.length)
{
case 1:
l = Long.parseLong(elements[0]);
if ((l < 0L) || (l > 4294967295L))
return null;
bytes[0] = (byte) (int) (l >> 24 & 0xFF);
bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
bytes[3] = (byte) (int) (l & 0xFF);
break;
case 2:
l = Integer.parseInt(elements[0]);
if ((l < 0L) || (l > 255L))
return null;
bytes[0] = (byte) (int) (l & 0xFF);
l = Integer.parseInt(elements[1]);
if ((l < 0L) || (l > 16777215L))
return null;
bytes[1] = (byte) (int) (l >> 16 & 0xFF);
bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
bytes[3] = (byte) (int) (l & 0xFF);
break;
case 3:
for (i = 0; i < 2; ++i)
{
l = Integer.parseInt(elements[i]);
if ((l < 0L) || (l > 255L))
return null;
bytes[i] = (byte) (int) (l & 0xFF);
}
l = Integer.parseInt(elements[2]);
if ((l < 0L) || (l > 65535L))
return null;
bytes[2] = (byte) (int) (l >> 8 & 0xFF);
bytes[3] = (byte) (int) (l & 0xFF);
break;
case 4:
for (i = 0; i < 4; ++i)
{
l = Integer.parseInt(elements[i]);
if ((l < 0L) || (l > 255L))
return null;
bytes[i] = (byte) (int) (l & 0xFF);
}
break;
default:
return null;
}
}
catch (NumberFormatException e)
{
return null;
}
return bytes;
}
public static String getHostIp()
{
try
{
return InetAddress.getLocalHost().getHostAddress();
}
catch (UnknownHostException e)
{
}
return "127.0.0.1";
}
public static String getHostName()
{
try
{
return InetAddress.getLocalHost().getHostName();
}
catch (UnknownHostException e)
{
}
return "未知";
}
}

View File

@ -0,0 +1,134 @@
package com.luckyframe.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,50 @@
package com.luckyframe.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,66 @@
package com.luckyframe.common.utils;
import java.security.MessageDigest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Md5加密方法
*
* @author ruoyi
*/
public class Md5Utils
{
private static final Logger log = LoggerFactory.getLogger(Md5Utils.class);
private static byte[] md5(String s)
{
MessageDigest algorithm;
try
{
algorithm = MessageDigest.getInstance("MD5");
algorithm.reset();
algorithm.update(s.getBytes("UTF-8"));
byte[] messageDigest = algorithm.digest();
return messageDigest;
}
catch (Exception e)
{
log.error("MD5 Error...", e);
}
return null;
}
private static final String toHex(byte hash[])
{
if (hash == null)
{
return null;
}
StringBuffer buf = new StringBuffer(hash.length * 2);
int i;
for (i = 0; i < hash.length; i++)
{
if ((hash[i] & 0xff) < 0x10)
{
buf.append("0");
}
buf.append(Long.toString(hash[i] & 0xff, 16));
}
return buf.toString();
}
public static String hash(String s)
{
try
{
return new String(toHex(md5(s)).getBytes("UTF-8"), "UTF-8");
}
catch (Exception e)
{
log.error("not supported charset...{}", e);
return s;
}
}
}

View File

@ -0,0 +1,25 @@
package com.luckyframe.common.utils;
import org.springframework.context.MessageSource;
import com.luckyframe.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,137 @@
package com.luckyframe.common.utils;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.luckyframe.common.support.Convert;
/**
* 客户端工具类
*
* @author ruoyi
*/
public class ServletUtils
{
/**
* 获取String参数
*/
public static String getParameter(String name)
{
return getRequest().getParameter(name);
}
/**
* 获取String参数
*/
public static String getParameter(String name, String defaultValue)
{
return Convert.toStr(getRequest().getParameter(name), defaultValue);
}
/**
* 获取Integer参数
*/
public static Integer getParameterToInt(String name)
{
return Convert.toInt(getRequest().getParameter(name));
}
/**
* 获取Integer参数
*/
public static Integer getParameterToInt(String name, Integer defaultValue)
{
return Convert.toInt(getRequest().getParameter(name), defaultValue);
}
/**
* 获取request
*/
public static HttpServletRequest getRequest()
{
return getRequestAttributes().getRequest();
}
/**
* 获取response
*/
public static HttpServletResponse getResponse()
{
return getRequestAttributes().getResponse();
}
/**
* 获取session
*/
public static HttpSession getSession()
{
return getRequest().getSession();
}
public static ServletRequestAttributes getRequestAttributes()
{
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
return (ServletRequestAttributes) attributes;
}
/**
* 将字符串渲染到客户端
*
* @param response 渲染对象
* @param string 待渲染的字符串
* @return null
*/
public static String renderString(HttpServletResponse response, String string)
{
try
{
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().print(string);
}
catch (IOException e)
{
e.printStackTrace();
}
return null;
}
/**
* 是否是Ajax异步请求
*
* @param request
*/
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,364 @@
package com.luckyframe.common.utils;
import java.util.Collection;
import java.util.Map;
import com.luckyframe.common.support.StrFormatter;
/**
* 字符串工具类
*
* @author ruoyi
*/
public class StringUtils extends org.apache.commons.lang3.StringUtils
{
/** 空字符串 */
private static final String NULLSTR = "";
/** 下划线 */
private static final char SEPARATOR = '_';
/**
* 获取参数不为空值
*
* @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);
}
/**
* 格式化文本, {} 表示占位符<br>
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
* 如果想输出 {} 使用 \\转义 { 即可如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
* <br>
* 通常使用format("this is {} for {}", "a", "b") -> this is a for b<br>
* 转义{} format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
* 转义\ format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
*
* @param template 文本模板被替换的部分用 {} 表示
* @param params 参数值
* @return 格式化后的文本
*/
public static String format(String template, Object... params)
{
if (isEmpty(params) || isEmpty(template))
{
return template;
}
return StrFormatter.format(template, params);
}
/**
* 下划线转驼峰命名
*/
public static String toUnderScoreCase(String str)
{
if (str == null)
{
return null;
}
StringBuilder sb = new StringBuilder();
// 前置字符是否大写
boolean preCharIsUpperCase = true;
// 当前字符是否大写
boolean curreCharIsUpperCase = true;
// 下一字符是否大写
boolean nexteCharIsUpperCase = true;
for (int i = 0; i < str.length(); i++)
{
char c = str.charAt(i);
if (i > 0)
{
preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
}
else
{
preCharIsUpperCase = false;
}
curreCharIsUpperCase = Character.isUpperCase(c);
if (i < (str.length() - 1))
{
nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
}
if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase)
{
sb.append(SEPARATOR);
}
else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase)
{
sb.append(SEPARATOR);
}
sb.append(Character.toLowerCase(c));
}
return sb.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,62 @@
package com.luckyframe.common.utils;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 线程相关工具类.
*
* @author ruoyi
*/
public class Threads
{
private static final Logger logger = LoggerFactory.getLogger("sys-user");
/**
* sleep等待,单位为毫秒
*/
public static void sleep(long milliseconds)
{
try
{
Thread.sleep(milliseconds);
}
catch (InterruptedException e)
{
return;
}
}
/**
* 停止线程池
* 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务.
* 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数.
* 如果仍人超時則強制退出.
* 另对在shutdown时线程本身被调用中断做了处理.
*/
public static void shutdownAndAwaitTermination(ExecutorService pool)
{
if (pool != null && !pool.isShutdown())
{
pool.shutdown();
try
{
if (!pool.awaitTermination(120, TimeUnit.SECONDS))
{
pool.shutdownNow();
if (!pool.awaitTermination(120, TimeUnit.SECONDS))
{
logger.info("Pool did not terminate");
}
}
}
catch (InterruptedException ie)
{
pool.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
}

View File

@ -0,0 +1,143 @@
package com.luckyframe.common.utils;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.luckyframe.project.system.menu.domain.Menu;
/**
* 权限数据处理
*
* @author ruoyi
*/
public class TreeUtils
{
/**
* 根据父节点的ID获取所有子节点
*
* @param list 分类表
* @param parentId 传入的父节点ID
* @return String
*/
public static List<Menu> getChildPerms(List<Menu> list, int parentId)
{
List<Menu> returnList = new ArrayList<Menu>();
for (Iterator<Menu> iterator = list.iterator(); iterator.hasNext();)
{
Menu t = (Menu) iterator.next();
// 根据传入的某个父节点ID,遍历该父节点的所有子节点
if (t.getParentId() == parentId)
{
recursionFn(list, t);
returnList.add(t);
}
}
return returnList;
}
/**
* 递归列表
*
* @param list
* @param t
*/
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,122 @@
package com.luckyframe.common.utils.bean;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Bean 工具类
*
* @author ruoyi
*/
public class BeanUtils
{
/** Bean方法名中属性名开始的下标 */
private static final int BEAN_METHOD_PROP_INDEX = 3;
/** * 匹配getter方法的正则表达式 */
private static final Pattern GET_PATTERN = Pattern.compile("get(\\p{javaUpperCase}\\w*)");
/** * 匹配setter方法的正则表达式 */
private static final Pattern SET_PATTERN = Pattern.compile("set(\\p{javaUpperCase}\\w*)");
/**
* Bean属性复制工具方法
*
* @param dest 目标对象
* @param src 源对象
*/
public static void copyBeanProp(Object dest, Object src)
{
List<Method> destSetters = getSetterMethods(dest);
List<Method> srcGetters = getGetterMethods(src);
try
{
for (Method setter : destSetters)
{
for (Method getter : srcGetters)
{
if (isMethodPropEquals(setter.getName(), getter.getName())
&& setter.getParameterTypes()[0].equals(getter.getReturnType()))
{
setter.invoke(dest, getter.invoke(src));
}
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
/**
* 获取对象的setter方法
*
* @param obj 对象
* @return 对象的setter方法列表
*/
public static List<Method> getSetterMethods(Object obj)
{
// setter方法列表
List<Method> setterMethods = new ArrayList<Method>();
// 获取所有方法
Method[] methods = obj.getClass().getMethods();
// 查找setter方法
for (Method method : methods)
{
Matcher m = SET_PATTERN.matcher(method.getName());
if (m.matches() && (method.getParameterTypes().length == 1))
{
setterMethods.add(method);
}
}
// 返回setter方法列表
return setterMethods;
}
/**
* 获取对象的getter方法
*
* @param obj 对象
* @return 对象的getter方法列表
*/
public static List<Method> getGetterMethods(Object obj)
{
// getter方法列表
List<Method> getterMethods = new ArrayList<Method>();
// 获取所有方法
Method[] methods = obj.getClass().getMethods();
// 查找getter方法
for (Method method : methods)
{
Matcher m = GET_PATTERN.matcher(method.getName());
if (m.matches() && (method.getParameterTypes().length == 0))
{
getterMethods.add(method);
}
}
// 返回getter方法列表
return getterMethods;
}
/**
* 检查Bean方法名中的属性名是否相等<br>
* 如getName()和setName()属性名一样getName()和setAge()属性名不一样
*
* @param m1 方法名1
* @param m2 方法名2
* @return 属性名一样返回true否则返回false
*/
public static boolean isMethodPropEquals(String m1, String m2)
{
return m1.substring(BEAN_METHOD_PROP_INDEX).equals(m2.substring(BEAN_METHOD_PROP_INDEX));
}
}

View File

@ -0,0 +1,169 @@
package com.luckyframe.common.utils.file;
import java.io.File;
import java.io.IOException;
import org.springframework.web.multipart.MultipartFile;
import com.luckyframe.common.exception.file.FileNameLengthLimitExceededException;
import com.luckyframe.common.exception.file.FileSizeLimitExceededException;
import com.luckyframe.common.utils.DateUtils;
import com.luckyframe.common.utils.Md5Utils;
import com.luckyframe.framework.config.LuckyFrameConfig;
/**
* 文件上传工具类
*
* @author ruoyi
*/
public class FileUploadUtils
{
/**
* 默认大小 50M
*/
public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;
/**
* 默认的文件名最大长度 100
*/
public static final int DEFAULT_FILE_NAME_LENGTH = 100;
/**
* 默认上传的地址
*/
private static String defaultBaseDir = LuckyFrameConfig.getProfile();
/**
* 默认文件类型jpg
*/
public static final String IMAGE_JPG_EXTENSION = ".jpg";
private static int counter = 0;
public static void setDefaultBaseDir(String defaultBaseDir)
{
FileUploadUtils.defaultBaseDir = defaultBaseDir;
}
public static String getDefaultBaseDir()
{
return defaultBaseDir;
}
/**
* 以默认配置进行文件上传
*
* @param file 上传的文件
* @return 文件名称
* @throws Exception
*/
public static final String upload(MultipartFile file) throws IOException
{
try
{
return upload(getDefaultBaseDir(), file, FileUploadUtils.IMAGE_JPG_EXTENSION);
}
catch (Exception e)
{
throw new IOException(e.getMessage(), e);
}
}
/**
* 根据文件路径上传
*
* @param baseDir 相对应用的基目录
* @param file 上传的文件
* @return 文件名称
* @throws IOException
*/
public static final String upload(String baseDir, MultipartFile file) throws IOException
{
try
{
return upload(baseDir, file, FileUploadUtils.IMAGE_JPG_EXTENSION);
}
catch (Exception e)
{
throw new IOException(e.getMessage(), e);
}
}
/**
* 文件上传
*
* @param baseDir 相对应用的基目录
* @param file 上传的文件
* @param extension 上传文件类型
* @return 返回上传成功的文件名
* @throws FileSizeLimitExceededException 如果超出最大大小
* @throws FileNameLengthLimitExceededException 文件名太长
* @throws IOException 比如读写文件出错时
*/
public static final String upload(String baseDir, MultipartFile file, String extension)
throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException
{
int fileNamelength = file.getOriginalFilename().length();
if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
{
throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
}
assertAllowed(file);
String fileName = extractFilename(file, extension);
File desc = getAbsoluteFile(baseDir, baseDir + fileName);
file.transferTo(desc);
return fileName;
}
public static final String extractFilename(MultipartFile file, String extension)
{
String filename = file.getOriginalFilename();
filename = DateUtils.datePath() + "/" + encodingFilename(filename) + extension;
return filename;
}
private static final File getAbsoluteFile(String uploadDir, String filename) throws IOException
{
File desc = new File(File.separator + filename);
if (!desc.getParentFile().exists())
{
desc.getParentFile().mkdirs();
}
if (!desc.exists())
{
desc.createNewFile();
}
return desc;
}
/**
* 编码文件名
*/
private static final String encodingFilename(String filename)
{
filename = filename.replace("_", " ");
filename = Md5Utils.hash(filename + System.nanoTime() + counter++);
return filename;
}
/**
* 文件大小校验
*
* @param file 上传的文件
* @return
* @throws FileSizeLimitExceededException 如果超出最大大小
*/
public static final void assertAllowed(MultipartFile file) throws FileSizeLimitExceededException
{
long size = file.getSize();
if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE)
{
throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
}
}
}

View File

@ -0,0 +1,90 @@
package com.luckyframe.common.utils.file;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
/**
* 文件处理工具类
*
* @author ruoyi
*/
public class FileUtils
{
/**
* 输出指定文件的byte数组
*
* @param filePath 文件路径
* @param os 输出流
* @return
*/
public static void writeBytes(String filePath, OutputStream os) throws IOException
{
FileInputStream fis = null;
try
{
File file = new File(filePath);
if (!file.exists())
{
throw new FileNotFoundException(filePath);
}
fis = new FileInputStream(file);
byte[] b = new byte[1024];
int length;
while ((length = fis.read(b)) > 0)
{
os.write(b, 0, length);
}
}
catch (IOException e)
{
throw e;
}
finally
{
if (os != null)
{
try
{
os.close();
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
if (fis != null)
{
try
{
fis.close();
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
}
}
/**
* 删除文件
*
* @param filePath 文件
* @return
*/
public static boolean deleteFile(String filePath)
{
boolean flag = false;
File file = new File(filePath);
// 路径为文件且不为空则进行删除
if (file.isFile() && file.exists())
{
file.delete();
flag = true;
}
return flag;
}
}

View File

@ -0,0 +1,248 @@
package com.luckyframe.common.utils.http;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 通用http发送方法
*
* @author ruoyi
*/
public class HttpUtils
{
private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
/**
* 向指定 URL 发送GET方法的请求
*
* @param url 发送请求的 URL
* @param param 请求参数请求参数应该是 name1=value1&name2=value2 的形式
* @return 所代表远程资源的响应结果
*/
public static String sendGet(String url, String param)
{
StringBuilder result = new StringBuilder();
BufferedReader in = null;
try
{
String urlNameString = url + "?" + param;
log.info("sendGet - {}", urlNameString);
URL realUrl = new URL(urlNameString);
URLConnection connection = realUrl.openConnection();
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
connection.connect();
in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
while ((line = in.readLine()) != null)
{
result.append(line);
}
log.info("recv - {}", result);
}
catch (ConnectException e)
{
log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
}
catch (SocketTimeoutException e)
{
log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
}
catch (IOException e)
{
log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
}
catch (Exception e)
{
log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
}
finally
{
try
{
if (in != null)
{
in.close();
}
}
catch (Exception ex)
{
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
}
}
return result.toString();
}
/**
* 向指定 URL 发送POST方法的请求
*
* @param url 发送请求的 URL
* @param param 请求参数请求参数应该是 name1=value1&name2=value2 的形式
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, String param)
{
PrintWriter out = null;
BufferedReader in = null;
StringBuilder result = new StringBuilder();
try
{
String urlNameString = url + "?" + param;
log.info("sendPost - {}", urlNameString);
URL realUrl = new URL(urlNameString);
URLConnection conn = realUrl.openConnection();
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("contentType", "utf-8");
conn.setDoOutput(true);
conn.setDoInput(true);
out = new PrintWriter(conn.getOutputStream());
out.print(param);
out.flush();
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
String line;
while ((line = in.readLine()) != null)
{
result.append(line);
}
log.info("recv - {}", result);
}
catch (ConnectException e)
{
log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
}
catch (SocketTimeoutException e)
{
log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
}
catch (IOException e)
{
log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
}
catch (Exception e)
{
log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
}
finally
{
try
{
if (out != null)
{
out.close();
}
if (in != null)
{
in.close();
}
}
catch (IOException ex)
{
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
}
}
return result.toString();
}
public static String sendSSLPost(String url, String param)
{
StringBuilder result = new StringBuilder();
String urlNameString = url + "?" + param;
try
{
log.info("sendSSLPost - {}", urlNameString);
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());
URL console = new URL(urlNameString);
HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("contentType", "utf-8");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setSSLSocketFactory(sc.getSocketFactory());
conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
conn.connect();
InputStream is = conn.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String ret = "";
while ((ret = br.readLine()) != null)
{
if (ret != null && !ret.trim().equals(""))
{
result.append(new String(ret.getBytes("ISO-8859-1"), "utf-8"));
}
}
log.info("recv - {}", result);
conn.disconnect();
br.close();
}
catch (ConnectException e)
{
log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e);
}
catch (SocketTimeoutException e)
{
log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e);
}
catch (IOException e)
{
log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e);
}
catch (Exception e)
{
log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e);
}
return result.toString();
}
private static class TrustAnyTrustManager implements X509TrustManager
{
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
{
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
{
}
@Override
public X509Certificate[] getAcceptedIssuers()
{
return new X509Certificate[] {};
}
}
private static class TrustAnyHostnameVerifier implements HostnameVerifier
{
@Override
public boolean verify(String hostname, SSLSession session)
{
return true;
}
}
}

View File

@ -0,0 +1,791 @@
package com.luckyframe.common.utils.poi;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.apache.poi.hssf.usermodel.DVConstraint;
import org.apache.poi.hssf.usermodel.HSSFDataValidation;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFDataValidation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.luckyframe.common.exception.BusinessException;
import com.luckyframe.common.reflect.ReflectUtils;
import com.luckyframe.common.support.Convert;
import com.luckyframe.common.utils.DateUtils;
import com.luckyframe.common.utils.StringUtils;
import com.luckyframe.framework.aspectj.lang.annotation.Excel;
import com.luckyframe.framework.aspectj.lang.annotation.Excel.Type;
import com.luckyframe.framework.config.LuckyFrameConfig;
import com.luckyframe.framework.web.domain.AjaxResult;
/**
* Excel相关处理
*
* @author ruoyi
*/
public class ExcelUtil<T>
{
private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
/**
* Excel sheet最大行数默认65536
*/
public static final int sheetSize = 65536;
/**
* 工作表名称
*/
private String sheetName;
/**
* 导出类型EXPORT:导出数据IMPORT导入模板
*/
private Type type;
/**
* 工作薄对象
*/
private Workbook wb;
/**
* 工作表对象
*/
private Sheet sheet;
/**
* 导入导出数据列表
*/
private List<T> list;
/**
* 注解列表
*/
private List<Field> fields;
/**
* 实体对象
*/
public Class<T> clazz;
public ExcelUtil(Class<T> clazz)
{
this.clazz = clazz;
}
public void init(List<T> list, String sheetName, Type type)
{
if (list == null)
{
list = new ArrayList<T>();
}
this.list = list;
this.sheetName = sheetName;
this.type = type;
createExcelField();
createWorkbook();
}
/**
* 对excel表单默认第一个索引名转换成list
*
* @param input 输入流
* @return 转换后集合
*/
public List<T> importExcel(InputStream is) throws Exception
{
return importExcel(StringUtils.EMPTY, is);
}
/**
* 对excel表单指定表格索引名转换成list
*
* @param sheetName 表格索引名
* @param input 输入流
* @return 转换后集合
*/
public List<T> importExcel(String sheetName, InputStream is) throws Exception
{
this.type = Type.IMPORT;
this.wb = WorkbookFactory.create(is);
List<T> list = new ArrayList<T>();
Sheet sheet = null;
if (StringUtils.isNotEmpty(sheetName))
{
// 如果指定sheet名,则取指定sheet中的内容.
sheet = wb.getSheet(sheetName);
}
else
{
// 如果传入的sheet名不存在则默认指向第1个sheet.
sheet = wb.getSheetAt(0);
}
if (sheet == null)
{
throw new IOException("文件sheet不存在");
}
int rows = sheet.getPhysicalNumberOfRows();
if (rows > 0)
{
// 默认序号
int serialNum = 0;
// 有数据时才处理 得到类的所有field.
Field[] allFields = clazz.getDeclaredFields();
// 定义一个map用于存放列的序号和field.
Map<Integer, Field> fieldsMap = new HashMap<Integer, Field>();
for (int col = 0; col < allFields.length; col++)
{
Field field = allFields[col];
Excel attr = field.getAnnotation(Excel.class);
if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
{
// 设置类的私有字段属性可访问.
field.setAccessible(true);
fieldsMap.put(++serialNum, field);
}
}
for (int i = 1; i < rows; i++)
{
// 从第2行开始取数据,默认第一行是表头.
Row row = sheet.getRow(i);
int cellNum = serialNum;
T entity = null;
for (int column = 0; column < cellNum; column++)
{
Object val = this.getCellValue(row, column);
// 如果不存在实例则新建.
entity = (entity == null ? clazz.newInstance() : entity);
// 从map中得到对应列的field.
Field field = fieldsMap.get(column + 1);
// 取得类型,并根据对象类型设置值.
Class<?> fieldType = field.getType();
if (String.class == fieldType)
{
String s = Convert.toStr(val);
if (StringUtils.endsWith(s, ".0"))
{
val = StringUtils.substringBefore(s, ".0");
}
else
{
val = Convert.toStr(val);
}
}
else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType))
{
val = Convert.toInt(val);
}
else if ((Long.TYPE == fieldType) || (Long.class == fieldType))
{
val = Convert.toLong(val);
}
else if ((Double.TYPE == fieldType) || (Double.class == fieldType))
{
val = Convert.toDouble(val);
}
else if ((Float.TYPE == fieldType) || (Float.class == fieldType))
{
val = Convert.toFloat(val);
}
else if (BigDecimal.class == fieldType)
{
val = Convert.toBigDecimal(val);
}
else if (Date.class == fieldType)
{
if (val instanceof String)
{
val = DateUtils.parseDate(val);
}
else if (val instanceof Double)
{
val = DateUtil.getJavaDate((Double) val);
}
}
if (StringUtils.isNotNull(fieldType))
{
Excel attr = field.getAnnotation(Excel.class);
String propertyName = field.getName();
if (StringUtils.isNotEmpty(attr.targetAttr()))
{
propertyName = field.getName() + "." + attr.targetAttr();
}
else if (StringUtils.isNotEmpty(attr.readConverterExp()))
{
val = reverseByExp(String.valueOf(val), attr.readConverterExp());
}
ReflectUtils.invokeSetter(entity, propertyName, val);
}
}
list.add(entity);
}
}
return list;
}
/**
* 对list数据源将其里面的数据导入到excel表单
*
* @param list 导出数据集合
* @param sheetName 工作表的名称
* @return 结果
*/
public AjaxResult exportExcel(List<T> list, String sheetName)
{
this.init(list, sheetName, Type.EXPORT);
return exportExcel();
}
/**
* 对list数据源将其里面的数据导入到excel表单
*
* @param sheetName 工作表的名称
* @return 结果
*/
public AjaxResult importTemplateExcel(String sheetName)
{
this.init(null, sheetName, Type.IMPORT);
return exportExcel();
}
/**
* 对list数据源将其里面的数据导入到excel表单
*
* @return 结果
*/
public AjaxResult exportExcel()
{
OutputStream out = null;
try
{
// 取出一共有多少个sheet.
double sheetNo = Math.ceil(list.size() / sheetSize);
for (int index = 0; index <= sheetNo; index++)
{
createSheet(sheetNo, index);
Cell cell = null; // 产生单元格
// 产生一行
Row row = sheet.createRow(0);
// 写入各个字段的列头名称
for (int i = 0; i < fields.size(); i++)
{
Field field = fields.get(i);
Excel attr = field.getAnnotation(Excel.class);
// 创建列
cell = row.createCell(i);
// 设置列中写入内容为String类型
cell.setCellType(CellType.STRING);
CellStyle cellStyle = wb.createCellStyle();
cellStyle.setAlignment(HorizontalAlignment.CENTER);
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
if (attr.name().indexOf("注:") >= 0)
{
Font font = wb.createFont();
font.setColor(HSSFFont.COLOR_RED);
cellStyle.setFont(font);
cellStyle.setFillForegroundColor(HSSFColorPredefined.YELLOW.getIndex());
sheet.setColumnWidth(i, 6000);
}
else
{
Font font = wb.createFont();
// 粗体显示
font.setBold(true);
// 选择需要用到的字体格式
cellStyle.setFont(font);
cellStyle.setFillForegroundColor(HSSFColorPredefined.LIGHT_YELLOW.getIndex());
// 设置列宽
sheet.setColumnWidth(i, (int) ((attr.width() + 0.72) * 256));
row.setHeight((short) (attr.height() * 20));
}
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
cellStyle.setWrapText(true);
cell.setCellStyle(cellStyle);
// 写入列名
cell.setCellValue(attr.name());
// 如果设置了提示信息则鼠标放上去提示.
if (StringUtils.isNotEmpty(attr.prompt()))
{
// 这里默认设了2-101列提示.
setHSSFPrompt(sheet, "", attr.prompt(), 1, 100, i, i);
}
// 如果设置了combo属性则本列只能选择不能输入
if (attr.combo().length > 0)
{
// 这里默认设了2-101列只能选择不能输入.
setHSSFValidation(sheet, attr.combo(), 1, 100, i, i);
}
}
if (Type.EXPORT.equals(type))
{
fillExcelData(index, row, cell);
}
}
String filename = encodingFilename(sheetName);
out = new FileOutputStream(getAbsoluteFile(filename));
wb.write(out);
return AjaxResult.success(filename);
}
catch (Exception e)
{
log.error("导出Excel异常{}", e.getMessage());
throw new BusinessException("导出Excel失败请联系网站管理员");
}
finally
{
if (wb != null)
{
try
{
wb.close();
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
if (out != null)
{
try
{
out.close();
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
}
}
/**
* 填充excel数据
*
* @param index 序号
* @param row 单元格行
* @param cell 类型单元格
*/
public void fillExcelData(int index, Row row, Cell cell)
{
int startNo = index * sheetSize;
int endNo = Math.min(startNo + sheetSize, list.size());
// 写入各条记录,每条记录对应excel表中的一行
CellStyle cs = wb.createCellStyle();
cs.setAlignment(HorizontalAlignment.CENTER);
cs.setVerticalAlignment(VerticalAlignment.CENTER);
for (int i = startNo; i < endNo; i++)
{
row = sheet.createRow(i + 1 - startNo);
// 得到导出对象.
T vo = (T) list.get(i);
for (int j = 0; j < fields.size(); j++)
{
// 获得field.
Field field = fields.get(j);
// 设置实体类私有属性可访问
field.setAccessible(true);
Excel attr = field.getAnnotation(Excel.class);
try
{
// 设置行高
row.setHeight((short) (attr.height() * 20));
// 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.
if (attr.isExport())
{
// 创建cell
cell = row.createCell(j);
cell.setCellStyle(cs);
if (vo == null)
{
// 如果数据存在就填入,不存在填入空格.
cell.setCellValue("");
continue;
}
// 用于读取对象中的属性
Object value = getTargetValue(vo, field, attr);
String dateFormat = attr.dateFormat();
String readConverterExp = attr.readConverterExp();
if (StringUtils.isNotEmpty(dateFormat))
{
cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value));
}
else if (StringUtils.isNotEmpty(readConverterExp))
{
cell.setCellValue(convertByExp(String.valueOf(value), readConverterExp));
}
else
{
cell.setCellType(CellType.STRING);
// 如果数据存在就填入,不存在填入空格.
cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix());
}
}
}
catch (Exception e)
{
log.error("导出Excel失败{}", e.getMessage());
}
}
}
}
/**
* 设置单元格上提示
*
* @param sheet 要设置的sheet.
* @param promptTitle 标题
* @param promptContent 内容
* @param firstRow 开始行
* @param endRow 结束行
* @param firstCol 开始列
* @param endCol 结束列
* @return 设置好的sheet.
*/
public static Sheet setHSSFPrompt(Sheet sheet, String promptTitle, String promptContent, int firstRow, int endRow,
int firstCol, int endCol)
{
// 构造constraint对象
DVConstraint constraint = DVConstraint.createCustomFormulaConstraint("DD1");
// 四个参数分别是起始行终止行起始列终止列
CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
// 数据有效性对象
HSSFDataValidation dataValidationView = new HSSFDataValidation(regions, constraint);
dataValidationView.createPromptBox(promptTitle, promptContent);
sheet.addValidationData(dataValidationView);
return sheet;
}
/**
* 设置某些列的值只能输入预制的数据,显示下拉框.
*
* @param sheet 要设置的sheet.
* @param textlist 下拉框显示的内容
* @param firstRow 开始行
* @param endRow 结束行
* @param firstCol 开始列
* @param endCol 结束列
* @return 设置好的sheet.
*/
public static Sheet setHSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol,
int endCol)
{
DataValidationHelper helper = sheet.getDataValidationHelper();
// 加载下拉列表内容
DataValidationConstraint constraint = helper.createExplicitListConstraint(textlist);
// 设置数据有效性加载在哪个单元格上,四个参数分别是起始行终止行起始列终止列
CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
// 数据有效性对象
DataValidation dataValidation = helper.createValidation(constraint, regions);
// 处理Excel兼容性问题
if (dataValidation instanceof XSSFDataValidation)
{
dataValidation.setSuppressDropDownArrow(true);
dataValidation.setShowErrorBox(true);
}
else
{
dataValidation.setSuppressDropDownArrow(false);
}
sheet.addValidationData(dataValidation);
return sheet;
}
/**
* 解析导出值 0=,1=,2=未知
*
* @param propertyValue 参数值
* @param converterExp 翻译注解
* @return 解析后值
* @throws Exception
*/
public static String convertByExp(String propertyValue, String converterExp) throws Exception
{
try
{
String[] convertSource = converterExp.split(",");
for (String item : convertSource)
{
String[] itemArray = item.split("=");
if (itemArray[0].equals(propertyValue))
{
return itemArray[1];
}
}
}
catch (Exception e)
{
throw e;
}
return propertyValue;
}
/**
* 反向解析值 =0,=1,未知=2
*
* @param propertyValue 参数值
* @param converterExp 翻译注解
* @return 解析后值
* @throws Exception
*/
public static String reverseByExp(String propertyValue, String converterExp) throws Exception
{
try
{
String[] convertSource = converterExp.split(",");
for (String item : convertSource)
{
String[] itemArray = item.split("=");
if (itemArray[1].equals(propertyValue))
{
return itemArray[0];
}
}
}
catch (Exception e)
{
throw e;
}
return propertyValue;
}
/**
* 编码文件名
*/
public String encodingFilename(String filename)
{
filename = UUID.randomUUID().toString() + "_" + filename + ".xlsx";
return filename;
}
/**
* 获取下载路径
*
* @param filename 文件名称
*/
public String getAbsoluteFile(String filename)
{
String downloadPath = LuckyFrameConfig.getDownloadPath() + filename;
File desc = new File(downloadPath);
if (!desc.getParentFile().exists())
{
desc.getParentFile().mkdirs();
}
return downloadPath;
}
/**
* 获取bean中的属性值
*
* @param vo 实体对象
* @param field 字段
* @param excel 注解
* @return 最终的属性值
* @throws Exception
*/
private Object getTargetValue(T vo, Field field, Excel excel) throws Exception
{
Object o = field.get(vo);
if (StringUtils.isNotEmpty(excel.targetAttr()))
{
String target = excel.targetAttr();
if (target.indexOf(".") > -1)
{
String[] targets = target.split("[.]");
for (String name : targets)
{
o = getValue(o, name);
}
}
else
{
o = getValue(o, target);
}
}
return o;
}
/**
* 以类的属性的get方法方法形式获取值
*
* @param o
* @param name
* @return value
* @throws Exception
*/
private Object getValue(Object o, String name) throws Exception
{
if (StringUtils.isNotEmpty(name))
{
Class<?> clazz = o.getClass();
String methodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
Method method = clazz.getMethod(methodName);
o = method.invoke(o);
}
return o;
}
/**
* 得到所有定义字段
*/
private void createExcelField()
{
this.fields = new ArrayList<Field>();
List<Field> tempFields = new ArrayList<>();
Class<?> tempClass = clazz;
tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
while (tempClass != null)
{
tempClass = tempClass.getSuperclass();
if (tempClass != null)
tempFields.addAll(Arrays.asList(tempClass.getDeclaredFields()));
}
putToFields(tempFields);
}
/**
* 放到字段集合中
*/
private void putToFields(List<Field> fields)
{
for (Field field : fields)
{
Excel attr = field.getAnnotation(Excel.class);
if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
{
this.fields.add(field);
}
}
}
/**
* 创建一个工作簿
*/
public void createWorkbook()
{
this.wb = new SXSSFWorkbook(500);
}
/**
* 创建工作表
*
* @param sheetName指定Sheet名称
* @param sheetNo sheet数量
* @param index 序号
*/
public void createSheet(double sheetNo, int index)
{
this.sheet = wb.createSheet();
// 设置工作表的名称.
if (sheetNo == 0)
{
wb.setSheetName(index, sheetName);
}
else
{
wb.setSheetName(index, sheetName + index);
}
}
/**
* 获取单元格值
*
* @param row 获取的行
* @param column 获取单元格列号
* @return 单元格值
*/
public Object getCellValue(Row row, int column)
{
if (row == null)
{
return row;
}
Object val = "";
try
{
Cell cell = row.getCell(column);
if (cell != null)
{
if (cell.getCellTypeEnum() == CellType.NUMERIC)
{
val = cell.getNumericCellValue();
if (HSSFDateUtil.isCellDateFormatted(cell))
{
val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换
}
else
{
if ((Double) val % 1 > 0)
{
val = new DecimalFormat("0.00").format(val);
}
else
{
val = new DecimalFormat("0").format(val);
}
}
}
else if (cell.getCellTypeEnum() == CellType.STRING)
{
val = cell.getStringCellValue();
}
else if (cell.getCellTypeEnum() == CellType.BOOLEAN)
{
val = cell.getBooleanCellValue();
}
else if (cell.getCellTypeEnum() == CellType.ERROR)
{
val = cell.getErrorCellValue();
}
}
}
catch (Exception e)
{
return val;
}
return val;
}
}

View File

@ -0,0 +1,46 @@
package com.luckyframe.common.utils.security;
import org.apache.commons.lang3.StringUtils;
import com.luckyframe.common.constant.PermissionConstants;
import com.luckyframe.common.utils.MessageUtils;
/**
* permission 工具类
*
* @author ruoyi
*/
public class PermissionUtils
{
/**
* 权限错误消息提醒
*
* @param permissionsStr 错误信息
* @return
*/
public static String getMsg(String permissionsStr)
{
String permission = StringUtils.substringBetween(permissionsStr, "[", "]");
String msg = MessageUtils.message("no.view.permission", permission);
if (StringUtils.endsWithIgnoreCase(permission, PermissionConstants.ADD_PERMISSION))
{
msg = MessageUtils.message("no.create.permission", permission);
}
else if (StringUtils.endsWithIgnoreCase(permission, PermissionConstants.EDIT_PERMISSION))
{
msg = MessageUtils.message("no.update.permission", permission);
}
else if (StringUtils.endsWithIgnoreCase(permission, PermissionConstants.REMOVE_PERMISSION))
{
msg = MessageUtils.message("no.delete.permission", permission);
}
else if (StringUtils.endsWithIgnoreCase(permission, PermissionConstants.EXPORT_PERMISSION))
{
msg = MessageUtils.message("no.export.permission", permission);
}
else if (StringUtils.endsWithAny(permission, new String[] { PermissionConstants.VIEW_PERMISSION, PermissionConstants.LIST_PERMISSION }))
{
msg = MessageUtils.message("no.view.permission", permission);
}
return msg;
}
}

View File

@ -0,0 +1,84 @@
package com.luckyframe.common.utils.security;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.mgt.RealmSecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import com.luckyframe.common.utils.StringUtils;
import com.luckyframe.common.utils.bean.BeanUtils;
import com.luckyframe.framework.shiro.realm.UserRealm;
import com.luckyframe.project.system.user.domain.User;
/**
* shiro 工具类
*
* @author ruoyi
*/
public class ShiroUtils
{
public static Subject getSubject()
{
return SecurityUtils.getSubject();
}
public static Session getSession()
{
return SecurityUtils.getSubject().getSession();
}
public static void logout()
{
getSubject().logout();
}
public static User getSysUser()
{
User user = null;
Object obj = getSubject().getPrincipal();
if (StringUtils.isNotNull(obj))
{
user = new User();
BeanUtils.copyBeanProp(user, obj);
}
return user;
}
public static void setSysUser(User user)
{
Subject subject = getSubject();
PrincipalCollection principalCollection = subject.getPrincipals();
String realmName = principalCollection.getRealmNames().iterator().next();
PrincipalCollection newPrincipalCollection = new SimplePrincipalCollection(user, realmName);
// 重新加载Principal
subject.runAs(newPrincipalCollection);
}
public static void clearCachedAuthorizationInfo()
{
RealmSecurityManager rsm = (RealmSecurityManager) SecurityUtils.getSecurityManager();
UserRealm realm = (UserRealm) rsm.getRealms().iterator().next();
realm.clearCachedAuthorizationInfo();
}
public static Long getUserId()
{
return getSysUser().getUserId().longValue();
}
public static String getLoginName()
{
return getSysUser().getLoginName();
}
public static String getIp()
{
return getSubject().getSession().getHost();
}
public static String getSessionId()
{
return String.valueOf(getSubject().getSession().getId());
}
}

View File

@ -0,0 +1,101 @@
package com.luckyframe.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,97 @@
package com.luckyframe.common.xss;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.luckyframe.common.utils.StringUtils;
/**
* 防止XSS攻击的过滤器
*
* @author ruoyi
*/
public class XssFilter implements Filter
{
/**
* 排除链接
*/
public List<String> excludes = new ArrayList<>();
/**
* xss过滤开关
*/
public boolean enabled = false;
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
String tempExcludes = filterConfig.getInitParameter("excludes");
String tempEnabled = filterConfig.getInitParameter("enabled");
if (StringUtils.isNotEmpty(tempExcludes))
{
String[] url = tempExcludes.split(",");
for (int i = 0; url != null && i < url.length; i++)
{
excludes.add(url[i]);
}
}
if (StringUtils.isNotEmpty(tempEnabled))
{
enabled = Boolean.valueOf(tempEnabled);
}
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
if (handleExcludeURL(req, resp))
{
chain.doFilter(request, response);
return;
}
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);
chain.doFilter(xssRequest, response);
}
private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response)
{
if (!enabled)
{
return true;
}
if (excludes == null || excludes.isEmpty())
{
return false;
}
String url = request.getServletPath();
for (String pattern : excludes)
{
Pattern p = Pattern.compile("^" + pattern);
Matcher m = p.matcher(url);
if (m.find())
{
return true;
}
}
return false;
}
@Override
public void destroy()
{
}
}

View File

@ -0,0 +1,40 @@
package com.luckyframe.common.xss;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.jsoup.Jsoup;
import org.jsoup.safety.Whitelist;
/**
* XSS过滤处理
*
* @author ruoyi
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper
{
/**
* @param request
*/
public XssHttpServletRequestWrapper(HttpServletRequest request)
{
super(request);
}
@Override
public String[] getParameterValues(String name)
{
String[] values = super.getParameterValues(name);
if (values != null)
{
int length = values.length;
String[] escapseValues = new String[length];
for (int i = 0; i < length; i++)
{
// 防xss攻击和过滤前后空格
escapseValues[i] = Jsoup.clean(values[i], Whitelist.relaxed()).trim();
}
return escapseValues;
}
return super.getParameterValues(name);
}
}

View File

@ -0,0 +1,122 @@
package com.luckyframe.framework.aspectj;
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import com.luckyframe.common.utils.StringUtils;
import com.luckyframe.common.utils.security.ShiroUtils;
import com.luckyframe.framework.aspectj.lang.annotation.DataScope;
import com.luckyframe.framework.web.domain.BaseEntity;
import com.luckyframe.project.system.role.domain.Role;
import com.luckyframe.project.system.user.domain.User;
/**
* 数据过滤处理
*
* @author ruoyi
*/
@Aspect
@Component
public class DataScopeAspect
{
/**
* 全部数据权限
*/
public static final String DATA_SCOPE_ALL = "1";
/**
* 自定数据权限
*/
public static final String DATA_SCOPE_CUSTOM = "2";
/**
* 数据权限过滤关键字
*/
public static final String DATA_SCOPE = "dataScope";
// 配置织入点
@Pointcut("@annotation(com.luckyframe.framework.aspectj.lang.annotation.DataScope)")
public void dataScopePointCut()
{
}
@Before("dataScopePointCut()")
public void doBefore(JoinPoint point) throws Throwable
{
handleDataScope(point);
}
protected void handleDataScope(final JoinPoint joinPoint)
{
// 获得注解
DataScope controllerDataScope = getAnnotationLog(joinPoint);
if (controllerDataScope == null)
{
return;
}
// 获取当前的用户
User currentUser = ShiroUtils.getSysUser();
if (currentUser != null)
{
// 如果是超级管理员则不过滤数据
if (!currentUser.isAdmin())
{
dataScopeFilter(joinPoint, currentUser, controllerDataScope.tableAlias());
}
}
}
/**
* 数据范围过滤
* @param joinPoint 切点
* @param user 用户
* @param alias 别名
*/
public static void dataScopeFilter(JoinPoint joinPoint, User user, String alias)
{
StringBuilder sqlString = new StringBuilder();
for (Role role : user.getRoles())
{
String dataScope = role.getDataScope();
if (DATA_SCOPE_ALL.equals(dataScope))
{
sqlString = new StringBuilder();
break;
}
else if (DATA_SCOPE_CUSTOM.equals(dataScope))
{
sqlString.append(StringUtils.format(
" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", alias,
role.getRoleId()));
}
}
if (StringUtils.isNotBlank(sqlString.toString()))
{
BaseEntity baseEntity = (BaseEntity) joinPoint.getArgs()[0];
baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
}
}
/**
* 是否存在注解如果存在就获取
*/
private DataScope getAnnotationLog(JoinPoint joinPoint)
{
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null)
{
return method.getAnnotation(DataScope.class);
}
return null;
}
}

View File

@ -0,0 +1,59 @@
package com.luckyframe.framework.aspectj;
import java.lang.reflect.Method;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import com.luckyframe.common.utils.StringUtils;
import com.luckyframe.framework.aspectj.lang.annotation.DataSource;
import com.luckyframe.framework.datasource.DynamicDataSourceContextHolder;
/**
* 多数据源处理
*
* @author ruoyi
*/
@Aspect
@Order(1)
@Component
public class DataSourceAspect
{
protected Logger logger = LoggerFactory.getLogger(getClass());
@Pointcut("@annotation(com.luckyframe.framework.aspectj.lang.annotation.DataSource)")
public void dsPointCut()
{
}
@Around("dsPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable
{
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
DataSource dataSource = method.getAnnotation(DataSource.class);
if (StringUtils.isNotNull(dataSource))
{
DynamicDataSourceContextHolder.setDateSoureType(dataSource.value().name());
}
try
{
return point.proceed();
}
finally
{
// 销毁数据源 在执行方法之后
DynamicDataSourceContextHolder.clearDateSoureType();
}
}
}

View File

@ -0,0 +1,172 @@
package com.luckyframe.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.stereotype.Component;
import com.alibaba.fastjson.JSONObject;
import com.luckyframe.common.utils.ServletUtils;
import com.luckyframe.common.utils.StringUtils;
import com.luckyframe.common.utils.security.ShiroUtils;
import com.luckyframe.framework.aspectj.lang.annotation.Log;
import com.luckyframe.framework.aspectj.lang.enums.BusinessStatus;
import com.luckyframe.framework.manager.AsyncManager;
import com.luckyframe.framework.manager.factory.AsyncFactory;
import com.luckyframe.project.monitor.operlog.domain.OperLog;
import com.luckyframe.project.system.user.domain.User;
/**
* 操作日志记录处理
*
* @author ruoyi
*/
@Aspect
@Component
public class LogAspect
{
private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
// 配置织入点
@Pointcut("@annotation(com.luckyframe.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);
}
protected void handleLog(final JoinPoint joinPoint, final Exception e)
{
try
{
// 获得注解
Log controllerLog = getAnnotationLog(joinPoint);
if (controllerLog == null)
{
return;
}
// 获取当前的用户
User currentUser = ShiroUtils.getSysUser();
// *========数据库日志=========*//
OperLog operLog = new OperLog();
operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
// 请求的地址
String ip = ShiroUtils.getIp();
operLog.setOperIp(ip);
operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());
if (currentUser != null)
{
operLog.setOperName(currentUser.getLoginName());
if (StringUtils.isNotNull(currentUser.getDept())
&& StringUtils.isNotEmpty(currentUser.getDept().getDeptName()))
{
operLog.setDeptName(currentUser.getDept().getDeptName());
}
}
if (e != null)
{
operLog.setStatus(BusinessStatus.FAIL.ordinal());
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);
// 保存数据库
AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
}
catch (Exception exp)
{
// 记录本地异常日志
log.error("==前置通知异常==");
log.error("异常信息:{}", exp.getMessage());
exp.printStackTrace();
}
}
/**
* 获取注解中对方法的描述信息 用于Controller层注解
*
* @param log 日志
* @param operLog 操作日志
* @throws Exception
*/
public void getControllerMethodDescription(Log log, OperLog operLog) throws Exception
{
// 设置action动作
operLog.setBusinessType(log.businessType().ordinal());
// 设置标题
operLog.setTitle(log.title());
// 设置操作人类别
operLog.setOperatorType(log.operatorType().ordinal());
// 是否需要保存request参数和值
if (log.isSaveRequestData())
{
// 获取参数的信息传入到数据库中
setRequestValue(operLog);
}
}
/**
* 获取请求的参数放到log中
*
* @param operLog
* @param request
*/
private void setRequestValue(OperLog operLog)
{
Map<String, String[]> map = ServletUtils.getRequest().getParameterMap();
String params = JSONObject.toJSONString(map);
operLog.setOperParam(StringUtils.substring(params, 0, 255));
}
/**
* 是否存在注解如果存在就获取
*/
private 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,23 @@
package com.luckyframe.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.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataScope
{
/**
* 表的别名
*/
public String tableAlias() default "";
}

View File

@ -0,0 +1,23 @@
package com.luckyframe.framework.aspectj.lang.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.luckyframe.framework.aspectj.lang.enums.DataSourceType;
/**
* 自定义多数据源切换注解
*
* @author ruoyi
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource
{
/**
* 切换数据源名称
*/
public DataSourceType value() default DataSourceType.MASTER;
}

View File

@ -0,0 +1,92 @@
package com.luckyframe.framework.aspectj.lang.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义导出Excel数据注解
*
* @author ruoyi
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Excel
{
/**
* 导出到Excel中的名字.
*/
public String name();
/**
* 日期格式, : yyyy-MM-dd
*/
public String dateFormat() default "";
/**
* 读取内容转表达式 (: 0=,1=,2=未知)
*/
public String readConverterExp() default "";
/**
* 导出时在excel中每个列的高度 单位为字符
*/
public double height() default 14;
/**
* 导出时在excel中每个列的宽 单位为字符
*/
public double width() default 16;
/**
* 文字后缀,% 90 变成90%
*/
public String suffix() default "";
/**
* 当值为空时,字段的默认值
*/
public String defaultValue() default "";
/**
* 提示信息
*/
public String prompt() default "";
/**
* 设置只能选择不能输入的列内容.
*/
public String[] combo() default {};
/**
* 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
*/
public boolean isExport() default true;
/**
* 另一个类中的属性名称,支持多级获取,以小数点隔开
*/
public String targetAttr() default "";
/**
* 字段类型0导出导入1仅导出2仅导入
*/
Type type() default Type.ALL;
public enum Type
{
ALL(0), EXPORT(1), IMPORT(2);
private final int value;
Type(int value)
{
this.value = value;
}
public int value()
{
return this.value;
}
}
}

View File

@ -0,0 +1,41 @@
package com.luckyframe.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;
import com.luckyframe.framework.aspectj.lang.enums.BusinessType;
import com.luckyframe.framework.aspectj.lang.enums.OperatorType;
/**
* 自定义操作日志记录注解
*
* @author ruoyi
*
*/
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log
{
/**
* 模块
*/
public String title() default "";
/**
* 功能
*/
public BusinessType businessType() default BusinessType.OTHER;
/**
* 操作人类别
*/
public OperatorType operatorType() default OperatorType.MANAGE;
/**
* 是否保存请求的参数
*/
public boolean isSaveRequestData() default true;
}

View File

@ -0,0 +1,20 @@
package com.luckyframe.framework.aspectj.lang.enums;
/**
* 操作状态
*
* @author ruoyi
*
*/
public enum BusinessStatus
{
/**
* 成功
*/
SUCCESS,
/**
* 失败
*/
FAIL,
}

View File

@ -0,0 +1,60 @@
package com.luckyframe.framework.aspectj.lang.enums;
/**
* 业务操作类型
*
* @author ruoyi
*
*/
public enum BusinessType
{
/**
* 其它
*/
OTHER,
/**
* 新增
*/
INSERT,
/**
* 修改
*/
UPDATE,
/**
* 删除
*/
DELETE,
/**
* 授权
*/
GRANT,
/**
* 导出
*/
EXPORT,
/**
* 导入
*/
IMPORT,
/**
* 强退
*/
FORCE,
/**
* 生成代码
*/
GENCODE,
/**
* 清空数据
*/
CLEAN,
}

View File

@ -0,0 +1,19 @@
package com.luckyframe.framework.aspectj.lang.enums;
/**
* 数据源
*
* @author ruoyi
*/
public enum DataSourceType
{
/**
* 主库
*/
MASTER,
/**
* 从库
*/
SLAVE
}

View File

@ -0,0 +1,25 @@
package com.luckyframe.framework.aspectj.lang.enums;
/**
* 操作人类别
*
* @author ruoyi
*
*/
public enum OperatorType
{
/**
* 其它
*/
OTHER,
/**
* 后台用户
*/
MANAGE,
/**
* 手机端用户
*/
MOBILE
}

View File

@ -0,0 +1,86 @@
package com.luckyframe.framework.config;
import java.util.Properties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
/**
* 验证码配置
*
* @author ruoyi
*/
@Configuration
public class CaptchaConfig
{
@Bean(name = "captchaProducer")
public DefaultKaptcha getKaptchaBean()
{
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties();
// 是否有边框 默认为true 我们可以自己设置yesno
properties.setProperty("kaptcha.border", "yes");
// 边框颜色 默认为Color.BLACK
properties.setProperty("kaptcha.border.color", "105,179,90");
// 验证码文本字符颜色 默认为Color.BLACK
properties.setProperty("kaptcha.textproducer.font.color", "blue");
// 验证码图片宽度 默认为200
properties.setProperty("kaptcha.image.width", "160");
// 验证码图片高度 默认为50
properties.setProperty("kaptcha.image.height", "60");
// 验证码文本字符大小 默认为40
properties.setProperty("kaptcha.textproducer.font.size", "30");
// KAPTCHA_SESSION_KEY
properties.setProperty("kaptcha.session.key", "kaptchaCode");
// 验证码文本字符间距 默认为2
properties.setProperty("kaptcha.textproducer.char.space", "3");
// 验证码文本字符长度 默认为5
properties.setProperty("kaptcha.textproducer.char.length", "5");
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
properties.setProperty("kaptcha.textproducer.font.names", "Arial,Courier");
// 验证码噪点颜色 默认为Color.BLACK
properties.setProperty("kaptcha.noise.color", "white");
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
@Bean(name = "captchaProducerMath")
public DefaultKaptcha getKaptchaBeanMath()
{
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties();
// 是否有边框 默认为true 我们可以自己设置yesno
properties.setProperty("kaptcha.border", "yes");
// 边框颜色 默认为Color.BLACK
properties.setProperty("kaptcha.border.color", "105,179,90");
// 验证码文本字符颜色 默认为Color.BLACK
properties.setProperty("kaptcha.textproducer.font.color", "blue");
// 验证码图片宽度 默认为200
properties.setProperty("kaptcha.image.width", "160");
// 验证码图片高度 默认为50
properties.setProperty("kaptcha.image.height", "60");
// 验证码文本字符大小 默认为40
properties.setProperty("kaptcha.textproducer.font.size", "35");
// KAPTCHA_SESSION_KEY
properties.setProperty("kaptcha.session.key", "kaptchaCodeMath");
// 验证码文本生成器
properties.setProperty("kaptcha.textproducer.impl", "com.luckyframe.framework.config.KaptchaTextCreator");
// 验证码文本字符间距 默认为2
properties.setProperty("kaptcha.textproducer.char.space", "3");
// 验证码文本字符长度 默认为5
properties.setProperty("kaptcha.textproducer.char.length", "6");
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
properties.setProperty("kaptcha.textproducer.font.names", "Arial,Courier");
// 验证码噪点颜色 默认为Color.BLACK
properties.setProperty("kaptcha.noise.color", "white");
// 干扰实现类
properties.setProperty("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise");
// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
properties.setProperty("kaptcha.obscurificator.impl", "com.google.code.kaptcha.impl.ShadowGimpy");
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
}

View File

@ -0,0 +1,51 @@
package com.luckyframe.framework.config;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
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.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.luckyframe.framework.aspectj.lang.enums.DataSourceType;
import com.luckyframe.framework.config.properties.DruidProperties;
import com.luckyframe.framework.datasource.DynamicDataSource;
/**
* druid 配置多数据源
*
* @author ruoyi
*/
@Configuration
public class DruidConfig
{
@Bean
@ConfigurationProperties("spring.datasource.druid.master")
public DataSource masterDataSource(DruidProperties druidProperties)
{
DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
return druidProperties.dataSource(dataSource);
}
@Bean
@ConfigurationProperties("spring.datasource.druid.slave")
@ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
public DataSource slaveDataSource(DruidProperties druidProperties)
{
DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
return druidProperties.dataSource(dataSource);
}
@Bean(name = "dynamicDataSource")
@Primary
public DynamicDataSource dataSource(DataSource masterDataSource, DataSource slaveDataSource)
{
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
targetDataSources.put(DataSourceType.SLAVE.name(), slaveDataSource);
return new DynamicDataSource(masterDataSource, targetDataSources);
}
}

View File

@ -0,0 +1,46 @@
package com.luckyframe.framework.config;
import java.util.Map;
import javax.servlet.DispatcherType;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.google.common.collect.Maps;
import com.luckyframe.common.utils.StringUtils;
import com.luckyframe.common.xss.XssFilter;
/**
* Filter配置
*
* @author ruoyi
*/
@Configuration
public class FilterConfig
{
@Value("${xss.enabled}")
private String enabled;
@Value("${xss.excludes}")
private String excludes;
@Value("${xss.urlPatterns}")
private String urlPatterns;
@SuppressWarnings({ "rawtypes", "unchecked" })
@Bean
public FilterRegistrationBean xssFilterRegistration()
{
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setDispatcherTypes(DispatcherType.REQUEST);
registration.setFilter(new XssFilter());
registration.addUrlPatterns(StringUtils.split(urlPatterns, ","));
registration.setName("xssFilter");
registration.setOrder(Integer.MAX_VALUE);
Map<String, String> initParameters = Maps.newHashMap();
initParameters.put("excludes", excludes);
initParameters.put("enabled", enabled);
registration.setInitParameters(initParameters);
return registration;
}
}

View File

@ -0,0 +1,66 @@
package com.luckyframe.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 void setAuthor(String author)
{
GenConfig.author = author;
}
public static String getPackageName()
{
return packageName;
}
public void setPackageName(String packageName)
{
GenConfig.packageName = packageName;
}
public static String getAutoRemovePre()
{
return autoRemovePre;
}
public void setAutoRemovePre(String autoRemovePre)
{
GenConfig.autoRemovePre = autoRemovePre;
}
public static String getTablePrefix()
{
return tablePrefix;
}
public void setTablePrefix(String tablePrefix)
{
GenConfig.tablePrefix = tablePrefix;
}
}

View File

@ -0,0 +1,43 @@
package com.luckyframe.framework.config;
import java.util.Locale;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
/**
* 资源文件配置加载
*
* @author ruoyi
*/
@Configuration
public class I18nConfig implements WebMvcConfigurer
{
@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,75 @@
package com.luckyframe.framework.config;
import java.util.Random;
import com.google.code.kaptcha.text.impl.DefaultTextCreator;
/**
* 验证码文本生成器
*
* @author ruoyi
*/
public class KaptchaTextCreator extends DefaultTextCreator
{
private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(",");
@Override
public String getText()
{
Integer result = 0;
Random random = new Random();
int x = random.nextInt(10);
int y = random.nextInt(10);
StringBuilder suChinese = new StringBuilder();
int randomoperands = (int) Math.round(Math.random() * 2);
if (randomoperands == 0)
{
result = x * y;
suChinese.append(CNUMBERS[x]);
suChinese.append("*");
suChinese.append(CNUMBERS[y]);
}
else if (randomoperands == 1)
{
if (!(x == 0) && y % x == 0)
{
result = y / x;
suChinese.append(CNUMBERS[y]);
suChinese.append("/");
suChinese.append(CNUMBERS[x]);
}
else
{
result = x + y;
suChinese.append(CNUMBERS[x]);
suChinese.append("+");
suChinese.append(CNUMBERS[y]);
}
}
else if (randomoperands == 2)
{
if (x >= y)
{
result = x - y;
suChinese.append(CNUMBERS[x]);
suChinese.append("-");
suChinese.append(CNUMBERS[y]);
}
else
{
result = y - x;
suChinese.append(CNUMBERS[y]);
suChinese.append("-");
suChinese.append(CNUMBERS[x]);
}
}
else
{
result = x + y;
suChinese.append(CNUMBERS[x]);
suChinese.append("+");
suChinese.append(CNUMBERS[y]);
}
suChinese.append("=?@" + result);
return suChinese.toString();
}
}

View File

@ -0,0 +1,94 @@
package com.luckyframe.framework.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 读取项目中相关的配置
* =================================================================
* 这是一个受限制的自由软件您不能在任何未经允许的前提下对程序代码进行修改和用于商业用途也不允许对程序代码修改后以任何形式任何目的的再发布
* 为了尊重作者的劳动成果LuckyFrame关键版权信息严禁篡改 有任何疑问欢迎联系作者讨论 QQ:1573584944 Seagull
* =================================================================
* @author Seagull
* @date 2019年2月12日
*/
@Component
@ConfigurationProperties(prefix = "ruoyi")
public class LuckyFrameConfig
{
/** 项目名称 */
private String name;
/** 版本 */
private String version;
/** 版权年份 */
private String copyrightYear;
/** 上传路径 */
private static String profile;
/** 获取地址开关 */
private static boolean addressEnabled;
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;
}
public static String getProfile()
{
return profile;
}
public void setProfile(String profile)
{
LuckyFrameConfig.profile = profile;
}
public static boolean isAddressEnabled()
{
return addressEnabled;
}
public void setAddressEnabled(boolean addressEnabled)
{
LuckyFrameConfig.addressEnabled = addressEnabled;
}
public static String getAvatarPath()
{
return profile + "avatar/";
}
public static String getDownloadPath()
{
return profile + "download/";
}
public static String getUploadPath()
{
return profile + "upload/";
}
}

View File

@ -0,0 +1,42 @@
package com.luckyframe.framework.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 通用配置
*
* @author ruoyi
*/
@Configuration
public class ResourcesConfig implements WebMvcConfigurer
{
/**
* 首页地址
*/
@Value("${shiro.user.indexUrl}")
private String indexUrl;
/**
* 默认首页的设置当输入域名是可以自动跳转到默认指定的网页
*/
@Override
public void addViewControllers(ViewControllerRegistry registry)
{
registry.addViewController("/").setViewName("forward:" + indexUrl);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
/** 文件上传路径 */
registry.addResourceHandler("/profile/**").addResourceLocations("file:" + LuckyFrameConfig.getProfile());
/** swagger配置 */
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}

View File

@ -0,0 +1,58 @@
package com.luckyframe.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", "LuckyFrameScheduler");
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.txIsolationLevelSerializable", "true");
// sqlserver 启用
//prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?");
prop.put("org.quartz.jobStore.misfireThreshold", "12000");
prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
factory.setQuartzProperties(prop);
factory.setSchedulerName("LuckyFrameScheduler");
// 延时启动
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,33 @@
package com.luckyframe.framework.config;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;
import com.luckyframe.common.utils.ServletUtils;
/**
* 服务相关配置
*
* @author ruoyi
*
*/
@Component
public class ServerConfig
{
/**
* 获取完整的请求路径包括域名端口上下文访问路径
*
* @return 服务地址
*/
public String getUrl()
{
HttpServletRequest request = ServletUtils.getRequest();
return getDomain(request);
}
public static String getDomain(HttpServletRequest request)
{
StringBuffer url = request.getRequestURL();
String contextPath = request.getServletContext().getContextPath();
return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString();
}
}

View File

@ -0,0 +1,381 @@
package com.luckyframe.framework.config;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.Filter;
import org.apache.commons.io.IOUtils;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.config.ConfigurationException;
import org.apache.shiro.io.ResourceUtils;
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.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
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.luckyframe.common.utils.StringUtils;
import com.luckyframe.framework.shiro.realm.UserRealm;
import com.luckyframe.framework.shiro.session.OnlineSessionDAO;
import com.luckyframe.framework.shiro.session.OnlineSessionFactory;
import com.luckyframe.framework.shiro.web.filter.LogoutFilter;
import com.luckyframe.framework.shiro.web.filter.captcha.CaptchaValidateFilter;
import com.luckyframe.framework.shiro.web.filter.online.OnlineSessionFilter;
import com.luckyframe.framework.shiro.web.filter.sync.SyncOnlineSessionFilter;
import com.luckyframe.framework.shiro.web.session.OnlineWebSessionManager;
import com.luckyframe.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.captchaEnabled}")
private boolean captchaEnabled;
// 验证码类型
@Value("${shiro.user.captchaType}")
private String captchaType;
// 设置Cookie的域名
@Value("${shiro.cookie.domain}")
private String domain;
// 设置cookie的有效访问路径
@Value("${shiro.cookie.path}")
private String path;
// 设置HttpOnly属性
@Value("${shiro.cookie.httpOnly}")
private boolean httpOnly;
// 设置Cookie的过期时间秒为单位
@Value("${shiro.cookie.maxAge}")
private int maxAge;
// 登录地址
@Value("${shiro.user.loginUrl}")
private String loginUrl;
// 权限认证失败地址
@Value("${shiro.user.unauthorizedUrl}")
private String unauthorizedUrl;
/**
* 缓存管理器 使用Ehcache实现
*/
@Bean
public EhCacheManager getEhCacheManager()
{
net.sf.ehcache.CacheManager cacheManager = net.sf.ehcache.CacheManager.getCacheManager("ruoyi");
EhCacheManager em = new EhCacheManager();
if (StringUtils.isNull(cacheManager))
{
em.setCacheManager(new net.sf.ehcache.CacheManager(getCacheManagerConfigFileInputStream()));
return em;
}
else
{
em.setCacheManager(cacheManager);
return em;
}
}
/**
* 返回配置文件流 避免ehcache配置文件一直被占用无法完全销毁项目重新部署
*/
protected InputStream getCacheManagerConfigFileInputStream()
{
String configFile = "classpath:ehcache/ehcache-shiro.xml";
InputStream inputStream = null;
try
{
inputStream = ResourceUtils.getInputStreamForPath(configFile);
byte[] b = IOUtils.toByteArray(inputStream);
InputStream in = new ByteArrayInputStream(b);
return in;
}
catch (IOException e)
{
throw new ConfigurationException(
"Unable to obtain input stream for cacheManagerConfigFile [" + configFile + "]", e);
}
finally
{
IOUtils.closeQuietly(inputStream);
}
}
/**
* 自定义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);
// 去掉 JSESSIONID
manager.setSessionIdUrlRewritingEnabled(false);
// 是否定时检查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);
// 去掉 JSESSIONID
manager.setSessionIdUrlRewritingEnabled(false);
// 定义要使用的无效的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.setRememberMeManager(rememberMeManager());
// 注入缓存管理器;
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("/logo.png**", "anon");
filterChainDefinitionMap.put("/indexlogo.png**", "anon");
filterChainDefinitionMap.put("/css/**", "anon");
filterChainDefinitionMap.put("/docs/**", "anon");
filterChainDefinitionMap.put("/fonts/**", "anon");
filterChainDefinitionMap.put("/img/**", "anon");
filterChainDefinitionMap.put("/ajax/**", "anon");
filterChainDefinitionMap.put("/js/**", "anon");
filterChainDefinitionMap.put("/ruoyi/**", "anon");
filterChainDefinitionMap.put("/druid/**", "anon");
filterChainDefinitionMap.put("/captcha/captchaImage**", "anon");
// 退出 logout地址shiro去清除session
filterChainDefinitionMap.put("/logout", "logout");
// 不需要拦截的访问
filterChainDefinitionMap.put("/login", "anon,captchaValidate");
// 系统权限列表
// filterChainDefinitionMap.putAll(SpringUtils.getBean(IMenuService.class).selectPermsAll());
Map<String, Filter> filters = new LinkedHashMap<>();
filters.put("onlineSession", onlineSessionFilter());
filters.put("syncOnlineSession", syncOnlineSessionFilter());
filters.put("captchaValidate", captchaValidateFilter());
// 注销成功则跳转到指定页面
filters.put("logout", logoutFilter());
shiroFilterFactoryBean.setFilters(filters);
// 所有请求需要认证
filterChainDefinitionMap.put("/**", "user,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;
}
/**
* 自定义验证码过滤器
*/
@Bean
public CaptchaValidateFilter captchaValidateFilter()
{
CaptchaValidateFilter captchaValidateFilter = new CaptchaValidateFilter();
captchaValidateFilter.setCaptchaEnabled(captchaEnabled);
captchaValidateFilter.setCaptchaType(captchaType);
return captchaValidateFilter;
}
/**
* cookie 属性设置
*/
public SimpleCookie rememberMeCookie()
{
SimpleCookie cookie = new SimpleCookie("rememberMe");
cookie.setDomain(domain);
cookie.setPath(path);
cookie.setHttpOnly(httpOnly);
cookie.setMaxAge(maxAge * 24 * 60 * 60);
return cookie;
}
/**
* 记住我
*/
public CookieRememberMeManager rememberMeManager()
{
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
cookieRememberMeManager.setCipherKey(Base64.decode("fCq+/xW488hMTCD+cmJ3aQ=="));
return cookieRememberMeManager;
}
/**
* 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,58 @@
package com.luckyframe.framework.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* Swagger2的接口配置
*
* @author ruoyi
*/
@Configuration
@EnableSwagger2
public class SwaggerConfig
{
/** 系统基础配置 */
@Autowired
private LuckyFrameConfig lfConfig;
/**
* 创建API
*/
@Bean
public Docket createRestApi()
{
return new Docket(DocumentationType.SWAGGER_2)
// 详细定制
.apiInfo(apiInfo())
.select()
// 指定当前包路径
.apis(RequestHandlerSelectors.basePackage("com.luckyframe.project.tool.swagger"))
// 扫描所有 .apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
/**
* 添加摘要信息
*/
private ApiInfo apiInfo()
{
// 用ApiInfoBuilder进行定制
return new ApiInfoBuilder()
.title("标题若依管理系统_接口文档")
.description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...")
.contact(new Contact(lfConfig.getName(), null, null))
.version("版本号:" + lfConfig.getVersion())
.build();
}
}

View File

@ -0,0 +1,53 @@
package com.luckyframe.framework.config;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
/**
* 线程池配置
*
* @author ruoyi
**/
@Configuration
public class ThreadPoolConfig
{
// 核心线程池大小
private int corePoolSize = 50;
// 最大可创建的线程数
private int maxPoolSize = 200;
// 队列最大长度
private int queueCapacity = 1000;
// 线程池维护线程所允许的空闲时间
private int keepAliveSeconds = 300;
@Bean(name = "threadPoolTaskExecutor")
public ThreadPoolTaskExecutor threadPoolTaskExecutor()
{
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setMaxPoolSize(maxPoolSize);
executor.setCorePoolSize(corePoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(keepAliveSeconds);
// 线程池对拒绝任务(无线程可用)的处理策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
/**
* 执行周期性或定时任务
*/
@Bean(name = "scheduledExecutorService")
protected ScheduledExecutorService scheduledExecutorService()
{
return new ScheduledThreadPoolExecutor(corePoolSize,
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build());
}
}

View File

@ -0,0 +1,77 @@
package com.luckyframe.framework.config.properties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import com.alibaba.druid.pool.DruidDataSource;
/**
* druid 配置属性
*
* @author ruoyi
*/
@Configuration
public class DruidProperties
{
@Value("${spring.datasource.druid.initialSize}")
private int initialSize;
@Value("${spring.datasource.druid.minIdle}")
private int minIdle;
@Value("${spring.datasource.druid.maxActive}")
private int maxActive;
@Value("${spring.datasource.druid.maxWait}")
private int maxWait;
@Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}")
private int timeBetweenEvictionRunsMillis;
@Value("${spring.datasource.druid.minEvictableIdleTimeMillis}")
private int minEvictableIdleTimeMillis;
@Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}")
private int maxEvictableIdleTimeMillis;
@Value("${spring.datasource.druid.validationQuery}")
private String validationQuery;
@Value("${spring.datasource.druid.testWhileIdle}")
private boolean testWhileIdle;
@Value("${spring.datasource.druid.testOnBorrow}")
private boolean testOnBorrow;
@Value("${spring.datasource.druid.testOnReturn}")
private boolean testOnReturn;
public DruidDataSource dataSource(DruidDataSource datasource)
{
/** 配置初始化大小、最小、最大 */
datasource.setInitialSize(initialSize);
datasource.setMaxActive(maxActive);
datasource.setMinIdle(minIdle);
/** 配置获取连接等待超时的时间 */
datasource.setMaxWait(maxWait);
/** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
/** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);
/**
* 用来检测连接是否有效的sql要求是一个查询语句常用select 'x'如果validationQuery为nulltestOnBorrowtestOnReturntestWhileIdle都不会起作用
*/
datasource.setValidationQuery(validationQuery);
/** 建议配置为true不影响性能并且保证安全性。申请连接的时候检测如果空闲时间大于timeBetweenEvictionRunsMillis执行validationQuery检测连接是否有效。 */
datasource.setTestWhileIdle(testWhileIdle);
/** 申请连接时执行validationQuery检测连接是否有效做了这个配置会降低性能。 */
datasource.setTestOnBorrow(testOnBorrow);
/** 归还连接时执行validationQuery检测连接是否有效做了这个配置会降低性能。 */
datasource.setTestOnReturn(testOnReturn);
return datasource;
}
}

View File

@ -0,0 +1,26 @@
package com.luckyframe.framework.datasource;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* 动态数据源
*
* @author ruoyi
*/
public class DynamicDataSource extends AbstractRoutingDataSource
{
public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources)
{
super.setDefaultTargetDataSource(defaultTargetDataSource);
super.setTargetDataSources(targetDataSources);
super.afterPropertiesSet();
}
@Override
protected Object determineCurrentLookupKey()
{
return DynamicDataSourceContextHolder.getDateSoureType();
}
}

View File

@ -0,0 +1,45 @@
package com.luckyframe.framework.datasource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 数据源切换处理
*
* @author ruoyi
*/
public class DynamicDataSourceContextHolder
{
public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);
/**
* 使用ThreadLocal维护变量ThreadLocal为每个使用该变量的线程提供独立的变量副本
* 所以每一个线程都可以独立地改变自己的副本而不会影响其它线程所对应的副本
*/
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
/**
* 设置数据源的变量
*/
public static void setDateSoureType(String dsType)
{
log.info("切换到{}数据源", dsType);
CONTEXT_HOLDER.set(dsType);
}
/**
* 获得数据源的变量
*/
public static String getDateSoureType()
{
return CONTEXT_HOLDER.get();
}
/**
* 清空数据源变量
*/
public static void clearDateSoureType()
{
CONTEXT_HOLDER.remove();
}
}

View File

@ -0,0 +1,53 @@
package com.luckyframe.framework.manager;
import java.util.TimerTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import com.luckyframe.common.utils.Threads;
import com.luckyframe.common.utils.spring.SpringUtils;
/**
* 异步任务管理器
*
* @author liuhulu
*/
public class AsyncManager
{
/**
* 操作延迟10毫秒
*/
private final int OPERATE_DELAY_TIME = 10;
/**
* 异步操作任务调度线程池
*/
private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
/**
* 单例模式
*/
private static AsyncManager me = new AsyncManager();
public static AsyncManager me()
{
return me;
}
/**
* 执行任务
*
* @param task 任务
*/
public void execute(TimerTask task)
{
executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
}
/**
* 停止任务线程池
*/
public void shutdown()
{
Threads.shutdownAndAwaitTermination(executor);
}
}

View File

@ -0,0 +1,64 @@
package com.luckyframe.framework.manager;
import com.luckyframe.framework.shiro.web.session.SpringSessionValidationScheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
/**
* 确保应用退出时能关闭后台线程
*
* @author cj
*/
@Component
public class ShutdownManager
{
private static final Logger logger = LoggerFactory.getLogger("sys-user");
@Autowired(required = false)
private SpringSessionValidationScheduler springSessionValidationScheduler;
@PreDestroy
public void destroy()
{
shutdownSpringSessionValidationScheduler();
shutdownAsyncManager();
}
/**
* 停止Seesion会话检查
*/
private void shutdownSpringSessionValidationScheduler()
{
if (springSessionValidationScheduler != null && springSessionValidationScheduler.isEnabled())
{
try
{
logger.info("====关闭会话验证任务====");
springSessionValidationScheduler.disableSessionValidation();
}
catch (Exception e)
{
logger.error(e.getMessage(), e);
}
}
}
/**
* 停止异步执行任务
*/
private void shutdownAsyncManager()
{
try
{
logger.info("====关闭后台任务任务线程池====");
AsyncManager.me().shutdown();
}
catch (Exception e)
{
logger.error(e.getMessage(), e);
}
}
}

View File

@ -0,0 +1,135 @@
package com.luckyframe.framework.manager.factory;
import java.util.TimerTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.luckyframe.common.constant.Constants;
import com.luckyframe.common.utils.AddressUtils;
import com.luckyframe.common.utils.LogUtils;
import com.luckyframe.common.utils.ServletUtils;
import com.luckyframe.common.utils.security.ShiroUtils;
import com.luckyframe.common.utils.spring.SpringUtils;
import com.luckyframe.project.monitor.logininfor.domain.Logininfor;
import com.luckyframe.project.monitor.logininfor.service.LogininforServiceImpl;
import com.luckyframe.project.monitor.online.domain.OnlineSession;
import com.luckyframe.project.monitor.online.domain.UserOnline;
import com.luckyframe.project.monitor.online.service.IUserOnlineService;
import com.luckyframe.project.monitor.operlog.domain.OperLog;
import com.luckyframe.project.monitor.operlog.service.IOperLogService;
import eu.bitwalker.useragentutils.UserAgent;
/**
* 异步工厂产生任务用
*
* @author liuhulu
*
*/
public class AsyncFactory
{
private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user");
/**
* 同步session到数据库
*
* @param session 在线用户会话
* @return 任务task
*/
public static TimerTask syncSessionToDb(final OnlineSession session)
{
return new TimerTask()
{
@Override
public void run()
{
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.setLoginLocation(AddressUtils.getRealAddressByIP(session.getHost()));
online.setBrowser(session.getBrowser());
online.setOs(session.getOs());
online.setStatus(session.getStatus());
online.setSession(session);
SpringUtils.getBean(IUserOnlineService.class).saveOnline(online);
}
};
}
/**
* 操作日志记录
*
* @param operLog 操作日志信息
* @return 任务task
*/
public static TimerTask recordOper(final OperLog operLog)
{
return new TimerTask()
{
@Override
public void run()
{
// 远程查询操作地点
operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
SpringUtils.getBean(IOperLogService.class).insertOperlog(operLog);
}
};
}
/**
* 记录登陆信息
*
* @param username 用户名
* @param status 状态
* @param message 消息
* @param args 列表
* @return 任务task
*/
public static TimerTask recordLogininfor(final String username, final String status, final String message, final Object... args)
{
final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
final String ip = ShiroUtils.getIp();
return new TimerTask()
{
@Override
public void run()
{
StringBuilder s = new StringBuilder();
s.append(LogUtils.getBlock(ip));
s.append(AddressUtils.getRealAddressByIP(ip));
s.append(LogUtils.getBlock(username));
s.append(LogUtils.getBlock(status));
s.append(LogUtils.getBlock(message));
// 打印信息到日志
sys_user_logger.info(s.toString(), args);
// 获取客户端操作系统
String os = userAgent.getOperatingSystem().getName();
// 获取客户端浏览器
String browser = userAgent.getBrowser().getName();
// 封装对象
Logininfor logininfor = new Logininfor();
logininfor.setLoginName(username);
logininfor.setIpaddr(ip);
logininfor.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
logininfor.setBrowser(browser);
logininfor.setOs(os);
logininfor.setMsg(message);
// 日志状态
if (Constants.LOGIN_SUCCESS.equals(status) || Constants.LOGOUT.equals(status))
{
logininfor.setStatus(Constants.SUCCESS);
}
else if (Constants.LOGIN_FAIL.equals(status))
{
logininfor.setStatus(Constants.FAIL);
}
// 插入数据
SpringUtils.getBean(LogininforServiceImpl.class).insertLogininfor(logininfor);
}
};
}
}

View File

@ -0,0 +1,143 @@
package com.luckyframe.framework.shiro.realm;
import java.util.HashSet;
import java.util.Set;
import org.apache.shiro.SecurityUtils;
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.luckyframe.common.exception.user.CaptchaException;
import com.luckyframe.common.exception.user.RoleBlockedException;
import com.luckyframe.common.exception.user.UserBlockedException;
import com.luckyframe.common.exception.user.UserNotExistsException;
import com.luckyframe.common.exception.user.UserPasswordNotMatchException;
import com.luckyframe.common.exception.user.UserPasswordRetryLimitExceedException;
import com.luckyframe.common.utils.security.ShiroUtils;
import com.luckyframe.framework.shiro.service.LoginService;
import com.luckyframe.project.system.menu.service.IMenuService;
import com.luckyframe.project.system.role.service.IRoleService;
import com.luckyframe.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)
{
User user = ShiroUtils.getSysUser();
// 角色列表
Set<String> roles = new HashSet<String>();
// 功能列表
Set<String> menus = new HashSet<String>();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// 管理员拥有所有权限
if (user.isAdmin())
{
info.addRole("admin");
info.addStringPermission("*:*:*");
}
else
{
roles = roleService.selectRoleKeys(user.getUserId());
menus = menuService.selectPermsByUserId(user.getUserId());
// 角色加入AuthorizationInfo认证对象
info.setRoles(roles);
// 权限加入AuthorizationInfo认证对象
info.setStringPermissions(menus);
}
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 (CaptchaException e)
{
throw new AuthenticationException(e.getMessage(), e);
}
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;
}
/**
* 清理缓存权限
*/
public void clearCachedAuthorizationInfo()
{
this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
}
}

View File

@ -0,0 +1,136 @@
package com.luckyframe.framework.shiro.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import com.luckyframe.common.constant.Constants;
import com.luckyframe.common.constant.ShiroConstants;
import com.luckyframe.common.constant.UserConstants;
import com.luckyframe.common.exception.user.CaptchaException;
import com.luckyframe.common.exception.user.UserBlockedException;
import com.luckyframe.common.exception.user.UserDeleteException;
import com.luckyframe.common.exception.user.UserNotExistsException;
import com.luckyframe.common.exception.user.UserPasswordNotMatchException;
import com.luckyframe.common.utils.DateUtils;
import com.luckyframe.common.utils.MessageUtils;
import com.luckyframe.common.utils.ServletUtils;
import com.luckyframe.common.utils.security.ShiroUtils;
import com.luckyframe.framework.manager.AsyncManager;
import com.luckyframe.framework.manager.factory.AsyncFactory;
import com.luckyframe.project.system.user.domain.User;
import com.luckyframe.project.system.user.domain.UserStatus;
import com.luckyframe.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(ServletUtils.getRequest().getAttribute(ShiroConstants.CURRENT_CAPTCHA)))
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
throw new CaptchaException();
}
// 用户名或密码为空 错误
if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password))
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));
throw new UserNotExistsException();
}
// 密码如果不在指定范围内 错误
if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
|| password.length() > UserConstants.PASSWORD_MAX_LENGTH)
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
throw new UserPasswordNotMatchException();
}
// 用户名不在指定范围内 错误
if (username.length() < UserConstants.USERNAME_MIN_LENGTH
|| username.length() > UserConstants.USERNAME_MAX_LENGTH)
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
throw new UserPasswordNotMatchException();
}
// 查询用户信息
User user = userService.selectUserByLoginName(username);
if (user == null && maybeMobilePhoneNumber(username))
{
user = userService.selectUserByPhoneNumber(username);
}
if (user == null && maybeEmail(username))
{
user = userService.selectUserByEmail(username);
}
if (user == null)
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.not.exists")));
throw new UserNotExistsException();
}
if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.delete")));
throw new UserDeleteException();
}
if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.blocked", user.getRemark())));
throw new UserBlockedException();
}
passwordService.validate(user, password);
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
recordLoginInfo(user);
return user;
}
private boolean maybeEmail(String username)
{
if (!username.matches(UserConstants.EMAIL_PATTERN))
{
return false;
}
return true;
}
private boolean maybeMobilePhoneNumber(String username)
{
if (!username.matches(UserConstants.MOBILE_PHONE_NUMBER_PATTERN))
{
return false;
}
return true;
}
/**
* 记录登录信息
*/
public void recordLoginInfo(User user)
{
user.setLoginIp(ShiroUtils.getIp());
user.setLoginDate(DateUtils.getNowDate());
userService.updateUserInfo(user);
}
}

View File

@ -0,0 +1,90 @@
package com.luckyframe.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.luckyframe.common.constant.Constants;
import com.luckyframe.common.exception.user.UserPasswordNotMatchException;
import com.luckyframe.common.exception.user.UserPasswordRetryLimitExceedException;
import com.luckyframe.common.utils.MessageUtils;
import com.luckyframe.framework.manager.AsyncManager;
import com.luckyframe.framework.manager.factory.AsyncFactory;
import com.luckyframe.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())
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginName, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.exceed", maxRetryCount)));
throw new UserPasswordRetryLimitExceedException(Integer.valueOf(maxRetryCount).intValue());
}
if (!matches(user, password))
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginName, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.count", retryCount)));
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,117 @@
package com.luckyframe.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.luckyframe.framework.manager.AsyncManager;
import com.luckyframe.framework.manager.factory.AsyncFactory;
import com.luckyframe.project.monitor.online.domain.OnlineSession;
import com.luckyframe.project.monitor.online.domain.UserOnline;
import com.luckyframe.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();
}
AsyncManager.me().execute(AsyncFactory.syncSessionToDb(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,56 @@
package com.luckyframe.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.luckyframe.common.utils.ServletUtils;
import com.luckyframe.common.utils.IpUtils;
import com.luckyframe.common.utils.StringUtils;
import com.luckyframe.project.monitor.online.domain.OnlineSession;
import com.luckyframe.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.getRequest().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.luckyframe.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.luckyframe.common.constant.Constants;
import com.luckyframe.common.utils.MessageUtils;
import com.luckyframe.common.utils.StringUtils;
import com.luckyframe.common.utils.security.ShiroUtils;
import com.luckyframe.framework.manager.AsyncManager;
import com.luckyframe.framework.manager.factory.AsyncFactory;
import com.luckyframe.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 = ShiroUtils.getSysUser();
if (StringUtils.isNotNull(user))
{
String loginName = user.getLoginName();
// 记录用户退出日志
AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginName, Constants.LOGOUT, MessageUtils.message("user.logout.success")));
}
// 退出登录
subject.logout();
}
catch (SessionException ise)
{
log.error("logout fail.", ise);
}
issueRedirect(request, response, redirectUrl);
}
catch (Exception e)
{
log.error("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,77 @@
package com.luckyframe.framework.shiro.web.filter.captcha;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.web.filter.AccessControlFilter;
import com.google.code.kaptcha.Constants;
import com.luckyframe.common.constant.ShiroConstants;
import com.luckyframe.common.utils.StringUtils;
import com.luckyframe.common.utils.security.ShiroUtils;
/**
* 验证码过滤器
*
* @author ruoyi
*/
public class CaptchaValidateFilter extends AccessControlFilter
{
/**
* 是否开启验证码
*/
private boolean captchaEnabled = true;
/**
* 验证码类型
*/
private String captchaType = "math";
public void setCaptchaEnabled(boolean captchaEnabled)
{
this.captchaEnabled = captchaEnabled;
}
public void setCaptchaType(String captchaType)
{
this.captchaType = captchaType;
}
@Override
public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception
{
request.setAttribute(ShiroConstants.CURRENT_ENABLED, captchaEnabled);
request.setAttribute(ShiroConstants.CURRENT_TYPE, captchaType);
return super.onPreHandle(request, response, mappedValue);
}
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
throws Exception
{
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
// 验证码禁用 或不是表单提交 允许访问
if (captchaEnabled == false || !"post".equals(httpServletRequest.getMethod().toLowerCase()))
{
return true;
}
return validateResponse(httpServletRequest, httpServletRequest.getParameter(ShiroConstants.CURRENT_VALIDATECODE));
}
public boolean validateResponse(HttpServletRequest request, String validateCode)
{
Object obj = ShiroUtils.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);
String code = String.valueOf(obj != null ? obj : "");
if (StringUtils.isEmpty(validateCode) || !validateCode.equalsIgnoreCase(code))
{
return false;
}
return true;
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception
{
request.setAttribute(ShiroConstants.CURRENT_CAPTCHA, ShiroConstants.CAPTCHA_ERROR);
return true;
}
}

View File

@ -0,0 +1,94 @@
package com.luckyframe.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.luckyframe.common.constant.ShiroConstants;
import com.luckyframe.common.utils.security.ShiroUtils;
import com.luckyframe.framework.shiro.session.OnlineSessionDAO;
import com.luckyframe.project.monitor.online.domain.OnlineSession;
import com.luckyframe.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.getSysUser();
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 false;
}
// 跳转到登录页
@Override
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException
{
WebUtils.issueRedirect(request, response, loginUrl);
}
}

View File

@ -0,0 +1,36 @@
package com.luckyframe.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.luckyframe.common.constant.ShiroConstants;
import com.luckyframe.framework.shiro.session.OnlineSessionDAO;
import com.luckyframe.project.monitor.online.domain.OnlineSession;
/**
* 同步Session数据到Db
*
* @author ruoyi
*/
public class SyncOnlineSessionFilter extends PathMatchingFilter
{
@Autowired
private OnlineSessionDAO onlineSessionDAO;
/**
* 同步会话数据到DB 一次请求最多同步一次 防止过多处理 需要放到Shiro过滤器之前
*/
@Override
protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) 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.luckyframe.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.luckyframe.common.constant.ShiroConstants;
import com.luckyframe.common.utils.spring.SpringUtils;
import com.luckyframe.project.monitor.online.domain.OnlineSession;
import com.luckyframe.project.monitor.online.domain.UserOnline;
import com.luckyframe.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,147 @@
package com.luckyframe.framework.shiro.web.session;
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;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import com.luckyframe.common.utils.Threads;
/**
* 自定义任务调度器完成
*
* @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;
/**
* 定时器用于处理超时的挂起请求也用于连接断开时的重连
*/
@Autowired
@Qualifier("scheduledExecutorService")
private ScheduledExecutorService executorService;
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...");
}
if (this.enabled)
{
Threads.shutdownAndAwaitTermination(executorService);
}
this.enabled = false;
}
}

View File

@ -0,0 +1,160 @@
package com.luckyframe.framework.web.controller;
import java.beans.PropertyEditorSupport;
import java.util.Date;
import java.util.List;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.luckyframe.common.utils.DateUtils;
import com.luckyframe.common.utils.StringUtils;
import com.luckyframe.common.utils.security.ShiroUtils;
import com.luckyframe.framework.web.domain.AjaxResult;
import com.luckyframe.framework.web.page.PageDomain;
import com.luckyframe.framework.web.page.TableDataInfo;
import com.luckyframe.framework.web.page.TableSupport;
import com.luckyframe.project.system.user.domain.User;
/**
* web层通用数据处理
*
* @author ruoyi
*/
public class BaseController
{
/**
* 将前台传递过来的日期格式的字符串自动转化为Date类型
*/
@InitBinder
public void initBinder(WebDataBinder binder)
{
// Date 类型转换
binder.registerCustomEditor(Date.class, new PropertyEditorSupport()
{
@Override
public void setAsText(String text)
{
setValue(DateUtils.parseDate(text));
}
});
}
/**
* 设置请求分页数据
*/
protected void startPage()
{
PageDomain pageDomain = TableSupport.buildPageRequest();
Integer pageNum = pageDomain.getPageNum();
Integer pageSize = pageDomain.getPageSize();
if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize))
{
String orderBy = pageDomain.getOrderBy();
PageHelper.startPage(pageNum, pageSize, orderBy);
}
}
/**
* 响应请求分页数据
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
protected TableDataInfo getDataTable(List<?> list)
{
TableDataInfo rspData = new TableDataInfo();
rspData.setCode(0);
rspData.setRows(list);
rspData.setTotal(new PageInfo(list).getTotal());
return rspData;
}
/**
* 响应返回结果
*
* @param rows 影响行数
* @return 操作结果
*/
protected AjaxResult toAjax(int rows)
{
return rows > 0 ? success() : error();
}
/**
* 响应返回结果
*
* @param result 结果
* @return 操作结果
*/
protected AjaxResult toAjax(boolean result)
{
return result ? success() : error();
}
/**
* 返回成功
*/
public AjaxResult success()
{
return AjaxResult.success();
}
/**
* 返回失败消息
*/
public AjaxResult error()
{
return AjaxResult.error();
}
/**
* 返回成功消息
*/
public AjaxResult success(String message)
{
return AjaxResult.success(message);
}
/**
* 返回失败消息
*/
public AjaxResult error(String message)
{
return AjaxResult.error(message);
}
/**
* 返回错误码消息
*/
public AjaxResult error(int code, String message)
{
return AjaxResult.error(code, message);
}
/**
* 页面跳转
*/
public String redirect(String url)
{
return StringUtils.format("redirect:{}", url);
}
public User getSysUser()
{
return ShiroUtils.getSysUser();
}
public void setSysUser(User user)
{
ShiroUtils.setSysUser(user);
}
public Long getUserId()
{
return getSysUser().getUserId();
}
public String getLoginName()
{
return getSysUser().getLoginName();
}
}

View File

@ -0,0 +1,94 @@
package com.luckyframe.framework.web.domain;
import java.util.HashMap;
/**
* 操作消息提醒
*
* @author ruoyi
*/
public class AjaxResult extends HashMap<String, Object>
{
private static final long serialVersionUID = 1L;
/**
* 初始化一个新创建的 Message 对象
*/
public AjaxResult()
{
}
/**
* 返回错误消息
*
* @return 错误消息
*/
public static AjaxResult error()
{
return error(1, "操作失败");
}
/**
* 返回错误消息
*
* @param msg 内容
* @return 错误消息
*/
public static AjaxResult error(String msg)
{
return error(500, msg);
}
/**
* 返回错误消息
*
* @param code 错误码
* @param msg 内容
* @return 错误消息
*/
public static AjaxResult error(int code, String msg)
{
AjaxResult json = new AjaxResult();
json.put("code", code);
json.put("msg", msg);
return json;
}
/**
* 返回成功消息
*
* @param msg 内容
* @return 成功消息
*/
public static AjaxResult success(String msg)
{
AjaxResult json = new AjaxResult();
json.put("msg", msg);
json.put("code", 0);
return json;
}
/**
* 返回成功消息
*
* @return 成功消息
*/
public static AjaxResult success()
{
return AjaxResult.success("操作成功");
}
/**
* 返回成功消息
*
* @param key 键值
* @param value 内容
* @return 成功消息
*/
@Override
public AjaxResult put(String key, Object value)
{
super.put(key, value);
return this;
}
}

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