├── .gitignore ├── README.md ├── back ├── .gitignore ├── Dockerfile ├── pom.xml ├── sql │ ├── shiny-data.sql │ └── shiny.sql └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── xkcoding │ │ │ └── shiny │ │ │ ├── ShinyApplication.java │ │ │ ├── common │ │ │ ├── ApiResponse.java │ │ │ ├── MyMapper.java │ │ │ ├── PageResult.java │ │ │ ├── ShinyConst.java │ │ │ ├── property │ │ │ │ └── ShinyProperties.java │ │ │ └── status │ │ │ │ ├── OperateStatus.java │ │ │ │ └── Status.java │ │ │ ├── config │ │ │ ├── AsyncConfig.java │ │ │ ├── ModelMapperConfig.java │ │ │ ├── RedisListenerConfig.java │ │ │ ├── RedisReceiverConfig.java │ │ │ └── ScheduleConfig.java │ │ │ ├── controller │ │ │ ├── SpiderConfigController.java │ │ │ ├── SpiderContentController.java │ │ │ ├── SpiderController.java │ │ │ └── SpiderLogController.java │ │ │ ├── exception │ │ │ └── ShinyException.java │ │ │ ├── handler │ │ │ └── GlobalExceptionHandler.java │ │ │ ├── mapper │ │ │ ├── EmailLogMapper.java │ │ │ ├── SpiderConfigMapper.java │ │ │ ├── SpiderContentMapper.java │ │ │ ├── SpiderLogMapper.java │ │ │ ├── SysConfigMapper.java │ │ │ ├── SysRoleMapper.java │ │ │ ├── SysUserMapper.java │ │ │ └── SysUserRoleMapper.java │ │ │ ├── model │ │ │ ├── EmailLogDO.java │ │ │ ├── SpiderConfigDO.java │ │ │ ├── SpiderContentDO.java │ │ │ ├── SpiderLogDO.java │ │ │ ├── SysConfigDO.java │ │ │ ├── SysRoleDO.java │ │ │ ├── SysUserDO.java │ │ │ ├── SysUserRoleDO.java │ │ │ ├── query │ │ │ │ ├── SpiderConfigPageQuery.java │ │ │ │ ├── SpiderContentPageQuery.java │ │ │ │ ├── SpiderLogPageQuery.java │ │ │ │ └── base │ │ │ │ │ └── PageCondition.java │ │ │ └── vo │ │ │ │ ├── SpiderConfigVO.java │ │ │ │ └── SpiderContentVO.java │ │ │ ├── service │ │ │ ├── IMailService.java │ │ │ ├── ISpiderConfigService.java │ │ │ ├── ISpiderContentService.java │ │ │ ├── ISpiderLogService.java │ │ │ ├── ISpiderService.java │ │ │ └── impl │ │ │ │ ├── MailServiceImpl.java │ │ │ │ ├── SpiderConfigServiceImpl.java │ │ │ │ ├── SpiderContentServiceImpl.java │ │ │ │ ├── SpiderLogServiceImpl.java │ │ │ │ └── SpiderServiceImpl.java │ │ │ ├── task │ │ │ ├── NotificationTask.java │ │ │ ├── SpiderTask.java │ │ │ ├── SpiderTaskFactory.java │ │ │ └── SpiderTaskManager.java │ │ │ └── util │ │ │ ├── DriverUtil.java │ │ │ ├── ShinyUtil.java │ │ │ └── SpringContextHolderUtil.java │ └── resources │ │ ├── META-INF │ │ └── additional-spring-configuration-metadata.json │ │ ├── application.yml │ │ ├── banner.txt │ │ ├── beetl.properties │ │ ├── email │ │ └── software-update.html │ │ ├── logback-spring.xml │ │ └── mybatis │ │ ├── generator │ │ ├── datasource.properties │ │ └── generatorConfig.xml │ │ └── mapper │ │ ├── EmailLogMapper.xml │ │ ├── SpiderConfigMapper.xml │ │ ├── SpiderContentMapper.xml │ │ ├── SpiderLogMapper.xml │ │ ├── SysConfigMapper.xml │ │ ├── SysRoleMapper.xml │ │ ├── SysUserMapper.xml │ │ └── SysUserRoleMapper.xml │ └── test │ └── java │ └── com │ └── xkcoding │ └── shiny │ ├── ShinyApplicationTests.java │ ├── service │ └── impl │ │ └── MailServiceImplTest.java │ └── spider │ ├── ChromeDriverTest.java │ ├── PhantomJsTest.java │ ├── SpiderTest.java │ ├── XclientSpiderChromeTest.java │ └── XclientSpiderPhantomJsTest.java ├── front ├── .browserslistrc ├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── README.md ├── babel.config.js ├── package.json ├── postcss.config.js ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── App.vue │ ├── api │ │ └── index.js │ ├── assets │ │ └── images │ │ │ ├── avatar.jpg │ │ │ └── logo.png │ ├── components │ │ └── common │ │ │ └── custom-layout.vue │ ├── config │ │ └── index.js │ ├── directive │ │ └── index.js │ ├── lib │ │ ├── tools.js │ │ └── util.js │ ├── main.js │ ├── mock │ │ └── index.js │ ├── router │ │ ├── index.js │ │ └── router.js │ ├── store │ │ ├── actions.js │ │ ├── index.js │ │ ├── mutations.js │ │ └── state.js │ └── views │ │ ├── App.vue │ │ ├── Dev.vue │ │ ├── Manage.vue │ │ └── Push.vue ├── vue.config.js └── yarn.lock └── mysql ├── Dockerfile ├── mysqld.cnf ├── setup.sh └── sql ├── privileges.sql ├── shiny-data.sql └── shiny.sql /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### xkcoding-后端 template 3 | ### Spring Boot ### 4 | /target/ 5 | !.mvn/wrapper/maven-wrapper.jar 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.ipr 20 | out/ 21 | gen/ 22 | 23 | ### NetBeans ### 24 | /nbproject/private/ 25 | /build/ 26 | /nbbuild/ 27 | /dist/ 28 | /nbdist/ 29 | /.nb-gradle/ 30 | 31 | ### LOGS ### 32 | logs/ 33 | *.log 34 | 35 | ### Mac OS ### 36 | .DS_Store 37 | 38 | ### xkcoding-前端 template 39 | # Logs 40 | logs 41 | npm-debug.log* 42 | yarn-debug.log* 43 | yarn-error.log* 44 | 45 | # Runtime data 46 | pids 47 | *.pid 48 | *.seed 49 | *.pid.lock 50 | 51 | # Directory for instrumented libs generated by jscoverage/JSCover 52 | lib-cov 53 | 54 | # Coverage directory used by tools like istanbul 55 | coverage 56 | 57 | # nyc test coverage 58 | .nyc_output 59 | 60 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 61 | .grunt 62 | 63 | # Bower dependency directory (https://bower.io/) 64 | bower_components 65 | 66 | # node-waf configuration 67 | .lock-wscript 68 | 69 | # Compiled binary addons (https://nodejs.org/api/addons.html) 70 | build/Release 71 | 72 | # Dependency directories 73 | node_modules/ 74 | jspm_packages/ 75 | 76 | # TypeScript v1 declaration files 77 | typings/ 78 | 79 | # Optional npm cache directory 80 | .npm 81 | 82 | # Optional eslint cache 83 | .eslintcache 84 | 85 | # Optional REPL history 86 | .node_repl_history 87 | 88 | # Output of 'npm pack' 89 | *.tgz 90 | 91 | # Yarn Integrity file 92 | .yarn-integrity 93 | 94 | # dotenv environment variables file 95 | .env 96 | 97 | # parcel-bundler cache (https://parceljs.org/) 98 | .cache 99 | 100 | # next.js build output 101 | .next 102 | 103 | # nuxt.js build output 104 | .nuxt 105 | 106 | # vuepress build output 107 | .vuepress/dist 108 | 109 | # Serverless directories 110 | .serverless 111 | back/driver/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # shiny-telegram 2 | 3 | > 译为:闪耀的电报,为什么要取这个名字?因为 github 新建项目的时候有个随机名。。。 4 | 5 | ## 主要功能 6 | 1. 解析 http://xclient.info 网站获取对应软件历史版本 7 | 2. 软件名和对应在 xclient.info 的网页地址维护管理接口 8 | 3. 列表展示软件最近更新版本,以及最近更新时间 9 | 4. 点击列表页可以查看某个软件具体信息,包括软件基本信息,所有版本信息,所有版本更新时间,所有版本下载地址及提取码 10 | 5. 每天9点定时检查所有配置软件,若有最近两天更新的软件,则把最近更新的软件列表统一发邮件通知 11 | 12 | ## 使用技术 13 | 1. Spring Boot 后台框架 14 | 2. Spring Task 定时任务 15 | 3. Spring Email 邮件通知 16 | 4. Selenium + ChromeDriver( https://sites.google.com/a/chromium.org/chromedriver/downloads )/PhantomJs( http://phantomjs.org/download.html ) 模拟浏览器行为处理反爬 17 | 5. Jsoup + Xsoup 解析 DOM 节点 18 | 6. Mysql 存储 19 | 7. Vue + iView 前端框架 20 | 21 | ## 项目目录 22 | ```bash 23 | . 24 | ├── README.md 项目介绍 25 | ├── back 项目后端 26 | ├── front 项目前端 27 | └── mysql 项目 mysql docker镜像构建文件 28 | ``` 29 | 30 | ## 项目构建与运行 31 | ### 项目构建 32 | #### mysql 镜像构建 33 | 1. 构建 `mysql` 镜像 34 | ```bash 35 | $ cd mysql 36 | $ docker build -t shiny-mysql . 37 | Sending build context to Docker daemon 24.06kB 38 | Step 1/9 : FROM mysql:5.7 39 | ---> 0d16d0a97dd1 40 | Step 2/9 : MAINTAINER yangkai.shen 237497819@qq.com 41 | ---> Running in 7f5fa09ba5dd 42 | Removing intermediate container 7f5fa09ba5dd 43 | ---> 7188872d8492 44 | Step 3/9 : ENV MYSQL_ALLOW_EMPTY_PASSWORD yes 45 | ---> Running in f11ed6362744 46 | Removing intermediate container f11ed6362744 47 | ---> dbc977df5488 48 | Step 4/9 : COPY setup.sh /mysql/setup.sh 49 | ---> 7f31fff84f9e 50 | Step 5/9 : COPY sql/shiny.sql /mysql/shiny.sql 51 | ---> 44e65ddf7fa9 52 | Step 6/9 : COPY sql/shiny-data.sql /mysql/shiny-data.sql 53 | ---> 2a86658ba4f9 54 | Step 7/9 : COPY sql/privileges.sql /mysql/privileges.sql 55 | ---> 44b44deb7d07 56 | Step 8/9 : COPY ./mysqld.cnf /etc/mysql/mysql.conf.d/mysqld.cnf 57 | ---> 14a88aec77c0 58 | Step 9/9 : CMD ["sh", "/mysql/setup.sh"] 59 | ---> Running in e0e78e73e646 60 | Removing intermediate container e0e78e73e646 61 | ---> 8ea97c1bf792 62 | Successfully built 8ea97c1bf792 63 | Successfully tagged shiny-mysql:latest 64 | ``` 65 | 2. 运行 `mysql` 镜像 66 | 67 | ```bash 68 | $ mkdir -p $HOME/docker/shiny/mysql/data 69 | $ mkdir -p $HOME/docker/shiny/mysql/logs 70 | $ docker run -d --name shiny-mysql -p 13306:3306 -v $HOME/shiny/mysql/data:/var/lib/mysql -v $HOME/shiny/mysql/logs:/logs shiny-mysql 71 | 974de62c11fb294b2330af339f8b07299a69f956f2a0df1ee5d2e8cbab1dd485 72 | ``` 73 | 3. 查看镜像构建日志 74 | ```bash 75 | $ docker logs shiny-mysql 76 | 0.设置时区为东八区.... 77 | 2018-09-10 22:59:56 78 | MySQL Community Server 5.7.22 is not running. 79 | 1.启动mysql.... 80 | .. 81 | MySQL Community Server 5.7.22 is started. 82 | MySQL Community Server 5.7.22 is running. 83 | 2.开始创建数据库和表结构.... 84 | 3.创建数据库和表结构完毕.... 85 | 4.开始导入数据.... 86 | 5.导入数据完毕.... 87 | MySQL Community Server 5.7.22 is running. 88 | 6.开始修改密码.... 89 | host user 90 | localhost mysql.session 91 | localhost mysql.sys 92 | localhost root 93 | 7.修改密码完毕.... 94 | MySQL Community Server 5.7.22 is running. 95 | /mysql/setup.sh: 1: /mysql/setup.sh: mysql容器启动完毕,且数据导入成功: not found 96 | ``` 97 | 98 | ### 项目运行 99 | #### 源码运行 100 | 101 | #### 镜像运行 102 | 1. `mysql` 镜像 103 | - 使用上面自己构建的镜像 104 | - 拉取远端镜像,`docker pull registry.cn-hangzhou.aliyuncs.com/xkcoding/shiny-telegram-mysql:latest` 105 | 2. 运行 `mysql` 镜像 106 | ```bash 107 | $ mkdir -p $HOME/docker/shiny/mysql/data 108 | $ mkdir -p $HOME/docker/shiny/mysql/logs 109 | $ docker run -d --name shiny-mysql -p 13306:3306 -v $HOME/shiny/mysql/data:/var/lib/mysql -v $HOME/shiny/mysql/logs:/logs registry.cn-hangzhou.aliyuncs.com/xkcoding/shiny-telegram-mysql:latest 110 | 014226044c171d37a122128765b618560b992909eda6ccc71f07584a7fea6569 111 | ``` 112 | 113 | 114 | ## 项目截图 115 | 116 | ## 联系我 117 | - 邮箱: 237497819@qq.com 118 | - 扣扣: 237497819 -------------------------------------------------------------------------------- /back/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ -------------------------------------------------------------------------------- /back/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM hub.c.163.com/library/java:8-alpine 2 | 3 | MAINTAINER yangkai.shen 237497819@qq.com 4 | 5 | ADD target/*.jar back.jar 6 | 7 | EXPOSE 8080 8 | 9 | ENTRYPOINT ["java", "-jar", "/back.jar"] 10 | -------------------------------------------------------------------------------- /back/sql/shiny-data.sql: -------------------------------------------------------------------------------- 1 | use `shiny`; 2 | -- ---------------------------- 3 | -- 5、采集配置表数据 4 | -- ---------------------------- 5 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1, 'Movist', 'http://xclient.info/s/movist.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '一款CPU占用率低的高清多格式媒体播放器'); 6 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2, 'Things', 'http://xclient.info/s/things.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '一款优秀的GTD任务管理工具'); 7 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (3, 'iStatistica', 'http://xclient.info/s/istatistica.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '一款高颜值的系统监控工具'); 8 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (4, 'TinyCal', 'http://xclient.info/s/tinycal.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '小历 - 小而美的日历'); 9 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (5, 'Money Pro', 'http://xclient.info/s/money-pro.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '可同步账单、预算和账户'); 10 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (6, 'OmniPlan', 'http://xclient.info/s/omni-plan.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '专业版 最NB的项目管理流程软件'); 11 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (7, 'Navicat Premium', 'http://xclient.info/s/navicat-premium.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '强大的数据库管理工具'); 12 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (8, 'OmniGraffle Pro', 'http://xclient.info/s/omnigraffle.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '强大的图形工具'); 13 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (9, 'XMind 8 Pro', 'http://xclient.info/s/xmind.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '最受欢迎思维导图软件'); 14 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (10, 'StarUML', 'http://xclient.info/s/staruml.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '强大的UML工具'); 15 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (11, 'ScreenFlow', 'http://xclient.info/s/screenflow.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '优秀的屏幕录像软件'); 16 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (12, 'EdrawMax', 'http://xclient.info/s/edraw-max.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '亿图图示专家 基于矢量的绘图工具'); 17 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (13, 'Charles', 'http://xclient.info/s/charles.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', 'Mac上的抓包工具'); 18 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (14, 'SnippetsLab', 'http://xclient.info/s/snippetslab.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '构建你的私人代码片段库'); 19 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (15, 'Adobe Photoshop CC', 'http://xclient.info/s/adobe-photoshop-cc.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', ''); 20 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (16, 'Adobe Photoshop Lightroom CC', 'http://xclient.info/s/adobe-lightroom-cc.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', ''); 21 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (17, 'VMware Fusion', 'http://xclient.info/s/vmware-fusion.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '强大的虚拟机应用'); 22 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (18, 'Tuxera NTFS', 'http://xclient.info/s/tuxera-ntfs.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '让你的Mac支持NTFS'); 23 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (19, 'Parallels Desktop', 'http://xclient.info/s/parallels-desktop.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '最佳Mac虚拟机解决方案'); 24 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (20, 'Microsoft Office', 'http://xclient.info/s/office-for-mac.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '多国语言大客户版'); 25 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (21, 'Beyond Compare', 'http://xclient.info/s/beyond-compare.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '文件对比利器'); 26 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (22, 'Sublime Text', 'http://xclient.info/s/sublime-text.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '一款优秀的代码编辑器'); 27 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (23, 'UltraEdit', 'http://xclient.info/s/ultraedit.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '老牌文本编辑器'); 28 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (24, 'Understand', 'http://xclient.info/s/understand.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '代码阅读分析软件'); 29 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (25, 'Paste', 'http://xclient.info/s/paste-for-mac.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '剪切板增强工具'); 30 | -------------------------------------------------------------------------------- /back/sql/shiny.sql: -------------------------------------------------------------------------------- 1 | -- 创建数据库 2 | create database IF NOT EXISTS `shiny` default character set utf8 collate utf8_general_ci; 3 | 4 | use `shiny`; 5 | 6 | -- ---------------------------- 7 | -- 1、参数配置表 8 | -- ---------------------------- 9 | CREATE TABLE IF NOT EXISTS `sys_config` ( 10 | `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '参数主键', 11 | `config_name` varchar(100) DEFAULT '' COMMENT '参数名称', 12 | `config_key` varchar(100) DEFAULT '' COMMENT '参数键名', 13 | `config_value` varchar(100) DEFAULT '' COMMENT '参数键值', 14 | `config_type` int(2) DEFAULT 0 COMMENT '系统内置(0否 1是)', 15 | `create_by` varchar(64) DEFAULT '' COMMENT '创建者', 16 | `create_time` datetime DEFAULT NULL COMMENT '创建时间', 17 | `update_by` varchar(64) DEFAULT '' COMMENT '更新者', 18 | `update_time` datetime DEFAULT NULL COMMENT '更新时间', 19 | `remark` varchar(500) DEFAULT '' COMMENT '备注', 20 | PRIMARY KEY (`id`) 21 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='参数配置表'; 22 | 23 | -- ---------------------------- 24 | -- 2、系统用户表 25 | -- ---------------------------- 26 | CREATE TABLE IF NOT EXISTS `sys_user` ( 27 | `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID', 28 | `dept_id` int(11) DEFAULT NULL COMMENT '部门ID', 29 | `login_name` varchar(30) NOT NULL COMMENT '登录账号', 30 | `user_name` varchar(30) NOT NULL COMMENT '用户昵称', 31 | `user_type` varchar(2) DEFAULT '00' COMMENT '用户类型(00系统用户)', 32 | `email` varchar(50) DEFAULT '' COMMENT '用户邮箱', 33 | `phonenumber` varchar(11) DEFAULT '' COMMENT '手机号码', 34 | `sex` int(2) DEFAULT 0 COMMENT '用户性别(0男 1女 2未知)', 35 | `avatar` varchar(100) DEFAULT '' COMMENT '头像路径', 36 | `password` varchar(100) DEFAULT '' COMMENT '密码', 37 | `status` int(2) DEFAULT 1 COMMENT '帐号状态(0停用 1正常)', 38 | `del_flag` int(2) DEFAULT 0 COMMENT '删除标志(0代表存在 1代表删除)', 39 | `login_ip` varchar(20) DEFAULT '' COMMENT '最后登陆IP', 40 | `login_date` datetime DEFAULT NULL COMMENT '最后登陆时间', 41 | `create_by` varchar(64) DEFAULT '' COMMENT '创建者', 42 | `create_time` datetime DEFAULT NULL COMMENT '创建时间', 43 | `update_by` varchar(64) DEFAULT '' COMMENT '更新者', 44 | `update_time` datetime DEFAULT NULL COMMENT '更新时间', 45 | `remark` varchar(500) DEFAULT '' COMMENT '备注', 46 | PRIMARY KEY (`id`) 47 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='系统用户表'; 48 | 49 | -- ---------------------------- 50 | -- 3、角色信息表 51 | -- ---------------------------- 52 | CREATE TABLE IF NOT EXISTS `sys_role` ( 53 | `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '角色ID', 54 | `role_name` varchar(30) NOT NULL COMMENT '角色名称', 55 | `role_key` varchar(100) NOT NULL COMMENT '角色权限字符串', 56 | `role_sort` int(4) NOT NULL COMMENT '显示顺序', 57 | `status` int(2) DEFAULT 1 COMMENT '角色状态(0停用 1正常)', 58 | `create_by` varchar(64) DEFAULT '' COMMENT '创建者', 59 | `create_time` datetime DEFAULT NULL COMMENT '创建时间', 60 | `update_by` varchar(64) DEFAULT '' COMMENT '更新者', 61 | `update_time` datetime DEFAULT NULL COMMENT '更新时间', 62 | `remark` varchar(500) DEFAULT '' COMMENT '备注', 63 | PRIMARY KEY (`id`) 64 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色信息表'; 65 | 66 | -- ---------------------------- 67 | -- 4、用户和角色关联表 68 | -- ---------------------------- 69 | CREATE TABLE IF NOT EXISTS `sys_user_role` ( 70 | `user_id` int(11) NOT NULL COMMENT '用户ID', 71 | `role_id` int(11) NOT NULL COMMENT '角色ID', 72 | PRIMARY KEY (`user_id`,`role_id`) 73 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户和角色关联表'; 74 | 75 | -- ---------------------------- 76 | -- 5、采集配置 77 | -- ---------------------------- 78 | CREATE TABLE IF NOT EXISTS `spider_config` ( 79 | `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '配置主键', 80 | `spider_name` varchar(100) DEFAULT '' COMMENT '采集名称', 81 | `spider_url` varchar(500) DEFAULT '' COMMENT '采集URL', 82 | `last_spider_time` datetime DEFAULT NULL COMMENT '上次采集时间', 83 | `create_by` varchar(64) DEFAULT '' COMMENT '创建者', 84 | `create_time` datetime DEFAULT NULL COMMENT '创建时间', 85 | `update_by` varchar(64) DEFAULT '' COMMENT '更新者', 86 | `update_time` datetime DEFAULT NULL COMMENT '更新时间', 87 | `remark` varchar(500) DEFAULT '' COMMENT '备注', 88 | PRIMARY KEY (`id`) 89 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='采集配置'; 90 | 91 | -- ---------------------------- 92 | -- 6、采集内容 93 | -- ---------------------------- 94 | CREATE TABLE IF NOT EXISTS `spider_content` ( 95 | `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '内容主键', 96 | `config_id` int(11) NOT NULL COMMENT '采集配置id', 97 | `config_name` varchar(100) NOT NULL COMMENT '采集配置名称', 98 | `title` varchar(100) DEFAULT '' COMMENT '软件名称', 99 | `content` text COMMENT '软件详细信息', 100 | `version` varchar(100) DEFAULT '' COMMENT '软件版本', 101 | `language` varchar(100) DEFAULT '' COMMENT '软件语言', 102 | `update_time` date DEFAULT NULL COMMENT '软件更新时间', 103 | `size` varchar(100) DEFAULT '' COMMENT '软件大小', 104 | `ct_pan_url` varchar(500) DEFAULT '' COMMENT '城通网盘链接', 105 | `ct_pan_code` varchar(500) DEFAULT '' COMMENT '城通网盘提取码', 106 | `bd_pan_url` varchar(500) DEFAULT '' COMMENT '百度网盘链接', 107 | `bd_pan_code` varchar(500) DEFAULT '' COMMENT '百度网盘提取码', 108 | `spider_time` datetime DEFAULT NULL COMMENT '采集时间', 109 | PRIMARY KEY (`id`) 110 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='采集内容'; 111 | 112 | -- ---------------------------- 113 | -- 7、采集日志记录 114 | -- ---------------------------- 115 | CREATE TABLE IF NOT EXISTS `spider_log` ( 116 | `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '日志主键', 117 | `config_id` int(11) NOT NULL COMMENT '采集配置 id', 118 | `spider_name` varchar(100) DEFAULT '' COMMENT '采集名称', 119 | `version` varchar(100) DEFAULT '' COMMENT '采集版本', 120 | `spider_url` varchar(500) DEFAULT '' COMMENT '采集URL', 121 | `status` int(2) DEFAULT 1 COMMENT '采集状态(0异常 1正常)', 122 | `error_msg` varchar(2000) DEFAULT '' COMMENT '错误消息', 123 | `spider_time` datetime DEFAULT NULL COMMENT '采集时间', 124 | PRIMARY KEY (`id`) 125 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='采集日志记录'; 126 | 127 | -- ---------------------------- 128 | -- 8、邮件记录 129 | -- ---------------------------- 130 | CREATE TABLE IF NOT EXISTS `email_log` ( 131 | `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '邮件主键', 132 | `to` text NOT NULL COMMENT '收件人邮箱地址(多个逗号分隔)', 133 | `subject` varchar(100) DEFAULT '' COMMENT '邮件主题', 134 | `content` text NOT NULL COMMENT '邮件内容', 135 | `is_template` int(2) DEFAULT 1 COMMENT '是否是模板邮件(0否 1是)', 136 | `template_path` varchar(100) DEFAULT NULL COMMENT '模板路径', 137 | `template_name` varchar(100) DEFAULT NULL COMMENT '模板名称', 138 | `send_time` datetime DEFAULT NULL COMMENT '邮件发送时间', 139 | PRIMARY KEY (`id`) 140 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='邮件记录'; -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/ShinyApplication.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny; 2 | 3 | import com.xkcoding.shiny.common.property.ShinyProperties; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 7 | import tk.mybatis.spring.annotation.MapperScan; 8 | 9 | /** 10 | *

11 | * 后端启动类 12 | *

