Compare commits

...

200 Commits

Author SHA1 Message Date
755300db3c update 2021-01-14 23:26:38 +08:00
a790f8042d update 2021-01-14 23:22:03 +08:00
d0db2021a6 v3.4.1发布 2021-01-10 17:55:48 +08:00
c403fc7496 更新orange主题手机端首尾章节跳转逻辑 2021-01-07 20:59:19 +08:00
e4927d7ac6 爬虫管理系统设置session默认超时时间为1天,解决由于编写爬虫规则时间过长导致的提交失败问题 2021-01-05 21:46:01 +08:00
a00a2141f2 爬虫管理系统设置session默认超时时间为1天,解决由于编写爬虫规则时间过长导致的提交失败问题 2021-01-05 21:45:04 +08:00
7cc7d8b541 v3.4.0发布 2021-01-04 10:28:01 +08:00
e4822979e2 elasticsearch升级到7.x,集成RestHighLevelClient客户端 2021-01-03 13:42:40 +08:00
ab741ec6bf v3.3.0发布 2020-12-28 12:06:19 +08:00
057c0646cd v3.3.0发布 2020-12-28 12:02:34 +08:00
57a9cd09ef v3.3.0发布 2020-12-28 11:06:27 +08:00
1a49e2a340 增加外部配置文件来配置网站信息 2020-12-28 10:58:38 +08:00
f8411c2337 v3.3.0发布 2020-12-28 09:34:22 +08:00
343a741c21 更新展示图片 2020-12-27 15:54:50 +08:00
f1a5fb4813 更新展示图片 2020-12-27 15:34:23 +08:00
0428356bd4 新增蓝色主题模版 2020-12-27 09:43:45 +08:00
c01097cd5f 更新v3.3.0的安装文档 2020-12-26 23:53:05 +08:00
7e650a0a04 修改版本号 2020-12-26 22:27:51 +08:00
45c59ecc37 前端新增深色主题模版 2020-12-26 22:16:58 +08:00
5e3962fef4 update 2020-12-26 20:10:11 +08:00
7f5035e369 update 2020-12-26 20:08:07 +08:00
44aad39847 update 2020-12-26 20:00:21 +08:00
6ad51908d5 文件夹结构调整,新增模版自定义功能 2020-12-26 19:13:07 +08:00
f03ab953d0 v3.2.0发布 2020-12-26 11:45:19 +08:00
5cc9dfa1bc v3.2.0发布 2020-12-26 11:42:09 +08:00
2fbda60617 修复jwt校验失败后的bug 2020-12-24 17:13:36 +08:00
39c19ac004 页面不存在则跳转到404页面 2020-12-24 16:54:37 +08:00
7494fe431a 页面不存在则跳转到404页面 2020-12-24 16:45:48 +08:00
c9f1500976 新增404页面,访问已删除的书页/目录页/内容页自动跳转到404页面 2020-12-24 16:26:21 +08:00
f61c252e71 爬虫代码优化 2020-12-24 01:30:00 +08:00
6fd183c2ae 爬虫代码优化 2020-12-24 01:22:19 +08:00
c3daaecaaa 爬虫代码优化 2020-12-24 01:17:52 +08:00
1b6cc8ccd5 爬虫代码优化 2020-12-24 00:10:19 +08:00
0a10504461 优化章节字数算法,优化爬虫代码 2020-12-23 23:48:34 +08:00
1046a7ffc1 后台数据校验优化 2020-12-22 23:12:22 +08:00
612555dbe6 更新QQ群 2020-12-22 09:35:24 +08:00
d5768e4011 后台首页gitee仓库地址更新 2020-12-21 17:51:54 +08:00
5982eb623f 更新文档 2020-12-16 09:53:39 +08:00
85ad5fa3b2 增加官网地址 2020-12-15 10:23:12 +08:00
bdc81f7676 更新安卓客户端 2020-12-13 10:09:42 +08:00
f31c86f362 修复手机端导航栏书架的点击问题 2020-12-13 09:33:59 +08:00
45d8902429 更新接口文档示例 2020-12-12 12:16:13 +08:00
ff9696bb7e 添加接口文档示例 2020-12-12 12:03:40 +08:00
cacebcaa33 小说章节列表接口排序字段新增默认值 2020-12-12 11:16:24 +08:00
355cb80458 restful api改造 2020-12-12 10:03:15 +08:00
a8c74d061c 修改gitee仓库地址 2020-12-11 13:40:35 +08:00
a713b66c1b 爬虫优化,兼容更多源站 2020-12-10 19:04:44 +08:00
e9d915c1fe 修改版本号 2020-12-10 13:39:57 +08:00
cd3520971d 修改版本号 2020-12-10 08:40:15 +08:00
dc4c9138ee novel-admin加入父工程管理 2020-12-09 18:24:23 +08:00
f830600c3e 爬虫优化,提升兼容性 2020-12-09 16:39:15 +08:00
154210719f 简化.gitignore 2020-12-09 08:48:27 +08:00
11e744e6a8 删掉不知道是啥文件 2020-12-07 16:11:20 +08:00
944ef912e2 修复后台管理首页因为数据库大小写敏感导致的报错 2020-12-07 16:06:46 +08:00
2ce51d5fc0 图片更新 2020-12-04 17:06:53 +08:00
2f4b671d84 修改版本号 2020-12-04 16:50:44 +08:00
6ffd8d90d7 样式优化 2020-12-04 16:43:12 +08:00
1e2b6f4103 样式优化 2020-12-04 16:21:33 +08:00
24c7175872 新增微信公众号 2020-12-03 08:38:06 +08:00
a6b009cc84 v3.0.1发布 2020-12-03 03:02:44 +08:00
04afa759a7 v3.0.1发布 2020-12-03 02:56:54 +08:00
1be39a0f13 手机端UI更新 2020-12-03 02:01:48 +08:00
2fd0349a80 v2.11.0发布 2020-12-02 11:42:59 +08:00
79fd85ab9b v2.11.0发布 2020-12-02 11:41:06 +08:00
0b22bbb111 文档更新 2020-12-01 12:15:56 +08:00
7f4d315f25 后台新闻模块开发完成 2020-12-01 12:14:25 +08:00
f7375c5779 release_v2.10.0发布 2020-12-01 06:02:41 +08:00
194461f729 修改版本号 2020-12-01 06:01:24 +08:00
6bf6b44493 文档更新 2020-12-01 05:55:15 +08:00
cffa00a54a 显示优化 2020-12-01 05:48:56 +08:00
b279763383 后台首页更 新,新增会员总数/作家总数/作品总数/交易总数统计,新增7日内会员新增/作家新增/作品新增/交易新增统计报表 2020-12-01 05:42:12 +08:00
cfe19854a5 v2.9.1发布 2020-12-01 03:05:09 +08:00
28cebad48d 后台管理系统修改密码长度5位以上,修复admin账号登录后无法修改密码的bug 2020-12-01 03:02:48 +08:00
68a1ece57c update 2020-11-27 21:14:45 +08:00
77645da2bd update readme 2020-11-23 08:48:11 +08:00
36376aa623 update readme 2020-11-23 08:44:27 +08:00
9e98665cca v2.9.0发布 2020-11-23 08:29:50 +08:00
9a19a33406 章节字数计算规则优化 2020-11-23 08:21:58 +08:00
a4f7042b87 更新sql 2020-11-22 18:06:01 +08:00
31aa3192fd 小说章节定价规则自定义 2020-11-22 17:15:20 +08:00
cd11854eff v2.8.0发布 2020-11-17 10:52:44 +08:00
85f5048fd9 v2.8.0发布 2020-11-17 10:49:59 +08:00
f625ee38e1 作家后台完善 2020-11-17 10:25:31 +08:00
2c3e346ea7 修复小说阅读的时候按键盘→会报错的bug 2020-11-12 12:03:45 +08:00
66093cb065 v2.7.1发布 2020-11-10 11:56:11 +08:00
beba6e5154 作家后台小说列表新增昨日订阅量统计 2020-11-09 18:18:27 +08:00
04d3aef82b 展示图更新 2020-11-09 15:10:30 +08:00
018daf8d37 修改上传提示图片 2020-11-09 14:53:18 +08:00
8e0f1f12a4 作者后台菜单栏图标修改 2020-11-09 14:11:02 +08:00
165c96cd48 v2.7.0发布 2020-11-06 08:01:07 +08:00
e343134ce2 手机端购买页面更新&版本号更改 2020-11-05 07:47:17 +08:00
a1adb2c7df 删除垃圾文件夹 2020-11-03 15:21:19 +08:00
81a82d8e72 展示图更新 2020-11-03 15:18:50 +08:00
1d33094bd7 展示图更新 2020-11-03 15:15:46 +08:00
4cccea5d75 作家专区新增稿费收入查询(订阅明细+稿费汇总) 2020-11-03 14:58:59 +08:00
fbfb68583f update 2020-11-03 09:01:33 +08:00
655957904b update 2020-11-03 08:55:32 +08:00
99e973091d 自动更新排除掉原创小说 2020-11-03 08:41:48 +08:00
5fdf618223 自动更新排除掉原创小说 2020-11-03 08:30:45 +08:00
03c4e6c54b v2.6.5发布 2020-11-03 07:41:38 +08:00
29527301cf front模块添加message配置文件,覆盖common模块的配置,方便打包后直接修改网站信息 2020-11-03 07:36:13 +08:00
29d03a7a22 通用header.html加入script参数 2020-11-03 07:24:13 +08:00
ad4199dc4e 添加示例网站 2020-11-03 06:57:46 +08:00
4f7f9af6a9 update readme 2020-11-03 06:54:52 +08:00
ee2a0f514f 排行榜页面显示问题修复 2020-10-25 20:27:24 +08:00
70f04bd37c 小说封面图片上传 2020-08-10 07:12:14 +08:00
9d621edaec update readme 2020-07-03 09:31:57 +08:00
56c0a81c1b update readme 2020-07-03 08:57:38 +08:00
6b3b88c147 Merge branch 'release_v2.6.1' into release_v2.6.2 2020-07-02 23:17:14 +08:00
894ee67f56 优化mac端浏览器的识别问题 2020-07-02 23:15:21 +08:00
a88891b72f v2.6.2发布 2020-06-29 16:45:51 +08:00
5c7724c813 修改首页缓存时间 2020-06-29 16:43:10 +08:00
79c9f3e0f1 Merge branch 'release_v2.6.0' into release_v2.6.1 2020-06-25 10:49:15 +08:00
575142f9f3 修复部分maven版本admin模块build失败的问题 2020-06-25 10:46:27 +08:00
83c2460c83 v2.6.1发布 2020-06-22 11:06:52 +08:00
c7642ac2ef 修复搜索引擎模式下按更新时间筛选的bug 2020-06-22 11:01:23 +08:00
5af570a514 v2.6.0发布 2020-06-15 18:08:09 +08:00
0d96ff81b6 v2.6.0发布 2020-06-15 17:47:12 +08:00
7733cf1e3f 更新版本号 2020-06-15 15:13:37 +08:00
c9c714e71e 增加单本采集任务 2020-06-15 15:08:15 +08:00
3cbb6bf3fb 遇到错误章节直接中断改为遇到错误章节跳过,解决某些网站由于大量章节错误而导致的大量书籍未爬取完的情况 2020-06-15 10:06:35 +08:00
750e234f60 更新 2020-06-09 04:26:32 +08:00
c1d485c42b 更新 2020-06-09 04:19:10 +08:00
0e2e6229cd 增加新源,过滤简介中的特殊字符,提高爬虫兼容性 2020-06-08 16:54:58 +08:00
f8a669eb01 关闭分表的升级通道 2020-06-01 17:33:46 +08:00
6d56399d0f 文档更新 2020-06-01 16:12:46 +08:00
1a0c1f864b v2.5.0发布 2020-06-01 15:40:37 +08:00
b193aca288 默认开启分表功能(适用于新用户),通过添加配置spring.autoconfigure.exclude=io.shardingsphere.shardingjdbc.spring.boot.SpringBootConfiguration来关闭分表功能(适用于老用户升级) 2020-06-01 11:31:05 +08:00
7a6d7a4442 暂时关闭分表功能,有需要自己开启 2020-06-01 09:24:37 +08:00
5505840b6e 暂时关闭分表功能,有需要的自己开启 2020-06-01 09:22:00 +08:00
xxy
8eb3048b91 文档更新 2020-05-29 10:10:25 +08:00
xxy
1b138c2aad 文档更新 2020-05-29 10:06:45 +08:00
f5e2dbaa6b 更改配置文件中redis配置位置 2020-05-26 18:52:38 +08:00
xxy
b6cb9aaedc 文档更新 2020-05-26 18:17:34 +08:00
f9f1e474ec 引入shardingjdbc,将小说内容表分为10个小表 2020-05-26 18:09:19 +08:00
xxy
06bf848e99 更新文档 2020-05-26 13:17:23 +08:00
6e171d20ed 集成fastDfs 2020-05-26 13:07:53 +08:00
c62acc288e 集成OSS对象存储 2020-05-26 11:31:30 +08:00
xxy
9975faed01 点击量计算优化 2020-05-26 02:27:39 +08:00
xxy
8fde3a3725 点击量计算优化 2020-05-26 02:13:28 +08:00
xxy
430504ee28 点击量计算优化 2020-05-26 02:10:37 +08:00
xxy
16447c60ec 引入redisson 2020-05-26 00:28:12 +08:00
xxy
be7cbe2d6f 欲引入Redisson框架实现分布式锁 2020-05-26 00:04:00 +08:00
xxy
8f1ed88b07 es采集优化 2020-05-25 23:38:46 +08:00
xxy
9b9851e7ab 文档更新 2020-05-25 23:16:08 +08:00
a55edf0408 es优化 2020-05-25 21:37:00 +08:00
856c4c0667 es优化 2020-05-25 21:26:47 +08:00
e4dd5bcb71 引入rabbitmq流量削峰,累积点击量后统一更新 2020-05-25 21:06:51 +08:00
5dbddbdd96 es导入优化 2020-05-25 17:51:05 +08:00
73be43e1c5 优化es采集 2020-05-25 17:11:03 +08:00
ce2a3b4647 集成redis 2020-05-25 16:54:39 +08:00
68abdeca93 文档更新 2020-05-25 10:59:24 +08:00
0b505a3922 v2.1.2发布 2020-05-25 10:51:22 +08:00
353cb8c536 修复网路图片保存时文件损坏的情况 2020-05-25 10:40:50 +08:00
xxy
e1e1310b9e 解决book_index的主键生成冲突 2020-05-24 17:59:03 +08:00
4c42ac0d29 文档更新 2020-05-24 09:17:49 +08:00
d025d3d514 优化列表页显示 2020-05-24 02:04:02 +08:00
a0fb8e481a 1.解决爬虫线程停止失败的bug,2新增新笔趣阁源,兼容更多源站 2020-05-24 00:54:27 +08:00
80b933db8d v2.1.1发布 2020-05-22 11:58:42 +08:00
87a060280a 1.解决小说/章节发布表单重复提交问题,2.解决小说章节发布字数计算问题,3.解决个人发布小说字体更改问题 2020-05-22 11:49:18 +08:00
9c78f400dc v2.1.0发布 2020-05-21 09:15:47 +08:00
c2cdf73893 1优化网络图片转换策略 2020-05-21 08:46:46 +08:00
a13ea78c3f 1优化es导入策略,2增加默认图片,在读取网络图片失败时设置,防止一直失败重试 2020-05-21 08:16:37 +08:00
0144b77983 v2.1.0发布 2020-05-20 22:13:53 +08:00
07b9ffde96 修改版本号 2020-05-20 21:30:19 +08:00
002a0723f7 索引+搜索优化 2020-05-20 21:23:59 +08:00
8a628f081f 集成elasticsearch搜索引擎 2020-05-20 18:08:29 +08:00
4aa6b82143 更新书趣阁规则 2020-05-18 20:13:46 +08:00
c80b02caf0 v2.0.2发布 2020-05-18 17:31:00 +08:00
5e16119880 增加笔趣阁书源 2020-05-18 17:08:43 +08:00
231b94f1da v2.0.2发布 2020-05-18 14:51:02 +08:00
92ce982899 1.优化爬虫编写规则,兼容更多网站 2.新增书趣阁书源 2020-05-18 14:01:49 +08:00
8c2e43c04f Merge branch 'master' into release_v2.0.1 2020-05-17 22:21:50 +08:00
f553d23fb9 v2.0.1发布 2020-05-17 22:14:53 +08:00
xxy
9773b73475 修改版本号 2020-05-16 13:29:32 +08:00
xxy
5543b905cd 小说发布防xss攻击 2020-05-16 13:20:08 +08:00
xxy
e273906441 小说发布防xss攻击 2020-05-16 13:05:44 +08:00
xxy
83dc04c50b Merge branch 'develop' of https://gitee.com/xiongxyang/novel-plus into develop 2020-05-16 12:05:33 +08:00
xxy
b4f5b18e93 1.修复昵称修改不会显示在顶部栏的问题
2.修复底部作者专区超链接问题
2020-05-16 12:01:02 +08:00
fe80c21812 Merge branch 'develop' of https://gitee.com/xiongxyang/novel-plus into develop 2020-05-16 11:46:11 +08:00
4c2a7f12c1 gitignore add file 2020-05-16 11:44:33 +08:00
xxy
e24e87b546 修复性别修改问题 2020-05-16 03:05:49 +08:00
xxy
b8b074d40a v2.0.0版本发布 2020-05-14 07:18:17 +08:00
xxy
a662f42bcf 修改版本号 2020-05-13 22:35:25 +08:00
xxy
0fa929f9de 用户购买功能实现 2020-05-13 21:43:07 +08:00
xxy
401d23871d 作家专区开发实现 2020-05-13 19:45:57 +08:00
xxy
4878f17de8 更新版本号 2020-05-11 22:36:06 +08:00
e9ab6d8bb0 v1.1.1发布 2020-05-11 18:37:59 +08:00
c8d7a10d9f 增加充值模块,接通支付宝充值 2020-05-11 18:28:07 +08:00
xxy
d30c6bfd6e 文档更新 2020-05-10 18:18:09 +08:00
xxy
334f3e17a6 文档更新 2020-05-10 18:16:06 +08:00
xxy
a202100818 添加统计代码 2020-05-10 01:31:21 +08:00
xxy
84814e0792 添加Dockerfile文件 2020-05-09 14:18:04 +08:00
xxy
dde10c983e release-1.1.0发布 2020-05-08 08:52:30 +08:00
xxy
c9428bf0e7 增加自动更新线程的配置 2020-05-08 07:49:41 +08:00
xxy
0e2e610d18 优化更新策略,支持同时启动多个爬虫程序来加快小说更新速率 2020-05-07 23:34:13 +08:00
xxy
9df69edc2c 更新时间排序修复 2020-05-07 05:24:57 +08:00
xxy
16aa925521 自动更新优化 2020-05-07 04:57:41 +08:00
xxy
320d693238 解决XSS攻击 2020-05-07 04:21:02 +08:00
xxy
ca9fd1c2f7 上传后台管理系统代码 2020-05-06 07:40:43 +08:00
2831 changed files with 461421 additions and 1228 deletions

18
.gitignore vendored
View File

