mirror of
https://gitee.com/bookshelfplus/bookshelfplus
synced 2025-09-01 22:53:29 +08:00
Merge branch 'develop'
This commit is contained in:
7
.gitignore
vendored
7
.gitignore
vendored
@@ -14,7 +14,8 @@ package-lock.json
|
||||
# 排除所有调试产生的log文件
|
||||
*.log
|
||||
|
||||
.vs/*
|
||||
# 排除idea项目 iml 文件
|
||||
bookshelfplus.iml
|
||||
|
||||
*.njsproj.user
|
||||
obj/*
|
||||
# TODO文件
|
||||
TODO*
|
89
README.md
89
README.md
@@ -1,17 +1,88 @@
|
||||
# 计算机类电子书网站开源项目
|
||||
<div style="text-align: center;" align="center">
|
||||
<h1>书栖网 网站开源项目</h1>
|
||||
<p>一个完全免费无门槛的计算机类电子书下载网站</p>
|
||||
</div>
|
||||
|
||||
> 如需获取计算机类电子书,请访问https://books.only4.work/ ,或前往Git仓库👉([GitHub](https://github.com/only-4/computer-related-books)、[Gitee](https://gitee.com/only4/computer-related-books))
|
||||
项目官网:https://bookshelf.plus
|
||||
|
||||
当前项目为 https://books.only4.work 网站源代码,你也可以通过这个项目搭建一个属于自己的电子书分享与管理平台。
|
||||
开源仓库:<a href="https://github.com/bookshelfplus/bookshelfplus" target="_blank">GitHub</a> <a href="https://gitee.com/bookshelfplus/bookshelfplus" target="_blank">Gitee</a>
|
||||
|
||||
[接口文档](api.md)
|
||||

|
||||
|
||||
## 前端
|
||||
## 简介
|
||||
|
||||
开发使用 nodemon,代码变动后自动重启。
|
||||
前项目为书栖网官网开源项目,你也可以通过这个项目搭建一个属于自己的电子书分享与管理平台。
|
||||
|
||||
使用以下代码安装 nodemon
|
||||
> 如需获取计算机类电子书,请访问https://bookshelf.plus/ ,或前往Git仓库👉([GitHub](https://github.com/only-4/computer-related-books)、[Gitee](https://gitee.com/only4/computer-related-books))
|
||||
|
||||
```
|
||||
|
||||
|
||||
## 开始使用
|
||||
|
||||
> 所需环境:Java JDK 8+,Maven,MySQL 5.7+,nodejs等
|
||||
|
||||
### 安装环境
|
||||
|
||||
```bash
|
||||
# 安装 nodejs
|
||||
# 官方网站:https://nodejs.org/zh-cn/
|
||||
# 下载地址:https://nodejs.org/dist/v16.14.0/node-v16.14.0-x64.msi
|
||||
|
||||
# 安装 JDK 8
|
||||
|
||||
# 安装 Maven
|
||||
|
||||
# 安装 MySQL 5.7
|
||||
|
||||
# 导入数据库SQL脚本
|
||||
|
||||
# nodemon(可选)
|
||||
# 开发使用 nodemon,代码变动后自动重启。
|
||||
# 使用以下代码安装 nodemon
|
||||
npm i nodemon -g
|
||||
```
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 功能展示
|
||||
|
||||
### 功能列表
|
||||
|
||||
- [x] 首页。简约(说白了其实就是懒),一个搜索框就够了。后期考虑添加热门搜索功能。
|
||||
- [ ] 书籍列表页,也是搜索结果页。就是一个书单列表,带分页功能。
|
||||
- [ ] 书籍详情页。主要是显示书籍的各种详细信息(书名,简介,缩略图等),还有下载方式,同时还有反馈功能(连接失效反馈,版权问题申诉下架等)
|
||||
- [ ] 管理员后台。
|
||||
- [ ] 用户登录后台。
|
||||
|
||||
### 功能截图
|
||||
|
||||
截图待补充...
|
||||
|
||||
|
||||
|
||||
## 项目架构
|
||||
|
||||
> 项目前后端分离开发,使用了不同的技术,通过nginx进行反向代理
|
||||
|
||||
**前端**采用`nodejs`开发,使用`axios`、`jQuery`等组件。
|
||||
|
||||
**后端**采用`SpringBoot`开发,数据库连接使用`mybatis`、`alibaba druid`,接口文档生成使用`swagger2`,参数验证采用`hibernate`,日期时间处理使用`joda-time`工具类,同时还使用了`lombok`简化代码。
|
||||
|
||||
**数据库**采用`MySQL`,会话缓存采用`redis`。
|
||||
|
||||
**反向代理**使用`nginx`。
|
||||
|
||||
**对象存储**对接腾讯云COS存储(`cos_api`)。
|
||||
|
||||
|
||||
|
||||
## 开发工具
|
||||
|
||||
前端:VS Code,后端:idea,数据库:MySQL
|
||||
|
||||
|
||||
|
||||
## 注意事项
|
||||
|
||||
- nginx启动目录不能包含中文,否则无法启动
|
||||
|
||||
|
@@ -0,0 +1,26 @@
|
||||
// 带参数的post请求
|
||||
function postRequest(url, params) {
|
||||
return axios({
|
||||
method: 'post',
|
||||
url: url,
|
||||
data: params,
|
||||
})
|
||||
}
|
||||
|
||||
// 带参数的get请求
|
||||
function getRequest(url, params) {
|
||||
return axios({
|
||||
method: 'get',
|
||||
url: url,
|
||||
params: params,
|
||||
})
|
||||
}
|
||||
|
||||
// 带参数的put请求
|
||||
function putRequest(url, params) {
|
||||
return axios({
|
||||
method: 'put',
|
||||
url: url,
|
||||
data: params
|
||||
})
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
// refer: https://juejin.cn/post/6844903960705236999
|
||||
var xhr = new window.XMLHttpRequest;
|
||||
xhr.responseType = "document";
|
||||
// 通过get的方式请求当前文件
|
||||
xhr.open("head", location.href);
|
||||
xhr.send(null);
|
||||
// 监听请求状态变化
|
||||
xhr.onreadystatechange = function () {
|
||||
var time = null,
|
||||
curDate = null;
|
||||
if (xhr.readyState === 2) {
|
||||
// 获取响应头里的时间戳
|
||||
time = xhr.getResponseHeader("Date");
|
||||
// countDown(new Date(time).getTime());
|
||||
var timeOff = getTimeOff(new Date(time).getTime());
|
||||
|
||||
var target = document.getElementById("timeOff");
|
||||
if (target) {
|
||||
target.innerHTML = "本地时间比服务器" + (timeOff > 0 ? "慢" : "快") + Math.abs(timeOff / 1000) + "秒";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function getTimeOff(time) {
|
||||
let serverTime = getNowDate(time, 8); // Head请求,返回服务器当前时间戳
|
||||
let localTime = getNowDate(Date.now(), 8); // 用户本地时间戳
|
||||
|
||||
let timeOff = serverTime - localTime;
|
||||
return timeOff;
|
||||
}
|
||||
|
||||
// function countDown(time) {
|
||||
// let targetTime = Date.parse('2025/12/12 00:00:00');
|
||||
// let serverTime = getNowDate(time, 8); // Head请求,返回服务器当前时间戳
|
||||
// let localTime = getNowDate(Date.now(), 8); // 用户本地时间戳
|
||||
|
||||
// let timeOff = serverTime - localTime;
|
||||
// let rightTargetTime = targetTime - timeOff; // 去除偏差后的目标时间
|
||||
|
||||
// if(rightTargetTime <= localTime) {
|
||||
// console.log('按钮可点击')
|
||||
// } else {
|
||||
// console.log('按钮不可点击')
|
||||
// }
|
||||
// }
|
||||
|
||||
function getNowDate(localTime, timeZone) {
|
||||
var timezone = timeZone || 8; //目标时区时间,东八区
|
||||
// 本地时间和格林威治的时间差,单位为分钟
|
||||
var offset_GMT = new Date().getTimezoneOffset();
|
||||
// 本地时间距 1970 年 1 月 1 日午夜(GMT 时间)之间的毫秒数
|
||||
var nowDate = localTime;
|
||||
var targetDate = nowDate + offset_GMT * 60 * 1000 + timezone * 60 * 60 * 1000;
|
||||
return targetDate;
|
||||
}
|
File diff suppressed because one or more lines are too long
2
bookshelfplus-frontend/public/assets/lib/axios/0.26.1/axios.min.js
vendored
Normal file
2
bookshelfplus-frontend/public/assets/lib/axios/0.26.1/axios.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -70,7 +70,6 @@ hr {
|
||||
/* 标题 siteTitle */
|
||||
.siteTitle h1 {
|
||||
margin-top: 130px;
|
||||
display: inline-block;
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
@@ -82,8 +81,14 @@ hr {
|
||||
/* 正文样式 */
|
||||
.main {
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
/* max-width: 600px; */
|
||||
max-width: min(90vw, 720px);
|
||||
min-height: 50vh;
|
||||
}
|
||||
|
||||
.main > h1 {
|
||||
margin-block-start: 40px;
|
||||
}
|
||||
|
||||
.main p {
|
||||
|
@@ -20,10 +20,22 @@ router.get('/category', function (req, res) {
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/book', function (req, res) {
|
||||
res.render('book', {
|
||||
title: "书籍详情"
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/about', function (req, res) {
|
||||
res.render('about', {
|
||||
title: "关于"
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/status', function (req, res) {
|
||||
res.render('status', {
|
||||
title: "网站状态检测"
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
@@ -1,23 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<%- include("./component/header.html"); %>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<%- include("./component/navbar.html"); %>
|
||||
|
||||
<div class="main" align="center">
|
||||
<div class="siteTitle">
|
||||
<h1>书栖网</h1>
|
||||
</div>
|
||||
|
||||
<div class="sloganBox">
|
||||
<p class="emphasize">
|
||||
一个完全免费无门槛的计算机类电子书下载网站
|
||||
</p>
|
||||
</div>
|
||||
<h1>书栖网</h1>
|
||||
<p>一个完全免费无门槛的计算机类电子书下载网站</p>
|
||||
|
||||
<h2>随便唠唠</h2>
|
||||
<p>本网站是“计算机类电子书”仓库的前身,我们希望能够搭建一个电子书共享平台,供大家在学习中方便搜索以及下载。</p>
|
||||
@@ -40,14 +30,11 @@
|
||||
<hr>
|
||||
<p>最后,还是要说一下版权的问题。我们十分重视版权。我们所整理的电子书全部来自于互联网,其中部分来自于下载站、公众号等。如果其中包含您的作品,且您不希望我们将您的作品作为免费分享出来,请联系<span>contact@only4.work</span>并提供相应证明材料,我们核实后将会第一时间删除。同时,您在本网站上下载的所有电子书文件,仅供学习交流使用,不可二次传播,特别是不可设置扫码关注等门槛二次分享。
|
||||
</p>
|
||||
<hr>
|
||||
|
||||
<h2>特别说明</h2>
|
||||
<p>本站电子书由“张小弟之家”整理,出于方便学习之目的,您从本站下载的电子书仅供学习交流使用,如需他用请联系原作者。<a href="https://gitee.com/only4/computer-related-books" target="_blank">查看同步更新Gitee仓库</a></p>
|
||||
<p>由于信息量较大,我们无法做到一一确认相关电子书的权属管理,如本站不慎侵犯了您的权利,请发送邮件至<b>contact@only4.work</b>,来信请注明相关链接以及您的相关证明材料,我们收到邮件后会第一时间与您取得联系并积极处理,多谢理解!</p>
|
||||
|
||||
</div>
|
||||
|
||||
<%- include("./component/footer.html"); %>
|
||||
</body>
|
||||
|
||||
</html>
|
24
bookshelfplus-frontend/views/book.html
Normal file
24
bookshelfplus-frontend/views/book.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<%- include("./component/header.html"); %>
|
||||
</head>
|
||||
<body>
|
||||
<%- include("./component/navbar.html"); %>
|
||||
<main class="main">
|
||||
<h1><%= title %></h1>
|
||||
<div id="container">
|
||||
</div>
|
||||
</main>
|
||||
<%- include("./component/footer.html"); %>
|
||||
|
||||
<script>
|
||||
getRequest("/book/get", { id: 1 })
|
||||
.then(function (response) {
|
||||
console.log(response.data);
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@@ -1,21 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<%- include("./component/header.html"); %>
|
||||
</head>
|
||||
<body>
|
||||
<%- include("./component/navbar.html"); %>
|
||||
|
||||
<h1><%= title %></h1>
|
||||
|
||||
<main class="main">
|
||||
<h1><%= title %></h1>
|
||||
<div id="container">
|
||||
<a href="./book">书本详情页</a>
|
||||
</div>
|
||||
</main>
|
||||
<%- include("./component/footer.html"); %>
|
||||
|
||||
<script>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@@ -1,6 +1,13 @@
|
||||
<div class="footer">
|
||||
<div class="footer" style="margin-top: 10vh;">
|
||||
<hr>
|
||||
<p>书栖网 • 2021-2022</p>
|
||||
<p>
|
||||
书栖网 • 2021-2022
|
||||
<br>
|
||||
<small>
|
||||
<a href="/status">网站状态检测</a>
|
||||
</small>
|
||||
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- https://gist.github.com/macbookandrew/f33dbbc0aa582d0515919dc5fb95c00a -->
|
||||
@@ -14,10 +21,7 @@
|
||||
return res;
|
||||
}
|
||||
function fontmin(text) {
|
||||
// 设置post type
|
||||
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||
// 接口地址
|
||||
axios.post('/fontmin/getfont', { text: text, font: "" })
|
||||
axios.post('../fontmin/getfont', { text: text, font: "" })
|
||||
.then(function (response) {
|
||||
// 当接口成功返回时,动态设置css
|
||||
let styleDom = document.createElement('style');
|
||||
|
@@ -4,7 +4,15 @@
|
||||
<title><%= title; %></title>
|
||||
|
||||
<link rel="stylesheet" href="./assets/stylesheets/style.css">
|
||||
<!-- <script src="https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js"></script> -->
|
||||
<script src="./assets/lib/jquery/3.6.0/jquery.min.js"></script>
|
||||
<script src="./assets/lib/axios/0.26.1/axios.min.js"></script>
|
||||
|
||||
<script src="./assets/lib/axios/0.20.0/axios.min.js"></script>
|
||||
<script src="./assets/javascripts/httpRequest.js"></script>
|
||||
<script>
|
||||
// API地址
|
||||
const APIHOST = '<%= global.site.api.prefix %>';
|
||||
axios.defaults.baseURL = APIHOST;
|
||||
|
||||
// 请求头 Content-Type
|
||||
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||
</script>
|
52
bookshelfplus-frontend/views/component/searchbox.html
Normal file
52
bookshelfplus-frontend/views/component/searchbox.html
Normal file
@@ -0,0 +1,52 @@
|
||||
<div class="searchBox">
|
||||
<input id="searchInput" type="text" placeholder="只需两步:搜索、下载 就这么简单" />
|
||||
<input id="searchButton" type="button" value="搜一下" />
|
||||
</div>
|
||||
<script>
|
||||
// /**
|
||||
// * 内容改变时并不会触发事件,但是在失去焦点的时候会触发。
|
||||
// */
|
||||
// $("#inputid").change(function () {
|
||||
// console.log($(this).val());
|
||||
// });
|
||||
// /**
|
||||
// * 只要文本类容发生改变,就会触发该事件
|
||||
// */
|
||||
// $("#inputid").bind("input propertychange", function () {
|
||||
// console.log($(this).val());
|
||||
// });
|
||||
|
||||
// // 搜索框文字改变事件(实时)
|
||||
// $("#searchInput").bind("input propertychange", function () {
|
||||
// if ($('#searchInput').val() !== "")
|
||||
// $('#searchInput').val("这个功能还没做呢,再等等吧");
|
||||
// });
|
||||
|
||||
// 搜索框获得焦点事件
|
||||
$('#searchInput').focus(() => {
|
||||
// $('#searchInput').val("");
|
||||
$('#searchInput').attr('placeholder', "在这里输入您想搜索的电子书吧")
|
||||
})
|
||||
|
||||
// 搜索框失去焦点事件
|
||||
$('#searchInput').blur((that) => {
|
||||
// $('#searchInput').val("");
|
||||
$('#searchInput').attr('placeholder', "只需两步:搜索、下载 就这么简单")
|
||||
})
|
||||
|
||||
// 文本框回车事件
|
||||
$('#searchInput').keydown(function (e) {
|
||||
var curKey = e.which;
|
||||
if (curKey == 13) {
|
||||
$("#searchButton").click();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// 搜索按钮点击事件
|
||||
$('#searchButton').click(function () {
|
||||
if ($('#searchInput').val() !== "") {
|
||||
location.href = "search?keyword=" + encodeURIComponent($('#searchInput').val());
|
||||
}
|
||||
});
|
||||
</script>
|
@@ -1,5 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<%- include("./component/header.html"); %>
|
||||
|
@@ -1,82 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<%- include("./component/header.html"); %>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<%- include("./component/navbar.html"); %>
|
||||
|
||||
<div class="main" align="center">
|
||||
<div class="main">
|
||||
<div class="siteTitle">
|
||||
<h1>书栖网</h1>
|
||||
<h1>书栖网</h1>
|
||||
</div>
|
||||
|
||||
<div class="searchBox">
|
||||
<input id="searchInput" type="text" placeholder="只需两步:搜索、下载 就这么简单" />
|
||||
<input id="searchButton" type="button" value="搜一下" />
|
||||
</div>
|
||||
|
||||
<%- include("./component/searchbox.html"); %>
|
||||
<div class="sloganBox">
|
||||
<p class="emphasize">
|
||||
一个完全免费无门槛的计算机类电子书下载网站
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 30vh;"></div>
|
||||
|
||||
<%- include("./component/footer.html"); %>
|
||||
|
||||
<script>
|
||||
// /**
|
||||
// * 内容改变时并不会触发事件,但是在失去焦点的时候会触发。
|
||||
// */
|
||||
// $("#inputid").change(function () {
|
||||
// console.log($(this).val());
|
||||
// });
|
||||
// /**
|
||||
// * 只要文本类容发生改变,就会触发该事件
|
||||
// */
|
||||
// $("#inputid").bind("input propertychange", function () {
|
||||
// console.log($(this).val());
|
||||
// });
|
||||
|
||||
// // 搜索框文字改变事件(实时)
|
||||
// $("#searchInput").bind("input propertychange", function () {
|
||||
// if ($('#searchInput').val() !== "")
|
||||
// $('#searchInput').val("这个功能还没做呢,再等等吧");
|
||||
// });
|
||||
|
||||
// 搜索框获得焦点事件
|
||||
$('#searchInput').focus(() => {
|
||||
// $('#searchInput').val("");
|
||||
$('#searchInput').attr('placeholder', "在这里输入您想搜索的电子书吧")
|
||||
})
|
||||
|
||||
// 搜索框失去焦点事件
|
||||
$('#searchInput').blur((that) => {
|
||||
// $('#searchInput').val("");
|
||||
$('#searchInput').attr('placeholder', "只需两步:搜索、下载 就这么简单")
|
||||
})
|
||||
|
||||
// 文本框回车事件
|
||||
$('#searchInput').keydown(function (e) {
|
||||
var curKey = e.which;
|
||||
if (curKey == 13) {
|
||||
$("#searchButton").click();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// 搜索按钮点击事件
|
||||
$('#searchButton').click(function () {
|
||||
if ($('#searchInput').val() !== "") {
|
||||
location.href = "search?keyword=" + encodeURIComponent($('#searchInput').val());
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
@@ -1,21 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<%- include("./component/header.html"); %>
|
||||
</head>
|
||||
<body>
|
||||
<%- include("./component/navbar.html"); %>
|
||||
|
||||
<h1><%= title %></h1>
|
||||
|
||||
<main class="main">
|
||||
<h1><%= title %></h1>
|
||||
<div id="container">
|
||||
</div>
|
||||
</main>
|
||||
<%- include("./component/footer.html"); %>
|
||||
|
||||
<script>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
104
bookshelfplus-frontend/views/status.html
Normal file
104
bookshelfplus-frontend/views/status.html
Normal file
@@ -0,0 +1,104 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<%- include("./component/header.html"); %>
|
||||
<style>
|
||||
.info-disabled {
|
||||
color: #999;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<%- include("./component/navbar.html"); %>
|
||||
<main class="main">
|
||||
<h1>
|
||||
<%= title %>
|
||||
</h1>
|
||||
<div id="container">
|
||||
<input id="checkBtn" type="button" value="检测" onclick="startCheck()">
|
||||
|
||||
<div class="parentNode">
|
||||
<div class="childrenNode">
|
||||
<h3 class="title">网络连通性</h3>
|
||||
<span id="onlineStatus" class="info"></span>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="title">网络后台状态</h3>
|
||||
<span id="backendStatus" class="info"></span>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="title">网络数据库状态</h3>
|
||||
<span id="databaseStatus" class="info info-disabled">暂不提供检测</span>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="title">服务器时间与本机时间差</h3>
|
||||
<span id="timeOff" class="info">正在计算</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<%- include("./component/footer.html"); %>
|
||||
<script>
|
||||
var timeout = null;
|
||||
$('.info').css("display", "none");
|
||||
|
||||
function startCheck() {
|
||||
if (timeout) clearTimeout(timeout);
|
||||
|
||||
document.getElementById("checkBtn").value = "检测中";
|
||||
document.getElementById("checkBtn").disabled = "disabled";
|
||||
$('.info').html("loading...");
|
||||
$('.info-disabled').html("暂不提供检测");
|
||||
$('.info').css("display", "");
|
||||
|
||||
var i = 0, timeSpan = 300;
|
||||
setTimeout(checkOnlineStatus, timeSpan * ++i);
|
||||
setTimeout(checkBackendStatus, timeSpan * ++i);
|
||||
setTimeout(checkTimeOff, timeSpan * ++i);
|
||||
setTimeout(finishCheck, timeSpan * ++i);
|
||||
}
|
||||
|
||||
function checkOnlineStatus() {
|
||||
var onlineStatus = window.navigator.onLine;
|
||||
$("#onlineStatus").text(onlineStatus ? "已连接" : "您当前未连接互联网");
|
||||
}
|
||||
|
||||
function checkBackendStatus() {
|
||||
var backendStatus = false;
|
||||
getRequest("/status/getProcessCpu", {})
|
||||
.then(function (response) {
|
||||
console.log("response.data", response.data);
|
||||
if (response.data == 0) {
|
||||
backendStatus = true;
|
||||
}
|
||||
$("#backendStatus").text("后台连接正常");
|
||||
})
|
||||
.catch(function (error) {
|
||||
$("#backendStatus").text("后台连接异常");
|
||||
});
|
||||
}
|
||||
|
||||
function checkTimeOff() {
|
||||
var oldScriptDom = document.getElementById("timeCalibrationScript");
|
||||
if (oldScriptDom) oldScriptDom.parentNode.removeChild(oldScriptDom);
|
||||
|
||||
oldScriptDom = document.createElement("script");
|
||||
oldScriptDom.id = "timeCalibrationScript";
|
||||
oldScriptDom.src = "./assets/javascripts/timeCalibration.js?" + Date.now() + "-" + new Date().getTime();
|
||||
document.body.appendChild(oldScriptDom);
|
||||
}
|
||||
|
||||
function finishCheck() {
|
||||
document.getElementById("checkBtn").value = "重新检测";
|
||||
document.getElementById("checkBtn").disabled = "";
|
||||
|
||||
if (timeout) clearTimeout(timeout);
|
||||
timeout = setTimeout(startCheck, 5000);
|
||||
}
|
||||
|
||||
// $(document).ready(function () {
|
||||
// startCheck();
|
||||
// });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@@ -0,0 +1,118 @@
|
||||
package plus.bookshelf.Controller.Controller;
|
||||
|
||||
import com.sun.management.OperatingSystemMXBean;
|
||||
import com.sun.management.ThreadMXBean;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Api(value = "状态检测")
|
||||
@Controller("status")
|
||||
@RequestMapping("/status")
|
||||
public class StatusController {
|
||||
|
||||
@ApiOperation(value = "线程CPU占用时间", notes = "获取服务器当前线程CPU占用时间。此方法通过统计线程CPU占用时间来统计当前进程占用CPU情况。")
|
||||
@RequestMapping(value = "getProcessCpu", method = {RequestMethod.GET})
|
||||
@ResponseBody
|
||||
public Object get() {
|
||||
OperatingSystemMXBean operatingSystemMXBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
|
||||
ThreadMXBean threadBean = (ThreadMXBean) ManagementFactory.getThreadMXBean();
|
||||
String processCpu = getProcessCpu(operatingSystemMXBean, threadBean);
|
||||
|
||||
System.out.println(processCpu);
|
||||
return processCpu;
|
||||
}
|
||||
|
||||
// @ApiOperation(value = "服务端状态", notes = "获取服务器当前状态信息")
|
||||
// @RequestMapping(value = "get", method = {RequestMethod.GET})
|
||||
// @ResponseBody
|
||||
// public Object get() {
|
||||
// OperatingSystemMXBean operatingSystemMXBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
|
||||
// ThreadMXBean threadBean = (ThreadMXBean) ManagementFactory.getThreadMXBean();
|
||||
// // com.sun.management.OperatingSystemMXBean mxbean = operatingSystemMXBean;
|
||||
// // System.out.println("操作系统: " + mxbean.getName());
|
||||
// // System.out.println("CPU数量:" + mxbean.getAvailableProcessors());
|
||||
// // System.out.println("虚拟内存:" + mxbean.getCommittedVirtualMemorySize() / 1024 + "KB");
|
||||
// // System.out.println("可用物理内存:" + mxbean.getFreePhysicalMemorySize() / 1024 + "KB");
|
||||
// // System.out.println("Free Swap Space Size :" + mxbean.getFreeSwapSpaceSize() / 1024 + "KB");
|
||||
// // System.out.println("Process CPU Time : " + mxbean.getProcessCpuTime());
|
||||
// // System.out.println("总物理内存大小:" + mxbean.getTotalPhysicalMemorySize() / 1024 + "KB");
|
||||
// // System.out.println("Total Swap Space Size:" + mxbean.getTotalSwapSpaceSize() / 1024 + "KB");
|
||||
//
|
||||
// Map<String, Object> result = new HashMap<>();
|
||||
// result.put("SystemCpuLoad", operatingSystemMXBean.getSystemCpuLoad());
|
||||
// result.put("ProcessCpuLoad", operatingSystemMXBean.getProcessCpuLoad());
|
||||
//
|
||||
// // result.put("ProcessCpuTime", operatingSystemMXBean.getProcessCpuTime());
|
||||
//
|
||||
// // result.put("CommittedVirtualMemorySize", operatingSystemMXBean.getCommittedVirtualMemorySize());
|
||||
//
|
||||
// // result.put("FreePhysicalMemorySize", operatingSystemMXBean.getFreePhysicalMemorySize());
|
||||
// // result.put("TotalPhysicalMemorySize", operatingSystemMXBean.getTotalPhysicalMemorySize());
|
||||
// result.put("PhysicalMemorySizeRate", 100l * operatingSystemMXBean.getFreePhysicalMemorySize() / operatingSystemMXBean.getTotalPhysicalMemorySize());
|
||||
// // 可用物理内存百分比
|
||||
//
|
||||
// // result.put("FreeSwapSpaceSize", operatingSystemMXBean.getFreeSwapSpaceSize());
|
||||
// // result.put("TotalSwapSpaceSize", operatingSystemMXBean.getTotalSwapSpaceSize());
|
||||
// result.put("SwapSpaceSizeRate", 100l * operatingSystemMXBean.getFreeSwapSpaceSize() / operatingSystemMXBean.getTotalSwapSpaceSize());
|
||||
// // 可用交换空间百分比
|
||||
//
|
||||
// // result.put("SystemLoadAverage", operatingSystemMXBean.getSystemLoadAverage());
|
||||
//
|
||||
// result.put("aaa", getProcessCpu(operatingSystemMXBean, threadBean));
|
||||
//
|
||||
// // Object[] a = new Object[]{
|
||||
// // // operatingSystemMXBean.getArch(),
|
||||
// // // operatingSystemMXBean.getName(),
|
||||
// // // operatingSystemMXBean.getSystemLoadAverage(),
|
||||
// // // operatingSystemMXBean.getVersion(),
|
||||
// // // operatingSystemMXBean.getAvailableProcessors(),
|
||||
// //
|
||||
// // // operatingSystemMXBean.getSystemCpuLoad(),
|
||||
// // // operatingSystemMXBean.getProcessCpuLoad(),
|
||||
// // // operatingSystemMXBean.getProcessCpuTime(),
|
||||
// //
|
||||
// // // operatingSystemMXBean.getCommittedVirtualMemorySize(),
|
||||
// //
|
||||
// // // operatingSystemMXBean.getFreePhysicalMemorySize(),
|
||||
// // // operatingSystemMXBean.getTotalPhysicalMemorySize(),
|
||||
// //
|
||||
// // // operatingSystemMXBean.getFreeSwapSpaceSize(),
|
||||
// // // operatingSystemMXBean.getTotalSwapSpaceSize(),
|
||||
// // };
|
||||
// return result;
|
||||
// }
|
||||
|
||||
// refer: https://blog.csdn.net/as403045314/article/details/101337176
|
||||
private long preTime = System.nanoTime();
|
||||
private long preUsedTime = 0;
|
||||
|
||||
/**
|
||||
* getSystemLoadAverage()方法得到的操作系统统计的整个系统负载,不能较好的反应本进程的CPU占用情况
|
||||
* 此方法通过统计线程CPU占用时间来统计当前进程占用CPU情况
|
||||
*
|
||||
* @param osMxBean
|
||||
* @param threadBean
|
||||
* @return
|
||||
*/
|
||||
public String getProcessCpu(OperatingSystemMXBean osMxBean, ThreadMXBean threadBean) {
|
||||
long totalTime = 0;
|
||||
for (long id : threadBean.getAllThreadIds()) {
|
||||
totalTime += threadBean.getThreadCpuTime(id);
|
||||
}
|
||||
long curtime = System.nanoTime();
|
||||
long usedTime = totalTime - preUsedTime;
|
||||
long totalPassedTime = curtime - preTime;
|
||||
preTime = curtime;
|
||||
preUsedTime = totalTime;
|
||||
// return (((double) usedTime) / totalPassedTime / osMxBean.getAvailableProcessors()) * 100;
|
||||
return String.valueOf(new BigDecimal(usedTime * 100 / (totalPassedTime * osMxBean.getAvailableProcessors())));
|
||||
}
|
||||
}
|
BIN
docs/image/homepage.png
Normal file
BIN
docs/image/homepage.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
@@ -34,9 +34,14 @@
|
||||
url: 'http://localhost/api/',
|
||||
title: 'API'
|
||||
},
|
||||
"<p>API测试</p>",
|
||||
{
|
||||
url: 'http://localhost/api/book/get?id=1',
|
||||
title: 'API测试:Book'
|
||||
title: ''
|
||||
},
|
||||
{
|
||||
url: 'http://localhost/api/status/getProcessCpu',
|
||||
title: ''
|
||||
},
|
||||
"<hr>",
|
||||
{
|
||||
|
6
server/查看nginx运行进程.bat
Normal file
6
server/查看nginx运行进程.bat
Normal file
@@ -0,0 +1,6 @@
|
||||
@echo off
|
||||
|
||||
tasklist /fi "imagename eq nginx.exe"
|
||||
|
||||
echo.
|
||||
pause
|
Reference in New Issue
Block a user