13 | * 14 | * @package: com.xkcoding.shiny 15 | * @description: 后端启动类 16 | * @author: yangkai.shen 17 | * @date: Created in 2018/8/15 上午10:24 18 | * @copyright: Copyright (c) 2018 19 | * @version: V1.0 20 | * @modified: yangkai.shen 21 | */ 22 | @SpringBootApplication 23 | @MapperScan(basePackages = {"com.xkcoding.shiny.mapper"}) 24 | @EnableConfigurationProperties(ShinyProperties.class) 25 | public class ShinyApplication { 26 | 27 | public static void main(String[] args) { 28 | SpringApplication.run(ShinyApplication.class, args); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/common/ApiResponse.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.common; 2 | 3 | import com.xkcoding.shiny.common.status.Status; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | *

10 | * API 统一返回格式封装 11 | *

12 | * 13 | * @package: com.xkcoding.shiny.common 14 | * @description: API 统一返回格式封装 15 | * @author: yangkai.shen 16 | * @date: Created in 2018/8/15 下午8:42 17 | * @copyright: Copyright (c) 2018 18 | * @version: V1.0 19 | * @modified: yangkai.shen 20 | */ 21 | @Data 22 | public class ApiResponse implements Serializable { 23 | 24 | private static final long serialVersionUID = 1672493411204459264L; 25 | 26 | /** 27 | * 返回码 28 | */ 29 | private Integer code; 30 | 31 | /** 32 | * 返回信息 33 | */ 34 | private String msg; 35 | 36 | /** 37 | * 返回数据 38 | */ 39 | private Object data; 40 | 41 | /** 42 | * 默认构造 43 | */ 44 | public ApiResponse() { 45 | this.code = Status.SUCCESS.getCode(); 46 | this.msg = Status.SUCCESS.getMsg(); 47 | } 48 | 49 | /** 50 | * 构造 API 返回对象 51 | * 52 | * @param code 返回码 53 | * @param msg 返回信息 54 | * @param data 数据 55 | */ 56 | public ApiResponse(Integer code, String msg, Object data) { 57 | this.code = code; 58 | this.msg = msg; 59 | this.data = data; 60 | } 61 | 62 | /** 63 | * 通用构造包含返回信息的 ApiResponse
64 | * 主要用于只包含返回信息,不包含数据时的返回 65 | * 66 | * @param code 状态码 67 | * @param msg 信息 68 | * @return ApiResponse 69 | */ 70 | public static ApiResponse of(int code, String msg, Object data) { 71 | return new ApiResponse(code, msg, data); 72 | } 73 | 74 | /** 75 | * 通用构造包含返回信息的 ApiResponse
76 | * 主要用于只包含返回信息,不包含数据时的返回 77 | * 78 | * @param code 状态码 79 | * @param msg 信息 80 | * @return ApiResponse 81 | */ 82 | public static ApiResponse ofMessage(int code, String msg) { 83 | return new ApiResponse(code, msg, null); 84 | } 85 | 86 | /** 87 | * 通用构造包含返回信息的 ApiResponse
88 | * 主要用于只包含返回信息,不包含数据时的返回 89 | * 90 | * @param msg 信息 91 | * @return ApiResponse 92 | */ 93 | public static ApiResponse ofMessage(String msg) { 94 | return new ApiResponse(Status.SUCCESS.getCode(), msg, null); 95 | } 96 | 97 | /** 98 | * 通用构造包含返回数据的 ApiResponse
99 | * 主要用于操作成功时的返回(不带数据) 100 | * 101 | * @return ApiResponse 102 | */ 103 | public static ApiResponse ofSuccess() { 104 | return new ApiResponse(Status.SUCCESS.getCode(), Status.SUCCESS.getMsg(), null); 105 | } 106 | 107 | /** 108 | * 通用构造包含返回数据的 ApiResponse
109 | * 主要用于操作成功时的返回 110 | * 111 | * @param data 操作成功时需要返回的数据 112 | * @return ApiResponse 113 | */ 114 | public static ApiResponse ofSuccess(Object data) { 115 | return new ApiResponse(Status.SUCCESS.getCode(), Status.SUCCESS.getMsg(), data); 116 | } 117 | 118 | /** 119 | * 通过 Status 构造 ApiResponse
120 | * 主要用于出现异常时的返回 121 | * 122 | * @param status {@link Status} 123 | * @return ApiResponse 124 | */ 125 | public static ApiResponse ofStatus(Status status) { 126 | return new ApiResponse(status.getCode(), status.getMsg(), null); 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/common/MyMapper.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.common; 2 | 3 | import tk.mybatis.mapper.common.Mapper; 4 | import tk.mybatis.mapper.common.MySqlMapper; 5 | 6 | /** 7 | *

8 | * 通用 Mapper 9 | *

10 | * 11 | * @package: com.xkcoding.shiny.common 12 | * @description: 通用 Mapper 13 | * @author: yangkai.shen 14 | * @date: Created in 2018/8/15 下午6:43 15 | * @copyright: Copyright (c) 2018 16 | * @version: V1.0 17 | * @modified: yangkai.shen 18 | */ 19 | public interface MyMapper extends Mapper, MySqlMapper { 20 | } 21 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/common/PageResult.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.common; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | *

11 | * 分页结果 12 | *

13 | * 14 | * @package: com.xkcoding.shiny.common 15 | * @description: 分页结果 16 | * @author: yangkai.shen 17 | * @date: Created in 2018/8/15 下午10:00 18 | * @copyright: Copyright (c) 2018 19 | * @version: V1.0 20 | * @modified: yangkai.shen 21 | */ 22 | @Data 23 | @NoArgsConstructor 24 | @AllArgsConstructor 25 | public class PageResult { 26 | /** 27 | * 总条数 28 | */ 29 | private Long total; 30 | 31 | /** 32 | * 列表数据 33 | */ 34 | private List list; 35 | } 36 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/common/ShinyConst.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.common; 2 | 3 | /** 4 | *

5 | * Shiny常量池 6 | *

7 | * 8 | * @package: com.xkcoding.shiny.common 9 | * @description: Shiny常量池 10 | * @author: yangkai.shen 11 | * @date: Created in 2018/8/15 下午10:04 12 | * @copyright: Copyright (c) 2018 13 | * @version: V1.0 14 | * @modified: yangkai.shen 15 | */ 16 | public interface ShinyConst { 17 | /** 18 | * 默认当前页 19 | */ 20 | Integer DEFAULT_CURRENT_PAGE = 1; 21 | 22 | /** 23 | * 默认每页条数 24 | */ 25 | Integer DEFAULT_PAGE_SIZE = 20; 26 | 27 | /** 28 | * Redis 中监听的邮件通道 29 | */ 30 | String MAIL_CHANNEL = "channel_mail"; 31 | } 32 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/common/property/ShinyProperties.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.common.property; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | 6 | /** 7 | *

8 | * 自定义配置 9 | *

10 | * 11 | * @package: com.xkcoding.shiny.common.property 12 | * @description: 自定义配置 13 | * @author: yangkai.shen 14 | * @date: Created in 2018/8/27 上午9:57 15 | * @copyright: Copyright (c) 2018 16 | * @version: V1.0 17 | * @modified: yangkai.shen 18 | */ 19 | @ConfigurationProperties(prefix = "shiny") 20 | @Data 21 | public class ShinyProperties { 22 | /** 23 | * 软件名称 24 | */ 25 | private String name; 26 | 27 | /** 28 | * 软件版本 29 | */ 30 | private String version; 31 | 32 | /** 33 | * 版权年份 34 | */ 35 | private String copyrightYear; 36 | 37 | /** 38 | * 作者 39 | */ 40 | private String developer; 41 | 42 | /** 43 | * driver 路径 44 | */ 45 | private String driverPath; 46 | 47 | /** 48 | * 并发软件采集的数量 49 | */ 50 | private Integer spiderNum; 51 | 52 | /** 53 | * 邮件发送人 54 | */ 55 | private String mailFrom; 56 | 57 | } 58 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/common/status/OperateStatus.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.common.status; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | *

7 | * 操作状态枚举 8 | *

9 | * 10 | * @package: com.xkcoding.shiny.common.status 11 | * @description: 操作状态枚举 12 | * @author: yangkai.shen 13 | * @date: Created in 2018/8/28 下午9:04 14 | * @copyright: Copyright (c) 2018 15 | * @version: V1.0 16 | * @modified: yangkai.shen 17 | */ 18 | @Getter 19 | public enum OperateStatus { 20 | /** 21 | * 成功 22 | */ 23 | SUCCESS(1), 24 | 25 | /** 26 | * 失败 27 | */ 28 | ERROR(0); 29 | 30 | OperateStatus(Integer code) { 31 | this.code = code; 32 | } 33 | 34 | private Integer code; 35 | } 36 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/common/status/Status.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.common.status; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | *

7 | * 状态码枚举 8 | *

9 | * 10 | * @package: com.xkcoding.shiny.common.status 11 | * @description: 状态码枚举 12 | * @author: yangkai.shen 13 | * @date: Created in 2018/8/15 下午8:37 14 | * @copyright: Copyright (c) 2018 15 | * @version: V1.0 16 | * @modified: yangkai.shen 17 | */ 18 | @Getter 19 | public enum Status { 20 | /** 21 | * 操作成功 22 | */ 23 | SUCCESS(200, "操作成功"), 24 | 25 | /** 26 | * 请求错误 27 | */ 28 | BAD_REQUEST(400, "请求错误"), 29 | 30 | /** 31 | * 尚未登录 32 | */ 33 | UNAUTHORIZED(401, "尚未登录"), 34 | 35 | /** 36 | * 权限不够 37 | */ 38 | FORBIDDEN(403, "权限不够"), 39 | 40 | /** 41 | * 请求不存在 42 | */ 43 | REQUEST_NOT_FOUND(404, "请求不存在"), 44 | 45 | /** 46 | * 服务器内部错误 47 | */ 48 | INTERNAL_SERVER_ERROR(500, "服务器内部错误"), 49 | 50 | /** 51 | * 请求参数错误 52 | */ 53 | REQUEST_PARAMS_ERROR(50000, "请求参数错误"), 54 | 55 | /** 56 | * 采集配置不存在 57 | */ 58 | CONFIG_NOT_EXIST(50001, "采集配置不存在"), 59 | 60 | /** 61 | * 日志id列表不能为空 62 | */ 63 | LOG_ID_LIST_NOT_EMPTY(50002, "日志id列表不能为空"), 64 | 65 | /** 66 | * 采集id列表不能为空 67 | */ 68 | CONFIG_ID_LIST_NOT_EMPTY(50003, "采集id列表不能为空"), 69 | 70 | /** 71 | * 采集配置 URL 不能为空 72 | */ 73 | CONFIG_URL_NOT_BLANK(50004, "采集配置 URL 不能为空"), 74 | 75 | /** 76 | * 采集配置已存在 77 | */ 78 | CONFIG_EXIST(50005, "采集配置已存在"); 79 | 80 | private Integer code; 81 | private String msg; 82 | 83 | Status(Integer code, String msg) { 84 | this.code = code; 85 | this.msg = msg; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/config/AsyncConfig.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.scheduling.annotation.EnableAsync; 6 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 7 | 8 | import java.util.concurrent.Executor; 9 | 10 | /** 11 | *

12 | * 异步任务配置 13 | *

14 | * 15 | * @package: com.xkcoding.shiny.config 16 | * @description: 异步任务配置 17 | * @author: yangkai.shen 18 | * @date: Created in 2018/8/27 下午6:41 19 | * @copyright: Copyright (c) 2018 20 | * @version: V1.0 21 | * @modified: yangkai.shen 22 | */ 23 | @Configuration 24 | @EnableAsync 25 | public class AsyncConfig { 26 | 27 | @Bean 28 | public Executor asyncExecutor() { 29 | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 30 | executor.setCorePoolSize(200); 31 | executor.setMaxPoolSize(250); 32 | executor.setQueueCapacity(50); 33 | executor.setThreadNamePrefix("Async-Thread-"); 34 | executor.initialize(); 35 | return executor; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/config/ModelMapperConfig.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.config; 2 | 3 | import org.modelmapper.ModelMapper; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | /** 8 | *

9 | * ModelMapper 配置类 10 | *

11 | * 12 | * @package: com.xkcoding.shiny.config 13 | * @description: ModelMapper 配置类 14 | * @author: yangkai.shen 15 | * @date: Created in 2018/8/15 下午8:35 16 | * @copyright: Copyright (c) 2018 17 | * @version: V1.0 18 | * @modified: yangkai.shen 19 | */ 20 | @Configuration 21 | public class ModelMapperConfig { 22 | @Bean 23 | public ModelMapper modelMapper() { 24 | return new ModelMapper(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/config/RedisListenerConfig.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.config; 2 | 3 | import com.xkcoding.shiny.common.ShinyConst; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.data.redis.connection.RedisConnectionFactory; 8 | import org.springframework.data.redis.core.StringRedisTemplate; 9 | import org.springframework.data.redis.listener.PatternTopic; 10 | import org.springframework.data.redis.listener.RedisMessageListenerContainer; 11 | import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; 12 | 13 | import java.util.concurrent.CountDownLatch; 14 | 15 | /** 16 | *

17 | * Redis 发布/订阅配置 18 | *

19 | * 20 | * @package: com.xkcoding.shiny.config 21 | * @description: Redis 发布/订阅配置 22 | * @author: yangkai.shen 23 | * @date: Created in 2018/9/6 下午4:15 24 | * @copyright: Copyright (c) 2018 25 | * @version: V1.0 26 | * @modified: yangkai.shen 27 | */ 28 | @Configuration 29 | @Slf4j 30 | public class RedisListenerConfig { 31 | 32 | /** 33 | * 初始化监听器 34 | * 35 | * @param connectionFactory 连接工厂 36 | * @param listenerAdapter 监听器 37 | * @return 监听器容器 38 | */ 39 | @Bean 40 | public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) { 41 | log.info("【Redis】启动监听......"); 42 | RedisMessageListenerContainer container = new RedisMessageListenerContainer(); 43 | container.setConnectionFactory(connectionFactory); 44 | container.addMessageListener(listenerAdapter, new PatternTopic(ShinyConst.MAIL_CHANNEL)); 45 | return container; 46 | } 47 | 48 | /** 49 | * 利用反射来创建监听到消息之后的执行方法 50 | * 51 | * @param receiver 接收到消息的对象 52 | * @return {@link MessageListenerAdapter} 53 | */ 54 | @Bean 55 | public MessageListenerAdapter listenerAdapter(RedisReceiverConfig receiver) { 56 | return new MessageListenerAdapter(receiver, "receiveMessage"); 57 | } 58 | 59 | @Bean 60 | public RedisReceiverConfig receiver(CountDownLatch latch) { 61 | return new RedisReceiverConfig(latch); 62 | } 63 | 64 | @Bean 65 | public CountDownLatch latch() { 66 | return new CountDownLatch(1); 67 | } 68 | 69 | /** 70 | * 使用默认的工厂初始化redis操作模板 71 | * 72 | * @param connectionFactory 连接工厂 73 | * @return {@link StringRedisTemplate} 74 | */ 75 | @Bean 76 | public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory connectionFactory) { 77 | return new StringRedisTemplate(connectionFactory); 78 | } 79 | 80 | } -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/config/RedisReceiverConfig.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.config; 2 | 3 | import cn.hutool.core.lang.Dict; 4 | import cn.hutool.json.JSONUtil; 5 | import com.xkcoding.shiny.model.SpiderContentDO; 6 | import com.xkcoding.shiny.service.IMailService; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | 10 | import javax.mail.MessagingException; 11 | import java.util.concurrent.CountDownLatch; 12 | 13 | /** 14 | *

15 | * redis 接收消息接口 实现 16 | *

17 | * 18 | * @package: com.xkcoding.shiny.service.impl 19 | * @description: redis 接收消息接口 实现 20 | * @author: yangkai.shen 21 | * @date: Created in 2018/9/6 下午4:20 22 | * @copyright: Copyright (c) 2018 23 | * @version: V1.0 24 | * @modified: yangkai.shen 25 | */ 26 | @Slf4j 27 | public class RedisReceiverConfig { 28 | private CountDownLatch latch; 29 | 30 | @Autowired 31 | private IMailService mailService; 32 | 33 | @Autowired 34 | public RedisReceiverConfig(CountDownLatch latch) { 35 | this.latch = latch; 36 | } 37 | 38 | /** 39 | * 接收消息执行的方法 40 | * 41 | * @param message 消息 42 | */ 43 | public void receiveMessage(Object message) throws MessagingException { 44 | log.info("【收到消息】消息内容:{}", JSONUtil.toJsonStr(message)); 45 | mailService.sendHtmlTemplateMail("237497819@qq.com", "软件更新通知", Dict.create().set("trDataList", JSONUtil.toList(JSONUtil.parseArray(message), SpiderContentDO.class)), "email", "software-update.html"); 46 | latch.countDown(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/config/ScheduleConfig.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.config; 2 | 3 | import org.apache.commons.lang3.concurrent.BasicThreadFactory; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.ComponentScan; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.scheduling.annotation.EnableScheduling; 8 | import org.springframework.scheduling.annotation.SchedulingConfigurer; 9 | import org.springframework.scheduling.config.ScheduledTaskRegistrar; 10 | 11 | import java.util.concurrent.Executor; 12 | import java.util.concurrent.ScheduledThreadPoolExecutor; 13 | 14 | /** 15 | *

16 | * 定时任务配置 17 | *

18 | * 19 | * @package: com.xkcoding.shiny.config 20 | * @description: 定时任务配置 21 | * @author: yangkai.shen 22 | * @date: Created in 2018/8/22 下午9:59 23 | * @copyright: Copyright (c) 2018 24 | * @version: V1.0 25 | * @modified: yangkai.shen 26 | */ 27 | @Configuration 28 | @EnableScheduling 29 | @ComponentScan(basePackages = "com.xkcoding.shiny.task") 30 | public class ScheduleConfig implements SchedulingConfigurer { 31 | 32 | @Override 33 | public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { 34 | taskRegistrar.setScheduler(taskExecutor()); 35 | } 36 | 37 | @Bean 38 | public Executor taskExecutor() { 39 | return new ScheduledThreadPoolExecutor(100, new BasicThreadFactory.Builder().namingPattern("Schedule-Thread-%d").build()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/controller/SpiderConfigController.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.controller; 2 | 3 | import cn.hutool.core.collection.CollUtil; 4 | import cn.hutool.core.util.ObjectUtil; 5 | import com.xkcoding.shiny.common.ApiResponse; 6 | import com.xkcoding.shiny.common.PageResult; 7 | import com.xkcoding.shiny.common.status.Status; 8 | import com.xkcoding.shiny.exception.ShinyException; 9 | import com.xkcoding.shiny.model.SpiderConfigDO; 10 | import com.xkcoding.shiny.model.query.SpiderConfigPageQuery; 11 | import com.xkcoding.shiny.model.vo.SpiderConfigVO; 12 | import com.xkcoding.shiny.service.ISpiderConfigService; 13 | import com.xkcoding.shiny.util.ShinyUtil; 14 | import lombok.extern.slf4j.Slf4j; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.web.bind.annotation.*; 17 | 18 | import java.util.List; 19 | 20 | /** 21 | *

22 | * 采集配置Controller 23 | *

24 | * 25 | * @package: com.xkcoding.shiny.controller 26 | * @description: 采集配置Controller 27 | * @author: yangkai.shen 28 | * @date: Created in 2018/8/15 下午8:33 29 | * @copyright: Copyright (c) 2018 30 | * @version: V1.0 31 | * @modified: yangkai.shen 32 | */ 33 | @RestController 34 | @RequestMapping("/api/spider/config") 35 | @Slf4j 36 | public class SpiderConfigController { 37 | private final ISpiderConfigService spiderConfigService; 38 | 39 | @Autowired 40 | public SpiderConfigController(ISpiderConfigService spiderConfigService) { 41 | this.spiderConfigService = spiderConfigService; 42 | } 43 | 44 | /** 45 | * 保存采集配置 46 | * 47 | * @param spiderConfigVO 采集配置 VO 48 | * @return 采集配置 DO 49 | * @throws ShinyException 参数异常 50 | */ 51 | @PostMapping("") 52 | public ApiResponse addConfig(@RequestBody SpiderConfigVO spiderConfigVO) throws ShinyException { 53 | if (ShinyUtil.isEmpty(spiderConfigVO, SpiderConfigVO.class)) { 54 | throw new ShinyException(Status.REQUEST_PARAMS_ERROR); 55 | } 56 | SpiderConfigDO spiderConfigDO = spiderConfigService.saveConfig(spiderConfigVO); 57 | return ApiResponse.ofSuccess(spiderConfigDO); 58 | } 59 | 60 | /** 61 | * 更新采集配置 62 | * 63 | * @param id 配置 id 64 | * @param spiderConfigVO 采集配置 VO 65 | * @return 采集配置 DO 66 | * @throws ShinyException 参数异常 67 | */ 68 | @PutMapping("/{id}") 69 | public ApiResponse updateConfig(@PathVariable Integer id, @RequestBody SpiderConfigVO spiderConfigVO) throws ShinyException { 70 | if (ShinyUtil.isEmpty(spiderConfigVO, SpiderConfigVO.class) || !ObjectUtil.equal(id, spiderConfigVO.getId())) { 71 | throw new ShinyException(Status.REQUEST_PARAMS_ERROR); 72 | } 73 | SpiderConfigDO spiderConfigDO = spiderConfigService.updateConfig(id, spiderConfigVO); 74 | return ApiResponse.ofSuccess(spiderConfigDO); 75 | } 76 | 77 | /** 78 | * 根据 id 删除采集配置 79 | * 80 | * @param id 配置 id 81 | * @throws ShinyException 参数异常 82 | */ 83 | @DeleteMapping("/{id}") 84 | public ApiResponse deleteConfig(@PathVariable Integer id) throws ShinyException { 85 | if (ObjectUtil.isNull(id)) { 86 | throw new ShinyException(Status.REQUEST_PARAMS_ERROR); 87 | } 88 | spiderConfigService.deleteConfig(id); 89 | return ApiResponse.ofSuccess(); 90 | } 91 | 92 | /** 93 | * 批量删除采集配置 94 | * 95 | * @param ids 配置 id 列表 96 | * @throws ShinyException 参数不能为空 97 | */ 98 | @DeleteMapping("") 99 | public ApiResponse deleteLogBatch(@RequestBody List ids) throws ShinyException { 100 | if (CollUtil.isEmpty(ids)) { 101 | throw new ShinyException(Status.CONFIG_ID_LIST_NOT_EMPTY); 102 | } 103 | spiderConfigService.deleteBatch(ids); 104 | return ApiResponse.ofSuccess(); 105 | } 106 | 107 | /** 108 | * 查看单个采集配置详情 109 | * 110 | * @param id 配置 id 111 | * @return 采集配置 VO 112 | * @throws ShinyException 参数异常 / 采集配置不存在 113 | */ 114 | @GetMapping("/{id}") 115 | public ApiResponse getConfig(@PathVariable Integer id) throws ShinyException { 116 | if (ObjectUtil.isNull(id)) { 117 | throw new ShinyException(Status.REQUEST_PARAMS_ERROR); 118 | } 119 | SpiderConfigVO spiderConfigVO = spiderConfigService.getConfig(id); 120 | return ApiResponse.ofSuccess(spiderConfigVO); 121 | } 122 | 123 | /** 124 | * 返回采集配置列表 125 | * 126 | * @param query 查询条件 127 | * @return 采集配置列表 128 | */ 129 | @GetMapping("") 130 | public ApiResponse listConfig(SpiderConfigPageQuery query) { 131 | query = ShinyUtil.checkPageCondition(query, SpiderConfigPageQuery.class); 132 | PageResult pageResult = spiderConfigService.listSpiderConfig(query); 133 | return ApiResponse.ofSuccess(pageResult); 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/controller/SpiderContentController.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.controller; 2 | 3 | import cn.hutool.core.util.ObjectUtil; 4 | import com.xkcoding.shiny.common.ApiResponse; 5 | import com.xkcoding.shiny.common.PageResult; 6 | import com.xkcoding.shiny.common.status.Status; 7 | import com.xkcoding.shiny.exception.ShinyException; 8 | import com.xkcoding.shiny.model.query.SpiderContentPageQuery; 9 | import com.xkcoding.shiny.model.vo.SpiderContentVO; 10 | import com.xkcoding.shiny.service.ISpiderContentService; 11 | import com.xkcoding.shiny.util.ShinyUtil; 12 | import lombok.extern.slf4j.Slf4j; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.web.bind.annotation.GetMapping; 15 | import org.springframework.web.bind.annotation.PathVariable; 16 | import org.springframework.web.bind.annotation.RequestMapping; 17 | import org.springframework.web.bind.annotation.RestController; 18 | 19 | /** 20 | *

21 | * 采集内容 Controller 22 | *

23 | * 24 | * @package: com.xkcoding.shiny.controller 25 | * @description: 采集内容 Controller 26 | * @author: yangkai.shen 27 | * @date: Created in 2018/9/3 下午9:38 28 | * @copyright: Copyright (c) 2018 29 | * @version: V1.0 30 | * @modified: yangkai.shen 31 | */ 32 | @RestController 33 | @RequestMapping("/api/spider/content") 34 | @Slf4j 35 | public class SpiderContentController { 36 | private final ISpiderContentService spiderContentService; 37 | 38 | @Autowired 39 | public SpiderContentController(ISpiderContentService spiderContentService) { 40 | this.spiderContentService = spiderContentService; 41 | } 42 | 43 | /** 44 | * 查看单个采集内容详情 45 | * 46 | * @param configId 采集配置id 47 | * @return 单个采集内容 48 | * @throws ShinyException 参数错误 49 | */ 50 | @GetMapping("/{configId}") 51 | public ApiResponse listSpiderContent(@PathVariable Integer configId, SpiderContentPageQuery query) throws ShinyException { 52 | if (ObjectUtil.isNull(configId)) { 53 | throw new ShinyException(Status.REQUEST_PARAMS_ERROR); 54 | } 55 | query = ShinyUtil.checkPageCondition(query, SpiderContentPageQuery.class); 56 | PageResult pageResult = spiderContentService.getSpiderContent(configId, query); 57 | return ApiResponse.ofSuccess(pageResult); 58 | } 59 | 60 | /** 61 | * 查询采集信息列表 62 | * 63 | * @param query 查询条件 64 | * @return 采集信息列表 65 | */ 66 | @GetMapping("") 67 | public ApiResponse listSpiderContent(SpiderContentPageQuery query) { 68 | query = ShinyUtil.checkPageCondition(query, SpiderContentPageQuery.class); 69 | PageResult pageResult = spiderContentService.listSpiderContent(query); 70 | return ApiResponse.ofSuccess(pageResult); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/controller/SpiderController.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.controller; 2 | 3 | import cn.hutool.core.util.ObjectUtil; 4 | import com.xkcoding.shiny.common.ApiResponse; 5 | import com.xkcoding.shiny.common.status.Status; 6 | import com.xkcoding.shiny.exception.ShinyException; 7 | import com.xkcoding.shiny.model.SpiderConfigDO; 8 | import com.xkcoding.shiny.service.ISpiderConfigService; 9 | import com.xkcoding.shiny.service.ISpiderContentService; 10 | import com.xkcoding.shiny.service.ISpiderService; 11 | import lombok.extern.slf4j.Slf4j; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.web.bind.annotation.GetMapping; 14 | import org.springframework.web.bind.annotation.PathVariable; 15 | import org.springframework.web.bind.annotation.RequestMapping; 16 | import org.springframework.web.bind.annotation.RestController; 17 | 18 | /** 19 | *

20 | * 采集 Controller 21 | *

22 | * 23 | * @package: com.xkcoding.shiny.controller 24 | * @description: 采集 Controller 25 | * @author: yangkai.shen 26 | * @date: Created in 2018/8/27 下午2:28 27 | * @copyright: Copyright (c) 2018 28 | * @version: V1.0 29 | * @modified: yangkai.shen 30 | */ 31 | @RestController 32 | @RequestMapping("/api/spider") 33 | @Slf4j 34 | public class SpiderController { 35 | private final ISpiderConfigService spiderConfigService; 36 | 37 | private final ISpiderContentService spiderContentService; 38 | 39 | private final ISpiderService spiderService; 40 | 41 | @Autowired 42 | public SpiderController(ISpiderConfigService spiderConfigService, ISpiderContentService spiderContentService, ISpiderService spiderService) { 43 | this.spiderConfigService = spiderConfigService; 44 | this.spiderContentService = spiderContentService; 45 | this.spiderService = spiderService; 46 | } 47 | 48 | /** 49 | * 重新爬取今天采集的所有软件信息 50 | */ 51 | @GetMapping("") 52 | public ApiResponse reSpiderAllToday() throws InterruptedException { 53 | // 删除所有今天采集的内容 54 | spiderContentService.deleteAllToday(); 55 | 56 | // 重新采集 57 | spiderService.reSpiderAllToday(); 58 | return ApiResponse.ofSuccess(); 59 | } 60 | 61 | /** 62 | * 重新爬取今天采集的某个软件信息 63 | */ 64 | @GetMapping("/{id}") 65 | public ApiResponse reSpiderToday(@PathVariable Integer id) throws ShinyException, InterruptedException { 66 | SpiderConfigDO spiderConfigDO = spiderConfigService.selectSpiderConfig(id); 67 | if (ObjectUtil.isNull(spiderConfigDO)) { 68 | throw new ShinyException(Status.CONFIG_NOT_EXIST); 69 | } 70 | 71 | // 删除当前配置 id 对应的今天采集的内容 72 | spiderContentService.deleteToday(id); 73 | 74 | // 重新采集 75 | spiderService.reSpiderToday(id); 76 | return ApiResponse.ofSuccess(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/controller/SpiderLogController.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.controller; 2 | 3 | import cn.hutool.core.collection.CollUtil; 4 | import com.xkcoding.shiny.common.ApiResponse; 5 | import com.xkcoding.shiny.common.PageResult; 6 | import com.xkcoding.shiny.common.status.Status; 7 | import com.xkcoding.shiny.exception.ShinyException; 8 | import com.xkcoding.shiny.model.SpiderLogDO; 9 | import com.xkcoding.shiny.model.query.SpiderLogPageQuery; 10 | import com.xkcoding.shiny.service.ISpiderLogService; 11 | import com.xkcoding.shiny.util.ShinyUtil; 12 | import lombok.extern.slf4j.Slf4j; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.web.bind.annotation.*; 15 | 16 | import java.util.List; 17 | 18 | /** 19 | *

20 | * 采集日志 Controller 21 | *

22 | * 23 | * @package: com.xkcoding.shiny.controller 24 | * @description: 采集日志 Controller 25 | * @author: yangkai.shen 26 | * @date: Created in 2018/8/29 下午9:09 27 | * @copyright: Copyright (c) 2018 28 | * @version: V1.0 29 | * @modified: yangkai.shen 30 | */ 31 | @RestController 32 | @RequestMapping("/api/spider/log") 33 | @Slf4j 34 | public class SpiderLogController { 35 | private final ISpiderLogService spiderLogService; 36 | 37 | @Autowired 38 | public SpiderLogController(ISpiderLogService spiderLogService) { 39 | this.spiderLogService = spiderLogService; 40 | } 41 | 42 | /** 43 | * 返回采集日志列表 44 | * 45 | * @param query 查询条件 46 | * @return 采集配置日志列表 47 | */ 48 | @GetMapping("") 49 | public ApiResponse listLog(SpiderLogPageQuery query) { 50 | query = ShinyUtil.checkPageCondition(query, SpiderLogPageQuery.class); 51 | PageResult pageResult = spiderLogService.listSpiderLog(query); 52 | return ApiResponse.ofSuccess(pageResult); 53 | } 54 | 55 | /** 56 | * 根据 id 删除日志 57 | * 58 | * @param id 日志id 59 | */ 60 | @DeleteMapping("/{id}") 61 | public ApiResponse deleteLog(@PathVariable Integer id) { 62 | spiderLogService.deleteLogById(id); 63 | return ApiResponse.ofSuccess(); 64 | } 65 | 66 | /** 67 | * 批量删除日志 68 | * 69 | * @param ids 日志 id 列表 70 | * @throws ShinyException 参数不能为空 71 | */ 72 | @DeleteMapping("") 73 | public ApiResponse deleteLogBatch(@RequestBody List ids) throws ShinyException { 74 | if (CollUtil.isEmpty(ids)) { 75 | throw new ShinyException(Status.LOG_ID_LIST_NOT_EMPTY); 76 | } 77 | spiderLogService.deleteBatch(ids); 78 | return ApiResponse.ofSuccess(); 79 | } 80 | 81 | /** 82 | * 清空采集日志 83 | */ 84 | @DeleteMapping(value = "", params = "today") 85 | public ApiResponse deleteTodayLog() { 86 | spiderLogService.deleteTodayLog(); 87 | return ApiResponse.ofSuccess(); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/exception/ShinyException.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.exception; 2 | 3 | import com.xkcoding.shiny.common.status.Status; 4 | import lombok.Getter; 5 | 6 | /** 7 | *

8 | * 通用全局异常 9 | *

10 | * 11 | * @package: com.xkcoding.shiny.exception 12 | * @description: 通用全局异常 13 | * @author: yangkai.shen 14 | * @date: Created in 2018/8/15 下午8:39 15 | * @copyright: Copyright (c) 2018 16 | * @version: V1.0 17 | * @modified: yangkai.shen 18 | */ 19 | @Getter 20 | public class ShinyException extends Exception { 21 | /** 22 | * 异常码 23 | */ 24 | private Integer code; 25 | 26 | /** 27 | * 错误信息 28 | */ 29 | private String msg; 30 | 31 | /** 32 | * 返回内容 33 | */ 34 | private Object data; 35 | 36 | public ShinyException(Integer code, String msg) { 37 | super(msg); 38 | this.code = code; 39 | this.msg = msg; 40 | } 41 | 42 | public ShinyException(Integer code, String msg, Object data) { 43 | super(msg); 44 | this.code = code; 45 | this.msg = msg; 46 | this.data = data; 47 | } 48 | 49 | 50 | public ShinyException(String msg, Integer code, Object data) { 51 | super(msg); 52 | this.msg = msg; 53 | this.code = code; 54 | this.data = data; 55 | } 56 | 57 | public ShinyException(Status status) { 58 | super(status.getMsg()); 59 | this.code = status.getCode(); 60 | this.msg = status.getMsg(); 61 | } 62 | 63 | public ShinyException(Status status, Object data) { 64 | super(status.getMsg()); 65 | this.code = status.getCode(); 66 | this.msg = status.getMsg(); 67 | this.data = data; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/handler/GlobalExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.handler; 2 | 3 | import com.xkcoding.shiny.common.ApiResponse; 4 | import com.xkcoding.shiny.common.status.Status; 5 | import com.xkcoding.shiny.exception.ShinyException; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.http.converter.HttpMessageNotReadableException; 8 | import org.springframework.web.bind.MethodArgumentNotValidException; 9 | import org.springframework.web.bind.annotation.ControllerAdvice; 10 | import org.springframework.web.bind.annotation.ExceptionHandler; 11 | import org.springframework.web.bind.annotation.ResponseBody; 12 | import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; 13 | import org.springframework.web.servlet.NoHandlerFoundException; 14 | 15 | /** 16 | *

17 | * 全局异常处理 18 | *

19 | * 20 | * @package: com.xkcoding.shiny.handler 21 | * @description: 全局异常处理 22 | * @author: yangkai.shen 23 | * @date: Created in 2018/8/15 下午8:40 24 | * @copyright: Copyright (c) 2018 25 | * @version: V1.0 26 | * @modified: yangkai.shen 27 | */ 28 | @Slf4j 29 | @ControllerAdvice 30 | public class GlobalExceptionHandler { 31 | 32 | @ExceptionHandler(value = Exception.class) 33 | @ResponseBody 34 | public ApiResponse handlerException(Exception e) { 35 | if (e instanceof NoHandlerFoundException) { 36 | log.error("【全局异常拦截】NoHandlerFoundException: 请求方法 {}, 请求路径 {}", ((NoHandlerFoundException) e).getRequestURL(), ((NoHandlerFoundException) e).getHttpMethod()); 37 | return ApiResponse.ofStatus(Status.REQUEST_NOT_FOUND); 38 | } else if (e instanceof MethodArgumentNotValidException) { 39 | log.error("【全局异常拦截】MethodArgumentNotValidException", e); 40 | return ApiResponse.ofStatus(Status.REQUEST_PARAMS_ERROR); 41 | } else if (e instanceof MethodArgumentTypeMismatchException) { 42 | log.error("【全局异常拦截】MethodArgumentTypeMismatchException: 参数名 {}, 异常信息 {}", ((MethodArgumentTypeMismatchException) e).getName(), ((MethodArgumentTypeMismatchException) e).getMessage()); 43 | return ApiResponse.ofStatus(Status.REQUEST_PARAMS_ERROR); 44 | } else if (e instanceof HttpMessageNotReadableException) { 45 | log.error("【全局异常拦截】HttpMessageNotReadableException: 错误信息 {}", ((HttpMessageNotReadableException) e).getMessage()); 46 | return ApiResponse.ofStatus(Status.REQUEST_PARAMS_ERROR); 47 | } else if (e instanceof ShinyException) { 48 | log.error("【全局异常拦截】ShinyException: 状态码 {}, 异常信息 {}", ((ShinyException) e).getCode(), e.getMessage()); 49 | return new ApiResponse(((ShinyException) e).getCode(), e.getMessage(), ((ShinyException) e).getData()); 50 | } 51 | log.error("【全局异常拦截】: 异常信息 {} ", e.getMessage()); 52 | return ApiResponse.ofStatus(Status.INTERNAL_SERVER_ERROR); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/mapper/EmailLogMapper.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.mapper; 2 | 3 | import com.xkcoding.shiny.common.MyMapper; 4 | import com.xkcoding.shiny.model.EmailLogDO; 5 | import org.springframework.stereotype.Component; 6 | 7 | /** 8 | *

9 | * 邮件记录 Mapper 10 | *

11 | * 12 | * @package: com.xkcoding.shiny.mapper 13 | * @description: 邮件记录 Mapper 14 | * @author: yangkai.shen 15 | * @date: Created in 2018/9/9 下午2:57 16 | * @copyright: Copyright (c) 2018 17 | * @version: V1.0 18 | * @modified: yangkai.shen 19 | */ 20 | @Component 21 | public interface EmailLogMapper extends MyMapper { 22 | } -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/mapper/SpiderConfigMapper.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.mapper; 2 | 3 | import com.xkcoding.shiny.common.MyMapper; 4 | import com.xkcoding.shiny.model.SpiderConfigDO; 5 | import org.apache.ibatis.annotations.Param; 6 | import org.springframework.stereotype.Component; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | *

12 | * 采集参数配置Mapper类 13 | *

14 | * 15 | * @package: com.xkcoding.shiny.mapper 16 | * @description: 采集参数配置Mapper类 17 | * @author: yangkai.shen 18 | * @date: Created in 2018/8/15 下午6:45 19 | * @copyright: Copyright (c) 2018 20 | * @version: V1.0 21 | * @modified: yangkai.shen 22 | */ 23 | @Component 24 | public interface SpiderConfigMapper extends MyMapper { 25 | 26 | /** 27 | * 根据采集名称查询采集配置列表 28 | * 29 | * @param text 采集配置名称 / 采集配置备注 30 | * @return 采集配置列表 31 | */ 32 | List selectSpiderConfigByText(@Param("text") String text); 33 | 34 | /** 35 | * 批量删除采集配置 36 | * 37 | * @param ids 采集 id 列表 38 | */ 39 | void deleteBatch(@Param("ids") List ids); 40 | } -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/mapper/SpiderContentMapper.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.mapper; 2 | 3 | import com.xkcoding.shiny.common.MyMapper; 4 | import com.xkcoding.shiny.model.SpiderContentDO; 5 | import com.xkcoding.shiny.model.query.SpiderContentPageQuery; 6 | import org.apache.ibatis.annotations.Param; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | *

13 | * 采集内容Mapper类 14 | *

15 | * 16 | * @package: com.xkcoding.shiny.mapper 17 | * @description: 采集内容Mapper类 18 | * @author: yangkai.shen 19 | * @date: Created in 2018/8/15 下午6:45 20 | * @copyright: Copyright (c) 2018 21 | * @version: V1.0 22 | * @modified: yangkai.shen 23 | */ 24 | @Component 25 | public interface SpiderContentMapper extends MyMapper { 26 | /** 27 | * 查询单个采集内容 28 | * 29 | * @param configId 采集配置 id 30 | * @param query 查询条件 31 | * @return 单个采集内容列表 32 | */ 33 | List selectSingleSpiderContent(@Param("configId") Integer configId, @Param("query") SpiderContentPageQuery query); 34 | 35 | /** 36 | * 查询采集信息列表 37 | * 38 | * @param query 查询条件 39 | * @return 采集信息列表 40 | */ 41 | List selectSpiderContent(@Param("query") SpiderContentPageQuery query); 42 | 43 | /** 44 | * 获取指定采集时间的并且软件更新时间在指定范围内的软件信息 45 | * 46 | * @param spiderTime 采集时间 47 | * @param updateTimeStart 软件更新时间 - 起始范围 48 | * @param updateTimeEnd 软件更新时间 - 结束范围 49 | * @return 指定采集时间的并且软件更新时间在指定范围内的软件信息 50 | */ 51 | List selectLatestSpiderContent(@Param("spiderTime") String spiderTime, @Param("updateTimeStart") String updateTimeStart, @Param("updateTimeEnd") String updateTimeEnd); 52 | } -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/mapper/SpiderLogMapper.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.mapper; 2 | 3 | import com.xkcoding.shiny.common.MyMapper; 4 | import com.xkcoding.shiny.model.SpiderLogDO; 5 | import org.apache.ibatis.annotations.Param; 6 | import org.springframework.stereotype.Component; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | *

12 | * 采集日志Mapper类 13 | *

14 | * 15 | * @package: com.xkcoding.shiny.mapper 16 | * @description: 采集日志Mapper类 17 | * @author: yangkai.shen 18 | * @date: Created in 2018/8/15 下午6:47 19 | * @copyright: Copyright (c) 2018 20 | * @version: V1.0 21 | * @modified: yangkai.shen 22 | */ 23 | @Component 24 | public interface SpiderLogMapper extends MyMapper { 25 | /** 26 | * 根据查询条件模糊查询采集日志列表 27 | * 28 | * @param spiderName 采集名称 29 | * @param version 采集版本 30 | * @param status 采集状态 31 | * @param errorMsg 错误信息 32 | * @param startTime 开始时间 33 | * @param endTime 结束时间 34 | * @return 采集日志列表 35 | */ 36 | List selectSpiderLogByParam(@Param("spiderName") String spiderName, @Param("version") String version, @Param("status") Integer status, @Param("errorMsg") String errorMsg, @Param("startTime") String startTime, @Param("endTime") String endTime); 37 | 38 | /** 39 | * 根据 id 列表批量删除日志 40 | * 41 | * @param ids 日志 id 列表 42 | */ 43 | void deleteBatch(@Param("ids") List ids); 44 | 45 | /** 46 | * 删除一段时间内的采集的日志 47 | * 48 | * @param startTime 开始日期 49 | * @param endTime 结束日期 50 | */ 51 | void deleteByDuring(@Param("startTime") String startTime, @Param("endTime") String endTime); 52 | } -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/mapper/SysConfigMapper.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.mapper; 2 | 3 | import com.xkcoding.shiny.common.MyMapper; 4 | import com.xkcoding.shiny.model.SysConfigDO; 5 | import org.springframework.stereotype.Component; 6 | 7 | /** 8 | *

9 | * 系统参数配置Mapper类 10 | *

11 | * 12 | * @package: com.xkcoding.shiny.mapper 13 | * @description: 系统参数配置Mapper类 14 | * @author: yangkai.shen 15 | * @date: Created in 2018/8/15 下午6:46 16 | * @copyright: Copyright (c) 2018 17 | * @version: V1.0 18 | * @modified: yangkai.shen 19 | */ 20 | @Component 21 | public interface SysConfigMapper extends MyMapper { 22 | } -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/mapper/SysRoleMapper.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.mapper; 2 | 3 | import com.xkcoding.shiny.common.MyMapper; 4 | import com.xkcoding.shiny.model.SysRoleDO; 5 | import org.springframework.stereotype.Component; 6 | 7 | /** 8 | *

9 | * 系统角色Mapper类 10 | *

11 | * 12 | * @package: com.xkcoding.shiny.mapper 13 | * @description: 系统角色Mapper类 14 | * @author: yangkai.shen 15 | * @date: Created in 2018/8/15 下午6:46 16 | * @copyright: Copyright (c) 2018 17 | * @version: V1.0 18 | * @modified: yangkai.shen 19 | */ 20 | @Component 21 | public interface SysRoleMapper extends MyMapper { 22 | } -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/mapper/SysUserMapper.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.mapper; 2 | 3 | import com.xkcoding.shiny.common.MyMapper; 4 | import com.xkcoding.shiny.model.SysUserDO; 5 | import org.springframework.stereotype.Component; 6 | 7 | /** 8 | *

9 | * 系统用户Mapper类 10 | *

11 | * 12 | * @package: com.xkcoding.shiny.mapper 13 | * @description: 系统用户Mapper类 14 | * @author: yangkai.shen 15 | * @date: Created in 2018/8/15 下午6:49 16 | * @copyright: Copyright (c) 2018 17 | * @version: V1.0 18 | * @modified: yangkai.shen 19 | */ 20 | @Component 21 | public interface SysUserMapper extends MyMapper { 22 | } -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/mapper/SysUserRoleMapper.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.mapper; 2 | 3 | import com.xkcoding.shiny.common.MyMapper; 4 | import com.xkcoding.shiny.model.SysUserRoleDO; 5 | import org.springframework.stereotype.Component; 6 | 7 | /** 8 | *

9 | * 系统用户-角色关联关系Mapper类 10 | *

11 | * 12 | * @package: com.xkcoding.shiny.mapper 13 | * @description: 系统用户-角色关联关系Mapper类 14 | * @author: yangkai.shen 15 | * @date: Created in 2018/8/15 下午6:50 16 | * @copyright: Copyright (c) 2018 17 | * @version: V1.0 18 | * @modified: yangkai.shen 19 | */ 20 | @Component 21 | public interface SysUserRoleMapper extends MyMapper { 22 | } -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/model/EmailLogDO.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.model; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.Column; 6 | import javax.persistence.GeneratedValue; 7 | import javax.persistence.Id; 8 | import javax.persistence.Table; 9 | import java.util.Date; 10 | 11 | /** 12 | *

13 | * 邮件记录 DO 14 | *

15 | * 16 | * @package: com.xkcoding.shiny.model 17 | * @description: 邮件记录 DO 18 | * @author: yangkai.shen 19 | * @date: Created in 2018/9/9 下午2:56 20 | * @copyright: Copyright (c) 2018 21 | * @version: V1.0 22 | * @modified: yangkai.shen 23 | */ 24 | @Data 25 | @Table(name = "email_log") 26 | public class EmailLogDO { 27 | /** 28 | * 邮件主键 29 | */ 30 | @Id 31 | @Column(name = "id") 32 | @GeneratedValue(generator = "JDBC") 33 | private Integer id; 34 | 35 | /** 36 | * 邮件主题 37 | */ 38 | @Column(name = "subject") 39 | private String subject; 40 | 41 | /** 42 | * 是否是模板邮件(0否 1是) 43 | */ 44 | @Column(name = "is_template") 45 | private Integer isTemplate; 46 | 47 | /** 48 | * 模板路径 49 | */ 50 | @Column(name = "template_path") 51 | private String templatePath; 52 | 53 | /** 54 | * 模板名称 55 | */ 56 | @Column(name = "template_name") 57 | private String templateName; 58 | 59 | /** 60 | * 邮件发送时间 61 | */ 62 | @Column(name = "send_time") 63 | private Date sendTime; 64 | 65 | /** 66 | * 收件人邮箱地址(多个逗号分隔) 67 | */ 68 | @Column(name = "to") 69 | private String to; 70 | 71 | /** 72 | * 邮件内容 73 | */ 74 | @Column(name = "content") 75 | private String content; 76 | 77 | /** 78 | * 获取邮件主键 79 | * 80 | * @return id - 邮件主键 81 | */ 82 | public Integer getId() { 83 | return id; 84 | } 85 | 86 | /** 87 | * 设置邮件主键 88 | * 89 | * @param id 邮件主键 90 | */ 91 | public void setId(Integer id) { 92 | this.id = id; 93 | } 94 | 95 | /** 96 | * 获取邮件主题 97 | * 98 | * @return subject - 邮件主题 99 | */ 100 | public String getSubject() { 101 | return subject; 102 | } 103 | 104 | /** 105 | * 设置邮件主题 106 | * 107 | * @param subject 邮件主题 108 | */ 109 | public void setSubject(String subject) { 110 | this.subject = subject; 111 | } 112 | 113 | /** 114 | * 获取是否是模板邮件(0否 1是) 115 | * 116 | * @return is_template - 是否是模板邮件(0否 1是) 117 | */ 118 | public Integer getIsTemplate() { 119 | return isTemplate; 120 | } 121 | 122 | /** 123 | * 设置是否是模板邮件(0否 1是) 124 | * 125 | * @param isTemplate 是否是模板邮件(0否 1是) 126 | */ 127 | public void setIsTemplate(Integer isTemplate) { 128 | this.isTemplate = isTemplate; 129 | } 130 | 131 | /** 132 | * 获取模板路径 133 | * 134 | * @return template_path - 模板路径 135 | */ 136 | public String getTemplatePath() { 137 | return templatePath; 138 | } 139 | 140 | /** 141 | * 设置模板路径 142 | * 143 | * @param templatePath 模板路径 144 | */ 145 | public void setTemplatePath(String templatePath) { 146 | this.templatePath = templatePath; 147 | } 148 | 149 | /** 150 | * 获取模板名称 151 | * 152 | * @return template_name - 模板名称 153 | */ 154 | public String getTemplateName() { 155 | return templateName; 156 | } 157 | 158 | /** 159 | * 设置模板名称 160 | * 161 | * @param templateName 模板名称 162 | */ 163 | public void setTemplateName(String templateName) { 164 | this.templateName = templateName; 165 | } 166 | 167 | /** 168 | * 获取邮件发送时间 169 | * 170 | * @return send_time - 邮件发送时间 171 | */ 172 | public Date getSendTime() { 173 | return sendTime; 174 | } 175 | 176 | /** 177 | * 设置邮件发送时间 178 | * 179 | * @param sendTime 邮件发送时间 180 | */ 181 | public void setSendTime(Date sendTime) { 182 | this.sendTime = sendTime; 183 | } 184 | 185 | /** 186 | * 获取收件人邮箱地址(多个逗号分隔) 187 | * 188 | * @return to - 收件人邮箱地址(多个逗号分隔) 189 | */ 190 | public String getTo() { 191 | return to; 192 | } 193 | 194 | /** 195 | * 设置收件人邮箱地址(多个逗号分隔) 196 | * 197 | * @param to 收件人邮箱地址(多个逗号分隔) 198 | */ 199 | public void setTo(String to) { 200 | this.to = to; 201 | } 202 | 203 | /** 204 | * 获取邮件内容 205 | * 206 | * @return content - 邮件内容 207 | */ 208 | public String getContent() { 209 | return content; 210 | } 211 | 212 | /** 213 | * 设置邮件内容 214 | * 215 | * @param content 邮件内容 216 | */ 217 | public void setContent(String content) { 218 | this.content = content; 219 | } 220 | } -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/model/SpiderConfigDO.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import javax.persistence.Column; 9 | import javax.persistence.GeneratedValue; 10 | import javax.persistence.Id; 11 | import javax.persistence.Table; 12 | import java.util.Date; 13 | 14 | /** 15 | *

16 | * 采集配置 17 | *

18 | * 19 | * @package: com.xkcoding.shiny.model 20 | * @description: 采集配置 21 | * @author: yangkai.shen 22 | * @date: Created in 2018/8/15 下午6:50 23 | * @copyright: Copyright (c) 2018 24 | * @version: V1.0 25 | * @modified: yangkai.shen 26 | */ 27 | @Table(name = "spider_config") 28 | @Data 29 | @Builder 30 | @NoArgsConstructor 31 | @AllArgsConstructor 32 | public class SpiderConfigDO { 33 | /** 34 | * 配置主键 35 | */ 36 | @Id 37 | @Column(name = "id") 38 | @GeneratedValue(generator = "JDBC") 39 | private Integer id; 40 | 41 | /** 42 | * 采集名称 43 | */ 44 | @Column(name = "spider_name") 45 | private String spiderName; 46 | 47 | /** 48 | * 采集URL 49 | */ 50 | @Column(name = "spider_url") 51 | private String spiderUrl; 52 | 53 | /** 54 | * 上次采集时间 55 | */ 56 | @Column(name = "last_spider_time") 57 | private Date lastSpiderTime; 58 | 59 | /** 60 | * 创建者 61 | */ 62 | @Column(name = "create_by") 63 | private String createBy; 64 | 65 | /** 66 | * 创建时间 67 | */ 68 | @Column(name = "create_time") 69 | private Date createTime; 70 | 71 | /** 72 | * 更新者 73 | */ 74 | @Column(name = "update_by") 75 | private String updateBy; 76 | 77 | /** 78 | * 更新时间 79 | */ 80 | @Column(name = "update_time") 81 | private Date updateTime; 82 | 83 | /** 84 | * 备注 85 | */ 86 | @Column(name = "remark") 87 | private String remark; 88 | 89 | /** 90 | * 获取配置主键 91 | * 92 | * @return id - 配置主键 93 | */ 94 | public Integer getId() { 95 | return id; 96 | } 97 | 98 | /** 99 | * 设置配置主键 100 | * 101 | * @param id 配置主键 102 | */ 103 | public void setId(Integer id) { 104 | this.id = id; 105 | } 106 | 107 | /** 108 | * 获取采集名称 109 | * 110 | * @return spider_name - 采集名称 111 | */ 112 | public String getSpiderName() { 113 | return spiderName; 114 | } 115 | 116 | /** 117 | * 设置采集名称 118 | * 119 | * @param spiderName 采集名称 120 | */ 121 | public void setSpiderName(String spiderName) { 122 | this.spiderName = spiderName; 123 | } 124 | 125 | /** 126 | * 获取采集URL 127 | * 128 | * @return spider_url - 采集URL 129 | */ 130 | public String getSpiderUrl() { 131 | return spiderUrl; 132 | } 133 | 134 | /** 135 | * 设置采集URL 136 | * 137 | * @param spiderUrl 采集URL 138 | */ 139 | public void setSpiderUrl(String spiderUrl) { 140 | this.spiderUrl = spiderUrl; 141 | } 142 | 143 | /** 144 | * 获取上次采集时间 145 | * 146 | * @return last_spider_time - 上次采集时间 147 | */ 148 | public Date getLastSpiderTime() { 149 | return lastSpiderTime; 150 | } 151 | 152 | /** 153 | * 设置上次采集时间 154 | * 155 | * @param lastSpiderTime 上次采集时间 156 | */ 157 | public void setLastSpiderTime(Date lastSpiderTime) { 158 | this.lastSpiderTime = lastSpiderTime; 159 | } 160 | 161 | /** 162 | * 获取创建者 163 | * 164 | * @return create_by - 创建者 165 | */ 166 | public String getCreateBy() { 167 | return createBy; 168 | } 169 | 170 | /** 171 | * 设置创建者 172 | * 173 | * @param createBy 创建者 174 | */ 175 | public void setCreateBy(String createBy) { 176 | this.createBy = createBy; 177 | } 178 | 179 | /** 180 | * 获取创建时间 181 | * 182 | * @return create_time - 创建时间 183 | */ 184 | public Date getCreateTime() { 185 | return createTime; 186 | } 187 | 188 | /** 189 | * 设置创建时间 190 | * 191 | * @param createTime 创建时间 192 | */ 193 | public void setCreateTime(Date createTime) { 194 | this.createTime = createTime; 195 | } 196 | 197 | /** 198 | * 获取更新者 199 | * 200 | * @return update_by - 更新者 201 | */ 202 | public String getUpdateBy() { 203 | return updateBy; 204 | } 205 | 206 | /** 207 | * 设置更新者 208 | * 209 | * @param updateBy 更新者 210 | */ 211 | public void setUpdateBy(String updateBy) { 212 | this.updateBy = updateBy; 213 | } 214 | 215 | /** 216 | * 获取更新时间 217 | * 218 | * @return update_time - 更新时间 219 | */ 220 | public Date getUpdateTime() { 221 | return updateTime; 222 | } 223 | 224 | /** 225 | * 设置更新时间 226 | * 227 | * @param updateTime 更新时间 228 | */ 229 | public void setUpdateTime(Date updateTime) { 230 | this.updateTime = updateTime; 231 | } 232 | 233 | /** 234 | * 获取备注 235 | * 236 | * @return remark - 备注 237 | */ 238 | public String getRemark() { 239 | return remark; 240 | } 241 | 242 | /** 243 | * 设置备注 244 | * 245 | * @param remark 备注 246 | */ 247 | public void setRemark(String remark) { 248 | this.remark = remark; 249 | } 250 | } -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/model/SpiderContentDO.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import javax.persistence.Column; 9 | import javax.persistence.GeneratedValue; 10 | import javax.persistence.Id; 11 | import javax.persistence.Table; 12 | import java.util.Date; 13 | 14 | /** 15 | *

16 | * 采集内容 17 | *

18 | * 19 | * @package: com.xkcoding.shiny.model 20 | * @description: 采集内容 21 | * @author: yangkai.shen 22 | * @date: Created in 2018/8/15 下午6:51 23 | * @copyright: Copyright (c) 2018 24 | * @version: V1.0 25 | * @modified: yangkai.shen 26 | */ 27 | @Table(name = "spider_content") 28 | @Builder 29 | @Data 30 | @NoArgsConstructor 31 | @AllArgsConstructor 32 | public class SpiderContentDO { 33 | /** 34 | * 内容主键 35 | */ 36 | @Id 37 | @Column(name = "id") 38 | @GeneratedValue(generator = "JDBC") 39 | private Integer id; 40 | 41 | /** 42 | * 采集配置id 43 | */ 44 | @Column(name = "config_id") 45 | private Integer configId; 46 | 47 | /** 48 | * 采集配置名称 49 | */ 50 | @Column(name = "config_name") 51 | private String configName; 52 | 53 | /** 54 | * 软件名称 55 | */ 56 | @Column(name = "title") 57 | private String title; 58 | 59 | /** 60 | * 软件版本 61 | */ 62 | @Column(name = "version") 63 | private String version; 64 | 65 | /** 66 | * 软件语言 67 | */ 68 | @Column(name = "language") 69 | private String language; 70 | 71 | /** 72 | * 软件更新时间 73 | */ 74 | @Column(name = "update_time") 75 | private Date updateTime; 76 | 77 | /** 78 | * 软件大小 79 | */ 80 | @Column(name = "size") 81 | private String size; 82 | 83 | /** 84 | * 城通网盘链接 85 | */ 86 | @Column(name = "ct_pan_url") 87 | private String ctPanUrl; 88 | 89 | /** 90 | * 城通网盘提取码 91 | */ 92 | @Column(name = "ct_pan_code") 93 | private String ctPanCode; 94 | 95 | /** 96 | * 百度网盘链接 97 | */ 98 | @Column(name = "bd_pan_url") 99 | private String bdPanUrl; 100 | 101 | /** 102 | * 百度网盘提取码 103 | */ 104 | @Column(name = "bd_pan_code") 105 | private String bdPanCode; 106 | 107 | /** 108 | * 采集时间 109 | */ 110 | @Column(name = "spider_time") 111 | private Date spiderTime; 112 | 113 | /** 114 | * 软件详细信息 115 | */ 116 | @Column(name = "content") 117 | private String content; 118 | 119 | /** 120 | * 获取内容主键 121 | * 122 | * @return id - 内容主键 123 | */ 124 | public Integer getId() { 125 | return id; 126 | } 127 | 128 | /** 129 | * 设置内容主键 130 | * 131 | * @param id 内容主键 132 | */ 133 | public void setId(Integer id) { 134 | this.id = id; 135 | } 136 | 137 | /** 138 | * 获取采集配置id 139 | * 140 | * @return config_id - 采集配置id 141 | */ 142 | public Integer getConfigId() { 143 | return configId; 144 | } 145 | 146 | /** 147 | * 设置采集配置id 148 | * 149 | * @param configId 采集配置id 150 | */ 151 | public void setConfigId(Integer configId) { 152 | this.configId = configId; 153 | } 154 | 155 | /** 156 | * 获取采集配置名称 157 | * 158 | * @return config_name - 采集配置名称 159 | */ 160 | public String getConfigName() { 161 | return configName; 162 | } 163 | 164 | /** 165 | * 设置采集配置名称 166 | * 167 | * @param configName 采集配置名称 168 | */ 169 | public void setConfigName(String configName) { 170 | this.configName = configName; 171 | } 172 | 173 | /** 174 | * 获取软件名称 175 | * 176 | * @return title - 软件名称 177 | */ 178 | public String getTitle() { 179 | return title; 180 | } 181 | 182 | /** 183 | * 设置软件名称 184 | * 185 | * @param title 软件名称 186 | */ 187 | public void setTitle(String title) { 188 | this.title = title; 189 | } 190 | 191 | /** 192 | * 获取软件版本 193 | * 194 | * @return version - 软件版本 195 | */ 196 | public String getVersion() { 197 | return version; 198 | } 199 | 200 | /** 201 | * 设置软件版本 202 | * 203 | * @param version 软件版本 204 | */ 205 | public void setVersion(String version) { 206 | this.version = version; 207 | } 208 | 209 | /** 210 | * 获取软件语言 211 | * 212 | * @return language - 软件语言 213 | */ 214 | public String getLanguage() { 215 | return language; 216 | } 217 | 218 | /** 219 | * 设置软件语言 220 | * 221 | * @param language 软件语言 222 | */ 223 | public void setLanguage(String language) { 224 | this.language = language; 225 | } 226 | 227 | /** 228 | * 获取软件更新时间 229 | * 230 | * @return update_time - 软件更新时间 231 | */ 232 | public Date getUpdateTime() { 233 | return updateTime; 234 | } 235 | 236 | /** 237 | * 设置软件更新时间 238 | * 239 | * @param updateTime 软件更新时间 240 | */ 241 | public void setUpdateTime(Date updateTime) { 242 | this.updateTime = updateTime; 243 | } 244 | 245 | /** 246 | * 获取软件大小 247 | * 248 | * @return size - 软件大小 249 | */ 250 | public String getSize() { 251 | return size; 252 | } 253 | 254 | /** 255 | * 设置软件大小 256 | * 257 | * @param size 软件大小 258 | */ 259 | public void setSize(String size) { 260 | this.size = size; 261 | } 262 | 263 | /** 264 | * 获取城通网盘链接 265 | * 266 | * @return ct_pan_url - 城通网盘链接 267 | */ 268 | public String getCtPanUrl() { 269 | return ctPanUrl; 270 | } 271 | 272 | /** 273 | * 设置城通网盘链接 274 | * 275 | * @param ctPanUrl 城通网盘链接 276 | */ 277 | public void setCtPanUrl(String ctPanUrl) { 278 | this.ctPanUrl = ctPanUrl; 279 | } 280 | 281 | /** 282 | * 获取城通网盘提取码 283 | * 284 | * @return ct_pan_code - 城通网盘提取码 285 | */ 286 | public String getCtPanCode() { 287 | return ctPanCode; 288 | } 289 | 290 | /** 291 | * 设置城通网盘提取码 292 | * 293 | * @param ctPanCode 城通网盘提取码 294 | */ 295 | public void setCtPanCode(String ctPanCode) { 296 | this.ctPanCode = ctPanCode; 297 | } 298 | 299 | /** 300 | * 获取百度网盘链接 301 | * 302 | * @return bd_pan_url - 百度网盘链接 303 | */ 304 | public String getBdPanUrl() { 305 | return bdPanUrl; 306 | } 307 | 308 | /** 309 | * 设置百度网盘链接 310 | * 311 | * @param bdPanUrl 百度网盘链接 312 | */ 313 | public void setBdPanUrl(String bdPanUrl) { 314 | this.bdPanUrl = bdPanUrl; 315 | } 316 | 317 | /** 318 | * 获取百度网盘提取码 319 | * 320 | * @return bd_pan_code - 百度网盘提取码 321 | */ 322 | public String getBdPanCode() { 323 | return bdPanCode; 324 | } 325 | 326 | /** 327 | * 设置百度网盘提取码 328 | * 329 | * @param bdPanCode 百度网盘提取码 330 | */ 331 | public void setBdPanCode(String bdPanCode) { 332 | this.bdPanCode = bdPanCode; 333 | } 334 | 335 | /** 336 | * 获取采集时间 337 | * 338 | * @return spider_time - 采集时间 339 | */ 340 | public Date getSpiderTime() { 341 | return spiderTime; 342 | } 343 | 344 | /** 345 | * 设置采集时间 346 | * 347 | * @param spiderTime 采集时间 348 | */ 349 | public void setSpiderTime(Date spiderTime) { 350 | this.spiderTime = spiderTime; 351 | } 352 | 353 | /** 354 | * 获取软件详细信息 355 | * 356 | * @return content - 软件详细信息 357 | */ 358 | public String getContent() { 359 | return content; 360 | } 361 | 362 | /** 363 | * 设置软件详细信息 364 | * 365 | * @param content 软件详细信息 366 | */ 367 | public void setContent(String content) { 368 | this.content = content; 369 | } 370 | } -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/model/SpiderLogDO.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.model; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.Column; 6 | import javax.persistence.GeneratedValue; 7 | import javax.persistence.Id; 8 | import javax.persistence.Table; 9 | import java.util.Date; 10 | 11 | /** 12 | *

13 | * 采集日志 14 | *

15 | * 16 | * @package: com.xkcoding.shiny.model 17 | * @description: 采集日志 18 | * @author: yangkai.shen 19 | * @date: Created in 2018/8/15 下午6:51 20 | * @copyright: Copyright (c) 2018 21 | * @version: V1.0 22 | * @modified: yangkai.shen 23 | */ 24 | @Table(name = "spider_log") 25 | @Data 26 | public class SpiderLogDO { 27 | /** 28 | * 日志主键 29 | */ 30 | @Id 31 | @Column(name = "id") 32 | @GeneratedValue(generator = "JDBC") 33 | private Integer id; 34 | 35 | /** 36 | * 采集配置id 37 | */ 38 | @Column(name = "config_id") 39 | private Integer configId; 40 | 41 | /** 42 | * 采集名称 43 | */ 44 | @Column(name = "spider_name") 45 | private String spiderName; 46 | 47 | /** 48 | * 采集版本 49 | */ 50 | @Column(name = "version") 51 | private String version; 52 | 53 | /** 54 | * 采集URL 55 | */ 56 | @Column(name = "spider_url") 57 | private String spiderUrl; 58 | 59 | /** 60 | * 采集状态(0异常 1正常) 61 | */ 62 | @Column(name = "status") 63 | private Integer status; 64 | 65 | /** 66 | * 错误消息 67 | */ 68 | @Column(name = "error_msg") 69 | private String errorMsg; 70 | 71 | /** 72 | * 采集时间 73 | */ 74 | @Column(name = "spider_time") 75 | private Date spiderTime; 76 | 77 | /** 78 | * 获取日志主键 79 | * 80 | * @return id - 日志主键 81 | */ 82 | public Integer getId() { 83 | return id; 84 | } 85 | 86 | /** 87 | * 设置日志主键 88 | * 89 | * @param id 日志主键 90 | */ 91 | public void setId(Integer id) { 92 | this.id = id; 93 | } 94 | 95 | /** 96 | * 获取采集名称 97 | * 98 | * @return spider_name - 采集名称 99 | */ 100 | public String getSpiderName() { 101 | return spiderName; 102 | } 103 | 104 | /** 105 | * 设置采集名称 106 | * 107 | * @param spiderName 采集名称 108 | */ 109 | public void setSpiderName(String spiderName) { 110 | this.spiderName = spiderName; 111 | } 112 | 113 | /** 114 | * 获取采集版本 115 | * 116 | * @return version - 采集版本 117 | */ 118 | public String getVersion() { 119 | return version; 120 | } 121 | 122 | /** 123 | * 设置采集版本 124 | * 125 | * @param version 采集版本 126 | */ 127 | public void setVersion(String version) { 128 | this.version = version; 129 | } 130 | 131 | /** 132 | * 获取采集URL 133 | * 134 | * @return spider_url - 采集URL 135 | */ 136 | public String getSpiderUrl() { 137 | return spiderUrl; 138 | } 139 | 140 | /** 141 | * 设置采集URL 142 | * 143 | * @param spiderUrl 采集URL 144 | */ 145 | public void setSpiderUrl(String spiderUrl) { 146 | this.spiderUrl = spiderUrl; 147 | } 148 | 149 | /** 150 | * 获取采集状态(0异常 1正常) 151 | * 152 | * @return status - 采集状态(0异常 1正常) 153 | */ 154 | public Integer getStatus() { 155 | return status; 156 | } 157 | 158 | /** 159 | * 设置采集状态(0异常 1正常) 160 | * 161 | * @param status 采集状态(0异常 1正常) 162 | */ 163 | public void setStatus(Integer status) { 164 | this.status = status; 165 | } 166 | 167 | /** 168 | * 获取错误消息 169 | * 170 | * @return error_msg - 错误消息 171 | */ 172 | public String getErrorMsg() { 173 | return errorMsg; 174 | } 175 | 176 | /** 177 | * 设置错误消息 178 | * 179 | * @param errorMsg 错误消息 180 | */ 181 | public void setErrorMsg(String errorMsg) { 182 | this.errorMsg = errorMsg; 183 | } 184 | 185 | /** 186 | * 获取采集时间 187 | * 188 | * @return spider_time - 采集时间 189 | */ 190 | public Date getSpiderTime() { 191 | return spiderTime; 192 | } 193 | 194 | /** 195 | * 设置采集时间 196 | * 197 | * @param spiderTime 采集时间 198 | */ 199 | public void setSpiderTime(Date spiderTime) { 200 | this.spiderTime = spiderTime; 201 | } 202 | } -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/model/SysConfigDO.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.model; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.Column; 6 | import javax.persistence.GeneratedValue; 7 | import javax.persistence.Id; 8 | import javax.persistence.Table; 9 | import java.util.Date; 10 | 11 | /** 12 | *

13 | * 系统配置 14 | *

15 | * 16 | * @package: com.xkcoding.shiny.model 17 | * @description: 系统配置 18 | * @author: yangkai.shen 19 | * @date: Created in 2018/8/15 下午6:51 20 | * @copyright: Copyright (c) 2018 21 | * @version: V1.0 22 | * @modified: yangkai.shen 23 | */ 24 | @Table(name = "sys_config") 25 | @Data 26 | public class SysConfigDO { 27 | /** 28 | * 参数主键 29 | */ 30 | @Id 31 | @Column(name = "id") 32 | @GeneratedValue(generator = "JDBC") 33 | private Integer id; 34 | 35 | /** 36 | * 参数名称 37 | */ 38 | @Column(name = "config_name") 39 | private String configName; 40 | 41 | /** 42 | * 参数键名 43 | */ 44 | @Column(name = "config_key") 45 | private String configKey; 46 | 47 | /** 48 | * 参数键值 49 | */ 50 | @Column(name = "config_value") 51 | private String configValue; 52 | 53 | /** 54 | * 系统内置(0否 1是) 55 | */ 56 | @Column(name = "config_type") 57 | private Integer configType; 58 | 59 | /** 60 | * 创建者 61 | */ 62 | @Column(name = "create_by") 63 | private String createBy; 64 | 65 | /** 66 | * 创建时间 67 | */ 68 | @Column(name = "create_time") 69 | private Date createTime; 70 | 71 | /** 72 | * 更新者 73 | */ 74 | @Column(name = "update_by") 75 | private String updateBy; 76 | 77 | /** 78 | * 更新时间 79 | */ 80 | @Column(name = "update_time") 81 | private Date updateTime; 82 | 83 | /** 84 | * 备注 85 | */ 86 | @Column(name = "remark") 87 | private String remark; 88 | 89 | /** 90 | * 获取参数主键 91 | * 92 | * @return id - 参数主键 93 | */ 94 | public Integer getId() { 95 | return id; 96 | } 97 | 98 | /** 99 | * 设置参数主键 100 | * 101 | * @param id 参数主键 102 | */ 103 | public void setId(Integer id) { 104 | this.id = id; 105 | } 106 | 107 | /** 108 | * 获取参数名称 109 | * 110 | * @return config_name - 参数名称 111 | */ 112 | public String getConfigName() { 113 | return configName; 114 | } 115 | 116 | /** 117 | * 设置参数名称 118 | * 119 | * @param configName 参数名称 120 | */ 121 | public void setConfigName(String configName) { 122 | this.configName = configName; 123 | } 124 | 125 | /** 126 | * 获取参数键名 127 | * 128 | * @return config_key - 参数键名 129 | */ 130 | public String getConfigKey() { 131 | return configKey; 132 | } 133 | 134 | /** 135 | * 设置参数键名 136 | * 137 | * @param configKey 参数键名 138 | */ 139 | public void setConfigKey(String configKey) { 140 | this.configKey = configKey; 141 | } 142 | 143 | /** 144 | * 获取参数键值 145 | * 146 | * @return config_value - 参数键值 147 | */ 148 | public String getConfigValue() { 149 | return configValue; 150 | } 151 | 152 | /** 153 | * 设置参数键值 154 | * 155 | * @param configValue 参数键值 156 | */ 157 | public void setConfigValue(String configValue) { 158 | this.configValue = configValue; 159 | } 160 | 161 | /** 162 | * 获取系统内置(0否 1是) 163 | * 164 | * @return config_type - 系统内置(0否 1是) 165 | */ 166 | public Integer getConfigType() { 167 | return configType; 168 | } 169 | 170 | /** 171 | * 设置系统内置(0否 1是) 172 | * 173 | * @param configType 系统内置(0否 1是) 174 | */ 175 | public void setConfigType(Integer configType) { 176 | this.configType = configType; 177 | } 178 | 179 | /** 180 | * 获取创建者 181 | * 182 | * @return create_by - 创建者 183 | */ 184 | public String getCreateBy() { 185 | return createBy; 186 | } 187 | 188 | /** 189 | * 设置创建者 190 | * 191 | * @param createBy 创建者 192 | */ 193 | public void setCreateBy(String createBy) { 194 | this.createBy = createBy; 195 | } 196 | 197 | /** 198 | * 获取创建时间 199 | * 200 | * @return create_time - 创建时间 201 | */ 202 | public Date getCreateTime() { 203 | return createTime; 204 | } 205 | 206 | /** 207 | * 设置创建时间 208 | * 209 | * @param createTime 创建时间 210 | */ 211 | public void setCreateTime(Date createTime) { 212 | this.createTime = createTime; 213 | } 214 | 215 | /** 216 | * 获取更新者 217 | * 218 | * @return update_by - 更新者 219 | */ 220 | public String getUpdateBy() { 221 | return updateBy; 222 | } 223 | 224 | /** 225 | * 设置更新者 226 | * 227 | * @param updateBy 更新者 228 | */ 229 | public void setUpdateBy(String updateBy) { 230 | this.updateBy = updateBy; 231 | } 232 | 233 | /** 234 | * 获取更新时间 235 | * 236 | * @return update_time - 更新时间 237 | */ 238 | public Date getUpdateTime() { 239 | return updateTime; 240 | } 241 | 242 | /** 243 | * 设置更新时间 244 | * 245 | * @param updateTime 更新时间 246 | */ 247 | public void setUpdateTime(Date updateTime) { 248 | this.updateTime = updateTime; 249 | } 250 | 251 | /** 252 | * 获取备注 253 | * 254 | * @return remark - 备注 255 | */ 256 | public String getRemark() { 257 | return remark; 258 | } 259 | 260 | /** 261 | * 设置备注 262 | * 263 | * @param remark 备注 264 | */ 265 | public void setRemark(String remark) { 266 | this.remark = remark; 267 | } 268 | } -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/model/SysRoleDO.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.model; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.Column; 6 | import javax.persistence.GeneratedValue; 7 | import javax.persistence.Id; 8 | import javax.persistence.Table; 9 | import java.util.Date; 10 | 11 | /** 12 | *

13 | * 系统角色 14 | *

15 | * 16 | * @package: com.xkcoding.shiny.model 17 | * @description: 系统角色 18 | * @author: yangkai.shen 19 | * @date: Created in 2018/8/15 下午6:51 20 | * @copyright: Copyright (c) 2018 21 | * @version: V1.0 22 | * @modified: yangkai.shen 23 | */ 24 | @Table(name = "sys_role") 25 | @Data 26 | public class SysRoleDO { 27 | /** 28 | * 角色ID 29 | */ 30 | @Id 31 | @Column(name = "id") 32 | @GeneratedValue(generator = "JDBC") 33 | private Integer id; 34 | 35 | /** 36 | * 角色名称 37 | */ 38 | @Column(name = "role_name") 39 | private String roleName; 40 | 41 | /** 42 | * 角色权限字符串 43 | */ 44 | @Column(name = "role_key") 45 | private String roleKey; 46 | 47 | /** 48 | * 显示顺序 49 | */ 50 | @Column(name = "role_sort") 51 | private Integer roleSort; 52 | 53 | /** 54 | * 角色状态(0停用 1正常) 55 | */ 56 | @Column(name = "status") 57 | private Integer status; 58 | 59 | /** 60 | * 创建者 61 | */ 62 | @Column(name = "create_by") 63 | private String createBy; 64 | 65 | /** 66 | * 创建时间 67 | */ 68 | @Column(name = "create_time") 69 | private Date createTime; 70 | 71 | /** 72 | * 更新者 73 | */ 74 | @Column(name = "update_by") 75 | private String updateBy; 76 | 77 | /** 78 | * 更新时间 79 | */ 80 | @Column(name = "update_time") 81 | private Date updateTime; 82 | 83 | /** 84 | * 备注 85 | */ 86 | @Column(name = "remark") 87 | private String remark; 88 | 89 | /** 90 | * 获取角色ID 91 | * 92 | * @return id - 角色ID 93 | */ 94 | public Integer getId() { 95 | return id; 96 | } 97 | 98 | /** 99 | * 设置角色ID 100 | * 101 | * @param id 角色ID 102 | */ 103 | public void setId(Integer id) { 104 | this.id = id; 105 | } 106 | 107 | /** 108 | * 获取角色名称 109 | * 110 | * @return role_name - 角色名称 111 | */ 112 | public String getRoleName() { 113 | return roleName; 114 | } 115 | 116 | /** 117 | * 设置角色名称 118 | * 119 | * @param roleName 角色名称 120 | */ 121 | public void setRoleName(String roleName) { 122 | this.roleName = roleName; 123 | } 124 | 125 | /** 126 | * 获取角色权限字符串 127 | * 128 | * @return role_key - 角色权限字符串 129 | */ 130 | public String getRoleKey() { 131 | return roleKey; 132 | } 133 | 134 | /** 135 | * 设置角色权限字符串 136 | * 137 | * @param roleKey 角色权限字符串 138 | */ 139 | public void setRoleKey(String roleKey) { 140 | this.roleKey = roleKey; 141 | } 142 | 143 | /** 144 | * 获取显示顺序 145 | * 146 | * @return role_sort - 显示顺序 147 | */ 148 | public Integer getRoleSort() { 149 | return roleSort; 150 | } 151 | 152 | /** 153 | * 设置显示顺序 154 | * 155 | * @param roleSort 显示顺序 156 | */ 157 | public void setRoleSort(Integer roleSort) { 158 | this.roleSort = roleSort; 159 | } 160 | 161 | /** 162 | * 获取角色状态(0停用 1正常) 163 | * 164 | * @return status - 角色状态(0停用 1正常) 165 | */ 166 | public Integer getStatus() { 167 | return status; 168 | } 169 | 170 | /** 171 | * 设置角色状态(0停用 1正常) 172 | * 173 | * @param status 角色状态(0停用 1正常) 174 | */ 175 | public void setStatus(Integer status) { 176 | this.status = status; 177 | } 178 | 179 | /** 180 | * 获取创建者 181 | * 182 | * @return create_by - 创建者 183 | */ 184 | public String getCreateBy() { 185 | return createBy; 186 | } 187 | 188 | /** 189 | * 设置创建者 190 | * 191 | * @param createBy 创建者 192 | */ 193 | public void setCreateBy(String createBy) { 194 | this.createBy = createBy; 195 | } 196 | 197 | /** 198 | * 获取创建时间 199 | * 200 | * @return create_time - 创建时间 201 | */ 202 | public Date getCreateTime() { 203 | return createTime; 204 | } 205 | 206 | /** 207 | * 设置创建时间 208 | * 209 | * @param createTime 创建时间 210 | */ 211 | public void setCreateTime(Date createTime) { 212 | this.createTime = createTime; 213 | } 214 | 215 | /** 216 | * 获取更新者 217 | * 218 | * @return update_by - 更新者 219 | */ 220 | public String getUpdateBy() { 221 | return updateBy; 222 | } 223 | 224 | /** 225 | * 设置更新者 226 | * 227 | * @param updateBy 更新者 228 | */ 229 | public void setUpdateBy(String updateBy) { 230 | this.updateBy = updateBy; 231 | } 232 | 233 | /** 234 | * 获取更新时间 235 | * 236 | * @return update_time - 更新时间 237 | */ 238 | public Date getUpdateTime() { 239 | return updateTime; 240 | } 241 | 242 | /** 243 | * 设置更新时间 244 | * 245 | * @param updateTime 更新时间 246 | */ 247 | public void setUpdateTime(Date updateTime) { 248 | this.updateTime = updateTime; 249 | } 250 | 251 | /** 252 | * 获取备注 253 | * 254 | * @return remark - 备注 255 | */ 256 | public String getRemark() { 257 | return remark; 258 | } 259 | 260 | /** 261 | * 设置备注 262 | * 263 | * @param remark 备注 264 | */ 265 | public void setRemark(String remark) { 266 | this.remark = remark; 267 | } 268 | } -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/model/SysUserRoleDO.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.model; 2 | 3 | import lombok.Data; 4 | 5 | import javax.persistence.Column; 6 | import javax.persistence.Id; 7 | import javax.persistence.Table; 8 | 9 | /** 10 | *

11 | * 系统用户角色 12 | *

13 | * 14 | * @package: com.xkcoding.shiny.model 15 | * @description: 系统用户角色 16 | * @author: yangkai.shen 17 | * @date: Created in 2018/8/15 下午6:51 18 | * @copyright: Copyright (c) 2018 19 | * @version: V1.0 20 | * @modified: yangkai.shen 21 | */ 22 | @Table(name = "sys_user_role") 23 | @Data 24 | public class SysUserRoleDO { 25 | /** 26 | * 用户ID 27 | */ 28 | @Id 29 | @Column(name = "user_id") 30 | private Integer userId; 31 | 32 | /** 33 | * 角色ID 34 | */ 35 | @Id 36 | @Column(name = "role_id") 37 | private Integer roleId; 38 | 39 | /** 40 | * 获取用户ID 41 | * 42 | * @return user_id - 用户ID 43 | */ 44 | public Integer getUserId() { 45 | return userId; 46 | } 47 | 48 | /** 49 | * 设置用户ID 50 | * 51 | * @param userId 用户ID 52 | */ 53 | public void setUserId(Integer userId) { 54 | this.userId = userId; 55 | } 56 | 57 | /** 58 | * 获取角色ID 59 | * 60 | * @return role_id - 角色ID 61 | */ 62 | public Integer getRoleId() { 63 | return roleId; 64 | } 65 | 66 | /** 67 | * 设置角色ID 68 | * 69 | * @param roleId 角色ID 70 | */ 71 | public void setRoleId(Integer roleId) { 72 | this.roleId = roleId; 73 | } 74 | } -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/model/query/SpiderConfigPageQuery.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.model.query; 2 | 3 | import com.xkcoding.shiny.model.query.base.PageCondition; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | 7 | /** 8 | *

9 | * 采集配置查询条件 10 | *

11 | * 12 | * @package: com.xkcoding.shiny.model.query 13 | * @description: 采集配置查询条件 14 | * @author: yangkai.shen 15 | * @date: Created in 2018/8/15 下午10:10 16 | * @copyright: Copyright (c) 2018 17 | * @version: V1.0 18 | * @modified: yangkai.shen 19 | */ 20 | @Data 21 | @EqualsAndHashCode(callSuper = true) 22 | public class SpiderConfigPageQuery extends PageCondition { 23 | /** 24 | * 采集配置名称 / 采集配置备注 25 | */ 26 | private String text; 27 | } 28 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/model/query/SpiderContentPageQuery.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.model.query; 2 | 3 | import com.xkcoding.shiny.model.query.base.PageCondition; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | 7 | /** 8 | *

9 | * 采集内容查询条件 10 | *

11 | * 12 | * @package: com.xkcoding.shiny.model.query 13 | * @description: 采集内容查询条件 14 | * @author: yangkai.shen 15 | * @date: Created in 2018/9/3 下午9:56 16 | * @copyright: Copyright (c) 2018 17 | * @version: V1.0 18 | * @modified: yangkai.shen 19 | */ 20 | @Data 21 | @EqualsAndHashCode(callSuper = true) 22 | public class SpiderContentPageQuery extends PageCondition { 23 | /** 24 | * 采集配置名称 25 | */ 26 | private String configName; 27 | 28 | /** 29 | * 软件名称 30 | */ 31 | private String title; 32 | 33 | /** 34 | * 软件描述内容 35 | */ 36 | private String content; 37 | 38 | /** 39 | * 软件版本 40 | */ 41 | private String version; 42 | 43 | /** 44 | * 软件语言 45 | */ 46 | private String language; 47 | 48 | /** 49 | * 软件更新日期 50 | */ 51 | private String updateTime; 52 | 53 | /** 54 | * 采集时间 55 | */ 56 | private String spiderTime; 57 | } 58 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/model/query/SpiderLogPageQuery.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.model.query; 2 | 3 | import com.xkcoding.shiny.model.query.base.PageCondition; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | 7 | /** 8 | *

9 | * 采集日志查询条件 10 | *

11 | * 12 | * @package: com.xkcoding.shiny.model.query 13 | * @description: 采集日志查询条件 14 | * @author: yangkai.shen 15 | * @date: Created in 2018/8/29 下午9:11 16 | * @copyright: Copyright (c) 2018 17 | * @version: V1.0 18 | * @modified: yangkai.shen 19 | */ 20 | @Data 21 | @EqualsAndHashCode(callSuper = true) 22 | public class SpiderLogPageQuery extends PageCondition { 23 | /** 24 | * 采集名称 25 | */ 26 | private String spiderName; 27 | 28 | /** 29 | * 采集版本 30 | */ 31 | private String version; 32 | 33 | /** 34 | * 采集状态(0异常 1正常) 35 | */ 36 | private Integer status; 37 | 38 | /** 39 | * 错误消息 40 | */ 41 | private String errorMsg; 42 | 43 | /** 44 | * 采集时间 - 起始时间 45 | */ 46 | private String startTime; 47 | 48 | /** 49 | * 采集时间 - 结束时间 50 | */ 51 | private String endTime; 52 | } -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/model/query/base/PageCondition.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.model.query.base; 2 | 3 | import lombok.Data; 4 | 5 | import javax.validation.constraints.Pattern; 6 | 7 | /** 8 | *

9 | * 分页基本条件 10 | *

11 | * 12 | * @package: com.xkcoding.shiny.model.query.base 13 | * @description: 分页基本条件 14 | * @author: yangkai.shen 15 | * @date: Created in 2018/8/15 下午10:08 16 | * @copyright: Copyright (c) 2018 17 | * @version: V1.0 18 | * @modified: yangkai.shen 19 | */ 20 | @Data 21 | public class PageCondition { 22 | /** 23 | * 当前页 24 | */ 25 | private Integer currentPage; 26 | 27 | /** 28 | * 每页条数 29 | */ 30 | private Integer pageSize; 31 | } 32 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/model/vo/SpiderConfigVO.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.model.vo; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.util.Date; 7 | 8 | /** 9 | *

10 | * 采集配置VO 11 | *

12 | * 13 | * @package: com.xkcoding.shiny.model.vo 14 | * @description: 采集配置VO 15 | * @author: yangkai.shen 16 | * @date: Created in 2018/8/15 下午9:51 17 | * @copyright: Copyright (c) 2018 18 | * @version: V1.0 19 | * @modified: yangkai.shen 20 | */ 21 | @Data 22 | public class SpiderConfigVO implements Serializable { 23 | /** 24 | * 配置主键 25 | */ 26 | private Integer id; 27 | 28 | /** 29 | * 采集名称 30 | */ 31 | private String spiderName; 32 | 33 | /** 34 | * 采集URL 35 | */ 36 | private String spiderUrl; 37 | 38 | /** 39 | * 上次采集时间 40 | */ 41 | private Date lastSpiderTime; 42 | 43 | /** 44 | * 创建者 45 | */ 46 | private String createBy; 47 | 48 | /** 49 | * 创建时间 50 | */ 51 | private Date createTime; 52 | 53 | /** 54 | * 更新者 55 | */ 56 | private String updateBy; 57 | 58 | /** 59 | * 更新时间 60 | */ 61 | private Date updateTime; 62 | 63 | /** 64 | * 备注 65 | */ 66 | private String remark; 67 | } 68 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/model/vo/SpiderContentVO.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.model.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.io.Serializable; 9 | import java.util.Date; 10 | 11 | /** 12 | *

13 | * 采集内容VO 14 | *

15 | * 16 | * @package: com.xkcoding.shiny.model.vo 17 | * @description: 采集内容VO 18 | * @author: yangkai.shen 19 | * @date: Created in 2018/9/3 下午9:46 20 | * @copyright: Copyright (c) 2018 21 | * @version: V1.0 22 | * @modified: yangkai.shen 23 | */ 24 | @Builder 25 | @Data 26 | @NoArgsConstructor 27 | @AllArgsConstructor 28 | public class SpiderContentVO implements Serializable { 29 | 30 | private static final long serialVersionUID = 1230401625684294310L; 31 | /** 32 | * 内容主键 33 | */ 34 | private Integer id; 35 | 36 | /** 37 | * 采集配置id 38 | */ 39 | private Integer configId; 40 | 41 | /** 42 | * 采集配置名称 43 | */ 44 | private String configName; 45 | 46 | /** 47 | * 软件名称 48 | */ 49 | private String title; 50 | 51 | /** 52 | * 软件版本 53 | */ 54 | private String version; 55 | 56 | /** 57 | * 软件语言 58 | */ 59 | private String language; 60 | 61 | /** 62 | * 软件更新时间 63 | */ 64 | private Date updateTime; 65 | 66 | /** 67 | * 软件大小 68 | */ 69 | private String size; 70 | 71 | /** 72 | * 城通网盘链接 73 | */ 74 | private String ctPanUrl; 75 | 76 | /** 77 | * 城通网盘提取码 78 | */ 79 | private String ctPanCode; 80 | 81 | /** 82 | * 百度网盘链接 83 | */ 84 | private String bdPanUrl; 85 | 86 | /** 87 | * 百度网盘提取码 88 | */ 89 | private String bdPanCode; 90 | 91 | /** 92 | * 采集时间 93 | */ 94 | private Date spiderTime; 95 | 96 | /** 97 | * 软件详细信息 98 | */ 99 | private String content; 100 | 101 | } -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/service/IMailService.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.service; 2 | 3 | import javax.mail.MessagingException; 4 | import java.util.Map; 5 | 6 | /** 7 | *

8 | * 邮件接口 9 | *

10 | * 11 | * @package: com.xkcoding.shiny.service 12 | * @description: 邮件接口 13 | * @author: yangkai.shen 14 | * @date: Created in 2018/9/5 下午10:37 15 | * @copyright: Copyright (c) 2018 16 | * @version: V1.0 17 | * @modified: yangkai.shen 18 | */ 19 | public interface IMailService { 20 | 21 | /** 22 | * 发送简单邮件 23 | * 24 | * @param to 收件人 25 | * @param subject 邮件主题 26 | * @param content 邮件内容 27 | */ 28 | void sendSimpleMail(String to, String subject, String content); 29 | 30 | /** 31 | * 发送简单 HTML 邮件 32 | * 33 | * @param to 收件人 34 | * @param subject 邮件主题 35 | * @param html HTML 内容 36 | */ 37 | void sendHtmlMail(String to, String subject, String html); 38 | 39 | /** 40 | * 发送 HTML 模板邮件 41 | * 42 | * @param to 收件人 43 | * @param subject 邮件主题 44 | * @param params 模板参数 45 | * @param templatePath 模板路径 46 | * @param templateName 模板名称 47 | */ 48 | void sendHtmlTemplateMail(String to, String subject, Map params, String templatePath, String templateName) throws MessagingException; 49 | 50 | /** 51 | * 发送附件邮件 52 | * 53 | * @param to 收件人 54 | * @param subject 邮件主题 55 | * @param content 邮件内容 56 | * @param filePath 附件路径 57 | */ 58 | void sendAttachmentsMail(String to, String subject, String content, String filePath); 59 | 60 | /** 61 | * 发送静态资源邮件 62 | * 63 | * @param to 收件人 64 | * @param subject 邮件主题 65 | * @param content 邮件内容 66 | * @param rscPath 静态资源路径 67 | * @param rscId 静态资源 id 68 | */ 69 | void sendInlineResourceMail(String to, String subject, String content, String rscPath, String rscId); 70 | } 71 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/service/ISpiderConfigService.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.service; 2 | 3 | import com.xkcoding.shiny.common.PageResult; 4 | import com.xkcoding.shiny.exception.ShinyException; 5 | import com.xkcoding.shiny.model.SpiderConfigDO; 6 | import com.xkcoding.shiny.model.query.SpiderConfigPageQuery; 7 | import com.xkcoding.shiny.model.vo.SpiderConfigVO; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | *

13 | * 采集配置Service接口 14 | *

15 | * 16 | * @package: com.xkcoding.shiny.service 17 | * @description: 采集配置Service接口 18 | * @author: yangkai.shen 19 | * @date: Created in 2018/8/15 下午9:48 20 | * @copyright: Copyright (c) 2018 21 | * @version: V1.0 22 | * @modified: yangkai.shen 23 | */ 24 | public interface ISpiderConfigService { 25 | 26 | /** 27 | * 分页采集配置列表 28 | * 29 | * @param query 查询条件 30 | * @return 分页采集配置列表信息 31 | */ 32 | PageResult listSpiderConfig(SpiderConfigPageQuery query); 33 | 34 | /** 35 | * 全部采集配置列表 36 | * 37 | * @return 全部采集配置列表 38 | */ 39 | List listAllSpiderConfig(); 40 | 41 | /** 42 | * 根据配置id获取采集配置 43 | * 44 | * @param id 配置 id 45 | * @return 采集配置 DO 46 | */ 47 | SpiderConfigDO selectSpiderConfig(Integer id); 48 | 49 | /** 50 | * 保存采集配置 51 | * 52 | * @param spiderConfigVO 采集配置 VO 53 | * @return 采集配置 DO 54 | * @throws ShinyException 采集配置已存在 55 | */ 56 | SpiderConfigDO saveConfig(SpiderConfigVO spiderConfigVO) throws ShinyException; 57 | 58 | /** 59 | * 更新采集配置 60 | * 61 | * @param id 配置 id 62 | * @param spiderConfigVO 采集配置 VO 63 | * @return 采集配置 DO 64 | * @throws ShinyException 采集配置不存在 65 | */ 66 | SpiderConfigDO updateConfig(Integer id, SpiderConfigVO spiderConfigVO) throws ShinyException; 67 | 68 | /** 69 | * 根据配置 id 删除采集配置 70 | * 71 | * @param id 配置 id 72 | */ 73 | void deleteConfig(Integer id); 74 | 75 | /** 76 | * 获取采集配置详情 77 | * 78 | * @param id 配置 id 79 | * @return 采集配置 VO 80 | * @throws ShinyException 采集配置不存在 81 | */ 82 | SpiderConfigVO getConfig(Integer id) throws ShinyException; 83 | 84 | /** 85 | * 批量删除采集配置 86 | * 87 | * @param ids 采集 id 列表 88 | */ 89 | void deleteBatch(List ids); 90 | } 91 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/service/ISpiderContentService.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.service; 2 | 3 | import com.xkcoding.shiny.common.PageResult; 4 | import com.xkcoding.shiny.exception.ShinyException; 5 | import com.xkcoding.shiny.model.SpiderContentDO; 6 | import com.xkcoding.shiny.model.query.SpiderContentPageQuery; 7 | import com.xkcoding.shiny.model.vo.SpiderContentVO; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | *

13 | * 采集内容接口 14 | *

15 | * 16 | * @package: com.xkcoding.shiny.service 17 | * @description: 采集内容接口 18 | * @author: yangkai.shen 19 | * @date: Created in 2018/8/27 下午9:48 20 | * @copyright: Copyright (c) 2018 21 | * @version: V1.0 22 | * @modified: yangkai.shen 23 | */ 24 | public interface ISpiderContentService { 25 | /** 26 | * 删除今天采集的所有软件信息 27 | */ 28 | void deleteAllToday(); 29 | 30 | /** 31 | * 删除今天采集的某个软件信息 32 | * 33 | * @param configId 采集配置 id 34 | */ 35 | void deleteToday(Integer configId); 36 | 37 | /** 38 | * 查看单个软件的采集信息 39 | * 40 | * @param configId 配置id 41 | * @param query 查询条件 42 | * @return 分页信息 43 | * @throws ShinyException 采集配置不存在 44 | */ 45 | PageResult getSpiderContent(Integer configId, SpiderContentPageQuery query) throws ShinyException; 46 | 47 | /** 48 | * 查询采集信息列表 49 | * 50 | * @param query 查询条件 51 | * @return 采集信息列表 52 | */ 53 | PageResult listSpiderContent(SpiderContentPageQuery query); 54 | 55 | /** 56 | * 获取今天采集的最近更新时间在2天内的所有软件信息 57 | * 58 | * @return 今天采集的最近更新时间在2天内的所有软件信息 59 | */ 60 | List listLatestSoftware(); 61 | } 62 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/service/ISpiderLogService.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.service; 2 | 3 | import com.xkcoding.shiny.common.PageResult; 4 | import com.xkcoding.shiny.model.SpiderLogDO; 5 | import com.xkcoding.shiny.model.query.SpiderLogPageQuery; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | *

11 | * 采集日志服务接口 12 | *

13 | * 14 | * @package: com.xkcoding.shiny.service 15 | * @description: 采集日志服务接口 16 | * @author: yangkai.shen 17 | * @date: Created in 2018/8/28 下午8:54 18 | * @copyright: Copyright (c) 2018 19 | * @version: V1.0 20 | * @modified: yangkai.shen 21 | */ 22 | public interface ISpiderLogService { 23 | /** 24 | * 保存采集日志 25 | * 26 | * @param spiderLogDO 采集日志 DO 27 | */ 28 | void saveSpiderLog(SpiderLogDO spiderLogDO); 29 | 30 | /** 31 | * 采集日志列表 32 | * 33 | * @param query 查询条件 34 | * @return 采集日志列表 35 | */ 36 | PageResult listSpiderLog(SpiderLogPageQuery query); 37 | 38 | /** 39 | * 根据 id 删除日志 40 | * 41 | * @param id 日志 id 42 | */ 43 | void deleteLogById(Integer id); 44 | 45 | /** 46 | * 批量删除日志 47 | * 48 | * @param ids 日志 id 列表 49 | */ 50 | void deleteBatch(List ids); 51 | 52 | /** 53 | * 删除今天采集的日志 54 | */ 55 | void deleteTodayLog(); 56 | } 57 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/service/ISpiderService.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.service; 2 | 3 | import com.xkcoding.shiny.model.SpiderConfigDO; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | *

9 | * 爬虫接口 10 | *

11 | * 12 | * @package: com.xkcoding.shiny.service 13 | * @description: 爬虫接口 14 | * @author: yangkai.shen 15 | * @date: Created in 2018/8/27 下午6:35 16 | * @copyright: Copyright (c) 2018 17 | * @version: V1.0 18 | * @modified: yangkai.shen 19 | */ 20 | public interface ISpiderService { 21 | /** 22 | * 根据配置列表采集信息 23 | * 24 | * @param configDOList 采集配置列表 25 | */ 26 | void spider(List configDOList) throws InterruptedException; 27 | 28 | /** 29 | * 重新爬取今天采集的所有软件信息 30 | */ 31 | void reSpiderAllToday() throws InterruptedException; 32 | 33 | /** 34 | * 重新爬取今天采集的某个软件信息 35 | * 36 | * @param configId 采集配置id 37 | */ 38 | void reSpiderToday(Integer configId) throws InterruptedException; 39 | } 40 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/service/impl/MailServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.service.impl; 2 | 3 | import cn.hutool.extra.template.engine.beetl.BeetlUtil; 4 | import com.xkcoding.shiny.common.property.ShinyProperties; 5 | import com.xkcoding.shiny.service.IMailService; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.beetl.core.Template; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.mail.javamail.JavaMailSender; 10 | import org.springframework.mail.javamail.MimeMessageHelper; 11 | import org.springframework.stereotype.Service; 12 | 13 | import javax.mail.MessagingException; 14 | import javax.mail.internet.MimeMessage; 15 | import java.util.Map; 16 | 17 | /** 18 | *

19 | * 邮件接口实现 20 | *

21 | * 22 | * @package: com.xkcoding.shiny.service.impl 23 | * @description: 邮件接口实现 24 | * @author: yangkai.shen 25 | * @date: Created in 2018/9/6 下午8:56 26 | * @copyright: Copyright (c) 2018 27 | * @version: V1.0 28 | * @modified: yangkai.shen 29 | */ 30 | @Service 31 | @Slf4j 32 | public class MailServiceImpl implements IMailService { 33 | private final JavaMailSender mailSender; 34 | 35 | private final ShinyProperties shinyProperties; 36 | 37 | @Autowired 38 | public MailServiceImpl(JavaMailSender mailSender, ShinyProperties shinyProperties) { 39 | this.mailSender = mailSender; 40 | this.shinyProperties = shinyProperties; 41 | } 42 | 43 | /** 44 | * 发送简单邮件 45 | * 46 | * @param to 收件人 47 | * @param subject 邮件主题 48 | * @param content 邮件内容 49 | */ 50 | @Override 51 | public void sendSimpleMail(String to, String subject, String content) { 52 | 53 | } 54 | 55 | /** 56 | * 发送简单 HTML 邮件 57 | * 58 | * @param to 收件人 59 | * @param subject 邮件主题 60 | * @param html HTML 内容 61 | */ 62 | @Override 63 | public void sendHtmlMail(String to, String subject, String html) { 64 | 65 | } 66 | 67 | /** 68 | * 发送 HTML 模板邮件 69 | * 70 | * @param to 收件人 71 | * @param subject 邮件主题 72 | * @param params 模板参数 73 | * @param templatePath 模板路径 74 | * @param templateName 模板名称 75 | */ 76 | @Override 77 | public void sendHtmlTemplateMail(String to, String subject, Map params, String templatePath, String templateName) throws MessagingException { 78 | MimeMessage message = mailSender.createMimeMessage(); 79 | MimeMessageHelper helper = new MimeMessageHelper(message, true); 80 | helper.setFrom(shinyProperties.getMailFrom()); 81 | helper.setTo(to); 82 | helper.setSubject(subject); 83 | Template template = BeetlUtil.getClassPathTemplate(templatePath, templateName); 84 | //渲染模板 85 | String result = BeetlUtil.render(template, params); 86 | helper.setText(result, true); 87 | mailSender.send(message); 88 | } 89 | 90 | /** 91 | * 发送附件邮件 92 | * 93 | * @param to 收件人 94 | * @param subject 邮件主题 95 | * @param content 邮件内容 96 | * @param filePath 附件路径 97 | */ 98 | @Override 99 | public void sendAttachmentsMail(String to, String subject, String content, String filePath) { 100 | 101 | } 102 | 103 | /** 104 | * 发送静态资源邮件 105 | * 106 | * @param to 收件人 107 | * @param subject 邮件主题 108 | * @param content 邮件内容 109 | * @param rscPath 静态资源路径 110 | * @param rscId 静态资源 id 111 | */ 112 | @Override 113 | public void sendInlineResourceMail(String to, String subject, String content, String rscPath, String rscId) { 114 | 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/service/impl/SpiderConfigServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.service.impl; 2 | 3 | import cn.hutool.core.collection.CollUtil; 4 | import cn.hutool.core.util.ObjectUtil; 5 | import cn.hutool.core.util.StrUtil; 6 | import com.github.pagehelper.Page; 7 | import com.github.pagehelper.PageHelper; 8 | import com.xkcoding.shiny.common.PageResult; 9 | import com.xkcoding.shiny.common.status.Status; 10 | import com.xkcoding.shiny.exception.ShinyException; 11 | import com.xkcoding.shiny.mapper.SpiderConfigMapper; 12 | import com.xkcoding.shiny.model.SpiderConfigDO; 13 | import com.xkcoding.shiny.model.query.SpiderConfigPageQuery; 14 | import com.xkcoding.shiny.model.vo.SpiderConfigVO; 15 | import com.xkcoding.shiny.service.ISpiderConfigService; 16 | import com.xkcoding.shiny.util.ShinyUtil; 17 | import org.modelmapper.ModelMapper; 18 | import org.springframework.beans.factory.annotation.Autowired; 19 | import org.springframework.stereotype.Service; 20 | 21 | import java.util.List; 22 | import java.util.stream.Collectors; 23 | 24 | /** 25 | *

26 | * 采集配置Service接口实现 27 | *

28 | * 29 | * @package: com.xkcoding.shiny.service.impl 30 | * @description: 采集配置Service接口实现 31 | * @author: yangkai.shen 32 | * @date: Created in 2018/8/15 下午10:02 33 | * @copyright: Copyright (c) 2018 34 | * @version: V1.0 35 | * @modified: yangkai.shen 36 | */ 37 | @Service 38 | public class SpiderConfigServiceImpl implements ISpiderConfigService { 39 | private final SpiderConfigMapper spiderConfigMapper; 40 | 41 | private final ModelMapper modelMapper; 42 | 43 | @Autowired 44 | public SpiderConfigServiceImpl(SpiderConfigMapper spiderConfigMapper, ModelMapper modelMapper) { 45 | this.spiderConfigMapper = spiderConfigMapper; 46 | this.modelMapper = modelMapper; 47 | } 48 | 49 | /** 50 | * 分页采集配置列表 51 | * 52 | * @param query 查询条件 53 | * @return 分页采集配置列表信息 54 | */ 55 | @Override 56 | public PageResult listSpiderConfig(SpiderConfigPageQuery query) { 57 | PageHelper.startPage(query.getCurrentPage(), query.getPageSize()); 58 | 59 | String spiderName = StrUtil.trim(query.getText()); 60 | if (StrUtil.isBlank(spiderName)) { 61 | spiderName = null; 62 | } 63 | List spiderConfigDOList = spiderConfigMapper.selectSpiderConfigByText(spiderName); 64 | 65 | Long total = ((Page) spiderConfigDOList).getTotal(); 66 | List spiderConfigVOList = spiderConfigDOList.stream().map(spiderConfigDO -> modelMapper.map(spiderConfigDO, SpiderConfigVO.class)).collect(Collectors.toList()); 67 | return new PageResult<>(total, spiderConfigVOList); 68 | } 69 | 70 | /** 71 | * 全部采集配置列表 72 | * 73 | * @return 全部采集配置列表 74 | */ 75 | @Override 76 | public List listAllSpiderConfig() { 77 | return spiderConfigMapper.selectAll(); 78 | } 79 | 80 | /** 81 | * 根据配置id获取采集配置 82 | * 83 | * @param id 配置 id 84 | * @return 采集配置 DO 85 | */ 86 | @Override 87 | public SpiderConfigDO selectSpiderConfig(Integer id) { 88 | return spiderConfigMapper.selectByPrimaryKey(id); 89 | } 90 | 91 | /** 92 | * 保存采集配置 93 | * 94 | * @param spiderConfigVO 采集配置 VO 95 | * @return 采集配置 DO 96 | * @throws ShinyException 配置已存在 97 | */ 98 | @Override 99 | public SpiderConfigDO saveConfig(SpiderConfigVO spiderConfigVO) throws ShinyException { 100 | if (StrUtil.isBlank(spiderConfigVO.getSpiderUrl())) { 101 | throw new ShinyException(Status.CONFIG_URL_NOT_BLANK); 102 | } 103 | 104 | // 检查采集配置是否存在 105 | SpiderConfigDO query = SpiderConfigDO.builder().spiderUrl(spiderConfigVO.getSpiderUrl()).build(); 106 | List exist = spiderConfigMapper.select(query); 107 | if (CollUtil.isNotEmpty(exist)) { 108 | throw new ShinyException(Status.CONFIG_EXIST); 109 | } 110 | 111 | // VO -> DO 112 | SpiderConfigDO spiderConfigDO = modelMapper.map(spiderConfigVO, SpiderConfigDO.class); 113 | ShinyUtil.beforeInsert(spiderConfigDO, SpiderConfigDO.class, true); 114 | spiderConfigMapper.insertUseGeneratedKeys(spiderConfigDO); 115 | return spiderConfigDO; 116 | } 117 | 118 | /** 119 | * 更新采集配置 120 | * 121 | * @param id 配置 id 122 | * @param spiderConfigVO 采集配置 VO 123 | * @return 采集配置 DO 124 | * @throws ShinyException 采集配置不存在 125 | */ 126 | @Override 127 | public SpiderConfigDO updateConfig(Integer id, SpiderConfigVO spiderConfigVO) throws ShinyException { 128 | SpiderConfigDO exist = spiderConfigMapper.selectByPrimaryKey(id); 129 | if (ObjectUtil.isNull(exist)) { 130 | throw new ShinyException(Status.CONFIG_NOT_EXIST); 131 | } 132 | 133 | SpiderConfigDO spiderConfigDO = modelMapper.map(spiderConfigVO, SpiderConfigDO.class); 134 | ShinyUtil.beforeUpdate(spiderConfigDO, SpiderConfigDO.class, true); 135 | spiderConfigMapper.updateByPrimaryKeySelective(spiderConfigDO); 136 | 137 | return spiderConfigMapper.selectByPrimaryKey(id); 138 | } 139 | 140 | /** 141 | * 根据配置 id 删除采集配置 142 | * 143 | * @param id 配置 id 144 | */ 145 | @Override 146 | public void deleteConfig(Integer id) { 147 | spiderConfigMapper.deleteByPrimaryKey(id); 148 | } 149 | 150 | /** 151 | * 获取采集配置详情 152 | * 153 | * @param id 配置 id 154 | * @return 采集配置 VO 155 | * @throws ShinyException 采集配置不存在 156 | */ 157 | @Override 158 | public SpiderConfigVO getConfig(Integer id) throws ShinyException { 159 | SpiderConfigDO exist = spiderConfigMapper.selectByPrimaryKey(id); 160 | if (ObjectUtil.isNull(exist)) { 161 | throw new ShinyException(Status.CONFIG_NOT_EXIST); 162 | } 163 | return modelMapper.map(exist, SpiderConfigVO.class); 164 | } 165 | 166 | /** 167 | * 批量删除采集配置 168 | * 169 | * @param ids 采集 id 列表 170 | */ 171 | @Override 172 | public void deleteBatch(List ids) { 173 | spiderConfigMapper.deleteBatch(ids); 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/service/impl/SpiderContentServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.service.impl; 2 | 3 | import cn.hutool.core.date.DateTime; 4 | import cn.hutool.core.date.DateUtil; 5 | import cn.hutool.core.util.ObjectUtil; 6 | import com.github.pagehelper.Page; 7 | import com.github.pagehelper.PageHelper; 8 | import com.xkcoding.shiny.common.PageResult; 9 | import com.xkcoding.shiny.common.status.Status; 10 | import com.xkcoding.shiny.exception.ShinyException; 11 | import com.xkcoding.shiny.mapper.SpiderConfigMapper; 12 | import com.xkcoding.shiny.mapper.SpiderContentMapper; 13 | import com.xkcoding.shiny.model.SpiderConfigDO; 14 | import com.xkcoding.shiny.model.SpiderContentDO; 15 | import com.xkcoding.shiny.model.query.SpiderContentPageQuery; 16 | import com.xkcoding.shiny.model.vo.SpiderContentVO; 17 | import com.xkcoding.shiny.service.ISpiderContentService; 18 | import lombok.extern.slf4j.Slf4j; 19 | import org.modelmapper.ModelMapper; 20 | import org.springframework.beans.factory.annotation.Autowired; 21 | import org.springframework.stereotype.Service; 22 | 23 | import java.util.List; 24 | import java.util.stream.Collectors; 25 | 26 | /** 27 | *

28 | * 采集内容接口实现 29 | *

30 | * 31 | * @package: com.xkcoding.shiny.service.impl 32 | * @description: 采集内容接口实现 33 | * @author: yangkai.shen 34 | * @date: Created in 2018/8/27 下午9:50 35 | * @copyright: Copyright (c) 2018 36 | * @version: V1.0 37 | * @modified: yangkai.shen 38 | */ 39 | @Service 40 | @Slf4j 41 | public class SpiderContentServiceImpl implements ISpiderContentService { 42 | private final SpiderContentMapper spiderContentMapper; 43 | 44 | private final SpiderConfigMapper spiderConfigMapper; 45 | 46 | private final ModelMapper modelMapper; 47 | 48 | @Autowired 49 | public SpiderContentServiceImpl(SpiderContentMapper spiderContentMapper, SpiderConfigMapper spiderConfigMapper, ModelMapper modelMapper) { 50 | this.spiderContentMapper = spiderContentMapper; 51 | this.spiderConfigMapper = spiderConfigMapper; 52 | this.modelMapper = modelMapper; 53 | } 54 | 55 | /** 56 | * 删除今天采集的所有软件信息 57 | */ 58 | @Override 59 | public void deleteAllToday() { 60 | SpiderContentDO query = SpiderContentDO.builder().spiderTime(DateUtil.parseDate(DateUtil.today())).build(); 61 | int delete = spiderContentMapper.delete(query); 62 | log.info("【删除采集内容】已删除 {} 条采集日期为 {} 的软件信息", delete, DateUtil.parseDate(DateUtil.today())); 63 | } 64 | 65 | /** 66 | * 删除今天采集的某个软件信息 67 | * 68 | * @param configId 采集配置 id 69 | */ 70 | @Override 71 | public void deleteToday(Integer configId) { 72 | SpiderContentDO query = SpiderContentDO.builder().configId(configId).spiderTime(DateUtil.parseDate(DateUtil.today())).build(); 73 | int delete = spiderContentMapper.delete(query); 74 | log.info("【删除采集内容】已删除 {} 条,配置 id 为 {} 并且采集日期为 {} 的软件信息", delete, configId, DateUtil.parseDate(DateUtil.today())); 75 | } 76 | 77 | /** 78 | * 查看单个软件的采集信息 79 | * 80 | * @param configId 配置id 81 | * @param query 查询条件 82 | * @return 分页信息 83 | * @throws ShinyException 采集配置不存在 84 | */ 85 | @Override 86 | public PageResult getSpiderContent(Integer configId, SpiderContentPageQuery query) throws ShinyException { 87 | // 判断配置是否存在 88 | SpiderConfigDO exist = spiderConfigMapper.selectByPrimaryKey(configId); 89 | if (ObjectUtil.isNull(exist)) { 90 | throw new ShinyException(Status.CONFIG_NOT_EXIST); 91 | } 92 | 93 | // 分页 94 | PageHelper.startPage(query.getCurrentPage(), query.getPageSize()); 95 | 96 | // 查询采集信息 97 | List spiderContentDOList = spiderContentMapper.selectSingleSpiderContent(configId, query); 98 | Long total = ((Page) spiderContentDOList).getTotal(); 99 | 100 | // DO -> VO 101 | List spiderContentVOList = spiderContentDOList.stream().map(spiderContentDO -> modelMapper.map(spiderContentDO, SpiderContentVO.class)).collect(Collectors.toList()); 102 | return new PageResult<>(total, spiderContentVOList); 103 | } 104 | 105 | /** 106 | * 查询采集信息列表 107 | * 108 | * @param query 查询条件 109 | * @return 采集信息列表 110 | */ 111 | @Override 112 | public PageResult listSpiderContent(SpiderContentPageQuery query) { 113 | // 分页 114 | PageHelper.startPage(query.getCurrentPage(), query.getPageSize()); 115 | 116 | // 查询采集信息 117 | List spiderContentDOList = spiderContentMapper.selectSpiderContent(query); 118 | Long total = ((Page) spiderContentDOList).getTotal(); 119 | 120 | // DO -> VO 121 | List spiderContentVOList = spiderContentDOList.stream().map(spiderContentDO -> modelMapper.map(spiderContentDO, SpiderContentVO.class)).collect(Collectors.toList()); 122 | return new PageResult<>(total, spiderContentVOList); 123 | } 124 | 125 | /** 126 | * 获取今天采集的最近更新时间在2天内的所有软件信息 127 | * 128 | * @return 今天采集的最近更新时间在2天内的所有软件信息 129 | */ 130 | @Override 131 | public List listLatestSoftware() { 132 | DateTime now = DateUtil.date(); 133 | 134 | DateTime today = DateUtil.beginOfDay(now); 135 | DateTime startTime = DateUtil.offsetDay(today, -2); 136 | DateTime endTime = today; 137 | 138 | return spiderContentMapper.selectLatestSpiderContent(today.toString(), startTime.toString(), endTime.toString()); 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/service/impl/SpiderLogServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.service.impl; 2 | 3 | import cn.hutool.core.date.DateUtil; 4 | import cn.hutool.core.util.StrUtil; 5 | import com.github.pagehelper.Page; 6 | import com.github.pagehelper.PageHelper; 7 | import com.xkcoding.shiny.common.PageResult; 8 | import com.xkcoding.shiny.mapper.SpiderLogMapper; 9 | import com.xkcoding.shiny.model.SpiderLogDO; 10 | import com.xkcoding.shiny.model.query.SpiderLogPageQuery; 11 | import com.xkcoding.shiny.service.ISpiderLogService; 12 | import lombok.extern.slf4j.Slf4j; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.scheduling.annotation.Async; 15 | import org.springframework.stereotype.Service; 16 | 17 | import java.util.List; 18 | 19 | /** 20 | *

21 | * 采集日志接口实现 22 | *

23 | * 24 | * @package: com.xkcoding.shiny.service.impl 25 | * @description: 采集日志接口实现 26 | * @author: yangkai.shen 27 | * @date: Created in 2018/8/28 下午8:55 28 | * @copyright: Copyright (c) 2018 29 | * @version: V1.0 30 | * @modified: yangkai.shen 31 | */ 32 | @Service 33 | @Slf4j 34 | public class SpiderLogServiceImpl implements ISpiderLogService { 35 | private final SpiderLogMapper spiderLogMapper; 36 | 37 | @Autowired 38 | public SpiderLogServiceImpl(SpiderLogMapper spiderLogMapper) { 39 | this.spiderLogMapper = spiderLogMapper; 40 | } 41 | 42 | /** 43 | * 保存采集日志 44 | * 45 | * @param spiderLogDO 采集日志 DO 46 | */ 47 | @Async("asyncExecutor") 48 | @Override 49 | public void saveSpiderLog(SpiderLogDO spiderLogDO) { 50 | spiderLogMapper.insertUseGeneratedKeys(spiderLogDO); 51 | } 52 | 53 | /** 54 | * 采集日志列表 55 | * 56 | * @param query 查询条件 57 | * @return 采集日志列表 58 | */ 59 | @Override 60 | public PageResult listSpiderLog(SpiderLogPageQuery query) { 61 | PageHelper.startPage(query.getCurrentPage(), query.getPageSize()); 62 | 63 | String spiderName = StrUtil.trim(query.getSpiderName()); 64 | String version = StrUtil.trim(query.getVersion()); 65 | Integer status = query.getStatus(); 66 | String errorMsg = StrUtil.trim(query.getErrorMsg()); 67 | String startTime = StrUtil.trim(query.getStartTime()); 68 | String endTime = StrUtil.trim(query.getEndTime()); 69 | 70 | if (StrUtil.isBlank(spiderName)) { 71 | spiderName = null; 72 | } 73 | if (StrUtil.isBlank(version)) { 74 | version = null; 75 | } 76 | if (StrUtil.isBlank(errorMsg)) { 77 | errorMsg = null; 78 | } 79 | if (StrUtil.isBlank(startTime)) { 80 | startTime = null; 81 | } 82 | if (StrUtil.isBlank(endTime)) { 83 | endTime = null; 84 | } 85 | 86 | List spiderLogDOList = spiderLogMapper.selectSpiderLogByParam(spiderName, version, status, errorMsg, startTime, endTime); 87 | 88 | Long total = ((Page) spiderLogDOList).getTotal(); 89 | 90 | return new PageResult<>(total, spiderLogDOList); 91 | } 92 | 93 | /** 94 | * 根据 id 删除日志 95 | * 96 | * @param id 日志 id 97 | */ 98 | @Override 99 | public void deleteLogById(Integer id) { 100 | spiderLogMapper.deleteByPrimaryKey(id); 101 | } 102 | 103 | /** 104 | * 批量删除日志 105 | * 106 | * @param ids 日志 id 列表 107 | */ 108 | @Override 109 | public void deleteBatch(List ids) { 110 | spiderLogMapper.deleteBatch(ids); 111 | } 112 | 113 | /** 114 | * 删除今天采集的日志 115 | */ 116 | @Override 117 | public void deleteTodayLog() { 118 | String today = DateUtil.today(); 119 | String tomorrow = DateUtil.tomorrow().toDateStr(); 120 | spiderLogMapper.deleteByDuring(today, tomorrow); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/service/impl/SpiderServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.service.impl; 2 | 3 | import cn.hutool.core.collection.CollUtil; 4 | import com.xkcoding.shiny.common.property.ShinyProperties; 5 | import com.xkcoding.shiny.mapper.SpiderConfigMapper; 6 | import com.xkcoding.shiny.model.SpiderConfigDO; 7 | import com.xkcoding.shiny.service.ISpiderService; 8 | import com.xkcoding.shiny.task.SpiderTaskFactory; 9 | import com.xkcoding.shiny.task.SpiderTaskManager; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.scheduling.annotation.Async; 13 | import org.springframework.stereotype.Service; 14 | 15 | import java.util.List; 16 | import java.util.concurrent.CountDownLatch; 17 | 18 | /** 19 | *

20 | * 爬虫接口实现 21 | *

22 | * 23 | * @package: com.xkcoding.shiny.service.impl 24 | * @description: 爬虫接口实现 25 | * @author: yangkai.shen 26 | * @date: Created in 2018/8/27 下午6:36 27 | * @copyright: Copyright (c) 2018 28 | * @version: V1.0 29 | * @modified: yangkai.shen 30 | */ 31 | @Service 32 | @Slf4j 33 | public class SpiderServiceImpl implements ISpiderService { 34 | private final SpiderConfigMapper spiderConfigMapper; 35 | 36 | private final ShinyProperties shinyProperties; 37 | 38 | @Autowired 39 | public SpiderServiceImpl(SpiderConfigMapper spiderConfigMapper, ShinyProperties shinyProperties) { 40 | this.spiderConfigMapper = spiderConfigMapper; 41 | this.shinyProperties = shinyProperties; 42 | } 43 | 44 | /** 45 | * 根据配置列表采集信息 46 | * 47 | * @param configDOList 采集配置列表 48 | */ 49 | @Override 50 | public void spider(List configDOList) throws InterruptedException { 51 | log.info("【采集任务】开始采集软件信息......"); 52 | // 按照同时启动浏览器的数量分隔列表 53 | List> spiderList = CollUtil.split(configDOList, shinyProperties.getSpiderNum()); 54 | for (List spider : spiderList) { 55 | // 初始化任务数量 56 | CountDownLatch lock = new CountDownLatch(spider.size()); 57 | // 遍历,每个页面调取线程采集 58 | for (SpiderConfigDO spiderConfigDO : spider) { 59 | SpiderTaskManager.me().execute(SpiderTaskFactory.spiderTaskWithLock(spiderConfigDO, lock)); 60 | } 61 | 62 | // 加锁,等待所有任务完成 63 | lock.await(); 64 | } 65 | log.info("【采集任务】采集软件信息,全部任务采集完成"); 66 | } 67 | 68 | /** 69 | * 重新爬取今天采集的所有软件信息 70 | */ 71 | @Async("asyncExecutor") 72 | @Override 73 | public void reSpiderAllToday() throws InterruptedException { 74 | log.info("【异步任务】开始重新采集所有软件信息......"); 75 | // 获取所有软件名称-采集页面配置 76 | List configDOList = spiderConfigMapper.selectAll(); 77 | 78 | if (CollUtil.isNotEmpty(configDOList)) { 79 | spider(configDOList); 80 | } 81 | } 82 | 83 | /** 84 | * 重新爬取今天采集的某个软件信息 85 | * 86 | * @param configId 采集配置id 87 | */ 88 | @Async("asyncExecutor") 89 | @Override 90 | public void reSpiderToday(Integer configId) throws InterruptedException { 91 | log.info("【异步任务】开始重新采集配置 id 为 {} 的软件信息......", configId); 92 | // 获取采集配置id的软件名称-采集页面配置 93 | SpiderConfigDO query = SpiderConfigDO.builder().id(configId).build(); 94 | List configDOList = spiderConfigMapper.select(query); 95 | 96 | if (CollUtil.isNotEmpty(configDOList)) { 97 | spider(configDOList); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/task/NotificationTask.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.task; 2 | 3 | import cn.hutool.core.collection.CollUtil; 4 | import cn.hutool.json.JSONUtil; 5 | import com.xkcoding.shiny.common.ShinyConst; 6 | import com.xkcoding.shiny.model.SpiderContentDO; 7 | import com.xkcoding.shiny.service.ISpiderContentService; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.data.redis.core.StringRedisTemplate; 11 | import org.springframework.scheduling.annotation.Scheduled; 12 | import org.springframework.stereotype.Component; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | *

18 | * 通知任务 19 | *

20 | * 21 | * @package: com.xkcoding.shiny.task 22 | * @description: 通知任务 23 | * @author: yangkai.shen 24 | * @date: Created in 2018/9/4 下午8:18 25 | * @copyright: Copyright (c) 2018 26 | * @version: V1.0 27 | * @modified: yangkai.shen 28 | */ 29 | @Component 30 | @Slf4j 31 | public class NotificationTask { 32 | private final ISpiderContentService spiderContentService; 33 | 34 | private final StringRedisTemplate stringRedisTemplate; 35 | 36 | @Autowired 37 | public NotificationTask(ISpiderContentService spiderContentService, StringRedisTemplate stringRedisTemplate) { 38 | this.spiderContentService = spiderContentService; 39 | this.stringRedisTemplate = stringRedisTemplate; 40 | } 41 | 42 | /** 43 | * 每天早晨9点执行一次 44 | */ 45 | @Scheduled(cron = "0 0 9 1/1 1/1 ?") 46 | public void notification() { 47 | log.info("【定时任务】检查今天采集的软件版本更新情况......"); 48 | boolean hasUpdate = checkContent(); 49 | log.info("【定时任务】今天采集的软件版本更新情况,检查完成,{}", hasUpdate ? "软件有更新,邮件已发送" : "软件近两天无更新"); 50 | } 51 | 52 | /** 53 | * 检查采集内容 54 | * 55 | * @return 是否存在更新 56 | */ 57 | private boolean checkContent() { 58 | List spiderContentDOList = spiderContentService.listLatestSoftware(); 59 | if (CollUtil.isNotEmpty(spiderContentDOList)) { 60 | stringRedisTemplate.convertAndSend(ShinyConst.MAIL_CHANNEL, JSONUtil.toJsonStr(spiderContentDOList)); 61 | return true; 62 | } 63 | return false; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/task/SpiderTask.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.task; 2 | 3 | import com.xkcoding.shiny.mapper.SpiderConfigMapper; 4 | import com.xkcoding.shiny.model.SpiderConfigDO; 5 | import com.xkcoding.shiny.service.ISpiderService; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.scheduling.annotation.Scheduled; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | *

15 | * 定时采集任务 16 | *

17 | * 18 | * @package: com.xkcoding.shiny.task 19 | * @description: 定时采集任务 20 | * @author: yangkai.shen 21 | * @date: Created in 2018/8/22 下午9:58 22 | * @copyright: Copyright (c) 2018 23 | * @version: V1.0 24 | * @modified: yangkai.shen 25 | */ 26 | @Component 27 | @Slf4j 28 | public class SpiderTask { 29 | private final SpiderConfigMapper spiderConfigMapper; 30 | 31 | private final ISpiderService spiderService; 32 | 33 | @Autowired 34 | public SpiderTask(SpiderConfigMapper spiderConfigMapper, ISpiderService spiderService) { 35 | this.spiderConfigMapper = spiderConfigMapper; 36 | this.spiderService = spiderService; 37 | } 38 | 39 | /** 40 | * 每天凌晨2点执行一次 41 | */ 42 | @Scheduled(cron = "0 0 2 1/1 1/1 ?") 43 | public void spider() throws InterruptedException { 44 | log.info("【定时任务】开始采集软件信息......"); 45 | // 获取所有软件名称-采集页面配置 46 | List configDOList = spiderConfigMapper.selectAll(); 47 | 48 | spiderService.spider(configDOList); 49 | log.info("【定时任务】采集软件信息,全部任务采集完成"); 50 | } 51 | 52 | /** 53 | * 每天9点定时检测是否存在新版本 54 | */ 55 | @Scheduled(cron = "0 0 9 1/1 1/1 ?") 56 | public void email() { 57 | log.info("【定时任务】开始检测是否存在新版本......"); 58 | // 检测是否存在最近2天的软件新版本 59 | // 发邮件 60 | log.info("【定时任务】检测是否存在新版本,检测完成"); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/task/SpiderTaskManager.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.task; 2 | 3 | import org.apache.commons.lang3.concurrent.BasicThreadFactory; 4 | 5 | import java.util.TimerTask; 6 | import java.util.concurrent.ScheduledThreadPoolExecutor; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | /** 10 | *

11 | * 采集任务管理器 12 | *

13 | * 14 | * @package: com.xkcoding.shiny.task 15 | * @description: 采集任务管理器 16 | * @author: yangkai.shen 17 | * @date: Created in 2018/8/22 下午9:46 18 | * @copyright: Copyright (c) 2018 19 | * @version: V1.0 20 | * @modified: yangkai.shen 21 | */ 22 | public class SpiderTaskManager { 23 | /** 24 | * 采集操作延时 25 | */ 26 | private static final int SPIDER_DELAY_TIME = 2000; 27 | 28 | /** 29 | * 异步操作采集的线程池 30 | */ 31 | private ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(50, new BasicThreadFactory.Builder().namingPattern("Spider-Thread-%d").build()); 32 | 33 | private SpiderTaskManager() { 34 | } 35 | 36 | private static SpiderTaskManager manager = new SpiderTaskManager(); 37 | 38 | public static SpiderTaskManager me() { 39 | return manager; 40 | } 41 | 42 | public void execute(TimerTask task) { 43 | executor.schedule(task, SPIDER_DELAY_TIME, TimeUnit.MILLISECONDS); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/util/DriverUtil.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.util; 2 | 3 | import com.xkcoding.shiny.common.property.ShinyProperties; 4 | import org.openqa.selenium.chrome.ChromeDriver; 5 | import org.openqa.selenium.phantomjs.PhantomJSDriver; 6 | import org.openqa.selenium.phantomjs.PhantomJSDriverService; 7 | import org.openqa.selenium.remote.DesiredCapabilities; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.io.File; 12 | 13 | /** 14 | *

15 | * DriverUtil 工具类 16 | *

17 | * 18 | * @package: com.xkcoding.shiny.util 19 | * @description: DriverUtil 工具类 20 | * @author: yangkai.shen 21 | * @date: Created in 2018/8/25 下午1:48 22 | * @copyright: Copyright (c) 2018 23 | * @version: V1.0 24 | * @modified: yangkai.shen 25 | */ 26 | @Component 27 | public class DriverUtil { 28 | @Autowired 29 | private ShinyProperties shinyProperties; 30 | 31 | /** 32 | * 获取 ChromeDriver 驱动 33 | * 34 | * @return ChromeDriver 驱动 35 | */ 36 | public ChromeDriver getChromeDriver() { 37 | System.setProperty("webdriver.chrome.driver", getChromeDriverPath()); 38 | 39 | return new ChromeDriver(); 40 | } 41 | 42 | /** 43 | * 获取适合本机系统的 ChromeDriver 路径 44 | * 45 | * @return ChromeDriver 路径 46 | */ 47 | private String getChromeDriverPath() { 48 | if (ShinyUtil.isMac()) { 49 | return shinyProperties.getDriverPath() + File.separator + "chrome-driver/macos/chromedriver"; 50 | } else if (ShinyUtil.isLinux()) { 51 | return shinyProperties.getDriverPath() + File.separator + "chrome-driver/linux/chromedriver"; 52 | } else { 53 | return shinyProperties.getDriverPath() + File.separator + "chrome-driver/windows/chromedriver.exe"; 54 | } 55 | } 56 | 57 | /** 58 | * 获取 PhantomJs 驱动 59 | * 60 | * @return PhantomJs 驱动 61 | */ 62 | public PhantomJSDriver getPhantomJSDriver() { 63 | //设置必要参数 64 | DesiredCapabilities capabilities = new DesiredCapabilities(); 65 | //ssl证书支持 66 | capabilities.setCapability("acceptSslCerts", true); 67 | //截屏支持 68 | capabilities.setCapability("takesScreenshot", false); 69 | //css搜索支持 70 | capabilities.setCapability("cssSelectorsEnabled", true); 71 | //js支持 72 | capabilities.setJavascriptEnabled(true); 73 | //驱动支持 74 | capabilities.setCapability(PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY, getPhantomJsPath()); 75 | 76 | return new PhantomJSDriver(capabilities); 77 | } 78 | 79 | /** 80 | * 获取适合本机系统的 PhantomJs 路径 81 | * 82 | * @return PhantomJs 路径 83 | */ 84 | private String getPhantomJsPath() { 85 | if (ShinyUtil.isMac()) { 86 | return shinyProperties.getDriverPath() + File.separator + "phantomjs/macos/phantomjs"; 87 | } else if (ShinyUtil.isLinux()) { 88 | return shinyProperties.getDriverPath() + File.separator + "phantomjs/linux/X64/phantomjs"; 89 | } else { 90 | return shinyProperties.getDriverPath() + File.separator + "phantomjs/windows/phantomjs.exe"; 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/util/ShinyUtil.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.util; 2 | 3 | import cn.hutool.core.util.ObjectUtil; 4 | import cn.hutool.core.util.ReflectUtil; 5 | import cn.hutool.system.SystemUtil; 6 | import com.xkcoding.shiny.common.ShinyConst; 7 | import com.xkcoding.shiny.model.query.base.PageCondition; 8 | 9 | import java.lang.reflect.Field; 10 | import java.lang.reflect.Method; 11 | import java.util.Date; 12 | 13 | /** 14 | *

15 | * Shiny常用工具类 16 | *

17 | * 18 | * @package: com.xkcoding.shiny.util 19 | * @description: Shiny常用工具类 20 | * @author: yangkai.shen 21 | * @date: Created in 2018/8/15 下午10:06 22 | * @copyright: Copyright (c) 2018 23 | * @version: V1.0 24 | * @modified: yangkai.shen 25 | */ 26 | public class ShinyUtil { 27 | 28 | /** 29 | * 校验分页参数,为NULL,设置分页参数默认值 30 | * 31 | * @param condition 查询参数 32 | * @param clazz 类 33 | * @param {@link PageCondition} 34 | * @return T 35 | */ 36 | public static T checkPageCondition(T condition, Class clazz) { 37 | if (ObjectUtil.isNull(condition)) { 38 | condition = ReflectUtil.newInstance(clazz); 39 | } 40 | if (ObjectUtil.isNull(condition.getCurrentPage())) { 41 | condition.setCurrentPage(ShinyConst.DEFAULT_CURRENT_PAGE); 42 | } 43 | if (ObjectUtil.isNull(condition.getPageSize())) { 44 | condition.setPageSize(ShinyConst.DEFAULT_PAGE_SIZE); 45 | } 46 | return condition; 47 | } 48 | 49 | /** 50 | * 是否是 Mac 系统 51 | * 52 | * @return truefalse 否 53 | */ 54 | static Boolean isMac() { 55 | return SystemUtil.getOsInfo().isMac() || SystemUtil.getOsInfo().isMacOsX(); 56 | } 57 | 58 | /** 59 | * 是否是 Linux 系统 60 | * 61 | * @return truefalse 否 62 | */ 63 | static Boolean isLinux() { 64 | return SystemUtil.getOsInfo().isLinux(); 65 | } 66 | 67 | /** 68 | * 是否是 Windows 系统 69 | * 70 | * @return truefalse 否 71 | */ 72 | public static Boolean isWindows() { 73 | return SystemUtil.getOsInfo().isWindows(); 74 | } 75 | 76 | /** 77 | * 判断对象是否为空对象,属性都为null 78 | * 79 | * @param object 对象 80 | * @param clazz 对象类型 81 | * @return 是否为空,true - 空 / false - 非空 82 | */ 83 | public static Boolean isEmpty(Object object, Class clazz) { 84 | if (ObjectUtil.isNull(object)) { 85 | return true; 86 | } 87 | Field[] fields = ReflectUtil.getFields(clazz); 88 | for (Field field : fields) { 89 | Object fieldValue = ReflectUtil.getFieldValue(object, field); 90 | if (ObjectUtil.isNotNull(fieldValue)) { 91 | return false; 92 | } 93 | } 94 | return true; 95 | } 96 | 97 | /** 98 | * 插入前操作 99 | * 100 | * @param obj 对象 101 | * @param clazz 对象类型 102 | * @param override 是否覆盖属性 103 | */ 104 | public static void beforeInsert(Object obj, Class clazz, boolean override) { 105 | Method setCreateBy = ReflectUtil.getMethod(clazz, "setCreateBy"); 106 | Method getCreateBy = ReflectUtil.getMethod(clazz, "getCreateBy"); 107 | Method setCreateTime = ReflectUtil.getMethod(clazz, "setCreateTime"); 108 | Method getCreateTime = ReflectUtil.getMethod(clazz, "getCreateTime"); 109 | 110 | if (setCreateBy != null) { 111 | if (override || ObjectUtil.isNull(ReflectUtil.invoke(obj, getCreateBy))) { 112 | ReflectUtil.invoke(obj, setCreateBy, "管理员"); 113 | } 114 | } 115 | if (setCreateTime != null) { 116 | if (override || ObjectUtil.isNull(ReflectUtil.invoke(obj, getCreateTime))) { 117 | ReflectUtil.invoke(obj, setCreateTime, new Date()); 118 | } 119 | } 120 | 121 | beforeUpdate(obj, clazz, override); 122 | } 123 | 124 | /** 125 | * 更新前操作 126 | * 127 | * @param obj 对象 128 | * @param clazz 对象类型 129 | * @param override 是否覆盖属性 130 | */ 131 | public static void beforeUpdate(Object obj, Class clazz, boolean override) { 132 | Method setUpdateBy = ReflectUtil.getMethod(clazz, "setUpdateBy"); 133 | Method getUpdateBy = ReflectUtil.getMethod(clazz, "getUpdateBy"); 134 | Method setUpdateTime = ReflectUtil.getMethod(clazz, "setUpdateTime"); 135 | Method getUpdateTime = ReflectUtil.getMethod(clazz, "getUpdateTime"); 136 | 137 | if (setUpdateBy != null) { 138 | if (override || ObjectUtil.isNull(ReflectUtil.invoke(obj, getUpdateBy))) { 139 | ReflectUtil.invoke(obj, setUpdateBy, "管理员"); 140 | } 141 | } 142 | if (setUpdateTime != null) { 143 | if (override || ObjectUtil.isNull(ReflectUtil.invoke(obj, getUpdateTime))) { 144 | ReflectUtil.invoke(obj, setUpdateTime, new Date()); 145 | } 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /back/src/main/java/com/xkcoding/shiny/util/SpringContextHolderUtil.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.util; 2 | 3 | import org.springframework.beans.BeansException; 4 | import org.springframework.context.ApplicationContext; 5 | import org.springframework.context.ApplicationContextAware; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | *

10 | * Spring的ApplicationContext的持有者,可以用静态方法的方式获取spring容器中的bean 11 | *

12 | * 13 | * @package: com.xkcoding.shiny.util 14 | * @description: Spring的ApplicationContext的持有者, 可以用静态方法的方式获取spring容器中的bean 15 | * @author: yangkai.shen 16 | * @date: Created in 2018/8/25 下午2:40 17 | * @copyright: Copyright (c) 2018 18 | * @version: V1.0 19 | * @modified: yangkai.shen 20 | */ 21 | @Component 22 | public class SpringContextHolderUtil implements ApplicationContextAware { 23 | 24 | private static ApplicationContext applicationContext; 25 | 26 | @Override 27 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 28 | SpringContextHolderUtil.applicationContext = applicationContext; 29 | } 30 | 31 | public static ApplicationContext getApplicationContext() { 32 | assertApplicationContext(); 33 | return applicationContext; 34 | } 35 | 36 | @SuppressWarnings("unchecked") 37 | public static T getBean(String beanName) { 38 | assertApplicationContext(); 39 | return (T) applicationContext.getBean(beanName); 40 | } 41 | 42 | public static T getBean(Class requiredType) { 43 | assertApplicationContext(); 44 | return applicationContext.getBean(requiredType); 45 | } 46 | 47 | private static void assertApplicationContext() { 48 | if (SpringContextHolderUtil.applicationContext == null) { 49 | throw new RuntimeException("applicaitonContext属性为null,请检查是否注入了SpringContextHolder!"); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /back/src/main/resources/META-INF/additional-spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": [ 3 | { 4 | "name": "shiny.name", 5 | "type": "java.lang.String", 6 | "description": "应用名称." 7 | }, 8 | { 9 | "name": "shiny.version", 10 | "type": "java.lang.String", 11 | "description": "应用版本号." 12 | }, 13 | { 14 | "name": "shiny.copyrightYear", 15 | "type": "java.lang.String", 16 | "description": "版权年份." 17 | }, 18 | { 19 | "name": "shiny.developer", 20 | "type": "java.lang.String", 21 | "description": "开发者." 22 | }, 23 | { 24 | "name": "shiny.driver-path", 25 | "type": "java.lang.String", 26 | "description": "driver 路径." 27 | }, 28 | { 29 | "name": "shiny.spider-num", 30 | "type": "java.lang.Integer", 31 | "defaultValue": 5, 32 | "description": "并发软件采集的数量." 33 | }, 34 | { 35 | "name": "shiny.mail-from", 36 | "type": "java.lang.String", 37 | "description": "邮件发送人." 38 | } 39 | ] 40 | } -------------------------------------------------------------------------------- /back/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | # 自定义配置 2 | shiny: 3 | # 名称 4 | name: ${spring.application.name} 5 | # 版本 6 | version: 0.0.1 7 | # 版权年份 8 | copyrightYear: 2018 9 | # 作者 10 | developer: Yangkai.Shen 11 | # driver 路径 12 | driver-path: /Users/yangkai.shen/Documents/code/back-end/shiny-telegram/back/driver 13 | # 并发软件采集的数量 14 | spider-num: 5 15 | # 邮件发送人 16 | mail-from: shiny-telegram 17 | 18 | spring: 19 | application: 20 | name: shiny 21 | datasource: 22 | url: jdbc:mysql://localhost:3306/shiny?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8 23 | username: root 24 | password: root 25 | driver-class-name: com.mysql.cj.jdbc.Driver 26 | type: com.zaxxer.hikari.HikariDataSource 27 | hikari: 28 | minimum-idle: 5 29 | connection-test-query: SELECT 1 FROM DUAL 30 | maximum-pool-size: 20 31 | auto-commit: true 32 | idle-timeout: 30000 33 | pool-name: ShinyHikariCP 34 | max-lifetime: 60000 35 | connection-timeout: 30000 36 | mvc: 37 | throw-exception-if-no-handler-found: true 38 | resources: 39 | add-mappings: false 40 | jackson: 41 | date-format: yyyy-MM-dd HH:mm:ss 42 | time-zone: GMT+8 43 | mail: 44 | host: smtp.yeah.net 45 | default-encoding: UTF-8 46 | username: hutool@yeah.net 47 | password: q1w2e3 48 | redis: 49 | database: 0 50 | host: localhost 51 | port: 6379 52 | password: 53 | jedis: 54 | pool: 55 | max-active: 8 56 | max-idle: 8 57 | max-wait: -1ms 58 | timeout: 30000ms 59 | 60 | server: 61 | port: 8080 62 | servlet: 63 | context-path: /shiny 64 | tomcat: 65 | uri-encoding: utf-8 66 | 67 | # mybatis 配置 68 | mybatis: 69 | type-aliases-package: com.xkcoding.scaffold.model 70 | mapper-locations: classpath:mybatis/mapper/*.xml 71 | configuration: 72 | map-underscore-to-camel-case: true 73 | 74 | # 通用 Mapper 配置 75 | mapper: 76 | mappers: com.xkcoding.shiny.common.MyMapper 77 | notEmpty: true 78 | 79 | # PageHelper 配置 80 | pagehelper: 81 | helper-dialect: mysql 82 | reasonable: true 83 | support-methods-arguments: true 84 | params: count=countSql 85 | 86 | #日志配置 87 | logging: 88 | level: 89 | com.xkcoding: info 90 | org.springframework: info 91 | com.xkcoding.shiny.mapper: debug -------------------------------------------------------------------------------- /back/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ${AnsiColor.BRIGHT_GREEN} 2 | 3 | ###### ## ## #### ## ## ## ## 4 | ## ## ## ## ## ### ## ## ## 5 | ## ## ## ## #### ## #### 6 | ###### ######### ## ## ## ## ## 7 | ## ## ## ## ## #### ## 8 | ## ## ## ## ## ## ### ## 9 | ###### ## ## #### ## ## ## 10 | 11 | ${AnsiColor.BRIGHT_RED} 12 | Application 版本: ${shiny.name} - ${shiny.version} 13 | Application 开发: ${shiny.developer} 14 | Application 时间: ${shiny.copyrightYear} 15 | Spring Boot 版本: ${spring-boot.version} 16 | ${AnsiColor.BRIGHT_WHITE} -------------------------------------------------------------------------------- /back/src/main/resources/beetl.properties: -------------------------------------------------------------------------------- 1 | ENGINE=org.beetl.core.engine.DefaultTemplateEngine 2 | DELIMITER_PLACEHOLDER_START=${ 3 | DELIMITER_PLACEHOLDER_END=} 4 | DELIMITER_STATEMENT_START=@ 5 | DELIMITER_STATEMENT_END=null 6 | RESOURCE.tagSuffix=tag -------------------------------------------------------------------------------- /back/src/main/resources/email/software-update.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 软件更新通知 6 | 104 | 105 | 106 |
107 |

老板,您要的软件又更新啦!

108 |
109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 |
软件名软件版本更新日期城通网盘链接百度网盘链接提取码采集日期
122 |
123 |
124 | 125 | 126 | @for(trData in trDataList){ 127 | 128 | 129 | 130 | 131 | 139 | 147 | 148 | 149 | 150 | @} 151 | 152 |
${trData.configName}${trData.version}${trData.updateTime,"yyyy-MM-dd"} 132 | @if(trData.ctPanUrl!=null && @cn.hutool.core.util.StrUtil.containsAny(trData.ctPanUrl,"http")){ 133 | 城通网盘 134 | @} 135 | @if(trData.ctPanUrl!=null && !@cn.hutool.core.util.StrUtil.containsAny(trData.ctPanUrl,"http")){ 136 | ${trData.ctPanUrl} 137 | @} 138 | 140 | @if(trData.bdPanUrl!=null && @cn.hutool.core.util.StrUtil.containsAny(trData.bdPanUrl,"http")){ 141 | 百度网盘 142 | @} 143 | @if(trData.bdPanUrl!=null && !@cn.hutool.core.util.StrUtil.containsAny(trData.bdPanUrl,"http")){ 144 | ${trData.bdPanUrl} 145 | @} 146 | ${trData.bdPanCode}${trData.spiderTime,"yyyy-MM-dd"}
153 |
154 |
155 | 156 | 157 | 158 |
159 | 由 Shiny-Telegram 发送 160 | by 161 | Yangkai.Shen 162 |
163 | 164 | -------------------------------------------------------------------------------- /back/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | INFO 7 | 8 | 9 | %date [%thread] %-5level [%logger{50}] %file:%line - %msg%n 10 | UTF-8 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ERROR 19 | 20 | DENY 21 | 22 | ACCEPT 23 | 24 | 25 | 26 | 27 | 28 | 29 | logs/shiny/info.created_on_%d{yyyy-MM-dd}.part_%i.log 30 | 31 | 90 32 | 33 | 34 | 35 | 36 | 2MB 37 | 38 | 39 | 40 | 41 | 42 | 43 | %date [%thread] %-5level [%logger{50}] %file:%line - %msg%n 44 | UTF-8 45 | 46 | 47 | 48 | 49 | 50 | 51 | Error 52 | 53 | 54 | 55 | 56 | 57 | 58 | logs/shiny/error.created_on_%d{yyyy-MM-dd}.part_%i.log 59 | 60 | 90 61 | 62 | 63 | 2MB 64 | 65 | 66 | 67 | %date [%thread] %-5level [%logger{50}] %file:%line - %msg%n 68 | UTF-8 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /back/src/main/resources/mybatis/generator/datasource.properties: -------------------------------------------------------------------------------- 1 | jdbc.url=jdbc:mysql://localhost:3306/shiny?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false 2 | jdbc.user=root 3 | jdbc.password=root 4 | jdbc.driverClass=com.mysql.jdbc.Driver -------------------------------------------------------------------------------- /back/src/main/resources/mybatis/generator/generatorConfig.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 22 | 23 | 24 | 26 | 27 | 29 | 30 | 33 | 34 |
35 |
36 |
-------------------------------------------------------------------------------- /back/src/main/resources/mybatis/mapper/EmailLogMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /back/src/main/resources/mybatis/mapper/SpiderConfigMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 26 | 27 | 28 | DELETE FROM spider_config WHERE id IN 29 | 31 | #{item} 32 | 33 | 34 | -------------------------------------------------------------------------------- /back/src/main/resources/mybatis/mapper/SpiderContentMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 52 | 53 | 105 | 106 | 113 | -------------------------------------------------------------------------------- /back/src/main/resources/mybatis/mapper/SpiderLogMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 39 | 40 | 41 | DELETE FROM spider_log WHERE id IN 42 | 44 | #{item} 45 | 46 | 47 | 48 | 49 | DELETE FROM spider_log 50 | WHERE 51 | 52 | `spider_time` >= #{startTime} AND `spider_time` <= #{endTime} 53 | 54 | 55 | -------------------------------------------------------------------------------- /back/src/main/resources/mybatis/mapper/SysConfigMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /back/src/main/resources/mybatis/mapper/SysRoleMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /back/src/main/resources/mybatis/mapper/SysUserMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /back/src/main/resources/mybatis/mapper/SysUserRoleMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /back/src/test/java/com/xkcoding/shiny/ShinyApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ShinyApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /back/src/test/java/com/xkcoding/shiny/service/impl/MailServiceImplTest.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.service.impl; 2 | 3 | import cn.hutool.core.lang.Dict; 4 | import com.xkcoding.shiny.ShinyApplicationTests; 5 | import com.xkcoding.shiny.common.PageResult; 6 | import com.xkcoding.shiny.model.query.SpiderContentPageQuery; 7 | import com.xkcoding.shiny.model.vo.SpiderContentVO; 8 | import com.xkcoding.shiny.service.IMailService; 9 | import com.xkcoding.shiny.service.ISpiderContentService; 10 | import org.junit.Test; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | 13 | import javax.mail.MessagingException; 14 | import java.util.List; 15 | 16 | /** 17 | *

18 | * 邮件发送测试类 19 | *

20 | * 21 | * @package: com.xkcoding.shiny.service.impl 22 | * @description: 邮件发送测试类 23 | * @author: yangkai.shen 24 | * @date: Created in 2018/9/6 下午9:06 25 | * @copyright: Copyright (c) 2018 26 | * @version: V1.0 27 | * @modified: yangkai.shen 28 | */ 29 | public class MailServiceImplTest extends ShinyApplicationTests { 30 | @Autowired 31 | private IMailService mailService; 32 | 33 | @Autowired 34 | private ISpiderContentService spiderContentService; 35 | 36 | @Test 37 | public void sendHtmlTemplateMail() throws MessagingException { 38 | SpiderContentPageQuery query = new SpiderContentPageQuery(); 39 | query.setCurrentPage(1); 40 | query.setPageSize(50); 41 | PageResult pageResult = spiderContentService.listSpiderContent(query); 42 | List list = pageResult.getList(); 43 | mailService.sendHtmlTemplateMail("237497819@qq.com", "软件更新通知", Dict.create().set("trDataList", list), "email", "software-update.html"); 44 | } 45 | } -------------------------------------------------------------------------------- /back/src/test/java/com/xkcoding/shiny/spider/ChromeDriverTest.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.spider; 2 | 3 | import cn.hutool.core.util.RandomUtil; 4 | import com.xkcoding.shiny.ShinyApplicationTests; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.jsoup.Jsoup; 7 | import org.jsoup.nodes.Document; 8 | import org.jsoup.select.Elements; 9 | import org.junit.Test; 10 | import org.openqa.selenium.By; 11 | import org.openqa.selenium.WebDriver; 12 | import org.openqa.selenium.WebElement; 13 | import org.openqa.selenium.chrome.ChromeDriver; 14 | import org.openqa.selenium.support.ui.ExpectedCondition; 15 | import org.openqa.selenium.support.ui.WebDriverWait; 16 | import us.codecraft.xsoup.Xsoup; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Set; 20 | 21 | /** 22 | *

23 | * 测试 ChromeDriver
24 | * chromeDriver是谷歌的浏览器驱动,用来适配Selenium,有图形页面存在,在调试爬虫下载运行的功能的时候会相对方便 25 | *

26 | * 27 | * @package: com.xkcoding.shiny.spider 28 | * @description: 测试 ChromeDriver 29 | * @author: yangkai.shen 30 | * @date: Created in 2018/8/21 下午8:08 31 | * @copyright: Copyright (c) 2018 32 | * @version: V1.0 33 | * @modified: yangkai.shen 34 | */ 35 | @Slf4j 36 | public class ChromeDriverTest extends ShinyApplicationTests { 37 | 38 | @Test 39 | public void testThings() throws InterruptedException { 40 | ArrayList list = new ArrayList<>(); 41 | System.setProperty("webdriver.chrome.driver", "/Users/yangkai.shen/Desktop/chromedriver"); // 此处PATH替换为你的chromedriver所在路径 42 | WebDriver driver = new ChromeDriver(); 43 | // 让浏览器访问 xclient.info 44 | driver.get("http://xclient.info/s/things.html?t=" + RandomUtil.simpleUUID()); 45 | String oriWin = driver.getWindowHandle(); 46 | list.add(oriWin); 47 | // 用下面代码也可以实现 48 | //driver.navigate().to("http://www.baidu.com"); 49 | // 获取 网页的 title 50 | System.out.println(" Page title is: " + driver.getTitle()); 51 | Document document = Jsoup.parse(driver.getPageSource()); 52 | 53 | String summary = Xsoup.compile("//*[@id=\"main\"]/div/article/div[3]/p/text()").evaluate(document).get(); 54 | log.debug("【summary】: {}", summary); 55 | String postContentHtml = Xsoup.compile("//*[@id=\"post-content\"]").evaluate(document).get(); 56 | log.debug("【content】: {}", postContentHtml); 57 | 58 | String versionsHTML = Xsoup.compile("//*[@id=\"versions\"]/table").evaluate(document).get(); 59 | log.debug("【versions】: {}", versionsHTML); 60 | Document versionsDocument = Jsoup.parse(versionsHTML); 61 | Elements trs = versionsDocument.select("table").select("tbody").select("tr"); 62 | 63 | WebElement element = driver.findElement(By.xpath("//*[@id=\"versions\"]/table/tbody/tr[1]/td[5]/a[2]")); 64 | element.click(); 65 | Thread.sleep(1000); 66 | Set handles = driver.getWindowHandles(); 67 | for (String handle : handles) { 68 | if (list.indexOf(handle) == -1) { 69 | WebDriverWait wait = new WebDriverWait(driver, 3); 70 | wait.until(new ExceptWindow(handle)); 71 | log.info(handle); 72 | list.add(handle); 73 | } 74 | } 75 | 76 | log.debug(driver.getCurrentUrl()); 77 | Document bdDocument = Jsoup.parse(driver.getPageSource()); 78 | String bdLink = Xsoup.compile("//*[@id=\"body\"]/div[1]/div[2]/a/@data-link").evaluate(bdDocument).get(); 79 | String bdKey = Xsoup.compile("//*[@id=\"body\"]/div[1]/div[2]/a/@data-clipboard-text").evaluate(bdDocument).get(); 80 | log.debug("【百度】{}【提取码】{}", bdLink, bdKey); 81 | 82 | // for (Element tr : trs) { 83 | // Elements tds = tr.select("td"); 84 | // 85 | // String version = tds.get(0).text(); 86 | // String language = tds.get(1).text(); 87 | // String date = tds.get(2).text(); 88 | // String size = tds.get(3).text(); 89 | // Element linkElement = tds.get(4); 90 | // Elements downloadElements = linkElement.select(".btn-download"); 91 | // for (int k = 0; k < downloadElements.size(); k++) { 92 | // if (StrUtil.containsIgnoreCase(downloadElements.get(k).text(), "城通网盘")) { 93 | // newDriver.get(downloadElements.get(k).attr("href")); 94 | // Document ctDocument = Jsoup.parse(newDriver.getPageSource()); 95 | // String ctLink = Xsoup.compile("//*[@id=\"body\"]/div[1]/div[2]/a/@href").evaluate(ctDocument).get(); 96 | // log.debug("【城通】{}", ctLink); 97 | // } else if (StrUtil.containsIgnoreCase(downloadElements.get(k).text(), "百度云盘")) { 98 | // newDriver.get(downloadElements.get(k).attr("href")); 99 | // Document bdDocument = Jsoup.parse(newDriver.getPageSource()); 100 | // String bdLink = Xsoup.compile("//*[@id=\"body\"]/div[1]/div[2]/a/@data-link").evaluate(bdDocument).get(); 101 | // String bdKey = Xsoup.compile("//*[@id=\"body\"]/div[1]/div[2]/a/@data-clipboard-text").evaluate(bdDocument).get(); 102 | // log.debug("【百度】{}【提取码】{}", bdLink, bdKey); 103 | // } 104 | // } 105 | // log.info("【版本】{},【语言】{},【更新日期】{},【文件大小】{},【城通】{},【百度】{}", version, language, date, size, null, null); 106 | // } 107 | 108 | // 关闭浏览器 109 | driver.quit(); 110 | } 111 | 112 | static class ExceptWindow implements ExpectedCondition { 113 | private String id; 114 | 115 | public ExceptWindow(String id) { 116 | this.id = id; 117 | } 118 | 119 | @Override 120 | public WebDriver apply(WebDriver d) { 121 | return d.switchTo().window(id); 122 | } 123 | } 124 | 125 | } 126 | -------------------------------------------------------------------------------- /back/src/test/java/com/xkcoding/shiny/spider/PhantomJsTest.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.spider; 2 | 3 | import cn.hutool.core.util.RandomUtil; 4 | import cn.hutool.json.JSONUtil; 5 | import com.xkcoding.shiny.ShinyApplicationTests; 6 | import com.xkcoding.shiny.util.DriverUtil; 7 | import org.assertj.core.util.Sets; 8 | import org.jsoup.Jsoup; 9 | import org.jsoup.nodes.Document; 10 | import org.junit.Test; 11 | import org.openqa.selenium.By; 12 | import org.openqa.selenium.WebDriver; 13 | import org.openqa.selenium.WebElement; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import us.codecraft.xsoup.Xsoup; 16 | 17 | import java.util.Set; 18 | 19 | /** 20 | *

21 | * 测试 PhantomJs
22 | * PhantomJs是一个基于webkit内核的无头浏览器,即没有UI界面,即它就是一个浏览器,只是其内的点击、翻页等人为相关操作需要程序设计实现; 23 | * 因为爬虫如果每次爬取都调用一次谷歌浏览器来实现操作,在性能上会有一定影响,而且连续开启十几个浏览器简直是内存噩梦, 24 | * 因此选用phantomJs来替换chromeDriver 25 | * PhantomJs在本地开发时候还好,如果要部署到服务器,就必须下载linux版本的PhantomJs,相比window操作繁琐 26 | *

27 | * 28 | * @package: com.xkcoding.shiny.spider 29 | * @description: 测试 PhantomJs 30 | * @author: yangkai.shen 31 | * @date: Created in 2018/8/21 下午10:38 32 | * @copyright: Copyright (c) 2018 33 | * @version: V1.0 34 | * @modified: yangkai.shen 35 | */ 36 | public class PhantomJsTest extends ShinyApplicationTests { 37 | @Autowired 38 | private DriverUtil driverUtil; 39 | 40 | @Test 41 | public void test() throws InterruptedException { 42 | WebDriver driver = driverUtil.getPhantomJSDriver(); 43 | // 已访问的 TAB 集合,用户存放已经访问过的 TAB 44 | Set windowSet = Sets.newHashSet(); 45 | 46 | // 让浏览器访问 xclient.info 47 | driver.get("http://xclient.info/s/things.html?t=" + RandomUtil.simpleUUID()); 48 | // 软件首页 TAB 49 | String oldWindow = driver.getWindowHandle(); 50 | windowSet.addAll(driver.getWindowHandles()); 51 | // 用下面代码也可以实现 52 | //driver.navigate().to("http://www.baidu.com"); 53 | // 获取 网页的 title 54 | System.out.println(" Page title is: " + driver.getTitle()); 55 | Document document = Jsoup.parse(driver.getPageSource()); 56 | 57 | String summary = Xsoup.compile("//*[@id=\"main\"]/div/article/div[3]/p/text()").evaluate(document).get(); 58 | System.err.println("【summary】: " + summary); 59 | 60 | WebElement element = driver.findElement(By.xpath("//*[@id=\"versions\"]/table/tbody/tr[1]/td[5]/a[2]")); 61 | element.click(); 62 | Thread.sleep(1000); 63 | 64 | // 浏览器所有 TAB 65 | Set windowHandles = driver.getWindowHandles(); 66 | System.err.println(JSONUtil.toJsonStr(windowHandles)); 67 | 68 | // 切换 TAB,只切换到未访问过的 TAB 69 | for (String windowHandle : windowHandles) { 70 | if (!windowSet.contains(windowHandle)) { 71 | // 切换 TAB 72 | driver.switchTo().window(windowHandle); 73 | // 已访问的 TAB 里添加一条记录 74 | windowSet.add(windowHandle); 75 | break; 76 | } 77 | } 78 | System.err.println(driver.getCurrentUrl()); 79 | Document bdDocument = Jsoup.parse(driver.getPageSource()); 80 | String bdLink = Xsoup.compile("//*[@id=\"body\"]/div[1]/div[2]/a/@data-link").evaluate(bdDocument).get(); 81 | String bdKey = Xsoup.compile("//*[@id=\"body\"]/div[1]/div[2]/a/@data-clipboard-text").evaluate(bdDocument).get(); 82 | System.err.println("【百度】" + bdLink + "【提取码】" + bdKey); 83 | 84 | // 回到原来的 TAB 页 85 | driver.switchTo().window(oldWindow); 86 | System.err.println(driver.getCurrentUrl()); 87 | 88 | Set windows = driver.getWindowHandles(); 89 | System.err.println(JSONUtil.toJsonStr(windows)); 90 | driver.quit(); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /back/src/test/java/com/xkcoding/shiny/spider/SpiderTest.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.spider; 2 | 3 | import cn.hutool.core.util.RandomUtil; 4 | import cn.hutool.core.util.StrUtil; 5 | import cn.hutool.http.HttpUtil; 6 | import com.google.common.collect.Maps; 7 | import com.xkcoding.shiny.ShinyApplicationTests; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.jsoup.Jsoup; 10 | import org.jsoup.nodes.Document; 11 | import org.jsoup.nodes.Element; 12 | import org.jsoup.select.Elements; 13 | import org.junit.Test; 14 | import us.codecraft.xsoup.Xsoup; 15 | 16 | import java.util.Map; 17 | 18 | /** 19 | *

20 | * 爬虫测试 21 | *

22 | * 23 | * @package: com.xkcoding.shiny.spider 24 | * @description: 爬虫测试 25 | * @author: yangkai.shen 26 | * @date: Created in 2018/8/15 下午11:44 27 | * @copyright: Copyright (c) 2018 28 | * @version: V1.0 29 | * @modified: yangkai.shen 30 | */ 31 | @Slf4j 32 | public class SpiderTest extends ShinyApplicationTests { 33 | 34 | @Test 35 | public void thingsTest() { 36 | // String url = "http://xclient.info/s/things.html"; 37 | String url = "http://xclient.info/s/vmware-fusion.html"; 38 | Map params = Maps.newHashMap(); 39 | params.put("t", RandomUtil.simpleUUID()); 40 | String html = HttpUtil.get(url, params); 41 | 42 | // 获取 summary 43 | // List summaries = ReUtil.findAll("
(.*?)
", html, 1); 44 | // log.debug("【summary】: {}", HtmlUtil.cleanHtmlTag(CollUtil.getFirst(summaries))); 45 | 46 | Document document = Jsoup.parse(html); 47 | String summary = Xsoup.compile("//*[@id=\"main\"]/div/article/div[3]/p/text()").evaluate(document).get(); 48 | log.debug("【summary】: {}", summary); 49 | String postContentHtml = Xsoup.compile("//*[@id=\"post-content\"]").evaluate(document).get(); 50 | log.debug("【content】: {}", postContentHtml); 51 | 52 | String versionsHTML = Xsoup.compile("//*[@id=\"versions\"]/table").evaluate(document).get(); 53 | log.debug("【versions】: {}", versionsHTML); 54 | Document versionsDocument = Jsoup.parse(versionsHTML); 55 | Elements trs = versionsDocument.select("table").select("tbody").select("tr"); 56 | 57 | getVersionInfo(trs); 58 | 59 | } 60 | 61 | public static void getVersionInfo(Elements trs) { 62 | for (Element tr : trs) { 63 | Elements tds = tr.select("td"); 64 | 65 | String version = tds.get(0).text(); 66 | String language = tds.get(1).text(); 67 | String date = tds.get(2).text(); 68 | String size = tds.get(3).text(); 69 | Element linkElement = tds.get(4); 70 | Elements downloadElements = linkElement.select(".btn-download"); 71 | for (int k = 0; k < downloadElements.size(); k++) { 72 | if (StrUtil.containsIgnoreCase(downloadElements.get(k).text(), "城通网盘")) { 73 | log.debug("【城通】{}", downloadElements.get(k).attr("href")); 74 | } else if (StrUtil.containsIgnoreCase(downloadElements.get(k).text(), "百度云盘")) { 75 | log.debug("【百度】{}", downloadElements.get(k).attr("href")); 76 | } 77 | } 78 | log.info("【版本】{},【语言】{},【更新日期】{},【文件大小】{},【城通】{},【百度】{}", version, language, date, size, null, null); 79 | } 80 | } 81 | 82 | @Test 83 | public void testSoftInfo(){ 84 | String url = "http://xclient.info/s/things.html"; 85 | Map params = Maps.newLinkedHashMap(); 86 | params.put("a", "dl"); 87 | params.put("v", "3.6.1"); 88 | params.put("k", "1"); 89 | params.put("t", RandomUtil.simpleUUID()); 90 | String html = HttpUtil.get(url, params); 91 | System.out.println(html); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /back/src/test/java/com/xkcoding/shiny/spider/XclientSpiderChromeTest.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.spider; 2 | 3 | import cn.hutool.json.JSONUtil; 4 | import com.xkcoding.shiny.ShinyApplicationTests; 5 | import com.xkcoding.shiny.mapper.SpiderConfigMapper; 6 | import com.xkcoding.shiny.model.SpiderConfigDO; 7 | import com.xkcoding.shiny.model.SpiderContentDO; 8 | import com.xkcoding.shiny.task.SpiderTaskFactory; 9 | import com.xkcoding.shiny.util.DriverUtil; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.junit.Test; 12 | import org.openqa.selenium.WebDriver; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | 15 | import java.util.List; 16 | 17 | /** 18 | *

19 | * xclient.info 采集测试 20 | *

21 | * 22 | * @package: com.xkcoding.shiny.spider 23 | * @description: xclient.info 采集测试 24 | * @author: yangkai.shen 25 | * @date: Created in 2018/8/24 下午6:42 26 | * @copyright: Copyright (c) 2018 27 | * @version: V1.0 28 | * @modified: yangkai.shen 29 | */ 30 | @Slf4j 31 | public class XclientSpiderChromeTest extends ShinyApplicationTests { 32 | @Autowired 33 | private SpiderConfigMapper spiderConfigMapper; 34 | @Autowired 35 | private DriverUtil driverUtil; 36 | 37 | 38 | @Test 39 | public void test() throws InterruptedException { 40 | 41 | long start = System.currentTimeMillis(); 42 | 43 | WebDriver driver = driverUtil.getChromeDriver(); 44 | 45 | SpiderConfigDO spiderConfigDO = spiderConfigMapper.selectByPrimaryKey(20); 46 | 47 | List spiderContentDOList = SpiderTaskFactory.executeSpider(driver, spiderConfigDO); 48 | 49 | long end = System.currentTimeMillis(); 50 | 51 | System.out.println("耗时:" + (end - start) / 1000 + " 秒"); 52 | 53 | log.info(JSONUtil.toJsonStr(spiderContentDOList)); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /back/src/test/java/com/xkcoding/shiny/spider/XclientSpiderPhantomJsTest.java: -------------------------------------------------------------------------------- 1 | package com.xkcoding.shiny.spider; 2 | 3 | import cn.hutool.json.JSONUtil; 4 | import com.xkcoding.shiny.ShinyApplicationTests; 5 | import com.xkcoding.shiny.mapper.SpiderConfigMapper; 6 | import com.xkcoding.shiny.model.SpiderConfigDO; 7 | import com.xkcoding.shiny.model.SpiderContentDO; 8 | import com.xkcoding.shiny.task.SpiderTaskFactory; 9 | import com.xkcoding.shiny.util.DriverUtil; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.junit.Test; 12 | import org.openqa.selenium.WebDriver; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | 15 | import java.util.List; 16 | 17 | /** 18 | *

19 | * xclient.info PhantomJs 采集测试 20 | *

21 | * 22 | * @package: com.xkcoding.shiny.spider 23 | * @description: xclient.info PhantomJs 采集测试 24 | * @author: yangkai.shen 25 | * @date: Created in 2018/8/24 下午6:42 26 | * @copyright: Copyright (c) 2018 27 | * @version: V1.0 28 | * @modified: yangkai.shen 29 | */ 30 | @Slf4j 31 | public class XclientSpiderPhantomJsTest extends ShinyApplicationTests { 32 | @Autowired 33 | private SpiderConfigMapper spiderConfigMapper; 34 | 35 | @Autowired 36 | private DriverUtil driverUtil; 37 | 38 | @Test 39 | public void test() throws InterruptedException { 40 | long start = System.currentTimeMillis(); 41 | 42 | WebDriver driver = driverUtil.getPhantomJSDriver(); 43 | 44 | SpiderConfigDO spiderConfigDO = spiderConfigMapper.selectByPrimaryKey(20); 45 | 46 | List spiderContentDOList = SpiderTaskFactory.executeSpider(driver, spiderConfigDO); 47 | 48 | long end = System.currentTimeMillis(); 49 | 50 | System.out.println("耗时:" + (end - start) / 1000 + " 秒"); 51 | 52 | log.info(JSONUtil.toJsonStr(spiderContentDOList)); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /front/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not ie <= 8 4 | -------------------------------------------------------------------------------- /front/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = false 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /front/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | extends: ["plugin:vue/essential", "@vue/prettier"], 7 | rules: { 8 | "no-console": process.env.NODE_ENV === "production" ? "error" : "off", 9 | "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off" 10 | }, 11 | parserOptions: { 12 | parser: "babel-eslint" 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /front/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | -------------------------------------------------------------------------------- /front/README.md: -------------------------------------------------------------------------------- 1 | # front 2 | 3 | shiny-telegram 的前端项目 4 | 5 | ## 项目构建 6 | 7 | ``` 8 | yarn install 9 | ``` 10 | 11 | ### 项目编译和开发时热部署 12 | 13 | ``` 14 | yarn run serve 15 | ``` 16 | 17 | ### 项目构建和生产环境压缩文件 18 | 19 | ``` 20 | yarn run build 21 | ``` 22 | 23 | ### 检查和修复文件 24 | 25 | ``` 26 | yarn run lint 27 | ``` 28 | -------------------------------------------------------------------------------- /front/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["@vue/app"] 3 | }; 4 | -------------------------------------------------------------------------------- /front/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "front", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "iview": "^3.1.1", 12 | "vue": "^2.5.17", 13 | "vue-router": "^3.0.1", 14 | "vuex": "^3.0.1" 15 | }, 16 | "devDependencies": { 17 | "@vue/cli-plugin-babel": "^3.0.3", 18 | "@vue/cli-plugin-eslint": "^3.0.3", 19 | "@vue/cli-service": "^3.0.3", 20 | "@vue/eslint-config-prettier": "^3.0.3", 21 | "less": "^3.8.1", 22 | "less-loader": "^4.1.0", 23 | "lint-staged": "^7.2.2", 24 | "stylus": "^0.54.5", 25 | "stylus-loader": "^3.0.2", 26 | "vue-template-compiler": "^2.5.17" 27 | }, 28 | "gitHooks": { 29 | "pre-commit": "lint-staged" 30 | }, 31 | "lint-staged": { 32 | "*.js": [ 33 | "vue-cli-service lint", 34 | "git add" 35 | ], 36 | "*.vue": [ 37 | "vue-cli-service lint", 38 | "git add" 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /front/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | }; 6 | -------------------------------------------------------------------------------- /front/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkcoding/shiny-telegram/2e78bed542fc8cc36471e29aa9730d4fcb74841d/front/public/favicon.ico -------------------------------------------------------------------------------- /front/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | shiny 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /front/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 8 | -------------------------------------------------------------------------------- /front/src/api/index.js: -------------------------------------------------------------------------------- 1 | // 管理所有 ajax 请求 2 | -------------------------------------------------------------------------------- /front/src/assets/images/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkcoding/shiny-telegram/2e78bed542fc8cc36471e29aa9730d4fcb74841d/front/src/assets/images/avatar.jpg -------------------------------------------------------------------------------- /front/src/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xkcoding/shiny-telegram/2e78bed542fc8cc36471e29aa9730d4fcb74841d/front/src/assets/images/logo.png -------------------------------------------------------------------------------- /front/src/components/common/custom-layout.vue: -------------------------------------------------------------------------------- 1 | 100 | 101 | 119 | 120 | 174 | -------------------------------------------------------------------------------- /front/src/config/index.js: -------------------------------------------------------------------------------- 1 | export default { 2 | // 项目的配置信息 3 | }; 4 | -------------------------------------------------------------------------------- /front/src/directive/index.js: -------------------------------------------------------------------------------- 1 | // 存放 vue 的一些自定义指令 2 | -------------------------------------------------------------------------------- /front/src/lib/tools.js: -------------------------------------------------------------------------------- 1 | // 无业务的工具方法 2 | -------------------------------------------------------------------------------- /front/src/lib/util.js: -------------------------------------------------------------------------------- 1 | // 与业务结合的工具方法 2 | -------------------------------------------------------------------------------- /front/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import App from "./App.vue"; 3 | import router from "./router"; 4 | import store from "./store"; 5 | import iView from "iview"; 6 | import "iview/dist/styles/iview.css"; 7 | import CustomLayout from "components/common/custom-layout"; 8 | 9 | Vue.config.productionTip = false; 10 | 11 | Vue.use(iView); 12 | 13 | Vue.component("custom-layout", CustomLayout); 14 | 15 | new Vue({ 16 | router, 17 | store, 18 | render: h => h(App) 19 | }).$mount("#app"); 20 | -------------------------------------------------------------------------------- /front/src/mock/index.js: -------------------------------------------------------------------------------- 1 | import Mock from "mockjs"; 2 | // mock 模拟数据 3 | export default Mock; 4 | -------------------------------------------------------------------------------- /front/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Router from "vue-router"; 3 | import routes from "./router"; 4 | 5 | Vue.use(Router); 6 | export default new Router({ 7 | routes 8 | }); 9 | -------------------------------------------------------------------------------- /front/src/router/router.js: -------------------------------------------------------------------------------- 1 | export default [ 2 | { 3 | path: "/", 4 | redirect: "/app" 5 | }, 6 | { 7 | path: "/app", 8 | name: "app", 9 | component: () => import("views/App.vue") 10 | }, 11 | { 12 | path: "/push", 13 | name: "push", 14 | component: () => import("views/Push.vue") 15 | }, 16 | { 17 | path: "/dev", 18 | name: "dev", 19 | component: () => import("views/Dev.vue") 20 | }, 21 | { 22 | path: "/manage", 23 | name: "manage", 24 | component: () => import("views/Manage.vue") 25 | } 26 | ]; 27 | -------------------------------------------------------------------------------- /front/src/store/actions.js: -------------------------------------------------------------------------------- 1 | export default {}; 2 | -------------------------------------------------------------------------------- /front/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuex from "vuex"; 3 | import state from "./state"; 4 | import mutations from "./mutations"; 5 | import actions from "./actions"; 6 | 7 | Vue.use(Vuex); 8 | 9 | export default new Vuex.Store({ 10 | state, 11 | mutations, 12 | actions 13 | }); 14 | -------------------------------------------------------------------------------- /front/src/store/mutations.js: -------------------------------------------------------------------------------- 1 | export default {}; 2 | -------------------------------------------------------------------------------- /front/src/store/state.js: -------------------------------------------------------------------------------- 1 | export default {}; 2 | -------------------------------------------------------------------------------- /front/src/views/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 18 | 19 | 21 | -------------------------------------------------------------------------------- /front/src/views/Dev.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | 17 | 19 | -------------------------------------------------------------------------------- /front/src/views/Manage.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | 17 | 19 | -------------------------------------------------------------------------------- /front/src/views/Push.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | 17 | 19 | -------------------------------------------------------------------------------- /front/vue.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const resolve = dir => path.join(__dirname, dir); 4 | 5 | const BASE_URL = process.env.NODE_ENV === "production" ? "/shiny/" : "/"; 6 | 7 | module.exports = { 8 | lintOnSave: true, 9 | baseUrl: BASE_URL, 10 | chainWebpack: config => { 11 | config.resolve.alias 12 | .set("api", resolve("src/api")) 13 | .set("components", resolve("src/components")) 14 | .set("config", resolve("src/config")) 15 | .set("lib", resolve("src/lib")) 16 | .set("views", resolve("src/views")); 17 | }, 18 | // 打包时不生成.map文件 19 | productionSourceMap: false, 20 | devServer: { 21 | // proxy: "http://localhost:8080", 22 | port: 4000 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /mysql/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mysql:5.7 2 | 3 | MAINTAINER yangkai.shen 237497819@qq.com 4 | 5 | #设置免密登录 6 | ENV MYSQL_ALLOW_EMPTY_PASSWORD yes 7 | 8 | #将所需文件放到容器中 9 | COPY setup.sh /mysql/setup.sh 10 | COPY sql/shiny.sql /mysql/shiny.sql 11 | COPY sql/shiny-data.sql /mysql/shiny-data.sql 12 | COPY sql/privileges.sql /mysql/privileges.sql 13 | COPY ./mysqld.cnf /etc/mysql/mysql.conf.d/mysqld.cnf 14 | 15 | #设置容器启动时执行的命令 16 | CMD ["sh", "/mysql/setup.sh"] -------------------------------------------------------------------------------- /mysql/mysqld.cnf: -------------------------------------------------------------------------------- 1 | # set client default character 2 | [mysql] 3 | default-character-set=utf8 4 | [mysqld] 5 | pid-file = /var/run/mysqld/mysqld.pid 6 | socket = /var/run/mysqld/mysqld.sock 7 | datadir = /var/lib/mysql 8 | log-error = /var/log/mysql/error.log 9 | # By default we only accept connections from localhost 10 | bind-address = 0.0.0.0 11 | # Disabling symbolic-links is recommended to prevent assorted security risks 12 | symbolic-links=0 13 | # set 1 means Ignore capital letters and lowercase letters 14 | lower_case_table_names=1 15 | # set client default character 16 | character-set-server = utf8 -------------------------------------------------------------------------------- /mysql/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #set -e 3 | 4 | #修改时区为东八区 5 | echo '0.设置时区为东八区....' 6 | cp /usr/share/zoneinfo/PRC /etc/localtime 7 | date "+%Y-%m-%d %H:%M:%S" 8 | 9 | #查看mysql服务的状态,方便调试,这条语句可以删除 10 | echo `service mysql status` 11 | 12 | echo '1.启动mysql....' 13 | #启动mysql 14 | service mysql start 15 | sleep 3 16 | echo `service mysql status` 17 | 18 | echo '2.开始创建数据库和表结构....' 19 | #导入数据 20 | mysql < /mysql/shiny.sql 21 | echo '3.创建数据库和表结构完毕....' 22 | 23 | echo '4.开始导入数据....' 24 | #导入数据 25 | mysql < /mysql/shiny-data.sql 26 | echo '5.导入数据完毕....' 27 | 28 | sleep 3 29 | echo `service mysql status` 30 | 31 | #重新设置mysql密码 32 | echo '6.开始修改密码....' 33 | mysql < /mysql/privileges.sql 34 | echo '7.修改密码完毕....' 35 | 36 | #sleep 3 37 | echo `service mysql status` 38 | echo `mysql容器启动完毕,且数据导入成功` 39 | 40 | tail -f /dev/null -------------------------------------------------------------------------------- /mysql/sql/privileges.sql: -------------------------------------------------------------------------------- 1 | use mysql; 2 | select host, user from user; 3 | -- 因为mysql版本是5.7,因此新建用户为如下命令: 4 | create user shiny identified by '123456'; 5 | -- 将docker_mysql数据库的权限授权给创建的docker用户,密码为123456: 6 | grant all on shiny.* to shiny@'%' identified by '123456' with grant option; 7 | -- 这一条命令一定要有: 8 | flush privileges; -------------------------------------------------------------------------------- /mysql/sql/shiny-data.sql: -------------------------------------------------------------------------------- 1 | use `shiny`; 2 | -- ---------------------------- 3 | -- 5、采集配置表数据 4 | -- ---------------------------- 5 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1, 'Movist', 'http://xclient.info/s/movist.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '一款CPU占用率低的高清多格式媒体播放器'); 6 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2, 'Things', 'http://xclient.info/s/things.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '一款优秀的GTD任务管理工具'); 7 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (3, 'iStatistica', 'http://xclient.info/s/istatistica.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '一款高颜值的系统监控工具'); 8 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (4, 'TinyCal', 'http://xclient.info/s/tinycal.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '小历 - 小而美的日历'); 9 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (5, 'Money Pro', 'http://xclient.info/s/money-pro.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '可同步账单、预算和账户'); 10 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (6, 'OmniPlan', 'http://xclient.info/s/omni-plan.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '专业版 最NB的项目管理流程软件'); 11 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (7, 'Navicat Premium', 'http://xclient.info/s/navicat-premium.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '强大的数据库管理工具'); 12 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (8, 'OmniGraffle Pro', 'http://xclient.info/s/omnigraffle.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '强大的图形工具'); 13 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (9, 'XMind 8 Pro', 'http://xclient.info/s/xmind.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '最受欢迎思维导图软件'); 14 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (10, 'StarUML', 'http://xclient.info/s/staruml.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '强大的UML工具'); 15 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (11, 'ScreenFlow', 'http://xclient.info/s/screenflow.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '优秀的屏幕录像软件'); 16 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (12, 'EdrawMax', 'http://xclient.info/s/edraw-max.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '亿图图示专家 基于矢量的绘图工具'); 17 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (13, 'Charles', 'http://xclient.info/s/charles.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', 'Mac上的抓包工具'); 18 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (14, 'SnippetsLab', 'http://xclient.info/s/snippetslab.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '构建你的私人代码片段库'); 19 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (15, 'Adobe Photoshop CC', 'http://xclient.info/s/adobe-photoshop-cc.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', ''); 20 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (16, 'Adobe Photoshop Lightroom CC', 'http://xclient.info/s/adobe-lightroom-cc.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', ''); 21 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (17, 'VMware Fusion', 'http://xclient.info/s/vmware-fusion.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '强大的虚拟机应用'); 22 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (18, 'Tuxera NTFS', 'http://xclient.info/s/tuxera-ntfs.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '让你的Mac支持NTFS'); 23 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (19, 'Parallels Desktop', 'http://xclient.info/s/parallels-desktop.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '最佳Mac虚拟机解决方案'); 24 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (20, 'Microsoft Office', 'http://xclient.info/s/office-for-mac.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '多国语言大客户版'); 25 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (21, 'Beyond Compare', 'http://xclient.info/s/beyond-compare.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '文件对比利器'); 26 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (22, 'Sublime Text', 'http://xclient.info/s/sublime-text.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '一款优秀的代码编辑器'); 27 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (23, 'UltraEdit', 'http://xclient.info/s/ultraedit.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '老牌文本编辑器'); 28 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (24, 'Understand', 'http://xclient.info/s/understand.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '代码阅读分析软件'); 29 | INSERT INTO `spider_config`(`id`, `spider_name`, `spider_url`, `last_spider_time`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (25, 'Paste', 'http://xclient.info/s/paste-for-mac.html', NULL, '管理员', '2018-09-10 00:00:00', '管理员', '2018-09-10 00:00:00', '剪切板增强工具'); 30 | -------------------------------------------------------------------------------- /mysql/sql/shiny.sql: -------------------------------------------------------------------------------- 1 | -- 创建数据库 2 | create database IF NOT EXISTS `shiny` default character set utf8 collate utf8_general_ci; 3 | 4 | use `shiny`; 5 | 6 | -- ---------------------------- 7 | -- 1、参数配置表 8 | -- ---------------------------- 9 | CREATE TABLE IF NOT EXISTS `sys_config` ( 10 | `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '参数主键', 11 | `config_name` varchar(100) DEFAULT '' COMMENT '参数名称', 12 | `config_key` varchar(100) DEFAULT '' COMMENT '参数键名', 13 | `config_value` varchar(100) DEFAULT '' COMMENT '参数键值', 14 | `config_type` int(2) DEFAULT 0 COMMENT '系统内置(0否 1是)', 15 | `create_by` varchar(64) DEFAULT '' COMMENT '创建者', 16 | `create_time` datetime DEFAULT NULL COMMENT '创建时间', 17 | `update_by` varchar(64) DEFAULT '' COMMENT '更新者', 18 | `update_time` datetime DEFAULT NULL COMMENT '更新时间', 19 | `remark` varchar(500) DEFAULT '' COMMENT '备注', 20 | PRIMARY KEY (`id`) 21 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='参数配置表'; 22 | 23 | -- ---------------------------- 24 | -- 2、系统用户表 25 | -- ---------------------------- 26 | CREATE TABLE IF NOT EXISTS `sys_user` ( 27 | `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID', 28 | `dept_id` int(11) DEFAULT NULL COMMENT '部门ID', 29 | `login_name` varchar(30) NOT NULL COMMENT '登录账号', 30 | `user_name` varchar(30) NOT NULL COMMENT '用户昵称', 31 | `user_type` varchar(2) DEFAULT '00' COMMENT '用户类型(00系统用户)', 32 | `email` varchar(50) DEFAULT '' COMMENT '用户邮箱', 33 | `phonenumber` varchar(11) DEFAULT '' COMMENT '手机号码', 34 | `sex` int(2) DEFAULT 0 COMMENT '用户性别(0男 1女 2未知)', 35 | `avatar` varchar(100) DEFAULT '' COMMENT '头像路径', 36 | `password` varchar(100) DEFAULT '' COMMENT '密码', 37 | `status` int(2) DEFAULT 1 COMMENT '帐号状态(0停用 1正常)', 38 | `del_flag` int(2) DEFAULT 0 COMMENT '删除标志(0代表存在 1代表删除)', 39 | `login_ip` varchar(20) DEFAULT '' COMMENT '最后登陆IP', 40 | `login_date` datetime DEFAULT NULL COMMENT '最后登陆时间', 41 | `create_by` varchar(64) DEFAULT '' COMMENT '创建者', 42 | `create_time` datetime DEFAULT NULL COMMENT '创建时间', 43 | `update_by` varchar(64) DEFAULT '' COMMENT '更新者', 44 | `update_time` datetime DEFAULT NULL COMMENT '更新时间', 45 | `remark` varchar(500) DEFAULT '' COMMENT '备注', 46 | PRIMARY KEY (`id`) 47 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='系统用户表'; 48 | 49 | -- ---------------------------- 50 | -- 3、角色信息表 51 | -- ---------------------------- 52 | CREATE TABLE IF NOT EXISTS `sys_role` ( 53 | `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '角色ID', 54 | `role_name` varchar(30) NOT NULL COMMENT '角色名称', 55 | `role_key` varchar(100) NOT NULL COMMENT '角色权限字符串', 56 | `role_sort` int(4) NOT NULL COMMENT '显示顺序', 57 | `status` int(2) DEFAULT 1 COMMENT '角色状态(0停用 1正常)', 58 | `create_by` varchar(64) DEFAULT '' COMMENT '创建者', 59 | `create_time` datetime DEFAULT NULL COMMENT '创建时间', 60 | `update_by` varchar(64) DEFAULT '' COMMENT '更新者', 61 | `update_time` datetime DEFAULT NULL COMMENT '更新时间', 62 | `remark` varchar(500) DEFAULT '' COMMENT '备注', 63 | PRIMARY KEY (`id`) 64 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色信息表'; 65 | 66 | -- ---------------------------- 67 | -- 4、用户和角色关联表 68 | -- ---------------------------- 69 | CREATE TABLE IF NOT EXISTS `sys_user_role` ( 70 | `user_id` int(11) NOT NULL COMMENT '用户ID', 71 | `role_id` int(11) NOT NULL COMMENT '角色ID', 72 | PRIMARY KEY (`user_id`,`role_id`) 73 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户和角色关联表'; 74 | 75 | -- ---------------------------- 76 | -- 5、采集配置 77 | -- ---------------------------- 78 | CREATE TABLE IF NOT EXISTS `spider_config` ( 79 | `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '配置主键', 80 | `spider_name` varchar(100) DEFAULT '' COMMENT '采集名称', 81 | `spider_url` varchar(500) DEFAULT '' COMMENT '采集URL', 82 | `last_spider_time` datetime DEFAULT NULL COMMENT '上次采集时间', 83 | `create_by` varchar(64) DEFAULT '' COMMENT '创建者', 84 | `create_time` datetime DEFAULT NULL COMMENT '创建时间', 85 | `update_by` varchar(64) DEFAULT '' COMMENT '更新者', 86 | `update_time` datetime DEFAULT NULL COMMENT '更新时间', 87 | `remark` varchar(500) DEFAULT '' COMMENT '备注', 88 | PRIMARY KEY (`id`) 89 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='采集配置'; 90 | 91 | -- ---------------------------- 92 | -- 6、采集内容 93 | -- ---------------------------- 94 | CREATE TABLE IF NOT EXISTS `spider_content` ( 95 | `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '内容主键', 96 | `config_id` int(11) NOT NULL COMMENT '采集配置id', 97 | `config_name` varchar(100) NOT NULL COMMENT '采集配置名称', 98 | `title` varchar(100) DEFAULT '' COMMENT '软件名称', 99 | `content` text COMMENT '软件详细信息', 100 | `version` varchar(100) DEFAULT '' COMMENT '软件版本', 101 | `language` varchar(100) DEFAULT '' COMMENT '软件语言', 102 | `update_time` date DEFAULT NULL COMMENT '软件更新时间', 103 | `size` varchar(100) DEFAULT '' COMMENT '软件大小', 104 | `ct_pan_url` varchar(500) DEFAULT '' COMMENT '城通网盘链接', 105 | `ct_pan_code` varchar(500) DEFAULT '' COMMENT '城通网盘提取码', 106 | `bd_pan_url` varchar(500) DEFAULT '' COMMENT '百度网盘链接', 107 | `bd_pan_code` varchar(500) DEFAULT '' COMMENT '百度网盘提取码', 108 | `spider_time` datetime DEFAULT NULL COMMENT '采集时间', 109 | PRIMARY KEY (`id`) 110 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='采集内容'; 111 | 112 | -- ---------------------------- 113 | -- 7、采集日志记录 114 | -- ---------------------------- 115 | CREATE TABLE IF NOT EXISTS `spider_log` ( 116 | `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '日志主键', 117 | `config_id` int(11) NOT NULL COMMENT '采集配置 id', 118 | `spider_name` varchar(100) DEFAULT '' COMMENT '采集名称', 119 | `version` varchar(100) DEFAULT '' COMMENT '采集版本', 120 | `spider_url` varchar(500) DEFAULT '' COMMENT '采集URL', 121 | `status` int(2) DEFAULT 1 COMMENT '采集状态(0异常 1正常)', 122 | `error_msg` varchar(2000) DEFAULT '' COMMENT '错误消息', 123 | `spider_time` datetime DEFAULT NULL COMMENT '采集时间', 124 | PRIMARY KEY (`id`) 125 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='采集日志记录'; 126 | 127 | -- ---------------------------- 128 | -- 8、邮件记录 129 | -- ---------------------------- 130 | CREATE TABLE IF NOT EXISTS `email_log` ( 131 | `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '邮件主键', 132 | `to` text NOT NULL COMMENT '收件人邮箱地址(多个逗号分隔)', 133 | `subject` varchar(100) DEFAULT '' COMMENT '邮件主题', 134 | `content` text NOT NULL COMMENT '邮件内容', 135 | `is_template` int(2) DEFAULT 1 COMMENT '是否是模板邮件(0否 1是)', 136 | `template_path` varchar(100) DEFAULT NULL COMMENT '模板路径', 137 | `template_name` varchar(100) DEFAULT NULL COMMENT '模板名称', 138 | `send_time` datetime DEFAULT NULL COMMENT '邮件发送时间', 139 | PRIMARY KEY (`id`) 140 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='邮件记录'; --------------------------------------------------------------------------------