@ -1,12 +1,6 @@
/.idea
/cachedata
/logs
/novel-common/target
/novel-front/target
/novel-front/*.iml
/novel-common/*.iml
/novel-mobile/target
/novel-mobile/*.iml
/novel-front/novel-front.iml
/novel-crawl/novel-crawl.iml
/novel-crawl/target
**/logs
**/.idea
**/cachedata
**/target
**/*.iml

256
README.md
View File

@ -1,28 +1,43 @@
[![index](./assets/热门云产品1040.100.jpg)](https://cloud.tencent.com/act/cps/redirect?redirect=1052&cps_key=736e609d66e0ac4e57813316cec6fd0b&from=console)
[![index]( https://s1.ax1x.com/2020/07/03/NOSA5q.jpg )]( https://cloud.tencent.com/act/cps/redirect?redirect=1052&cps_key=736e609d66e0ac4e57813316cec6fd0b&from=console )
# 小说精品屋-plus
#### 前言
#### 官网
https://xiongxyang.gitee.io/home/
#### 新项目小说精品屋-微服务版
基于小说精品屋-plus构建的Spring Cloud 微服务小说门户平台
GitHub仓库地址 https://github.com/201206030/novel-cloud
Gitee仓库地址 https://gitee.com/novel_dev_team/novel-cloud
#### 演示地址
[点击前往](http://47.106.243.172:8888/)
小说精品屋-plus致力于打造一个完整的商用小说门户平台
#### 项目介绍
[小说精品屋](https://github.com/201206030/fiction_house)是一个多平台web、安卓app、微信小程序、功能完善的小说弹幕网站包含精品小说专区、轻小说专区和漫画专区。包括小说/漫画分类、小说/漫画搜索、小说/漫画排行、完本小说/漫画、小说/漫画评分、小说/漫画在线阅读、小说/漫画书架、小说/漫画阅读记录、小说下载、小说弹幕、小说/漫画自动爬取、小说内容自动分享到微博、邮件自动推广、链接自动推送到百度搜索引擎等功能。包含电脑端、移动端、微信小程序等多个平台现已开源web端、安卓端、小程序端源码。
小说精品屋-plus是在[小说精品屋](https://github.com/201206030/fiction_house)的基础上去除了漫画和弹幕模块专注于小说是一个多端PC、WAP阅读、功能完善的原创文学CMS系统由前台门户系统、作家后台管理系统、平台后台管理系统、爬虫管理系统等多个子系统构成支持会员充值、订阅模式、新闻发布和实时统计报表等功能。
小说精品屋-plus是在小说精品屋的基础上重新进行了数据库设计代码重构和功能增强提升了程序整体的可读性和性能增加了很多商用特性主要升级如下
小说精品屋-plus重新进行了数据库设计代码重构和功能增强提升了程序整体的可读性和性能增加了很多商用特性主要升级如下
- [x] 数据库重新设计结构调整
- [x] 服务端代码重构MyBatis3升级为MyBatis3DynamicSql
- [x] 移动站与PC站站点分离浏览器自动识别跳转
- [x] PC站UI更新
- [x] 支持前端模版自定义内置多套模版
- [x] 新闻模块
- [x] 排行榜
- [x] 小说评论模块
- [x] 阅读主题模块
- [ ] 作家专区
- [ ] 充值
- [ ] 后台管理系统
- [x] 作家专区
- [x] 充值
- [x] 订阅
- [x] 后台管理系统
- [x] 爬虫管理系统
#### 项目结构
@ -30,59 +45,165 @@
```
novel-plus -- 父工程
novel-common -- 通用模块
novel-front -- 前台门户系统
novel-crawl -- 爬虫管理系统
novel-admin -- 后台管理系统
novel-front -- 前台门户&作家后台管理子系统可拆分
novel-crawl -- 爬虫管理系统
novel-admin -- 平台后台管理系统
templates -- 前端模版
```
#### 技术选型
Springboot+Mybatis+Mysql+Ehcache+Thymeleaf+Layui
#### PC站截图
| 技术 | 说明
| -------------------- | ---------------------------
| SpringBoot | Spring应用快速开发脚手架
| MyBatis | 持久层ORM框架
| MyBatis Dynamic SQL | Mybatis动态sql
| PageHelper | MyBatis分页插件
| MyBatisGenerator | 持久层代码生成插件
| Sharding-Jdbc | 代码层分库分表中间件
| JJWT | JWT登录支持
| SpringSecurity | 安全框架
| Shiro | 安全框架
| Ehcache | Java进程内缓存框架(默认缓存)
| Redis | 分布式缓存(缓存替换方案默认关闭一行配置开启)
| ElasticSearch | 搜索引擎(搜索增强方案默认关闭一行配置开启)
| RabbitMq | 消息队列(流量削峰默认关闭一行配置开启)
| OSS | 阿里云对象存储服务(图片存储方式之一一行配置即可切换)
| FastDfs |开源轻量级分布式文件系统(图片存储方式之一一行配置即可切换)
| Redisson | 实现分布式锁
| Lombok | 简化对象封装工具
| Docker | 应用容器引擎
| Mysql | 数据库服务
| Thymeleaf | 模板引擎
| Layui | 前端UI
#### 开发工具
感谢Jetbrains公司提供的免费License
[![index]( https://s3.ax1x.com/2021/01/14/sdHsJg.png )]( https://www.jetbrains.com/?from=小说精品屋)
#### 接口文档
![index](./assets/1588548668698.gif)
[点击查看接口文档示例](doc/api/api.md)
![index](./assets/1588548784395.gif)
![index](./assets/1588548916980.gif)
#### 手机站截图
#### 橙色主题模版截图
##### PC站截图
1. 首页
![index](./assets/QQ%E5%9B%BE%E7%89%8720191018162208.jpg)
![img](https://s3.ax1x.com/2020/12/27/r5400A.png)
2. 分类索引页
2. 小说详情页
![img](https://oscimg.oschina.net/oscnet/up-d0b2e03129bfae47b8bb96a491b73d383c5.png)
![微信图片_20190904181558](./assets/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20190904181558.png)
3. 搜索页
![img](https://s3.ax1x.com/2020/12/27/r5TO8x.png)
3. 目录页
![img](https://oscimg.oschina.net/oscnet/up-ed5f689557718924acac76bc3ebca36afcb.png)
![QQ图片20191018161901](./assets/QQ%E5%9B%BE%E7%89%8720191108022250.png)
4. 排行榜
![img](https://oscimg.oschina.net/oscnet/up-78d5a68586cd92a86c669311f414508f922.png)
5. 详情页
![img](https://oscimg.oschina.net/oscnet/up-8be2495a2869f93626b0c9c1df6f329747a.png)
6. 阅读页
![img](https://oscimg.oschina.net/oscnet/up-517c84148d2db8e11717a8bbecc57fa1be7.png)
7. 用户中心
![img](https://oscimg.oschina.net/oscnet/up-805a30e7a663a3fd5cb39a7ea26bc132a01.png)
8. 充值
![img](https://oscimg.oschina.net/oscnet/up-5a601b0b3af3224d0bebcfe12fc15075d34.png)
![img](https://oscimg.oschina.net/oscnet/up-face25d02c07b05b2ce954cc4bf4ee6a0cc.png)
9. 作家专区
![img](https://oscimg.oschina.net/oscnet/up-30766372cc7f56480ff1d7d55198204f6ea.png)
![img](https://s3.ax1x.com/2020/11/17/DVFiQI.png)
![img](https://s1.ax1x.com/2020/11/09/B7X5oF.png)
![img](https://s1.ax1x.com/2020/11/09/B7XLsx.png)
10. 购买
![img](https://oscimg.oschina.net/oscnet/up-ce0f585efd82a9670335f118cf5897c85e9.png)
![img](https://oscimg.oschina.net/oscnet/up-f849960f4c1303fea77d26e64fc505a7180.png)
##### 手机站截图
1. 首页
<img src="https://s3.ax1x.com/2020/12/27/r5447n.jpg" alt="index" width="300" />
2. 小说列表页
<img src="https://s3.ax1x.com/2020/12/27/r55xKg.jpg" alt="微信图片_20190904181558" width="300" />
3. 小说详情页
<img src="https://s3.ax1x.com/2020/12/28/roZWOf.jpg" alt="QQ图片20191018161901" width="300" />
4. 小说阅读页
![QQ图片20191018161901](./assets/QQ%E5%9B%BE%E7%89%8720191018161901.png)
<img src="https://s3.ax1x.com/2020/12/27/r55Stx.jpg" alt="QQ图片20191018161901" width="300" />
##### 爬虫管理系统截图
#### 爬虫管理系统截图
![img](https://s1.ax1x.com/2020/11/03/BsOgbD.png)
![QQ图片20191018161901](./assets/crawl_index.png)
![img](https://s1.ax1x.com/2020/11/03/BsOHr8.png)
##### 后台管理系统截图
![img](https://oscimg.oschina.net/oscnet/up-0552343538674a22a64819834100558f39b.png)
![img](https://s3.ax1x.com/2020/12/01/DWgLNT.png)
![img](https://s3.ax1x.com/2020/12/01/DfmRCd.png)
![img](https://oscimg.oschina.net/oscnet/up-faf5dda7320674c29a1772bc0c81d74762e.png)
#### 深色主题模版截图
##### PC站截图
1. 首页
![index](https://static.oschina.net/uploads/img/202006/24151811_wIus.png)
##### 手机站截图
1. 首页
![index](https://static.oschina.net/uploads/img/202006/24151812_OOob.jpg)
4. 小说详情页
![微信图片_20190904181558](https://static.oschina.net/uploads/img/202006/24151812_ZosF.png)
5. 目录页
![QQ图片20191018161901](https://static.oschina.net/uploads/img/202006/24151812_Krva.png)
5. 小说阅读页
![QQ图片20191018161901](https://static.oschina.net/uploads/img/202006/24151813_fDgT.png)
#### 蓝色主题模版截图更新中
![QQ图片20191018161901](https://s3.ax1x.com/2020/12/27/r5Fe0A.png)
#### 安装步骤
@ -91,44 +212,79 @@ Springboot+Mybatis+Mysql+Ehcache+Thymeleaf+Layui
1. 安装MySQL软件
2. 修改MySQL`max_allowed_packet `配置建议100M
3. 新建数据库设置编码为utf8mb4
4. 执行sql/novel_plus.sql脚本文件
4. 执行doc/sql/novel_plus.sql脚本文件
##### 爬虫管理系统安装
1. 修改novel-common模块下application-dev.yml文件中的数据库配置
1. 修改novel-common模块下application-common-dev.yml配置文件中的数据库配置
2. 修改novel-crawl模块下application.yml文件中的管理员账号密码
3. 启动程序打开浏览器默认8081端口访问
4. 选择已有或新增爬虫源支持自定义爬虫规则点击`开启`按钮开始爬取小说数据
##### 前台小说门户安装
##### 前台小说门户安装jar包形式部署时需要复制templates文件夹到jar文件的相同目录下
1. 修改novel-common模块下application-dev.yml文件中的数据库配置
2. 启动程序打开浏览器默认8080端口访问
1. 修改novel-common模块下application-common-dev.yml配置文件中的数据库配置
2. 修改novel-front模块下application-website配置文件中的网站信息
![mini-code](https://s3.ax1x.com/2020/12/28/royaex.png)
3. 修改novel-front模块下application.yml配置文件中的模版名为你需要使用的模版名templates文件夹下的模版文件夹名内置orange和dark两套模版
![mini-code](https://s3.ax1x.com/2020/12/26/r4uGM6.png)
4. 启动程序打开浏览器默认8080端口访问
**喜欢此项目的可以给我的GitHub和Gitee加个Star支持一下 **
#### 演示地址
#### 其他安装教程
[点击前往](http://www.java2nb.com)(前台门户)
##### version<3.3.0版本
包安装教程[点击前往](https://my.oschina.net/java2nb/blog/4272630)
宝塔安装教程非官方[点击前往](https://www.daniao.org/9166.html)
docker安装教程[点击前往](https://my.oschina.net/java2nb/blog/4271989)
##### version>=3.3.0版本
包安装教程[点击前往](https://my.oschina.net/java2nb/blog/4842472)
#### 代码仓库
Gitee仓库地址 https://gitee.com/xiongxyang/novel-plus
GitHub仓库地址 https://github.com/201206030/novel-plus
Gitee仓库地址 https://gitee.com/novel_dev_team/novel-plus
#### QQ交流群
![mini-code](./assets/qq_group.png)
[点击前往官网查看](https://xiongxyang.gitee.io/home/service.htm)
#### 捐赠支持
问问题的三要素
开源项目不易若此项目能得到你的青睐可以捐赠支持作者持续开发与维护
1. 说明背景使用了哪个模块要做什么
![mini-code](./assets/jk.png)
2. 怎么输入或操作的得到了什么结果 截图日志
3. 哪里不明白或有什么疑问
#### 微信公众号发布最新更新资讯最新前端模版最新爬虫规则技术文档等
![mini-code](https://s3.ax1x.com/2020/12/03/DoImOx.png)
#### 赞赏支持
开源项目不易若此项目能得到你的青睐那么你可以赞赏支持作者持续开发与维护
- 服务器的费用也是一笔开销
- 为用户提供更好的开发环境
- 一杯咖啡
![mini-code](https://s1.ax1x.com/2020/10/31/BUQJwq.png)
#### 免责声明
本项目提供的爬虫工具仅用于采集项目初期的测试数据请勿用于商业盈利
用户使用本系统从事任何违法违规的事情一切后果由用户自行承担作者不承担任何责任
#### 备注
精品小说屋所有相关项目均已在开源中国公开感兴趣的可进入[开源中国](https://www.oschina.net/p/fiction_house)按关键字`精品小说屋`搜索。
[![index](./assets/120060.jpg)](https://www.aliyun.com/minisite/goods?userCode=uf4nasee )
[![index](https://s1.ax1x.com/2020/07/03/NOSuMF.jpg)](https://www.aliyun.com/minisite/goods?userCode=uf4nasee )

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 185 KiB

116
doc/api/api.md Normal file
View File

@ -0,0 +1,116 @@
<h1 class="curproject-name"> 小说精品屋-plus </h1>
小说精品屋-plus接口
# 作家模块
## 小说章节分页列表查询接口
<a id=小说章节分页列表查询接口> </a>
### 基本信息
**Path** /book/queryIndexList
**Method** GET
**接口描述:**
<p>作家后台章节管理页面需要请求该接口获取小说章节分页列表信息</p>
### 请求参数
**Query**
| 参数名称 | 是否必须 | 示例 | 备注 |
| ------------ | ------------ | ------------ | ------------ |
| bookId | 是 | 1334337530296893441 | 小说ID |
| curr | 否 | 1 | 查询页码默认1 |
| limit | 否 | 5 | 分页大小默认5 |
### 返回数据
<table>
<thead class="ant-table-thead">
<tr>
<th key=name>名称</th><th key=type>类型</th><th key=required>是否必须</th><th key=default>默认值</th><th key=desc>备注</th><th key=sub>其他信息</th>
</tr>
</thead><tbody className="ant-table-tbody"><tr key=0-0><td key=0><span style="padding-left: 0px"><span style="color: #8c8a8a"></span> code</span></td><td key=1><span>number</span></td><td key=2>必须</td><td key=3></td><td key=4><span style="white-space: pre-wrap">响应状态吗200表示成功</span></td><td key=5></td></tr><tr key=0-1><td key=0><span style="padding-left: 0px"><span style="color: #8c8a8a"></span> msg</span></td><td key=1><span>string</span></td><td key=2>必须</td><td key=3></td><td key=4><span style="white-space: pre-wrap">响应信息</span></td><td key=5></td></tr><tr key=0-2><td key=0><span style="padding-left: 0px"><span style="color: #8c8a8a"></span> data</span></td><td key=1><span>object</span></td><td key=2>必须</td><td key=3></td><td key=4><span style="white-space: pre-wrap">响应数据</span></td><td key=5></td></tr><tr key=0-2-0><td key=0><span style="padding-left: 20px"><span style="color: #8c8a8a">├─</span> total</span></td><td key=1><span>number</span></td><td key=2>必须</td><td key=3></td><td key=4><span style="white-space: pre-wrap">总数量</span></td><td key=5></td></tr><tr key=0-2-1><td key=0><span style="padding-left: 20px"><span style="color: #8c8a8a">├─</span> list</span></td><td key=1><span>object []</span></td><td key=2>必须</td><td key=3></td><td key=4><span style="white-space: pre-wrap">章节数据集合</span></td><td key=5><p key=3><span style="font-weight: '700'">item 类型: </span><span>object</span></p></td></tr><tr key=0-2-1-0><td key=0><span style="padding-left: 40px"><span style="color: #8c8a8a">├─</span> id</span></td><td key=1><span>string</span></td><td key=2>必须</td><td key=3></td><td key=4><span style="white-space: pre-wrap">章节ID</span></td><td key=5></td></tr><tr key=0-2-1-1><td key=0><span style="padding-left: 40px"><span style="color: #8c8a8a">├─</span> bookId</span></td><td key=1><span>string</span></td><td key=2>必须</td><td key=3></td><td key=4><span style="white-space: pre-wrap">小说ID</span></td><td key=5></td></tr><tr key=0-2-1-2><td key=0><span style="padding-left: 40px"><span style="color: #8c8a8a">├─</span> indexName</span></td><td key=1><span>string</span></td><td key=2>必须</td><td key=3></td><td key=4><span style="white-space: pre-wrap">章节名</span></td><td key=5></td></tr><tr key=0-2-1-3><td key=0><span style="padding-left: 40px"><span style="color: #8c8a8a">├─</span> isVip</span></td><td key=1><span>number</span></td><td key=2>必须</td><td key=3></td><td key=4><span style="white-space: pre-wrap">是否收费1:收费0:免费</span></td><td key=5></td></tr><tr key=0-2-1-4><td key=0><span style="padding-left: 40px"><span style="color: #8c8a8a">├─</span> updateTime</span></td><td key=1><span>string</span></td><td key=2>必须</td><td key=3></td><td key=4><span style="white-space: pre-wrap">更新时间</span></td><td key=5></td></tr><tr key=0-2-2><td key=0><span style="padding-left: 20px"><span style="color: #8c8a8a">├─</span> pageNum</span></td><td key=1><span>number</span></td><td key=2>必须</td><td key=3></td><td key=4><span style="white-space: pre-wrap">页码</span></td><td key=5></td></tr><tr key=0-2-3><td key=0><span style="padding-left: 20px"><span style="color: #8c8a8a">├─</span> pageSize</span></td><td key=1><span>number</span></td><td key=2>必须</td><td key=3></td><td key=4><span style="white-space: pre-wrap">分页大小</span></td><td key=5></td></tr><tr key=0-2-4><td key=0><span style="padding-left: 20px"><span style="color: #8c8a8a">├─</span> size</span></td><td key=1><span>number</span></td><td key=2>必须</td><td key=3></td><td key=4><span style="white-space: pre-wrap">当前页数量</span></td><td key=5></td></tr>
</tbody>
</table>
## 小说章节删除接口
<a id=小说章节删除接口> </a>
### 基本信息
**Path** /author/deleteIndex/{indexId}
**Method** DELETE
**接口描述:**
<p>作家后台章节管理页面点击删除按钮请求该接口删除小说章节内容</p>
### 请求参数
**Headers**
| 参数名称 | 参数值 | 是否必须 | 示例 | 备注 |
| ------------ | ------------ | ------------ | ------------ | ------------ |
| Content-Type | application/x-www-form-urlencoded | 是 | | |
| Authorization | | 是 | eyJhbGciOiJIUzUxMiJ9.eyJleHAiOjE2MDgzNDg0NzksInN1YiI6IntcImlkXCI6MTI1NTA2MDMyODMyMjAyNzUyMCxcInVzZXJuYW1lXCI6XCIxMzU2MDQyMTMyNFwiLFwibmlja05hbWVcIjpcIjEzNTYwNDIxMzI0XCJ9IiwiY3JlYXRlZCI6MTYwNzc0MzY3OTkxM30.0qhwis_zPb6t8wGNejMhDZ2iHCL9Tgh2UHd1gcQBCp8t6RW3ggSwtfo4l_RgMT_v8jOkLW91GzTVWlNnTE6LCA | 认证JWT请求登录接口成功后返回 |
**路径参数**
| 参数名称 | 示例 | 备注 |
| ------------ | ------------ | ------------ |
| indexId | 1337603246936645632 | 章节ID |
### 返回数据
<table>
<thead class="ant-table-thead">
<tr>
<th key=name>名称</th><th key=type>类型</th><th key=required>是否必须</th><th key=default>默认值</th><th key=desc>备注</th><th key=sub>其他信息</th>
</tr>
</thead><tbody className="ant-table-tbody"><tr key=0-0><td key=0><span style="padding-left: 0px"><span style="color: #8c8a8a"></span> code</span></td><td key=1><span>number</span></td><td key=2>必须</td><td key=3></td><td key=4><span style="white-space: pre-wrap">响应状态吗200表示成功</span></td><td key=5></td></tr><tr key=0-1><td key=0><span style="padding-left: 0px"><span style="color: #8c8a8a"></span> msg</span></td><td key=1><span>string</span></td><td key=2>必须</td><td key=3></td><td key=4><span style="white-space: pre-wrap">响应信息</span></td><td key=5></td></tr>
</tbody>
</table>
## 小说章节发布接口
<a id=小说章节发布接口> </a>
### 基本信息
**Path** /author/addBookContent
**Method** POST
**接口描述:**
<p>作家后台章节发布页面点击提交按钮请求该接口新增小说章节内容</p>
### 请求参数
**Headers**
| 参数名称 | 参数值 | 是否必须 | 示例 | 备注 |
| ------------ | ------------ | ------------ | ------------ | ------------ |
| Content-Type | application/x-www-form-urlencoded | 是 | | |
| Authorization | | 是 | eyJhbGciOiJIUzUxMiJ9.eyJleHAiOjE2MDgzNDg0NzksInN1YiI6IntcImlkXCI6MTI1NTA2MDMyODMyMjAyNzUyMCxcInVzZXJuYW1lXCI6XCIxMzU2MDQyMTMyNFwiLFwibmlja05hbWVcIjpcIjEzNTYwNDIxMzI0XCJ9IiwiY3JlYXRlZCI6MTYwNzc0MzY3OTkxM30.0qhwis_zPb6t8wGNejMhDZ2iHCL9Tgh2UHd1gcQBCp8t6RW3ggSwtfo4l_RgMT_v8jOkLW91GzTVWlNnTE6LCA | 认证JWT请求登录接口成功后返回 |
**Body**
| 参数名称 | 参数类型 | 是否必须 | 示例 | 备注 |
| ------------ | ------------ | ------------ | ------------ | ------------ |
| bookId | text | 是 | 1334337530296893441 | 小说ID |
| indexName | text | 是 | 第六章未婚妻(下) | 章节名 |
| content | text | 是 | 开始之时,李七夜还是生疏无比,那怕他对于刀术的所有奥义了然于胸,但是,他出刀之时依然会颤抖,无法达到妙及巅毫的要求。 | 章节内容 |
| isVip | text | 是 | 1 | 是否收费1:收费0:免费 |
### 返回数据
<table>
<thead class="ant-table-thead">
<tr>
<th key=name>名称</th><th key=type>类型</th><th key=required>是否必须</th><th key=default>默认值</th><th key=desc>备注</th><th key=sub>其他信息</th>
</tr>
</thead><tbody className="ant-table-tbody"><tr key=0-0><td key=0><span style="padding-left: 0px"><span style="color: #8c8a8a"></span> code</span></td><td key=1><span>number</span></td><td key=2>必须</td><td key=3></td><td key=4><span style="white-space: pre-wrap">响应状态吗200表示成功</span></td><td key=5></td></tr><tr key=0-1><td key=0><span style="padding-left: 0px"><span style="color: #8c8a8a"></span> msg</span></td><td key=1><span>string</span></td><td key=2>必须</td><td key=3></td><td key=4><span style="white-space: pre-wrap">响应信息</span></td><td key=5></td></tr>
</tbody>
</table>

82
doc/es/index_create.txt Normal file
View File

@ -0,0 +1,82 @@
PUT /novel
{
"mappings" : {
"book" : {
"properties" : {
"id" : {
"type" : "long"
},
"authorId" : {
"type" : "long"
},
"authorName" : {
"type" : "text",
"analyzer": "ik_smart",
"boost": 1.9
},
"bookName" : {
"type" : "text",
"analyzer": "ik_smart",
"boost": 2
},
"bookDesc" : {
"type" : "text",
"analyzer": "ik_smart",
"boost": 0.1
},
"bookStatus" : {
"type" : "short"
},
"catId" : {
"type" : "integer"
},
"catName" : {
"type" : "text",
"analyzer": "ik_smart",
"boost": 1.0
},
"lastIndexId" : {
"type" : "long"
},
"lastIndexName" : {
"type" : "text",
"analyzer": "ik_smart",
"boost": 0.1
},
"lastIndexUpdateTime" : {
"type": "keyword"
},
"picUrl" : {
"type" : "keyword"
},
"score" : {
"type" : "float"
},
"wordCount" : {
"type" : "integer"
},
"workDirection" : {
"type" : "short"
},
"visitCount" : {
"type": "long"
}
}
}
}
}

33
doc/sql/20200511.sql Normal file
View File

@ -0,0 +1,33 @@
/*
Navicat MySQL Data Transfer
Source Server : localhost
Source Server Version : 50725
Source Host : localhost:3306
Source Database : novel_plus
Target Server Type : MYSQL
Target Server Version : 50725
File Encoding : 65001
Date: 2020-05-11 17:56:23
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for order_pay
-- ----------------------------
DROP TABLE IF EXISTS `order_pay`;
CREATE TABLE `order_pay` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`out_trade_no` bigint(20) NOT NULL COMMENT '商户订单号',
`trade_no` varchar(64) DEFAULT NULL COMMENT '支付宝/微信交易号',
`pay_channel` tinyint(1) NOT NULL DEFAULT '1' COMMENT '支付渠道1支付宝2微信',
`total_amount` int(11) NOT NULL COMMENT '交易金额(单位元)',
`user_id` bigint(20) NOT NULL COMMENT '支付用户ID',
`pay_status` tinyint(1) DEFAULT '2' COMMENT '支付状态0支付失败1支付成功2待支付',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4 COMMENT='充值订单';

87
doc/sql/20200513.sql Normal file
View File

@ -0,0 +1,87 @@
/*
Navicat MySQL Data Transfer
Source Server : localhost
Source Server Version : 50624
Source Host : localhost:3306
Source Database : novel_plus
Target Server Type : MYSQL
Target Server Version : 50624
File Encoding : 65001
Date: 2020-05-13 21:42:20
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for author
-- ----------------------------
DROP TABLE IF EXISTS `author`;
CREATE TABLE `author` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` bigint(20) DEFAULT NULL COMMENT '用户ID',
`invite_code` varchar(20) DEFAULT NULL COMMENT '邀请码',
`pen_name` varchar(20) DEFAULT NULL COMMENT '笔名',
`tel_phone` varchar(20) DEFAULT NULL COMMENT '手机号码',
`chat_account` varchar(50) DEFAULT NULL COMMENT 'QQ或微信账号',
`email` varchar(50) DEFAULT NULL COMMENT '电子邮箱',
`work_direction` tinyint(4) DEFAULT NULL COMMENT '作品方向0男频1女频',
`status` tinyint(4) DEFAULT '0' COMMENT '0正常1封禁',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COMMENT='作者表';
-- ----------------------------
-- Records of author
-- ----------------------------
INSERT INTO `author` VALUES ('1', null, 'reerer', 'abc', '13560487656', '23484388', '23484388@qq.com', '0', '0', null);
INSERT INTO `author` VALUES ('2', '1255060328322027520', 'rwrr445554', '梦入神机', '13560421324', '1179705413', 'reerer@qq.com', '0', '0', '2020-05-13 14:01:31');
-- ----------------------------
-- Table structure for author_code
-- ----------------------------
DROP TABLE IF EXISTS `author_code`;
CREATE TABLE `author_code` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`invite_code` varchar(100) DEFAULT NULL COMMENT '邀请码',
`validity_time` datetime DEFAULT NULL COMMENT '有效时间',
`is_use` tinyint(1) DEFAULT '0' COMMENT '是否使用过0未使用1:使用过',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`create_user_id` bigint(20) DEFAULT NULL COMMENT '创建人ID',
PRIMARY KEY (`id`),
UNIQUE KEY `key_code` (`invite_code`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COMMENT='作家邀请码表';
-- ----------------------------
-- Records of author_code
-- ----------------------------
INSERT INTO `author_code` VALUES ('3', 'reerer', '2020-05-27 22:43:45', '1', '2020-05-13 11:40:56', '1');
INSERT INTO `author_code` VALUES ('4', '123456', '2020-05-28 00:00:00', '0', '2020-05-13 14:09:55', '1');
INSERT INTO `author_code` VALUES ('5', 'ww34343', '2020-05-21 00:00:00', '0', '2020-05-13 14:18:58', '1');
-- ----------------------------
-- Table structure for user_buy_record
-- ----------------------------
DROP TABLE IF EXISTS `user_buy_record`;
CREATE TABLE `user_buy_record` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`book_id` bigint(20) DEFAULT NULL COMMENT '购买的小说ID',
`book_name` varchar(50) DEFAULT NULL COMMENT '购买的小说名',
`book_index_id` bigint(20) DEFAULT NULL COMMENT '购买的章节ID',
`book_index_name` varchar(100) DEFAULT NULL COMMENT '购买的章节名',
`buy_amount` int(11) DEFAULT NULL COMMENT '购买使用的屋币数量',
`create_time` datetime DEFAULT NULL COMMENT '购买时间',
PRIMARY KEY (`id`),
UNIQUE KEY `key_userId_indexId` (`user_id`,`book_index_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COMMENT='用户消费记录表';
-- ----------------------------
-- Records of user_buy_record
-- ----------------------------
INSERT INTO `user_buy_record` VALUES ('1', '1255060328322027520', '1260400284744613890', '我是一只消消乐2', '1260522024606953472', '第三章', '10', '2020-05-13 21:29:09');
INSERT INTO `user_buy_record` VALUES ('2', '1255060328322027520', '1260400284744613890', '我是一只消消乐2', '1260564410687107072', '第四章', '10', '2020-05-13 21:40:38');

3
doc/sql/20200518.sql Normal file
View File

@ -0,0 +1,3 @@
INSERT INTO `crawl_source` (`id`, `source_name`, `crawl_rule`, `source_status`, `create_time`, `update_time`) VALUES ('4', '书趣阁', '{\r\n \"bookListUrl\": \"http://m.shuquge.com/sort/{catId}/0_{page}.html\",\r\n \"catIdRule\": {\r\n \"catId1\": \"1\",\r\n \"catId2\": \"2\",\r\n \"catId3\": \"3\",\r\n \"catId4\": \"4\",\r\n \"catId5\": \"7\",\r\n \"catId6\": \"6\",\r\n \"catId7\": \"8\"\r\n },\r\n \"bookIdPatten\": \"href=\\\"/s/(\\\\d+)\\\\.html\\\"\",\r\n \"pagePatten\": \"第(\\\\d+)/\\\\d+页\",\r\n \"totalPagePatten\": \"\\\\d+/(\\\\d+)页\",\r\n \"bookDetailUrl\": \"http://m.shuquge.com/s/{bookId}.html\",\r\n \"bookNamePatten\": \"<a\\\\s+href=\\\"/s/\\\\d+\\\\.html\\\"><h2>([^/]+)</h2></a>\",\r\n \"authorNamePatten\": \"<p>作者:([^/]+)</p>\",\r\n \"picUrlPatten\": \"src=\\\"(http://www.shuquge.com/files/article/image/\\\\d+/\\\\d+/\\\\d+s\\\\.jpg)\\\"\",\r\n \"statusPatten\": \"<p>状态:([^/]+)</p>\",\r\n \"bookStatusRule\": {\r\n \"连载中\": 0,\r\n \"完本\": 1\r\n },\r\n \"descStart\": \"<div class=\\\"intro_info\\\">\",\r\n \"descEnd\": \"最新章节推荐地址\",\r\n \"bookIndexUrl\": \"http://www.shuquge.com/txt/{bookId}/index.html\",\r\n \"bookIndexStart\": \"》正文\",\r\n \"indexIdPatten\": \"<dd><a\\\\s+href=\\\"(\\\\d+)\\\\.html\\\">[^/]+</a></dd>\",\r\n \"indexNamePatten\": \"<dd><a\\\\s+href=\\\"\\\\d+\\\\.html\\\">([^/]+)</a></dd>\",\r\n \"bookContentUrl\": \"http://www.shuquge.com/txt/{bookId}/{indexId}.html\",\r\n \"contentStart\": \"<div id=\\\"content\\\" class=\\\"showtxt\\\">\",\r\n \"contentEnd\": \"http://www.shuquge.com\"\r\n}', '1', '2020-05-18 12:02:34', '2020-05-18 12:02:34');
INSERT INTO `crawl_source` (`id`, `source_name`, `crawl_rule`, `source_status`, `create_time`, `update_time`) VALUES ('5', '笔趣阁', '{\"bookListUrl\":\"http://m.mcmssc.com/xclass/{catId}/{page}.html\",\"catIdRule\":{\"catId1\":\"1\",\"catId2\":\"2\",\"catId3\":\"3\",\"catId4\":\"4\",\"catId5\":\"5\",\"catId6\":\"6\",\"catId7\":\"7\"},\"bookIdPatten\":\"href=\\\"/(\\\\d+_\\\\d+)/\\\"\",\"pagePatten\":\"class=\\\"page_txt\\\"\\\\s+value=\\\"(\\\\d+)/\\\\d+\\\"\\\\s+size=\",\"totalPagePatten\":\"class=\\\"page_txt\\\"\\\\s+value=\\\"\\\\d+/(\\\\d+)\\\"\\\\s+size=\",\"bookDetailUrl\":\"http://m.mcmssc.com/{bookId}/\",\"bookNamePatten\":\"<span\\\\s+class=\\\"title\\\">([^/]+)</span>\",\"authorNamePatten\":\"<a\\\\s+href=\\\"/author/\\\\d+/\\\">([^/]+)</a>\",\"picUrlPatten\":\"<img\\\\s+src=\\\"([^>]+)\\\"\\\\s+onerror=\",\"picUrlPrefix\":\"http://m.mcmssc.com/\",\"statusPatten\":\">状态:([^/]+)<\",\"bookStatusRule\":{\"连载\":0,\"全本\":1},\"visitCountPatten\":\">点击:(\\\\d+)<\",\"descStart\":\"<p class=\\\"review\\\">\",\"descEnd\":\"</p>\",\"bookIndexUrl\":\"http://m.mcmssc.com/{bookId}/all.html\",\"indexIdPatten\":\"<a\\\\s+href=\\\"/\\\\d+_\\\\d+/(\\\\d+)\\\\.html\\\">[^/]+</a>\",\"indexNamePatten\":\"<a\\\\s+href=\\\"/\\\\d+_\\\\d+/\\\\d+\\\\.html\\\">([^/]+)</a>\",\"bookContentUrl\":\"http://www.mcmssc.com/{bookId}/{indexId}.html\",\"contentStart\":\"</p>\",\"contentEnd\":\"<div align=\\\"center\\\">\"}', '1', '2020-05-18 15:57:41', '2020-05-18 15:57:41');
UPDATE `crawl_source` SET `source_name` = '书趣阁', `crawl_rule` = '{\n \"bookListUrl\": \"http://m.shuquge.com/sort/{catId}/0_{page}.html\",\n \"catIdRule\": {\n \"catId1\": \"1\",\n \"catId2\": \"2\",\n \"catId3\": \"3\",\n \"catId4\": \"4\",\n \"catId5\": \"7\",\n \"catId6\": \"6\",\n \"catId7\": \"8\"\n },\n \"bookIdPatten\": \"href=\\\"/s/(\\\\d+)\\\\.html\\\"\",\n \"pagePatten\": \"第(\\\\d+)/\\\\d+页\",\n \"totalPagePatten\": \"\\\\d+/(\\\\d+)页\",\n \"bookDetailUrl\": \"http://m.shuquge.com/s/{bookId}.html\",\n \"bookNamePatten\": \"<a\\\\s+href=\\\"/s/\\\\d+\\\\.html\\\"><h2>([^/]+)</h2></a>\",\n \"authorNamePatten\": \"<p>作者:([^/]+)</p>\",\n \"picUrlPatten\": \"src=\\\"(http://www.shuquge.com/files/article/image/\\\\d+/\\\\d+/\\\\d+s\\\\.jpg)\\\"\",\n \"statusPatten\": \"<p>状态:([^/]+)</p>\",\n \"bookStatusRule\": {\n \"连载中\": 0,\n \"完本\": 1\n },\n \"descStart\": \"<div class=\\\"intro_info\\\">\",\n \"descEnd\": \"最新章节推荐地址\",\n \"bookIndexUrl\": \"http://www.shuquge.com/txt/{bookId}/index.html\",\n \"bookIndexStart\": \"<dt>《\",\n \"indexIdPatten\": \"<dd><a\\\\s+href=\\\"(\\\\d+)\\\\.html\\\">[^/]+</a></dd>\",\n \"indexNamePatten\": \"<dd><a\\\\s+href=\\\"\\\\d+\\\\.html\\\">([^/]+)</a></dd>\",\n \"bookContentUrl\": \"http://www.shuquge.com/txt/{bookId}/{indexId}.html\",\n \"contentStart\": \"<div id=\\\"content\\\" class=\\\"showtxt\\\">\",\n \"contentEnd\": \"http://www.shuquge.com\"\n}', `source_status` = 1, `create_time` = '2020-05-18 12:02:34', `update_time` = '2020-05-18 12:02:34' WHERE `id` = 4;

2
doc/sql/20200608.sql Normal file
View File

@ -0,0 +1,2 @@
INSERT INTO `crawl_source` (`id`, `source_name`, `crawl_rule`, `source_status`, `create_time`, `update_time`) VALUES
(6, '新笔趣阁', '{\n \"bookListUrl\": \"http://www.xbiquge.la/fenlei/{catId}_{page}.html\",\n \"catIdRule\": {\n \"catId1\": \"1\",\n \"catId2\": \"2\",\n \"catId3\": \"3\",\n \"catId4\": \"4\",\n \"catId5\": \"6\",\n \"catId6\": \"5\"\n },\n \"bookIdPatten\": \"<a\\\\s+href=\\\"http://www.xbiquge.la/(\\\\d+/\\\\d+)/\\\"\\\\s+target=\\\"_blank\\\">\",\n \"pagePatten\": \"<em\\\\s+id=\\\"pagestats\\\">(\\\\d+)/\\\\d+</em>\",\n \"totalPagePatten\": \"<em\\\\s+id=\\\"pagestats\\\">\\\\d+/(\\\\d+)</em>\",\n \"bookDetailUrl\": \"http://www.xbiquge.la/{bookId}/\",\n \"bookNamePatten\": \"<h1>([^/]+)</h1>\",\n \"authorNamePatten\": \"者:([^/]+)</p>\",\n \"picUrlPatten\": \"src=\\\"(http://www.xbiquge.la/files/article/image/\\\\d+/\\\\d+/\\\\d+s\\\\.jpg)\\\"\",\n \"bookStatusRule\": {},\n \"descStart\": \"<div id=\\\"intro\\\">\",\n \"descEnd\": \"</div>\",\n \"upadateTimePatten\": \"<p>最后更新:(\\\\d+-\\\\d+-\\\\d+\\\\s\\\\d+:\\\\d+:\\\\d+)</p>\",\n \"upadateTimeFormatPatten\": \"yyyy-MM-dd HH:mm:ss\",\n \"bookIndexUrl\": \"http://www.xbiquge.la/{bookId}/\",\n \"indexIdPatten\": \"<a\\\\s+href=\'/\\\\d+/\\\\d+/(\\\\d+)\\\\.html\'\\\\s+>[^/]+</a>\",\n \"indexNamePatten\": \"<a\\\\s+href=\'/\\\\d+/\\\\d+/\\\\d+\\\\.html\'\\\\s+>([^/]+)</a>\",\n \"bookContentUrl\": \"http://www.xbiquge.la/{bookId}/{indexId}.html\",\n \"contentStart\": \"<div id=\\\"content\\\">\",\n \"contentEnd\": \"<p>\"\n}', 0, '2020-05-23 22:46:58', '2020-05-23 22:46:58');

40
doc/sql/20200615.sql Normal file
View File

@ -0,0 +1,40 @@
/*
Navicat MySQL Data Transfer
Source Server : localhost
Source Server Version : 50725
Source Host : localhost:3306
Source Database : novel_plus
Target Server Type : MYSQL
Target Server Version : 50725
File Encoding : 65001
Date: 2020-06-15 15:06:55
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for crawl_single_task
-- ----------------------------
DROP TABLE IF EXISTS `crawl_single_task`;
CREATE TABLE `crawl_single_task` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`source_id` int(11) DEFAULT NULL COMMENT '爬虫源ID',
`source_name` varchar(50) DEFAULT NULL COMMENT '爬虫源名',
`source_book_id` varchar(255) DEFAULT NULL COMMENT '源站小说ID',
`cat_id` int(11) DEFAULT NULL COMMENT '分类ID',
`book_name` varchar(50) DEFAULT NULL COMMENT '爬取的小说名',
`author_name` varchar(50) DEFAULT NULL COMMENT '爬取的小说作者名',
`task_status` tinyint(1) DEFAULT '2' COMMENT '任务状态0失败1成功2未执行',
`exc_count` tinyint(2) DEFAULT '0' COMMENT '已经执行次数最多执行5次',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COMMENT='抓取单本小说任务表';
-- ----------------------------
-- Records of crawl_single_task
-- ----------------------------
INSERT INTO `crawl_single_task` VALUES ('6', '2', '百书斋', '1', '1', '1', '1', '0', '5', '2020-06-15 14:36:07');
INSERT INTO `crawl_single_task` VALUES ('7', '5', '笔趣阁', '108_108291', '1', '衍天志之不朽仙', '白衣少年丶', '1', '1', '2020-06-15 14:46:08');

27
doc/sql/20201103.sql Normal file
View File

@ -0,0 +1,27 @@
CREATE TABLE `author_income_detail` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`author_id` bigint(20) NOT NULL COMMENT '作家ID',
`book_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '作品ID,0表示全部作品',
`income_date` date NOT NULL COMMENT '收入日期',
`income_account` int(11) NOT NULL DEFAULT '0' COMMENT '订阅总额',
`income_count` int(11) NOT NULL DEFAULT '0' COMMENT '订阅次数',
`income_number` int(11) NOT NULL DEFAULT '0' COMMENT '订阅人数',
`create_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='稿费收入明细统计表';
CREATE TABLE `author_income` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`author_id` bigint(20) NOT NULL COMMENT '作家ID',
`book_id` bigint(20) NOT NULL COMMENT '作品ID',
`income_month` date NOT NULL COMMENT '收入月份',
`pre_tax_income` bigint(20) NOT NULL DEFAULT '0' COMMENT '税前收入',
`after_tax_income` bigint(20) NOT NULL DEFAULT '0' COMMENT '税后收入',
`pay_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '支付状态0待支付1已支付',
`confirm_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '稿费确认状态0待确认1已确认',
`detail` varchar(255) DEFAULT NULL COMMENT '详情',
`create_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='稿费收入统计表';

1
doc/sql/20201109.sql Normal file
View File

@ -0,0 +1 @@
alter table book add column `yesterday_buy` int(11) DEFAULT '0' COMMENT '昨日订阅数' after comment_count;

1
doc/sql/20201122.sql Normal file
View File

@ -0,0 +1 @@
alter table book_index add column `book_price` int(3) DEFAULT 0 COMMENT '章节费用屋币' after `is_vip`;

32
doc/sql/20201201.sql Normal file
View File

@ -0,0 +1,32 @@
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (246, 241, '批量删除', NULL, 'novel:news:batchRemove', 2, NULL, 6, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (245, 241, '删除', NULL, 'novel:news:remove', 2, NULL, 6, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (244, 241, '修改', NULL, 'novel:news:edit', 2, NULL, 6, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (243, 241, '新增', NULL, 'novel:news:add', 2, NULL, 6, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (242, 241, '查看', NULL, 'novel:news:detail', 2, NULL, 6, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (241, 234, '新闻列表', 'novel/news', 'novel:news:news', 1, 'fa', 8, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (240, 235, '批量删除', NULL, 'novel:category:batchRemove', 2, NULL, 6, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (239, 235, '删除', NULL, 'novel:category:remove', 2, NULL, 6, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (238, 235, '修改', NULL, 'novel:category:edit', 2, NULL, 6, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (237, 235, '新增', NULL, 'novel:category:add', 2, NULL, 6, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (236, 235, '查看', NULL, 'novel:category:detail', 2, NULL, 6, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (235, 234, '类别管理', 'novel/category', 'novel:category:category', 1, 'fa', 6, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (234, 0, '新闻管理', '', '', 0, 'fa fa-newspaper-o', 8, NULL, NULL);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4889, 1, 246);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4890, 1, 245);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4891, 1, 244);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4892, 1, 243);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4893, 1, 242);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4899, 1, 241);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4894, 1, 240);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4895, 1, 239);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4896, 1, 238);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4897, 1, 237);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4898, 1, 236);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4900, 1, 235);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4888, 1, 234);
delete from sys_menu where menu_id = 202;

View File

@ -2,19 +2,65 @@
Navicat MySQL Data Transfer
Source Server : localhost
Source Server Version : 50624
Source Server Version : 50725
Source Host : localhost:3306
Source Database : novel_biz
Source Database : novel_plus
Target Server Type : MYSQL
Target Server Version : 50624
Target Server Version : 50725
File Encoding : 65001
Date: 2020-05-02 10:53:04
Date: 2020-05-18 13:59:04
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for author
-- ----------------------------
DROP TABLE IF EXISTS `author`;
CREATE TABLE `author` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` bigint(20) DEFAULT NULL COMMENT '用户ID',
`invite_code` varchar(20) DEFAULT NULL COMMENT '邀请码',
`pen_name` varchar(20) DEFAULT NULL COMMENT '笔名',
`tel_phone` varchar(20) DEFAULT NULL COMMENT '手机号码',
`chat_account` varchar(50) DEFAULT NULL COMMENT 'QQ或微信账号',
`email` varchar(50) DEFAULT NULL COMMENT '电子邮箱',
`work_direction` tinyint(4) DEFAULT NULL COMMENT '作品方向0男频1女频',
`status` tinyint(4) DEFAULT '0' COMMENT '0正常1封禁',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COMMENT='作者表';
-- ----------------------------
-- Records of author
-- ----------------------------
INSERT INTO `author` VALUES ('1', null, 'reerer', 'abc', '13560487656', '23484388', '23484388@qq.com', '0', '0', null);
INSERT INTO `author` VALUES ('2', '1255060328322027520', 'rwrr445554', '梦入神机', '13560421324', '1179705413', 'reerer@qq.com', '0', '0', '2020-05-13 14:01:31');
-- ----------------------------
-- Table structure for author_code
-- ----------------------------
DROP TABLE IF EXISTS `author_code`;
CREATE TABLE `author_code` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`invite_code` varchar(100) DEFAULT NULL COMMENT '邀请码',
`validity_time` datetime DEFAULT NULL COMMENT '有效时间',
`is_use` tinyint(1) DEFAULT '0' COMMENT '是否使用过0未使用1:使用过',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`create_user_id` bigint(20) DEFAULT NULL COMMENT '创建人ID',
PRIMARY KEY (`id`),
UNIQUE KEY `key_code` (`invite_code`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COMMENT='作家邀请码表';
-- ----------------------------
-- Records of author_code
-- ----------------------------
INSERT INTO `author_code` VALUES ('3', 'reerer', '2020-05-27 22:43:45', '1', '2020-05-13 11:40:56', '1');
INSERT INTO `author_code` VALUES ('4', '123456', '2020-05-28 00:00:00', '0', '2020-05-13 14:09:55', '1');
INSERT INTO `author_code` VALUES ('5', 'ww34343', '2020-05-21 00:00:00', '0', '2020-05-13 14:18:58', '1');
-- ----------------------------
-- Table structure for book
-- ----------------------------
@ -49,7 +95,7 @@ CREATE TABLE `book` (
UNIQUE KEY `key_uq_bookName_authorName` (`book_name`,`author_name`) USING BTREE,
KEY `key_lastIndexUpdateTime` (`last_index_update_time`) USING BTREE,
KEY `key_createTime` (`create_time`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1256127379949019137 DEFAULT CHARSET=utf8mb4 COMMENT='小说表';
) ENGINE=InnoDB AUTO_INCREMENT=1262260513468559361 DEFAULT CHARSET=utf8mb4 COMMENT='小说表';
-- ----------------------------
-- Records of book
@ -156,7 +202,7 @@ CREATE TABLE `book_content` (
`content` mediumtext COMMENT '小说章节内容',
PRIMARY KEY (`id`),
UNIQUE KEY `key_uq_indexId` (`index_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3342428 DEFAULT CHARSET=utf8mb4 COMMENT='小说内容表';
) ENGINE=InnoDB AUTO_INCREMENT=3347665 DEFAULT CHARSET=utf8mb4 COMMENT='小说内容表';
-- ----------------------------
-- Records of book_content
@ -179,7 +225,7 @@ CREATE TABLE `book_index` (
UNIQUE KEY `key_uq_bookId_indexNum` (`book_id`,`index_num`) USING BTREE,
KEY `key_bookId` (`book_id`) USING BTREE,
KEY `key_indexNum` (`index_num`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1256373101432717313 DEFAULT CHARSET=utf8mb4 COMMENT='小说目录表';
) ENGINE=InnoDB AUTO_INCREMENT=1262260612777095169 DEFAULT CHARSET=utf8mb4 COMMENT='小说目录表';
-- ----------------------------
-- Records of book_index
@ -303,13 +349,15 @@ CREATE TABLE `crawl_source` (
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT='爬虫源表';
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COMMENT='爬虫源表';
-- ----------------------------
-- Records of crawl_source
-- ----------------------------
INSERT INTO `crawl_source` VALUES ('2', '百书斋', '{\r\n \"bookListUrl\": \"https://m.baishuzhai.com/blhb/{catId}/{page}.html\",\r\n \"catIdRule\": {\r\n \"catId1\": \"1\",\r\n \"catId2\": \"2\",\r\n \"catId3\": \"3\",\r\n \"catId4\": \"4\",\r\n \"catId5\": \"5\",\r\n \"catId6\": \"6\",\r\n \"catId7\": \"7\"\r\n },\r\n \"bookIdPatten\": \"href=\\\"/ibook/(\\\\d+/\\\\d+)/\\\"\",\r\n \"pagePatten\": \"value=\\\"(\\\\d+)/\\\\d+\\\"\",\r\n \"totalPagePatten\": \"value=\\\"\\\\d+/(\\\\d+)\\\"\",\r\n \"bookDetailUrl\": \"https://m.baishuzhai.com/ibook/{bookId}/\",\r\n \"bookNamePatten\": \"<span class=\\\"title\\\">([^/]+)</span>\",\r\n \"authorNamePatten\": \">作者:([^/]+)<\",\r\n \"picUrlPatten\": \"<img src=\\\"([^>]+)\\\"\\\\s+onerror=\\\"this.src=\",\r\n \"statusPatten\": \"状态:([^/]+)</li>\",\r\n \"bookStatusRule\": {\r\n \"连载\": 0,\r\n \"完成\": 1\r\n },\r\n \"scorePatten\": \"<em>([^<]+)</em>\",\r\n \"descStart\": \"<p class=\\\"review\\\">\",\r\n \"descEnd\": \"</p>\",\r\n \"upadateTimePatten\": \"更新:(\\\\d+-\\\\d+-\\\\d+)</li>\",\r\n \"upadateTimeFormatPatten\": \"yy-MM-dd\",\r\n \"bookIndexUrl\": \"https://m.baishuzhai.com/ibook/{bookId}/all.html\",\r\n \"indexIdPatten\": \"<a\\\\s+style=\\\"\\\"\\\\s+href=\\\"/ibook/\\\\d+/\\\\d+/(\\\\d+)\\\\.html\\\">[^/]+</a>\",\r\n \"indexNamePatten\": \"<a\\\\s+style=\\\"\\\"\\\\s+href=\\\"/ibook/\\\\d+/\\\\d+/\\\\d+\\\\.html\\\">([^/]+)</a>\",\r\n \"bookContentUrl\": \"https://baishuzhai.com/ibook/{bookId}/{indexId}.html\",\r\n \"contentStart\": \"id=\\\"content\\\">\",\r\n \"contentEnd\": \"<script>\"\r\n}', '0', '2020-05-01 14:22:50', '2020-05-01 14:22:50');
INSERT INTO `crawl_source` VALUES ('3', '书包网', '{\r\n \"bookListUrl\": \"https://www.bookbao8.com/booklist-p_{page}-c_{catId}-t_0-o_0.html\",\r\n \"catIdRule\": {\r\n \"catId1\": \"5\",\r\n \"catId2\": \"4\",\r\n \"catId3\": \"8\",\r\n \"catId4\": \"9\",\r\n \"catId5\": \"3\",\r\n \"catId6\": \"7\"\r\n },\r\n \"bookIdPatten\": \"href=\\\"/book/(\\\\d+/\\\\d+/id_[^.]+).html\\\"\",\r\n \"pagePatten\": \"<span\\\\s+class=\\\"current\\\">([^<]+)</span>\",\r\n \"totalPagePatten\": \"/共(\\\\d+)页\",\r\n \"bookDetailUrl\": \"https://www.bookbao8.com/book/{bookId}.html\",\r\n \"bookNamePatten\": \"<div\\\\s+id=\\\"info\\\">\\\\s*<h1>([^<]+)</h1>\",\r\n \"authorNamePatten\": \"<p>作者:<a\\\\s+href=\\\"/Search/[^\\\"]+\\\"\\\\s+target=\\\"_blank\\\">([^<]+)</a></p>\",\r\n \"picUrlPatten\": \"<div\\\\s+id=\\\"fmimg\\\">\\\\s*<img\\\\s+alt=\\\"[^\\\"]+\\\"\\\\s+src=\\\"([^\\\"]+)\\\"\",\r\n \"statusPatten\": \"<p>状态:([^<]+)</p>\",\r\n \"bookStatusRule\": {\r\n \"连载中\": 0,\r\n \"已完结\": 1\r\n },\r\n \"visitCountPatten\": \"<em\\\\s+id=\\\"hits\\\">(\\\\d+)</em>\",\r\n \"descStart\": \"<div class=\\\"infocontent\\\">\",\r\n \"descEnd\": \"</div>\",\r\n \"upadateTimePatten\": \"<p>更新时间:(\\\\d+-\\\\d+-\\\\d+\\\\s\\\\d+:\\\\d+:\\\\d+)</p>\",\r\n \"upadateTimeFormatPatten\": \"yyyy-MM-dd HH:mm:ss\",\r\n \"bookIndexUrl\": \"https://www.bookbao8.com/book/{bookId}.html\",\r\n \"indexIdPatten\": \"<li>\\\\s*<a\\\\s+href=\\\"/views/\\\\d+/\\\\d+/id_[^_]+_(\\\\d+).html\\\"\\\\s+target=\\\"_blank\\\">\",\r\n \"indexNamePatten\": \"<li>\\\\s*<a\\\\s+href=\\\"/views/\\\\d+/\\\\d+/id_[^_]+_\\\\d+.html\\\"\\\\s+target=\\\"_blank\\\">([^<]+)</a>\",\r\n \"bookContentUrl\": \"https://www.bookbao8.com/views/{bookId}_{indexId}.html\",\r\n \"contentStart\": \"<dd id=\\\"contents\\\">\",\r\n \"contentEnd\": \"</dd>\"\r\n}', '0', '2020-05-04 17:42:22', '2020-05-04 17:42:22');
INSERT INTO `crawl_source` VALUES ('4', '书趣阁', '{\r\n \"bookListUrl\": \"http://m.shuquge.com/sort/{catId}/0_{page}.html\",\r\n \"catIdRule\": {\r\n \"catId1\": \"1\",\r\n \"catId2\": \"2\",\r\n \"catId3\": \"3\",\r\n \"catId4\": \"4\",\r\n \"catId5\": \"7\",\r\n \"catId6\": \"6\",\r\n \"catId7\": \"8\"\r\n },\r\n \"bookIdPatten\": \"href=\\\"/s/(\\\\d+)\\\\.html\\\"\",\r\n \"pagePatten\": \"第(\\\\d+)/\\\\d+页\",\r\n \"totalPagePatten\": \"\\\\d+/(\\\\d+)页\",\r\n \"bookDetailUrl\": \"http://m.shuquge.com/s/{bookId}.html\",\r\n \"bookNamePatten\": \"<a\\\\s+href=\\\"/s/\\\\d+\\\\.html\\\"><h2>([^/]+)</h2></a>\",\r\n \"authorNamePatten\": \"<p>作者:([^/]+)</p>\",\r\n \"picUrlPatten\": \"src=\\\"(http://www.shuquge.com/files/article/image/\\\\d+/\\\\d+/\\\\d+s\\\\.jpg)\\\"\",\r\n \"statusPatten\": \"<p>状态:([^/]+)</p>\",\r\n \"bookStatusRule\": {\r\n \"连载中\": 0,\r\n \"完本\": 1\r\n },\r\n \"descStart\": \"<div class=\\\"intro_info\\\">\",\r\n \"descEnd\": \"最新章节推荐地址\",\r\n \"bookIndexUrl\": \"http://www.shuquge.com/txt/{bookId}/index.html\",\r\n \"bookIndexStart\": \"》正文\",\r\n \"indexIdPatten\": \"<dd><a\\\\s+href=\\\"(\\\\d+)\\\\.html\\\">[^/]+</a></dd>\",\r\n \"indexNamePatten\": \"<dd><a\\\\s+href=\\\"\\\\d+\\\\.html\\\">([^/]+)</a></dd>\",\r\n \"bookContentUrl\": \"http://www.shuquge.com/txt/{bookId}/{indexId}.html\",\r\n \"contentStart\": \"<div id=\\\"content\\\" class=\\\"showtxt\\\">\",\r\n \"contentEnd\": \"http://www.shuquge.com\"\r\n}', '1', '2020-05-18 12:02:34', '2020-05-18 12:02:34');
INSERT INTO `crawl_source` (`id`, `source_name`, `crawl_rule`, `source_status`, `create_time`, `update_time`) VALUES ('5', '笔趣阁', '{\"bookListUrl\":\"http://m.mcmssc.com/xclass/{catId}/{page}.html\",\"catIdRule\":{\"catId1\":\"1\",\"catId2\":\"2\",\"catId3\":\"3\",\"catId4\":\"4\",\"catId5\":\"5\",\"catId6\":\"6\",\"catId7\":\"7\"},\"bookIdPatten\":\"href=\\\"/(\\\\d+_\\\\d+)/\\\"\",\"pagePatten\":\"class=\\\"page_txt\\\"\\\\s+value=\\\"(\\\\d+)/\\\\d+\\\"\\\\s+size=\",\"totalPagePatten\":\"class=\\\"page_txt\\\"\\\\s+value=\\\"\\\\d+/(\\\\d+)\\\"\\\\s+size=\",\"bookDetailUrl\":\"http://m.mcmssc.com/{bookId}/\",\"bookNamePatten\":\"<span\\\\s+class=\\\"title\\\">([^/]+)</span>\",\"authorNamePatten\":\"<a\\\\s+href=\\\"/author/\\\\d+/\\\">([^/]+)</a>\",\"picUrlPatten\":\"<img\\\\s+src=\\\"([^>]+)\\\"\\\\s+onerror=\",\"picUrlPrefix\":\"http://m.mcmssc.com/\",\"statusPatten\":\">状态:([^/]+)<\",\"bookStatusRule\":{\"连载\":0,\"全本\":1},\"visitCountPatten\":\">点击:(\\\\d+)<\",\"descStart\":\"<p class=\\\"review\\\">\",\"descEnd\":\"</p>\",\"bookIndexUrl\":\"http://m.mcmssc.com/{bookId}/all.html\",\"indexIdPatten\":\"<a\\\\s+href=\\\"/\\\\d+_\\\\d+/(\\\\d+)\\\\.html\\\">[^/]+</a>\",\"indexNamePatten\":\"<a\\\\s+href=\\\"/\\\\d+_\\\\d+/\\\\d+\\\\.html\\\">([^/]+)</a>\",\"bookContentUrl\":\"http://www.mcmssc.com/{bookId}/{indexId}.html\",\"contentStart\":\"</p>\",\"contentEnd\":\"<div align=\\\"center\\\">\"}', '1', '2020-05-18 15:57:41', '2020-05-18 15:57:41');
-- ----------------------------
-- Table structure for friend_link
@ -378,6 +426,27 @@ CREATE TABLE `news_category` (
INSERT INTO `news_category` VALUES ('1', '招募', '10', null, null, null, null);
INSERT INTO `news_category` VALUES ('3', '公告', '11', null, null, null, null);
-- ----------------------------
-- Table structure for order_pay
-- ----------------------------
DROP TABLE IF EXISTS `order_pay`;
CREATE TABLE `order_pay` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`out_trade_no` bigint(20) NOT NULL COMMENT '商户订单号',
`trade_no` varchar(64) DEFAULT NULL COMMENT '支付宝/微信交易号',
`pay_channel` tinyint(1) NOT NULL DEFAULT '1' COMMENT '支付渠道1支付宝2微信',
`total_amount` int(11) NOT NULL COMMENT '交易金额(单位元)',
`user_id` bigint(20) NOT NULL COMMENT '支付用户ID',
`pay_status` tinyint(1) DEFAULT '2' COMMENT '支付状态0支付失败1支付成功2待支付',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4 COMMENT='充值订单';
-- ----------------------------
-- Records of order_pay
-- ----------------------------
-- ----------------------------
-- Table structure for sys_data_perm
-- ----------------------------
@ -422,13 +491,6 @@ CREATE TABLE `sys_dept` (
-- ----------------------------
-- Records of sys_dept
-- ----------------------------
INSERT INTO `sys_dept` VALUES ('6', '0', '研发部', '1', '1');
INSERT INTO `sys_dept` VALUES ('7', '6', '研發一部', '1', '1');
INSERT INTO `sys_dept` VALUES ('8', '6', '研发二部', '2', '1');
INSERT INTO `sys_dept` VALUES ('9', '0', '销售部', '2', '1');
INSERT INTO `sys_dept` VALUES ('10', '9', '销售一部', '1', '1');
INSERT INTO `sys_dept` VALUES ('11', '0', '产品部', '3', '1');
INSERT INTO `sys_dept` VALUES ('12', '11', '产品一部', '1', '1');
INSERT INTO `sys_dept` VALUES ('13', '0', '测试部', '5', '1');
INSERT INTO `sys_dept` VALUES ('14', '13', '测试一部', '1', '1');
INSERT INTO `sys_dept` VALUES ('15', '13', '测试二部', '2', '1');
@ -456,7 +518,7 @@ CREATE TABLE `sys_dict` (
KEY `sys_dict_value` (`value`),
KEY `sys_dict_label` (`name`),
KEY `sys_dict_del_flag` (`del_flag`)
) ENGINE=InnoDB AUTO_INCREMENT=140 DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='字典表';
) ENGINE=InnoDB AUTO_INCREMENT=142 DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='字典表';
-- ----------------------------
-- Records of sys_dict
@ -589,6 +651,8 @@ INSERT INTO `sys_dict` VALUES ('136', '富文本', '6', 'page_type', '页面显
INSERT INTO `sys_dict` VALUES ('137', '上传图片单文件', '7', 'page_type', '页面显示类型', '7', null, null, null, null, null, '', null);
INSERT INTO `sys_dict` VALUES ('138', '隐藏域', '11', 'page_type', '页面显示类型', '11', null, null, null, null, null, '', null);
INSERT INTO `sys_dict` VALUES ('139', '不显示', '12', 'page_type', '页面显示类型', '12', null, null, null, null, null, '', null);
INSERT INTO `sys_dict` VALUES ('140', '男频', '0', 'work_direction', '作品方向', '0', null, null, null, null, null, '', null);
INSERT INTO `sys_dict` VALUES ('141', '女频', '1', 'work_direction', '作品方向', '1', null, null, null, null, null, '', null);
-- ----------------------------
-- Table structure for sys_file
@ -664,7 +728,7 @@ CREATE TABLE `sys_gen_columns` (
`is_required` tinyint(1) DEFAULT NULL COMMENT '是否必填',
`dict_type` varchar(100) CHARACTER SET utf8 DEFAULT '' COMMENT '页面显示为下拉时使用字典类型从字典表中取出',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=801 DEFAULT CHARSET=utf8mb4;
) ENGINE=InnoDB AUTO_INCREMENT=815 DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Records of sys_gen_columns
@ -728,6 +792,20 @@ INSERT INTO `sys_gen_columns` VALUES ('797', 'fb_order', 'push_time', 'datetime'
INSERT INTO `sys_gen_columns` VALUES ('798', 'fb_order', 'push_ip', 'varchar', 'String', '推送IP', '31', '推送IP', '6', '0', 'del_flag');
INSERT INTO `sys_gen_columns` VALUES ('799', 'fb_order', 'mcht_id', 'bigint', 'BigDecimal', '商户id', '90', '商户id', '3', '0', 'theme');
INSERT INTO `sys_gen_columns` VALUES ('800', 'fb_order', 'sn', 'char', 'String', 'QR编号', '100', 'QR编号', '1', '0', 'del_flag');
INSERT INTO `sys_gen_columns` VALUES ('801', 'author', 'user_id', 'bigint', 'Long', '用户ID', '2', '用户ID', '1', '0', null);
INSERT INTO `sys_gen_columns` VALUES ('802', 'author', 'invite_code', 'varchar', 'String', '邀请码', '3', '邀请码', '1', '0', null);
INSERT INTO `sys_gen_columns` VALUES ('803', 'author', 'pen_name', 'varchar', 'String', '笔名', '4', '笔名', '1', '0', null);
INSERT INTO `sys_gen_columns` VALUES ('804', 'author', 'tel_phone', 'varchar', 'String', '手机号码', '5', '手机号码', '1', '0', null);
INSERT INTO `sys_gen_columns` VALUES ('805', 'author', 'chat_account', 'varchar', 'String', 'QQ或微信账号', '6', 'QQ或微信账号', '1', '0', null);
INSERT INTO `sys_gen_columns` VALUES ('806', 'author', 'email', 'varchar', 'String', '电子邮箱', '7', '电子邮箱', '1', '0', null);
INSERT INTO `sys_gen_columns` VALUES ('807', 'author', 'work_direction', 'tinyint', 'Integer', '作品方向0男频1女频', '8', '作品方向0男频1女频', '2', '0', 'work_direction');
INSERT INTO `sys_gen_columns` VALUES ('808', 'author', 'status', 'tinyint', 'Integer', '0正常1封禁', '10', '0正常1封禁', '1', '0', null);
INSERT INTO `sys_gen_columns` VALUES ('809', 'author', 'create_time', 'datetime', 'Date', '创建时间', '9', '入驻时间', '4', '0', null);
INSERT INTO `sys_gen_columns` VALUES ('810', 'author_code', 'invite_code', 'varchar', 'String', '邀请码', '2', '邀请码', '1', '1', null);
INSERT INTO `sys_gen_columns` VALUES ('811', 'author_code', 'validity_time', 'datetime', 'Date', '有效时间', '3', '有效时间', '4', '1', null);
INSERT INTO `sys_gen_columns` VALUES ('812', 'author_code', 'is_use', 'tinyint', 'Integer', '是否使用过0未使用1:使用过', '4', '是否使用过0未使用1:使用过', '1', '0', null);
INSERT INTO `sys_gen_columns` VALUES ('813', 'author_code', 'create_time', 'datetime', 'Date', '创建时间', '5', '创建时间', '4', '0', null);
INSERT INTO `sys_gen_columns` VALUES ('814', 'author_code', 'create_user_id', 'bigint', 'Long', '创建人ID', '6', '创建人ID', '1', '0', null);
-- ----------------------------
-- Table structure for sys_gen_table
@ -807,11 +885,8 @@ CREATE TABLE `sys_log` (
`ip` varchar(64) DEFAULT NULL COMMENT 'IP地址',
`gmt_create` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1369 DEFAULT CHARSET=utf8 COMMENT='系统日志';
) ENGINE=InnoDB AUTO_INCREMENT=1412 DEFAULT CHARSET=utf8 COMMENT='系统日志';
-- ----------------------------
-- Records of sys_log
-- ----------------------------
-- ----------------------------
-- Table structure for sys_menu
@ -829,7 +904,7 @@ CREATE TABLE `sys_menu` (
`gmt_create` datetime DEFAULT NULL COMMENT '创建时间',
`gmt_modified` datetime DEFAULT NULL COMMENT '修改时间',
PRIMARY KEY (`menu_id`)
) ENGINE=InnoDB AUTO_INCREMENT=215 DEFAULT CHARSET=utf8 COMMENT='菜单管理';
) ENGINE=InnoDB AUTO_INCREMENT=234 DEFAULT CHARSET=utf8 COMMENT='菜单管理';
-- ----------------------------
-- Records of sys_menu
@ -886,6 +961,19 @@ INSERT INTO `sys_menu` VALUES ('211', '209', '新增', null, 'system:dataPerm:ad
INSERT INTO `sys_menu` VALUES ('212', '209', '修改', null, 'system:dataPerm:edit', '2', null, '6', null, null);
INSERT INTO `sys_menu` VALUES ('213', '209', '删除', null, 'system:dataPerm:remove', '2', null, '6', null, null);
INSERT INTO `sys_menu` VALUES ('214', '209', '批量删除', null, 'system:dataPerm:batchRemove', '2', null, '6', null, null);
INSERT INTO `sys_menu` VALUES ('221', '0', '作家管理', '', '', '0', 'fa fa-user-o', '10', null, null);
INSERT INTO `sys_menu` VALUES ('222', '221', '作者列表', 'novel/author', 'novel:author:author', '1', 'fa', '6', null, null);
INSERT INTO `sys_menu` VALUES ('223', '222', '查看', null, 'novel:author:detail', '2', null, '6', null, null);
INSERT INTO `sys_menu` VALUES ('224', '222', '新增', null, 'novel:author:add', '2', null, '6', null, null);
INSERT INTO `sys_menu` VALUES ('225', '222', '修改', null, 'novel:author:edit', '2', null, '6', null, null);
INSERT INTO `sys_menu` VALUES ('226', '222', '删除', null, 'novel:author:remove', '2', null, '6', null, null);
INSERT INTO `sys_menu` VALUES ('227', '222', '批量删除', null, 'novel:author:batchRemove', '2', null, '6', null, null);
INSERT INTO `sys_menu` VALUES ('228', '221', '邀请码管理', 'novel/authorCode', 'novel:authorCode:authorCode', '1', 'fa', '3', null, null);
INSERT INTO `sys_menu` VALUES ('229', '228', '查看', null, 'novel:authorCode:detail', '2', null, '6', null, null);
INSERT INTO `sys_menu` VALUES ('230', '228', '新增', null, 'novel:authorCode:add', '2', null, '6', null, null);
INSERT INTO `sys_menu` VALUES ('231', '228', '修改', null, 'novel:authorCode:edit', '2', null, '6', null, null);
INSERT INTO `sys_menu` VALUES ('232', '228', '删除', null, 'novel:authorCode:remove', '2', null, '6', null, null);
INSERT INTO `sys_menu` VALUES ('233', '228', '批量删除', null, 'novel:authorCode:batchRemove', '2', null, '6', null, null);
-- ----------------------------
-- Table structure for sys_role
@ -906,9 +994,6 @@ CREATE TABLE `sys_role` (
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES ('1', '超级用户角色', 'admin', '拥有最高权限', '2', '2017-08-12 00:43:52', '2017-08-12 19:14:59');
INSERT INTO `sys_role` VALUES ('59', '普通用户', null, '基本用户权限', null, null, null);
INSERT INTO `sys_role` VALUES ('60', '测试', null, '&lt;div&gt;', null, null, null);
INSERT INTO `sys_role` VALUES ('61', 'test', null, '测试', null, null, null);
-- ----------------------------
-- Table structure for sys_role_data_perm
@ -919,22 +1004,22 @@ CREATE TABLE `sys_role_data_perm` (
`role_id` bigint(20) DEFAULT NULL COMMENT '角色ID',
`perm_id` bigint(20) DEFAULT NULL COMMENT '权限ID',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=63 DEFAULT CHARSET=utf8 COMMENT='角色与数据权限对应关系';
) ENGINE=InnoDB AUTO_INCREMENT=79 DEFAULT CHARSET=utf8 COMMENT='角色与数据权限对应关系';
-- ----------------------------
-- Records of sys_role_data_perm
-- ----------------------------
INSERT INTO `sys_role_data_perm` VALUES ('49', '1', '214');
INSERT INTO `sys_role_data_perm` VALUES ('50', '1', '213');
INSERT INTO `sys_role_data_perm` VALUES ('51', '1', '212');
INSERT INTO `sys_role_data_perm` VALUES ('52', '1', '211');
INSERT INTO `sys_role_data_perm` VALUES ('53', '1', '210');
INSERT INTO `sys_role_data_perm` VALUES ('54', '1', '1199168630769283072');
INSERT INTO `sys_role_data_perm` VALUES ('55', '1', '-1');
INSERT INTO `sys_role_data_perm` VALUES ('56', '1', '1199168630454710272');
INSERT INTO `sys_role_data_perm` VALUES ('60', '60', '211');
INSERT INTO `sys_role_data_perm` VALUES ('61', '60', '-1');
INSERT INTO `sys_role_data_perm` VALUES ('62', '60', '1199170283966787584');
INSERT INTO `sys_role_data_perm` VALUES ('71', '1', '214');
INSERT INTO `sys_role_data_perm` VALUES ('72', '1', '213');
INSERT INTO `sys_role_data_perm` VALUES ('73', '1', '212');
INSERT INTO `sys_role_data_perm` VALUES ('74', '1', '211');
INSERT INTO `sys_role_data_perm` VALUES ('75', '1', '210');
INSERT INTO `sys_role_data_perm` VALUES ('76', '1', '1260412100929482752');
INSERT INTO `sys_role_data_perm` VALUES ('77', '1', '-1');
INSERT INTO `sys_role_data_perm` VALUES ('78', '1', '1260412099998347264');
-- ----------------------------
-- Table structure for sys_role_menu
@ -945,7 +1030,7 @@ CREATE TABLE `sys_role_menu` (
`role_id` bigint(20) DEFAULT NULL COMMENT '角色ID',
`menu_id` bigint(20) DEFAULT NULL COMMENT '菜单ID',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4704 DEFAULT CHARSET=utf8 COMMENT='角色与菜单对应关系';
) ENGINE=InnoDB AUTO_INCREMENT=4830 DEFAULT CHARSET=utf8 COMMENT='角色与菜单对应关系';
-- ----------------------------
-- Records of sys_role_menu
@ -1166,59 +1251,6 @@ INSERT INTO `sys_role_menu` VALUES ('3280', '59', '3');
INSERT INTO `sys_role_menu` VALUES ('3281', '59', '78');
INSERT INTO `sys_role_menu` VALUES ('3282', '59', '1');
INSERT INTO `sys_role_menu` VALUES ('3283', '59', '-1');
INSERT INTO `sys_role_menu` VALUES ('4505', '1', '208');
INSERT INTO `sys_role_menu` VALUES ('4506', '1', '207');
INSERT INTO `sys_role_menu` VALUES ('4507', '1', '206');
INSERT INTO `sys_role_menu` VALUES ('4508', '1', '205');
INSERT INTO `sys_role_menu` VALUES ('4509', '1', '204');
INSERT INTO `sys_role_menu` VALUES ('4510', '1', '92');
INSERT INTO `sys_role_menu` VALUES ('4511', '1', '57');
INSERT INTO `sys_role_menu` VALUES ('4512', '1', '30');
INSERT INTO `sys_role_menu` VALUES ('4513', '1', '29');
INSERT INTO `sys_role_menu` VALUES ('4514', '1', '28');
INSERT INTO `sys_role_menu` VALUES ('4515', '1', '104');
INSERT INTO `sys_role_menu` VALUES ('4516', '1', '48');
INSERT INTO `sys_role_menu` VALUES ('4517', '1', '214');
INSERT INTO `sys_role_menu` VALUES ('4518', '1', '213');
INSERT INTO `sys_role_menu` VALUES ('4519', '1', '212');
INSERT INTO `sys_role_menu` VALUES ('4520', '1', '211');
INSERT INTO `sys_role_menu` VALUES ('4521', '1', '210');
INSERT INTO `sys_role_menu` VALUES ('4522', '1', '76');
INSERT INTO `sys_role_menu` VALUES ('4523', '1', '75');
INSERT INTO `sys_role_menu` VALUES ('4524', '1', '74');
INSERT INTO `sys_role_menu` VALUES ('4525', '1', '62');
INSERT INTO `sys_role_menu` VALUES ('4526', '1', '56');
INSERT INTO `sys_role_menu` VALUES ('4527', '1', '55');
INSERT INTO `sys_role_menu` VALUES ('4528', '1', '15');
INSERT INTO `sys_role_menu` VALUES ('4529', '1', '26');
INSERT INTO `sys_role_menu` VALUES ('4530', '1', '25');
INSERT INTO `sys_role_menu` VALUES ('4531', '1', '24');
INSERT INTO `sys_role_menu` VALUES ('4532', '1', '14');
INSERT INTO `sys_role_menu` VALUES ('4533', '1', '13');
INSERT INTO `sys_role_menu` VALUES ('4534', '1', '12');
INSERT INTO `sys_role_menu` VALUES ('4535', '1', '61');
INSERT INTO `sys_role_menu` VALUES ('4536', '1', '22');
INSERT INTO `sys_role_menu` VALUES ('4537', '1', '21');
INSERT INTO `sys_role_menu` VALUES ('4538', '1', '20');
INSERT INTO `sys_role_menu` VALUES ('4539', '1', '83');
INSERT INTO `sys_role_menu` VALUES ('4540', '1', '81');
INSERT INTO `sys_role_menu` VALUES ('4541', '1', '80');
INSERT INTO `sys_role_menu` VALUES ('4542', '1', '79');
INSERT INTO `sys_role_menu` VALUES ('4543', '1', '71');
INSERT INTO `sys_role_menu` VALUES ('4544', '1', '203');
INSERT INTO `sys_role_menu` VALUES ('4545', '1', '202');
INSERT INTO `sys_role_menu` VALUES ('4546', '1', '27');
INSERT INTO `sys_role_menu` VALUES ('4547', '1', '91');
INSERT INTO `sys_role_menu` VALUES ('4548', '1', '77');
INSERT INTO `sys_role_menu` VALUES ('4549', '1', '209');
INSERT INTO `sys_role_menu` VALUES ('4550', '1', '73');
INSERT INTO `sys_role_menu` VALUES ('4551', '1', '7');
INSERT INTO `sys_role_menu` VALUES ('4552', '1', '6');
INSERT INTO `sys_role_menu` VALUES ('4553', '1', '2');
INSERT INTO `sys_role_menu` VALUES ('4554', '1', '3');
INSERT INTO `sys_role_menu` VALUES ('4555', '1', '78');
INSERT INTO `sys_role_menu` VALUES ('4556', '1', '1');
INSERT INTO `sys_role_menu` VALUES ('4557', '1', '-1');
INSERT INTO `sys_role_menu` VALUES ('4611', '61', '208');
INSERT INTO `sys_role_menu` VALUES ('4612', '61', '207');
INSERT INTO `sys_role_menu` VALUES ('4613', '61', '206');
@ -1312,6 +1344,72 @@ INSERT INTO `sys_role_menu` VALUES ('4700', '60', '78');
INSERT INTO `sys_role_menu` VALUES ('4701', '60', '1');
INSERT INTO `sys_role_menu` VALUES ('4702', '60', '-1');
INSERT INTO `sys_role_menu` VALUES ('4703', '60', '3');
INSERT INTO `sys_role_menu` VALUES ('4764', '1', '227');
INSERT INTO `sys_role_menu` VALUES ('4765', '1', '226');
INSERT INTO `sys_role_menu` VALUES ('4766', '1', '225');
INSERT INTO `sys_role_menu` VALUES ('4767', '1', '224');
INSERT INTO `sys_role_menu` VALUES ('4768', '1', '223');
INSERT INTO `sys_role_menu` VALUES ('4769', '1', '208');
INSERT INTO `sys_role_menu` VALUES ('4770', '1', '207');
INSERT INTO `sys_role_menu` VALUES ('4771', '1', '206');
INSERT INTO `sys_role_menu` VALUES ('4772', '1', '205');
INSERT INTO `sys_role_menu` VALUES ('4773', '1', '204');
INSERT INTO `sys_role_menu` VALUES ('4774', '1', '92');
INSERT INTO `sys_role_menu` VALUES ('4775', '1', '57');
INSERT INTO `sys_role_menu` VALUES ('4776', '1', '30');
INSERT INTO `sys_role_menu` VALUES ('4777', '1', '29');
INSERT INTO `sys_role_menu` VALUES ('4778', '1', '28');
INSERT INTO `sys_role_menu` VALUES ('4779', '1', '104');
INSERT INTO `sys_role_menu` VALUES ('4780', '1', '48');
INSERT INTO `sys_role_menu` VALUES ('4781', '1', '214');
INSERT INTO `sys_role_menu` VALUES ('4782', '1', '213');
INSERT INTO `sys_role_menu` VALUES ('4783', '1', '212');
INSERT INTO `sys_role_menu` VALUES ('4784', '1', '211');
INSERT INTO `sys_role_menu` VALUES ('4785', '1', '210');
INSERT INTO `sys_role_menu` VALUES ('4786', '1', '76');
INSERT INTO `sys_role_menu` VALUES ('4787', '1', '75');
INSERT INTO `sys_role_menu` VALUES ('4788', '1', '74');
INSERT INTO `sys_role_menu` VALUES ('4789', '1', '62');
INSERT INTO `sys_role_menu` VALUES ('4790', '1', '56');
INSERT INTO `sys_role_menu` VALUES ('4791', '1', '55');
INSERT INTO `sys_role_menu` VALUES ('4792', '1', '15');
INSERT INTO `sys_role_menu` VALUES ('4793', '1', '26');
INSERT INTO `sys_role_menu` VALUES ('4794', '1', '25');
INSERT INTO `sys_role_menu` VALUES ('4795', '1', '24');
INSERT INTO `sys_role_menu` VALUES ('4796', '1', '14');
INSERT INTO `sys_role_menu` VALUES ('4797', '1', '13');
INSERT INTO `sys_role_menu` VALUES ('4798', '1', '12');
INSERT INTO `sys_role_menu` VALUES ('4799', '1', '61');
INSERT INTO `sys_role_menu` VALUES ('4800', '1', '22');
INSERT INTO `sys_role_menu` VALUES ('4801', '1', '21');
INSERT INTO `sys_role_menu` VALUES ('4802', '1', '20');
INSERT INTO `sys_role_menu` VALUES ('4803', '1', '83');
INSERT INTO `sys_role_menu` VALUES ('4804', '1', '81');
INSERT INTO `sys_role_menu` VALUES ('4805', '1', '80');
INSERT INTO `sys_role_menu` VALUES ('4806', '1', '79');
INSERT INTO `sys_role_menu` VALUES ('4807', '1', '71');
INSERT INTO `sys_role_menu` VALUES ('4808', '1', '222');
INSERT INTO `sys_role_menu` VALUES ('4809', '1', '203');
INSERT INTO `sys_role_menu` VALUES ('4810', '1', '202');
INSERT INTO `sys_role_menu` VALUES ('4811', '1', '27');
INSERT INTO `sys_role_menu` VALUES ('4812', '1', '91');
INSERT INTO `sys_role_menu` VALUES ('4813', '1', '77');
INSERT INTO `sys_role_menu` VALUES ('4814', '1', '209');
INSERT INTO `sys_role_menu` VALUES ('4815', '1', '73');
INSERT INTO `sys_role_menu` VALUES ('4816', '1', '7');
INSERT INTO `sys_role_menu` VALUES ('4817', '1', '6');
INSERT INTO `sys_role_menu` VALUES ('4818', '1', '2');
INSERT INTO `sys_role_menu` VALUES ('4819', '1', '3');
INSERT INTO `sys_role_menu` VALUES ('4820', '1', '78');
INSERT INTO `sys_role_menu` VALUES ('4821', '1', '1');
INSERT INTO `sys_role_menu` VALUES ('4822', '1', '228');
INSERT INTO `sys_role_menu` VALUES ('4823', '1', '233');
INSERT INTO `sys_role_menu` VALUES ('4824', '1', '232');
INSERT INTO `sys_role_menu` VALUES ('4825', '1', '231');
INSERT INTO `sys_role_menu` VALUES ('4826', '1', '230');
INSERT INTO `sys_role_menu` VALUES ('4827', '1', '229');
INSERT INTO `sys_role_menu` VALUES ('4828', '1', '221');
INSERT INTO `sys_role_menu` VALUES ('4829', '1', '-1');
-- ----------------------------
-- Table structure for sys_user
@ -1343,19 +1441,7 @@ CREATE TABLE `sys_user` (
-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES ('1', 'admin', '超级管理员', 'd633268afedf209e1e4ea0f5f43228a8', '6', 'admin@example.com', '17699999999', '1', '1', '2017-08-15 21:40:39', '2017-08-15 21:41:00', '96', '2017-12-14 00:00:00', '148', 'ccc', '122;121;', '北京市', '北京市市辖区', '东城区');
INSERT INTO `sys_user` VALUES ('2', 'test', '临时用户', 'd0af8fa1272ef5a152d9e27763eea293', '6', 'test@bootdo.com', null, '1', '1', '2017-08-14 13:43:05', '2017-08-14 21:15:36', null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('36', 'ldh', '刘德华', 'bfd9394475754fbe45866eba97738c36', '7', 'ldh@bootdo.com', null, '1', null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('123', 'zxy', '张学友', '35174ba93f5fe7267f1fb3c1bf903781', '6', 'zxy@bootdo', null, '0', null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('124', 'wyf', '吴亦凡', 'e179e6f687bbd57b9d7efc4746c8090a', '6', 'wyf@bootdo.com', null, '1', null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('130', 'lh', '鹿晗', '7924710cd673f68967cde70e188bb097', '9', 'lh@bootdo.com', null, '1', null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('131', 'lhc', '令狐冲', 'd515538e17ecb570ba40344b5618f5d4', '6', 'lhc@bootdo.com', null, '0', null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('132', 'lyf', '刘亦菲', '7fdb1d9008f45950c1620ba0864e5fbd', '13', 'lyf@bootdo.com', null, '1', null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('134', 'lyh', '李彦宏', 'dc26092b3244d9d432863f2738180e19', '8', 'lyh@bootdo.com', null, '1', null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('135', 'wjl', '王健林', '3967697dfced162cf6a34080259b83aa', '6', 'wjl@bootod.com', null, '1', null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('136', 'gdg', '郭德纲', '3bb1bda86bc02bf6478cd91e42135d2f', '9', 'gdg@bootdo.com', null, '1', null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('137', 'test2', 'test2', '649169898e69272c0e5bc899baf1e904', null, '1179705413@qq.com', null, '1', null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('138', 'test3', 'test3', '4428f69c806f51128f3974f948a2f272', '16', '1179705413@qq.com', null, '1', null, null, null, null, null, null, null, null, null, null, null);
INSERT INTO `sys_user` VALUES ('1', 'admin', '超级管理员', 'd633268afedf209e1e4ea0f5f43228a8', '14', 'admin@example.com', '17699999999', '1', '1', '2017-08-15 21:40:39', '2017-08-15 21:41:00', '96', '2017-12-14 00:00:00', '148', 'ccc', '122;121;', '北京市', '北京市市辖区', '东城区');
-- ----------------------------
-- Table structure for sys_user_role
@ -1460,6 +1546,29 @@ INSERT INTO `user_bookshelf` VALUES ('39', '1255060328322027520', '1254681071191
INSERT INTO `user_bookshelf` VALUES ('40', '1255060328322027520', '1254676970567565312', '3264258', '2020-04-30 09:57:18', '2020-04-30 19:19:11');
INSERT INTO `user_bookshelf` VALUES ('41', '1255060328322027520', '1254675594315759616', '1254675594496114688', '2020-04-30 18:37:18', null);
-- ----------------------------
-- Table structure for user_buy_record
-- ----------------------------
DROP TABLE IF EXISTS `user_buy_record`;
CREATE TABLE `user_buy_record` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`book_id` bigint(20) DEFAULT NULL COMMENT '购买的小说ID',
`book_name` varchar(50) DEFAULT NULL COMMENT '购买的小说名',
`book_index_id` bigint(20) DEFAULT NULL COMMENT '购买的章节ID',
`book_index_name` varchar(100) DEFAULT NULL COMMENT '购买的章节名',
`buy_amount` int(11) DEFAULT NULL COMMENT '购买使用的屋币数量',
`create_time` datetime DEFAULT NULL COMMENT '购买时间',
PRIMARY KEY (`id`),
UNIQUE KEY `key_userId_indexId` (`user_id`,`book_index_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COMMENT='用户消费记录表';
-- ----------------------------
-- Records of user_buy_record
-- ----------------------------
INSERT INTO `user_buy_record` VALUES ('1', '1255060328322027520', '1260400284744613890', '我是一只消消乐2', '1260522024606953472', '第三章', '10', '2020-05-13 21:29:09');
INSERT INTO `user_buy_record` VALUES ('2', '1255060328322027520', '1260400284744613890', '我是一只消消乐2', '1260564410687107072', '第四章', '10', '2020-05-13 21:40:38');
-- ----------------------------
-- Table structure for user_feedback
-- ----------------------------
@ -1513,3 +1622,218 @@ INSERT INTO `user_read_history` VALUES ('111', '1255060328322027520', '125495762
INSERT INTO `user_read_history` VALUES ('113', '1255060328322027520', '1254676970567565312', '3264258', '2020-04-30 19:19:11', '2020-04-30 19:19:11');
INSERT INTO `user_read_history` VALUES ('117', '1255060328322027520', '1254946661743603712', '1254946914001629184', '2020-04-30 19:37:09', '2020-04-30 19:37:09');
INSERT INTO `user_read_history` VALUES ('118', '1255060328322027520', '1254957312633352192', '3335449', '2020-04-30 19:37:36', '2020-04-30 19:37:36');
DROP TABLE IF EXISTS `book_content0`;
CREATE TABLE `book_content0` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`index_id` bigint(20) DEFAULT NULL COMMENT '目录ID',
`content` mediumtext COMMENT '小说章节内容',
PRIMARY KEY (`id`),
UNIQUE KEY `key_uq_indexId` (`index_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1155 DEFAULT CHARSET=utf8mb4 COMMENT='小说内容表';
-- ----------------------------
-- Table structure for book_content1
-- ----------------------------
DROP TABLE IF EXISTS `book_content1`;
CREATE TABLE `book_content1` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`index_id` bigint(20) DEFAULT NULL COMMENT '目录ID',
`content` mediumtext COMMENT '小说章节内容',
PRIMARY KEY (`id`),
UNIQUE KEY `key_uq_indexId` (`index_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=406 DEFAULT CHARSET=utf8mb4 COMMENT='小说内容表';
-- ----------------------------
-- Table structure for book_content2
-- ----------------------------
DROP TABLE IF EXISTS `book_content2`;
CREATE TABLE `book_content2` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`index_id` bigint(20) DEFAULT NULL COMMENT '目录ID',
`content` mediumtext COMMENT '小说章节内容',
PRIMARY KEY (`id`),
UNIQUE KEY `key_uq_indexId` (`index_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1222 DEFAULT CHARSET=utf8mb4 COMMENT='小说内容表';
-- ----------------------------
-- Table structure for book_content3
-- ----------------------------
DROP TABLE IF EXISTS `book_content3`;
CREATE TABLE `book_content3` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`index_id` bigint(20) DEFAULT NULL COMMENT '目录ID',
`content` mediumtext COMMENT '小说章节内容',
PRIMARY KEY (`id`),
UNIQUE KEY `key_uq_indexId` (`index_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=410 DEFAULT CHARSET=utf8mb4 COMMENT='小说内容表';
-- ----------------------------
-- Table structure for book_content4
-- ----------------------------
DROP TABLE IF EXISTS `book_content4`;
CREATE TABLE `book_content4` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`index_id` bigint(20) DEFAULT NULL COMMENT '目录ID',
`content` mediumtext COMMENT '小说章节内容',
PRIMARY KEY (`id`),
UNIQUE KEY `key_uq_indexId` (`index_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1188 DEFAULT CHARSET=utf8mb4 COMMENT='小说内容表';
-- ----------------------------
-- Table structure for book_content5
-- ----------------------------
DROP TABLE IF EXISTS `book_content5`;
CREATE TABLE `book_content5` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`index_id` bigint(20) DEFAULT NULL COMMENT '目录ID',
`content` mediumtext COMMENT '小说章节内容',
PRIMARY KEY (`id`),
UNIQUE KEY `key_uq_indexId` (`index_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=416 DEFAULT CHARSET=utf8mb4 COMMENT='小说内容表';
-- ----------------------------
-- Table structure for book_content6
-- ----------------------------
DROP TABLE IF EXISTS `book_content6`;
CREATE TABLE `book_content6` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`index_id` bigint(20) DEFAULT NULL COMMENT '目录ID',
`content` mediumtext COMMENT '小说章节内容',
PRIMARY KEY (`id`),
UNIQUE KEY `key_uq_indexId` (`index_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1180 DEFAULT CHARSET=utf8mb4 COMMENT='小说内容表';
-- ----------------------------
-- Table structure for book_content7
-- ----------------------------
DROP TABLE IF EXISTS `book_content7`;
CREATE TABLE `book_content7` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`index_id` bigint(20) DEFAULT NULL COMMENT '目录ID',
`content` mediumtext COMMENT '小说章节内容',
PRIMARY KEY (`id`),
UNIQUE KEY `key_uq_indexId` (`index_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=404 DEFAULT CHARSET=utf8mb4 COMMENT='小说内容表';
-- ----------------------------
-- Table structure for book_content8
-- ----------------------------
DROP TABLE IF EXISTS `book_content8`;
CREATE TABLE `book_content8` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`index_id` bigint(20) DEFAULT NULL COMMENT '目录ID',
`content` mediumtext COMMENT '小说章节内容',
PRIMARY KEY (`id`),
UNIQUE KEY `key_uq_indexId` (`index_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1134 DEFAULT CHARSET=utf8mb4 COMMENT='小说内容表';
-- ----------------------------
-- Table structure for book_content9
-- ----------------------------
DROP TABLE IF EXISTS `book_content9`;
CREATE TABLE `book_content9` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`index_id` bigint(20) DEFAULT NULL COMMENT '目录ID',
`content` mediumtext COMMENT '小说章节内容',
PRIMARY KEY (`id`),
UNIQUE KEY `key_uq_indexId` (`index_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=415 DEFAULT CHARSET=utf8mb4 COMMENT='小说内容表';
DROP TABLE IF EXISTS `crawl_single_task`;
CREATE TABLE `crawl_single_task` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`source_id` int(11) DEFAULT NULL COMMENT '爬虫源ID',
`source_name` varchar(50) DEFAULT NULL COMMENT '爬虫源名',
`source_book_id` varchar(255) DEFAULT NULL COMMENT '源站小说ID',
`cat_id` int(11) DEFAULT NULL COMMENT '分类ID',
`book_name` varchar(50) DEFAULT NULL COMMENT '爬取的小说名',
`author_name` varchar(50) DEFAULT NULL COMMENT '爬取的小说作者名',
`task_status` tinyint(1) DEFAULT '2' COMMENT '任务状态0失败1成功2未执行',
`exc_count` tinyint(2) DEFAULT '0' COMMENT '已经执行次数最多执行5次',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COMMENT='抓取单本小说任务表';
-- ----------------------------
-- Records of crawl_single_task
-- ----------------------------
INSERT INTO `crawl_single_task` VALUES ('6', '2', '百书斋', '1', '1', '1', '1', '0', '5', '2020-06-15 14:36:07');
INSERT INTO `crawl_single_task` VALUES ('7', '5', '笔趣阁', '108_108291', '1', '衍天志之不朽仙', '白衣少年丶', '1', '1', '2020-06-15 14:46:08');
UPDATE `crawl_source` SET `source_name` = '书趣阁', `crawl_rule` = '{\n \"bookListUrl\": \"http://m.shuquge.com/sort/{catId}/0_{page}.html\",\n \"catIdRule\": {\n \"catId1\": \"1\",\n \"catId2\": \"2\",\n \"catId3\": \"3\",\n \"catId4\": \"4\",\n \"catId5\": \"7\",\n \"catId6\": \"6\",\n \"catId7\": \"8\"\n },\n \"bookIdPatten\": \"href=\\\"/s/(\\\\d+)\\\\.html\\\"\",\n \"pagePatten\": \"第(\\\\d+)/\\\\d+页\",\n \"totalPagePatten\": \"\\\\d+/(\\\\d+)页\",\n \"bookDetailUrl\": \"http://m.shuquge.com/s/{bookId}.html\",\n \"bookNamePatten\": \"<a\\\\s+href=\\\"/s/\\\\d+\\\\.html\\\"><h2>([^/]+)</h2></a>\",\n \"authorNamePatten\": \"<p>作者:([^/]+)</p>\",\n \"picUrlPatten\": \"src=\\\"(http://www.shuquge.com/files/article/image/\\\\d+/\\\\d+/\\\\d+s\\\\.jpg)\\\"\",\n \"statusPatten\": \"<p>状态:([^/]+)</p>\",\n \"bookStatusRule\": {\n \"连载中\": 0,\n \"完本\": 1\n },\n \"descStart\": \"<div class=\\\"intro_info\\\">\",\n \"descEnd\": \"最新章节推荐地址\",\n \"bookIndexUrl\": \"http://www.shuquge.com/txt/{bookId}/index.html\",\n \"bookIndexStart\": \"<dt>《\",\n \"indexIdPatten\": \"<dd><a\\\\s+href=\\\"(\\\\d+)\\\\.html\\\">[^/]+</a></dd>\",\n \"indexNamePatten\": \"<dd><a\\\\s+href=\\\"\\\\d+\\\\.html\\\">([^/]+)</a></dd>\",\n \"bookContentUrl\": \"http://www.shuquge.com/txt/{bookId}/{indexId}.html\",\n \"contentStart\": \"<div id=\\\"content\\\" class=\\\"showtxt\\\">\",\n \"contentEnd\": \"http://www.shuquge.com\"\n}', `source_status` = 1, `create_time` = '2020-05-18 12:02:34', `update_time` = '2020-05-18 12:02:34' WHERE `id` = 4;
INSERT INTO `friend_link` ( `link_name`, `link_url`, `sort`, `is_open`, `create_user_id`, `create_time`, `update_user_id`, `update_time`) VALUES
('小羊影视', 'http://video.java2nb.com/', 11, 1, NULL, NULL, NULL, NULL),
('官方论坛', 'http://bbs.java2nb.com', 21, 1, NULL, NULL, NULL, NULL);
CREATE TABLE `author_income_detail` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`author_id` bigint(20) NOT NULL COMMENT '作家ID',
`book_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '作品ID,0表示全部作品',
`income_date` date NOT NULL COMMENT '收入日期',
`income_account` int(11) NOT NULL DEFAULT '0' COMMENT '订阅总额',
`income_count` int(11) NOT NULL DEFAULT '0' COMMENT '订阅次数',
`income_number` int(11) NOT NULL DEFAULT '0' COMMENT '订阅人数',
`create_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='稿费收入明细统计表';
CREATE TABLE `author_income` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`author_id` bigint(20) NOT NULL COMMENT '作家ID',
`book_id` bigint(20) NOT NULL COMMENT '作品ID',
`income_month` date NOT NULL COMMENT '收入月份',
`pre_tax_income` bigint(20) NOT NULL DEFAULT '0' COMMENT '税前收入',
`after_tax_income` bigint(20) NOT NULL DEFAULT '0' COMMENT '税后收入',
`pay_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '支付状态0待支付1已支付',
`confirm_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '稿费确认状态0待确认1已确认',
`detail` varchar(255) DEFAULT NULL COMMENT '详情',
`create_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='稿费收入统计表';
alter table book add column `yesterday_buy` int(11) DEFAULT '0' COMMENT '昨日订阅数' after comment_count;
alter table book_index add column `book_price` int(3) DEFAULT 0 COMMENT '章节费用屋币' after `is_vip`;
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (246, 241, '批量删除', NULL, 'novel:news:batchRemove', 2, NULL, 6, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (245, 241, '删除', NULL, 'novel:news:remove', 2, NULL, 6, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (244, 241, '修改', NULL, 'novel:news:edit', 2, NULL, 6, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (243, 241, '新增', NULL, 'novel:news:add', 2, NULL, 6, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (242, 241, '查看', NULL, 'novel:news:detail', 2, NULL, 6, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (241, 234, '新闻列表', 'novel/news', 'novel:news:news', 1, 'fa', 8, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (240, 235, '批量删除', NULL, 'novel:category:batchRemove', 2, NULL, 6, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (239, 235, '删除', NULL, 'novel:category:remove', 2, NULL, 6, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (238, 235, '修改', NULL, 'novel:category:edit', 2, NULL, 6, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (237, 235, '新增', NULL, 'novel:category:add', 2, NULL, 6, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (236, 235, '查看', NULL, 'novel:category:detail', 2, NULL, 6, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (235, 234, '类别管理', 'novel/category', 'novel:category:category', 1, 'fa', 6, NULL, NULL);
INSERT INTO `sys_menu`(`menu_id`, `parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`, `gmt_create`, `gmt_modified`) VALUES (234, 0, '新闻管理', '', '', 0, 'fa fa-newspaper-o', 8, NULL, NULL);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4889, 1, 246);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4890, 1, 245);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4891, 1, 244);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4892, 1, 243);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4893, 1, 242);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4899, 1, 241);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4894, 1, 240);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4895, 1, 239);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4896, 1, 238);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4897, 1, 237);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4898, 1, 236);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4900, 1, 235);
INSERT INTO `sys_role_menu`(`id`, `role_id`, `menu_id`) VALUES (4888, 1, 234);
delete from sys_menu where menu_id = 202;

View File

@ -0,0 +1,3 @@
novel_plus.sqlΪȫ<CEAA><C8AB>sql<71>ļ<EFBFBD><C4BC><EFBFBD>yyyyMMdd.sqlΪ<6C><CEAA><EFBFBD><EFBFBD>sql<71>ļ<EFBFBD><C4BC><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>û<EFBFBD>ֻ<EFBFBD><EFBFBD>Ҫִ<EFBFBD><EFBFBD>novel_plus.sql<71>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>ɡ<EFBFBD>
<EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><EFBFBD><EFBFBD><EFBFBD>´<EFBFBD><EFBFBD><EFBFBD><EFBFBD>󣬸<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϴδ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĸ<EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD>䣬ִ<EFBFBD>и<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֮<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>sql<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD>

6
novel-admin/Dockerfile Normal file
View File

@ -0,0 +1,6 @@
FROM java:8
ADD novel-admin-1.0.0.jar /root
ENV dburl=""
ENV username=""
ENV password=""
ENTRYPOINT ["sh","-c","java -Dspring.datasource.url=${dburl} -Dspring.datasource.username=${username} -Dspring.datasource.password=${password} -jar /root/novel-admin-1.0.0.jar"]

264
novel-admin/pom.xml Normal file
View File

@ -0,0 +1,264 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.java2nb</groupId>
<artifactId>novel-admin</artifactId>
<version>3.3.0</version>
<packaging>jar</packaging>
<name>novel-admin</name>
<description>小说精品屋后台管理</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<velocity.version>1.7</velocity.version>
<activiti.version>5.22.0</activiti.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- NekoHTML 是一个简单地HTML扫描器和标签补偿器(tag balancer) ,使得程序能解析HTML文档并用标准的XML接口来访问其中的信息
这个解析器能投扫描HTML文件并修正许多作者人或机器在编写HTML文档过程中常犯的错误
NekoHTML 能增补缺失的父元素自动用结束标签关闭相应的元素以及不匹配的内嵌元素标签
NekoHTML 的开发使用了Xerces Native Interface (XNI)后者是Xerces2的实现基础-->
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
</dependency>
<!--mybatis -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.4</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<!--druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.28</version>
</dependency>
<!--commons -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.6</version>
</dependency>
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
<version>1.10</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<!--shiro -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!-- shiro ehcache -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<exclusions>
<exclusion>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
</exclusion>
</exclusions>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
<!-- utils -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.31</version>
</dependency>
<!--velocity代码生成使用模板 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-data-redis</artifactId>-->
<!--</dependency>-->
<!-- quartz -->
<!--<dependency>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-cache</artifactId>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>net.sf.ehcache</groupId>-->
<!--<artifactId>ehcache</artifactId>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-devtools</artifactId>-->
<!--<optional>true</optional>-->
<!--</dependency>-->
<!--swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
<!-- 添加redis支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.4</version>
</dependency>
<!-- ehchache -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<!--war包部署需要-->
<!--<dependency>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-web</artifactId>-->
<!--&lt;!&ndash; 移除嵌入式tomcat插件 &ndash;&gt;-->
<!--<exclusions>-->
<!--<exclusion>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-tomcat</artifactId>-->
<!--</exclusion>-->
<!--</exclusions>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>javax.servlet</groupId>-->
<!--<artifactId>javax.servlet-api</artifactId>-->
<!--<version>3.1.0</version>-->
<!--<scope>provided</scope>-->
<!--</dependency>-->
</dependencies>
<build>
<plugins>
<!--<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>-->
<!--SpringBoot项目默认使用spring-boot-maven-plugin要打成被其他项目引用的jar包需要更换此插件-->
<!-- <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<!--<distributionManagement>
<repository>
<id>nexus_release</id>
<name>release</name>
<url>http://47.106.243.172:8081/nexus/content/repositories/releases/</url>
</repository>
<snapshotRepository>
<id>nexus_snapshots</id>
<name>snapshots</name>
<url>http://47.106.243.172:8081/nexus/content/repositories/snapshots/</url>
</snapshotRepository>
</distributionManagement>-->
</project>

View File

@ -0,0 +1,25 @@
package com.java2nb;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.transaction.annotation.EnableTransactionManagement;
//关闭SpringSecurity的功能
@EnableAutoConfiguration(exclude = {
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class
})
@EnableTransactionManagement
@ServletComponentScan
@MapperScan("com.java2nb.*.dao")
@SpringBootApplication
@EnableCaching
public class AdminApplication {
public static void main(String[] args) {
SpringApplication.run(AdminApplication.class, args);
}
}

View File

@ -0,0 +1,12 @@
package com.java2nb.common.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.lang.annotation.RetentionPolicy;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
String value() default "";
}

View File

@ -0,0 +1,104 @@
package com.java2nb.common.aspect;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import com.java2nb.common.service.LogService;
import com.java2nb.system.domain.UserToken;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import com.java2nb.common.annotation.Log;
import com.java2nb.common.dao.LogDao;
import com.java2nb.common.domain.LogDO;
import com.java2nb.common.utils.HttpContextUtils;
import com.java2nb.common.utils.IPUtils;
import com.java2nb.common.utils.JSONUtils;
import com.java2nb.common.utils.ShiroUtils;
import com.java2nb.system.domain.UserDO;
@Aspect
@Component
public class LogAspect {
private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);
@Autowired
LogService logService;
@Pointcut("@annotation(com.java2nb.common.annotation.Log)")
public void logPointCut() {
}
@Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
long beginTime = System.currentTimeMillis();
// 执行方法
Object result = point.proceed();
// 执行时长(毫秒)
long time = System.currentTimeMillis() - beginTime;
//异步保存日志
saveLog(point, time);
return result;
}
void saveLog(ProceedingJoinPoint joinPoint, long time) throws InterruptedException {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
LogDO sysLog = new LogDO();
Log syslog = method.getAnnotation(Log.class);
if (syslog != null) {
// 注解上的描述
sysLog.setOperation(syslog.value());
}
// 请求的方法名
String className = joinPoint.getTarget().getClass().getName();
String methodName = signature.getName();
sysLog.setMethod(className + "." + methodName + "()");
// 请求的参数
Object[] args = joinPoint.getArgs();
try {
String params = JSONUtils.beanToJson(args[0]).substring(0, 4999);
sysLog.setParams(params);
} catch (Exception e) {
}
// 获取request
HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
// 设置IP地址
sysLog.setIp(IPUtils.getIpAddr(request));
// 用户名
UserDO currUser = ShiroUtils.getUser();
if (null == currUser) {
if (null != sysLog.getParams()) {
sysLog.setUserId(-1L);
sysLog.setUsername(sysLog.getParams());
} else {
sysLog.setUserId(-1L);
sysLog.setUsername("获取用户信息为空");
}
} else {
sysLog.setUserId(ShiroUtils.getUserId());
sysLog.setUsername(ShiroUtils.getUser().getUsername());
}
sysLog.setTime((int) time);
// 系统当前时间
Date date = new Date();
sysLog.setGmtCreate(date);
// 保存系统日志
logService.save(sysLog);
}
}

View File

@ -0,0 +1,61 @@
package com.java2nb.common.aspect;
import com.java2nb.common.utils.HttpContextUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import sun.net.util.IPAddressUtil;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
@Aspect
@Component
public class WebLogAspect {
private static final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);
@Pointcut("execution( * com.java2nb..controller.*.*(..))")//两个..代表所有子目录,最后括号里的两个..代表所有参数
public void logPointCut() {
}
@Before("logPointCut()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 记录下请求内容
logger.info("请求地址 : " + request.getRequestURL().toString());
logger.info("HTTP METHOD : " + request.getMethod());
// 获取真实的ip地址
//logger.info("IP : " + IPAddressUtil.getClientIpAddress(request));
logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "."
+ joinPoint.getSignature().getName());
logger.info("参数 : " + Arrays.toString(joinPoint.getArgs()));
// loggger.info("参数 : " + joinPoint.getArgs());
}
@AfterReturning(returning = "ret", pointcut = "logPointCut()")// returning的值和doAfterReturning的参数名一致
public void doAfterReturning(Object ret) throws Throwable {
// 处理完请求,返回内容(返回值太复杂时,打印的是物理存储空间的地址)
logger.debug("返回值 : " + ret);
}
@Around("logPointCut()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
long startTime = System.currentTimeMillis();
Object ob = pjp.proceed();// ob 为方法的返回值
logger.info("耗时 : " + (System.currentTimeMillis() - startTime));
return ob;
}
}

View File

@ -0,0 +1,50 @@
package com.java2nb.common.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
*
* @author xiongxy
* @date 2019-09-25 15:09:21
* <p>
* Email 122741482@qq.com
* <p>
* Describe:
*/
@Component
public class ApplicationContextRegister implements ApplicationContextAware {
private static Logger logger = LoggerFactory.getLogger(ApplicationContextRegister.class);
private static ApplicationContext APPLICATION_CONTEXT;
/**
* 设置spring上下文
* @param applicationContext spring上下文
* @throws BeansException
* */
@Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
logger.debug("ApplicationContext registed-->{}", applicationContext);
APPLICATION_CONTEXT = applicationContext;
}
/**
* 获取容器
* @return
*/
public static ApplicationContext getApplicationContext() {
return APPLICATION_CONTEXT;
}
/**
* 获取容器对象
* @param type
* @param <T>
* @return
*/
public static <T> T getBean(Class<T> type) {
return APPLICATION_CONTEXT.getBean(type);
}
}

