后台图书管理功能
富文本编辑器wangEditor
基于javascript与css开发是Web富文本编辑器,轻量、简洁、易用、开源免费。
代码演示
我们在test.ftl中添加富文本编辑器演示下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 引入wangEditor -->
<script src="/resources/wangEditor.min.js"></script>
</head>
<body>
<div>
<button id="btnRead">读取内容</button>
<button id="btnWrite">写入内容</button>
</div>
<div id="divEditor" style="width: 800px;height: 600px"></div>
<script>
var E = window.wangEditor;
var editor = new E("#divEditor");//完成富文本编辑器初始化
editor.create();//创建富文本编辑器,显式在页面上
document.getElementById("btnRead").onclick = function (){
var content = editor.txt.html();//获取编辑器现有的html内容
alert(content)
}
document.getElementById("btnWrite").onclick = function (){
var content = "<li style='color: red'>新内容<b>测试</b></li>";
editor.txt.html(content);//设置编辑器现有的html内容
}
</script>
</body>
</html>
运行项目,在浏览器中访问http://localhost:8080/test/t1
实现图书管理功能
首先,打开pom.xml文件,引入Spring MVC文件上传底层依赖和Json Html解析组件,并发布到lib包
<!--Spring MVC文件上传底层依赖-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<!--Json Html解析组件-->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.12.1</version>
</dependency>
打开BookService.java新增创建新的图书的方法,并在BookServiceImpl.java类中添加相应的方法实现。
/**
* 创建新的图书
* @param book 图书对象
* @return 返回图书对象
*/
public Book createBook(Book book);
/**
* 创建新的图书
*
* @param book 图书对象
* @return 返回图书对象
*/
@Transactional
public Book createBook(Book book) {
bookMapper.insert(book);
return book;
}
然后在com.ql.reader.controller.management包下创建MBookController.java图书管理控制器类,编写跳转到图书管理页面、上传图片和新增图书的方法。
package com.ql.reader.controller.management;
import com.ql.reader.entity.Book;
import com.ql.reader.service.BookService;
import com.ql.reader.service.exception.BussinessException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Controller
@RequestMapping("/management/book")
public class MBookController {
@Resource
private BookService bookService;
@GetMapping("/index.html")
public ModelAndView showBook(){
return new ModelAndView("/management/book");
}
/**
* wangEditor文件上传
* @param file 上传文件
* @param request 原生请求对象
* @return
* @throws IOException
*/
@PostMapping("/upload")
@ResponseBody
public Map upload(@RequestParam("img") MultipartFile file, HttpServletRequest request) throws IOException {
//得到上传目录
String uploadPath = request.getServletContext().getResource("/").getPath() + "/upload/";
//文件名
String fileName = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
//扩展名
String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
//保存文件到upload目录
file.transferTo(new File(uploadPath+fileName+suffix));
Map result = new HashMap();
result.put("errno",0);
result.put("data", new String[]{"/upload/"+fileName+suffix});
return result;
}
@PostMapping("/create")
@ResponseBody
public Map createBook(Book book){
Map result = new HashMap();
try {
book.setEvaluationQuantity(0);
book.setEvaluationScore(0f);
Document doc = Jsoup.parse(book.getDescription());//解析图书详情
Element img = doc.select("img").first();//获取图书详情第一图的元素对象
String cover = img.attr("src");
book.setCover(cover);//来自于description描述的第一幅图
bookService.createBook(book);
result.put("code", "0");
result.put("msg", "success");
} catch (BussinessException e) {
e.printStackTrace();
result.put("code", e.getCode());
result.put("msg", e.getMsg());
}
return result;
}
}
在src/main/webapp/WEB-INF/ftl/management目录下新增图书管理的前端页面book.ftl
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>图书管理功能</title>
<style>
#dlgBook{
padding: 10px
}
</style>
<link rel="stylesheet" href="/resources/layui/css/layui.css">
<script src="/resources/wangEditor.min.js"></script>
<script type="text/html" id="toolbar">
<div class="layui-btn-container">
<button class="layui-btn layui-btn-sm" id="btnAdd" onclick="showCreate()">添加</button>
</div>
</script>
</head>
<body>
<div class="layui-container">
<blockquote class="layui-elem-quote">图书列表</blockquote>
<!-- 数据表格 -->
<table id="grdBook" lay-filter="grdBook"></table>
</div>
<!--表单内容-->
<div id="dialog" style="padding: 10px;display: none">
<form class="layui-form" >
<div class="layui-form-item">
<!-- 图书类别 -->
<select id="categoryId" name="categoryId" lay-verify="required" lay-filter=
"categoryId">
<option value=""></option>
<option value="1">前端</option>
<option value="2">后端</option>
<option value="3">测试</option>
<option value="4">产品</option>
</select>
</div>
<div class="layui-form-item">
<!-- 书名 -->
<input type="text" id="bookName" name="bookName" required lay-verify="required" placeholder="请输入书名"
autocomplete="off" class="layui-input">
</div>
<div class="layui-form-item">
<!-- 子标题 -->
<input type="text" id="subTitle" name="subTitle" required lay-verify="required" placeholder="请输入子标题"
autocomplete="off" class="layui-input">
</div>
<div class="layui-form-item">
<!-- 作者 -->
<input type="text" id="author" name="author" required lay-verify="required" placeholder="请输入作者信息"
autocomplete="off" class="layui-input">
</div>
<div style="margin-top: 30px;font-size: 130%">图书介绍(默认第一图将作为图书封面)</div>
<div class="layui-form-item" >
<!-- wangEditor编辑器 -->
<div id="editor" style="width: 100%">
</div>
</div>
<!-- 图书编号 -->
<input id="bookId" type="hidden">
<!-- 当前表单操作类型,create代表新增 update代表修改 -->
<input id="optype" type="hidden">
<div class="layui-form-item" style="text-align: center">
<!-- 提交按钮 -->
<button class="layui-btn" lay-submit="" lay-filter="btnSubmit">立即提交</button>
</div>
</form>
</div>
<script src="/resources/layui/layui.all.js"></script>
<script>
// table数据表格对象
var table = layui.table;
// jQuery
var $ = layui.$;
// wangEditor富文本编辑器对象
var editor = null;
// 初始化图书列表
table.render({
// 指定div
elem: '#grdBook'
// 数据表格id
, id : "bookList"
// 指定工具栏,包含新增添加
, toolbar: "#toolbar"
// 数据接口
, url: "/management/book/list"
// 开启分页
, page: true
// 表头
, cols: [[
{field: 'bookName', title: '书名', width: '300'}
, {field: 'subTitle', title: '子标题', width: '200'}
, {field: 'author', title: '作者', width: '200'}
, {type: 'space', title: '操作', width: '200' , templet : function(d){
// 为每一行表格数据生成"修改"与"删除"按钮,并附加data-id属性代表图书编号
return "<button class='layui-btn layui-btn-sm btn-update' data-id='" + d.bookId + "' data-type='update' οnclick='showUpdate(this)'>修改</button>" +
"<button class='layui-btn layui-btn-sm btn-delete' data-id='" + d.bookId + "' οnclick='showDelete(this)'>删除</button>";
}
}
]]
});
// 显示更新图书对话框
// obj对应点击的"修改"按钮对象
function showUpdate(obj){
// 弹出"编辑图书"对话框
layui.layer.open({
// 指定div
id: "dlgBook",
// 标题
title: "编辑图书",
type: 1,
// 设置对话框内容,复制自dialog DIV
content: $('#dialog').html(),
// 设置对话框宽度高度
area: ['820px', '730px'],
resize: false // 是否允许调整尺寸
})
// 获取"修改"按钮附带的图书编号
var bookId = $(obj).data("id");
// 为表单隐藏域赋值,提交表单时用到
$("#dlgBook #bookId").val(bookId);
// 初始化富文本编辑器
editor = new wangEditor('#dlgBook #editor');
// 设置图片上传路径
editor.customConfig.uploadImgServer = '/management/book/upload'
// 图片上传时的参数名
editor.customConfig.uploadFileName = 'img';
editor.create(); // 创建wangEditor
// 设置当前表单提交时提交至"update"更新地址
$("#dlgBook #optype").val("update");
layui.form.render();
// 发送ajax请求,获取对应图书信息
$.get("/management/book/id/" + bookId , {} , function(json){
// 文本框回填已有数据
// 书名
$("#dlgBook #bookName").val(json.data.bookName);
// 子标题
$("#dlgBook #subTitle").val(json.data.subTitle);
// 作者
$("#dlgBook #author").val(json.data.author);
// 分类选项
$("#dlgBook #categoryId").val(json.data.categoryId);
// 设置图文内容
editor.txt.html(json.data.description);
// 重新渲染LayUI表单
layui.form.render();
} , "json")
}
// 显示新增图书对话框
function showCreate(){
// 弹出"新增图书"对话框
layui.layer.open({
id: "dlgBook",
title: "新增图书",
type: 1,
content: $('#dialog').html(),
area: ['820px', '730px'],
resize: false
})
// 初始化wangEditor
editor = new wangEditor('#dlgBook #editor');
// 设置图片上传地址
editor.customConfig.uploadImgServer = '/management/book/upload';
// 设置图片上传参数
editor.customConfig.uploadFileName = 'img';
// 创建wangEditor
editor.create();
// LayUI表单重新渲染
layui.form.render();
// 设置当前表单提交时提交至"create"新增地址
$("#dlgBook #optype").val("create");
};
// 对话框表单提交
layui.form.on('submit(btnSubmit)', function(data){
// 获取表单数据
var formData = data.field;
// 判断是否包含至少一副图片,默认第一图作为封面显示
var description = editor.txt.html();
if(description.indexOf("img") == -1){
layui.layer.msg('请放置一副图片作为封面');
return false;
}
// 获取当前表单要提交的地址
// 如果是新增数据则提交至create
// 如果是更新数据则提交至update
var optype = $("#dlgBook #optype").val();
if(optype == "update"){
// 更新数据时,提交时需要附加图书编号
formData.bookId=$("#dlgBook #bookId").val();
}
// 附加图书详细描述的图文html
formData.description = description;
// 向服务器发送请求
$.post("/management/book/" + optype , formData , function(json){
if(json.code=="0"){
// 处理成功,关闭对话框,刷新列表,提示操作成功
layui.layer.closeAll();
table.reload('bookList');
layui.layer.msg('数据操作成功,图书列表已刷新');
}else{
// 处理失败,提示错误信息
layui.layer.msg(json.msg);
}
} ,"json")
return false;
});
// 删除图书
function showDelete(obj){
// 获取当前点击的删除按钮中包含的图书编号
var bookId = $(obj).data("id");
// 利用layui的询问对话框进行确认
layui.layer.confirm('确定要执行删除操作吗?', {icon: 3, title:'提示'}, function(index){
// 确认按钮后发送ajax请求,包含图书编号
$.get("/management/book/delete/" + bookId, {}, function (json) {
if(json.code=="0"){
// 删除成功刷新表格
table.reload('bookList');
// 提示操作成功
layui.layer.msg('数据操作成功,图书列表已刷新');
// 关闭对话框
layui.layer.close(index);
}else{
// 处理失败,提示错误信息
layui.layer.msg(json.msg);
}
}, "json");
});
}
</script>
</body>
</html>
运行项目,在浏览器中输入http://localhost:8080/management/book/index.html点击添加,打开新增图书弹框,输入信息提交测试。
提交成功后在浏览器中访问http://localhost:8080/在图书列表的最后面查到刚新增的图书。
实现图书分页查询
打开MBookController.java编写分页查询方法
@GetMapping("/list")
@ResponseBody
public Map list(Integer page, Integer limit){
if (page==null){
page=1;
}
if (limit==null){
limit=10;
}
IPage<Book> pageObject = bookService.paging(null, null, page, limit);
Map result = new HashMap();
result.put("code", "0");
result.put("msg", "success");
result.put("data", pageObject.getRecords());//当前页面数据
result.put("count", pageObject.getTotal());//未分页时记录总数
return result;
}
运行项目,浏览器访问http://localhost:8080/management/book/index.html
实现图书修改更新功能
打开BookService.java添加更新图书数据方法,并在BookServiceImpl.java添加方法实现
/**
* 更新图书
* @param book 新图书数据
* @return 更新后的数据
*/
public Book updateBook(Book book);
/**
* 更新图书
*
* @param book 新图书数据
* @return 更新后的数据
*/
@Transactional
public Book updateBook(Book book) {
bookMapper.updateById(book);
return book;
}
然后打开MBookController.java添加根据Id获取图书和更新图书的方法
/**
* 根据图书ID获取图书
* @param bookId 图书ID
* @return 图书信息
*/
@GetMapping("/id/{id}")
@ResponseBody
public Map selectById(@PathVariable("id") Long bookId){
Book book = bookService.selectById(bookId);
Map result = new HashMap();
result.put("code", "0");
result.put("msg","success");
result.put("data", book);
return result;
}
/**
* 更新图书数据
* @param book
* @return
*/
@PostMapping("/update")
@ResponseBody
public Map updateBook(Book book) {
Map result = new HashMap();
try {
Book rawBook = bookService.selectById(book.getBookId());
rawBook.setBookName(book.getBookName());
rawBook.setSubTitle(book.getSubTitle());
rawBook.setAuthor(book.getAuthor());
rawBook.setCategoryId(book.getCategoryId());
rawBook.setDescription(book.getDescription());
Document doc = Jsoup.parse(book.getDescription());
String cover = doc.select("img").first().attr("src");
rawBook.setCover(cover);
bookService.updateBook(rawBook);
result.put("code", "0");
result.put("msg", "success");
} catch (BussinessException e) {
e.printStackTrace();
result.put("code", e.getCode());
result.put("msg", e.getMsg());
}
return result;
}
运行项目,在浏览器访问http://localhost:8080/management/book/index.html并找到我们上次新增的测试图书信息,并点击修改为
提交数据后修改成功。
实现图书删除功能
打开BookService.java编写删除图书的方法,并在BookServiceImpl.java添加方法实现
/**
* 删除图书及相关数据
* @param bookId
*/
public void deleteBook(Long bookId);
/**
* 删除图书及相关数据
*
* @param bookId 图书编号
*/
@Transactional
public void deleteBook(Long bookId) {
bookMapper.deleteById(bookId);
QueryWrapper<MemberReadState> mrsQueryWrapper = new QueryWrapper<>();
mrsQueryWrapper.eq("book_id", bookId);
memberReadStateMapper.delete(mrsQueryWrapper);
QueryWrapper<Evaluation> evaluationQueryWrapper = new QueryWrapper<>();
evaluationQueryWrapper.eq("book_id", bookId);
evaluationMapper.delete(evaluationQueryWrapper);
}
然后打开MBookController.java编写删除图书的控制器方法
@GetMapping("/delete/{id}")
@ResponseBody
public Map deleteBook(@PathVariable("id") Long bookId){
Map result = new HashMap();
try {
bookService.deleteBook(bookId);
result.put("code", "0");
result.put("msg", "success");
} catch (BussinessException e) {
e.printStackTrace();
result.put("code", e.getCode());
result.put("msg", e.getMsg());
}
return result;
}
运行项目,浏览器访问http://localhost:8080/management/book/index.html并找到我们添加的测试数据删除。
删除成功后数据消失。