Compare commits
296 Commits
Author | SHA1 | Date | |
---|---|---|---|
13786834a0 | |||
|
e0dccb6fd2 | ||
845b1b077e | |||
|
bb62066b82 | ||
63f1c9a54e | |||
|
c9156f12d1 | ||
325401e198 | |||
|
5126e31867 | ||
f7994d232d | |||
|
f78349a1d2 | ||
44c1ca91fc | |||
|
b0b608de5a | ||
|
523698a967 | ||
|
405a2e05ed | ||
|
6b59dfbf26 | ||
5a8f805a15 | |||
42a2829847 | |||
dfb39e5ee8 | |||
|
946c032ba5 | ||
|
3a77e5af4d | ||
|
1d282b1095 | ||
|
bb7deda121 | ||
|
0d000223a2 | ||
|
51eb22adaa | ||
|
c56ca2809c | ||
|
383450ebe4 | ||
|
ebc1da0972 | ||
|
9dc1fe47d9 | ||
|
35d3420470 | ||
|
529b42a185 | ||
|
58a8cefaf5 | ||
|
b9cef34a06 | ||
|
928e3fac48 | ||
|
c9429557b3 | ||
|
4bed4fd34d | ||
|
5d52e389d6 | ||
|
767c26d89b | ||
|
83125ae55a | ||
|
b5f715eda6 | ||
|
cc3298f3b4 | ||
|
2b69814296 | ||
|
2880b6282c | ||
|
ff560ae790 | ||
|
c5a35ea54e | ||
|
22c2c48eea | ||
|
580d18a500 | ||
|
5868aa4a98 | ||
|
42cbbe5999 | ||
|
9dc21ed87a | ||
|
32e63ed1fb | ||
|
35ee930661 | ||
|
19aeab2856 | ||
|
866ce22bb5 | ||
|
84c2c213a9 | ||
|
9cc1a7b871 | ||
|
5e12b5a8b1 | ||
|
8ab7d0c341 | ||
|
4b9adc3acd | ||
|
a67ef95b25 | ||
|
39e9f8221a | ||
|
40cdb1f19e | ||
|
106dccb68f | ||
|
5aeae15228 | ||
|
837a4a7650 | ||
|
8c81842571 | ||
|
64d4504178 | ||
|
3072d757f0 | ||
|
62c88d78fc | ||
|
ff323e6eea | ||
|
e240905d58 | ||
|
f23e720fb9 | ||
|
faffadeba9 | ||
|
b2353a0ea1 | ||
|
d5e2b55c28 | ||
|
35910c34e1 | ||
|
d19325aaad | ||
|
df5578f267 | ||
|
9a5a4cae52 | ||
|
9a689cac65 | ||
|
238cc21ffa | ||
|
b950c666cc | ||
|
828207f672 | ||
|
ce0028cc49 | ||
|
9e2c75c3ec | ||
|
d36967d852 | ||
|
9e3308d6ca | ||
|
85688595f8 | ||
|
9a97129c79 | ||
|
6444cd6ebb | ||
|
310ae76e8c | ||
|
473da94244 | ||
|
5ed2aa1690 | ||
|
c43cf5d5ae | ||
|
1087f5e48b | ||
|
b74be9f961 | ||
|
6029f9d9c0 | ||
|
2c10ec4831 | ||
|
89ad88e359 | ||
|
a7decc0c76 | ||
|
cb5e30a7bb | ||
|
e8a646dbe8 | ||
|
d44700a971 | ||
|
50e1e0e951 | ||
|
90b1dbcf9f | ||
|
1ba7617165 | ||
|
57a6944ec5 | ||
|
d251734267 | ||
|
c128cba5f6 | ||
|
a6f1380e9c | ||
|
3d7243e276 | ||
|
bd17be5dd5 | ||
|
77086daeb9 | ||
|
553cec1338 | ||
|
f424187334 | ||
|
8d639b6a8c | ||
|
91a78a8459 | ||
|
14b3c6da2f | ||
|
f048496d73 | ||
|
c467970e93 | ||
|
15ed9cab08 | ||
|
7bb4c42cb8 | ||
|
f936a6b71b | ||
|
aefe882faa | ||
|
bc4364ea53 | ||
|
5a2f3da51a | ||
|
f536f4e0b2 | ||
|
0a54e784db | ||
|
ee22c4b77a | ||
|
62d3c43436 | ||
|
1affbf16ac | ||
|
974f8c18b4 | ||
|
6e2948ab9c | ||
|
92614c7344 | ||
|
2e63b2706a | ||
|
530af3a5e3 | ||
|
b83612681f | ||
|
40290e6ac8 | ||
|
ff87689671 | ||
|
022d24ae54 | ||
|
d707be00de | ||
|
c7b82047ae | ||
|
4603b11326 | ||
|
04a3aa987b | ||
|
47d4698ac3 | ||
|
0ce47b9a81 | ||
|
1c7294e855 | ||
|
05b6cb29d8 | ||
|
fb9cc32322 | ||
|
8ef2d9923b | ||
|
60970f14c4 | ||
|
7fc169c4f5 | ||
|
10580d231f | ||
|
2ba00eb861 | ||
|
9b4a5187cc | ||
|
84b266d8bd | ||
|
4ef6582b2a | ||
|
e067de6c79 | ||
|
7c59a50ec4 | ||
|
e735411bc3 | ||
|
02790f5ad3 | ||
|
57c3f4dfc6 | ||
|
13bd71f0a7 | ||
|
89484b2587 | ||
|
a6b502d901 | ||
|
53a85db09c | ||
|
e075eeaeff | ||
|
8baaf7a609 | ||
|
e6701e557e | ||
|
36f92c54e9 | ||
|
86997b234f | ||
|
5f57415b53 | ||
|
2e8a8455a2 | ||
|
dcf39ffea7 | ||
|
a7f408b054 | ||
|
b8f3d4f3b7 | ||
|
b8baf22387 | ||
|
f28840f822 | ||
|
59a6a2c0d4 | ||
|
a99033e572 | ||
|
913bed79ad | ||
|
1adb661bcf | ||
|
acfc93d837 | ||
|
4bb1347545 | ||
|
7dad169b3d | ||
|
4f0b8915e0 | ||
|
52a0908477 | ||
|
7c4bfb6e26 | ||
|
9f85a65029 | ||
|
e370181f70 | ||
|
a133bf1276 | ||
|
533786d9e1 | ||
|
0f6f3de253 | ||
|
74ff2df6a2 | ||
|
fff744290e | ||
|
31a4967420 | ||
|
c8a9e2dd60 | ||
|
1a9239b093 | ||
|
607ff151a0 | ||
|
3cd8b22b89 | ||
|
c955b8357f | ||
|
fbb4f8e005 | ||
|
bc63a91dc1 | ||
|
fbf3922635 | ||
|
7459332382 | ||
|
decea5cf86 | ||
|
c8c004e75b | ||
|
2db39c0b77 | ||
|
230fedaae8 | ||
|
8f06c3a0a6 | ||
|
6dfe6863c5 | ||
|
81a5878f71 | ||
|
02e2b7f325 | ||
|
faba445664 | ||
|
c30cde0176 | ||
|
a91bbb07b2 | ||
|
b991a07182 | ||
|
a16cc728bb | ||
|
6eccd3d2c4 | ||
|
0f51df5fec | ||
|
ee499905b3 | ||
|
8b2f36fb72 | ||
|
54c0843561 | ||
|
237f699f70 | ||
|
e55c86c407 | ||
|
0aac5fdc20 | ||
|
924bf8c2d3 | ||
|
4c407c5b60 | ||
|
1be1b94c71 | ||
|
fe22eab018 | ||
|
f79faab1c3 | ||
|
302d03a77c | ||
|
1196926ac9 | ||
|
cc71076b45 | ||
|
3368da0b2f | ||
|
f72141527d | ||
|
6ac58f9900 | ||
|
d8c6aefd13 | ||
|
a960ca062f | ||
|
270587c990 | ||
|
bfc7385fae | ||
|
91d69aab6a | ||
|
f968a41303 | ||
|
fe56e51d96 | ||
|
aaceb3bbbd | ||
|
6513a0861b | ||
|
a705cc76fb | ||
|
97e015ac49 | ||
|
6a547ac856 | ||
|
92cb24801b | ||
|
98883e63f5 | ||
|
cfe5f358a8 | ||
|
2a78c3ce05 | ||
|
3754a4db90 | ||
|
8c493c0868 | ||
|
0b9f38436a | ||
|
8676c8d1a9 | ||
|
8091cfc3d2 | ||
|
e89993073c | ||
|
aae34e0691 | ||
|
f0956589e0 | ||
|
cf42ea4c3e | ||
|
d69df99a10 | ||
|
f3ae2ab5f4 | ||
|
fd3538d11f | ||
|
36e13aaa36 | ||
|
fda9cb64de | ||
|
b0b3fbfa17 | ||
|
fafffe5aec | ||
|
395e35f3fa | ||
|
d1d49f7973 | ||
|
c3aab407a7 | ||
|
3090fd35f3 | ||
|
8884d2ca43 | ||
|
41311e9385 | ||
|
03add0d05a | ||
|
cf960d4210 | ||
|
4e7861b5b1 | ||
|
6bd68544c6 | ||
|
ee84f8d68e | ||
|
5c26835a3c | ||
|
6e91e49404 | ||
|
2be78755f4 | ||
|
36f168fa2d | ||
|
c2b865e996 | ||
|
3b5f178ca7 | ||
|
f7b195a21e | ||
|
c995483ec6 | ||
|
b247c78994 | ||
|
09795f2d59 | ||
|
afb9886756 | ||
|
160fa38c52 | ||
|
0b062c0e1a | ||
|
060178d4fc | ||
|
a214f4074b | ||
|
cf269c5eea | ||
|
c85203b8e6 |
24
.drone.yml
Normal file
24
.drone.yml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: bookmarkPublish
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
branch:
|
||||||
|
- master
|
||||||
|
|
||||||
|
clone:
|
||||||
|
disable: true
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: deploy
|
||||||
|
image: appleboy/drone-ssh
|
||||||
|
settings:
|
||||||
|
host:
|
||||||
|
from_secret: devHost
|
||||||
|
port: 22
|
||||||
|
user: root
|
||||||
|
key:
|
||||||
|
from_secret: privateSsh
|
||||||
|
command_timeout: 30m
|
||||||
|
script:
|
||||||
|
- cd /root/bookmark && git pull && bash build.sh && bash syncFile.sh
|
31
.env
Normal file
31
.env
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#Mysql地址
|
||||||
|
MYSQL_ADDRESS=mysql:3306
|
||||||
|
#Mysql密码
|
||||||
|
MYSQL_PASSWORD=123456
|
||||||
|
#redis地址
|
||||||
|
REDIS_HOST=redis
|
||||||
|
#redis端口
|
||||||
|
REDIS_PORT=6379
|
||||||
|
# smtp地址
|
||||||
|
SMTP_HOST=
|
||||||
|
# smtp用户名
|
||||||
|
SMTP_USERNAME=
|
||||||
|
# smtp密码
|
||||||
|
SMTP_PASSWORD=
|
||||||
|
# 外网访问域名
|
||||||
|
BOOKMARK_HOST=localhost
|
||||||
|
# 文件存储地址(比如用户上传的icon文件)
|
||||||
|
BOOKMARK_FILE_SAVE_PATH=./data/files
|
||||||
|
# jwt密钥
|
||||||
|
JWT_SECRET=123456
|
||||||
|
# http网络代理ip(github api调用可能需要)
|
||||||
|
PROXY_IP=
|
||||||
|
# http网络代理端口
|
||||||
|
PROXY_PORT=
|
||||||
|
# 如果要支持github登陆需要配置以下两个参数
|
||||||
|
# github clientId
|
||||||
|
GITHUB_CLIENT_ID=
|
||||||
|
# github secret
|
||||||
|
GITHUB_SECRET=
|
||||||
|
# 管理员用户id
|
||||||
|
MANAGE_USER_ID=-1
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
.idea
|
20
DEPLOY.md
Normal file
20
DEPLOY.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
本程序基于 docker 来进行部署,使用 docker-compose 管理服务。
|
||||||
|
|
||||||
|
**注意,仅在 x86 环境下测试,arm 下不保证可用性(目前测试可用)**
|
||||||
|
|
||||||
|
## 首次部署
|
||||||
|
|
||||||
|
0. 克隆代码`git clone https://github.com/FleyX/bookmark.git`
|
||||||
|
1. 进入文件夹`cd bookmark`
|
||||||
|
2. 安装新版的 docker,docker-compose,zip `apt install docker docker-compose zip`
|
||||||
|
3. 修改.env 文件中的参数,改为你的实际配置
|
||||||
|
4. 修改`浏览器插件/bookmarkBrowserPlugin/static/js/config.js`中的 bookmarkHost,改为你的实际部署路径
|
||||||
|
5. 修改`浏览器插件/bookmarkBrowserPlugin/tab/index.html`中的`<meta http-equiv="Refresh" content="0;url=https://bm.fleyx.com" />`,将 url 改为你的实际部署地址
|
||||||
|
6. 执行`build.sh`编译前后端代码 `bash build.sh`
|
||||||
|
7. root 权限运行 `docker-compose up -d` 启动服务。
|
||||||
|
|
||||||
|
## 更新系统
|
||||||
|
|
||||||
|
0. 代码库更新`cd bookmark;git pull`
|
||||||
|
1. 执行`build.sh`编译前后端代码 `bash build.sh`
|
||||||
|
2. root 权限运行 `docker-compose restart` 启动服务
|
115
HELP.md
Normal file
115
HELP.md
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
## 使用教程
|
||||||
|
|
||||||
|
### 首页
|
||||||
|
|
||||||
|
![首页](https://qiniupic.fleyx.com/blog/20220329202726.png?imageView2/2/w/1920)
|
||||||
|
|
||||||
|
#### 多功能搜索框
|
||||||
|
|
||||||
|
1. 搜索
|
||||||
|
|
||||||
|
搜索框支持书签搜索和网页搜索,输入关键词会在下方展示搜索结果:
|
||||||
|
|
||||||
|
![](https://qiniupic.fleyx.com/blog/20220329203152.png?imageView2/2/w/1920)
|
||||||
|
|
||||||
|
书签搜索支持**拼音/拼音首字母/名称关键字/链接关键词**搜索.比如对于`博客园。https://cnblogs.com`,可通过以下方式搜索到:
|
||||||
|
|
||||||
|
- ky (拼音首字母)
|
||||||
|
- boke (拼音)
|
||||||
|
- 客园 (名称关键词)
|
||||||
|
- blogs (链接关键词)
|
||||||
|
|
||||||
|
**注意不支持组合搜索,也就是不能同时用两种内容搜索**
|
||||||
|
|
||||||
|
2. 快捷键
|
||||||
|
|
||||||
|
tab/方向键上/下:用于选择书签(默认不选中书签)
|
||||||
|
enter/回车: 未选中书签情况下,用于发起网页搜索。选中书签的情况下跳转到对应书签
|
||||||
|
|
||||||
|
3. 网页搜索引擎
|
||||||
|
|
||||||
|
默认网页搜索引擎为**百度**,可点击图标进行切换,会自动保存选择的搜索引擎
|
||||||
|
|
||||||
|
![](https://qiniupic.fleyx.com/blog/20220329204103.png?imageView2/2/w/1920)
|
||||||
|
|
||||||
|
4. 搜索结果快捷操作
|
||||||
|
|
||||||
|
搜索书签后,通过鼠标悬浮在搜索结果上展示快捷操作,可进行如下操作:
|
||||||
|
|
||||||
|
- 定位到书签树中(仅在书签管理页面展示)
|
||||||
|
- 复制书签链接
|
||||||
|
- 固定到首页下方
|
||||||
|
|
||||||
|
![](https://qiniupic.fleyx.com/blog/20220329212023.png?imageView2/2/w/1920)
|
||||||
|
|
||||||
|
#### 书签固定区
|
||||||
|
|
||||||
|
可将一些常用书签固定在下方,方便快速跳转,最多可添加 20 个书签,未手动固定的情况下默认会按访问量顺序展示书签
|
||||||
|
|
||||||
|
![](https://qiniupic.fleyx.com/blog/20220329212211.png?imageView2/2/w/1920)
|
||||||
|
|
||||||
|
### 书签管理
|
||||||
|
|
||||||
|
通过点击右上方的头像,选择书签管理进入。
|
||||||
|
|
||||||
|
![](https://qiniupic.fleyx.com/blog/20220329212513.png?imageView2/2/w/1920)
|
||||||
|
|
||||||
|
本页面以书签树的形式展示所有的书签。
|
||||||
|
|
||||||
|
![](https://qiniupic.fleyx.com/blog/20220329212745.png?imageView2/2/w/1920)
|
||||||
|
|
||||||
|
上方搜索框介绍见[上一节:多功能搜索框](#多功能搜索框)
|
||||||
|
|
||||||
|
#### 书签树
|
||||||
|
|
||||||
|
- 新增
|
||||||
|
|
||||||
|
新增书签/文件夹可通过点击第一行"+"(添加到根路径)或者右键文件夹选择新增(添加到当前文件夹下)
|
||||||
|
|
||||||
|
![](https://qiniupic.fleyx.com/blog/20220329213056.png?imageView2/2/w/1920)
|
||||||
|
|
||||||
|
- 修改
|
||||||
|
|
||||||
|
右键要修改的书签/文件夹,选择修改按钮
|
||||||
|
|
||||||
|
- 删除
|
||||||
|
|
||||||
|
- 右键要删除的书签/文件夹选择删除
|
||||||
|
- 点击第一行的![](https://qiniupic.fleyx.com/blog/20220329213336.png?imageView2/2/w/1920),进入多选模式,然后再点击删除图标进行批量删除
|
||||||
|
![](https://qiniupic.fleyx.com/blog/20220329213551.png?imageView2/2/w/1920)
|
||||||
|
|
||||||
|
- 排序
|
||||||
|
|
||||||
|
支持拖拽排序或移动文件夹
|
||||||
|
|
||||||
|
![](https://qiniupic.fleyx.com/blog/20220329213716.png?imageView2/2/w/1920)
|
||||||
|
|
||||||
|
- 导入/导出
|
||||||
|
|
||||||
|
通过文件导入功能,快速导入现有浏览器书签
|
||||||
|
|
||||||
|
![](https://qiniupic.fleyx.com/blog/20220329214827.png?imageView2/2/w/1920)
|
||||||
|
|
||||||
|
点击书签右侧导出按钮,可导出现有书签数据到 html 文件中,此文件可直接导入到浏览器中
|
||||||
|
|
||||||
|
![](https://qiniupic.fleyx.com/blog/20220329214936.png?imageView2/2/w/1920)
|
||||||
|
|
||||||
|
### 个人中心
|
||||||
|
|
||||||
|
通过右上角悬浮菜单进入个人中心页面,可进行头像更换,密码修改等操作
|
||||||
|
|
||||||
|
### 浏览器插件
|
||||||
|
|
||||||
|
浏览器插件功能终于有 0.1 版本,支持鼠标右键菜单添加书签。
|
||||||
|
|
||||||
|
#### 安装插件
|
||||||
|
|
||||||
|
1. 首先下载插件压缩包,下载地址:[点击下载](https://fleyx.com/static/bookmarkBrowserPlugin.7z)
|
||||||
|
|
||||||
|
2. 安装插件(以 chrome 浏览器为例,其他支持插件的浏览器差不多)进入插件管理页面->开启开发者模式->加载已解压的拓展程序
|
||||||
|
|
||||||
|
![](https://qiniupic.fleyx.com/blog/202204151605709.png)
|
||||||
|
|
||||||
|
3. 之后页面点击右键->添加到书签,即可
|
||||||
|
|
||||||
|
![](https://qiniupic.fleyx.com/blog/202204151607593.png)
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 FleyX
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
140
README.md
140
README.md
@ -1,84 +1,56 @@
|
|||||||
本项目是一个云书签的项目,取名为:签签世界。
|
![图片](https://s3.fleyx.com/picbed/2023/08/Snipaste_2023-08-13_15-33-16.png)
|
||||||
|
|
||||||
访问地址:[bm.tapme.top](http://bm.tapme.top)
|
本项目是一个在线书签管理的项目,名为:签签世界.
|
||||||
|
|
||||||
web端已经完成。
|
在线使用地址(长期提供服务):[bm.fleyx.com](https://bm.fleyx.com),
|
||||||
|
|
||||||
# 缘由
|
**为获得更好的体验,建议将主页设置为 bm.fleyx.com,并安装浏览器拓展,[点击查看如何安装](https://blog.fleyx.com/blog/detail/20220329/#%e6%b5%8f%e8%a7%88%e5%99%a8%e6%8f%92%e4%bb%b6)**
|
||||||
|
|
||||||
1. 主要用的是 chrome,但是有时候需要用其他的浏览器:Firefox,ie 等。然后这些浏览器上没有书签,想进个网站还得打开 chrome 复制 url,太麻烦。
|
也可自己部署搭建,教程见:[docker-compose 部署](https://github.com/FleyX/bookmark/blob/master/DEPLOY.md)
|
||||||
|
|
||||||
2. chrome 必须翻墙才能同步书签,体验不是那么好。
|
# 缘由
|
||||||
|
|
||||||
3. 如果书签全放在 chrome 上,相当于绑定死 chrome 浏览器了,很难迁移到别的优秀浏览器,比如 firfox 上。
|
1. 主要用的是 chrome,但是有时候需要用其他的浏览器:Firefox,ie 等。然后这些浏览器上没有书签,想进个网站还得打开 chrome 复制 url,太麻烦。
|
||||||
|
|
||||||
所以有了这样这样一个项目,建立一个和平台无关的书签管理器,可在任意平台使用。
|
2. chrome 必须翻墙才能同步书签,体验不是那么好。
|
||||||
|
|
||||||
计划开发顺序如下:web 端->chrome 插件->firfox 插件。
|
3. 如果书签全放在 chrome 上,相当于绑定死 chrome 浏览器了,很难迁移到别的优秀浏览器,比如 firfox 上。
|
||||||
|
|
||||||
最终目的就是所有浏览器(不包含 ie10 及以下等远古浏览器)中都能便捷的使用书签。
|
所以有了这样这样一个项目,建立一个和平台无关的书签管理器,可在任意平台使用。
|
||||||
|
|
||||||
# 主要功能
|
# 主要功能
|
||||||
|
|
||||||
## 查
|
帮助文档:[点击跳转](https://blog.fleyx.com/blog/detail/20220329/)
|
||||||
|
|
||||||
1. 节点树展示书签
|
- 支持从 chrome,edge,firefox 等浏览器导入书签数据。
|
||||||
![](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190801185846.png)
|
- 支持从 OneEnv 导入书签数据
|
||||||
采用懒加载方式加载每一层数据,即使大量数据也不会卡顿。
|
- 树型多级目录支持
|
||||||
|
- 支持导出标准 html 书签文件
|
||||||
2. 全文检索<br>
|
- 强大的检索功能,支持拼音检索
|
||||||
![](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190801190427.png)
|
- 支持浏览器插件,安装插件以后可右键添加书签
|
||||||
|
|
||||||
- 可对`书签名`和`链接`进行全文检索
|
# 更新日志
|
||||||
- 支持方向键-上/下切换,回车确认
|
|
||||||
- 可直接搜索 google/baidu,tab 键切换。
|
## 1.4.1
|
||||||
![](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190801190720.png)
|
|
||||||
- 支持右键复制 url(移动端不支持右键,需点击编辑-->菜单键)
|
- 修复书签名过长无法导入问题
|
||||||
![](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190801191010.png)
|
|
||||||
|
## 1.4
|
||||||
## 增
|
|
||||||
|
- 优化首图加载逻辑
|
||||||
![](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190801191452.png)
|
- 支持 OneEnv 备份文件导入
|
||||||
|
|
||||||
1. 手动编辑导入
|
## 1.3
|
||||||
![](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190801191601.png)
|
|
||||||
2. 谷歌、火狐浏览器书签备份文件直接导入.如果同一级别下名称相同导致冲突,将跳过,保留原有的。
|
![pic](https://s3.fleyx.com/picbed/2023/08/Snipaste_2023-08-13_15-01-20.png)
|
||||||
![](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190801191721.png)
|
|
||||||
|
搜索引擎支持自定义[#43](https://github.com/FleyX/bookmark/issues/43)
|
||||||
## 改
|
|
||||||
|
位置:右上角个人中心-管理搜索引擎
|
||||||
1. 修改节点内容,右键->编辑。(移动端长按相当于右键)
|
|
||||||
2. 修改书签顺序,所属文件夹,直接拖拽书签到目标位置
|
# TODO
|
||||||
|
|
||||||
|
- [x] 主页功能
|
||||||
# 开发进度
|
- [x] 拼音检索
|
||||||
|
- [x] 书签导出
|
||||||
## 2019-06-27
|
- [x] 浏览器插件
|
||||||
|
|
||||||
**tag: 第一篇:环境搭建**
|
|
||||||
|
|
||||||
前端 react 框架搭建完成。
|
|
||||||
|
|
||||||
## 2019-07-10
|
|
||||||
|
|
||||||
**tag: 第二篇:注册登录重置密码完成**
|
|
||||||
|
|
||||||
后台框架搭建,并完成以下功能:
|
|
||||||
|
|
||||||
- 登录,注册,重置密码,发送验证码接口完成
|
|
||||||
- 书签 html 上传解析并存到数据库,仅测试了 chrome 导出的书签文件
|
|
||||||
- 查询某个用户的书签树
|
|
||||||
|
|
||||||
前台完成以下功能:
|
|
||||||
|
|
||||||
- 注册,登录,重置密码界面完成
|
|
||||||
|
|
||||||
## 2019-07-22
|
|
||||||
|
|
||||||
增删改查功能完成。支持节点拖拽
|
|
||||||
|
|
||||||
## 2019-07-30
|
|
||||||
|
|
||||||
- docker 部署重新整理,部署更方便了。
|
|
||||||
- 加入 elasticsearch 全文检索,可以方便的搜索书签啦。
|
|
||||||
- 树节点增加右键菜单,更加便捷的增删改
|
|
||||||
|
4
bookMarkDocker/.gitignore
vendored
4
bookMarkDocker/.gitignore
vendored
@ -1,4 +0,0 @@
|
|||||||
mavenRep
|
|
||||||
es/data
|
|
||||||
mysql/data
|
|
||||||
nginx/log
|
|
@ -1,29 +0,0 @@
|
|||||||
本程序基于 docker 来进行部署。
|
|
||||||
|
|
||||||
docker 镜像 构建文件为本目录下的`Dockerfile`,已经生产推送到阿里云的容器镜像库:registry.cn-hangzhou.aliyuncs.com/fleyx/node-java-env:v2.本镜像包含如下:
|
|
||||||
|
|
||||||
- node 运行环境,已安装 cnpm
|
|
||||||
- java 运行编译环境,openjdk11
|
|
||||||
- maven 运行环境,已设置为阿里源
|
|
||||||
|
|
||||||
部署过程如下:
|
|
||||||
|
|
||||||
1. 首先运行 init.sh 进行前后端打包。
|
|
||||||
2. 将密码,smtp 等相关敏感信息设置 到环境变量中,内容如下:<br/>
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export MYSQL_PASSWORD=123456
|
|
||||||
export JWT_SECRET=123456
|
|
||||||
export SMTP_HOST=localhost
|
|
||||||
export SMTP_USERNAME=test
|
|
||||||
export SMTP_PASSWORD=test
|
|
||||||
export SMTP_PORT=465
|
|
||||||
```
|
|
||||||
|
|
||||||
两种设置办法:
|
|
||||||
|
|
||||||
- 在终端执行上述命令.这种办法在关闭终端后这些变量会失效,如果重新部署 docker-compose 会报警告--环境变量未定义
|
|
||||||
|
|
||||||
- 写到配置文件中,比如/etc/profile 等文件中,然后`source /etc/profile` 使其生效。
|
|
||||||
|
|
||||||
3. 执行`docker-compose up -d` 后台启动系统。
|
|
@ -1,98 +0,0 @@
|
|||||||
version: "2"
|
|
||||||
services:
|
|
||||||
bookmark-mysql:
|
|
||||||
image: mysql:8.0.16
|
|
||||||
container_name: bookmark-mysql
|
|
||||||
ports:
|
|
||||||
- 3307:3306
|
|
||||||
networks:
|
|
||||||
- bookmark
|
|
||||||
volumes:
|
|
||||||
- ./mysql/data:/var/lib/mysql
|
|
||||||
- ./mysql/temp:/var/lib/mysql-files
|
|
||||||
- ./mysql/my.cnf:/etc/mysql/my.cnf
|
|
||||||
- /etc/localtime:/etc/localtime
|
|
||||||
- ./timezone:/etc/timezone
|
|
||||||
environment:
|
|
||||||
- MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD}
|
|
||||||
- MYSQL_DATABASE=bookmark
|
|
||||||
bookmark-redis:
|
|
||||||
image: redis:3.2.10
|
|
||||||
container_name: bookmark-redis
|
|
||||||
volumes:
|
|
||||||
- /etc/localtime:/etc/localtime
|
|
||||||
- ./timezone:/etc/timezone
|
|
||||||
networks:
|
|
||||||
- bookmark
|
|
||||||
# redis未设置密码,如端口暴露可能会被攻击
|
|
||||||
ports:
|
|
||||||
- 6380:6379
|
|
||||||
bookmark-es:
|
|
||||||
image: elasticsearch:7.2.0
|
|
||||||
container_name: bookmark-es
|
|
||||||
volumes:
|
|
||||||
- /etc/localtime:/etc/localtime
|
|
||||||
- ./timezone:/etc/timezone
|
|
||||||
- ./es/data:/usr/share/elasticsearch/data
|
|
||||||
- ./es/ik:/usr/share/elasticsearch/plugins/ik
|
|
||||||
- ./es/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
|
|
||||||
environment:
|
|
||||||
- "ES_JAVA_OPTS=-Xms1500m -Xmx1500m"
|
|
||||||
ports:
|
|
||||||
- 9200:9200
|
|
||||||
- 9300:9300
|
|
||||||
networks:
|
|
||||||
- bookmark
|
|
||||||
bookmark-front:
|
|
||||||
image: nginx
|
|
||||||
container_name: bookmark-front
|
|
||||||
depends_on:
|
|
||||||
- bookmark-service
|
|
||||||
networks:
|
|
||||||
- bookmark
|
|
||||||
volumes:
|
|
||||||
- /etc/localtime:/etc/localtime
|
|
||||||
- ./timezone:/etc/timezone
|
|
||||||
- ../front/build:/opt/dist
|
|
||||||
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
|
|
||||||
- ./nginx/log:/var/log/nginx
|
|
||||||
- ${BOOKMARK_FILE_SAVE_PATH}/files/public:/opt/files/public
|
|
||||||
ports:
|
|
||||||
- 8083:8080
|
|
||||||
bookmark-service:
|
|
||||||
image: registry.cn-hangzhou.aliyuncs.com/fleyx/node-java-env:v2
|
|
||||||
container_name: bookmark-service
|
|
||||||
depends_on:
|
|
||||||
- bookmark-mysql
|
|
||||||
- bookmark-redis
|
|
||||||
- bookmark-es
|
|
||||||
networks:
|
|
||||||
- bookmark
|
|
||||||
volumes:
|
|
||||||
- /etc/localtime:/etc/localtime
|
|
||||||
- ./timezone:/etc/timezone
|
|
||||||
- ../bookMarkService/web/target/bookmark-web-1.0-SNAPSHOT.jar:/opt/app/service.jar
|
|
||||||
- ${BOOKMARK_FILE_SAVE_PATH}:/opt/files
|
|
||||||
working_dir: /opt/app
|
|
||||||
command:
|
|
||||||
- /bin/bash
|
|
||||||
- -c
|
|
||||||
- |
|
|
||||||
sleep 20 && \
|
|
||||||
ls -l && \
|
|
||||||
java -jar -DisDev=false \
|
|
||||||
-DjwtSecret=${JWT_SECRET} \
|
|
||||||
-Dmybatis-plus.configuration.log-impl=org.apache.ibatis.logging.nologging.NoLoggingImpl \
|
|
||||||
-Dspring.mail.host=${SMTP_HOST} \
|
|
||||||
-Dspring.mail.username=${SMTP_USERNAME} \
|
|
||||||
-Dspring.mail.password=${SMTP_PASSWORD} \
|
|
||||||
-Dspring.datasource.druid.password=${MYSQL_PASSWORD} \
|
|
||||||
-Dspring.datasource.druid.url=jdbc:mysql://bookmark-mysql:3306/bookmark?useUnicode=true\&characterEncoding=utf-8\&useSSL=false\&useJDBCCompliantTimezoneShift=true\&useLegacyDatetimeCode=false\&serverTimezone=UTC \
|
|
||||||
-Dspring.redis.host=bookmark-redis \
|
|
||||||
-Des.host=bookmark-es \
|
|
||||||
-DserviceAddress=${BOOKMARK_HOST} \
|
|
||||||
-DfileSavePath=/opt/files \
|
|
||||||
-DserviceAddress=https://bm.tapme.top \
|
|
||||||
service.jar
|
|
||||||
networks:
|
|
||||||
bookmark:
|
|
@ -1,15 +0,0 @@
|
|||||||
#/bin/bash
|
|
||||||
base=$(cd "$(dirname "$0")";pwd)
|
|
||||||
|
|
||||||
# 创建es存放数据文件夹并设置读写权限
|
|
||||||
mkdir $base/es/data>/dev/null 2>&1
|
|
||||||
|
|
||||||
chmod 777 $base/es/data
|
|
||||||
|
|
||||||
sysctl -w vm.max_map_count=262144>/dev/null 2>&1
|
|
||||||
|
|
||||||
# 用于前后端打包
|
|
||||||
|
|
||||||
docker run -it --rm --name buildBookmark -v $base/../front:/opt/front registry.cn-hangzhou.aliyuncs.com/fleyx/node-java-env:v2 sh -c "cd /opt/front && npm --registry https://registry.npm.taobao.org install && npm run build"
|
|
||||||
|
|
||||||
docker run -it --rm --name buildBookmark -v $base/mavenRep:/opt/mavenRep -v $base/../bookMarkService:/opt/backend registry.cn-hangzhou.aliyuncs.com/fleyx/node-java-env:v2 sh -c "cd /opt/backend && mvn clean install && echo over"
|
|
1
bookMarkService/.gitignore
vendored
1
bookMarkService/.gitignore
vendored
@ -17,6 +17,7 @@ static
|
|||||||
*.iws
|
*.iws
|
||||||
*.iml
|
*.iml
|
||||||
*.ipr
|
*.ipr
|
||||||
|
node_modules
|
||||||
|
|
||||||
### NetBeans ###
|
### NetBeans ###
|
||||||
/nbproject/private/
|
/nbproject/private/
|
||||||
|
14
bookMarkService/business/api/pom.xml
Normal file
14
bookMarkService/business/api/pom.xml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>bookmark-business</artifactId>
|
||||||
|
<groupId>com.fanxb</groupId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>bookmark-business-api</artifactId>
|
||||||
|
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.fanxb.bookmark.business.api;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/13
|
||||||
|
**/
|
||||||
|
public interface BookmarkApi {
|
||||||
|
/**
|
||||||
|
* 更新某个用户的icon数据
|
||||||
|
*
|
||||||
|
* @param userId 用户id
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/11
|
||||||
|
**/
|
||||||
|
void updateUserBookmarkIcon(int userId);
|
||||||
|
|
||||||
|
/***
|
||||||
|
* 删除一次数据
|
||||||
|
* @author fanxb
|
||||||
|
* @param delete 是否删除问题数据
|
||||||
|
* @param userId userId
|
||||||
|
* @return 返回删除的数据
|
||||||
|
* @date 2021/3/17
|
||||||
|
**/
|
||||||
|
Set<String> dealBadBookmark(boolean delete, int userId);
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.fanxb.bookmark.business.api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/8/20 下午2:12
|
||||||
|
*/
|
||||||
|
public interface UserApi {
|
||||||
|
/**
|
||||||
|
* 版本自增
|
||||||
|
*
|
||||||
|
* @param userId 用户id
|
||||||
|
*/
|
||||||
|
void versionPlus(int userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新所有用户的version
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/13
|
||||||
|
**/
|
||||||
|
void allUserVersionPlus();
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* 用于模块间的方法相互调用,具体使用如下:
|
||||||
|
* 1. 首先在business模块下建立interface接口,然后在个具体模块中实现
|
||||||
|
* 2. 最后诸如interface,就能实现同级模块间的直接调用
|
||||||
|
*/
|
||||||
|
package com.fanxb.bookmark.business.api;
|
@ -12,12 +12,27 @@
|
|||||||
<artifactId>bookmark-business-bookmark</artifactId>
|
<artifactId>bookmark-business-bookmark</artifactId>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fanxb</groupId>
|
||||||
|
<artifactId>bookmark-business-api</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
<!--html文件解析-->
|
<!--html文件解析-->
|
||||||
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
|
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jsoup</groupId>
|
<groupId>org.jsoup</groupId>
|
||||||
<artifactId>jsoup</artifactId>
|
<artifactId>jsoup</artifactId>
|
||||||
<version>1.12.1</version>
|
<version>1.15.3</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.houbb</groupId>
|
||||||
|
<artifactId>pinyin</artifactId>
|
||||||
|
<version>0.3.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.xerial</groupId>
|
||||||
|
<artifactId>sqlite-jdbc</artifactId>
|
||||||
|
<version>3.44.1.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.fanxb.bookmark.business.bookmark.constant;
|
||||||
|
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
public class FileConstant {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网站icon存储路径
|
||||||
|
*/
|
||||||
|
public static final String FAVICON_PATH = Paths.get("files", "public", "favicon").toString();
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
package com.fanxb.bookmark.business.bookmark.consumer;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.dao.PinBookmarkDao;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.entity.redis.BookmarkDeleteMessage;
|
||||||
|
import com.fanxb.bookmark.common.annotation.MqConsumer;
|
||||||
|
import com.fanxb.bookmark.common.constant.EsConstant;
|
||||||
|
import com.fanxb.bookmark.common.constant.RedisConstant;
|
||||||
|
import com.fanxb.bookmark.common.entity.redis.RedisConsumer;
|
||||||
|
import com.fanxb.bookmark.common.util.EsUtil;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created with IntelliJ IDEA
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* Date: 2020/3/29
|
||||||
|
* Time: 13:08
|
||||||
|
*/
|
||||||
|
@MqConsumer(RedisConstant.BOOKMARK_DELETE_ES)
|
||||||
|
public class BookmarkDeleteMessageConsumer implements RedisConsumer {
|
||||||
|
private final PinBookmarkDao pinBookmarkDao;
|
||||||
|
private final EsUtil esUtil;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public BookmarkDeleteMessageConsumer(PinBookmarkDao pinBookmarkDao, EsUtil esUtil) {
|
||||||
|
this.pinBookmarkDao = pinBookmarkDao;
|
||||||
|
this.esUtil = esUtil;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deal(String message) {
|
||||||
|
BookmarkDeleteMessage obj = JSON.parseObject(message, BookmarkDeleteMessage.class);
|
||||||
|
//删除首页固定的数据
|
||||||
|
pinBookmarkDao.deleteUnExistBookmark(obj.getUserId());
|
||||||
|
//删除es数据
|
||||||
|
if (CollectionUtil.isNotEmpty(obj.getBookmarkIds())) {
|
||||||
|
esUtil.deleteBatch(EsConstant.BOOKMARK_INDEX, obj.getBookmarkIds());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package com.fanxb.bookmark.business.bookmark.consumer;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.entity.BookmarkEs;
|
||||||
|
import com.fanxb.bookmark.common.annotation.MqConsumer;
|
||||||
|
import com.fanxb.bookmark.common.constant.EsConstant;
|
||||||
|
import com.fanxb.bookmark.common.constant.RedisConstant;
|
||||||
|
import com.fanxb.bookmark.common.entity.po.Bookmark;
|
||||||
|
import com.fanxb.bookmark.common.entity.EsEntity;
|
||||||
|
import com.fanxb.bookmark.common.entity.redis.RedisConsumer;
|
||||||
|
import com.fanxb.bookmark.common.util.EsUtil;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插入/更新数据到es中
|
||||||
|
* Created with IntelliJ IDEA
|
||||||
|
* Created By Fxb
|
||||||
|
* Date: 2020/3/29
|
||||||
|
* Time: 11:34
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
@MqConsumer(RedisConstant.BOOKMARK_INSERT_ES)
|
||||||
|
public class BookmarkInsertEsConsumer implements RedisConsumer {
|
||||||
|
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private EsUtil esUtil;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deal(String message) {
|
||||||
|
List<Bookmark> bookmarks = JSONArray.parseArray(message, Bookmark.class);
|
||||||
|
if (CollectionUtil.isEmpty(bookmarks)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<EsEntity<BookmarkEs>> esList = bookmarks.stream()
|
||||||
|
.map(item -> new EsEntity<>(item.getBookmarkId().toString(), new BookmarkEs(item))).collect(Collectors.toList());
|
||||||
|
esUtil.insertBatch(EsConstant.BOOKMARK_INDEX, esList);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
package com.fanxb.bookmark.business.bookmark.consumer;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.dao.BookmarkDao;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.entity.redis.VisitNumPlus;
|
||||||
|
import com.fanxb.bookmark.common.annotation.MqConsumer;
|
||||||
|
import com.fanxb.bookmark.common.constant.RedisConstant;
|
||||||
|
import com.fanxb.bookmark.common.entity.redis.RedisConsumer;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新书签时间
|
||||||
|
* Created with IntelliJ IDEA
|
||||||
|
* Created By Fxb
|
||||||
|
* Date: 2020/5/12
|
||||||
|
* Time: 10:33
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
@MqConsumer(RedisConstant.BOOKMARK_VISIT_NUM_PLUS)
|
||||||
|
@Slf4j
|
||||||
|
public class BookmarkVisitNumPlusConsumer implements RedisConsumer {
|
||||||
|
|
||||||
|
private final BookmarkDao bookmarkDao;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public BookmarkVisitNumPlusConsumer(BookmarkDao bookmarkDao) {
|
||||||
|
this.bookmarkDao = bookmarkDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deal(String message) {
|
||||||
|
VisitNumPlus item = JSON.parseObject(message, VisitNumPlus.class);
|
||||||
|
try {
|
||||||
|
bookmarkDao.updateVisitNum(item);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("书签访问次数增加失败:{}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package com.fanxb.bookmark.business.bookmark.controller;
|
package com.fanxb.bookmark.business.bookmark.controller;
|
||||||
|
|
||||||
import com.fanxb.bookmark.business.bookmark.service.BookmarkBackupService;
|
import com.fanxb.bookmark.business.bookmark.service.BookmarkBackupService;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.service.impl.BookmarkBackupServiceImpl;
|
||||||
import com.fanxb.bookmark.common.entity.Result;
|
import com.fanxb.bookmark.common.entity.Result;
|
||||||
import com.fanxb.bookmark.common.util.ThreadPoolUtil;
|
import com.fanxb.bookmark.common.util.ThreadPoolUtil;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -20,17 +21,17 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
@RequestMapping("/bookmarkBackup")
|
@RequestMapping("/bookmarkBackup")
|
||||||
public class BookmarkBackupController {
|
public class BookmarkBackupController {
|
||||||
|
|
||||||
private BookmarkBackupService backupService;
|
private final BookmarkBackupService backupService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public BookmarkBackupController(BookmarkBackupService backupService) {
|
public BookmarkBackupController(BookmarkBackupServiceImpl backupService) {
|
||||||
this.backupService = backupService;
|
this.backupService = backupService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/mysqlToEs")
|
@PostMapping("/mysqlToEs")
|
||||||
public Result backupToEs() {
|
public Result backupToEs() {
|
||||||
//异步执行同步任务
|
//异步执行同步任务
|
||||||
ThreadPoolUtil.execute(() -> backupService.backupToEs());
|
ThreadPoolUtil.execute(backupService::backupToEs);
|
||||||
return Result.success(null);
|
return Result.success(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
package com.fanxb.bookmark.business.bookmark.controller;
|
package com.fanxb.bookmark.business.bookmark.controller;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.fanxb.bookmark.business.bookmark.entity.BatchDeleteBody;
|
import com.fanxb.bookmark.business.bookmark.entity.BatchDeleteBody;
|
||||||
import com.fanxb.bookmark.business.bookmark.entity.BookmarkEs;
|
import com.fanxb.bookmark.business.bookmark.entity.BookmarkEs;
|
||||||
import com.fanxb.bookmark.business.bookmark.entity.MoveNodeBody;
|
import com.fanxb.bookmark.business.bookmark.entity.MoveNodeBody;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.service.BookmarkBackupService;
|
||||||
import com.fanxb.bookmark.business.bookmark.service.BookmarkService;
|
import com.fanxb.bookmark.business.bookmark.service.BookmarkService;
|
||||||
import com.fanxb.bookmark.common.entity.Bookmark;
|
import com.fanxb.bookmark.business.bookmark.service.PinYinService;
|
||||||
|
import com.fanxb.bookmark.common.entity.po.Bookmark;
|
||||||
import com.fanxb.bookmark.common.entity.Result;
|
import com.fanxb.bookmark.common.entity.Result;
|
||||||
import com.fanxb.bookmark.common.entity.UserContext;
|
|
||||||
import com.fanxb.bookmark.common.util.UserContextHolder;
|
import com.fanxb.bookmark.common.util.UserContextHolder;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@ -24,9 +26,12 @@ import java.util.List;
|
|||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/bookmark")
|
@RequestMapping("/bookmark")
|
||||||
public class BookmarkController {
|
public class BookmarkController {
|
||||||
|
@Autowired
|
||||||
|
private BookmarkBackupService bookmarkBackupService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private BookmarkService bookmarkService;
|
private BookmarkService bookmarkService;
|
||||||
|
@Autowired
|
||||||
|
private PinYinService pinYinService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description: 获取路径为path的书签数据
|
* Description: 获取路径为path的书签数据
|
||||||
@ -49,7 +54,7 @@ public class BookmarkController {
|
|||||||
* @date 2019/12/14 0:09
|
* @date 2019/12/14 0:09
|
||||||
*/
|
*/
|
||||||
@GetMapping("/currentUser")
|
@GetMapping("/currentUser")
|
||||||
public Result getBookmarkMap(){
|
public Result getBookmarkMap() {
|
||||||
return Result.success(bookmarkService.getOneBookmarkTree(UserContextHolder.get().getUserId()));
|
return Result.success(bookmarkService.getOneBookmarkTree(UserContextHolder.get().getUserId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,9 +67,9 @@ public class BookmarkController {
|
|||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/8 15:17
|
* @date 2019/7/8 15:17
|
||||||
*/
|
*/
|
||||||
@PutMapping("/uploadBookmarkFile")
|
@RequestMapping("/uploadBookmarkFile")
|
||||||
public Result uploadFile(@RequestParam("file") MultipartFile file, @RequestParam("path") String path) throws Exception {
|
public Result uploadFile(@RequestParam("file") MultipartFile file, @RequestParam("path") String path) throws Exception {
|
||||||
bookmarkService.parseBookmarkFile(UserContextHolder.get().getUserId(), file.getInputStream(), path);
|
bookmarkService.parseBookmarkFile(UserContextHolder.get().getUserId(), file, path);
|
||||||
return Result.success(null);
|
return Result.success(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,8 +98,7 @@ public class BookmarkController {
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/updateOne")
|
@PostMapping("/updateOne")
|
||||||
public Result editCurrentUserBookmark(@RequestBody Bookmark bookmark) {
|
public Result editCurrentUserBookmark(@RequestBody Bookmark bookmark) {
|
||||||
bookmarkService.updateOne(UserContextHolder.get().getUserId(), bookmark);
|
return Result.success(bookmarkService.updateOne(UserContextHolder.get().getUserId(), bookmark));
|
||||||
return Result.success(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -107,7 +111,7 @@ public class BookmarkController {
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/batchDelete")
|
@PostMapping("/batchDelete")
|
||||||
public Result batchDelete(@RequestBody BatchDeleteBody body) {
|
public Result batchDelete(@RequestBody BatchDeleteBody body) {
|
||||||
bookmarkService.batchDelete(UserContextHolder.get().getUserId(), body.getFolderIdList(), body.getBookmarkIdList());
|
bookmarkService.batchDelete(UserContextHolder.get().getUserId(), body.getPathList(), body.getBookmarkIdList());
|
||||||
return Result.success(null);
|
return Result.success(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,8 +144,70 @@ public class BookmarkController {
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/syncBookmark")
|
@PostMapping("/syncBookmark")
|
||||||
public Result syncBookmark() {
|
public Result syncBookmark() {
|
||||||
bookmarkService.syncUserBookmark(UserContextHolder.get().getUserId());
|
bookmarkBackupService.syncUserBookmark(UserContextHolder.get().getUserId());
|
||||||
return Result.success(null);
|
return Result.success(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能描述: 全量更新拼音数据
|
||||||
|
*
|
||||||
|
* @return com.fanxb.bookmark.common.entity.Result
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2020/3/22 22:22
|
||||||
|
*/
|
||||||
|
@PostMapping("/allPinyinCreate")
|
||||||
|
public Result changeAllPinyin() {
|
||||||
|
pinYinService.changeAll();
|
||||||
|
return Result.success(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能描述: 书签增加1
|
||||||
|
*
|
||||||
|
* @param id id
|
||||||
|
* @return com.fanxb.bookmark.common.entity.Result
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2020/5/12 10:44
|
||||||
|
*/
|
||||||
|
@PostMapping("/visitNum")
|
||||||
|
public Result visitNum(int id) {
|
||||||
|
bookmarkService.visitNumPlus(id);
|
||||||
|
return Result.success(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能描述: 获取用户访问次数前10的书签
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
@GetMapping("/user/popular")
|
||||||
|
public Result currentUserPopular() {
|
||||||
|
return Result.success(bookmarkService.userPopular(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新所有的icon
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/11
|
||||||
|
**/
|
||||||
|
@PostMapping("/updateCurrentUserIcon")
|
||||||
|
public Result updateCurrentUserIcon() {
|
||||||
|
bookmarkService.updateUserBookmarkIcon(UserContextHolder.get().getUserId());
|
||||||
|
return Result.success(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查/删除无父节点的数据
|
||||||
|
*
|
||||||
|
* @return com.fanxb.bookmark.common.entity.Result
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/17
|
||||||
|
**/
|
||||||
|
@PostMapping("/dealBadBookmark")
|
||||||
|
public Result dealBadBookmark(@RequestBody JSONObject obj) {
|
||||||
|
return Result.success(bookmarkService.dealBadBookmark(obj.getBoolean("delete"), UserContextHolder.get().getUserId()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
package com.fanxb.bookmark.business.bookmark.controller;
|
||||||
|
|
||||||
|
import com.fanxb.bookmark.business.bookmark.entity.po.PInBookmarkPo;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.service.HomePinService;
|
||||||
|
import com.fanxb.bookmark.common.entity.Result;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首页相关接口
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/home")
|
||||||
|
public class HomeController {
|
||||||
|
|
||||||
|
private final HomePinService homePinService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public HomeController(HomePinService homePinService) {
|
||||||
|
this.homePinService = homePinService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取首页固定标签
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
@GetMapping("/pin")
|
||||||
|
public Result getPin() {
|
||||||
|
return Result.success(homePinService.getHomePinList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增固定书签
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
@PutMapping("/pin")
|
||||||
|
public Result addPin(@RequestBody PInBookmarkPo po) {
|
||||||
|
return Result.success(homePinService.addOne(po));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除书签
|
||||||
|
*
|
||||||
|
* @param id url参数id
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
@DeleteMapping("/pin")
|
||||||
|
public Result deleteOne(int id) {
|
||||||
|
homePinService.delete(id);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
}
|
@ -1,27 +0,0 @@
|
|||||||
package com.fanxb.bookmark.business.bookmark.dao;
|
|
||||||
|
|
||||||
import com.fanxb.bookmark.common.entity.Bookmark;
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
|
||||||
import org.apache.ibatis.annotations.Param;
|
|
||||||
import org.apache.ibatis.annotations.Select;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created with IntelliJ IDEA
|
|
||||||
* Created By Fxb
|
|
||||||
* Date: 2019/11/12
|
|
||||||
* Time: 0:24
|
|
||||||
*/
|
|
||||||
@Mapper
|
|
||||||
public interface BookmarkBackupDao {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分页获取所有的书签
|
|
||||||
* @param size 大小
|
|
||||||
* @param startIndex 开始下标
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Select("select * from bookmark order by bookmarkId limit ${startIndex},${size}")
|
|
||||||
List<Bookmark> getBookmarkListPage(@Param("size") int size,@Param("startIndex") int startIndex);
|
|
||||||
}
|
|
@ -1,8 +1,12 @@
|
|||||||
package com.fanxb.bookmark.business.bookmark.dao;
|
package com.fanxb.bookmark.business.bookmark.dao;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.fanxb.bookmark.business.bookmark.entity.BookmarkEs;
|
import com.fanxb.bookmark.business.bookmark.entity.BookmarkEs;
|
||||||
import com.fanxb.bookmark.common.entity.Bookmark;
|
import com.fanxb.bookmark.business.bookmark.entity.redis.VisitNumPlus;
|
||||||
|
import com.fanxb.bookmark.common.entity.po.Bookmark;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
import org.apache.ibatis.annotations.Update;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -15,13 +19,12 @@ import java.util.List;
|
|||||||
* @date 2019/7/8 16:39
|
* @date 2019/7/8 16:39
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
public interface BookmarkDao {
|
public interface BookmarkDao extends BaseMapper<Bookmark> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description: 插入一条书签记录
|
* Description: 插入一条书签记录
|
||||||
*
|
*
|
||||||
* @param node node
|
* @param node node
|
||||||
* @return void
|
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/8 16:49
|
* @date 2019/7/8 16:49
|
||||||
*/
|
*/
|
||||||
@ -54,7 +57,7 @@ public interface BookmarkDao {
|
|||||||
* Description: 根据用户id获取其所有数据
|
* Description: 根据用户id获取其所有数据
|
||||||
*
|
*
|
||||||
* @param userId userid
|
* @param userId userid
|
||||||
* @return java.util.List<com.fanxb.bookmark.common.entity.Bookmark>
|
* @return java.util.List<com.fanxb.bookmark.common.entity.po.Bookmark>
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/9 18:55
|
* @date 2019/7/9 18:55
|
||||||
*/
|
*/
|
||||||
@ -65,21 +68,21 @@ public interface BookmarkDao {
|
|||||||
*
|
*
|
||||||
* @param userId userId
|
* @param userId userId
|
||||||
* @param path path
|
* @param path path
|
||||||
* @return java.util.List<com.fanxb.bookmark.common.entity.Bookmark>
|
* @return java.util.List<com.fanxb.bookmark.common.entity.po.Bookmark>
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/17 14:48
|
* @date 2019/7/17 14:48
|
||||||
*/
|
*/
|
||||||
List<Bookmark> getListByUserIdAndPath(@Param("userId") int userId, @Param("path") String path);
|
List<Bookmark> getListByUserIdAndPath(@Param("userId") int userId, @Param("path") String path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description: 删除某用户某个书签文件下所有数据
|
* Description: 删除某用户某个书签路径下所有数据,不包含文件夹自身
|
||||||
*
|
*
|
||||||
* @param userId 用户id
|
* @param userId 用户id
|
||||||
* @param folderId 文件夹id
|
* @param path 文件夹id
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/12 14:13
|
* @date 2019/7/12 14:13
|
||||||
*/
|
*/
|
||||||
void deleteUserFolder(@Param("userId") int userId, @Param("folderId") int folderId);
|
void deleteUserFolder(@Param("userId") int userId, @Param("path") String path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description: 删除用户书签
|
* Description: 删除用户书签
|
||||||
@ -135,27 +138,127 @@ public interface BookmarkDao {
|
|||||||
void updatePathAndSort(@Param("userId") int userId, @Param("bookmarkId") int bookmarkId, @Param("path") String path, @Param("sort") int sort);
|
void updatePathAndSort(@Param("userId") int userId, @Param("bookmarkId") int bookmarkId, @Param("path") String path, @Param("sort") int sort);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description: 获取某个文件夹下所有的节点id
|
* Description: 获取某个路径下所有的节点id
|
||||||
*
|
*
|
||||||
* @param userId userId
|
* @param userId userId
|
||||||
* @param folderId folderId
|
* @param path path
|
||||||
* @return java.util.List<java.lang.Integer>
|
* @return java.util.List<java.lang.Integer>
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/25 14:14
|
* @date 2019/7/25 14:14
|
||||||
*/
|
*/
|
||||||
List<Integer> getChildrenBookmarkId(@Param("userId") int userId, @Param("folderId") int folderId);
|
List<Integer> getChildrenBookmarkId(@Param("userId") int userId, @Param("path") String path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description: 根据用户id,类别,分页查找书签
|
* Description: 根据用户id,类别,分页查找书签
|
||||||
*
|
*
|
||||||
|
* @param userId userId
|
||||||
|
* @param type type
|
||||||
|
* @param start start
|
||||||
|
* @param size size
|
||||||
|
* @return java.util.List<com.fanxb.bookmark.business.bookmark.entity.BookmarkEs>
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/26 15:23
|
* @date 2019/7/26 15:23
|
||||||
* @param userId userId
|
|
||||||
* @param type type
|
|
||||||
* @param start start
|
|
||||||
* @param size size
|
|
||||||
* @return java.util.List<com.fanxb.bookmark.business.bookmark.entity.BookmarkEs>
|
|
||||||
*/
|
*/
|
||||||
List<BookmarkEs> selectBookmarkEsByUserIdAndType(@Param("userId") int userId, @Param("type") int type, @Param("start") int start, @Param("size") int size);
|
List<BookmarkEs> selectBookmarkEsByUserIdAndType(@Param("userId") int userId, @Param("type") int type, @Param("start") int start, @Param("size") int size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能描述: 查询所有的bookmark,用于全量更新拼音key
|
||||||
|
*
|
||||||
|
* @param bookmarkId bookmarkId
|
||||||
|
* @param size size
|
||||||
|
* @return List<Bookmark>
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2020/3/22 22:06
|
||||||
|
*/
|
||||||
|
@Select("select bookmarkId,name,url from bookmark where bookmarkId>${bookmarkId} order by bookmarkId asc limit 0,${size}")
|
||||||
|
List<Bookmark> selectPinyinEmpty(@Param("bookmarkId") int bookmarkId, @Param("size") int size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能描述: 更新一个bookmark的key
|
||||||
|
*
|
||||||
|
* @param bookmarkId id
|
||||||
|
* @param searchKey searchKey
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2020/3/22 22:08
|
||||||
|
*/
|
||||||
|
@Update("update bookmark set searchKey=#{searchKey} where bookmarkId=#{bookmarkId}")
|
||||||
|
void updateSearchKey(@Param("bookmarkId") int bookmarkId, @Param("searchKey") String searchKey);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量更新searchKey
|
||||||
|
*
|
||||||
|
* @param list list
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2020/3/22 22:08
|
||||||
|
*/
|
||||||
|
void updateSearchKeyBatch(List<Bookmark> list);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页获取所有的书签
|
||||||
|
*
|
||||||
|
* @param size 大小
|
||||||
|
* @param startIndex 开始下标
|
||||||
|
* @return bookmark List
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
@Select("select * from bookmark order by bookmarkId limit ${startIndex},${size}")
|
||||||
|
List<Bookmark> getBookmarkListPage(@Param("size") int size, @Param("startIndex") int startIndex);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能描述: 书签访问次数+1
|
||||||
|
*
|
||||||
|
* @param item 信息
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2020/5/12 10:40
|
||||||
|
*/
|
||||||
|
@Update("update bookmark set visitNum=visitNum+1 where userId=#{userId} and bookmarkId=#{bookmarkId}")
|
||||||
|
void updateVisitNum(VisitNumPlus item);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询用户最常访问的几个书签
|
||||||
|
*
|
||||||
|
* @param userId 用户id
|
||||||
|
* @param num num
|
||||||
|
* @return java.util.List<com.fanxb.bookmark.common.entity.po.Bookmark>
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/8/20 上午11:52
|
||||||
|
*/
|
||||||
|
@Select("select bookmarkId,name,url,icon from bookmark where userId=#{userId} and type=0 order by visitNum desc limit 0,#{num}")
|
||||||
|
List<Bookmark> selectPopular(@Param("userId") int userId, @Param("num") int num);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取某用户无icon的条目
|
||||||
|
*
|
||||||
|
* @param userId userId
|
||||||
|
* @param start 开始
|
||||||
|
* @param size 数量
|
||||||
|
* @return java.util.List<com.fanxb.bookmark.common.entity.po.Bookmark>
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/8/20 下午12:02
|
||||||
|
*/
|
||||||
|
@Select("select userId,bookmarkId,url,icon from bookmark where userId=#{userId} and icon='' order by bookmarkId asc limit #{start},#{size}")
|
||||||
|
List<Bookmark> selectUserNoIcon(@Param("userId") int userId, @Param("start") int start, @Param("size") int size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新icon
|
||||||
|
*
|
||||||
|
* @param bookmarkId bookmarkId
|
||||||
|
* @param icon icon
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/13
|
||||||
|
**/
|
||||||
|
@Update("update bookmark set icon=#{icon} where bookmarkId=#{bookmarkId}")
|
||||||
|
void updateIcon(@Param("bookmarkId") int bookmarkId, @Param("icon") String icon);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询一个用户全部的书签路径
|
||||||
|
*
|
||||||
|
* @param userId userId
|
||||||
|
* @return java.util.List<com.fanxb.bookmark.common.entity.po.Bookmark>
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/8/20 上午11:58
|
||||||
|
*/
|
||||||
|
@Select("select bookmarkId,path from bookmark where userId=#{userId}")
|
||||||
|
List<Bookmark> selectBookmarkIdPathByUserId(int userId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
package com.fanxb.bookmark.business.bookmark.dao;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface HostIconDao {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插入一条数据
|
||||||
|
*
|
||||||
|
* @param host host
|
||||||
|
* @param iconPath path
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
@Insert("insert into host_icon(host,iconPath) value(#{host},#{iconPath})")
|
||||||
|
void insert(@Param("host") String host, @Param("iconPath") String iconPath);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据host获取iconPath
|
||||||
|
*
|
||||||
|
* @param host host
|
||||||
|
* @return {@link String}
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
@Select("select iconPath from host_icon where host=#{host} limit 1")
|
||||||
|
String selectByHost(String host);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除一条
|
||||||
|
*
|
||||||
|
* @param host host
|
||||||
|
* @author FleyX
|
||||||
|
*/
|
||||||
|
@Delete("delete from host_icon where host=#{host}")
|
||||||
|
void deleteByHost(String host);
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package com.fanxb.bookmark.business.bookmark.dao;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.entity.po.PInBookmarkPo;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.entity.vo.HomePinItemVo;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface PinBookmarkDao extends BaseMapper<PInBookmarkPo> {
|
||||||
|
|
||||||
|
/***
|
||||||
|
* 获取用户固定的书签
|
||||||
|
*
|
||||||
|
* @param userId userId
|
||||||
|
* @return {@link List<HomePinItemVo>}
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
@Select("select a.id,b.bookmarkId,b.name,b.url,b.icon from pin_bookmark a inner join bookmark b on a.bookmarkId=b.bookmarkId where a.userId=#{userId}")
|
||||||
|
List<HomePinItemVo> selectUserPin(int userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前最大的序列号
|
||||||
|
*
|
||||||
|
* @param userId userId
|
||||||
|
* @return {@link int}
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
@Select("select ifnull(max(sort),0) from pin_bookmark where userId=#{userId}")
|
||||||
|
int getUserMaxSort(int userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除书签后,需要清理此表,将不存在的书签删除
|
||||||
|
*
|
||||||
|
* @param userId userId
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
void deleteUnExistBookmark(int userId);
|
||||||
|
}
|
@ -13,6 +13,12 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class BatchDeleteBody{
|
public class BatchDeleteBody{
|
||||||
private List<Integer> folderIdList;
|
/**
|
||||||
|
* 要删除的书签路径
|
||||||
|
*/
|
||||||
|
private List<String> pathList;
|
||||||
|
/**
|
||||||
|
* 要删除的书签id
|
||||||
|
*/
|
||||||
private List<Integer> bookmarkIdList;
|
private List<Integer> bookmarkIdList;
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package com.fanxb.bookmark.business.bookmark.entity;
|
package com.fanxb.bookmark.business.bookmark.entity;
|
||||||
|
|
||||||
import com.fanxb.bookmark.common.entity.Bookmark;
|
import com.fanxb.bookmark.common.entity.po.Bookmark;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
package com.fanxb.bookmark.business.bookmark.entity;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created with IntelliJ IDEA
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* Date: 2020/3/19
|
||||||
|
* Time: 0:05
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class PinYinBody {
|
||||||
|
/**
|
||||||
|
* 待转换拼音的文本列表
|
||||||
|
*/
|
||||||
|
private List<String> strs;
|
||||||
|
private Config config;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class Config {
|
||||||
|
/**
|
||||||
|
* 是否启用分词模式
|
||||||
|
*/
|
||||||
|
private boolean segment;
|
||||||
|
/**
|
||||||
|
* 是否启用多音字
|
||||||
|
*/
|
||||||
|
private boolean heteronym;
|
||||||
|
/**
|
||||||
|
* 风格
|
||||||
|
*/
|
||||||
|
private int style;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package com.fanxb.bookmark.business.bookmark.entity.po;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首页固定标签
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@TableName("pin_bookmark")
|
||||||
|
public class PInBookmarkPo {
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private int id;
|
||||||
|
private int userId;
|
||||||
|
private int bookmarkId;
|
||||||
|
private int sort;
|
||||||
|
private long createDate;
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.fanxb.bookmark.business.bookmark.entity.redis;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class BookmarkDeleteMessage {
|
||||||
|
/**
|
||||||
|
* 用户id
|
||||||
|
*/
|
||||||
|
private int userId;
|
||||||
|
/**
|
||||||
|
* 批量删除的书签id
|
||||||
|
*/
|
||||||
|
private Collection<String> bookmarkIds;
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.fanxb.bookmark.business.bookmark.entity.redis;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created with IntelliJ IDEA
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* Date: 2020/5/12 11:47
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class VisitNumPlus {
|
||||||
|
/**
|
||||||
|
* 用户id
|
||||||
|
*/
|
||||||
|
private int userId;
|
||||||
|
/**
|
||||||
|
* 书签id
|
||||||
|
*/
|
||||||
|
private int bookmarkId;
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package com.fanxb.bookmark.business.bookmark.entity.vo;
|
||||||
|
|
||||||
|
import com.fanxb.bookmark.business.bookmark.entity.po.PInBookmarkPo;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public class HomePinItemVo {
|
||||||
|
/**
|
||||||
|
* pinBookmark Id
|
||||||
|
*/
|
||||||
|
private Integer id;
|
||||||
|
/**
|
||||||
|
* 书签id
|
||||||
|
*/
|
||||||
|
private int bookmarkId;
|
||||||
|
/**
|
||||||
|
* 书签名
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
/**
|
||||||
|
* url
|
||||||
|
*/
|
||||||
|
private String url;
|
||||||
|
/**
|
||||||
|
* icon
|
||||||
|
*/
|
||||||
|
private String icon;
|
||||||
|
}
|
@ -1,38 +1,12 @@
|
|||||||
package com.fanxb.bookmark.business.bookmark.service;
|
package com.fanxb.bookmark.business.bookmark.service;
|
||||||
|
|
||||||
import com.fanxb.bookmark.business.bookmark.dao.BookmarkBackupDao;
|
|
||||||
import com.fanxb.bookmark.business.bookmark.dao.BookmarkDao;
|
|
||||||
import com.fanxb.bookmark.common.constant.EsConstant;
|
|
||||||
import com.fanxb.bookmark.common.entity.Bookmark;
|
|
||||||
import com.fanxb.bookmark.common.entity.EsEntity;
|
|
||||||
import com.fanxb.bookmark.common.util.EsUtil;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created with IntelliJ IDEA
|
|
||||||
* Created By Fxb
|
|
||||||
* Date: 2019/11/12
|
|
||||||
* Time: 0:22
|
|
||||||
*
|
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
|
* Date: 2020/3/29
|
||||||
|
* Time: 12:43
|
||||||
*/
|
*/
|
||||||
@Service
|
public interface BookmarkBackupService {
|
||||||
public class BookmarkBackupService {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private BookmarkBackupDao bookmarkBackupDao;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private EsUtil esUtil;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 一次同步BACKUP_SIZE条到es中
|
|
||||||
*/
|
|
||||||
private static final int BACKUP_SIZE = 500;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 功能描述: 将mysql数据同步到es中
|
* 功能描述: 将mysql数据同步到es中
|
||||||
@ -40,14 +14,14 @@ public class BookmarkBackupService {
|
|||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/11/12 0:22
|
* @date 2019/11/12 0:22
|
||||||
*/
|
*/
|
||||||
public void backupToEs() {
|
void backupToEs();
|
||||||
int start = 0;
|
|
||||||
List<Bookmark> list;
|
/**
|
||||||
while ((list = bookmarkBackupDao.getBookmarkListPage(BACKUP_SIZE, start)).size() != 0) {
|
* Description: 将某个用户的书签数据mysql同步到es中
|
||||||
List<EsEntity> batchList = new ArrayList<>(list.size());
|
*
|
||||||
list.forEach(item -> batchList.add(new EsEntity<>(item.getBookmarkId().toString(), item)));
|
* @param userId 用户id
|
||||||
esUtil.insertBatch(EsConstant.BOOKMARK_INDEX, batchList);
|
* @author fanxb
|
||||||
start += BACKUP_SIZE;
|
* @date 2019/7/26 11:27
|
||||||
}
|
*/
|
||||||
}
|
void syncUserBookmark(int userId);
|
||||||
}
|
}
|
||||||
|
@ -1,323 +1,150 @@
|
|||||||
package com.fanxb.bookmark.business.bookmark.service;
|
package com.fanxb.bookmark.business.bookmark.service;
|
||||||
|
|
||||||
import com.fanxb.bookmark.business.bookmark.dao.BookmarkDao;
|
|
||||||
import com.fanxb.bookmark.business.bookmark.entity.BookmarkEs;
|
import com.fanxb.bookmark.business.bookmark.entity.BookmarkEs;
|
||||||
import com.fanxb.bookmark.business.bookmark.entity.MoveNodeBody;
|
import com.fanxb.bookmark.business.bookmark.entity.MoveNodeBody;
|
||||||
import com.fanxb.bookmark.common.constant.EsConstant;
|
import com.fanxb.bookmark.common.entity.po.Bookmark;
|
||||||
import com.fanxb.bookmark.common.constant.RedisConstant;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import com.fanxb.bookmark.common.entity.Bookmark;
|
|
||||||
import com.fanxb.bookmark.common.entity.EsEntity;
|
|
||||||
import com.fanxb.bookmark.common.entity.redis.UserBookmarkUpdate;
|
|
||||||
import com.fanxb.bookmark.common.exception.FormDataException;
|
|
||||||
import com.fanxb.bookmark.common.util.EsUtil;
|
|
||||||
import com.fanxb.bookmark.common.util.RedisUtil;
|
|
||||||
import com.fanxb.bookmark.common.util.UserContextHolder;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.elasticsearch.index.query.BoolQueryBuilder;
|
|
||||||
import org.elasticsearch.index.query.QueryBuilders;
|
|
||||||
import org.elasticsearch.index.query.TermQueryBuilder;
|
|
||||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
|
||||||
import org.jsoup.Jsoup;
|
|
||||||
import org.jsoup.nodes.Document;
|
|
||||||
import org.jsoup.nodes.Element;
|
|
||||||
import org.jsoup.select.Elements;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.dao.DuplicateKeyException;
|
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.*;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 类功能简述:
|
* Created with IntelliJ IDEA
|
||||||
* 类功能详述:
|
|
||||||
*
|
*
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/8 15:00
|
* Date: 2020/3/29
|
||||||
|
* Time: 12:25
|
||||||
*/
|
*/
|
||||||
@Service
|
public interface BookmarkService {
|
||||||
@Slf4j
|
|
||||||
public class BookmarkService {
|
|
||||||
/**
|
/**
|
||||||
* chrome导出书签tag
|
* chrome导出书签tag
|
||||||
*/
|
*/
|
||||||
private static final String DT = "dt";
|
String DT = "dt";
|
||||||
private static final String A = "a";
|
String A = "a";
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private BookmarkDao bookmarkDao;
|
|
||||||
@Autowired
|
|
||||||
private StringRedisTemplate redisTemplate;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private EsUtil esUtil;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description: 解析书签文件
|
|
||||||
*
|
|
||||||
* @param stream 输入流
|
|
||||||
* @param path 存放路径
|
|
||||||
* @author fanxb
|
|
||||||
* @date 2019/7/9 18:44
|
|
||||||
*/
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void parseBookmarkFile(int userId, InputStream stream, String path) throws Exception {
|
|
||||||
Document doc = Jsoup.parse(stream, "utf-8", "");
|
|
||||||
Elements elements = doc.select("html>body>dl>dt");
|
|
||||||
//获取当前层sort最大值
|
|
||||||
Integer sortBase = bookmarkDao.selectMaxSort(userId, path);
|
|
||||||
if (sortBase == null) {
|
|
||||||
sortBase = 0;
|
|
||||||
}
|
|
||||||
int count = 0;
|
|
||||||
// 將要插入es的书签数据放到list中,最后一次插入,尽量避免mysql回滚了,但是es插入了
|
|
||||||
List<EsEntity> insertEsList = new ArrayList<>();
|
|
||||||
for (int i = 0, length = elements.size(); i < length; i++) {
|
|
||||||
if (i == 0) {
|
|
||||||
Elements firstChildren = elements.get(0).child(1).children();
|
|
||||||
count = firstChildren.size();
|
|
||||||
for (int j = 0; j < count; j++) {
|
|
||||||
dealBookmark(userId, firstChildren.get(j), path, sortBase + j, insertEsList);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dealBookmark(userId, elements.get(i), path, sortBase + count + i - 1, insertEsList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
redisTemplate.opsForList().leftPush(RedisConstant.BOOKMARK_UPDATE_TIME, new UserBookmarkUpdate(userId, System.currentTimeMillis()).toString());
|
|
||||||
esUtil.insertBatch(EsConstant.BOOKMARK_INDEX, insertEsList);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description: 处理html节点,解析出文件夹和书签
|
|
||||||
*
|
|
||||||
* @param ele 待处理节点
|
|
||||||
* @param path 节点路径,不包含自身
|
|
||||||
* @param sort 当前层级中的排序序号
|
|
||||||
* @author fanxb
|
|
||||||
* @date 2019/7/8 14:49
|
|
||||||
*/
|
|
||||||
private void dealBookmark(int userId, Element ele, String path, int sort, List<EsEntity> insertList) {
|
|
||||||
if (!DT.equalsIgnoreCase(ele.tagName())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Element first = ele.child(0);
|
|
||||||
if (A.equalsIgnoreCase(first.tagName())) {
|
|
||||||
//说明为链接
|
|
||||||
Bookmark node = new Bookmark(userId, path, first.ownText(), first.attr("href"), first.attr("icon")
|
|
||||||
, Long.parseLong(first.attr("add_date")) * 1000, sort);
|
|
||||||
//存入数据库
|
|
||||||
insertOne(node);
|
|
||||||
insertList.add(new EsEntity<>(node.getBookmarkId().toString(), new BookmarkEs(node)));
|
|
||||||
} else {
|
|
||||||
//说明为文件夹
|
|
||||||
Bookmark node = new Bookmark(userId, path, first.ownText(), Long.parseLong(first.attr("add_date")) * 1000, sort);
|
|
||||||
Integer sortBase = 0;
|
|
||||||
if (insertOne(node)) {
|
|
||||||
sortBase = bookmarkDao.selectMaxSort(node.getUserId(), path);
|
|
||||||
if (sortBase == null) {
|
|
||||||
sortBase = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String childPath = path + "." + node.getBookmarkId();
|
|
||||||
Elements children = ele.child(1).children();
|
|
||||||
for (int i = 0, size = children.size(); i < size; i++) {
|
|
||||||
dealBookmark(userId, children.get(i), childPath, sortBase + i + 1, insertList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description: 插入一条书签,如果已经存在同名书签将跳过
|
|
||||||
*
|
|
||||||
* @param node node
|
|
||||||
* @return boolean 如果已经存在返回true,否则false
|
|
||||||
* @author fanxb
|
|
||||||
* @date 2019/7/8 17:25
|
|
||||||
*/
|
|
||||||
private boolean insertOne(Bookmark node) {
|
|
||||||
//先根据name,userId,parentId获取此节点id
|
|
||||||
Integer id = bookmarkDao.selectIdByUserIdAndNameAndPath(node.getUserId(), node.getName(), node.getPath());
|
|
||||||
if (id == null) {
|
|
||||||
bookmarkDao.insertOne(node);
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
node.setBookmarkId(id);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 功能描述: 获取某个用户的书签map
|
|
||||||
*
|
|
||||||
* @param userId userId
|
|
||||||
* @return java.util.Map<java.lang.String, java.util.List < com.fanxb.bookmark.common.entity.Bookmark>>
|
|
||||||
* @author fanxb
|
|
||||||
* @date 2019/12/14 0:02
|
|
||||||
*/
|
|
||||||
public Map<String, List<Bookmark>> getOneBookmarkTree(int userId) {
|
|
||||||
List<Bookmark> list = bookmarkDao.getListByUserId(userId);
|
|
||||||
Map<String, List<Bookmark>> map = new HashMap<>(50);
|
|
||||||
list.forEach(item -> {
|
|
||||||
map.computeIfAbsent(item.getPath(), k -> new ArrayList<>());
|
|
||||||
map.get(item.getPath()).add(item);
|
|
||||||
});
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description: 根据userId和path获取书签列表
|
* Description: 根据userId和path获取书签列表
|
||||||
*
|
*
|
||||||
* @param userId userId
|
* @param userId userId
|
||||||
* @param path path
|
* @param path path
|
||||||
* @return java.util.List<com.fanxb.bookmark.common.entity.Bookmark>
|
* @return java.util.List<com.fanxb.bookmark.common.entity.po.Bookmark>
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/15 13:40
|
* @date 2019/7/15 13:40
|
||||||
*/
|
*/
|
||||||
public List<Bookmark> getBookmarkListByPath(int userId, String path) {
|
List<Bookmark> getBookmarkListByPath(int userId, String path);
|
||||||
return bookmarkDao.getListByUserIdAndPath(userId, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description: 批量删除书签
|
* 功能描述: 获取某个用户的书签map
|
||||||
*
|
*
|
||||||
* @param userId 用户id
|
* @param userId userId
|
||||||
* @param folderIdList 书签文件夹id list
|
* @return java.util.Map<java.lang.String, java.util.List < com.fanxb.bookmark.common.entity.po.Bookmark>>
|
||||||
* @param bookmarkIdList 书签id list
|
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/12 14:09
|
* @date 2019/12/14 0:02
|
||||||
*/
|
*/
|
||||||
@Transactional(rollbackFor = Exception.class)
|
Map<String, List<Bookmark>> getOneBookmarkTree(int userId);
|
||||||
public void batchDelete(int userId, List<Integer> folderIdList, List<Integer> bookmarkIdList) {
|
|
||||||
Set<Integer> set = new HashSet<>();
|
/**
|
||||||
for (Integer item : folderIdList) {
|
* Description: 解析书签文件
|
||||||
set.addAll(bookmarkDao.getChildrenBookmarkId(userId, item));
|
*
|
||||||
bookmarkDao.deleteUserFolder(userId, item);
|
* @param stream 输入流
|
||||||
bookmarkIdList.add(item);
|
* @param path 存放路径
|
||||||
}
|
* @param userId userId
|
||||||
if (bookmarkIdList.size() > 0) {
|
* @throws Exception 各种异常
|
||||||
bookmarkDao.deleteUserBookmark(userId, bookmarkIdList);
|
* @author fanxb
|
||||||
}
|
* @date 2019/7/9 18:44
|
||||||
set.addAll(bookmarkIdList);
|
*/
|
||||||
redisTemplate.opsForList().leftPush(RedisConstant.BOOKMARK_UPDATE_TIME, new UserBookmarkUpdate(userId, System.currentTimeMillis()).toString());
|
void parseBookmarkFile(int userId, MultipartFile file, String path) throws Exception;
|
||||||
//es 中批量删除
|
|
||||||
esUtil.deleteBatch(EsConstant.BOOKMARK_INDEX, set);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description: 详情
|
* Description: 详情
|
||||||
*
|
*
|
||||||
* @param bookmark 插入一条记录
|
* @param bookmark 插入一条记录
|
||||||
* @return com.fanxb.bookmark.common.entity.Bookmark
|
* @return com.fanxb.bookmark.common.entity.po.Bookmark
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/12 17:18
|
* @date 2019/7/12 17:18
|
||||||
*/
|
*/
|
||||||
@Transactional(rollbackFor = Exception.class)
|
Bookmark addOne(Bookmark bookmark);
|
||||||
public Bookmark addOne(Bookmark bookmark) {
|
|
||||||
int userId = UserContextHolder.get().getUserId();
|
|
||||||
Integer sort = bookmarkDao.selectMaxSort(userId, bookmark.getPath());
|
|
||||||
bookmark.setSort(sort == null ? 1 : sort + 1);
|
|
||||||
bookmark.setUserId(userId);
|
|
||||||
bookmark.setCreateTime(System.currentTimeMillis());
|
|
||||||
bookmark.setAddTime(bookmark.getCreateTime());
|
|
||||||
try {
|
|
||||||
bookmarkDao.insertOne(bookmark);
|
|
||||||
} catch (DuplicateKeyException e) {
|
|
||||||
throw new FormDataException("同级目录下不能存在相同名称的数据");
|
|
||||||
}
|
|
||||||
//如果是书签,插入到es中
|
|
||||||
if (bookmark.getType() == 0) {
|
|
||||||
esUtil.insertOrUpdateOne(EsConstant.BOOKMARK_INDEX,
|
|
||||||
new EsEntity<>(bookmark.getBookmarkId().toString(), new BookmarkEs(bookmark)));
|
|
||||||
}
|
|
||||||
redisTemplate.opsForList().leftPush(RedisConstant.BOOKMARK_UPDATE_TIME, new UserBookmarkUpdate(userId, System.currentTimeMillis()).toString());
|
|
||||||
return bookmark;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description: 编辑某个用户的某个书签
|
* Description: 编辑某个用户的某个书签
|
||||||
*
|
*
|
||||||
* @param userId userId
|
* @param userId userId
|
||||||
* @param bookmark bookmark
|
* @param bookmark bookmark
|
||||||
|
* @return 更新后的icon
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/17 14:42
|
* @date 2019/7/17 14:42
|
||||||
*/
|
*/
|
||||||
@Transactional(rollbackFor = Exception.class)
|
String updateOne(int userId, Bookmark bookmark);
|
||||||
public void updateOne(int userId, Bookmark bookmark) {
|
|
||||||
bookmark.setUserId(userId);
|
|
||||||
bookmarkDao.editBookmark(bookmark);
|
|
||||||
if (bookmark.getType() == 0) {
|
|
||||||
esUtil.insertOrUpdateOne(EsConstant.BOOKMARK_INDEX,
|
|
||||||
new EsEntity<>(bookmark.getBookmarkId().toString(), new BookmarkEs(bookmark)));
|
|
||||||
}
|
|
||||||
redisTemplate.opsForList().leftPush(RedisConstant.BOOKMARK_UPDATE_TIME, new UserBookmarkUpdate(userId, System.currentTimeMillis()).toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 批量删除书签
|
||||||
|
*
|
||||||
|
* @param userId 用户id
|
||||||
|
* @param pathList 要删除的路径list
|
||||||
|
* @param bookmarkIdList 书签id list
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2019/7/12 14:09
|
||||||
|
*/
|
||||||
|
void batchDelete(int userId, List<String> pathList, List<Integer> bookmarkIdList);
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
/**
|
||||||
public void moveNode(int userId, MoveNodeBody body) {
|
* 功能描述: 移动一个节点
|
||||||
if (body.getSort() == -1) {
|
*
|
||||||
Integer max = bookmarkDao.selectMaxSort(userId, body.getTargetPath());
|
* @param userId userId
|
||||||
body.setSort(max == null ? 1 : max);
|
* @param body body
|
||||||
} else {
|
* @author 123
|
||||||
//更新目标节点的sort
|
* @date 2020/3/29 12:30
|
||||||
bookmarkDao.sortPlus(userId, body.getTargetPath(), body.getSort());
|
*/
|
||||||
}
|
void moveNode(int userId, MoveNodeBody body);
|
||||||
//如果目标位置和当前位置不在一个层级中需要更新子节点的path
|
|
||||||
if (!body.getTargetPath().equals(body.getSourcePath())) {
|
|
||||||
bookmarkDao.updateChildrenPath(userId, body.getSourcePath() + "." + body.getBookmarkId()
|
|
||||||
, body.getTargetPath() + "." + body.getBookmarkId());
|
|
||||||
}
|
|
||||||
//更新被移动节点的path和sort
|
|
||||||
bookmarkDao.updatePathAndSort(userId, body.getBookmarkId(), body.getTargetPath(), body.getSort());
|
|
||||||
redisTemplate.opsForList().leftPush(RedisConstant.BOOKMARK_UPDATE_TIME, new UserBookmarkUpdate(userId, System.currentTimeMillis()).toString());
|
|
||||||
log.info("{},从{}移动到{},sort:{}", userId, body.getSourcePath(), body.getTargetPath(), body.getSort());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description: 根据context搜索
|
* Description: 根据context搜索
|
||||||
*
|
*
|
||||||
* @param userId userId
|
* @param userId userId
|
||||||
* @param context context
|
* @param context context
|
||||||
|
* @return es搜索结果
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/25 10:45
|
* @date 2019/7/25 10:45
|
||||||
*/
|
*/
|
||||||
public List<BookmarkEs> searchUserBookmark(int userId, String context) {
|
List<BookmarkEs> searchUserBookmark(int userId, String context);
|
||||||
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
|
|
||||||
boolQueryBuilder.must(QueryBuilders.termQuery("userId", userId));
|
|
||||||
boolQueryBuilder.must(QueryBuilders.multiMatchQuery(context, "name", "url"));
|
|
||||||
SearchSourceBuilder builder = new SearchSourceBuilder();
|
|
||||||
builder.size(5);
|
|
||||||
builder.query(boolQueryBuilder);
|
|
||||||
return esUtil.search(EsConstant.BOOKMARK_INDEX, builder, BookmarkEs.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description: 将某个用户的书签数据mysql同步到es中
|
* 功能描述: 当前用户书签访问次数+1
|
||||||
*
|
*
|
||||||
|
* @param id 书签id
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/26 11:27
|
* @date 2020/5/12 10:21
|
||||||
*/
|
*/
|
||||||
public void syncUserBookmark(int userId) {
|
void visitNumPlus(int id);
|
||||||
//删除旧的数据
|
|
||||||
esUtil.deleteByQuery(EsConstant.BOOKMARK_INDEX, new TermQueryBuilder("userId", userId));
|
|
||||||
int index = 0;
|
|
||||||
int size = 500;
|
|
||||||
List<EsEntity> res = new ArrayList<>();
|
|
||||||
do {
|
|
||||||
res.clear();
|
|
||||||
bookmarkDao.selectBookmarkEsByUserIdAndType(userId, 0, index, size)
|
|
||||||
.forEach(item -> res.add(new EsEntity<>(item.getBookmarkId().toString(), item)));
|
|
||||||
if (res.size() > 0) {
|
|
||||||
esUtil.insertBatch(EsConstant.BOOKMARK_INDEX, res);
|
|
||||||
}
|
|
||||||
index += size;
|
|
||||||
} while (res.size() == 500);
|
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* 功能描述: 获取用户访问次数前num的书签数据
|
||||||
|
*
|
||||||
|
* @param num 获取条数
|
||||||
|
* @return java.util.List<com.fanxb.bookmark.common.entity.po.Bookmark>
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2020/8/26 15:54
|
||||||
|
*/
|
||||||
|
List<Bookmark> userPopular(int num);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新某个用户的icon数据
|
||||||
|
*
|
||||||
|
* @param userId 用户id
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/11
|
||||||
|
**/
|
||||||
|
void updateUserBookmarkIcon(int userId);
|
||||||
|
|
||||||
|
/***
|
||||||
|
* 检查无父节点的数据
|
||||||
|
* @author fanxb
|
||||||
|
* @param delete 是否删除数据
|
||||||
|
* @param userId 用户id
|
||||||
|
* @return java.util.List<java.lang.String>
|
||||||
|
* @date 2021/3/17
|
||||||
|
**/
|
||||||
|
Set<String> dealBadBookmark(boolean delete, int userId);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
package com.fanxb.bookmark.business.bookmark.service;
|
||||||
|
|
||||||
|
import com.fanxb.bookmark.business.bookmark.entity.po.PInBookmarkPo;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.entity.vo.HomePinItemVo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首页相关的书签接口
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
public interface HomePinService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取固定的标签
|
||||||
|
*
|
||||||
|
* @return {@link List<HomePinItemVo>}
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
List<HomePinItemVo> getHomePinList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增一个
|
||||||
|
*
|
||||||
|
* @return {@link HomePinItemVo}
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
PInBookmarkPo addOne(PInBookmarkPo po);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除一个
|
||||||
|
*
|
||||||
|
* @param id id
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
void delete(int id);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
package com.fanxb.bookmark.business.bookmark.service;
|
||||||
|
|
||||||
|
import com.fanxb.bookmark.common.entity.po.Bookmark;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created with IntelliJ IDEA
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* Date: 2020/3/18
|
||||||
|
* Time: 23:47
|
||||||
|
*/
|
||||||
|
public interface PinYinService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分隔符
|
||||||
|
*/
|
||||||
|
String PARTITION = "||";
|
||||||
|
/**
|
||||||
|
* 拼音接口路径
|
||||||
|
*/
|
||||||
|
String PATH = "/pinyinChange";
|
||||||
|
/**
|
||||||
|
* 分页查询页大小
|
||||||
|
*/
|
||||||
|
int SIZE = 500;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能描述: 首次上线用于全量初始化
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2020/3/22 21:40
|
||||||
|
*/
|
||||||
|
void changeAll();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理bookmark searchKey
|
||||||
|
*
|
||||||
|
* @param bookmark 处理单个
|
||||||
|
* @return java.util.List<com.fanxb.bookmark.common.entity.po.Bookmark>
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/13
|
||||||
|
**/
|
||||||
|
Bookmark changeBookmark(Bookmark bookmark);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理bookmarks searchKey
|
||||||
|
*
|
||||||
|
* @param bookmarks 待处理舒淇啊你列表
|
||||||
|
* @return java.util.List<com.fanxb.bookmark.common.entity.po.Bookmark>
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/13
|
||||||
|
**/
|
||||||
|
List<Bookmark> changeBookmarks(List<Bookmark> bookmarks);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能描述:返回用于前端搜索的key
|
||||||
|
*
|
||||||
|
* @param stringList 待拼音化的字符串
|
||||||
|
* @return java.util.List<java.lang.String>
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2020/3/22 21:38
|
||||||
|
*/
|
||||||
|
List<String> changeStrings(List<String> stringList);
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.fanxb.bookmark.business.bookmark.service.impl;
|
||||||
|
|
||||||
|
import com.fanxb.bookmark.business.api.BookmarkApi;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.service.BookmarkService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bookmark模块api暴露
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/13
|
||||||
|
**/
|
||||||
|
@Service
|
||||||
|
public class BookmarkApiImpl implements BookmarkApi {
|
||||||
|
private final BookmarkService bookmarkService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public BookmarkApiImpl(BookmarkService bookmarkService) {
|
||||||
|
this.bookmarkService = bookmarkService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateUserBookmarkIcon(int userId) {
|
||||||
|
bookmarkService.updateUserBookmarkIcon(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> dealBadBookmark(boolean delete, int userId) {
|
||||||
|
return bookmarkService.dealBadBookmark(delete, userId);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
package com.fanxb.bookmark.business.bookmark.service.impl;
|
||||||
|
|
||||||
|
import com.fanxb.bookmark.business.bookmark.dao.BookmarkDao;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.entity.BookmarkEs;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.service.BookmarkBackupService;
|
||||||
|
import com.fanxb.bookmark.common.constant.EsConstant;
|
||||||
|
import com.fanxb.bookmark.common.entity.po.Bookmark;
|
||||||
|
import com.fanxb.bookmark.common.entity.EsEntity;
|
||||||
|
import com.fanxb.bookmark.common.util.EsUtil;
|
||||||
|
import org.elasticsearch.index.query.TermQueryBuilder;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created with IntelliJ IDEA
|
||||||
|
* Created By Fxb
|
||||||
|
* Date: 2019/11/12
|
||||||
|
* Time: 0:22
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class BookmarkBackupServiceImpl implements BookmarkBackupService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private BookmarkDao bookmarkDao;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private EsUtil esUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一次同步BACKUP_SIZE条到es中
|
||||||
|
*/
|
||||||
|
private static final int BACKUP_SIZE = 500;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void backupToEs() {
|
||||||
|
int start = 0;
|
||||||
|
List<Bookmark> list;
|
||||||
|
while ((list = bookmarkDao.getBookmarkListPage(BACKUP_SIZE, start)).size() != 0) {
|
||||||
|
List<EsEntity<BookmarkEs>> batchList = new ArrayList<>(list.size());
|
||||||
|
list.forEach(item -> batchList.add(new EsEntity<>(item.getBookmarkId().toString(), new BookmarkEs(item))));
|
||||||
|
esUtil.insertBatch(EsConstant.BOOKMARK_INDEX, batchList);
|
||||||
|
start += BACKUP_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void syncUserBookmark(int userId) {
|
||||||
|
//删除旧的数据
|
||||||
|
esUtil.deleteByQuery(EsConstant.BOOKMARK_INDEX, new TermQueryBuilder("userId", userId));
|
||||||
|
int index = 0;
|
||||||
|
int size = 500;
|
||||||
|
List<EsEntity<BookmarkEs>> res = new ArrayList<>();
|
||||||
|
do {
|
||||||
|
res.clear();
|
||||||
|
bookmarkDao.selectBookmarkEsByUserIdAndType(userId, 0, index, size)
|
||||||
|
.forEach(item -> res.add(new EsEntity<>(item.getBookmarkId().toString(), item)));
|
||||||
|
if (res.size() > 0) {
|
||||||
|
esUtil.insertBatch(EsConstant.BOOKMARK_INDEX, res);
|
||||||
|
}
|
||||||
|
index += size;
|
||||||
|
} while (res.size() == 500);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,503 @@
|
|||||||
|
package com.fanxb.bookmark.business.bookmark.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.codec.Base64Decoder;
|
||||||
|
import cn.hutool.core.io.FileUtil;
|
||||||
|
import cn.hutool.core.util.*;
|
||||||
|
import cn.hutool.core.util.HashUtil;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.fanxb.bookmark.business.api.UserApi;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.constant.FileConstant;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.dao.BookmarkDao;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.dao.HostIconDao;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.entity.BookmarkEs;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.entity.MoveNodeBody;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.entity.redis.BookmarkDeleteMessage;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.entity.redis.VisitNumPlus;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.service.BookmarkService;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.service.PinYinService;
|
||||||
|
import com.fanxb.bookmark.common.constant.CommonConstant;
|
||||||
|
import com.fanxb.bookmark.common.constant.EsConstant;
|
||||||
|
import com.fanxb.bookmark.common.constant.RedisConstant;
|
||||||
|
import com.fanxb.bookmark.common.entity.po.Bookmark;
|
||||||
|
import com.fanxb.bookmark.common.exception.CustomException;
|
||||||
|
import com.fanxb.bookmark.common.util.*;
|
||||||
|
import com.mysql.cj.conf.url.SingleConnectionUrl;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import org.elasticsearch.index.query.BoolQueryBuilder;
|
||||||
|
import org.elasticsearch.index.query.QueryBuilders;
|
||||||
|
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||||
|
import org.jsoup.Jsoup;
|
||||||
|
import org.jsoup.nodes.Document;
|
||||||
|
import org.jsoup.nodes.Element;
|
||||||
|
import org.jsoup.select.Elements;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.awt.print.Book;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.SocketTimeoutException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类功能简述:
|
||||||
|
* 类功能详述:
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class BookmarkServiceImpl implements BookmarkService {
|
||||||
|
@Value("${urlIconAddress}")
|
||||||
|
private String urlIconAddress;
|
||||||
|
|
||||||
|
private final BookmarkDao bookmarkDao;
|
||||||
|
private final PinYinService pinYinService;
|
||||||
|
private final UserApi userApi;
|
||||||
|
private final EsUtil esUtil;
|
||||||
|
private final HostIconDao hostIconDao;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public BookmarkServiceImpl(BookmarkDao bookmarkDao, PinYinService pinYinService, UserApi userApi, EsUtil esUtil, HostIconDao hostIconDao) {
|
||||||
|
this.bookmarkDao = bookmarkDao;
|
||||||
|
this.pinYinService = pinYinService;
|
||||||
|
this.userApi = userApi;
|
||||||
|
this.esUtil = esUtil;
|
||||||
|
this.hostIconDao = hostIconDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void parseBookmarkFile(int userId, MultipartFile file, String path) throws Exception {
|
||||||
|
List<Bookmark> bookmarks = new ArrayList<>();
|
||||||
|
//获取当前层sort最大值
|
||||||
|
Integer sortBase = bookmarkDao.selectMaxSort(userId, path);
|
||||||
|
if (sortBase == null) {
|
||||||
|
sortBase = 0;
|
||||||
|
}
|
||||||
|
if (file.getOriginalFilename().endsWith(".db3")) {
|
||||||
|
//处理db文件
|
||||||
|
readFromOneEnv(bookmarks, userId, file, path, sortBase);
|
||||||
|
} else {
|
||||||
|
InputStream stream = file.getInputStream();
|
||||||
|
Document doc = Jsoup.parse(stream, "utf-8", "");
|
||||||
|
Elements elements = doc.select("html>body>dl>dt");
|
||||||
|
for (int i = 0, length = elements.size(); i < length; i++) {
|
||||||
|
dealBookmark(userId, elements.get(i), path, sortBase + i, bookmarks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//每一千条处理插入一次,批量更新搜索字段
|
||||||
|
List<Bookmark> tempList = new ArrayList<>(1000);
|
||||||
|
for (int i = 0; i < bookmarks.size(); i++) {
|
||||||
|
tempList.add(bookmarks.get(i));
|
||||||
|
if (tempList.size() == 1000 || i == bookmarks.size() - 1) {
|
||||||
|
tempList = pinYinService.changeBookmarks(tempList);
|
||||||
|
bookmarkDao.updateSearchKeyBatch(tempList);
|
||||||
|
tempList.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
userApi.versionPlus(userId);
|
||||||
|
|
||||||
|
//异步更新icon
|
||||||
|
ThreadPoolUtil.execute(() -> {
|
||||||
|
updateUserBookmarkIcon(userId);
|
||||||
|
userApi.versionPlus(userId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 处理html节点,解析出文件夹和书签
|
||||||
|
*
|
||||||
|
* @param ele 待处理节点
|
||||||
|
* @param path 节点路径,不包含自身
|
||||||
|
* @param sort 当前层级中的排序序号
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
private void dealBookmark(int userId, Element ele, String path, int sort, List<Bookmark> bookmarks) {
|
||||||
|
if (!DT.equalsIgnoreCase(ele.tagName())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Element first = ele.child(0);
|
||||||
|
if (A.equalsIgnoreCase(first.tagName())) {
|
||||||
|
//说明为链接
|
||||||
|
Bookmark node = new Bookmark(userId, path, first.ownText(), first.attr("href"), ""
|
||||||
|
, Long.parseLong(first.attr("add_date")) * 1000, sort);
|
||||||
|
//存入数据库
|
||||||
|
insertOne(node);
|
||||||
|
bookmarks.add(node);
|
||||||
|
} else {
|
||||||
|
//说明为文件夹
|
||||||
|
Bookmark node = new Bookmark(userId, path, first.ownText(), Long.parseLong(first.attr("add_date")) * 1000, sort);
|
||||||
|
Integer sortBase = 0;
|
||||||
|
//同名文件夹将会合并
|
||||||
|
if (insertOne(node)) {
|
||||||
|
sortBase = bookmarkDao.selectMaxSort(node.getUserId(), path);
|
||||||
|
if (sortBase == null) {
|
||||||
|
sortBase = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String childPath = path + "." + node.getBookmarkId();
|
||||||
|
Elements children = ele.child(1).children();
|
||||||
|
for (int i = 0, size = children.size(); i < size; i++) {
|
||||||
|
dealBookmark(userId, children.get(i), childPath, sortBase + i + 1, bookmarks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理oneenv的导出
|
||||||
|
*
|
||||||
|
* @param bookmarks 书签列表
|
||||||
|
* @param userId 用户id
|
||||||
|
* @param file file
|
||||||
|
* @param path path
|
||||||
|
* @param sort sort
|
||||||
|
*/
|
||||||
|
private void readFromOneEnv(List<Bookmark> bookmarks, int userId, MultipartFile file, String path, int sort) {
|
||||||
|
String filePath = CommonConstant.fileSavePath + "/files/" + IdUtil.simpleUUID() + ".db3";
|
||||||
|
try {
|
||||||
|
file.transferTo(FileUtil.newFile(filePath));
|
||||||
|
try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + filePath)) {
|
||||||
|
Statement stat = conn.createStatement();
|
||||||
|
ResultSet rs = stat.executeQuery("select * from on_categorys");
|
||||||
|
Map<Long, Bookmark> folderMap = new HashMap<>();
|
||||||
|
Map<Long, Integer> childSortBaseMap = new HashMap<>();
|
||||||
|
while (rs.next()) {
|
||||||
|
long addTime = rs.getLong("add_time");
|
||||||
|
Bookmark folder = new Bookmark(userId, path, StrUtil.nullToEmpty(rs.getString("name")), addTime == 0 ? System.currentTimeMillis() : addTime * 1000, sort++);
|
||||||
|
int childSortBase = 0;
|
||||||
|
if (insertOne(folder)) {
|
||||||
|
childSortBase = ObjectUtil.defaultIfNull(bookmarkDao.selectMaxSort(userId, path), 0);
|
||||||
|
}
|
||||||
|
long id = rs.getLong("id");
|
||||||
|
folderMap.put(id, folder);
|
||||||
|
childSortBaseMap.put(id, childSortBase);
|
||||||
|
}
|
||||||
|
rs.close();
|
||||||
|
rs = stat.executeQuery("select * from on_links");
|
||||||
|
while (rs.next()) {
|
||||||
|
long fId = rs.getLong("fid");
|
||||||
|
long addTime = rs.getLong("add_time");
|
||||||
|
int tempSort = childSortBaseMap.get(fId);
|
||||||
|
childSortBaseMap.put(fId, tempSort + 1);
|
||||||
|
Bookmark folder = folderMap.get(fId);
|
||||||
|
String curPath = folder == null ? "" : folder.getPath() + "." + folder.getBookmarkId();
|
||||||
|
Bookmark bookmark = new Bookmark(userId, curPath, StrUtil.nullToEmpty(rs.getString("title"))
|
||||||
|
, StrUtil.nullToEmpty(rs.getString("url")), "", addTime == 0 ? System.currentTimeMillis() : addTime * 1000, tempSort);
|
||||||
|
bookmarks.add(bookmark);
|
||||||
|
insertOne(bookmark);
|
||||||
|
}
|
||||||
|
rs.close();
|
||||||
|
stat.close();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 插入一条书签,如果已经存在同名书签将跳过
|
||||||
|
*
|
||||||
|
* @param node node
|
||||||
|
* @return boolean 如果已经存在返回true,否则false
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
private boolean insertOne(Bookmark node) {
|
||||||
|
//先根据name,userId,parentId获取此节点id
|
||||||
|
Integer id = bookmarkDao.selectIdByUserIdAndNameAndPath(node.getUserId(), node.getName(), node.getPath());
|
||||||
|
if (id == null) {
|
||||||
|
bookmarkDao.insertOne(node);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
node.setBookmarkId(id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, List<Bookmark>> getOneBookmarkTree(int userId) {
|
||||||
|
List<Bookmark> list = bookmarkDao.getListByUserId(userId);
|
||||||
|
Map<String, List<Bookmark>> map = new HashMap<>(50);
|
||||||
|
list.forEach(item -> {
|
||||||
|
map.computeIfAbsent(item.getPath(), k -> new ArrayList<>());
|
||||||
|
map.get(item.getPath()).add(item);
|
||||||
|
});
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Bookmark> getBookmarkListByPath(int userId, String path) {
|
||||||
|
return bookmarkDao.getListByUserIdAndPath(userId, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void batchDelete(int userId, List<String> pathList, List<Integer> bookmarkIdList) {
|
||||||
|
//所有要删除的书签id
|
||||||
|
Set<String> set = new HashSet<>();
|
||||||
|
for (String path : pathList) {
|
||||||
|
Integer id = Integer.parseInt(ArrayUtil.reverse(path.split("\\."))[0]);
|
||||||
|
set.addAll(bookmarkDao.getChildrenBookmarkId(userId, path).stream().map(String::valueOf).collect(Collectors.toSet()));
|
||||||
|
//删除此文件夹所有的子节点
|
||||||
|
bookmarkDao.deleteUserFolder(userId, path);
|
||||||
|
bookmarkIdList.add(id);
|
||||||
|
}
|
||||||
|
if (bookmarkIdList.size() > 0) {
|
||||||
|
bookmarkDao.deleteUserBookmark(userId, bookmarkIdList);
|
||||||
|
set.addAll(bookmarkIdList.stream().map(String::valueOf).collect(Collectors.toSet()));
|
||||||
|
}
|
||||||
|
RedisUtil.addToMq(RedisConstant.BOOKMARK_DELETE_ES, new BookmarkDeleteMessage(userId, set));
|
||||||
|
userApi.versionPlus(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Bookmark addOne(Bookmark bookmark) {
|
||||||
|
int userId = UserContextHolder.get().getUserId();
|
||||||
|
Integer sort = bookmarkDao.selectMaxSort(userId, bookmark.getPath());
|
||||||
|
bookmark.setSort(sort == null ? 1 : sort + 1);
|
||||||
|
bookmark.setUserId(userId);
|
||||||
|
bookmark.setCreateTime(System.currentTimeMillis());
|
||||||
|
bookmark.setAddTime(bookmark.getCreateTime());
|
||||||
|
bookmark.setIcon(bookmark.getType() == 1 ? "" : getIconPath(bookmark.getUrl(), bookmark.getIcon(), bookmark.getIconUrl(), true));
|
||||||
|
//文件夹和书签都建立搜索key
|
||||||
|
pinYinService.changeBookmark(bookmark);
|
||||||
|
bookmarkDao.insertOne(bookmark);
|
||||||
|
userApi.versionPlus(userId);
|
||||||
|
if (StrUtil.isEmpty(bookmark.getIcon()) && bookmark.getType() == 0) {
|
||||||
|
updateIconAsync(bookmark.getBookmarkId(), bookmark.getUrl(), userId);
|
||||||
|
}
|
||||||
|
return bookmark;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public String updateOne(int userId, Bookmark bookmark) {
|
||||||
|
bookmark.setUserId(userId);
|
||||||
|
if (bookmark.getType() == 0) {
|
||||||
|
pinYinService.changeBookmark(bookmark);
|
||||||
|
bookmark.setIcon(getIconPath(bookmark.getUrl(), null, null, true));
|
||||||
|
if (StrUtil.isEmpty(bookmark.getIcon())) {
|
||||||
|
updateIconAsync(bookmark.getBookmarkId(), bookmark.getUrl(), userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bookmarkDao.editBookmark(bookmark);
|
||||||
|
userApi.versionPlus(userId);
|
||||||
|
return bookmark.getIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步更新书签icon
|
||||||
|
*
|
||||||
|
* @param id 书签id
|
||||||
|
* @param url 书签url
|
||||||
|
* @param userId userId
|
||||||
|
*/
|
||||||
|
private void updateIconAsync(int id, String url, int userId) {
|
||||||
|
ThreadPoolUtil.execute(() -> {
|
||||||
|
String icon = getIconPath(url, null, null, false);
|
||||||
|
if (StrUtil.isEmpty(icon)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bookmarkDao.updateIcon(id, icon);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void moveNode(int userId, MoveNodeBody body) {
|
||||||
|
if (body.getSort() == -1) {
|
||||||
|
Integer max = bookmarkDao.selectMaxSort(userId, body.getTargetPath());
|
||||||
|
body.setSort(max == null ? 1 : max);
|
||||||
|
} else {
|
||||||
|
//更新目标节点的sort
|
||||||
|
bookmarkDao.sortPlus(userId, body.getTargetPath(), body.getSort());
|
||||||
|
}
|
||||||
|
//如果目标位置和当前位置不在一个层级中需要更新子节点的path
|
||||||
|
if (!body.getTargetPath().equals(body.getSourcePath())) {
|
||||||
|
bookmarkDao.updateChildrenPath(userId, body.getSourcePath() + "." + body.getBookmarkId()
|
||||||
|
, body.getTargetPath() + "." + body.getBookmarkId());
|
||||||
|
}
|
||||||
|
//更新被移动节点的path和sort
|
||||||
|
bookmarkDao.updatePathAndSort(userId, body.getBookmarkId(), body.getTargetPath(), body.getSort());
|
||||||
|
userApi.versionPlus(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BookmarkEs> searchUserBookmark(int userId, String context) {
|
||||||
|
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
|
||||||
|
boolQueryBuilder.must(QueryBuilders.termQuery("userId", userId));
|
||||||
|
boolQueryBuilder.must(QueryBuilders.multiMatchQuery(context, "name", "url"));
|
||||||
|
SearchSourceBuilder builder = new SearchSourceBuilder();
|
||||||
|
builder.size(5);
|
||||||
|
builder.query(boolQueryBuilder);
|
||||||
|
return esUtil.search(EsConstant.BOOKMARK_INDEX, builder, BookmarkEs.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitNumPlus(int id) {
|
||||||
|
VisitNumPlus item = new VisitNumPlus(UserContextHolder.get().getUserId(), id);
|
||||||
|
RedisUtil.addToMq(RedisConstant.BOOKMARK_VISIT_NUM_PLUS, JSON.toJSONString(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Bookmark> userPopular(int num) {
|
||||||
|
return bookmarkDao.selectPopular(UserContextHolder.get().getUserId(), num);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateUserBookmarkIcon(int userId) {
|
||||||
|
log.info("开始更新:{}", userId);
|
||||||
|
int size = 100;
|
||||||
|
int start = 0;
|
||||||
|
List<Bookmark> deal;
|
||||||
|
while (!(deal = bookmarkDao.selectUserNoIcon(userId, start, size)).isEmpty()) {
|
||||||
|
start += size;
|
||||||
|
deal.forEach(item -> {
|
||||||
|
String icon = getIconPath(item.getUrl(), null, null, false);
|
||||||
|
if (StrUtil.isNotEmpty(icon)) {
|
||||||
|
bookmarkDao.updateIcon(item.getBookmarkId(), icon);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
userApi.versionPlus(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> dealBadBookmark(boolean delete, int userId) {
|
||||||
|
List<Bookmark> bookmarks = bookmarkDao.selectBookmarkIdPathByUserId(userId);
|
||||||
|
Set<Integer> idSet = new HashSet<>(bookmarks.size());
|
||||||
|
bookmarks.forEach(item -> idSet.add(item.getBookmarkId()));
|
||||||
|
Set<String> resPath = new HashSet<>();
|
||||||
|
bookmarks.forEach(item -> {
|
||||||
|
if (StrUtil.isEmpty(item.getPath())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String parentId = item.getPath().substring(item.getPath().lastIndexOf(".") + 1);
|
||||||
|
if (!idSet.contains(Integer.valueOf(parentId))) {
|
||||||
|
resPath.add(item.getPath());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (delete && resPath.size() > 0) {
|
||||||
|
resPath.forEach(item -> bookmarkDao.deleteUserFolder(userId, item));
|
||||||
|
userApi.versionPlus(userId);
|
||||||
|
}
|
||||||
|
return resPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取icon,通过网络获取,或者从base64还原
|
||||||
|
*
|
||||||
|
* @param url 书签url路径
|
||||||
|
* @param icon base64编码的icon
|
||||||
|
* @param iconUrl base64编码的文件,文件名,用于获取文件名后缀
|
||||||
|
* @param quick 是否快速获取
|
||||||
|
* @return {@link String}
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
private String getIconPath(String url, String icon, String iconUrl, boolean quick) {
|
||||||
|
String host;
|
||||||
|
try {
|
||||||
|
URL urlObj = new URL(url);
|
||||||
|
host = urlObj.getAuthority();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("url无法解析出domain:{}", url);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (StrUtil.isNotBlank(icon)) {
|
||||||
|
//优先从base64还原出图片
|
||||||
|
try {
|
||||||
|
byte[] b = Base64Decoder.decode(icon.substring(icon.indexOf(",") + 1));
|
||||||
|
String iconPath = saveToFile(iconUrl, host, b);
|
||||||
|
hostIconDao.deleteByHost(host);
|
||||||
|
hostIconDao.insert(host, iconPath);
|
||||||
|
return iconPath;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("解析base64获取icon故障:{}", iconUrl, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String iconPath = hostIconDao.selectByHost(host);
|
||||||
|
if (iconPath != null) {
|
||||||
|
return iconPath;
|
||||||
|
}
|
||||||
|
//再根据url解析
|
||||||
|
iconPath = saveFile(host, urlIconAddress + "/icon?url=" + host + "&size=16..128..256", quick);
|
||||||
|
if (StrUtil.isNotEmpty(iconPath)) {
|
||||||
|
hostIconDao.insert(host, iconPath);
|
||||||
|
}
|
||||||
|
return iconPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存文件到icon路径
|
||||||
|
*
|
||||||
|
* @param host host
|
||||||
|
* @param url url
|
||||||
|
* @param quick 是否快速获取,快速获取超时时间1s
|
||||||
|
* @return {@link String}
|
||||||
|
* @author FleyX
|
||||||
|
*/
|
||||||
|
private String saveFile(String host, String url, boolean quick) {
|
||||||
|
try (Response res = (quick ? HttpUtil.getSHORT_CLIENT() : HttpUtil.getClient(false)).newCall(new Request.Builder().url(url)
|
||||||
|
.header("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36 Edg/100.0.1185.36")
|
||||||
|
.get().build()).execute()) {
|
||||||
|
assert res.body() != null;
|
||||||
|
if (!HttpUtil.checkIsOk(res.code())) {
|
||||||
|
throw new CustomException("请求错误:" + res.code());
|
||||||
|
}
|
||||||
|
byte[] data = res.body().byteStream().readAllBytes();
|
||||||
|
if (data.length > 0) {
|
||||||
|
String iconUrl = new URL(res.request().url().toString()).getPath();
|
||||||
|
return saveToFile(iconUrl, host, data);
|
||||||
|
} else {
|
||||||
|
log.info("未获取到icon:{}", url);
|
||||||
|
}
|
||||||
|
} catch (SocketTimeoutException timeoutException) {
|
||||||
|
log.info("获取icon超时:{}", host);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("url获取icon故障:{}", url, e);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存到文件中
|
||||||
|
*
|
||||||
|
* @param iconUrl icon文件名
|
||||||
|
* @param host host
|
||||||
|
* @param b 数据
|
||||||
|
* @return {@link String}
|
||||||
|
* @author FleyX
|
||||||
|
*/
|
||||||
|
private String saveToFile(String iconUrl, String host, byte[] b) {
|
||||||
|
String fileName = host.replace(":", ".") + iconUrl.substring(iconUrl.lastIndexOf("."));
|
||||||
|
String filePath = Paths.get(FileConstant.FAVICON_PATH, host.replace("www", "").replaceAll("\\.", "").substring(0, 2), fileName).toString();
|
||||||
|
FileUtil.writeBytes(b, Paths.get(CommonConstant.fileSavePath, filePath).toString());
|
||||||
|
return File.separator + filePath;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
package com.fanxb.bookmark.business.bookmark.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.dao.BookmarkDao;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.dao.PinBookmarkDao;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.entity.po.PInBookmarkPo;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.entity.vo.HomePinItemVo;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.service.BookmarkService;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.service.HomePinService;
|
||||||
|
import com.fanxb.bookmark.common.entity.UserContext;
|
||||||
|
import com.fanxb.bookmark.common.entity.po.Bookmark;
|
||||||
|
import com.fanxb.bookmark.common.exception.CustomException;
|
||||||
|
import com.fanxb.bookmark.common.util.UserContextHolder;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class HomePinServiceImpl implements HomePinService {
|
||||||
|
|
||||||
|
private final PinBookmarkDao pinBookmarkDao;
|
||||||
|
private final BookmarkDao bookmarkDao;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public HomePinServiceImpl(PinBookmarkDao pinBookmarkDao, BookmarkDao bookmarkDao) {
|
||||||
|
this.pinBookmarkDao = pinBookmarkDao;
|
||||||
|
this.bookmarkDao = bookmarkDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首页固定书签最大数量
|
||||||
|
*/
|
||||||
|
private static final int MAX_PIN = 20;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<HomePinItemVo> getHomePinList() {
|
||||||
|
List<HomePinItemVo> res = new ArrayList<>(MAX_PIN);
|
||||||
|
if (UserContextHolder.get() != null) {
|
||||||
|
res.addAll(pinBookmarkDao.selectUserPin(UserContextHolder.get().getUserId()));
|
||||||
|
if (res.size() < MAX_PIN - 1) {
|
||||||
|
//需要从取到的书签数据中排除已经固定到首页的数据
|
||||||
|
Set<Integer> existBookmark = res.stream().map(HomePinItemVo::getBookmarkId).collect(Collectors.toSet());
|
||||||
|
List<Bookmark> bookmarks = bookmarkDao.selectPopular(UserContextHolder.get().getUserId(), MAX_PIN - 1);
|
||||||
|
res.addAll(bookmarks.stream().filter(item -> !existBookmark.contains(item.getBookmarkId())).limit(MAX_PIN - res.size() - 1)
|
||||||
|
.map(item -> new HomePinItemVo(null, item.getBookmarkId(), item.getName(), item.getUrl(), item.getIcon())).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PInBookmarkPo addOne(PInBookmarkPo po) {
|
||||||
|
int userId = UserContextHolder.get().getUserId();
|
||||||
|
long count = pinBookmarkDao.selectCount(new QueryWrapper<PInBookmarkPo>().eq("userId", userId));
|
||||||
|
if (count > MAX_PIN) {
|
||||||
|
throw new CustomException("固定数量已超过最大限制:" + MAX_PIN);
|
||||||
|
}
|
||||||
|
po.setUserId(userId);
|
||||||
|
po.setCreateDate(System.currentTimeMillis());
|
||||||
|
po.setSort(pinBookmarkDao.getUserMaxSort(userId) + 1);
|
||||||
|
pinBookmarkDao.insert(po);
|
||||||
|
return po;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(int id) {
|
||||||
|
pinBookmarkDao.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
package com.fanxb.bookmark.business.bookmark.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
|
import com.fanxb.bookmark.business.api.UserApi;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.dao.BookmarkDao;
|
||||||
|
import com.fanxb.bookmark.business.bookmark.service.PinYinService;
|
||||||
|
import com.fanxb.bookmark.common.entity.po.Bookmark;
|
||||||
|
import com.fanxb.bookmark.common.exception.CustomException;
|
||||||
|
import com.fanxb.bookmark.common.util.UserContextHolder;
|
||||||
|
import com.github.houbb.pinyin.constant.enums.PinyinStyleEnum;
|
||||||
|
import com.github.houbb.pinyin.util.PinyinHelper;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created with IntelliJ IDEA
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* Date: 2020/3/18
|
||||||
|
* Time: 23:48
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class PinYinServiceImpl implements PinYinService {
|
||||||
|
|
||||||
|
|
||||||
|
private final BookmarkDao bookmarkDao;
|
||||||
|
private final UserApi userApi;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public PinYinServiceImpl(BookmarkDao bookmarkDao, UserApi userApi) {
|
||||||
|
this.bookmarkDao = bookmarkDao;
|
||||||
|
this.userApi = userApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void changeAll() {
|
||||||
|
if (!UserContextHolder.get().getManageUser()) {
|
||||||
|
throw new CustomException("非管理员用户,无法执行本操作");
|
||||||
|
}
|
||||||
|
int i = 0;
|
||||||
|
while (true) {
|
||||||
|
List<Bookmark> bookmarks = changeBookmarks(bookmarkDao.selectPinyinEmpty(i, SIZE));
|
||||||
|
if (bookmarks.size() > 0) {
|
||||||
|
bookmarkDao.updateSearchKeyBatch(bookmarks);
|
||||||
|
}
|
||||||
|
if (bookmarks.size() < SIZE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i = bookmarks.get(SIZE - 1).getBookmarkId();
|
||||||
|
}
|
||||||
|
//更新所有用户版本数据
|
||||||
|
userApi.allUserVersionPlus();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bookmark changeBookmark(Bookmark bookmark) {
|
||||||
|
return changeBookmarks(Collections.singletonList(bookmark)).get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Bookmark> changeBookmarks(List<Bookmark> bookmarks) {
|
||||||
|
List<String> resList = changeStrings(bookmarks.stream().map(Bookmark::getName).collect(Collectors.toList()));
|
||||||
|
for (int j = 0, size = bookmarks.size(); j < size; j++) {
|
||||||
|
Bookmark bookmark = bookmarks.get(j);
|
||||||
|
int length = bookmark.getUrl().length();
|
||||||
|
bookmark.setSearchKey(resList.get(j) + (length == 0 ? "" : (PARTITION + bookmark.getUrl().substring(0, Math.min(length, 50)))));
|
||||||
|
}
|
||||||
|
return bookmarks;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> changeStrings(List<String> stringList) {
|
||||||
|
return stringList.stream().map(item -> {
|
||||||
|
List<String> temp = Arrays.stream(PinyinHelper.toPinyin(item.replaceAll(" ", ""), PinyinStyleEnum.NORMAL).split(" "))
|
||||||
|
.filter(one -> one.length() > 0).collect(Collectors.toList());
|
||||||
|
return item.toLowerCase(Locale.getDefault()) + PARTITION + CollectionUtil.join(temp, "") + PARTITION
|
||||||
|
+ temp.stream().map(one -> one.substring(0, 1)).collect(Collectors.joining());
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
@ -4,22 +4,16 @@
|
|||||||
|
|
||||||
|
|
||||||
<insert id="insertOne" useGeneratedKeys="true" keyColumn="bookmarkId" keyProperty="bookmarkId">
|
<insert id="insertOne" useGeneratedKeys="true" keyColumn="bookmarkId" keyProperty="bookmarkId">
|
||||||
insert into bookmark(userId,path,type,name,url,icon,sort,addTime,createTime)
|
insert into bookmark(userId,path,type,name,searchKey,url,icon,sort,addTime,createTime)
|
||||||
value
|
value
|
||||||
( #{userId},#{path},#{type},#{name},
|
( #{userId},#{path},#{type},#{name},#{searchKey},#{url},#{icon},
|
||||||
<if test="url == null">
|
|
||||||
"","",
|
|
||||||
</if>
|
|
||||||
<if test="url != null">
|
|
||||||
#{url},#{icon},
|
|
||||||
</if>
|
|
||||||
#{sort},#{addTime},#{createTime})
|
#{sort},#{addTime},#{createTime})
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
<select id="selectIdByUserIdAndNameAndPath" resultType="java.lang.Integer">
|
<select id="selectIdByUserIdAndNameAndPath" resultType="java.lang.Integer">
|
||||||
select bookmarkId
|
select bookmarkId
|
||||||
from bookmark
|
from bookmark
|
||||||
where userId = #{userId} and path = #{path} and name = #{name};
|
where userId = #{userId} and path = #{path} and name = #{name} limit 1;
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectMaxSort" resultType="java.lang.Integer">
|
<select id="selectMaxSort" resultType="java.lang.Integer">
|
||||||
@ -28,29 +22,30 @@
|
|||||||
where userId = #{userId} and path = #{path}
|
where userId = #{userId} and path = #{path}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="getListByUserId" resultType="com.fanxb.bookmark.common.entity.Bookmark">
|
<select id="getListByUserId" resultType="com.fanxb.bookmark.common.entity.po.Bookmark">
|
||||||
select
|
select
|
||||||
bookmarkId,
|
bookmarkId,
|
||||||
path,
|
path,
|
||||||
type,
|
type,
|
||||||
name,
|
name,
|
||||||
url,
|
searchKey,
|
||||||
icon,
|
url,
|
||||||
sort
|
icon,
|
||||||
|
sort
|
||||||
from bookmark
|
from bookmark
|
||||||
where userId = #{userId}
|
where userId = #{userId}
|
||||||
order by path, sort
|
order by path, sort
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="getListByUserIdAndPath" resultType="com.fanxb.bookmark.common.entity.Bookmark">
|
<select id="getListByUserIdAndPath" resultType="com.fanxb.bookmark.common.entity.po.Bookmark">
|
||||||
select
|
select
|
||||||
bookmarkId,
|
bookmarkId,
|
||||||
path,
|
path,
|
||||||
type,
|
type,
|
||||||
name,
|
name,
|
||||||
url,
|
url,
|
||||||
icon,
|
icon,
|
||||||
sort
|
sort
|
||||||
from bookmark
|
from bookmark
|
||||||
where userId = #{userId} and path = #{path}
|
where userId = #{userId} and path = #{path}
|
||||||
order by sort
|
order by sort
|
||||||
@ -59,24 +54,18 @@
|
|||||||
<delete id="deleteUserFolder">
|
<delete id="deleteUserFolder">
|
||||||
DELETE
|
DELETE
|
||||||
FROM
|
FROM
|
||||||
bookmark
|
bookmark
|
||||||
WHERE
|
WHERE
|
||||||
userId = #{userId}
|
userId = #{userId}
|
||||||
and path LIKE (SELECT a.path
|
and (path = #{path} or path like concat(#{path},".%"))
|
||||||
FROM (SELECT CONCAT(path, '.', '${folderId}', '%') AS path
|
|
||||||
FROM bookmark
|
|
||||||
WHERE bookmarkId = #{folderId}) a);
|
|
||||||
</delete>
|
</delete>
|
||||||
|
|
||||||
<select id="getChildrenBookmarkId" resultType="integer">
|
<select id="getChildrenBookmarkId" resultType="integer">
|
||||||
select bookmarkId
|
select bookmarkId
|
||||||
from bookmark
|
from bookmark
|
||||||
where
|
where
|
||||||
userId = #{userId}
|
userId = #{userId}
|
||||||
and path LIKE (SELECT a.path
|
and (path =#{path} or path like concat(#{path},".%") );
|
||||||
FROM (SELECT CONCAT(path, '.', '${folderId}', '%') AS path
|
|
||||||
FROM bookmark
|
|
||||||
WHERE bookmarkId = #{folderId}) a);
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<delete id="deleteUserBookmark">
|
<delete id="deleteUserBookmark">
|
||||||
@ -86,9 +75,9 @@
|
|||||||
</foreach>
|
</foreach>
|
||||||
</delete>
|
</delete>
|
||||||
|
|
||||||
<update id="editBookmark" parameterType="com.fanxb.bookmark.common.entity.Bookmark">
|
<update id="editBookmark" parameterType="com.fanxb.bookmark.common.entity.po.Bookmark">
|
||||||
update bookmark
|
update bookmark
|
||||||
set name = #{name}, url = #{url}
|
set name = #{name}, url = #{url},searchKey = #{searchKey},icon=#{icon}
|
||||||
where bookmarkId = #{bookmarkId} and userId = #{userId}
|
where bookmarkId = #{bookmarkId} and userId = #{userId}
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
@ -112,15 +101,25 @@
|
|||||||
|
|
||||||
<select id="selectBookmarkEsByUserIdAndType" resultType="com.fanxb.bookmark.business.bookmark.entity.BookmarkEs">
|
<select id="selectBookmarkEsByUserIdAndType" resultType="com.fanxb.bookmark.business.bookmark.entity.BookmarkEs">
|
||||||
select
|
select
|
||||||
userId,
|
userId,
|
||||||
bookmarkId,
|
bookmarkId,
|
||||||
name,
|
name,
|
||||||
url
|
url
|
||||||
from bookmark
|
from bookmark
|
||||||
where userId = #{userId} and type = #{type}
|
where userId = #{userId} and type = #{type}
|
||||||
order by bookmarkId
|
order by bookmarkId
|
||||||
limit ${start}, ${size}
|
limit ${start}, ${size}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<update id="updateSearchKeyBatch">
|
||||||
|
UPDATE `bookmark` a JOIN
|
||||||
|
(
|
||||||
|
<foreach collection="list" item="item" separator="union">
|
||||||
|
select #{item.bookmarkId} as bookmarkId,#{item.searchKey} as searchKey
|
||||||
|
</foreach>
|
||||||
|
) b USING(bookmarkId)
|
||||||
|
SET a.searchKey=b.searchKey;
|
||||||
|
</update>
|
||||||
|
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.fanxb.bookmark.business.bookmark.dao.PinBookmarkDao">
|
||||||
|
|
||||||
|
<delete id="deleteUnExistBookmark">
|
||||||
|
delete
|
||||||
|
a
|
||||||
|
from pin_bookmark a
|
||||||
|
left join bookmark b on
|
||||||
|
a.bookmarkId = b.bookmarkId
|
||||||
|
where a.userId = #{userId}
|
||||||
|
and b.bookmarkId is null
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
</mapper>
|
@ -14,6 +14,7 @@
|
|||||||
<modules>
|
<modules>
|
||||||
<module>user</module>
|
<module>user</module>
|
||||||
<module>bookmark</module>
|
<module>bookmark</module>
|
||||||
|
<module>api</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@ -22,12 +23,6 @@
|
|||||||
<artifactId>bookmark-common</artifactId>
|
<artifactId>bookmark-common</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,5 +11,12 @@
|
|||||||
|
|
||||||
<artifactId>bookmark-business-user</artifactId>
|
<artifactId>bookmark-business-user</artifactId>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fanxb</groupId>
|
||||||
|
<artifactId>bookmark-business-api</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
@ -1,10 +1,8 @@
|
|||||||
package com.fanxb.bookmark.business.user.constant;
|
package com.fanxb.bookmark.business.user.constant;
|
||||||
|
|
||||||
import com.fanxb.bookmark.common.constant.Constant;
|
import com.fanxb.bookmark.common.constant.CommonConstant;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
import java.io.File;
|
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -20,6 +18,6 @@ public class FileConstant {
|
|||||||
/**
|
/**
|
||||||
* 用户头像目录
|
* 用户头像目录
|
||||||
*/
|
*/
|
||||||
public static String iconPath = Paths.get("files", "public", "icon").toString();
|
public static String iconPath = Paths.get(CommonConstant.fileSavePath, "files", "public", "icon").toString();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.consumer;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.fanxb.bookmark.business.user.dao.UserDao;
|
||||||
|
import com.fanxb.bookmark.common.annotation.MqConsumer;
|
||||||
|
import com.fanxb.bookmark.common.constant.RedisConstant;
|
||||||
|
import com.fanxb.bookmark.common.entity.redis.RedisConsumer;
|
||||||
|
import com.fanxb.bookmark.common.entity.redis.UserBookmarkUpdate;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2020/1/26 上午11:54
|
||||||
|
*/
|
||||||
|
@MqConsumer(RedisConstant.BOOKMARK_UPDATE_VERSION)
|
||||||
|
public class UserInfoUpdateConsumer implements RedisConsumer {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserDao userDao;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deal(String message) {
|
||||||
|
// int userId = Integer.parseInt(message);
|
||||||
|
// if (userId == -1) {
|
||||||
|
// userDao.updateAllBookmarkUpdateVersion();
|
||||||
|
// } else {
|
||||||
|
// userDao.updateLastBookmarkUpdateTime(userId);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,16 @@
|
|||||||
package com.fanxb.bookmark.business.user.controller;
|
package com.fanxb.bookmark.business.user.controller;
|
||||||
|
|
||||||
import com.fanxb.bookmark.business.user.entity.EmailUpdateBody;
|
|
||||||
import com.fanxb.bookmark.business.user.entity.UpdatePasswordBody;
|
|
||||||
import com.fanxb.bookmark.business.user.entity.UsernameBody;
|
|
||||||
import com.fanxb.bookmark.business.user.service.BaseInfoService;
|
import com.fanxb.bookmark.business.user.service.BaseInfoService;
|
||||||
|
import com.fanxb.bookmark.business.user.vo.EmailUpdateBody;
|
||||||
|
import com.fanxb.bookmark.business.user.vo.UpdatePasswordBody;
|
||||||
|
import com.fanxb.bookmark.business.user.vo.UsernameBody;
|
||||||
import com.fanxb.bookmark.common.entity.Result;
|
import com.fanxb.bookmark.common.entity.Result;
|
||||||
|
import com.fanxb.bookmark.common.entity.po.User;
|
||||||
|
import com.fanxb.bookmark.common.util.UserContextHolder;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 类功能简述:用户基本信息相关功能
|
* 类功能简述:用户基本信息相关功能
|
||||||
@ -23,8 +23,12 @@ import javax.validation.Valid;
|
|||||||
@Validated
|
@Validated
|
||||||
public class BaseInfoController {
|
public class BaseInfoController {
|
||||||
|
|
||||||
|
private final BaseInfoService baseInfoService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private BaseInfoService baseInfoService;
|
public BaseInfoController(BaseInfoService baseInfoService) {
|
||||||
|
this.baseInfoService = baseInfoService;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description: 修改密码
|
* Description: 修改密码
|
||||||
@ -82,4 +86,17 @@ public class BaseInfoController {
|
|||||||
baseInfoService.verifyEmail(secret);
|
baseInfoService.verifyEmail(secret);
|
||||||
return Result.success(null);
|
return Result.success(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改用户默认搜索引擎
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/14
|
||||||
|
**/
|
||||||
|
@PostMapping("/updateSearchEngine")
|
||||||
|
public Result updateSearchEngine(@RequestBody User user) {
|
||||||
|
user.setUserId(UserContextHolder.get().getUserId());
|
||||||
|
baseInfoService.changeDefaultSearchEngine(user);
|
||||||
|
return Result.success(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.controller;
|
||||||
|
|
||||||
|
import com.fanxb.bookmark.business.user.entity.Feedback;
|
||||||
|
import com.fanxb.bookmark.business.user.service.FeedbackService;
|
||||||
|
import com.fanxb.bookmark.common.entity.Result;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created with IntelliJ IDEA
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* Date: 2020/3/10
|
||||||
|
* Time: 23:16
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/feedback")
|
||||||
|
public class FeedbackController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private FeedbackService feedbackService;
|
||||||
|
|
||||||
|
@PutMapping("")
|
||||||
|
public Result addone(@Validated @RequestBody Feedback feedback) {
|
||||||
|
feedbackService.addOne(feedback);
|
||||||
|
return Result.success(null);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.controller;
|
||||||
|
|
||||||
|
import com.fanxb.bookmark.business.user.service.NotifyAnnounceService;
|
||||||
|
import com.fanxb.bookmark.common.entity.Result;
|
||||||
|
import com.fanxb.bookmark.common.util.UserContextHolder;
|
||||||
|
import org.apache.ibatis.annotations.Update;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021-10-17 14:03
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/announce/user")
|
||||||
|
public class NotifyAnnounceController {
|
||||||
|
@Autowired
|
||||||
|
private NotifyAnnounceService notifyAnnounceService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取站内信
|
||||||
|
*/
|
||||||
|
@GetMapping
|
||||||
|
public Result getUserAnnounce(@RequestParam int status) {
|
||||||
|
return Result.success(notifyAnnounceService.getUserAnnounce(UserContextHolder.get().getUserId(), status));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标记为已读
|
||||||
|
*/
|
||||||
|
@PostMapping("/read")
|
||||||
|
public Result readNotifyAnnounce(@RequestParam int notifyAnnounceId) {
|
||||||
|
notifyAnnounceService.markAsRead(UserContextHolder.get().getUserId(), notifyAnnounceId);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.controller;
|
||||||
|
|
||||||
|
import com.fanxb.bookmark.business.user.dao.SearchEngineDao;
|
||||||
|
import com.fanxb.bookmark.business.user.entity.SearchEngine;
|
||||||
|
import com.fanxb.bookmark.business.user.service.SearchEngineService;
|
||||||
|
import com.fanxb.bookmark.common.entity.Result;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/searchEngine")
|
||||||
|
public class SearchEngineController {
|
||||||
|
@Autowired
|
||||||
|
private SearchEngineService searchEngineService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列表查询
|
||||||
|
*/
|
||||||
|
@GetMapping("/list")
|
||||||
|
public Result list() {
|
||||||
|
return Result.success(searchEngineService.list());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/insert")
|
||||||
|
public Result insert(@RequestBody SearchEngine body){
|
||||||
|
searchEngineService.insertOne(body);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/edit")
|
||||||
|
public Result edit(@RequestBody SearchEngine body){
|
||||||
|
searchEngineService.editOne(body);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/delete")
|
||||||
|
public Result delete(@RequestBody SearchEngine body){
|
||||||
|
searchEngineService.deleteOne(body.getId());
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/setChecked")
|
||||||
|
public Result setChecked(@RequestBody SearchEngine body){
|
||||||
|
searchEngineService.setChecked(body.getId());
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,12 @@
|
|||||||
package com.fanxb.bookmark.business.user.controller;
|
package com.fanxb.bookmark.business.user.controller;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.fanxb.bookmark.business.user.entity.LoginBody;
|
import com.fanxb.bookmark.business.user.service.OauthService;
|
||||||
import com.fanxb.bookmark.business.user.entity.RegisterBody;
|
|
||||||
import com.fanxb.bookmark.business.user.service.UserService;
|
import com.fanxb.bookmark.business.user.service.UserService;
|
||||||
|
import com.fanxb.bookmark.business.user.vo.LoginBody;
|
||||||
|
import com.fanxb.bookmark.business.user.vo.OauthBody;
|
||||||
|
import com.fanxb.bookmark.business.user.vo.RegisterBody;
|
||||||
|
import com.fanxb.bookmark.business.user.service.impl.UserServiceImpl;
|
||||||
import com.fanxb.bookmark.common.entity.Result;
|
import com.fanxb.bookmark.common.entity.Result;
|
||||||
import com.fanxb.bookmark.common.util.UserContextHolder;
|
import com.fanxb.bookmark.common.util.UserContextHolder;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
@ -11,6 +14,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 类功能简述:
|
* 类功能简述:
|
||||||
* 类功能详述:
|
* 类功能详述:
|
||||||
@ -22,8 +27,16 @@ import org.springframework.web.multipart.MultipartFile;
|
|||||||
@RequestMapping("/user")
|
@RequestMapping("/user")
|
||||||
public class UserController {
|
public class UserController {
|
||||||
|
|
||||||
|
private final UserServiceImpl userServiceImpl;
|
||||||
|
private final OauthService oAuthService;
|
||||||
|
private final UserService userService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private UserService userService;
|
public UserController(UserServiceImpl userServiceImpl, OauthService oAuthService, UserService userService) {
|
||||||
|
this.userServiceImpl = userServiceImpl;
|
||||||
|
this.oAuthService = oAuthService;
|
||||||
|
this.userService = userService;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description: 获取验证码
|
* Description: 获取验证码
|
||||||
@ -35,7 +48,7 @@ public class UserController {
|
|||||||
*/
|
*/
|
||||||
@GetMapping("/authCode")
|
@GetMapping("/authCode")
|
||||||
public Result getAuthCode(@Param("email") String email) {
|
public Result getAuthCode(@Param("email") String email) {
|
||||||
userService.sendAuthCode(email);
|
userServiceImpl.sendAuthCode(email);
|
||||||
return Result.success(null);
|
return Result.success(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,9 +61,8 @@ public class UserController {
|
|||||||
* @date 2019/7/6 16:34
|
* @date 2019/7/6 16:34
|
||||||
*/
|
*/
|
||||||
@PutMapping("")
|
@PutMapping("")
|
||||||
public Result register(@RequestBody RegisterBody body) {
|
public Result register(@Valid @RequestBody RegisterBody body) {
|
||||||
userService.register(body);
|
return Result.success(userServiceImpl.register(body));
|
||||||
return Result.success(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -62,7 +74,7 @@ public class UserController {
|
|||||||
*/
|
*/
|
||||||
@GetMapping("/currentUserInfo")
|
@GetMapping("/currentUserInfo")
|
||||||
public Result currentUserInfo() {
|
public Result currentUserInfo() {
|
||||||
return Result.success(userService.getUserInfo(UserContextHolder.get().getUserId()));
|
return Result.success(userServiceImpl.getUserInfo(UserContextHolder.get().getUserId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -73,7 +85,7 @@ public class UserController {
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/icon")
|
@PostMapping("/icon")
|
||||||
public Result pushIcon(@RequestParam("file") MultipartFile file) throws Exception {
|
public Result pushIcon(@RequestParam("file") MultipartFile file) throws Exception {
|
||||||
return Result.success(userService.updateIcon(file));
|
return Result.success(userServiceImpl.updateIcon(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,7 +98,7 @@ public class UserController {
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
public Result login(@RequestBody LoginBody body) {
|
public Result login(@RequestBody LoginBody body) {
|
||||||
return Result.success(userService.login(body));
|
return Result.success(userServiceImpl.login(body));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -99,7 +111,7 @@ public class UserController {
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/resetPassword")
|
@PostMapping("/resetPassword")
|
||||||
public Result resetPassword(@RequestBody RegisterBody body) {
|
public Result resetPassword(@RequestBody RegisterBody body) {
|
||||||
userService.resetPassword(body);
|
userServiceImpl.resetPassword(body);
|
||||||
return Result.success(null);
|
return Result.success(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +125,7 @@ public class UserController {
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/checkPassword")
|
@PostMapping("/checkPassword")
|
||||||
public Result checkPassword(@RequestBody JSONObject obj) {
|
public Result checkPassword(@RequestBody JSONObject obj) {
|
||||||
return Result.success(userService.checkPassword(obj.getString("password")));
|
return Result.success(userServiceImpl.checkPassword(obj.getString("password")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/loginStatus")
|
@GetMapping("/loginStatus")
|
||||||
@ -121,5 +133,54 @@ public class UserController {
|
|||||||
return Result.success(null);
|
return Result.success(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 第三方登陆
|
||||||
|
*
|
||||||
|
* @param body 入参
|
||||||
|
* @return com.fanxb.bookmark.common.entity.Result
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/10
|
||||||
|
*/
|
||||||
|
@PostMapping("oAuthLogin")
|
||||||
|
public Result oAuthLogin(@RequestBody OauthBody body) {
|
||||||
|
return Result.success(oAuthService.oAuthCheck(body));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户version
|
||||||
|
*
|
||||||
|
* @date 2021/3/11
|
||||||
|
**/
|
||||||
|
@GetMapping("/version")
|
||||||
|
public Result getUserVersion() {
|
||||||
|
return Result.success(userService.getCurrentUserVersion(UserContextHolder.get().getUserId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新所有人的icon数据
|
||||||
|
*
|
||||||
|
* @return com.fanxb.bookmark.common.entity.Result
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/13
|
||||||
|
**/
|
||||||
|
@PostMapping("/updateAllUserIcon")
|
||||||
|
public Result updateAllUserIcon() {
|
||||||
|
userService.updateAllUserIcon();
|
||||||
|
return Result.success(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理所有的问题书签数据
|
||||||
|
*
|
||||||
|
* @param obj obj
|
||||||
|
* @return com.fanxb.bookmark.common.entity.Result
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/17
|
||||||
|
**/
|
||||||
|
@PostMapping("/dealAllUserBookmark")
|
||||||
|
public Result dealAllUserBookmark(@RequestBody JSONObject obj) {
|
||||||
|
return Result.success(userService.dealAllUserBookmark(obj.getBoolean("delete")));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.dao;
|
||||||
|
|
||||||
|
import com.fanxb.bookmark.business.user.entity.Feedback;
|
||||||
|
import org.apache.ibatis.annotations.Insert;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created with IntelliJ IDEA
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* Date: 2020/3/10
|
||||||
|
* Time: 23:14
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public interface FeedbackDao {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能描述: 插入一条记录
|
||||||
|
*
|
||||||
|
* @param feedback feedback
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2020/3/10 23:16
|
||||||
|
*/
|
||||||
|
@Insert("insert into feedback(userId,type,content) value(#{userId},#{type},#{content})")
|
||||||
|
void insertOne(Feedback feedback);
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.dao;
|
||||||
|
|
||||||
|
import com.fanxb.bookmark.business.user.vo.UserNotifyAnnounceRes;
|
||||||
|
import org.apache.ibatis.annotations.Insert;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
import org.apache.ibatis.annotations.Update;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021-10-17 14:19
|
||||||
|
*/
|
||||||
|
public interface NotifyAnnounceDao {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户站内信
|
||||||
|
*
|
||||||
|
* @param userId userId
|
||||||
|
* @param status status
|
||||||
|
* @return java.util.List<com.fanxb.bookmark.business.user.vo.UserNotifyAnnounceRes>
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/10/17 14:28
|
||||||
|
*/
|
||||||
|
List<UserNotifyAnnounceRes> queryUserAnnounce(@Param("userId") int userId, @Param("status") int status, @Param("date") long date);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理某人的邮件
|
||||||
|
*
|
||||||
|
* @param userId userId
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/10/17 15:05
|
||||||
|
*/
|
||||||
|
@Insert("insert into user_notify_announce(userId,notifyAnnounceId,status) select #{userId},notifyAnnounceId,0 from notify_announce a where a.createdDate > (select lastSyncAnnounceDate from user where userId=#{userId})")
|
||||||
|
void dealNotifyAnnounceById(int userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标记为已读
|
||||||
|
*
|
||||||
|
* @param userId userId
|
||||||
|
* @param notifyAnnounceId notifyAnnounceId
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/10/17 15:26
|
||||||
|
*/
|
||||||
|
@Update("update user_notify_announce set status=1,readDate=#{readDate} where userId=#{userId} and notifyAnnounceId=#{notifyAnnounceId}")
|
||||||
|
void markAsRead(@Param("userId") int userId, @Param("notifyAnnounceId") int notifyAnnounceId, @Param("readDate") long readDate);
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.dao;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.fanxb.bookmark.business.user.entity.SearchEngine;
|
||||||
|
|
||||||
|
public interface SearchEngineDao extends BaseMapper<SearchEngine> {
|
||||||
|
|
||||||
|
}
|
@ -1,11 +1,14 @@
|
|||||||
package com.fanxb.bookmark.business.user.dao;
|
package com.fanxb.bookmark.business.user.dao;
|
||||||
|
|
||||||
import com.fanxb.bookmark.common.entity.User;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.fanxb.bookmark.common.entity.redis.UserBookmarkUpdate;
|
import com.fanxb.bookmark.common.entity.po.User;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.apache.ibatis.annotations.Select;
|
||||||
import org.apache.ibatis.annotations.Update;
|
import org.apache.ibatis.annotations.Update;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 类功能简述:
|
* 类功能简述:
|
||||||
* 类功能详述:
|
* 类功能详述:
|
||||||
@ -14,7 +17,7 @@ import org.springframework.stereotype.Component;
|
|||||||
* @date 2019/7/6 11:36
|
* @date 2019/7/6 11:36
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
public interface UserDao {
|
public interface UserDao extends BaseMapper<User> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description: 新增一个用户
|
* Description: 新增一个用户
|
||||||
@ -30,7 +33,7 @@ public interface UserDao {
|
|||||||
*
|
*
|
||||||
* @param name username
|
* @param name username
|
||||||
* @param email email
|
* @param email email
|
||||||
* @return com.fanxb.bookmark.common.entity.User
|
* @return com.fanxb.bookmark.common.entity.po.User
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/6 16:45
|
* @date 2019/7/6 16:45
|
||||||
*/
|
*/
|
||||||
@ -59,12 +62,13 @@ public interface UserDao {
|
|||||||
/**
|
/**
|
||||||
* Description: 根据用户id查询用户信息
|
* Description: 根据用户id查询用户信息
|
||||||
*
|
*
|
||||||
* @param userId userId
|
* @param userId userId
|
||||||
* @return com.fanxb.bookmark.common.entity.User
|
* @param githubId githubId
|
||||||
|
* @return com.fanxb.bookmark.common.entity.po.User
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/30 16:08
|
* @date 2019/7/30 16:08
|
||||||
*/
|
*/
|
||||||
User selectByUserId(int userId);
|
User selectByUserIdOrGithubId(@Param("userId") Integer userId, @Param("githubId") Long githubId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description: 更新用户icon
|
* Description: 更新用户icon
|
||||||
@ -102,11 +106,11 @@ public interface UserDao {
|
|||||||
/**
|
/**
|
||||||
* 更新用户新邮箱
|
* 更新用户新邮箱
|
||||||
*
|
*
|
||||||
* @param userId userId
|
* @param userId userId
|
||||||
* @param newPassword userId
|
* @param newEmail email
|
||||||
*/
|
*/
|
||||||
@Update("update user set newEmail=#{newPassword} where userId= #{userId}")
|
@Update("update user set newEmail=#{newEmail} where userId= #{userId}")
|
||||||
void updateNewEmailByUserId(@Param("userId") int userId, @Param("newPassword") String newPassword);
|
void updateNewEmailByUserId(@Param("userId") int userId, @Param("newEmail") String newEmail);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新邮箱校验成功,更新邮箱
|
* 新邮箱校验成功,更新邮箱
|
||||||
@ -119,10 +123,78 @@ public interface UserDao {
|
|||||||
/**
|
/**
|
||||||
* 功能描述: 更新用户上次更新书签时间
|
* 功能描述: 更新用户上次更新书签时间
|
||||||
*
|
*
|
||||||
* @param item item
|
* @param userId userId
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2020/1/26 下午3:47
|
* @date 2020/1/26 下午3:47
|
||||||
*/
|
*/
|
||||||
@Update("update user set bookmarkChangeTime=#{updateTime} where userId=#{userId}")
|
@Update("update user set version=version+1 where userId=#{userId}")
|
||||||
void updateLastBookmarkUpdateTime(UserBookmarkUpdate item);
|
void updateUserVersion(int userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能描述: 更新所有用户的更新时间
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2020/3/29 18:18
|
||||||
|
*/
|
||||||
|
@Update("update user set version=version+1")
|
||||||
|
void updateAllBookmarkUpdateVersion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断用户名是否存在
|
||||||
|
*
|
||||||
|
* @param name name
|
||||||
|
* @return boolean
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/11
|
||||||
|
**/
|
||||||
|
@Select("select count(1) from user where username=#{name}")
|
||||||
|
boolean usernameExist(String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新githubId
|
||||||
|
*
|
||||||
|
* @param user user
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/11
|
||||||
|
**/
|
||||||
|
@Update("update user set githubId=#{githubId},email=#{email} where userId=#{userId}")
|
||||||
|
void updateEmailAndGithubId(User user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户版本
|
||||||
|
*
|
||||||
|
* @param userId userId
|
||||||
|
* @return int
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/11
|
||||||
|
**/
|
||||||
|
@Select("select version from user where userId=#{userId}")
|
||||||
|
int getUserVersion(int userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询用户id列表
|
||||||
|
*
|
||||||
|
* @param start 开始
|
||||||
|
* @param size 页大小
|
||||||
|
* @return java.util.List<java.lang.Integer>
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/13
|
||||||
|
**/
|
||||||
|
@Select("select userId from user order by userId limit #{start},#{size}")
|
||||||
|
List<Integer> selectUserIdPage(@Param("start") int start, @Param("size") int size);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新一个字段-一个条件
|
||||||
|
*
|
||||||
|
* @param column 字段名
|
||||||
|
* @param val 字段值
|
||||||
|
* @param termColumn 条件字段名
|
||||||
|
* @param termVal 条件字段值
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/10/17 15:03
|
||||||
|
*/
|
||||||
|
@Update("update user set ${column} = #{val} where ${termColumn} = #{termVal}")
|
||||||
|
void updateOneColumnByOneTerm(String column, Object val, String termColumn, Object termVal);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.entity;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created with IntelliJ IDEA
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* Date: 2020/3/10
|
||||||
|
* Time: 23:13
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class Feedback {
|
||||||
|
private int feedbackId;
|
||||||
|
private int userId;
|
||||||
|
private String type;
|
||||||
|
@NotEmpty(message = "内容不能为空")
|
||||||
|
private String content;
|
||||||
|
}
|
@ -1,20 +0,0 @@
|
|||||||
package com.fanxb.bookmark.business.user.entity;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 类功能简述:登录返回数据
|
|
||||||
* 类功能详述:
|
|
||||||
*
|
|
||||||
* @author fanxb
|
|
||||||
* @date 2019/7/6 16:52
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class LoginRes {
|
|
||||||
private String token;
|
|
||||||
private int userId;
|
|
||||||
private String username;
|
|
||||||
private String email;
|
|
||||||
private String lastLoginTime;
|
|
||||||
private String icon;
|
|
||||||
}
|
|
@ -0,0 +1,36 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021-10-17 14:04
|
||||||
|
*/
|
||||||
|
public class NotifyAnnounce {
|
||||||
|
/**
|
||||||
|
* 通知id
|
||||||
|
*/
|
||||||
|
private int notifyAnnounceId;
|
||||||
|
/**
|
||||||
|
* 发送人id
|
||||||
|
*/
|
||||||
|
private int senderId;
|
||||||
|
/**
|
||||||
|
* 标题
|
||||||
|
*/
|
||||||
|
private String title;
|
||||||
|
/**
|
||||||
|
* 正文
|
||||||
|
*/
|
||||||
|
private String content;
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
private Long createdDate;
|
||||||
|
/**
|
||||||
|
* 通知开始时间
|
||||||
|
*/
|
||||||
|
private Long startDate;
|
||||||
|
/**
|
||||||
|
* 通知结束时间
|
||||||
|
*/
|
||||||
|
private Long endDate;
|
||||||
|
}
|
@ -1,18 +0,0 @@
|
|||||||
package com.fanxb.bookmark.business.user.entity;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 类功能简述: 注册表单
|
|
||||||
* 类功能详述:
|
|
||||||
*
|
|
||||||
* @author fanxb
|
|
||||||
* @date 2019/7/6 11:23
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class RegisterBody {
|
|
||||||
private String username;
|
|
||||||
private String password;
|
|
||||||
private String email;
|
|
||||||
private String authCode;
|
|
||||||
}
|
|
@ -0,0 +1,29 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.entity;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@TableName("search_engine")
|
||||||
|
public class SearchEngine {
|
||||||
|
@TableId(type = IdType.AUTO)
|
||||||
|
private Integer id;
|
||||||
|
private Integer userId;
|
||||||
|
private Integer checked;
|
||||||
|
/**
|
||||||
|
* 名称
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
/**
|
||||||
|
* url
|
||||||
|
*/
|
||||||
|
private String url;
|
||||||
|
/**
|
||||||
|
* 图标
|
||||||
|
*/
|
||||||
|
private String icon;
|
||||||
|
}
|
@ -1,38 +0,0 @@
|
|||||||
package com.fanxb.bookmark.business.user.schedule;
|
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.fanxb.bookmark.business.user.dao.UserDao;
|
|
||||||
import com.fanxb.bookmark.common.constant.RedisConstant;
|
|
||||||
import com.fanxb.bookmark.common.entity.redis.UserBookmarkUpdate;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author fanxb
|
|
||||||
* @date 2020/1/26 上午11:54
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class UserInfoUpdate {
|
|
||||||
/**
|
|
||||||
* 阻塞时间
|
|
||||||
*/
|
|
||||||
private static final int BLOCK_TIME = 15;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private StringRedisTemplate redisTemplate;
|
|
||||||
@Autowired
|
|
||||||
private UserDao userDao;
|
|
||||||
|
|
||||||
@Scheduled(fixedDelay = 100000)
|
|
||||||
public void userBookmarkUpdateTime() {
|
|
||||||
String value;
|
|
||||||
while ((value = redisTemplate.opsForList().rightPop(RedisConstant.BOOKMARK_UPDATE_TIME, BLOCK_TIME, TimeUnit.SECONDS)) != null) {
|
|
||||||
UserBookmarkUpdate item = JSON.parseObject(value, UserBookmarkUpdate.class);
|
|
||||||
userDao.updateLastBookmarkUpdateTime(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* 定时调度类
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021-10-17 14:37
|
||||||
|
*/
|
||||||
|
package com.fanxb.bookmark.business.user.schedule;
|
@ -1,103 +1,59 @@
|
|||||||
package com.fanxb.bookmark.business.user.service;
|
package com.fanxb.bookmark.business.user.service;
|
||||||
|
|
||||||
import com.fanxb.bookmark.business.user.constant.RedisConstant;
|
import com.fanxb.bookmark.business.user.vo.EmailUpdateBody;
|
||||||
import com.fanxb.bookmark.business.user.dao.UserDao;
|
import com.fanxb.bookmark.business.user.vo.UpdatePasswordBody;
|
||||||
import com.fanxb.bookmark.business.user.entity.EmailUpdateBody;
|
import com.fanxb.bookmark.common.entity.po.User;
|
||||||
import com.fanxb.bookmark.business.user.entity.UpdatePasswordBody;
|
|
||||||
import com.fanxb.bookmark.common.constant.Constant;
|
/**
|
||||||
import com.fanxb.bookmark.common.entity.MailInfo;
|
* 个人信息修改
|
||||||
import com.fanxb.bookmark.common.exception.CustomException;
|
*
|
||||||
import com.fanxb.bookmark.common.exception.FormDataException;
|
* @author fanxb
|
||||||
import com.fanxb.bookmark.common.util.*;
|
* @date 2021/3/14
|
||||||
import lombok.extern.slf4j.Slf4j;
|
**/
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
public interface BaseInfoService {
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
|
||||||
import org.springframework.stereotype.Service;
|
/**
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
* 修改密码
|
||||||
|
*
|
||||||
import javax.annotation.PostConstruct;
|
* @param body body
|
||||||
import java.util.UUID;
|
* @author fanxb
|
||||||
|
* @date 2021/3/14
|
||||||
/**
|
**/
|
||||||
* 类功能简述:
|
void changePassword(UpdatePasswordBody body);
|
||||||
* 类功能详述:
|
|
||||||
*
|
/**
|
||||||
* @author fanxb
|
* Description: 修改用户名
|
||||||
* @date 2019/9/18 15:54
|
*
|
||||||
*/
|
* @param username 用户名
|
||||||
@Service
|
* @author fanxb
|
||||||
@Slf4j
|
* @date 2019/9/20 16:18
|
||||||
public class BaseInfoService {
|
*/
|
||||||
|
void updateUsername(String username);
|
||||||
private static final String VERIFY_EMAIL = FileUtil.streamToString(BaseInfoService.class
|
|
||||||
.getClassLoader().getResourceAsStream("verifyEmail.html"));
|
/**
|
||||||
|
* 功能描述: 预备更新email,需要校验密码
|
||||||
private static final String VERIFY_EMAIL_PATH = "/public/verifyEmail?key=";
|
*
|
||||||
|
* @param body body
|
||||||
@Autowired
|
* @author fanxb
|
||||||
private UserDao userDao;
|
* @date 2019/9/26 17:27
|
||||||
|
*/
|
||||||
public void changePassword(UpdatePasswordBody body) {
|
void updateEmail(EmailUpdateBody body);
|
||||||
int userId = UserContextHolder.get().getUserId();
|
|
||||||
String checkAuthKey = com.fanxb.bookmark.common.constant.RedisConstant.getPasswordCheckKey(userId, body.getActionId());
|
/**
|
||||||
String str = RedisUtil.get(checkAuthKey, String.class);
|
* 功能描述: 校验新邮箱,校验成功就更新
|
||||||
if (str == null) {
|
*
|
||||||
throw new CustomException("密码校验失败,无法更新密码");
|
* @param secret secret
|
||||||
}
|
* @author fanxb
|
||||||
userDao.updatePasswordByUserId(userId, HashUtil.getPassword(body.getPassword()));
|
* @date 2019/11/11 23:24
|
||||||
}
|
*/
|
||||||
|
void verifyEmail(String secret);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description: 修改用户名
|
* 修改用户默认搜索引擎
|
||||||
*
|
*
|
||||||
* @param username 用户名
|
* @param user user
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/9/20 16:18
|
* @date 2021/3/14
|
||||||
*/
|
**/
|
||||||
public void updateUsername(String username) {
|
void changeDefaultSearchEngine(User user);
|
||||||
userDao.updateUsernameByUserId(UserContextHolder.get().getUserId(), username);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 功能描述: 预备更新email,需要校验密码
|
|
||||||
*
|
|
||||||
* @param body body
|
|
||||||
* @author fanxb
|
|
||||||
* @date 2019/9/26 17:27
|
|
||||||
*/
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
public void updateEmail(EmailUpdateBody body) {
|
|
||||||
int userId = UserContextHolder.get().getUserId();
|
|
||||||
String checkAuthKey = com.fanxb.bookmark.common.constant.RedisConstant.getPasswordCheckKey(userId, body.getActionId());
|
|
||||||
String str = RedisUtil.get(checkAuthKey, String.class);
|
|
||||||
if (str == null) {
|
|
||||||
throw new CustomException("密码校验失败,无法更新email");
|
|
||||||
}
|
|
||||||
RedisUtil.delete(checkAuthKey);
|
|
||||||
String secret = UUID.randomUUID().toString().replaceAll("-", "");
|
|
||||||
String url = VERIFY_EMAIL.replaceAll("XXXX", Constant.serviceAddress + VERIFY_EMAIL_PATH + secret);
|
|
||||||
log.debug(url);
|
|
||||||
MailInfo info = new MailInfo(body.getEmail(), "验证邮箱", url);
|
|
||||||
MailUtil.sendMail(info, true);
|
|
||||||
RedisUtil.set(RedisConstant.getUpdateEmailKey(secret), String.valueOf(userId), TimeUtil.DAY_MS);
|
|
||||||
userDao.updateNewEmailByUserId(userId, body.getEmail());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 功能描述: 校验新邮箱,校验成功就更新
|
|
||||||
*
|
|
||||||
* @param secret secret
|
|
||||||
* @author fanxb
|
|
||||||
* @date 2019/11/11 23:24
|
|
||||||
*/
|
|
||||||
public void verifyEmail(String secret) {
|
|
||||||
String key = RedisConstant.getUpdateEmailKey(secret);
|
|
||||||
Integer userId = RedisUtil.get(key, Integer.class);
|
|
||||||
RedisUtil.delete(key);
|
|
||||||
if (userId == null) {
|
|
||||||
throw new CustomException("校验失败,请重试");
|
|
||||||
}
|
|
||||||
userDao.updateEmailByUserId(userId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.service;
|
||||||
|
|
||||||
|
import com.fanxb.bookmark.business.user.entity.Feedback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created with IntelliJ IDEA
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* Date: 2020/3/10
|
||||||
|
* Time: 23:17
|
||||||
|
*/
|
||||||
|
public interface FeedbackService {
|
||||||
|
/**
|
||||||
|
* 功能描述: 插入一条记录
|
||||||
|
*
|
||||||
|
* @param feedback feedback
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2020/3/10 23:18
|
||||||
|
*/
|
||||||
|
void addOne(Feedback feedback);
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.service;
|
||||||
|
|
||||||
|
import com.fanxb.bookmark.business.user.entity.NotifyAnnounce;
|
||||||
|
import com.fanxb.bookmark.business.user.vo.UserNotifyAnnounceRes;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021-10-17 14:07
|
||||||
|
*/
|
||||||
|
public interface NotifyAnnounceService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户通知
|
||||||
|
*
|
||||||
|
* @param userId 用户id
|
||||||
|
* @param status 状态 0:未读,1:已读
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/10/17 14:14
|
||||||
|
*/
|
||||||
|
List<UserNotifyAnnounceRes> getUserAnnounce(int userId, int status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标记为已读
|
||||||
|
*
|
||||||
|
* @param userId 用户id
|
||||||
|
* @param notifyAnnounceId 通知id
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/10/17 14:14
|
||||||
|
*/
|
||||||
|
void markAsRead(int userId, int notifyAnnounceId);
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.service;
|
||||||
|
|
||||||
|
import com.fanxb.bookmark.business.user.vo.OauthBody;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/8/20 下午2:13
|
||||||
|
*/
|
||||||
|
public interface OauthService {
|
||||||
|
/**
|
||||||
|
* oauth登陆校验
|
||||||
|
*
|
||||||
|
* @param body body
|
||||||
|
* @return java.lang.String
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/8/20 下午2:13
|
||||||
|
*/
|
||||||
|
String oAuthCheck(OauthBody body);
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.service;
|
||||||
|
|
||||||
|
import com.fanxb.bookmark.business.user.entity.SearchEngine;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface SearchEngineService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列表查询
|
||||||
|
*/
|
||||||
|
List<SearchEngine> list();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delete one by id
|
||||||
|
*
|
||||||
|
* @param id id
|
||||||
|
*/
|
||||||
|
void deleteOne(int id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insert one
|
||||||
|
*
|
||||||
|
* @param body body
|
||||||
|
*/
|
||||||
|
void insertOne(SearchEngine body);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* edit one
|
||||||
|
*
|
||||||
|
* @param body body
|
||||||
|
*/
|
||||||
|
void editOne(SearchEngine body);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设为默认搜索项
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
void setChecked(Integer id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新用户初始化
|
||||||
|
*
|
||||||
|
* @param userId userId
|
||||||
|
*/
|
||||||
|
void newUserInit(int userId);
|
||||||
|
}
|
@ -1,207 +1,65 @@
|
|||||||
package com.fanxb.bookmark.business.user.service;
|
package com.fanxb.bookmark.business.user.service;
|
||||||
|
|
||||||
import com.fanxb.bookmark.business.user.constant.FileConstant;
|
import com.fanxb.bookmark.common.util.TimeUtil;
|
||||||
import com.fanxb.bookmark.business.user.dao.UserDao;
|
|
||||||
import com.fanxb.bookmark.business.user.entity.LoginBody;
|
import java.util.Map;
|
||||||
import com.fanxb.bookmark.business.user.entity.LoginRes;
|
import java.util.Set;
|
||||||
import com.fanxb.bookmark.business.user.entity.RegisterBody;
|
|
||||||
import com.fanxb.bookmark.common.constant.Constant;
|
/**
|
||||||
import com.fanxb.bookmark.common.constant.NumberConstant;
|
* 用户接口
|
||||||
import com.fanxb.bookmark.common.constant.RedisConstant;
|
*
|
||||||
import com.fanxb.bookmark.common.entity.MailInfo;
|
* @author fanxb
|
||||||
import com.fanxb.bookmark.common.entity.User;
|
* @date 2021/3/11
|
||||||
import com.fanxb.bookmark.common.exception.FormDataException;
|
**/
|
||||||
import com.fanxb.bookmark.common.util.*;
|
public interface UserService {
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
String DEFAULT_ICON = "/favicon.ico";
|
||||||
import org.springframework.stereotype.Service;
|
/**
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
* 短期jwt失效时间
|
||||||
|
*/
|
||||||
import java.io.File;
|
long SHORT_EXPIRE_TIME = 2 * 60 * 60 * 1000;
|
||||||
import java.nio.file.Path;
|
/**
|
||||||
import java.nio.file.Paths;
|
* 长期jwt失效时间
|
||||||
import java.util.HashMap;
|
*/
|
||||||
import java.util.Map;
|
long LONG_EXPIRE_TIME = 300L * TimeUtil.DAY_MS;
|
||||||
import java.util.UUID;
|
|
||||||
|
/**
|
||||||
/**
|
* 头像文件大小限制 单位:KB
|
||||||
* 类功能简述:
|
*/
|
||||||
* 类功能详述:
|
int ICON_SIZE = 200;
|
||||||
*
|
|
||||||
* @author fanxb
|
/***
|
||||||
* @date 2019/7/5 17:39
|
* 获取一个可用的用户名
|
||||||
*/
|
* @author fanxb
|
||||||
@Service
|
* @return java.lang.String
|
||||||
public class UserService {
|
* @date 2021/3/11
|
||||||
|
**/
|
||||||
private static final String DEFAULT_ICON = "/favicon.ico";
|
String createNewUsername();
|
||||||
/**
|
|
||||||
* 短期jwt失效时间
|
/**
|
||||||
*/
|
* 获取当前用户的version
|
||||||
private static final long SHORT_EXPIRE_TIME = 2 * 60 * 60 * 1000;
|
*
|
||||||
/**
|
* @param userId userId
|
||||||
* 长期jwt失效时间
|
* @return int
|
||||||
*/
|
* @author fanxb
|
||||||
private static final long LONG_EXPIRE_TIME = 30L * TimeUtil.DAY_MS;
|
* @date 2021/3/11
|
||||||
|
**/
|
||||||
/**
|
int getCurrentUserVersion(int userId);
|
||||||
* 头像文件大小限制 单位:KB
|
|
||||||
*/
|
/**
|
||||||
private static final int ICON_SIZE = 200;
|
* 更新所有用户的空icon
|
||||||
|
*
|
||||||
@Autowired
|
* @author fanxb
|
||||||
private UserDao userDao;
|
* @date 2021/3/13
|
||||||
|
**/
|
||||||
/**
|
void updateAllUserIcon();
|
||||||
* Description: 向目标发送验证码
|
|
||||||
*
|
/**
|
||||||
* @param email 目标
|
* 检查所有用户的问题书签数据
|
||||||
* @author fanxb
|
*
|
||||||
* @date 2019/7/5 17:48
|
* @param delete 是否删除问题数据
|
||||||
*/
|
* @return 返回用户删除的数据
|
||||||
public void sendAuthCode(String email) {
|
* @author fanxb
|
||||||
MailInfo info = new MailInfo();
|
* @date 2021/3/17
|
||||||
info.setSubject("签签世界注册验证码");
|
**/
|
||||||
String code = StringUtil.getRandomString(6, 2);
|
Map<Integer, Set<String>> dealAllUserBookmark(boolean delete);
|
||||||
info.setContent("欢迎注册 签签世界 ,本次验证码");
|
}
|
||||||
info.setContent(code + " 是您的验证码,注意验证码有效期为15分钟哦!");
|
|
||||||
info.setReceiver(email);
|
|
||||||
if (Constant.isDev) {
|
|
||||||
code = "123456";
|
|
||||||
} else {
|
|
||||||
MailUtil.sendTextMail(info);
|
|
||||||
}
|
|
||||||
RedisUtil.set(Constant.authCodeKey(email), code, Constant.AUTH_CODE_EXPIRE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description: 用户注册
|
|
||||||
*
|
|
||||||
* @param body 注册表单
|
|
||||||
* @author fanxb
|
|
||||||
* @date 2019/7/6 11:30
|
|
||||||
*/
|
|
||||||
public void register(RegisterBody body) {
|
|
||||||
User user = userDao.selectByUsernameOrEmail(body.getUsername(), body.getEmail());
|
|
||||||
if (user != null) {
|
|
||||||
if (user.getUsername().equals(body.getUsername())) {
|
|
||||||
throw new FormDataException("用户名已经被注册");
|
|
||||||
}
|
|
||||||
if (user.getEmail().equals(body.getEmail())) {
|
|
||||||
throw new FormDataException("邮箱已经被注册");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
user = new User();
|
|
||||||
user.setUsername(body.getUsername());
|
|
||||||
user.setEmail(body.getEmail());
|
|
||||||
user.setIcon(DEFAULT_ICON);
|
|
||||||
user.setPassword(HashUtil.sha1(HashUtil.md5(body.getPassword())));
|
|
||||||
user.setCreateTime(System.currentTimeMillis());
|
|
||||||
user.setLastLoginTime(0);
|
|
||||||
userDao.addOne(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description: 登录
|
|
||||||
*
|
|
||||||
* @param body 登录表单
|
|
||||||
* @return LoginRes
|
|
||||||
* @author fanxb
|
|
||||||
* @date 2019/7/6 16:37
|
|
||||||
*/
|
|
||||||
public LoginRes login(LoginBody body) {
|
|
||||||
User userInfo = userDao.selectByUsernameOrEmail(body.getStr(), body.getStr());
|
|
||||||
if (userInfo == null) {
|
|
||||||
throw new FormDataException("账号/密码错误");
|
|
||||||
}
|
|
||||||
if (!HashUtil.sha1(HashUtil.md5(body.getPassword())).equals(userInfo.getPassword())) {
|
|
||||||
throw new FormDataException("账号/密码错误");
|
|
||||||
}
|
|
||||||
Map<String, String> data = new HashMap<>(1);
|
|
||||||
data.put("userId", String.valueOf(userInfo.getUserId()));
|
|
||||||
String token = JwtUtil.encode(data, Constant.jwtSecret, body.isRememberMe() ? LONG_EXPIRE_TIME : SHORT_EXPIRE_TIME);
|
|
||||||
LoginRes res = new LoginRes();
|
|
||||||
res.setToken(token);
|
|
||||||
res.setUserId(userInfo.getUserId());
|
|
||||||
res.setUsername(userInfo.getUsername());
|
|
||||||
res.setEmail(userInfo.getEmail());
|
|
||||||
res.setIcon(userInfo.getIcon());
|
|
||||||
userDao.updateLastLoginTime(System.currentTimeMillis(), userInfo.getUserId());
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description: 重置密码
|
|
||||||
*
|
|
||||||
* @param body 重置密码 由于参数和注册差不多,所以用同一个表单
|
|
||||||
* @author fanxb
|
|
||||||
* @date 2019/7/9 19:59
|
|
||||||
*/
|
|
||||||
public void resetPassword(RegisterBody body) {
|
|
||||||
User user = userDao.selectByUsernameOrEmail(body.getEmail(), body.getEmail());
|
|
||||||
if (user == null) {
|
|
||||||
throw new FormDataException("用户不存在");
|
|
||||||
}
|
|
||||||
String codeKey = Constant.authCodeKey(body.getEmail());
|
|
||||||
String realCode = RedisUtil.get(codeKey, String.class);
|
|
||||||
if (StringUtil.isEmpty(realCode) || (!realCode.equals(body.getAuthCode()))) {
|
|
||||||
throw new FormDataException("验证码错误");
|
|
||||||
}
|
|
||||||
RedisUtil.delete(codeKey);
|
|
||||||
String newPassword = HashUtil.getPassword(body.getPassword());
|
|
||||||
userDao.resetPassword(newPassword, body.getEmail());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description: 根据userId获取用户信息
|
|
||||||
*
|
|
||||||
* @param userId userId
|
|
||||||
* @return com.fanxb.bookmark.common.entity.User
|
|
||||||
* @author fanxb
|
|
||||||
* @date 2019/7/30 15:57
|
|
||||||
*/
|
|
||||||
public User getUserInfo(int userId) {
|
|
||||||
return userDao.selectByUserId(userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改用户头像
|
|
||||||
*
|
|
||||||
* @param file file
|
|
||||||
* @return 访问路径
|
|
||||||
*/
|
|
||||||
public String updateIcon(MultipartFile file) throws Exception {
|
|
||||||
if (file.getSize() / NumberConstant.K_SIZE > ICON_SIZE) {
|
|
||||||
throw new FormDataException("文件大小超过限制");
|
|
||||||
}
|
|
||||||
int userId = UserContextHolder.get().getUserId();
|
|
||||||
String fileName = file.getOriginalFilename();
|
|
||||||
String path = Paths.get(FileConstant.iconPath, userId + "." + System.currentTimeMillis() + fileName.substring(fileName.lastIndexOf("."))).toString();
|
|
||||||
Path realPath = Paths.get(Constant.fileSavePath, path);
|
|
||||||
FileUtil.ensurePathExist(realPath.getParent().toString());
|
|
||||||
file.transferTo(realPath);
|
|
||||||
path = File.separator + path;
|
|
||||||
userDao.updateUserIcon(userId, path);
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 功能描述: 密码校验,校验成功返回一个actionId,以执行敏感操作
|
|
||||||
*
|
|
||||||
* @param password password
|
|
||||||
* @return java.lang.String
|
|
||||||
* @author fanxb
|
|
||||||
* @date 2019/11/11 23:41
|
|
||||||
*/
|
|
||||||
public String checkPassword(String password) {
|
|
||||||
int userId = UserContextHolder.get().getUserId();
|
|
||||||
String pass = HashUtil.getPassword(password);
|
|
||||||
User user = userDao.selectByUserId(userId);
|
|
||||||
if (!user.getPassword().equals(pass)) {
|
|
||||||
throw new FormDataException("密码错误,请重试");
|
|
||||||
}
|
|
||||||
String actionId = UUID.randomUUID().toString().replaceAll("-", "");
|
|
||||||
String key = RedisConstant.getPasswordCheckKey(userId, actionId);
|
|
||||||
RedisUtil.set(key, "1", 5 * 60 * 1000);
|
|
||||||
return actionId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -0,0 +1,92 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.fanxb.bookmark.business.user.constant.RedisConstant;
|
||||||
|
import com.fanxb.bookmark.business.user.dao.UserDao;
|
||||||
|
import com.fanxb.bookmark.business.user.service.BaseInfoService;
|
||||||
|
import com.fanxb.bookmark.business.user.vo.EmailUpdateBody;
|
||||||
|
import com.fanxb.bookmark.business.user.vo.UpdatePasswordBody;
|
||||||
|
import com.fanxb.bookmark.common.constant.CommonConstant;
|
||||||
|
import com.fanxb.bookmark.common.entity.MailInfo;
|
||||||
|
import com.fanxb.bookmark.common.entity.po.User;
|
||||||
|
import com.fanxb.bookmark.common.exception.CustomException;
|
||||||
|
import com.fanxb.bookmark.common.util.*;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类功能简述:
|
||||||
|
* 类功能详述:
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2019/9/18 15:54
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class BaseInfoServiceImpl implements BaseInfoService {
|
||||||
|
|
||||||
|
private static final String VERIFY_EMAIL = FileUtil.streamToString(BaseInfoServiceImpl.class
|
||||||
|
.getClassLoader().getResourceAsStream("verifyEmail.html"));
|
||||||
|
|
||||||
|
private static final String VERIFY_EMAIL_PATH = "/public/verifyEmail?key=";
|
||||||
|
|
||||||
|
private final UserDao userDao;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public BaseInfoServiceImpl(UserDao userDao) {
|
||||||
|
this.userDao = userDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void changePassword(UpdatePasswordBody body) {
|
||||||
|
int userId = UserContextHolder.get().getUserId();
|
||||||
|
String password = userDao.selectByUserIdOrGithubId(userId, null).getPassword();
|
||||||
|
if (StrUtil.isNotEmpty(password) && !StrUtil.equals(password, HashUtil.getPassword(body.getOldPassword()))) {
|
||||||
|
throw new CustomException("旧密码错误");
|
||||||
|
}
|
||||||
|
userDao.updatePasswordByUserId(userId, HashUtil.getPassword(body.getPassword()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateUsername(String username) {
|
||||||
|
userDao.updateUsernameByUserId(UserContextHolder.get().getUserId(), username);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void updateEmail(EmailUpdateBody body) {
|
||||||
|
int userId = UserContextHolder.get().getUserId();
|
||||||
|
String oldPassword = userDao.selectByUserIdOrGithubId(userId, null).getPassword();
|
||||||
|
if (!StrUtil.equals(oldPassword, HashUtil.getPassword(body.getOldPassword()))) {
|
||||||
|
throw new CustomException("密码校验失败,无法更新email");
|
||||||
|
}
|
||||||
|
String secret = UUID.randomUUID().toString().replaceAll("-", "");
|
||||||
|
String url = VERIFY_EMAIL.replaceAll("XXXX", CommonConstant.serviceAddress + VERIFY_EMAIL_PATH + secret);
|
||||||
|
log.debug(url);
|
||||||
|
MailInfo info = new MailInfo(body.getEmail(), "验证邮箱", url);
|
||||||
|
MailUtil.sendMail(info, true);
|
||||||
|
RedisUtil.set(RedisConstant.getUpdateEmailKey(secret), String.valueOf(userId), TimeUtil.DAY_MS);
|
||||||
|
userDao.updateNewEmailByUserId(userId, body.getEmail());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void verifyEmail(String secret) {
|
||||||
|
String key = RedisConstant.getUpdateEmailKey(secret);
|
||||||
|
Integer userId = RedisUtil.get(key, Integer.class);
|
||||||
|
RedisUtil.delete(key);
|
||||||
|
if (userId == null) {
|
||||||
|
throw new CustomException("校验失败,请重试");
|
||||||
|
}
|
||||||
|
userDao.updateEmailByUserId(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void changeDefaultSearchEngine(User user) {
|
||||||
|
userDao.updateById(user);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.service.impl;
|
||||||
|
|
||||||
|
import com.fanxb.bookmark.business.user.dao.FeedbackDao;
|
||||||
|
import com.fanxb.bookmark.business.user.entity.Feedback;
|
||||||
|
import com.fanxb.bookmark.business.user.service.FeedbackService;
|
||||||
|
import com.fanxb.bookmark.common.util.UserContextHolder;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created with IntelliJ IDEA
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* Date: 2020/3/10
|
||||||
|
* Time: 23:17
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class FeedbackServiceImpl implements FeedbackService {
|
||||||
|
private final FeedbackDao feedbackDao;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public FeedbackServiceImpl(FeedbackDao feedbackDao) {
|
||||||
|
this.feedbackDao = feedbackDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addOne(Feedback feedback) {
|
||||||
|
feedback.setUserId(UserContextHolder.get().getUserId());
|
||||||
|
feedbackDao.insertOne(feedback);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.service.impl;
|
||||||
|
|
||||||
|
import com.fanxb.bookmark.business.user.dao.NotifyAnnounceDao;
|
||||||
|
import com.fanxb.bookmark.business.user.dao.UserDao;
|
||||||
|
import com.fanxb.bookmark.business.user.entity.NotifyAnnounce;
|
||||||
|
import com.fanxb.bookmark.business.user.service.NotifyAnnounceService;
|
||||||
|
import com.fanxb.bookmark.business.user.vo.UserNotifyAnnounceRes;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021-10-17 14:16
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class NotifyAnnounceServiceImpl implements NotifyAnnounceService {
|
||||||
|
@Autowired
|
||||||
|
private NotifyAnnounceDao notifyAnnounceDao;
|
||||||
|
@Autowired
|
||||||
|
private UserDao userDao;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public List<UserNotifyAnnounceRes> getUserAnnounce(int userId, int status) {
|
||||||
|
notifyAnnounceDao.dealNotifyAnnounceById(userId);
|
||||||
|
userDao.updateOneColumnByOneTerm("lastSyncAnnounceDate", System.currentTimeMillis(), "userId", userId);
|
||||||
|
return notifyAnnounceDao.queryUserAnnounce(userId, status, System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void markAsRead(int userId, int notifyAnnounceId) {
|
||||||
|
notifyAnnounceDao.markAsRead(userId, notifyAnnounceId, System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,122 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.fanxb.bookmark.business.user.dao.UserDao;
|
||||||
|
import com.fanxb.bookmark.business.user.service.OauthService;
|
||||||
|
import com.fanxb.bookmark.business.user.service.SearchEngineService;
|
||||||
|
import com.fanxb.bookmark.business.user.service.UserService;
|
||||||
|
import com.fanxb.bookmark.business.user.vo.OauthBody;
|
||||||
|
import com.fanxb.bookmark.common.constant.CommonConstant;
|
||||||
|
import com.fanxb.bookmark.common.entity.po.User;
|
||||||
|
import com.fanxb.bookmark.common.exception.CustomException;
|
||||||
|
import com.fanxb.bookmark.common.util.HttpUtil;
|
||||||
|
import com.fanxb.bookmark.common.util.JwtUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.fanxb.bookmark.business.user.service.UserService.LONG_EXPIRE_TIME;
|
||||||
|
import static com.fanxb.bookmark.business.user.service.UserService.SHORT_EXPIRE_TIME;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OAuth交互类
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/10
|
||||||
|
**/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class OauthServiceImpl implements OauthService {
|
||||||
|
|
||||||
|
@Value("${OAuth.github.clientId}")
|
||||||
|
private String githubClientId;
|
||||||
|
@Value("${OAuth.github.secret}")
|
||||||
|
private String githubSecret;
|
||||||
|
@Autowired
|
||||||
|
private SearchEngineService searchEngineService;
|
||||||
|
private final UserDao userDao;
|
||||||
|
private final UserService userService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public OauthServiceImpl(UserDao userDao, UserService userService) {
|
||||||
|
this.userDao = userDao;
|
||||||
|
this.userService = userService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public String oAuthCheck(OauthBody body) {
|
||||||
|
User current, other = new User();
|
||||||
|
if (StrUtil.equals(body.getType(), OauthBody.GITHUB)) {
|
||||||
|
Map<String, String> header = new HashMap<>(2);
|
||||||
|
header.put("accept", "application/json");
|
||||||
|
String url = "https://github.com/login/oauth/access_token?client_id=" + githubClientId + "&client_secret=" + githubSecret + "&code=" + body.getCode();
|
||||||
|
JSONObject obj = HttpUtil.getObj(url, header, true);
|
||||||
|
String accessToken = obj.getString("access_token");
|
||||||
|
if (StrUtil.isEmpty(accessToken)) {
|
||||||
|
throw new CustomException("github登陆失败,请稍后重试");
|
||||||
|
}
|
||||||
|
header.put("Authorization", "token " + accessToken);
|
||||||
|
JSONObject userInfo = HttpUtil.getObj("https://api.github.com/user", header, true);
|
||||||
|
other.setGithubId(userInfo.getLong("id"));
|
||||||
|
if (other.getGithubId() == null) {
|
||||||
|
log.error("github返回异常:{}", userInfo);
|
||||||
|
throw new CustomException("登陆异常,请稍后重试");
|
||||||
|
}
|
||||||
|
other.setEmail(userInfo.getString("email"));
|
||||||
|
other.setIcon(userInfo.getString("avatar_url"));
|
||||||
|
other.setUsername(userInfo.getString("login"));
|
||||||
|
current = userDao.selectByUserIdOrGithubId(null, other.getGithubId());
|
||||||
|
if (current == null) {
|
||||||
|
current = userDao.selectByUsernameOrEmail(null, other.getEmail());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new CustomException("不支持的登陆方式" + body.getType());
|
||||||
|
}
|
||||||
|
User newest = dealOauth(current, other);
|
||||||
|
return JwtUtil.encode(Collections.singletonMap("userId", String.valueOf(newest.getUserId())), CommonConstant.jwtSecret
|
||||||
|
, body.isRememberMe() ? LONG_EXPIRE_TIME : SHORT_EXPIRE_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* oauth登陆
|
||||||
|
*
|
||||||
|
* @param current 当前是否存在该用户
|
||||||
|
* @param other 第三方获取的数据
|
||||||
|
* @return User 最新的用户信息
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/11
|
||||||
|
**/
|
||||||
|
private User dealOauth(User current, User other) {
|
||||||
|
if (current == null) {
|
||||||
|
//判断用户名是否可用
|
||||||
|
if (userDao.usernameExist(other.getUsername())) {
|
||||||
|
other.setUsername(userService.createNewUsername());
|
||||||
|
}
|
||||||
|
other.setPassword("");
|
||||||
|
other.setCreateTime(System.currentTimeMillis());
|
||||||
|
other.setLastLoginTime(System.currentTimeMillis());
|
||||||
|
other.setIcon(UserService.DEFAULT_ICON);
|
||||||
|
other.setCreateTime(System.currentTimeMillis());
|
||||||
|
other.setLastLoginTime(System.currentTimeMillis());
|
||||||
|
other.setVersion(0);
|
||||||
|
userDao.addOne(other);
|
||||||
|
searchEngineService.newUserInit(other.getUserId());
|
||||||
|
return other;
|
||||||
|
} else {
|
||||||
|
if (!current.getEmail().equals(other.getEmail()) || !current.getGithubId().equals(other.getGithubId())) {
|
||||||
|
current.setEmail(other.getEmail());
|
||||||
|
current.setGithubId(other.getGithubId());
|
||||||
|
userDao.updateEmailAndGithubId(current);
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.alibaba.druid.support.ibatis.SpringIbatisBeanNameAutoProxyCreator;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
|
import com.fanxb.bookmark.business.user.dao.SearchEngineDao;
|
||||||
|
import com.fanxb.bookmark.business.user.dao.UserDao;
|
||||||
|
import com.fanxb.bookmark.business.user.entity.SearchEngine;
|
||||||
|
import com.fanxb.bookmark.business.user.service.SearchEngineService;
|
||||||
|
import com.fanxb.bookmark.common.entity.UserContext;
|
||||||
|
import com.fanxb.bookmark.common.entity.po.User;
|
||||||
|
import com.fanxb.bookmark.common.exception.CustomException;
|
||||||
|
import com.fanxb.bookmark.common.util.UserContextHolder;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class SearchEngineServiceImpl implements SearchEngineService {
|
||||||
|
@Autowired
|
||||||
|
private SearchEngineDao searchEngineDao;
|
||||||
|
@Autowired
|
||||||
|
private UserDao userDao;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SearchEngine> list() {
|
||||||
|
return searchEngineDao.selectList(new LambdaQueryWrapper<SearchEngine>().eq(SearchEngine::getUserId, UserContextHolder.get().getUserId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteOne(int id) {
|
||||||
|
SearchEngine engine = searchEngineDao.selectById(id);
|
||||||
|
if (engine.getUserId() != UserContextHolder.get().getUserId()) {
|
||||||
|
throw new CustomException("无法操作其他人数据");
|
||||||
|
}
|
||||||
|
if (engine.getChecked() == 1) {
|
||||||
|
throw new CustomException("默认搜索引擎无法删除");
|
||||||
|
}
|
||||||
|
searchEngineDao.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insertOne(SearchEngine body) {
|
||||||
|
checkOne(body);
|
||||||
|
body.setId(null).setChecked(0).setUserId(UserContextHolder.get().getUserId());
|
||||||
|
searchEngineDao.insert(body);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkOne(SearchEngine body) {
|
||||||
|
if (StrUtil.hasBlank(body.getIcon(), body.getUrl(), body.getName())) {
|
||||||
|
throw new CustomException("请填写完整");
|
||||||
|
}
|
||||||
|
if (!body.getUrl().contains("%s")) {
|
||||||
|
throw new CustomException("路径中必须包含%s");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void editOne(SearchEngine body) {
|
||||||
|
SearchEngine engine = searchEngineDao.selectById(body.getId());
|
||||||
|
if (engine.getUserId() != UserContextHolder.get().getUserId()) {
|
||||||
|
throw new CustomException("无法操作其他人数据");
|
||||||
|
}
|
||||||
|
checkOne(body);
|
||||||
|
searchEngineDao.updateById(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void setChecked(Integer id) {
|
||||||
|
int userId = UserContextHolder.get().getUserId();
|
||||||
|
LambdaUpdateWrapper<SearchEngine> update = new LambdaUpdateWrapper<SearchEngine>().set(SearchEngine::getChecked, 0).eq(SearchEngine::getUserId, userId).eq(SearchEngine::getChecked, 1);
|
||||||
|
searchEngineDao.update(null, update);
|
||||||
|
update = new LambdaUpdateWrapper<SearchEngine>().set(SearchEngine::getChecked, 1).eq(SearchEngine::getId, id).eq(SearchEngine::getUserId, userId);
|
||||||
|
searchEngineDao.update(null, update);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void newUserInit(int userId) {
|
||||||
|
searchEngineDao.insert(new SearchEngine().setUserId(userId).setIcon("icon-baidu").setName("百度").setUrl("https://www.baidu.com/s?ie=UTF-8&wd=%s").setChecked(1));
|
||||||
|
searchEngineDao.insert(new SearchEngine().setUserId(userId).setIcon("icon-bing").setName("必应").setUrl("https://www.bing.com/search?q=%s").setChecked(0));
|
||||||
|
searchEngineDao.insert(new SearchEngine().setUserId(userId).setIcon("icon-google").setName("谷歌").setUrl("https://www.google.com/search?q=%s").setChecked(0));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.service.impl;
|
||||||
|
|
||||||
|
import com.fanxb.bookmark.business.api.UserApi;
|
||||||
|
import com.fanxb.bookmark.business.user.dao.UserDao;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/8/20 下午2:15
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class UserApiImpl implements UserApi {
|
||||||
|
private final UserDao userDao;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public UserApiImpl(UserDao userDao) {
|
||||||
|
this.userDao = userDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void versionPlus(int userId) {
|
||||||
|
userDao.updateUserVersion(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void allUserVersionPlus() {
|
||||||
|
userDao.updateAllBookmarkUpdateVersion();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,274 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.RandomUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.fanxb.bookmark.business.api.BookmarkApi;
|
||||||
|
import com.fanxb.bookmark.business.user.constant.FileConstant;
|
||||||
|
import com.fanxb.bookmark.business.user.dao.UserDao;
|
||||||
|
import com.fanxb.bookmark.business.user.service.SearchEngineService;
|
||||||
|
import com.fanxb.bookmark.business.user.service.UserService;
|
||||||
|
import com.fanxb.bookmark.business.user.vo.LoginBody;
|
||||||
|
import com.fanxb.bookmark.business.user.vo.RegisterBody;
|
||||||
|
import com.fanxb.bookmark.common.constant.CommonConstant;
|
||||||
|
import com.fanxb.bookmark.common.constant.NumberConstant;
|
||||||
|
import com.fanxb.bookmark.common.constant.RedisConstant;
|
||||||
|
import com.fanxb.bookmark.common.entity.MailInfo;
|
||||||
|
import com.fanxb.bookmark.common.entity.po.User;
|
||||||
|
import com.fanxb.bookmark.common.exception.CustomException;
|
||||||
|
import com.fanxb.bookmark.common.exception.FormDataException;
|
||||||
|
import com.fanxb.bookmark.common.util.*;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类功能简述:
|
||||||
|
* 类功能详述:
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2019/7/5 17:39
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class UserServiceImpl implements UserService {
|
||||||
|
/**
|
||||||
|
* 登陆最大重试次数
|
||||||
|
*/
|
||||||
|
private static final int LOGIN_COUNT = 5;
|
||||||
|
@Autowired
|
||||||
|
private SearchEngineService searchEngineService;
|
||||||
|
|
||||||
|
private final UserDao userDao;
|
||||||
|
private final StringRedisTemplate redisTemplate;
|
||||||
|
private final BookmarkApi bookmarkApi;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public UserServiceImpl(UserDao userDao, StringRedisTemplate redisTemplate, BookmarkApi bookmarkApi) {
|
||||||
|
this.userDao = userDao;
|
||||||
|
this.redisTemplate = redisTemplate;
|
||||||
|
this.bookmarkApi = bookmarkApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 向目标发送验证码
|
||||||
|
*
|
||||||
|
* @param email 目标
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2019/7/5 17:48
|
||||||
|
*/
|
||||||
|
public void sendAuthCode(String email) {
|
||||||
|
MailInfo info = new MailInfo();
|
||||||
|
info.setSubject("签签世界注册验证码");
|
||||||
|
String code = StringUtil.getRandomString(6, 2);
|
||||||
|
info.setContent("欢迎注册 签签世界 ,本次验证码");
|
||||||
|
info.setContent(code + " 是您的验证码,注意验证码有效期为15分钟哦!");
|
||||||
|
info.setReceiver(email);
|
||||||
|
if (CommonConstant.isDev) {
|
||||||
|
code = "123456";
|
||||||
|
} else {
|
||||||
|
MailUtil.sendTextMail(info);
|
||||||
|
}
|
||||||
|
RedisUtil.set(CommonConstant.authCodeKey(email), code, CommonConstant.AUTH_CODE_EXPIRE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 用户注册
|
||||||
|
*
|
||||||
|
* @param body 注册表单
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2019/7/6 11:30
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public String register(RegisterBody body) {
|
||||||
|
User user = userDao.selectByUsernameOrEmail(body.getUsername(), body.getEmail());
|
||||||
|
if (user != null) {
|
||||||
|
if (user.getUsername().equals(body.getUsername())) {
|
||||||
|
throw new FormDataException("用户名已经被注册");
|
||||||
|
}
|
||||||
|
if (user.getEmail().equals(body.getEmail())) {
|
||||||
|
throw new FormDataException("邮箱已经被注册");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
user = new User();
|
||||||
|
user.setUsername(body.getUsername());
|
||||||
|
user.setEmail(body.getEmail());
|
||||||
|
user.setIcon(DEFAULT_ICON);
|
||||||
|
user.setPassword(HashUtil.sha1(HashUtil.md5(body.getPassword())));
|
||||||
|
user.setCreateTime(System.currentTimeMillis());
|
||||||
|
user.setLastLoginTime(System.currentTimeMillis());
|
||||||
|
user.setVersion(0);
|
||||||
|
userDao.addOne(user);
|
||||||
|
searchEngineService.newUserInit(user.getUserId());
|
||||||
|
Map<String, String> data = new HashMap<>(1);
|
||||||
|
data.put("userId", String.valueOf(user.getUserId()));
|
||||||
|
return JwtUtil.encode(data, CommonConstant.jwtSecret, LONG_EXPIRE_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 登录
|
||||||
|
*
|
||||||
|
* @param body 登录表单
|
||||||
|
* @return string
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2019/7/6 16:37
|
||||||
|
*/
|
||||||
|
public String login(LoginBody body) {
|
||||||
|
String key = RedisConstant.getUserFailCountKey(body.getStr());
|
||||||
|
String count = redisTemplate.opsForValue().get(key);
|
||||||
|
if (count != null && Integer.parseInt(count) >= LOGIN_COUNT) {
|
||||||
|
redisTemplate.expire(key, 30, TimeUnit.MINUTES);
|
||||||
|
throw new FormDataException("您已连续输错密码5次,请30分钟后再试,或联系管理员处理");
|
||||||
|
}
|
||||||
|
User userInfo = userDao.selectByUsernameOrEmail(body.getStr(), body.getStr());
|
||||||
|
if (userInfo == null || StrUtil.isEmpty(userInfo.getPassword()) || !HashUtil.sha1(HashUtil.md5(body.getPassword())).equals(userInfo.getPassword())) {
|
||||||
|
redisTemplate.opsForValue().set(key, count == null ? "1" : String.valueOf(Integer.parseInt(count) + 1), 30, TimeUnit.MINUTES);
|
||||||
|
throw new FormDataException("账号密码错误");
|
||||||
|
}
|
||||||
|
redisTemplate.delete(key);
|
||||||
|
userDao.updateLastLoginTime(System.currentTimeMillis(), userInfo.getUserId());
|
||||||
|
return JwtUtil.encode(Collections.singletonMap("userId", String.valueOf(userInfo.getUserId())), CommonConstant.jwtSecret
|
||||||
|
, body.isRememberMe() ? LONG_EXPIRE_TIME : SHORT_EXPIRE_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 重置密码
|
||||||
|
*
|
||||||
|
* @param body 重置密码 由于参数和注册差不多,所以用同一个表单
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2019/7/9 19:59
|
||||||
|
*/
|
||||||
|
public void resetPassword(RegisterBody body) {
|
||||||
|
User user = userDao.selectByUsernameOrEmail(body.getEmail(), body.getEmail());
|
||||||
|
if (user == null) {
|
||||||
|
throw new FormDataException("用户不存在");
|
||||||
|
}
|
||||||
|
String codeKey = CommonConstant.authCodeKey(body.getEmail());
|
||||||
|
String realCode = RedisUtil.get(codeKey, String.class);
|
||||||
|
if (StringUtil.isEmpty(realCode) || (!realCode.equals(body.getAuthCode()))) {
|
||||||
|
throw new FormDataException("验证码错误");
|
||||||
|
}
|
||||||
|
RedisUtil.delete(codeKey);
|
||||||
|
String newPassword = HashUtil.getPassword(body.getPassword());
|
||||||
|
userDao.resetPassword(newPassword, body.getEmail());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description: 根据userId获取用户信息
|
||||||
|
*
|
||||||
|
* @param userId userId
|
||||||
|
* @return com.fanxb.bookmark.common.entity.po.User
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2019/7/30 15:57
|
||||||
|
*/
|
||||||
|
public User getUserInfo(int userId) {
|
||||||
|
User user = userDao.selectByUserIdOrGithubId(userId, null);
|
||||||
|
user.setNoPassword(StrUtil.isEmpty(user.getPassword()));
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改用户头像
|
||||||
|
*
|
||||||
|
* @param file file
|
||||||
|
* @return 访问路径
|
||||||
|
*/
|
||||||
|
public String updateIcon(MultipartFile file) throws Exception {
|
||||||
|
if (file.getSize() / NumberConstant.K_SIZE > ICON_SIZE) {
|
||||||
|
throw new FormDataException("文件大小超过限制");
|
||||||
|
}
|
||||||
|
int userId = UserContextHolder.get().getUserId();
|
||||||
|
String fileName = file.getOriginalFilename();
|
||||||
|
assert fileName != null;
|
||||||
|
String path = Paths.get(FileConstant.iconPath, userId + "." + System.currentTimeMillis() + fileName.substring(fileName.lastIndexOf("."))).toString();
|
||||||
|
Path realPath = Paths.get(CommonConstant.fileSavePath, path);
|
||||||
|
FileUtil.ensurePathExist(realPath.getParent().toString());
|
||||||
|
file.transferTo(realPath);
|
||||||
|
path = File.separator + path;
|
||||||
|
userDao.updateUserIcon(userId, path);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能描述: 密码校验,校验成功返回一个actionId,以执行敏感操作
|
||||||
|
*
|
||||||
|
* @param password password
|
||||||
|
* @return java.lang.String
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2019/11/11 23:41
|
||||||
|
*/
|
||||||
|
public String checkPassword(String password) {
|
||||||
|
int userId = UserContextHolder.get().getUserId();
|
||||||
|
String pass = HashUtil.getPassword(password);
|
||||||
|
User user = userDao.selectByUserIdOrGithubId(userId, null);
|
||||||
|
if (!user.getPassword().equals(pass)) {
|
||||||
|
throw new FormDataException("密码错误,请重试");
|
||||||
|
}
|
||||||
|
String actionId = UUID.randomUUID().toString().replaceAll("-", "");
|
||||||
|
String key = RedisConstant.getPasswordCheckKey(userId, actionId);
|
||||||
|
RedisUtil.set(key, "1", 5 * 60 * 1000);
|
||||||
|
return actionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String createNewUsername() {
|
||||||
|
while (true) {
|
||||||
|
String name = RandomUtil.randomString(8);
|
||||||
|
if (!userDao.usernameExist(name)) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCurrentUserVersion(int userId) {
|
||||||
|
return userDao.getUserVersion(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateAllUserIcon() {
|
||||||
|
if (!UserContextHolder.get().getManageUser()) {
|
||||||
|
throw new CustomException("非管理员用户,无法执行操作");
|
||||||
|
}
|
||||||
|
ThreadPoolUtil.execute(() -> {
|
||||||
|
log.info("开始更新所有人icon");
|
||||||
|
int start = 0, size = 1000;
|
||||||
|
List<Integer> ids;
|
||||||
|
while ((ids = userDao.selectUserIdPage(start, size)).size() > 0) {
|
||||||
|
start += size;
|
||||||
|
ids.forEach(bookmarkApi::updateUserBookmarkIcon);
|
||||||
|
}
|
||||||
|
log.info("结束更新所有人icon");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Integer, Set<String>> dealAllUserBookmark(boolean delete) {
|
||||||
|
if (!UserContextHolder.get().getManageUser()) {
|
||||||
|
throw new CustomException("非管理员用户,无法执行操作");
|
||||||
|
}
|
||||||
|
log.info("开始处理所有问题书签数据");
|
||||||
|
int start = 0, size = 1000;
|
||||||
|
List<Integer> ids;
|
||||||
|
Map<Integer, Set<String>> res = new HashMap<>(1000);
|
||||||
|
while ((ids = userDao.selectUserIdPage(start, size)).size() > 0) {
|
||||||
|
start += size;
|
||||||
|
ids.forEach(id -> {
|
||||||
|
Set<String> oneUser = bookmarkApi.dealBadBookmark(delete, id);
|
||||||
|
if (oneUser.size() > 0) {
|
||||||
|
res.put(id, oneUser);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
log.info("处理完毕");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package com.fanxb.bookmark.business.user.entity;
|
package com.fanxb.bookmark.business.user.vo;
|
||||||
|
|
||||||
import com.fanxb.bookmark.business.user.constant.ValidatedConstant;
|
import com.fanxb.bookmark.business.user.constant.ValidatedConstant;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -17,7 +17,7 @@ import javax.validation.constraints.Pattern;
|
|||||||
@Data
|
@Data
|
||||||
public class EmailUpdateBody {
|
public class EmailUpdateBody {
|
||||||
@NotNull(message = "参数不为空")
|
@NotNull(message = "参数不为空")
|
||||||
private String actionId;
|
private String oldPassword;
|
||||||
@Email(message = "请输入有效邮箱地址")
|
@Email(message = "请输入有效邮箱地址")
|
||||||
private String email;
|
private String email;
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package com.fanxb.bookmark.business.user.entity;
|
package com.fanxb.bookmark.business.user.vo;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.vo;
|
||||||
|
|
||||||
|
import com.fanxb.bookmark.common.entity.po.User;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类功能简述:登录返回数据
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2019/7/6 16:52
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class LoginRes {
|
||||||
|
/**
|
||||||
|
* 用户信息
|
||||||
|
*/
|
||||||
|
private User user;
|
||||||
|
/**
|
||||||
|
* token
|
||||||
|
*/
|
||||||
|
private String token;
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 第三方登陆入参
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/3/10
|
||||||
|
**/
|
||||||
|
@Data
|
||||||
|
public class OauthBody {
|
||||||
|
public static final String GITHUB = "github";
|
||||||
|
/**
|
||||||
|
* 类别
|
||||||
|
*/
|
||||||
|
private String type;
|
||||||
|
/**
|
||||||
|
* 识别码
|
||||||
|
*/
|
||||||
|
private String code;
|
||||||
|
/**
|
||||||
|
* 是否保持登陆
|
||||||
|
*/
|
||||||
|
private boolean rememberMe;
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import javax.validation.constraints.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类功能简述: 注册表单
|
||||||
|
* 类功能详述:
|
||||||
|
*
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2019/7/6 11:23
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class RegisterBody {
|
||||||
|
@NotBlank(message = "用户名不能为空")
|
||||||
|
@Pattern(regexp = "^\\w{1,50}$", message = "用户名长度为1-50")
|
||||||
|
private String username;
|
||||||
|
@NotBlank(message = "密码不能为空")
|
||||||
|
@Pattern(regexp = "^\\w{6,18}$", message = "密码为6-18位组合")
|
||||||
|
private String password;
|
||||||
|
@NotBlank(message = "邮箱不能为空")
|
||||||
|
private String email;
|
||||||
|
private String authCode;
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package com.fanxb.bookmark.business.user.entity;
|
package com.fanxb.bookmark.business.user.vo;
|
||||||
|
|
||||||
import com.fanxb.bookmark.business.user.constant.ValidatedConstant;
|
import com.fanxb.bookmark.business.user.constant.ValidatedConstant;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -15,7 +15,7 @@ import javax.validation.constraints.Pattern;
|
|||||||
@Data
|
@Data
|
||||||
public class UpdatePasswordBody {
|
public class UpdatePasswordBody {
|
||||||
|
|
||||||
private String actionId;
|
private String oldPassword;
|
||||||
@Pattern(regexp = ValidatedConstant.PASSWORD_REG, message = ValidatedConstant.PASSWORD_MESSAGE)
|
@Pattern(regexp = ValidatedConstant.PASSWORD_REG, message = ValidatedConstant.PASSWORD_MESSAGE)
|
||||||
private String password;
|
private String password;
|
||||||
}
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.fanxb.bookmark.business.user.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021-10-17 14:22
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class UserNotifyAnnounceRes {
|
||||||
|
private int notifyAnnounceId;
|
||||||
|
private String title;
|
||||||
|
private String content;
|
||||||
|
private long readDate;
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package com.fanxb.bookmark.business.user.entity;
|
package com.fanxb.bookmark.business.user.vo;
|
||||||
|
|
||||||
import com.fanxb.bookmark.business.user.constant.ValidatedConstant;
|
import com.fanxb.bookmark.business.user.constant.ValidatedConstant;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* @description: 前后端交互类
|
||||||
|
* @author: fanxb
|
||||||
|
* @param: null
|
||||||
|
* @return:
|
||||||
|
* @date: 2021/3/10
|
||||||
|
*/
|
||||||
|
package com.fanxb.bookmark.business.user.vo;
|
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.fanxb.bookmark.business.user.dao.NotifyAnnounceDao">
|
||||||
|
|
||||||
|
<select id="queryUserAnnounce" resultType="com.fanxb.bookmark.business.user.vo.UserNotifyAnnounceRes">
|
||||||
|
select b.notifyAnnounceId,b.title,b.content,a.readDate from user_notify_announce a inner join notify_announce b
|
||||||
|
on a.notifyAnnounceId=b.notifyAnnounceId where a.userId=#{userId} and a.status=#{status}
|
||||||
|
<if test="status == 0">
|
||||||
|
and b.startDate<#{date} and b.endDate>#{date}
|
||||||
|
</if>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
|
||||||
|
</mapper>
|
@ -1,44 +1,40 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
<mapper namespace="com.fanxb.bookmark.business.user.dao.UserDao">
|
<mapper namespace="com.fanxb.bookmark.business.user.dao.UserDao">
|
||||||
|
|
||||||
|
|
||||||
<insert id="addOne">
|
<insert id="addOne" useGeneratedKeys="true" keyColumn="userId" keyProperty="userId">
|
||||||
insert into user (username, email, icon, password, createTime, lastLoginTime)
|
insert into user (username, email, icon, password, createTime, lastLoginTime, version)
|
||||||
value
|
value
|
||||||
(#{username}, #{email}, #{icon}, #{password}, #{createTime}, #{lastLoginTime})
|
(#{username}, #{email}, #{icon}, #{password}, #{createTime}, #{lastLoginTime}, #{version})
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
<select id="selectByUsernameOrEmail" resultType="com.fanxb.bookmark.common.entity.User">
|
<select id="selectByUsernameOrEmail" resultType="com.fanxb.bookmark.common.entity.po.User">
|
||||||
select
|
select *
|
||||||
userId,
|
from user
|
||||||
username,
|
where username = #{name}
|
||||||
email,
|
or email = #{email}
|
||||||
icon,
|
limit 1
|
||||||
password,
|
</select>
|
||||||
createTime
|
|
||||||
from user
|
<update id="updateLastLoginTime">
|
||||||
where username = #{name} or email = #{email}
|
update user
|
||||||
limit 1
|
set lastLoginTime = #{time}
|
||||||
</select>
|
where userId = #{userId}
|
||||||
|
</update>
|
||||||
<update id="updateLastLoginTime">
|
|
||||||
update user
|
<update id="resetPassword">
|
||||||
set lastLoginTime = #{time}
|
update user
|
||||||
where userId = #{userId}
|
set password = #{password}
|
||||||
</update>
|
where email = #{email}
|
||||||
|
</update>
|
||||||
<update id="resetPassword">
|
|
||||||
update user
|
<select id="selectByUserIdOrGithubId" resultType="com.fanxb.bookmark.common.entity.po.User">
|
||||||
set password = #{password}
|
select *
|
||||||
where email = #{email}
|
from user
|
||||||
</update>
|
where userId = #{userId}
|
||||||
|
or githubId = #{githubId}
|
||||||
<select id="selectByUserId" resultType="com.fanxb.bookmark.common.entity.User">
|
</select>
|
||||||
select *
|
|
||||||
from user
|
|
||||||
where userId = #{userId}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
@ -37,53 +37,87 @@
|
|||||||
<artifactId>commons-pool2</artifactId>
|
<artifactId>commons-pool2</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!--mybatis依赖-->
|
|
||||||
<!-- <dependency>-->
|
|
||||||
<!-- <groupId>org.mybatis.spring.boot</groupId>-->
|
|
||||||
<!-- <artifactId>mybatis-spring-boot-starter</artifactId>-->
|
|
||||||
<!-- <version>2.0.1</version>-->
|
|
||||||
<!-- </dependency>-->
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||||
<version>3.2.0</version>
|
<version>3.5.3.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
|
<version>2.5.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!--druid连接池依赖-->
|
<!--druid连接池依赖-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba</groupId>
|
<groupId>com.alibaba</groupId>
|
||||||
<artifactId>druid-spring-boot-starter</artifactId>
|
<artifactId>druid-spring-boot-starter</artifactId>
|
||||||
<version>1.1.18</version>
|
<version>1.2.18</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!--数据库版本管理-->
|
<!--数据库版本管理-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.flywaydb</groupId>
|
<groupId>org.flywaydb</groupId>
|
||||||
<artifactId>flyway-core</artifactId>
|
<artifactId>flyway-core</artifactId>
|
||||||
<version>5.2.4</version>
|
<version>9.21.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.flywaydb</groupId>
|
||||||
|
<artifactId>flyway-mysql</artifactId>
|
||||||
|
<version>9.21.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!--mysql jdbc依赖-->
|
<!--mysql jdbc依赖-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>mysql</groupId>
|
<groupId>mysql</groupId>
|
||||||
<artifactId>mysql-connector-java</artifactId>
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
<version>8.0.33</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- <!–邮件依赖–>-->
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>org.springframework.boot</groupId>-->
|
||||||
|
<!-- <artifactId>spring-boot-starter-mail</artifactId>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
|
|
||||||
|
<!-- <!–减负依赖–>-->
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>org.projectlombok</groupId>-->
|
||||||
|
<!-- <artifactId>lombok</artifactId>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
|
<!-- <!–json工具依赖–>-->
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>com.alibaba</groupId>-->
|
||||||
|
<!-- <artifactId>fastjson</artifactId>-->
|
||||||
|
<!-- <version>1.2.83</version>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>org.elasticsearch.client</groupId>-->
|
||||||
|
<!-- <artifactId>elasticsearch-rest-high-level-client</artifactId>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
|
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>cn.hutool</groupId>-->
|
||||||
|
<!-- <artifactId>hutool-all</artifactId>-->
|
||||||
|
<!-- <version>5.8.21</version>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
|
|
||||||
|
<!--单元测试-->
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
|
||||||
|
<!--mysql jdbc依赖-->
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>mysql</groupId>-->
|
||||||
|
<!-- <artifactId>mysql-connector-java</artifactId>-->
|
||||||
|
<!-- <version>8.0.33</version>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
|
|
||||||
<!--邮件依赖-->
|
<!--邮件依赖-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-mail</artifactId>
|
<artifactId>spring-boot-starter-mail</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!--减负依赖-->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.projectlombok</groupId>
|
|
||||||
<artifactId>lombok</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<!--json工具依赖-->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.alibaba</groupId>
|
|
||||||
<artifactId>fastjson</artifactId>
|
|
||||||
<version>1.2.56</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!--减负依赖-->
|
<!--减负依赖-->
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -94,7 +128,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba</groupId>
|
<groupId>com.alibaba</groupId>
|
||||||
<artifactId>fastjson</artifactId>
|
<artifactId>fastjson</artifactId>
|
||||||
<version>1.2.56</version>
|
<version>1.2.83</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
@ -103,6 +137,11 @@
|
|||||||
<artifactId>elasticsearch-rest-high-level-client</artifactId>
|
<artifactId>elasticsearch-rest-high-level-client</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-all</artifactId>
|
||||||
|
<version>5.8.25</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!--单元测试-->
|
<!--单元测试-->
|
||||||
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
|
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
package com.fanxb.bookmark.common.annotation;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.validation.constraints.Null;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义消费者注解
|
||||||
|
* Created with IntelliJ IDEA
|
||||||
|
* Created By Fxb
|
||||||
|
* Date: 2020/3/26
|
||||||
|
* Time: 15:26
|
||||||
|
*/
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Component
|
||||||
|
public @interface MqConsumer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 队列主题
|
||||||
|
*/
|
||||||
|
String value() default "default_es_topic";
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,126 @@
|
|||||||
|
package com.fanxb.bookmark.common.configuration;
|
||||||
|
|
||||||
|
import com.fanxb.bookmark.common.annotation.MqConsumer;
|
||||||
|
import com.fanxb.bookmark.common.entity.redis.RedisConsumer;
|
||||||
|
import com.fanxb.bookmark.common.factory.ThreadPoolFactory;
|
||||||
|
import com.fanxb.bookmark.common.util.RedisUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.DisposableBean;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.ApplicationArguments;
|
||||||
|
import org.springframework.boot.ApplicationRunner;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created with IntelliJ IDEA
|
||||||
|
* Created By Fxb
|
||||||
|
* Date: 2020/3/24
|
||||||
|
* Time: 15:37
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class MqConfiguration implements ApplicationRunner, DisposableBean {
|
||||||
|
/**
|
||||||
|
* 是否运行
|
||||||
|
*/
|
||||||
|
private static volatile boolean isRun = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订阅对象与执行方法关系(支持广播模式)
|
||||||
|
*/
|
||||||
|
private static final Map<String, List<RedisConsumer>> topicMap = new HashMap<>();
|
||||||
|
/**
|
||||||
|
* 执行线程池
|
||||||
|
*/
|
||||||
|
private static final ThreadPoolExecutor threadPoolExecutor = ThreadPoolFactory.createPool(2, 8, 5000, 1000, "mqConsumer");
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
ApplicationContext context;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(ApplicationArguments args) {
|
||||||
|
Map<String, Object> map = context.getBeansWithAnnotation(MqConsumer.class);
|
||||||
|
map.values().forEach(item -> {
|
||||||
|
if (!(item instanceof RedisConsumer)) {
|
||||||
|
log.warn("注意检测到被@EsConsumer注解的类{}未实现RedisConsumer接口", item.getClass().getCanonicalName());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MqConsumer[] annotations = item.getClass().getAnnotationsByType(MqConsumer.class);
|
||||||
|
MqConsumer annotation = annotations[0];
|
||||||
|
topicMap.computeIfAbsent(annotation.value(), k -> new ArrayList<>()).add((RedisConsumer) item);
|
||||||
|
});
|
||||||
|
log.info("redis订阅信息汇总完毕!!!!!!");
|
||||||
|
//由一个线程始终循环获取es队列数据
|
||||||
|
threadPoolExecutor.execute(loop());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
log.info("进程结束,关闭redis");
|
||||||
|
isRun = false;
|
||||||
|
ThreadPoolFactory.shutdown(threadPoolExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Runnable loop() {
|
||||||
|
return () -> {
|
||||||
|
while (isRun) {
|
||||||
|
AtomicInteger count = new AtomicInteger(0);
|
||||||
|
topicMap.forEach((k, v) -> {
|
||||||
|
try {
|
||||||
|
String message = RedisUtil.redisTemplate.opsForList().rightPop(k);
|
||||||
|
if (message == null) {
|
||||||
|
count.getAndIncrement();
|
||||||
|
} else {
|
||||||
|
pushTask(v, message, k);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("redis消息队列异常", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (count.get() == topicMap.keySet().size()) {
|
||||||
|
//当所有的队列都为空时休眠3s
|
||||||
|
try {
|
||||||
|
TimeUnit.SECONDS.sleep(3);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("休眠出错", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能描述: 推送任务到线程池中执行
|
||||||
|
*
|
||||||
|
* @param list list
|
||||||
|
* @param value value
|
||||||
|
* @param key key
|
||||||
|
* @author 123
|
||||||
|
* @date 2020/3/28 23:52
|
||||||
|
*/
|
||||||
|
private void pushTask(List<RedisConsumer> list, String value, String key) {
|
||||||
|
for (RedisConsumer consumer : list) {
|
||||||
|
threadPoolExecutor.execute(() -> {
|
||||||
|
try {
|
||||||
|
consumer.deal(value);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("执行消费任务出错", e);
|
||||||
|
if (list.size() == 1) {
|
||||||
|
//非广播消息进行数据回补
|
||||||
|
RedisUtil.redisTemplate.opsForList().rightPush(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,9 @@
|
|||||||
package com.fanxb.bookmark.common.configuration;
|
package com.fanxb.bookmark.common.configuration;
|
||||||
|
|
||||||
import com.fanxb.bookmark.common.factory.CustomThreadFactory;
|
import com.fanxb.bookmark.common.factory.CustomThreadFactory;
|
||||||
|
import com.fanxb.bookmark.common.factory.ThreadPoolFactory;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.scheduling.annotation.SchedulingConfigurer;
|
import org.springframework.scheduling.annotation.SchedulingConfigurer;
|
||||||
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
|
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
|
||||||
|
|
||||||
@ -11,15 +14,16 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
|
|||||||
* Created with IntelliJ IDEA
|
* Created with IntelliJ IDEA
|
||||||
*
|
*
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2020/1/26
|
|
||||||
*/
|
*/
|
||||||
|
@Configuration
|
||||||
|
@Slf4j
|
||||||
public class ScheduleConfig implements SchedulingConfigurer {
|
public class ScheduleConfig implements SchedulingConfigurer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
|
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
|
||||||
|
|
||||||
ScheduledExecutorService service = new ScheduledThreadPoolExecutor(5, new CustomThreadFactory("schedule"));
|
ScheduledExecutorService service = new ScheduledThreadPoolExecutor(5, new CustomThreadFactory("schedule"));
|
||||||
scheduledTaskRegistrar.setScheduler(service);
|
scheduledTaskRegistrar.setScheduler(service);
|
||||||
|
log.info("自定义schedule线程池成功");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,75 +1,76 @@
|
|||||||
package com.fanxb.bookmark.common.constant;
|
package com.fanxb.bookmark.common.constant;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 类功能简述:系统及常量类
|
* 类功能简述:系统及常量类
|
||||||
* 类功能详述:
|
* 类功能详述:
|
||||||
*
|
*
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/4/4 16:10
|
*/
|
||||||
*/
|
@Component
|
||||||
@Component
|
public class CommonConstant {
|
||||||
public class Constant {
|
|
||||||
|
|
||||||
|
/**
|
||||||
/**
|
* jwt key
|
||||||
* jwt key
|
*/
|
||||||
*/
|
public static final String JWT_KEY = "jwt-token";
|
||||||
public static final String JWT_KEY = "jwt-token";
|
|
||||||
|
|
||||||
|
/**
|
||||||
/**
|
* 验证码过期时间
|
||||||
* 验证码过期时间
|
*/
|
||||||
*/
|
public static int AUTH_CODE_EXPIRE = 15 * 60 * 1000;
|
||||||
public static int AUTH_CODE_EXPIRE = 15 * 60 * 1000;
|
|
||||||
|
/**
|
||||||
/**
|
* Description: 生成email存在redis中的key
|
||||||
* Description: 生成email存在redis中的key
|
*
|
||||||
*
|
* @param email 邮箱地址
|
||||||
* @param email 邮箱地址
|
* @return java.lang.String
|
||||||
* @return java.lang.String
|
* @author fanxb
|
||||||
* @author fanxb
|
* @date 2019/7/6 10:56
|
||||||
* @date 2019/7/6 10:56
|
*/
|
||||||
*/
|
public static String authCodeKey(String email) {
|
||||||
public static String authCodeKey(String email) {
|
return email + "_authCode";
|
||||||
return email + "_authCode";
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
public static boolean isDev = false;
|
* 是否为开发环境
|
||||||
|
*/
|
||||||
@Value("${isDev}")
|
public static boolean isDev = false;
|
||||||
public void setIsDev(boolean isDev) {
|
|
||||||
Constant.isDev = isDev;
|
@Value("${spring.profiles.active}")
|
||||||
}
|
public void setIsDev(String active) {
|
||||||
|
CommonConstant.isDev = active.contains("dev");
|
||||||
public static String jwtSecret = "";
|
}
|
||||||
|
|
||||||
@Value("${jwtSecret}")
|
public static String jwtSecret = "";
|
||||||
public void setJwtSecret(String jwtSecret) {
|
|
||||||
Constant.jwtSecret = jwtSecret;
|
@Value("${jwtSecret}")
|
||||||
}
|
public void setJwtSecret(String jwtSecret) {
|
||||||
|
CommonConstant.jwtSecret = jwtSecret;
|
||||||
/**
|
}
|
||||||
* 文件存储基路径
|
|
||||||
*/
|
/**
|
||||||
public static String fileSavePath = "./";
|
* 文件存储基路径
|
||||||
|
*/
|
||||||
@Value("${fileSavePath}")
|
public static String fileSavePath = "./";
|
||||||
public void setFileSavePath(String path) {
|
|
||||||
fileSavePath = path;
|
@Value("${fileSavePath}")
|
||||||
}
|
public void setFileSavePath(String path) {
|
||||||
|
fileSavePath = path;
|
||||||
|
}
|
||||||
/**
|
|
||||||
* 服务部署地址
|
|
||||||
*/
|
/**
|
||||||
public static String serviceAddress = "http://localhost";
|
* 服务部署地址
|
||||||
|
*/
|
||||||
@Value("${serviceAddress}")
|
public static String serviceAddress = "http://localhost";
|
||||||
public void setServiceAddress(String address) {
|
|
||||||
serviceAddress = address;
|
@Value("${serviceAddress}")
|
||||||
}
|
public void setServiceAddress(String address) {
|
||||||
|
serviceAddress = address;
|
||||||
}
|
}
|
||||||
|
}
|
@ -13,4 +13,8 @@ public class NumberConstant {
|
|||||||
* 2^10
|
* 2^10
|
||||||
*/
|
*/
|
||||||
public static final int K_SIZE = 1024;
|
public static final int K_SIZE = 1024;
|
||||||
|
/**
|
||||||
|
* 一天的秒数
|
||||||
|
*/
|
||||||
|
public static final int S_DAY = 24 * 60 * 60;
|
||||||
}
|
}
|
||||||
|
@ -14,5 +14,27 @@ public class RedisConstant {
|
|||||||
/**
|
/**
|
||||||
* 某用户书签数据更新时间,该队列左进右出
|
* 某用户书签数据更新时间,该队列左进右出
|
||||||
*/
|
*/
|
||||||
public static final String BOOKMARK_UPDATE_TIME = "bookmark_update_time";
|
public static final String BOOKMARK_UPDATE_VERSION = "bookmark_update_version";
|
||||||
|
/**
|
||||||
|
* 某个用户上传了文件夹,需要进行书签转化
|
||||||
|
*/
|
||||||
|
public static final String BOOKMARK_PINYIN_CHANGE = "bookmark_pinyin_change";
|
||||||
|
/**
|
||||||
|
* 插入书签数据到es中
|
||||||
|
*/
|
||||||
|
public static final String BOOKMARK_INSERT_ES = "bookmark_insert_es";
|
||||||
|
/**
|
||||||
|
* 从es中删除数据
|
||||||
|
*/
|
||||||
|
public static final String BOOKMARK_DELETE_ES = "bookmark_DELETE_es";
|
||||||
|
/**
|
||||||
|
* 书签访问次数+1
|
||||||
|
*/
|
||||||
|
public static final String BOOKMARK_VISIT_NUM_PLUS = "bookmark_visit_num_plus";
|
||||||
|
|
||||||
|
public static String getUserFailCountKey(String username) {
|
||||||
|
return "bookmark_user_fail_count_" + username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final String BING_IMG = "bing_img";
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
package com.fanxb.bookmark.common.controller;
|
||||||
|
|
||||||
|
import com.fanxb.bookmark.common.entity.Result;
|
||||||
|
import com.fanxb.bookmark.common.service.ConfigService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021-09-15-下午9:55
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/common/config")
|
||||||
|
public class ConfigController {
|
||||||
|
|
||||||
|
private final ConfigService configService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public ConfigController(ConfigService configService) {
|
||||||
|
this.configService = configService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取全局配置
|
||||||
|
*
|
||||||
|
* @return com.fanxb.bookmark.common.entity.Result
|
||||||
|
* @author fanxb
|
||||||
|
* @date 2021/9/15 下午9:56
|
||||||
|
*/
|
||||||
|
@GetMapping("/global")
|
||||||
|
public Result getGlobalConfig() {
|
||||||
|
return Result.success(configService.getGlobalConfig());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.fanxb.bookmark.common.dao;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.fanxb.bookmark.common.entity.po.GlobalConfigPo;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author fanxb
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface GlobalConfigDao extends BaseMapper<GlobalConfigPo> {
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package com.fanxb.bookmark.common.dao;
|
package com.fanxb.bookmark.common.dao;
|
||||||
|
|
||||||
import com.fanxb.bookmark.common.entity.Url;
|
import com.fanxb.bookmark.common.entity.po.Url;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -20,7 +20,7 @@ public interface UrlDao {
|
|||||||
*
|
*
|
||||||
* @author fanxb
|
* @author fanxb
|
||||||
* @date 2019/7/9 14:52
|
* @date 2019/7/9 14:52
|
||||||
* @return java.util.List<com.fanxb.bookmark.common.entity.Url>
|
* @return java.util.List<com.fanxb.bookmark.common.entity.po.Url>
|
||||||
*/
|
*/
|
||||||
List<Url> getPublicUrl();
|
List<Url> getPublicUrl();
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user