View File

@ -0,0 +1,32 @@
package com.java2nb.common.config;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.SessionListener;
public class BDSessionListener implements SessionListener {
private final AtomicInteger sessionCount = new AtomicInteger(0);
@Override
public void onStart(Session session) {
sessionCount.incrementAndGet();
}
@Override
public void onStop(Session session) {
sessionCount.decrementAndGet();
}
@Override
public void onExpiration(Session session) {
sessionCount.decrementAndGet();
}
public int getSessionCount() {
return sessionCount.get();
}
}

View File

@ -0,0 +1,24 @@
package com.java2nb.common.config;
public class Constant {
//演示系统账户
public static String DEMO_ACCOUNT = "test";
//自动去除表前缀
public static String AUTO_REOMVE_PRE = "true";
//停止计划任务
public static String STATUS_RUNNING_STOP = "stop";
//开启计划任务
public static String STATUS_RUNNING_START = "start";
//通知公告阅读状态-未读
public static String OA_NOTIFY_READ_NO = "0";
//通知公告阅读状态-已读
public static int OA_NOTIFY_READ_YES = 1;
//部门根节点id
public static Long DEPT_ROOT_ID = 0l;
//缓存方式
public static String CACHE_TYPE_REDIS ="redis";
public static String LOG_ERROR = "error";
}

