Compare commits

...

6 Commits

Author SHA1 Message Date
44c1ca91fc Merge pull request 'dev' (#17) from dev into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #17
2023-12-01 02:17:00 -05:00
fanxb
b0b608de5a docs:文档更新
Some checks failed
continuous-integration/drone/pr Build is failing
2023-12-01 14:58:42 +08:00
fanxb
523698a967 feat:首页图加载优化,增加OneNav导入支持 2023-12-01 13:18:44 +08:00
fanxb
405a2e05ed feat:首图下载下来 2023-11-29 23:42:33 +08:00
fanxb
6b59dfbf26 Merge branch 'master' into dev 2023-11-29 19:29:42 +08:00
42a2829847 Merge pull request 'master' (#16) from master into dev
Reviewed-on: #16
2023-11-25 00:49:22 -05:00
12 changed files with 250 additions and 123 deletions

View File

@ -1,12 +1,20 @@
本程序基于 docker 来进行部署,使用 docker-compose 管理服务。 本程序基于 docker 来进行部署,使用 docker-compose 管理服务。
部署过程如下: **注意,仅在 x86 环境下测试,arm 下不保证可用性(目前测试可用)**
**注意,仅在 x86 环境下测试,arm下不保证可用性目前测试可用** ## 首次部署
1. 安装新版的 docker,docker-compose,zip(注意:以下操作均在项目根目录下执行) 0. 克隆代码`git clone https://github.com/FleyX/bookmark.git`
2. 修改.env 文件中的参数,改为你的实际配置 1. 进入文件夹`cd bookmark`
3. 修改`浏览器插件/bookmarkBrowserPlugin/static/js/config.js`中的 bookmarkHost改为你的实际部署路径 2. 安装新版的 docker,docker-compose,zip `apt install docker docker-compose zip`
4. 修改`浏览器插件/bookmarkBrowserPlugin/tab/index.html`中的`<meta http-equiv="Refresh" content="0;url=https://bm.fleyx.com" />`,将 url 改为你的实际部署地址 3. 修改.env 文件中的参数,改为你的实际配置
5. 执行`build.sh`编译前后端代码 4. 修改`浏览器插件/bookmarkBrowserPlugin/static/js/config.js`中的 bookmarkHost改为你的实际部署路径
6. root 权限运行 `docker-compose up -d` 启动服务。 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` 启动服务

View File

@ -29,6 +29,11 @@
<artifactId>pinyin</artifactId> <artifactId>pinyin</artifactId>
<version>0.3.1</version> <version>0.3.1</version>
</dependency> </dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.44.1.0</version>
</dependency>
</dependencies> </dependencies>

View File

@ -69,7 +69,7 @@ public class BookmarkController {
*/ */
@RequestMapping("/uploadBookmarkFile") @RequestMapping("/uploadBookmarkFile")
public Result uploadFile(@RequestParam("file") MultipartFile file, @RequestParam("path") String path) throws Exception { public Result uploadFile(@RequestParam("file") MultipartFile file, @RequestParam("path") String path) throws Exception {
bookmarkService.parseBookmarkFile(UserContextHolder.get().getUserId(), file.getInputStream(), path); bookmarkService.parseBookmarkFile(UserContextHolder.get().getUserId(), file, path);
return Result.success(null); return Result.success(null);
} }

View File

@ -3,6 +3,7 @@ package com.fanxb.bookmark.business.bookmark.service;
import com.fanxb.bookmark.business.bookmark.entity.BookmarkEs; import com.fanxb.bookmark.business.bookmark.entity.BookmarkEs;
import com.fanxb.bookmark.business.bookmark.entity.MoveNodeBody; import com.fanxb.bookmark.business.bookmark.entity.MoveNodeBody;
import com.fanxb.bookmark.common.entity.po.Bookmark; import com.fanxb.bookmark.common.entity.po.Bookmark;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream; import java.io.InputStream;
import java.util.List; import java.util.List;
@ -54,7 +55,7 @@ public interface BookmarkService {
* @author fanxb * @author fanxb
* @date 2019/7/9 18:44 * @date 2019/7/9 18:44
*/ */
void parseBookmarkFile(int userId, InputStream stream, String path) throws Exception; void parseBookmarkFile(int userId, MultipartFile file, String path) throws Exception;
/** /**
* Description: 详情 * Description: 详情

View File

@ -2,10 +2,8 @@ package com.fanxb.bookmark.business.bookmark.service.impl;
import cn.hutool.core.codec.Base64Decoder; import cn.hutool.core.codec.Base64Decoder;
import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.*;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.HashUtil; import cn.hutool.core.util.HashUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.fanxb.bookmark.business.api.UserApi; import com.fanxb.bookmark.business.api.UserApi;
import com.fanxb.bookmark.business.bookmark.constant.FileConstant; import com.fanxb.bookmark.business.bookmark.constant.FileConstant;
@ -38,7 +36,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.awt.print.Book;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.InputStream; import java.io.InputStream;
@ -49,6 +49,10 @@ import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; 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.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -81,18 +85,25 @@ public class BookmarkServiceImpl implements BookmarkService {
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void parseBookmarkFile(int userId, InputStream stream, String path) throws Exception { public void parseBookmarkFile(int userId, MultipartFile file, String path) throws Exception {
Document doc = Jsoup.parse(stream, "utf-8", ""); List<Bookmark> bookmarks = new ArrayList<>();
Elements elements = doc.select("html>body>dl>dt");
//获取当前层sort最大值 //获取当前层sort最大值
Integer sortBase = bookmarkDao.selectMaxSort(userId, path); Integer sortBase = bookmarkDao.selectMaxSort(userId, path);
if (sortBase == null) { if (sortBase == null) {
sortBase = 0; sortBase = 0;
} }
List<Bookmark> bookmarks = new ArrayList<>(); if (file.getOriginalFilename().endsWith(".db3")) {
for (int i = 0, length = elements.size(); i < length; i++) { //处理db文件
dealBookmark(userId, elements.get(i), path, sortBase + i, bookmarks); 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); List<Bookmark> tempList = new ArrayList<>(1000);
for (int i = 0; i < bookmarks.size(); i++) { for (int i = 0; i < bookmarks.size(); i++) {
@ -151,6 +162,57 @@ public class BookmarkServiceImpl implements BookmarkService {
} }
} }
/**
* 处理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: 插入一条书签如果已经存在同名书签将跳过 * Description: 插入一条书签如果已经存在同名书签将跳过
* *
@ -288,7 +350,7 @@ public class BookmarkServiceImpl implements BookmarkService {
int size = 100; int size = 100;
int start = 0; int start = 0;
List<Bookmark> deal; List<Bookmark> deal;
while ((deal = bookmarkDao.selectUserNoIcon(userId, start, size)).size() > 0) { while (!(deal = bookmarkDao.selectUserNoIcon(userId, start, size)).isEmpty()) {
start += size; start += size;
deal.forEach(item -> { deal.forEach(item -> {
String icon = getIconPath(item.getUrl(), null, null); String icon = getIconPath(item.getUrl(), null, null);

View File

@ -2,8 +2,11 @@ package com.fanxb.bookmark.common.service.impl;
import cn.hutool.core.date.DateUnit; import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.fanxb.bookmark.common.constant.CommonConstant;
import com.fanxb.bookmark.common.constant.NumberConstant; import com.fanxb.bookmark.common.constant.NumberConstant;
import com.fanxb.bookmark.common.constant.RedisConstant; import com.fanxb.bookmark.common.constant.RedisConstant;
import com.fanxb.bookmark.common.dao.GlobalConfigDao; import com.fanxb.bookmark.common.dao.GlobalConfigDao;
@ -12,11 +15,16 @@ import com.fanxb.bookmark.common.entity.vo.GlobalConfigVo;
import com.fanxb.bookmark.common.service.ConfigService; import com.fanxb.bookmark.common.service.ConfigService;
import com.fanxb.bookmark.common.util.HttpUtil; import com.fanxb.bookmark.common.util.HttpUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.*; import java.util.*;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -61,21 +69,23 @@ public class ConfigServiceImpl implements ConfigService {
return str; return str;
} }
str = getBingImg(); str = getBingImg();
if (str != null) { stringRedisTemplate.opsForValue().set(RedisConstant.BING_IMG, str, 2, TimeUnit.HOURS);
stringRedisTemplate.opsForValue().set(RedisConstant.BING_IMG, str, 2, TimeUnit.HOURS);
}
return str; return str;
} }
private String getBingImg() { private String getBingImg() {
try { JSONObject bingObj = HttpUtil.getObj(bingHost + bingUrl, null, false);
JSONObject bingObj = HttpUtil.getObj(bingHost + bingUrl, null, false); String path = bingObj.getJSONArray("images").getJSONObject(0).getString("url");
String path = bingObj.getJSONArray("images").getJSONObject(0).getString("url"); String picUrl = bingHost + path;
return bingHost + path; Request request = new Request.Builder().url(picUrl).build();
try (Response res = HttpUtil.getClient(false).newCall(request).execute()) {
byte[] bytes = res.body().bytes();
String filePath = CommonConstant.fileSavePath + "/files/public/bing.jpg";
FileUtil.writeBytes(bytes, filePath);
} catch (Exception e) { } catch (Exception e) {
log.error("获取bing每日一图错误{}", e.getLocalizedMessage(), e); log.error("获取bing每日一图错误{}", e.getLocalizedMessage(), e);
} }
return null; return "/files/public/bing.jpg";
} }

View File

@ -6,12 +6,21 @@
<script> <script>
export default { export default {
name: "App" name: "App",
mounted() {
window.qieziStatisticKey = "b74c4b571b644782a837433209827874";
let script = document.createElement("script");
script.type = "text/javascript";
script.defer = true;
script.src = "https://qiezi.fleyx.com/qiezijs/1.0/qiezi_statistic.min.js";
document.getElementsByTagName("head")[0].appendChild(script);
}
}; };
</script> </script>
<style lang="less"> <style lang="less">
@import "./global.less"; @import "./global.less";
html, html,
body { body {
margin: 0; margin: 0;
@ -20,6 +29,7 @@ body {
background-color: @bgColor; background-color: @bgColor;
height: initial; height: initial;
} }
#app { #app {
font-family: Avenir, Helvetica, Arial, sans-serif; font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;

View File

@ -21,6 +21,7 @@
:data="{ path: form.path }" :data="{ path: form.path }"
:headers="{ 'jwt-token': token }" :headers="{ 'jwt-token': token }"
action="/bookmark/api/bookmark/uploadBookmarkFile" action="/bookmark/api/bookmark/uploadBookmarkFile"
accept=".html,.db3"
@change="fileChange" @change="fileChange"
> >
<p class="ant-upload-drag-icon"> <p class="ant-upload-drag-icon">

View File

@ -12,54 +12,54 @@ import router from "../router/index";
* @param {*} redirect 接口返回未认证是否跳转到登陆 * @param {*} redirect 接口返回未认证是否跳转到登陆
* @returns 数据 * @returns 数据
*/ */
async function request (url, method, params, body, isForm, redirect) { async function request(url, method, params, body, isForm, redirect) {
let options = { let options = {
url, url,
baseURL: "/bookmark/api", baseURL: "/bookmark/api",
method, method,
params, params,
headers: { headers: {
"jwt-token": window.jwtToken "jwt-token": window.jwtToken
} }
}; };
//如果是表单类型的请求,添加请求头 //如果是表单类型的请求,添加请求头
if (isForm) { if (isForm) {
options.headers["Content-Type"] = "multipart/form-data"; options.headers["Content-Type"] = "multipart/form-data";
} }
if (body) { if (body) {
options.data = body; options.data = body;
} }
let res; let res;
try { try {
res = await http.default.request(options); res = await http.default.request(options);
} catch (err) { } catch (err) {
window.vueInstance.$message.error("网络连接异常"); window.vueInstance.$message.error("网络连接异常");
console.error(err); console.error(err);
throw err; throw err;
} }
const { code, data, message } = res.data; const { code, data, message } = res.data;
if (code === 1) { if (code === 1) {
return data; return data;
} else if (code === -1 && redirect) { } else if (code === -1 && redirect) {
//未登陆根据redirect参数判断是否需要跳转到登陆页 //未登陆根据redirect参数判断是否需要跳转到登陆页
window.vueInstance.$message.error("您尚未登陆,请先登陆"); window.vueInstance.$message.error("您尚未登陆,请先登陆");
//跳转到登录页面需要清理缓存 //跳转到登录页面需要清理缓存
await this.$store.dispatch("treeData/clear"); await this.$store.dispatch("treeData/clear");
await this.$store.dispatch("globalConfig/clear"); await this.$store.dispatch("globalConfig/clear");
router.replace(`/public/login?redirect=${encodeURIComponent(router.currentRoute.fullPath)}`); router.replace(`/public/login?redirect=${encodeURIComponent(router.currentRoute.fullPath)}`);
throw new Error(message); throw new Error(message);
} else if (code === 0) { } else if (code === 0) {
//通用异常使用error提示 //通用异常使用error提示
window.vueInstance.$notification.error({ window.vueInstance.$notification.error({
message: "异常", message: "异常",
description: message description: message
}); });
throw new Error(message); throw new Error(message);
} else if (code === -2) { } else if (code === -2) {
//表单异常使用message提示 //表单异常使用message提示
window.vueInstance.$message.error(message); window.vueInstance.$message.error(message);
throw new Error(message); throw new Error(message);
} }
} }
/** /**
@ -68,8 +68,8 @@ async function request (url, method, params, body, isForm, redirect) {
* @param {*} params url参数 * @param {*} params url参数
* @param {*} redirect 未登陆是否跳转到登陆页 * @param {*} redirect 未登陆是否跳转到登陆页
*/ */
async function get (url, params = null, redirect = true) { async function get(url, params = null, redirect = true) {
return request(url, "get", params, null, false, redirect); return request(url, "get", params, null, false, redirect);
} }
/** /**
@ -80,8 +80,8 @@ async function get (url, params = null, redirect = true) {
* @param {*} isForm 是否表单数据 * @param {*} isForm 是否表单数据
* @param {*} redirect 是否重定向 * @param {*} redirect 是否重定向
*/ */
async function post (url, params, body, isForm = false, redirect = true) { async function post(url, params, body, isForm = false, redirect = true) {
return request(url, "post", params, body, isForm, redirect); return request(url, "post", params, body, isForm, redirect);
} }
/** /**
@ -92,8 +92,8 @@ async function post (url, params, body, isForm = false, redirect = true) {
* @param {*} isForm 是否表单数据 * @param {*} isForm 是否表单数据
* @param {*} redirect 是否重定向 * @param {*} redirect 是否重定向
*/ */
async function put (url, params, body, isForm = false, redirect = true) { async function put(url, params, body, isForm = false, redirect = true) {
return request(url, "put", params, body, isForm, redirect); return request(url, "put", params, body, isForm, redirect);
} }
/** /**
@ -102,13 +102,14 @@ async function put (url, params, body, isForm = false, redirect = true) {
* @param {*} params url参数 * @param {*} params url参数
* @param {*} redirect 是否重定向 * @param {*} redirect 是否重定向
*/ */
async function deletes (url, params = null, redirect = true) { async function deletes(url, params = null, redirect = true) {
return request(url, "delete", params, null, redirect); return request(url, "delete", params, null, redirect);
} }
export default { export default {
get, get,
post, post,
put, put,
delete: deletes delete: deletes,
http
}; };

View File

@ -5,18 +5,23 @@
源码地址 源码地址
<a href="https://github.com/FleyX/bookmark" target="_blank">github.com/FleyX/bookmark</a> <a href="https://github.com/FleyX/bookmark" target="_blank">github.com/FleyX/bookmark</a>
</div> </div>
<div>
当前版本{{ appVersion }}&emsp;&emsp;<a v-if="showNewVersion"
href="https://github.com/FleyX/bookmark/blob/master/DEPLOY.md">最新版本{{ latestVersion
}}</a>
</div>
<div> <div>
使用教程 使用教程
<a href="https://blog.fleyx.com/blog/detail/20220329" target="_blank">点击跳转</a> <a href="https://blog.fleyx.com/blog/detail/20220329" target="_blank">点击跳转</a>
</div> </div>
<div> <div>
浏览器插件 浏览器插件
<a href="/static/bookmarkBrowserPlugin.zip" download="浏览器插件.zip" target="_blank">最新版本{{ serverConfig.map.pluginVersion }}(注意更新)</a> <a href="/static/bookmarkBrowserPlugin.zip" download="浏览器插件.zip"
target="_blank">最新版本{{ serverConfig.map.pluginVersion }}(注意更新)</a>
,使用详情请参考使用教程 ,使用详情请参考使用教程
</div> </div>
<div>交流反馈qq群150056494,邮箱fleyx20@outlook.com</div> <div>交流反馈qq群150056494,邮箱fleyx20@outlook.com</div>
<div> <div>
统计
<a href="https://qiezi.fleyx.com" style="" target="_blank"> <a href="https://qiezi.fleyx.com" style="" target="_blank">
<div id="qieziStatisticHtmlHostPv" style="display: none"> <div id="qieziStatisticHtmlHostPv" style="display: none">
总访问次数: 总访问次数:
@ -36,27 +41,46 @@
<script> <script>
import { mapState } from "vuex"; import { mapState } from "vuex";
import { GLOBAL_CONFIG, SERVER_CONFIG } from "@/store/modules/globalConfig"; import { GLOBAL_CONFIG, SERVER_CONFIG } from "@/store/modules/globalConfig";
import httpUtil from "@/util/HttpUtil";
export default { export default {
name: "about", name: "about",
data() { data() {
return { version: "" }; return {
appVersion: "1.4", //
latestVersion: null,
showNewVersion: false
};
}, },
computed: { ...mapState(GLOBAL_CONFIG, [SERVER_CONFIG]) }, computed: { ...mapState(GLOBAL_CONFIG, [SERVER_CONFIG]) },
mounted() { async mounted() {
window.qieziStatisticKey = "b74c4b571b644782a837433209827874";
let script = document.createElement("script");
script.type = "text/javascript";
script.defer = true;
script.src = "https://qiezi.fleyx.com/qiezijs/1.0/qiezi_statistic.min.js";
document.getElementsByTagName("head")[0].appendChild(script);
let serverConfig = this.$store.state[GLOBAL_CONFIG + "/" + SERVER_CONFIG];
console.log(serverConfig); //
if (serverConfig.map.pluginVersion) { let res = await httpUtil.http.default.get("https://s3.fleyx.com/picbed/bookmark/config.json");
this.version = serverConfig.map.pluginVersion; console.log(res);
} this.latestVersion = res.data.latestAppVersion;
this.showNewVersion = this.checkVersion(this.appVersion, this.latestVersion);
}, },
}; methods: {
checkVersion: function(version, latestVersion) {
let versions = version.split(".");
let latestVersions = latestVersion.split(".");
for (let i = 0; i < versions.length; i++) {
if (i >= latestVersions.length) {
return false;
}
let versionNum = parseInt(versions[i]);
let latestVersionNum = parseInt(latestVersions[i]);
if (versionNum !== latestVersionNum) {
return versionNum < latestVersionNum;
}
}
return true;
}
}
}
;
</script> </script>
<style lang="less" scoped></style> <style lang="less" scoped></style>

View File

@ -1,20 +1,21 @@
module.exports = { module.exports = {
lintOnSave: false, lintOnSave: false,
configureWebpack: { configureWebpack: {
devtool: "source-map" devtool: "source-map"
}, },
devServer: { devServer: {
proxy: { port: 4531,
"/bookmark/api": { proxy: {
//这里最好有一个 / "/bookmark/api": {
target: "http://localhost:8088", // 服务器端接口地址 //这里最好有一个 /
ws: true, //如果要代理 websockets配置这个参数 target: "http://localhost:8088", // 服务器端接口地址
// 如果是https接口需要配置这个参数 ws: true, //如果要代理 websockets配置这个参数
changeOrigin: true, //是否跨域 // 如果是https接口需要配置这个参数
pathRewrite: { changeOrigin: true, //是否跨域
"^/bookmark/api": "/bookmark/api" pathRewrite: {
} "^/bookmark/api": "/bookmark/api"
} }
} }
} }
}
}; };

View File

@ -14,6 +14,7 @@ services:
- ./data/mysql/my.cnf:/etc/mysql/my.cnf - ./data/mysql/my.cnf:/etc/mysql/my.cnf
- /etc/localtime:/etc/localtime - /etc/localtime:/etc/localtime
- ./data/timezone:/etc/timezone - ./data/timezone:/etc/timezone
restart: unless-stopped
environment: environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD} - MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD}
- MYSQL_DATABASE=bookmark - MYSQL_DATABASE=bookmark
@ -25,6 +26,7 @@ services:
- /etc/localtime:/etc/localtime - /etc/localtime:/etc/localtime
- ./data/timezone:/etc/timezone - ./data/timezone:/etc/timezone
- ./data/redis:/data - ./data/redis:/data
restart: unless-stopped
networks: networks:
- bookmark - bookmark
@ -38,6 +40,7 @@ services:
- ./bookmark_front/dist:/opt/dist - ./bookmark_front/dist:/opt/dist
- ./data/nginx/nginx.conf:/etc/nginx/nginx.conf - ./data/nginx/nginx.conf:/etc/nginx/nginx.conf
- ${BOOKMARK_FILE_SAVE_PATH}/files/public:/opt/files/public - ${BOOKMARK_FILE_SAVE_PATH}/files/public:/opt/files/public
restart: unless-stopped
ports: ports:
- 8080:8080 - 8080:8080
@ -60,6 +63,7 @@ services:
- ./bookMarkService/web/target/bookmark-web-1.0-SNAPSHOT.jar:/opt/app/service.jar - ./bookMarkService/web/target/bookmark-web-1.0-SNAPSHOT.jar:/opt/app/service.jar
- ${BOOKMARK_FILE_SAVE_PATH}:/opt/files - ${BOOKMARK_FILE_SAVE_PATH}:/opt/files
working_dir: /opt/app working_dir: /opt/app
restart: unless-stopped
command: command:
- /bin/bash - /bin/bash
- -c - -c