我們經常可以看到各個博客網站中用於編輯文章的富文本編輯器,在富文本編輯器中,我們可以對我們的編輯內容樣式進行設置。富文本編輯器一般是通過插件來實現的,我們只需要在頁面中配置一下插件提供的一些API即可。本例中使用Editormd來演示如何配置使用富文本編輯器。
Editormd簡介
Editormd是國內開源的一款在線Markdown編輯器,可嵌入的 Markdown 在線編輯器(組件),基於 CodeMirror、jQuery 和 Marked 構建。
主要特性
支持“標準”Markdown / CommonMark和Github風格的語法,也可變身爲代碼編輯器。
- 支持實時預覽、圖片(跨域)上傳、預格式文本/代碼/表格插入、代碼摺疊、搜索替換、只讀模式、自定義樣式主題和多語言語法高亮等功能。
- 支持ToC(Table of Contents)、Emoji表情、Task lists、@鏈接等Markdown擴展語法。
- 支持TeX科學公式(基於KaTeX)、流程圖 Flowchart 和 時序圖 Sequence Diagram。
- 支持識別和解析HTML標籤,並且支持自定義過濾標籤解析,具有可靠的安全性和幾乎無限的擴展性。
- 支持 AMD / CMD 模塊化加載(支持 Require.js & Sea.js),並且支持自定義擴展插件。
- 兼容主流的瀏覽器(IE8+)和Zepto.js,且支持iPad等平板設備。
- 支持自定義主題樣式。
官網地址:https://pandao.github.io/editor.md/
創建文章表
在使用富文本編輯器之前,先來創建一個文章表article,這裏只添加了最基本的幾個字段, 以後想要擴展的話還可以添加標籤、時間、瀏覽量、點贊、評論等字段。建表SQL如下:
CREATE TABLE article(
id int(10) NOT NULL AUTO_INCREMENT COMMENT '文章唯一id',
author varchar(50) NOT NULL COMMENT '作者',
title varchar(100) NOT NULL COMMENT '標題',
content longtext NOT NULL COMMENT '文章內容'
PRIMARY KEY (id)
)ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
建完表,我們就可以開始編寫代碼來使用富文本編輯器了。
配置使用
1、創建一個SpringBoot項目,配置數據庫連接,我們這裏連接的是MyBatis(注意MySQL8需要在url中配置時區)。
spring:
datasource:
username: root
password: 123456
#?serverTimezone=UTC解決時區的報錯
url: jdbc:mysql://localhost:3306/springboot?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
thymeleaf:
cache: false
mybatis:
mapper-locations: classpath:com/wunian/mapper/*.xml
type-aliases-package: com.wunian.pojo
2、導入Editormd靜態資源,靜態資源的目錄結構如下圖所示。
3、編寫文章編輯頁面editor.html,引入Editormd的CSS和js文本,添加Editormd配置。
<!DOCTYPE html>
<html class="x-admin-sm" lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>及時雨的Blog</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width,user-scalable=yes, minimum-scale=0.4, initial-scale=0.8,target-densitydpi=low-dpi" />
<!--Editor.md-->
<link rel="stylesheet" th:href="@{/editormd/css/editormd.css}"/>
<link rel="shortcut icon" href="https://pandao.github.io/editor.md/favicon.ico" type="image/x-icon" />
</head>
<!--寫博客頁面-->
<body>
<div class="layui-fluid">
<div class="layui-row layui-col-space15">
<div class="layui-col-md12">
<!--博客表單-->
<form name="mdEditorForm">
<div>
標題: <input type="text" name="title">
</div>
<div>
作者: <input type="text" name="author">
</div>
<!-- 文章的主體內容 textarea -->
<div id="article-content">
<textarea name="content" id="content" style="display:none;"> </textarea>
</div>
</form>
</div>
</div>
</div>
</body>
<!--editormd-->
<script th:src="@{/editormd/jquery.min.js}"></script>
<script th:src="@{/editormd/editormd.js}"></script>
<script type="text/javascript">
var testEditor;
$(function() {
//這是一個最簡單的Editormd配置,往後我們要修改Editormd的
//功能或者樣式,就改這裏的配置就可以了
testEditor = editormd("article-content", {
width : "90%",
height : 640,
syncScrolling : "single",
path : "../editormd/lib/"
});
</script>
</html>
4、上面配置的只是最簡單的富文本編輯器功能,我們可以添加更多的配置來增加功能。
<script type="text/javascript">
var testEditor;
//window.onload = function(){ }
$(function() {
testEditor = editormd("article-content", {
width : "95%",
height : 500,
syncScrolling : "single",
path : "../editormd/lib/",
// 自定義的增強配置!
saveHTMLToTextarea : true, // 保存 HTML 到 Textarea
emoji: true, // 開啓表情的功能! 圖片的本地配置!
// theme: "light",//工具欄主題
// previewTheme: "dark",//預覽主題
// editorTheme: "pastel-on-dark",//編輯主題
// markdown的配置!
tex : true, // 開啓科學公式TeX語言支持,默認關閉
flowChart : true, // 開啓流程圖支持,默認關閉
sequenceDiagram : true, // 開啓時序/序列圖支持,默認關閉,
//圖片上傳
imageUpload : true,
imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp"],
imageUploadURL : "/article/file/upload", // 文件上傳的處理請求!
onload : function() {
console.log('onload', this);
},
/*指定需要顯示的功能按鈕*/
toolbarIcons : function() {
return ["undo","redo","|",
"bold","del","italic","quote","ucwords","uppercase","lowercase","|",
// "h1","h2","h3","h4","h5","h6","|",
"list-ul","list-ol","hr","|",
"link","reference-link","image","code","preformatted-text",
"code-block","table","datetime","emoji","html-entities","pagebreak","|",
"goto-line","watch","preview","fullscreen","clear","search","|",
//"help","info",
"releaseIcon", "index"]
},
// 這裏的自定義功能就好比,Vue 組件
/*自定義功能按鈕,下面我自定義了2個,一個是發佈,一個是返回首頁*/
toolbarIconTexts : {
releaseIcon : "<span bgcolor=\"gray\">發佈</span>",
index : "<span bgcolor=\"red\">返回首頁</span>",
},
/*給自定義按鈕指定回調函數*/
toolbarHandlers:{
releaseIcon : function(cm, icon, cursor, selection) {
//表單提交
mdEditorForm.method = "post";
mdEditorForm.action = "/article/addArticle";//提交至服務器的路徑
mdEditorForm.submit();
},
index : function(){
window.location.href = '/';
},
}
});
});
</script>
5、由於表情包的加載地址在國外,因此有時候可能加載不出來,我們可以把表情包下載到本地,放到/static/editormd/plugins/emoji-dialog/emoji
目錄下,並修改editormd.js
中的表情加載路徑爲我們的表情包存放的目錄路徑。
editormd.emoji = {
path : "../editormd/plugins/emoji-dialog/emoji/",
ext : ".png"
};
6、上傳圖片功能需要進行配置,我們可以在當前項目目錄下建立upload文件夾來上傳文件(注意這裏應該手動建立目錄,不要使用代碼創建),然後配置一下虛擬路徑(需要自定義WebMVC配置類)。
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
// 文件保存在真實目錄/upload/下,
// 訪問的時候使用虛路徑/upload,比如文件名爲1.png,就直接/upload/1.png就ok了。
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/upload/**")
.addResourceLocations("file:"+System.getProperty("user.dir")+"/upload/");
}
}
7、在Controller中編寫文件上傳的請求方法。
// MarkDown博客圖片上傳問題
@RequestMapping("/file/upload")
@ResponseBody
public JSONObject fileUpload(@RequestParam(value = "editormd-image-file", required = true) MultipartFile file, HttpServletRequest request) throws IOException {
//上傳路徑保存設置
//獲得SpringBoot當前項目的路徑:System.getProperty("user.dir")
String path = System.getProperty("user.dir")+"/upload/";
//按照月份進行分類:
Calendar instance = Calendar.getInstance();
String month = (instance.get(Calendar.MONTH) + 1)+"月";
path = path+month;
File realPath = new File(path);
if (!realPath.exists()){
realPath.mkdirs();
}
//上傳文件地址
System.out.println("上傳文件保存地址:"+realPath);
//解決文件名字問題:我們使用uuid;
String filename = "ks-"+UUID.randomUUID().toString().replaceAll("-", "")+".jpg";
//通過CommonsMultipartFile的方法直接寫文件(注意這個時候)
file.transferTo(new File(realPath +"/"+ filename));
//給editormd進行回調
JSONObject res = new JSONObject();
res.put("url","/upload/"+month+"/"+ filename);
res.put("success", 1);
res.put("message", "upload success!");
return res;
}
8、編寫文章顯示頁面article.html,同樣需要配置Editormd來正常顯示一些MarkDown文本。
<!DOCTYPE html>
<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 th:text="${article.title}"></title>
</head>
<!--讀博客的頁面-->
<body>
<div>
<!--文章頭部信息:標題,作者,最後更新日期,導航-->
<h2 style="margin: auto 0" th:text="${article.title}"></h2>
作者:<span style="float: left" th:text="${article.author}"></span>
<!--文章主體內容-->
<div id="doc-content">
<textarea style="display:none;" placeholder="markdown" th:text="${article.content}"></textarea>
</div>
</div>
<!--固定editormd依賴! -->
<link rel="stylesheet" th:href="@{/editormd/css/editormd.preview.css}"/>
<script th:src="@{/editormd/jquery.min.js}"></script>
<script th:src="@{/editormd/lib/marked.min.js}"></script>
<script th:src="@{/editormd/lib/prettify.min.js}"></script>
<script th:src="@{/editormd/lib/raphael.min.js}"></script>
<script th:src="@{/editormd/lib/underscore.min.js}"></script>
<script th:src="@{/editormd/lib/sequence-diagram.min.js}"></script>
<script th:src="@{/editormd/lib/flowchart.min.js}"></script>
<script th:src="@{/editormd/lib/jquery.flowchart.min.js}"></script>
<script th:src="@{/editormd/editormd.js}"></script>
<script type="text/javascript">
var testEditor;
$(function () {
// 綁定我們要渲染頁面的 div
testEditor = editormd.markdownToHTML("doc-content", {//注意:這裏是上面DIV的id
htmlDecode: "style,script,iframe",
emoji: true,
taskList: true,
tocm: true,
tex: true, // 默認不解析
flowChart: true, // 默認不解析
sequenceDiagram: true, // 默認不解析
codeFold: true
});
});
</script>
</body>
</html>
9、別忘了編寫保存文章和顯示文章的Controller請求方法。
//獲取文章進行顯示
@GetMapping("/{id}")
public String show(@PathVariable("id") int id,Model model){
Article article = articleMapper.getArticleById(id);
model.addAttribute("article",article);
return "article";
}
// 保存文章到數據庫!
@PostMapping("/addArticle")
public String addArticle(Article article){
articleMapper.addArticle(article);
return "editor";
}