View File

@ -0,0 +1,40 @@
package com.java2nb.common.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.zip.DataFormatException;
/**
* @author xiongxy
* @date 2019-09-25 15:09:21
*/
@Configuration
public class DateConverConfig {
@Bean
public Converter<String, Date> stringDateConvert() {
return new Converter<String, Date>() {
@Override
public Date convert(String source) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = null;
try {
date = sdf.parse((String) source);
} catch (Exception e) {
SimpleDateFormat sdfday = new SimpleDateFormat("yyyy-MM-dd");
try {
date = sdfday.parse((String) source);
} catch (ParseException e1) {
e1.printStackTrace();
}
}
return date;
}
};
}
}

View File

@ -0,0 +1,132 @@
package com.java2nb.common.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
import java.sql.SQLException;
/**
* Created by PrimaryKey on 17/2/4.
*/
@SuppressWarnings("AlibabaRemoveCommentedCode")
@Configuration
public class DruidDBConfig {
private Logger logger = LoggerFactory.getLogger(DruidDBConfig.class);
@Value("${spring.datasource.url}")
private String dbUrl;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.driverClassName}")
private String driverClassName;
@Value("${spring.datasource.initialSize}")
private int initialSize;
@Value("${spring.datasource.minIdle}")
private int minIdle;
@Value("${spring.datasource.maxActive}")
private int maxActive;
@Value("${spring.datasource.maxWait}")
private int maxWait;
@Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
private int timeBetweenEvictionRunsMillis;
@Value("${spring.datasource.minEvictableIdleTimeMillis}")
private int minEvictableIdleTimeMillis;
@Value("${spring.datasource.validationQuery}")
private String validationQuery;
@Value("${spring.datasource.testWhileIdle}")
private boolean testWhileIdle;
@Value("${spring.datasource.testOnBorrow}")
private boolean testOnBorrow;
@Value("${spring.datasource.testOnReturn}")
private boolean testOnReturn;
@Value("${spring.datasource.poolPreparedStatements}")
private boolean poolPreparedStatements;
@Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}")
private int maxPoolPreparedStatementPerConnectionSize;
@Value("${spring.datasource.filters}")
private String filters;
@Value("{spring.datasource.connectionProperties}")
private String connectionProperties;
@Bean(initMethod = "init", destroyMethod = "close") //声明其为Bean实例
@Primary //在同样的DataSource中首先使用被标注的DataSource
public DataSource dataSource() {
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(this.dbUrl);
datasource.setUsername(username);
datasource.setPassword(password);
datasource.setDriverClassName(driverClassName);
//configuration
datasource.setInitialSize(initialSize);
datasource.setMinIdle(minIdle);
datasource.setMaxActive(maxActive);
datasource.setMaxWait(maxWait);
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
datasource.setValidationQuery(validationQuery);
datasource.setTestWhileIdle(testWhileIdle);
datasource.setTestOnBorrow(testOnBorrow);
datasource.setTestOnReturn(testOnReturn);
datasource.setPoolPreparedStatements(poolPreparedStatements);
datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
try {
datasource.setFilters(filters);
} catch (SQLException e) {
logger.error("druid configuration initialization filter", e);
}
datasource.setConnectionProperties(connectionProperties);
return datasource;
}
@Bean
public ServletRegistrationBean druidServlet() {
ServletRegistrationBean reg = new ServletRegistrationBean();
reg.setServlet(new StatViewServlet());
reg.addUrlMappings("/druid/*");
reg.addInitParameter("allow", ""); //白名单
return reg;
}
@Bean public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
filterRegistrationBean.addInitParameter("profileEnable", "true");
filterRegistrationBean.addInitParameter("principalCookieName","USER_COOKIE");
filterRegistrationBean.addInitParameter("principalSessionName","USER_SESSION");
filterRegistrationBean.addInitParameter("DruidWebStatFilter","/*");
return filterRegistrationBean;
}
}

