2、SpringBoot整合editor.md实现markdown语法的编辑器
内容编辑页面
edit.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" th:src="@{/js/jquery-3.5.1.min.js}"></script>
<link rel="stylesheet" th:href="@{/editormd/css/editormd.css}"/>
<script rel="script" th:src="@{/editormd/js/editormd.min.js}"></script>
</head>
<body>
<div>
<input type="text" name="title" id="title" th:value="${editor.getTitle()}">
<input type="hidden" name="id" id="id" th:value="${editor.getId()}">
</div>
<div class="editormd" id="test-editormd">
<textarea class="editormd-markdown-textarea" name="test-editormd-markdown-doc" id="content" th:text="${editor.getContent()}"></textarea>
<!-- 第二个隐藏文本域,用来构造生成的HTML代码,方便表单POST提交,这里的name可以任意取,后台接受时以这个name键为准 -->
<textarea class="editormd-html-textarea" name="editormd-html-textarea" id="htmlContent" th:text="${editor.getHtmlContent()}"></textarea>
</div>
<div>
<button onclick="saveHtml()">保存</button>
</div>
<script type="text/javascript">
var testEditor;
$(function () {
testEditor = editormd("test-editormd", {
width: "70%",
height: 640,
syncScrolling: "single",
path: "/editormd/lib/",
//这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。
saveHTMLToTextarea: true, //这个配置,方便post提交表单
tocm: true, // Using [TOCM]
tex: true,// 开启科学公式TeX语言支持,默认关闭
flowChart: true,//开启流程图支持,默认关闭
/**上传图片相关配置如下*/
imageUpload : true,
imageFormats : ["jpg", "jpeg", "gif", "png"],
imageUploadURL : "/blog/imgUpload",//注意你后端的上传图片服务地址
/*上传图片成功后可以做一些自己的处理*/
//加载完成
onload: function () {
// alert("上传成功!");
//console.log('onload', this);
//this.fullscreen();
//this.unwatch();
// this.watch().fullscreen();
// this.width("100%");
// this.height(480);
// this.resize("100%", 640);
},
});
});
function saveHtml() {
var id = $("#id").val();
var title = $("#title").val();
var content = $("#content").val();
var htmlContent = $("#htmlContent").val();
$.ajax({
url: "/blog/save/" + id,
type: "post",
data: {
title: title,
content:content,
htmlContent:htmlContent
},
success:function () {
alert("发布成功");
},
error:function () {
alert("发布失败");
}
});
}
</script>
</body>
</html>
内容展示页面
preview.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>博客展示</title>
<link rel="stylesheet" th:href="@{/editormd/css/editormd.css}"/>
<link rel="stylesheet" th:href="@{/editormd/css/editormd.preview.min.css}" />
<link rel="stylesheet" th:href="@{/editormd/css/editormd.css}"/>
</head>
<body>
<div id="test-editormd">
<textarea style="display:none;" placeholder="markdown语言" th:text="${editor.getContent()}">#Editor.md</textarea>
</div>
<script type="text/javascript" th:src="@{/js/jquery-3.5.1.min.js}"></script>
<script type="text/javascript" th:src="@{/editormd/lib/marked.min.js}"></script>
<script type="text/javascript" th:src="@{/editormd/lib/raphael.min.js}"></script>
<script type="text/javascript" th:src="@{/editormd/lib/flowchart.min.js}"></script>
<script type="text/javascript" th:src="@{/editormd/lib/jquery.flowchart.min.js}"></script>
<script type="text/javascript" th:src="@{/editormd/lib/sequence-diagram.min.js}"></script>
<script type="text/javascript" th:src="@{/editormd/lib/underscore.min.js}"></script>
<script type="text/javascript" th:src="@{/editormd/lib/prettify.min.js}"></script>
<script type="text/javascript" th:src="@{/editormd/js/editormd.min.js}"></script>
<script type="text/javascript">
var testEditor;
$(function () {
// testEditor = editormd.markdownToHTML("content",{
// width: "100%",
// height: 600,
// path: "/editormd/lib/", //依赖lib文件夹路径
// preview: true,
// watch: true,
// editor: false
// });
testEditor = editormd.markdownToHTML("test-editormd", {
htmlDecode : "style,script,iframe",
emoji : true,
taskList : true,
tex : true, // 默认不解析
flowChart : true, // 默认不解析
sequenceDiagram : true // 默认不解析
});
})
</script>
</body>
</html>
博客的Controller
package com.qykhhr.societywebsite.controller;
import cn.hutool.core.util.IdUtil;
import com.qykhhr.societywebsite.entity.Editor;
import com.qykhhr.societywebsite.entity.FileInfo;
import com.qykhhr.societywebsite.entity.User;
import com.qykhhr.societywebsite.service.Impl.BlogServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.util.Date;
/**
* @author 雨林
*/
@Slf4j
@Controller
@RequestMapping("/blog")
public class BlogController {
@Autowired
BlogServiceImpl blogService;
/**
* 配置文件中配置文件保存的路径
*/
@Value("${img.location}")
private String folder;
/**
* 去博客(文章)的首页(列表)
* @return
*/
@GetMapping("/toBlogIndex")
public String toBlogIndex() {
return "blog/index";
}
/**
* 修改已经编辑过的文章
* 先通过传入的文章id得到Editor对象,然后用Model将editor对象带入edit页面中
* 在edit页面使用el表达式显示已经写过的文章内容,以及标题等
* @param id
* @param request
* @param model
* @return
*/
@GetMapping("/toUpdateBlog/{id}")
public String toBlogEdit(@PathVariable("id")String id, HttpServletRequest request,Model model) {
//从sessio域中获取对象
User user = (User) request.getSession().getAttribute("user");
System.out.println("id = " + id);
//先找到这个文章,然后放到model中
Editor editor = blogService.queryEditor(id);
if(editor != null){
model.addAttribute("editor",editor);
return "blog/edit";
}else{
return "error/4xx";
}
}
/**
* 去编辑页面,只是编辑
* 从session域中获取登录的User,然后通过hutool生成id,然后结合uid生成一个唯一文章的id
* 再设置editor的基本信息,设置内容、标题都为空,是为了避免在edit页面被el表达式调用为null
* @param request
* @param model
* @return
*/
@GetMapping("/toEdit")
public String toBlogEditPage(HttpServletRequest request,Model model) {
Editor editor = new Editor();
//生成的是不带-的字符串,类似于:b17f24ff026d40949c85a24f4f375d42
String simpleUUID = IdUtil.simpleUUID();
//设置博客的基本信息
//设置文章id
editor.setId(simpleUUID);
//避免被el在null调用
editor.setTitle("");
editor.setCreate_datetime(new Date());
editor.setContent("");
editor.setHtmlContent("");
model.addAttribute("editor",editor);
return "blog/edit";
}
/**
* 保存/更新 文章,edit页面的数据被自动封装为Editor对象
* @param editor
* @param request
* @param response
* @return
* @throws IOException
*/
@PostMapping("/save/{id}")
public String saveBlog(@PathVariable("id")String id, Editor editor, HttpServletRequest request, HttpServletResponse response) throws IOException {
User user = (User) request.getSession().getAttribute("user");
//设置文章的uid
editor.setUid(user.getUid());
System.out.println("editor = " + editor);
System.out.println("edit.getId" + editor.getId());
System.out.println("edit.getUid" + editor.getUid());
System.out.println("article.getTitle()" + editor.getTitle());
System.out.println("article.getContent() = " + editor.getContent());
Editor editorById = blogService.queryEditor(id);
System.out.println("saveBlog editorById = " + editorById);
//必须要在去博客页面就有唯一id,不能在保存这里生成唯一文章id,要不然就会一直保存
//如果数据库中已经有该id,给就是更新文章
if(editorById != null){
blogService.updateBlog(editor);
}else {
blogService.saveBlog(editor);
}
return "blog/success";
}
/**
* 预览,传入文章id,在数据库中查到markdown格式的内容信息并封装成Editor对象,通过Model带入到preview页面并被解析
* @param id
* @param
* @return
*/
@GetMapping("/preview/{id}")
public String preview(@PathVariable(value = "id") String id,Model model,HttpServletRequest request) {
HttpSession session = request.getSession();
User user = (User) session.getAttribute("user");
Editor editor = blogService.queryEditor(id);
if(user.getUid().equals(editor.getUid())){
System.out.println("editor = " + editor);
model.addAttribute("editor", editor);
return "blog/preview";
}else {
return "error/4xx";
}
}
/**
* 图片的上传
*
* @param request
* @param file
* @return
* @throws IOException
*/
@PostMapping("/imgUpload")
@ResponseBody
public FileInfo imageUpload(HttpServletRequest request, @RequestParam(value = "editormd-image-file", required = false) MultipartFile file) throws IOException {
if (!file.isEmpty()) {
//获取文件名
String filename = file.getOriginalFilename();
String[] split = filename.split("\\.");
//只接受jpg、png、gif、jpeg文件
if("jpg".equalsIgnoreCase(split[1]) || "png".equalsIgnoreCase(split[1]) || "gif".equalsIgnoreCase(split[1]) || "jpeg".equalsIgnoreCase(split[1])){
String simpleUUID = IdUtil.simpleUUID();
String photoName = simpleUUID + "." + split[1];
file.transferTo(new File(folder + photoName));
//http://localhost:8080 //获取协议号
String basePath = request.getScheme()
+ "://"
+ request.getServerName()//获取IP地址
+ ":"
+ request.getServerPort()//获取端口号
+ request.getContextPath();//获取工程路径
return new FileInfo(1, "上传成功", basePath + "/upload/" + photoName);
}
}
return null;
}
}