目录
1 需求分析 1
2技术栈 1
3 总体设计 1
3.1 系统功能概述 1
3.1.1 前台系统 1
3.1.2 后台系统 2
3.2 E-R模型 2
3.3 系统流程图 4
4 详细设计 5
4.1 前台系统 5
4.2 后台系统 8
5 总结 10
1 需求分析
图书借阅管理系统是模拟学校图书馆实现的一个具有前后台的web系统.对于读者,能够提供全文检索,个性化推荐,借阅等功能.对于管理员,能够提供可视化数据分析,信息管理等功能.
2技术栈
前端: Layui,jQuery,echarts
后端:Spring Boot,MyBatis,elasticsearch,thymeleaf(一个模板引擎,代替jsp)
开发工具:IDEA,HBuilder,postman,Navicat for MySQL
项目管理工具:Maven
3 总体设计
3.1 系统功能概述
3.1.1 前台系统
(1) 读者登录,注册,修改密码
(2) 基本资料查看,修改
(3) 图书查询(复杂查询),仿京东商城以图片卡片形式分页展示,可点击每本书的评价数进行评价,点击卡片查看详细图书信息以及借阅
(4) 个性化推荐图书:根据读者的兴趣爱好,本文转载自http://www.biyezuopin.vip/onews.asp?id=15210每本书对应读者的浏览量,每本书的借阅量,每本书的评论数进行多重排序,展示在读者面前
(5) 历史记录浏览,查询
(6) 基于elasticsearch搜索引擎的全文检索
3.1.2 后台系统
(1) 管理员登录,修改密码
(2) 读者管理:查看,添加,编辑,删除
(3) 管理员管理:查看,添加,删除
(4) 角色管理
(5) 统计分析:
A.分别以树状图,饼图展示图书分类占比
B.以折线图加饼图展示每年的图书类型借阅情况
C.查询每年的热门图书排名以及借阅次数
(6) 历史记录管理
(7) 图书管理:查看,添加,删除
<!DOCTYPE html>
<!--suppress ALL-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>spring-boot-bms</title>
<link rel="stylesheet" th:href="@{/css/layui.css}" media="all">
<script th:src="@{/layui.all.js}"></script>
<script th:src="@{/jquery-3.3.1.js}"></script>
<script th:src="@{/table_select.js}"></script>
<script th:src="@{/common.js}"></script>
</head>
<style>
.layui-form-select .layui-input {
padding-right: 0px;
cursor: pointer;
}
</style>
<body class="layui-layout-body" onload="getUrl()">
<div class="layui-layout layui-layout-admin">
<div th:replace="layout/adminHeader :: header"></div>
<div th:replace="layout/left :: left"></div>
<div class="layui-body" id="main_body">
<!-- 内容主体区域 -->
<blockquote class="layui-elem-quote layui-text">
what are you looking for...
</blockquote>
<form class="layui-form" action="/bookManage" accept-charset="UTF-8" th:fragment="book_search">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">ID</label>
<div class="layui-input-block">
<input type="text" name="s_bookId" autocomplete="off" placeholder="请输入" class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">书名</label>
<div class="layui-input-block">
<input type="text" name="s_bookName" placeholder="请输入"
autocomplete="off" class="layui-input" baiduSug=1>
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">作者</label>
<div class="layui-input-block">
<input type="text" name="s_author" placeholder="请输入"
autocomplete="off" class="layui-input" id="find_author">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">出版社</label>
<div class="layui-input-block">
<input type="text" name="s_press" placeholder="请输入"
autocomplete="off" class="layui-input" id="find_press">
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">分类</label>
<div class="layui-input-block">
<input type="text" name="s_bookType" placeholder="请输入"
autocomplete="off" class="layui-input" id="find_type">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">范围</label>
<div class="layui-input-inline" style="width: 100px;">
<input type="text" id="date1" name="s_date1" placeholder="yyyy-MM" autocomplete="off" class="layui-input">
</div>
<div class="layui-form-mid">-</div>
<div class="layui-input-inline" style="width: 100px;">
<input type="text" id="date2" name="s_date2" placeholder="yyyy-MM" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline">
<div class="layui-input-block">
<button class="layui-btn" lay-submit="" lay-filter="demo1">立即提交</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</div>
</form>
<table class="layui-hide" id="demo" lay-filter="test"></table>
</div>
<div th:replace="layout/footer :: footer"></div>
</div>
<div th:replace="common :: myInfo"></div>
<div th:replace="common :: myPw"></div>
<div th:replace="common :: showBookRow"></div>
<div th:replace="common :: editBookRow"></div>
<div th:replace="common :: newBook"></div>
<script>
layui.use(['element','form', 'layedit', 'laydate'], function () {
var form = layui.form;
var element = layui.element;
var laydate = layui.laydate;
element.init();
//常规用法
laydate.render({
elem: '#date1'
});
laydate.render({
elem: '#date2'
});
});
</script>
<!--搜索输入框-->
<script>
var tableSelect = layui.tableSelect;
tableSelect.render({
elem: '#find_author',
checkedKey: 'inputId',
table: {
url: '/input/author'
, response: {
statusCode: 200 //规定成功的状态码,默认:0
}
, parseData: function (res) {
return {
"code": 200
, "msg": ""
, "count": res.total
, "data": res.list
}
},
cols: [
[{
type: 'radio'
},
{
field: 'inputId',
title: 'ID'
},
{
field: 'inputName',
title: '作者'
}
]
]
},
done: function(elem, data) {
var NEWJSON = []
layui.each(data.data, function(index, item) {
NEWJSON.push(item.inputName)
})
elem.val(NEWJSON.join(","))
}
});
tableSelect.render({
elem: '#find_press',
checkedKey: 'inputId',
table: {
url: '/input/press'
, response: {
statusCode: 200 //规定成功的状态码,默认:0
}
, parseData: function (res) {
return {
"code": 200
, "msg": ""
, "count": res.total
, "data": res.list
}
},
cols: [
[{
type: 'radio'
},
{
field: 'inputId',
title: 'ID'
},
{
field: 'inputName',
title: '出版社'
}
]
]
},
done: function(elem, data) {
var NEWJSON = []
layui.each(data.data, function(index, item) {
NEWJSON.push(item.inputName)
})
elem.val(NEWJSON.join(","))
}
});
tableSelect.render({
elem: '#find_type',
checkedKey: 'inputId',
table: {
url: '/input/type'
, response: {
statusCode: 200 //规定成功的状态码,默认:0
}
, parseData: function (res) {
return {
"code": 200
, "msg": ""
, "count": res.total
, "data": res.list
}
},
cols: [
[{
type: 'radio'
},
{
field: 'inputId',
title: 'ID'
},
{
field: 'inputName',
title: '类型'
}
]
]
},
done: function(elem, data) {
var NEWJSON = []
layui.each(data.data, function(index, item) {
NEWJSON.push(item.inputName)
})
elem.val(NEWJSON.join(","))
}
});
</script>
<script type="text/html" id="barDemo2">
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="detail">查看</a>
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
</script>
<script th:inline="none">
var args = {};
args["s_bookId"] = 0, args["s_bookName"] = "#", args["s_author"] = "#", args["s_press"] = "#", args["s_bookType"] = "#", args["s_date1"] = "#", args["s_date2"] = "#";
function getUrl() {
if(location.search!=""){
var str = (location.search.length > 0 ? location.search.substring(1) : "");
var items = str.split("&");
var len = items.length, name, value;
for (i = 0; i < len; i++) {
item = items[i].split("=");
if (item[1].length > 0) {
name = decodeURIComponent(item[0]);
value = decodeURIComponent(item[1]);
args[name] = value;
console.log(value);
}
}
}
layui.use('table', function () {
var table = layui.table;
//展示已知数据
table.render({
elem: '#demo'
, url: '/book/all'
, method: 'get'
, response: {
statusCode: 200 //规定成功的状态码,默认:0
}
, where: {
"bookId": args["s_bookId"],
"bookName": args["s_bookName"].toString(),
"author": args["s_author"].toString(),
"press": args["s_press"].toString(),
"bookType": args["s_bookType"].toString(),
"date1": args["s_date1"].toString(),
"date2": args["s_date2"].toString(),
}
, even: true
, page: true //是否显示分页
, limits: [3, 4, 5]
, limit: 4 //每页默认显示的数量
, parseData: function (res) {
console.log(res);
return {
"code": 200
, "msg": ""
, "count": res.total
, "data": res.list
}
}
, toolbar: 'default' //开启工具栏,此处显示默认图标,可以自定义模板,详见文档
, cols: [[ //标题栏
{type: 'checkbox', fixed: 'left'}
, {field: 'bookId', title: 'ID', sort: true}
, {field: 'bookName', title: '书名'}
, {field: 'author', title: '作者'}
, {field: 'press', title: '出版社'}
, {field: 'bookDate', title: '出版日期',sort: true}
, {fixed: 'right',align: 'center', toolbar: '#barDemo2'}
]]
//,skin: 'line' //表格风格
});
//监听头工具栏事件
table.on('toolbar(test)', function (obj) {
var checkStatus = table.checkStatus(obj.config.id)
, data = checkStatus.data; //获取选中的数据
switch (obj.event) {
case 'add':
layer.open({
type: 1,
// title: 'iframe父子操作',
shadeClose: true, //点击遮罩关闭层
area: ['800px', '520px'],
content: $("#new_book"),
cancel: function (index, layero) {
$("#new_book").hide();
}
});
break;
case 'update':
if (data.length === 0) {
layer.msg('请选择一行');
} else if (data.length > 1) {
layer.msg('只能同时编辑一个');
} else {
layer.alert('编辑 [id]:' + checkStatus.data[0].id);
}
break;
case 'delete':
if (data.length === 0) {
layer.msg('请选择一行');
} else {
var array = [];
for (i = 0; i < data.length; i++) array.push(data[i].bookId);
alert(array);
$.ajax({
type: "post",
url: "/book/check",
data: {
"array": array
},
success: function (data) {
if (data > 0) {
alert("删除成功");
window.location.reload();
}
}
});
}
break;
}
;
});
//监听行工具事件
table.on('tool(test)', function (obj) { //注:tool 是工具条事件名,test 是 table 原始容器的属性 lay-filter="对应的值"
var data = obj.data //获得当前行数据
, layEvent = obj.event; //获得 lay-event 对应的值
if (layEvent === 'detail') {
layer.msg('查看操作');
$.ajax({
type: "get",
url: "/book/find",
data: {
"bookId": data.bookId
},
success: function (data) {
$("#bookId").val(data.bookId);
$("#bookName").val(data.bookName);
$("#author").val(data.author);
$("#press").val(data.press);
$("#bookDate").val(data.bookDate);
$("#bookType").val(data.bookType);
$("#bookDesc").val(data.bookDesc);
$("#bookImage").attr("src", data.photo);
layer.open({
type: 1,
// title: 'iframe父子操作',
shadeClose: true, //点击遮罩关闭层
area: ['800px', '520px'],
content: $("#show_row"),
cancel: function (index, layero) {
$("#show_row").hide();
}
});
}
});
} else if (layEvent === 'del') {
layer.confirm('真的删除行么', function (index) {
//向服务端发送删除指令
$.ajax({
type: "post",
url: "/book/delete",
data: {
"bookId": data.bookId
},
success: function (data) {
if (data > 0) {
obj.del(); //删除对应行(tr)的DOM结构
layer.close(index);
alert("图书删除成功");
window.location.reload();
} else {
alert("图书删除失败");
window.location.reload();
}
}
});
});
} else if (layEvent === 'edit') {
layer.msg('编辑操作');
$.ajax({
type: "get",
url: "/book/find",
data: {
"bookId": data.bookId
},
success: function (data) {
$("#_bookId").val(data.bookId);
$("#_bookName").val(data.bookName);
$("#_author").val(data.author);
$("#_press").val(data.press);
$("#_bookDate").val(data.bookDate);
$("#_bookType").val(data.bookType);
$("#_bookDesc").val(data.bookDesc);
$("#_bookImage").val(data.photo);
layer.open({
type: 1,
// title: 'iframe父子操作',
shadeClose: true, //点击遮罩关闭层
area: ['800px', '520px'],
content: $("#edit_row"),
cancel: function (index, layero) {
$("#edit_row").hide();
}
});
}
});
}
});
});
}
</script>
<script>
// 展示修改密码界面
$('#parentIframe').on('click', function () {
layer.open({
type: 1,
// title: 'iframe父子操作',
shadeClose: true, //点击遮罩关闭层
area: ['800px', '520px'],
content: $("#info"),
cancel: function (index, layero) {
$("#info").hide();
}
});
});
// 展示基本资料界面
$('#parentIframe2').on('click', function () {
layer.open({
type: 1,
// title: 'iframe父子操作',
shadeClose: true, //点击遮罩关闭层
area: ['800px', '520px'],
content: $("#owninfo"),
cancel: function (index, layero) {
$("#owninfo").hide();
}
});
});
</script>
</body>
</html>