View File

@ -0,0 +1,39 @@
package com.java2nb.common.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix="java2nb")
public class JnConfig {
//上传路径
private String uploadPath;
private String username;
private String password;
public String getUploadPath() {
return uploadPath;
}
public void setUploadPath(String uploadPath) {
this.uploadPath = uploadPath;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}

View File

@ -0,0 +1,82 @@
package com.java2nb.common.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}

View File

@ -0,0 +1,13 @@
package com.java2nb.common.config;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
@EnableAutoConfiguration(exclude = {
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class
})
@Configuration
public class SecuityConfig {
}

View File

@ -0,0 +1,203 @@
package com.java2nb.common.config;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.java2nb.common.redis.shiro.RedisCacheManager;
import com.java2nb.common.redis.shiro.RedisManager;
import com.java2nb.common.redis.shiro.RedisSessionDAO;
import com.java2nb.system.shiro.UserRealm;
import net.sf.ehcache.CacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.SessionListener;
import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
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.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
/**
* @author xiongxy
*/
@Configuration
public class ShiroConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.timeout}")
private int timeout;
@Value("${spring.cache.type}")
private String cacheType ;
@Value("${server.session-timeout}")
private int tomcatTimeout;
@Bean
public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
/**
* ShiroDialect为了在thymeleaf里使用shiro的标签的bean
*
* @return
*/
@Bean
public ShiroDialect shiroDialect() {
return new ShiroDialect();
}
@Bean
ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setSuccessUrl("/index");
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/login","anon");
filterChainDefinitionMap.put("/getVerify","anon");
filterChainDefinitionMap.put("/css/**", "anon");
filterChainDefinitionMap.put("/js/**", "anon");
filterChainDefinitionMap.put("/fonts/**", "anon");
filterChainDefinitionMap.put("/img/**", "anon");
filterChainDefinitionMap.put("/docs/**", "anon");
filterChainDefinitionMap.put("/layuimini/**", "anon");
filterChainDefinitionMap.put("/druid/**", "anon");
filterChainDefinitionMap.put("/upload/**", "anon");
filterChainDefinitionMap.put("/files/**", "anon");
filterChainDefinitionMap.put("/logout", "logout");
filterChainDefinitionMap.put("/blog", "anon");
filterChainDefinitionMap.put("/blog/open/**", "anon");
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//设置realm.
securityManager.setRealm(userRealm());
// 自定义缓存实现 使用redis
if (Constant.CACHE_TYPE_REDIS.equals(cacheType)) {
securityManager.setCacheManager(rediscacheManager());
} else {
securityManager.setCacheManager(ehCacheManager());
}
securityManager.setSessionManager(sessionManager());
return securityManager;
}
@Bean
UserRealm userRealm() {
UserRealm userRealm = new UserRealm();
return userRealm;
}
/**
* 开启shiro aop注解支持.
* 使用代理方式;所以需要开启代码支持;
*
* @param securityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
/**
* 配置shiro redisManager
*
* @return
*/
@Bean
public RedisManager redisManager() {
RedisManager redisManager = new RedisManager();
redisManager.setHost(host);
redisManager.setPort(port);
redisManager.setExpire(1800);// 配置缓存过期时间
//redisManager.setTimeout(1800);
redisManager.setPassword(password);
return redisManager;
}
/**
* cacheManager 缓存 redis实现
* 使用的是shiro-redis开源插件
*
* @return
*/
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() {
if (Constant.CACHE_TYPE_REDIS.equals(cacheType)) {
return redisSessionDAO();
} else {
return new MemorySessionDAO();
}
}
/**
* shiro session的管理
*/
@Bean
public DefaultWebSessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setGlobalSessionTimeout(tomcatTimeout * 1000);
sessionManager.setSessionDAO(sessionDAO());
Collection<SessionListener> listeners = new ArrayList<SessionListener>();
listeners.add(new BDSessionListener());
sessionManager.setSessionListeners(listeners);
return sessionManager;
}
@Bean
public EhCacheManager ehCacheManager() {
EhCacheManager em = new EhCacheManager();
em.setCacheManager(cacheManager());
return em;
}
@Bean("cacheManager2")
CacheManager cacheManager(){
return CacheManager.create();
}
}

View File

@ -0,0 +1,23 @@
package com.java2nb.common.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Configuration
@EnableAsync
public class SpringAsyncConfig {
// @Bean
// public AsyncTaskExecutor taskExecutor() {
// ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// executor.setMaxPoolSize(10);
// return executor;
// }
}

View File

@ -0,0 +1,48 @@
package com.java2nb.common.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* ${DESCRIPTION}
*
* @author xiongxy
* @create 2019-11-02 23:53
*/
@EnableSwagger2
@Configuration
public class Swagger2Config {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
//为当前包路径
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
//构建 api文档的详细信息函数
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
//页面标题
.title("功能测试")
//创建人
.contact(new Contact("xiongxy", "1179705413@qq.com", "1179705413@qq.com"))
//版本号
.version("1.0")
//描述
.description("API 描述")
.build();
}
}

View File

