Compare commits

..

No commits in common. "master" and "1.0" have entirely different histories.
master ... 1.0

320 changed files with 19885 additions and 18764 deletions

View File

@ -1,24 +0,0 @@
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
View File

@ -1,31 +0,0 @@
#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
View File

@ -1 +0,0 @@
.idea

View File

@ -1,20 +0,0 @@
本程序基于 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
View File

@ -1,115 +0,0 @@
## 使用教程
### 首页
![首页](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
View File

@ -1,21 +0,0 @@
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.

View File

@ -1,12 +1,8 @@
![图片](https://s3.fleyx.com/picbed/2023/08/Snipaste_2023-08-13_15-33-16.png)
本项目是一个云书签的项目,取名为:签签世界。
本项目是一个在线书签管理的项目,名为:签签世界.
访问地址:[bm.tapme.top](http://bm.tapme.top)
在线使用地址(长期提供服务):[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)
web端已经完成。
# 缘由
@ -18,39 +14,71 @@
所以有了这样这样一个项目,建立一个和平台无关的书签管理器,可在任意平台使用。
计划开发顺序如下web 端->chrome 插件->firfox 插件。
最终目的就是所有浏览器(不包含 ie10 及以下等远古浏览器)中都能便捷的使用书签。
# 主要功能
帮助文档:[点击跳转](https://blog.fleyx.com/blog/detail/20220329/)
## 查
- 支持从 chrome,edge,firefox 等浏览器导入书签数据。
- 支持从 OneEnv 导入书签数据
- 树型多级目录支持
- 支持导出标准 html 书签文件
- 强大的检索功能,支持拼音检索
- 支持浏览器插件,安装插件以后可右键添加书签
1. 节点树展示书签
![](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190801185846.png)
采用懒加载方式加载每一层数据,即使大量数据也不会卡顿。
# 更新日志
2. 全文检索<br>
![](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190801190427.png)
## 1.4.1
- 可对`书签名``链接`进行全文检索
- 支持方向键-上/下切换,回车确认
- 可直接搜索 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
![](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190801191452.png)
- 优化首图加载逻辑
- 支持 OneEnv 备份文件导入
1. 手动编辑导入
![](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190801191601.png)
2. 谷歌、火狐浏览器书签备份文件直接导入.如果同一级别下名称相同导致冲突,将跳过,保留原有的。
![](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190801191721.png)
## 1.3
##
![pic](https://s3.fleyx.com/picbed/2023/08/Snipaste_2023-08-13_15-01-20.png)
1. 修改节点内容,右键->编辑。(移动端长按相当于右键)
2. 修改书签顺序,所属文件夹,直接拖拽书签到目标位置
搜索引擎支持自定义[#43](https://github.com/FleyX/bookmark/issues/43)
位置:右上角个人中心-管理搜索引擎
# 开发进度
# TODO
## 2019-06-27
- [x] 主页功能
- [x] 拼音检索
- [x] 书签导出
- [x] 浏览器插件
**tag: 第一篇:环境搭建**
前端 react 框架搭建完成。
## 2019-07-10
**tag: 第二篇:注册登录重置密码完成**
后台框架搭建,并完成以下功能:
- 登录,注册,重置密码,发送验证码接口完成
- 书签 html 上传解析并存到数据库,仅测试了 chrome 导出的书签文件
- 查询某个用户的书签树
前台完成以下功能:
- 注册,登录,重置密码界面完成
## 2019-07-22
增删改查功能完成。支持节点拖拽
## 2019-07-30
- docker 部署重新整理,部署更方便了。
- 加入 elasticsearch 全文检索,可以方便的搜索书签啦。
- 树节点增加右键菜单,更加便捷的增删改

4
bookMarkDocker/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
mavenRep
es/data
mysql/data
nginx/log

29
bookMarkDocker/README.md Normal file
View File

@ -0,0 +1,29 @@
本程序基于 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` 后台启动系统。

View File

@ -0,0 +1,98 @@
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:

15
bookMarkDocker/init.sh Executable file
View File

@ -0,0 +1,15 @@
#/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"

View File

@ -10,8 +10,8 @@ http {
# SSL Settings
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# Logging Settings
access_log /dev/stdout;
error_log /dev/stderr;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# Gzip Settings
gzip on;
tcp_nopush on;
@ -31,7 +31,7 @@ http {
root /opt/dist/;
server_name _;
location /bookmark/api/ {
proxy_pass http://backend:8088;
proxy_pass http://bookmark-service:8088;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
client_max_body_size 100m;

View File

@ -51,7 +51,8 @@ under the License.
|
| Default: ${user.home}/.m2/repository
-->
<localRepository>/var/maven/.m2/repository</localRepository>
<localRepository>/opt/mavenRep</localRepository>
<!-- interactiveMode
| This will determine whether maven prompts you when it needs input. If set to false,

View File

@ -17,7 +17,6 @@ static
*.iws
*.iml
*.ipr
node_modules
### NetBeans ###
/nbproject/private/

View File

@ -1,14 +0,0 @@
<?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>

View File

@ -1,28 +0,0 @@
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);
}

View File

@ -1,22 +0,0 @@
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();
}

View File

@ -1,6 +0,0 @@
/**
* 用于模块间的方法相互调用,具体使用如下
* 1. 首先在business模块下建立interface接口然后在个具体模块中实现
* 2. 最后诸如interface,就能实现同级模块间的直接调用
*/
package com.fanxb.bookmark.business.api;

View File

@ -12,27 +12,12 @@
<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.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>
<version>1.12.1</version>
</dependency>
</dependencies>

View File

@ -1,16 +0,0 @@
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();
}

View File

@ -1,45 +0,0 @@
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());
}
}
}

View File

@ -1,43 +0,0 @@
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);
}
}

View File

@ -1,41 +0,0 @@
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());
}
}
}

View File

@ -1,7 +1,6 @@
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;
@ -21,17 +20,17 @@ import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/bookmarkBackup")
public class BookmarkBackupController {
private final BookmarkBackupService backupService;
private BookmarkBackupService backupService;
@Autowired
public BookmarkBackupController(BookmarkBackupServiceImpl backupService) {
public BookmarkBackupController(BookmarkBackupService backupService) {
this.backupService = backupService;
}
@PostMapping("/mysqlToEs")
public Result backupToEs() {
//异步执行同步任务
ThreadPoolUtil.execute(backupService::backupToEs);
ThreadPoolUtil.execute(() -> backupService.backupToEs());
return Result.success(null);
}
}

View File

@ -1,14 +1,12 @@
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.business.bookmark.service.PinYinService;
import com.fanxb.bookmark.common.entity.po.Bookmark;
import com.fanxb.bookmark.common.entity.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.*;
@ -26,12 +24,9 @@ import java.util.List;
@RestController
@RequestMapping("/bookmark")
public class BookmarkController {
@Autowired
private BookmarkBackupService bookmarkBackupService;
@Autowired
private BookmarkService bookmarkService;
@Autowired
private PinYinService pinYinService;
/**
* Description: 获取路径为path的书签数据
@ -67,9 +62,9 @@ public class BookmarkController {
* @author fanxb
* @date 2019/7/8 15:17
*/
@RequestMapping("/uploadBookmarkFile")
@PutMapping("/uploadBookmarkFile")
public Result uploadFile(@RequestParam("file") MultipartFile file, @RequestParam("path") String path) throws Exception {
bookmarkService.parseBookmarkFile(UserContextHolder.get().getUserId(), file, path);
bookmarkService.parseBookmarkFile(UserContextHolder.get().getUserId(), file.getInputStream(), path);
return Result.success(null);
}
@ -98,7 +93,8 @@ public class BookmarkController {
*/
@PostMapping("/updateOne")
public Result editCurrentUserBookmark(@RequestBody Bookmark bookmark) {
return Result.success(bookmarkService.updateOne(UserContextHolder.get().getUserId(), bookmark));
bookmarkService.updateOne(UserContextHolder.get().getUserId(), bookmark);
return Result.success(null);
}
/**
@ -111,7 +107,7 @@ public class BookmarkController {
*/
@PostMapping("/batchDelete")
public Result batchDelete(@RequestBody BatchDeleteBody body) {
bookmarkService.batchDelete(UserContextHolder.get().getUserId(), body.getPathList(), body.getBookmarkIdList());
bookmarkService.batchDelete(UserContextHolder.get().getUserId(), body.getFolderIdList(), body.getBookmarkIdList());
return Result.success(null);
}
@ -144,70 +140,8 @@ public class BookmarkController {
*/
@PostMapping("/syncBookmark")
public Result syncBookmark() {
bookmarkBackupService.syncUserBookmark(UserContextHolder.get().getUserId());
bookmarkService.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()));
}
}

View File

@ -1,56 +0,0 @@
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();
}
}

View File

@ -0,0 +1,27 @@
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);
}

View File

@ -1,12 +1,8 @@
package com.fanxb.bookmark.business.bookmark.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.fanxb.bookmark.business.bookmark.entity.BookmarkEs;
import com.fanxb.bookmark.business.bookmark.entity.redis.VisitNumPlus;
import com.fanxb.bookmark.common.entity.po.Bookmark;
import com.fanxb.bookmark.common.entity.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;
@ -19,12 +15,13 @@ import java.util.List;
* @date 2019/7/8 16:39
*/
@Component
public interface BookmarkDao extends BaseMapper<Bookmark> {
public interface BookmarkDao {
/**
* Description: 插入一条书签记录
*
* @param node node
* @return void
* @author fanxb
* @date 2019/7/8 16:49
*/
@ -57,7 +54,7 @@ public interface BookmarkDao extends BaseMapper<Bookmark> {
* Description: 根据用户id获取其所有数据
*
* @param userId userid
* @return java.util.List<com.fanxb.bookmark.common.entity.po.Bookmark>
* @return java.util.List<com.fanxb.bookmark.common.entity.Bookmark>
* @author fanxb
* @date 2019/7/9 18:55
*/
@ -68,21 +65,21 @@ public interface BookmarkDao extends BaseMapper<Bookmark> {
*
* @param userId userId
* @param path path
* @return java.util.List<com.fanxb.bookmark.common.entity.po.Bookmark>
* @return java.util.List<com.fanxb.bookmark.common.entity.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 path 文件夹id
* @param folderId 文件夹id
* @author fanxb
* @date 2019/7/12 14:13
*/
void deleteUserFolder(@Param("userId") int userId, @Param("path") String path);
void deleteUserFolder(@Param("userId") int userId, @Param("folderId") int folderId);
/**
* Description: 删除用户书签
@ -138,127 +135,27 @@ public interface BookmarkDao extends BaseMapper<Bookmark> {
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 path path
* @param folderId folderId
* @return java.util.List<java.lang.Integer>
* @author fanxb
* @date 2019/7/25 14:14
*/
List<Integer> getChildrenBookmarkId(@Param("userId") int userId, @Param("path") String path);
List<Integer> getChildrenBookmarkId(@Param("userId") int userId, @Param("folderId") int folderId);
/**
* Description: 根据用户id类别分页查找书签
*
* @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>
* @author fanxb
* @date 2019/7/26 15:23
*/
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);
}

View File

@ -1,39 +0,0 @@
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);
}

View File

@ -1,44 +0,0 @@
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);
}

View File

@ -13,12 +13,6 @@ import java.util.List;
*/
@Data
public class BatchDeleteBody{
/**
* 要删除的书签路径
*/
private List<String> pathList;
/**
* 要删除的书签id
*/
private List<Integer> folderIdList;
private List<Integer> bookmarkIdList;
}

View File

@ -1,6 +1,6 @@
package com.fanxb.bookmark.business.bookmark.entity;
import com.fanxb.bookmark.common.entity.po.Bookmark;
import com.fanxb.bookmark.common.entity.Bookmark;
import lombok.Data;
/**

View File

@ -1,41 +0,0 @@
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;
}
}

View File

@ -1,29 +0,0 @@
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;
}

View File

@ -1,26 +0,0 @@
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;
}

View File

@ -1,23 +0,0 @@
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;
}

View File

@ -1,37 +0,0 @@
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;
}

View File

@ -1,12 +1,38 @@
package com.fanxb.bookmark.business.bookmark.service;
/**
* @author fanxb
* Date: 2020/3/29
* Time: 12:43
*/
public interface BookmarkBackupService {
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
*/
@Service
public class BookmarkBackupService {
@Autowired
private BookmarkBackupDao bookmarkBackupDao;
@Autowired
private EsUtil esUtil;
/**
* 一次同步BACKUP_SIZE条到es中
*/
private static final int BACKUP_SIZE = 500;
/**
* 功能描述: 将mysql数据同步到es中
@ -14,14 +40,14 @@ public interface BookmarkBackupService {
* @author fanxb
* @date 2019/11/12 0:22
*/
void backupToEs();
/**
* Description: 将某个用户的书签数据mysql同步到es中
*
* @param userId 用户id
* @author fanxb
* @date 2019/7/26 11:27
*/
void syncUserBookmark(int userId);
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;
}
}
}

View File

@ -1,150 +1,323 @@
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.entity.po.Bookmark;
import org.springframework.web.multipart.MultipartFile;
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 java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
/**
* Created with IntelliJ IDEA
* 类功能简述
* 类功能详述
*
* @author fanxb
* Date: 2020/3/29
* Time: 12:25
* @date 2019/7/8 15:00
*/
public interface BookmarkService {
@Service
@Slf4j
public class BookmarkService {
/**
* chrome导出书签tag
*/
String DT = "dt";
String A = "a";
private static final String DT = "dt";
private static final String A = "a";
/**
* Description: 根据userId和path获取书签列表
*
* @param userId userId
* @param path path
* @return java.util.List<com.fanxb.bookmark.common.entity.po.Bookmark>
* @author fanxb
* @date 2019/7/15 13:40
*/
List<Bookmark> getBookmarkListByPath(int userId, String path);
@Autowired
private BookmarkDao bookmarkDao;
@Autowired
private StringRedisTemplate redisTemplate;
/**
* 功能描述: 获取某个用户的书签map
*
* @param userId userId
* @return java.util.Map<java.lang.String, java.util.List < com.fanxb.bookmark.common.entity.po.Bookmark>>
* @author fanxb
* @date 2019/12/14 0:02
*/
Map<String, List<Bookmark>> getOneBookmarkTree(int userId);
@Autowired
private EsUtil esUtil;
/**
* 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;
@Transactional(rollbackFor = Exception.class)
public void parseBookmarkFile(int userId, InputStream stream, String path) throws Exception {
Document doc = Jsoup.parse(stream, "utf-8", "");
Elements elements = doc.select("html>body>dl>dt");
//获取当前层sort最大值
Integer sortBase = bookmarkDao.selectMaxSort(userId, path);
if (sortBase == null) {
sortBase = 0;
}
int count = 0;
// 將要插入es的书签数据放到list中,最后一次插入尽量避免mysql回滚了但是es插入了
List<EsEntity> insertEsList = new ArrayList<>();
for (int i = 0, length = elements.size(); i < length; i++) {
if (i == 0) {
Elements firstChildren = elements.get(0).child(1).children();
count = firstChildren.size();
for (int j = 0; j < count; j++) {
dealBookmark(userId, firstChildren.get(j), path, sortBase + j, insertEsList);
}
} else {
dealBookmark(userId, elements.get(i), path, sortBase + count + i - 1, insertEsList);
}
}
redisTemplate.opsForList().leftPush(RedisConstant.BOOKMARK_UPDATE_TIME, new UserBookmarkUpdate(userId, System.currentTimeMillis()).toString());
esUtil.insertBatch(EsConstant.BOOKMARK_INDEX, insertEsList);
}
/**
* Description: 处理html节点解析出文件夹和书签
*
* @param ele 待处理节点
* @param path 节点路径不包含自身
* @param sort 当前层级中的排序序号
* @author fanxb
* @date 2019/7/8 14:49
*/
private void dealBookmark(int userId, Element ele, String path, int sort, List<EsEntity> insertList) {
if (!DT.equalsIgnoreCase(ele.tagName())) {
return;
}
Element first = ele.child(0);
if (A.equalsIgnoreCase(first.tagName())) {
//说明为链接
Bookmark node = new Bookmark(userId, path, first.ownText(), first.attr("href"), first.attr("icon")
, Long.parseLong(first.attr("add_date")) * 1000, sort);
//存入数据库
insertOne(node);
insertList.add(new EsEntity<>(node.getBookmarkId().toString(), new BookmarkEs(node)));
} else {
//说明为文件夹
Bookmark node = new Bookmark(userId, path, first.ownText(), Long.parseLong(first.attr("add_date")) * 1000, sort);
Integer sortBase = 0;
if (insertOne(node)) {
sortBase = bookmarkDao.selectMaxSort(node.getUserId(), path);
if (sortBase == null) {
sortBase = 0;
}
}
String childPath = path + "." + node.getBookmarkId();
Elements children = ele.child(1).children();
for (int i = 0, size = children.size(); i < size; i++) {
dealBookmark(userId, children.get(i), childPath, sortBase + i + 1, insertList);
}
}
}
/**
* Description: 插入一条书签如果已经存在同名书签将跳过
*
* @param node node
* @return boolean 如果已经存在返回true否则false
* @author fanxb
* @date 2019/7/8 17:25
*/
private boolean insertOne(Bookmark node) {
//先根据name,userId,parentId获取此节点id
Integer id = bookmarkDao.selectIdByUserIdAndNameAndPath(node.getUserId(), node.getName(), node.getPath());
if (id == null) {
bookmarkDao.insertOne(node);
return false;
} else {
node.setBookmarkId(id);
return true;
}
}
/**
* 功能描述: 获取某个用户的书签map
*
* @param userId userId
* @return java.util.Map<java.lang.String, java.util.List < com.fanxb.bookmark.common.entity.Bookmark>>
* @author fanxb
* @date 2019/12/14 0:02
*/
public Map<String, List<Bookmark>> getOneBookmarkTree(int userId) {
List<Bookmark> list = bookmarkDao.getListByUserId(userId);
Map<String, List<Bookmark>> map = new HashMap<>(50);
list.forEach(item -> {
map.computeIfAbsent(item.getPath(), k -> new ArrayList<>());
map.get(item.getPath()).add(item);
});
return map;
}
/**
* Description: 根据userId和path获取书签列表
*
* @param userId userId
* @param path path
* @return java.util.List<com.fanxb.bookmark.common.entity.Bookmark>
* @author fanxb
* @date 2019/7/15 13:40
*/
public List<Bookmark> getBookmarkListByPath(int userId, String path) {
return bookmarkDao.getListByUserIdAndPath(userId, path);
}
/**
* Description: 批量删除书签
*
* @param userId 用户id
* @param folderIdList 书签文件夹id list
* @param bookmarkIdList 书签id list
* @author fanxb
* @date 2019/7/12 14:09
*/
@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);
}
/**
* Description: 详情
*
* @param bookmark 插入一条记录
* @return com.fanxb.bookmark.common.entity.po.Bookmark
* @return com.fanxb.bookmark.common.entity.Bookmark
* @author fanxb
* @date 2019/7/12 17:18
*/
Bookmark addOne(Bookmark bookmark);
@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;
}
/**
* Description: 编辑某个用户的某个书签
*
* @param userId userId
* @param bookmark bookmark
* @return 更新后的icon
* @author fanxb
* @date 2019/7/17 14:42
*/
String updateOne(int userId, Bookmark bookmark);
@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());
}
/**
* 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);
/**
* 功能描述: 移动一个节点
*
* @param userId userId
* @param body body
* @author 123
* @date 2020/3/29 12:30
*/
void moveNode(int userId, MoveNodeBody body);
@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());
}
/**
* Description: 根据context搜索
*
* @param userId userId
* @param context context
* @return es搜索结果
* @author fanxb
* @date 2019/7/25 10:45
*/
List<BookmarkEs> searchUserBookmark(int userId, String context);
/**
* 功能描述: 当前用户书签访问次数+1
*
* @param id 书签id
* @author fanxb
* @date 2020/5/12 10:21
*/
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);
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);
}
/**
* Description: 将某个用户的书签数据mysql同步到es中
*
* @author fanxb
* @date 2019/7/26 11:27
*/
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);
}
}

View File

@ -1,39 +0,0 @@
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);
}

View File

@ -1,66 +0,0 @@
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);
}

View File

@ -1,34 +0,0 @@
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);
}
}

View File

@ -1,69 +0,0 @@
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);
}
}

View File

@ -1,503 +0,0 @@
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;
}
}

View File

@ -1,81 +0,0 @@
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);
}
}

View File

@ -1,83 +0,0 @@
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());
}
}

View File

@ -4,16 +4,22 @@
<insert id="insertOne" useGeneratedKeys="true" keyColumn="bookmarkId" keyProperty="bookmarkId">
insert into bookmark(userId,path,type,name,searchKey,url,icon,sort,addTime,createTime)
insert into bookmark(userId,path,type,name,url,icon,sort,addTime,createTime)
value
( #{userId},#{path},#{type},#{name},#{searchKey},#{url},#{icon},
( #{userId},#{path},#{type},#{name},
<if test="url == null">
"","",
</if>
<if test="url != null">
#{url},#{icon},
</if>
#{sort},#{addTime},#{createTime})
</insert>
<select id="selectIdByUserIdAndNameAndPath" resultType="java.lang.Integer">
select bookmarkId
from bookmark
where userId = #{userId} and path = #{path} and name = #{name} limit 1;
where userId = #{userId} and path = #{path} and name = #{name};
</select>
<select id="selectMaxSort" resultType="java.lang.Integer">
@ -22,13 +28,12 @@
where userId = #{userId} and path = #{path}
</select>
<select id="getListByUserId" resultType="com.fanxb.bookmark.common.entity.po.Bookmark">
<select id="getListByUserId" resultType="com.fanxb.bookmark.common.entity.Bookmark">
select
bookmarkId,
path,
type,
name,
searchKey,
url,
icon,
sort
@ -37,7 +42,7 @@
order by path, sort
</select>
<select id="getListByUserIdAndPath" resultType="com.fanxb.bookmark.common.entity.po.Bookmark">
<select id="getListByUserIdAndPath" resultType="com.fanxb.bookmark.common.entity.Bookmark">
select
bookmarkId,
path,
@ -57,7 +62,10 @@
bookmark
WHERE
userId = #{userId}
and (path = #{path} or path like concat(#{path},".%"))
and path LIKE (SELECT a.path
FROM (SELECT CONCAT(path, '.', '${folderId}', '%') AS path
FROM bookmark
WHERE bookmarkId = #{folderId}) a);
</delete>
<select id="getChildrenBookmarkId" resultType="integer">
@ -65,7 +73,10 @@
from bookmark
where
userId = #{userId}
and (path =#{path} or path like concat(#{path},".%") );
and path LIKE (SELECT a.path
FROM (SELECT CONCAT(path, '.', '${folderId}', '%') AS path
FROM bookmark
WHERE bookmarkId = #{folderId}) a);
</select>
<delete id="deleteUserBookmark">
@ -75,9 +86,9 @@
</foreach>
</delete>
<update id="editBookmark" parameterType="com.fanxb.bookmark.common.entity.po.Bookmark">
<update id="editBookmark" parameterType="com.fanxb.bookmark.common.entity.Bookmark">
update bookmark
set name = #{name}, url = #{url},searchKey = #{searchKey},icon=#{icon}
set name = #{name}, url = #{url}
where bookmarkId = #{bookmarkId} and userId = #{userId}
</update>
@ -111,15 +122,5 @@
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>

View File

@ -1,15 +0,0 @@
<?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>

View File

@ -14,7 +14,6 @@
<modules>
<module>user</module>
<module>bookmark</module>
<module>api</module>
</modules>
<dependencies>
@ -23,6 +22,12 @@
<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>

View File

@ -11,12 +11,5 @@
<artifactId>bookmark-business-user</artifactId>
<dependencies>
<dependency>
<groupId>com.fanxb</groupId>
<artifactId>bookmark-business-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

View File

@ -1,8 +1,10 @@
package com.fanxb.bookmark.business.user.constant;
import com.fanxb.bookmark.common.constant.CommonConstant;
import com.fanxb.bookmark.common.constant.Constant;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.File;
import java.nio.file.Paths;
/**
@ -18,6 +20,6 @@ public class FileConstant {
/**
* 用户头像目录
*/
public static String iconPath = Paths.get(CommonConstant.fileSavePath, "files", "public", "icon").toString();
public static String iconPath = Paths.get("files", "public", "icon").toString();
}

View File

@ -1,30 +0,0 @@
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);
// }
}
}

View File

@ -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,12 +23,8 @@ import org.springframework.web.bind.annotation.*;
@Validated
public class BaseInfoController {
private final BaseInfoService baseInfoService;
@Autowired
public BaseInfoController(BaseInfoService baseInfoService) {
this.baseInfoService = baseInfoService;
}
private BaseInfoService baseInfoService;
/**
* Description: 修改密码
@ -86,17 +82,4 @@ 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);
}
}

View File

@ -1,32 +0,0 @@
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);
}
}

View File

@ -1,37 +0,0 @@
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();
}
}

View File

@ -1,47 +0,0 @@
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();
}
}

View File

@ -1,12 +1,9 @@
package com.fanxb.bookmark.business.user.controller;
import com.alibaba.fastjson.JSONObject;
import com.fanxb.bookmark.business.user.service.OauthService;
import com.fanxb.bookmark.business.user.entity.LoginBody;
import com.fanxb.bookmark.business.user.entity.RegisterBody;
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;
@ -14,8 +11,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;
/**
* 类功能简述
* 类功能详述
@ -27,16 +22,8 @@ import javax.validation.Valid;
@RequestMapping("/user")
public class UserController {
private final UserServiceImpl userServiceImpl;
private final OauthService oAuthService;
private final UserService userService;
@Autowired
public UserController(UserServiceImpl userServiceImpl, OauthService oAuthService, UserService userService) {
this.userServiceImpl = userServiceImpl;
this.oAuthService = oAuthService;
this.userService = userService;
}
private UserService userService;
/**
* Description: 获取验证码
@ -48,7 +35,7 @@ public class UserController {
*/
@GetMapping("/authCode")
public Result getAuthCode(@Param("email") String email) {
userServiceImpl.sendAuthCode(email);
userService.sendAuthCode(email);
return Result.success(null);
}
@ -61,8 +48,9 @@ public class UserController {
* @date 2019/7/6 16:34
*/
@PutMapping("")
public Result register(@Valid @RequestBody RegisterBody body) {
return Result.success(userServiceImpl.register(body));
public Result register(@RequestBody RegisterBody body) {
userService.register(body);
return Result.success(null);
}
/**
@ -74,7 +62,7 @@ public class UserController {
*/
@GetMapping("/currentUserInfo")
public Result currentUserInfo() {
return Result.success(userServiceImpl.getUserInfo(UserContextHolder.get().getUserId()));
return Result.success(userService.getUserInfo(UserContextHolder.get().getUserId()));
}
@ -85,7 +73,7 @@ public class UserController {
*/
@PostMapping("/icon")
public Result pushIcon(@RequestParam("file") MultipartFile file) throws Exception {
return Result.success(userServiceImpl.updateIcon(file));
return Result.success(userService.updateIcon(file));
}
/**
@ -98,7 +86,7 @@ public class UserController {
*/
@PostMapping("/login")
public Result login(@RequestBody LoginBody body) {
return Result.success(userServiceImpl.login(body));
return Result.success(userService.login(body));
}
/**
@ -111,7 +99,7 @@ public class UserController {
*/
@PostMapping("/resetPassword")
public Result resetPassword(@RequestBody RegisterBody body) {
userServiceImpl.resetPassword(body);
userService.resetPassword(body);
return Result.success(null);
}
@ -125,7 +113,7 @@ public class UserController {
*/
@PostMapping("/checkPassword")
public Result checkPassword(@RequestBody JSONObject obj) {
return Result.success(userServiceImpl.checkPassword(obj.getString("password")));
return Result.success(userService.checkPassword(obj.getString("password")));
}
@GetMapping("/loginStatus")
@ -133,54 +121,5 @@ 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")));
}
}

View File

@ -1,27 +0,0 @@
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);
}

View File

@ -1,48 +0,0 @@
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);
}

View File

@ -1,8 +0,0 @@
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> {
}

View File

@ -1,14 +1,11 @@
package com.fanxb.bookmark.business.user.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.fanxb.bookmark.common.entity.po.User;
import com.fanxb.bookmark.common.entity.User;
import com.fanxb.bookmark.common.entity.redis.UserBookmarkUpdate;
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;
/**
* 类功能简述
* 类功能详述
@ -17,7 +14,7 @@ import java.util.List;
* @date 2019/7/6 11:36
*/
@Component
public interface UserDao extends BaseMapper<User> {
public interface UserDao {
/**
* Description: 新增一个用户
@ -33,7 +30,7 @@ public interface UserDao extends BaseMapper<User> {
*
* @param name username
* @param email email
* @return com.fanxb.bookmark.common.entity.po.User
* @return com.fanxb.bookmark.common.entity.User
* @author fanxb
* @date 2019/7/6 16:45
*/
@ -63,12 +60,11 @@ public interface UserDao extends BaseMapper<User> {
* Description: 根据用户id查询用户信息
*
* @param userId userId
* @param githubId githubId
* @return com.fanxb.bookmark.common.entity.po.User
* @return com.fanxb.bookmark.common.entity.User
* @author fanxb
* @date 2019/7/30 16:08
*/
User selectByUserIdOrGithubId(@Param("userId") Integer userId, @Param("githubId") Long githubId);
User selectByUserId(int userId);
/**
* Description: 更新用户icon
@ -107,10 +103,10 @@ public interface UserDao extends BaseMapper<User> {
* 更新用户新邮箱
*
* @param userId userId
* @param newEmail email
* @param newPassword userId
*/
@Update("update user set newEmail=#{newEmail} where userId= #{userId}")
void updateNewEmailByUserId(@Param("userId") int userId, @Param("newEmail") String newEmail);
@Update("update user set newEmail=#{newPassword} where userId= #{userId}")
void updateNewEmailByUserId(@Param("userId") int userId, @Param("newPassword") String newPassword);
/**
* 新邮箱校验成功更新邮箱
@ -123,78 +119,10 @@ public interface UserDao extends BaseMapper<User> {
/**
* 功能描述: 更新用户上次更新书签时间
*
* @param userId userId
* @param item item
* @author fanxb
* @date 2020/1/26 下午3:47
*/
@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);
@Update("update user set bookmarkChangeTime=#{updateTime} where userId=#{userId}")
void updateLastBookmarkUpdateTime(UserBookmarkUpdate item);
}

View File

@ -1,4 +1,4 @@
package com.fanxb.bookmark.business.user.vo;
package com.fanxb.bookmark.business.user.entity;
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 oldPassword;
private String actionId;
@Email(message = "请输入有效邮箱地址")
private String email;
}

View File

@ -1,21 +0,0 @@
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;
}

View File

@ -1,4 +1,4 @@
package com.fanxb.bookmark.business.user.vo;
package com.fanxb.bookmark.business.user.entity;
import lombok.Data;

View File

@ -0,0 +1,20 @@
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;
}

View File

@ -1,36 +0,0 @@
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;
}

View File

@ -0,0 +1,18 @@
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;
}

View File

@ -1,29 +0,0 @@
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;
}

View File

@ -1,4 +1,4 @@
package com.fanxb.bookmark.business.user.vo;
package com.fanxb.bookmark.business.user.entity;
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 oldPassword;
private String actionId;
@Pattern(regexp = ValidatedConstant.PASSWORD_REG, message = ValidatedConstant.PASSWORD_MESSAGE)
private String password;
}

View File

@ -1,4 +1,4 @@
package com.fanxb.bookmark.business.user.vo;
package com.fanxb.bookmark.business.user.entity;
import com.fanxb.bookmark.business.user.constant.ValidatedConstant;
import lombok.Data;

View File

@ -0,0 +1,38 @@
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);
}
}
}

View File

@ -1,7 +0,0 @@
/**
* 定时调度类
*
* @author fanxb
* @date 2021-10-17 14:37
*/
package com.fanxb.bookmark.business.user.schedule;

View File

@ -1,25 +1,52 @@
package com.fanxb.bookmark.business.user.service;
import com.fanxb.bookmark.business.user.vo.EmailUpdateBody;
import com.fanxb.bookmark.business.user.vo.UpdatePasswordBody;
import com.fanxb.bookmark.common.entity.po.User;
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;
/**
* 个人信息修改
* 类功能简述
* 类功能详述
*
* @author fanxb
* @date 2021/3/14
**/
public interface BaseInfoService {
* @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()));
}
/**
* 修改密码
*
* @param body body
* @author fanxb
* @date 2021/3/14
**/
void changePassword(UpdatePasswordBody body);
/**
* Description: 修改用户名
@ -28,7 +55,9 @@ public interface BaseInfoService {
* @author fanxb
* @date 2019/9/20 16:18
*/
void updateUsername(String username);
public void updateUsername(String username) {
userDao.updateUsernameByUserId(UserContextHolder.get().getUserId(), username);
}
/**
* 功能描述: 预备更新email需要校验密码
@ -37,7 +66,23 @@ public interface BaseInfoService {
* @author fanxb
* @date 2019/9/26 17:27
*/
void updateEmail(EmailUpdateBody body);
@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());
}
/**
* 功能描述: 校验新邮箱校验成功就更新
@ -46,14 +91,13 @@ public interface BaseInfoService {
* @author fanxb
* @date 2019/11/11 23:24
*/
void verifyEmail(String secret);
/**
* 修改用户默认搜索引擎
*
* @param user user
* @author fanxb
* @date 2021/3/14
**/
void changeDefaultSearchEngine(User user);
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);
}
}

View File

@ -1,21 +0,0 @@
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);
}

View File

@ -1,33 +0,0 @@
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);
}

View File

@ -1,19 +0,0 @@
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);
}

View File

@ -1,49 +0,0 @@
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);
}

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