commit 7d4b2abd4340dd2ce8ac66caea615b0043a39135 Author: gjq Date: Fri Dec 3 18:27:07 2021 +0800 .... diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4ffe5c8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +# Compiled class file +*.class +target + +.classpath +.project +.settings + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.ear +*.zip +*.tar.gz +*.rar +*.iml +.idea + +# virtual machine crash logs +hs_err_pid* diff --git a/docs/database/cases.sql b/docs/database/cases.sql new file mode 100644 index 0000000..20709a4 --- /dev/null +++ b/docs/database/cases.sql @@ -0,0 +1,195 @@ + +USE `xgl_cases`; + + + +-- ---------------------------- +-- Table structure for data_dict +-- ---------------------------- +DROP TABLE IF EXISTS `data_dict`; +CREATE TABLE `data_dict` ( + `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID, 主键,自增', + `createtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updatetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `datakey` varchar(32) NOT NULL COMMENT '字典key值', + `name` varchar(64) NOT NULL COMMENT '字典名称', + `isvalid` tinyint(4) DEFAULT '1' COMMENT '是否有效(1:有效,0:无效)', + `description` varchar(255) DEFAULT NULL COMMENT '描述', + PRIMARY KEY (`id`), + UNIQUE INDEX `ukey_datakey`(`datakey`) +) ENGINE = InnoDB COMMENT='数据字典表'; + +/*Data for the table `data_dict` */ +insert into `data_dict`(`id`,`createtime`,`updatetime`,`datakey`,`name`,`isvalid`,`description`) values (1,'2020-05-27 15:54:33','2020-05-27 15:54:33','isValid','状态',1,'全局使用,不可删除'); +insert into `data_dict`(`id`,`createtime`,`updatetime`,`datakey`,`name`,`isvalid`,`description`) values (2,'2020-05-27 16:24:01','2020-05-27 16:24:01','logType','日志类型',1,'系统日志使用'); +insert into `data_dict`(`id`,`createtime`,`updatetime`,`datakey`,`name`,`isvalid`,`description`) values (3,'2020-05-27 16:25:09','2020-05-27 16:25:09','isTask','任务状态',1,'任务使用'); +insert into `data_dict`(`id`,`createtime`,`updatetime`,`datakey`,`name`,`isvalid`,`description`) values (4,'2020-05-27 16:29:08','2020-05-27 16:29:08','tag_ppqa','标签_品牌全案',1,'案例库-品牌全案目录下的标签库'); +insert into `data_dict`(`id`,`createtime`,`updatetime`,`datakey`,`name`,`isvalid`,`description`) values (5,'2020-05-27 16:29:25','2020-05-27 16:29:49','tag_ggqa','标签_公关全案',1,'案例库-公关全案目录下的标签库'); +insert into `data_dict`(`id`,`createtime`,`updatetime`,`datakey`,`name`,`isvalid`,`description`) values (6,'2020-05-27 16:30:16','2020-05-27 16:30:30','tag_design','标签_创意设计',1,'案例库-创意设计目录下的标签库'); +insert into `data_dict`(`id`,`createtime`,`updatetime`,`datakey`,`name`,`isvalid`,`description`) values (7,'2020-05-27 16:30:43','2020-05-27 16:30:55','tag_video','标签_视频动画',1,'案例库-视频动画目录下的标签库'); +insert into `data_dict`(`id`,`createtime`,`updatetime`,`datakey`,`name`,`isvalid`,`description`) values (8,'2020-05-27 16:31:05','2020-05-27 18:12:32','tag_h5','标签_技术开发',1,'案例库-技术开发目录下的标签库'); +insert into `data_dict`(`id`,`createtime`,`updatetime`,`datakey`,`name`,`isvalid`,`description`) values (9,'2020-05-27 16:32:04','2020-05-27 16:32:14','tag_ldhd','标签_落地活动',1,'案例库-落地活动目录下的标签库'); +insert into `data_dict`(`id`,`createtime`,`updatetime`,`datakey`,`name`,`isvalid`,`description`) values (10,'2020-05-27 16:32:24','2020-05-27 16:42:16','tag_others','标签_其他案例',1,'案例库-其他案例目录下的标签库'); +insert into `data_dict`(`id`,`createtime`,`updatetime`,`datakey`,`name`,`isvalid`,`description`) values (11,'2020-05-27 16:39:02','2020-05-27 16:39:19','from_ppqa','来源_品牌全案',1,'案例库-品牌全案目录下的案例来源库'); +insert into `data_dict`(`id`,`createtime`,`updatetime`,`datakey`,`name`,`isvalid`,`description`) values (12,'2020-05-27 16:39:36','2020-05-27 16:39:46','from_ggqa','来源_公关全案',1,'案例库-公关全案目录下的案例来源库'); +insert into `data_dict`(`id`,`createtime`,`updatetime`,`datakey`,`name`,`isvalid`,`description`) values (13,'2020-05-27 16:40:01','2020-05-27 16:40:12','from_design','来源_创意设计',1,'案例库-创意设计目录下的案例来源库'); +insert into `data_dict`(`id`,`createtime`,`updatetime`,`datakey`,`name`,`isvalid`,`description`) values (14,'2020-05-27 16:40:15','2020-05-27 16:40:34','from_video','来源_视频动画',1,'案例库-视频动画目录下的案例来源库'); +insert into `data_dict`(`id`,`createtime`,`updatetime`,`datakey`,`name`,`isvalid`,`description`) values (15,'2020-05-27 16:40:47','2020-05-27 18:12:00','from_h5','来源_技术开发',1,'案例库-技术开发目录下的案例来源库'); +insert into `data_dict`(`id`,`createtime`,`updatetime`,`datakey`,`name`,`isvalid`,`description`) values (16,'2020-05-27 16:41:19','2020-05-27 16:41:39','from_ldhd','来源_落地活动',1,'案例库-落地活动目录下的案例来源库'); +insert into `data_dict`(`id`,`createtime`,`updatetime`,`datakey`,`name`,`isvalid`,`description`) values (17,'2020-05-27 16:41:48','2020-05-27 16:42:18','from_others','来源_其他案例',1,'案例库-其他案例目录下的案例来源库'); + + + +-- ---------------------------- +-- Table structure for data_dict_item +-- ---------------------------- +DROP TABLE IF EXISTS `data_dict_item`; +CREATE TABLE `data_dict_item` ( + `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID, 主键,自增', + `createtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updatetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `dictid` bigint(20) NOT NULL COMMENT '字典id值(data_dict表id)', + `value` varchar(50) NOT NULL COMMENT '字典value值(组合主键)', + `name` varchar(50) NOT NULL COMMENT '字典名字', + `sort` int(10) NOT NULL DEFAULT '0' COMMENT '排序', + PRIMARY KEY (`id`), + UNIQUE INDEX `ukey`(`dictId`, `value`) +) ENGINE = InnoDB COMMENT='数据字典值集合表'; + + + + +-- ---------------------------- +-- Table structure for content +-- ---------------------------- +DROP TABLE IF EXISTS `content`; +CREATE TABLE `content` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID, 主键,自增', + `createtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updatetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `type` enum('ppqa','ggqa','design','video','h5','ldhd','others') NOT NULL COMMENT '案例类型[ppqa:品牌全案, ggqa:公关全案, design:创意设计, video:视频动画, h5:技术开发, ldhd:落地活动, others:其他案例]', + `isvalid` tinyint(4) DEFAULT '1' COMMENT '是否有效(1:有效,0:无效)', + `fromid` int(11) NULL DEFAULT NULL COMMENT '案例来源ID', + `title` varchar(100) NOT NULL COMMENT '标题', + `desct` varchar(1000) NULL DEFAULT NULL COMMENT '摘要,描述', + `viewno` int(11) NULL DEFAULT NULL COMMENT '查看数', + `praiseno` int(11) NULL DEFAULT NULL COMMENT '点赞数', + `listicon` varchar(200) NULL DEFAULT NULL COMMENT '列表icon图', + `qrcode` varchar(200) NULL DEFAULT NULL COMMENT '二维码', + `sort` int(11) NULL DEFAULT 0 COMMENT '排序值, 值越大越考前', + `url` varchar(500) DEFAULT NULL COMMENT '访问地址', + `content` mediumtext COMMENT 'HTML内容,富文本内容存储在这', + `content_text` mediumtext COMMENT '纯Text内容,用于存到ES便于搜索', + `attachment` json DEFAULT NULL COMMENT '附件', + PRIMARY KEY (`ID`), + INDEX `idx_title`(`title`), + INDEX `idx_sort`(`sort`) +) ENGINE = InnoDB COMMENT = '案例库内容表'; + + + + +-- ---------------------------- +-- Table structure for content_images +-- ---------------------------- +DROP TABLE IF EXISTS `content_images`; +CREATE TABLE `content_images` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID, 主键,自增', + `createtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `cid` bigint(20) NOT NULL COMMENT '内容表ID', + `imgurl` varchar(500) NOT NULL COMMENT '图片地址', + `sort` int(11) NOT NULL DEFAULT '0' COMMENT '排序', + `ori_name` varchar(100) DEFAULT NULL COMMENT '原始名称', + PRIMARY KEY (`id`) +) ENGINE = InnoDB COMMENT = '内容图片集表'; + + + +-- ---------------------------- +-- Table structure for content_tags +-- ---------------------------- +DROP TABLE IF EXISTS `content_tags`; +CREATE TABLE `content_tags` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID, 主键,自增', + `createtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `cid` bigint(20) NOT NULL COMMENT '内容表ID', + `tid` bigint(20) NOT NULL COMMENT '标签id(与data_dict_item.id对应)', + PRIMARY KEY (`id`), + UNIQUE INDEX `ukey_value`(`cid`, `tid`) +) ENGINE = InnoDB COMMENT = '内容标签关联表'; + + + + + +-- ---------------------------- +-- Table structure for wx_department +-- 企业微信部门表 +-- ---------------------------- +DROP TABLE IF EXISTS `wx_department`; +CREATE TABLE `wx_department` ( + `id` bigint(20) NOT NULL COMMENT '主键, 部门id', + `createtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updatetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `name` varchar(100) NOT NULL COMMENT '部门名称', + `parentid` bigint(20) NOT NULL COMMENT '父亲部门id。根部门为1', + `order` int(11) DEFAULT NULL COMMENT '在父部门中的排序值', + PRIMARY KEY (`id`), + UNIQUE KEY `ukey_deptid` (`id`) +) DEFAULT CHARSET=utf8mb4 COMMENT='企业微信部门表'; + + + +-- ---------------------------- +-- Table structure for wx_user +-- 微信成员表 +-- ---------------------------- +DROP TABLE IF EXISTS `wx_user`; +CREATE TABLE `wx_user` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID, 主键,自增', + `createtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updatetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `userid` varchar(50) NOT NULL COMMENT '成员UserID,对应管理端的帐号,企业内必须唯一', + `name` varchar(50) NOT NULL COMMENT '成员名称', + `mobile` varchar(25) DEFAULT NULL COMMENT '手机号码', + `department` varchar(100) NOT NULL COMMENT '成员所属部门id列表', + `position` varchar(100) DEFAULT NULL COMMENT '职位信息', + `gender` char(1) DEFAULT '0' COMMENT '性别。0表示未定义,1表示男性,2表示女性', + `email` varchar(100) DEFAULT NULL COMMENT '邮箱', + `weixinid` varchar(50) DEFAULT NULL COMMENT '微信号', + `isleader` varchar(25) DEFAULT NULL COMMENT '上级字段,标识是否为上级', + `avatar` varchar(255) DEFAULT NULL COMMENT '头像url。注:如果要获取小图将url最后的”/0”改成”/100”即可', + `english_name` varchar(50) DEFAULT NULL COMMENT '英文名', + `status` smallint(6) NOT NULL DEFAULT '0' COMMENT '激活状态: 1=已激活,2=已禁用,4=未激活', + PRIMARY KEY (`id`), + UNIQUE KEY `ukey_userid` (`userid`) +) DEFAULT CHARSET=utf8mb4 COMMENT='微信成员表'; + + + +-- ---------------------------- +-- Function structure for getChildDeptIds +-- 递归查询子部门ID函数 +-- ---------------------------- +DROP FUNCTION IF EXISTS getChildDeptIds; +DELIMITER $$ +CREATE FUNCTION `getChildDeptIds`(rootdeptid INT) RETURNS VARCHAR(500) COMMENT '获取子部门ID列表,包含当前id' + BEGIN + DECLARE sChildList VARCHAR(500); + DECLARE sChildTemp VARCHAR(500); + SET sChildTemp =CAST(rootdeptid AS CHAR); + WHILE sChildTemp IS NOT NULL DO + IF (sChildList IS NOT NULL) THEN + SET sChildList = CONCAT(sChildList,',',sChildTemp); + ELSE + SET sChildList = CONCAT(sChildTemp); + END IF; + SELECT GROUP_CONCAT(deptid) INTO sChildTemp FROM wx_department WHERE FIND_IN_SET(parentid,sChildTemp)>0; + END WHILE; + RETURN sChildList; +END $$ +DELIMITER ; + + + + diff --git a/docs/database/system.sql b/docs/database/system.sql new file mode 100644 index 0000000..9ac9cdb --- /dev/null +++ b/docs/database/system.sql @@ -0,0 +1,186 @@ + +CREATE DATABASE IF NOT EXISTS `xgl_cases` DEFAULT CHARACTER SET utf8mb4; + +USE `xgl_cases`; + + + + +/*Table structure for table `permission` */ +DROP TABLE IF EXISTS `permission`; +CREATE TABLE `permission` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `permission_id` varchar(20) NOT NULL COMMENT '权限id', + `name` varchar(100) NOT NULL COMMENT '权限名称', + `description` varchar(255) DEFAULT NULL COMMENT '权限描述', + `url` varchar(255) DEFAULT NULL COMMENT '权限访问路径', + `perms` varchar(255) DEFAULT NULL COMMENT '权限标识', + `parent_id` int(11) DEFAULT NULL COMMENT '父级权限id', + `type` int(1) DEFAULT NULL COMMENT '类型 0:目录 1:菜单 2:按钮', + `order_num` int(3) DEFAULT '0' COMMENT '排序', + `icon` varchar(50) DEFAULT NULL COMMENT '图标', + `status` int(1) NOT NULL COMMENT '状态:1有效;2删除', + `create_time` datetime DEFAULT NULL, + `update_time` datetime DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB; + +/*Data for the table `permission` */ +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (1,'1','工作台','工作台','/workdest','workdest',0,1,1,'fa fa-home',1,'2017-09-27 21:22:02','2018-02-27 10:53:14'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (2,'2','权限管理','权限管理','',NULL,0,0,2,'fa fa-th-list',1,'2017-07-13 15:04:42','2018-02-27 10:53:14'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (3,'201','用户管理','用户管理','/users','users',2,1,1,'fa fa-circle-o',1,'2017-07-13 15:05:47','2018-02-27 10:53:14'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (4,'20101','列表查询','用户列表查询','/user/list','user:list',3,2,0,NULL,1,'2017-07-13 15:09:24','2017-10-09 05:38:29'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (5,'20102','新增','新增用户','/user/add','user:add',3,2,0,NULL,1,'2017-07-13 15:06:50','2018-02-28 17:58:46'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (6,'20103','编辑','编辑用户','/user/edit','user:edit',3,2,0,NULL,1,'2017-07-13 15:08:03','2018-02-27 10:53:14'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (7,'20104','删除','删除用户','/user/delete','user:delete',3,2,0,NULL,1,'2017-07-13 15:08:42','2018-02-27 10:53:14'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (8,'20105','批量删除','批量删除用户','/user/batch/delete','user:batchDelete',3,2,0,'',1,'2018-07-11 01:53:09','2018-07-11 01:53:09'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (9,'20106','分配角色','分配角色','/user/assign/role','user:assignRole',3,2,0,NULL,1,'2017-07-13 15:09:24','2017-10-09 05:38:29'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (10,'202','角色管理','角色管理','/roles','roles',2,1,2,'fa fa-circle-o',1,'2017-07-17 14:39:09','2018-02-27 10:53:14'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (11,'20201','列表查询','角色列表查询','/role/list','role:list',10,2,0,NULL,1,'2017-10-10 15:31:36','2018-02-27 10:53:14'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (12,'20202','新增','新增角色','/role/add','role:add',10,2,0,NULL,1,'2017-07-17 14:39:46','2018-02-27 10:53:14'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (13,'20203','编辑','编辑角色','/role/edit','role:edit',10,2,0,NULL,1,'2017-07-17 14:40:15','2018-02-27 10:53:14'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (14,'20204','删除','删除角色','/role/delete','role:delete',10,2,0,NULL,1,'2017-07-17 14:40:57','2018-02-27 10:53:14'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (15,'20205','批量删除','批量删除角色','/role/batch/delete','role:batchDelete',10,2,0,'',1,'2018-07-10 22:20:43','2018-07-10 22:20:43'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (16,'20206','分配权限','分配权限','/role/assign/permission','role:assignPerms',10,2,0,NULL,1,'2017-09-26 07:33:05','2018-02-27 10:53:14'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (17,'203','资源管理','资源管理','/permissions','permissions',2,1,3,'fa fa-circle-o',1,'2017-09-26 07:33:51','2018-02-27 10:53:14'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (18,'20301','列表查询','资源列表','/permission/list','permission:list',17,2,0,NULL,1,'2018-07-12 16:25:28','2018-07-12 16:25:33'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (19,'20302','新增','新增资源','/permission/add','permission:add',17,2,0,NULL,1,'2017-09-26 08:06:58','2018-02-27 10:53:14'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (20,'20303','编辑','编辑资源','/permission/edit','permission:edit',17,2,0,NULL,1,'2017-09-27 21:29:04','2018-02-27 10:53:14'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (21,'20304','删除','删除资源','/permission/delete','permission:delete',17,2,0,NULL,1,'2017-09-27 21:29:50','2018-02-27 10:53:14'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (22,'3','运维管理','运维管理','',NULL,0,0,3,'fa fa-th-list',1,'2018-07-06 15:19:26','2018-07-06 15:19:26'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (23,'301','数据监控','数据监控','/database/monitoring','database',22,1,1,'fa fa-circle-o',1,'2018-07-06 15:19:55','2018-09-12 13:14:48'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (24,'4','系统工具','系统工具','',NULL,0,0,4,'fa fa-th-list',1,'2018-07-06 15:20:38','2018-07-06 15:20:38'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (25,'401','图标工具','图标工具','/icons','icons',24,1,1,'fa fa-circle-o',1,'2018-07-06 15:21:00','2018-07-06 15:21:00'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (28,'5','在线用户','在线用户','/online/users','onlineUsers',2,1,4,'fa fa-circle-o',1,'2018-07-18 21:00:38','2018-07-19 12:47:42'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (29,'501','在线用户查询','在线用户查询','/online/user/list','onlineUser:list',28,2,0,NULL,1,'2018-07-18 21:01:25','2018-07-19 12:48:04'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (30,'502','踢出用户','踢出用户','/online/user/kickout','onlineUser:kickout',28,2,0,NULL,1,'2018-07-18 21:41:54','2018-07-19 12:48:25'); +insert into `permission`(`id`,`permission_id`,`name`,`description`,`url`,`perms`,`parent_id`,`type`,`order_num`,`icon`,`status`,`create_time`,`update_time`) values (31,'503','批量踢出','批量踢出','/online/user/batch/kickout','onlineUser:batchKickout',28,2,0,'',1,'2018-07-19 12:49:30','2018-07-19 12:49:30'); + + + + +/*Table structure for table `role` */ +DROP TABLE IF EXISTS `role`; +CREATE TABLE `role` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `role_id` varchar(20) NOT NULL COMMENT '角色id', + `name` varchar(50) NOT NULL COMMENT '角色名称', + `description` varchar(255) DEFAULT NULL COMMENT '角色描述', + `status` int(1) NOT NULL COMMENT '状态:1有效;2删除', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB; + +/*Data for the table `role` */ +insert into `role`(`id`,`role_id`,`name`,`description`,`status`,`create_time`,`update_time`) values (1,'1','超级管理员','超级管理员',1,'2017-06-28 20:30:05','2017-06-28 20:30:10'); +insert into `role`(`id`,`role_id`,`name`,`description`,`status`,`create_time`,`update_time`) values (2,'2','管理员','管理员',1,'2017-06-30 23:35:19','2017-10-11 09:32:33'); +insert into `role`(`id`,`role_id`,`name`,`description`,`status`,`create_time`,`update_time`) values (3,'3','普通用户','普通用户',1,'2017-06-30 23:35:44','2018-07-13 11:44:06'); + + + + +/*Table structure for table `role_permission` */ +DROP TABLE IF EXISTS `role_permission`; +CREATE TABLE `role_permission` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `role_id` varchar(20) NOT NULL COMMENT '角色id', + `permission_id` varchar(20) NOT NULL COMMENT '权限id', + PRIMARY KEY (`id`) +) ENGINE=InnoDB; + +/*Data for the table `role_permission` */ +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (1,'1','1'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (2,'1','2'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (3,'1','201'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (4,'1','20101'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (5,'1','20102'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (6,'1','20103'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (7,'1','20104'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (8,'1','20105'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (9,'1','20106'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (10,'1','202'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (11,'1','20201'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (12,'1','20202'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (13,'1','20203'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (14,'1','20204'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (15,'1','20205'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (16,'1','20206'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (17,'1','203'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (18,'1','20301'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (19,'1','20302'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (20,'1','20303'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (21,'1','20304'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (22,'1','5'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (23,'1','501'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (24,'1','502'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (25,'1','503'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (26,'1','3'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (27,'1','301'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (28,'1','4'); +insert into `role_permission`(`id`,`role_id`,`permission_id`) values (29,'1','401'); + + + + +/*Table structure for table `user` */ +DROP TABLE IF EXISTS `user`; +CREATE TABLE `user` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` varchar(20) NOT NULL COMMENT '用户id', + `username` varchar(50) NOT NULL COMMENT '用户名', + `password` varchar(50) NOT NULL, + `salt` varchar(128) DEFAULT NULL COMMENT '加密盐值', + `email` varchar(50) DEFAULT NULL COMMENT '邮箱', + `phone` varchar(50) DEFAULT NULL COMMENT '联系方式', + `sex` int(255) DEFAULT NULL COMMENT '年龄:1男2女', + `age` int(3) DEFAULT NULL COMMENT '年龄', + `status` int(1) NOT NULL COMMENT '用户状态:1有效; 2删除', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `last_login_time` datetime DEFAULT NULL COMMENT '最后登录时间', + PRIMARY KEY (`id`,`user_id`) +) ENGINE=InnoDB; + +/*Data for the table `user` */ +insert into `user`(`id`,`user_id`,`username`,`password`,`salt`,`status`,`create_time`,`update_time`) +values (1,'1','admin','64b4f7f481befa153d4be6273a5a9743','8ec2761c3ec31c4100884553abf1221b',1,'2019-12-01 12:00:00','2019-12-01 12:00:00'); + + + + +/*Table structure for table `user_role` */ +DROP TABLE IF EXISTS `user_role`; +CREATE TABLE `user_role` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` varchar(20) NOT NULL COMMENT '用户id', + `role_id` varchar(20) NOT NULL COMMENT '角色id', + PRIMARY KEY (`id`) +) ENGINE=InnoDB; + +/*Data for the table `user_role` */ +insert into `user_role`(`id`,`user_id`,`role_id`) values (1,'1','1'); + + + + + +-- ---------------------------- +-- Table structure for sys_log +-- ---------------------------- +DROP TABLE IF EXISTS `sys_log`; +CREATE TABLE `sys_log` ( + `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID, 主键,自增', + `createtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `type` int(10) NOT NULL COMMENT '日志类型(1:系统管理;2:登录日志;3:字典管理;4:案例管理)', + `operator` varchar(100) DEFAULT NULL COMMENT '操作者', + `ipaddr` varchar(150) DEFAULT NULL COMMENT 'IP地址', + `description` varchar(255) NOT NULL COMMENT '描述', + PRIMARY KEY (`id`) +) ENGINE = InnoDB COMMENT='系统日志表'; + + + + + + diff --git a/docs/document/公司案例库网站构建逻辑.docx b/docs/document/公司案例库网站构建逻辑.docx new file mode 100644 index 0000000..84c8e39 Binary files /dev/null and b/docs/document/公司案例库网站构建逻辑.docx differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..e5f1d37 --- /dev/null +++ b/pom.xml @@ -0,0 +1,289 @@ + + + 4.0.0 + com.nbclass + cases + 1.0-SNAPSHOT + war + + cases + http://maven.apache.org + + + org.springframework.boot + spring-boot-starter-parent + 2.3.0.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + 2.1.5 + 1.2.13 + 2.1.2 + 1.1.22 + 1.2.70 + 1.4 + 2.7 + 3.2.14 + 1.5.3 + 4.5.2 + 3.9.1 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-logging + + + + + + + org.springframework.boot + spring-boot-starter-log4j2 + + + org.springframework.boot + spring-boot-starter-tomcat + provided + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-aop + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + ${mybatis-spring-boot-starter.version} + + + org.springframework.boot + spring-boot-configuration-processor + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + com.alibaba + druid-spring-boot-starter + ${druid.springboot.version} + + + + + tk.mybatis + mapper-spring-boot-starter + ${mapper.starter.version} + + + + javax.persistence + persistence-api + + + + + + + com.github.pagehelper + pagehelper-spring-boot-starter + ${pagehelper-spring-boot-starter.version} + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + + + + + org.apache.shiro + shiro-spring + ${shiro-spring.version} + + + mysql + mysql-connector-java + + + com.github.theborakompanioni + thymeleaf-extras-shiro + 2.0.0 + + + + org.apache.commons + commons-lang3 + + + + com.alibaba + fastjson + ${fastjson.version} + + + + ognl + ognl + ${ognl.version} + + + + + com.aliyun + aliyun-java-sdk-core + ${aliyun-java-sdk-core.version} + + + com.aliyun.oss + aliyun-sdk-oss + ${aliyun-sdk-oss.version} + + + + + + org.springframework.boot + spring-boot-starter-data-elasticsearch + + + + + + + commons-fileupload + commons-fileupload + ${commons-fileupload.version} + + + commons-io + commons-io + ${commons-io.version} + + + com.googlecode.json-simple + json-simple + 1.1.1 + + + net.coobird + thumbnailator + 0.4.11 + + + + + org.projectlombok + lombok + provided + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.boot + spring-boot-devtools + true + true + + + + com.auth0 + java-jwt + 3.7.0 + + + + io.jsonwebtoken + jjwt + 0.9.1 + + + + + javax.servlet + jstl + + + + + org.apache.tomcat.embed + tomcat-embed-jasper + provided + + + + + + cases + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + org.mybatis.generator + mybatis-generator-maven-plugin + 1.3.7 + + ${basedir}/src/main/resources/generator/generatorConfig.xml + true + true + + + + mysql + mysql-connector-java + ${mysql.version} + + + tk.mybatis + mapper-generator + 1.1.5 + + + + + + + + diff --git a/src/main/java/com/nbclass/CasesBootApplication.java b/src/main/java/com/nbclass/CasesBootApplication.java new file mode 100644 index 0000000..620b4e3 --- /dev/null +++ b/src/main/java/com/nbclass/CasesBootApplication.java @@ -0,0 +1,28 @@ +package com.nbclass; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; + +import tk.mybatis.spring.annotation.MapperScan; + +/** + * + * @author Leon + * @datetime 2019年3月31日 下午7:21:36 + */ +@SpringBootApplication +@MapperScan(basePackages = "com.nbclass.**.mapper") +public class CasesBootApplication extends SpringBootServletInitializer { + + public static void main(String[] args) { + SpringApplication.run(CasesBootApplication.class, args); + } + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + return application.sources(CasesBootApplication.class); + } + +} diff --git a/src/main/java/com/nbclass/Interceptor/InterceptorConfig.java b/src/main/java/com/nbclass/Interceptor/InterceptorConfig.java new file mode 100644 index 0000000..9016721 --- /dev/null +++ b/src/main/java/com/nbclass/Interceptor/InterceptorConfig.java @@ -0,0 +1,39 @@ +package com.nbclass.Interceptor; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * @title: InterceptorConfig + * @Author gjt + * @Date: 2020-12-21 + * @Description: + */ +@Configuration +public class InterceptorConfig implements WebMvcConfigurer{ + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(jwtInterceptor()) + .addPathPatterns("/comment/**")// 拦截前端接口所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录 + //排除登录接口 + .excludePathPatterns("/wx/**"); + + //注册TestInterceptor拦截器 +// InterceptorRegistration registration = registry.addInterceptor(jwtInterceptor()); +// registration.addPathPatterns("/**"); //添加拦截路径 +// registration.excludePathPatterns( //添加不拦截路径 +// "/**/*.html", //html静态资源 +// "/**/*.js", //js静态资源 +// "/**/*.css", //css静态资源 +// "/**/*.woff", +// "/**/*.ttf", +// "/swagger-ui.html" +// ); + } + @Bean + public JWTInterceptor jwtInterceptor() { + return new JWTInterceptor(); + } +} diff --git a/src/main/java/com/nbclass/Interceptor/JWTInterceptor.java b/src/main/java/com/nbclass/Interceptor/JWTInterceptor.java new file mode 100644 index 0000000..57cb45f --- /dev/null +++ b/src/main/java/com/nbclass/Interceptor/JWTInterceptor.java @@ -0,0 +1,44 @@ +package com.nbclass.Interceptor; + +import com.alibaba.druid.util.StringUtils; +import com.auth0.jwt.exceptions.AlgorithmMismatchException; +import com.auth0.jwt.exceptions.SignatureVerificationException; +import com.auth0.jwt.exceptions.TokenExpiredException; +import com.nbclass.exception.ParameterException; +import com.nbclass.util.JWTUtils; +import io.jsonwebtoken.Claims; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Date; + +/** + * @author admin + */ +@Slf4j +public class JWTInterceptor implements HandlerInterceptor { + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + String token = request.getHeader("token"); + if(StringUtils.isEmpty(token)){ + throw new ParameterException("token不能为空"); + } + try { + Claims claims = JWTUtils.parseJWT(token); + //获取token的签发时间 + long issuedAt = claims.getIssuedAt().getTime(); + //获取token的过期时间 + long expiration = claims.getExpiration().getTime(); + if(expiration < issuedAt){ + throw new ParameterException("token已过期!"); + } + } catch (Exception e) { + log.error("token无效! 错误 ->", e); + throw new ParameterException("token无效!"); + } + return true; + } +} diff --git a/src/main/java/com/nbclass/activity/constant/Const.java b/src/main/java/com/nbclass/activity/constant/Const.java new file mode 100644 index 0000000..5a7dbbc --- /dev/null +++ b/src/main/java/com/nbclass/activity/constant/Const.java @@ -0,0 +1,60 @@ +package com.nbclass.activity.constant; + +import com.nbclass.util.CommonUtils; + +/** + * 项目常量 + * @author Leon + * @datetime 2019年4月11日 上午11:22:59 + */ +public class Const { + + /** + * 当前期数 + */ + public volatile static Integer period = 1; + + /** + * 测试环境appid + */ + public static final String test_appid = "2018050300000578"; + /** + * 生产环境appid + */ + public static final String product_appid = "2018081400000135"; + + /** + * 测试环境 + */ + public static final String test_client_id = "P_XGLBDHB"; + public static final String test_client_secret = "tX6Vwv72"; + public static final String test_api_host = "https://test-api.pingan.com.cn:20443"; + + /** + * 正式环境 + */ + public static final String product_client_id = "P_XGLKXSW"; + public static final String product_client_secret = " E1Fhw56u"; + public static final String product_api_host = "http://api.pingan.com.cn"; + + /** + * 活动结束时间 + */ + public static long hd_endtime = CommonUtils.getSimpleDate("2020-03-31 23:59:59").getTime(); + + /** + * 信广龙企业微信接口 + */ + public static final String QYWX_API_DOMAIN = "http://wx.szxgl.cn/qywx"; + + /** + * 支持的上传图片后缀 + */ + public static final String UPLOAD_IMAGE_SUFFIX = ".gif,.jpg,.jpeg,.png,.bmp"; + + /** + * 支持的上传视频后缀 + */ + public static final String UPLOAD_VIDEO_SUFFIX = ".mp4,.mov,.mkv,.rmvb,.rm,.avi,.flv"; + +} diff --git a/src/main/java/com/nbclass/activity/controller/ContentController.java b/src/main/java/com/nbclass/activity/controller/ContentController.java new file mode 100644 index 0000000..780c965 --- /dev/null +++ b/src/main/java/com/nbclass/activity/controller/ContentController.java @@ -0,0 +1,492 @@ +package com.nbclass.activity.controller; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import javax.annotation.Resource; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; + +import com.nbclass.activity.model.*; +import com.nbclass.activity.service.DataDictService; +import com.nbclass.exception.ParameterException; +import com.nbclass.system.service.UserService; +import com.nbclass.util.JWTUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.nbclass.activity.model.enums.ContentType; +import com.nbclass.activity.service.ContentService; +import com.nbclass.system.controller.BaseController; +import com.nbclass.system.model.SysLog; +import com.nbclass.system.model.User; +import com.nbclass.system.model.enums.SysLogType; +import com.nbclass.system.service.SysLogService; +import com.nbclass.util.CommonUtils; +import com.nbclass.util.PageUtil; +import com.nbclass.util.ResultUtil; +import com.nbclass.vo.base.PageResultVo; +import com.nbclass.vo.base.Result; + +/** + * 案例内容 + * @author Leon + * @datetime 2020年5月28日 下午4:43:17 + */ +@Controller +@RequestMapping("/console/content") +public class ContentController extends BaseController { + + @Resource + private ContentService service; + + @Resource + private SysLogService sysLogService; + + @Resource + private UserService userService; + + @Resource + private DataDictService dataDictService; + + /** + * 案例页面 + * @param model + * @return + */ + @GetMapping("/indexPage") + public String indexPage(Model model){ + return "content/list2"; + } + + /** + * 案例页面 + * @param model + * @return + */ + @GetMapping("/index-application") + public String application(Model model){ + return "content/application"; + } + + /** + * i技术开发案例页面 + * @param model + * @return + */ + @GetMapping("/index-h5") + public String h5Page(Model model){ + model.addAttribute("caseType", ContentType.h5.key()); + return "content/list"; + } + + /** + * i创意设计案例页面 + * @param model + * @return + */ + @GetMapping("/index-design") + public String designPage(Model model){ + model.addAttribute("caseType", ContentType.design.key()); + // return "content/list"; + return "content-editor/list"; + } + + /** + * i视频动画案例页面 + * @param model + * @return + */ + @GetMapping("/index-video") + public String videoPage(Model model){ + model.addAttribute("caseType", ContentType.video.key()); + return "content/list"; + } + + /** + * i品牌全案 - 富文本编辑器形式 + * @param model + * @return + */ + @GetMapping("/index-ppqa") + public String ppqaPage(Model model){ + model.addAttribute("caseType", ContentType.ppqa.key()); + return "content-editor/list"; + } + + /** + * i公关全案 - 富文本编辑器形式 + * @param model + * @return + */ + @GetMapping("/index-ggqa") + public String ggqaPage(Model model){ + model.addAttribute("caseType", ContentType.ggqa.key()); + return "content-editor/list"; + } + + /** + * i落地活动 - 富文本编辑器形式 + * @param model + * @return + */ + @GetMapping("/index-ldhd") + public String ldhdPage(Model model){ + model.addAttribute("caseType", ContentType.ldhd.key()); + return "content-editor/list"; + } + + /** + * i其他案例 - 富文本编辑器形式 + * @param model + * @return + */ + @GetMapping("/index-others") + public String othersPage(Model model){ + model.addAttribute("caseType", ContentType.others.key()); + return "content-editor/list"; + } + + /** + * i编辑页面 + * @param model + * @param id + * @return + */ + @GetMapping("/edit") + public String editPage(Model model, String caseType, Long id){ + Content entity = new Content(); + if(id!=null && id>0)entity=service.findById(id); + JSONObject obj = (JSONObject) JSON.toJSON(entity); + model.addAllAttributes(obj); + model.addAttribute("caseType", caseType); + return "content/edit"; + } + + /** + * i编辑页面 + * @param model + * @param id + * @return + */ + @GetMapping("/edit2") + public String editPage2(Model model, String caseType, Long id,Long applicationId,Integer count){ + Content entity = new Content(); + if(id!=null && id>0)entity=service.findById(id); + if(count!=null) entity.setCount(count); + if(applicationId!=null) entity.setApplicationId(applicationId); + JSONObject obj = (JSONObject) JSON.toJSON(entity); + model.addAllAttributes(obj); + model.addAttribute("caseType", caseType); + return "content/edit2"; + } + + /** + * i富文本编辑器的编辑页面 + * @param model + * @param caseType + * @param id + * @return + */ + @GetMapping("/edit-editor") + public String editEditorPage(Model model, String caseType, Long id){ + Content entity = new Content(); + if(id!=null && id>0)entity=service.findById(id); + JSONObject obj = (JSONObject) JSON.toJSON(entity); + model.addAllAttributes(obj); + model.addAttribute("caseType", caseType); + return "content-editor/edit"; + } + + /** + * i查询数据列表 + * @param entity + * @param limit + * @param offset + * @return + */ + @PostMapping("/list") + @ResponseBody + public PageResultVo getList(Content entity, Integer limit, Integer offset){ + PageHelper.startPage(PageUtil.getPageNo(limit, offset),limit); + List userList = service.getList(entity); + PageInfo pages = new PageInfo<>(userList); + return ResultUtil.table(userList,pages.getTotal()); + } + + /** + * i查询数据列表 + * @param entity + * @param limit + * @param offset + * @return + */ + @PostMapping("/list2") + @ResponseBody + public PageResultVo getList2(Content entity, Integer limit, Integer offset,HttpServletRequest request){ + User loginUser = getLoginUser(); + User user = userService.selectByUsername(loginUser.getUsername()); + if(!user.getUsername().contains("admin")){ + entity.setUserId(Long.parseLong(user.getId().toString())); + } + List list = Arrays.asList(entity.getTagLists()); + String[] strings = list.stream().filter(String -> !String.isEmpty()).toArray(String[]::new); + if(strings.length == 0){ + entity.setTagLists(null); + }else { + entity.setTagLists(strings); + entity.setCount(strings.length); + } + PageHelper.startPage(PageUtil.getPageNo(limit, offset),limit); + List userList = service.getList2(entity); + PageInfo pages = new PageInfo<>(userList); + return ResultUtil.table(userList,pages.getTotal()); + } + + + /** + * i添加或修改数据 + * @param entity + */ + @PostMapping("/merge") + @ResponseBody + public Result merge(Content entity){ + if(StringUtils.isNotBlank(entity.getImages())) { + // json数据去除多余的引号,否则存数据库报错 + String imgList = entity.getImages(); + imgList = imgList.replace("\"{", "{").replace("}\"", "}").replace("\\", ""); + entity.setImages(imgList); + } + String type = ""; + if(entity.getTagLists().length != 0){ + for (String tagList : entity.getTagLists()) { + if(tagList.equals("106") || tagList.equals("107") + || tagList.equals("108") || tagList.equals("109") + || tagList.equals("110") || tagList.equals("111") + || tagList.equals("112")){ + type = ContentType.getNameByCode(tagList); + } + } + } + String desc = null; + if(entity.getId()!=null && entity.getId()>0){ + service.update(entity); + if(entity.getApplicationId()!=null){ + //更新审核申请单状态 + service.updateApplicationStatus(entity.getApplicationId()); + } + desc="修改案例,案例类型:"+ContentType.getNameByCode(type)+",案例ID:"+entity.getId()+",案例标题:"+entity.getTitle(); + }else{ + User loginUser = getLoginUser(); + User user = userService.selectByUsername(loginUser.getUsername()); + entity.setUserId(Long.parseLong(user.getId().toString())); + service.add(entity); + //标签关联案例 + String[] tagList = entity.getTagLists(); + for (String s : tagList) { + ContentTags contentTags = new ContentTags(); + contentTags.setCid(entity.getId()); + contentTags.setTid(Long.parseLong(s)); + service.addContentTags(contentTags); + } + desc="添加案例,案例类型:"+ContentType.getNameByCode(type)+",案例ID:"+entity.getId()+",案例标题:"+entity.getTitle(); + } + User user = getLoginUser(); + sysLogService.add(new SysLog(SysLogType.cases.key(), user.getUserId()+"("+user.getUsername()+")", getIpAddr(), desc)); + + return Result.success(); + } + + /**删除用户*/ + @PostMapping("/delete") + @ResponseBody + public Result delete(String ids) { + List IdList = CommonUtils.toLongList(ids); + service.delete(IdList); + //取消案例关联标签的关系 + service.deleteContentTags(IdList); + User user = getLoginUser(); + sysLogService.add(new SysLog(SysLogType.cases.key(), user.getUserId()+"("+user.getUsername()+")", getIpAddr(), "删除案例,ids:"+ids)); + return Result.success(); + } + + /** + * 同步MySQL数据到ES + * @param ids 如果有值,同步指定id,如果没有值,同步全部 + * @return + */ + @PostMapping("/syncEsData") + @ResponseBody + public Result syncEsData(Content entity, @RequestParam(defaultValue="false")Boolean isReBuild) { + long total = service.syncEsData(entity, isReBuild); + User user = getLoginUser(); + String type = ""; + if(entity.getTagLists().length != 0){ + for (String tagList : entity.getTagLists()) { + if(tagList.equals("106") || tagList.equals("107") + || tagList.equals("108") || tagList.equals("109") + || tagList.equals("110") || tagList.equals("111") + || tagList.equals("112")){ + type = ContentType.getNameByCode(tagList); + } + } + } + sysLogService.add(new SysLog(SysLogType.cases.key(), user.getUserId()+"("+user.getUsername()+")", getIpAddr(), + "同步案例到ElasticSearch,案例类型:"+ContentType.getNameByCode(type)+",是否重建:"+isReBuild+",受影响的记录数:"+total)); + return Result.success(total); + } + + /** + * 查询案例标题、评论数和点赞数 + * @return + */ + @GetMapping("/getCaseTitle") + @ResponseBody + public Result getCaseTitle(Integer page,Integer pageSize){ + PageInfo list = service.getCaseTitle(page,pageSize); + return Result.success(list); + } + + /** + * 获取自定义标签列表 + * @param page + * @param pageSize + * @return + */ + @GetMapping("/getOtherLabels") + @ResponseBody + public Result getOtherLabels(Integer page,Integer pageSize){ + PageHelper.startPage(page,pageSize); + List list = service.getOtherLabels(); + return Result.success(new PageInfo<>(list)); + } + + /** + * 添加案例评分 + * @param request + * @return + */ + @PostMapping("/saveScore") + @ResponseBody + public Result saveScore(HttpServletRequest request,Long contentId,Double score){ + String token = request.getHeader("token"); + String Id = JWTUtils.getUserId(token); + Long userId = Long.parseLong(Id); + //查看用户是否已经打过分 + int result = service.getScore(userId,contentId); + if(result > 0 ) throw new ParameterException("请勿重复打分!"); + service.saveScore(userId,contentId,score); + return Result.success(); + } + + /** + * 根据案例id查询案例详情 + * @param contentId + * @return + */ + @GetMapping("/getEditContent") + @ResponseBody + public Result getEditContent(Long contentId){ + Content content = service.getEditContent(contentId); + return Result.success(content); + } + + /** + * 提交审核申请单 + * @param application + * @return + */ + @PostMapping("/saveApplication") + @ResponseBody + public Result saveApplication(Application application){ + //查询案例是否已提交过审核 + int result = service.getApplicationCount(application.getContentId()); + if(result > 0 ) throw new ParameterException("请勿重复提交审核!"); + User loginUser = getLoginUser(); + User user = userService.selectByUsername(loginUser.getUsername()); + application.setUserId(Long.parseLong(user.getId().toString())); + //根据userId获取微信用户信息 + WxUser wxUser = service.getQyWxUser(user.getUsername()); + //根据部门id获取用户领导 + List checks = service.getUserLeader(wxUser.getDepartment()); + application.setChecks(checks); + //添加审核申请单 + service.saveApplication(application); + return Result.success(); + } + + /** + * 撤回审核申请单 + * @return + */ + @PostMapping("/deleteApplication") + @ResponseBody + public Result deleteApplication(Long applicationId){ + //删除案例审核申请 + service.deleteApplication(applicationId); + return Result.success(); + } + + + /** + * 获取审核列表 + * @return + */ + @PostMapping("/getContentApplication") + @ResponseBody + public PageResultVo getContentApplication(Content entity,Integer limit, Integer offset){ + User loginUser = getLoginUser(); + User user = userService.selectByUsername(loginUser.getUsername()); + entity.setUserId(Long.parseLong(user.getId().toString())); + List list = Arrays.asList(entity.getTagLists()); + String[] strings = list.stream().filter(String -> !String.isEmpty()).toArray(String[]::new); + if(strings.length == 0){ + entity.setTagLists(null); + }else { + entity.setTagLists(strings); + entity.setCount(strings.length); + } + PageHelper.startPage(limit,offset); + List list2 = service.getContentApplication(entity); + PageInfo pageInfo = new PageInfo<>(list2); + return ResultUtil.table(list2,pageInfo.getTotal()); + } + + /** + * 审核案例 + * @return + */ + @PostMapping("/updateApplication") + @ResponseBody + public Result updateApplication(Check check){ + User loginUser = getLoginUser(); + User user = userService.selectByUsername(loginUser.getUsername()); + service.updateApplication(check,Long.parseLong(user.getId().toString())); + return Result.success(); + } + + /** + * 下线案例 + * @param contentId + * @return + */ + @PostMapping("/deleteRelease") + @ResponseBody + public Result deleteRelease(Long contentId){ + service.deleteRelease(contentId); + return Result.success(); + } + +} diff --git a/src/main/java/com/nbclass/activity/controller/DataDictController.java b/src/main/java/com/nbclass/activity/controller/DataDictController.java new file mode 100644 index 0000000..ccb182c --- /dev/null +++ b/src/main/java/com/nbclass/activity/controller/DataDictController.java @@ -0,0 +1,244 @@ +package com.nbclass.activity.controller; + +import java.util.List; + +import javax.annotation.Resource; + +import com.nbclass.activity.mapper.DataDictMapper; +import com.nbclass.activity.model.ContentTags; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.nbclass.activity.model.DataDict; +import com.nbclass.activity.model.DataDictItem; +import com.nbclass.activity.service.DataDictService; +import com.nbclass.exception.ParameterException; +import com.nbclass.system.controller.BaseController; +import com.nbclass.system.model.SysLog; +import com.nbclass.system.model.User; +import com.nbclass.system.model.enums.SysLogType; +import com.nbclass.system.service.SysLogService; +import com.nbclass.util.CommonUtils; +import com.nbclass.util.PageUtil; +import com.nbclass.util.ResultUtil; +import com.nbclass.vo.base.PageResultVo; +import com.nbclass.vo.base.Result; + +/** + * 数据字典 + * @author Leon + * @datetime 2020年5月28日 下午3:27:43 + */ +@Controller +@RequestMapping("/console/datadict") +public class DataDictController extends BaseController { + + @Resource + private DataDictService service; + + @Resource + private SysLogService sysLogService; + + @Resource + private DataDictMapper dataDictMapper; + + /** + * 列表页面 + * @return + */ + @GetMapping("/index") + public String indexPage(){ + return "data_dict/list"; + } + + /** + * 编辑页面 + * @param model + * @param id + * @return + */ + @GetMapping("/edit") + public String editPage(Model model, Long id){ + DataDict entity = new DataDict(); + if(id!=null && id>0)entity=service.findById(id); + JSONObject obj = (JSONObject) JSON.toJSON(entity); + model.addAllAttributes(obj); + return "data_dict/edit"; + } + + /** + * 报名用户信息列表 + * @param entity + * @param limit + * @param offset + * @return + */ + @PostMapping("/list") + @ResponseBody + public PageResultVo getList(DataDict entity, Integer limit, Integer offset){ + PageHelper.startPage(PageUtil.getPageNo(limit, offset),limit); + List userList = service.getList(entity); + PageInfo pages = new PageInfo<>(userList); + return ResultUtil.table(userList,pages.getTotal()); + } + + /** + * 根据字典ID查询子项列表 + * @param entity + * @param limit + * @param offset + * @return + */ + @PostMapping("/getItemList") + @ResponseBody + public PageResultVo getItemList(DataDictItem entity, Integer limit, Integer offset){ + PageHelper.startPage(PageUtil.getPageNo(limit, offset),limit); + List userList = service.getItemList(entity); + PageInfo pages = new PageInfo<>(userList); + return ResultUtil.table(userList,pages.getTotal()); + } + + /** + * i添加或修改记录 + * @param entity + */ + @PostMapping("/merge") + @ResponseBody + public Result merge(DataDict entity){ + String desc = null; + if(entity.getId()!=null && entity.getId()>0){ + service.update(entity); + desc = "修改数据字典,内容为:" + JSON.toJSONString(entity); + }else{ + int result = dataDictMapper.getDataDicName(entity.getName()); + if(result > 0 ) throw new ParameterException("该字典已存在!"); + service.add(entity); + desc = "添加数据字典,内容为:" + JSON.toJSONString(entity); + } + User user = getLoginUser(); + sysLogService.add(new SysLog(SysLogType.dict.key(), user.getUserId()+"("+user.getUsername()+")", getIpAddr(), desc)); + return Result.success(); + } + + /**删除记录*/ + @PostMapping("/delete") + @ResponseBody + public Result delete(String ids) { + List IdList = CommonUtils.toLongList(ids); + service.delete(IdList); + User user = getLoginUser(); + sysLogService.add(new SysLog(SysLogType.dict.key(), user.getUserId()+"("+user.getUsername()+")", getIpAddr(), "删除数据字典,ids:"+ids)); + return Result.success(); + } + + /** + * 根据字典key获取案例标签列表 + * @param dictKey + * @return + */ + @RequestMapping("getTagSelect") + @ResponseBody + public Result getTagSelect(String dictKey){ + if(StringUtils.isBlank(dictKey)) { + throw new ParameterException("参数不能为空"); + } + try { + List obj = service.getItemsByKey(dictKey); + return Result.success(obj); + } catch (Exception e) { + logger.error("getTagSelect异常", e); + return Result.error("获取数据失败"); + } + } + + /** + * 标签下拉联想获取数据 + * @param tags + * @return + */ + @ResponseBody + @RequestMapping("/getTags") + public JSONArray getCategoryTrees(String dictKey, String tags){ +// if(StringUtils.isBlank(dictKey)) { +// throw new ParameterException("参数不能为空"); +// } + JSONArray result = new JSONArray(); + //List list = service.getItemsByKey(dictKey); + List list = service.getItemsByKey("other_labels"); + for (DataDictItem entity : list) { + JSONObject obj = new JSONObject(); + obj.put("id", entity.getId()); + obj.put("value", entity.getName()); + result.add(obj); + } + return result; + } + + + /** + * 根据字典key获取案例来源列表 + * @param dictKey + * @return + */ + @RequestMapping("getCaseFromSelect") + @ResponseBody + public Result getCaseFromSelect(String dictKey){ + if(StringUtils.isBlank(dictKey)) { + throw new ParameterException("参数不能为空"); + } + try { + List obj = service.getItemsByKey(dictKey); + return Result.success(obj); + } catch (Exception e) { + logger.error("getCaseFromSelect异常", e); + return Result.error("获取数据失败"); + } + } + + + /** + * 添加或修改字典子项 + * @param entity + * @return + */ + @PostMapping("/mergeDataDictItem") + @ResponseBody + public Result mergeDataDictItem(DataDictItem entity){ + service.mergeDataDictItem(entity); + return Result.success(); + } + + /** + * 删除字典子项 + * @param entity + * @return + */ + @PostMapping("/deleteDataDictItem") + @ResponseBody + public Result deleteDataDictItem(Long id){ + service.deleteDataDictItem(id); + return Result.success(); + } + + /** + * 获取字典值 + * @return + */ + @GetMapping("/getDropDownBox") + @ResponseBody + public Result getDropDownBox(){ + List list = service.getDropDownBox(); + return Result.success(list); + } + +} diff --git a/src/main/java/com/nbclass/activity/controller/OssUploadController.java b/src/main/java/com/nbclass/activity/controller/OssUploadController.java new file mode 100644 index 0000000..39e881b --- /dev/null +++ b/src/main/java/com/nbclass/activity/controller/OssUploadController.java @@ -0,0 +1,92 @@ +package com.nbclass.activity.controller; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Date; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import com.alibaba.fastjson.JSONObject; +import com.nbclass.activity.constant.Const; +import com.nbclass.aliyun.sdk.AliyunOSSUtils; +import com.nbclass.exception.ParameterException; +import com.nbclass.system.controller.BaseController; +import com.nbclass.util.CommonUtils; +import com.nbclass.vo.base.Result; + +import lombok.extern.slf4j.Slf4j; + +/** + * 阿里云OSS上传工具 + * @author Leon + * @datetime 2020年5月27日 下午6:51:55 + */ +@Slf4j +@RestController +@RequestMapping("/console/tool/oss") +public class OssUploadController extends BaseController{ + + /** + * i上传文件到阿里云OSS + * @param file + * @param category 文件类别【icon:案例列表icon图,attachment:案例附件,image:案例正文图集,video:视频】 + * @return + */ + @PostMapping("/uploadFile") + public Result fileUploadTest(@RequestParam(required=false, value="file")MultipartFile file, String caseType, String category){ + if(file==null || file.isEmpty()){ + throw new ParameterException("请选择文件"); + } + /*if(StringUtils.isBlank(caseType)) { + throw new ParameterException("案例类型不能为空"); + }else if(!Arrays. asList("ppqa,ggqa,design,video,h5,ldhd,others".split(",")).contains(caseType)) { + throw new ParameterException("案例类型参数有误"); + }*/ + if(StringUtils.isBlank(category)) { + throw new ParameterException("文件类别不能为空"); + } + category = category.toLowerCase().trim(); + if(!Arrays. asList("icon,attachment,image,video".split(",")).contains(category)) { + throw new ParameterException("文件类别参数有误"); + } + try { + String suffix = "", ori_name = file.getOriginalFilename(); + if(StringUtils.isNotBlank(ori_name)){ + suffix = ori_name.substring(ori_name.lastIndexOf("."), ori_name.length()); + suffix = suffix.toLowerCase(); + } + if(("icon".equals(category)||"image".equals(category)) + && !Arrays. asList(Const.UPLOAD_IMAGE_SUFFIX.split(",")).contains(suffix)) { + throw new ParameterException("请上传正确的图片"); + } + + if("video".equals(category) && !Arrays. asList(Const.UPLOAD_VIDEO_SUFFIX.split(",")).contains(suffix)) { + throw new ParameterException("请上传正确的视频"); + } + + String daydir = CommonUtils.getSimpleDate(new Date(), "yyyyMM"); + if("icon".equals(category)) { // icon图上传一年1个目录 + daydir = CommonUtils.getSimpleDate(new Date(), "yyyy"); + }else if("video".equals(category)) { // 视频也是按一年1个目录 + daydir = CommonUtils.getSimpleDate(new Date(), "yyyy"); + } + + String filename = CommonUtils.getSimpleDate(new Date(), "yyyyMMddHHmmss")+"_"+CommonUtils.getCode(5)+suffix; + // 组成的文件key eg. /casetype-h5/icons/xxx.jpg + String url = AliyunOSSUtils.uploadBytes("casetype-"+caseType+"/"+category+"s"+"/"+daydir, filename, file.getBytes()); + JSONObject fileObj = new JSONObject(); + fileObj.put("url", url); + fileObj.put("ori_name", ori_name); + return Result.success(fileObj); + } catch (IOException e) { + log.error("上传到OSS文件异常", e); + return Result.error(e.getMessage()!=null ? e.getMessage() :"上传文件失败"); + } + } + +} diff --git a/src/main/java/com/nbclass/activity/controller/SysLogController.java b/src/main/java/com/nbclass/activity/controller/SysLogController.java new file mode 100644 index 0000000..c3df803 --- /dev/null +++ b/src/main/java/com/nbclass/activity/controller/SysLogController.java @@ -0,0 +1,73 @@ +package com.nbclass.activity.controller; + +import java.util.List; + +import javax.annotation.Resource; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.nbclass.system.controller.BaseController; +import com.nbclass.system.model.SysLog; +import com.nbclass.system.service.SysLogService; +import com.nbclass.util.CommonUtils; +import com.nbclass.util.PageUtil; +import com.nbclass.util.ResultUtil; +import com.nbclass.vo.base.PageResultVo; + +/** + * i系统日志 + * @author Leon + * @datetime 2020年6月3日 下午5:28:24 + */ +@Controller +@RequestMapping("/console/syslog") +public class SysLogController extends BaseController { + + @Resource + private SysLogService service; + + /** + * i查询列表页面 + * @param model + * @return + */ + @GetMapping("/index") + public String indexPage(){ + return "syslog/list"; + } + + /** + * i查询数据列表 + * @param entity + * @param limit + * @param offset + * @return + */ + @PostMapping("/list") + @ResponseBody + public PageResultVo getList(SysLog entity, Integer limit, Integer offset){ + PageHelper.startPage(PageUtil.getPageNo(limit, offset),limit); + List userList = service.getList(entity); + PageInfo pages = new PageInfo<>(userList); + return ResultUtil.table(userList,pages.getTotal()); + } + + /** + * i删除数据 + * @param ids + */ + @PostMapping("/delete") + @ResponseBody + public void delete(String ids) { + List IdList = CommonUtils.toLongList(ids); + service.delete(IdList); + outPrint(); + } + +} diff --git a/src/main/java/com/nbclass/activity/controller/casesfirst/CaseTypeController.java b/src/main/java/com/nbclass/activity/controller/casesfirst/CaseTypeController.java new file mode 100644 index 0000000..9eec68d --- /dev/null +++ b/src/main/java/com/nbclass/activity/controller/casesfirst/CaseTypeController.java @@ -0,0 +1,82 @@ +package com.nbclass.activity.controller.casesfirst; + +import com.github.pagehelper.PageInfo; +import com.nbclass.activity.model.*; +import com.nbclass.activity.service.CaseTypeService; +import com.nbclass.vo.base.Result; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 案例web前台 + * @author gao + * @datetime 2021年10月12日 + */ +@RestController +@RequestMapping("/caseType") +public class CaseTypeController { + + @Autowired + private CaseTypeService caseTypeService; + + /** + * 数据字典(案例类型、案例用途、创意形式、节日事件)列表查询 + * @return + */ + @GetMapping("/getTypeCase") + public Result getTypeCase(Integer dictId){ + List list = caseTypeService.getTypeCase(dictId); + return Result.success(list); + } + + /** + * 字典值类型列表查询 + * @return + */ + @GetMapping("/getDictionariesType") + public Result getDictionariesType(){ + List list = caseTypeService.getDictionariesType(); + return Result.success(list); + } + + /** + * 案例库列表 + * @param page + * @param pageSize + * @return + */ + @GetMapping("/getListCase") + public Result getListCase(Integer page,Integer pageSize){ + PageInfo list = caseTypeService.getListCase(page,pageSize); + return Result.success(list); + } + + /** + * 案例搜索框 + * @param parameter 任意参数(案例标签,案例标题,案例编号) + * @param dictItemId 案例类型id + * @return + */ + @GetMapping("/getSearchCase") + public Result getSearchCase(String parameter,Integer dictItemId,Integer page,Integer pageSize){ + PageInfo list = caseTypeService.getSearchCase(parameter,dictItemId,page,pageSize); + return Result.success(list); + } + + /** + * 获取案例标签 + * @param contentId 案例id + * @return + */ + @GetMapping("/getContentTags") + public Result getContentTags(Integer contentId){ + ContentTags contentTags = caseTypeService.getContentTags(contentId); + return Result.success(contentTags); + } + + +} diff --git a/src/main/java/com/nbclass/activity/controller/casesfirst/CommentController.java b/src/main/java/com/nbclass/activity/controller/casesfirst/CommentController.java new file mode 100644 index 0000000..3e067eb --- /dev/null +++ b/src/main/java/com/nbclass/activity/controller/casesfirst/CommentController.java @@ -0,0 +1,342 @@ +package com.nbclass.activity.controller.casesfirst; + +import com.github.pagehelper.PageInfo; +import com.nbclass.activity.model.*; +import com.nbclass.activity.service.CommentService; +import com.nbclass.activity.service.ContentService; +import com.nbclass.exception.ParameterException; +import com.nbclass.util.JWTUtils; +import com.nbclass.vo.base.Result; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; +import java.util.List; + +/** + * 评论api + */ +@RestController +@RequestMapping("/comment") +public class CommentController { + + @Autowired + private CommentService commentService; + + @Autowired + private ContentService contentService; + + /** + * 案例详情和评论列表 + * @param contentId + * @return + */ + @GetMapping("/getComment") + public Result getComment(HttpServletRequest request,Long contentId){ + String token = request.getHeader("token"); + String userId = JWTUtils.getUserId(token); + Content content = commentService.getComment(contentId,Long.parseLong(userId)); + return Result.success(content); + } + + /** + * 评论回复列表 + * @param request + * @param commentId 评论id + * @return + */ + @GetMapping("/getCommentReplyList") + public Result getCommentReplyList(HttpServletRequest request,Long commentId){ + String token = request.getHeader("token"); + String userId = JWTUtils.getUserId(token); + Comment comment = commentService.getCommentReplyList(commentId,Long.parseLong(userId)); + return Result.success(comment); + } + + /** + * 添加用户发布信息 + * @param comment + * @return + */ + @PostMapping("/saveComment") + public Result saveComment(Comment comment,HttpServletRequest request){ + String token = request.getHeader("token"); + String userId = JWTUtils.getUserId(token); + comment.setUserId(Long.parseLong(userId)); + commentService.saveComment(comment); + //更新案例总评论数 + contentService.updateComments(comment.getContentId()); + return Result.success(); + } + + /** + * 添加评论点赞 + * @param commentId 评论Id + * @return + */ + @PostMapping("/updatePraiseNo") + public Result updatePraiseNo(Long commentId, HttpServletRequest request){ + String token = request.getHeader("token"); + String userId = JWTUtils.getUserId(token); + //根据评论id获取被点赞人Id + Comment comment = commentService.getCommentUserId(commentId); + System.out.println(comment); + Praise praise = new Praise(); + praise.setCommentId(commentId); + praise.setPraiseId(Long.parseLong(userId)); + praise.setUserId(comment.getUserId()); + commentService.savePraiseNo(praise); + //评论总数加1 + commentService.updatePraiseno(commentId); + return Result.success(); + } + + /** + * 取消评论点赞 + * @return + */ + @PostMapping("/deletePraise") + public Result deletePraise(Long commentId,HttpServletRequest request){ + String token = request.getHeader("token"); + String userId = JWTUtils.getUserId(token); + commentService.deletePraise(commentId,Long.parseLong(userId)); + //总点赞数减一 + commentService.updatePraiseNoONE(commentId); + return Result.success(); + } + + /** + * 添加案例点赞 + * @param contentId + * @return + */ + @PostMapping("/updateContentPraiseNo") + public Result updateContentPraiseNo(Long contentId){ + commentService.updateContentPraiseNo(contentId); + return Result.success(); + } + + + /** + * 用户回复 + * @param comment + * @param request + * @return + */ + @PostMapping("/saveUserReply") + public Result saveUserReply(Comment comment,HttpServletRequest request){ + String token = request.getHeader("token"); + String userId = JWTUtils.getUserId(token); + comment.setReplyId(Long.parseLong(userId)); + commentService.saveUserReply(comment); + //评论总回复数加一 + commentService.updateReplyNumberONE(comment.getCommentId()); + //更新案例总评论数 + contentService.updateComments(comment.getContentId()); + return Result.success(); + } + + /** + * 用户举报 + * @param report + * @return + */ + @PostMapping("/saveReport") + public Result saveReport(Report report,HttpServletRequest request){ + String token = request.getHeader("token"); + String userId = JWTUtils.getUserId(token); + report.setReportId(Long.parseLong(userId)); + commentService.saveReport(report); + return Result.success(); + } + + /** + * 举报列表获取 + * @param page + * @param pageSize + * @return + */ + @GetMapping("/getReport") + public Result getReport(Integer page,Integer pageSize,HttpServletRequest request){ + String token = request.getHeader("token"); + String userId = JWTUtils.getUserId(token); + PageInfo list = commentService.getReport(page,pageSize,userId); + return Result.success(list); + } + + + + /** + * 添加标签、索引反馈日志 + * @return + */ + @PostMapping("/saveLabelLogger") + public Result saveLabelLogger(LabelLogger labelLogger,HttpServletRequest request){ + String token = request.getHeader("token"); + String userId = JWTUtils.getUserId(token); + labelLogger.setUserId(Long.parseLong(userId)); + commentService.saveLabelLogger(labelLogger); + //案例索引标签反馈次数+1 + contentService.updateLabelFeedback(labelLogger.getContentId()); + return Result.success(); + } + + /** + * 标签、索引反馈日志列表 + * @param request + * @param page + * @param pageSize + * @return + */ + @GetMapping("/getLabelLogger") + public Result getLabelLogger(HttpServletRequest request,Integer page,Integer pageSize){ + String token = request.getHeader("token"); + String userId = JWTUtils.getUserId(token); + PageInfo list = commentService.getLabelLogger(page,pageSize,Long.parseLong(userId)); + return Result.success(list); + } + + /** + * 新建文件夹 + * @param favoritesFolder + * @param request + * @return + */ + @PostMapping("/saveFavorites") + public Result saveFavorites(FavoritesFolder favoritesFolder, HttpServletRequest request){ + String token = request.getHeader("token"); + String userId = JWTUtils.getUserId(token); + //判断文件夹是否重名 + int result = commentService.getFavoritesName(favoritesFolder.getName()); + if(result > 0){ + throw new ParameterException("文件夹已存在!"); + } + favoritesFolder.setUserId(Long.parseLong(userId)); + commentService.saveFavorites(favoritesFolder); + return Result.success(); + } + + /** + * 案例详情的文件夹列表 + * @param request + * @return + */ + @GetMapping("/getUserFolder") + public Result getUserFolder(HttpServletRequest request,Integer page,Integer pageSize,Long commentId){ + String token = request.getHeader("token"); + String userId = JWTUtils.getUserId(token); + PageInfo list = commentService.getUserFolder(Long.parseLong(userId),page,pageSize,commentId); + return Result.success(list); + } + + /** + * 收藏案例到文件夹中 + * @param contentId + * @return + */ + @PostMapping("/saveFolder") + public Result saveFolder(Long folderId,Long contentId){ + //判断该文件夹是否已被收藏 + int result = commentService.getFolderExistence(folderId,contentId); + if(result > 0 ){ + throw new ParameterException("该文件夹已被收藏!"); + } + //收藏案例到文件夹中 + commentService.saveFolder(folderId,contentId); + //添加收藏总数 + commentService.saveFolderTotal(folderId); + //更新案例的收藏总数+1 + commentService.updateCollectionNumber(contentId); + return Result.success(); + } + + /** + * 取消文件夹中的案例收藏 + * @param folderId + * @param contentId + * @return + */ + @PostMapping("/deleteFolderResources") + public Result deleteFolderResources(Long folderId,Long contentId){ + commentService.deleteFolderResources(folderId,contentId); + //更新案例的收藏总数-1 + commentService.updateCollectionNumberReduce(contentId); + return Result.success(); + } + + /** + * 获取用户文件夹列表 + * @param request + * @return + */ + @GetMapping("/getUserFolderList") + public Result getUserFolderList(HttpServletRequest request,Integer page,Integer pageSize){ + String token = request.getHeader("token"); + String userId = JWTUtils.getUserId(token); + PageInfo list = commentService.getUserFolderList(Long.parseLong(userId),page,pageSize); + return Result.success(list); + } + + /** + * 我的收藏 + * @param request + * @param page + * @param pageSize + * @return + */ + @GetMapping("/getMyCollection") + public Result getMyCollection(HttpServletRequest request,Integer page,Integer pageSize,Long folderId){ + String token = request.getHeader("token"); + String userId = JWTUtils.getUserId(token); + PageInfo list = commentService.getMyCollection(Long.parseLong(userId),page,pageSize,folderId); + return Result.success(list); + } + + /** + * 个人中心回复列表 + * @param page + * @param pageSize + * @return + */ + @GetMapping("/getReplyList") + public Result getReplyList(HttpServletRequest request,Integer page,Integer pageSize){ + String token = request.getHeader("token"); + String userId = JWTUtils.getUserId(token); + PageInfo list = commentService.getReplyList(Long.parseLong(userId),page,pageSize); + return Result.success(list); + } + + /** + * 点赞列表 + * @param request + * @param page + * @param pageSize + * @return + */ + @GetMapping("/getFabulousList") + public Result getFabulousList(HttpServletRequest request,Integer page,Integer pageSize){ + String token = request.getHeader("token"); + String userId = JWTUtils.getUserId(token); + PageInfo list = commentService.getFabulousList(Long.parseLong(userId),page,pageSize); + return Result.success(list); + } + + /** + * 案例打分 + * @param scoring + * @return + */ + @PostMapping("/saveScoring") + public Result saveScoring(HttpServletRequest request,Scoring scoring){ + String token = request.getHeader("token"); + String userId = JWTUtils.getUserId(token); + scoring.setUserId(Long.parseLong(userId)); + commentService.saveScoring(scoring); + return Result.success(); + } + + +} diff --git a/src/main/java/com/nbclass/activity/controller/casesfirst/WxController.java b/src/main/java/com/nbclass/activity/controller/casesfirst/WxController.java new file mode 100644 index 0000000..d66f0dc --- /dev/null +++ b/src/main/java/com/nbclass/activity/controller/casesfirst/WxController.java @@ -0,0 +1,218 @@ +package com.nbclass.activity.controller.casesfirst; + + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.nbclass.activity.model.WeiXiUser; +import com.nbclass.activity.service.WxService; +import com.nbclass.exception.ParameterException; + +import com.nbclass.util.HttpUtils; +import com.nbclass.util.JWTUtils; +import com.nbclass.vo.base.Result; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.servlet.http.HttpServletRequest; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + + +/** + * 微信接口 + * @author gao + * @datetime 2021年10月14日 + */ +@Controller +@RequestMapping("/wx") +public class WxController { + + /** + * wx的AppID + */ + private static final String appId = "wx013ea7738ce6991f"; + + /** + * wx的AppSecret + */ + private static final String AppSecret = "03255f509c6b53cb2b94c9bd21b8aaa8"; + + /** + * 企业微信corpid + */ + private static final String corpid = "wwc0b239a20872ff25"; + + /** + * 企业微信corpsecret(客户的secret) + */ + private static final String corpsecret = "VuJ-Sd2X-oUwFUCzzdQfDZDe0Ryb3IbvkczFu8KUP0o"; + + @Autowired + private WxService wxService; + + @RequestMapping("/loginPage") + public String loginPage(){ + return "loginPage"; + } + + @RequestMapping("/weixinLogin") + public String weixinLogin(){ + return "weixinLogin"; + } + + @RequestMapping("/demo") + public String demo(){ + return "demo"; + } + + /** + * 获取微信用户信息 + * @param request + * @return + */ + @GetMapping("/getWxUser") + @ResponseBody + public Result getWxUser(HttpServletRequest request){ + if(request.getParameter("code")==null){ + throw new ParameterException("code参数异常!"); + } + + //获取code + String code = request.getParameter("code"); + + //获取access_token + String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code"; + url = String.format(url,appId,AppSecret,code); + JSONObject jsonObject = HttpUtils.httpGet(url); + + if(jsonObject.getString("access_token")==null){ + throw new ParameterException("access_token参数异常!"); + } + + if(jsonObject.getString("openid")==null){ + throw new ParameterException("openid参数异常!"); + } + + String accessToken = jsonObject.getString("access_token"); + String openid = jsonObject.getString("openid"); + //String wxUnionId = jsonObject.getString("unionid"); + + //数据库查询是否有该openid,如果有直接从数据库获取用户信息 + int result = wxService.getOpenId(openid); + if(result == 0){ + //获取用户信息 + String url2 = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s"; + url2 = String.format(url2,accessToken,openid); + JSONObject jsonUser = HttpUtils.httpGet(url2); + WeiXiUser weiXiUser = jsonUser.toJavaObject(WeiXiUser.class); + //添加用户信息到数据库 + wxService.saveWxUser(weiXiUser); + } + //数据库获取用户信息 + WeiXiUser weiXiUser = wxService.getWxUser(openid); + WeiXiUser user = new WeiXiUser(); + user.setId(weiXiUser.getId()); + user.setOpenid(weiXiUser.getOpenid()); + + String token = ""; + + //生成token + String subject = JSON.toJSONString(user); + try { + token = JWTUtils.createJWT(UUID.randomUUID().toString(), "admin", subject, 7200 * 1000, null); + } catch (Exception e) { + e.printStackTrace(); + } + Map map = new HashMap<>(); + map.put("token",token); + map.put("nickname",weiXiUser.getNickname()); + map.put("headimgurl",weiXiUser.getHeadimgurl()); + + + //获取企业微信的access_token + /* String qyWxUrl = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s"; + qyWxUrl = String.format(qyWxUrl,corpid,corpsecret); + JSONObject qyWxJson = HttpUtils.httpGet(qyWxUrl); + if(qyWxJson.getString("access_token")==null){ + throw new ParameterException("企业微信的access_token参数异常!"); + } + String qyWxAccessToken = qyWxJson.getString("access_token"); + + //获取客户群列表 + String qyWxListUrl = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/groupchat/list?access_token=%s"; + qyWxListUrl = String.format(qyWxListUrl,qyWxAccessToken); + String limit = "{\"limit\": 1000}"; + String s1 = HttpUtil.doPostJson(qyWxListUrl, limit); + JSONObject jsonObject = JSON.parseObject(s1); + + if(jsonObject.getString("group_chat_list")==null){ + throw new ParameterException("企业微信的chatId参数异常!"); + } + + String s = jsonObject.toJSONString(); + System.out.println(s); + Map groupChats = JSONObject.parseObject(s,Map.class); + JSONArray jsonArray = JSONArray.parseArray(groupChats.get("group_chat_list").toString()); + //获取chatId + String chatId = jsonArray.getJSONObject(0).getString("chat_id"); + + //获取客户群详情 + String khUrl = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/groupchat/get?access_token=%s"; + khUrl = String.format(khUrl,qyWxAccessToken); + String chat_id = "{\"chat_id\": \""+chatId+"\"}"; + String s2 = HttpUtil.doPostJson(khUrl, chat_id); + System.out.println(s2); + String group_chat = JSON.parseObject(s2).get("group_chat").toString(); + GroupChat groupChat = JSONObject.parseObject(group_chat, GroupChat.class); + System.out.println(groupChat); + List memberLists = groupChat.getMember_list(); + List list = new ArrayList<>(); + for (MemberList memberList : memberLists) { + *//* if(wxUnionId.equals(memberList.getUnionid())){ + + }*//* + + System.out.println(memberList.getUnionid()); + }*/ + + + return Result.success(map); + } + + /** + * 查看用户基础信息 + * @return + */ + @GetMapping("/getUserBasicData") + @ResponseBody + public Result getUserBasicData(HttpServletRequest request){ + String token = request.getHeader("token"); + String userId = JWTUtils.getUserId(token); + WeiXiUser weiXiUser = wxService.getUserBasicData(Long.parseLong(userId)); + return Result.success(weiXiUser); + } + + /** + * 更新用户基础信息 + * @param weiXiUser + * @return + */ + @PostMapping("/updateBasicData") + @ResponseBody + public Result updateBasicData(WeiXiUser weiXiUser, HttpServletRequest request){ + String token = request.getHeader("token"); + String userId = JWTUtils.getUserId(token); + weiXiUser.setId(Long.parseLong(userId)); + weiXiUser.setUpdateTime(new Date()); + wxService.updateBasicData(weiXiUser); + return Result.success(); + } + + +} diff --git a/src/main/java/com/nbclass/activity/controller/frontapi/FrontContentController.java b/src/main/java/com/nbclass/activity/controller/frontapi/FrontContentController.java new file mode 100644 index 0000000..4585cd5 --- /dev/null +++ b/src/main/java/com/nbclass/activity/controller/frontapi/FrontContentController.java @@ -0,0 +1,88 @@ +package com.nbclass.activity.controller.frontapi; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.alibaba.fastjson.JSONObject; +import com.nbclass.activity.model.Content; +import com.nbclass.activity.model.enums.ContentType; +import com.nbclass.activity.service.ElasticSearchService; +import com.nbclass.exception.ParameterException; +import com.nbclass.system.controller.BaseController; +import com.nbclass.vo.base.Result; + +/** + * i前端获取案例查询 + * @author Leon + * @datetime 2020年5月21日 下午5:32:25 + */ +@RestController +@RequestMapping("/front/api/content") +public class FrontContentController extends BaseController { + +// @Resource +// private ContentService service; + + @Resource + private ElasticSearchService esService; + + /** + * 查询案例列表 + * @param page + * @param o + * @param response + * @return + */ + @RequestMapping("/list") + public Result getList(String type, HttpServletResponse response, + @RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "10") Integer pageSize, + String keyWord, String tagIds, String sourceIds){ + response.setHeader("Access-Control-Allow-Origin", "*"); + if(StringUtils.isNotBlank(type)){ + type = type.trim().toLowerCase(); + if(!ContentType.ppqa.key().equals(type) && !ContentType.ggqa.key().equals(type) && + !ContentType.design.key().equals(type) && !ContentType.video.key().equals(type) && + !ContentType.h5.key().equals(type) && !ContentType.ldhd.key().equals(type) + && !ContentType.others.key().equals(type)){ + throw new ParameterException("参数[type]不是有效的数据!"); + } + } + // List tagIdList = CommonUtils.toIntList(tagIds); + // List sourceIdList = CommonUtils.toIntList(sourceIds); + JSONObject resultObj = esService.getList(pageNum, pageSize, type, keyWord, tagIds, sourceIds); + return Result.success(resultObj); + } + + /** + * 根据id查找单条记录 + * @param id + * @param response + * @return + */ + @RequestMapping("/findById") + public Result findById(Long id, String type, HttpServletResponse response){ + response.setHeader("Access-Control-Allow-Origin", "*"); + if(StringUtils.isBlank(type)){ + throw new ParameterException("参数[type]不能为空!"); + } + type=type.trim().toLowerCase(); + if(!ContentType.ppqa.key().equals(type) && !ContentType.ggqa.key().equals(type) && + !ContentType.design.key().equals(type) && !ContentType.video.key().equals(type) && + !ContentType.h5.key().equals(type) && !ContentType.ldhd.key().equals(type) + && !ContentType.others.key().equals(type)){ + throw new ParameterException("参数[type]不是有效的数据!"); + } + if(id == null || id < 1) { + throw new ParameterException("参数[id]不能为空!"); + } + // ES里保存的ID是唯一的,所以不需要提交type字段查询 + Content content = esService.findById(id); + return Result.success(content); + } + +} diff --git a/src/main/java/com/nbclass/activity/controller/frontapi/FrontContentLikeNumController.java b/src/main/java/com/nbclass/activity/controller/frontapi/FrontContentLikeNumController.java new file mode 100644 index 0000000..69d0725 --- /dev/null +++ b/src/main/java/com/nbclass/activity/controller/frontapi/FrontContentLikeNumController.java @@ -0,0 +1,66 @@ +package com.nbclass.activity.controller.frontapi; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.nbclass.activity.service.ContentService; +import com.nbclass.exception.LogicalException; +import com.nbclass.exception.ParameterException; +import com.nbclass.exception.ServiceException; +import com.nbclass.system.controller.BaseController; +import com.nbclass.util.WebUtils; +import com.nbclass.vo.base.Result; + +/** + * i案例库阅读数点赞数功能 + * @author Leon + * @datetime 2020年5月22日 下午2:02:13 + */ +@RestController +public class FrontContentLikeNumController extends BaseController { + + @Resource + private ContentService service; + + /** + * 提交阅读数点赞数 + * @param type 提交类型[view:阅读数, like:点赞数] + * @param id 点赞记录id + * @param response + * @return + */ + @PostMapping("/front/api/content/addNum") + public Result updateContentNum(String type, Long id, HttpServletResponse response){ + response.setHeader("Access-Control-Allow-Origin", "*"); + try { + if(StringUtils.isBlank(type))throw new ParameterException("参数type不能为空"); + if(id == null || id < 1)throw new ParameterException("案例id不能为空"); + + String cookieNum = WebUtils.getValueFromCookie(getRequest(), "case_content_num_"+type+"_"+id); + if(StringUtils.isNotBlank(cookieNum)){ + if("view".equals(type)){ + return Result.success(); + }else{ + throw new ParameterException("你已经点过赞了"); + } + } + int num = service.updateContentNum(type, id);; + + WebUtils.addCookie(response, "case_content_num_"+type+"_"+id, String.valueOf(type+id), 3600 * 24 * 1); + return Result.success(num); + } catch (Exception e) { + String errmsg = "保存失败"; + if(e instanceof ParameterException || e instanceof ServiceException || e instanceof LogicalException){ + errmsg = e.getMessage(); + }else{ + logger.error("提交阅读数点赞数失败", e); + } + return Result.error(errmsg); + } + } + +} diff --git a/src/main/java/com/nbclass/activity/controller/frontapi/FrontDataDictController.java b/src/main/java/com/nbclass/activity/controller/frontapi/FrontDataDictController.java new file mode 100644 index 0000000..22008e3 --- /dev/null +++ b/src/main/java/com/nbclass/activity/controller/frontapi/FrontDataDictController.java @@ -0,0 +1,79 @@ +package com.nbclass.activity.controller.frontapi; + +import java.util.List; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.nbclass.activity.model.DataDictItem; +import com.nbclass.activity.model.enums.ContentType; +import com.nbclass.activity.service.DataDictService; +import com.nbclass.exception.ParameterException; +import com.nbclass.system.controller.BaseController; +import com.nbclass.vo.base.Result; + +/** + * i前端获取案例标签或来源列表 + * @author Leon + * @datetime 2020年5月21日 下午5:32:25 + */ +@RestController +@RequestMapping("/front/api/dict") +public class FrontDataDictController extends BaseController { + + @Resource + public DataDictService service; + + /** + * 根据类型查询案例标签列表 + * @param type + * @param response + * @return + */ + @RequestMapping("/getTags") + public Result getTags(String type, HttpServletResponse response){ + response.setHeader("Access-Control-Allow-Origin", "*"); + if(StringUtils.isBlank(type)) { + throw new ParameterException("参数type不能为空"); + } + type=type.trim().toLowerCase(); + if(!ContentType.ppqa.key().equals(type) && !ContentType.ggqa.key().equals(type) && + !ContentType.design.key().equals(type) && !ContentType.video.key().equals(type) && + !ContentType.h5.key().equals(type) && !ContentType.ldhd.key().equals(type) + && !ContentType.others.key().equals(type)){ + throw new ParameterException("参数[type]不是有效的数据!"); + } + type = "tag_"+type; + List list = service.getItemsByKey(type); + return Result.success(list); + } + + /** + * 根据类型查询案例来源列表 + * @param type + * @param response + * @return + */ + @RequestMapping("/getSources") + public Result getSources(String type, HttpServletResponse response){ + response.setHeader("Access-Control-Allow-Origin", "*"); + if(StringUtils.isBlank(type)) { + throw new ParameterException("参数type不能为空"); + } + type=type.trim().toLowerCase(); + if(!ContentType.ppqa.key().equals(type) && !ContentType.ggqa.key().equals(type) && + !ContentType.design.key().equals(type) && !ContentType.video.key().equals(type) && + !ContentType.h5.key().equals(type) && !ContentType.ldhd.key().equals(type) + && !ContentType.others.key().equals(type)){ + throw new ParameterException("参数[type]不是有效的数据!"); + } + type = "from_"+type; + List list = service.getItemsByKey(type); + return Result.success(list); + } + +} diff --git a/src/main/java/com/nbclass/activity/controller/keditor/KindEditorController.java b/src/main/java/com/nbclass/activity/controller/keditor/KindEditorController.java new file mode 100644 index 0000000..10d9eed --- /dev/null +++ b/src/main/java/com/nbclass/activity/controller/keditor/KindEditorController.java @@ -0,0 +1,332 @@ +package com.nbclass.activity.controller.keditor; + +import java.io.File; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.fileupload.FileItemFactory; +import org.apache.commons.fileupload.FileUploadException; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import net.coobird.thumbnailator.Thumbnails; + +/** + * kindeditor上传文件 - 保存的本地项目的相对目录 + * @author Leon + * @datetime 2019年4月9日 下午7:52:31 + */ +@RequestMapping("/console/kindeditor/local") +@RestController +public class KindEditorController { + + protected static Logger logger = LoggerFactory.getLogger(KindEditorController.class); + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + private static final long upload_max_size = 5242880; // 上传文件最大值,5M + + @PostMapping("/api/file-upload") + public Map fileUpload(HttpServletRequest request, + HttpServletResponse response,@RequestParam("imgFile")MultipartFile file) + throws ServletException, IOException, FileUploadException { + response.setContentType("text/html; charset=UTF-8"); + ServletContext application = request.getSession().getServletContext(); + String savePath = application.getRealPath("/") + "keditor-attached/"; + + // 文件保存目录URL + String saveUrl = request.getContextPath() + "/keditor-attached/"; + + // 定义允许上传的文件扩展名 + HashMap extMap = new HashMap(); + extMap.put("image", "gif,jpg,jpeg,png,bmp"); + extMap.put("flash", "swf,flv"); + extMap.put("media", "swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb,mp4,mov"); // 上传音视频格式 + extMap.put("file", "doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2"); + + if (!ServletFileUpload.isMultipartContent(request)) { + return getError("请选择文件。"); + } + // 检查目录 + File uploadDir = new File(savePath); + if (!uploadDir.isDirectory()) { + // return getError("上传目录不存在。"); + uploadDir.mkdirs(); + } + // 检查目录写权限 + if (!uploadDir.canWrite()) { + return getError("上传目录没有写权限。"); + } + + String dirName = request.getParameter("dir"); + if (dirName == null) { + dirName = "image"; + } + if (!extMap.containsKey(dirName)) { + return getError("目录名不正确。"); + } + // 创建文件夹 + savePath += dirName + "/"; + saveUrl += dirName + "/"; + File saveDirFile = new File(savePath); + if (!saveDirFile.exists()) { + saveDirFile.mkdirs(); + } + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); + String ymd = sdf.format(new Date()); + savePath += ymd + "/"; + saveUrl += ymd + "/"; + File dirFile = new File(savePath); + if (!dirFile.exists()) { + dirFile.mkdirs(); + } + + FileItemFactory factory = new DiskFileItemFactory(); + ServletFileUpload upload = new ServletFileUpload(factory); + upload.setHeaderEncoding("UTF-8"); + //List items = upload.parseRequest(request); + //Iterator itr = items.iterator(); + + // FileItem item = (FileItem) itr.next(); + String fileName = file.getOriginalFilename(); + + // 检查文件大小 + if (file.getSize() > upload_max_size) { + return getError("上传文件大小超过限制,请上传5M内的文件。"); + } + // 检查扩展名 + String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase(); + if (!Arrays. asList(extMap.get(dirName).split(",")).contains(fileExt)) { + return getError("上传文件扩展名是不允许的扩展名。\n只允许" + extMap.get(dirName) + "格式。"); + } + + SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss"); + String newFileName = df.format(new Date()) + "_" + new Random().nextInt(1000) + "." + fileExt; + try { + logger.info("savePath="+savePath+", newFileName="+newFileName); + // File uploadedFile = new File(savePath, newFileName); + File saveFile = new File(savePath+newFileName); + file.transferTo(saveFile); + createThumbnail(savePath, newFileName); + } catch (Exception e) { + e.printStackTrace(); + return getError("上传文件失败。"); + } + Map msg = new HashMap(); + msg.put("error", 0); + msg.put("url", saveUrl + newFileName); + return msg; + } + + private Map getError(String message) { + Map msg = new HashMap(); + msg.put("error", 1); + msg.put("message", message); + return msg; + } + + /** + * @param savePath + * @param newFileName + */ + private void createThumbnail(String savePath, String newFileName) { + try { + Thumbnails.of(savePath+newFileName) + .size(200,200) + .toFile(savePath+"thump"+newFileName); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @SuppressWarnings("unchecked") + @RequestMapping(value = "/api/file-manager") + public void fileManager(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + ServletContext application = request.getSession().getServletContext(); + ServletOutputStream out = response.getOutputStream(); + // 根目录路径,可以指定绝对路径,比如 /var/www/attached/ + String rootPath = application.getRealPath("/") + "keditor-attached/"; + // 根目录URL,可以指定绝对路径,比如 http://www.yoursite.com/attached/ + + String rootUrl = request.getContextPath() + "/keditor-attached/"; + + // 图片扩展名 + String[] fileTypes = new String[] { "gif", "jpg", "jpeg", "png", "bmp" }; + + String dirName = request.getParameter("dir"); + if (dirName != null) { + if (!Arrays. asList(new String[] { "image", "flash", "media", "file" }).contains(dirName)) { + out.println("Invalid Directory name."); + return; + } + rootPath += dirName + "/"; + rootUrl += dirName + "/"; + File saveDirFile = new File(rootPath); + if (!saveDirFile.exists()) { + saveDirFile.mkdirs(); + } + } + // 根据path参数,设置各路径和URL + String path = StringUtils.trimToEmpty(request.getParameter("path")); + String currentPath = rootPath + path; + String currentUrl = rootUrl + path; + String currentDirPath = path; + String moveupDirPath = ""; + if (StringUtils.isNotBlank(path)) { + String str = currentDirPath.substring(0, + currentDirPath.length() - 1); + moveupDirPath = str.lastIndexOf("/") >= 0 ? str.substring(0, + str.lastIndexOf("/") + 1) : ""; + } + + // 排序形式,name or size or type + String order = request.getParameter("order") != null ? request.getParameter("order").toLowerCase() : "name"; + + // 不允许使用..移动到上一级目录 + if (path.indexOf("..") >= 0) { + out.println("Access is not allowed."); + return; + } + // 最后一个字符不是/ + if (!"".equals(path) && !path.endsWith("/")) { + out.println("Parameter is not valid."); + return; + } + // 目录不存在或不是目录 + File currentPathFile = new File(currentPath); + if (!currentPathFile.isDirectory()) { + out.println("Directory does not exist."); + return; + } + // 遍历目录取的文件信息 + List> fileList = new ArrayList>(); + if (currentPathFile.listFiles() != null) { + for (File file : currentPathFile.listFiles()) { + Hashtable hash = new Hashtable(); + String fileName = file.getName(); + if (file.isDirectory()) { + hash.put("is_dir", true); + hash.put("has_file", (file.listFiles() != null)); + hash.put("filesize", 0L); + hash.put("is_photo", false); + hash.put("filetype", ""); + } else if (file.isFile()) { + String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase(); + hash.put("is_dir", false); + hash.put("has_file", false); + hash.put("filesize", file.length()); + hash.put("is_photo", Arrays. asList(fileTypes).contains(fileExt)); + hash.put("filetype", fileExt); + } + hash.put("filename", fileName); + hash.put("datetime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(file.lastModified())); + fileList.add(hash); + } + } + + if ("size".equals(order)) { + Collections.sort(fileList, new SizeComparator()); + } else if ("type".equals(order)) { + Collections.sort(fileList, new TypeComparator()); + } else { + Collections.sort(fileList, new NameComparator()); + } + Map msg = new HashMap(); + msg.put("moveup_dir_path", moveupDirPath); + msg.put("current_dir_path", currentDirPath); + msg.put("current_url", currentUrl); + msg.put("total_count", fileList.size()); + msg.put("file_list", fileList); + response.setContentType("application/json; charset=UTF-8"); + String msgStr = objectMapper.writeValueAsString(msg); + out.println(msgStr); + } + + @SuppressWarnings("rawtypes") + class NameComparator implements Comparator { + public int compare(Object a, Object b) { + Hashtable hashA = (Hashtable) a; + Hashtable hashB = (Hashtable) b; + if (((Boolean) hashA.get("is_dir")) + && !((Boolean) hashB.get("is_dir"))) { + return -1; + } else if (!((Boolean) hashA.get("is_dir")) + && ((Boolean) hashB.get("is_dir"))) { + return 1; + } else { + return ((String) hashA.get("filename")) + .compareTo((String) hashB.get("filename")); + } + } + } + + @SuppressWarnings("rawtypes") + class SizeComparator implements Comparator { + public int compare(Object a, Object b) { + Hashtable hashA = (Hashtable) a; + Hashtable hashB = (Hashtable) b; + if (((Boolean) hashA.get("is_dir")) + && !((Boolean) hashB.get("is_dir"))) { + return -1; + } else if (!((Boolean) hashA.get("is_dir")) + && ((Boolean) hashB.get("is_dir"))) { + return 1; + } else { + if (((Long) hashA.get("filesize")) > ((Long) hashB + .get("filesize"))) { + return 1; + } else if (((Long) hashA.get("filesize")) < ((Long) hashB + .get("filesize"))) { + return -1; + } else { + return 0; + } + } + } + } + + @SuppressWarnings("rawtypes") + class TypeComparator implements Comparator { + public int compare(Object a, Object b) { + Hashtable hashA = (Hashtable) a; + Hashtable hashB = (Hashtable) b; + if (((Boolean) hashA.get("is_dir")) + && !((Boolean) hashB.get("is_dir"))) { + return -1; + } else if (!((Boolean) hashA.get("is_dir")) + && ((Boolean) hashB.get("is_dir"))) { + return 1; + } else { + return ((String) hashA.get("filetype")) + .compareTo((String) hashB.get("filetype")); + } + } + } + +} diff --git a/src/main/java/com/nbclass/activity/controller/keditor/KindEditorUploadToCDNController.java b/src/main/java/com/nbclass/activity/controller/keditor/KindEditorUploadToCDNController.java new file mode 100644 index 0000000..90f3504 --- /dev/null +++ b/src/main/java/com/nbclass/activity/controller/keditor/KindEditorUploadToCDNController.java @@ -0,0 +1,337 @@ +package com.nbclass.activity.controller.keditor; + +import java.io.File; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.fileupload.FileItemFactory; +import org.apache.commons.fileupload.FileUploadException; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import net.coobird.thumbnailator.Thumbnails; + +/** + * kindeditor上传文件 - 保存到cdn + * @author Leon + * @datetime 2019年4月15日 下午4:50:49 + */ +@RequestMapping("/console/kindeditor/cdn") +@RestController +public class KindEditorUploadToCDNController { + + protected static Logger logger = LoggerFactory.getLogger(KindEditorUploadToCDNController.class); + + // CDN保存目录 + private static final String upload_dir = "/mnt/cdn/xgl-cases/keditor-attached/"; + + private static final String cdn_domain = "https://cdn.szxgl.cn/"; + + private static final long upload_max_size = 5242880; // 上传文件最大值,5M + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + @PostMapping("/api/file-upload") + public Map fileUpload(HttpServletRequest request, + HttpServletResponse response,@RequestParam("imgFile")MultipartFile file) + throws ServletException, IOException, FileUploadException { + response.setContentType("text/html; charset=UTF-8"); + // ServletContext application = request.getSession().getServletContext(); + String savePath = upload_dir; + + // 文件保存目录URL + // String saveUrl = request.getContextPath() + "/attached/"; + + // 定义允许上传的文件扩展名 + HashMap extMap = new HashMap(); + extMap.put("image", "gif,jpg,jpeg,png,bmp"); + extMap.put("flash", "swf,flv"); + extMap.put("media", "swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb,mp4,mov"); // 上传音视频格式 + extMap.put("file", "doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2"); + + if (!ServletFileUpload.isMultipartContent(request)) { + return getError("请选择文件。"); + } + // 检查目录 + File uploadDir = new File(savePath); + if (!uploadDir.isDirectory()) { + uploadDir.mkdirs(); + } + // 检查目录写权限 + if (!uploadDir.canWrite()) { + return getError("上传目录没有写权限。"); + } + + String dirName = request.getParameter("dir"); + if (dirName == null) { + dirName = "image"; + } + if (!extMap.containsKey(dirName)) { + return getError("目录名不正确。"); + } + // 创建文件夹 + savePath += dirName + "/"; + File saveDirFile = new File(savePath); + if (!saveDirFile.exists()) { + saveDirFile.mkdirs(); + } + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); + String ymd = sdf.format(new Date()); + savePath += ymd + "/"; + File dirFile = new File(savePath); + if (!dirFile.exists()) { + dirFile.mkdirs(); + } + + FileItemFactory factory = new DiskFileItemFactory(); + ServletFileUpload upload = new ServletFileUpload(factory); + upload.setHeaderEncoding("UTF-8"); + //List items = upload.parseRequest(request); + //Iterator itr = items.iterator(); + + // FileItem item = (FileItem) itr.next(); + String fileName = file.getOriginalFilename(); + + // 检查文件大小 + if (file.getSize() > upload_max_size) { + return getError("上传文件大小超过限制,请上传5M内的文件。"); + } + // 检查扩展名 + String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase(); + if (!Arrays. asList(extMap.get(dirName).split(",")).contains(fileExt)) { + return getError("上传文件扩展名是不允许的扩展名。\n只允许" + extMap.get(dirName) + "格式。"); + } + + SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss"); + String newFileName = df.format(new Date()) + "_" + new Random().nextInt(1000) + "." + fileExt; + try { + logger.info("savePath="+savePath+", newFileName="+newFileName); + // File uploadedFile = new File(savePath, newFileName); + File saveFile = new File(savePath+newFileName); + file.transferTo(saveFile); + createThumbnail(savePath, newFileName); + } catch (Exception e) { + e.printStackTrace(); + return getError("上传文件失败。"); + } + String url = savePath + newFileName; + String host = cdn_domain; + url = url.replace("/mnt/cdn/", host); + + Map msg = new HashMap(); + msg.put("error", 0); + msg.put("url", url); + return msg; + } + + private Map getError(String message) { + Map msg = new HashMap(); + msg.put("error", 1); + msg.put("message", message); + return msg; + } + + /** + * @param savePath + * @param newFileName + */ + private void createThumbnail(String savePath, String newFileName){ + try { + Thumbnails.of(savePath+newFileName) + .size(200,200) + .toFile(savePath+"thump"+newFileName); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @SuppressWarnings("unchecked") + @RequestMapping(value = "/api/file-manager") + public void fileManager(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + // ServletContext application = request.getSession().getServletContext(); + ServletOutputStream out = response.getOutputStream(); + // 根目录路径,可以指定绝对路径,比如 /var/www/attached/ + String rootPath = upload_dir; + // 根目录URL,可以指定绝对路径,比如 http://www.yoursite.com/attached/ + //String rootUrl = request.getContextPath() + "/attached/"; + + // 图片扩展名 + String[] fileTypes = new String[] { "gif", "jpg", "jpeg", "png", "bmp" }; + + String dirName = request.getParameter("dir"); + if (dirName != null) { + if (!Arrays. asList(new String[] { "image", "flash", "media", "file" }).contains(dirName)) { + out.println("Invalid Directory name."); + return; + } + rootPath += dirName + "/"; + File saveDirFile = new File(rootPath); + if (!saveDirFile.exists()) { + saveDirFile.mkdirs(); + } + } + // 根据path参数,设置各路径和URL + String path = StringUtils.trimToEmpty(request.getParameter("path")); + String currentPath = rootPath + path; + String currentDirPath = path; + String moveupDirPath = ""; + if (StringUtils.isNotBlank(path)) { + String str = currentDirPath.substring(0, currentDirPath.length() - 1); + moveupDirPath = str.lastIndexOf("/") >= 0 ? str.substring(0, str.lastIndexOf("/") + 1) : ""; + } + + // 排序形式,name or size or type + String order = request.getParameter("order") != null ? request.getParameter("order").toLowerCase() : "name"; + + // 不允许使用..移动到上一级目录 + if (path.indexOf("..") >= 0) { + out.println("Access is not allowed."); + return; + } + // 最后一个字符不是/ + if (!"".equals(path) && !path.endsWith("/")) { + out.println("Parameter is not valid."); + return; + } + // 目录不存在或不是目录 + File currentPathFile = new File(currentPath); + if (!currentPathFile.isDirectory()) { + out.println("Directory does not exist."); + return; + } + // 遍历目录取的文件信息 + List> fileList = new ArrayList>(); + if (currentPathFile.listFiles() != null) { + for (File file : currentPathFile.listFiles()) { + Hashtable hash = new Hashtable(); + String fileName = file.getName(); + if (file.isDirectory()) { + hash.put("is_dir", true); + hash.put("has_file", (file.listFiles() != null)); + hash.put("filesize", 0L); + hash.put("is_photo", false); + hash.put("filetype", ""); + } else if (file.isFile()) { + String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase(); + hash.put("is_dir", false); + hash.put("has_file", false); + hash.put("filesize", file.length()); + hash.put("is_photo", Arrays. asList(fileTypes).contains(fileExt)); + hash.put("filetype", fileExt); + } + hash.put("filename", fileName); + hash.put("datetime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(file.lastModified())); + fileList.add(hash); + } + } + + if ("size".equals(order)) { + Collections.sort(fileList, new SizeComparator()); + } else if ("type".equals(order)) { + Collections.sort(fileList, new TypeComparator()); + } else { + Collections.sort(fileList, new NameComparator()); + } + + String currentUrl = currentPath; + String host = cdn_domain; + currentUrl = currentUrl.replace("/mnt/cdn/", host); + + Map msg = new HashMap(); + msg.put("moveup_dir_path", moveupDirPath); + msg.put("current_dir_path", currentDirPath); + msg.put("current_url", currentUrl); + msg.put("total_count", fileList.size()); + msg.put("file_list", fileList); + response.setContentType("application/json; charset=UTF-8"); + String msgStr = objectMapper.writeValueAsString(msg); + out.println(msgStr); + } + + @SuppressWarnings("rawtypes") + class NameComparator implements Comparator { + public int compare(Object a, Object b) { + Hashtable hashA = (Hashtable) a; + Hashtable hashB = (Hashtable) b; + if (((Boolean) hashA.get("is_dir")) + && !((Boolean) hashB.get("is_dir"))) { + return -1; + } else if (!((Boolean) hashA.get("is_dir")) + && ((Boolean) hashB.get("is_dir"))) { + return 1; + } else { + return ((String) hashA.get("filename")) + .compareTo((String) hashB.get("filename")); + } + } + } + + @SuppressWarnings("rawtypes") + class SizeComparator implements Comparator { + public int compare(Object a, Object b) { + Hashtable hashA = (Hashtable) a; + Hashtable hashB = (Hashtable) b; + if (((Boolean) hashA.get("is_dir")) + && !((Boolean) hashB.get("is_dir"))) { + return -1; + } else if (!((Boolean) hashA.get("is_dir")) + && ((Boolean) hashB.get("is_dir"))) { + return 1; + } else { + if (((Long) hashA.get("filesize")) > ((Long) hashB + .get("filesize"))) { + return 1; + } else if (((Long) hashA.get("filesize")) < ((Long) hashB + .get("filesize"))) { + return -1; + } else { + return 0; + } + } + } + } + + @SuppressWarnings("rawtypes") + class TypeComparator implements Comparator { + public int compare(Object a, Object b) { + Hashtable hashA = (Hashtable) a; + Hashtable hashB = (Hashtable) b; + if (((Boolean) hashA.get("is_dir")) + && !((Boolean) hashB.get("is_dir"))) { + return -1; + } else if (!((Boolean) hashA.get("is_dir")) + && ((Boolean) hashB.get("is_dir"))) { + return 1; + } else { + return ((String) hashA.get("filetype")) + .compareTo((String) hashB.get("filetype")); + } + } + } + +} diff --git a/src/main/java/com/nbclass/activity/controller/keditor/KindEditorUploadToOSSController.java b/src/main/java/com/nbclass/activity/controller/keditor/KindEditorUploadToOSSController.java new file mode 100644 index 0000000..0900c34 --- /dev/null +++ b/src/main/java/com/nbclass/activity/controller/keditor/KindEditorUploadToOSSController.java @@ -0,0 +1,216 @@ +package com.nbclass.activity.controller.keditor; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; +import java.util.Random; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.fileupload.FileItemFactory; +import org.apache.commons.fileupload.FileUploadException; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import com.nbclass.aliyun.sdk.AliyunOSSUtils; +import com.nbclass.util.CommonUtils; + +import lombok.extern.slf4j.Slf4j; +import net.coobird.thumbnailator.Thumbnails; + +/** + * kindeditor上传文件 - 保存到阿里云OSS + * @author Leon + * @datetime 2020年6月8日 下午2:26:44 + */ +@Slf4j +@RequestMapping("/console/kindeditor/oss") +@RestController +public class KindEditorUploadToOSSController { + + // OSS保存目录 + private static final String upload_dir = "kindeditor-attached/"; + + private static final long upload_max_size = 5242880; // 上传文件最大值,5M + + @PostMapping("/api/file-upload") + public Map fileUpload(HttpServletRequest request, + HttpServletResponse response,@RequestParam("imgFile")MultipartFile file) + throws ServletException, IOException, FileUploadException { + response.setContentType("text/html; charset=UTF-8"); + String savePath = upload_dir; + + // 文件保存目录URL + // String saveUrl = request.getContextPath() + "/keditor-attached/"; + + // 定义允许上传的文件扩展名 + HashMap extMap = new HashMap(); + extMap.put("image", "gif,jpg,jpeg,png,bmp"); + extMap.put("flash", "swf,flv"); + extMap.put("media", "swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb,mp4,mov"); // 上传音视频格式 + extMap.put("file", "doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2"); + + if (!ServletFileUpload.isMultipartContent(request)) { + return getError("请选择文件。"); + } + // 检查目录 + File uploadDir = new File(savePath); + if (!uploadDir.isDirectory()){ + // return getError("上传目录不存在。"); + uploadDir.mkdirs(); + } + // 检查目录写权限 + if (!uploadDir.canWrite()){ + return getError("上传目录没有写权限。"); + } + + String dirName = request.getParameter("dir"); + if (StringUtils.isBlank(dirName)) { + dirName = "image"; + } + if (!extMap.containsKey(dirName)) { + return getError("目录名不正确。"); + } + // 文件夹加上类型目录 + savePath += dirName + "/"; + // 文件夹加上日期目录 + savePath += CommonUtils.getSimpleDate(new Date(), "yyyyMM"); // yyyyMMdd + + FileItemFactory factory = new DiskFileItemFactory(); + ServletFileUpload upload = new ServletFileUpload(factory); + upload.setHeaderEncoding("UTF-8"); + //List items = upload.parseRequest(request); + //Iterator itr = items.iterator(); + + // FileItem item = (FileItem) itr.next(); + String fileName = file.getOriginalFilename(); + + // 检查文件大小 + if (file.getSize() > upload_max_size) { + return getError("上传文件大小超过限制,请上传5M内的文件。"); + } + // 检查扩展名 + String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase(); + if (!Arrays. asList(extMap.get(dirName).split(",")).contains(fileExt)) { + return getError("上传文件扩展名是不允许的扩展名。\n只允许" + extMap.get(dirName) + "格式。"); + } + + String url = null; + String newFileName = CommonUtils.getSimpleDate(new Date(), "yyyyMMddHHmmss") + "_" + new Random().nextInt(1000) + "." + fileExt; + try { + // File saveFile = new File(savePath+newFileName); + // file.transferTo(saveFile); + // createThumbnail(savePath, newFileName); + + url = AliyunOSSUtils.uploadBytes(savePath, newFileName, file.getBytes()); + log.info("kindeditor上传文件到oss, url="+url); + // 阿里云OSS缩略图,在URL后面加上:?x-oss-process=image/resize,m_fill,h_200,w_200 + } catch (Exception e) { + e.printStackTrace(); + return getError("上传文件失败。"); + } + + Map msg = new HashMap(); + msg.put("error", 0); + msg.put("url", url); + return msg; + } + + private Map getError(String message) { + Map msg = new HashMap(); + msg.put("error", 1); + msg.put("message", message); + return msg; + } + + /** + * @param savePath + * @param newFileName + */ + + @SuppressWarnings("unused") + private void createThumbnail(String savePath, String newFileName) { + try { + Thumbnails.of(savePath+newFileName) + .size(200,200) + .toFile(savePath+"thump"+newFileName); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @SuppressWarnings("rawtypes") + class NameComparator implements Comparator { + public int compare(Object a, Object b) { + Hashtable hashA = (Hashtable) a; + Hashtable hashB = (Hashtable) b; + if (((Boolean) hashA.get("is_dir")) + && !((Boolean) hashB.get("is_dir"))) { + return -1; + } else if (!((Boolean) hashA.get("is_dir")) + && ((Boolean) hashB.get("is_dir"))) { + return 1; + } else { + return ((String) hashA.get("filename")) + .compareTo((String) hashB.get("filename")); + } + } + } + + @SuppressWarnings("rawtypes") + class SizeComparator implements Comparator { + public int compare(Object a, Object b) { + Hashtable hashA = (Hashtable) a; + Hashtable hashB = (Hashtable) b; + if (((Boolean) hashA.get("is_dir")) + && !((Boolean) hashB.get("is_dir"))) { + return -1; + } else if (!((Boolean) hashA.get("is_dir")) + && ((Boolean) hashB.get("is_dir"))) { + return 1; + } else { + if (((Long) hashA.get("filesize")) > ((Long) hashB + .get("filesize"))) { + return 1; + } else if (((Long) hashA.get("filesize")) < ((Long) hashB + .get("filesize"))) { + return -1; + } else { + return 0; + } + } + } + } + + @SuppressWarnings("rawtypes") + class TypeComparator implements Comparator { + public int compare(Object a, Object b) { + Hashtable hashA = (Hashtable) a; + Hashtable hashB = (Hashtable) b; + if (((Boolean) hashA.get("is_dir")) + && !((Boolean) hashB.get("is_dir"))) { + return -1; + } else if (!((Boolean) hashA.get("is_dir")) + && ((Boolean) hashB.get("is_dir"))) { + return 1; + } else { + return ((String) hashA.get("filetype")) + .compareTo((String) hashB.get("filetype")); + } + } + } + +} diff --git a/src/main/java/com/nbclass/activity/mapper/CaseTypeMapper.java b/src/main/java/com/nbclass/activity/mapper/CaseTypeMapper.java new file mode 100644 index 0000000..efd868f --- /dev/null +++ b/src/main/java/com/nbclass/activity/mapper/CaseTypeMapper.java @@ -0,0 +1,49 @@ +package com.nbclass.activity.mapper; + +import com.nbclass.activity.model.Content; +import com.nbclass.activity.model.ContentTags; +import com.nbclass.activity.model.DataDict; +import com.nbclass.activity.model.DataDictItem; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface CaseTypeMapper { + + + /** + * 查询(案例类型、案例用途、创意形式、节日事件) + * @return + */ + List getTypeCase(Integer dictId); + + /** + * 字典值类型列表查询 + * @return + */ + List getDictionariesType(); + + /** + * 案例搜索框 + * @param dictItemId 案例类型id + * @return + */ + List getSearchCase(@Param("parameter") String parameter, + @Param("dictItemId") Integer dictItemId); + + /** + * 案例库列表 + * @return + */ + List getListCase(); + + /** + * 获取案例标签 + * @param contentId 案例id + * @return + */ + ContentTags getContentTags(Integer contentId); + +} diff --git a/src/main/java/com/nbclass/activity/mapper/CommentMapper.java b/src/main/java/com/nbclass/activity/mapper/CommentMapper.java new file mode 100644 index 0000000..e3f833a --- /dev/null +++ b/src/main/java/com/nbclass/activity/mapper/CommentMapper.java @@ -0,0 +1,212 @@ +package com.nbclass.activity.mapper; + +import com.nbclass.activity.model.*; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface CommentMapper { + + /** + * 案例详情和评论列表 + * @param contentId + * @return + */ + Content getComment(@Param("contentId") Long contentId, + @Param("userId") Long userId); + + + /** + * 评论回复列表 + * @param commentId + * @param userId + * @return + */ + Comment getCommentReplyList(@Param("commentId") Long commentId, + @Param("userId") Long userId); + + /** + * 添加用户发布信息 + * @param comment + * @return + */ + void saveComment(Comment comment); + + /** + * 根据评论id获取被点赞人Id + * @param commentId + * @return + */ + Comment getCommentUserId(Long commentId); + + /** + * 添加评论点赞 + * @param praise + * @return + */ + void savePraiseNo(Praise praise); + + /** + * 添加案例点赞 + * @param contentId + * @return + */ + void updateContentPraiseNo(Long contentId); + + /** + * 评论总数加1 + * @param commentId + */ + void updatePraiseno(Long commentId); + + /** + * 用户回复 + * @param comment + */ + void saveUserReply(Comment comment); + + /** + * 用户举报 + * @param report + * @return + */ + void saveReport(Report report); + + /** + * 举报列表获取 + * @return + */ + List getReport(String userId); + + /** + * 添加标签、索引反馈日志 + * @return + */ + void saveLabelLogger(LabelLogger labelLogger); + + /** + * 新建文件夹 + * @param favoritesFolder + * @return + */ + void saveFavorites(FavoritesFolder favoritesFolder); + + /** + * 案例详情的文件夹列表 + * @return + */ + List getUserFolder(@Param("userId") Long userId, + @Param("commentId") Long commentId); + + /** + * 收藏案例到文件夹中 + * @param contentId + * @return + */ + void saveFolder(@Param("folderId") Long folderId, + @Param("contentId") Long contentId); + + /** + * 添加收藏总数 + * @param folderId + */ + void saveFolderTotal(Long folderId); + + /** + * 判断该文件夹是否已被收藏 + * @param folderId + * @param contentId + * @return + */ + int getFolderExistence(@Param("folderId") Long folderId, + @Param("contentId") Long contentId); + + /** + * 判断文件夹是否重名 + * @param name + * @return + */ + int getFavoritesName(String name); + + /** + * 取消文件夹中的案例收藏 + * @param folderId + * @param contentId + * @return + */ + void deleteFolderResources(@Param("folderId") Long folderId, + @Param("contentId") Long contentId); + + /** + * 我的收藏 + * @return + */ + List getMyCollection(@Param("userId") Long userId, + @Param("folderId") Long folderId); + + /** + * 获取用户文件夹列表 + * @return + */ + List getUserFolderList(Long userId); + + /** + * 取消评论点赞 + * @return + */ + void deletePraise(@Param("commentId") Long commentId, + @Param("userId") Long userId); + + /** + * 总点赞数减一 + * @param commentId + */ + void updatePraiseNoONE(Long commentId); + + /** + * 评论总回复数加一 + */ + void updateReplyNumberONE(Long commentId); + + /** + * 回复列表 + * @param userId + * @return + */ + List getReplyList(Long userId); + + /** + * 点赞列表 + * @param userId + * @return + */ + List getFabulousList(Long userId); + + /** + * 更新案例的收藏总数+1 + * @param contentId + */ + void updateCollectionNumber(Long contentId); + + /** + * 更新案例的收藏总数-1 + * @param contentId + */ + void updateCollectionNumberReduce(Long contentId); + + /** + * 标签、索引反馈日志列表 + * @param userId + * @return + */ + List getLabelLogger(Long userId); + + /** + * 案例打分 + * @param scoring + */ + void saveScoring(Scoring scoring); + +} diff --git a/src/main/java/com/nbclass/activity/mapper/ContentMapper.java b/src/main/java/com/nbclass/activity/mapper/ContentMapper.java new file mode 100644 index 0000000..67e110e --- /dev/null +++ b/src/main/java/com/nbclass/activity/mapper/ContentMapper.java @@ -0,0 +1,221 @@ +package com.nbclass.activity.mapper; + +import java.util.List; + +import com.nbclass.activity.model.*; +import org.apache.ibatis.annotations.Param; + +import com.nbclass.util.MyMapper; + +public interface ContentMapper extends MyMapper { + + /** + * 根据id查找记录 + * @param id + * @return + */ + public Content findById(long id); + + /** + * 根据条件查询列表 + * @param entity + * @return + */ + public List getList(Content entity); + + /** + * 根据条件查询列表 - 前端页面查询 + * @param entity + * @return + */ + public List getListByFront(Content entity); + + /** + * 根据id批量删除记录 + * @param list + */ + public void deleteByIds(List list); + + + /** + * 删除关联的标签 + * @param cid + */ + public void deleteTags(long cid); + + /** + * 批量添加标签 + * @param list + */ + public void insertContentTags(List list); + + /** + * 通过内容ID删除图片集 + * @param cid + */ + public void deleteImages(long cid); + + /** + * 批量添加图片 + * @param list + */ + public void insertContentImages(List list); + + /** + * 添加点赞数阅读数 + * @param type [view, like] + * @param id + */ + public void updateContentNum(@Param("type")String type, @Param("id")Long id); + + /** + * 查询案例标题和评论数和点赞数 + * @return + */ + List getCaseTitle(); + + /** + * 标签关联案例 + * @param contentTags + */ + void addContentTags(ContentTags contentTags); + + /** + * 获取自定义标签列表 + * @return + */ + List getOtherLabels(); + + /** + * 取消案例关联标签的关系 + * @param idList + */ + void deleteContentTags(List idList); + + /** + * 案例索引标签反馈次数+1 + * @param contentId + */ + void updateLabelFeedback(Long contentId); + + /** + * 根据条件查询列表 + * @param entity + * @return + */ + List getList2(Content entity); + + /** + * 更新案例总评论数 + * @param contentId + */ + void updateComments(Long contentId); + + /** + * 添加案例评分 + * @param userId + * @param contentId + * @param score + */ + void saveScore(@Param("userId") Long userId, + @Param("contentId") Long contentId, + @Param("score") Double score); + + /** + * 查看用户是否已经打过分 + * @param userId + * @param contentId + * @return + */ + int getScore(@Param("userId") Long userId, + @Param("contentId") Long contentId); + + /** + * 根据案例id查询案例详情 + * @param contentId + * @return + */ + Content getEditContent(Long contentId); + + /** + * 提交审核申请单 + * @param application + */ + void saveApplication(Application application); + + /** + * 添加审核人信息 + * @param check + */ + void saveCheck(Check check); + + /** + *查询案例是否已提交过审核 + * @param contentId + * @return + */ + int getApplicationCount(Long contentId); + + /** + * 删除案例审核申请 + * @param applicationId + */ + void deleteApplication(Long applicationId); + + /** + * 删除审核人信息 + * @param applicationId + */ + void deleteCheck(Long applicationId); + + /** + * 更新审核申请单状态 + * @param applicationId + */ + void updateApplicationStatus(Long applicationId); + + /** + * 更新审核人状态 + * @param applicationId + */ + void updateCheckStatus(Long applicationId); + + /** + * 获取审核列表 + * @param entity + * @return + */ + List getContentApplication(Content entity); + + /** + * 更新审核表状态 + * @param check + */ + void updateCheck(Check check); + + /** + * 更新申请单状态 + * @param application + */ + void updateApplication(Application application); + + /** + * 查询案例id + * @return + */ + Long getContentId(Long applicationId); + + /** + * 更新案例状态 + * @param contentId + */ + void updateContentRelease(Long contentId,Integer release); + + /** + * 根据案例id查询申请单信息 + * @param contentId + * @return + */ + Application getApplication(Long contentId); + +} diff --git a/src/main/java/com/nbclass/activity/mapper/DataDictItemMapper.java b/src/main/java/com/nbclass/activity/mapper/DataDictItemMapper.java new file mode 100644 index 0000000..612fda0 --- /dev/null +++ b/src/main/java/com/nbclass/activity/mapper/DataDictItemMapper.java @@ -0,0 +1,59 @@ +package com.nbclass.activity.mapper; + +import java.util.List; + +import com.nbclass.activity.model.ContentTags; +import org.apache.ibatis.annotations.Param; + +import com.nbclass.activity.model.DataDictItem; +import com.nbclass.util.MyMapper; + +/** + * + * @author Leon + * @datetime 2020年6月1日 下午9:15:33 + */ +public interface DataDictItemMapper extends MyMapper { + + /** + * 根据dictid查询字典item列表 + * @param entity + * @return + */ + public List getList(DataDictItem entity); + + /** + * 判断记录是否存在 + * @param entity + * @return + */ + public Long checkExist(DataDictItem entity); + + + /** + * 根据id检查字典是否在案例标签中有使用 + * @param id + * @return + */ + public Long checkContentTag(@Param("id")Long id); + + /** + * 根据id检查字典是否在案例来源中有使用 + * @param id + * @return + */ + public Long checkContentFrom(@Param("id")Long id); + + /** + * 获取字典值 + * @return + */ + List getDropDownBox(); + + /** + * 根据名字查询tasId + * @param name + * @return + */ + String[] getTagId(String name); +} diff --git a/src/main/java/com/nbclass/activity/mapper/DataDictMapper.java b/src/main/java/com/nbclass/activity/mapper/DataDictMapper.java new file mode 100644 index 0000000..4e9c905 --- /dev/null +++ b/src/main/java/com/nbclass/activity/mapper/DataDictMapper.java @@ -0,0 +1,75 @@ +package com.nbclass.activity.mapper; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.nbclass.activity.model.DataDict; +import com.nbclass.activity.model.DataDictItem; +import com.nbclass.util.MyMapper; + +public interface DataDictMapper extends MyMapper { + + /** + * 根据条件查询列表 + * @param entity + * @return + */ + public List getList(DataDict entity); + + /** + * 删除前验证 + * @param list + * @return + */ + public Long delCheck(List list); + + /** + * 根据id批量删除记录 + * @param list + */ + public void deleteByIds(List list); + + /** + * 通过字典Key获取子集 + * @param datakey + * @return + */ + public List getItemsByKey(@Param(value="datakey")String datakey); + + /** + * 根据字典名获取列表 + * @param datakey + * @param tagNames + * @return + */ + public List getItemsByNames(@Param(value="datakey")String datakey, @Param("tagNames")List tagNames); + + /** + * 保存字典item + * @param entity + */ + public void insertDataDictItem(DataDictItem entity); + + /** + * 根据标签名称查询标签信息 + * @param postTagList + * @return + */ + List getDataDictTemName(@Param("tagNames")ArrayList postTagList); + + /** + * 获取自定义标签id + * @return + */ + Long getDataDictID(); + + /** + * 查询字典值是否重复 + * @param name + * @return + */ + int getDataDicName(String name); + +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/activity/mapper/WXMapper.java b/src/main/java/com/nbclass/activity/mapper/WXMapper.java new file mode 100644 index 0000000..05805a5 --- /dev/null +++ b/src/main/java/com/nbclass/activity/mapper/WXMapper.java @@ -0,0 +1,67 @@ +package com.nbclass.activity.mapper; + +import com.nbclass.activity.model.Check; +import com.nbclass.activity.model.WeiXiUser; +import com.nbclass.activity.model.WxUser; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface WXMapper { + + /** + * //数据库查询是否有该openid,如果有直接从数据库获取用户信息 + * @param openid + * @return + */ + int getOpenId(String openid); + + + /** + * //添加用户信息到数据库 + * @param weiXiUser + */ + void saveWxUser(WeiXiUser weiXiUser); + + /** + * //数据库获取用户信息 + * @param openid + * @return + */ + WeiXiUser getWxUser(String openid); + + /** + * 根据用户id获取信息 + * @param userId + * @return + */ + WeiXiUser getUser(String userId); + + /** + * 更新用户基础信息 + * @param weiXiUser + * @return + */ + void updateBasicData(WeiXiUser weiXiUser); + + /** + * 查看用户基础信息 + * @return + */ + WeiXiUser getUserBasicData(Long userId); + + /** + * 根据userId获取微信用户信息 + * @param username + * @return + */ + WxUser getQyWxUser(String username); + + /** + * 根据部门id获取用户领导 + * @return + */ + List getUserLeader(String department); + +} diff --git a/src/main/java/com/nbclass/activity/mapper/WxDepartmentMapper.java b/src/main/java/com/nbclass/activity/mapper/WxDepartmentMapper.java new file mode 100644 index 0000000..10181a3 --- /dev/null +++ b/src/main/java/com/nbclass/activity/mapper/WxDepartmentMapper.java @@ -0,0 +1,27 @@ +package com.nbclass.activity.mapper; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.nbclass.activity.model.WxDepartment; +import com.nbclass.util.MyMapper; + +/** + * + * @author Leon + * @datetime 2020年6月2日 下午4:42:57 + */ +public interface WxDepartmentMapper extends MyMapper { + + + public void insertBatch(List list); + + /** + * 通过父极id获取子部门id列表,返回结果包含当前父级id + * @param parentid + * @return 返回id以逗号分隔 + */ + public String getChildDeptIds(@Param("parentid")int parentid); + +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/activity/mapper/WxUserMapper.java b/src/main/java/com/nbclass/activity/mapper/WxUserMapper.java new file mode 100644 index 0000000..749de11 --- /dev/null +++ b/src/main/java/com/nbclass/activity/mapper/WxUserMapper.java @@ -0,0 +1,53 @@ +package com.nbclass.activity.mapper; + +import java.util.List; + +import org.apache.ibatis.annotations.Param; + +import com.nbclass.activity.model.WxUser; +import com.nbclass.util.MyMapper; + +/** + * + * @author Leon + * @datetime 2020年6月2日 下午4:42:57 + */ +public interface WxUserMapper extends MyMapper { + + // 这个没用,使用insertSelective方法。 + public void insertCustom(WxUser entity); + + /** + * 根据userid修改记录 + * @param entity + */ + public void updateByUserId(WxUser entity); + + /** + * 获取成员UserID列表 + * @return + */ + public List getUserIds(); + + /** + * 通过部门ID列表获取用户信息列表 + * @param deptids + * @return + */ + public List getUsersByDeptIds(@Param("deptids")String[] deptids); + + /** + * 通过用户ID列表获取用户信息列表 + * @param userids + * @return + */ + public List getUsersByUserIds(@Param("userids")String[] userids); + + + /** + * 删除此userids之外的用户 + * @param userIds + */ + public void delOtherUsers(@Param("userids")List userids); + +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/activity/model/Application.java b/src/main/java/com/nbclass/activity/model/Application.java new file mode 100644 index 0000000..b092d65 --- /dev/null +++ b/src/main/java/com/nbclass/activity/model/Application.java @@ -0,0 +1,54 @@ +package com.nbclass.activity.model; + +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +@Data +public class Application implements Serializable { + + private static final long serialVersionUID = 22459352105621985L; + + /** + * id(主键自增) + */ + private Long id; + + /** + * 案例id + */ + private Long contentId; + + /** + * 申请人id + */ + private Long userId; + + /** + * 审核类型(1、案例审核) + */ + private Integer type; + + /** + * 审核状态(1、待审核 2、通过 3、不通过) + */ + private Integer status; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 审核人 + */ + private List checks; + +} diff --git a/src/main/java/com/nbclass/activity/model/Check.java b/src/main/java/com/nbclass/activity/model/Check.java new file mode 100644 index 0000000..343fd09 --- /dev/null +++ b/src/main/java/com/nbclass/activity/model/Check.java @@ -0,0 +1,46 @@ +package com.nbclass.activity.model; + +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +@Data +public class Check implements Serializable { + + private static final long serialVersionUID = -6085309152205259190L; + + /** + * id(主键自增) + */ + private Long id; + + /** + * 申请单id + */ + private Long applicationId; + + /** + * 审核人id + */ + private Long checkId; + + /** + * 审核状态(1、待审核 2、通过 3、失败) + */ + private Integer status; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + + + +} diff --git a/src/main/java/com/nbclass/activity/model/Comment.java b/src/main/java/com/nbclass/activity/model/Comment.java new file mode 100644 index 0000000..56e5f59 --- /dev/null +++ b/src/main/java/com/nbclass/activity/model/Comment.java @@ -0,0 +1,81 @@ +package com.nbclass.activity.model; + +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +@Data +public class Comment implements Serializable { + + private static final long serialVersionUID = 1702315030539408893L; + + /** + * 评论id(主键自增) + */ + private Long id; + + /** + * 案例id + */ + private Long contentId; + + /** + * 评论人id + */ + private Long userId; + + /** + * 回复人id(回复有值,没有回复,默认值是0) + */ + private Long replyId; + + /** + * 评论id(有值代表回复,0代表主评论) + */ + private Long commentId; + + /** + * 评论内容 + */ + private String commentContent; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 点赞总数 + */ + private Integer praiseNo; + + /** + * 总回复数 + */ + private Integer replyNumber; + + /** + * 评论用户名称 + */ + private String nickname; + + /** + * 评论用户头像 + */ + private String headimgurl; + + /** + * 点赞人id(有值代表已点赞,没有值代表没有点赞) + */ + private Long praiseId; + + //回复列表 + private List respondents; + + //最新2人的点赞人列表 + private List userList; + + +} diff --git a/src/main/java/com/nbclass/activity/model/Content.java b/src/main/java/com/nbclass/activity/model/Content.java new file mode 100644 index 0000000..4d34df8 --- /dev/null +++ b/src/main/java/com/nbclass/activity/model/Content.java @@ -0,0 +1,199 @@ +package com.nbclass.activity.model; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import javax.persistence.*; + +import lombok.Data; + +@Data +@Table(name = "content") +public class Content implements Serializable { + + private static final long serialVersionUID = -6422276602170816740L; + + /** + * ID, 主键,自增 + */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + /** + * 创建时间 + */ + private Date createtime; + + /** + * 修改时间 + */ + private Date updatetime; + + /** + * 案例类型[ppqa:品牌全案, ggqa:公关全案, design:创意设计, video:视频动画, h5:技术开发, ldhd:落地活动, others:其他案例] + */ + private String type; + + + /** + * 是否有效(1:有效,0:无效) + */ + private Byte isvalid; + + /** + * 案例来源ID + */ + private Integer fromid; + // 案例来源名称 + @Transient + private String fromName; + @Transient + private String fromids; // 案例来源id,多个逗号分隔 + + /** + * 标题 + */ + private String title; + + /** + * 摘要,描述 + */ + private String desct; + + /** + * 查看数 + */ + private Integer viewno; + + /** + * 点赞数 + */ + private Integer praiseno; + + /** + * 收藏数 + */ + private Integer collectionNumber; + + /** + * 列表icon图 + */ + private String listicon; + + /** + * 二维码 + */ + private String qrcode; + + /** + * 排序值, 值越大越考前 + */ + private Integer sort; + + /** + * 访问地址 + */ + private String url; + + /** + * 内容,富文本内容存储在这 + */ + private String content; + + /** + * 纯Text内容,用于存到ES便于搜索 + */ + private String content_text; + + /** + * 附件 + */ + private String attachment; + + /** + * 创建人id + */ + private Long userId; + + /** + * 索引标签反馈次数 + */ + private Integer labelFeedback; + + /** + * 字典数据名称 + */ + private String name; + + /** + * 可见性 + */ + private Integer visibility; + + /** + *评论数 + */ + private Integer comments; + + /** + * 发布状态(1、未发布 2、已发布 4、已下线) + */ + private Integer release; + + /** + * 审核状态(1、待审核 2、已上线 3、不通过 4、已下线 5、未提交) + */ + private Integer status; + + //用户人名称 + private String userName; + + //用户人职位 + private String position; + + //申请单id + @Transient + private Long applicationId; + + //审核表案例状态 + private Long checkStatus; + + //申请单 + private Application application; + + //总评分 + private Double TotalScore; + + //评分总人数 + private Integer userTotal; + + + + // 标签 + @Transient + private String tags; + @Transient + private List tagList = new ArrayList(); + + //案例分类 + private String[] tagLists; + + //反馈次数 + private Integer quantity; + + // 图片集 + @Transient + private String images; + @Transient + private List imgList = new ArrayList(); + + //评论列表 + private List commentators; + + //查询标签个数 控制前端案例列表的查看操作 + private Integer count; + +} diff --git a/src/main/java/com/nbclass/activity/model/ContentImages.java b/src/main/java/com/nbclass/activity/model/ContentImages.java new file mode 100644 index 0000000..d86c038 --- /dev/null +++ b/src/main/java/com/nbclass/activity/model/ContentImages.java @@ -0,0 +1,47 @@ +package com.nbclass.activity.model; + +import java.util.Date; + +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import lombok.Data; + +@Data +@Table(name = "content_images") +public class ContentImages { + /** + * ID, 主键,自增 + */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + /** + * 创建时间 + */ + private Date createtime; + + /** + * 内容表ID + */ + private Long cid; + + /** + * 图片地址 + */ + private String imgurl; + + /** + * 排序 + */ + private Integer sort; + + /** + * 图片原始名称 + */ + private String ori_name; + +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/activity/model/ContentTags.java b/src/main/java/com/nbclass/activity/model/ContentTags.java new file mode 100644 index 0000000..9bc9bd0 --- /dev/null +++ b/src/main/java/com/nbclass/activity/model/ContentTags.java @@ -0,0 +1,53 @@ +package com.nbclass.activity.model; + +import java.util.Date; + +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Transient; + +import lombok.Data; + +@Data +@Table(name = "content_tags") +public class ContentTags { + /** + * ID, 主键,自增 + */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + /** + * 创建时间 + */ + private Date createtime; + + /** + * 内容表ID + */ + private Long cid; + + /** + * 标签id(与data_dict_item.id对应) + */ + private Long tid; + + /** + * 字典id + */ + private Long dictId; + + /** + * + */ + + + + // 标签名(查询字段) + @Transient + private String tagName; + +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/activity/model/DataDict.java b/src/main/java/com/nbclass/activity/model/DataDict.java new file mode 100644 index 0000000..6fa7d15 --- /dev/null +++ b/src/main/java/com/nbclass/activity/model/DataDict.java @@ -0,0 +1,52 @@ +package com.nbclass.activity.model; + +import java.util.Date; + +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import lombok.Data; + +@Data +@Table(name = "data_dict") +public class DataDict { + /** + * ID, 主键,自增 + */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + /** + * 创建时间 + */ + private Date createtime; + + /** + * 修改时间 + */ + private Date updatetime; + + /** + * 字典key值 + */ + private String datakey; + + /** + * 字典名称 + */ + private String name; + + /** + * 是否有效(1:有效,0:无效) + */ + private Byte isvalid; + + /** + * 描述 + */ + private String description; + +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/activity/model/DataDictItem.java b/src/main/java/com/nbclass/activity/model/DataDictItem.java new file mode 100644 index 0000000..6298376 --- /dev/null +++ b/src/main/java/com/nbclass/activity/model/DataDictItem.java @@ -0,0 +1,53 @@ +package com.nbclass.activity.model; + +import java.util.Date; + +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import lombok.Data; + +@Data +@Table(name = "data_dict_item") +public class DataDictItem { + /** + * ID, 主键,自增 + */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + /** + * 创建时间 + */ + private Date createtime; + + /** + * 修改时间 + */ + private Date updatetime; + + /** + * 字典id值(data_dict表id) + */ + private Long dictid; + + /** + * 字典value值(组合主键) + */ + private String value; + + /** + * 字典名字 + */ + private String name; + + /** + * 排序 + */ + private Integer sort; + + +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/activity/model/FavoritesFolder.java b/src/main/java/com/nbclass/activity/model/FavoritesFolder.java new file mode 100644 index 0000000..cffe62c --- /dev/null +++ b/src/main/java/com/nbclass/activity/model/FavoritesFolder.java @@ -0,0 +1,37 @@ +package com.nbclass.activity.model; + +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +@Data +public class FavoritesFolder implements Serializable { + + private static final long serialVersionUID = -220203874286975484L; + + private Long id; + + /** + * 文件夹名称 + */ + private String name; + + /** + *创建人id + */ + private Long userId; + + private Date createTime; + + /** + * 收藏总数 + */ + private Integer totalCollections; + + /** + * 案例Id + */ + private Long contentId; + +} diff --git a/src/main/java/com/nbclass/activity/model/GroupChat.java b/src/main/java/com/nbclass/activity/model/GroupChat.java new file mode 100644 index 0000000..464eb35 --- /dev/null +++ b/src/main/java/com/nbclass/activity/model/GroupChat.java @@ -0,0 +1,29 @@ +package com.nbclass.activity.model; + +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +@Data +public class GroupChat implements Serializable { + + private static final long serialVersionUID = -4159209038197422844L; + + private String chat_id; + + private String name; + + private String owner; + + private Date create_time; + + private String notice; + + + + private List member_list; + + +} diff --git a/src/main/java/com/nbclass/activity/model/GroupChatList.java b/src/main/java/com/nbclass/activity/model/GroupChatList.java new file mode 100644 index 0000000..eaf0028 --- /dev/null +++ b/src/main/java/com/nbclass/activity/model/GroupChatList.java @@ -0,0 +1,16 @@ +package com.nbclass.activity.model; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class GroupChatList implements Serializable { + + private static final long serialVersionUID = 279034174223992751L; + + private String chat_id; + + private Integer status; + +} diff --git a/src/main/java/com/nbclass/activity/model/LabelLogger.java b/src/main/java/com/nbclass/activity/model/LabelLogger.java new file mode 100644 index 0000000..cdaf3cf --- /dev/null +++ b/src/main/java/com/nbclass/activity/model/LabelLogger.java @@ -0,0 +1,54 @@ +package com.nbclass.activity.model; + +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +@Data +public class LabelLogger implements Serializable { + + private static final long serialVersionUID = 8533327511622545026L; + + /** + * id(主键自增) + */ + private Long id; + + /** + * 案例id + */ + private Long contentId; + + /** + * 反馈人 + */ + private Long userId; + + /** + * 日志 + */ + private String logger; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 状态(0、待解决 1、已解决) + */ + private int status; + + /** + * 反馈人名称 + */ + private String name; + + /** + * 案例名称 + */ + private String contentName; + +} + diff --git a/src/main/java/com/nbclass/activity/model/MemberList.java b/src/main/java/com/nbclass/activity/model/MemberList.java new file mode 100644 index 0000000..e7c243d --- /dev/null +++ b/src/main/java/com/nbclass/activity/model/MemberList.java @@ -0,0 +1,26 @@ +package com.nbclass.activity.model; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class MemberList implements Serializable { + + private static final long serialVersionUID = 2160707045527379917L; + + private String userid; + + private String type; + + private String unionid; + + private Long join_time; + + private Integer join_scene; + + private String group_nickname; + + private String name; + +} diff --git a/src/main/java/com/nbclass/activity/model/Praise.java b/src/main/java/com/nbclass/activity/model/Praise.java new file mode 100644 index 0000000..aba0a41 --- /dev/null +++ b/src/main/java/com/nbclass/activity/model/Praise.java @@ -0,0 +1,38 @@ +package com.nbclass.activity.model; + +import lombok.Data; + +import java.io.Serializable; + +@Data +public class Praise implements Serializable { + + private static final long serialVersionUID = -1111401809162956593L; + + /** + * 点赞id(主键自增) + */ + private Long id; + + /** + * 评论id + */ + private Long commentId; + + /** + * 点赞人id + */ + private Long praiseId; + + /** + * 被点赞人id(评论人id) + */ + private Long userId; + + /** + * 点赞时间 + */ + private String createTime; + + +} diff --git a/src/main/java/com/nbclass/activity/model/QueryCriteria.java b/src/main/java/com/nbclass/activity/model/QueryCriteria.java new file mode 100644 index 0000000..1920d00 --- /dev/null +++ b/src/main/java/com/nbclass/activity/model/QueryCriteria.java @@ -0,0 +1,95 @@ +package com.nbclass.activity.model; + +import lombok.Data; + +import java.util.Date; + +@Data +public class QueryCriteria { + + /** + * 案例编号 + */ + private Long contentId; + + /** + * 案例标题 + */ + private String title; + + /** + * 案例状态 + */ + private Integer status; + + /** + * 反馈次数 + */ + private Integer labelFeedback; + + /** + * 标签 + */ + private String labelName; + + /** + * 品牌公司 + */ + private String brandCompany; + + /** + * 广告公司 + */ + private String advertisingAgency; + + /** + * 案例用途 + */ + private Integer purposeCase; + + /** + * 创意形式 + */ + private Integer formCreative; + + /** + * 案例类型 + */ + private Integer typeCase; + + /** + * 节日事件 + */ + private Integer eventsFestival; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 创建时间区间 + */ + private Date createTimeSection; + + /** + * 修改时间 + */ + private Date updateTime; + + /** + * 修改时间区间 + */ + private Date updateTimeSection; + + /** + * 上线时间 + */ + private Date onlineTime; + + /** + * 上线时间 + */ + private Date onlineTimeSection; + +} diff --git a/src/main/java/com/nbclass/activity/model/Report.java b/src/main/java/com/nbclass/activity/model/Report.java new file mode 100644 index 0000000..f14cfbc --- /dev/null +++ b/src/main/java/com/nbclass/activity/model/Report.java @@ -0,0 +1,49 @@ +package com.nbclass.activity.model; + +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +@Data +public class Report implements Serializable { + + private static final long serialVersionUID = 6136060231077523641L; + + /** + * id(主键自增) + */ + private Long id; + + /** + * 评论id + */ + private Long commentId; + + /** + * 举报人Id + */ + private Long reportId; + + + /** + * 举报内容 + */ + private String reportContent; + + /** + *举报类型(1、政治、色情等违法言论,2、人身攻击,3、故意引战倾向等不当言论,4、其他原因) + */ + private Integer reportType; + + /** + * 处理状态(0、未处理,1、已处理) + */ + private Integer status; + + /** + * 举报时间 + */ + private Date createTime; + +} diff --git a/src/main/java/com/nbclass/activity/model/Scoring.java b/src/main/java/com/nbclass/activity/model/Scoring.java new file mode 100644 index 0000000..caf494b --- /dev/null +++ b/src/main/java/com/nbclass/activity/model/Scoring.java @@ -0,0 +1,36 @@ +package com.nbclass.activity.model; + +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +@Data +public class Scoring implements Serializable { + + private static final long serialVersionUID = -9026107018961218312L; + + private Long id; + + /** + * 案例id + */ + private Long contentId; + + /** + * 评分数 + */ + private Double score; + + /** + * 评分人 + */ + private Long userId; + + /** + * 创建时间 + */ + private Date createTime; + + +} diff --git a/src/main/java/com/nbclass/activity/model/WeiXiUser.java b/src/main/java/com/nbclass/activity/model/WeiXiUser.java new file mode 100644 index 0000000..d898ddc --- /dev/null +++ b/src/main/java/com/nbclass/activity/model/WeiXiUser.java @@ -0,0 +1,95 @@ +package com.nbclass.activity.model; + +import com.alibaba.fastjson.JSON; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.io.Serializable; +import java.util.Date; + +/** + * 微信用户成员 + */ +@Data +public class WeiXiUser implements Serializable { + + private static final long serialVersionUID = -4661130931634820819L; + + private Long id; + + /** + * 普通用户的标识,对当前开发者帐号唯一 + */ + private String openid; + + /** + * 普通用户昵称 + */ + private String nickname; + + /** + * 普通用户性别,1为男性,2为女性 + */ + private Integer sex; + + /** + * 普通用户个人资料填写的省份 + */ + private String province; + + /** + * 普通用户个人资料填写的城市 + */ + private String city; + + /** + * 国家,如中国为CN + */ + private String country; + + /** + * 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空 + */ + private String headimgurl; + + /** + * 用户特权信息,json数组,如微信沃卡用户为(chinaunicom) + */ + private JSON privilege; + + /** + * 用户统一标识。针对一个微信开放平台帐号下的应用,同一用户的unionid是唯一的。 + */ + private String unionid; + + /** + * 生日 + */ + private Date birthday; + + /** + * 职业id(dict_item的id) + */ + private Integer occupationId; + + /** + * 公司 + */ + private String company; + + /** + * 邮箱 + */ + private String mailbox; + + /** + * 简介 + */ + private String briefIntroduction; + + private Date createTime; + + private Date updateTime; + + +} diff --git a/src/main/java/com/nbclass/activity/model/WxDepartment.java b/src/main/java/com/nbclass/activity/model/WxDepartment.java new file mode 100644 index 0000000..390e2cc --- /dev/null +++ b/src/main/java/com/nbclass/activity/model/WxDepartment.java @@ -0,0 +1,30 @@ +package com.nbclass.activity.model; + +import java.io.Serializable; + +import javax.persistence.Id; +import javax.persistence.Table; + +import lombok.Data; + +/** + * 企业微信部门表 + * @author leiyun + * @datetime 2017年12月21日 下午4:17:39 + */ +@Data +@Table(name = "wx_department") +public class WxDepartment implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + private Long id; + + private String name; + + private Long parentid; + + private Integer order; + +} diff --git a/src/main/java/com/nbclass/activity/model/WxUser.java b/src/main/java/com/nbclass/activity/model/WxUser.java new file mode 100644 index 0000000..a748173 --- /dev/null +++ b/src/main/java/com/nbclass/activity/model/WxUser.java @@ -0,0 +1,46 @@ +package com.nbclass.activity.model; + +import java.io.Serializable; + +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import lombok.Data; + +/** + * 微信成员 + * @author leiyun + * @datetime 2017年12月21日 上午10:58:59 + */ +@Data +@Table(name = "wx_user") +public class WxUser implements Serializable{ + + private static final long serialVersionUID = 1L; + + /** + * ID, 主键,自增 + */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String userid; + private String name; + private String mobile; + + private String department; + private String position; + private String gender; // 性别。0表示未定义,1表示男性,2表示女性 + + private String email; + private String weixinid; + private String isleader; + private String avatar; + private String english_name; + + private int status; + +} diff --git a/src/main/java/com/nbclass/activity/model/enums/ContentType.java b/src/main/java/com/nbclass/activity/model/enums/ContentType.java new file mode 100644 index 0000000..4b21731 --- /dev/null +++ b/src/main/java/com/nbclass/activity/model/enums/ContentType.java @@ -0,0 +1,57 @@ +package com.nbclass.activity.model.enums; + +import org.apache.commons.lang3.StringUtils; + +/** + * i案例类型枚举 + * @author Leon + * @datetime 2020年5月29日 下午1:56:11 + */ +public enum ContentType { + + ppqa("106", "品牌全案"), + + ggqa("107", "公关全案"), + + design("108", "创意设计"), + + video("109", "视频动画"), + + h5("110", "技术开发"), + + ldhd("111", "落地活动"), + + others("112", "其他案例") + ; + + // 枚举值 + private final String key; + + // 枚举描述 + private final String desc; + + + ContentType(final String key, final String desc ) { + this.key = key; + this.desc = desc; + } + + public String key() { + return key; + } + + public String desc() { + return desc; + } + + + public static String getNameByCode(String key){ + for(ContentType entity : ContentType.values()){ + if(key.equals(entity.key)){ + return entity.desc; + } + } + return null; + } + +} diff --git a/src/main/java/com/nbclass/activity/service/CaseTypeService.java b/src/main/java/com/nbclass/activity/service/CaseTypeService.java new file mode 100644 index 0000000..ef1a4dd --- /dev/null +++ b/src/main/java/com/nbclass/activity/service/CaseTypeService.java @@ -0,0 +1,52 @@ +package com.nbclass.activity.service; + +import com.github.pagehelper.PageInfo; +import com.nbclass.activity.model.Content; +import com.nbclass.activity.model.ContentTags; +import com.nbclass.activity.model.DataDict; +import com.nbclass.activity.model.DataDictItem; + +import java.util.List; + +/** + * + * @author gaojiuqi + * @datetime 2021年10月12日 下午14:42 + */ +public interface CaseTypeService { + + /** + * 查询(案例类型、案例用途、创意形式、节日事件) + * @return + */ + List getTypeCase(Integer dictId); + + /** + * 字典值类型列表查询 + * @return + */ + List getDictionariesType(); + + /** + * 案例搜索框 + * @param dictItemId 案例类型id + * @return + */ + PageInfo getSearchCase(String parameter, Integer dictItemId,Integer page, Integer pageSize); + + /** + * 案例库列表 + * @param page + * @param pageSize + * @return + */ + PageInfo getListCase(Integer page, Integer pageSize); + + /** + * 获取案例标签 + * @param contentId 案例id + * @return + */ + ContentTags getContentTags(Integer contentId); + +} diff --git a/src/main/java/com/nbclass/activity/service/CommentService.java b/src/main/java/com/nbclass/activity/service/CommentService.java new file mode 100644 index 0000000..dee81fc --- /dev/null +++ b/src/main/java/com/nbclass/activity/service/CommentService.java @@ -0,0 +1,208 @@ +package com.nbclass.activity.service; + +import com.github.pagehelper.PageInfo; +import com.nbclass.activity.model.*; + +public interface CommentService { + + /** + * 案例详情和评论列表 + * @param contentId + * @return + */ + Content getComment(Long contentId,Long userId); + + /** + * 评论回复列表 + * @param commentId + * @param userId + * @return + */ + Comment getCommentReplyList(Long commentId,Long userId); + + /** + * 添加用户发布信息 + * @param comment + * @return + */ + void saveComment(Comment comment); + + /** + * 根据评论id获取被点赞人Id + * @param commentId + * @return + */ + Comment getCommentUserId(Long commentId); + + /** + * 添加评论点赞 + * @param praise + * @return + */ + void savePraiseNo(Praise praise); + + /** + * 添加案例点赞 + * @param contentId + * @return + */ + void updateContentPraiseNo(Long contentId); + + /** + * 评论总数加1 + * @param commentId + */ + void updatePraiseno(Long commentId); + + /** + * 用户回复 + * @param comment + * @return + */ + void saveUserReply(Comment comment); + + /** + * 用户举报 + * @param report + * @return + */ + void saveReport(Report report); + + /** + * 举报列表获取 + * @param page + * @param pageSize + * @return + */ + PageInfo getReport(Integer page, Integer pageSize, String userId); + + /** + * 添加标签、索引反馈日志 + * @return + */ + void saveLabelLogger(LabelLogger labelLogger); + + /** + * 新建文件夹 + * @param favoritesFolder + * @return + */ + void saveFavorites(FavoritesFolder favoritesFolder); + + /** + * 案例详情的文件夹列表 + * @return + */ + PageInfo getUserFolder(Long userId, Integer page, Integer pageSize,Long commentId); + + /** + * 收藏案例到文件夹中 + * @param contentId + * @return + */ + void saveFolder(Long folderId,Long contentId); + + /** + * 添加收藏总数 + * @param folderId + */ + void saveFolderTotal(Long folderId); + + /** + * 判断该文件夹是否已被收藏 + * @param folderId + * @param contentId + * @return + */ + int getFolderExistence(Long folderId, Long contentId); + + /** + * 判断文件夹是否重名 + * @param name + * @return + */ + int getFavoritesName(String name); + + /** + * 取消文件夹中的案例收藏 + * @param folderId + * @param contentId + * @return + */ + void deleteFolderResources(Long folderId, Long contentId); + + /** + * 我的收藏 + * @param page + * @param pageSize + * @return + */ + PageInfo getMyCollection(Long userId, Integer page, Integer pageSize,Long folderId); + + /** + * 获取用户文件夹列表 + * @return + */ + PageInfo getUserFolderList(Long userId, Integer page, Integer pageSize); + + /** + * 取消评论点赞 + * @return + */ + void deletePraise(Long commentId, Long userId); + + /** + * 总点赞数减一 + * @param commentId + */ + void updatePraiseNoONE(Long commentId); + + /** + * 评论总回复数加一 + */ + void updateReplyNumberONE(Long commentId); + + /** + * 回复列表 + * @param userId + * @param page + * @param pageSize + * @return + */ + PageInfo getReplyList(Long userId, Integer page, Integer pageSize); + + /** + * 点赞列表 + * @param page + * @param pageSize + * @return + */ + PageInfo getFabulousList(Long userId, Integer page, Integer pageSize); + + /** + * 更新案例的收藏总数+1 + * @param contentId + */ + void updateCollectionNumber(Long contentId); + + /** + * 更新案例的收藏总数-1 + * @param contentId + */ + void updateCollectionNumberReduce(Long contentId); + + /** + * 标签、索引反馈日志列表 + * @param page + * @param pageSize + * @return + */ + PageInfo getLabelLogger(Integer page, Integer pageSize, Long userId); + + /** + * 案例打分 + * @param scoring + */ + void saveScoring(Scoring scoring); + +} diff --git a/src/main/java/com/nbclass/activity/service/ContentService.java b/src/main/java/com/nbclass/activity/service/ContentService.java new file mode 100644 index 0000000..8731b05 --- /dev/null +++ b/src/main/java/com/nbclass/activity/service/ContentService.java @@ -0,0 +1,193 @@ +package com.nbclass.activity.service; + +import java.util.List; + +import com.github.pagehelper.PageInfo; +import com.nbclass.activity.model.*; + +/** + * + * @author Leon + * @datetime 2020年5月28日 下午4:42:15 + */ +public interface ContentService { + + /** + * 添加 + * @param entity + */ + public void add(Content entity); + + /** + * 修改 + * @param entity + */ + public void update(Content entity); + + /** + * 删除 + * @param ids + */ + public void delete(List ids); + + /** + * 根据id查询 + * @param id + * @return entity + */ + public Content findById(Long id); + + /** + * 根据条件查询列表 + * @param entity + * @return + */ + public List getList(Content entity); + + /** + * 根据条件查询列表 - 前端页面查询 + * @param entity + * @return + */ + public List getListByFront(Content entity); + + /** + * 添加点赞数阅读数 + * @param type [view, like] + * @param id 案例ID + */ + public int updateContentNum(String type, Long id); + + /** + * 同步数据库数据到ES + * @param entity + * @param isReBuild 是否重建,true:删除所有文档重建 + */ + public long syncEsData(Content entity, boolean isReBuild); + + /** + * 查询案例标题和评论数和点赞数 + * @return + */ + PageInfo getCaseTitle(Integer page,Integer pageSize); + + /** + * 标签关联案例 + * @param contentTags + */ + void addContentTags(ContentTags contentTags); + + /** + * 获取自定义标签列表 + * @return + */ + List getOtherLabels(); + + /** + * 取消案例关联标签的关系 + * @param idList + */ + void deleteContentTags(List idList); + + /** + * 案例索引标签反馈次数+1 + * @param contentId + */ + void updateLabelFeedback(Long contentId); + + /** + * 根据条件查询列表 + * @param entity + * @return + */ + List getList2(Content entity); + + /** + * 更新案例总评论数 + * @param contentId + */ + void updateComments(Long contentId); + + /** + * 添加案例评分 + * @param userId + * @param contentId + * @param score + */ + void saveScore(Long userId, Long contentId, Double score); + + /** + * 查看用户是否已经打过分 + * @param userId + * @param contentId + * @return + */ + int getScore(Long userId, Long contentId); + + /** + * 根据案例id查询案例详情 + * @param contentId + * @return + */ + Content getEditContent(Long contentId); + + /** + * 提交审核申请单 + * @param application + */ + void saveApplication(Application application); + + /** + * 查询案例是否已提交过审核 + * @param contentId + * @return + */ + int getApplicationCount(Long contentId); + + /** + * 删除案例审核申请 + * @param applicationId + */ + void deleteApplication(Long applicationId); + + /** + * 更新审核申请单状态 + * @param applicationId + */ + void updateApplicationStatus(Long applicationId); + + /** + * 获取审核列表 + * @param entity + * @return + */ + List getContentApplication(Content entity); + + /** + * 审核案例 + * @param check + * @param userId + */ + void updateApplication(Check check, Long userId); + + /** + * 根据userId获取微信用户信息 + * @param username + * @return + */ + WxUser getQyWxUser(String username); + + /** + * 根据部门id获取用户领导 + * @param department + * @return + */ + List getUserLeader(String department); + + /** + * 下线案例 + * @param contentId + */ + void deleteRelease(Long contentId); + +} diff --git a/src/main/java/com/nbclass/activity/service/DataDictService.java b/src/main/java/com/nbclass/activity/service/DataDictService.java new file mode 100644 index 0000000..9344a84 --- /dev/null +++ b/src/main/java/com/nbclass/activity/service/DataDictService.java @@ -0,0 +1,86 @@ +package com.nbclass.activity.service; + +import java.util.List; + +import com.nbclass.activity.model.ContentTags; +import com.nbclass.activity.model.DataDict; +import com.nbclass.activity.model.DataDictItem; + +/** + * + * @author Leon + * @datetime 2020年5月28日 下午3:13:52 + */ +public interface DataDictService { + + /** + * 添加 + * @param entity + */ + public void add(DataDict entity); + + /** + * 修改 + * @param entity + */ + public void update(DataDict entity); + + /** + * 删除 + * @param ids + */ + public void delete(List ids); + + /** + * 根据id查询 + * @param id + * @return entity + */ + public DataDict findById(Long id); + + /** + * 根据条件查询列表 + * @param entity + * @return + */ + public List getList(DataDict entity); + + /** + * 通过字典Key获取子集 + * @param datakey + * @return + */ + public List getItemsByKey(String datakey); + + /** + * 根据dictid查询字典item列表 + * @param entity + * @return + */ + public List getItemList(DataDictItem entity); + + /** + * 添加或修改字典子项 + * @param entity + */ + public void mergeDataDictItem(DataDictItem entity); + + /** + * 删除字典子项 + * @param id + */ + public void deleteDataDictItem(Long id); + + /** + * 获取字典值 + * @return + */ + List getDropDownBox(); + + /** + * 根据名字查询tasId + * @param name + * @return + */ + String[] getTagId(String name); +} diff --git a/src/main/java/com/nbclass/activity/service/ElasticSearchService.java b/src/main/java/com/nbclass/activity/service/ElasticSearchService.java new file mode 100644 index 0000000..0e258f9 --- /dev/null +++ b/src/main/java/com/nbclass/activity/service/ElasticSearchService.java @@ -0,0 +1,60 @@ +package com.nbclass.activity.service; + +import java.util.List; + +import com.alibaba.fastjson.JSONObject; +import com.nbclass.activity.model.Content; + +/** + * ES搜索 + * @author Leon + * @datetime 2020年6月1日 下午3:00:41 + */ +public interface ElasticSearchService { + + /** + * 添加或修改文档索引 + * @param entity + */ + public void merge(Content entity); + + /** + * 删除 + * @param ids + */ + public void deleteDocByIds(List ids); + + /** + * 根据条件删除 + * @param entity + */ + public void deleteDocByQuery(Content entity); + + /** + * 判断一个文档是否存在 + * @param id + * @return + */ + public boolean existDoc(Long id); + + /** + * 根据id查询 + * @param id + * @return entity + */ + public Content findById(Long id); + + /** + * 根据条件查询列表 + * @param pageNum + * @param pageSize + * @param type 案例类型 + * @param keyWord 关键词 + * @param tagIds 标签ID, 多个英文逗号分隔 + * @param sourceIds 案例来源ID, 多个英文逗号分隔 + * @return + */ + public JSONObject getList(Integer pageNum, Integer pageSize, String type, String keyWord, String tagIds, String sourceIds); + + +} diff --git a/src/main/java/com/nbclass/activity/service/WxService.java b/src/main/java/com/nbclass/activity/service/WxService.java new file mode 100644 index 0000000..6c4cc03 --- /dev/null +++ b/src/main/java/com/nbclass/activity/service/WxService.java @@ -0,0 +1,47 @@ +package com.nbclass.activity.service; + +import com.nbclass.activity.model.WeiXiUser; + +public interface WxService { + + /** + * 数据库查询是否有该openid,如果有直接从数据库获取用户信息 + * @param openid + * @return + */ + int getOpenId(String openid); + + /** + * 添加用户信息到数据库 + * @param weiXiUser + */ + void saveWxUser(WeiXiUser weiXiUser); + + /** + * 数据库获取用户信息 + * @param openid + * @return + */ + WeiXiUser getWxUser(String openid); + + /** + * 根据用户id获取信息 + * @param userId + * @return + */ + WeiXiUser getUser(String userId); + + /** + * 更新用户基础信息 + * @param weiXiUser + * @return + */ + void updateBasicData(WeiXiUser weiXiUser); + + /** + * 查看用户基础信息 + * @return + */ + WeiXiUser getUserBasicData(Long userId); + +} diff --git a/src/main/java/com/nbclass/activity/service/WxUserService.java b/src/main/java/com/nbclass/activity/service/WxUserService.java new file mode 100644 index 0000000..b8d139d --- /dev/null +++ b/src/main/java/com/nbclass/activity/service/WxUserService.java @@ -0,0 +1,30 @@ +package com.nbclass.activity.service; + +import java.util.List; + +import com.nbclass.activity.model.WxUser; + +/** + * + * @author Leon + * @datetime 2020年6月2日 下午4:50:28 + */ +public interface WxUserService{ + + /** + * 批量保存用户 + * @param userList + */ + public void merge(List userList); + + /** + * 同步企业微信成员 + */ + public void syncWxUser(); + + /** + * 同步企业微信部门 + */ + public void syncWxDepartment(); + +} diff --git a/src/main/java/com/nbclass/activity/service/impl/CaseTypeServiceImpl.java b/src/main/java/com/nbclass/activity/service/impl/CaseTypeServiceImpl.java new file mode 100644 index 0000000..c70c279 --- /dev/null +++ b/src/main/java/com/nbclass/activity/service/impl/CaseTypeServiceImpl.java @@ -0,0 +1,51 @@ +package com.nbclass.activity.service.impl; + +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.nbclass.activity.mapper.CaseTypeMapper; +import com.nbclass.activity.model.Content; +import com.nbclass.activity.model.ContentTags; +import com.nbclass.activity.model.DataDict; +import com.nbclass.activity.model.DataDictItem; +import com.nbclass.activity.service.CaseTypeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class CaseTypeServiceImpl implements CaseTypeService { + + @Autowired + private CaseTypeMapper caseTypeMapper; + + @Override + public List getTypeCase(Integer dictId) { + return caseTypeMapper.getTypeCase(dictId); + } + + @Override + public List getDictionariesType() { + return caseTypeMapper.getDictionariesType(); + } + + @Override + public PageInfo getSearchCase(String parameter, Integer dictItemId,Integer page, Integer pageSize) { + PageHelper.startPage(page,pageSize); + List list = caseTypeMapper.getSearchCase(parameter,dictItemId); + return new PageInfo<>(list); + } + + @Override + public PageInfo getListCase(Integer page, Integer pageSize) { + PageHelper.startPage(page,pageSize); + List list = caseTypeMapper.getListCase(); + return new PageInfo<>(list); + } + + @Override + public ContentTags getContentTags(Integer contentId) { + return caseTypeMapper.getContentTags(contentId); + } + +} diff --git a/src/main/java/com/nbclass/activity/service/impl/CommentServiceImpl.java b/src/main/java/com/nbclass/activity/service/impl/CommentServiceImpl.java new file mode 100644 index 0000000..f14854d --- /dev/null +++ b/src/main/java/com/nbclass/activity/service/impl/CommentServiceImpl.java @@ -0,0 +1,178 @@ +package com.nbclass.activity.service.impl; + +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.nbclass.activity.mapper.CommentMapper; +import com.nbclass.activity.model.*; +import com.nbclass.activity.service.CommentService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class CommentServiceImpl implements CommentService { + + @Autowired + private CommentMapper commentMapper; + + @Override + public Content getComment(Long contentId,Long userId) { + return commentMapper.getComment(contentId,userId); + } + + @Override + public Comment getCommentReplyList(Long commentId, Long userId) { + return commentMapper.getCommentReplyList(commentId,userId); + } + + @Override + public void saveComment(Comment comment) { + commentMapper.saveComment(comment); + } + + @Override + public Comment getCommentUserId(Long commentId) { + return commentMapper.getCommentUserId(commentId); + } + + @Override + public void savePraiseNo(Praise praise) { + commentMapper.savePraiseNo(praise); + } + + @Override + public void updateContentPraiseNo(Long contentId) { + commentMapper.updateContentPraiseNo(contentId); + } + + @Override + public void updatePraiseno(Long commentId) { + commentMapper.updatePraiseno(commentId); + } + + @Override + public void saveUserReply(Comment comment) { + commentMapper.saveUserReply(comment); + } + + @Override + public void saveReport(Report report) { + commentMapper.saveReport(report); + } + + @Override + public PageInfo getReport(Integer page, Integer pageSize, String userId) { + PageHelper.startPage(page,pageSize); + List list = commentMapper.getReport(userId); + return new PageInfo<>(list); + } + + @Override + public void saveLabelLogger(LabelLogger labelLogger) { + commentMapper.saveLabelLogger(labelLogger); + } + + @Override + public void saveFavorites(FavoritesFolder favoritesFolder) { + commentMapper.saveFavorites(favoritesFolder); + } + + @Override + public PageInfo getUserFolder(Long userId, Integer page, Integer pageSize,Long commentId) { + PageHelper.startPage(page,pageSize); + List list = commentMapper.getUserFolder(userId,commentId); + return new PageInfo<>(list); + } + + @Override + public void saveFolder(Long folderId,Long contentId) { + commentMapper.saveFolder(folderId,contentId); + } + + @Override + public void saveFolderTotal(Long folderId) { + commentMapper.saveFolderTotal(folderId); + } + + @Override + public int getFolderExistence(Long folderId, Long contentId) { + return commentMapper.getFolderExistence(folderId,contentId); + } + + @Override + public int getFavoritesName(String name) { + return commentMapper.getFavoritesName(name); + } + + @Override + public void deleteFolderResources(Long folderId, Long contentId) { + commentMapper.deleteFolderResources(folderId,contentId); + } + + @Override + public PageInfo getMyCollection(Long userId, Integer page, Integer pageSize,Long folderId) { + PageHelper.startPage(page,pageSize); + List list = commentMapper.getMyCollection(userId,folderId); + return new PageInfo<>(list); + } + + @Override + public PageInfo getUserFolderList(Long userId, Integer page, Integer pageSize) { + PageHelper.startPage(page,pageSize); + List list = commentMapper.getUserFolderList(userId); + return new PageInfo<>(list); + } + + @Override + public void deletePraise(Long commentId, Long userId) { + commentMapper.deletePraise(commentId,userId); + } + + @Override + public void updatePraiseNoONE(Long commentId) { + commentMapper.updatePraiseNoONE(commentId); + } + + @Override + public void updateReplyNumberONE(Long commentId) { + commentMapper.updateReplyNumberONE(commentId); + } + + @Override + public PageInfo getReplyList(Long userId, Integer page, Integer pageSize) { + PageHelper.startPage(page,pageSize); + List list = commentMapper.getReplyList(userId); + return new PageInfo<>(list); + } + + @Override + public PageInfo getFabulousList(Long userId, Integer page, Integer pageSize) { + PageHelper.startPage(page,pageSize); + List list = commentMapper.getFabulousList(userId); + return new PageInfo<>(list); + } + + @Override + public void updateCollectionNumber(Long contentId) { + commentMapper.updateCollectionNumber(contentId); + } + + @Override + public void updateCollectionNumberReduce(Long contentId) { + commentMapper.updateCollectionNumberReduce(contentId); + } + + @Override + public PageInfo getLabelLogger(Integer page, Integer pageSize, Long userId) { + PageHelper.startPage(page,pageSize); + List list = commentMapper.getLabelLogger(userId); + return new PageInfo<>(list); + } + + @Override + public void saveScoring(Scoring scoring) { + commentMapper.saveScoring(scoring); + } + +} diff --git a/src/main/java/com/nbclass/activity/service/impl/ContentServiceImpl.java b/src/main/java/com/nbclass/activity/service/impl/ContentServiceImpl.java new file mode 100644 index 0000000..1ead819 --- /dev/null +++ b/src/main/java/com/nbclass/activity/service/impl/ContentServiceImpl.java @@ -0,0 +1,470 @@ +package com.nbclass.activity.service.impl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import javax.annotation.Resource; +import javax.transaction.Transactional; + +import com.nbclass.activity.mapper.WXMapper; +import com.nbclass.activity.model.*; +import com.nbclass.activity.service.WxService; +import com.nbclass.system.service.UserService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.nbclass.activity.mapper.ContentMapper; +import com.nbclass.activity.mapper.DataDictMapper; +import com.nbclass.activity.model.enums.ContentType; +import com.nbclass.activity.service.ContentService; +import com.nbclass.activity.service.ElasticSearchService; +import com.nbclass.exception.ParameterException; +import com.nbclass.util.CommonUtils; + +/** + * + * @author Leon + * @datetime 2020年5月28日 下午4:42:45 + */ +@Service +public class ContentServiceImpl implements ContentService { + + @Resource + private ContentMapper mapper; + + @Resource + private DataDictMapper dataDictMapper; + + @Resource + private ElasticSearchService esService; + + @Resource + private DataDictMapper dataDictMapper2; + + @Resource + private WXMapper wxMapper; + + + private void baseSaveVerify(Content entity) { + /*if(StringUtils.isBlank(entity.getType())) { + throw new ParameterException("案例类型不能为空"); + }*/ + if(StringUtils.isBlank(entity.getTitle())) { + throw new ParameterException("标题不能为空"); + } + /*if(entity.getFromid() == null || entity.getFromid() < 1) { + throw new ParameterException("案例来源不能为空"); + }*/ + if(StringUtils.isBlank(entity.getDesct())) { + throw new ParameterException("描述不能为空"); + } + if(StringUtils.isBlank(entity.getListicon())) { + throw new ParameterException("封面图不能为空"); + } + + // 链接形式的案例 + if(ContentType.h5.key().equals(entity.getType()) || ContentType.video.key().equals(entity.getType())) { + if(StringUtils.isBlank(entity.getUrl())) { + throw new ParameterException("URL不能为空"); + } + } + + // 富文本编辑的案例 + // 0527开发群确认的,记录关键词“都是富文本” + if(ContentType.design.key().equals(entity.getType()) + || ContentType.ppqa.key().equals(entity.getType()) + || ContentType.ggqa.key().equals(entity.getType()) + || ContentType.ldhd.key().equals(entity.getType()) + || ContentType.others.key().equals(entity.getType())) { + if(StringUtils.isBlank(entity.getContent())) { + throw new ParameterException("内容不能为空"); + } + } + + if(StringUtils.isBlank(entity.getAttachment()))entity.setAttachment(null); // 空字符串导致MySQL存储json类型异常 + } + +// // 修改案例标签和图集 +// private void updateLabelAndImages(Content o){ +// long cid = o.getId(); +// List newTagList = new ArrayList(); +// if(StringUtils.isNotBlank(o.getTags())){ +// ArrayList postTagList = CommonUtils.str2List(o.getTags()); +// // 查询出 dictid +// DataDict dataDict = new DataDict(); +// dataDict.setDatakey("tag_"+o.getType()); +// dataDict = dataDictMapper.selectOne(dataDict); +// +// +// List taglist = dataDictMapper.getItemsByNames("tag_"+o.getType(), postTagList); +// HashMap tagMap = new HashMap(); +// for (DataDictItem dataDictItem : taglist) { +// tagMap.put(dataDictItem.getName(), dataDictItem); +// } +// for (String tag : postTagList) { +// if(StringUtils.isBlank(tag))continue; +// DataDictItem ddItem = null; +// if(tagMap.containsKey(tag)) { +// ddItem = tagMap.get(tag); +// }else { +// // 字典表里没有则新增标签 +// ddItem = new DataDictItem(); +// ddItem.setDictid(dataDict.getId()); +// ddItem.setName(tag); +// ddItem.setValue(tag); +// dataDictMapper.insertDataDictItem(ddItem); +// } +// ContentTags label = new ContentTags(); +// label.setCid(cid); +// label.setTid(ddItem.getId()); +// newTagList.add(label); +// } +// } +// mapper.deleteTags(cid); +// if(newTagList.size() > 0)mapper.insertContentTags(newTagList); +// +// +// List imgList = new ArrayList(); +// String images = o.getImages(); +// if(StringUtils.isNotBlank(images)){ +// JSONArray array = JSONArray.parseArray(images); +// for(int i=0, j=array.size();i 0){ +// mapper.insertContentImages(imgList); +// } +// } + + // 修改案例标签和图集 + private void updateLabelAndImages(Content o){ + long cid = o.getId(); + List newTagList = new ArrayList(); + if(StringUtils.isNotBlank(o.getTags())){ + ArrayList postTagList = CommonUtils.str2List(o.getTags()); + // 查询自定义标签的dictid + Long dictId = dataDictMapper2.getDataDictID(); + + //根据标签名称查询标签信息 + List tagList = dataDictMapper2.getDataDictTemName(postTagList); + HashMap tagMap = new HashMap(); + for (DataDictItem dataDictItem : tagList) { + tagMap.put(dataDictItem.getName(), dataDictItem); + } + for (String tag : postTagList) { + if(StringUtils.isBlank(tag))continue; + DataDictItem ddItem = null; + if(tagMap.containsKey(tag)) { + ddItem = tagMap.get(tag); + }else { + // 字典表里没有则新增标签 + ddItem = new DataDictItem(); + ddItem.setDictid(dictId); + ddItem.setName(tag); + ddItem.setValue(tag); + dataDictMapper.insertDataDictItem(ddItem); + } + ContentTags label = new ContentTags(); + label.setCid(cid); + label.setTid(ddItem.getId()); + newTagList.add(label); + } + } + mapper.deleteTags(cid); + if(o.getTagLists() != null){ + String[] tagList1 = o.getTagLists(); + for (String s : tagList1) { + ContentTags contentTags = new ContentTags(); + contentTags.setCid(cid); + contentTags.setTid(Long.parseLong(s)); + newTagList.add(contentTags); + } + } + if(newTagList.size() > 0)mapper.insertContentTags(newTagList); + + + List imgList = new ArrayList(); + String images = o.getImages(); + if(StringUtils.isNotBlank(images)){ + JSONArray array = JSONArray.parseArray(images); + for(int i=0, j=array.size();i 0){ + mapper.insertContentImages(imgList); + } + } + + @Transactional + @Override + public void add(Content entity) { + baseSaveVerify(entity); + entity.setType(null); + mapper.insertSelective(entity); + updateLabelAndImages(entity); + + // 提交到ElasticSearch + entity = findById(entity.getId()); + esService.merge(entity); + } + + @Transactional + @Override + public void update(Content entity) { + baseSaveVerify(entity); + entity.setType(null); + mapper.updateByPrimaryKeySelective(entity); + updateLabelAndImages(entity); + + // 提交到ElasticSearch + entity = findById(entity.getId()); + esService.merge(entity); + } + + @Override + public void delete(List ids) { + if(ids == null || ids.isEmpty()){ + throw new ParameterException("id不能为空"); + } + // 从数据库中删除 + mapper.deleteByIds(ids); + // 从ES中删除 + esService.deleteDocByIds(ids); + } + + @Override + public Content findById(Long id) { + if(id == null || id < 1){ + throw new ParameterException("id不能为空"); + } + Content entity = mapper.findById(id); + if(entity!=null&&entity.getId()!=null&&entity.getId()>0) { + if(entity.getImgList()!=null)entity.setImages(JSON.toJSONString(entity.getImgList())); + if(entity.getTagList()!=null)entity.setTags(JSON.toJSONString(entity.getTagList())); + } + return entity; + } + + @Override + public List getList(Content entity) { + return mapper.getList(entity); + } + + @Override + public List getListByFront(Content entity) { + return mapper.getListByFront(entity); + } + + @Override + public int updateContentNum(String type, Long id) { + if(StringUtils.isBlank(type)){ + throw new ParameterException("类型不能为空"); + } + if(id == null || id < 1){ + throw new ParameterException("id不能为空"); + } + mapper.updateContentNum(type, id); + Content entity = findById(id); + + // 提交到ElasticSearch + esService.merge(entity); + + Integer result = 0; + if("view".equals(type)){ + result = entity.getViewno(); + }else if("like".equals(type)){ + result = entity.getPraiseno(); + } + if(result == null)result=1; + return result; + } + + @Override + public long syncEsData(Content entity, boolean isReBuild) { + if(StringUtils.isBlank(entity.getType())) { + throw new ParameterException("案例类型不能为空"); + } + if(isReBuild) { + // 如果重建索引,则先把所有记录删除,这个也可用于删除脏数据。 + esService.deleteDocByQuery(entity); + } + PageHelper.startPage(1, 1000); + List dataList = getListByFront(entity); + PageInfo pages = new PageInfo<>(dataList); + for (Content content : dataList) { + // 提交到ElasticSearch + esService.merge(content); + } + return pages.getTotal(); + } + + @Override + public PageInfo getCaseTitle(Integer page,Integer pageSize) { + PageHelper.startPage(page,pageSize); + List list = mapper.getCaseTitle(); + return new PageInfo<>(list); + } + + @Override + public void addContentTags(ContentTags contentTags) { + mapper.addContentTags(contentTags); + } + + @Override + public List getOtherLabels() { + List list = mapper.getOtherLabels(); + return list; + } + + @Override + public void deleteContentTags(List idList) { + mapper.deleteContentTags(idList); + } + + @Override + public void updateLabelFeedback(Long contentId) { + mapper.updateLabelFeedback(contentId); + } + + @Override + public List getList2(Content entity) { + return mapper.getList2(entity); + } + + @Override + public void updateComments(Long contentId) { + mapper.updateComments(contentId); + } + + @Override + public void saveScore(Long userId, Long contentId, Double score) { + mapper.saveScore(userId,contentId,score); + } + + @Override + public int getScore(Long userId, Long contentId) { + return mapper.getScore(userId,contentId); + } + + @Override + public Content getEditContent(Long contentId) { + return mapper.getEditContent(contentId); + } + + @Override + @Transactional + public void saveApplication(Application application) { + //添加审核申请单 + mapper.saveApplication(application); + //添加审核人信息 + Check check = new Check(); + check.setApplicationId(application.getId()); + List checks = application.getChecks(); + if(checks == null ) throw new ParameterException("审核人不能为空!"); + for (Check check1 : checks) { + check.setCheckId(check1.getCheckId()); + mapper.saveCheck(check); + } + //更新案例状态(审核可能是下架重新申请的) + mapper.updateContentRelease(application.getContentId(),1); + } + + @Override + public int getApplicationCount(Long contentId) { + return mapper.getApplicationCount(contentId); + } + + @Override + @Transactional + public void deleteApplication(Long applicationId) { + //删除案例审核申请 + mapper.deleteApplication(applicationId); + //删除审核人信息 + mapper.deleteCheck(applicationId); + } + + @Override + @Transactional + public void updateApplicationStatus(Long applicationId) { + //更新审核申请单状态 + mapper.updateApplicationStatus(applicationId); + //更新审核人状态 + mapper.updateCheckStatus(applicationId); + } + + @Override + public List getContentApplication(Content entity) { + return mapper.getContentApplication(entity); + } + + @Override + @Transactional + public void updateApplication(Check check, Long userId) { + //更新审核表状态 + check.setCheckId(userId); + mapper.updateCheck(check); + Application application = new Application(); + application.setId(check.getApplicationId()); + //更新申请单状态 + if(check.getStatus() == 2){ + //审核通过 + application.setStatus(2); + //查询案例id + Long contentId = mapper.getContentId(check.getApplicationId()); + //更新案例状态 + mapper.updateContentRelease(contentId,2); + }else { + //审核驳回 + application.setStatus(3); + } + mapper.updateApplication(application); + + } + + @Override + public WxUser getQyWxUser(String username) { + return wxMapper.getQyWxUser(username); + } + + @Override + public List getUserLeader(String department) { + return wxMapper.getUserLeader(department); + } + + @Override + @Transactional + public void deleteRelease(Long contentId) { + //根据案例id查询申请单信息 + Application application = mapper.getApplication(contentId); + //删除申请单信息 + mapper.deleteApplication(application.getId()); + //删除审核表信息 + mapper.deleteCheck(application.getId()); + //案例表状态修改为已下线 + mapper.updateContentRelease(contentId,4); + } + + +} diff --git a/src/main/java/com/nbclass/activity/service/impl/DataDictServiceImpl.java b/src/main/java/com/nbclass/activity/service/impl/DataDictServiceImpl.java new file mode 100644 index 0000000..aae6a6b --- /dev/null +++ b/src/main/java/com/nbclass/activity/service/impl/DataDictServiceImpl.java @@ -0,0 +1,146 @@ +package com.nbclass.activity.service.impl; + +import java.util.List; + +import javax.annotation.Resource; + +import com.nbclass.activity.model.ContentTags; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import com.nbclass.activity.mapper.DataDictItemMapper; +import com.nbclass.activity.mapper.DataDictMapper; +import com.nbclass.activity.model.DataDict; +import com.nbclass.activity.model.DataDictItem; +import com.nbclass.activity.service.DataDictService; +import com.nbclass.exception.ParameterException; + +/** + * + * @author Leon + * @datetime 2020年5月28日 下午3:23:26 + */ +@Service +public class DataDictServiceImpl implements DataDictService { + + @Resource + private DataDictMapper mapper; + + @Resource + DataDictItemMapper dataDictItemMapper; + + private void baseSaveVerify(DataDict entity) { + + } + + @Override + public void add(DataDict entity) { + baseSaveVerify(entity); + mapper.insertSelective(entity); + } + + @Override + public void update(DataDict entity) { + baseSaveVerify(entity); + mapper.updateByPrimaryKeySelective(entity); + } + + @Override + public void delete(List ids) { + if(ids == null || ids.isEmpty()){ + throw new ParameterException("id不能为空"); + } + Long cnt = mapper.delCheck(ids); + if(cnt!=null && cnt>0) { + throw new ParameterException("请先删除子项再删除字典!"); + } + Long dataDictID = mapper.getDataDictID(); + for (Long id : ids) { + if(dataDictID.equals(id)) throw new ParameterException("该字典不可删除!"); + } + mapper.deleteByIds(ids); + } + + @Override + public DataDict findById(Long id) { + if(id == null || id < 1){ + throw new ParameterException("id不能为空"); + } + DataDict search = new DataDict(); + search.setId(id); + DataDict entity = mapper.selectOne(search); + return entity; + } + + @Override + public List getList(DataDict entity) { + return mapper.getList(entity); + } + + @Override + public List getItemsByKey(String datakey) { + if(StringUtils.isBlank(datakey)) { + throw new ParameterException("参数不能为空"); + } + return mapper.getItemsByKey(datakey); + } + + @Override + public List getItemList(DataDictItem entity) { + return dataDictItemMapper.getList(entity); + } + + @Override + public void mergeDataDictItem(DataDictItem entity) { + if(entity.getDictid() == null || entity.getDictid() < 1) { + throw new ParameterException("字典ID不能为空"); + } + if(StringUtils.isBlank(entity.getValue())) { + throw new ParameterException("编码不能为空"); + } + if(StringUtils.isBlank(entity.getName())) { + throw new ParameterException("名称不能为空"); + } + + Long cnt = dataDictItemMapper.checkExist(entity); + if(cnt!=null && cnt>0) { + throw new ParameterException("该记录已存在"); + } + if(entity.getId()!=null && entity.getId()>0) { + dataDictItemMapper.updateByPrimaryKeySelective(entity); + }else { + entity.setId(null); + dataDictItemMapper.insertSelective(entity); + } + } + + @Override + public void deleteDataDictItem(Long id) { + if(id == null || id < 1) { + throw new ParameterException("ID不能为空"); + } + Long cnt = dataDictItemMapper.checkContentTag(id); + if(cnt!=null && cnt>0) { + throw new ParameterException("该标签正在使用,请先从案例中解除此标签"); + } + + Long cnt2 = dataDictItemMapper.checkContentFrom(id); + if(cnt2!=null && cnt2>0) { + throw new ParameterException("该案例来源正在使用,请先从案例中解除此来源"); + } + + dataDictItemMapper.deleteByPrimaryKey(id); + } + + @Override + public List getDropDownBox() { + return dataDictItemMapper.getDropDownBox(); + } + + @Override + public String[] getTagId(String name) { + return dataDictItemMapper.getTagId(name); + } + + +} diff --git a/src/main/java/com/nbclass/activity/service/impl/ElasticSearchServiceImpl.java b/src/main/java/com/nbclass/activity/service/impl/ElasticSearchServiceImpl.java new file mode 100644 index 0000000..4245dba --- /dev/null +++ b/src/main/java/com/nbclass/activity/service/impl/ElasticSearchServiceImpl.java @@ -0,0 +1,349 @@ +package com.nbclass.activity.service.impl; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.annotation.Resource; + +import org.apache.commons.lang3.StringUtils; +import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; +import org.elasticsearch.action.admin.indices.get.GetIndexRequest; +import org.elasticsearch.action.delete.DeleteRequest; +import org.elasticsearch.action.delete.DeleteResponse; +import org.elasticsearch.action.get.GetRequest; +import org.elasticsearch.action.get.GetResponse; +import org.elasticsearch.action.index.IndexRequest; +import org.elasticsearch.action.index.IndexResponse; +import org.elasticsearch.action.search.SearchRequest; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.action.support.master.AcknowledgedResponse; +import org.elasticsearch.action.update.UpdateRequest; +import org.elasticsearch.action.update.UpdateResponse; +import org.elasticsearch.client.RequestOptions; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.client.indices.CreateIndexRequest; +import org.elasticsearch.client.indices.CreateIndexResponse; +import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.index.reindex.BulkByScrollResponse; +import org.elasticsearch.index.reindex.DeleteByQueryRequest; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.elasticsearch.search.sort.SortOrder; +import org.springframework.stereotype.Service; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.nbclass.activity.model.Content; +import com.nbclass.activity.model.ContentTags; +import com.nbclass.activity.service.ContentService; +import com.nbclass.activity.service.ElasticSearchService; +import com.nbclass.exception.ParameterException; +import com.nbclass.exception.ServiceException; + +import lombok.extern.slf4j.Slf4j; + +/** + * 案例内容ES操作 + * @author Leon + * @datetime 2020年6月1日 下午3:02:00 + */ +@Slf4j +@Service +public class ElasticSearchServiceImpl implements ElasticSearchService { + + @Resource + private RestHighLevelClient restHighLevelClient; + + @Resource + private ContentService contentService; + + private static final String es_index_content = "es-cases-content"; + + + /** + * 检查索引是否存在 + * @throws IOException + */ + private boolean existIndex() throws IOException{ + GetIndexRequest request = new GetIndexRequest().indices(es_index_content); + @SuppressWarnings("deprecation") + boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT); + return exists; + } + + // 创建索引 + public void createIndex(){ + try { + // 检查索引是否存在 + if(existIndex())return; + + CreateIndexRequest indexRequest = new CreateIndexRequest(es_index_content); + CreateIndexResponse indexResponse = restHighLevelClient.indices().create(indexRequest, RequestOptions.DEFAULT); + log.info("创建索引, 返回值=>{}, 确认状态=>{}", indexResponse.index(), indexResponse.isAcknowledged()); + }catch (Exception e) { + log.info("创建索引异常", e); + } + } + + // 删除索引 + public void deleteIndex(){ + try { + DeleteIndexRequest indexRequest = new DeleteIndexRequest(es_index_content); + AcknowledgedResponse delete = restHighLevelClient.indices().delete(indexRequest, RequestOptions.DEFAULT); + log.info("删除索引, 返回值=>{}, 确认状态=>{}", delete.isFragment(), delete.isAcknowledged()); + }catch (Exception e) { + log.info("删除索引异常", e); + } + } + + // 创建或者更新文档 + @Override + public void merge(Content entity) { + try { + if(entity!=null && entity.getTagList()!=null && entity.getTagList().size()>0) { + String tags = ""; + for(ContentTags tag : entity.getTagList()) { + if(StringUtils.isBlank(tag.getTagName()))continue; + tags += (StringUtils.isBlank(tags)?"":",")+tag.getTagName(); + } + entity.setTags(tags); // 将标签组到字符串里,便于搜索。 + } + + createIndex(); // 判断索引是否存在,不存在创建索引 + + // 判断document是否存在,存在修改,不存在新增 + GetRequest getRequest = new GetRequest(es_index_content, String.valueOf(entity.getId())); + boolean exists = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT); + if(!exists) { + // 创建文档索引 + IndexRequest indexRequest = new IndexRequest(es_index_content); + indexRequest.id(String.valueOf(entity.getId())).source(JSON.toJSONString(entity), XContentType.JSON); + @SuppressWarnings("unused") + IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT); + log.info("添加文档,新建ES索引成功,id = " + entity.getId()); + }else { + // 修改文档索引 + UpdateRequest updateRequest = new UpdateRequest(es_index_content, String.valueOf(entity.getId())); + updateRequest.doc(JSON.toJSONString(entity), XContentType.JSON); + @SuppressWarnings("unused") + UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT); + log.info("修改文档,重建ES索引成功,id = " + entity.getId()); + } + } catch (IOException e) { + log.error("添加文档,新建ES索引失败,id = " + entity.getId(), e); + throw new ServiceException("案例更新ES索引失败"); + } + } + + @Override + public void deleteDocByIds(List ids) { + if(ids == null || ids.isEmpty()){ + return; + } + try { + for (Long id : ids) { + // DeleteRequest + DeleteRequest deleteRequest = new DeleteRequest(es_index_content, String.valueOf(id)); + @SuppressWarnings("unused") + DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT); + } + } catch (IOException e) { + log.error("删除案例ES索引失败", e); + throw new ServiceException("删除案例ES索引失败"); + } + } + + // matchQuery:会将搜索词分词,再与目标查询字段进行匹配,若分词中的任意一个词与目标字段匹配上,则可查询到。 + // termQuery:不会对搜索词进行分词处理,而是作为一个整体与目标字段进行匹配,若完全匹配,则可查询到。 + @Override + public void deleteDocByQuery(Content entity) { + if(entity.getType()!=null) { + throw new ParameterException("案例类型不能为空"); + } + try { + DeleteByQueryRequest request = new DeleteByQueryRequest(es_index_content); + request.setConflicts("proceed"); // 发生冲突即略过 + request.setQuery(QueryBuilders.termQuery("type", entity.getType())); + BulkByScrollResponse bulkResponse = restHighLevelClient.deleteByQuery(request, RequestOptions.DEFAULT); + + TimeValue timeTaken = bulkResponse.getTook(); + boolean timedOut = bulkResponse.isTimedOut(); + long totalDocs = bulkResponse.getTotal(); + long updatedDocs = bulkResponse.getUpdated(); + long deletedDocs = bulkResponse.getDeleted(); + long batches = bulkResponse.getBatches(); + long noops = bulkResponse.getNoops(); + long versionConflicts = bulkResponse.getVersionConflicts(); + log.info("根据案例类型删除文档,花费时间:" + timeTaken + ",是否超时:" + timedOut + ",总文档数:" + totalDocs + ",更新数:" + + updatedDocs + ",删除数:" + deletedDocs + ",批量次数:" + batches + ",跳过数:" + noops + ",冲突数:" + versionConflicts); + } catch (IOException e) { + log.error("根据案例类型删除文档异常", e); + } + } + + @Override + public boolean existDoc(Long id){ + boolean exists = false; + GetRequest getRequest = new GetRequest(es_index_content, String.valueOf(id)); + try { + exists = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT); + } catch (IOException e) { + e.printStackTrace(); + } + return exists; + } + + // 获取文档 + @Override + public Content findById(Long id) { + // GetRequest + GetRequest getRequest = new GetRequest(es_index_content, String.valueOf(id)); + // 查询ES + GetResponse getResponse; + Content content = null; + try { + getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT); + content = JSON.parseObject(getResponse.getSourceAsString(), Content.class); + if(content == null) { + content = contentService.findById(id); + } + if(content!=null && content.getId()!=null && content.getId()>0) { + content.setTags(null); + content.setImages(null); + } + } catch (IOException e) { + log.error("从ES查询数据失败", e); + throw new ServiceException("从ES查询数据失败"); + } + return content; + } + + /** + * 从数据库查询 + * @return + */ + private JSONObject getListByMySQL(Integer pageNum, Integer pageSize, String type, String keyWord, String tagIds, String sourceIds) { + JSONObject result = new JSONObject(); + Content param = new Content(); + param.setType(type); + param.setTitle(keyWord); + param.setTags(tagIds); + param.setFromids(sourceIds); + PageHelper.startPage(pageNum, pageSize); + List dataList = contentService.getListByFront(param); + PageInfo pages = new PageInfo<>(dataList); + if(dataList!=null && dataList.size()>0) { + for (Content entity : dataList) { + // 清空一些前端用不上的字段 + entity.setTags(null); + entity.setImages(null); + entity.setImgList(null); + } + } + + result.put("total", pages.getTotal()); // 总记录数 + result.put("rows", dataList); // 数据体 + int totalPage = (int)(pages.getTotal() % pageSize==0 ? pages.getTotal()/pageSize : pages.getTotal()/pageSize+1); + result.put("totalPage", totalPage); // 总页数 + return result; + } + + @Override + public JSONObject getList(Integer pageNum, Integer pageSize, String type, String keyWord, String tagIds, String sourceIds) { + // 封装Map参数返回 + JSONObject result = new JSONObject(); + try { + // 选择标签或来源过滤时,从数据库查询记录 + /*if(StringUtils.isNotBlank(tagIds) || StringUtils.isNotBlank(sourceIds)) { + return getListByMySQL(pageNum, pageSize, type, keyWord, tagIds, sourceIds); + }*/ + + SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); + // 分页采用简单的from + size分页,适用数据量小的,了解更多分页方式可自行查阅资料 + searchSourceBuilder.from((pageNum - 1) * pageSize); // 从0开始 + searchSourceBuilder.size(pageSize); + + // 查询条件,只有查询关键字不为空才带查询条件 + if (StringUtils.isNoneBlank(keyWord)) { + // QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery(keyword, "name", "desc"); + // searchSourceBuilder.query(queryBuilder); + } + + BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); + if(StringUtils.isNotBlank(type)) { // 案例类型 + boolQueryBuilder.must(QueryBuilders.termQuery("type", type)); + if (StringUtils.isNoneBlank(keyWord)){ + BoolQueryBuilder keywordQuery = QueryBuilders.boolQuery(); + keywordQuery.should(QueryBuilders.matchQuery("title", keyWord)); + keywordQuery.should(QueryBuilders.matchQuery("desct", keyWord)); + keywordQuery.should(QueryBuilders.matchQuery("fromName", keyWord)); + keywordQuery.should(QueryBuilders.matchQuery("tags", keyWord)); + keywordQuery.should(QueryBuilders.matchQuery("content_text", keyWord)); + boolQueryBuilder.must(keywordQuery); + } + }else { + if (StringUtils.isNoneBlank(keyWord)){ + boolQueryBuilder.should(QueryBuilders.matchQuery("title", keyWord)); //.boost(3) // 给name字段更高的权重 + boolQueryBuilder.should(QueryBuilders.matchQuery("desct", keyWord)); // description 默认权重 1 + boolQueryBuilder.should(QueryBuilders.matchQuery("fromName", keyWord)); + boolQueryBuilder.should(QueryBuilders.matchQuery("tags", keyWord)); + boolQueryBuilder.should(QueryBuilders.matchQuery("content_text", keyWord)); + boolQueryBuilder.minimumShouldMatch(1); // 至少一个should条件满足 + } + } + //选择标签或来源过滤 + if(StringUtils.isNotBlank(tagIds)){ + List tagIdList = Arrays.asList(tagIds.split(",")); + for(String tagId:tagIdList) { + boolQueryBuilder.must(QueryBuilders.termQuery("tagList.id", tagId)); + } + } + if(StringUtils.isNotBlank(sourceIds)){ + List sourIdList = Arrays.asList(sourceIds.split(",")); + for(String sourId:sourIdList) { + boolQueryBuilder.must(QueryBuilders.termQuery("fromid", sourId)); + } + } + searchSourceBuilder.query(boolQueryBuilder); + + + // 排序,根据ID倒叙 + searchSourceBuilder.sort("id", SortOrder.DESC); + // SearchRequest + SearchRequest searchRequest = new SearchRequest(); + searchRequest.source(searchSourceBuilder); + // 查询ES + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); + SearchHits hits = searchResponse.getHits(); + // 获取总数 + Long total = hits.getTotalHits().value; + // 遍历封装列表对象 + List dataList = new ArrayList<>(); + SearchHit[] searchHits = hits.getHits(); + for (SearchHit searchHit : searchHits) { + Content entity = JSON.parseObject(searchHit.getSourceAsString(), Content.class); + // 清空一些前端用不上的字段 + entity.setTags(null); + entity.setImages(null); + entity.setImgList(null); + dataList.add(entity); + } + result.put("total", total); // 总记录数 + result.put("rows", dataList); // 数据体 + int totalPage = (int)(total % pageSize==0 ? total/pageSize : total/pageSize+1); + result.put("totalPage", totalPage); // 总页数 + }catch (Exception e) { + log.error("从es查询数据列表异常", e); + } + return result; + } + +} diff --git a/src/main/java/com/nbclass/activity/service/impl/WxServiceImpl.java b/src/main/java/com/nbclass/activity/service/impl/WxServiceImpl.java new file mode 100644 index 0000000..2d1b614 --- /dev/null +++ b/src/main/java/com/nbclass/activity/service/impl/WxServiceImpl.java @@ -0,0 +1,46 @@ +package com.nbclass.activity.service.impl; + +import com.nbclass.activity.mapper.WXMapper; +import com.nbclass.activity.model.WeiXiUser; +import com.nbclass.activity.service.WxService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class WxServiceImpl implements WxService { + + @Autowired + private WXMapper wxMapper; + + + @Override + public int getOpenId(String openid) { + return wxMapper.getOpenId(openid); + } + + @Override + public void saveWxUser(WeiXiUser weiXiUser) { + wxMapper.saveWxUser(weiXiUser); + } + + @Override + public WeiXiUser getWxUser(String openid) { + return wxMapper.getWxUser(openid); + } + + @Override + public WeiXiUser getUser(String userId) { + return wxMapper.getUser(userId); + } + + @Override + public void updateBasicData(WeiXiUser weiXiUser) { + wxMapper.updateBasicData(weiXiUser); + } + + @Override + public WeiXiUser getUserBasicData(Long userId) { + return wxMapper.getUserBasicData(userId); + } + +} diff --git a/src/main/java/com/nbclass/activity/service/impl/WxUserServiceImpl.java b/src/main/java/com/nbclass/activity/service/impl/WxUserServiceImpl.java new file mode 100644 index 0000000..f34b7b4 --- /dev/null +++ b/src/main/java/com/nbclass/activity/service/impl/WxUserServiceImpl.java @@ -0,0 +1,145 @@ +package com.nbclass.activity.service.impl; + +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.Resource; +import javax.transaction.Transactional; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.nbclass.activity.constant.Const; +import com.nbclass.activity.mapper.WxDepartmentMapper; +import com.nbclass.activity.mapper.WxUserMapper; +import com.nbclass.activity.model.WxDepartment; +import com.nbclass.activity.model.WxUser; +import com.nbclass.activity.service.WxUserService; +import com.nbclass.system.model.User; +import com.nbclass.system.service.UserService; +import com.nbclass.util.HttpUtils; +import com.nbclass.util.PasswordHelper; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class WxUserServiceImpl implements WxUserService { + + @Resource + private WxUserMapper wxUserMapper; + + @Resource + private UserService userService; + + @Resource + private WxDepartmentMapper deptMapper; + + + @Transactional + @Override + public void merge(List userList){ + if(userList == null || userList.size() == 0)return; + + List dbUserIds = wxUserMapper.getUserIds(); // 查询数据库已有的数据 + List existIds = new ArrayList(); + for (WxUser wxUser : userList) { + User account = new User(); + account.setUserId(wxUser.getName()); // 将姓名存储到userid字段 + account.setUsername(wxUser.getUserid()); // 企业微信userid,作为登录账号 + account.setPassword("password"); + account.setEmail(wxUser.getEmail()); + account.setPhone(wxUser.getMobile()); + account.setSex(StringUtils.isBlank(wxUser.getGender()) ? null : Integer.parseInt(wxUser.getGender())); + account.setStatus(1); + account.setPassword("szxgl.cn"); // 默认登录密码 + PasswordHelper.encryptPassword(account); + + existIds.add(wxUser.getUserid()); + if(dbUserIds.contains(wxUser.getUserid())){ + wxUserMapper.updateByUserId(wxUser); + }else{ + wxUserMapper.insertSelective(wxUser); + } + userService.updateQyWxUser(account); + } + // 删除当前企业微信不存在的用户 + if(existIds.size()>0)wxUserMapper.delOtherUsers(existIds); + } + + @Override + public void syncWxUser() { + try { + String url = Const.QYWX_API_DOMAIN + "/open/api/user/list?secretKey=yunlei.888"; + JSONObject jsonObject = HttpUtils.httpPost(url); + if(jsonObject !=null && jsonObject.getIntValue("ret") == 0){ + List userList = new ArrayList(); + JSONArray jsonArray = jsonObject.getJSONArray("list"); + if(jsonArray!=null && jsonArray.size() > 0){ + /* + for(int i=0; i list = new ArrayList(); + JSONArray jsonArray = jsonObject.getJSONArray("list"); + if(jsonArray!=null && jsonArray.size() > 0){ + for (Object object : jsonArray) { + WxDepartment wxDepartment = JSON.toJavaObject((JSONObject)object, WxDepartment.class); + list.add(wxDepartment); + } + } + if(list.size() > 0)deptMapper.insertBatch(list); + log.info("同步企业部门成功,部门数量为:"+list.size()); + }else{ + log.error("同步企业部门出错: "+jsonObject); + } + } catch (Exception e) { + log.error("同步企业部门异常", e); + } + } + + public static void main(String[] args) { + String jsonstr = "{\"id\":1,\"Name\":\"信广龙\",\"Order\":100000000,\"parentId\":5}"; + WxDepartment wxUser = JSON.toJavaObject(JSONObject.parseObject(jsonstr), WxDepartment.class); + System.out.println(JSON.toJSON(wxUser)); + } + +} diff --git a/src/main/java/com/nbclass/activity/task/ActivityRunner.java b/src/main/java/com/nbclass/activity/task/ActivityRunner.java new file mode 100644 index 0000000..d64ac40 --- /dev/null +++ b/src/main/java/com/nbclass/activity/task/ActivityRunner.java @@ -0,0 +1,25 @@ +package com.nbclass.activity.task; + +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +/** + * 启动时加载的任务 + * Created by Leon on 2019/12/11 15:10 + */ +@Component +@Order(1) +public class ActivityRunner implements ApplicationRunner { + + //@Resource + // private UserInfoService userInfoService; + + @SuppressWarnings("unused") + @Override + public void run(ApplicationArguments appArgs) throws Exception { + + } + +} diff --git a/src/main/java/com/nbclass/activity/task/MultiThreadScheduleTask.java b/src/main/java/com/nbclass/activity/task/MultiThreadScheduleTask.java new file mode 100644 index 0000000..cbbed20 --- /dev/null +++ b/src/main/java/com/nbclass/activity/task/MultiThreadScheduleTask.java @@ -0,0 +1,56 @@ +package com.nbclass.activity.task; + +import javax.annotation.Resource; + +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import com.nbclass.activity.service.WxUserService; + +import lombok.extern.slf4j.Slf4j; + +/** + * 定时任务 + * @author Leon + * @datetime 2020年6月2日 下午6:53:05 + */ +@Slf4j +@Component +@EnableScheduling // 1.开启定时任务 +@EnableAsync // 2.开启多线程/异步注解 +public class MultiThreadScheduleTask { + + @Resource + private WxUserService wxUserService; + + /** + * 定时同步企业微信用户 + */ + @Async + @Scheduled(cron="0 0 */6 * * ? ") // 每6小时运行一次 + public void syncWxUser() { + log.info("同步企业微信用户 ......"); + wxUserService.syncWxUser(); + } + + /** + * 定时同步企业微信部门 + */ + @Async + /* @Scheduled(fixedDelay = 1000*120) */ + @Scheduled(cron="0 0 1 * * ?") // 每天凌晨1点执行一次 + public void syncWxDepartment() { + log.info("同步企业微信部门 ......"); + wxUserService.syncWxDepartment(); + } + + /** + * 每天中午12点触发:0 0 12 * * ? + * 每天凌晨1点执行一次:0 0 1 * * ? + * 每隔1分钟执行一次:0 *\/1 * * * ? + */ + +} diff --git a/src/main/java/com/nbclass/aliyun/sdk/AliyunConstant.java b/src/main/java/com/nbclass/aliyun/sdk/AliyunConstant.java new file mode 100644 index 0000000..d81d7c4 --- /dev/null +++ b/src/main/java/com/nbclass/aliyun/sdk/AliyunConstant.java @@ -0,0 +1,40 @@ +package com.nbclass.aliyun.sdk; + +/** + * + * @author Leon + * @datetime 2019年4月12日 下午5:27:12 + */ +public class AliyunConstant { + + // 编码类型 + public static final String ENCODE_TYPE = "UTF-8"; + // 阿里云API签名方式,目前支持HMAC-SHA1 + public static final String ALGORITHM = "HmacSHA1"; + + // AccessKey ID + public static final String accessKeyId = "sSJ5t0yC1CaKhPJ4"; + // AccessKey Secret + public static final String accessKeySecret = "PsbdUTexU95BkiqO4ADELXpIaYdWGk"; + + // 访问域名 + public static final String access_doamin = "https://szxgl.oss-cn-shenzhen.aliyuncs.com/"; + // endpoint外网地址 + public static final String endpoint_ww = "oss-cn-shenzhen.aliyuncs.com"; + // endpoint内网地址 + public static final String endpoint_nw = "oss-cn-shenzhen-internal.aliyuncs.com"; + // 区域ID + public static final String regionId = "cn-shenzhen"; + // OSS区域 + public static final String ossLocation = "oss-cn-shenzhen"; + // OSS Bucket + public static final String ossBucketName = "szxgl"; + + + /** + * oss文件存放目录前缀 + */ + public static final String key_prefix = "xgl-cases/"; + + +} diff --git a/src/main/java/com/nbclass/aliyun/sdk/AliyunOSSUtils.java b/src/main/java/com/nbclass/aliyun/sdk/AliyunOSSUtils.java new file mode 100644 index 0000000..e5c1c07 --- /dev/null +++ b/src/main/java/com/nbclass/aliyun/sdk/AliyunOSSUtils.java @@ -0,0 +1,174 @@ +package com.nbclass.aliyun.sdk; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.file.Files; +import java.util.Date; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.aliyun.oss.OSSClient; +import com.aliyun.oss.OSSClientBuilder; +import com.nbclass.exception.ParameterException; +import com.nbclass.exception.ServiceException; +import com.nbclass.util.CommonUtils; + +/** + * 阿里云OSS操作 + * @author leiyun + * @datetime 2017年1月17日 下午3:58:16 + */ +public class AliyunOSSUtils { + + private static Logger logger = LoggerFactory.getLogger(AliyunOSSUtils.class); + + public static void main(String[] args) throws Exception { + boolean flag = true; + deleteObject(AliyunConstant.key_prefix + "casetype-h5/attachments/202005/20200529104151_wsblg.jpg"); + if(flag)return; + File file = new File("D:\\Temp\\images\\2.jpg"); + byte[] bt = Files.readAllBytes(file.toPath()); + String imgurl = uploadBytes("test","oppo.jpg", bt); + System.out.println("imgurl="+imgurl); + } + + /** + * 删除文件 + * @param key + */ + public static void deleteObject(String key){ + if(StringUtils.isBlank(key)) { + throw new ParameterException("key不能为空"); + } + OSSClient ossClient = null; + try { + // 创建OSSClient实例 + OSSClientBuilder builder = new OSSClientBuilder(); + // 国内服务器使用内网上传到oss + if(CommonUtils.isNw()){ + // 使用内网节点 + ossClient = (OSSClient) builder.build(AliyunConstant.endpoint_nw, AliyunConstant.accessKeyId, AliyunConstant.accessKeySecret); + }else{ + // 使用外网节点 + ossClient = (OSSClient) builder.build(AliyunConstant.endpoint_ww, AliyunConstant.accessKeyId, AliyunConstant.accessKeySecret); + } + ossClient.deleteObject(AliyunConstant.ossBucketName, key); + } catch (RuntimeException e) { + logger.error("阿里云OSS上传文件出错", e); + throw new ServiceException("网络异常,请稍候再试!"); + } finally{ + if(ossClient!=null){ + // 关闭OSSClient。 + ossClient.shutdown(); + } + } + } + + /** + * 上传Byte数组 + * @param filename + * @param content + * @return + */ + public static String uploadBytes(String filename, byte[] content){ + return uploadBytes(null, filename, content); + } + + public static String uploadBytes(String key, String filename, byte[] content){ + String url = null; + OSSClient ossClient = null; + try { + // 创建OSSClient实例 + // ossClient = new OSSClient(AliyunConstant.endpoint_nw, AliyunConstant.accessKeyId, AliyunConstant.accessKeySecret); + OSSClientBuilder builder = new OSSClientBuilder(); + + // 国内服务器使用内网上传到oss + if(CommonUtils.isNw()){ + logger.info("上传文件到OSS, 使用内网节点"); + ossClient = (OSSClient) builder.build(AliyunConstant.endpoint_nw, AliyunConstant.accessKeyId, AliyunConstant.accessKeySecret); + }else{ + logger.info("上传文件到OSS, 使用外网节点"); + ossClient = (OSSClient) builder.build(AliyunConstant.endpoint_ww, AliyunConstant.accessKeyId, AliyunConstant.accessKeySecret); + + } + + if(StringUtils.isNotBlank(key)){ + key = AliyunConstant.key_prefix + key +"/"; + }else{ + key = AliyunConstant.key_prefix; + } + // String daydir = Tools.getSimpleDate(new Date(), "yyyyMM")+"/"; + String daydir = ""; + key = key + daydir + filename; + ossClient.putObject(AliyunConstant.ossBucketName, key, new ByteArrayInputStream(content)); + url = AliyunConstant.access_doamin + key; + } catch (RuntimeException e) { + logger.error("阿里云OSS上传文件出错", e); + throw new ServiceException("网络异常,请稍候再试!"); + } finally{ + if(ossClient!=null){ + // 关闭OSSClient。 + ossClient.shutdown(); + } + } + return url; + } + + /** + * 上传网络流 + * @param filename + * @param sourceUrl + * @return + */ + public static String uploadByURL(String filename, String sourceUrl){ + if(StringUtils.isBlank(sourceUrl))return null; + sourceUrl = sourceUrl.trim(); + if(!sourceUrl.startsWith("http://") && !sourceUrl.startsWith("https://"))return null; + String url = null; + OSSClient ossClient = null; + InputStream inputStream = null; + try { + // 创建OSSClient实例 + // ossClient = new OSSClient(AliyunConstant.endpoint_ww, AliyunConstant.accessKeyId, AliyunConstant.accessKeySecret); + OSSClientBuilder builder = new OSSClientBuilder(); + + // 国内服务器使用内网上传到oss + if(CommonUtils.isNw()){ + logger.info("上传文件到OSS, 使用内网节点"); + ossClient = (OSSClient) builder.build(AliyunConstant.endpoint_nw, AliyunConstant.accessKeyId, AliyunConstant.accessKeySecret); + }else{ + logger.info("上传文件到OSS, 使用外网节点"); + ossClient = (OSSClient) builder.build(AliyunConstant.endpoint_ww, AliyunConstant.accessKeyId, AliyunConstant.accessKeySecret); + + } + + String daydir = CommonUtils.getSimpleDate(new Date(), "yyyyMM")+"/"; + String key = AliyunConstant.key_prefix + daydir + filename; + // 上传网络流 + inputStream = new URL(sourceUrl).openStream(); + ossClient.putObject(AliyunConstant.ossBucketName, key, inputStream); + + url = AliyunConstant.access_doamin + key; + } catch (IOException | RuntimeException e) { + logger.error("阿里云OSS上传文件出错", e); + throw new ServiceException("网络异常,请稍候再试!"); + } finally{ + if(ossClient!=null){ + ossClient.shutdown(); + } + try { + if(inputStream!=null)inputStream.close(); + inputStream=null; + } catch (IOException e) { + e.printStackTrace(); + } + } + return url; + } + +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/component/MyErrorAttributes.java b/src/main/java/com/nbclass/component/MyErrorAttributes.java new file mode 100644 index 0000000..8b03b51 --- /dev/null +++ b/src/main/java/com/nbclass/component/MyErrorAttributes.java @@ -0,0 +1,27 @@ +package com.nbclass.component; + +import java.util.Map; + +import org.springframework.boot.web.servlet.error.DefaultErrorAttributes; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.WebRequest; + +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +@Component +public class MyErrorAttributes extends DefaultErrorAttributes{ + + @Override + public Map getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) { + @SuppressWarnings("deprecation") + Map map = super.getErrorAttributes(webRequest, includeStackTrace); + @SuppressWarnings("unchecked") + Map ext = (Map)webRequest.getAttribute("ext", 0); + map.put("ext",ext); + return map; + } + +} diff --git a/src/main/java/com/nbclass/config/CorsConfig.java b/src/main/java/com/nbclass/config/CorsConfig.java new file mode 100644 index 0000000..49e6479 --- /dev/null +++ b/src/main/java/com/nbclass/config/CorsConfig.java @@ -0,0 +1,31 @@ +package com.nbclass.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * 跨域请求配置 + * @author Leon + * @datetime 2019年4月3日 下午4:45:49 + */ +@Configuration +public class CorsConfig { + + @Bean + public WebMvcConfigurer corsConfigurer() { + return new WebMvcConfigurer() { + @Override + public void addCorsMappings(CorsRegistry registry) { + registry + .addMapping("/api/**") // 允许跨域请求的地址 + .allowedOrigins("*") // 允许任何域请求 + .allowedMethods("*") // 允许任何方法(post、get等) + .allowedHeaders("*") // 允许任何头 + .allowCredentials(true) + ; + } + }; + } +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/config/DateConverter.java b/src/main/java/com/nbclass/config/DateConverter.java new file mode 100644 index 0000000..ec30ec2 --- /dev/null +++ b/src/main/java/com/nbclass/config/DateConverter.java @@ -0,0 +1,21 @@ +package com.nbclass.config; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.stereotype.Component; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +@Component +public class DateConverter implements Converter { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + @Override + public Date convert(String source) { + try { + return sdf.parse(source); + } catch (ParseException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/src/main/java/com/nbclass/config/DefaultViewConfig.java b/src/main/java/com/nbclass/config/DefaultViewConfig.java new file mode 100644 index 0000000..e434883 --- /dev/null +++ b/src/main/java/com/nbclass/config/DefaultViewConfig.java @@ -0,0 +1,23 @@ +package com.nbclass.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * 默认首页 + * @author Leon + * @datetime 2019年4月11日 下午5:14:24 + */ +@Configuration +public class DefaultViewConfig implements WebMvcConfigurer { + + @Override + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/").setViewName("forward:/index.html"); + registry.setOrder(Ordered.HIGHEST_PRECEDENCE); // 设置为最高级,哪怕其他controller里有映射(也就是 /)那么根据优先级,也会先加载这个配置 + WebMvcConfigurer.super.addViewControllers(registry); + } + +} diff --git a/src/main/java/com/nbclass/enums/ResponseStatus.java b/src/main/java/com/nbclass/enums/ResponseStatus.java new file mode 100644 index 0000000..b36b6b2 --- /dev/null +++ b/src/main/java/com/nbclass/enums/ResponseStatus.java @@ -0,0 +1,33 @@ +package com.nbclass.enums; + +/** + * @version V1.0 + * @date 2018年7月13日 + * @author superzheng + */ +public enum ResponseStatus { + + /** + * 返回状态 + */ + SUCCESS(200, "操作成功!"), + FORBIDDEN(403, "您没有权限访问!"), + NOT_FOUND(404, "资源不存在!"), + ERROR(500, "服务器内部错误!"); + + private Integer code; + private String message; + + ResponseStatus(Integer code, String message) { + this.code = code; + this.message = message; + } + + public Integer getCode() { + return code; + } + + public String getMessage() { + return message; + } +} diff --git a/src/main/java/com/nbclass/exception/CommonExceptionAdvice.java b/src/main/java/com/nbclass/exception/CommonExceptionAdvice.java new file mode 100644 index 0000000..bf58a2c --- /dev/null +++ b/src/main/java/com/nbclass/exception/CommonExceptionAdvice.java @@ -0,0 +1,81 @@ +package com.nbclass.exception; + +import java.io.IOException; +import java.io.PrintWriter; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.nbclass.vo.base.Result; +import org.apache.commons.lang3.StringUtils; +import org.apache.shiro.authz.AuthorizationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; + +import com.alibaba.fastjson.JSONObject; +import com.nbclass.util.CoreConst; + +/** + * 实现spring注解进行异常统一处理 + * @author Leon + * @datetime 2019年3月5日 下午6:08:54 + */ +@ControllerAdvice +public class CommonExceptionAdvice { + + private static Logger logger = LoggerFactory.getLogger(CommonExceptionAdvice.class); + + @ResponseStatus(HttpStatus.OK) + @ExceptionHandler(Exception.class) + @ResponseBody + public void defaultErrorHandler(HttpServletRequest request, HttpServletResponse response, Exception exception) { + response.setContentType("application/json;charset=UTF-8"); + response.setCharacterEncoding("UTF-8"); + String error = null; + try { + logger.info("RequestURL = "+request.getRequestURL()); + if(exception instanceof ParameterException || exception instanceof ServiceException || exception instanceof LogicalException){ + logger.info(exception.toString()); + }else if(exception instanceof org.springframework.web.multipart.MaxUploadSizeExceededException){ + error = "customer.file.upload.exceedlimit"; + }else{ + logger.error("系统异常: ", exception); + } + if(StringUtils.isBlank(error))error = exception.getMessage(); + + PrintWriter out = response.getWriter(); + if(StringUtils.isBlank(error)){ + response.setHeader("Content-Type", "text/html;charset=UTF-8"); + out.print("
Sorry, System error !
"); + }else{ + JSONObject json = new JSONObject(); + json.put(CoreConst.STATUS, CoreConst.STATUS_ERROR); + json.put(CoreConst.MSG, error); + out.print(json.toString()); + } + out.flush(); + out.close(); + } catch (IOException e) { + logger.error("统一处理异常错误", e); + } + } + + @ExceptionHandler(AuthorizationException.class) + public String handleAuth(HttpServletRequest request) { + request.setAttribute("javax.servlet.error.status_code",com.nbclass.enums.ResponseStatus.FORBIDDEN.getCode()); + return "forward:/error"; + } + + @ExceptionHandler(ParameterException.class) + @ResponseBody + public Result ParameterException(RuntimeException runtimeException){ + return Result.error(runtimeException.getMessage()); + } + +} + diff --git a/src/main/java/com/nbclass/exception/DataBaseException.java b/src/main/java/com/nbclass/exception/DataBaseException.java new file mode 100644 index 0000000..c03dad9 --- /dev/null +++ b/src/main/java/com/nbclass/exception/DataBaseException.java @@ -0,0 +1,26 @@ +package com.nbclass.exception; + +/** + * 数据库异常类 + * @author Leon + * @datetime 2019年3月31日 下午11:17:35 + */ +public class DataBaseException extends RuntimeException{ + + private static final long serialVersionUID = -7912461660403185962L; + + public DataBaseException(){ + } + + public DataBaseException(String message, Throwable cause){ + super(message, cause); + } + + public DataBaseException(String message){ + super(message); + } + + public DataBaseException(Throwable cause){ + super(cause); + } +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/exception/LogicalException.java b/src/main/java/com/nbclass/exception/LogicalException.java new file mode 100644 index 0000000..24df05b --- /dev/null +++ b/src/main/java/com/nbclass/exception/LogicalException.java @@ -0,0 +1,26 @@ +package com.nbclass.exception; + +/** + * 业务逻辑异常类 + * @author Leon + * @datetime 2019年3月31日 下午11:16:56 + */ +public class LogicalException extends RuntimeException{ + + private static final long serialVersionUID = 2494732724125452953L; + + public LogicalException(){ + } + + public LogicalException(String message, Throwable cause){ + super(message, cause); + } + + public LogicalException(String message){ + super(message); + } + + public LogicalException(Throwable cause){ + super(cause); + } +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/exception/ParameterException.java b/src/main/java/com/nbclass/exception/ParameterException.java new file mode 100644 index 0000000..6050923 --- /dev/null +++ b/src/main/java/com/nbclass/exception/ParameterException.java @@ -0,0 +1,26 @@ +package com.nbclass.exception; + +/** + * 参数错误异常类 + * @author Leon + * @datetime 2019年3月31日 下午11:01:35 + */ +public class ParameterException extends RuntimeException{ + + private static final long serialVersionUID = 7936887727544416780L; + + public ParameterException(){ + } + + public ParameterException(String message, Throwable cause){ + super(message, cause); + } + + public ParameterException(String message){ + super(message); + } + + public ParameterException(Throwable cause){ + super(cause); + } +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/exception/ServiceException.java b/src/main/java/com/nbclass/exception/ServiceException.java new file mode 100644 index 0000000..994d5af --- /dev/null +++ b/src/main/java/com/nbclass/exception/ServiceException.java @@ -0,0 +1,26 @@ +package com.nbclass.exception; + +/** + * 服务异常类 + * @author Leon + * @datetime 2019年3月31日 下午11:16:09 + */ +public class ServiceException extends RuntimeException{ + + private static final long serialVersionUID = 3794850430751334041L; + + public ServiceException(){ + } + + public ServiceException(String message, Throwable cause){ + super(message, cause); + } + + public ServiceException(String message){ + super(message); + } + + public ServiceException(Throwable cause){ + super(cause); + } +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/holder/SpringContextHolder.java b/src/main/java/com/nbclass/holder/SpringContextHolder.java new file mode 100644 index 0000000..4267b94 --- /dev/null +++ b/src/main/java/com/nbclass/holder/SpringContextHolder.java @@ -0,0 +1,53 @@ +package com.nbclass.holder; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +@Component +public class SpringContextHolder implements ApplicationContextAware { + + private static ApplicationContext appContext = null; + + /** + * 通过name获取 Bean. + * + * @param name + * @return + */ + public static Object getBean(String name) { + return appContext.getBean(name); + + } + + /** + * 通过class获取Bean. + * + * @param clazz + * @param + * @return + */ + public static T getBean(Class clazz) { + return appContext.getBean(clazz); + } + + /** + * 通过name,以及Clazz返回指定的Bean + * + * @param name + * @param clazz + * @param + * @return + */ + public static T getBean(String name, Class clazz) { + return appContext.getBean(name, clazz); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + if (appContext == null) { + appContext = applicationContext; + } + } +} diff --git a/src/main/java/com/nbclass/shiro/MyShiroRealm.java b/src/main/java/com/nbclass/shiro/MyShiroRealm.java new file mode 100644 index 0000000..840b419 --- /dev/null +++ b/src/main/java/com/nbclass/shiro/MyShiroRealm.java @@ -0,0 +1,156 @@ +package com.nbclass.shiro; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +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.LockedAccountException; +import org.apache.shiro.authc.SimpleAuthenticationInfo; +import org.apache.shiro.authc.UnknownAccountException; +import org.apache.shiro.authz.AuthorizationException; +import org.apache.shiro.authz.AuthorizationInfo; +import org.apache.shiro.authz.SimpleAuthorizationInfo; +import org.apache.shiro.mgt.RealmSecurityManager; +import org.apache.shiro.realm.AuthorizingRealm; +import org.apache.shiro.session.Session; +import org.apache.shiro.session.mgt.eis.SessionDAO; +import org.apache.shiro.subject.PrincipalCollection; +import org.apache.shiro.subject.SimplePrincipalCollection; +import org.apache.shiro.subject.support.DefaultSubjectContext; +import org.apache.shiro.util.ByteSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import com.nbclass.system.model.User; +import com.nbclass.system.service.PermissionService; +import com.nbclass.system.service.RoleService; +import com.nbclass.system.service.UserService; +import com.nbclass.util.CoreConst; +import com.nbclass.util.IpUtil; + +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +public class MyShiroRealm extends AuthorizingRealm { + + @Autowired + private UserService userService; + @Autowired + private RoleService roleService; + @Autowired + private PermissionService permissionService; + + //@Autowired + //private RedisSessionDAO redisSessionDAO; + @Autowired + private SessionDAO sessionDAO; + + //授权 + @Override + protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { + if(principals == null){ + throw new AuthorizationException("principals should not be null"); + } + User user = (User) principals.getPrimaryPrincipal(); + SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); + info.setRoles(roleService.findRoleByUserId(user.getUserId())); + info.setStringPermissions(permissionService.findPermsByUserId(user.getUserId())); + return info; + } + + //认证 + @Override + protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { + //获取用户的输入的账号. + String username = (String)token.getPrincipal(); + User user = userService.selectByUsername(username); + if(user==null) { + throw new UnknownAccountException(); + } + if (CoreConst.STATUS_INVALID.equals(user.getStatus())) { + // 帐号锁定 + throw new LockedAccountException(); + } + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + // 把ip放入user存入redis缓存里 + user.setLoginIpAddress(IpUtil.getIpAddr(request)); + SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo( + user, + user.getPassword(), + ByteSource.Util.bytes(user.getCredentialsSalt()), + getName() + ); + return authenticationInfo; + } + + /**清除认证信息*/ + public void removeCachedAuthenticationInfo(List userIds) { + if(null == userIds || userIds.size() == 0) { + return ; + } + List list = getSpcListByUserIds(userIds); + RealmSecurityManager securityManager = + (RealmSecurityManager) SecurityUtils.getSecurityManager(); + MyShiroRealm realm = (MyShiroRealm)securityManager.getRealms().iterator().next(); + for (SimplePrincipalCollection simplePrincipalCollection : list) { + realm.clearCachedAuthenticationInfo(simplePrincipalCollection); + } + } + + /** + * 根据userId 清除当前session存在的用户的权限缓存 + * @param userIds 已经修改了权限的userId + */ + public void clearAuthorizationByUserId(List userIds){ + if(null == userIds || userIds.size() == 0) { + return ; + } + List list = getSpcListByUserIds(userIds); + RealmSecurityManager securityManager = + (RealmSecurityManager) SecurityUtils.getSecurityManager(); + MyShiroRealm realm = (MyShiroRealm)securityManager.getRealms().iterator().next(); + for (SimplePrincipalCollection simplePrincipalCollection : list) { + realm.clearCachedAuthorizationInfo(simplePrincipalCollection); + } + } + + /** + * 根据用户id获取所有spc + * @param userIds 已经修改了权限的userId + */ + private List getSpcListByUserIds(List userIds){ + //获取所有session + // Collection sessions = redisSessionDAO.getActiveSessions(); + Collection sessions = sessionDAO.getActiveSessions(); + //定义返回 + List list = new ArrayList(); + for (Session session:sessions){ + //获取session登录信息。 + Object obj = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY); + if(null != obj && obj instanceof SimplePrincipalCollection){ + //强转 + SimplePrincipalCollection spc = (SimplePrincipalCollection)obj; + //判断用户,匹配用户ID。 + obj = spc.getPrimaryPrincipal(); + if(null != obj && obj instanceof User){ + User user = (User) obj; + System.out.println("user:"+user); + //比较用户ID,符合即加入集合 + if(null != user && userIds.contains(user.getUserId())){ + list.add(spc); + } + } + } + } + return list; + } +} diff --git a/src/main/java/com/nbclass/shiro/PermsService.java b/src/main/java/com/nbclass/shiro/PermsService.java new file mode 100644 index 0000000..0763174 --- /dev/null +++ b/src/main/java/com/nbclass/shiro/PermsService.java @@ -0,0 +1,19 @@ +package com.nbclass.shiro; + +import org.apache.shiro.SecurityUtils; +import org.springframework.stereotype.Component; + +/** + * js调用 thymeleaf 实现按钮权限 + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +@Component("perms") +public class PermsService +{ + public boolean hasPerm(String permission) + { + return SecurityUtils.getSubject().isPermitted(permission); + } +} diff --git a/src/main/java/com/nbclass/shiro/ShiroService.java b/src/main/java/com/nbclass/shiro/ShiroService.java new file mode 100644 index 0000000..61422f0 --- /dev/null +++ b/src/main/java/com/nbclass/shiro/ShiroService.java @@ -0,0 +1,125 @@ +package com.nbclass.shiro; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.apache.shiro.spring.web.ShiroFilterFactoryBean; +import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager; +import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver; +import org.apache.shiro.web.servlet.AbstractShiroFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.nbclass.holder.SpringContextHolder; +import com.nbclass.system.model.Permission; +import com.nbclass.system.service.PermissionService; +import com.nbclass.util.CoreConst; + +/** + * + * @author Leon + * @datetime 2019年4月1日 下午2:47:53 + */ +@Service +public class ShiroService { + + @Autowired + private PermissionService permissionService; + + /** + * 初始化加载权限 + * @return + */ + public Map loadFilterChainDefinitions() { + // 权限控制map.从数据库获取 + Map filterChainDefinitionMap = new LinkedHashMap(); + + filterChainDefinitionMap.put("/register", "anon"); + filterChainDefinitionMap.put("/login", "anon"); + filterChainDefinitionMap.put("/error/**", "anon"); + filterChainDefinitionMap.put("/kickout", "anon"); + /*filterChainDefinitionMap.put("/logout", "logout");*/ + filterChainDefinitionMap.put("/verificationCode", "anon"); // 登录验证码 + filterChainDefinitionMap.put("/qywx/qrLogin", "anon"); // 企业微信登录页面 + + // 前端接口放行 + filterChainDefinitionMap.put("/front/api/**", "anon"); // 前端接口 + filterChainDefinitionMap.put("/", "anon"); // 网站首页 + filterChainDefinitionMap.put("/caseType/**", "anon"); // 数据字典 + filterChainDefinitionMap.put("/wx/**", "anon"); // wx接口 + filterChainDefinitionMap.put("/comment/**", "anon"); // wx接口 + filterChainDefinitionMap.put("/console/content/saveScore", "anon"); // + + filterChainDefinitionMap.put("/mobile/*.html", "wxWebOAuth"); // 移动端页面授权拦截 + + // 静态资源按目录排除 + filterChainDefinitionMap.put("/css/**","anon"); + filterChainDefinitionMap.put("/js/**","anon"); + filterChainDefinitionMap.put("/img/**","anon"); + filterChainDefinitionMap.put("/libs/**","anon"); + // 静态资源按后缀排除 + filterChainDefinitionMap.put("/**/*.ico", "anon"); + filterChainDefinitionMap.put("/**/*.htm", "anon"); + filterChainDefinitionMap.put("/**/*.html", "anon"); + filterChainDefinitionMap.put("/**/*.css", "anon"); + filterChainDefinitionMap.put("/**/*.js", "anon"); + filterChainDefinitionMap.put("/**/*.jpg", "anon"); + filterChainDefinitionMap.put("/**/*.png", "anon"); + filterChainDefinitionMap.put("/**/*.gif", "anon"); + filterChainDefinitionMap.put("/**/*.webp", "anon"); + filterChainDefinitionMap.put("/**/*.ttf", "anon"); + filterChainDefinitionMap.put("/**/*.woff", "anon"); + filterChainDefinitionMap.put("/**/*.woff2", "anon"); + filterChainDefinitionMap.put("/**/*.mp3", "anon"); + filterChainDefinitionMap.put("/**/*.mp4", "anon"); + filterChainDefinitionMap.put("/**/*.txt", "anon"); + + + List permissionList = permissionService.selectAll(CoreConst.STATUS_VALID); + for(Permission permission : permissionList){ + if (StringUtils.isNotBlank(permission.getUrl())&& StringUtils.isNotBlank(permission.getPerms())) { + String perm = "perms[" + permission.getPerms()+ "]"; + filterChainDefinitionMap.put(permission.getUrl(),perm+",kickout"); + } + } + + filterChainDefinitionMap.put("/**", "user,kickout"); + + return filterChainDefinitionMap; + } + + /** + * 添加/修改/删除 后 重新加载权限 + */ + public void updatePermission() { + ShiroFilterFactoryBean shiroFilterFactoryBean = SpringContextHolder.getBean(ShiroFilterFactoryBean.class); + synchronized (shiroFilterFactoryBean) { + AbstractShiroFilter shiroFilter = null; + try { + shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject(); + } catch (Exception e) { + throw new RuntimeException("get ShiroFilter from shiroFilterFactoryBean error!"); + } + + PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter + .getFilterChainResolver(); + DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver + .getFilterChainManager(); + + // 清空老的权限控制 + manager.getFilterChains().clear(); + + shiroFilterFactoryBean.getFilterChainDefinitionMap().clear(); + shiroFilterFactoryBean.setFilterChainDefinitionMap(loadFilterChainDefinitions()); + // 重新构建生成 + Map chains = shiroFilterFactoryBean.getFilterChainDefinitionMap(); + for (Map.Entry entry : chains.entrySet()) { + String url = entry.getKey(); + String chainDefinition = entry.getValue().trim().replace(" ", ""); + manager.createChain(url, chainDefinition); + } + } + } +} diff --git a/src/main/java/com/nbclass/shiro/config/LoginType.java b/src/main/java/com/nbclass/shiro/config/LoginType.java new file mode 100644 index 0000000..e283d32 --- /dev/null +++ b/src/main/java/com/nbclass/shiro/config/LoginType.java @@ -0,0 +1,22 @@ +package com.nbclass.shiro.config; + +/** + * 登录类型 + * @author Leon + * @datetime 2019年4月22日 下午8:48:14 + */ +public enum LoginType { + + PASSWORD("password"), // 密码登录 + NOPASSWD("nopassword"); // 免密登录 + + private String code;// 状态值 + + private LoginType(String code) { + this.code = code; + } + public String getCode () { + return code; + } + +} diff --git a/src/main/java/com/nbclass/shiro/config/MyHashedCredentialsMatcher.java b/src/main/java/com/nbclass/shiro/config/MyHashedCredentialsMatcher.java new file mode 100644 index 0000000..578e724 --- /dev/null +++ b/src/main/java/com/nbclass/shiro/config/MyHashedCredentialsMatcher.java @@ -0,0 +1,19 @@ +package com.nbclass.shiro.config; + +import org.apache.shiro.authc.AuthenticationInfo; +import org.apache.shiro.authc.AuthenticationToken; +import org.apache.shiro.authc.credential.HashedCredentialsMatcher; + +public class MyHashedCredentialsMatcher extends HashedCredentialsMatcher { + + @Override + public boolean doCredentialsMatch(AuthenticationToken authcToken, AuthenticationInfo info) { + MyUsernamePasswordToken tk = (MyUsernamePasswordToken) authcToken; + // 如果是免密登录直接返回true + if(tk.getType().equals(LoginType.NOPASSWD)){ + return true; + } + // 不是免密登录,调用父类的方法 + return super.doCredentialsMatch(tk, info); + } +} diff --git a/src/main/java/com/nbclass/shiro/config/MyUsernamePasswordToken.java b/src/main/java/com/nbclass/shiro/config/MyUsernamePasswordToken.java new file mode 100644 index 0000000..b295e7d --- /dev/null +++ b/src/main/java/com/nbclass/shiro/config/MyUsernamePasswordToken.java @@ -0,0 +1,45 @@ +package com.nbclass.shiro.config; + +import org.apache.shiro.authc.UsernamePasswordToken; + +/** + * + * @author Leon + * @datetime 2019年4月22日 下午8:59:23 + */ +public class MyUsernamePasswordToken extends UsernamePasswordToken { + + private static final long serialVersionUID = 1744966815127132051L; + + private LoginType type; + + public MyUsernamePasswordToken() { + super(); + } + + public MyUsernamePasswordToken(String username, String password, LoginType type, boolean rememberMe, String host) { + super(username, password, rememberMe, host); + this.type = type; + } + + /**免密登录*/ + public MyUsernamePasswordToken(String username) { + super(username, "", false, null); + this.type = LoginType.NOPASSWD; + } + + /**账号密码登录*/ + public MyUsernamePasswordToken(String username, String password) { + super(username, password, false, null); + this.type = LoginType.PASSWORD; + } + + public LoginType getType() { + return type; + } + + public void setType(LoginType type) { + this.type = type; + } + +} diff --git a/src/main/java/com/nbclass/shiro/config/ShiroConfig.java b/src/main/java/com/nbclass/shiro/config/ShiroConfig.java new file mode 100644 index 0000000..9091530 --- /dev/null +++ b/src/main/java/com/nbclass/shiro/config/ShiroConfig.java @@ -0,0 +1,267 @@ +package com.nbclass.shiro.config; + +import java.util.LinkedHashMap; +import java.util.Map; + +import javax.servlet.Filter; + +import org.apache.shiro.authc.credential.HashedCredentialsMatcher; +import org.apache.shiro.cache.MemoryConstrainedCacheManager; +import org.apache.shiro.codec.Base64; +import org.apache.shiro.mgt.SecurityManager; +import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO; +import org.apache.shiro.session.mgt.eis.SessionDAO; +import org.apache.shiro.spring.LifecycleBeanPostProcessor; +import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; +import org.apache.shiro.spring.web.ShiroFilterFactoryBean; +import org.apache.shiro.web.mgt.CookieRememberMeManager; +import org.apache.shiro.web.mgt.DefaultWebSecurityManager; +import org.apache.shiro.web.servlet.SimpleCookie; +import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.nbclass.shiro.MyShiroRealm; +import com.nbclass.shiro.ShiroService; +import com.nbclass.shiro.filter.KickoutSessionControlFilter; +import com.nbclass.shiro.filter.MobilePageOAuthFilter; +import com.nbclass.shiro.filter.ResetPwdUrlFilter; + +import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; + +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +@Configuration +public class ShiroConfig { + + @Autowired + private ShiroService shiroService; + + /* + @Value("${spring.redis.host}") + private String host; + + @Value("${spring.redis.port}") + private int port; + + @Value("${spring.redis.timeout}") + private int timeout; + + @Value("${spring.redis.password}") + private String password; + */ + + @Bean + public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() { + return new LifecycleBeanPostProcessor(); + } + + /** + * ShiroDialect,为了在thymeleaf里使用shiro的标签的bean + * @return + */ + @Bean + public ShiroDialect shiroDialect() { + return new ShiroDialect(); + } + /** + * ShiroFilterFactoryBean 处理拦截资源文件问题。 + * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,因为在 + * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager + * + Filter Chain定义说明 + 1、一个URL可以配置多个Filter,使用逗号分隔 + 2、当设置多个过滤器时,全部验证通过,才视为通过 + 3、部分过滤器可指定参数,如perms,roles + * + */ + @Bean + public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager){ + ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); + // 必须设置 SecurityManager + shiroFilterFactoryBean.setSecurityManager(securityManager); + // 登录url + shiroFilterFactoryBean.setLoginUrl("/login"); + // 登录成功后要跳转的链接 + shiroFilterFactoryBean.setSuccessUrl("/index"); + //未授权界面; + shiroFilterFactoryBean.setUnauthorizedUrl("/error/403"); + //自定义拦截器 + Map filtersMap = new LinkedHashMap(); + //限制同一帐号同时在线的个数。 + filtersMap.put("kickout", kickoutSessionControlFilter()); + // 找回密码链接拦截验证 + filtersMap.put("resetPwdUrl", new ResetPwdUrlFilter()); + // 移动端页面授权拦截器 + filtersMap.put("wxWebOAuth", new MobilePageOAuthFilter()); + + shiroFilterFactoryBean.setFilters(filtersMap); + //拦截器. + Map filterChainDefinitionMap = shiroService.loadFilterChainDefinitions(); + shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); + return shiroFilterFactoryBean; + } + + /** + * cookie对象; + * @return + */ + public SimpleCookie rememberMeCookie(){ + //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe + SimpleCookie simpleCookie = new SimpleCookie("rememberMe"); + // + simpleCookie.setMaxAge(2592000); + return simpleCookie; + } + + /** + * cookie管理对象;记住我功能 + * @return + */ + public CookieRememberMeManager rememberMeManager(){ + CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); + cookieRememberMeManager.setCookie(rememberMeCookie()); + //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位) + cookieRememberMeManager.setCipherKey(Base64.decode("3AvVhmFLUs0KTA3Kprsdag==")); + return cookieRememberMeManager; + } + + @Bean(name = "securityManager") + public SecurityManager securityManager(){ + DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); + //设置realm. + securityManager.setRealm(myShiroRealm()); + /*记住我*/ + securityManager.setRememberMeManager(rememberMeManager()); + // 自定义缓存实现 使用redis + // securityManager.setCacheManager(redisCacheManager()); + securityManager.setCacheManager(new MemoryConstrainedCacheManager()); //Shiro默认提供了CacheManager的简单内存实现MemoryConstrainedCacheManager,可用于生产环境; + // 自定义session管理 使用redis + securityManager.setSessionManager(sessionManager()); + return securityManager; + } + + @Bean + public MyShiroRealm myShiroRealm(){ + MyShiroRealm myShiroRealm = new MyShiroRealm(); + myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher()); + return myShiroRealm; + } + + /** + * 凭证匹配器 + * ) + * @return + */ + @Bean + public HashedCredentialsMatcher hashedCredentialsMatcher(){ + // HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); + MyHashedCredentialsMatcher hashedCredentialsMatcher = new MyHashedCredentialsMatcher(); // 使用自定义匹配器,方便使用免密登录 + hashedCredentialsMatcher.setHashAlgorithmName("md5"); + hashedCredentialsMatcher.setHashIterations(2); + return hashedCredentialsMatcher; + } + + + /** + * 开启shiro aop注解支持. + * 使用代理方式;所以需要开启代码支持; + * @param securityManager + * @return + */ + @Bean + public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){ + AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); + authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); + return authorizationAttributeSourceAdvisor; + } + + /** + * 配置shiro redisManager + * 使用的是shiro-redis开源插件 + * @return + */ + /* + public RedisManager redisManager() { + RedisManager redisManager = new RedisManager(); + redisManager.setHost(host+":"+port); + // redisManager.setPort(port); + // 配置缓存过期时间 + // redisManager.setExpire(1800); + + redisManager.setTimeout(timeout); + redisManager.setPassword(password); + return redisManager; + } + */ + + /** + * cacheManager 缓存 redis实现 + * 使用的是shiro-redis开源插件 + * @return + */ + /* + @Bean + public RedisCacheManager redisCacheManager() { + RedisCacheManager redisCacheManager = new RedisCacheManager(); + redisCacheManager.setRedisManager(redisManager()); + return redisCacheManager; + } + */ + + /** + * RedisSessionDAO shiro sessionDao层的实现 通过redis + * 使用的是shiro-redis开源插件 + */ + /* + @Bean + public RedisSessionDAO redisSessionDAO() { + RedisSessionDAO redisSessionDAO = new RedisSessionDAO(); + redisSessionDAO.setRedisManager(redisManager()); + return redisSessionDAO; + } + */ + @Bean + public SessionDAO sessionDAO() { + // return new MemorySessionDAO(); //使用默认的MemorySessionDAO + return new EnterpriseCacheSessionDAO(); + } + + /** + * shiro session的管理 + */ + @Bean + public DefaultWebSessionManager sessionManager() { + DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); + // sessionManager.setSessionDAO(redisSessionDAO()); + sessionManager.setSessionDAO(sessionDAO()); + return sessionManager; + } + /** + * 限制同一账号登录同时登录人数控制 + * @return + */ + public KickoutSessionControlFilter kickoutSessionControlFilter(){ + KickoutSessionControlFilter kickoutSessionControlFilter = new KickoutSessionControlFilter(); + //使用cacheManager获取相应的cache来缓存用户登录的会话;用于保存用户—会话之间的关系的; + //这里我们还是用之前shiro使用的redisManager()实现的cacheManager()缓存管理 + //也可以重新另写一个,重新配置缓存时间之类的自定义缓存属性 + // kickoutSessionControlFilter.setCacheManager(redisCacheManager()); + kickoutSessionControlFilter.setCacheManager(new MemoryConstrainedCacheManager()); //Shiro默认提供了CacheManager的简单内存实现MemoryConstrainedCacheManager,可用于生产环境; + //用于根据会话ID,获取会话进行踢出操作的; + kickoutSessionControlFilter.setSessionManager(sessionManager()); + //是否踢出后来登录的,默认是false;即后者登录的用户踢出前者登录的用户;踢出顺序。 + kickoutSessionControlFilter.setKickoutAfter(false); + //同一个用户最大的会话数,默认5;比如5的意思是同一个用户允许最多同时五个人登录; + kickoutSessionControlFilter.setMaxSession(5); + //被踢出后重定向到的地址; + kickoutSessionControlFilter.setKickoutUrl("/kickout"); + return kickoutSessionControlFilter; + } + + +} diff --git a/src/main/java/com/nbclass/shiro/filter/KickoutSessionControlFilter.java b/src/main/java/com/nbclass/shiro/filter/KickoutSessionControlFilter.java new file mode 100644 index 0000000..bf1dbc8 --- /dev/null +++ b/src/main/java/com/nbclass/shiro/filter/KickoutSessionControlFilter.java @@ -0,0 +1,175 @@ +package com.nbclass.shiro.filter; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Serializable; +import java.util.Deque; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; + +import org.apache.shiro.cache.Cache; +import org.apache.shiro.cache.CacheManager; +import org.apache.shiro.session.Session; +import org.apache.shiro.session.mgt.DefaultSessionKey; +import org.apache.shiro.session.mgt.SessionManager; +import org.apache.shiro.subject.Subject; +import org.apache.shiro.web.filter.AccessControlFilter; +import org.apache.shiro.web.util.WebUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.fastjson.JSON; +import com.nbclass.system.model.User; + +/** + * @author superzheng + * @date 2018-07-18 + */ +public class KickoutSessionControlFilter extends AccessControlFilter { + + protected static Logger logger = LoggerFactory.getLogger(KickoutSessionControlFilter.class); + + /** + * 踢出后到的地址 + */ + private String kickoutUrl; + /** + * 踢出之前登录的/之后登录的用户 默认踢出之前登录的用户 + */ + private boolean kickoutAfter = false; + /** + * 同一个帐号最大会话数 默认5 + */ + private int maxSession = 5; + + private SessionManager sessionManager; + private Cache> cache; + + public void setKickoutUrl(String kickoutUrl) { + this.kickoutUrl = kickoutUrl; + } + + public void setKickoutAfter(boolean kickoutAfter) { + this.kickoutAfter = kickoutAfter; + } + + public void setMaxSession(int maxSession) { + this.maxSession = maxSession; + } + + public void setSessionManager(SessionManager sessionManager) { + this.sessionManager = sessionManager; + } + + public void setCacheManager(CacheManager cacheManager) { + this.cache = cacheManager.getCache("shiro_redis_cache"); + } + + @Override + protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { + return false; + } + + @Override + protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { + // HttpServletRequest req = (HttpServletRequest) request; + + Subject subject = getSubject(request, response); + if(!subject.isAuthenticated() && !subject.isRemembered()) { + //如果没有登录,直接进行之后的流程 + return true; + } + + + Session session = subject.getSession(); + User user = (User) subject.getPrincipal(); + String username = user.getUsername(); + Serializable sessionId = session.getId(); + + //读取缓存 没有就存入 + Deque deque = cache.get(username); + + //如果此用户没有session队列,也就是还没有登录过,缓存中没有 + //就new一个空队列,不然deque对象为空,会报空指针 + if(deque==null){ + deque = new LinkedList(); + } + + //如果队列里没有此sessionId,且用户没有被踢出;放入队列 + if(!deque.contains(sessionId) && session.getAttribute("kickout") == null) { + //将sessionId存入队列 + deque.push(sessionId); + //将用户的sessionId队列缓存 + cache.put(username, deque); + } + + //如果队列里的sessionId数超出最大会话数,开始踢人 + while(deque.size() > maxSession) { + Serializable kickoutSessionId = null; + //如果踢出后者 + if(kickoutAfter) { + kickoutSessionId = deque.removeFirst(); + //踢出后再更新下缓存队列 + cache.put(username, deque); + } else { //否则踢出前者 + kickoutSessionId = deque.removeLast(); + //踢出后再更新下缓存队列 + cache.put(username, deque); + } + + + + try { + //获取被踢出的sessionId的session对象 + Session kickoutSession = sessionManager.getSession(new DefaultSessionKey(kickoutSessionId)); + if(kickoutSession != null) { + //设置会话的kickout属性表示踢出了 + kickoutSession.setAttribute("kickout", true); + } + } catch (Exception e) {//ignore exception + } + } + + //如果被踢出了,直接退出,重定向到踢出后的地址 + if ((Boolean)session.getAttribute("kickout")!=null&&(Boolean)session.getAttribute("kickout") == true) { + //会话被踢出了 + try { + //退出登录 + subject.logout(); + } catch (Exception e) { //ignore + } + saveRequest(request); + + Map resultMap = new HashMap(2); + //判断是不是Ajax请求 + if ("XMLHttpRequest".equalsIgnoreCase(((HttpServletRequest) request).getHeader("X-Requested-With"))) { + resultMap.put("user_status", "300"); + resultMap.put("message", "您已经在其他地方登录,请重新登录!"); + //输出json串 + out(response, resultMap); + }else{ + //重定向 + WebUtils.issueRedirect(request, response, kickoutUrl); + } + return false; + } + return true; + } + private void out(ServletResponse hresponse, Map resultMap) + throws IOException { + try { + hresponse.setCharacterEncoding("UTF-8"); + PrintWriter out = hresponse.getWriter(); + out.println(JSON.toJSONString(resultMap)); + out.flush(); + out.close(); + } catch (Exception e) { + System.err.println("KickoutSessionFilter.class 输出JSON异常,可以忽略。"); + } + } +} diff --git a/src/main/java/com/nbclass/shiro/filter/MobilePageOAuthFilter.java b/src/main/java/com/nbclass/shiro/filter/MobilePageOAuthFilter.java new file mode 100644 index 0000000..0e8c3f3 --- /dev/null +++ b/src/main/java/com/nbclass/shiro/filter/MobilePageOAuthFilter.java @@ -0,0 +1,94 @@ +package com.nbclass.shiro.filter; + +import com.alibaba.fastjson.JSONObject; +import com.nbclass.util.CommonUtils; +import com.nbclass.util.HttpUtils; +import com.nbclass.util.WebUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.shiro.web.filter.AccessControlFilter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.net.URLEncoder; +import java.util.UUID; + +/** + * 移动端页面授权拦截器 + * @author Leon + * @datetime 2019年9月2日 上午10:55:53 + */ +public class MobilePageOAuthFilter extends AccessControlFilter { + + protected static Logger logger = LoggerFactory.getLogger(MobilePageOAuthFilter.class); + + private static final String WX_API_DOMAIN = "http://www.qiween.cn/wxapi"; + + private static final String OAUTH2_SCOPE = "snsapi_base"; + + @Override + protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object mappedValue) throws Exception { + HttpServletRequest request = (HttpServletRequest) servletRequest; + HttpServletResponse response = (HttpServletResponse) servletResponse; + response.setHeader("Cache-Control", "no-store"); + + String userAgent = StringUtils.trimToEmpty(request.getHeader("User-Agent")).toLowerCase(); + if(!userAgent.contains("micromessenger")){ // pc端打开不拦截 + return true; + } + + String openId = WebUtils.getValueFromCookie(request, "cookie_key_s3_vote_uid"); + String s_openId = (String) request.getSession().getAttribute("sk_wx_openid"); + if(StringUtils.isNotBlank(openId) && StringUtils.isNotBlank(s_openId)){ + return true; + } + + String httpRequestFullURL = getHttpRequestFullURL(request); + String redirectUrl = WX_API_DOMAIN+"/api/oauth?redirect_uri=" + URLEncoder.encode(httpRequestFullURL, "UTF-8")+"&scope="+OAUTH2_SCOPE; + String code = request.getParameter("code"); + if(StringUtils.isNotBlank(code)){ + String url = WX_API_DOMAIN+"/api/oauthInfo?code="+code+"&scope="+OAUTH2_SCOPE; + try { + JSONObject json = HttpUtils.httpGet(url); + if(json == null || json.getIntValue("errcode") == 40029 || json.getIntValue("errcode") == 40163 + || (StringUtils.isNotBlank(json.getString("msg")) && (json.getString("msg").contains("40029") || json.getString("msg").contains("40163"))) ){ + logger.info("微信授权失败,将重新跳转授权......"); + redirectUrl = CommonUtils.removeParamValue(redirectUrl, "code"); + response.sendRedirect(redirectUrl); + return false; + } + logger.info("微信授权获取到用户信息: "+json); + openId = json.getString("openId"); + WebUtils.addCookie(response, "cookie_key_s3_vote_uid", openId, 3600 * 24 * 7); + request.getSession().setAttribute("sk_wx_openid", openId); + } catch (Exception e) { + logger.error("授权失败:", e); + openId = UUID.randomUUID().toString().replace("-", ""); + WebUtils.addCookie(response, "cookie_key_s3_vote_uid", openId, 3600 * 24 * 7); // 7天有效期 + } + }else{ + response.sendRedirect(redirectUrl); + return false; + } + return true; + } + + @Override + protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { + return false; + } + + public static String getHttpRequestFullURL(HttpServletRequest request) { + StringBuffer requestURL = request.getRequestURL(); + String queryString = request.getQueryString(); + if (queryString == null) { + return requestURL.toString(); + } else { + return requestURL.append('?').append(queryString).toString(); + } + } + +} diff --git a/src/main/java/com/nbclass/shiro/filter/ResetPwdUrlFilter.java b/src/main/java/com/nbclass/shiro/filter/ResetPwdUrlFilter.java new file mode 100644 index 0000000..6146d15 --- /dev/null +++ b/src/main/java/com/nbclass/shiro/filter/ResetPwdUrlFilter.java @@ -0,0 +1,79 @@ +package com.nbclass.shiro.filter; + +import org.apache.commons.lang3.StringUtils; +import org.apache.shiro.web.filter.AccessControlFilter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import java.io.IOException; +import java.io.PrintWriter; + +/** + * 找回密码链接验证 + * @author Leon + * @datetime 2019年5月2日 下午6:59:01 + */ +public class ResetPwdUrlFilter extends AccessControlFilter { + + protected static Logger logger = LoggerFactory.getLogger(ResetPwdUrlFilter.class); + + @Override + protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { + logger.info("ResetPwdUrlFilter.isAccessAllowed ......"); + String verifyCode = request.getParameter("verifyCode"); + if(StringUtils.isBlank(verifyCode)){ + logger.info("进入重置密码页面,参数[verifyCode]为null ......"); + outPrintError(response, "The requested URL was not found on this server."); + return false; + } + /* + CustomerMapper customerMapper = SpringContextHolder.getBean(CustomerMapper.class); + try{ + // 查询验证码是否有效,半小时重置密码才有效 + CustomerResetPwd customerResetPwd = customerMapper.selectResetPwd(verifyCode); + if(customerResetPwd == null || customerResetPwd.getStatus() == null || customerResetPwd.getStatus() != 1){ + logger.info("进入重置密码页面,验证码已失效[verifyCode="+verifyCode+"]."); + outPrintError(response, "The requested URL was not found on this server."); + return false; + } + }finally{ + customerMapper = null; + } + */ + return true; + } + + @Override + protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { + return false; + } + + public void outPrintError(ServletResponse response, String result) { + response.setCharacterEncoding("UTF-8"); + response.setContentType("text/html; charset=UTF-8"); + PrintWriter out = null; + try { + String html = ""; + html += "Error 404 (Not Found)"; + html += ""; + html += ""; + html += ""; + html+="
"; + html += result; + html+="
"; + out = response.getWriter(); + out.print(html); + } catch (IOException e) { + logger.error("IO工作流出现异常!", e); + } finally { + if(out!=null){ + out.close(); + out = null; + } + } + } + + +} diff --git a/src/main/java/com/nbclass/system/controller/BaseController.java b/src/main/java/com/nbclass/system/controller/BaseController.java new file mode 100644 index 0000000..2832dc8 --- /dev/null +++ b/src/main/java/com/nbclass/system/controller/BaseController.java @@ -0,0 +1,186 @@ +package com.nbclass.system.controller; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.shiro.SecurityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.context.ContextLoader; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import com.alibaba.fastjson.JSONObject; +import com.nbclass.system.model.User; +import com.nbclass.util.CoreConst; +import com.nbclass.util.WebUtils; + +/** + * + * @author Leon + * @datetime 2019年4月1日 下午3:22:58 + */ +public abstract class BaseController { + + protected Logger logger = LoggerFactory.getLogger(getClass()); + + private static ThreadLocal> outPutMsg = new ThreadLocal>(); + + /** + * 获取request + * @return HttpServletRequest + */ + protected HttpServletRequest getRequest() { + return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + } + + /** + * 获取Response + * @return HttpServletResponse + */ + protected HttpServletResponse getResponse() { + return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse(); + } + + /** + * 获取session + * @return HttpSession + */ + protected HttpSession getSession() { + return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getSession(); + } + + protected ServletContext getServletContext() { + return ContextLoader.getCurrentWebApplicationContext().getServletContext(); + } + + public void outPrint() { + outPrint(null); + } + + public void outPrint(Object result) { + outPrint(result, true); + } + + /** + * 输出,同时清空outPutMsg + * @param response + * @param result + * @param respCode -- 是否返回响应状态吗,false:将直接输出result + */ + public void outPrint(Object result, boolean respCode) { + try { + HttpServletResponse response = getResponse(); + response.setCharacterEncoding("utf-8"); + response.setContentType("application/json"); + + PrintWriter out = response.getWriter(); + if(respCode){ + JSONObject obj = new JSONObject(); + if(result == null){ + // no msg + }else if(result instanceof String){ + obj.put(CoreConst.MSG, result); + }else{ + obj = (JSONObject) JSONObject.toJSON(result); + } + obj.put(CoreConst.STATUS, CoreConst.STATUS_SUCCESS); + out.print(obj.toString()); + }else{ + out.print(result.toString()); + } + getOutputMsg().clear(); + } catch (IOException e) { + logger.error("输出异常", e); + } + } + + /** + * 输出失败信息,同时清空outPutMsg + * @param response + * @param result void + */ + public void outPrintFail(Object result) { + try { + HttpServletResponse response = getResponse(); + response.setCharacterEncoding("utf-8"); + response.setContentType("application/json"); + + JSONObject obj = new JSONObject(); + if(result == null){ + // no msg + }else if(result instanceof String){ + obj.put(CoreConst.MSG, result); + }else{ + obj = (JSONObject) JSONObject.toJSON(result); + } + obj.put(CoreConst.STATUS, CoreConst.STATUS_ERROR); + PrintWriter out = response.getWriter(); + out.print(obj.toString()); + getOutputMsg().clear(); + } catch (IOException e) { + logger.error("输出异常", e); + } + } + + /** + * 线程绑定,其内容会在outPrint方法调用后清空 + * @return Map + */ + public Map getOutputMsg() { + Map output = outPutMsg.get(); + if(output==null){ + output = new HashMap(); + outPutMsg.set(output); + } + return output; + } + + public User getLoginUser(){ + User user = (User) SecurityUtils.getSubject().getPrincipal(); + return user; + } + + public int getLoginUserId(){ + int userid = -1; + User user = getLoginUser(); + if(user!=null && user.getId()!=null)userid=user.getId(); + return userid; + } + + /** + * 获取ip地址 + * @return + */ + public String getIpAddr() { + String ip = WebUtils.getReqIpAddr(getRequest()); + return ip; + } + + /** + * 是否是管理员角色 + * @return + */ + public boolean isAdminRole(){ + boolean isSuperAdmin = SecurityUtils.getSubject().hasRole("1"); //是否是超级管理员,admin的roleid为1 + boolean isBaseAdmin = SecurityUtils.getSubject().hasRole("1000000002073979"); //是否是普通管理员, 给客户的管理员 + boolean isAdmin = isSuperAdmin||isBaseAdmin; + return isAdmin; + } + + public static void main(String[] args) { + Object result = null; + result = ""; + JSONObject obj = (JSONObject) JSONObject.toJSON(result); + obj.put(CoreConst.STATUS, CoreConst.STATUS_SUCCESS); + System.out.println(obj); + } + +} diff --git a/src/main/java/com/nbclass/system/controller/DatabaseController.java b/src/main/java/com/nbclass/system/controller/DatabaseController.java new file mode 100644 index 0000000..e0faa89 --- /dev/null +++ b/src/main/java/com/nbclass/system/controller/DatabaseController.java @@ -0,0 +1,20 @@ +package com.nbclass.system.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.ModelAndView; + +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +@Controller +@RequestMapping("/database") +public class DatabaseController{ + @GetMapping(value = "/monitoring") + public ModelAndView databaseMonitoring(){ + return new ModelAndView("database/monitoring"); + } +} diff --git a/src/main/java/com/nbclass/system/controller/ErrorController.java b/src/main/java/com/nbclass/system/controller/ErrorController.java new file mode 100644 index 0000000..078df4e --- /dev/null +++ b/src/main/java/com/nbclass/system/controller/ErrorController.java @@ -0,0 +1,23 @@ +package com.nbclass.system.controller; + +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +@Controller +@RequestMapping("/error") +public class ErrorController { + /*shiro无权限时进入*/ + @RequestMapping("/403") + public String noPermission(HttpServletRequest request, HttpServletResponse response){ + response.setStatus(HttpStatus.FORBIDDEN.value()); + return "error/403"; + } +} diff --git a/src/main/java/com/nbclass/system/controller/OnlineUserController.java b/src/main/java/com/nbclass/system/controller/OnlineUserController.java new file mode 100644 index 0000000..28c9933 --- /dev/null +++ b/src/main/java/com/nbclass/system/controller/OnlineUserController.java @@ -0,0 +1,82 @@ +package com.nbclass.system.controller; + +import java.io.Serializable; +import java.util.List; + +import org.apache.shiro.SecurityUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.nbclass.system.service.UserService; +import com.nbclass.util.ResultUtil; +import com.nbclass.vo.UserOnlineVo; +import com.nbclass.vo.UserSessionVo; +import com.nbclass.vo.base.PageResultVo; +import com.nbclass.vo.base.ResponseVo; + +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ + +@Controller +@RequestMapping("/online/user") +public class OnlineUserController { + @Autowired + private UserService userService; + + // 在线用户列表 + @PostMapping("/list") + @ResponseBody + public PageResultVo onlineUsers(UserOnlineVo user, Integer limit, Integer offset){ + List userList = userService.selectOnlineUsers(user); + int endIndex = (offset+limit) > userList.size() ? userList.size() : (offset+limit); + return ResultUtil.table(userList.subList(offset,endIndex),(long)userList.size()); + } + + // 强制踢出用户 + @PostMapping("/kickout") + @ResponseBody + public ResponseVo kickout(String sessionId,String username) { + try { + if(SecurityUtils.getSubject().getSession().getId().equals(sessionId)){ + return ResultUtil.error("不能踢出自己"); + } + userService.kickout(sessionId,username); + return ResultUtil.success("踢出用户成功"); + } catch (Exception e) { + return ResultUtil.error("踢出用户失败"); + } + } + + // 批量强制踢出用户 + @PostMapping("/batch/kickout") + @ResponseBody + public ResponseVo kickout(@RequestBody List sessions) { + try { + //要踢出的用户中是否有自己 + boolean hasOwn=false; + Serializable sessionId = SecurityUtils.getSubject().getSession().getId(); + for (UserSessionVo sessionVo : sessions) { + if(sessionVo.getSessionId().equals(sessionId)){ + hasOwn=true; + }else{ + userService.kickout(sessionVo.getSessionId(),sessionVo.getUsername()); + } + + + } + if(hasOwn){ + return ResultUtil.success("不能踢出自己"); + } + return ResultUtil.success("踢出用户成功"); + } catch (Exception e) { + return ResultUtil.error("踢出用户失败"); + } + } +} diff --git a/src/main/java/com/nbclass/system/controller/PermissionController.java b/src/main/java/com/nbclass/system/controller/PermissionController.java new file mode 100644 index 0000000..a304d76 --- /dev/null +++ b/src/main/java/com/nbclass/system/controller/PermissionController.java @@ -0,0 +1,124 @@ +package com.nbclass.system.controller; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.nbclass.shiro.ShiroService; +import com.nbclass.system.model.Permission; +import com.nbclass.system.service.PermissionService; +import com.nbclass.util.CoreConst; +import com.nbclass.util.ResultUtil; +import com.nbclass.vo.base.ResponseVo; +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +@Controller +@RequestMapping("/permission") +public class PermissionController{ + private static final Logger logger = LoggerFactory.getLogger(PermissionController.class); + /**1:全部资源,2:菜单资源*/ + private static final String[] MENU_FLAG ={"1","2"}; + @Autowired + private PermissionService permissionService; + @Autowired + private ShiroService shiroService; + + + + /*权限列表数据*/ + @PostMapping("/list") + @ResponseBody + public List loadPermissions(String flag){ + List permissionListList = new ArrayList(); + if(StringUtils.isBlank(flag) || MENU_FLAG[0].equals(flag)){ + permissionListList = permissionService.selectAll(CoreConst.STATUS_VALID); + }else if(MENU_FLAG[1].equals(flag)){ + permissionListList = permissionService.selectAllMenuName(CoreConst.STATUS_VALID); + } + return permissionListList; + } + + /*添加权限*/ + @ResponseBody + @PostMapping("/add") + public ResponseVo addPermission(Permission permission){ + try { + int a = permissionService.insert(permission); + if (a > 0) { + shiroService.updatePermission(); + return ResultUtil.success("添加权限成功"); + } else { + return ResultUtil.error("添加权限失败"); + } + } catch (Exception e) { + logger.error(String.format("PermissionController.addPermission%s", e)); + throw e; + } + } + + /*删除权限*/ + @ResponseBody + @PostMapping("/delete") + public ResponseVo deletePermission(String permissionId){ + try { + int subPermsByPermissionIdCount = permissionService.selectSubPermsByPermissionId(permissionId); + if(subPermsByPermissionIdCount>0){ + return ResultUtil.error("改资源存在下级资源,无法删除!"); + } + int a = permissionService.updateStatus(permissionId,CoreConst.STATUS_INVALID); + if (a > 0) { + shiroService.updatePermission(); + return ResultUtil.success("删除权限成功"); + } else { + return ResultUtil.error("删除权限失败"); + } + } catch (Exception e) { + logger.error(String.format("PermissionController.deletePermission%s", e)); + throw e; + } + } + + /*权限详情*/ + @GetMapping("/edit") + public String detail(Model model, String permissionId) { + Permission permission = permissionService.findByPermissionId(permissionId); + if(null!=permission){ + if(permission.getParentId().equals(CoreConst.TOP_MENU_ID)){ + model.addAttribute("parentName", CoreConst.TOP_MENU_NAME); + }else{ + Permission parent = permissionService.findById(permission.getParentId()); + model.addAttribute("parentName", parent.getName()); + } + } + model.addAttribute("permission", permission); + return "permission/detail"; + } + + /*编辑权限*/ + @ResponseBody + @PostMapping("/edit") + public ResponseVo editPermission(@ModelAttribute("permission")Permission permission){ + int a = permissionService.updateByPermissionId(permission); + if (a > 0) { + shiroService.updatePermission(); + return ResultUtil.success("编辑权限成功"); + } else { + return ResultUtil.error("编辑权限失败"); + } + } + +} diff --git a/src/main/java/com/nbclass/system/controller/QyWxLoginController.java b/src/main/java/com/nbclass/system/controller/QyWxLoginController.java new file mode 100644 index 0000000..2632a1f --- /dev/null +++ b/src/main/java/com/nbclass/system/controller/QyWxLoginController.java @@ -0,0 +1,138 @@ +package com.nbclass.system.controller; + +import java.io.IOException; +import java.io.PrintWriter; +import java.net.URLEncoder; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.authc.AuthenticationException; +import org.apache.shiro.authc.LockedAccountException; +import org.apache.shiro.subject.Subject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +import com.alibaba.fastjson.JSONObject; +import com.nbclass.shiro.config.MyUsernamePasswordToken; +import com.nbclass.system.model.User; +import com.nbclass.system.service.UserService; +import com.nbclass.util.CommonUtils; +import com.nbclass.util.HttpUtils; + +import lombok.extern.slf4j.Slf4j; + +/** + * 企业微信扫码登录 + * @author Leon + * @datetime 2020年6月2日 下午4:18:04 + */ +@Slf4j +@Controller +@RequestMapping("/qywx") +public class QyWxLoginController { + + private static final int AgentId = 1000016; // 企业微信登录应用ID(信广龙广告) + + @Autowired + private UserService userService; + + /** + * PC端网页授权(企业微信授权登录) + * @param code + * @param request + * @param response + * @throws IOException + */ + @RequestMapping("/qrLogin") + public void qrLogin(String code, HttpServletRequest request, HttpServletResponse response) throws IOException{ + response.setHeader("Cache-Control", "no-store"); + String httpRequestFullURL = URLEncoder.encode(getBaseUrl(request)+"/qywx/qrLogin", "UTF-8"); + String redirectUrl = "http://show.szxgl.cn/qywx/api/sso/login?agentid="+AgentId+"&redirect_uri=" + httpRequestFullURL; + if(StringUtils.isBlank(code)){ + response.sendRedirect(redirectUrl); + return; + } + + String url = "http://show.szxgl.cn/qywx/api/sso/getUserInfo?agentid="+AgentId+"&code="+code; + try { + JSONObject json = HttpUtils.httpPost(url); + if(json == null || json.getIntValue("errcode") == 40029 || json.getIntValue("errcode") == 40163){ + log.info("企业微信授权失败,将重新跳转授权......"); + redirectUrl = CommonUtils.removeParamValue(redirectUrl, "code"); + response.sendRedirect(redirectUrl); + return; + } + log.info("企业微信扫码登录, 用户信息: "+json); + String userid = json.getString("userid"); + if(StringUtils.isBlank(userid)){ + outPrintError(response, "该账号未经授权,请联系管理员授权后再试!"); + return; + } + + // 企业微信登录成功,下一步进行系统shiro身份验证 + String username = userid; + MyUsernamePasswordToken token = new MyUsernamePasswordToken(username); // 免密登录,用于扫码登录手机验证码登录等场景 + try{ + Subject subject = SecurityUtils.getSubject(); + subject.login(token); + } catch (LockedAccountException e) { + token.clear(); + outPrintError(response, "用户已经被锁定不能登录,请联系管理员!"); + return; + } catch (AuthenticationException e) { + token.clear(); + outPrintError(response, "账号异常,请联系管理员处理!"); + return; + } + //更新最后登录时间 + userService.updateLastLoginTime((User) SecurityUtils.getSubject().getPrincipal()); + + response.sendRedirect(request.getContextPath()+"/admin"); + } catch (Exception e) { + log.error("企业微信登录授权失败", e); + outPrintError(response, "企业微信授权失败,请稍候再试!"); + } + } + + /** + * 输出错误信息到页面 + * @param response + * @param result + */ + public void outPrintError(HttpServletResponse response, String result) { + response.setCharacterEncoding("UTF-8"); + response.setContentType("text/html; charset=UTF-8"); + PrintWriter out = null; + try { + String html = ""; + html += "鉴权错误"; + html += ""; + html += ""; + html += ""; + html+="
"; + html += result; + html+="
"; + out = response.getWriter(); + out.print(html); + } catch (IOException e) { + throw new RuntimeException("IO工作流出现异常!"); + } finally { + if(out!=null){ + out.close(); + out = null; + } + } + } + + private static String getBaseUrl(HttpServletRequest request){ + String result = null; + int port = request.getServerPort(); + result = request.getScheme()+"://"+request.getServerName()+(port==80||port==443 ? "" : ":"+port)+request.getContextPath()+"/"; + return result; + } + +} diff --git a/src/main/java/com/nbclass/system/controller/RenderController.java b/src/main/java/com/nbclass/system/controller/RenderController.java new file mode 100644 index 0000000..2a0f0fa --- /dev/null +++ b/src/main/java/com/nbclass/system/controller/RenderController.java @@ -0,0 +1,41 @@ +package com.nbclass.system.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +/** + * @version V1.0 + * @date 2018年7月13日 + * @author superzheng + */ +@Controller +public class RenderController { + + /*工作台*/ + @GetMapping("/workdest") + public String workdest(){ + return "index/workdest"; + } + + /**用户列表入口*/ + @GetMapping("/users") + public String userList(){ + return "user/list"; + } + + /*角色列表入口*/ + @GetMapping("/roles") + public String roleList() { + return "role/list"; + } + + /*权限列表入口*/ + @GetMapping("/permissions") + public String permissionList(){ + return "permission/list"; + } + + /*在线用户入口*/ + @GetMapping("/online/users") + public String onlineUsers(){return "onlineUsers/list";} +} diff --git a/src/main/java/com/nbclass/system/controller/RoleController.java b/src/main/java/com/nbclass/system/controller/RoleController.java new file mode 100644 index 0000000..d574828 --- /dev/null +++ b/src/main/java/com/nbclass/system/controller/RoleController.java @@ -0,0 +1,184 @@ +package com.nbclass.system.controller; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.nbclass.shiro.MyShiroRealm; +import com.nbclass.system.model.Permission; +import com.nbclass.system.model.Role; +import com.nbclass.system.model.User; +import com.nbclass.system.service.PermissionService; +import com.nbclass.system.service.RoleService; +import com.nbclass.util.CoreConst; +import com.nbclass.util.PageUtil; +import com.nbclass.util.ResultUtil; +import com.nbclass.vo.PermissionTreeListVo; +import com.nbclass.vo.base.PageResultVo; +import com.nbclass.vo.base.ResponseVo; + +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +@Controller +@RequestMapping("/role") +public class RoleController { + private static final Logger logger = LoggerFactory.getLogger(RoleController.class); + @Autowired + private RoleService roleService; + @Autowired + private PermissionService permissionService; + @Autowired + private MyShiroRealm myShiroRealm; + + /*角色列表数据*/ + @PostMapping("/list") + @ResponseBody + public PageResultVo pageRoles(Role role, Integer limit, Integer offset) { + try { + PageHelper.startPage(PageUtil.getPageNo(limit, offset),limit); + List roleList = roleService.selectRoles(role); + PageInfo pages = new PageInfo<>(roleList); + return ResultUtil.table(roleList,pages.getTotal()); + } catch (Exception e) { + logger.error(String.format("RoleController.loadRoles%s", e)); + throw e; + } + + } + + /*新增角色*/ + @PostMapping("/add") + @ResponseBody + public ResponseVo addRole(Role role) { + try { + int a = roleService.insert(role); + if (a > 0) { + return ResultUtil.success("添加角色成功"); + } else { + return ResultUtil.error("添加角色失败"); + } + } catch (Exception e) { + logger.error(String.format("RoleController.addRole%s", e)); + throw e; + } + } + + /*删除角色*/ + @GetMapping("/delete") + @ResponseBody + public ResponseVo deleteRole(String roleId) { + if(roleService.findByRoleId(roleId).size()>0){ + return ResultUtil.error("删除失败,该角色下存在用户"); + } + List roleIdsList = Arrays.asList(roleId); + int a = roleService.updateStatusBatch(roleIdsList, CoreConst.STATUS_INVALID); + if (a > 0) { + return ResultUtil.success("删除角色成功"); + } else { + return ResultUtil.error("删除角色失败"); + } + } + + /*批量删除角色*/ + @GetMapping("/batch/delete") + @ResponseBody + public ResponseVo batchDeleteRole(String roleIdStr) { + String[] roleIds = roleIdStr.split(","); + List roleIdsList = Arrays.asList(roleIds); + if(roleService.findByRoleIds(roleIdsList).size()>0){ + return ResultUtil.error("删除失败,选择的角色下存在用户"); + } + int a = roleService.updateStatusBatch(roleIdsList, CoreConst.STATUS_INVALID); + if (a > 0) { + return ResultUtil.success("删除角色成功"); + } else { + return ResultUtil.error("删除角色失败"); + } + } + + /*编辑角色详情*/ + @GetMapping("/edit") + public String detail(Model model, Integer id) { + Role role = roleService.findById(id); + model.addAttribute("role", role); + return "role/detail"; + } + + /*编辑角色*/ + @PostMapping("/edit") + @ResponseBody + public ResponseVo editRole(@ModelAttribute("role") Role role) { + int a = roleService.updateByRoleId(role); + if (a > 0) { + return ResultUtil.success("编辑角色成功"); + } else { + return ResultUtil.error("编辑角色失败"); + } + } + + /*分配权限列表查询*/ + @PostMapping("/assign/permission/list") + @ResponseBody + public List assignRole(String roleId){ + List listVos = new ArrayList<>(); + List allPermissions = permissionService.selectAll(CoreConst.STATUS_VALID); + List hasPermissions = roleService.findPermissionsByRoleId(roleId); + for(Permission permission : allPermissions){ + PermissionTreeListVo vo = new PermissionTreeListVo(); + vo.setId(permission.getId()); + vo.setPermissionId(permission.getPermissionId()); + vo.setName(permission.getName()); + vo.setParentId(permission.getParentId()); + for(Permission hasPermission:hasPermissions){ + //有权限则选中 + if(hasPermission.getPermissionId().equals(permission.getPermissionId())){ + vo.setChecked(true); + break; + } + } + listVos.add(vo); + } + return listVos; + } + + + /*分配权限*/ + @PostMapping("/assign/permission") + @ResponseBody + public ResponseVo assignRole(String roleId, String permissionIdStr){ + List permissionIdsList = new ArrayList<>(); + if(StringUtils.isNotBlank(permissionIdStr)){ + String[] permissionIds = permissionIdStr.split(","); + permissionIdsList = Arrays.asList(permissionIds); + } + ResponseVo rv = roleService.addAssignPermission(roleId,permissionIdsList); + /*重新加载角色下所有用户权限*/ + List userList = roleService.findByRoleId(roleId); + if(userList.size()>0){ + List userIds = new ArrayList<>(); + for(User user : userList){ + userIds.add(user.getUserId()); + } + myShiroRealm.clearAuthorizationByUserId(userIds); + } + return rv; + } + +} diff --git a/src/main/java/com/nbclass/system/controller/SystemController.java b/src/main/java/com/nbclass/system/controller/SystemController.java new file mode 100644 index 0000000..74ec2a4 --- /dev/null +++ b/src/main/java/com/nbclass/system/controller/SystemController.java @@ -0,0 +1,200 @@ +package com.nbclass.system.controller; + +import java.util.Date; +import java.util.List; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.authc.AuthenticationException; +import org.apache.shiro.authc.LockedAccountException; +import org.apache.shiro.subject.Subject; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.nbclass.shiro.config.MyUsernamePasswordToken; +import com.nbclass.system.model.Permission; +import com.nbclass.system.model.SysLog; +import com.nbclass.system.model.User; +import com.nbclass.system.model.enums.SysLogType; +import com.nbclass.system.service.PermissionService; +import com.nbclass.system.service.SysLogService; +import com.nbclass.system.service.UserService; +import com.nbclass.util.CoreConst; +import com.nbclass.util.PasswordHelper; +import com.nbclass.util.ResultUtil; +import com.nbclass.util.UUIDUtil; +import com.nbclass.vo.base.ResponseVo; + +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +@Controller +public class SystemController extends BaseController{ + + @Resource + private UserService userService; + @Resource + private PermissionService permissionService; + @Resource + private SysLogService sysLogService; + + /*首页*/ + @RequestMapping(value={"/admin"}) + public String admin(){ + return "index/index"; + } + + /*注册*/ + @GetMapping(value = "/register") + public String register(){ + return "system/register"; + } + + /*提交注册*/ + @PostMapping("/register") + @ResponseBody + public ResponseVo register(HttpServletRequest request, User registerUser, String confirmPassword, String verification){ + if(true)return ResultUtil.error("注册失败,请稍后再试!"); + @SuppressWarnings("unused") + //判断验证码 + /* + * String rightCode = (String) + * request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY); if + * (StringUtils.isNotBlank(verification) && StringUtils.isNotBlank(rightCode) && + * verification.equals(rightCode)) { //验证码通过 } else { return + * ResultUtil.error("验证码错误!"); } + */ + String username = registerUser.getUsername(); + User user = userService.selectByUsername(username); + if (null != user) { + return ResultUtil.error("用户名已存在!"); + } + String password = registerUser.getPassword(); + //判断两次输入密码是否相等 + if (confirmPassword != null && password != null) { + if (!confirmPassword.equals(password)) { + return ResultUtil.error("两次密码不一致!"); + } + } + registerUser.setUserId(UUIDUtil.getUniqueIdByUUId()); + registerUser.setStatus(CoreConst.STATUS_VALID); + Date date = new Date(); + registerUser.setCreateTime(date); + registerUser.setUpdateTime(date); + registerUser.setLastLoginTime(date); + PasswordHelper.encryptPassword(registerUser); + //注册 + int registerResult = userService.register(registerUser); + if(registerResult > 0){ + return ResultUtil.success("注册成功!"); + }else { + return ResultUtil.error("注册失败,请稍后再试!"); + } + } + + /*登陆*/ + @GetMapping("/login") + public String login(){ + return "system/login"; + } + + /*提交登录*/ + @PostMapping("/login") + @ResponseBody + public ResponseVo login(HttpServletRequest request, String username, String password, + String verification, @RequestParam(value = "rememberMe", defaultValue = "0") Integer rememberMe){ + + /* + //判断验证码 + String rightCode = (String) request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY); + if (StringUtils.isNotBlank(verification) && StringUtils.isNotBlank(rightCode) && verification.equalsIgnoreCase(rightCode)) { + //验证码通过 + } else { + return ResultUtil.error("验证码错误!"); + } + */ + + MyUsernamePasswordToken token = new MyUsernamePasswordToken(username, password); // 账密登录 + // MyUsernamePasswordToken token = new MyUsernamePasswordToken(username); // 免密登录,用于扫码登录手机验证码登录等场景 + try{ + token.setRememberMe(1 == rememberMe); + Subject subject = SecurityUtils.getSubject(); + subject.login(token); + } catch (LockedAccountException e) { + token.clear(); + return ResultUtil.error("用户已经被锁定不能登录,请联系管理员!"); + } catch (AuthenticationException e) { + token.clear(); + return ResultUtil.error("用户名或者密码错误!"); + } + //更新最后登录时间 + userService.updateLastLoginTime((User) SecurityUtils.getSubject().getPrincipal()); + User user = getLoginUser(); + request.getSession().setAttribute("username",user.getUsername()); + sysLogService.add(new SysLog(SysLogType.login.key(), user.getUserId()+"("+user.getUsername()+")", getIpAddr(), "登录系统!")); + return ResultUtil.success("登录成功!"); + } + + /*踢出*/ + @GetMapping("/kickout") + public String kickout(){ + return "system/kickout"; + } + + /*登出*/ + @RequestMapping(value = "/logout") + @ResponseBody + public ResponseVo logout() { + Subject subject = SecurityUtils.getSubject(); + if(null!=subject){ + /* + String username = ((User) SecurityUtils.getSubject().getPrincipal()).getUsername(); + Serializable sessionId = SecurityUtils.getSubject().getSession().getId(); + Cache> cache = redisCacheManager.getCache(redisCacheManager.getKeyPrefix()+username); + Deque deques = cache.get(username); + for(Serializable deque : deques){ + if(sessionId.equals(deque)){ + deques.remove(deque); + break; + } + } + cache.put(username,deques); + */ + } + subject.logout(); + return ResultUtil.success("退出成功"); + } + + /*获取当前登录用户的菜单*/ + @PostMapping("/menu") + @ResponseBody + public List getMenus(){ + List permissionListList = permissionService.selectMenuByUserId(((User) SecurityUtils.getSubject().getPrincipal()).getUserId()); + return permissionListList; + } + + /*图标*/ + @GetMapping(value = "/icons") + public String getIcons(){ + return "ui/icons"; + } + + @GetMapping(value = "/test") + public String test(){ + return "ui/icons"; + } + + @GetMapping(value = "/test1") + public String test1(){ + return "ui/icons"; + } + +} diff --git a/src/main/java/com/nbclass/system/controller/UserController.java b/src/main/java/com/nbclass/system/controller/UserController.java new file mode 100644 index 0000000..605f4e3 --- /dev/null +++ b/src/main/java/com/nbclass/system/controller/UserController.java @@ -0,0 +1,239 @@ +package com.nbclass.system.controller; + +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.Set; + +import javax.annotation.Resource; + +import org.apache.commons.lang3.StringUtils; +import org.apache.shiro.SecurityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.alibaba.fastjson.JSON; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.nbclass.shiro.MyShiroRealm; +import com.nbclass.system.model.Role; +import com.nbclass.system.model.SysLog; +import com.nbclass.system.model.User; +import com.nbclass.system.model.enums.SysLogType; +import com.nbclass.system.service.RoleService; +import com.nbclass.system.service.SysLogService; +import com.nbclass.system.service.UserService; +import com.nbclass.util.CopyUtil; +import com.nbclass.util.CoreConst; +import com.nbclass.util.PageUtil; +import com.nbclass.util.PasswordHelper; +import com.nbclass.util.ResultUtil; +import com.nbclass.util.UUIDUtil; +import com.nbclass.vo.ChangePasswordVo; +import com.nbclass.vo.base.PageResultVo; +import com.nbclass.vo.base.ResponseVo; +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +@Controller +@RequestMapping("/user") +public class UserController extends BaseController{ + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private MyShiroRealm myShiroRealm; + @Autowired + private UserService userService; + @Autowired + private RoleService roleService; + @Autowired + private MyShiroRealm shiroRealm; + @Resource + private SysLogService sysLogService; + + /**用户列表数据*/ + @PostMapping("/list") + @ResponseBody + public PageResultVo loadUsers(User user, Integer limit, Integer offset){ + PageHelper.startPage(PageUtil.getPageNo(limit, offset),limit); + List userList = userService.selectUsers(user); + PageInfo pages = new PageInfo<>(userList); + return ResultUtil.table(userList,pages.getTotal()); + } + + /**新增用户*/ + @PostMapping("/add") + @ResponseBody + public ResponseVo add(User userForm, String confirmPassword){ + String username = userForm.getUsername(); + User user = userService.selectByUsername(username); + if (null != user) { + return ResultUtil.error("用户名已存在"); + } + String password = userForm.getPassword(); + //判断两次输入密码是否相等 + if (confirmPassword != null && password != null) { + if (!confirmPassword.equals(password)) { + return ResultUtil.error("两次密码不一致"); + } + } + userForm.setUserId(UUIDUtil.getUniqueIdByUUId()); + userForm.setStatus(CoreConst.STATUS_VALID); + Date date = new Date(); + userForm.setCreateTime(date); + userForm.setUpdateTime(date); + userForm.setLastLoginTime(date); + PasswordHelper.encryptPassword(userForm); + int num = userService.register(userForm); + if(num > 0){ + return ResultUtil.success("添加用户成功"); + }else { + return ResultUtil.error("添加用户失败"); + } + } + + /**编辑用户详情*/ + @GetMapping("/edit") + public String userDetail(Model model, String userId){ + User user = userService.selectByUserId(userId); + model.addAttribute("user", user); + return "user/userDetail"; + } + + /**编辑用户*/ + @PostMapping("/edit") + @ResponseBody + public ResponseVo editUser(User userForm){ + int a = userService.updateByUserId(userForm); + if (a > 0) { + return ResultUtil.success("编辑用户成功!"); + } else { + return ResultUtil.error("编辑用户失败"); + } + } + + /**删除用户*/ + @GetMapping("/delete") + @ResponseBody + public ResponseVo deleteUser(String userId) { + List userIdsList = Arrays.asList(userId); + int a = userService.updateStatusBatch(userIdsList,CoreConst.STATUS_INVALID); + if (a > 0) { + return ResultUtil.success("删除用户成功"); + } else { + return ResultUtil.error("删除用户失败"); + } + } + + /**批量删除用户*/ + @GetMapping("/batch/delete") + @ResponseBody + public ResponseVo batchDeleteUser(String userIdStr) { + String[] userIds = userIdStr.split(","); + List userIdsList = Arrays.asList(userIds); + int a = userService.updateStatusBatch(userIdsList,CoreConst.STATUS_INVALID); + if (a > 0) { + return ResultUtil.success("删除用户成功"); + } else { + return ResultUtil.error("删除用户失败"); + } + } + + /**分配角色列表查询*/ + @PostMapping("/assign/role/list") + @ResponseBody + public Map assignRoleList(String userId){ + List roleList = roleService.selectRoles(new Role()); + Set hasRoles = roleService.findRoleByUserId(userId); + Map jsonMap = new HashMap<>(2); + jsonMap.put("rows", roleList); + jsonMap.put("hasRoles",hasRoles); + return jsonMap; + } + + /**保存分配角色*/ + @PostMapping("/assign/role") + @ResponseBody + public ResponseVo assignRole(String userId, String roleIdStr){ + String[] roleIds = roleIdStr.split(","); + List roleIdsList = Arrays.asList(roleIds); + ResponseVo responseVo = userService.addAssignRole(userId,roleIdsList); + List userIds = new ArrayList<>(); + userIds.add(userId); + myShiroRealm.clearAuthorizationByUserId(userIds); + return responseVo; + } + + /*修改密码*/ + @RequestMapping(value = "/changePassword",method = RequestMethod.POST) + @ResponseBody + public ResponseVo changePassword(ChangePasswordVo changePasswordVo) { + if(!changePasswordVo.getNewPassword().equals(changePasswordVo.getConfirmNewPassword())){ + return ResultUtil.error("两次密码输入不一致"); + } + User loginUser = userService.selectByUserId(((User) SecurityUtils.getSubject().getPrincipal()).getUserId()); + User newUser = CopyUtil.getCopy(loginUser,User.class); + String sysOldPassword = loginUser.getPassword(); + newUser.setPassword(changePasswordVo.getOldPassword()); + String entryOldPassword = PasswordHelper.getPassword(newUser); + if(sysOldPassword.equals(entryOldPassword)){ + newUser.setPassword(changePasswordVo.getNewPassword()); + PasswordHelper.encryptPassword(newUser); + newUser.setUpdateTime(new Date()); + userService.updateUserByPrimaryKey(newUser); + //*清除登录缓存*// + List userIds = new ArrayList<>(); + userIds.add(loginUser.getUserId()); + shiroRealm.removeCachedAuthenticationInfo(userIds); + /*SecurityUtils.getSubject().logout();*/ + }else{ + return ResultUtil.error("您输入的旧密码有误"); + } + logger.info("账号[username="+loginUser.getUsername()+"]修改密码, 提交的参数为: "+JSON.toJSONString(changePasswordVo)); + + User user = getLoginUser(); + sysLogService.add(new SysLog(SysLogType.xtgl.key(), user.getUserId()+"("+user.getUsername()+")", getIpAddr(), "修改密码")); + return ResultUtil.success("修改密码成功"); + } + + /*管理员重置密码*/ + @PostMapping("/resetPwd") + @ResponseBody + public ResponseVo resetPassword(String userid, String password) { + if(StringUtils.isBlank(userid)){ + return ResultUtil.error("用户不能为空"); + } + if(StringUtils.isBlank(password)){ + return ResultUtil.error("密码不能为空"); + } + User dbUser = userService.selectByUserId(userid); + User newUser = new User(); + newUser.setId(dbUser.getId()); + newUser.setUserId(dbUser.getUserId()); + newUser.setUsername(dbUser.getUsername()); + newUser.setStatus(dbUser.getStatus()); + newUser.setPassword(password); + PasswordHelper.encryptPassword(newUser); + newUser.setUpdateTime(new Date()); + userService.updateUserByPrimaryKey(newUser); + logger.info("管理员重置密码[username="+dbUser.getUsername()+"], 提交的参数为: "+password); + User user = getLoginUser(); + sysLogService.add(new SysLog(SysLogType.xtgl.key(), user.getUserId()+"("+user.getUsername()+")", getIpAddr(), "管理员重置密码,账号:"+userid+"("+dbUser.getUsername()+")")); + return ResultUtil.success("修改密码成功"); + } + +} diff --git a/src/main/java/com/nbclass/system/mapper/PermissionMapper.java b/src/main/java/com/nbclass/system/mapper/PermissionMapper.java new file mode 100644 index 0000000..b9b2089 --- /dev/null +++ b/src/main/java/com/nbclass/system/mapper/PermissionMapper.java @@ -0,0 +1,86 @@ +package com.nbclass.system.mapper; + +import com.nbclass.system.model.Permission; +import com.nbclass.util.MyMapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Set; +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +public interface PermissionMapper extends MyMapper { + + /** + * 根据状态查询全部资源 + * @param status 状态 + * @return the list + */ + List selectAllPerms(Integer status); + + /** + * 根据状态查询全部菜单 + * @param status 状态 + * @return the list + */ + List selectAllMenuName(Integer status); + + /** + * 根据用户id查询权限集合 + * @param userId 状态 + * @return set + */ + Set findPermsByUserId(String userId); + + /** + * 根据角色id查询权限 + * @param id 角色id + * @return the list + */ + List findByRoleId(String id); + + /** + * 根据用户id查询权限 + * @param userId 用户id + * @return the list + */ + List selectByUserId(String userId); + + /** + * 根据用户id查询菜单 + * @param userId 用户id + * @return the list + */ + List selectMenuByUserId(String userId); + + /** + * 根据权限id修改状态 + * @param permissionId 权限id + * @param status 状态 + * @return int + */ + int updateStatusByPermissionId(@Param("permissionId") String permissionId, @Param("status") Integer status); + + /** + * 根据权限id查询权限 + * @param permissionId 权限id + * @return permission + */ + Permission selectByPermissionId(String permissionId); + + /** + * 根据权限bean修改权限 + * @param permission 权限 + * @return int + */ + int updateByPermissionId(Permission permission); + + /** + * 根据权限id查询有几个子资源 + * @param permissionId 权限id + * @return int + */ + int selectSubPermsByPermissionId(String permissionId); +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/system/mapper/RoleMapper.java b/src/main/java/com/nbclass/system/mapper/RoleMapper.java new file mode 100644 index 0000000..0cc5a46 --- /dev/null +++ b/src/main/java/com/nbclass/system/mapper/RoleMapper.java @@ -0,0 +1,45 @@ +package com.nbclass.system.mapper; + +import com.nbclass.system.model.Role; +import com.nbclass.util.MyMapper; + +import java.util.List; +import java.util.Map; +import java.util.Set; +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +public interface RoleMapper extends MyMapper { + /** + * 根据用户id查询角色集合 + * @param userId 用户id + * @return set + */ + Set findRoleByUserId(String userId); + + /** + * 根据role参数查询角色列表 + * @param role role + * @return list + */ + List selectRoles(Role role); + + /** + * 根据参数批量更新状态 + * @param params + * @return int + */ + int updateStatusBatch(Map params); + + /** + * 根据roleId更新角色信息 + * @param params + * @return int + */ + int updateByRoleId(Map params); + + + +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/system/mapper/RolePermissionMapper.java b/src/main/java/com/nbclass/system/mapper/RolePermissionMapper.java new file mode 100644 index 0000000..d6fb837 --- /dev/null +++ b/src/main/java/com/nbclass/system/mapper/RolePermissionMapper.java @@ -0,0 +1,11 @@ +package com.nbclass.system.mapper; + +import com.nbclass.system.model.RolePermission; +import com.nbclass.util.MyMapper; +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +public interface RolePermissionMapper extends MyMapper { +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/system/mapper/SysLogMapper.java b/src/main/java/com/nbclass/system/mapper/SysLogMapper.java new file mode 100644 index 0000000..bb1e60b --- /dev/null +++ b/src/main/java/com/nbclass/system/mapper/SysLogMapper.java @@ -0,0 +1,23 @@ +package com.nbclass.system.mapper; + +import java.util.List; + +import com.nbclass.system.model.SysLog; +import com.nbclass.util.MyMapper; + +public interface SysLogMapper extends MyMapper { + + /** + * 根据id批量删除记录 + * @param list + */ + public void deleteByIds(List list); + + /** + * 根据条件查询列表 + * @param entity + * @return + */ + public List getList(SysLog entity); + +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/system/mapper/UserMapper.java b/src/main/java/com/nbclass/system/mapper/UserMapper.java new file mode 100644 index 0000000..b196f54 --- /dev/null +++ b/src/main/java/com/nbclass/system/mapper/UserMapper.java @@ -0,0 +1,68 @@ +package com.nbclass.system.mapper; + +import com.nbclass.system.model.User; +import com.nbclass.util.MyMapper; + +import java.util.List; +import java.util.Map; +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +public interface UserMapper extends MyMapper { + /** + * 根据user参数查询用户列表 + * @param user + * @return list + */ + List selectUsers(User user); + + /** + * 根据用户名查询用户 + * @param username + * @return user + */ + User selectByUsername(String username); + + /** + * 根据用户ID查询用户 + * @param userId + * @return user + */ + User selectByUserId(String userId); + + /** + * 更新最后登录时间 + * @param user + */ + void updateLastLoginTime(User user); + + /** + * 根据用户id更新用户信息 + * @param user + * @return int + */ + int updateByUserId(User user); + + /** + * 根据参数批量修改用户状态 + * @param params + * @return int + */ + int updateStatusBatch(Map params); + + /** + * 根据角色id查询用户list + * @param roleId + * @return list + */ + List findByRoleId(String roleId); + + /** + * 根据角色id查询用户list + * @param roleIds + * @return list + */ + List findByRoleIds(List roleIds); +} diff --git a/src/main/java/com/nbclass/system/mapper/UserRoleMapper.java b/src/main/java/com/nbclass/system/mapper/UserRoleMapper.java new file mode 100644 index 0000000..7bc2e8a --- /dev/null +++ b/src/main/java/com/nbclass/system/mapper/UserRoleMapper.java @@ -0,0 +1,11 @@ +package com.nbclass.system.mapper; + +import com.nbclass.system.model.UserRole; +import com.nbclass.util.MyMapper; +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +public interface UserRoleMapper extends MyMapper { +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/system/model/ExcelColumn.java b/src/main/java/com/nbclass/system/model/ExcelColumn.java new file mode 100644 index 0000000..9387633 --- /dev/null +++ b/src/main/java/com/nbclass/system/model/ExcelColumn.java @@ -0,0 +1,35 @@ +package com.nbclass.system.model; + +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; + +/** + * 自定义实体类所需要的bean(Excel属性标题、位置等) + * @author Leon + * @datetime 2019年6月24日 下午3:07:48 + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface ExcelColumn { + + /** + * Excel标题 + * + * @return + * @author Lynch + */ + String value() default ""; + + /** + * Excel从左往右排列位置 + * + * @return + * @author Lynch + */ + int col() default 0; + +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/system/model/Permission.java b/src/main/java/com/nbclass/system/model/Permission.java new file mode 100644 index 0000000..f5ecd04 --- /dev/null +++ b/src/main/java/com/nbclass/system/model/Permission.java @@ -0,0 +1,252 @@ +package com.nbclass.system.model; + +import java.io.Serializable; +import java.util.Date; + +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +public class Permission implements Serializable { + /** + * + */ + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + /** + * 权限id + */ + private String permissionId; + + /** + * 权限名称 + */ + private String name; + + /** + * 权限描述 + */ + private String description; + + /** + * 权限访问路径 + */ + private String url; + + /** + * 权限标识 + */ + private String perms; + + /** + * 父级权限id + */ + private Integer parentId; + + /** + * 类型 0:目录 1:菜单 2:按钮 + */ + private Integer type; + + /** + * 排序 + */ + private Integer orderNum; + + /** + * 图标 + */ + private String icon; + /** + * 状态:1有效; 0无效 + */ + private Integer status; + + private Date createTime; + + private Date updateTime; + + /** + * @return id + */ + public Integer getId() { + return id; + } + + /** + * @param id + */ + public void setId(Integer id) { + this.id = id; + } + + /** + * 获取权限id + * + * @return permission_id - 权限id + */ + public String getPermissionId() { + return permissionId; + } + + /** + * 设置权限id + * + * @param permissionId 权限id + */ + public void setPermissionId(String permissionId) { + this.permissionId = permissionId == null ? null : permissionId.trim(); + } + + /** + * 获取权限名称 + * + * @return name - 权限名称 + */ + public String getName() { + return name; + } + + /** + * 设置权限名称 + * + * @param name 权限名称 + */ + public void setName(String name) { + this.name = name == null ? null : name.trim(); + } + + /** + * 获取权限描述 + * + * @return description - 权限描述 + */ + public String getDescription() { + return description; + } + + /** + * 设置权限描述 + * + * @param description 权限描述 + */ + public void setDescription(String description) { + this.description = description == null ? null : description.trim(); + } + + /** + * 获取权限访问路径 + * + * @return url - 权限访问路径 + */ + public String getUrl() { + return url; + } + + /** + * 设置权限访问路径 + * + * @param url 权限访问路径 + */ + public void setUrl(String url) { + this.url = url == null ? null : url.trim(); + } + + public String getPerms() { + return perms; + } + + public void setPerms(String perms) { + this.perms = perms; + } + + /** + * 获取父级权限id + * + * @return parent_id - 父级权限id + */ + public Integer getParentId() { + return parentId; + } + + /** + * 设置父级权限id + * + * @param parentId 父级权限id + */ + public void setParentId(Integer parentId) { + this.parentId = parentId; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Integer getOrderNum() { + return orderNum; + } + + public void setOrderNum(Integer orderNum) { + this.orderNum = orderNum; + } + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } + + /** + * 获取状态:1有效;2删除 + * + * @return status - 状态:1有效;2删除 + */ + public Integer getStatus() { + return status; + } + + /** + * 设置状态:1有效;2删除 + * + * @param status 状态:1有效;2删除 + */ + public void setStatus(Integer status) { + this.status = status; + } + + /** + * @return create_time + */ + public Date getCreateTime() { + return createTime; + } + + /** + * @param createTime + */ + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/system/model/Role.java b/src/main/java/com/nbclass/system/model/Role.java new file mode 100644 index 0000000..fd209b8 --- /dev/null +++ b/src/main/java/com/nbclass/system/model/Role.java @@ -0,0 +1,175 @@ +package com.nbclass.system.model; + +import java.io.Serializable; +import java.util.Date; + +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +public class Role implements Serializable { + /** + * + */ + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + /** + * 角色id + */ + private String roleId; + + /** + * 角色名称 + */ + private String name; + + /** + * 角色描述 + */ + private String description; + + /** + * 状态:1有效; 0无效 + */ + private Integer status; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * @return id + */ + public Integer getId() { + return id; + } + + /** + * @param id + */ + public void setId(Integer id) { + this.id = id; + } + + /** + * 获取角色id + * + * @return role_id - 角色id + */ + public String getRoleId() { + return roleId; + } + + /** + * 设置角色id + * + * @param roleId 角色id + */ + public void setRoleId(String roleId) { + this.roleId = roleId == null ? null : roleId.trim(); + } + + /** + * 获取角色名称 + * + * @return name - 角色名称 + */ + public String getName() { + return name; + } + + /** + * 设置角色名称 + * + * @param name 角色名称 + */ + public void setName(String name) { + this.name = name == null ? null : name.trim(); + } + + /** + * 获取角色描述 + * + * @return description - 角色描述 + */ + public String getDescription() { + return description; + } + + /** + * 设置角色描述 + * + * @param description 角色描述 + */ + public void setDescription(String description) { + this.description = description == null ? null : description.trim(); + } + + /** + * 获取状态:1有效;2删除 + * + * @return status - 状态:1有效;2删除 + */ + public Integer getStatus() { + return status; + } + + /** + * 设置状态:1有效;2删除 + * + * @param status 状态:1有效;2删除 + */ + public void setStatus(Integer status) { + this.status = status; + } + + /** + * 获取创建时间 + * + * @return create_time - 创建时间 + */ + public Date getCreateTime() { + return createTime; + } + + /** + * 设置创建时间 + * + * @param createTime 创建时间 + */ + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + /** + * 获取更新时间 + * + * @return update_time - 更新时间 + */ + public Date getUpdateTime() { + return updateTime; + } + + /** + * 设置更新时间 + * + * @param updateTime 更新时间 + */ + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/system/model/RolePermission.java b/src/main/java/com/nbclass/system/model/RolePermission.java new file mode 100644 index 0000000..f8b8b7b --- /dev/null +++ b/src/main/java/com/nbclass/system/model/RolePermission.java @@ -0,0 +1,82 @@ +package com.nbclass.system.model; + +import java.io.Serializable; + +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +public class RolePermission implements Serializable { + /** + * + */ + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + /** + * 角色id + */ + private String roleId; + + /** + * 权限id + */ + private String permissionId; + + /** + * @return id + */ + public Integer getId() { + return id; + } + + /** + * @param id + */ + public void setId(Integer id) { + this.id = id; + } + + /** + * 获取角色id + * + * @return role_id - 角色id + */ + public String getRoleId() { + return roleId; + } + + /** + * 设置角色id + * + * @param roleId 角色id + */ + public void setRoleId(String roleId) { + this.roleId = roleId == null ? null : roleId.trim(); + } + + /** + * 获取权限id + * + * @return permission_id - 权限id + */ + public String getPermissionId() { + return permissionId; + } + + /** + * 设置权限id + * + * @param permissionId 权限id + */ + public void setPermissionId(String permissionId) { + this.permissionId = permissionId == null ? null : permissionId.trim(); + } +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/system/model/SysLog.java b/src/main/java/com/nbclass/system/model/SysLog.java new file mode 100644 index 0000000..1f62b93 --- /dev/null +++ b/src/main/java/com/nbclass/system/model/SysLog.java @@ -0,0 +1,67 @@ +package com.nbclass.system.model; + +import java.util.Date; + +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Transient; + +import lombok.Data; + +/** + * + * @author Leon + * @datetime 2020年6月3日 下午5:15:38 + */ +@Data +@Table(name = "sys_log") +public class SysLog { + + public SysLog() { + + } + + public SysLog(int type, String operator, String ipaddr, String desc) { + this.type = type; + this.operator = operator; + this.ipaddr = ipaddr; + this.description = desc; + } + + /** + * ID, 主键,自增 + */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + /** + * 创建时间 + */ + private Date createtime; + + /** + * 日志类型(1:系统管理;2:登录日志;3:字典管理;4:案例管理) + */ + private Integer type; + @Transient + private String typeName; + + /** + * 操作者 + */ + private String operator; + + /** + * IP地址 + */ + private String ipaddr; + + /** + * 描述 + */ + private String description; + +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/system/model/User.java b/src/main/java/com/nbclass/system/model/User.java new file mode 100644 index 0000000..3194ab8 --- /dev/null +++ b/src/main/java/com/nbclass/system/model/User.java @@ -0,0 +1,359 @@ +package com.nbclass.system.model; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Transient; + +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +public class User implements Serializable{ + private static final long serialVersionUID = -8736616045315083846L; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + /** + * 用户id + */ + private String userId; + + /** + * 用户名 + */ + private String username; + + private String password; + + /** + * 加密盐值 + */ + private String salt; + + /** + * 邮箱 + */ + private String email; + + /** + * 联系方式 + */ + private String phone; + + /** + * 年龄:1男2女 + */ + private Integer sex; + + /** + * 年龄 + */ + private Integer age; + + /** + * 用户状态:1有效; 0无效 + */ + private Integer status; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 最后登录时间 + */ + private Date lastLoginTime; + + /** + * 登录ip + */ + @Transient + private String loginIpAddress; + + /** + * 角色 + */ + @Transient + private List roles; + + /** + * 角色名称 + */ + @Transient + private String rolename; + + /** + * @return id + */ + public Integer getId() { + return id; + } + + /** + * @param id + */ + public void setId(Integer id) { + this.id = id; + } + + /** + * 获取用户id + * + * @return user_id - 用户id + */ + public String getUserId() { + return userId; + } + + /** + * 设置用户id + * + * @param userId 用户id + */ + public void setUserId(String userId) { + this.userId = userId == null ? null : userId.trim(); + } + + /** + * 获取用户名 + * + * @return username - 用户名 + */ + public String getUsername() { + return username; + } + + /** + * 设置用户名 + * + * @param username 用户名 + */ + public void setUsername(String username) { + this.username = username == null ? null : username.trim(); + } + + /** + * @return password + */ + public String getPassword() { + return password; + } + + /** + * @param password + */ + public void setPassword(String password) { + this.password = password == null ? null : password.trim(); + } + + /** + * + * 重写获取盐值方法,自定义realm使用 + * Gets credentials salt. + * + * @return the credentials salt + */ + public String getCredentialsSalt() { + return username + "com.github.cnjd" + salt; + } + + + /** + * 获取加密盐值 + * + * @return salt - 加密盐值 + */ + public String getSalt() { + return salt; + } + + /** + * 设置加密盐值 + * + * @param salt 加密盐值 + */ + public void setSalt(String salt) { + this.salt = salt == null ? null : salt.trim(); + } + + /** + * 获取邮箱 + * + * @return email - 邮箱 + */ + public String getEmail() { + return email; + } + + /** + * 设置邮箱 + * + * @param email 邮箱 + */ + public void setEmail(String email) { + this.email = email == null ? null : email.trim(); + } + + /** + * 获取联系方式 + * + * @return phone - 联系方式 + */ + public String getPhone() { + return phone; + } + + /** + * 设置联系方式 + * + * @param phone 联系方式 + */ + public void setPhone(String phone) { + this.phone = phone == null ? null : phone.trim(); + } + + /** + * 获取年龄:1男2女 + * + * @return sex - 年龄:1男2女 + */ + public Integer getSex() { + return sex; + } + + /** + * 设置年龄:1男2女 + * + * @param sex 年龄:1男2女 + */ + public void setSex(Integer sex) { + this.sex = sex; + } + + /** + * 获取年龄 + * + * @return age - 年龄 + */ + public Integer getAge() { + return age; + } + + /** + * 设置年龄 + * + * @param age 年龄 + */ + public void setAge(Integer age) { + this.age = age; + } + + /** + * 获取用户状态:1有效; 2删除 + * + * @return status - 用户状态:1有效; 2删除 + */ + public Integer getStatus() { + return status; + } + + /** + * 设置用户状态:1有效; 2删除 + * + * @param status 用户状态:1有效; 2删除 + */ + public void setStatus(Integer status) { + this.status = status; + } + + /** + * 获取创建时间 + * + * @return create_time - 创建时间 + */ + public Date getCreateTime() { + return createTime; + } + + /** + * 设置创建时间 + * + * @param createTime 创建时间 + */ + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + /** + * 获取更新时间 + * + * @return update_time - 更新时间 + */ + public Date getUpdateTime() { + return updateTime; + } + + /** + * 设置更新时间 + * + * @param updateTime 更新时间 + */ + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + + /** + * 获取最后登录时间 + * + * @return last_login_time - 最后登录时间 + */ + public Date getLastLoginTime() { + return lastLoginTime; + } + + /** + * 设置最后登录时间 + * + * @param lastLoginTime 最后登录时间 + */ + public void setLastLoginTime(Date lastLoginTime) { + this.lastLoginTime = lastLoginTime; + } + + public String getLoginIpAddress() { + return loginIpAddress; + } + + public void setLoginIpAddress(String loginIpAddress) { + this.loginIpAddress = loginIpAddress; + } + + public List getRoles() { + return roles; + } + + public void setRoles(List roles) { + this.roles = roles; + } + + public String getRolename() { + return rolename; + } + + public void setRolename(String rolename) { + this.rolename = rolename; + } +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/system/model/UserRole.java b/src/main/java/com/nbclass/system/model/UserRole.java new file mode 100644 index 0000000..3bc4074 --- /dev/null +++ b/src/main/java/com/nbclass/system/model/UserRole.java @@ -0,0 +1,82 @@ +package com.nbclass.system.model; + +import java.io.Serializable; + +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +public class UserRole implements Serializable { + /** + * + */ + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + /** + * 用户id + */ + private String userId; + + /** + * 角色id + */ + private String roleId; + + /** + * @return id + */ + public Integer getId() { + return id; + } + + /** + * @param id + */ + public void setId(Integer id) { + this.id = id; + } + + /** + * 获取用户id + * + * @return user_id - 用户id + */ + public String getUserId() { + return userId; + } + + /** + * 设置用户id + * + * @param userId 用户id + */ + public void setUserId(String userId) { + this.userId = userId == null ? null : userId.trim(); + } + + /** + * 获取角色id + * + * @return role_id - 角色id + */ + public String getRoleId() { + return roleId; + } + + /** + * 设置角色id + * + * @param roleId 角色id + */ + public void setRoleId(String roleId) { + this.roleId = roleId == null ? null : roleId.trim(); + } +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/system/model/enums/SysLogType.java b/src/main/java/com/nbclass/system/model/enums/SysLogType.java new file mode 100644 index 0000000..5f03dba --- /dev/null +++ b/src/main/java/com/nbclass/system/model/enums/SysLogType.java @@ -0,0 +1,48 @@ +package com.nbclass.system.model.enums; + +/** + * i系统日志类型枚举 + * @author Leon + * @datetime 2020年6月3日 下午5:34:36 + */ +public enum SysLogType { + + xtgl(1, "系统管理"), + + login(2, "登录日志"), + + dict(3, "字典管理"), + + cases(4, "案例管理") + ; + + // 枚举值 + private final int key; + + // 枚举描述 + private final String desc; + + + SysLogType(final int key, final String desc ) { + this.key = key; + this.desc = desc; + } + + public int key() { + return key; + } + + public String desc() { + return desc; + } + + public static String getNameByCode(int key){ + for(SysLogType entity : SysLogType.values()){ + if(key == entity.key){ + return entity.desc; + } + } + return null; + } + +} diff --git a/src/main/java/com/nbclass/system/service/PermissionService.java b/src/main/java/com/nbclass/system/service/PermissionService.java new file mode 100644 index 0000000..a45c3ff --- /dev/null +++ b/src/main/java/com/nbclass/system/service/PermissionService.java @@ -0,0 +1,84 @@ +package com.nbclass.system.service; + +import java.util.List; +import java.util.Set; + +import com.nbclass.system.model.Permission; +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +public interface PermissionService { + + /** + * 根据用户id查询权限集合 + * @param userId + * @return set + */ + Set findPermsByUserId(String userId); + + /** + * 查询全部权限 + * @param status + * @return list + */ + List selectAll(Integer status); + + /** + * 查询全部菜单 + * @param status + * @return list + */ + List selectAllMenuName(Integer status); + + /** + * 根据用户id查询权限集合 + * @param userId + * @return list + */ + List selectMenuByUserId(String userId); + + /** + * 插入权限 + * @param permission + * @return int + */ + int insert(Permission permission); + + /** + * 根据权限id更新状态 + * @param permissionId + * @param status + * @return int + */ + int updateStatus(String permissionId, Integer status); + + /** + * 根据权限id查询权限 + * @param permissionId + * @return permission + */ + Permission findByPermissionId(String permissionId); + + /** + * 根据id查询权限 + * @param id + * @return permission + */ + Permission findById(Integer id); + + /** + * 更新权限 + * @param permission + * @return int + */ + int updateByPermissionId(Permission permission); + + /** + * 查询子权限条数 + * @param permissionId + * @return int + */ + int selectSubPermsByPermissionId(String permissionId); +} diff --git a/src/main/java/com/nbclass/system/service/RoleService.java b/src/main/java/com/nbclass/system/service/RoleService.java new file mode 100644 index 0000000..8b3a015 --- /dev/null +++ b/src/main/java/com/nbclass/system/service/RoleService.java @@ -0,0 +1,91 @@ +package com.nbclass.system.service; + +import java.util.List; +import java.util.Set; + +import com.nbclass.system.model.Permission; +import com.nbclass.system.model.Role; +import com.nbclass.system.model.User; +import com.nbclass.vo.base.ResponseVo; + +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +public interface RoleService { + + /** + * 根据用户id查询角色集合 + * @param userId + * @return set + */ + Set findRoleByUserId(String userId); + + /** + * 根据条件查询角色列表 + * @param role + * @return list + */ + List selectRoles(Role role); + + /** + * 插入角色 + * @param role + * @return int + */ + int insert(Role role); + + /** + * 批量更新状态 + * @param roleIds + * @param status + * @return int + */ + int updateStatusBatch(List roleIds, Integer status); + + /** + * 根据id查询角色 + * @param id + * @return role + */ + Role findById(Integer id); + + /** + * 根据角色id更新角色信息 + * @param role + * @return int + */ + int updateByRoleId(Role role); + + /** + * 根据角色id查询权限集合 + * @param roleId + * @return list + */ + List findPermissionsByRoleId(String roleId); + + /** + * 根据角色id保存分配权限 + * @param roleId + * @param permissionIdsList + * @return list + */ + ResponseVo addAssignPermission(String roleId, List permissionIdsList); + + /** + * 根据角色id下的所有用户 + * @param roleId + * @return list + */ + List findByRoleId(String roleId); + + /** + * 根据角色id下的所有用户 + * @param roleIds + * @return list + */ + List findByRoleIds(List roleIds); + + +} diff --git a/src/main/java/com/nbclass/system/service/SysLogService.java b/src/main/java/com/nbclass/system/service/SysLogService.java new file mode 100644 index 0000000..e91d9e5 --- /dev/null +++ b/src/main/java/com/nbclass/system/service/SysLogService.java @@ -0,0 +1,34 @@ +package com.nbclass.system.service; + +import java.util.List; + +import com.nbclass.system.model.SysLog; + +/** + * 系统日志Service + * @author Leon + * @datetime 2020年6月3日 下午5:17:36 + */ +public interface SysLogService { + + + /** + * 添加 + * @param entity + */ + public void add(SysLog entity); + + /** + * 删除 + * @param ids + */ + public void delete(List ids); + + /** + * 根据条件查询列表 + * @param entity + * @return + */ + public List getList(SysLog entity); + +} diff --git a/src/main/java/com/nbclass/system/service/UserService.java b/src/main/java/com/nbclass/system/service/UserService.java new file mode 100644 index 0000000..4518f9c --- /dev/null +++ b/src/main/java/com/nbclass/system/service/UserService.java @@ -0,0 +1,101 @@ +package com.nbclass.system.service; + +import java.io.Serializable; +import java.util.List; + +import com.nbclass.activity.model.Application; +import com.nbclass.system.model.User; +import com.nbclass.vo.UserOnlineVo; +import com.nbclass.vo.base.ResponseVo; +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +public interface UserService { + + /** + * 根据用户名查询用户 + * @param username + * @return user + */ + User selectByUsername(String username); + + /** + * 注册用户 + * @param user + * @return int + */ + int register(User user); + + /** + * 更新最后登录时间 + * @param user + */ + void updateLastLoginTime(User user); + + /** + * 根据条件查询用户列表 + * @param user + * @return list + */ + List selectUsers(User user); + + /** + * 根据用户id查询用户 + * @param userId + * @return user + */ + User selectByUserId(String userId); + + /** + * 根据用户id更新用户信息 + * @param user + * @return int + */ + int updateByUserId(User user); + + /** + * 根据用户id集合批量更新用户状态 + * @param userIds + * @param status + * @return int + */ + int updateStatusBatch(List userIds, Integer status); + + /** + * 根据用户id分配角色集合 + * @param userId + * @param roleIds + * @return int + */ + ResponseVo addAssignRole(String userId, List roleIds); + + /** + * 根据主键更新用户信息 + * @param user + * @return int + */ + int updateUserByPrimaryKey(User user); + + /** + * 查询在线用户 + * @param userOnlineVo + * @return list + */ + List selectOnlineUsers(UserOnlineVo userOnlineVo); + + /** + * 踢出用户 + * @param sessionId 会话id + * @param username 用户名 + */ + void kickout(Serializable sessionId, String username); + + /** + * 修改企业微信用户信息 + * @param user + */ + public void updateQyWxUser(User user); + +} diff --git a/src/main/java/com/nbclass/system/service/impl/PermissionServiceImpl.java b/src/main/java/com/nbclass/system/service/impl/PermissionServiceImpl.java new file mode 100644 index 0000000..b0fe941 --- /dev/null +++ b/src/main/java/com/nbclass/system/service/impl/PermissionServiceImpl.java @@ -0,0 +1,80 @@ +package com.nbclass.system.service.impl; + +import com.nbclass.system.mapper.PermissionMapper; +import com.nbclass.system.model.Permission; +import com.nbclass.system.service.PermissionService; +import com.nbclass.util.CoreConst; +import com.nbclass.util.UUIDUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.List; +import java.util.Set; +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +@Service +public class PermissionServiceImpl implements PermissionService { + @Autowired + private PermissionMapper permissionMapper; + + @Override + public Set findPermsByUserId(String userId) { + return permissionMapper.findPermsByUserId(userId); + } + + @Override + public List selectAll(Integer status) { + return permissionMapper.selectAllPerms(status); + } + + @Override + public List selectAllMenuName(Integer status) { + return permissionMapper.selectAllMenuName(status); + } + + @Override + public List selectMenuByUserId(String userId) { + return permissionMapper.selectMenuByUserId(userId); + } + + @Override + public int insert(Permission permission) { + Date date = new Date(); + permission.setPermissionId(UUIDUtil.getUniqueIdByUUId()); + permission.setStatus(CoreConst.STATUS_VALID); + permission.setCreateTime(date); + permission.setUpdateTime(date); + return permissionMapper.insert(permission); + } + + @Override + public int updateStatus(String permissionId,Integer status) { + return permissionMapper.updateStatusByPermissionId(permissionId,status); + } + + @Override + public Permission findByPermissionId(String permissionId) { + return permissionMapper.selectByPermissionId(permissionId); + } + + @Override + public Permission findById(Integer id) { + Permission permission = new Permission(); + permission.setId(id); + return permissionMapper.selectByPrimaryKey(permission); + } + + @Override + public int updateByPermissionId(Permission permission) { + return permissionMapper.updateByPermissionId(permission); + } + + @Override + public int selectSubPermsByPermissionId(String permissionId) { + return permissionMapper.selectSubPermsByPermissionId(permissionId); + } +} diff --git a/src/main/java/com/nbclass/system/service/impl/RoleServiceImpl.java b/src/main/java/com/nbclass/system/service/impl/RoleServiceImpl.java new file mode 100644 index 0000000..31f3407 --- /dev/null +++ b/src/main/java/com/nbclass/system/service/impl/RoleServiceImpl.java @@ -0,0 +1,116 @@ +package com.nbclass.system.service.impl; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.nbclass.system.mapper.PermissionMapper; +import com.nbclass.system.mapper.RoleMapper; +import com.nbclass.system.mapper.RolePermissionMapper; +import com.nbclass.system.mapper.UserMapper; +import com.nbclass.system.model.Permission; +import com.nbclass.system.model.Role; +import com.nbclass.system.model.RolePermission; +import com.nbclass.system.model.User; +import com.nbclass.system.service.RoleService; +import com.nbclass.util.ResultUtil; +import com.nbclass.util.UUIDUtil; +import com.nbclass.vo.base.ResponseVo; + +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +@Service +public class RoleServiceImpl implements RoleService { + + @Autowired + private RoleMapper roleMapper; + @Autowired + private PermissionMapper permissionMapper; + @Autowired + private RolePermissionMapper rolePermissionMapper; + @Autowired + private UserMapper userMapper; + + @Override + public Set findRoleByUserId(String userId) { + return roleMapper.findRoleByUserId(userId); + } + + @Override + public List selectRoles(Role role) { + return roleMapper.selectRoles(role); + } + + @Override + public int insert(Role role) { + role.setRoleId(UUIDUtil.getUniqueIdByUUId()); + role.setStatus(1); + role.setCreateTime(new Date()); + return roleMapper.insert(role); + } + + @Override + public int updateStatusBatch(List roleIds, Integer status) { + Map params = new HashMap(2); + params.put("roleIds",roleIds); + params.put("status",status); + return roleMapper.updateStatusBatch(params); + } + + @Override + public Role findById(Integer id) { + Role role = new Role(); + role.setId(id); + return roleMapper.selectByPrimaryKey(role); + } + + @Override + public int updateByRoleId(Role role) { + Map params = new HashMap<>(3); + params.put("name",role.getName()); + params.put("description",role.getDescription()); + params.put("role_id",role.getRoleId()); + return roleMapper.updateByRoleId(params); + } + + @Override + public List findPermissionsByRoleId(String roleId) { + return permissionMapper.findByRoleId(roleId); + } + + @Override + public ResponseVo addAssignPermission(String roleId, List permissionIds) { + try{ + RolePermission rolePermission = new RolePermission(); + rolePermission.setRoleId(roleId); + rolePermissionMapper.delete(rolePermission); + for(String permissionId : permissionIds){ + rolePermission.setId(null); + rolePermission.setPermissionId(permissionId); + rolePermissionMapper.insert(rolePermission); + } + return ResultUtil.success("分配权限成功"); + }catch(Exception e){ + return ResultUtil.error("分配权限失败"); + } + } + + @Override + public List findByRoleId(String roleId) { + return userMapper.findByRoleId(roleId); + } + + @Override + public List findByRoleIds(List roleIds) { + return userMapper.findByRoleIds(roleIds); + } + +} diff --git a/src/main/java/com/nbclass/system/service/impl/SysLogServiceImpl.java b/src/main/java/com/nbclass/system/service/impl/SysLogServiceImpl.java new file mode 100644 index 0000000..14967f1 --- /dev/null +++ b/src/main/java/com/nbclass/system/service/impl/SysLogServiceImpl.java @@ -0,0 +1,57 @@ +package com.nbclass.system.service.impl; + +import java.util.List; + +import javax.annotation.Resource; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import com.nbclass.exception.ParameterException; +import com.nbclass.system.mapper.SysLogMapper; +import com.nbclass.system.model.SysLog; +import com.nbclass.system.model.enums.SysLogType; +import com.nbclass.system.service.SysLogService; + +/** + * + * @author Leon + * @datetime 2020年6月3日 下午5:18:54 + */ +@Service +public class SysLogServiceImpl implements SysLogService { + + @Resource + private SysLogMapper mapper; + + @Override + public void add(SysLog entity) { + /*if(entity.getType() == null || entity.getType() < 1) { + throw new ParameterException("type不能为空"); + }*/ + if(StringUtils.isBlank(entity.getDescription())) { + throw new ParameterException("描述不能为空"); + } + mapper.insertSelective(entity); + } + + @Override + public void delete(List ids) { + if(ids == null || ids.isEmpty()){ + throw new ParameterException("id不能为空"); + } + mapper.deleteByIds(ids); + } + + @Override + public List getList(SysLog entity) { + List list = mapper.getList(entity); + if(list!=null && !list.isEmpty()) { + for (SysLog sysLog : list) { + sysLog.setTypeName(SysLogType.getNameByCode(sysLog.getType())); + } + } + return list; + } + +} diff --git a/src/main/java/com/nbclass/system/service/impl/UserServiceImpl.java b/src/main/java/com/nbclass/system/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..e0399cf --- /dev/null +++ b/src/main/java/com/nbclass/system/service/impl/UserServiceImpl.java @@ -0,0 +1,231 @@ +package com.nbclass.system.service.impl; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.apache.shiro.session.Session; +import org.apache.shiro.subject.SimplePrincipalCollection; +import org.apache.shiro.subject.support.DefaultSubjectContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.nbclass.exception.ParameterException; +import com.nbclass.system.mapper.UserMapper; +import com.nbclass.system.mapper.UserRoleMapper; +import com.nbclass.system.model.User; +import com.nbclass.system.model.UserRole; +import com.nbclass.system.service.UserService; +import com.nbclass.util.ResultUtil; +import com.nbclass.vo.UserOnlineVo; +import com.nbclass.vo.base.ResponseVo; + +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +@Service +public class UserServiceImpl implements UserService { + + /* + @Autowired + private RedisSessionDAO redisSessionDAO; + + @Autowired + private SessionManager sessionManager; + + @Autowired + private RedisCacheManager redisCacheManager; + */ + + + @Autowired + private UserMapper userMapper; + @Autowired + private UserRoleMapper userRoleMapper; + + @Override + public User selectByUsername(String username) { + return userMapper.selectByUsername(username); + } + + @Override + public int register(User user) { + int a = userMapper.insert(user); + return a; + } + + @Override + public void updateLastLoginTime(User user) { + userMapper.updateLastLoginTime(user); + } + + @Override + public List selectUsers(User user) { + return userMapper.selectUsers(user); + } + + @Override + public User selectByUserId(String userId) { + return userMapper.selectByUserId(userId); + } + + @Override + public int updateByUserId(User user) { + return userMapper.updateByUserId(user); + } + + @Override + public int updateStatusBatch(List userIds,Integer status) { + Map params = new HashMap(2); + params.put("userIds",userIds); + params.put("status",status); + return userMapper.updateStatusBatch(params); + } + + @Override + public ResponseVo addAssignRole(String userId, List roleIds) { + try{ + UserRole userRole = new UserRole(); + userRole.setUserId(userId); + userRoleMapper.delete(userRole); + for(String roleId :roleIds){ + userRole.setId(null); + userRole.setRoleId(roleId); + userRoleMapper.insert(userRole); + } + return ResultUtil.success("分配角色成功"); + }catch(Exception e){ + return ResultUtil.error("分配角色失败"); + } + } + + @Override + public int updateUserByPrimaryKey(User user) { + return userMapper.updateByPrimaryKey(user); + } + + @Override + public List selectOnlineUsers(UserOnlineVo userVo) { + List onlineUserList = new ArrayList(); + /* + // 因为我们是用redis实现了shiro的session的Dao,而且是采用了shiro+redis这个插件 + // 所以从spring容器中获取redisSessionDAO + // 来获取session列表. + Collection sessions = redisSessionDAO.getActiveSessions(); + Iterator it = sessions.iterator(); + // 遍历session + while (it.hasNext()) { + // 这是shiro已经存入session的 + // 现在直接取就是了 + Session session = it.next(); + //标记为已提出的不加入在线列表 + if(session.getAttribute("kickout") != null) { + continue; + } + UserOnlineVo onlineUser = getSessionBo(session); + if(onlineUser!=null){ + 用户名搜索 + if(StringUtils.isNotBlank(userVo.getUsername())){ + if(onlineUser.getUsername().contains(userVo.getUsername()) ){ + onlineUserList.add(onlineUser); + } + }else{ + onlineUserList.add(onlineUser); + } + } + } + */ + return onlineUserList; + } + + @Override + public void kickout(Serializable sessionId, String username) { + /* + getSessionBysessionId(sessionId).setAttribute("kickout", true); + //读取缓存,找到并从队列中移除 + Cache> cache = redisCacheManager.getCache(redisCacheManager.getKeyPrefix()+username); + Deque deques = cache.get(username); + for(Serializable deque : deques){ + if(sessionId.equals(deque)){ + deques.remove(deque); + break; + } + } + cache.put(username,deques); + */ + } + + /* + private Session getSessionBysessionId(Serializable sessionId){ + Session kickoutSession = sessionManager.getSession(new DefaultSessionKey(sessionId)); + return kickoutSession; + } + */ + + @SuppressWarnings("unused") + private UserOnlineVo getSessionBo(Session session){ + //获取session登录信息。 + Object obj = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY); + if(null == obj){ + return null; + } + //确保是 SimplePrincipalCollection对象。 + if(obj instanceof SimplePrincipalCollection){ + SimplePrincipalCollection spc = (SimplePrincipalCollection)obj; + obj = spc.getPrimaryPrincipal(); + if(null != obj && obj instanceof User){ + User user = (User) obj; + //存储session + user 综合信息 + UserOnlineVo userBo = new UserOnlineVo(); + //最后一次和系统交互的时间 + userBo.setLastAccess(session.getLastAccessTime()); + //主机的ip地址 + userBo.setHost(user.getLoginIpAddress()); + //session ID + userBo.setSessionId(session.getId().toString()); + //最后登录时间 + userBo.setLastLoginTime(user.getLastLoginTime()); + //回话到期 ttl(ms) + userBo.setTimeout(session.getTimeout()); + //session创建时间 + userBo.setStartTime(session.getStartTimestamp()); + //是否踢出 + userBo.setSessionStatus(false); + /*用户名*/ + userBo.setUsername(user.getUsername()); + return userBo; + } + } + return null; + } + + @Override + public void updateQyWxUser(User user) { + if(user == null)return; + if(StringUtils.isBlank(user.getUsername())) { + throw new ParameterException("用户名不能为空"); + } + User dbUser = selectByUsername(user.getUsername()); + if(dbUser != null && StringUtils.isNotBlank(dbUser.getUserId())) { + if(StringUtils.isNotBlank(user.getEmail()))dbUser.setEmail(user.getEmail()); + if(StringUtils.isNotBlank(user.getPhone()))dbUser.setPhone(user.getPhone()); + if(user.getSex()!=null)dbUser.setSex(user.getSex()); + updateByUserId(dbUser); + }else { + user.setCreateTime(new Date()); + userMapper.insertSelective(user); + // 更新用户角色 + List roleIds = new ArrayList(); + roleIds.add("3"); // 固定角色id为3 + addAssignRole(user.getUserId(), roleIds); + } + } + + +} diff --git a/src/main/java/com/nbclass/util/BCrypt.java b/src/main/java/com/nbclass/util/BCrypt.java new file mode 100644 index 0000000..cb9d83c --- /dev/null +++ b/src/main/java/com/nbclass/util/BCrypt.java @@ -0,0 +1,777 @@ +// Copyright (c) 2006 Damien Miller +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +package com.nbclass.util; + +import java.io.UnsupportedEncodingException; +import java.security.SecureRandom; + +/** + * BCrypt implements OpenBSD-style Blowfish password hashing using + * the scheme described in "A Future-Adaptable Password Scheme" by + * Niels Provos and David Mazieres. + *

+ * This password hashing system tries to thwart off-line password + * cracking using a computationally-intensive hashing algorithm, + * based on Bruce Schneier's Blowfish cipher. The work factor of + * the algorithm is parameterised, so it can be increased as + * computers get faster. + *

+ * Usage is really simple. To hash a password for the first time, + * call the hashpw method with a random salt, like this: + *

+ * + * String pw_hash = BCrypt.hashpw(plain_password, BCrypt.gensalt());
+ *
+ *

+ * To check whether a plaintext password matches one that has been + * hashed previously, use the checkpw method: + *

+ * + * if (BCrypt.checkpw(candidate_password, stored_hash))
+ *     System.out.println("It matches");
+ * else
+ *     System.out.println("It does not match");
+ *
+ *

+ * The gensalt() method takes an optional parameter (log_rounds) + * that determines the computational complexity of the hashing: + *

+ * + * String strong_salt = BCrypt.gensalt(10)
+ * String stronger_salt = BCrypt.gensalt(12)
+ *
+ *

+ * The amount of work increases exponentially (2**log_rounds), so + * each increment is twice as much work. The default log_rounds is + * 10, and the valid range is 4 to 30. + * + * @author Damien Miller + * @version 0.2 + */ +public class BCrypt { + // BCrypt parameters + private static final int GENSALT_DEFAULT_LOG2_ROUNDS = 10; + private static final int BCRYPT_SALT_LEN = 16; + + // Blowfish parameters + private static final int BLOWFISH_NUM_ROUNDS = 16; + + // Initial contents of key schedule + private static final int P_orig[] = { + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, + 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, + 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, + 0x9216d5d9, 0x8979fb1b + }; + private static final int S_orig[] = { + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, + 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, + 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, + 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, + 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, + 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, + 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, + 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, + 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, + 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, + 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, + 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, + 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, + 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, + 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, + 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, + 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, + 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, + 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, + 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, + 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, + 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, + 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, + 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, + 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, + 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, + 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, + 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, + 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, + 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, + 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, + 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, + 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, + 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, + 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, + 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, + 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, + 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, + 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, + 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, + 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, + 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, + 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, + 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, + 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, + 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, + 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, + 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, + 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, + 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, + 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, + 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, + 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, + 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, + 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, + 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, + 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, + 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, + 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, + 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, + 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, + 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, + 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, + 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, + 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, + 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, + 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, + 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, + 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, + 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, + 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, + 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, + 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, + 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, + 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, + 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, + 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, + 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, + 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, + 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, + 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, + 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, + 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, + 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, + 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, + 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, + 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, + 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, + 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, + 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, + 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, + 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, + 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, + 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, + 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, + 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, + 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, + 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, + 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, + 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, + 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, + 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, + 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, + 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, + 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, + 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, + 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, + 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, + 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, + 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, + 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, + 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, + 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, + 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, + 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, + 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, + 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, + 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, + 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, + 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, + 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, + 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, + 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, + 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, + 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, + 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, + 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, + 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, + 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, + 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, + 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, + 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, + 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, + 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, + 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, + 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, + 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, + 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, + 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, + 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, + 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, + 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, + 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, + 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, + 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, + 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, + 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, + 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, + 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, + 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, + 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, + 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, + 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, + 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, + 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, + 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, + 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, + 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, + 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, + 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0, + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, + 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, + 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, + 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, + 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, + 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, + 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, + 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, + 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, + 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, + 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, + 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, + 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, + 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, + 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, + 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, + 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, + 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, + 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, + 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, + 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, + 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, + 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, + 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, + 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, + 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, + 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, + 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, + 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, + 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, + 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, + 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, + 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, + 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, + 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, + 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, + 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, + 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, + 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, + 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, + 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, + 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, + 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, + 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, + 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, + 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, + 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, + 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, + 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, + 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, + 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, + 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, + 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, + 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 + }; + + // bcrypt IV: "OrpheanBeholderScryDoubt". The C implementation calls + // this "ciphertext", but it is really plaintext or an IV. We keep + // the name to make code comparison easier. + static private final int bf_crypt_ciphertext[] = { + 0x4f727068, 0x65616e42, 0x65686f6c, + 0x64657253, 0x63727944, 0x6f756274 + }; + + // Table for Base64 encoding + static private final char base64_code[] = { + '.', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', + '6', '7', '8', '9' + }; + + // Table for Base64 decoding + static private final byte index_64[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 0, 1, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, -1, -1, + -1, -1, -1, -1, -1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + -1, -1, -1, -1, -1, -1, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, -1, -1, -1, -1, -1 + }; + + // Expanded Blowfish key + private int P[]; + private int S[]; + + /** + * Encode a byte array using bcrypt's slightly-modified base64 + * encoding scheme. Note that this is *not* compatible with + * the standard MIME-base64 encoding. + * + * @param d the byte array to encode + * @param len the number of bytes to encode + * @return base64-encoded string + * @exception IllegalArgumentException if the length is invalid + */ + private static String encode_base64(byte d[], int len) + throws IllegalArgumentException { + int off = 0; + StringBuffer rs = new StringBuffer(); + int c1, c2; + + if (len <= 0 || len > d.length) + throw new IllegalArgumentException ("Invalid len"); + + while (off < len) { + c1 = d[off++] & 0xff; + rs.append(base64_code[(c1 >> 2) & 0x3f]); + c1 = (c1 & 0x03) << 4; + if (off >= len) { + rs.append(base64_code[c1 & 0x3f]); + break; + } + c2 = d[off++] & 0xff; + c1 |= (c2 >> 4) & 0x0f; + rs.append(base64_code[c1 & 0x3f]); + c1 = (c2 & 0x0f) << 2; + if (off >= len) { + rs.append(base64_code[c1 & 0x3f]); + break; + } + c2 = d[off++] & 0xff; + c1 |= (c2 >> 6) & 0x03; + rs.append(base64_code[c1 & 0x3f]); + rs.append(base64_code[c2 & 0x3f]); + } + return rs.toString(); + } + + /** + * Look up the 3 bits base64-encoded by the specified character, + * range-checking againt conversion table + * @param x the base64-encoded value + * @return the decoded value of x + */ + private static byte char64(char x) { + if ((int)x < 0 || (int)x > index_64.length) + return -1; + return index_64[(int)x]; + } + + /** + * Decode a string encoded using bcrypt's base64 scheme to a + * byte array. Note that this is *not* compatible with + * the standard MIME-base64 encoding. + * @param s the string to decode + * @param maxolen the maximum number of bytes to decode + * @return an array containing the decoded bytes + * @throws IllegalArgumentException if maxolen is invalid + */ + private static byte[] decode_base64(String s, int maxolen) + throws IllegalArgumentException { + StringBuffer rs = new StringBuffer(); + int off = 0, slen = s.length(), olen = 0; + byte ret[]; + byte c1, c2, c3, c4, o; + + if (maxolen <= 0) + throw new IllegalArgumentException ("Invalid maxolen"); + + while (off < slen - 1 && olen < maxolen) { + c1 = char64(s.charAt(off++)); + c2 = char64(s.charAt(off++)); + if (c1 == -1 || c2 == -1) + break; + o = (byte)(c1 << 2); + o |= (c2 & 0x30) >> 4; + rs.append((char)o); + if (++olen >= maxolen || off >= slen) + break; + c3 = char64(s.charAt(off++)); + if (c3 == -1) + break; + o = (byte)((c2 & 0x0f) << 4); + o |= (c3 & 0x3c) >> 2; + rs.append((char)o); + if (++olen >= maxolen || off >= slen) + break; + c4 = char64(s.charAt(off++)); + o = (byte)((c3 & 0x03) << 6); + o |= c4; + rs.append((char)o); + ++olen; + } + + ret = new byte[olen]; + for (off = 0; off < olen; off++) + ret[off] = (byte)rs.charAt(off); + return ret; + } + + /** + * Blowfish encipher a single 64-bit block encoded as + * two 32-bit halves + * @param lr an array containing the two 32-bit half blocks + * @param off the position in the array of the blocks + */ + private final void encipher(int lr[], int off) { + int i, n, l = lr[off], r = lr[off + 1]; + + l ^= P[0]; + for (i = 0; i <= BLOWFISH_NUM_ROUNDS - 2;) { + // Feistel substitution on left word + n = S[(l >> 24) & 0xff]; + n += S[0x100 | ((l >> 16) & 0xff)]; + n ^= S[0x200 | ((l >> 8) & 0xff)]; + n += S[0x300 | (l & 0xff)]; + r ^= n ^ P[++i]; + + // Feistel substitution on right word + n = S[(r >> 24) & 0xff]; + n += S[0x100 | ((r >> 16) & 0xff)]; + n ^= S[0x200 | ((r >> 8) & 0xff)]; + n += S[0x300 | (r & 0xff)]; + l ^= n ^ P[++i]; + } + lr[off] = r ^ P[BLOWFISH_NUM_ROUNDS + 1]; + lr[off + 1] = l; + } + + /** + * Cycically extract a word of key material + * @param data the string to extract the data from + * @param offp a "pointer" (as a one-entry array) to the + * current offset into data + * @return the next word of material from data + */ + private static int streamtoword(byte data[], int offp[]) { + int i; + int word = 0; + int off = offp[0]; + + for (i = 0; i < 4; i++) { + word = (word << 8) | (data[off] & 0xff); + off = (off + 1) % data.length; + } + + offp[0] = off; + return word; + } + + /** + * Initialise the Blowfish key schedule + */ + private void init_key() { + P = (int[])P_orig.clone(); + S = (int[])S_orig.clone(); + } + + /** + * Key the Blowfish cipher + * @param key an array containing the key + */ + private void key(byte key[]) { + int i; + int koffp[] = { 0 }; + int lr[] = { 0, 0 }; + int plen = P.length, slen = S.length; + + for (i = 0; i < plen; i++) + P[i] = P[i] ^ streamtoword(key, koffp); + + for (i = 0; i < plen; i += 2) { + encipher(lr, 0); + P[i] = lr[0]; + P[i + 1] = lr[1]; + } + + for (i = 0; i < slen; i += 2) { + encipher(lr, 0); + S[i] = lr[0]; + S[i + 1] = lr[1]; + } + } + + /** + * Perform the "enhanced key schedule" step described by + * Provos and Mazieres in "A Future-Adaptable Password Scheme" + * http://www.openbsd.org/papers/bcrypt-paper.ps + * @param data salt information + * @param key password information + */ + private void ekskey(byte data[], byte key[]) { + int i; + int koffp[] = { 0 }, doffp[] = { 0 }; + int lr[] = { 0, 0 }; + int plen = P.length, slen = S.length; + + for (i = 0; i < plen; i++) + P[i] = P[i] ^ streamtoword(key, koffp); + + for (i = 0; i < plen; i += 2) { + lr[0] ^= streamtoword(data, doffp); + lr[1] ^= streamtoword(data, doffp); + encipher(lr, 0); + P[i] = lr[0]; + P[i + 1] = lr[1]; + } + + for (i = 0; i < slen; i += 2) { + lr[0] ^= streamtoword(data, doffp); + lr[1] ^= streamtoword(data, doffp); + encipher(lr, 0); + S[i] = lr[0]; + S[i + 1] = lr[1]; + } + } + + /** + * Perform the central password hashing step in the + * bcrypt scheme + * @param password the password to hash + * @param salt the binary salt to hash with the password + * @param log_rounds the binary logarithm of the number + * of rounds of hashing to apply + * @param cdata the plaintext to encrypt + * @return an array containing the binary hashed password + */ + public byte[] crypt_raw(byte password[], byte salt[], int log_rounds, + int cdata[]) { + int rounds, i, j; + int clen = cdata.length; + byte ret[]; + + if (log_rounds < 4 || log_rounds > 30) + throw new IllegalArgumentException ("Bad number of rounds"); + rounds = 1 << log_rounds; + if (salt.length != BCRYPT_SALT_LEN) + throw new IllegalArgumentException ("Bad salt length"); + + init_key(); + ekskey(salt, password); + for (i = 0; i != rounds; i++) { + key(password); + key(salt); + } + + for (i = 0; i < 64; i++) { + for (j = 0; j < (clen >> 1); j++) + encipher(cdata, j << 1); + } + + ret = new byte[clen * 4]; + for (i = 0, j = 0; i < clen; i++) { + ret[j++] = (byte)((cdata[i] >> 24) & 0xff); + ret[j++] = (byte)((cdata[i] >> 16) & 0xff); + ret[j++] = (byte)((cdata[i] >> 8) & 0xff); + ret[j++] = (byte)(cdata[i] & 0xff); + } + return ret; + } + + /** + * Hash a password using the OpenBSD bcrypt scheme + * @param password the password to hash + * @param salt the salt to hash with (perhaps generated + * using BCrypt.gensalt) + * @return the hashed password + */ + public static String hashpw(String password, String salt) { + BCrypt B; + String real_salt; + byte passwordb[], saltb[], hashed[]; + char minor = (char)0; + int rounds, off = 0; + StringBuffer rs = new StringBuffer(); + + if (salt.charAt(0) != '$' || salt.charAt(1) != '2') + throw new IllegalArgumentException ("Invalid salt version"); + if (salt.charAt(2) == '$') + off = 3; + else { + minor = salt.charAt(2); + if (minor != 'a' || salt.charAt(3) != '$') + throw new IllegalArgumentException ("Invalid salt revision"); + off = 4; + } + + // Extract number of rounds + if (salt.charAt(off + 2) > '$') + throw new IllegalArgumentException ("Missing salt rounds"); + rounds = Integer.parseInt(salt.substring(off, off + 2)); + + real_salt = salt.substring(off + 3, off + 25); + try { + passwordb = (password + (minor >= 'a' ? "\000" : "")).getBytes("UTF-8"); + } catch (UnsupportedEncodingException uee) { + throw new AssertionError("UTF-8 is not supported"); + } + + saltb = decode_base64(real_salt, BCRYPT_SALT_LEN); + + B = new BCrypt(); + hashed = B.crypt_raw(passwordb, saltb, rounds, + (int[])bf_crypt_ciphertext.clone()); + + rs.append("$2"); + if (minor >= 'a') + rs.append(minor); + rs.append("$"); + if (rounds < 10) + rs.append("0"); + if (rounds > 30) { + throw new IllegalArgumentException( + "rounds exceeds maximum (30)"); + } + rs.append(Integer.toString(rounds)); + rs.append("$"); + rs.append(encode_base64(saltb, saltb.length)); + rs.append(encode_base64(hashed, + bf_crypt_ciphertext.length * 4 - 1)); + return rs.toString(); + } + + /** + * Generate a salt for use with the BCrypt.hashpw() method + * @param log_rounds the log2 of the number of rounds of + * hashing to apply - the work factor therefore increases as + * 2**log_rounds. + * @param random an instance of SecureRandom to use + * @return an encoded salt value + */ + public static String gensalt(int log_rounds, SecureRandom random) { + StringBuffer rs = new StringBuffer(); + byte rnd[] = new byte[BCRYPT_SALT_LEN]; + + random.nextBytes(rnd); + + rs.append("$2a$"); + if (log_rounds < 10) + rs.append("0"); + if (log_rounds > 30) { + throw new IllegalArgumentException( + "log_rounds exceeds maximum (30)"); + } + rs.append(Integer.toString(log_rounds)); + rs.append("$"); + rs.append(encode_base64(rnd, rnd.length)); + return rs.toString(); + } + + /** + * Generate a salt for use with the BCrypt.hashpw() method + * @param log_rounds the log2 of the number of rounds of + * hashing to apply - the work factor therefore increases as + * 2**log_rounds. + * @return an encoded salt value + */ + public static String gensalt(int log_rounds) { + return gensalt(log_rounds, new SecureRandom()); + } + + /** + * Generate a salt for use with the BCrypt.hashpw() method, + * selecting a reasonable default for the number of hashing + * rounds to apply + * @return an encoded salt value + */ + public static String gensalt() { + return gensalt(GENSALT_DEFAULT_LOG2_ROUNDS); + } + + /** + * Check that a plaintext password matches a previously hashed + * one + * @param plaintext the plaintext password to verify + * @param hashed the previously-hashed password + * @return true if the passwords match, false otherwise + */ + public static boolean checkpw(String plaintext, String hashed) { + byte hashed_bytes[]; + byte try_bytes[]; + try { + String try_pw = hashpw(plaintext, hashed); + hashed_bytes = hashed.getBytes("UTF-8"); + try_bytes = try_pw.getBytes("UTF-8"); + } catch (UnsupportedEncodingException uee) { + return false; + } + if (hashed_bytes.length != try_bytes.length) + return false; + byte ret = 0; + for (int i = 0; i < try_bytes.length; i++) + ret |= hashed_bytes[i] ^ try_bytes[i]; + return ret == 0; + } +} diff --git a/src/main/java/com/nbclass/util/CommonUtils.java b/src/main/java/com/nbclass/util/CommonUtils.java new file mode 100644 index 0000000..2de94e7 --- /dev/null +++ b/src/main/java/com/nbclass/util/CommonUtils.java @@ -0,0 +1,849 @@ +package com.nbclass.util; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.security.SecureRandom; +import java.sql.Timestamp; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.UUID; +import java.util.regex.Pattern; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CommonUtils { + + protected static Logger logger = LoggerFactory.getLogger(CommonUtils.class); + + + /** + * 转换Date类型为字符串类型 + * + * @param value + * @return + */ + public static String getSimpleDate(Date value) { + return getSimpleDate(value, "yyyy-MM-dd HH:mm:ss"); + } + + /** + * 转换Date类型为中文字符串类型 + * + * @param value + * @return + */ + public static String getChinieseDate(Date value) { + return getSimpleDate(value, "yyyy年MM月dd日HH时mm分"); + } + + /** + * 转换Date类型为字符串类型 + * + * @param value + * @return + */ + public static String getSimpleDate(Date value, String pattern) { + SimpleDateFormat formatter = new SimpleDateFormat(pattern); + return formatter.format(value); + } + + /** + * 判断字符串是否空或空字符串 + * + * @param str + * @return + */ + public static boolean isEmpty(String str) { + if (str == null || str.trim().length() == 0) { + return true; + } + return false; + } + + /** + * 判断字符串是否为非空 + * + * @param str + * @return + */ + public static boolean isNotEmpty(String str) { + if (str == null || str.trim().length() == 0) { + return false; + } + return true; + } + + /** + * 返回trim后的字符串,如空字符串,则直接返回空。 + * + * @param str + * @return + */ + public static String trimToEmpty(String str) { + if (str == null || str.trim().length() == 0) { + return null; + } + return str.trim(); + } + + /** + * 返回trim后的字符串,如果为null,则返回"" + * + * @param str + * @return + */ + public static String trimToEmptyForce(String str) { + if (str == null || str.trim().length() == 0) { + return ""; + } + return str.trim(); + } + + /** + * 判断字符是否为数值型 + * + * @param str + * @return + */ + public static boolean isNumeric(String str) { + try { + Integer.parseInt(str); + return true; + } catch (NumberFormatException e) { + return false; + } + + } + + /** + * 获取几月后的时间 + * + * @param d + * @param d + * @return + */ + public static Date nextMonth(Date d, int m) { + Calendar now = Calendar.getInstance(); + now.setTime(d); + now.set(Calendar.MONTH, now.get(Calendar.MONTH) + m); + return now.getTime(); + } + + /** + * 获取几天后的时间 + * + * @param d + * @param day + * @return + */ + public static Date nextDate(Date d, int day) { + Calendar now = Calendar.getInstance(); + now.setTime(d); + now.set(Calendar.DATE, now.get(Calendar.DATE) + day); + return now.getTime(); + } + + /** + * 获取几小时后的时间 + * + * @param d + * @param d + * @return + */ + public static Date nextHour(Date d, int hour) { + Calendar now = Calendar.getInstance(); + now.setTime(d); + now.set(Calendar.HOUR_OF_DAY, now.get(Calendar.HOUR_OF_DAY) + hour); + return now.getTime(); + } + + /** + * 获取几分钟后的时间 + * + * @param d + * @param minute + * @return + */ + public static Date nextMinute(Date d, int minute) { + Calendar now = Calendar.getInstance(); + now.setTime(d); + now.set(Calendar.MINUTE, now.get(Calendar.MINUTE) + minute); + return now.getTime(); + } + + /** + * 获取两个日期的间隔天数 + * + * @param startDay + * @param endDay + * @return + */ + public static int dayInterval(Date startDay, Date endDay) { + return (int) ((endDay.getTime() - startDay.getTime()) / (24 * 60 * 60 * 1000)); + } + + /** + * 转换String类型为Date类型 + * + * @param value + * @return + * @throws java.text.ParseException + */ + public static Date getSimpleDate(String value){ + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + try { + return formatter.parse(value); + } catch (ParseException e) { + } + return null; + } + + /** + * 转换String类型为Date类型 + * + * @param value + * @return + * @throws java.text.ParseException + */ + public static Date getSimpleDateBy(String value, String pattern){ + SimpleDateFormat formatter = new SimpleDateFormat(pattern); + try { + return formatter.parse(value); + } catch (ParseException e) { + } + return null; + } + + /** + * 转换String类型为Date类型 + * + * @param value + * @return + * @throws java.text.ParseException + */ + public static Date getSimpleDate2(String value) throws ParseException { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + return formatter.parse(value); + } + + /** + * 把时分秒置为0 + * + * @param date + * @return + */ + public static Date getDateOnly(Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MILLISECOND, 0); + return cal.getTime(); + } + + /** + * 首字母大写 + * + * @param name + * @return + */ + public static String getUpperName(String name) { + byte[] items = name.getBytes(); + items[0] = (byte) ((char) items[0] - 'a' + 'A'); + return new String(items); + } + + /** + * 判断字符串是否合法(不含有非法字符或中文) 若数组中其中一字符串含有非法字符,返回false,反之,返回true + * + * @param sarray + * @return + */ + public static boolean judgeIllegalChar(String[] sarray) { + boolean result = true; + if (sarray != null) { + Pattern pattern = Pattern.compile("^\\w+$"); + for (int i = 0; i < sarray.length; i++) { + if (!pattern.matcher(sarray[i]).matches()) { + result = false; + break; + } + } + } else { + result = false; + } + return result; + } + + /** + * 判断字符串是否为合法邮箱 + * + * @param email + * @return + */ + public static boolean judgeEmail(String email) { + boolean result = false; + if (email != null) { + Pattern pattern = Pattern + .compile("^([a-z0-9A-Z._-])+@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$"); + if (pattern.matcher(email).matches()) { + result = true; + } + } + return result; + } + + /** + * 判断字符串是否合法(不含有非法字符,可含中文) 若数组中其中一字符串含有非法字符,返回false,反之,返回true + * + * @param sarray + * @return + */ + public static boolean judgeIllegalCharAndChinese(String[] sarray) { + boolean result = true; + if (sarray != null) { + Pattern pattern = Pattern.compile("^[\u4e00-\u9fa5a-zA-Z0-9_-]+$"); + for (int i = 0; i < sarray.length; i++) { + if (sarray[i] == null || !pattern.matcher(sarray[i]).matches()) { + result = false; + break; + } + } + } else { + result = false; + } + return result; + } + + /** + * 判断字符串是否合法(不含 ' 字符,可含中文) 若数组中其中一字符串含有非法字符,返回false,反之,返回true + * + * @param sarray + * @return + */ + public static boolean judgePartIllegalCharAndChinese(String[] sarray) { + boolean result = true; + if (sarray != null) { + Pattern pattern = Pattern.compile("[^\']+"); + for (int i = 0; i < sarray.length; i++) { + if (sarray[i] == null || !pattern.matcher(sarray[i]).matches()) { + result = false; + break; + } + } + } else { + result = false; + } + return result; + } + + public static String apiEncode(Integer uid, Integer wuid) { + String randString = UUID.randomUUID().toString(); + String startString = randString.substring(0, 4); + String endString = randString.substring(0, 10); + String midString = "C"; + wuid = wuid << 2; + uid = uid << 3; + return startString + uid + midString + wuid + endString; + } + + public static Integer[] apiDecode(String key) { + key = key.substring(0, key.length() - 10).substring(4); + String[] array = key.split("C"); + Integer uid = Integer.parseInt(array[0]); + uid = uid >> 3; + Integer wuid = Integer.parseInt(array[1]); + wuid = wuid >> 2; + return new Integer[] { uid, wuid }; + } + + /** + * 分享链接编码 + * + * @param uid + * @return + */ + public static String shareEncode(Integer uid) { + String randString = UUID.randomUUID().toString(); + String startString = randString.substring(0, 4); + String endString = randString.substring(0, 10); + String midString = "C"; + uid = uid << 3; + return startString + uid + midString + endString; + } + + /** + * 分享链接解码 + * + * @param key + * @return + */ + public static Integer shareDecode(String key) { + key = key.substring(0, key.length() - 10).substring(4); + String[] array = key.split("C"); + Integer uid = Integer.parseInt(array[0]); + uid = uid >> 3; + return uid; + } + + /** + * 截取左边max个字符,ascll码大于255算两个字符,字符过长以...结尾 + * + * @param s + * @param max + * @return + */ + public static String left(String s, int max) { + char[] cs = s.toCharArray(); + int count = 0; + int last = cs.length; + for (int i = 0, len = last; i < len; i++) { + if (cs[i] > 255) { + count += 2; + } else { + count++; + } + if (count > max) { + last = i + 1; + break; + } + } + if (count <= max) { + return s; + } + max -= 3; + for (int i = last - 1; i >= 0; i--) { + if (cs[i] > 255) { + count -= 2; + } else { + count--; + } + if (count <= max) { + return s.substring(0, i) + "..."; + } + } + return "..."; + } + + /** + * 从指定的时间截取年月日。将时分秒毫秒都设置为0 + * + * @param source + * 原始时间 + * @return 将时分秒毫秒都设置为0的日期 + */ + public static Date trimDate(Date source) { + Calendar cal = Calendar.getInstance(); + cal.setTime(source); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + return cal.getTime(); + } + + /** + * 获取字符串的长度,中文占一个字符,英文数字占半个字符 + * + * @param value + * 指定的字符串 + * @return 字符串的长度 + */ + public static double length(String value) { + double valueLength = 0; + String chinese = "[\u4e00-\u9fa5]"; + for (int i = 0; i < value.length(); i++) { + String temp = value.substring(i, i + 1); + if (temp.matches(chinese)) { + valueLength += 1; + } else { + valueLength += 0.5; + } + } + return Math.ceil(valueLength); + } + + /** + * 生成一个随机码 + * + * @return + */ + /* + public static String getRandomCode() { + SimpleDateFormat millSecondFormat = new SimpleDateFormat( + "yyyyMMddHHmmssSSS"); + String prefix = millSecondFormat.format(new Date()); + Random random = new Random(); + int number = random.nextInt(100); + return prefix + number; + } + */ + + /** + * 计算两个时间之间的秒数,注意不能超过50年 + * @param start 开始时间 + * @param end 结束时间 + * @return + */ + public static int calSecondsBetween(Date start, Date end) { + long times = (end.getTime() - start.getTime()) / 1000; + return (int)times; + } + + public static java.sql.Date UtilDateToSQLDate(Date utilDate) { + if (utilDate == null) return null; + return new java.sql.Date(utilDate.getTime()); + } + + public static Timestamp UtilDateToSQLTimestamp(Date utilDate){ + if (utilDate == null) return null; + return new Timestamp(utilDate.getTime()); + } + + public static final String REGEX_MOBILE_EXACT = "^((13[0-9])|(14[5,7,9])|(15[0-3,5-9])|(16[6])|(17[0-3,5-8])|(18[0-9])|(19[89]))\\d{8}$"; + + /** + * 验证手机号(精确) + * @param phone 待验证文本 + * @return {@code true}: 匹配
{@code false}: 不匹配 + */ + public static boolean isMobile(String phone) { + boolean result = StringUtils.isNotBlank(phone) && Pattern.matches(REGEX_MOBILE_EXACT, phone); + return result; + } + + /** + * 获取随机代码 + * @param length 需要的长度 + * @return + */ + public static String getRandomCode(int length) { + char[] chs = { 'a', 'b', 'c', '1', '2', '3', 'd', 'e', 'f', + 'A', 'B', 'C', 'D', 'E', 'F', + '4', '5', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', + '6', '8', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', + 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '6', '7', '8', '9', + '2', '5', '9', + 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; + SecureRandom random = new SecureRandom(); + char[] value = new char[length]; + for (int i = 0; i < length; i++) { + value[i] = chs[random.nextInt(chs.length)]; + } + String code = new String(value); + return code; + } + + public static int getValidInt(String str){ + return getValidInt(str, -1); + } + + public static int getValidInt(String str, int defaultVal){ + int result = defaultVal; + try { + if(StringUtils.isNotBlank(str)){ + result = Integer.parseInt(str); + } + } catch (NumberFormatException e) { + e.printStackTrace(); + } + return result; + } + + /** + * 封装JDK自带的UUID, 通过Random数字生成, 中间无-分割. + */ + public static String getUUID() { + String uuid = UUID.randomUUID().toString().trim().replaceAll("-", ""); + //uuid = uuid + "|yupenxiqi"; + if(uuid.length() > 28)uuid = uuid.substring(0, 28); + return uuid; + } + + public static String getOpenId(String prefix) { + int length = 28; + if(StringUtils.isNotBlank(prefix)){ + length -= prefix.length(); + } + + char[] chs = { 'a', 'b', 'c', '1', '2', '3', 'd', 'e', 'f', + 'A', 'B', 'C', 'D', 'E', 'F', + '4', '5', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', + '6', '8', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', + 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '6', '7', '8', '9', + '2', '5', '9', + 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; + SecureRandom random = new SecureRandom(); + char[] value = new char[length]; + for (int i = 0; i < length; i++) { + value[i] = chs[random.nextInt(chs.length)]; + } + String code = new String(value); + if(StringUtils.isNotBlank(prefix)){ + code = prefix+code; + } + return code; + } + + + /** + * 向URL中添加参数(有则修改,无则添加) + * @param url + * @param ParamName + * @param ParamValue + * @return + */ + public static String addParamValue(String url, String ParamName, String ParamValue) { + if(StringUtils.isNotBlank(url) && StringUtils.isNotBlank(ParamName) && StringUtils.isNotBlank(ParamValue)) { + if(url.contains(ParamName+"=")){ + url = replaceParamValue(url, ParamName, ParamValue); + }else{ + if(url.contains("?") || url.contains("\\?")){ + url += "&"+ParamName+"=" + ParamValue; + }else{ + url += "?"+ParamName+"=" + ParamValue; + } + } + } + return url; + } + + /** + * 替换URL参数的值 + * @param url + * @param ParamName + * @param ParamValue + * @return + */ + public static String replaceParamValue(String url, String ParamName, String ParamValue) { + if(StringUtils.isNotBlank(url) && StringUtils.isNotBlank(ParamName) && StringUtils.isNotBlank(ParamValue)) { + url = url.replaceAll("(\\?" + ParamName +"=[^&]*)", "?"+ParamName + "=" + ParamValue); + url = url.replaceAll("(\\&" + ParamName +"=[^&]*)", "&"+ParamName + "=" + ParamValue); + } + return url; + } + + /** + * 删除URL中的参数 + * @param url + * @param ParamName + * @return + */ + public static String removeParamValue(String url, String ParamName) { + if(StringUtils.isNotBlank(url) && StringUtils.isNotBlank(ParamName)) { + while(url.contains("?"+ParamName+"=") || url.contains("%3f"+ParamName+"%3d") || url.contains("%3F"+ParamName+"%3D") + || url.contains("&"+ParamName+"=") || url.contains("%26"+ParamName+"%3d") || url.contains("%26"+ParamName+"%3D")){ + url = url.replaceAll("(\\?" + ParamName +"=[^&]*)", ""); + url = url.replaceAll("(%3f" + ParamName +"%3d[^&]*)", ""); + url = url.replaceAll("(%3F" + ParamName +"%3D[^&]*)", ""); + + url = url.replaceAll("(\\&" + ParamName +"=[^&]*)", ""); + url = url.replaceAll("(%26" + ParamName +"%3d[^&]*)", ""); + url = url.replaceAll("(%26" + ParamName +"%3D[^&]*)", ""); + } + } + return url; + } + + /** + * 优惠码的生成 + * @return + */ + public static String getCode(int length) { + char[] chs = { 'a', 'b', 'c', '1', '2', '3', '4', '5', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', + 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '6', '7', '8', '9' }; + SecureRandom random = new SecureRandom(); + final char[] value = new char[length]; + for (int i = 0; i < length; i++) { + value[i] = chs[random.nextInt(chs.length)]; + } + final String code = new String(value); + return code; + } + + /** + * 生成随机邀请码 + * @return + */ + public static String getInvitecode() { + int length = 4; + char[] chs = { 'A', 'B', 'C', '1', '2', '3', '4', '5', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', + 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '6', '7', '8', '9' }; + SecureRandom random = new SecureRandom(); + final char[] value = new char[length]; + for (int i = 0; i < length; i++) { + value[i] = chs[random.nextInt(chs.length)]; + } + final String code = new String(value); + return code; + } + + public static int[] toIntArray(String[] array) { + int[] result = new int[array.length]; + int count = 0; + for (int i = 0; i < array.length; i++) { + if (array[i] != null && !array[i].trim().equals("") && !array[i].trim().equals("undefined")) + result[count++] = Integer.parseInt(array[i]); + } + return result; + } + + public static int[] toIntArray(ArrayList array){ + int[] result = new int[array.size()]; + int count = 0; + for (int i = 0; i < array.size(); i++) { + String item = array.get(i); + if (item != null && !item.trim().equals("")) + result[count++] = Integer.parseInt(item); + } + return result; + } + + public static int[] toIntArray(String str){ + if(str == null || str.equals("")) return null; + int[] result; + if(str.indexOf(",")!=-1){ + String[] strArr = str.split(","); + result =toIntArray(strArr); + }else{ + result = new int[]{Integer.parseInt(str)}; + } + return result; + } + + public static List toIntList(String str){ + List idList = null; + if(str == null || str.equals("")) return null; + int[] result = toIntArray(str); + if(result!=null && result.length>0){ + idList = new ArrayList(); + for (int id : result) { + idList.add(id); + } + } + return idList; + } + + + public static long[] toLongArray(String[] array) { + long[] result = new long[array.length]; + int count = 0; + for (int i = 0; i < array.length; i++) { + if (array[i] != null && !array[i].trim().equals("") && !array[i].trim().equals("undefined")) + result[count++] = Long.parseLong(array[i]); + } + return result; + } + + public static long[] toLongArray(String str){ + if(str == null || str.equals("")) return null; + long[] result; + if(str.indexOf(",")!=-1){ + String[] strArr = str.split(","); + result = toLongArray(strArr); + }else{ + result = new long[]{Long.parseLong(str)}; + } + return result; + } + + public static List toLongList(String str){ + List idList = null; + if(str == null || str.equals("")) return null; + long[] result = toLongArray(str); + if(result!=null && result.length>0){ + idList = new ArrayList(); + for (long id : result) { + idList.add(id); + } + } + return idList; + } + + /** + * 获取请求URL,到ContextPath止 + * @param request + * @return + */ + public static String getBaseUrl(HttpServletRequest request){ + String result = null; + int port = request.getServerPort(); + result = request.getScheme()+"://"+request.getServerName()+(port==80||port==443 ? "" : ":"+port)+request.getContextPath()+"/"; + return result; + } + + /** + * 获取服务器IP地址 + * @return + */ + public static String getHostIP(){ + String hostip = null; + try { + InetAddress address = InetAddress.getLocalHost(); + hostip = address.getHostAddress(); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + return hostip; + } + + /** + * 获取当前服务器cdn域名 + * 国内: 39.108.10.19 - 172.18.219.193 + * 国外: 47.88.236.90 - 172.21.7.78 + * @return + */ + /** + * 是否是内网 + * @return + */ + public static boolean isNw(){ + boolean isnw = false; + String hostip = getHostIP(); + if(hostip.startsWith("172.") || hostip.startsWith("10.")){ + isnw = true; + } + return isnw; + } + + /** + * str数组转list + * @param str + * @return + */ + public static ArrayList str2List(String str){ + ArrayList list = new ArrayList<>(); + if(str!=null && str.trim().length()>0){ + if(str.indexOf(",")!=-1){ + String[] arr = str.split(","); + for (String string : arr) { + list.add(string); + } + }else{ + list.add(str); + } + } + return list; + } + + public static void main(String[] args) { + for (int i=0; i < 10; i++) { + System.out.println(getInvitecode()); + } + } +} diff --git a/src/main/java/com/nbclass/util/CopyUtil.java b/src/main/java/com/nbclass/util/CopyUtil.java new file mode 100644 index 0000000..cd87a58 --- /dev/null +++ b/src/main/java/com/nbclass/util/CopyUtil.java @@ -0,0 +1,143 @@ +package com.nbclass.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.BeanUtils; + +import java.beans.BeanInfo; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.util.ArrayList; +import java.util.List; +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +public class CopyUtil { + private static Logger logger = LoggerFactory.getLogger(CopyUtil.class); + /** + * @param source 源 + * @param dest 目标 + */ + public static void copy(Object source, Object dest) { + try { + if (source == null || dest == null) { + return; + } + // 获取属性 + BeanInfo sourceBean = Introspector.getBeanInfo(source.getClass(), Object.class); + PropertyDescriptor[] sourceProperty = sourceBean.getPropertyDescriptors(); + BeanInfo destBean = Introspector.getBeanInfo(dest.getClass(), Object.class); + PropertyDescriptor[] destProperty = destBean.getPropertyDescriptors(); + for (int i = 0; i < sourceProperty.length; i++) { + for (int j = 0; j < destProperty.length; j++) { + if (sourceProperty[i].getName().equals(destProperty[j].getName())) { + try { + // 调用source的getter方法和dest的setter方法 + destProperty[j].getWriteMethod().invoke(dest, sourceProperty[i].getReadMethod().invoke(source)); + break; + } catch (Exception e) { + logger.info("属性赋值失败," + sourceProperty[i].getName() + e.getMessage()); + } + } + } + } + } catch (Exception e) { + logger.info("对象赋值失败," + source + "," + dest); + } + } + + /** + * @param source 源 + * @param dest 目标 + */ + public static void copyNotNull(Object source, Object dest) { + try { + if (source == null || dest == null) { + return; + } + // 获取属性 + BeanInfo sourceBean = Introspector.getBeanInfo(source.getClass(), Object.class); + PropertyDescriptor[] sourceProperty = sourceBean.getPropertyDescriptors(); + BeanInfo destBean = Introspector.getBeanInfo(dest.getClass(), Object.class); + PropertyDescriptor[] destProperty = destBean.getPropertyDescriptors(); + for (int i = 0; i < sourceProperty.length; i++) { + for (int j = 0; j < destProperty.length; j++) { + if (sourceProperty[i].getName().equals(destProperty[j].getName()) && CoreUtils.notNull(sourceProperty[i].getReadMethod().invoke(source))) { + try { + // 调用source的getter方法和dest的setter方法 + destProperty[j].getWriteMethod().invoke(dest, sourceProperty[i].getReadMethod().invoke(source)); + break; + } catch (Exception e) { + logger.info("属性赋值失败," + sourceProperty[i].getName() + e.getMessage()); + } + } + } + } + } catch (Exception e) { + logger.info("对象赋值失败," + source + "," + dest); + } + } + + /*** + * + * @param source + * 源 + * @param clazz + * 目标类 + * @return 目标类实例 + */ + public static T getCopy(Object source, Class clazz) { + T dest = null; + try { + dest = clazz.newInstance(); + copy(source, dest); + } catch (Exception e) { + e.printStackTrace(); + logger.info("对象复制错误:" + e.getMessage()); + } + return dest; + } + + /*** + * + * @param source + * 源 + * @param dest + * 目标类 + * @param ignoreProperties + * 过滤掉的属性 + */ + public static Object getCopy(Object source, Object dest, String... ignoreProperties) { + try { + BeanUtils.copyProperties(source, dest, ignoreProperties); + } catch (Exception e) { + e.printStackTrace(); + logger.info("对象复制错误:" + e.getMessage()); + } + return dest; + } + + @SuppressWarnings("rawtypes") + public static List getCopyList(List sources, Class clazz) { + List clazzs = new ArrayList<>(); + if (sources == null) { + return clazzs; + } + for (Object source : sources) { + try { + T dest = clazz.newInstance(); + copy(source, dest); + clazzs.add(dest); + } catch (InstantiationException e) { + e.printStackTrace(); + logger.info("对象复制错误:" + e.getMessage()); + } catch (IllegalAccessException e) { + e.printStackTrace(); + logger.info("对象复制错误:" + e.getMessage()); + } + } + return clazzs; + } +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/util/CoreConst.java b/src/main/java/com/nbclass/util/CoreConst.java new file mode 100644 index 0000000..d9fcdb0 --- /dev/null +++ b/src/main/java/com/nbclass/util/CoreConst.java @@ -0,0 +1,48 @@ +package com.nbclass.util; +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +public class CoreConst { + + /** + * 用户状态:1有效; 2删除 + */ + public static final Integer STATUS_VALID = 1; + public static final Integer STATUS_INVALID = 0; + + public static Integer TOP_MENU_ID = 0; + public static String TOP_MENU_NAME = "顶层菜单"; + + + /** 响应状态码 key **/ + public static final String STATUS = "ret"; + + /** 成功状态码 **/ + public static final int STATUS_SUCCESS = 0; + + /** 成功消息 **/ + public static final String STATUS_MSG = "操作成功"; + + /** 失败状态码 **/ + public static final int STATUS_ERROR = -1; + + /** 响应消息 key **/ + public static final String MSG = "msg"; + + /** 响应内容 key **/ + public static final String DATA = "data"; + + /** + * 用户个人权限在session中的key + */ + public static final String SESSION_USER = "user"; + + public static final String SESSION_USER_ID = "userId"; + + public static final String SESSION_USER_NAME = "userName"; + + public static final String SESSION_USER_ISADMIN = "userIsAdmin"; + +} diff --git a/src/main/java/com/nbclass/util/CoreUtils.java b/src/main/java/com/nbclass/util/CoreUtils.java new file mode 100644 index 0000000..c182d96 --- /dev/null +++ b/src/main/java/com/nbclass/util/CoreUtils.java @@ -0,0 +1,60 @@ +package com.nbclass.util; + +import org.apache.commons.beanutils.PropertyUtils; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +public class CoreUtils { + + public static T copy(Object orig, Class clazz) { + T dest = null; + try { + if (notNull(orig)) { + dest = clazz.newInstance(); + PropertyUtils.copyProperties(dest, orig); + } + } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { + e.printStackTrace(); + } + return dest; + } + + public static List copyList(List origs, Class clazz) { + List list = new ArrayList(); + if (notNull(origs)) { + for (Object orig : origs) { + list.add(copy(orig, clazz)); + } + } + return list; + } + + public static boolean notNullAndEmpty(String string) { + return null == string || "".equals(string) ? false : true; + } + + public static boolean notNullAndZero(List list) { + return null == list || list.size() == 0 ? false : true; + } + + public static boolean notNull(Object object) { + if (object instanceof List) { + return notNullAndZero((List) object); + } else if (object instanceof String) { + return notNullAndEmpty((String) object); + } else { + return null != object; + } + } + + public static boolean isEmpty(String string) { + return null == string || "".equals(string) ? true : false; + } + +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/util/HttpClientUtil.java b/src/main/java/com/nbclass/util/HttpClientUtil.java new file mode 100644 index 0000000..acb24af --- /dev/null +++ b/src/main/java/com/nbclass/util/HttpClientUtil.java @@ -0,0 +1,174 @@ +package com.nbclass.util; + +import com.alibaba.fastjson.JSONObject; +import com.nbclass.exception.ServiceException; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpEntity; +import org.apache.http.HttpStatus; +import org.apache.http.client.config.CookieSpecs; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.Map.Entry; + +/** + * HttpClients 请求工具类 + * @author Leon + * @datetime 2018年8月13日 下午4:42:17 + */ +public class HttpClientUtil { + + private static Logger logger = LoggerFactory.getLogger(HttpClientUtil.class); + + private static final CloseableHttpClient httpClient; + + static { + RequestConfig globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.IGNORE_COOKIES).setConnectTimeout(10000).setSocketTimeout(10000).build(); + httpClient = HttpClientBuilder.create().setDefaultRequestConfig(globalConfig).build(); + } + + /** + * POST请求 + * @param url + * @param json + * @return + */ + public static JSONObject doPost(String url, JSONObject json){ + // CloseableHttpClient client = HttpClients.custom().setDefaultRequestConfig(globalConfig).build(); + HttpPost httpPost = new HttpPost(url); + JSONObject response = null; + CloseableHttpResponse res = null; + try { + // 设置请求的header + // httpPost.setHeader("Content-Type", "application/json;charset=utf-8"); + httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); + httpPost.setHeader("Accept", "application/json;charset=utf-8"); + + // StringEntity s = new StringEntity(json.toString(), "UTF-8"); + StringEntity s = new StringEntity(formatPostData(json), "UTF-8"); + // s.setContentEncoding("UTF-8"); + // s.setContentType("application/json");//发送json数据需要设置contentType + httpPost.setEntity(s); + + res = httpClient.execute(httpPost); + int statusCode = res.getStatusLine().getStatusCode(); + if (statusCode != HttpStatus.SC_OK) { + logger.info("请求接口返回状态吗, getStatusCode="+statusCode+", getReasonPhrase="+res.getStatusLine().getReasonPhrase()); + httpPost.abort(); + throw new ServiceException("HttpClient,error status code :" + statusCode); + } + + HttpEntity entity = res.getEntity(); + if (entity != null) { + String result = EntityUtils.toString(entity, "UTF-8"); + response = JSONObject.parseObject(result); + } + } catch (Exception e) { + logger.error("HTTP-POST请求出错, URL="+url, e); + } finally { + httpPost.releaseConnection(); + if (res != null) { + try { + EntityUtils.consume(res.getEntity()); + } catch (IOException e){} + try { + res.close(); + } catch (IOException e){} + } + } + return response; + } + + /** + * GET请求 + * @param url + * @return + */ + public static JSONObject doGet(String url){ + HttpGet httpGet = new HttpGet(url); + CloseableHttpResponse res = null; + JSONObject response = null; + try { + // 设置请求的header + httpGet.setHeader("Content-Type", "application/json;charset=utf-8"); + httpGet.setHeader("Accept", "application/json;charset=utf-8"); + + res = httpClient.execute(httpGet); + int statusCode = res.getStatusLine().getStatusCode(); + if (statusCode != HttpStatus.SC_OK) { + logger.info("请求接口返回状态码, getStatusCode="+statusCode+", getReasonPhrase="+res.getStatusLine().getReasonPhrase()); + httpGet.abort(); + throw new ServiceException("HttpClient,error status code :" + statusCode); + } + + HttpEntity entity = res.getEntity(); + if (entity != null) { + String result = EntityUtils.toString(entity, "UTF-8"); + response = JSONObject.parseObject(result); + } + } catch (Exception e) { + logger.error("HTTP-GET请求出错, URL="+url, e); + } finally { + httpGet.releaseConnection(); + if (res != null) { + try { + EntityUtils.consume(res.getEntity()); + } catch (IOException e){} + try { + res.close(); + } catch (IOException e){} + } + } + return response; + } + + protected static String formatPostData(JSONObject json){ + String result = null; + try { + JSONObject jsonObject = json; + if(jsonObject != null){ + result = "?"; + for (Entry entry : jsonObject.entrySet()) { + if(StringUtils.isEmpty(result)){ + result = entry.getKey() + "=" + entry.getValue(); + }else{ + result += "&" + entry.getKey() + "=" + entry.getValue(); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return result; + } + + protected static String formatPostData(String strdata){ + String result = strdata; + try { + JSONObject jsonObject = JSONObject.parseObject(strdata); + if(jsonObject != null){ + result = ""; + for (Entry entry : jsonObject.entrySet()) { + if(StringUtils.isEmpty(result)){ + result = entry.getKey() + "=" + entry.getValue(); + }else{ + result += "&" + entry.getKey() + "=" + entry.getValue(); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return result; + } + +} diff --git a/src/main/java/com/nbclass/util/HttpUtil.java b/src/main/java/com/nbclass/util/HttpUtil.java new file mode 100644 index 0000000..b8488c2 --- /dev/null +++ b/src/main/java/com/nbclass/util/HttpUtil.java @@ -0,0 +1,123 @@ +package com.nbclass.util; + + +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class HttpUtil { + public static String doGet(String url) { // 无参数get请求 + return doGet(url, null); + } + + public static String doGet(String url, Map param) { // 带参数get请求 + CloseableHttpClient httpClient = HttpClients.createDefault(); // 创建一个默认可关闭的Httpclient 对象 + String resultMsg = ""; // 设置返回值 + CloseableHttpResponse response = null; // 定义HttpResponse 对象 + try { + URIBuilder builder = new URIBuilder(url); // 创建URI,可以设置host,设置参数等 + if (param != null) { + for (String key : param.keySet()) { + builder.addParameter(key, param.get(key)); + } + } + URI uri = builder.build(); + HttpGet httpGet = new HttpGet(uri); // 创建http GET请求 + response = httpClient.execute(httpGet); // 执行请求 + if (response.getStatusLine().getStatusCode() == 200) { // 判断返回状态为200则给返回值赋值 + resultMsg = EntityUtils.toString(response.getEntity(), "UTF-8"); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { // 不要忘记关闭 + try { + if (response != null) { + response.close(); + } + httpClient.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return resultMsg; + } + + public static String doPost(String url) { // 无参数post请求 + return doPost(url, null); + } + + public static String doPost(String url, Map param) {// 带参数post请求 + CloseableHttpClient httpClient = HttpClients.createDefault(); // 创建一个默认可关闭的Httpclient 对象 + CloseableHttpResponse response = null; + String resultMsg = ""; + try { + HttpPost httpPost = new HttpPost(url); // 创建Http Post请求 + if (param != null) { // 创建参数列表 + List paramList = new ArrayList(); + for (String key : param.keySet()) { + paramList.add(new BasicNameValuePair(key, param.get(key))); + } + UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);// 模拟表单 + httpPost.setEntity(entity); + } + response = httpClient.execute(httpPost); // 执行http请求 + if (response.getStatusLine().getStatusCode() == 200) { + resultMsg = EntityUtils.toString(response.getEntity(), "utf-8"); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (response != null) { + response.close(); + } + httpClient.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return resultMsg; + } + + public static String doPostJson(String url, String json) { + CloseableHttpClient httpClient = HttpClients.createDefault(); + CloseableHttpResponse response = null; + String resultString = ""; + try { + HttpPost httpPost = new HttpPost(url); + StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON); + httpPost.setEntity(entity); + response = httpClient.execute(httpPost); + if (response.getStatusLine().getStatusCode() == 200) { + resultString = EntityUtils.toString(response.getEntity(), "utf-8"); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (response != null) { + response.close(); + } + httpClient.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return resultString; + } +} diff --git a/src/main/java/com/nbclass/util/HttpUtils.java b/src/main/java/com/nbclass/util/HttpUtils.java new file mode 100644 index 0000000..7947668 --- /dev/null +++ b/src/main/java/com/nbclass/util/HttpUtils.java @@ -0,0 +1,142 @@ +package com.nbclass.util; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Map.Entry; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.fastjson.JSONObject; + + +/** + * HTTP请求工具类 + * @author leon + * @datetime 2016年5月19日 下午6:05:53 + */ +public class HttpUtils { + + private static final Logger logger = LoggerFactory.getLogger(HttpUtils.class); + + /** + * 默认http连接超时时间(单位:ms) + */ + public static final int HTTP_CONNECT_TIMEOUT = 5000; + + + public static JSONObject httpGet(String requestUrl){ + return httpGet(requestUrl, null); + } + + public static JSONObject httpGet(String requestUrl, String postData){ + return httpRequest(requestUrl, "GET", postData); + } + + public static JSONObject httpPost(String requestUrl){ + return httpPost(requestUrl, null); + } + + public static JSONObject httpPost(String requestUrl, String postData){ + return httpRequest(requestUrl, "POST", postData); + } + + private static JSONObject httpRequest(String requestUrl, String requestMethod, String postData) { + JSONObject jsonObject = null; + StringBuffer buffer = new StringBuffer(); + OutputStream outputStream = null; + InputStream inputStream = null; + InputStreamReader inputStreamReader = null; + BufferedReader bufferedReader = null; + HttpURLConnection httpUrlConn = null; + try{ + postData = formatPostData(postData); + // logger.info("httpRequestUrl: "+requestUrl+", postData: "+postData); + URL url = new URL(requestUrl); + httpUrlConn = (HttpURLConnection) url.openConnection(); + httpUrlConn.setDoOutput(true); + httpUrlConn.setDoInput(true); + httpUrlConn.setUseCaches(false); + //设置请求方式(GET/POST) + httpUrlConn.setRequestMethod(requestMethod); + if ("GET".equalsIgnoreCase(requestMethod)){ + httpUrlConn.connect(); + } + //当有数据需要提交时 + if (postData != null){ + outputStream = httpUrlConn.getOutputStream(); + outputStream.write(postData.getBytes("UTF-8")); + + } + //将返回的输入流转换成字符串 + inputStream = httpUrlConn.getInputStream(); + inputStreamReader = new InputStreamReader(inputStream, "UTF-8"); + bufferedReader = new BufferedReader(inputStreamReader); + for(String str = null; (str = bufferedReader.readLine()) != null;){ + buffer.append(str); + } + + jsonObject = JSONObject.parseObject(buffer.toString()); + }catch (Exception e) { + logger.error("https request error:{}", e); + }finally{ + try { + if(httpUrlConn!=null){ + httpUrlConn.disconnect(); + httpUrlConn=null; + } + } catch (Exception e) {} + try { + if(outputStream!=null){ + outputStream.close(); + outputStream=null; + } + } catch (IOException e) {} + try { + if(inputStreamReader!=null){ + inputStreamReader.close(); + inputStreamReader = null; + } + } catch (IOException e) {} + try { + if(inputStream!=null){ + inputStream.close(); + inputStream = null; + } + } catch (IOException e) {} + try { + if(bufferedReader!=null){ + bufferedReader.close(); + bufferedReader = null; + } + } catch (IOException e) {} + } + return jsonObject; + } + + private static String formatPostData(String strdata){ + String result = strdata; + try { + JSONObject jsonObject = JSONObject.parseObject(strdata); + if(jsonObject != null){ + result = ""; + for (Entry entry : jsonObject.entrySet()) { + if(StringUtils.isBlank(result)){ + result = entry.getKey() + "=" + entry.getValue(); + }else{ + result += "&" + entry.getKey() + "=" + entry.getValue(); + } + } + } + } catch (Exception e) { + } + return result; + } + +} diff --git a/src/main/java/com/nbclass/util/IpUtil.java b/src/main/java/com/nbclass/util/IpUtil.java new file mode 100644 index 0000000..2161a2e --- /dev/null +++ b/src/main/java/com/nbclass/util/IpUtil.java @@ -0,0 +1,46 @@ +package com.nbclass.util; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import javax.servlet.http.HttpServletRequest; + +/** + * + * @author Leon + * @datetime 2019年4月1日 下午10:08:26 + */ +public class IpUtil { + + public static String getIpAddr(HttpServletRequest request) { + 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("WL-Proxy-Client-IP"); + } + if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + if("127.0.0.1".equals(ip)){ + //根据网卡取本机配置的IP + InetAddress inet=null; + try { + inet = InetAddress.getLocalHost(); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + ip= inet.getHostAddress(); + } + } + // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 + if(ip != null && ip.length() > 50){ + // if(ip.indexOf(",")>0){ + // ip = ip.substring(0,ip.indexOf(",")); + // } + ip = ip.substring(0,50); + } + return ip; + } + +} diff --git a/src/main/java/com/nbclass/util/JWTUtils.java b/src/main/java/com/nbclass/util/JWTUtils.java new file mode 100644 index 0000000..6208d19 --- /dev/null +++ b/src/main/java/com/nbclass/util/JWTUtils.java @@ -0,0 +1,149 @@ +package com.nbclass.util; + + +import com.alibaba.fastjson.JSON; + +import com.alibaba.fastjson.JSONObject; +import com.nbclass.activity.model.WeiXiUser; +import com.nbclass.exception.ParameterException; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.JwtBuilder; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.StringUtils; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * @author admin + */ +public class JWTUtils { + + /** + * 加密密文 + */ + public static final String JWT_SECRET = "onyx"; + public static final int JWT_TTL = 60 * 60 * 1000; //millisecond + + /** + * 由字符串生成加密key + * + * @return + */ + public static SecretKey generalKey() { + String stringKey = JWT_SECRET; + // 本地的密码解码 + byte[] encodedKey = Base64.decodeBase64(stringKey); + // 根据给定的字节数组使用AES加密算法构造一个密钥 + SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES"); + return key; + } + + + /** + * 创建jwt + */ + public static String createJWT(String id, String issuer, String subject, long ttlMillis, Map claims) throws Exception { + + // 指定签名的时候使用的签名算法,也就是header那部分,jjwt已经将这部分内容封装好了。 + SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; + + // 生成JWT的时间 + long nowMillis = System.currentTimeMillis(); + + // 生成签名的时候使用的秘钥secret,切记这个秘钥不能外露哦。它就是你服务端的私钥,在任何场景都不应该流露出去。 + // 一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。 + SecretKey key = generalKey(); + + // 下面就是在为payload添加各种标准声明和私有声明了 + JwtBuilder builder = Jwts.builder() // 这里其实就是new一个JwtBuilder,设置jwt的body + //.setClaims(claims) // 如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的 + .setId(id) // 设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为一次性token,从而回避重放攻击。 + .setIssuedAt(new Date(nowMillis)) // iat: jwt的签发时间 + .setIssuer(issuer) // issuer:jwt签发人 + .setSubject(subject) // sub(Subject):代表这个JWT的主体,即它的所有人,这个是一个json格式的字符串,可以存放什么userid,roldid之类的,作为什么用户的唯一标志。 + .signWith(signatureAlgorithm, key); // 设置签名使用的签名算法和签名使用的秘钥 + + // 设置过期时间 + if (ttlMillis >= 0) { + long expMillis = nowMillis + ttlMillis; + builder.setExpiration(new Date(expMillis)); + } + return builder.compact(); + } + + /** + * 解密jwt + */ + public static Claims parseJWT(String jwt) throws Exception { + SecretKey key = generalKey(); //签名秘钥,和生成的签名的秘钥一模一样 + Claims claims = Jwts.parser() //得到DefaultJwtParser + .setSigningKey(key) //设置签名的秘钥 + .parseClaimsJws(jwt).getBody(); //设置需要解析的jwt + return claims; + } + + /** + * 获取用户ID + * @param token + */ + public static String getUserId(String token){ + String userId = ""; + try { + Claims claims = JWTUtils.parseJWT(token); + String subject = claims.getSubject(); + JSONObject jsonObject = JSON.parseObject(subject); + userId = jsonObject.getString("id"); + } catch (Exception e) { + throw new ParameterException("token无效或token过期"); + } + return userId; + } + + + public static void main(String[] args) { + + WeiXiUser user = new WeiXiUser(); + user.setId(1L); + user.setOpenid("asdfsaf123"); + user.setNickname("张三"); + String subject = JSON.toJSONString(user); + + // 创建payload的私有声明(根据特定的业务需要添加,如果要拿这个做验证,一般是需要和jwt的接收方提前沟通好验证方式的) + /*Map claims = new HashMap<>(); + claims.put("id", "110"); + claims.put("user_name", "zhaojun"); + claims.put("nick_name", "zhaojun22");*/ + + try { + String jwt = JWTUtils.createJWT(UUID.randomUUID().toString(), "Anson", subject, JWT_TTL,null); + System.out.println("JWT:" + jwt); + System.out.println(jwt.length()); + + System.out.println("解密"); + + Claims c = JWTUtils.parseJWT(jwt); + System.out.println(c.getId()); + System.out.println(c.getIssuedAt()); + System.out.println(c.getIssuedAt().getTime()); + Date expiration = c.getExpiration(); + System.out.println(expiration); + System.out.println(expiration.getTime()); + System.out.println(c.getSubject()); + System.out.println(c.getIssuer()); + System.out.println(c.get("id", String.class)); + System.out.println(c.get("user_name", String.class)); + System.out.println(c.get("nick_name", String.class)); + + } catch (Exception e) { + e.printStackTrace(); + } + + } +} \ No newline at end of file diff --git a/src/main/java/com/nbclass/util/MyMapper.java b/src/main/java/com/nbclass/util/MyMapper.java new file mode 100644 index 0000000..f0c7cd8 --- /dev/null +++ b/src/main/java/com/nbclass/util/MyMapper.java @@ -0,0 +1,38 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2016 abel533@gmail.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.nbclass.util; + +import tk.mybatis.mapper.common.Mapper; +import tk.mybatis.mapper.common.MySqlMapper; + +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +public interface MyMapper extends Mapper, MySqlMapper { + //TODO + //FIXME 特别注意,该接口不能被扫描到,否则会出错 +} diff --git a/src/main/java/com/nbclass/util/PageUtil.java b/src/main/java/com/nbclass/util/PageUtil.java new file mode 100644 index 0000000..5093d6b --- /dev/null +++ b/src/main/java/com/nbclass/util/PageUtil.java @@ -0,0 +1,19 @@ +package com.nbclass.util; + +/** + * + * @author Leon + * @datetime 2020年6月3日 下午7:07:17 + */ +public class PageUtil { + + /** + * i获取pgeNo,特别注意下,这个offset是起始位置,不是页码 + * @param limit 每页条数 + * @param offset 其实位置,比如limit为5,第一页offset值为0,第二页为5,第二页为10 + * @return + */ + public static Integer getPageNo(Integer limit,Integer offset){ + return offset==0 ? 1 : offset / limit + 1; + } +} diff --git a/src/main/java/com/nbclass/util/PasswordHelper.java b/src/main/java/com/nbclass/util/PasswordHelper.java new file mode 100644 index 0000000..8d46e29 --- /dev/null +++ b/src/main/java/com/nbclass/util/PasswordHelper.java @@ -0,0 +1,63 @@ +package com.nbclass.util; + +import org.apache.shiro.crypto.RandomNumberGenerator; +import org.apache.shiro.crypto.SecureRandomNumberGenerator; +import org.apache.shiro.crypto.hash.SimpleHash; +import org.apache.shiro.util.ByteSource; + +import com.nbclass.system.model.User; + +/** + * 密码加密 + * @author Leon + * @datetime 2019年4月1日 下午10:09:02 + */ +public class PasswordHelper { + + private static RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator(); + private static String algorithmName = "md5"; + private static int hashIterations = 2; + + public static void encryptPassword(User user) { + user.setSalt(randomNumberGenerator.nextBytes().toHex()); + String newPassword = new SimpleHash(algorithmName, user.getPassword(), ByteSource.Util.bytes(user.getCredentialsSalt()), hashIterations).toHex(); + user.setPassword(newPassword); + } + + public static String getPassword(User user){ + String encryptPassword = new SimpleHash(algorithmName,user.getPassword(), ByteSource.Util.bytes(user.getCredentialsSalt()),hashIterations).toHex(); + return encryptPassword; + } + + /** + * 使用BCrypt对密码进行加密 + * @param password + * @return + */ + public static String encryptPwdByBCrypt(String password){ + return BCrypt.hashpw(password, BCrypt.gensalt()); + } + + /** + * BCrypt 密码验证 + * @param password 明文 + * @param ciphertext 密文 + * @return if equal ? true : false + */ + public static boolean checkPwdByBCrypt(String password, String ciphertext){ + return BCrypt.checkpw(password, ciphertext); + } + + public static void main(String[] args) { + User user = new User(); + user.setUsername("admin"); + user.setPassword("szxgl.com"); + encryptPassword(user); + System.out.println("salt="+user.getSalt()); + System.out.println("password="+user.getPassword()); + + String pwd1 = encryptPwdByBCrypt("123456"); + boolean result = checkPwdByBCrypt("123456", pwd1); + System.out.println("pwd1="+pwd1+", result="+result); + } +} diff --git a/src/main/java/com/nbclass/util/ResultUtil.java b/src/main/java/com/nbclass/util/ResultUtil.java new file mode 100644 index 0000000..2a9cd77 --- /dev/null +++ b/src/main/java/com/nbclass/util/ResultUtil.java @@ -0,0 +1,55 @@ +package com.nbclass.util; + +import java.util.List; + +import com.nbclass.vo.base.PageResultVo; +import com.nbclass.vo.base.ResponseVo; + +import static com.nbclass.util.CoreConst.STATUS_MSG; + +/** + * + * @author Leon + * @datetime 2019年4月1日 下午2:44:52 + */ +public class ResultUtil{ + + public static ResponseVo success(){ + return vo(CoreConst.STATUS_SUCCESS,null,null); + } + + public static ResponseVo success(String msg){ + return vo(CoreConst.STATUS_SUCCESS, msg,null); + } + + public static ResponseVo success(Object data){ + return vo(CoreConst.STATUS_SUCCESS, STATUS_MSG, data); + } + + public static ResponseVo success(String msg, Object data){ + return vo(CoreConst.STATUS_SUCCESS, msg, data); + } + + public static ResponseVo error(){ + return vo(CoreConst.STATUS_ERROR, null, null); + } + + public static ResponseVo error(String msg){ + return vo(CoreConst.STATUS_ERROR, msg, null); + } + + public static ResponseVo error(String msg, Object data){ + return vo(CoreConst.STATUS_ERROR, msg,data); + } + + public static PageResultVo table( List list, Long total){ + return new PageResultVo(list, total); + } + + public static ResponseVo vo(Integer status, String message, Object data) { + return new ResponseVo(status, message, data); + } + + + +} diff --git a/src/main/java/com/nbclass/util/ShortenUtil.java b/src/main/java/com/nbclass/util/ShortenUtil.java new file mode 100644 index 0000000..4669cd1 --- /dev/null +++ b/src/main/java/com/nbclass/util/ShortenUtil.java @@ -0,0 +1,127 @@ +package com.nbclass.util; + +import java.util.Stack; + +/** + * + * @author Leon + * @datetime 2019年4月11日 下午3:40:42 + */ +public class ShortenUtil { + + private static final char[] array = { + 'a', 'z', 'm', 'b', 'v', 'o', 'h', 'c', 'w', 'k', 'y', 'i', 'f', 's', 'l', 't', 'd', 'x', 'n', 'g', 'r', 'p', 'e', 'u', 'q', 'j', + '0', '8', '4', '9', '5', '2', '6', '3', '7', '1', + 'P', 'G', 'A', 'Z', 'R', 'I', 'F', 'C', 'T', 'W', 'O', 'J', 'U', 'Y', 'E', 'N', 'V', 'H', 'B', 'M', 'S', 'L', 'X', 'D', 'Q', 'K' + }; + + //private static final char[] array1 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray(); + + public static void main(String[] args) { + long id = 200; + String str = encode(id); + System.out.println("62System=" +str); + System.out.println("10System=" +decode(str)); + } + + /** + * _10_to_62 + * @param number + * @return + */ + public static String encode(long number){ + number = 500000+number; + Long rest=number; + Stack stack=new Stack(); + StringBuilder result=new StringBuilder(0); + while(rest!=0){ + stack.add(array[new Long((rest-(rest/62)*62)).intValue()]); + rest=rest/62; + } + for(;!stack.isEmpty();){ + result.append(stack.pop()); + } + return result.toString(); + } + + /** + * _10_to_62 + * 将10进制转化为62进制 + * @param number + * @param length 转化成的62进制长度,不足length长度的话高位补0,否则不改变什么 + * @return + */ + public static String encode(long number, int length){ + Long rest=number; + Stack stack=new Stack(); + StringBuilder result=new StringBuilder(0); + while(rest!=0){ + stack.add(array[new Long((rest-(rest/62)*62)).intValue()]); + rest=rest/62; + } + for(;!stack.isEmpty();){ + result.append(stack.pop()); + } + int result_length = result.length(); + StringBuilder temp0 = new StringBuilder(); + for(int i = 0; i < length - result_length; i++){ + temp0.append('0'); + } + return temp0.toString() + result.toString(); + } + + public static long decode(String sixty_str){ + int multiple=1; + long result=0; + Character c; + for(int i=0;i= 0; i-- ) { + int num = 0; + if ( ident[i] > 48 && ident[i] <= 57 ) { + num = ident[i] - 48; + } + else if ( ident[i] >= 65 && ident[i] <= 90 ) { + num = ident[i] - 65 + 10; + } + else if ( ident[i] >= 97 && ident[i] <= 122 ) { + num = ident[i] - 97 + 10 + 26; + } + keisu = (int) java.lang.Math.pow( base, cnt ); + decimal += num * keisu; + cnt++; + } + return String.format( "%08d", decimal ); + } + +} diff --git a/src/main/java/com/nbclass/util/UUIDUtil.java b/src/main/java/com/nbclass/util/UUIDUtil.java new file mode 100644 index 0000000..db975fb --- /dev/null +++ b/src/main/java/com/nbclass/util/UUIDUtil.java @@ -0,0 +1,60 @@ +package com.nbclass.util; + +import java.util.UUID; + +/** + * + * @author Leon + * @datetime 2019年4月1日 下午10:12:05 + */ +public class UUIDUtil { + + private static final int SHORT_LENGTH = 8; + + public static String uuid() { + String str = UUID.randomUUID().toString(); + String temp = str.replace("-",""); + return temp; + } + + public static String getUniqueIdByUUId() { + //最大支持1-9个集群机器部署 + int machineId = 1; + int hashCodeV = UUID.randomUUID().toString().hashCode(); + if(hashCodeV < 0) { + hashCodeV = - hashCodeV; + } + // 0 代表前面补充0 + // 4 代表长度为4 + // d 代表参数为正数型 + return machineId + String.format("%015d", hashCodeV); + } + public static void main(String[] args) { + System.out.println(getUniqueIdByUUId()); + System.out.println(uuid()); + } + + + + public static String[] chars = new String[] { "a", "b", "c", "d", "e", "f", + "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", + "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", + "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", + "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", + "W", "X", "Y", "Z" }; + + + public static String generateShortUuid() { + StringBuffer shortBuffer = new StringBuffer(); + String uuid = UUID.randomUUID().toString().replace("-", ""); + for (int i = 0; i < SHORT_LENGTH; i++) { + String str = uuid.substring(i * 4, i * 4 + 4); + int x = Integer.parseInt(str, 16); + shortBuffer.append(chars[x % 0x3E]); + } + return shortBuffer.toString(); + + } + + +} diff --git a/src/main/java/com/nbclass/util/WebUtils.java b/src/main/java/com/nbclass/util/WebUtils.java new file mode 100644 index 0000000..756c61c --- /dev/null +++ b/src/main/java/com/nbclass/util/WebUtils.java @@ -0,0 +1,80 @@ +package com.nbclass.util; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; + +public class WebUtils { + + /** + * cookie默认保存时长 (1天) + */ + private static final int COOKIE_DEFAULT_MAXAGE = 3600 * 24 * 1; + + + public static void addCookie(HttpServletResponse response, String name, String value){ + addCookie(response, name, value, COOKIE_DEFAULT_MAXAGE); + } + + public static void addCookie(HttpServletResponse response, String name, String value, int maxage){ + Cookie cookie = new Cookie(name, value); + cookie.setPath("/"); + cookie.setMaxAge(maxage > 0 ? maxage : COOKIE_DEFAULT_MAXAGE); + response.addCookie(cookie); + } + + public static void removeCookie(HttpServletRequest request, HttpServletResponse response, String name){ + if(StringUtils.isBlank(name))return; + try { + name = name.trim(); + Cookie[] cookies = request.getCookies(); + if(cookies == null || cookies.length == 0)return; + for (Cookie cookie : cookies) { + if (cookie.getName().contains(name)) { + String cookieName = cookie.getName(); + Cookie newCookie = new Cookie(cookieName, null); + newCookie.setMaxAge(0); + newCookie.setPath("/"); // 根据你创建cookie的路径进行填写 + response.addCookie(newCookie); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static String getValueFromCookie(HttpServletRequest request, String cookieName) { + if(cookieName==null || cookieName.trim().equals(""))return null; + Cookie[] cookies = request.getCookies(); + if (cookies != null && cookies.length > 0) { + for (int i = 0; i < cookies.length; i++) { + Cookie item = cookies[i]; + String name = item.getName(); + if (cookieName.equals(name)) { + return item.getValue(); + } + } + } + return null; + } + + public static String getReqIpAddr(HttpServletRequest request) { + 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("WL-Proxy-Client-IP"); + } + if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + if(ip == null){ + ip = "未知IP"; + } + return ip; + } + +} diff --git a/src/main/java/com/nbclass/vo/ChangePasswordVo.java b/src/main/java/com/nbclass/vo/ChangePasswordVo.java new file mode 100644 index 0000000..2a4e936 --- /dev/null +++ b/src/main/java/com/nbclass/vo/ChangePasswordVo.java @@ -0,0 +1,36 @@ +package com.nbclass.vo; + +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +public class ChangePasswordVo { + String oldPassword; + String newPassword; + String confirmNewPassword; + + public String getOldPassword() { + return oldPassword; + } + + public void setOldPassword(String oldPassword) { + this.oldPassword = oldPassword; + } + + public String getNewPassword() { + return newPassword; + } + + public void setNewPassword(String newPassword) { + this.newPassword = newPassword; + } + + public String getConfirmNewPassword() { + return confirmNewPassword; + } + + public void setConfirmNewPassword(String confirmNewPassword) { + this.confirmNewPassword = confirmNewPassword; + } +} diff --git a/src/main/java/com/nbclass/vo/PermissionTreeListVo.java b/src/main/java/com/nbclass/vo/PermissionTreeListVo.java new file mode 100644 index 0000000..a0eac9f --- /dev/null +++ b/src/main/java/com/nbclass/vo/PermissionTreeListVo.java @@ -0,0 +1,63 @@ +package com.nbclass.vo; + +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +public class PermissionTreeListVo { + private Integer id; + private String permissionId; + private String name; + private Integer parentId; + private Boolean open=true; + private Boolean checked=false; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getPermissionId() { + return permissionId; + } + + public void setPermissionId(String permissionId) { + this.permissionId = permissionId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getParentId() { + return parentId; + } + + public void setParentId(Integer parentId) { + this.parentId = parentId; + } + + public Boolean getOpen() { + return open; + } + + public void setOpen(Boolean open) { + this.open = open; + } + + public Boolean getChecked() { + return checked; + } + + public void setChecked(Boolean checked) { + this.checked = checked; + } +} diff --git a/src/main/java/com/nbclass/vo/UserOnlineVo.java b/src/main/java/com/nbclass/vo/UserOnlineVo.java new file mode 100644 index 0000000..42dcddb --- /dev/null +++ b/src/main/java/com/nbclass/vo/UserOnlineVo.java @@ -0,0 +1,87 @@ +package com.nbclass.vo; + +import java.io.Serializable; +import java.util.Date; + +/** + * @version V1.0 + * @date 2018年7月20日 + * @author superzheng + */ +public class UserOnlineVo implements Serializable { + + private static final long serialVersionUID = 1L; + + private String sessionId; + private String username; + private String host; + private Date startTime; + private Date lastAccess; + private Date lastLoginTime; + private long timeout; + private boolean sessionStatus = Boolean.TRUE; + + public String getSessionId() { + return sessionId; + } + + public void setSessionId(String sessionId) { + this.sessionId = sessionId; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public Date getStartTime() { + return startTime; + } + + public void setStartTime(Date startTime) { + this.startTime = startTime; + } + + public Date getLastAccess() { + return lastAccess; + } + + public void setLastAccess(Date lastAccess) { + this.lastAccess = lastAccess; + } + + public Date getLastLoginTime() { + return lastLoginTime; + } + + public void setLastLoginTime(Date lastLoginTime) { + this.lastLoginTime = lastLoginTime; + } + + public long getTimeout() { + return timeout; + } + + public void setTimeout(long timeout) { + this.timeout = timeout; + } + + public boolean isSessionStatus() { + return sessionStatus; + } + + public void setSessionStatus(boolean sessionStatus) { + this.sessionStatus = sessionStatus; + } +} diff --git a/src/main/java/com/nbclass/vo/UserSessionVo.java b/src/main/java/com/nbclass/vo/UserSessionVo.java new file mode 100644 index 0000000..663dffc --- /dev/null +++ b/src/main/java/com/nbclass/vo/UserSessionVo.java @@ -0,0 +1,27 @@ +package com.nbclass.vo; + +/** + * @version V1.0 + * @date 2018年7月20日 + * @author superzheng + */ +public class UserSessionVo { + private String sessionId; + private String username; + + public String getSessionId() { + return sessionId; + } + + public void setSessionId(String sessionId) { + this.sessionId = sessionId; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } +} diff --git a/src/main/java/com/nbclass/vo/base/PageResultVo.java b/src/main/java/com/nbclass/vo/base/PageResultVo.java new file mode 100644 index 0000000..cff7556 --- /dev/null +++ b/src/main/java/com/nbclass/vo/base/PageResultVo.java @@ -0,0 +1,34 @@ +package com.nbclass.vo.base; + +import java.util.List; +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +public class PageResultVo { + private List rows; + private Long total; + + public List getRows() { + return rows; + } + + public void setRows(List rows) { + this.rows = rows; + } + + public Long getTotal() { + return total; + } + + public void setTotal(Long total) { + this.total = total; + } + + public PageResultVo(List rows ,Long total) { + this.total = total; + this.rows = rows; + } + +} diff --git a/src/main/java/com/nbclass/vo/base/ResponseVo.java b/src/main/java/com/nbclass/vo/base/ResponseVo.java new file mode 100644 index 0000000..2b5aea7 --- /dev/null +++ b/src/main/java/com/nbclass/vo/base/ResponseVo.java @@ -0,0 +1,43 @@ +package com.nbclass.vo.base; +/** + * @version V1.0 + * @date 2018年7月11日 + * @author superzheng + */ +public class ResponseVo { + private Integer ret; + private String msg; + private T data; + + public Integer getRet() { + return ret; + } + + public void setRet(Integer ret) { + this.ret = ret; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } + + public ResponseVo(Integer ret, String msg, T data) { + this.ret = ret; + this.msg = msg; + this.data = data; + } + + +} diff --git a/src/main/java/com/nbclass/vo/base/Result.java b/src/main/java/com/nbclass/vo/base/Result.java new file mode 100644 index 0000000..4b7dcfb --- /dev/null +++ b/src/main/java/com/nbclass/vo/base/Result.java @@ -0,0 +1,58 @@ +package com.nbclass.vo.base; + +import com.nbclass.util.CoreConst; + +import lombok.Data; + +import java.util.Map; + +/** + * 返回数据对象 + * @author Leon + * @datetime 2020年1月10日 下午2:12:08 + */ +@Data +public class Result { + + private int ret; + private String msg; + private Object data; + private Map map; + + public Result() { + } + + public Result(int ret, String msg, Object data) { + this.ret = ret; + this.msg = msg; + this.data = data; + } + + public static Result success() { + return new Result(CoreConst.STATUS_SUCCESS, null, null); + } + + public static Result success(Object data) { + return new Result(CoreConst.STATUS_SUCCESS, null, data); + } + public static Result success(Map map) { + return new Result(CoreConst.STATUS_SUCCESS, null, map); + } + + public static Result success(String msg, Object data) { + return new Result(CoreConst.STATUS_SUCCESS, msg, data); + } + + public static Result error() { + return new Result(CoreConst.STATUS_ERROR, null, null); + } + + public static Result error(String msg) { + return new Result(CoreConst.STATUS_ERROR, msg, null); + } + + public static Result error(int code, String msg) { + return new Result(code, msg, null); + } + +} diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml new file mode 100644 index 0000000..92ee609 --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,42 @@ +spring: + # 数据库配置 + datasource: + type: com.alibaba.druid.pool.DruidDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://39.108.110.167:13376/xgl_cases?autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=GMT%2B8&characterEncoding=UTF-8 + username: root + password: 'szxgl@2001B' + druid: + initial-size: 3 + min-idle: 1 + max-active: 500 + max-wait: 60000 # 获取连接等待超时的时间 + time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位是毫秒 + test-while-idle: true # 申请连接的时候检测, 建议配置为true,不影响性能 + test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效 + test-on-return: false # 归还连接时执行validationQuery检测连接是否有效 + validation-query: SELECT 1 + log-abandoned: true # 关闭abanded连接时输出错误日志 + remove-abandoned: false # 是否开启连接泄漏监测,对性能会有一些影响,建议怀疑存在泄漏之后再打开 + remove-abandoned-timeout: 1800 # 1800秒,也就是30分钟 + filters: stat, wall + web-stat-filter: + exclusions: '*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*' + stat-view-servlet: + enabled: true + url-pattern: /druid/* + login-username: admin + login-password: szxgl.com + data: + elasticsearch: + repositories: + enabled: true # 开启 Elasticsearch仓库(默认值:true) + client: + reactive: + endpoints: 127.0.0.1:9200 + connection-timeout: 5000 + socket-timeout: 5000 + + + diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml new file mode 100644 index 0000000..9f2ee41 --- /dev/null +++ b/src/main/resources/application-prod.yml @@ -0,0 +1,42 @@ +spring: + # 数据库配置 + datasource: + type: com.alibaba.druid.pool.DruidDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://rm-wz9vza84pe0hb338kbo.mysql.rds.aliyuncs.com:3306/xgl_cases?autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=GMT%2B8&characterEncoding=UTF-8 + username: root + password: 'lyg8266@Qiween#com' + druid: + initial-size: 3 + min-idle: 1 + max-active: 500 + max-wait: 60000 # 获取连接等待超时的时间 + time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位是毫秒 + test-while-idle: true # 申请连接的时候检测, 建议配置为true,不影响性能 + test-on-borrow: false # 申请连接时执行validationQuery检测连接是否有效 + test-on-return: false # 归还连接时执行validationQuery检测连接是否有效 + validation-query: SELECT 1 + log-abandoned: true # 关闭abanded连接时输出错误日志 + remove-abandoned: false # 是否开启连接泄漏监测,对性能会有一些影响,建议怀疑存在泄漏之后再打开 + remove-abandoned-timeout: 1800 # 1800秒,也就是30分钟 + filters: stat, wall + web-stat-filter: + exclusions: '*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*' + stat-view-servlet: + enabled: true + url-pattern: /druid/* + login-username: admin + login-password: szxgl.com + data: + elasticsearch: + repositories: + enabled: true # 开启 Elasticsearch仓库(默认值:true) + client: + reactive: + endpoints: 127.0.0.1:9200 + connection-timeout: 5000 + socket-timeout: 5000 + + + diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..a956fc3 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,71 @@ +# tomcat配置 +server: + port: 8081 + servlet: + context-path: /cases + jsp: + init-parameters: + development: true # 开发者模式,不加这个修改jsp内容不会实时生效 + tomcat: + uri-encoding: utf-8 + remoteip: + remote-ip-header: x-forwarded-for + protocol-header: x-forwarded-proto + port-header: X-Forwarded-Port + +logging: + level: + root: INFO + com.nbclass: DEBUG + tk.mybatis: DEBUG + org.springframework: INFO + +spring: + profiles: + active: dev # 环境 dev|test|prod + main: + allow-bean-definition-overriding: true # 当遇到相同名字bean的时候,是否允许覆盖注册 + + thymeleaf: + # 关闭缓存,相当于调试模式,修改模板直接生效 + cache: false + mode: LEGACYHTML5 + #enabled: false + messages: + encoding: UTF-8 + basename: i18n/messages + use-code-as-default-message: true + jackson: + date-format: yyyy-MM-dd HH:mm:ss + time-zone: GMT+8 + default-property-inclusion: non-null # 响应JSON数据过滤NULL值 + servlet: + multipart: + enabled: true # 开启 multipart上传功能 + max-file-size: 100MB # 最大单文件大小 + max-request-size: 200MB # 最大请求大小 + file-size-threshold: 5KB # 文件写入磁盘的阈值 +# mvc: +# view: +# prefix: /WEB-INF/ +# suffix: .jsp +# static-path-pattern: /** +mybatis: + type-aliases-package: com.nbclass.*.model + mapper-locations: classpath:mapper/**/*.xml + configuration: + # 进行自动映射时,数据以下划线命名,如数据库返回的"order_address"命名字段是否映射为class的"orderAddress"字段。默认为false + map-underscore-to-camel-case: false + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl +mapper: + mappers: com.nbclass.util.MyMapper + not-empty: false + identity: MYSQL +pagehelper: + helperDialect: mysql + reasonable: false # 分页参数合理化,启用时,如果参数超出范围也会返回数据,禁用时返回空 + supportMethodsArguments: true + params: count=countSql + + + diff --git a/src/main/resources/generator/generatorConfig.xml b/src/main/resources/generator/generatorConfig.xml new file mode 100644 index 0000000..3ce2a1b --- /dev/null +++ b/src/main/resources/generator/generatorConfig.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
\ No newline at end of file diff --git a/src/main/resources/log4j2-spring.xml b/src/main/resources/log4j2-spring.xml new file mode 100644 index 0000000..5c32e90 --- /dev/null +++ b/src/main/resources/log4j2-spring.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/activity/CaseTypeMapper.xml b/src/main/resources/mapper/activity/CaseTypeMapper.xml new file mode 100644 index 0000000..09a5be8 --- /dev/null +++ b/src/main/resources/mapper/activity/CaseTypeMapper.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/activity/CommentMapper.xml b/src/main/resources/mapper/activity/CommentMapper.xml new file mode 100644 index 0000000..6972371 --- /dev/null +++ b/src/main/resources/mapper/activity/CommentMapper.xml @@ -0,0 +1,604 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + insert into comment + ( + content_id, + user_id, + comment_content, + create_time + ) + values + ( + #{contentId}, + #{userId}, + #{commentContent}, + now() + ) + + + + + + insert into praise + ( + comment_id, + praise_id, + user_id, + create_time + ) + values + ( + #{commentId}, + #{praiseId}, + #{userId}, + now() + ) + + + + update comment set + + praiseno = praiseno + 1 + + where id = #{commentId} + + + + update content set + + praiseno = praiseno+1 + + where id = #{contentId} + + + + insert into comment + ( + content_id, + user_id, + reply_id, + comment_id, + comment_content, + create_time + ) + values + ( + #{contentId}, + #{userId}, + #{replyId}, + #{commentId}, + #{commentContent}, + now() + ) + + + + insert into report + ( + comment_id, + report_id, + report_content, + report_type, + create_time + ) + values + ( + #{commentId}, + #{reportId}, + #{reportContent}, + #{reportType}, + now() + ) + + + + + + insert into label_logger + ( + content_id, + user_id, + logger, + create_time + ) + values + ( + #{contentId}, + #{userId}, + #{logger}, + now() + ) + + + + insert into favorites_folder + ( + name, + user_id, + create_time + ) + values + ( + #{name}, + #{userId}, + now() + ) + + + + + + insert into folder_resources + ( + folder_id, + content_id, + create_time + ) + values + ( + #{folderId}, + #{contentId}, + now() + ) + + + + update favorites_folder set + + total_collections = total_collections+1 + + where id = #{folderId} + + + + + + + + delete from folder_resources where folder_id = #{folderId} and content_id = #{contentId} + + + + + + + + + + delete from praise where comment_id = #{commentId} and praise_id = #{userId} + + + + update comment set + + praiseno = praiseno - 1 + + where id = #{commentId} + + + + update comment set + + reply_number = reply_number + 1 + + where id = #{commentId} + + + + + + + + + + update content set + + collection_number = collection_number + 1 + + where id = #{contentId} + + + + update content set + + collection_number = collection_number - 1 + + where id = #{contentId} + + + + update content set + + label_feedback = label_feedback + 1 + + where id = #{contentId} + + + + + + insert into scoring_table + ( + content_id, + score, + user_id, + create_time + ) + values + ( + #{contentId}, + #{score}, + #{userId}, + now() + ) + + + diff --git a/src/main/resources/mapper/activity/ContentMapper.xml b/src/main/resources/mapper/activity/ContentMapper.xml new file mode 100644 index 0000000..ed2fc33 --- /dev/null +++ b/src/main/resources/mapper/activity/ContentMapper.xml @@ -0,0 +1,434 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + delete from content where id in + + #{item} + + + + + + + + + + + + + + delete from content_tags WHERE cid = #{cid} + + + + INSERT IGNORE INTO content_tags (cid, tid) + values + + (#{item.cid}, #{item.tid} ) + + + + + delete from content_images WHERE cid = #{cid} + + + + INSERT IGNORE INTO content_images (cid, imgurl, sort, ori_name) + values + + (#{item.cid}, #{item.imgurl}, #{item.sort}, #{item.ori_name} ) + + + + + + UPDATE content + + + viewno = IF(viewno IS NULL, 1, viewno+1) + + + praiseno = IF(praiseno IS NULL, 1, praiseno+1) + + + WHERE id = #{id} + + + + + + insert ignore into content_tags + ( + createtime, + cid, + tid + ) + values + ( + now(), + #{cid}, + #{tid} + ) + + + + + + delete from content_tags where cid in + + #{id} + + + + + update content set + + comments = comments + 1 + + where id = #{contentId} + + + + insert into scoring_table + ( + content_id, + score, + user_id, + create_time + ) + values + ( + #{contentId}, + #{score}, + #{userId}, + now() + ) + + + + + + + + insert into application + ( + content_id, + user_id, + type, + create_time + ) + values + ( + #{contentId}, + #{userId}, + #{type}, + now() + ) + + + + insert into `check` + ( + application_id, + check_id, + create_time + ) + values + ( + #{applicationId}, + #{checkId}, + now() + ) + + + + + + delete from application where id = #{applicationId} + + + + delete from `check` where application_id = #{applicationId} + + + + update application set + + status = 1 + + where id = #{applicationId} + + + + update `check` set + + status = 1 + + where application_id = #{applicationId} + + + + + + + + update `check` set + + status = #{status} + + where application_id = #{applicationId} and check_id = #{checkId} + + + + + + update content set + + `release` = #{release} + + where id = #{contentId} + + + + update application set + + status = #{status} + + where id = #{id} + + + + + diff --git a/src/main/resources/mapper/activity/DataDictItemMapper.xml b/src/main/resources/mapper/activity/DataDictItemMapper.xml new file mode 100644 index 0000000..68da645 --- /dev/null +++ b/src/main/resources/mapper/activity/DataDictItemMapper.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/mapper/activity/DataDictMapper.xml b/src/main/resources/mapper/activity/DataDictMapper.xml new file mode 100644 index 0000000..bd0a250 --- /dev/null +++ b/src/main/resources/mapper/activity/DataDictMapper.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + delete from data_dict where id in + + #{item} + + + + + + + + + + + + + INSERT ignore INTO data_dict_item(dictid, `value`, `name`) VALUES (#{dictid}, #{value}, #{name} ) + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/activity/WXMapper.xml b/src/main/resources/mapper/activity/WXMapper.xml new file mode 100644 index 0000000..b436e7e --- /dev/null +++ b/src/main/resources/mapper/activity/WXMapper.xml @@ -0,0 +1,101 @@ + + + + + + + + insert into weixi_user + ( + openid, + nickname, + sex, + province, + city, + headimgurl, + unionid, + create_time, + update_time + ) + values + ( + #{openid}, + #{nickname}, + #{sex}, + #{province}, + #{city}, + #{headimgurl}, + #{unionid}, + now(), + now() + ) + + + + + + + + + + update weixi_user + + + birthday = #{birthday}, + + + occupation_id = #{occupationId}, + + + company = #{company}, + + + mailbox = #{mailbox}, + + + brief_introduction = #{briefIntroduction}, + + + update_time = #{updateTime} + + + where id = #{id} + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/activity/WxDepartmentMapper.xml b/src/main/resources/mapper/activity/WxDepartmentMapper.xml new file mode 100644 index 0000000..1a3a643 --- /dev/null +++ b/src/main/resources/mapper/activity/WxDepartmentMapper.xml @@ -0,0 +1,18 @@ + + + + + + insert into wx_department (id, `name`, parentid, `order`) + values + + (#{o.id}, #{o.name}, #{o.parentid}, #{o.order}) + + ON DUPLICATE KEY UPDATE `name` = VALUES(name), parentid = VALUES(parentid), `order` = VALUES(`order`) + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/activity/WxUserMapper.xml b/src/main/resources/mapper/activity/WxUserMapper.xml new file mode 100644 index 0000000..9a054a1 --- /dev/null +++ b/src/main/resources/mapper/activity/WxUserMapper.xml @@ -0,0 +1,66 @@ + + + + + + insert into wx_user (userid, name, mobile, department, position, gender, email, weixinid, + isleader, avatar, english_name, status) + values (#{userid}, #{name}, #{mobile}, #{department}, #{position}, #{gender}, #{email}, #{weixinid}, + #{isleader}, #{avatar}, #{english_name}, #{status}) + + + + update wx_user set name = #{name}, mobile = #{mobile}, department = #{department} + + , position = #{position} + + + , gender = #{gender} + + + , email = #{email} + + + , weixinid = #{weixinid} + + + , isleader = #{isleader} + + + , avatar = #{avatar} + + + , english_name = #{english_name} + + + , `status` = #{status} + + where userid = #{userid} + + + + + + + + + + delete from wx_user where userid not in + + #{userid} + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/system/PermissionMapper.xml b/src/main/resources/mapper/system/PermissionMapper.xml new file mode 100644 index 0000000..22ecbe2 --- /dev/null +++ b/src/main/resources/mapper/system/PermissionMapper.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + id, permission_id, name, description, url, perms, parent_id, type, order_num, icon, status, create_time, update_time + + + + + + + + + + + + + + + + UPDATE + permission + SET + status=#{status}, update_time=now() + where + permission_id = #{permissionId} + + + + + + UPDATE + permission + SET + name=#{name},description=#{description},url=#{url},perms=#{perms}, parent_id=#{parentId}, order_num=#{orderNum}, icon=#{icon}, update_time=now() + where + permission_id = #{permissionId} + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/system/RoleMapper.xml b/src/main/resources/mapper/system/RoleMapper.xml new file mode 100644 index 0000000..b82d81d --- /dev/null +++ b/src/main/resources/mapper/system/RoleMapper.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + id, role_id, name, description, status, create_time, update_time + + + + + + + + UPDATE + role + SET + status=#{status}, update_time=now() + where + role_id in + + #{item} + + + + + UPDATE + role + SET + name=#{name},description=#{description}, update_time=now() + where + role_id = #{role_id} + + + \ No newline at end of file diff --git a/src/main/resources/mapper/system/RolePermissionMapper.xml b/src/main/resources/mapper/system/RolePermissionMapper.xml new file mode 100644 index 0000000..4b3ad35 --- /dev/null +++ b/src/main/resources/mapper/system/RolePermissionMapper.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + id, role_id, permission_id + + \ No newline at end of file diff --git a/src/main/resources/mapper/system/SysLogMapper.xml b/src/main/resources/mapper/system/SysLogMapper.xml new file mode 100644 index 0000000..eddd55e --- /dev/null +++ b/src/main/resources/mapper/system/SysLogMapper.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + delete from sys_log where id in + + #{item} + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/system/UserMapper.xml b/src/main/resources/mapper/system/UserMapper.xml new file mode 100644 index 0000000..29c9407 --- /dev/null +++ b/src/main/resources/mapper/system/UserMapper.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + user.id, user.user_id, user.username, user.password, user.salt, user.email, user.phone, user.sex, user.age, user.status, + user.create_time, user.update_time, user.last_login_time + + + + + + + + + + update user SET last_login_time = now() where id = #{id,jdbcType=BIGINT} + + + + update user SET email=#{email},phone=#{phone},sex=#{sex},age=#{age},update_time = now() where user_id = #{userId,jdbcType=BIGINT} + + + + UPDATE + user + SET + status=#{status}, update_time=now() + where + user_id in + + #{item} + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/system/UserRoleMapper.xml b/src/main/resources/mapper/system/UserRoleMapper.xml new file mode 100644 index 0000000..c8280dd --- /dev/null +++ b/src/main/resources/mapper/system/UserRoleMapper.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + id, user_id, role_id + + \ No newline at end of file diff --git a/src/main/resources/static/css/cases/content.css b/src/main/resources/static/css/cases/content.css new file mode 100644 index 0000000..9cd4b79 --- /dev/null +++ b/src/main/resources/static/css/cases/content.css @@ -0,0 +1,13 @@ + +#fileInput{position:absolute;left:0;top:0;right:0;bottom:0;opacity:0;} + +.fileList_parent{margin:10px 0px;} +.fileList_parent th{background:#dadada;font-weight:bold;} +.fileList_parent th,.fileList_parent td{padding:5px;} +.fileList tr:nth-of-type(2n){background:#dadada;} +.fileList .td-filename{max-width: 90px;} + +.progressParent{width:200px;height:20px;border-radius:5px;background:#ccc;overflow:hidden;position:relative;} +.progress{width:0%;height:20px;background:#a5d24a;} +.progressNum{display:inline-block;width:100%;height:20px;text-align:center;line-height:20px;color:#fff;position:absolute;left:0;top:0;} + diff --git a/src/main/resources/static/css/common.css b/src/main/resources/static/css/common.css new file mode 100644 index 0000000..71a7c41 --- /dev/null +++ b/src/main/resources/static/css/common.css @@ -0,0 +1,441 @@ +.mt0{ + margin-top: 0px; +} +.mt10{ + margin-top: 10px; +} +.mt20{ + margin-top: 20px; +} +.mr0{ + margin-right: 0px; +} +.mr10{ + margin-right: 10px; +} +.mr20{ + margin-right: 20px; +} +.mb0{ + margin-bottom: 0px; +} +.mb10{ + margin-bottom: 10px; +} +.mb20{ + margin-bottom: 20px; +} +.ml0{ + margin-left: 0px; +} +.ml10{ + margin-left: 10px; +} +.ml20{ + margin-left: 20px; +} +.pb-15{ + padding-bottom: 15px; +} +.pr-5{ + padding-right: 5px; +} +.pl-15{ + padding-left: 15px; +} +.btn { + border-width: 0; + padding: 7px 14px; + font-size: 14px; + outline: none !important; + background-image: none !important; + filter: none; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + text-shadow: none; +} + +.red{ + color: red; +} + +.blue.btn { + color: white; + background-color: #4b8df8; +} + +.cursor-pointer{ + cursor: pointer; +} + +.display-none{ + display: none; +} +.display-block{ + display: block; +} +.navbar-custom-menu>.navbar-nav>li> .dropdown-left{ + right: auto; +} +/*.dropdown-menu>li>a { + padding: 3px 14px; +}*/ +.dropdown-menu{ + min-width: 100px; +} +.dropdown-menu .divider { + margin: 1px 0; +} +.navbar-nav>.user-menu>.dropdown-menu { + width: auto; +} +.form-group label{ + font-weight: 500; + color:#353535; +} +.control-sidebar{ + min-height: 100%; +} +.content-wrapper{ + padding-bottom: 15px; +} +.fixed .control-sidebar{ + position: fixed; + max-height: 100%; + overflow: auto; + padding-bottom: 50px; +} + +/*旋转*/ +.icon-spin { + display: inline-block; + -webkit-animation: spin 1s infinite linear; + animation: spin 1s infinite linear; +} +.icon-spin-music { + display: inline-block; + -webkit-animation: spin 5s infinite linear; + animation: spin 5s infinite linear; +} +@-webkit-keyframes spin { + 0% { + -webkit-transform: rotate(0) + } + + 100% { + -webkit-transform: rotate(359deg) + } +} + +@keyframes spin { + 0% { + -webkit-transform: rotate(0); + transform: rotate(0) + } + + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg) + } +} + +.bootstrap-table .table thead>tr>th { + background-color: #f5f5f5; +} +.fixed-table-pagination .pagination-detail, .fixed-table-pagination div.pagination { + margin-left: 10px; +} +/*layer弹出框自定义样式示例*/ +body .demo-class .layui-layer-title{background:#c00; color:#fff; border: none;} +body .demo-class .layui-layer-btn{border-top:1px solid #E9E7E7} +body .demo-class .layui-layer-btn a{background:#2e8ded;} +body .demo-class .layui-layer-btn .layui-layer-btn1{background:#f1f1f1;} + +.fontawesome-icon-list div i{ + color: #4969b3; +} + +.table thead>tr>th{ + background-color: #ecf0f5!important; +} + +.grid-table-toolbar{ + margin-top: 10px; + margin-bottom: 10px; +} + +/*.jax-table .fixed-table-toolbar .bs-bars, .fixed-table-toolbar .columns, .fixed-table-toolbar .search { + margin-top: 0px!important; +}*/ + +.nav-tabs-custom>.nav-tabs>li.active.danger{ + border-top-color: #dd4b39 +} +.nav>li>.jax-tab-a { + padding: 8px 15px; +} + +.jax-nav-tabs{ + background-color: #f9f9f9; +} +/*菜单*/ +.sidebar-menu li.li-close>a>.fa-angle-left, .sidebar-menu li.li-close>a>.pull-right-container>.fa-angle-left { + -webkit-transform: rotate(0deg); + -ms-transform: rotate(0deg); + -o-transform: rotate(0deg); + transform: rotate(0deg); +} + +.sidebar-menu li a{ + -webkit-transition: all 0.2s ; + -ms-transition: all 0.2s ; + -o-transition: all 0.2s ; + transition: all 0.2s; +} +.sidebar-menu li.li-open>a>.fa-angle-left, .sidebar-menu li.li-open>a>.pull-right-container>.fa-angle-left { + -webkit-transform: rotate(-90deg); + -ms-transform: rotate(-90deg); + -o-transform: rotate(-90deg); + transform: rotate(-90deg); +} + +.sidebar-menu>li.li-open>a:hover { + color: #fff; + background: #1e282c; +} + +.skin-blue-light .sidebar-menu>li.li-open>a:hover { + color: #000; + background: #f4f4f5 +} +.skin-black-light .sidebar-menu>li.li-open>a:hover { + color: #000; + background: #f4f4f5 +} +.skin-purple-light .sidebar-menu>li.li-open>a:hover { + color: #000; + background: #f4f4f5 +} +.skin-green-light .sidebar-menu>li.li-open>a:hover { + color: #000; + background: #f4f4f5 +} +.skin-red-light .sidebar-menu>li.li-open>a:hover { + color: #000; + background: #f4f4f5 +} +.skin-yellow-light .sidebar-menu>li.li-open>a:hover { + color: #000; + background: #f4f4f5 +} +.upload-music-div,.upload-img-div{ + margin-bottom: 20px; +} +.upload-div1{ + padding-left: 8px; +} +.upload-div2{ + padding-left: 15px; +} +.jax-upload-btn{ + font-size: 20px; + padding: 3px 0; + color: #5d5d5d; +} +.upload-music-btn:hover,.upload-img-btn:hover{ + cursor: pointer; + color: #3d78e2; +} + +.jax-box{ + border-radius: 3px; + background: #ffffff; + border: 1px solid #e6e7e7; + border-bottom: none; + margin-bottom: 10px; + width: 100%; + padding: 10px; + box-shadow: 0 1px 1px rgba(0,0,0,0.1); +} +.jax-box .form-group{ + margin-bottom: 0px; +} +.jax-box .form-group label{ + padding-left: 5px; + padding-right: 5px; + padding-top: 7px; +} +.jax-box .control-label{ + text-align: left; +} + +.jax-box-table{ + padding-top: 0px; +} + +.table-btn{ + margin: 0 2px; + border-radius: 10px; + padding: 2px 5px; + font-size: 12px; +} +.table-btn.table-btn-info{ + color: #00c0ef; + border: 1px solid #00c0ef; +} +.table-btn.table-btn-info:hover{ + color: #00acd6; + border: 1px solid #00acd6; +} +.table-btn.table-btn-success{ + color: #00a65a; + border: 1px solid #00a65a; +} +.table-btn.table-btn-success:hover{ + color: #008d4c; + border: 1px solid #008d4c; +} +.table-btn.table-btn-warning{ + color: #ec971f; + border: 1px solid #ec971f; +} +.table-btn.table-btn-warning:hover{ + color: #dc8d1e; + border: 1px solid #dc8d1e; +} +.table-btn.table-btn-danger{ + color: #dd4b39; + border: 1px solid #dd4b39; +} +.table-btn.table-btn-danger:hover{ + color: #d73925; + border: 1px solid #d73925; +} + +.treegrid-tbody tr :first-child.table-btn-info{ + border-left: 1px solid #00c0ef!important; +} +.treegrid-tbody tr :first-child.table-btn-danger{ + border-left: 1px solid #dd4b39!important; +} + +@media (max-width: 767px){ + .dropdown-menu li.divider { + background-color: #eee!important; + } + .navbar-nav .open .dropdown-menu>li>a { + line-height: 16px; + } + .navbar-nav .open .dropdown-menu .dropdown-header, .navbar-nav .open .dropdown-menu>li>a { + padding: 5px 15px 5px 20px; + } + .upload-div1,.upload-div2{ + padding-left: 0px; + } +} +@media (max-width: 991px) { + .dropdown-li { + position: relative!important; + } + .dropdown-left a{ + color: #777!important; + } +} + + +.zb-checkbox{ + position: relative; +} +thead .zb-checkbox label{ + padding-top: 2px; +} +.zb-checkbox input[type="checkbox"] { + opacity: 0; +} +.zb-checkbox label:before { + content: ''; + width: 18px; + height: 18px; + display: inline-block; + border-radius: 2px; + border: 1px solid #ddd; + background: #fff; +} +thead .zb-checkbox input[type="checkbox"]:checked + label:after { + top:24%; +} +.zb-checkbox input[type="checkbox"]:checked + label:after { + display: inline-block; + font-family: 'Glyphicons Halflings'; + content: "\e013"; + top: 18%; + left: 5%; + position: absolute; + font-size: 10px; + line-height: 1; + width: 16px; + height: 16px; + color: #009ddc; +} +.zb-checkbox label { + cursor: pointer; + text-align: center; + position: absolute; + left: 10px; +} +.fixed-table-container tbody tr.selected td{ + border-bottom: 1px solid #e9e9e9; + background-color: #f2f8ff; +} +.fixed-table-container tbody tr.selected:hover td{ + background-color: #f5f5f5; +} + + + + +.zb-radio{ + position: relative; +} +thead .zb-radio label{ + padding-top: 2px; +} +.zb-radio input[type="radio"] { + opacity: 0; +} +.zb-radio label:before { + content: ''; + width: 18px; + height: 18px; + display: inline-block; + border-radius: 50px; + border: 1px solid #ddd; + background: #fff; +} +thead .zb-radio input[type="radio"]:checked + label:after { + top:24%; +} +.zb-radio input[type="radio"]:checked + label:after { + display: inline-block; + font-family: 'Glyphicons Halflings'; + content: "\e013"; + top: 18%; + left: 5%; + position: absolute; + font-size: 10px; + line-height: 1; + width: 16px; + height: 16px; + color: #009ddc; +} +.zb-radio label { + cursor: pointer; + text-align: center; + position: absolute; + left: 10px; +} +.jax-box-table .treegrid-selected{ + background-color: #f2f8ff!important; +} +.ke-content img{max-width:100%;} diff --git a/src/main/resources/static/css/login.css b/src/main/resources/static/css/login.css new file mode 100644 index 0000000..a79c5d4 --- /dev/null +++ b/src/main/resources/static/css/login.css @@ -0,0 +1,409 @@ + +body{background-color: #1e282c;} + +ol, ul { + list-style: none; +} + +button { + outline: none; +} + +.btn:active, .btn:focus { + outline: 0 !important; +} + +.ml-15 { + margin-left: 15px; +} + +.ml-20 { + margin-left: 20px; +} + +.mb-20 { + margin-bottom: 20px; +} + +.pb-10 { + padding-bottom: 20px; +} + +.pb-20 { + padding-bottom: 20px; +} + +.pb-30 { + padding-bottom: 30px; +} +.bg-47bf82{ + background: #47bf82; +} +.bg-6e8bd6{ + background: #6e8bd6; +} +.bg-ad53c4{ + background: #ad53c4; +} +.bg-b98140{ + background: #b98140; +} +.center{ + text-align: center; +} + +/*-------top-start------*/ +.logo-a { + float: left; + padding: 5px 0; + height: 54px; +} + +.logo-a img { + height: 100%; +} + +.navbar-default .navbar-toggle { + border-color: #0086da; + background-color: #0086da; + margin-top: 10px; + margin-bottom: 10px; +} + +.navbar-default .navbar-toggle .icon-bar { + background-color: #fff; +} + +.navbar-default .navbar-toggle:hover, .navbar-default .navbar-toggle:focus { + background-color: #0086da; +} + +.navbar-nav .active { + border-bottom: 4px solid #3977de; +} + +@media (max-width: 768px) { + .logo-a { + padding-left: 15px; + } + + .navbar-nav .active { + border-bottom: 4px solid #3977de; + border-left: 1px solid #f8f8f8; + border-right: 1px solid #f8f8f8; + } +} + +.navbar-nav .active a { + color: #3977de !important; +} + +.navbar-default .navbar-nav > .active > a, .navbar-default .navbar-nav > .active > a:hover { + color: #3977de; +} + +.navbar-default .navbar-nav > li > a:hover { + color: #3977de; +} + +.navbar-nav li a { + font-size: 15px; +} + +.navbar-default .navbar-nav > .color-red > a { + color: red; +} + +.navbar-default .navbar-nav > .active > a, .navbar-default .navbar-nav > .active > a:hover { + background-color: #f8f8f8; +} + +.dropdown-menu { + min-width: 110px; +} + +.navbar-nav > li > .dropdown-menu { + background-color: #fff; + margin-top: 4px; +} + +.navbar-nav > li > .dropdown-menu a { + color: #585858; +} + +.navbar-default .navbar-nav .open .dropdown-menu > li > a:focus, .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover { + color: #3977de; +} + +.navbar-default .navbar-nav > .open > a, .navbar-default .navbar-nav > .open > a:focus, .navbar-default .navbar-nav > .open > a:hover { + color: #3977de; + background-color: transparent; +} + +.dropdown-menu .divider { + margin: 3px 0; +} + +.flex-prev i { + color: rgba(0, 0, 0, 0.65); + font-size: 30px; +} + +.flex-next i { + color: rgba(0, 0, 0, 0.65); + font-size: 30px; +} + +/*-------footer-start------*/ +.footer-section { + padding-top: 30px; + background: #313131; +} + +.footer-section h5 { + color: #cccccc; + font-size: 14px; + text-transform: uppercase; + margin-bottom: 20px; + font-weight: bold; + position: relative; +} + +.footer-section h5:after { + content: ""; + display: block; + margin-top: 20px; + width: 25px; + height: 4px; + background: #ff6400; +} + +.footer-section p { + color: #999999; + font-size: 14px; +} + +.footer-section .footer-nav li { + line-height: 24px; +} + +.footer-section .footer-nav li.active a { + color: #ff6400; +} + +.footer-section .footer-nav li a { + font-size: 14px; + line-height: 2; + color: #999999; + text-decoration: none; +} + +.footer-section .footer-nav li a:hover { + color: #ff6400; +} + +.footer-section .contacts-list i { + min-width: 20px; + margin-right: 5px; +} + +.footer-section .contacts-list p { + margin-bottom: 0; +} + +.footer-section .contacts-list a { + color: #999; + text-decoration: none; +} + +.footer-section .form-control { + border-color: #333333; +} + +.footer-section .form-control:focus, .footer-section .form-control:active { + border-color: #ddd; +} + +.footer-section .form-control-feedback { + color: #999; + top: 16px; + font-size: 15px; +} + +.footer-section ul { + margin: 0; + padding: 0; +} + +.footer-section .form-control { + background: none; + box-shadow: none !important; + outline: none; + border: none; + border-bottom: 1px solid #999; + border-radius: 0; + font-size: 14px; + padding-left: 0; + height: 50px; + color: #999; +} + +.footer-content { + margin-bottom: 30px; +} + +.copyright-section { + padding: 30px 0; + text-align: center; +} +.copyright-section p { + margin-bottom: 0; + font-size: 10px; + text-transform: uppercase; + font-family: 'Montserrat', sans-serif; +} +.copyright-dark.copyright-section { + background: #313131; + border-top: 1px solid #545252; +} + +.copyright-dark.copyright-section p { + color: #999; +} + +.copyright-dark.copyright-section p span { + color: #ccc; +} +.copyright-light.copyright-section { + background: #fff; + border-top: 1px solid #c7c6c6; +} + +.copyright-light.copyright-section p { + color: #6c6b6b; +} + +.copyright-light.copyright-section p span { + color: #6c6b6b; +} + +/*swipper*/ +.swiper-button-next { + background-image: none; + font-size: 28px; + opacity: .6; + color: rgba(0, 0, 0, .65) +} + +.swiper-button-prev { + background-image: none; + font-size: 28px; + opacity: .6; + color: rgba(0, 0, 0, .65) +} + +.swiper-container .swiper-button-next:hover, .swiper-container .swiper-button-prev:hover { + opacity: 1 +} + +/*login内容开始*/ +input{ + -webkit-appearance: none; +} +.login-content { + position: relative; + /*margin-top: 55px;*/ +} + +.login-bg { + /*background: url(../img/login-bg.jpg) center top no-repeat;*/ + /*background-color: currentColor;*/ + width: 100%; + /*height: 750px;*/ + top: 0px; +} + +.login-box { + position: absolute; + z-index: 2; + /* + margin-top: 8%; + margin-right: 15%; + */ + margin-top: 10%; + margin-right: 42%; + + top: 0px; + right: 0px; + padding-bottom: 30px; + background: #fff; + border-radius: 3px; + border-color: #e2e2e2; +} + +.login-form { + width: 324px; + float: right; + padding: 0px 26px; +} + +.login-form .login-title { + margin-top: 20px; + margin-bottom: 15px; + font-size: 18px; + color: #4e4e4e; +} + +.vcode-icon{ + font-weight: 700; + font-size: 15px; +} + +@media (max-width: 768px) { + .login-box { + right: 50%; + margin-right: -162px; + } +} + +.login-form .form-control-feedback { + color: #666; + left: 0; + right: auto; +} + +.login-form .has-feedback .form-control { + padding-left: 35px; + padding-right: 10px; + height: 40px; +} +.login-form .form-control-feedback{ + width: 40px; + height: 40px; + line-height: 40px; +} + +vcode { + font-size: 0px; +} + +.vcode-content { + width: 60%; + display: inline-block; +} + +.vcode-input { + display: inline-block; + vertical-align: middle; + border-top-right-radius: 0px; + border-bottom-right-radius: 0px; +} + +.vcode-img { + width: 40%; + height: 40px; + position: absolute; +} +.position-a{ + right: 120px; +} \ No newline at end of file diff --git a/src/main/resources/static/favicon.ico b/src/main/resources/static/favicon.ico new file mode 100644 index 0000000..f4e960f Binary files /dev/null and b/src/main/resources/static/favicon.ico differ diff --git a/src/main/resources/static/img/person.jpg b/src/main/resources/static/img/person.jpg new file mode 100644 index 0000000..0d2b0d8 Binary files /dev/null and b/src/main/resources/static/img/person.jpg differ diff --git a/src/main/resources/static/js/cases/content.js b/src/main/resources/static/js/cases/content.js new file mode 100644 index 0000000..61ff818 --- /dev/null +++ b/src/main/resources/static/js/cases/content.js @@ -0,0 +1,292 @@ + +// 元素 +var oFileBox = $(".fileBox"); //选择文件父级盒子 +var oFileInput = $("#fileInput"); //选择文件按钮 + +var oFileList_parent = $(".fileList_parent"); //表格 +var oFileList = $(".fileList"); //表格tbody +var oFileBtn = $("#fileBtn"); //上传按钮 + +var flieList = []; //数据,为一个复合数组 +//var sizeObj = []; //存放每个文件大小的数组,用来比较去重 + +$(function(){ + + //点击选择文件按钮选文件 + oFileInput.on("change",function(){ + flieList = new Array(); // 重新选择前先删除上次选择的 + analysisList(this.files); + }) + + // 删除表格单行文件 + oFileList.on("click","a.btn_delfile",function(){ + if(!confirm("确认删除?"))return; + var oTr = $(this).parents("tr"); + var index = oTr.index(); + oTr.remove(); //删除这一行 + flieList.splice(index,1); // 删除数据 + // sizeObj.splice(index,1); // 删除文件大小数组中的项 + }); + + // 预览表格单行文件 + oFileList.on("click","a.btn_viewfile",function(){ + var imgurl = $(this).parent().find('.imgurl').val(); + if(imgurl==null || $.trim(imgurl)=='')return; + layer.photos({ + photos: {"id":'a1',"start":0,"data":[{"src":""+imgurl+""}]} + ,anim: 5 // 0-6的选择,指定弹出图片动画类型,默认随机 + }); + }); + + // 只允许输入数字 + oFileList.on("keyup",".sort",function(){ + $(this).val($(this).val().replace(/\D/g,'')); + }); + // 只允许粘贴数字 + oFileList.on("paste",".sort",function(){ + $(this).val($(this).val().replace(/\D/g,'')); + }); + + //上传 + oFileBtn.on("click",function(){ + // oFileBtn.off(); + var tr = oFileList.find(".uploaddata"); //获取所有tr列表 + var successNum = 0; //已上传成功的数目 + // oFileList.off(); //取消删除事件 + oFileBox.slideUp(); //隐藏输入框 + // oFileList.find("a.btn_delfile").text("等待上传"); + + for( var i=0;i 16){ + alert('最多只能上传16张图片'); + return false; + }else{ + var totallength = obj.length; + var uptr = oFileList.find(".uploaddata"); + if(uptr.length > 0)totallength+=uptr.length; + var dbtr = oFileList.find(".dbdata"); + if(dbtr.length > 0)totallength+=dbtr.length; + if(totallength > 16){ + alert('最多只能上传16张图片'); + return false; + } + } + } + + + // 先全部校验一遍 + for( var i=0;i 10*1024*1024){ + if(size > 2*1024*1024){ + alert('文件"'+ name +'"超过了2M,不能上传'); + return false; + } + //文件类型不为这几种,就不上传 + if(("png/jpg/jpeg/bmp/gif").indexOf(type) == -1){ + alert('文件"'+ name +'"类型不对,不能上传'); + return false; + } + } + + for( var i=0;i20)name=name.substr(0,10)+'...'+name.substr(name.length-5); + + var oTr = $(""); + var str = ''+ name +''; + str += ''; + str += ''; + str += '
'; + str += '

'; + str += '0%'; + str += '
'; + str += ''; + str += ''; + str += ''; + str += '删除'; + str += '  预览'; + str += ''; + + oTr.html(str); + oTr.appendTo(oFileList); + } +} + +function uploadFn(obj,i){ + var formData = new FormData(); + var arrNow = flieList[i]; //获取数据数组的当前项 + + // 从当前项中获取上传文件,放到 formData对象里面,formData参数以key name的方式 + var result = arrNow[0]; //数据 + formData.append("file" , result); + + var name = arrNow[1]; //文件名 + formData.append("filename" , name); + + var progress = obj.find(".progress"); //上传进度背景元素 + var progressNum = obj.find(".progressNum"); //上传进度元素文字 +// var obtn_delfile = obj.find("a.btn_delfile"); //按钮 + +// obtn_delfile.text("正在上传"); //改变操作按钮 +// obtn_delfile.off(); + + var request = $.ajax({ + type: "POST", + url: 'console/tool/oss/uploadFile?caseType='+caseType+'&category=image', + data: formData, //这里上传的数据使用了formData 对象 + processData : false, //必须false才会自动加上正确的Content-Type + contentType : false, + //这里我们先拿到jQuery产生的XMLHttpRequest对象,为其增加 progress 事件绑定,然后再返回交给ajax使用 + xhr: function(){ + var xhr = $.ajaxSettings.xhr(); + if(onprogress && xhr.upload){ + xhr.upload.addEventListener("progress", onprogress, false); + return xhr; + } + }, + //上传成功后回调 + success: function(result){ + result = result.data; + obj.removeClass('uploaddata').addClass('dbdata'); // 删除待上传标记,增加已上传成功标记 + obj.find(".imgbtn").show(); + obj.find(".imgurl").val(result.url); + obj.find(".filename").text(result.ori_name); + }, + + //上传失败后回调 + error: function(){ + obj.find(".imgbtn").show(); + /* + obtn_delfile.text("重传"); + obtn_delfile.on("click",function(){ + request.abort(); //终止本次 + uploadFn(obj,i); + }); + */ + } + + }); + + //侦查附件上传情况 ,这个方法大概0.05-0.1秒执行一次 + function onprogress(evt){ + var loaded = evt.loaded; //已经上传大小情况 + var tot = evt.total; //附件总大小 + var per = Math.floor(100*loaded/tot); //已经上传的百分比 + progressNum.html(per +"%"); + progress.css("width", per +"%"); + } +} + + +//字节大小转换,参数为b +function bytesToSize(bytes) { + var sizes = ['Bytes', 'KB', 'MB']; + if (bytes == 0) return 'n/a'; + var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); + return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i]; +}; + +//通过文件名,返回文件的后缀名 +function fileType(name){ + var nameArr = name.split("."); + return nameArr[nameArr.length-1].toLowerCase(); +} + +// 设置数据行到表格 +function setTableList(dataList){ + if(dataList == null || dataList == undefined || dataList.length == 0)return; + dataList=dataList.replace(new RegExp('"','g'),'"'); // java返回的引号变成了" +// dataList=dataList.replace(/\s*/g,''); // 去除字符串内所有的空格 +// console.log('dataList='+dataList); + dataList = JSON.parse(dataList); + oFileList.empty(); // 先清空元素内容 + for( var i=0; i20)fname=fname.substr(0,10)+'...'+fname.substr(fname.length-5); + var oTr = $(""); + var str = ''+ fname +''; + str += ''; + str += ''; + str += ''; + str += ''; + str += ''; + str += '  '; + str += ''; + + oTr.html(str); + oTr.appendTo(oFileList); + } + oFileList_parent.show(); // 表格显示 + oFileList.find(".imgbtn").show(); // 操作按钮显示 +} + +// 返回json格式数据给后端 +function getImgJsonList(){ + var jsonArray = new Array(); + var trs = oFileList.find(".dbdata"); //获取所有tr列表 + for( var i=0;i'):(tableOptions.clickToSelect==true?$(''):$(''))); + $check.attr("id", id).parent().addClass("zb-checkbox").append($label); + }); + $(tableOptions.id).find("input:radio").each(function (i) { + var $check = $(this); + if ($check.attr("id") && $check.next("label")) { + return; + } + var name = $check.attr("name"); + var id = name + "-" + i; + var $label = (i==0?$(''):(tableOptions.clickToSelect==true?$(''):$(''))); + $check.attr("id", id).parent().addClass("zb-radio").append($label); + }); + if ($.isFunction(options.onPostBody)) { + options.onPostBody(); + } + } + }); + } + function queryInitParams(params) { + var temp = { //这里的键的名字和控制器的变量名必须一致,这边改动,控制器也需要改成一样的 + limit: params.limit, //页面大小 + offset: params.offset //页码 + }; + return temp; + } + + function responseHandler(data) { + return data; + } + + function tableLoadSuccess(data) { + } + + /*刷新表格 :flag-是否跳转到当前页。默认首页*/ + core.refreshTable = function (id, flag) { + if (flag) { + $(id).bootstrapTable("refresh"); + } else { + $(id).bootstrapTable("refresh", {"pageNumber": 1}); + } + } + + /*根据data选中数据*/ + core.checkTableBy=function (id,data) { + $(id).bootstrapTable("checkBy", data) + } + + /*根据uniqueId获取所选列*/ + core.getRowByUniqueId = function (id, val) { + return $(id).bootstrapTable("getRowByUniqueId", val); + } + core.selectSingleData = function (id){ + var selectContent = $(id).bootstrapTable('getSelections'); + if(typeof(selectContent) == 'undefined' || selectContent == "") { + layer.msg("请先选择一条数据!"); + return false; + }else if(selectContent.length > 1){ + layer.msg("只能选择一条数据!"); + return false; + }else{ + var selectData = selectContent[0]; + return selectData; + } + } + + core.selectMutiData = function (id){ + var checkedRows= $(id).bootstrapTable('getSelections'); + if(checkedRows.length==0){ + layer.msg("请先选择一条数据!"); + return false; + }else{ + return checkedRows; + } + } + + + /*更新某一列的值 index-行索引,field-字段名,value-值*/ + core.updateCell = function (id, index, field, value) { + var updateCellOptions = { + index: index, + field: field, + value: value + } + return $(id).bootstrapTable("updateCell", updateCellOptions); + } + + /*禁用button*/ + core.mask = function (e) { + var i = "" + $(e).append(i); + $(e).attr('disabled', "true");//添加disabled属性 + } + /*启用button*/ + core.unmask = function (e) { + $(e).children('i').remove(); + $(e).removeAttr('disabled');//添加disabled属性 + } + + /*询问框*/ + core.confirm = function(content,d){ + layer.confirm(content, { + icon: 3, + title: "系统提示", + btn: ['确认', '取消'], + btnclass: ['btn btn-primary', 'btn btn-danger'], + }, function (index) { + layer.close(index); + d(true); + }); + } + + //date类型到字符串 + core.formatterDateTime = function (date) { + var datetime = date.getFullYear() + + "-"// "年" + + ((date.getMonth() + 1) >= 10 ? (date.getMonth() + 1) + : "0" + (date.getMonth() + 1)) + + "-"// "月" + + (date.getDate() < 10 ? "0" + date.getDate() : date + .getDate()) + + " " + + (date.getHours() < 10 ? "0" + date.getHours() : date + .getHours()) + + ":" + + (date.getMinutes() < 10 ? "0" + date.getMinutes() + : date.getMinutes()) + + ":" + + (date.getSeconds() < 10 ? "0" + date.getSeconds() + : date.getSeconds()); + return datetime; + } + + //long类型转时间字符串 + core.longMsTimeConvertToDateTime = function (time) { + var myDate = new Date(time); + return this.formatterDateTime(myDate); + } + + /*日期+*/ + core.addDate = function (date, days) { + if (days == undefined || days == '') { + days = 1; + } + var date = new Date(date); + date.setDate(date.getDate() + days); + var month = date.getMonth() + 1; + var day = date.getDate(); + return date.getFullYear() + '-' + getFormatDate(month) + '-' + getFormatDate(day); + } + function getFormatDate(arg) { + if (arg == undefined || arg == '') { + return ''; + } + var re = arg + ''; + if (re.length < 2) { + re = '0' + re; + } + return re; + } + + /*是否是数组*/ + core.isArray = function (s) { + return s instanceof Array; + } + + core.clearForm = function (id) { + + var objId = document.getElementById(id); + if (objId == undefined) { + return; + } + for (var i = 0; i < objId.elements.length; i++) { + if (objId.elements[i].type == "text") { + objId.elements[i].value = ""; + } + else if (objId.elements[i].type == "password") { + objId.elements[i].value = ""; + } + else if (objId.elements[i].type == "radio") { + objId.elements[i].checked = false; + } + else if (objId.elements[i].type == "checkbox") { + objId.elements[i].checked = false; + } + else if (objId.elements[i].type == "select-one") { + objId.elements[i].options[0].selected = true; + } + else if (objId.elements[i].type == "select-multiple") { + for (var j = 0; j < objId.elements[i].options.length; j++) { + objId.elements[i].options[j].selected = false; + } + } + else if (objId.elements[i].type == "textarea") { + objId.elements[i].value = ""; + } + } + } + + /*清除表单错误提示*/ + core.clearError = function (id) { + $(id).find(".warning,.valid,.promimg").remove(); + $(id).find(".error").removeClass("error"); + $(id).find(".prombtn").removeClass("prombtn"); + $(id).find(".prominput").removeClass("prominput"); + } + /*保留两位小数*/ + core.numberTwo = function (num) { + if (isNaN(num) || num == "") { + return num; + } else { + if (isNaN(parseFloat(num).toFixed(2))) { + return num; + } else { + return parseFloat(num).toFixed(2); + } + } + } + /*数字千分话并保留两位小数*/ + core.numToTwo = function (num) { + try { + num = this.numberTwo(num).replace(/(\d)(?=(\d{3})+\.)/g, '$1,'); + } finally { + return num; + } + } + + + // 判断是否为json对象 + core.isJsonObject = function (obj) { + var isjson = typeof(obj) == "object" && Object.prototype.toString.call(obj).toLowerCase() == "[object object]" && !obj.length; + return isjson; + } + + + return core; +})(Core, window); diff --git a/src/main/resources/static/js/init.js b/src/main/resources/static/js/init.js new file mode 100644 index 0000000..4b8724e --- /dev/null +++ b/src/main/resources/static/js/init.js @@ -0,0 +1,201 @@ +$(document).ajaxStart(function() { +// Pace.restart(); +}); +$(function () { + /*固定布局*/ + $("#fixCheckBox").click(function () { + var neg = $('.main-header').outerHeight() ; + var window_height = $(window).height(); + if($(this).is(':checked')) { + $("body").addClass("fixed"); + $(".content-wrapper, .right-side").css('min-height', window_height); + }else{ + $("body").removeClass("fixed"); + $(".content-wrapper, .right-side").css('min-height', window_height-neg); + $(".control-sidebar").removeAttr("style"); + } + }) + /*盒状布局*/ + $("#layoutBox").click(function(){ + if($(this).is(':checked')) { + $("body").addClass("layout-boxed"); + }else{ + $("body").removeClass("layout-boxed"); + } + }) +}); +$(function(){ + var clickHref="";//点击菜单判断使用 + //菜单列表html + var menus = ''; + $.ajax({ + type: 'POST', + url: "menu" , + data: {} , + success: function (data) { + GetData(0, data) + $("#menu").append(menus); + /*菜单点击事件*/ + $(".sidebar-menu a").click(function () { + var aHref=$(this).attr("href"); + if(clickHref==aHref){ + if(aHref.substring(1,aHref.length)!=""){ + Core.load("#content",aHref.substring(1,aHref.length)); + } + }else{ + clickHref = aHref;//赋值 + } + }); + /*初始化加载菜单样式*/ + loadMenuRefresh(); + } + }); + //根据菜单主键id生成菜单列表html + //id:菜单主键id + //arry:菜单数组信息 + function GetData(id, arry) { + var childArry = GetParentArry(id, arry); + if (childArry.length > 0) { + if(menus==""){ + menus += '