@ -0,0 +1,17 @@
package com.java2nb.common.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Component
class WebConfigurer extends WebMvcConfigurerAdapter {
@Autowired
JnConfig jnConfig;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/files/**").addResourceLocations("file:///"+ jnConfig.getUploadPath());
}
}

View File

@ -0,0 +1,21 @@
package com.java2nb.common.controller;
import com.java2nb.system.domain.UserToken;
import org.springframework.stereotype.Controller;
import com.java2nb.common.utils.ShiroUtils;
import com.java2nb.system.domain.UserDO;
@Controller
public class BaseController {
public UserDO getUser() {
return ShiroUtils.getUser();
}
public Long getUserId() {
return getUser().getUserId();
}
public String getUsername() {
return getUser().getUsername();
}
}

View File

@ -0,0 +1,148 @@
package com.java2nb.common.controller;
import com.java2nb.common.config.Constant;
import com.java2nb.common.domain.DictDO;
import com.java2nb.common.service.DictService;
import com.java2nb.common.utils.PageBean;
import com.java2nb.common.utils.Query;
import com.java2nb.common.utils.R;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 字典表
* @author xiongxy
* @email 1179705413@qq.com
* @date 2019-09-29 18:28:07
*/
@Controller
@RequestMapping("/common/dict")
public class DictController extends BaseController {
@Autowired
private DictService dictService;
@GetMapping()
@RequiresPermissions("common:dict:dict")
String dict() {
return "common/dict/dict";
}
@ResponseBody
@GetMapping("/list")
@RequiresPermissions("common:dict:dict")
public PageBean list(@RequestParam Map<String, Object> params) {
// 查询列表数据
Query query = new Query(params);
List<DictDO> dictList = dictService.list(query);
int total = dictService.count(query);
PageBean pageBean = new PageBean(dictList, total);
return pageBean;
}
@GetMapping("/add")
@RequiresPermissions("common:dict:add")
String add() {
return "common/dict/add";
}
@GetMapping("/edit/{id}")
@RequiresPermissions("common:dict:edit")
String edit(@PathVariable("id") Long id, Model model) {
DictDO dict = dictService.get(id);
model.addAttribute("dict", dict);
return "common/dict/edit";
}
/**
* 保存
*/
@ResponseBody
@PostMapping("/save")
@RequiresPermissions("common:dict:add")
public R save(DictDO dict) {
if (Constant.DEMO_ACCOUNT.equals(getUsername())) {
return R.error(1, "演示系统不允许修改,完整体验请部署程序");
}
if (dictService.save(dict) > 0) {
return R.ok();
}
return R.error();
}
/**
* 修改
*/
@ResponseBody
@RequestMapping("/update")
@RequiresPermissions("common:dict:edit")
public R update(DictDO dict) {
if (Constant.DEMO_ACCOUNT.equals(getUsername())) {
return R.error(1, "演示系统不允许修改,完整体验请部署程序");
}
dictService.update(dict);
return R.ok();
}
/**
* 删除
*/
@PostMapping("/remove")
@ResponseBody
@RequiresPermissions("common:dict:remove")
public R remove(Long id) {
if (Constant.DEMO_ACCOUNT.equals(getUsername())) {
return R.error(1, "演示系统不允许修改,完整体验请部署程序");
}
if (dictService.remove(id) > 0) {
return R.ok();
}
return R.error();
}
/**
* 删除
*/
@PostMapping("/batchRemove")
@ResponseBody
@RequiresPermissions("common:dict:batchRemove")
public R remove(@RequestParam("ids[]") Long[] ids) {
if (Constant.DEMO_ACCOUNT.equals(getUsername())) {
return R.error(1, "演示系统不允许修改,完整体验请部署程序");
}
dictService.batchRemove(ids);
return R.ok();
}
@GetMapping("/type")
@ResponseBody
public List<DictDO> listType() {
return dictService.listType();
};
// 类别已经指定增加
@GetMapping("/add/{type}/{description}")
@RequiresPermissions("common:dict:add")
String addD(Model model, @PathVariable("type") String type, @PathVariable("description") String description) {
model.addAttribute("type", type);
model.addAttribute("description", description);
return "common/dict/add";
}
@ResponseBody
@GetMapping("/list/{type}")
public List<DictDO> listByType(@PathVariable("type") String type) {
// 查询列表数据
Map<String, Object> map = new HashMap<>(16);
map.put("type", type);
List<DictDO> dictList = dictService.list(map);
return dictList;
}
}

View File

@ -0,0 +1,196 @@
package com.java2nb.common.controller;
import com.java2nb.common.config.JnConfig;
import com.java2nb.common.domain.FileDO;
import com.java2nb.common.service.FileService;
import com.java2nb.common.utils.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 文件上传
*
* @author xiongxy
* @email 1179705413@qq.com
* @date 2019-09-19 16:02:20
*/
@Controller
@RequestMapping("/common/sysFile")
public class FileController extends BaseController {
@Autowired
private FileService sysFileService;
@Autowired
private JnConfig jnConfig;
@GetMapping()
@RequiresPermissions("common:sysFile:sysFile")
String sysFile(Model model) {
Map<String, Object> params = new HashMap<>(16);
return "common/file/file";
}
@ResponseBody
@GetMapping("/list")
@RequiresPermissions("common:sysFile:sysFile")
public PageBean list(@RequestParam Map<String, Object> params) {
// 查询列表数据
Query query = new Query(params);
List<FileDO> sysFileList = sysFileService.list(query);
int total = sysFileService.count(query);
PageBean pageBean = new PageBean(sysFileList, total);
return pageBean;
}
@GetMapping("/add")
// @RequiresPermissions("common:bComments")
String add() {
return "common/sysFile/add";
}
@GetMapping("/edit")
// @RequiresPermissions("common:bComments")
String edit(Long id, Model model) {
FileDO sysFile = sysFileService.get(id);
model.addAttribute("sysFile", sysFile);
return "common/sysFile/edit";
}
/**
* 信息
*/
@RequestMapping("/info/{id}")
@RequiresPermissions("common:info")
public R info(@PathVariable("id") Long id) {
FileDO sysFile = sysFileService.get(id);
return R.ok().put("sysFile", sysFile);
}
/**
* 保存
*/
@ResponseBody
@PostMapping("/save")
@RequiresPermissions("common:save")
public R save(FileDO sysFile) {
if (sysFileService.save(sysFile) > 0) {
return R.ok();
}
return R.error();
}
/**
* 修改
*/
@RequestMapping("/update")
@RequiresPermissions("common:update")
public R update(@RequestBody FileDO sysFile) {
sysFileService.update(sysFile);
return R.ok();
}
/**
* 删除
*/
@PostMapping("/remove")
@ResponseBody
// @RequiresPermissions("common:remove")
public R remove(Long id, HttpServletRequest request) {
if ("test".equals(getUsername())) {
return R.error(1, "演示系统不允许修改,完整体验请部署程序");
}
String fileName = jnConfig.getUploadPath() + sysFileService.get(id).getUrl().replace("/files/", "");
if (sysFileService.remove(id) > 0) {
boolean b = FileUtil.deleteFile(fileName);
if (!b) {
return R.error("数据库记录删除成功,文件删除失败");
}
return R.ok();
} else {
return R.error();
}
}
/**
* 删除
*/
@PostMapping("/batchRemove")
@ResponseBody
@RequiresPermissions("common:remove")
public R remove(@RequestParam("ids[]") Long[] ids) {
if ("test".equals(getUsername())) {
return R.error(1, "演示系统不允许修改,完整体验请部署程序");
}
sysFileService.batchRemove(ids);
return R.ok();
}
@ResponseBody
@PostMapping("/upload")
R upload(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
if ("test".equals(getUsername())) {
return R.error(1, "演示系统不允许修改,完整体验请部署程序");
}
Date date = new Date();
String year = DateUtils.format(date,DateUtils.YEAR_PATTERN);
String month = DateUtils.format(date,DateUtils.MONTH_PATTERN);
String day = DateUtils.format(date,DateUtils.DAY_PATTERN);
String fileName = file.getOriginalFilename();
String fileDir = year+"/"+month+"/"+day + "/";
fileName = FileUtil.renameToUUID(fileName);
FileDO sysFile = new FileDO(FileType.fileType(fileName), "/files/" + fileDir + fileName, date);
try {
FileUtil.uploadFile(file.getBytes(), jnConfig.getUploadPath()+fileDir, fileName);
} catch (Exception e) {
return R.error();
}
if (sysFileService.save(sysFile) > 0) {
return R.ok().put("fileName",sysFile.getUrl());
}
return R.error();
}
/**
* 文件下载
*/
@RequestMapping(value = "/download")
public void fileDownload(String filePath,String fileName, HttpServletResponse resp) throws Exception {
String realFilePath = jnConfig.getUploadPath() + filePath;
InputStream in = new FileInputStream(realFilePath);
//设置响应头对文件进行url编码
fileName = URLEncoder.encode(fileName, "UTF-8");
resp.setHeader("Content-Disposition", "attachment;filename=" + fileName);
resp.setContentLength(in.available());
OutputStream out = resp.getOutputStream();
byte[] b = new byte[1024];
int len = 0;
while ((len = in.read(b)) != -1) {
out.write(b, 0, len);
}
out.flush();
out.close();
in.close();
}
}

View File

@ -0,0 +1,157 @@
package com.java2nb.common.controller;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.java2nb.common.domain.GenColumnsDO;
import com.java2nb.common.service.GeneratorService;
import com.java2nb.common.utils.GenUtils;
import com.java2nb.common.utils.PageBean;
import com.java2nb.common.utils.R;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RequestMapping("/common/generator")
@Controller
public class GeneratorController {
String prefix = "common/generator";
@Autowired
GeneratorService generatorService;
@Autowired
private ObjectMapper objectMapper;
@GetMapping()
String generator() {
return prefix + "/list";
}
@ResponseBody
@GetMapping("/list")
List<Map<String, Object>> list(String tableName) {
List<Map<String, Object>> list = generatorService.list(tableName);
return list;
}
;
@RequestMapping("/downLoadCode/{tableName}")
public void downLoadCode(HttpServletRequest request, HttpServletResponse response,
@PathVariable("tableName") String tableName) throws IOException {
String[] tableNames = new String[]{tableName};
byte[] data = generatorService.downloadCode(tableNames);
response.reset();
response.setHeader("Content-Disposition", "attachment; filename=\"java2nb.zip\"");
response.addHeader("Content-Length", "" + data.length);
response.setContentType("application/octet-stream; charset=UTF-8");
IOUtils.write(data, response.getOutputStream());
}
@ResponseBody
@PostMapping("/genCode")
public R genCode(String tableName) {
String[] tableNames = new String[]{tableName};
generatorService.generatorCode(tableNames);
return R.ok("代码生成成功,请到本地项目中查看!");
}
@RequestMapping("/batchDownload")
public void batchDownload(HttpServletRequest request, HttpServletResponse response, String tables) throws IOException {
String[] tableNames = new String[]{};
tableNames = JSON.parseArray(tables).toArray(tableNames);
byte[] data = generatorService.downloadCode(tableNames);
response.reset();
response.setHeader("Content-Disposition", "attachment; filename=\"java2nb.zip\"");
response.addHeader("Content-Length", "" + data.length);
response.setContentType("application/octet-stream; charset=UTF-8");
IOUtils.write(data, response.getOutputStream());
}
@ResponseBody
@PostMapping("/batchCode")
public R batchCode(String tables) {
String[] tableNames = new String[]{};
tableNames = JSON.parseArray(tables).toArray(tableNames);
generatorService.generatorCode(tableNames);
return R.ok("代码批量生成成功,请到本地项目中查看!");
}
@GetMapping("/edit")
public String edit(Model model) {
Configuration conf = GenUtils.getConfig();
Map<String, Object> property = new HashMap<>(16);
property.put("author", conf.getProperty("author"));
property.put("email", conf.getProperty("email"));
property.put("package", conf.getProperty("package"));
property.put("autoRemovePre", conf.getProperty("autoRemovePre"));
property.put("tablePrefix", conf.getProperty("tablePrefix"));
property.put("srcPath", conf.getProperty("srcPath"));
model.addAttribute("property", property);
return prefix + "/edit";
}
@ResponseBody
@PostMapping("/update")
R update(@RequestParam Map<String, Object> map) {
try {
PropertiesConfiguration conf = new PropertiesConfiguration("generator.properties");
conf.setProperty("author", map.get("author"));
conf.setProperty("email", map.get("email"));
conf.setProperty("package", map.get("package"));
conf.setProperty("autoRemovePre", map.get("autoRemovePre"));
conf.setProperty("tablePrefix", map.get("tablePrefix"));
conf.setProperty("srcPath", map.get("srcPath"));
conf.save();
} catch (ConfigurationException e) {
return R.error("保存配置文件出错");
}
return R.ok();
}
@GetMapping("/genColumns")
String genColumns(String tableName, Model model) {
model.addAttribute("tableName", tableName);
return "common/genColumns/genColumns";
}
@ResponseBody
@GetMapping("/genColumns/list")
@SneakyThrows
public R genColumnsList(String tableName) {
List<GenColumnsDO> genColumns = generatorService.listColumnsByTableName(tableName);
int total = genColumns.size();
PageBean pageBean = new PageBean(genColumns, total);
return R.ok().put("data", pageBean);
}
/**
* 保存
*/
@ApiOperation(value = "新增", notes = "新增")
@ResponseBody
@PostMapping("/genColumns/save")
public R save(@RequestBody List<GenColumnsDO> list) {
generatorService.genColumnsSave(list);
return R.ok();
}
}

View File

@ -0,0 +1,57 @@
package com.java2nb.common.controller;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.java2nb.common.domain.LogDO;
import com.java2nb.common.domain.PageDO;
import com.java2nb.common.service.LogService;
import com.java2nb.common.utils.Query;
import com.java2nb.common.utils.R;
@RequestMapping("/common/log")
@Controller
public class LogController {
@Autowired
LogService logService;
String prefix = "common/log";
@GetMapping()
String log() {
return prefix + "/log";
}
@ResponseBody
@GetMapping("/list")
PageDO<LogDO> list(@RequestParam Map<String, Object> params) {
Query query = new Query(params);
PageDO<LogDO> page = logService.queryList(query);
return page;
}
@ResponseBody
@PostMapping("/remove")
R remove(Long id) {
if (logService.remove(id)>0) {
return R.ok();
}
return R.error();
}
@ResponseBody
@PostMapping("/batchRemove")
R batchRemove(@RequestParam("ids[]") Long[] ids) {
int r = logService.batchRemove(ids);
if (r > 0) {
return R.ok();
}
return R.error();
}
}

View File

@ -0,0 +1,35 @@
package com.java2nb.common.dao;
import com.java2nb.common.domain.DictDO;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Mapper;
/**
* 字典表
*
* @author xiongxy
* @email 1179705413@qq.com
* @date 2019-10-03 15:45:42
*/
@Mapper
public interface DictDao {
DictDO get(Long id);
List<DictDO> list(Map<String, Object> map);
int count(Map<String, Object> map);
int save(DictDO dict);
int update(DictDO dict);
int remove(Long id);
int batchRemove(Long[] ids);
List<DictDO> listType();
}

View File

@ -0,0 +1,32 @@
package com.java2nb.common.dao;
import com.java2nb.common.domain.FileDO;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Mapper;
/**
* 文件上传
* @author xiongxy
* @email 1179705413@qq.com
* @date 2019-10-03 15:45:42
*/
@Mapper
public interface FileDao {
FileDO get(Long id);
List<FileDO> list(Map<String,Object> map);
int count(Map<String,Object> map);
int save(FileDO file);
int update(FileDO file);
int remove(Long id);
int batchRemove(Long[] ids);
}

View File

@ -0,0 +1,38 @@
package com.java2nb.common.dao;
import java.util.List;
import java.util.Map;
import com.java2nb.common.domain.GenColumnsDO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
*
* @author xiongxy
* @email 1179705413@qq.com
* @date 2019-11-22 10:39:29
*/
@Mapper
public interface GenColumnsDao {
GenColumnsDO get(Long id);
List<GenColumnsDO> list(Map<String,Object> map);
int count(Map<String,Object> map);
int save(GenColumnsDO genColumns);
int update(GenColumnsDO genColumns);
int remove(Long id);
int batchRemove(Long[] ids);
void saveBatch(List<GenColumnsDO> list);
void deleteByTableName(@Param("tableName") String tableName);
}

View File

@ -0,0 +1,28 @@
package com.java2nb.common.dao;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
public interface GeneratorMapper {
@Select("select table_name tableName, engine, table_comment tableComment, create_time createTime from information_schema.tables"
+ " where table_schema = (select database()) and table_name like concat('%',#{tableName},'%')")
List<Map<String, Object>> list(@Param("tableName") String tableName);
@Select("select count(*) from information_schema.tables where table_schema = (select database())")
int count(Map<String, Object> map);
@Select("select table_name tableName, engine, table_comment tableComment, create_time createTime from information_schema.tables \r\n"
+ " where table_schema = (select database()) and table_name = #{tableName}")
Map<String, String> get(String tableName);
@Select("select column_name columnName, data_type dataType, column_comment columnComment, column_key columnKey, extra from information_schema.columns\r\n"
+ " where table_name = #{tableName} and table_schema = (select database()) order by ordinal_position")
List<Map<String, String>> listColumns(String tableName);
@Select("select column_name columnName, data_type dataType, column_comment columnComment, column_key columnKey, extra from information_schema.columns\r\n"
+ " where table_name = #{tableName} and table_schema = (select database()) and column_key = 'PRI' limit 1")
Map<String, String> getPriColumn(String tableName);
}

View File

@ -0,0 +1,32 @@
package com.java2nb.common.dao;
import com.java2nb.common.domain.LogDO;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Mapper;
/**
* 系统日志
* @author xiongxy
* @email 1179705413@qq.com
* @date 2019-10-03 15:45:42
*/
@Mapper
public interface LogDao {
LogDO get(Long id);
List<LogDO> list(Map<String,Object> map);
int count(Map<String,Object> map);
int save(LogDO log);
int update(LogDO log);
int remove(Long id);
int batchRemove(Long[] ids);
}

View File

@ -0,0 +1,93 @@
package com.java2nb.common.domain;
/**
* 列的属性
*
*
*/
public class ColumnDO {
// 列名
private String columnName;
// 列名类型
private String dataType;
// 列名备注
private String comments;
// 属性名称(第一个字母大写)user_name => UserName
private String attrName;
// 属性名称(第一个字母小写)user_name => userName
private String attrname;
// 属性类型
private String attrType;
// auto_increment
private String extra;
public String getColumnName() {
return columnName;
}
public void setColumnName(String columnName) {
this.columnName = columnName;
}
public String getDataType() {
return dataType;
}
public void setDataType(String dataType) {
this.dataType = dataType;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
public String getAttrname() {
return attrname;
}
public void setAttrname(String attrname) {
this.attrname = attrname;
}
public String getAttrName() {
return attrName;
}
public void setAttrName(String attrName) {
this.attrName = attrName;
}
public String getAttrType() {
return attrType;
}
public void setAttrType(String attrType) {
this.attrType = attrType;
}
public String getExtra() {
return extra;
}
public void setExtra(String extra) {
this.extra = extra;
}
@Override
public String toString() {
return "ColumnDO{" +
"columnName='" + columnName + '\'' +
", dataType='" + dataType + '\'' +
", comments='" + comments + '\'' +
", attrName='" + attrName + '\'' +
", attrname='" + attrname + '\'' +
", attrType='" + attrType + '\'' +
", extra='" + extra + '\'' +
'}';
}
}

View File

@ -0,0 +1,221 @@
package com.java2nb.common.domain;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* 字典表
*
* @author xiongxy
* @email 1179705413@qq.com
* @date 2019-09-29 18:28:07
*/
public class DictDO implements Serializable {
private static final long serialVersionUID = 1L;
//编号
private Long id;
//标签名
private String name;
//数据值
private String value;
//类型
private String type;
//描述
private String description;
//排序(升序)
private BigDecimal sort;
//父级编号
private Long parentId;
//创建者
private Integer createBy;
//创建时间
private Date createDate;
//更新者
private Long updateBy;
//更新时间
private Date updateDate;
//备注信息
private String remarks;
//删除标记
private String delFlag;
/**
* 设置:编号
*/
public void setId(Long id) {
this.id = id;
}
/**
* 获取:编号
*/
public Long getId() {
return id;
}
/**
* 设置:标签名
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取:标签名
*/
public String getName() {
return name;
}
/**
* 设置:数据值
*/
public void setValue(String value) {
this.value = value;
}
/**
* 获取:数据值
*/
public String getValue() {
return value;
}
/**
* 设置:类型
*/
public void setType(String type) {
this.type = type;
}
/**
* 获取:类型
*/
public String getType() {
return type;
}
/**
* 设置:描述
*/
public void setDescription(String description) {
this.description = description;
}
/**
* 获取:描述
*/
public String getDescription() {
return description;
}
/**
* 设置:排序(升序)
*/
public void setSort(BigDecimal sort) {
this.sort = sort;
}
/**
* 获取:排序(升序)
*/
public BigDecimal getSort() {
return sort;
}
/**
* 设置:父级编号
*/
public void setParentId(Long parentId) {
this.parentId = parentId;
}
/**
* 获取:父级编号
*/
public Long getParentId() {
return parentId;
}
/**
* 设置:创建者
*/
public void setCreateBy(Integer createBy) {
this.createBy = createBy;
}
/**
* 获取:创建者
*/
public Integer getCreateBy() {
return createBy;
}
/**
* 设置:创建时间
*/
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
/**
* 获取:创建时间
*/
public Date getCreateDate() {
return createDate;
}
/**
* 设置:更新者
*/
public void setUpdateBy(Long updateBy) {
this.updateBy = updateBy;
}
/**
* 获取:更新者
*/
public Long getUpdateBy() {
return updateBy;
}
/**
* 设置:更新时间
*/
public void setUpdateDate(Date updateDate) {
this.updateDate = updateDate;
}
/**
* 获取:更新时间
*/
public Date getUpdateDate() {
return updateDate;
}
/**
* 设置:备注信息
*/
public void setRemarks(String remarks) {
this.remarks = remarks;
}
/**
* 获取:备注信息
*/
public String getRemarks() {
return remarks;
}
/**
* 设置:删除标记
*/
public void setDelFlag(String delFlag) {
this.delFlag = delFlag;
}
/**
* 获取:删除标记
*/
public String getDelFlag() {
return delFlag;
}
@Override
public String toString() {
return "DictDO{" +
"id=" + id +
", name='" + name + '\'' +
", value='" + value + '\'' +
", type='" + type + '\'' +
", description='" + description + '\'' +
", sort=" + sort +
", parentId=" + parentId +
", createBy=" + createBy +
", createDate=" + createDate +
", updateBy=" + updateBy +
", updateDate=" + updateDate +
", remarks='" + remarks + '\'' +
", delFlag='" + delFlag + '\'' +
'}';
}
}

View File

@ -0,0 +1,104 @@
package com.java2nb.common.domain;
import java.io.Serializable;
import java.util.Date;
/**
* 文件上传
*
* @author xiongxy
* @email 1179705413@qq.com
* @date 2019-09-19 16:02:20
*/
public class FileDO implements Serializable {
private static final long serialVersionUID = 1L;
//
private Long id;
// 文件类型
private Integer type;
// URL地址
private String url;
// 创建时间
private Date createDate;
public FileDO() {
super();
}
public FileDO(Integer type, String url, Date createDate) {
super();
this.type = type;
this.url = url;
this.createDate = createDate;
}
/**
* 设置:
*/
public void setId(Long id) {
this.id = id;
}
/**
* 获取:
*/
public Long getId() {
return id;
}
/**
* 设置:文件类型
*/
public void setType(Integer type) {
this.type = type;
}
/**
* 获取:文件类型
*/
public Integer getType() {
return type;
}
/**
* 设置URL地址
*/
public void setUrl(String url) {
this.url = url;
}
/**
* 获取URL地址
*/
public String getUrl() {
return url;
}
/**
* 设置:创建时间
*/
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
/**
* 获取:创建时间
*/
public Date getCreateDate() {
return createDate;
}
@Override
public String toString() {
return "FileDO{" +
"id=" + id +
", type=" + type +
", url='" + url + '\'' +
", createDate=" + createDate +
'}';
}
}

View File

@ -0,0 +1,163 @@
package com.java2nb.common.domain;
import java.io.Serializable;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.java2nb.common.jsonserializer.LongToStringSerializer;
import lombok.Data;
/**
* @author xiongxy
* @email 1179705413@qq.com
* @date 2019-11-22 18:03:46
*/
public class GenColumnsDO implements Serializable {
private static final long serialVersionUID = 1L;
//主键
//java中的long能表示的范围比js中number大,也就意味着部分数值在js中存不下(变成不准确的值)
//所以通过序列化成字符串来解决
@JsonSerialize(using = LongToStringSerializer.class)
private Long id;
//表名
private String tableName;
//列名
private String columnName;
//列类型
private String columnType;
//映射java类型
private String javaType;
//列注释
private String columnComment;
//列排序(升序)
private Integer columnSort;
//列标签名
private String columnLabel;
//页面显示类型1、文本框 2、下拉框 3、数值4、日期 5、文本域6、富文本 7、上传图片【单文件】 8、上传图片【多文件】9、上传文件【单文件】 10、上传文件【多文件】11、隐藏域 12、不显示
private Integer pageType;
//是否必填
private Integer isRequired;
//页面显示为下拉时使用,字典类型从字典表中取出
private String dictType;
// 属性名称(第一个字母大写)user_name => UserName
private String attrName;
// 属性名称(第一个字母小写)user_name => userName
private String attrname;
private String extra;
public String getExtra() {
return extra;
}
public void setExtra(String extra) {
this.extra = extra;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public String getColumnName() {
return columnName;
}
public void setColumnName(String columnName) {
this.columnName = columnName;
}
public String getColumnType() {
return columnType;
}
public void setColumnType(String columnType) {
this.columnType = columnType;
}
public String getJavaType() {
return javaType;
}
public void setJavaType(String javaType) {
this.javaType = javaType;
}
public String getColumnComment() {
return columnComment;
}
public void setColumnComment(String columnComment) {
this.columnComment = columnComment;
}
public Integer getColumnSort() {
return columnSort;
}
public void setColumnSort(Integer columnSort) {
this.columnSort = columnSort;
}
public String getColumnLabel() {
return columnLabel;
}
public void setColumnLabel(String columnLabel) {
this.columnLabel = columnLabel;
}
public Integer getPageType() {
return pageType;
}
public void setPageType(Integer pageType) {
this.pageType = pageType;
}
public Integer getIsRequired() {
return isRequired;
}
public void setIsRequired(Integer isRequired) {
this.isRequired = isRequired;
}
public String getDictType() {
return dictType;
}
public void setDictType(String dictType) {
this.dictType = dictType;
}
public String getAttrName() {
return attrName;
}
public void setAttrName(String attrName) {
this.attrName = attrName;
}
public String getAttrname() {
return attrname;
}
public void setAttrname(String attrname) {
this.attrname = attrname;
}
}

View File

@ -0,0 +1,112 @@
package com.java2nb.common.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.util.Date;
public class LogDO {
private Long id;
private Long userId;
private String username;
private String operation;
private Integer time;
private String method;
private String params;
private String ip;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private Date gmtCreate;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username == null ? null : username.trim();
}
public String getOperation() {
return operation;
}
public void setOperation(String operation) {
this.operation = operation == null ? null : operation.trim();
}
public Integer getTime() {
return time;
}
public void setTime(Integer time) {
this.time = time;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method == null ? null : method.trim();
}
public String getParams() {
return params;
}
public void setParams(String params) {
this.params = params == null ? null : params.trim();
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip == null ? null : ip.trim();
}
public Date getGmtCreate() {
return gmtCreate;
}
public void setGmtCreate(Date gmtCreate) {
this.gmtCreate = gmtCreate;
}
@Override
public String toString() {
return "LogDO{" +
"id=" + id +
", userId=" + userId +
", username='" + username + '\'' +
", operation='" + operation + '\'' +
", time=" + time +
", method='" + method + '\'' +
", params='" + params + '\'' +
", ip='" + ip + '\'' +
", gmtCreate=" + gmtCreate +
'}';
}
}

View File

@ -0,0 +1,86 @@
package com.java2nb.common.domain;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class PageDO<T> {
private int offset;
private int limit;
private int total;
private Map<String, Object> params;
private String param;
private List<T> rows;
public PageDO() {
super();
this.offset = 0;
this.limit = 10;
this.total = 1;
this.params = new HashMap<>();
this.param = "";
this.rows = new ArrayList<>();
}
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset;
}
public int getLimit() {
return limit;
}
public void setLimit(int limit) {
this.limit = limit;
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public Map<String, Object> getParams() {
return params;
}
public void setParams(Map<String, Object> params) {
this.params = params;
}
public List<T> getRows() {
return rows;
}
public void setRows(List<T> rows) {
this.rows = rows;
}
public String getParam() {
return param;
}
public void setParam(String param) {
this.param = param;
}
@Override
public String toString() {
return "PageDO{" +
"offset=" + offset +
", limit=" + limit +
", total=" + total +
", params=" + params +
", param='" + param + '\'' +
", rows=" + rows +
'}';
}
}

View File

@ -0,0 +1,88 @@
package com.java2nb.common.domain;
import lombok.Data;
import java.util.List;
/**
* 表数据
*
* @author chenshun
* @email 1179705413@qq.com
* @date 2019-09-25 15:09:21
*/
public class TableDO {
//表的名称
private String tableName;
//表的备注
private String comments;
//表的主键
private GenColumnsDO pk;
//表的列名(不包含主键)
private List<GenColumnsDO> columns;
//类名(第一个字母大写)sys_user => SysUser
private String className;
//类名(第一个字母小写)sys_user => sysUser
private String classname;
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
public GenColumnsDO getPk() {
return pk;
}
public void setPk(GenColumnsDO pk) {
this.pk = pk;
}
public List<GenColumnsDO> getColumns() {
return columns;
}
public void setColumns(List<GenColumnsDO> columns) {
this.columns = columns;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getClassname() {
return classname;
}
public void setClassname(String classname) {
this.classname = classname;
}
@Override
public String toString() {
return "TableDO{" +
"tableName='" + tableName + '\'' +
", comments='" + comments + '\'' +
", pk=" + pk +
", columns=" + columns +
", className='" + className + '\'' +
", classname='" + classname + '\'' +
'}';
}
}

View File

@ -0,0 +1,151 @@
package com.java2nb.common.domain;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.alibaba.fastjson.JSON;
/**
* tree TODO <br>
*
* @author xiongxy
*
*/
public class Tree<T> {
/**
* 节点ID
*/
private String id;
/**
* 显示节点文本
*/
private String text;
/**
* 节点状态open closed
*/
private Map<String, Object> state;
/**
* 节点是否被选中 true false
*/
private boolean checked = false;
/**
* 节点属性
*/
private Map<String, Object> attributes;
/**
* 节点的子节点
*/
private List<Tree<T>> children = new ArrayList<Tree<T>>();
/**
* 父ID
*/
private String parentId;
/**
* 是否有父节点
*/
private boolean hasParent = false;
/**
* 是否有子节点
*/
private boolean hasChildren = false;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public Map<String, Object> getState() {
return state;
}
public void setState(Map<String, Object> state) {
this.state = state;
}
public boolean isChecked() {
return checked;
}
public void setChecked(boolean checked) {
this.checked = checked;
}
public Map<String, Object> getAttributes() {
return attributes;
}
public void setAttributes(Map<String, Object> attributes) {
this.attributes = attributes;
}
public List<Tree<T>> getChildren() {
return children;
}
public void setChildren(List<Tree<T>> children) {
this.children = children;
}
public boolean isHasParent() {
return hasParent;
}
public void setHasParent(boolean isParent) {
this.hasParent = isParent;
}
public boolean isHasChildren() {
return hasChildren;
}
public void setChildren(boolean isChildren) {
this.hasChildren = isChildren;
}
public String getParentId() {
return parentId;
}
public void setParentId(String parentId) {
this.parentId = parentId;
}
public Tree(String id, String text, Map<String, Object> state, boolean checked, Map<String, Object> attributes,
List<Tree<T>> children, boolean isParent, boolean isChildren, String parentID) {
super();
this.id = id;
this.text = text;
this.state = state;
this.checked = checked;
this.attributes = attributes;
this.children = children;
this.hasParent = isParent;
this.hasChildren = isChildren;
this.parentId = parentID;
}
public Tree() {
super();
}
@Override
public String toString() {
return JSON.toJSONString(this);
}
}

View File

@ -0,0 +1,25 @@
package com.java2nb.common.exception;
import lombok.Data;
/**
* 自定义业务异常
*/
@Data
public class BusinessException extends RuntimeException {
private static final long serialVersionUID = 1L;
private String msg;
private int code;
public BusinessException(int code,String msg) {
//不调用父类Throwable的fillInStackTrace()方法生成栈追踪信息,提高应用性能
//构造器之间的调用必须在第一行
super(msg, null, false, false);
this.code = code;
this.msg = msg;
}
}

View File

@ -0,0 +1,81 @@
package com.java2nb.common.exception;
import com.java2nb.common.config.Constant;
import com.java2nb.common.domain.LogDO;
import com.java2nb.common.service.LogService;
import com.java2nb.common.utils.HttpServletUtils;
import com.java2nb.common.utils.R;
import com.java2nb.common.utils.ShiroUtils;
import com.java2nb.system.domain.UserDO;
import org.apache.shiro.authz.AuthorizationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
/**
* 异常处理器
*/
@RestControllerAdvice
public class CommonExceptionHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
LogService logService;
/**
* 自定义业务异常处理
*/
@ExceptionHandler(BusinessException.class)
public R handleBusinessException(BusinessException e) {
logger.error(e.getMessage(), e);
return R.error(e.getCode(),e.getMessage());
}
@ExceptionHandler(DuplicateKeyException.class)
public R handleDuplicateKeyException(DuplicateKeyException e) {
logger.error(e.getMessage(), e);
return R.error("数据库中已存在该记录");
}
@ExceptionHandler(org.springframework.web.servlet.NoHandlerFoundException.class)
public R noHandlerFoundException(org.springframework.web.servlet.NoHandlerFoundException e) {
logger.error(e.getMessage(), e);
return R.error(404, "没找找到页面");
}
@ExceptionHandler(AuthorizationException.class)
public Object handleAuthorizationException(AuthorizationException e, HttpServletRequest request) {
logger.error(e.getMessage(), e);
if (HttpServletUtils.jsAjax(request)) {
return R.error(403, "未授权");
}
return new ModelAndView("error/403");
}
@ExceptionHandler({Exception.class})
public Object handleException(Exception e, HttpServletRequest request) {
LogDO logDO = new LogDO();
logDO.setGmtCreate(new Date());
logDO.setOperation(Constant.LOG_ERROR);
logDO.setMethod(request.getRequestURL().toString());
logDO.setParams(e.toString());
UserDO current = ShiroUtils.getUser();
if(null!=current){
logDO.setUserId(current.getUserId());
logDO.setUsername(current.getUsername());
}
logService.save(logDO);
logger.error(e.getMessage(), e);
if (HttpServletUtils.jsAjax(request)) {
return R.error(500, "服务器错误,请联系管理员");
}
return new ModelAndView("error/500");
}
}

View File

@ -0,0 +1,66 @@
package com.java2nb.common.exception;
import com.java2nb.common.utils.R;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
@RestController
public class MainsiteErrorController implements ErrorController {
private Logger logger = LoggerFactory.getLogger(getClass());
private static final String ERROR_PATH = "/error";
@Autowired
ErrorAttributes errorAttributes;
@RequestMapping(
value = {ERROR_PATH},
produces = {"text/html"}
)
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
int code = response.getStatus();
if (404 == code) {
return new ModelAndView("error/404");
} else if (403 == code) {
return new ModelAndView("error/403");
} else if (401 == code) {
return new ModelAndView("login");
} else {
return new ModelAndView("error/500");
}
}
@RequestMapping(value = ERROR_PATH)
public R handleError(HttpServletRequest request, HttpServletResponse response) {
response.setStatus(200);
int code = response.getStatus();
if (404 == code) {
return R.error(404, "未找到资源");
} else if (403 == code) {
return R.error(403, "没有访问权限");
} else if (401 == code) {
return R.error(403, "登录过期");
} else {
return R.error(500, "服务器错误");
}
}
@Override
public String getErrorPath() {
// TODO Auto-generated method stub
return ERROR_PATH;
}
}

View File

@ -0,0 +1,155 @@
package com.java2nb.common.interceptor;
import com.java2nb.common.utils.ShiroUtils;
import com.java2nb.system.domain.DataPermDO;
import com.java2nb.system.domain.UserDO;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Intercepts({@Signature(
type = Executor.class,
method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
), @Signature(
type = Executor.class,
method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}
)})
@Component
public class DataPermInterceptor implements Interceptor {
public DataPermInterceptor() {
super();
}
//插件运行的代码,它将代替原有的方法
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object[] args = invocation.getArgs();
MappedStatement mappedStatement = (MappedStatement) args[0];
String sqlId = mappedStatement.getId();
String methodName = sqlId.substring(sqlId.lastIndexOf(".") + 1);
if (methodName.endsWith("ByPerm")) {
Object parameter = args[1];
RowBounds rowBounds = (RowBounds) args[2];
ResultHandler resultHandler = (ResultHandler) args[3];
Executor executor = (Executor) invocation.getTarget();
CacheKey cacheKey;
BoundSql boundSql;
if (args.length == 4) {
boundSql = mappedStatement.getBoundSql(parameter);
cacheKey = executor.createCacheKey(mappedStatement, parameter, rowBounds, boundSql);
} else {
cacheKey = (CacheKey) args[4];
boundSql = (BoundSql) args[5];
}
Class<BoundSql> boundSqlClass = BoundSql.class;
Field field = boundSqlClass.getDeclaredField("sql");
field.setAccessible(true);
String lastSql = boundSql.getSql();
Pattern tableNamePattern = Pattern.compile("\\s+from\\s+([^\\s]+)\\s*");
Matcher tableNameMatcher = tableNamePattern.matcher(lastSql);
if (tableNameMatcher.find()) {
String tableName = tableNameMatcher.group(1);
if(!tableName.contains("_")){
if(tableNameMatcher.find()) {
tableName = tableNameMatcher.group(1);
}
}
UserDO user = ShiroUtils.getUser();
List<DataPermDO> perms = user.getDataPerms().get(tableName);
String pageSql = "";
int limitIndex = lastSql.indexOf(" limit ");
if (limitIndex != -1) {
pageSql = lastSql.substring(limitIndex);
lastSql = lastSql.substring(0, limitIndex);
}
String orderSql = "";
int orderIndex = lastSql.indexOf(" order ");
if (orderIndex == -1) {
orderIndex = lastSql.indexOf(" ORDER ");
}
if (orderIndex != -1) {
orderSql = lastSql.substring(orderIndex);
lastSql = lastSql.substring(0, orderIndex);
}
String linkSql = " WHERE ";
String permSql = "";
boolean allPerms= false;
if (perms != null && perms.size() > 0) {
Class userClass = UserDO.class;
for (DataPermDO perm : perms) {
if (allPerms) {
break;
}
String attrName = perm.getCrlAttrName();
String columnName = perm.getCrlColumnName();
String permCode = perm.getPermCode();
switch (permCode.substring(0, permCode.indexOf("_"))) {
case "all": {
allPerms = true;
break;
}
case "own": {
Field attrNameField = userClass.getDeclaredField(attrName);
attrNameField.setAccessible(true);
String attrValue = attrNameField.get(user) + "";
permSql += ("or " + columnName + "=" + attrValue + " ");
break;
}
case "sup": {
Field supAttrNameField = userClass.getDeclaredField("sup" + (attrName.substring(0, 1).toUpperCase() + attrName.substring(1)) + "s");
supAttrNameField.setAccessible(true);
String supAttrValue = (String) supAttrNameField.get(user);
permSql += ("or " + columnName + " in(" + supAttrValue + ") ");
break;
}
}
}
}
if (!allPerms) {
if(permSql.length()==0){
permSql = "0";
}else{
permSql = permSql.replaceFirst("or","");
}
lastSql = lastSql + linkSql + "(" + permSql + ")";
}
lastSql += (orderSql + pageSql);
}
field.set(boundSql, lastSql);
return executor.query(mappedStatement, parameter, rowBounds, resultHandler, cacheKey, boundSql);
}
return invocation.proceed();
}
// 拦截类型StatementHandler
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}

View File

@ -0,0 +1,20 @@
package com.java2nb.common.jsonserializer;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
public class LongToStringSerializer extends JsonSerializer<Long> {
@Override
public void serialize(Long value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
if(value != null){
jsonGenerator.writeString(value+"");
}else{
jsonGenerator.writeNull();
}
}
}

View File

@ -0,0 +1,194 @@
package com.java2nb.common.redis.shiro;
/**
* @author xiongxy
* @version V1.0
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.util.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RedisCache<K, V> implements Cache<K, V> {
private Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* The wrapped Jedis instance.
*/
private RedisManager cache;
/**
* The Redis key prefix for the sessions
*/
private String keyPrefix = "shiro_redis_session:";
/**
* Returns the Redis session keys
* prefix.
* @return The prefix
*/
public String getKeyPrefix() {
return keyPrefix;
}
/**
* Sets the Redis sessions key
* prefix.
* @param keyPrefix The prefix
*/
public void setKeyPrefix(String keyPrefix) {
this.keyPrefix = keyPrefix;
}
/**
* 通过一个JedisManager实例构造RedisCache
*/
public RedisCache(RedisManager cache){
if (cache == null) {
throw new IllegalArgumentException("Cache argument cannot be null.");
}
this.cache = cache;
}
/**
* Constructs a cache instance with the specified
* Redis manager and using a custom key prefix.
* @param cache The cache manager instance
* @param prefix The Redis key prefix
*/
public RedisCache(RedisManager cache,
String prefix){
this( cache );
// set the prefix
this.keyPrefix = prefix;
}
/**
* 获得byte[]型的key
* @param key
* @return
*/
private byte[] getByteKey(K key){
if(key instanceof String){
String preKey = this.keyPrefix + key;
return preKey.getBytes();
}else{
return SerializeUtils.serialize(key);
}
}
@Override
public V get(K key) throws CacheException {
logger.debug("根据key从Redis中获取对象 key [" + key + "]");
try {
if (key == null) {
return null;
}else{
byte[] rawValue = cache.get(getByteKey(key));
@SuppressWarnings("unchecked")
V value = (V)SerializeUtils.deserialize(rawValue);
return value;
}
} catch (Throwable t) {
throw new CacheException(t);
}
}
@Override
public V put(K key, V value) throws CacheException {
logger.debug("根据key从存储 key [" + key + "]");
try {
cache.set(getByteKey(key), SerializeUtils.serialize(value));
return value;
} catch (Throwable t) {
throw new CacheException(t);
}
}
@Override
public V remove(K key) throws CacheException {
logger.debug("从redis中删除 key [" + key + "]");
try {
V previous = get(key);
cache.del(getByteKey(key));
return previous;
} catch (Throwable t) {
throw new CacheException(t);
}
}
@Override
public void clear() throws CacheException {
logger.debug("从redis中删除所有元素");
try {
cache.flushDB();
} catch (Throwable t) {
throw new CacheException(t);
}
}
@Override
public int size() {
try {
Long longSize = new Long(cache.dbSize());
return longSize.intValue();
} catch (Throwable t) {
throw new CacheException(t);
}
}
@SuppressWarnings("unchecked")
@Override
public Set<K> keys() {
try {
Set<byte[]> keys = cache.keys(this.keyPrefix + "*");
if (CollectionUtils.isEmpty(keys)) {
return Collections.emptySet();
}else{
Set<K> newKeys = new HashSet<K>();
for(byte[] key:keys){
newKeys.add((K)key);
}
return newKeys;
}
} catch (Throwable t) {
throw new CacheException(t);
}
}
@Override
public Collection<V> values() {
try {
Set<byte[]> keys = cache.keys(this.keyPrefix + "*");
if (!CollectionUtils.isEmpty(keys)) {
List<V> values = new ArrayList<V>(keys.size());
for (byte[] key : keys) {
@SuppressWarnings("unchecked")
V value = get((K)key);
if (value != null) {
values.add(value);
}
}
return Collections.unmodifiableList(values);
} else {
return Collections.emptyList();
}
} catch (Throwable t) {
throw new CacheException(t);
}
}
}

View File

@ -0,0 +1,77 @@
package com.java2nb.common.redis.shiro;
/**
* @author xiongxy
* @version V1.0
*/
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RedisCacheManager implements CacheManager {
private static final Logger logger = LoggerFactory
.getLogger(RedisCacheManager.class);
// fast lookup by name map
private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();
private RedisManager redisManager;
/**
* The Redis key prefix for caches
*/
private String keyPrefix = "shiro_redis_cache:";
/**
* Returns the Redis session keys
* prefix.
* @return The prefix
*/
public String getKeyPrefix() {
return keyPrefix;
}
/**
* Sets the Redis sessions key
* prefix.
* @param keyPrefix The prefix
*/
public void setKeyPrefix(String keyPrefix) {
this.keyPrefix = keyPrefix;
}
@Override
public <K, V> Cache<K, V> getCache(String name) throws CacheException {
logger.debug("获取名称为: " + name + " 的RedisCache实例");
Cache c = caches.get(name);
if (c == null) {
// initialize the Redis manager instance
redisManager.init();
// create a new cache instance
c = new RedisCache<K, V>(redisManager, keyPrefix);
// add it to the cache collection
caches.put(name, c);
}
return c;
}
public RedisManager getRedisManager() {
return redisManager;
}
public void setRedisManager(RedisManager redisManager) {
this.redisManager = redisManager;
}
}

View File

@ -0,0 +1,228 @@
package com.java2nb.common.redis.shiro;
/**
* @author xiongxy
* @version V1.0
*/
import java.util.Set;
import org.springframework.beans.factory.annotation.Value;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
*
*/
public class RedisManager {
@Value("${spring.redis.host}")
private String host = "127.0.0.1";
@Value("${spring.redis.port}")
private int port = 6379;
// 0 - never expire
private int expire = 0;
//timeout for jedis try to connect to redis server, not expire time! In milliseconds
@Value("${spring.redis.timeout}")
private int timeout = 0;
@Value("${spring.redis.password}")
private String password = "";
private static JedisPool jedisPool = null;
public RedisManager() {
}
/**
* 初始化方法
*/
public void init() {
if (jedisPool == null) {
if (password != null && !"".equals(password)) {
jedisPool = new JedisPool(new JedisPoolConfig(), host, port, timeout, password);
} else if (timeout != 0) {
jedisPool = new JedisPool(new JedisPoolConfig(), host, port, timeout);
} else {
jedisPool = new JedisPool(new JedisPoolConfig(), host, port);
}
}
}
/**
* get value from redis
*
* @param key
* @return
*/
public byte[] get(byte[] key) {
byte[] value = null;
Jedis jedis = jedisPool.getResource();
try {
value = jedis.get(key);
} finally {
if (jedis != null) {
jedis.close();
}
}
return value;
}
/**
* set
*
* @param key
* @param value
* @return
*/
public byte[] set(byte[] key, byte[] value) {
Jedis jedis = jedisPool.getResource();
try {
jedis.set(key, value);
if (this.expire != 0) {
jedis.expire(key, this.expire);
}
} finally {
if (jedis != null) {
jedis.close();
}
}
return value;
}
/**
* set
*
* @param key
* @param value
* @param expire
* @return
*/
public byte[] set(byte[] key, byte[] value, int expire) {
Jedis jedis = jedisPool.getResource();
try {
jedis.set(key, value);
if (expire != 0) {
jedis.expire(key, expire);
}
} finally {
if (jedis != null) {
jedis.close();
}
}
return value;
}
/**
* del
*
* @param key
*/
public void del(byte[] key) {
Jedis jedis = jedisPool.getResource();
try {
jedis.del(key);
} finally {
if (jedis != null) {
jedis.close();
}
}
}
/**
* flush
*/
public void flushDB() {
Jedis jedis = jedisPool.getResource();
try {
jedis.flushDB();
} finally {
if (jedis != null) {
jedis.close();
}
}
}
/**
* size
*/
public Long dbSize() {
Long dbSize = 0L;
Jedis jedis = jedisPool.getResource();
try {
dbSize = jedis.dbSize();
} finally {
if (jedis != null) {
jedis.close();
}
}
return dbSize;
}
/**
* keys
*
* @param regex
* @return
*/
public Set<byte[]> keys(String pattern) {
Set<byte[]> keys = null;
Jedis jedis = jedisPool.getResource();
try {
keys = jedis.keys(pattern.getBytes());
} finally {
if (jedis != null) {
jedis.close();
}
}
return keys;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public int getExpire() {
return expire;
}
public void setExpire(int expire) {
this.expire = expire;
}
public int getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}

View File

@ -0,0 +1,139 @@
package com.java2nb.common.redis.shiro;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
/**
* @author xiongxy
* @version V1.0
*/
public class RedisSessionDAO extends AbstractSessionDAO {
private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class);
/**
* shiro-redis的session对象前缀
*/
private RedisManager redisManager;
/**
* The Redis key prefix for the sessions
*/
private String keyPrefix = "shiro_redis_session:";
@Override
public void update(Session session) throws UnknownSessionException {
this.saveSession(session);
}
/**
* save session
* @param session
* @throws UnknownSessionException
*/
private void saveSession(Session session) throws UnknownSessionException{
if(session == null || session.getId() == null){
logger.error("session or session id is null");
return;
}
byte[] key = getByteKey(session.getId());
byte[] value = SerializeUtils.serialize(session);
session.setTimeout(redisManager.getExpire()*1000);
this.redisManager.set(key, value, redisManager.getExpire());
}
@Override
public void delete(Session session) {
if(session == null || session.getId() == null){
logger.error("session or session id is null");
return;
}
redisManager.del(this.getByteKey(session.getId()));
}
@Override
public Collection<Session> getActiveSessions() {
Set<Session> sessions = new HashSet<Session>();
Set<byte[]> keys = redisManager.keys(this.keyPrefix + "*");
if(keys != null && keys.size()>0){
for(byte[] key:keys){
Session s = (Session)SerializeUtils.deserialize(redisManager.get(key));
sessions.add(s);
}
}
return sessions;
}
@Override
protected Serializable doCreate(Session session) {
Serializable sessionId = this.generateSessionId(session);
this.assignSessionId(session, sessionId);
this.saveSession(session);
return sessionId;
}
@Override
protected Session doReadSession(Serializable sessionId) {
if(sessionId == null){
logger.error("session id is null");
return null;
}
Session s = (Session)SerializeUtils.deserialize(redisManager.get(this.getByteKey(sessionId)));
return s;
}
/**
* 获得byte[]型的key
* @param key
* @return
*/
private byte[] getByteKey(Serializable sessionId){
String preKey = this.keyPrefix + sessionId;
return preKey.getBytes();
}
public RedisManager getRedisManager() {
return redisManager;
}
public void setRedisManager(RedisManager redisManager) {
this.redisManager = redisManager;
/**
* 初始化redisManager
*/
this.redisManager.init();
}
/**
* Returns the Redis session keys
* prefix.
* @return The prefix
*/
public String getKeyPrefix() {
return keyPrefix;
}
/**
* Sets the Redis sessions key
* prefix.
* @param keyPrefix The prefix
*/
public void setKeyPrefix(String keyPrefix) {
this.keyPrefix = keyPrefix;
}
}

