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.
|
86
README.md
86
README.md
@ -1,8 +1,12 @@
|
||||
本项目是一个云书签的项目,取名为:签签世界。
|
||||
![图片](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)**
|
||||
|
||||
也可自己部署搭建,教程见:[docker-compose 部署](https://github.com/FleyX/bookmark/blob/master/DEPLOY.md)
|
||||
|
||||
# 缘由
|
||||
|
||||
@ -14,71 +18,39 @@ web端已经完成。
|
||||
|
||||
所以有了这样这样一个项目,建立一个和平台无关的书签管理器,可在任意平台使用。
|
||||
|
||||
计划开发顺序如下:web 端->chrome 插件->firfox 插件。
|
||||
|
||||
最终目的就是所有浏览器(不包含 ie10 及以下等远古浏览器)中都能便捷的使用书签。
|
||||
|
||||
# 主要功能
|
||||
|
||||
## 查
|
||||
帮助文档:[点击跳转](https://blog.fleyx.com/blog/detail/20220329/)
|
||||
|
||||
1. 节点树展示书签
|
||||
![](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190801185846.png)
|
||||
采用懒加载方式加载每一层数据,即使大量数据也不会卡顿。
|
||||
- 支持从 chrome,edge,firefox 等浏览器导入书签数据。
|
||||
- 支持从 OneEnv 导入书签数据
|
||||
- 树型多级目录支持
|
||||
- 支持导出标准 html 书签文件
|
||||
- 强大的检索功能,支持拼音检索
|
||||
- 支持浏览器插件,安装插件以后可右键添加书签
|
||||
|
||||
2. 全文检索<br>
|
||||
![](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190801190427.png)
|
||||
# 更新日志
|
||||
|
||||
- 可对`书签名`和`链接`进行全文检索
|
||||
- 支持方向键-上/下切换,回车确认
|
||||
- 可直接搜索 google/baidu,tab 键切换。
|
||||
![](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190801190720.png)
|
||||
- 支持右键复制 url(移动端不支持右键,需点击编辑-->菜单键)
|
||||
![](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190801191010.png)
|
||||
## 1.4.1
|
||||
|
||||
## 增
|
||||
- 修复书签名过长无法导入问题
|
||||
|
||||
![](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190801191452.png)
|
||||
## 1.4
|
||||
|
||||
1. 手动编辑导入
|
||||
![](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190801191601.png)
|
||||
2. 谷歌、火狐浏览器书签备份文件直接导入.如果同一级别下名称相同导致冲突,将跳过,保留原有的。
|
||||
![](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190801191721.png)
|
||||
- 优化首图加载逻辑
|
||||
- 支持 OneEnv 备份文件导入
|
||||
|
||||
## 改
|
||||
## 1.3
|
||||
|
||||
1. 修改节点内容,右键->编辑。(移动端长按相当于右键)
|
||||
2. 修改书签顺序,所属文件夹,直接拖拽书签到目标位置
|
||||
![pic](https://s3.fleyx.com/picbed/2023/08/Snipaste_2023-08-13_15-01-20.png)
|
||||
|
||||
搜索引擎支持自定义[#43](https://github.com/FleyX/bookmark/issues/43)
|
||||
|
||||
# 开发进度
|
||||
位置:右上角个人中心-管理搜索引擎
|
||||
|
||||
## 2019-06-27
|
||||
# TODO
|
||||
|
||||
**tag: 第一篇:环境搭建**
|
||||
|
||||
前端 react 框架搭建完成。
|
||||
|
||||
## 2019-07-10
|
||||
|
||||
**tag: 第二篇:注册登录重置密码完成**
|
||||
|
||||
后台框架搭建,并完成以下功能:
|
||||
|
||||
- 登录,注册,重置密码,发送验证码接口完成
|
||||
- 书签 html 上传解析并存到数据库,仅测试了 chrome 导出的书签文件
|
||||
- 查询某个用户的书签树
|
||||
|
||||
前台完成以下功能:
|
||||
|
||||
- 注册,登录,重置密码界面完成
|
||||
|
||||
## 2019-07-22
|
||||
|
||||
增删改查功能完成。支持节点拖拽
|
||||
|
||||
## 2019-07-30
|
||||
|
||||
- docker 部署重新整理,部署更方便了。
|
||||
- 加入 elasticsearch 全文检索,可以方便的搜索书签啦。
|
||||
- 树节点增加右键菜单,更加便捷的增删改
|
||||
- [x] 主页功能
|
||||
- [x] 拼音检索
|
||||
- [x] 书签导出
|
||||
- [x] 浏览器插件
|
||||
|
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
|
||||
*.iml
|
||||
*.ipr
|
||||
node_modules
|
||||
|
||||
### NetBeans ###
|
||||
/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>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.fanxb</groupId>
|
||||
<artifactId>bookmark-business-api</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<!--html文件解析-->
|
||||
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
|
||||
<dependency>
|
||||
<groupId>org.jsoup</groupId>
|
||||
<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>
|
||||
</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;
|
||||
|
||||
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.util.ThreadPoolUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -20,17 +21,17 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RequestMapping("/bookmarkBackup")
|
||||
public class BookmarkBackupController {
|
||||
|
||||
private BookmarkBackupService backupService;
|
||||
private final BookmarkBackupService backupService;
|
||||
|
||||
@Autowired
|
||||
public BookmarkBackupController(BookmarkBackupService backupService) {
|
||||
public BookmarkBackupController(BookmarkBackupServiceImpl backupService) {
|
||||
this.backupService = backupService;
|
||||
}
|
||||
|
||||
@PostMapping("/mysqlToEs")
|
||||
public Result backupToEs() {
|
||||
//异步执行同步任务
|
||||
ThreadPoolUtil.execute(() -> backupService.backupToEs());
|
||||
ThreadPoolUtil.execute(backupService::backupToEs);
|
||||
return Result.success(null);
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,14 @@
|
||||
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.BookmarkEs;
|
||||
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.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.UserContext;
|
||||
import com.fanxb.bookmark.common.util.UserContextHolder;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@ -24,9 +26,12 @@ import java.util.List;
|
||||
@RestController
|
||||
@RequestMapping("/bookmark")
|
||||
public class BookmarkController {
|
||||
|
||||
@Autowired
|
||||
private BookmarkBackupService bookmarkBackupService;
|
||||
@Autowired
|
||||
private BookmarkService bookmarkService;
|
||||
@Autowired
|
||||
private PinYinService pinYinService;
|
||||
|
||||
/**
|
||||
* Description: 获取路径为path的书签数据
|
||||
@ -49,7 +54,7 @@ public class BookmarkController {
|
||||
* @date 2019/12/14 0:09
|
||||
*/
|
||||
@GetMapping("/currentUser")
|
||||
public Result getBookmarkMap(){
|
||||
public Result getBookmarkMap() {
|
||||
return Result.success(bookmarkService.getOneBookmarkTree(UserContextHolder.get().getUserId()));
|
||||
}
|
||||
|
||||
@ -62,9 +67,9 @@ public class BookmarkController {
|
||||
* @author fanxb
|
||||
* @date 2019/7/8 15:17
|
||||
*/
|
||||
@PutMapping("/uploadBookmarkFile")
|
||||
@RequestMapping("/uploadBookmarkFile")
|
||||
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);
|
||||
}
|
||||
|
||||
@ -93,8 +98,7 @@ public class BookmarkController {
|
||||
*/
|
||||
@PostMapping("/updateOne")
|
||||
public Result editCurrentUserBookmark(@RequestBody Bookmark bookmark) {
|
||||
bookmarkService.updateOne(UserContextHolder.get().getUserId(), bookmark);
|
||||
return Result.success(null);
|
||||
return Result.success(bookmarkService.updateOne(UserContextHolder.get().getUserId(), bookmark));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -107,7 +111,7 @@ public class BookmarkController {
|
||||
*/
|
||||
@PostMapping("/batchDelete")
|
||||
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);
|
||||
}
|
||||
|
||||
@ -140,8 +144,70 @@ public class BookmarkController {
|
||||
*/
|
||||
@PostMapping("/syncBookmark")
|
||||
public Result syncBookmark() {
|
||||
bookmarkService.syncUserBookmark(UserContextHolder.get().getUserId());
|
||||
bookmarkBackupService.syncUserBookmark(UserContextHolder.get().getUserId());
|
||||
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;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
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.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
@ -15,13 +19,12 @@ import java.util.List;
|
||||
* @date 2019/7/8 16:39
|
||||
*/
|
||||
@Component
|
||||
public interface BookmarkDao {
|
||||
public interface BookmarkDao extends BaseMapper<Bookmark> {
|
||||
|
||||
/**
|
||||
* Description: 插入一条书签记录
|
||||
*
|
||||
* @param node node
|
||||
* @return void
|
||||
* @author fanxb
|
||||
* @date 2019/7/8 16:49
|
||||
*/
|
||||
@ -54,7 +57,7 @@ public interface BookmarkDao {
|
||||
* Description: 根据用户id获取其所有数据
|
||||
*
|
||||
* @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
|
||||
* @date 2019/7/9 18:55
|
||||
*/
|
||||
@ -65,21 +68,21 @@ public interface BookmarkDao {
|
||||
*
|
||||
* @param userId userId
|
||||
* @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
|
||||
* @date 2019/7/17 14:48
|
||||
*/
|
||||
List<Bookmark> getListByUserIdAndPath(@Param("userId") int userId, @Param("path") String path);
|
||||
|
||||
/**
|
||||
* Description: 删除某用户某个书签文件下所有数据
|
||||
* Description: 删除某用户某个书签路径下所有数据,不包含文件夹自身
|
||||
*
|
||||
* @param userId 用户id
|
||||
* @param folderId 文件夹id
|
||||
* @param userId 用户id
|
||||
* @param path 文件夹id
|
||||
* @author fanxb
|
||||
* @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: 删除用户书签
|
||||
@ -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);
|
||||
|
||||
/**
|
||||
* Description: 获取某个文件夹下所有的节点id
|
||||
* Description: 获取某个路径下所有的节点id
|
||||
*
|
||||
* @param userId userId
|
||||
* @param folderId folderId
|
||||
* @param userId userId
|
||||
* @param path path
|
||||
* @return java.util.List<java.lang.Integer>
|
||||
* @author fanxb
|
||||
* @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,类别,分页查找书签
|
||||
*
|
||||
* @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
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* 功能描述: 查询所有的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
|
||||
public class BatchDeleteBody{
|
||||
private List<Integer> folderIdList;
|
||||
/**
|
||||
* 要删除的书签路径
|
||||
*/
|
||||
private List<String> pathList;
|
||||
/**
|
||||
* 要删除的书签id
|
||||
*/
|
||||
private List<Integer> bookmarkIdList;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
||||
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
|
||||
* Date: 2020/3/29
|
||||
* Time: 12:43
|
||||
*/
|
||||
@Service
|
||||
public class BookmarkBackupService {
|
||||
public interface BookmarkBackupService {
|
||||
|
||||
@Autowired
|
||||
private BookmarkBackupDao bookmarkBackupDao;
|
||||
|
||||
@Autowired
|
||||
private EsUtil esUtil;
|
||||
|
||||
/**
|
||||
* 一次同步BACKUP_SIZE条到es中
|
||||
*/
|
||||
private static final int BACKUP_SIZE = 500;
|
||||
|
||||
/**
|
||||
* 功能描述: 将mysql数据同步到es中
|
||||
@ -40,14 +14,14 @@ public class BookmarkBackupService {
|
||||
* @author fanxb
|
||||
* @date 2019/11/12 0:22
|
||||
*/
|
||||
public void backupToEs() {
|
||||
int start = 0;
|
||||
List<Bookmark> list;
|
||||
while ((list = bookmarkBackupDao.getBookmarkListPage(BACKUP_SIZE, start)).size() != 0) {
|
||||
List<EsEntity> batchList = new ArrayList<>(list.size());
|
||||
list.forEach(item -> batchList.add(new EsEntity<>(item.getBookmarkId().toString(), item)));
|
||||
esUtil.insertBatch(EsConstant.BOOKMARK_INDEX, batchList);
|
||||
start += BACKUP_SIZE;
|
||||
}
|
||||
}
|
||||
void backupToEs();
|
||||
|
||||
/**
|
||||
* Description: 将某个用户的书签数据mysql同步到es中
|
||||
*
|
||||
* @param userId 用户id
|
||||
* @author fanxb
|
||||
* @date 2019/7/26 11:27
|
||||
*/
|
||||
void syncUserBookmark(int userId);
|
||||
}
|
||||
|
@ -1,323 +1,150 @@
|
||||
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.MoveNodeBody;
|
||||
import com.fanxb.bookmark.common.constant.EsConstant;
|
||||
import com.fanxb.bookmark.common.constant.RedisConstant;
|
||||
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 com.fanxb.bookmark.common.entity.po.Bookmark;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
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
|
||||
* @date 2019/7/8 15:00
|
||||
* Date: 2020/3/29
|
||||
* Time: 12:25
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class BookmarkService {
|
||||
public interface BookmarkService {
|
||||
/**
|
||||
* chrome导出书签tag
|
||||
*/
|
||||
private static final String DT = "dt";
|
||||
private static final 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;
|
||||
}
|
||||
String DT = "dt";
|
||||
String A = "a";
|
||||
|
||||
/**
|
||||
* Description: 根据userId和path获取书签列表
|
||||
*
|
||||
* @param userId userId
|
||||
* @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
|
||||
* @date 2019/7/15 13:40
|
||||
*/
|
||||
public List<Bookmark> getBookmarkListByPath(int userId, String path) {
|
||||
return bookmarkDao.getListByUserIdAndPath(userId, path);
|
||||
}
|
||||
|
||||
List<Bookmark> getBookmarkListByPath(int userId, String path);
|
||||
|
||||
/**
|
||||
* Description: 批量删除书签
|
||||
* 功能描述: 获取某个用户的书签map
|
||||
*
|
||||
* @param userId 用户id
|
||||
* @param folderIdList 书签文件夹id list
|
||||
* @param bookmarkIdList 书签id list
|
||||
* @param userId userId
|
||||
* @return java.util.Map<java.lang.String, java.util.List < com.fanxb.bookmark.common.entity.po.Bookmark>>
|
||||
* @author fanxb
|
||||
* @date 2019/7/12 14:09
|
||||
* @date 2019/12/14 0:02
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void batchDelete(int userId, List<Integer> folderIdList, List<Integer> bookmarkIdList) {
|
||||
Set<Integer> set = new HashSet<>();
|
||||
for (Integer item : folderIdList) {
|
||||
set.addAll(bookmarkDao.getChildrenBookmarkId(userId, item));
|
||||
bookmarkDao.deleteUserFolder(userId, item);
|
||||
bookmarkIdList.add(item);
|
||||
}
|
||||
if (bookmarkIdList.size() > 0) {
|
||||
bookmarkDao.deleteUserBookmark(userId, bookmarkIdList);
|
||||
}
|
||||
set.addAll(bookmarkIdList);
|
||||
redisTemplate.opsForList().leftPush(RedisConstant.BOOKMARK_UPDATE_TIME, new UserBookmarkUpdate(userId, System.currentTimeMillis()).toString());
|
||||
//es 中批量删除
|
||||
esUtil.deleteBatch(EsConstant.BOOKMARK_INDEX, set);
|
||||
}
|
||||
Map<String, List<Bookmark>> getOneBookmarkTree(int userId);
|
||||
|
||||
/**
|
||||
* Description: 解析书签文件
|
||||
*
|
||||
* @param stream 输入流
|
||||
* @param path 存放路径
|
||||
* @param userId userId
|
||||
* @throws Exception 各种异常
|
||||
* @author fanxb
|
||||
* @date 2019/7/9 18:44
|
||||
*/
|
||||
void parseBookmarkFile(int userId, MultipartFile file, String path) throws Exception;
|
||||
|
||||
/**
|
||||
* Description: 详情
|
||||
*
|
||||
* @param bookmark 插入一条记录
|
||||
* @return com.fanxb.bookmark.common.entity.Bookmark
|
||||
* @return com.fanxb.bookmark.common.entity.po.Bookmark
|
||||
* @author fanxb
|
||||
* @date 2019/7/12 17:18
|
||||
*/
|
||||
@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());
|
||||
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;
|
||||
}
|
||||
Bookmark addOne(Bookmark bookmark);
|
||||
|
||||
/**
|
||||
* Description: 编辑某个用户的某个书签
|
||||
*
|
||||
* @param userId userId
|
||||
* @param bookmark bookmark
|
||||
* @return 更新后的icon
|
||||
* @author fanxb
|
||||
* @date 2019/7/17 14:42
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
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());
|
||||
}
|
||||
String updateOne(int userId, Bookmark bookmark);
|
||||
|
||||
/**
|
||||
* 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());
|
||||
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());
|
||||
redisTemplate.opsForList().leftPush(RedisConstant.BOOKMARK_UPDATE_TIME, new UserBookmarkUpdate(userId, System.currentTimeMillis()).toString());
|
||||
log.info("{},从{}移动到{},sort:{}", userId, body.getSourcePath(), body.getTargetPath(), body.getSort());
|
||||
}
|
||||
/**
|
||||
* 功能描述: 移动一个节点
|
||||
*
|
||||
* @param userId userId
|
||||
* @param body body
|
||||
* @author 123
|
||||
* @date 2020/3/29 12:30
|
||||
*/
|
||||
void moveNode(int userId, MoveNodeBody body);
|
||||
|
||||
/**
|
||||
* Description: 根据context搜索
|
||||
*
|
||||
* @param userId userId
|
||||
* @param context context
|
||||
* @return es搜索结果
|
||||
* @author fanxb
|
||||
* @date 2019/7/25 10:45
|
||||
*/
|
||||
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);
|
||||
}
|
||||
List<BookmarkEs> searchUserBookmark(int userId, String context);
|
||||
|
||||
/**
|
||||
* Description: 将某个用户的书签数据mysql同步到es中
|
||||
* 功能描述: 当前用户书签访问次数+1
|
||||
*
|
||||
* @param id 书签id
|
||||
* @author fanxb
|
||||
* @date 2019/7/26 11:27
|
||||
* @date 2020/5/12 10:21
|
||||
*/
|
||||
public void syncUserBookmark(int userId) {
|
||||
//删除旧的数据
|
||||
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);
|
||||
void visitNumPlus(int id);
|
||||
|
||||
}
|
||||
/**
|
||||
* 功能描述: 获取用户访问次数前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 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
|
||||
( #{userId},#{path},#{type},#{name},
|
||||
<if test="url == null">
|
||||
"","",
|
||||
</if>
|
||||
<if test="url != null">
|
||||
#{url},#{icon},
|
||||
</if>
|
||||
( #{userId},#{path},#{type},#{name},#{searchKey},#{url},#{icon},
|
||||
#{sort},#{addTime},#{createTime})
|
||||
</insert>
|
||||
|
||||
<select id="selectIdByUserIdAndNameAndPath" resultType="java.lang.Integer">
|
||||
select bookmarkId
|
||||
from bookmark
|
||||
where userId = #{userId} and path = #{path} and name = #{name};
|
||||
where userId = #{userId} and path = #{path} and name = #{name} limit 1;
|
||||
</select>
|
||||
|
||||
<select id="selectMaxSort" resultType="java.lang.Integer">
|
||||
@ -28,29 +22,30 @@
|
||||
where userId = #{userId} and path = #{path}
|
||||
</select>
|
||||
|
||||
<select id="getListByUserId" resultType="com.fanxb.bookmark.common.entity.Bookmark">
|
||||
<select id="getListByUserId" resultType="com.fanxb.bookmark.common.entity.po.Bookmark">
|
||||
select
|
||||
bookmarkId,
|
||||
path,
|
||||
type,
|
||||
name,
|
||||
url,
|
||||
icon,
|
||||
sort
|
||||
bookmarkId,
|
||||
path,
|
||||
type,
|
||||
name,
|
||||
searchKey,
|
||||
url,
|
||||
icon,
|
||||
sort
|
||||
from bookmark
|
||||
where userId = #{userId}
|
||||
order by path, sort
|
||||
</select>
|
||||
|
||||
<select id="getListByUserIdAndPath" resultType="com.fanxb.bookmark.common.entity.Bookmark">
|
||||
<select id="getListByUserIdAndPath" resultType="com.fanxb.bookmark.common.entity.po.Bookmark">
|
||||
select
|
||||
bookmarkId,
|
||||
path,
|
||||
type,
|
||||
name,
|
||||
url,
|
||||
icon,
|
||||
sort
|
||||
bookmarkId,
|
||||
path,
|
||||
type,
|
||||
name,
|
||||
url,
|
||||
icon,
|
||||
sort
|
||||
from bookmark
|
||||
where userId = #{userId} and path = #{path}
|
||||
order by sort
|
||||
@ -59,24 +54,18 @@
|
||||
<delete id="deleteUserFolder">
|
||||
DELETE
|
||||
FROM
|
||||
bookmark
|
||||
bookmark
|
||||
WHERE
|
||||
userId = #{userId}
|
||||
and path LIKE (SELECT a.path
|
||||
FROM (SELECT CONCAT(path, '.', '${folderId}', '%') AS path
|
||||
FROM bookmark
|
||||
WHERE bookmarkId = #{folderId}) a);
|
||||
userId = #{userId}
|
||||
and (path = #{path} or path like concat(#{path},".%"))
|
||||
</delete>
|
||||
|
||||
<select id="getChildrenBookmarkId" resultType="integer">
|
||||
select bookmarkId
|
||||
from bookmark
|
||||
where
|
||||
userId = #{userId}
|
||||
and path LIKE (SELECT a.path
|
||||
FROM (SELECT CONCAT(path, '.', '${folderId}', '%') AS path
|
||||
FROM bookmark
|
||||
WHERE bookmarkId = #{folderId}) a);
|
||||
userId = #{userId}
|
||||
and (path =#{path} or path like concat(#{path},".%") );
|
||||
</select>
|
||||
|
||||
<delete id="deleteUserBookmark">
|
||||
@ -86,9 +75,9 @@
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
<update id="editBookmark" parameterType="com.fanxb.bookmark.common.entity.Bookmark">
|
||||
<update id="editBookmark" parameterType="com.fanxb.bookmark.common.entity.po.Bookmark">
|
||||
update bookmark
|
||||
set name = #{name}, url = #{url}
|
||||
set name = #{name}, url = #{url},searchKey = #{searchKey},icon=#{icon}
|
||||
where bookmarkId = #{bookmarkId} and userId = #{userId}
|
||||
</update>
|
||||
|
||||
@ -112,15 +101,25 @@
|
||||
|
||||
<select id="selectBookmarkEsByUserIdAndType" resultType="com.fanxb.bookmark.business.bookmark.entity.BookmarkEs">
|
||||
select
|
||||
userId,
|
||||
bookmarkId,
|
||||
name,
|
||||
url
|
||||
userId,
|
||||
bookmarkId,
|
||||
name,
|
||||
url
|
||||
from bookmark
|
||||
where userId = #{userId} and type = #{type}
|
||||
order by bookmarkId
|
||||
limit ${start}, ${size}
|
||||
</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>
|
@ -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>
|
||||
<module>user</module>
|
||||
<module>bookmark</module>
|
||||
<module>api</module>
|
||||
</modules>
|
||||
|
||||
<dependencies>
|
||||
@ -22,12 +23,6 @@
|
||||
<artifactId>bookmark-common</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</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>
|
||||
|
||||
|
||||
|
@ -11,5 +11,12 @@
|
||||
|
||||
<artifactId>bookmark-business-user</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.fanxb</groupId>
|
||||
<artifactId>bookmark-business-api</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -1,10 +1,8 @@
|
||||
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 javax.annotation.PostConstruct;
|
||||
import java.io.File;
|
||||
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;
|
||||
|
||||
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.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.po.User;
|
||||
import com.fanxb.bookmark.common.util.UserContextHolder;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
|
||||
/**
|
||||
* 类功能简述:用户基本信息相关功能
|
||||
@ -23,8 +23,12 @@ import javax.validation.Valid;
|
||||
@Validated
|
||||
public class BaseInfoController {
|
||||
|
||||
private final BaseInfoService baseInfoService;
|
||||
|
||||
@Autowired
|
||||
private BaseInfoService baseInfoService;
|
||||
public BaseInfoController(BaseInfoService baseInfoService) {
|
||||
this.baseInfoService = baseInfoService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description: 修改密码
|
||||
@ -82,4 +86,17 @@ public class BaseInfoController {
|
||||
baseInfoService.verifyEmail(secret);
|
||||
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;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.fanxb.bookmark.business.user.entity.LoginBody;
|
||||
import com.fanxb.bookmark.business.user.entity.RegisterBody;
|
||||
import com.fanxb.bookmark.business.user.service.OauthService;
|
||||
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.util.UserContextHolder;
|
||||
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.multipart.MultipartFile;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
/**
|
||||
* 类功能简述:
|
||||
* 类功能详述:
|
||||
@ -22,8 +27,16 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
@RequestMapping("/user")
|
||||
public class UserController {
|
||||
|
||||
private final UserServiceImpl userServiceImpl;
|
||||
private final OauthService oAuthService;
|
||||
private final UserService userService;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
public UserController(UserServiceImpl userServiceImpl, OauthService oAuthService, UserService userService) {
|
||||
this.userServiceImpl = userServiceImpl;
|
||||
this.oAuthService = oAuthService;
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description: 获取验证码
|
||||
@ -35,7 +48,7 @@ public class UserController {
|
||||
*/
|
||||
@GetMapping("/authCode")
|
||||
public Result getAuthCode(@Param("email") String email) {
|
||||
userService.sendAuthCode(email);
|
||||
userServiceImpl.sendAuthCode(email);
|
||||
return Result.success(null);
|
||||
}
|
||||
|
||||
@ -48,9 +61,8 @@ public class UserController {
|
||||
* @date 2019/7/6 16:34
|
||||
*/
|
||||
@PutMapping("")
|
||||
public Result register(@RequestBody RegisterBody body) {
|
||||
userService.register(body);
|
||||
return Result.success(null);
|
||||
public Result register(@Valid @RequestBody RegisterBody body) {
|
||||
return Result.success(userServiceImpl.register(body));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -62,7 +74,7 @@ public class UserController {
|
||||
*/
|
||||
@GetMapping("/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")
|
||||
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")
|
||||
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")
|
||||
public Result resetPassword(@RequestBody RegisterBody body) {
|
||||
userService.resetPassword(body);
|
||||
userServiceImpl.resetPassword(body);
|
||||
return Result.success(null);
|
||||
}
|
||||
|
||||
@ -113,7 +125,7 @@ public class UserController {
|
||||
*/
|
||||
@PostMapping("/checkPassword")
|
||||
public Result checkPassword(@RequestBody JSONObject obj) {
|
||||
return Result.success(userService.checkPassword(obj.getString("password")));
|
||||
return Result.success(userServiceImpl.checkPassword(obj.getString("password")));
|
||||
}
|
||||
|
||||
@GetMapping("/loginStatus")
|
||||
@ -121,5 +133,54 @@ public class UserController {
|
||||
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;
|
||||
|
||||
import com.fanxb.bookmark.common.entity.User;
|
||||
import com.fanxb.bookmark.common.entity.redis.UserBookmarkUpdate;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.fanxb.bookmark.common.entity.po.User;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 类功能简述:
|
||||
* 类功能详述:
|
||||
@ -14,7 +17,7 @@ import org.springframework.stereotype.Component;
|
||||
* @date 2019/7/6 11:36
|
||||
*/
|
||||
@Component
|
||||
public interface UserDao {
|
||||
public interface UserDao extends BaseMapper<User> {
|
||||
|
||||
/**
|
||||
* Description: 新增一个用户
|
||||
@ -30,7 +33,7 @@ public interface UserDao {
|
||||
*
|
||||
* @param name username
|
||||
* @param email email
|
||||
* @return com.fanxb.bookmark.common.entity.User
|
||||
* @return com.fanxb.bookmark.common.entity.po.User
|
||||
* @author fanxb
|
||||
* @date 2019/7/6 16:45
|
||||
*/
|
||||
@ -59,12 +62,13 @@ public interface UserDao {
|
||||
/**
|
||||
* Description: 根据用户id查询用户信息
|
||||
*
|
||||
* @param userId userId
|
||||
* @return com.fanxb.bookmark.common.entity.User
|
||||
* @param userId userId
|
||||
* @param githubId githubId
|
||||
* @return com.fanxb.bookmark.common.entity.po.User
|
||||
* @author fanxb
|
||||
* @date 2019/7/30 16:08
|
||||
*/
|
||||
User selectByUserId(int userId);
|
||||
User selectByUserIdOrGithubId(@Param("userId") Integer userId, @Param("githubId") Long githubId);
|
||||
|
||||
/**
|
||||
* Description: 更新用户icon
|
||||
@ -102,11 +106,11 @@ public interface UserDao {
|
||||
/**
|
||||
* 更新用户新邮箱
|
||||
*
|
||||
* @param userId userId
|
||||
* @param newPassword userId
|
||||
* @param userId userId
|
||||
* @param newEmail email
|
||||
*/
|
||||
@Update("update user set newEmail=#{newPassword} where userId= #{userId}")
|
||||
void updateNewEmailByUserId(@Param("userId") int userId, @Param("newPassword") String newPassword);
|
||||
@Update("update user set newEmail=#{newEmail} where userId= #{userId}")
|
||||
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
|
||||
* @date 2020/1/26 下午3:47
|
||||
*/
|
||||
@Update("update user set bookmarkChangeTime=#{updateTime} where userId=#{userId}")
|
||||
void updateLastBookmarkUpdateTime(UserBookmarkUpdate item);
|
||||
@Update("update user set version=version+1 where userId=#{userId}")
|
||||
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,52 +1,25 @@
|
||||
package com.fanxb.bookmark.business.user.service;
|
||||
|
||||
import com.fanxb.bookmark.business.user.constant.RedisConstant;
|
||||
import com.fanxb.bookmark.business.user.dao.UserDao;
|
||||
import com.fanxb.bookmark.business.user.entity.EmailUpdateBody;
|
||||
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;
|
||||
import com.fanxb.bookmark.common.util.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.UUID;
|
||||
import com.fanxb.bookmark.business.user.vo.EmailUpdateBody;
|
||||
import com.fanxb.bookmark.business.user.vo.UpdatePasswordBody;
|
||||
import com.fanxb.bookmark.common.entity.po.User;
|
||||
|
||||
/**
|
||||
* 类功能简述:
|
||||
* 类功能详述:
|
||||
* 个人信息修改
|
||||
*
|
||||
* @author fanxb
|
||||
* @date 2019/9/18 15:54
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class BaseInfoService {
|
||||
|
||||
private static final String VERIFY_EMAIL = FileUtil.streamToString(BaseInfoService.class
|
||||
.getClassLoader().getResourceAsStream("verifyEmail.html"));
|
||||
|
||||
private static final String VERIFY_EMAIL_PATH = "/public/verifyEmail?key=";
|
||||
|
||||
@Autowired
|
||||
private UserDao userDao;
|
||||
|
||||
public void changePassword(UpdatePasswordBody 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("密码校验失败,无法更新密码");
|
||||
}
|
||||
userDao.updatePasswordByUserId(userId, HashUtil.getPassword(body.getPassword()));
|
||||
}
|
||||
* @date 2021/3/14
|
||||
**/
|
||||
public interface BaseInfoService {
|
||||
|
||||
/**
|
||||
* 修改密码
|
||||
*
|
||||
* @param body body
|
||||
* @author fanxb
|
||||
* @date 2021/3/14
|
||||
**/
|
||||
void changePassword(UpdatePasswordBody body);
|
||||
|
||||
/**
|
||||
* Description: 修改用户名
|
||||
@ -55,9 +28,7 @@ public class BaseInfoService {
|
||||
* @author fanxb
|
||||
* @date 2019/9/20 16:18
|
||||
*/
|
||||
public void updateUsername(String username) {
|
||||
userDao.updateUsernameByUserId(UserContextHolder.get().getUserId(), username);
|
||||
}
|
||||
void updateUsername(String username);
|
||||
|
||||
/**
|
||||
* 功能描述: 预备更新email,需要校验密码
|
||||
@ -66,23 +37,7 @@ public class BaseInfoService {
|
||||
* @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());
|
||||
}
|
||||
void updateEmail(EmailUpdateBody body);
|
||||
|
||||
/**
|
||||
* 功能描述: 校验新邮箱,校验成功就更新
|
||||
@ -91,13 +46,14 @@ public class BaseInfoService {
|
||||
* @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);
|
||||
}
|
||||
void verifyEmail(String secret);
|
||||
|
||||
/**
|
||||
* 修改用户默认搜索引擎
|
||||
*
|
||||
* @param user user
|
||||
* @author fanxb
|
||||
* @date 2021/3/14
|
||||
**/
|
||||
void changeDefaultSearchEngine(User user);
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
import com.fanxb.bookmark.business.user.constant.FileConstant;
|
||||
import com.fanxb.bookmark.business.user.dao.UserDao;
|
||||
import com.fanxb.bookmark.business.user.entity.LoginBody;
|
||||
import com.fanxb.bookmark.business.user.entity.LoginRes;
|
||||
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;
|
||||
import com.fanxb.bookmark.common.entity.User;
|
||||
import com.fanxb.bookmark.common.exception.FormDataException;
|
||||
import com.fanxb.bookmark.common.util.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import com.fanxb.bookmark.common.util.TimeUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 类功能简述:
|
||||
* 类功能详述:
|
||||
* 用户接口
|
||||
*
|
||||
* @author fanxb
|
||||
* @date 2019/7/5 17:39
|
||||
*/
|
||||
@Service
|
||||
public class UserService {
|
||||
|
||||
private static final String DEFAULT_ICON = "/favicon.ico";
|
||||
* @date 2021/3/11
|
||||
**/
|
||||
public interface UserService {
|
||||
String DEFAULT_ICON = "/favicon.ico";
|
||||
/**
|
||||
* 短期jwt失效时间
|
||||
*/
|
||||
private static final long SHORT_EXPIRE_TIME = 2 * 60 * 60 * 1000;
|
||||
long SHORT_EXPIRE_TIME = 2 * 60 * 60 * 1000;
|
||||
/**
|
||||
* 长期jwt失效时间
|
||||
*/
|
||||
private static final long LONG_EXPIRE_TIME = 30L * TimeUtil.DAY_MS;
|
||||
long LONG_EXPIRE_TIME = 300L * TimeUtil.DAY_MS;
|
||||
|
||||
/**
|
||||
* 头像文件大小限制 单位:KB
|
||||
*/
|
||||
private static final int ICON_SIZE = 200;
|
||||
int ICON_SIZE = 200;
|
||||
|
||||
@Autowired
|
||||
private UserDao userDao;
|
||||
|
||||
/**
|
||||
* 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 (Constant.isDev) {
|
||||
code = "123456";
|
||||
} else {
|
||||
MailUtil.sendTextMail(info);
|
||||
}
|
||||
RedisUtil.set(Constant.authCodeKey(email), code, Constant.AUTH_CODE_EXPIRE);
|
||||
}
|
||||
* @return java.lang.String
|
||||
* @date 2021/3/11
|
||||
**/
|
||||
String createNewUsername();
|
||||
|
||||
/**
|
||||
* 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获取用户信息
|
||||
* 获取当前用户的version
|
||||
*
|
||||
* @param userId userId
|
||||
* @return com.fanxb.bookmark.common.entity.User
|
||||
* @return int
|
||||
* @author fanxb
|
||||
* @date 2019/7/30 15:57
|
||||
*/
|
||||
public User getUserInfo(int userId) {
|
||||
return userDao.selectByUserId(userId);
|
||||
}
|
||||
* @date 2021/3/11
|
||||
**/
|
||||
int getCurrentUserVersion(int userId);
|
||||
|
||||
/**
|
||||
* 修改用户头像
|
||||
* 更新所有用户的空icon
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
* @author fanxb
|
||||
* @date 2021/3/13
|
||||
**/
|
||||
void updateAllUserIcon();
|
||||
|
||||
/**
|
||||
* 功能描述: 密码校验,校验成功返回一个actionId,以执行敏感操作
|
||||
* 检查所有用户的问题书签数据
|
||||
*
|
||||
* @param password password
|
||||
* @return java.lang.String
|
||||
* @param delete 是否删除问题数据
|
||||
* @return 返回用户删除的数据
|
||||
* @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;
|
||||
}
|
||||
* @date 2021/3/17
|
||||
**/
|
||||
Map<Integer, Set<String>> dealAllUserBookmark(boolean delete);
|
||||
}
|
||||
|
@ -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 lombok.Data;
|
||||
@ -17,7 +17,7 @@ import javax.validation.constraints.Pattern;
|
||||
@Data
|
||||
public class EmailUpdateBody {
|
||||
@NotNull(message = "参数不为空")
|
||||
private String actionId;
|
||||
private String oldPassword;
|
||||
@Email(message = "请输入有效邮箱地址")
|
||||
private String email;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.fanxb.bookmark.business.user.entity;
|
||||
package com.fanxb.bookmark.business.user.vo;
|
||||
|
||||
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 lombok.Data;
|
||||
@ -15,7 +15,7 @@ import javax.validation.constraints.Pattern;
|
||||
@Data
|
||||
public class UpdatePasswordBody {
|
||||
|
||||
private String actionId;
|
||||
private String oldPassword;
|
||||
@Pattern(regexp = ValidatedConstant.PASSWORD_REG, message = ValidatedConstant.PASSWORD_MESSAGE)
|
||||
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 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>
|
@ -3,22 +3,17 @@
|
||||
<mapper namespace="com.fanxb.bookmark.business.user.dao.UserDao">
|
||||
|
||||
|
||||
<insert id="addOne">
|
||||
insert into user (username, email, icon, password, createTime, lastLoginTime)
|
||||
value
|
||||
(#{username}, #{email}, #{icon}, #{password}, #{createTime}, #{lastLoginTime})
|
||||
<insert id="addOne" useGeneratedKeys="true" keyColumn="userId" keyProperty="userId">
|
||||
insert into user (username, email, icon, password, createTime, lastLoginTime, version)
|
||||
value
|
||||
(#{username}, #{email}, #{icon}, #{password}, #{createTime}, #{lastLoginTime}, #{version})
|
||||
</insert>
|
||||
|
||||
<select id="selectByUsernameOrEmail" resultType="com.fanxb.bookmark.common.entity.User">
|
||||
select
|
||||
userId,
|
||||
username,
|
||||
email,
|
||||
icon,
|
||||
password,
|
||||
createTime
|
||||
<select id="selectByUsernameOrEmail" resultType="com.fanxb.bookmark.common.entity.po.User">
|
||||
select *
|
||||
from user
|
||||
where username = #{name} or email = #{email}
|
||||
where username = #{name}
|
||||
or email = #{email}
|
||||
limit 1
|
||||
</select>
|
||||
|
||||
@ -34,10 +29,11 @@
|
||||
where email = #{email}
|
||||
</update>
|
||||
|
||||
<select id="selectByUserId" resultType="com.fanxb.bookmark.common.entity.User">
|
||||
<select id="selectByUserIdOrGithubId" resultType="com.fanxb.bookmark.common.entity.po.User">
|
||||
select *
|
||||
from user
|
||||
where userId = #{userId}
|
||||
or githubId = #{githubId}
|
||||
</select>
|
||||
|
||||
|
@ -37,53 +37,87 @@
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--mybatis依赖-->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.mybatis.spring.boot</groupId>-->
|
||||
<!-- <artifactId>mybatis-spring-boot-starter</artifactId>-->
|
||||
<!-- <version>2.0.1</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<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>
|
||||
|
||||
<!--druid连接池依赖-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-starter</artifactId>
|
||||
<version>1.1.18</version>
|
||||
<version>1.2.18</version>
|
||||
</dependency>
|
||||
|
||||
<!--数据库版本管理-->
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<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>
|
||||
<!--mysql jdbc依赖-->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.33</version>
|
||||
</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>
|
||||
<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.56</version>
|
||||
</dependency>
|
||||
|
||||
<!--减负依赖-->
|
||||
<dependency>
|
||||
@ -94,7 +128,7 @@
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>1.2.56</version>
|
||||
<version>1.2.83</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
@ -103,6 +137,11 @@
|
||||
<artifactId>elasticsearch-rest-high-level-client</artifactId>
|
||||
</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 -->
|
||||
|
@ -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;
|
||||
|
||||
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.config.ScheduledTaskRegistrar;
|
||||
|
||||
@ -11,15 +14,16 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
* Created with IntelliJ IDEA
|
||||
*
|
||||
* @author fanxb
|
||||
* @date 2020/1/26
|
||||
*/
|
||||
@Configuration
|
||||
@Slf4j
|
||||
public class ScheduleConfig implements SchedulingConfigurer {
|
||||
|
||||
@Override
|
||||
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
|
||||
|
||||
ScheduledExecutorService service = new ScheduledThreadPoolExecutor(5, new CustomThreadFactory("schedule"));
|
||||
scheduledTaskRegistrar.setScheduler(service);
|
||||
log.info("自定义schedule线程池成功");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,10 +8,9 @@ import org.springframework.stereotype.Component;
|
||||
* 类功能详述:
|
||||
*
|
||||
* @author fanxb
|
||||
* @date 2019/4/4 16:10
|
||||
*/
|
||||
@Component
|
||||
public class Constant {
|
||||
public class CommonConstant {
|
||||
|
||||
|
||||
/**
|
||||
@ -37,18 +36,21 @@ public class Constant {
|
||||
return email + "_authCode";
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为开发环境
|
||||
*/
|
||||
public static boolean isDev = false;
|
||||
|
||||
@Value("${isDev}")
|
||||
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 void setJwtSecret(String jwtSecret) {
|
||||
Constant.jwtSecret = jwtSecret;
|
||||
CommonConstant.jwtSecret = jwtSecret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -71,5 +73,4 @@ public class Constant {
|
||||
public void setServiceAddress(String address) {
|
||||
serviceAddress = address;
|
||||
}
|
||||
|
||||
}
|
@ -13,4 +13,8 @@ public class NumberConstant {
|
||||
* 2^10
|
||||
*/
|
||||
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;
|
||||
|
||||
import com.fanxb.bookmark.common.entity.Url;
|
||||
import com.fanxb.bookmark.common.entity.po.Url;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
@ -20,7 +20,7 @@ public interface UrlDao {
|
||||
*
|
||||
* @author fanxb
|
||||
* @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();
|
||||
}
|
||||
|
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