View File

@ -0,0 +1,89 @@
package com.java2nb.common.redis.shiro;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author xiongxy
* @version V1.0
*/
public class SerializeUtils {
private static Logger logger = LoggerFactory.getLogger(SerializeUtils.class);
/**
* 反序列化
* @param bytes
* @return
*/
public static Object deserialize(byte[] bytes) {
Object result = null;
if (isEmpty(bytes)) {
return null;
}
try {
ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
try {
ObjectInputStream objectInputStream = new ObjectInputStream(byteStream);
try {
result = objectInputStream.readObject();
}
catch (ClassNotFoundException ex) {
throw new Exception("Failed to deserialize object type", ex);
}
}
catch (Throwable ex) {
throw new Exception("Failed to deserialize", ex);
}
} catch (Exception e) {
logger.error("Failed to deserialize",e);
}
return result;
}
public static boolean isEmpty(byte[] data) {
return (data == null || data.length == 0);
}
/**
* 序列化
* @param object
* @return
*/
public static byte[] serialize(Object object) {
byte[] result = null;
if (object == null) {
return new byte[0];
}
try {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(128);
try {
if (!(object instanceof Serializable)) {
throw new IllegalArgumentException(SerializeUtils.class.getSimpleName() + " requires a Serializable payload " +
"but received an object of type [" + object.getClass().getName() + "]");
}
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteStream);
objectOutputStream.writeObject(object);
objectOutputStream.flush();
result = byteStream.toByteArray();
}
catch (Throwable ex) {
throw new Exception("Failed to serialize", ex);
}
} catch (Exception ex) {
logger.error("Failed to serialize",ex);
}
return result;
}
}

View File

@ -0,0 +1,56 @@
package com.java2nb.common.service;
import com.java2nb.common.domain.DictDO;
import com.java2nb.system.domain.UserDO;
import java.util.List;
import java.util.Map;
/**
* 字典表
*
* @author xiongxy
* @email 1179705413@qq.com
* @date 2019-09-29 18:28:07
*/
public interface DictService {
DictDO get(Long id);
List<DictDO> list(Map<String, Object> map);
int count(Map<String, Object> map);
int save(DictDO dict);
int update(DictDO dict);
int remove(Long id);
int batchRemove(Long[] ids);
List<DictDO> listType();
String getName(String type,String value);
/**
* 获取爱好列表
* @return
* @param userDO
*/
List<DictDO> getHobbyList(UserDO userDO);
/**
* 获取性别列表
* @return
*/
List<DictDO> getSexList();
/**
* 根据type获取数据
* @param map
* @return
*/
List<DictDO> listByType(String type);
}

View File

@ -0,0 +1,37 @@
package com.java2nb.common.service;
import com.java2nb.common.domain.FileDO;
import java.util.List;
import java.util.Map;
/**
* 文件上传
*
* @author xiongxy
* @email 1179705413@qq.com
* @date 2019-09-19 16:02:20
*/
public interface FileService {
FileDO get(Long id);
List<FileDO> list(Map<String, Object> map);
int count(Map<String, Object> map);
int save(FileDO sysFile);
int update(FileDO sysFile);
int remove(Long id);
int batchRemove(Long[] ids);
/**
* 判断一个文件是否存在
* @param url FileDO中存的路径
* @return
*/
Boolean isExist(String url);
}

View File

@ -0,0 +1,30 @@
/**
*
*/
package com.java2nb.common.service;
import java.util.List;
import java.util.Map;
import com.java2nb.common.domain.GenColumnsDO;
import org.springframework.stereotype.Service;
/**
* @author xiongxy
* @Time 2019-10-20 11:23:09
* @description
*
*/
@Service
public interface GeneratorService {
List<Map<String, Object>> list(String tableName);
void generatorCode(String[] tableNames);
byte[] downloadCode(String[] tableNames);
List<GenColumnsDO> listColumnsByTableName(String tableName);
boolean genColumnsSave(List<GenColumnsDO> list);
}

View File

@ -0,0 +1,16 @@
package com.java2nb.common.service;
import java.util.List;
import org.springframework.stereotype.Service;
import com.java2nb.common.domain.LogDO;
import com.java2nb.common.domain.PageDO;
import com.java2nb.common.utils.Query;
@Service
public interface LogService {
void save(LogDO logDO);
PageDO<LogDO> queryList(Query query);
int remove(Long id);
int batchRemove(Long[] ids);
}

View File

@ -0,0 +1,109 @@
package com.java2nb.common.service.impl;
import com.java2nb.common.utils.StringUtils;
import com.java2nb.system.domain.UserDO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import com.java2nb.common.dao.DictDao;
import com.java2nb.common.domain.DictDO;
import com.java2nb.common.service.DictService;
@Service
public class DictServiceImpl implements DictService {
@Autowired
private DictDao dictDao;
@Override
public DictDO get(Long id) {
return dictDao.get(id);
}
@Override
public List<DictDO> list(Map<String, Object> map) {
return dictDao.list(map);
}
@Override
public int count(Map<String, Object> map) {
return dictDao.count(map);
}
@Override
public int save(DictDO dict) {
return dictDao.save(dict);
}
@Override
public int update(DictDO dict) {
return dictDao.update(dict);
}
@Override
public int remove(Long id) {
return dictDao.remove(id);
}
@Override
public int batchRemove(Long[] ids) {
return dictDao.batchRemove(ids);
}
@Override
public List<DictDO> listType() {
return dictDao.listType();
}
@Override
public String getName(String type, String value) {
Map<String, Object> param = new HashMap<String, Object>(16);
param.put("type", type);
param.put("value", value);
String rString = dictDao.list(param).get(0).getName();
return rString;
}
@Override
public List<DictDO> getHobbyList(UserDO userDO) {
Map<String, Object> param = new HashMap<>(16);
param.put("type", "hobby");
List<DictDO> hobbyList = dictDao.list(param);
if (StringUtils.isNotEmpty(userDO.getHobby())) {
String userHobbys[] = userDO.getHobby().split(";");
for (String userHobby : userHobbys) {
for (DictDO hobby : hobbyList) {
if (!Objects.equals(userHobby, hobby.getId().toString())) {
continue;
}
hobby.setRemarks("true");
break;
}
}
}
return hobbyList;
}
@Override
public List<DictDO> getSexList() {
Map<String, Object> param = new HashMap<>(16);
param.put("type", "sex");
return dictDao.list(param);
}
@Override
public List<DictDO> listByType(String type) {
Map<String, Object> param = new HashMap<>(16);
param.put("type", type);
return dictDao.list(param);
}
}

View File

@ -0,0 +1,72 @@
package com.java2nb.common.service.impl;
import com.java2nb.common.config.JnConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.File;
import java.util.List;
import java.util.Map;
import com.java2nb.common.dao.FileDao;
import com.java2nb.common.domain.FileDO;
import com.java2nb.common.service.FileService;
import org.springframework.util.StringUtils;
@Service
public class FileServiceImpl implements FileService {
@Autowired
private FileDao sysFileMapper;
@Autowired
private JnConfig jnConfig;
@Override
public FileDO get(Long id){
return sysFileMapper.get(id);
}
@Override
public List<FileDO> list(Map<String, Object> map){
return sysFileMapper.list(map);
}
@Override
public int count(Map<String, Object> map){
return sysFileMapper.count(map);
}
@Override
public int save(FileDO sysFile){
return sysFileMapper.save(sysFile);
}
@Override
public int update(FileDO sysFile){
return sysFileMapper.update(sysFile);
}
@Override
public int remove(Long id){
return sysFileMapper.remove(id);
}
@Override
public int batchRemove(Long[] ids){
return sysFileMapper.batchRemove(ids);
}
@Override
public Boolean isExist(String url) {
Boolean isExist = false;
if (!StringUtils.isEmpty(url)) {
String filePath = url.replace("/files/", "");
filePath = jnConfig.getUploadPath() + filePath;
File file = new File(filePath);
if (file.exists()) {
isExist = true;
}
}
return isExist;
}
}

View File

@ -0,0 +1,141 @@
package com.java2nb.common.service.impl;
import java.io.ByteArrayOutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipOutputStream;
import com.java2nb.common.dao.GenColumnsDao;
import com.java2nb.common.domain.GenColumnsDO;
import lombok.SneakyThrows;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.java2nb.common.dao.GeneratorMapper;
import com.java2nb.common.service.GeneratorService;
import com.java2nb.common.utils.GenUtils;
import org.springframework.transaction.annotation.Transactional;
@Service
public class GeneratorServiceImpl implements GeneratorService {
@Autowired
GeneratorMapper generatorMapper;
@Autowired
GenColumnsDao genColumnsDao;
@Override
public List<Map<String, Object>> list(String tableName) {
List<Map<String, Object>> list = generatorMapper.list(tableName);
return list;
}
@Override
public void generatorCode(String[] tableNames) {
for (String tableName : tableNames) {
//查询表信息
Map<String, String> table = generatorMapper.get(tableName);
//查询列信息
List<Map<String, String>> columns = generatorMapper.listColumns(tableName);
//生成代码
GenUtils.generatorCode(table, columns, null);
}
}
@Override
public byte[] downloadCode(String[] tableNames) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ZipOutputStream zip = new ZipOutputStream(outputStream);
for (String tableName : tableNames) {
//查询表信息
Map<String, String> table = generatorMapper.get(tableName);
//查询列信息
List<Map<String, String>> columns = generatorMapper.listColumns(tableName);
//生成代码
GenUtils.generatorCode(table, columns, zip);
}
IOUtils.closeQuietly(zip);
return outputStream.toByteArray();
}
@Override
public List<GenColumnsDO> listColumnsByTableName(String tableName) {
Map<String, Object> query = new HashMap<>();
query.put("tableName", tableName);
query.put("sort", "column_sort");
query.put("order", "asc");
List<GenColumnsDO> columnList = genColumnsDao.list(query);
if (columnList.size() == 0) {
//查询列信息
List<Map<String, String>> columns = generatorMapper.listColumns(tableName);
int columnSort = 0;
for (Map<String, String> column : columns) {
GenColumnsDO genColumnsDO = transGenColumnDO(tableName,column,++columnSort);
if(!"PRI".equalsIgnoreCase(column.get("columnKey"))) {
columnList.add(genColumnsDO);
}else{
genColumnsDO.setColumnSort(0);
genColumnsDO.setPageType(11);
columnList.add(0,genColumnsDO);
}
}
}else{
Map<String, String> column = generatorMapper.getPriColumn(tableName);
GenColumnsDO genColumnsDO = transGenColumnDO(tableName,column,0);
genColumnsDO.setPageType(11);
columnList.add(0,genColumnsDO);
}
return columnList;
}
@Transactional
@Override
public boolean genColumnsSave(List<GenColumnsDO> list) {
GenColumnsDO pkColumn = list.get(0);
String tableName = pkColumn.getTableName();
genColumnsDao.deleteByTableName(tableName);
list.remove(0);
genColumnsDao.saveBatch(list);
//查询表信息
Map<String, String> table = generatorMapper.get(tableName);
//生成代码
GenUtils.generatorCode(table,pkColumn, list);
return true;
}
@SneakyThrows
public GenColumnsDO transGenColumnDO(String tableName,Map<String, String> column,int columnSort){
GenColumnsDO genColumnsDO = new GenColumnsDO();
genColumnsDO.setTableName(tableName);
genColumnsDO.setColumnName(column.get("columnName"));
genColumnsDO.setColumnType(column.get("dataType"));
genColumnsDO.setColumnComment(column.get("columnComment"));
PropertiesConfiguration conf = new PropertiesConfiguration("generator.properties");
genColumnsDO.setJavaType(conf.getString(column.get("dataType")));
genColumnsDO.setColumnSort(columnSort);
genColumnsDO.setExtra(column.get("extra"));
genColumnsDO.setIsRequired(0);
if ("Date".equals(conf.getString(column.get("dataType")))) {
genColumnsDO.setPageType(4);
} else {
genColumnsDO.setPageType(1);
}
genColumnsDO.setColumnLabel(column.get("columnComment"));
return genColumnsDO;
}
}

View File

@ -0,0 +1,45 @@
package com.java2nb.common.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import com.java2nb.common.dao.LogDao;
import com.java2nb.common.domain.LogDO;
import com.java2nb.common.domain.PageDO;
import com.java2nb.common.service.LogService;
import com.java2nb.common.utils.Query;
@Service
public class LogServiceImpl implements LogService {
@Autowired
LogDao logMapper;
@Async
@Override
public void save(LogDO logDO) {
logMapper.save(logDO);
}
@Override
public PageDO<LogDO> queryList(Query query) {
int total = logMapper.count(query);
List<LogDO> logs = logMapper.list(query);
PageDO<LogDO> page = new PageDO<>();
page.setTotal(total);
page.setRows(logs);
return page;
}
@Override
public int remove(Long id) {
int count = logMapper.remove(id);
return count;
}
@Override
public int batchRemove(Long[] ids){
return logMapper.batchRemove(ids);
}
}

View File

@ -0,0 +1,52 @@
package com.java2nb.common.utils;
/**
* 自定义异常
*
*/
public class BDException extends RuntimeException {
private static final long serialVersionUID = 1L;
private String msg;
private int code = 500;
public BDException(String msg) {
super(msg);
this.msg = msg;
}
public BDException(String msg, Throwable e) {
super(msg, e);
this.msg = msg;
}
public BDException(String msg, int code) {
super(msg);
this.msg = msg;
this.code = code;
}
public BDException(String msg, int code, Throwable e) {
super(msg, e);
this.msg = msg;
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}

View File

@ -0,0 +1,5 @@
package com.java2nb.common.utils;
public class Base64Utils {
}

View File

@ -0,0 +1,89 @@
package com.java2nb.common.utils;
import com.java2nb.common.domain.Tree;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class BuildTree {
public static <T> Tree<T> build(List<Tree<T>> nodes) {
if (nodes == null) {
return null;
}
List<Tree<T>> topNodes = new ArrayList<Tree<T>>();
for (Tree<T> children : nodes) {
String pid = children.getParentId();
if (pid == null || "0".equals(pid)) {
topNodes.add(children);
continue;
}
for (Tree<T> parent : nodes) {
String id = parent.getId();
if (id != null && id.equals(pid)) {
parent.getChildren().add(children);
children.setHasParent(true);
parent.setChildren(true);
continue;
}
}
}
Tree<T> root = new Tree<T>();
if (topNodes.size() == 1) {
root = topNodes.get(0);
} else {
root.setId("-1");
root.setParentId("");
root.setHasParent(false);
root.setChildren(true);
root.setChecked(true);
root.setChildren(topNodes);
root.setText("顶级节点");
Map<String, Object> state = new HashMap<>(16);
state.put("opened", true);
root.setState(state);
}
return root;
}
public static <T> List<Tree<T>> buildList(List<Tree<T>> nodes, String idParam) {
if (nodes == null) {
return null;
}
List<Tree<T>> topNodes = new ArrayList<Tree<T>>();
for (Tree<T> children : nodes) {
String pid = children.getParentId();
if (pid == null || idParam.equals(pid)) {
topNodes.add(children);
continue;
}
for (Tree<T> parent : nodes) {
String id = parent.getId();
if (id != null && id.equals(pid)) {
parent.getChildren().add(children);
children.setHasParent(true);
parent.setChildren(true);
continue;
}
}
}
return topNodes;
}
}

View File

@ -0,0 +1,131 @@
package com.java2nb.common.utils;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
/**
* 日期处理
*/
public class DateUtils {
private final static Logger logger = LoggerFactory.getLogger(DateUtils.class);
public final static String YEAR_PATTERN = "yyyy";
public final static String MONTH_PATTERN = "MM";
public final static String DAY_PATTERN = "dd";
/**
* 时间格式(yyyy-MM-dd)
*/
public final static String DATE_PATTERN = "yyyy-MM-dd";
/**
* 时间格式(yyyy-MM-dd HH:mm:ss)
*/
public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
public static String format(Date date) {
return format(date, DATE_PATTERN);
}
public static String format(Date date, String pattern) {
if (date != null) {
SimpleDateFormat df = new SimpleDateFormat(pattern);
return df.format(date);
}
return null;
}
/**
* 计算距离现在多久,非精确
*
* @param date
* @return
*/
public static String getTimeBefore(Date date) {
Date now = new Date();
long l = now.getTime() - date.getTime();
long day = l / (24 * 60 * 60 * 1000);
long hour = (l / (60 * 60 * 1000) - day * 24);
long min = ((l / (60 * 1000)) - day * 24 * 60 - hour * 60);
long s = (l / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
String r = "";
if (day > 0) {
r += day + "";
} else if (hour > 0) {
r += hour + "小时";
} else if (min > 0) {
r += min + "";
} else if (s > 0) {
r += s + "";
}
r += "";
return r;
}
/**
* 计算距离现在多久,精确
*
* @param date
* @return
*/
public static String getTimeBeforeAccurate(Date date) {
Date now = new Date();
long l = now.getTime() - date.getTime();
long day = l / (24 * 60 * 60 * 1000);
long hour = (l / (60 * 60 * 1000) - day * 24);
long min = ((l / (60 * 1000)) - day * 24 * 60 - hour * 60);
long s = (l / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
String r = "";
if (day > 0) {
r += day + "";
}
if (hour > 0) {
r += hour + "小时";
}
if (min > 0) {
r += min + "";
}
if (s > 0) {
r += s + "";
}
r += "";
return r;
}
/**
* 获取过去第几天的日期
*
* @param past
* @return
*/
@SneakyThrows
public static String getPastDate(int past,Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) - past);
Date today = calendar.getTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(today);
}
/**
* 获取过去几天的日期集合
*
* @param past
* @return
*/
public static List<String> getDateList(int past,Date date) {
List<String> result = new ArrayList<>(past);
for(int i = past - 1 ; i > 0 ; i--){
result.add(getPastDate(i,date));
}
//今天的日期
result.add(new SimpleDateFormat("yyyy-MM-dd").format(date));
return result;
}
}

View File

@ -0,0 +1,12 @@
package com.java2nb.common.utils;
public class ExceptionUtils {
public static String getExceptionAllinformation(Exception ex) {
String sOut = "";
StackTraceElement[] trace = ex.getStackTrace();
for (StackTraceElement s : trace) {
sOut += "\tat " + s + "\r\n";
}
return sOut;
}
}

View File

@ -0,0 +1,55 @@
package com.java2nb.common.utils;
/* authorzss
* 日期2017年3月31日
* 功能:根据文件名称判断类型
* 接受参数类型String
* 返回参数类型String
* 备注:文件类型不完善,有需要的自行添加
*/
public class FileType {
public static int fileType(String fileName) {
if (fileName == null) {
fileName = "文件名为空!";
return 500;
} else {
// 获取文件后缀名并转化为写,用于后续比较
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length()).toLowerCase();
// 创建图片类型数组0
String[] img = { "bmp", "jpg", "jpeg", "png", "tiff", "gif", "pcx", "tga", "exif", "fpx", "svg", "psd",
"cdr", "pcd", "dxf", "ufo", "eps", "ai", "raw", "wmf" };
for (int i = 0; i < img.length; i++) {
if (img[i].equals(fileType)) {
return 0;
}
}
// 创建文档类型数组1
String[] document = { "txt", "doc", "docx", "xls", "htm", "html", "jsp", "rtf", "wpd", "pdf", "ppt" };
for (int i = 0; i < document.length; i++) {
if (document[i].equals(fileType)) {
return 1;
}
}
// 创建视频类型数组2
String[] video = { "mp4", "avi", "mov", "wmv", "asf", "navi", "3gp", "mkv", "f4v", "rmvb", "webm" };
for (int i = 0; i < video.length; i++) {
if (video[i].equals(fileType)) {
return 2;
}
}
// 创建音乐类型数组3
String[] music = { "mp3", "wma", "wav", "mod", "ra", "cd", "md", "asf", "aac", "vqf", "ape", "mid", "ogg",
"m4a", "vqf" };
for (int i = 0; i < music.length; i++) {
if (music[i].equals(fileType)) {
return 3;
}
}
}
//4
return 99;
}
}

View File

@ -0,0 +1,37 @@
package com.java2nb.common.utils;
import java.io.File;
import java.io.FileOutputStream;
import java.util.UUID;
public class FileUtil {
public static void uploadFile(byte[] file, String filePath, String fileName) throws Exception {
File targetFile = new File(filePath);
if (!targetFile.exists()) {
targetFile.mkdirs();
}
FileOutputStream out = new FileOutputStream(filePath + fileName);
out.write(file);
out.flush();
out.close();
}
public static boolean deleteFile(String fileName) {
File file = new File(fileName);
// 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
if (file.exists() && file.isFile()) {
if (file.delete()) {
return true;
} else {
return false;
}
} else {
return false;
}
}
public static String renameToUUID(String fileName) {
return UUID.randomUUID() + "." + fileName.substring(fileName.lastIndexOf(".") + 1);
}
}

View File

@ -0,0 +1,376 @@
package com.java2nb.common.utils;
import com.java2nb.common.config.Constant;
import com.java2nb.common.domain.ColumnDO;
import com.java2nb.common.domain.GenColumnsDO;
import com.java2nb.common.domain.TableDO;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.WordUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* 代码生成器 工具类
*/
public class GenUtils {
public static List<String> getTemplates() {
List<String> templates = new ArrayList<String>();
templates.add("templates/common/generator/domain.java.vm");
templates.add("templates/common/generator/Dao.java.vm");
//templates.add("templates/common/generator/Mapper.java.vm");
templates.add("templates/common/generator/Mapper.xml.vm");
templates.add("templates/common/generator/Service.java.vm");
templates.add("templates/common/generator/ServiceImpl.java.vm");
templates.add("templates/common/generator/Controller.java.vm");
templates.add("templates/common/generator/list.html.vm");
templates.add("templates/common/generator/add.html.vm");
templates.add("templates/common/generator/edit.html.vm");
templates.add("templates/common/generator/detail.html.vm");
templates.add("templates/common/generator/list.js.vm");
templates.add("templates/common/generator/add.js.vm");
templates.add("templates/common/generator/edit.js.vm");
templates.add("templates/common/generator/menu.sql.vm");
//templates.add("templates/common/generator/menu.sql.vm");
return templates;
}
/**
* 生成代码
*/
public static void generatorCode(Map<String, String> table,
List<Map<String, String>> columns, ZipOutputStream zip) {
/*//封装模板数据
Map<String, Object> map = new HashMap<>(16);
//配置信息
Configuration config = getConfig();
//表信息
TableDO tableDO = new TableDO();
tableDO.setTableName(table.get("tableName"));
tableDO.setComments(table.get("tableComment"));
//表名转换成Java类名
String className = tableToJava(tableDO.getTableName(), config.getString("tablePrefix"), config.getString("autoRemovePre"));
tableDO.setClassName(className);
tableDO.setClassname(StringUtils.uncapitalize(className));
//列信息
List<ColumnDO> columsList = new ArrayList<>();
for (Map<String, String> column : columns) {
ColumnDO columnDO = new ColumnDO();
columnDO.setColumnName(column.get("columnName"));
columnDO.setDataType(column.get("dataType"));
columnDO.setComments(column.get("columnComment"));
columnDO.setExtra(column.get("extra"));
//列名转换成Java属性名
String attrName = columnToJava(columnDO.getColumnName());
columnDO.setAttrName(attrName);
columnDO.setAttrname(StringUtils.uncapitalize(attrName));
//列的数据类型转换成Java类型
String attrType = config.getString(columnDO.getDataType(), "unknowType");
switch (attrType) {
case "BigDecimal": {
map.put("hasBigDecimal", true);
break;
}
case "Date": {
map.put("hasDate", true);
break;
}
case "Long": {
map.put("hasLong", true);
break;
}
}
columnDO.setAttrType(attrType);
//是否主键
if ("PRI".equalsIgnoreCase(column.get("columnKey")) && tableDO.getPk() == null) {
tableDO.setPk(columnDO);
}
columsList.add(columnDO);
}
tableDO.setColumns(columsList);
//没主键,则第一个字段为主键
if (tableDO.getPk() == null) {
tableDO.setPk(tableDO.getColumns().get(0));
}
//设置velocity资源加载器
Properties prop = new Properties();
prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
Velocity.init(prop);
map.put("tableName", tableDO.getTableName());
map.put("comments", tableDO.getComments());
map.put("pk", tableDO.getPk());
map.put("className", tableDO.getClassName());
map.put("classname", tableDO.getClassname());
map.put("pathName", config.getString("package").substring(config.getString("package").lastIndexOf(".") + 1));
map.put("columns", tableDO.getColumns());
map.put("package", config.getString("package"));
map.put("author", config.getString("author"));
map.put("email", config.getString("email"));
map.put("datetime", DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN));
VelocityContext context = new VelocityContext(map);
//获取模板列表
List<String> templates = getTemplates();
for (String template : templates) {
//渲染模板
StringWriter sw = new StringWriter();
Template tpl = Velocity.getTemplate(template, "UTF-8");
tpl.merge(context, sw);
try {
String fileName = getFileName(template, tableDO.getClassname(), tableDO.getClassName(), config.getString("package"));
if (zip != null) {
//添加到zip
zip.putNextEntry(new ZipEntry(fileName));
IOUtils.write(sw.toString(), zip, "UTF-8");
IOUtils.closeQuietly(sw);
zip.closeEntry();
} else {
String srcPath = config.getString("srcPath");
fileName = srcPath + File.separator + fileName;
File file = new File(fileName);
if (file.exists()) {
file = new File(fileName + 1);
}
File parentCatelog = file.getParentFile();
if (!parentCatelog.exists()) {
parentCatelog.mkdirs();
}
OutputStream fos = new FileOutputStream(file);
IOUtils.write(sw.toString(), fos, "UTF-8");
fos.close();
}
} catch (IOException e) {
throw new RuntimeException("渲染模板失败,表名:" + tableDO.getTableName(), e);
}
}*/
}
/**
* 列名转换成Java属性名
*/
public static String columnToJava(String columnName) {
return WordUtils.capitalizeFully(columnName, new char[]{'_'}).replace("_", "");
}
/**
* 表名转换成Java类名
*/
public static String tableToJava(String tableName, String tablePrefix, String autoRemovePre) {
if (Constant.AUTO_REOMVE_PRE.equals(autoRemovePre)) {
tableName = tableName.substring(tableName.indexOf("_") + 1);
}
if (StringUtils.isNotBlank(tablePrefix)) {
tableName = tableName.replace(tablePrefix, "");
}
return columnToJava(tableName);
}
/**
* 获取配置信息
*/
public static Configuration getConfig() {
try {
return new PropertiesConfiguration("generator.properties");
} catch (ConfigurationException e) {
throw new RuntimeException("获取配置文件失败,", e);
}
}
/**
* 获取文件名
*/
public static String getFileName(String template, String classname, String className, String packageName) {
String moduleName = packageName.substring(packageName.lastIndexOf(".") + 1);
String javaPackagePath = "main" + File.separator + "java" + File.separator;
//String modulesname=config.getString("packageName");
if (StringUtils.isNotBlank(packageName)) {
javaPackagePath += packageName.replace(".", File.separator) + File.separator;
}
if (template.contains("domain.java.vm")) {
return javaPackagePath + "domain" + File.separator + className + "DO.java";
}
if (template.contains("Dao.java.vm")) {
return javaPackagePath + "dao" + File.separator + className + "Dao.java";
}
// if(template.contains("Mapper.java.vm")){
// return packagePath + "dao" + File.separator + className + "Mapper.java";
// }
if (template.contains("Service.java.vm")) {
return javaPackagePath + "service" + File.separator + className + "Service.java";
}
if (template.contains("ServiceImpl.java.vm")) {
return javaPackagePath + "service" + File.separator + "impl" + File.separator + className + "ServiceImpl.java";
}
if (template.contains("Controller.java.vm")) {
return javaPackagePath + "controller" + File.separator + className + "Controller.java";
}
if (template.contains("Mapper.xml.vm")) {
return "main" + File.separator + "resources" + File.separator + "mybatis" + File.separator + moduleName + File.separator + className + "Mapper.xml";
}
if (template.contains("list.html.vm")) {
return "main" + File.separator + "resources" + File.separator + "templates" + File.separator
+ moduleName + File.separator + classname + File.separator + classname + ".html";
// + "modules" + File.separator + "generator" + File.separator + className.toLowerCase() + ".html";
}
if (template.contains("add.html.vm")) {
return "main" + File.separator + "resources" + File.separator + "templates" + File.separator
+ moduleName + File.separator + classname + File.separator + "add.html";
}
if (template.contains("edit.html.vm")) {
return "main" + File.separator + "resources" + File.separator + "templates" + File.separator
+ moduleName + File.separator + classname + File.separator + "edit.html";
}
if (template.contains("detail.html.vm")) {
return "main" + File.separator + "resources" + File.separator + "templates" + File.separator
+ moduleName + File.separator + classname + File.separator + "detail.html";
}
if (template.contains("list.js.vm")) {
return "main" + File.separator + "resources" + File.separator + "static" + File.separator + "js" + File.separator
+ "appjs" + File.separator + moduleName + File.separator + classname + File.separator + classname + ".js";
// + "modules" + File.separator + "generator" + File.separator + className.toLowerCase() + ".js";
}
if (template.contains("add.js.vm")) {
return "main" + File.separator + "resources" + File.separator + "static" + File.separator + "js" + File.separator
+ "appjs" + File.separator + moduleName + File.separator + classname + File.separator + "add.js";
}
if (template.contains("edit.js.vm")) {
return "main" + File.separator + "resources" + File.separator + "static" + File.separator + "js" + File.separator
+ "appjs" + File.separator + moduleName + File.separator + classname + File.separator + "edit.js";
}
if (template.contains("menu.sql.vm")) {
return "main" + File.separator + "resources" + File.separator + "static" + File.separator + "sql"
+ File.separator + moduleName + File.separator + classname + File.separator + "menu.js";
}
// if(template.contains("menu.sql.vm")){
// return className.toLowerCase() + "_menu.sql";
// }
return null;
}
public static void generatorCode(Map<String, String> table, GenColumnsDO pkColumn, List<GenColumnsDO> list) {
//封装模板数据
Map<String, Object> map = new HashMap<>(16);
//配置信息
Configuration config = getConfig();
//表信息
TableDO tableDO = new TableDO();
tableDO.setTableName(table.get("tableName"));
tableDO.setComments(table.get("tableComment"));
//表名转换成Java类名
String className = tableToJava(tableDO.getTableName(), config.getString("tablePrefix"), config.getString("autoRemovePre"));
tableDO.setClassName(className);
tableDO.setClassname(StringUtils.uncapitalize(className));
Collections.sort(list, Comparator.comparingInt(GenColumnsDO::getColumnSort));
for(GenColumnsDO genColumnsDO : list){
String attrName = columnToJava(genColumnsDO.getColumnName());
genColumnsDO.setAttrName(attrName);
genColumnsDO.setAttrname(StringUtils.uncapitalize(attrName));
}
String attrName = columnToJava(pkColumn.getColumnName());
pkColumn.setAttrName(attrName);
pkColumn.setAttrname(StringUtils.uncapitalize(attrName));
tableDO.setPk(pkColumn);
list.add(0,pkColumn);
tableDO.setColumns(list);
//设置velocity资源加载器
Properties prop = new Properties();
prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
Velocity.init(prop);
map.put("tableName", tableDO.getTableName());
map.put("comments", tableDO.getComments());
map.put("pk", tableDO.getPk());
map.put("className", tableDO.getClassName());
map.put("classname", tableDO.getClassname());
map.put("pathName", config.getString("package").substring(config.getString("package").lastIndexOf(".") + 1));
map.put("columns", tableDO.getColumns());
map.put("package", config.getString("package"));
map.put("author", config.getString("author"));
map.put("email", config.getString("email"));
map.put("datetime", DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN));
VelocityContext context = new VelocityContext(map);
//获取模板列表
List<String> templates = getTemplates();
for (String template : templates) {
//渲染模板
StringWriter sw = new StringWriter();
Template tpl = Velocity.getTemplate(template, "UTF-8");
tpl.merge(context, sw);
try {
String fileName = getFileName(template, tableDO.getClassname(), tableDO.getClassName(), config.getString("package"));
String srcPath = config.getString("srcPath");
fileName = srcPath + File.separator + fileName;
File file = new File(fileName);
if (file.exists()) {
file = new File(fileName + 1);
}
File parentCatelog = file.getParentFile();
if (!parentCatelog.exists()) {
parentCatelog.mkdirs();
}
OutputStream fos = new FileOutputStream(file);
IOUtils.write(sw.toString(), fos, "UTF-8");
fos.close();
} catch (IOException e) {
throw new RuntimeException("渲染模板失败,表名:" + tableDO.getTableName(), e);
}
}
}
}

View File

@ -0,0 +1,12 @@
package com.java2nb.common.utils;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
public class HttpContextUtils {
public static HttpServletRequest getHttpServletRequest() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
}
}

View File

@ -0,0 +1,14 @@
package com.java2nb.common.utils;
import javax.servlet.http.HttpServletRequest;
public class HttpServletUtils {
public static boolean jsAjax(HttpServletRequest req){
//判断是否为ajax请求默认不是
boolean isAjaxRequest = false;
if(!StringUtils.isBlank(req.getHeader("x-requested-with")) && req.getHeader("x-requested-with").equals("XMLHttpRequest")){
isAjaxRequest = true;
}
return isAjaxRequest;
}
}

View File

@ -0,0 +1,32 @@
package com.java2nb.common.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
public class IPUtils {
private static Logger logger = LoggerFactory.getLogger(IPUtils.class);
/**
* 获取IP地址
*
* 使用Nginx等反向代理软件 则不能通过request.getRemoteAddr()获取IP地址
* 如果使用了多级反向代理的话X-Forwarded-For的值并不止一个而是一串IP地址X-Forwarded-For中第一个非unknown的有效IP字符串则为真实IP地址
*/
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();
}
return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
}
}

View File

@ -0,0 +1,163 @@
package com.java2nb.common.utils;
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
/**
* <p>名称IdWorker.java</p>
* <p>描述分布式自增长ID</p>
* <pre>
* Twitter的 Snowflake JAVA实现方案
* </pre>
* 核心代码为其IdWorker这个类实现其原理结构如下我分别用一个0表示一位用—分割开部分的作用
* 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
* 在上面的字符串中第一位为未使用实际上也可作为long的符号位接下来的41位为毫秒级时间
* 然后5位datacenter标识位5位机器ID并不算标识符实际是为线程标识
* 然后12位该毫秒内的当前毫秒内的计数加起来刚好64位为一个Long型。
* 这样的好处是整体上按照时间自增排序并且整个分布式系统内不会产生ID碰撞由datacenter和机器ID作区分
* 并且效率较高经测试snowflake每秒能够产生26万ID左右完全满足需要。
* <p>
* 64位ID (42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))
*
*/
public class IdWorker {
// 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
private final static long twepoch = 1288834974657L;
// 机器标识位数
private final static long workerIdBits = 5L;
// 数据中心标识位数
private final static long datacenterIdBits = 5L;
// 机器ID最大值
private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
// 数据中心ID最大值
private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
// 毫秒内自增位
private final static long sequenceBits = 12L;
// 机器ID偏左移12位
private final static long workerIdShift = sequenceBits;
// 数据中心ID左移17位
private final static long datacenterIdShift = sequenceBits + workerIdBits;
// 时间毫秒左移22位
private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
/* 上次生产id时间戳 */
private static long lastTimestamp = -1L;
// 0并发控制
private long sequence = 0L;
private final long workerId;
// 数据标识id部分
private final long datacenterId;
public IdWorker(){
this.datacenterId = getDatacenterId(maxDatacenterId);
this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
}
/**
* @param workerId
* 工作机器ID
* @param datacenterId
* 序列号
*/
public IdWorker(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
/**
* 获取下一个ID
*
* @return
*/
public synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
if (lastTimestamp == timestamp) {
// 当前毫秒内,则+1
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
// 当前毫秒内计数满了,则等待下一秒
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
// ID偏移组合生成最终的ID并返回ID
long nextId = ((timestamp - twepoch) << timestampLeftShift)
| (datacenterId << datacenterIdShift)
| (workerId << workerIdShift) | sequence;
return nextId;
}
private long tilNextMillis(final long lastTimestamp) {
long timestamp = this.timeGen();
while (timestamp <= lastTimestamp) {
timestamp = this.timeGen();
}
return timestamp;
}
private long timeGen() {
return System.currentTimeMillis();
}
/**
* <p>
* 获取 maxWorkerId
* </p>
*/
protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
StringBuffer mpid = new StringBuffer();
mpid.append(datacenterId);
String name = ManagementFactory.getRuntimeMXBean().getName();
if (!name.isEmpty()) {
/*
* GET jvmPid
*/
mpid.append(name.split("@")[0]);
}
/*
* MAC + PID 的 hashcode 获取16个低位
*/
return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
}
/**
* <p>
* 数据标识id部分
* </p>
*/
protected static long getDatacenterId(long maxDatacenterId) {
long id = 0L;
try {
InetAddress ip = InetAddress.getLocalHost();
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
if (network == null) {
id = 1L;
} else {
byte[] mac = network.getHardwareAddress();
id = ((0x000000FF & (long) mac[mac.length - 1])
| (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
id = id % (maxDatacenterId + 1);
}
} catch (Exception e) {
System.out.println(" getDatacenterId: " + e.getMessage());
}
return id;
}
}

View File

@ -0,0 +1,77 @@
package com.java2nb.common.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
/**
* @author xiongxy
* @date 2019-09-25 15:09:21
*/
@Slf4j
public class ImageUtils {
/***
* 剪裁图片
* @param file 图片
* @param x 起点横坐标
* @param y 纵坐标
* @param w 长
* @param h 高
* @throws IOException
* @date 2019-09-25 15:09:21
*/
public static BufferedImage cutImage(MultipartFile file, int x, int y, int w, int h,String prefix) {
Iterator iterator = ImageIO.getImageReadersByFormatName(prefix);
try {
ImageReader reader = (ImageReader)iterator.next();
//转换成输入流
InputStream in = file.getInputStream();
ImageInputStream iis = ImageIO.createImageInputStream(in);
reader.setInput(iis, true);
ImageReadParam param = reader.getDefaultReadParam();
Rectangle rect = new Rectangle(x, y, w,h);
param.setSourceRegion(rect);
BufferedImage bi = reader.read(0,param);
return bi;
} catch (Exception e) {
log.error(e.getMessage(),e);
}
return null;
}
/***
* 图片旋转指定角度
* @param bufferedimage 图像
* @param degree 角度
* @return
* @date 2019-09-25 15:09:21
*/
public static BufferedImage rotateImage(BufferedImage bufferedimage, int degree) {
int w = bufferedimage.getWidth();
int h = bufferedimage.getHeight();
int type = bufferedimage.getColorModel().getTransparency();
BufferedImage img;
Graphics2D graphics2d;
(graphics2d = (img = new BufferedImage(w, h, type))
.createGraphics()).setRenderingHint(
RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2d.setPaint(Color.WHITE);
graphics2d.fillRect(0, 0, w, h);
graphics2d.rotate(Math.toRadians(degree), w / 2, h / 2);
graphics2d.drawImage(bufferedimage, 0, 0,Color.WHITE, null);
graphics2d.dispose();
return img;
}
}

View File

@ -0,0 +1,86 @@
package com.java2nb.common.utils;
import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import java.util.HashMap;
import java.util.Map;
public class JSONUtils {
/**
* Bean对象转JSON
*
* @param object
* @param dataFormatString
* @return
*/
public static String beanToJson(Object object, String dataFormatString) {
if (object != null) {
if (StringUtils.isEmpty(dataFormatString)) {
return JSONObject.toJSONString(object);
}
return JSON.toJSONStringWithDateFormat(object, dataFormatString);
} else {
return null;
}
}
/**
* Bean对象转JSON
*
* @param object
* @return
*/
public static String beanToJson(Object object) {
if (object != null) {
return JSON.toJSONString(object);
} else {
return null;
}
}
/**
* String转JSON字符串
*
* @param key
* @param value
* @return
*/
public static String stringToJsonByFastjson(String key, String value) {
if (StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) {
return null;
}
Map<String, String> map = new HashMap<String, String>(16);
map.put(key, value);
return beanToJson(map, null);
}
/**
* 将json字符串转换成对象
*
* @param json
* @param clazz
* @return
*/
public static Object jsonToBean(String json, Object clazz) {
if (StringUtils.isEmpty(json) || clazz == null) {
return null;
}
return JSON.parseObject(json, clazz.getClass());
}
/**
* json字符串转map
*
* @param json
* @return
*/
@SuppressWarnings("unchecked")
public static Map<String, Object> jsonToMap(String json) {
if (StringUtils.isEmpty(json)) {
return null;
}
return JSON.parseObject(json, Map.class);
}
}

View File

@ -0,0 +1,28 @@
package com.java2nb.common.utils;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
public class MD5Utils {
private static final String SALT = "1qazxsw2";
private static final String ALGORITH_NAME = "md5";
private static final int HASH_ITERATIONS = 2;
public static String encrypt(String pswd) {
String newPassword = new SimpleHash(ALGORITH_NAME, pswd, ByteSource.Util.bytes(SALT), HASH_ITERATIONS).toHex();
return newPassword;
}
public static String encrypt(String username, String pswd) {
String newPassword = new SimpleHash(ALGORITH_NAME, pswd, ByteSource.Util.bytes(username + SALT),
HASH_ITERATIONS).toHex();
return newPassword;
}
public static void main(String[] args) {
//System.out.println(MD5Utils.encrypt("admin", "1"));
}
}

View File

@ -0,0 +1,35 @@
package com.java2nb.common.utils;
import java.io.Serializable;
import java.util.List;
/**
* @Author xiongxy
*/
public class PageBean implements Serializable {
private static final long serialVersionUID = 1L;
private int total;
private List<?> rows;
public PageBean(List<?> list, int total) {
this.rows = list;
this.total = total;
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public List<?> getRows() {
return rows;
}
public void setRows(List<?> rows) {
this.rows = rows;
}
}

View File

@ -0,0 +1,41 @@
package com.java2nb.common.utils;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 查询参数
*/
public class Query extends LinkedHashMap<String, Object> {
private static final long serialVersionUID = 1L;
//
private int offset;
// 每页条数
private int limit;
public Query(Map<String, Object> params) {
this.putAll(params);
// 分页参数
this.offset = Integer.parseInt(params.get("offset").toString());
this.limit = Integer.parseInt(params.get("limit").toString());
this.put("offset", offset);
this.put("page", offset / limit + 1);
this.put("limit", limit);
}
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.put("offset", offset);
}
public int getLimit() {
return limit;
}
public void setLimit(int limit) {
this.limit = limit;
}
}

View File

@ -0,0 +1,50 @@
package com.java2nb.common.utils;
import java.util.HashMap;
import java.util.Map;
public class R extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
public R() {
put("code", 0);
put("msg", "操作成功");
}
public static R error() {
return error(1, "操作失败");
}
public static R error(String msg) {
return error(500, msg);
}
public static R error(int code, String msg) {
R r = new R();
r.put("code", code);
r.put("msg", msg);
return r;
}
public static R ok(String msg) {
R r = new R();
r.put("msg", msg);
return r;
}
public static R ok(Map<String, Object> map) {
R r = new R();
r.putAll(map);
return r;
}
public static R ok() {
return new R();
}
@Override
public R put(String key, Object value) {
super.put(key, value);
return this;
}
}

View File

@ -0,0 +1,122 @@
package com.java2nb.common.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;
/**
* @author xiongxy
*/
public class RandomValidateCodeUtil {
public static final String RANDOMCODEKEY = "RANDOMVALIDATECODEKEY";//放到session中的key
private String randString = "0123456789";//随机产生只有数字的字符串 private String
//private String randString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";//随机产生只有字母的字符串
//private String randString = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";//随机产生数字与字母组合的字符串
private int width = 95;// 图片宽
private int height = 25;// 图片高
private int lineSize = 40;// 干扰线数量
private int stringNum = 4;// 随机产生字符数量
private static final Logger logger = LoggerFactory.getLogger(RandomValidateCodeUtil.class);
private Random random = new Random();
/**
* 获得字体
*/
private Font getFont() {
return new Font("Fixedsys", Font.CENTER_BASELINE, 18);
}
/**
* 获得颜色
*/
private Color getRandColor(int fc, int bc) {
if (fc > 255) {
fc = 255;
}
if (bc > 255) {
bc = 255;
}
int r = fc + random.nextInt(bc - fc - 16);
int g = fc + random.nextInt(bc - fc - 14);
int b = fc + random.nextInt(bc - fc - 18);
return new Color(r, g, b);
}
/**
* 生成随机图片
*/
public void getRandcode(HttpServletRequest request, HttpServletResponse response) {
HttpSession session = request.getSession();
// BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
Graphics g = image.getGraphics();// 产生Image对象的Graphics对象,改对象可以在图像上进行各种绘制操作
g.fillRect(0, 0, width, height);//图片大小
g.setFont(new Font("Default", Font.ROMAN_BASELINE, 18));//字体大小
g.setColor(getRandColor(110, 133));//字体颜色
// 绘制干扰线
for (int i = 0; i <= lineSize; i++) {
drowLine(g);
}
// 绘制随机字符
String randomString = "";
for (int i = 1; i <= stringNum; i++) {
randomString = drowString(g, randomString, i);
}
logger.info(randomString);
//将生成的随机字符串保存到session中
session.removeAttribute(RANDOMCODEKEY);
session.setAttribute(RANDOMCODEKEY, randomString);
g.dispose();
try {
// 将内存中的图片通过流动形式输出到客户端
ImageIO.write(image, "JPEG", response.getOutputStream());
} catch (Exception e) {
logger.error("将内存中的图片通过流动形式输出到客户端失败>>>> ", e);
}
}
/**
* 绘制字符串
*/
private String drowString(Graphics g, String randomString, int i) {
g.setFont(getFont());
g.setColor(new Color(random.nextInt(101), random.nextInt(111), random
.nextInt(121)));
String rand = String.valueOf(getRandomString(random.nextInt(randString
.length())));
randomString += rand;
g.translate(random.nextInt(3), random.nextInt(3));
g.drawString(rand, 13 * i, 16);
return randomString;
}
/**
* 绘制干扰线
*/
private void drowLine(Graphics g) {
int x = random.nextInt(width);
int y = random.nextInt(height);
int xl = random.nextInt(13);
int yl = random.nextInt(15);
g.drawLine(x, y, x + xl, y + yl);
}
/**
* 获取随机的字符
*/
public String getRandomString(int num) {
return String.valueOf(randString.charAt(num));
}
}

View File

@ -0,0 +1,601 @@
package com.java2nb.common.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@Component
@Slf4j
public final class RedisUtil {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒)
* @return
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
log.error(e.getMessage(),e);
return false;
}
}
/**
* 根据key 获取过期时间
*
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判断key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
log.error(e.getMessage(),e);
return false;
}
}
/**
* 删除缓存
*
* @param key 可以传一个值 或多个
*/
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete(CollectionUtils.arrayToList(key));
}
}
}
/**
* 普通缓存获取
*
* @param key 键
* @return 值
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 普通缓存放入
*
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
log.error(e.getMessage(),e);
return false;
}
}
/**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
log.error(e.getMessage(),e);
return false;
}
}
/**
* 递增
*
* @param key 键
* @param delta 要增加几(大于0)
* @return
*/
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* 递减
*
* @param key 键
* @param delta 要减少几(小于0)
* @return
*/
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
// ================================Map=================================
/**
* HashGet
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return 值
*/
public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
}
/**
* 获取hashKey对应的所有键值
*
* @param key 键
* @return 对应的多个键值
*/
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* HashSet
*
* @param key 键
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public boolean hmset(String key, Map<String, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
log.error(e.getMessage(),e);
return false;
}
}
/**
* HashSet 并设置时间
*
* @param key 键
* @param map 对应多个键值
* @param time 时间(秒)
* @return true成功 false失败
*/
public boolean hmset(String key, Map<String, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
log.error(e.getMessage(),e);
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
log.error(e.getMessage(),e);
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
log.error(e.getMessage(),e);
return false;
}
}
/**
* 删除hash表中的值
*
* @param key 键 不能为null
* @param item 项 可以使多个 不能为null
*/
public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
}
/**
* 判断hash表中是否有该项的值
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return true 存在 false不存在
*/
public boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
*
* @param key 键
* @param item 项
* @param by 要增加几(大于0)
* @return
*/
public double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by);
}
/**
* hash递减
*
* @param key 键
* @param item 项
* @param by 要减少记(小于0)
* @return
*/
public double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
}
/**
* 根据key获取Set中的所有值
*
* @param key 键
* @return
*/
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
log.error(e.getMessage(),e);
return null;
}
}
/**
* 根据value从一个set中查询,是否存在
*
* @param key 键
* @param value 值
* @return true 存在 false不存在
*/
public boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
log.error(e.getMessage(),e);
return false;
}
}
/**
* 将数据放入set缓存
*
* @param key 键
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
log.error(e.getMessage(),e);
return 0;
}
}
/**
* 将set数据放入缓存
*
* @param key 键
* @param time 时间(秒)
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSetAndTime(String key, long time, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if (time > 0)
expire(key, time);
return count;
} catch (Exception e) {
log.error(e.getMessage(),e);
return 0;
}
}
/**
* 获取set缓存的长度
*
* @param key 键
* @return
*/
public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
log.error(e.getMessage(),e);
return 0;
}
}
/**
* 移除值为value的
*
* @param key 键
* @param values 值 可以是多个
* @return 移除的个数
*/
public long setRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
log.error(e.getMessage(),e);
return 0;
}
}
/**
* 获取list缓存的内容
*
* @param key 键
* @param start 开始
* @param end 结束 0 到 -代表所有值
* @return
*/
public List<Object> lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
log.error(e.getMessage(),e);
return null;
}
}
/**
* 获取list缓存的长度
*
* @param key 键
* @return
*/
public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
log.error(e.getMessage(),e);
return 0;
}
}
/**
* 通过索引 获取list中的值
*
* @param key 键
* @param index 索引 index>=0时 0 表头, 第二个元素依次类推index<0时-,表尾,-倒数第二个元素,依次类推
* @return
*/
public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
log.error(e.getMessage(),e);
return null;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
log.error(e.getMessage(),e);
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0)
expire(key, time);
return true;
} catch (Exception e) {
log.error(e.getMessage(),e);
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public boolean lSet(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
log.error(e.getMessage(),e);
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, List<Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0)
expire(key, time);
return true;
} catch (Exception e) {
log.error(e.getMessage(),e);
return false;
}
}
/**
* 根据索引修改list中的某条数据
*
* @param key 键
* @param index 索引
* @param value 值
* @return
*/
public boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
log.error(e.getMessage(),e);
return false;
}
}
/**
* 移除N个值为value
*
* @param key 键
* @param count 移除多少个
* @param value 值
* @return 移除的个数
*/
public long lRemove(String key, long count, Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
log.error(e.getMessage(),e);
return 0;
}
}
}

View File

@ -0,0 +1,41 @@
package com.java2nb.common.utils;
import com.java2nb.system.domain.UserToken;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.subject.Subject;
import com.java2nb.system.domain.UserDO;
import org.springframework.beans.factory.annotation.Autowired;
import java.lang.reflect.InvocationTargetException;
import java.security.Principal;
import java.util.Collection;
import java.util.List;
public class ShiroUtils {
@Autowired
private static SessionDAO sessionDAO;
public static Subject getSubjct() {
return SecurityUtils.getSubject();
}
public static UserDO getUser() {
Object object = getSubjct().getPrincipal();
return (UserDO)object;
}
public static Long getUserId() {
return getUser().getUserId();
}
public static void logout() {
getSubjct().logout();
}
public static List<Principal> getPrinciples() {
List<Principal> principals = null;
Collection<Session> sessions = sessionDAO.getActiveSessions();
return principals;
}
}

View File

@ -0,0 +1,82 @@
//package com.java2nb.common.utils;
//
//import org.apache.commons.lang3.Validate;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//import org.springframework.beans.factory.DisposableBean;
//import org.springframework.context.ApplicationContext;
//import org.springframework.context.ApplicationContextAware;
//import org.springframework.context.annotation.Lazy;
//import org.springframework.stereotype.Service;
//
///**
// * 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候取出ApplicaitonContext.
// *
// */
//@Service
//@Lazy(false)
//public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
//
// private static ApplicationContext applicationContext = null;
//
// private static Logger logger = LoggerFactory.getLogger(SpringContextHolder.class);
//
// /**
// * 取得存储在静态变量中的ApplicationContext.
// */
// public static ApplicationContext getApplicationContext() {
// assertContextInjected();
// return applicationContext;
// }
//
// /**
// * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
// */
// @SuppressWarnings("unchecked")
// public static <T> T getBean(String name) {
// assertContextInjected();
// return (T) applicationContext.getBean(name);
// }
//
// /**
// * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
// */
// public static <T> T getBean(Class<T> requiredType) {
// assertContextInjected();
// return applicationContext.getBean(requiredType);
// }
//
// /**
// * 清除SpringContextHolder中的ApplicationContext为Null.
// */
// public static void clearHolder() {
// if (logger.isDebugEnabled()) {
// logger.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
// }
// applicationContext = null;
// }
//
// /**
// * 实现ApplicationContextAware接口, 注入Context到静态变量中.
// */
// @Override
// public void setApplicationContext(ApplicationContext applicationContext) {
// SpringContextHolder.applicationContext = applicationContext;
// }
//
// /**
// * 实现DisposableBean接口, 在Context关闭时清理静态变量.
// */
// @Override
// public void destroy() throws Exception {
// SpringContextHolder.clearHolder();
// }
//
// /**
// * 检查ApplicationContext不为空.
// */
// private static void assertContextInjected() {
// Validate.validState(applicationContext != null,
// "applicaitonContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder.");
// }
//}

View File

@ -0,0 +1,7 @@
package com.java2nb.common.utils;
/**
* @author xiongxy
*/
public class StringUtils extends org.apache.commons.lang3.StringUtils{
}

View File

@ -0,0 +1,323 @@
/**
* Copyright &copy; 2012-2016 <a href="https://github.com/thinkgem/jeesite">JeeSite</a> All rights reserved.
*/
package com.java2nb.common.utils;
import org.apache.commons.lang3.time.DateFormatUtils;
import java.util.Arrays;
import java.util.Date;
/**
* 时间计算工具类
*/
public class TimeUtils {
public static String toTimeString(long time) {
TimeUtils t = new TimeUtils(time);
int day = t.get(TimeUtils.DAY);
int hour = t.get(TimeUtils.HOUR);
int minute = t.get(TimeUtils.MINUTE);
int second = t.get(TimeUtils.SECOND);
StringBuilder sb = new StringBuilder();
if (day > 0){
sb.append(day).append("");
}
if (hour > 0){
sb.append(hour).append("");
}
if (minute > 0){
sb.append(minute).append("");
}
if (second > 0){
sb.append(second).append("");
}
return sb.toString();
}
/**
* 时间字段常量,表示“秒”
*/
public final static int SECOND = 0;
/**
* 时间字段常量,表示“分”
*/
public final static int MINUTE = 1;
/**
* 时间字段常量,表示“时”
*/
public final static int HOUR = 2;
/**
* 时间字段常量,表示“天”
*/
public final static int DAY = 3;
/**
* 各常量允许的最大值
*/
private final int[] maxFields = { 59, 59, 23, Integer.MAX_VALUE - 1 };
/**
* 各常量允许的最小值
*/
private final int[] minFields = { 0, 0, 0, Integer.MIN_VALUE };
/**
* 默认的字符串格式时间分隔符
*/
private String timeSeparator = ":";
/**
* 时间数据容器
*/
private int[] fields = new int[4];
/**
* 无参构造,将各字段置为 0
*/
public TimeUtils() {
this(0, 0, 0, 0);
}
/**
* 使用时、分构造一个时间
* @param hour 小时
* @param minute 分钟
*/
public TimeUtils(int hour, int minute) {
this(0, hour, minute, 0);
}
/**
* 使用时、分、秒构造一个时间
* @param hour 小时
* @param minute 分钟
* @param second 秒
*/
public TimeUtils(int hour, int minute, int second) {
this(0, hour, minute, second);
}
/**
* 使用一个字符串构造时间<br/>
* Time time = new Time("14:22:23");
* @param time 字符串格式的时间,默认采用“:”作为分隔符
*/
public TimeUtils(String time) {
this(time, null);
}
/**
* 使用时间毫秒构建时间
* @param time
*/
public TimeUtils(long time){
this(new Date(time));
}
/**
* 使用日期对象构造时间
* @param date
*/
public TimeUtils(Date date){
this(DateFormatUtils.formatUTC(date, "HH:mm:ss"));
}
/**
* 使用天、时、分、秒构造时间,进行全字符的构造
* @param day 天
* @param hour 时
* @param minute 分
* @param second 秒
*/
public TimeUtils(int day, int hour, int minute, int second) {
initialize(day, hour, minute, second);
}
/**
* 使用一个字符串构造时间,指定分隔符<br/>
* Time time = new Time("14-22-23", "-");
* @param time 字符串格式的时间
*/
public TimeUtils(String time, String timeSeparator) {
if(timeSeparator != null) {
setTimeSeparator(timeSeparator);
}
parseTime(time);
}
/**
* 设置时间字段的值
* @param field 时间字段常量
* @param value 时间字段的值
*/
public void set(int field, int value) {
if(value < minFields[field]) {
throw new IllegalArgumentException(value + ", time value must be positive.");
}
fields[field] = value % (maxFields[field] + 1);
// 进行进位计算
int carry = value / (maxFields[field] + 1);
if(carry > 0) {
int upFieldValue = get(field + 1);
set(field + 1, upFieldValue + carry);
}
}
/**
* 获得时间字段的值
* @param field 时间字段常量
* @return 该时间字段的值
*/
public int get(int field) {
if(field < 0 || field > fields.length - 1) {
throw new IllegalArgumentException(field + ", field value is error.");
}
return fields[field];
}
/**
* 将时间进行“加”运算,即加上一个时间
* @param time 需要加的时间
* @return 运算后的时间
*/
public TimeUtils addTime(TimeUtils time) {
TimeUtils result = new TimeUtils();
int up = 0; // 进位标志
for (int i = 0; i < fields.length; i++) {
int sum = fields[i] + time.fields[i] + up;
up = sum / (maxFields[i] + 1);
result.fields[i] = sum % (maxFields[i] + 1);
}
return result;
}
/**
* 将时间进行“减”运算,即减去一个时间
* @param time 需要减的时间
* @return 运算后的时间
*/
public TimeUtils subtractTime(TimeUtils time) {
TimeUtils result = new TimeUtils();
int down = 0; // 退位标志
for (int i = 0, k = fields.length - 1; i < k; i++) {
int difference = fields[i] + down;
if (difference >= time.fields[i]) {
difference -= time.fields[i];
down = 0;
} else {
difference += maxFields[i] + 1 - time.fields[i];
down = -1;
}
result.fields[i] = difference;
}
result.fields[DAY] = fields[DAY] - time.fields[DAY] + down;
return result;
}
/**
* 获得时间字段的分隔符
* @return
*/
public String getTimeSeparator() {
return timeSeparator;
}
/**
* 设置时间字段的分隔符(用于字符串格式的时间)
* @param timeSeparator 分隔符字符串
*/
public void setTimeSeparator(String timeSeparator) {
this.timeSeparator = timeSeparator;
}
private void initialize(int day, int hour, int minute, int second) {
set(DAY, day);
set(HOUR, hour);
set(MINUTE, minute);
set(SECOND, second);
}
private void parseTime(String time) {
if(time == null) {
initialize(0, 0, 0, 0);
return;
}
String t = time;
int field = DAY;
set(field--, 0);
int p = -1;
while((p = t.indexOf(timeSeparator)) > -1) {
parseTimeField(time, t.substring(0, p), field--);
t = t.substring(p + timeSeparator.length());
}
parseTimeField(time, t, field--);
}
private void parseTimeField(String time, String t, int field) {
if(field < SECOND || t.length() < 1) {
parseTimeException(time);
}
char[] chs = t.toCharArray();
int n = 0;
for(int i = 0; i < chs.length; i++) {
if(chs[i] <= ' ') {
continue;
}
if(chs[i] >= '0' && chs[i] <= '9') {
n = n * 10 + chs[i] - '0';
continue;
}
parseTimeException(time);
}
set(field, n);
}
private void parseTimeException(String time) {
throw new IllegalArgumentException(time + ", time format error, HH"
+ this.timeSeparator + "mm" + this.timeSeparator + "ss");
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(16);
sb.append(fields[DAY]).append(',').append(' ');
buildString(sb, HOUR).append(timeSeparator);
buildString(sb, MINUTE).append(timeSeparator);
buildString(sb, SECOND);
return sb.toString();
}
private StringBuilder buildString(StringBuilder sb, int field) {
if(fields[field] < 10) {
sb.append('0');
}
return sb.append(fields[field]);
}
public int hashCode() {
final int PRIME = 31;
int result = 1;
result = PRIME * result + Arrays.hashCode(fields);
return result;
}
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final TimeUtils other = (TimeUtils) obj;
if (!Arrays.equals(fields, other.fields)) {
return false;
}
return true;
}
}

View File

@ -0,0 +1,5 @@
package com.java2nb.common.utils;
public class UploadUtils {
}

View File

@ -0,0 +1,61 @@
package com.java2nb.common.xss;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.Arrays;
import java.util.List;
public class XssAndSqlHttpServletRequestWrapper extends HttpServletRequestWrapper {
private HttpServletRequest request;
/**
* 假如有有html 代码是自己传来的 需要设定对应的name 不过滤
*/
private static final List<String> noFilterNames = Arrays.asList("attach","push_ip","content");
public XssAndSqlHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
this.request = request;
}
@Override
public String getParameter(String name) {
String value = request.getParameter(name);
if (!StringUtils.isEmpty(value) && !noFilterNames.contains(name)) {
value = htmlEncodeByRegExp(value);
}
return value;
}
@Override
public String[] getParameterValues(String name) {
String[] parameterValues = super.getParameterValues(name);
if (parameterValues == null || noFilterNames.contains(name)) {
return parameterValues;
}
for (int i = 0; i < parameterValues.length; i++) {
String value = parameterValues[i];
if (!StringUtils.isEmpty(value)){
parameterValues[i] = htmlEncodeByRegExp(value);
}
}
return parameterValues;
}
private String htmlEncodeByRegExp(String str) {
String temp = "" ;
temp = str
//.replaceAll("&", "&amp;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;");
//.replaceAll("\\s", "&nbsp;")
//.replaceAll("\'", "&#39;")
//.replaceAll("\"", "&quot;");
return temp;
}
}

View File

@ -0,0 +1,45 @@
package com.java2nb.common.xss;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@WebFilter(filterName = "xssFilter", urlPatterns = "/*", asyncSupported = true)
@Component
public class XssFilter implements Filter {
private static final List<String> NO_XSS_PATH = Arrays.asList("/common/generator/batchCode","/common/generator/batchDownload");
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletRequest req = (HttpServletRequest) request;
String reqURI = req.getRequestURI();
if(NO_XSS_PATH.contains(reqURI)){
chain.doFilter(request,response);
}else {
XssAndSqlHttpServletRequestWrapper xssRequestWrapper = new XssAndSqlHttpServletRequestWrapper(req);
chain.doFilter(xssRequestWrapper, response);
}
}
@Override
public void init(FilterConfig arg0) {
// TODO Auto-generated method stub
}
}

View File

@ -0,0 +1,28 @@
package com.java2nb.common.xss;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.apache.commons.text.StringEscapeUtils;
import java.io.IOException;
public class XssStringJsonSerializer extends JsonSerializer<String> {
@Override
public Class<String> handledType() {
return String.class;
}
/**
* 假如有html代码是自己传来的,需要设定对应的name,不走StringEscapeUtils.escapeHtml4(value)过滤
*/
@Override
public void serialize(String value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
throws IOException {
if (value != null) {
String encodedValue = StringEscapeUtils.escapeHtml4(value);
jsonGenerator.writeString(encodedValue);
}
}
}

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