我们可以在官网下载它:https://pandao.github.io/editor.md/
, 得到它的压缩包!
解压以后,在examples
目录下面,可以看到他的很多案例使用!看人家怎么写的,然后进行模仿就好了!
我们可以将整个解压的文件倒入我们的项目,将一些无用的测试和案例删掉即可!
article
:文章表
字段 | 备注 | |
---|---|---|
id | int | 文章的唯一ID |
author | varchar | 作者 |
title | varchar | 标题 |
content | longtext | 文章的内容 |
建表SQL:
CREATE TABLE `article` (
`id` int(10) NOT NULL AUTO_INCREMENT COMMENT 'int文章的唯一ID',
`author` varchar(50) NOT NULL COMMENT '作者',
`title` varchar(100) NOT NULL COMMENT '标题',
`content` longtext NOT NULL COMMENT '文章的内容',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
SpringBoot
项目依赖<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 如果按照上面已经选了一些依赖,那么只需要添加这个依赖即可 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
</dependencies>
SpringBoot
项目配置我们在这里使用的是yml配置。
server:
port: 8081
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
# 记得创建自己本地的数据库哦,并修改密码
url: jdbc:mysql://localhost:3306/markdown?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
username: root
password: laochou
# 这里的配置主要是用来上传文件映射来使用的,这个location就是我们的存放图像的目录。当然这里还是要看你的数据库图片路径是如何设置的。
# 大家仔细的话,我在static目录下有个upload目录,这个目录就是我存放上传图片的目录。但是我们在location里面只到了 static这层,因此我的数据库中存放的便是 "/upload/xxxx.png"。拼接在一起就刚好。
# 图片的绝对路径:F:\JAVA\SpringBoot-MarkDown\src\main\resources\static\upload\0deeac80-6071-45e7-a1f4-d0107173a077.jpg
servlet:
multipart:
location: F:/JAVA/SpringBoot-MarkDown/src/main/resources/static
web:
resources:
static-locations: classpath:static/, file:${spring.servlet.multipart.location}
mybatis:
mapper-locations: classpath:/mappers/*.xml
type-aliases-package: cn.laochou.markdown.pojo
configuration:
map-underscore-to-camel-case: true
SpringBoot
代码编写本项目为Demo
,所以代码写的比较随意,没有做很多的校验,大家勿怪,我们先看下代码结构吧
OK,我们先从我们的Article
实体来讲
package cn.laochou.markdown.pojo;
public class Article {
private int id;
private String title;
private String author;
private String content;
// 省去了 Get和Set方法。在这里个人建议还是使用原生的Get和Set。
}
然后就看我们的Mapper
吧。因为Mapper
来操作数据库的,其实这里只有两个方法,一个是插入文章数据,一个便是根据Id获取文章数据。
@Mapper
public interface ArticleMapper {
public int insertArticle(Article article);
public Article getArticleById(int id);
}
Ok,ArticleMapper
的接口大家看到了,因为我们采用的还是MyBatis
,那么肯定是由ArticleMapper.xml
:
DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.laochou.markdown.mapper.ArticleMapper">
<insert id="insertArticle" parameterType="cn.laochou.markdown.pojo.Article">
insert into article (title, author, content) values(#{title}, #{author}, #{content});
insert>
<select id="getArticleById" resultType="cn.laochou.markdown.pojo.Article" parameterType="int">
select * from article where id = #{id};
select>
mapper>
接下来,就是我们的Service
层了,其实也就是两个方法。没啥很大的区别
@Service
public class ArticleService {
private final ArticleMapper articleMapper;
@Autowired
public ArticleService(ArticleMapper articleMapper) {
this.articleMapper = articleMapper;
}
public boolean publishArticle(Article article) {
int res = articleMapper.insertArticle(article);
if(res > 0) {
return true;
}
return false;
}
public Article getArticleById(int id) {
return articleMapper.getArticleById(id);
}
}
最后就是我们的Controller
层了,因为Controller
层会用到一个工具类FileUtil
,所以先展示我们的FileUtils
/**
* 文件上传工具类
*/
public class FileUtils {
// static目录下的upload目录可自己建,也可不建。因为在上传的时候,会判断是否存在,若不存在便自动创建
private static final String prePath = System.getProperty("user.dir") + "/src/main/resources/static/upload/";
/**
* 上传文件
* @param file
* @return 返回文件路径(以相对路径放回)
*/
public static String uploadFile(MultipartFile file) {
if(file.isEmpty()) {
return "";
}
// 获取原文件名
String originFileName = file.getOriginalFilename();
// 我们通过UUID 来重新重组文件名
String uid = UUID.randomUUID().toString();
assert originFileName != null;
String suffix = originFileName.substring(originFileName.lastIndexOf('.') + 1);
String path = prePath + uid + "." + suffix;
String returnPath = "/upload/" + uid + "." + suffix;
File newFile = new File(path);
if(newFile.getParentFile() != null && !newFile.getParentFile().exists()) {
System.out.println("创建目录ing");
// 上面的 newFile.getParentFile() 已经保证了不为null.
if(newFile.getParentFile().mkdirs()) {
System.out.println("创建目录成功");
}else {
System.out.println("创建目录失败");
return "";
}
}
try {
file.transferTo(newFile);
} catch (IOException e) {
e.printStackTrace();
return "";
}
return returnPath;
}
}
@Controller
@RequestMapping("/article")
public class ArticleController {
private final ArticleService articleService;
@Autowired
public ArticleController(ArticleService articleService) {
this.articleService = articleService;
}
@RequestMapping("/publish")
@ResponseBody
public String publishArticle(Article article) {
boolean res = articleService.publishArticle(article);
if(res) {
return "success";
}
return "false";
}
@RequestMapping("/image/upload")
@ResponseBody
// 注意RequestParam中的name,不可改。
public JSONObject imageUpload(@RequestParam("editormd-image-file") MultipartFile image) {
JSONObject jsonObject = new JSONObject();
if(image != null) {
String path = FileUtils.uploadFile(image);
System.out.println(path);
jsonObject.put("url", path);
jsonObject.put("success", 1);
jsonObject.put("message", "upload success!");
return jsonObject;
}
jsonObject.put("success", 0);
jsonObject.put("message", "upload error!");
return jsonObject;
}
@RequestMapping("/get/{id}")
public ModelAndView getArticleById(@PathVariable(name = "id")int id) {
ModelAndView modelAndView = new ModelAndView();
Article article = articleService.getArticleById(id);
modelAndView.setViewName("article");
if(article == null) {
modelAndView.addObject("article", new Article());
}
modelAndView.addObject("article", article);
return modelAndView;
}
}
@Controller
@RequestMapping("/markdown")
public class MarkDownController {
// 这个接口,主要是进行跳转页面的。
@RequestMapping("/edit")
public String edit() {
return "edit";
}
}
因为本人是后端研发,所以前端这边,花的时间挺久的,同样也挺丑的。
首先就是我们的一个静态资源。
css
: 我们需要将我们下载好的editormd
解压后editor.md-master
文件夹中的examples
目录中的css
文件夹中的style.css
拷贝到我们的 static/css/examples/style.css
,以及editor.md-master
文件夹下的 editormd.css
拷贝到我们的static/css
目录。以上的目录放在哪里,可以根据自己的个性以及想法,但是一定得保证访问的到,你如果觉得有问题,就跟我同样的目录。js
: 我们需要将我们下载好的editormd
解压后editor.md-master
文件夹中的examples
目录中的js
文件夹中的所有js
文件 拷贝到我们的 static/css/examples/
目录下,以及editor.md-master
文件夹下的 editormd.min.js
拷贝到我们的 static/js
目录。fonts
: 这个目录很重要,如果没有这个目录,Markdown
的编辑工具栏的icon
无法显示。需要将editor.md-master
文件夹中的fonts
文件夹直接拷贝到static
文件夹中。lib
: 将editor.md-master
文件夹中的lib文件拷贝到static
文件夹中即可。plugins
: 将editor.md-master
文件夹中的plugin
文件拷贝到static
文件夹中即可。接下来就是我们的HTML
文件了
edit.html
:
DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8" />
<title>Simple example - Editor.md examplestitle>
<link rel="stylesheet" th:href="@{/css/examples/style.css}" />
<link rel="stylesheet" th:href="@{/css/editormd.css}" />
<link rel="shortcut icon" href="https://pandao.github.io/editor.md/favicon.ico" type="image/x-icon" />
head>
<body>
<div id="layout">
<header>
<h1>Simple exampleh1>
header>
<form name="mdEditorForm">
标题:<input type="text" name="title"><br>
作者:<input type="text" name="author">
<div id="test-editormd">
<textarea style="display:none;" name="content">textarea>
div>
form>
div>
<script th:src="@{/js/examples/jquery.min.js}">script>
<script th:src="@{/js/editormd.min.js}">script>
<script type="text/javascript">
var testEditor;
$(function() {
testEditor = editormd("test-editormd", {
width : "90%",
height : 640,
syncScrolling : "single",
path : "../lib/",
// 表示支持上传图片
imageUpload : true,
imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp"],
// 上传图片的请求接口
imageUploadURL : "/article/image/upload",
// 工具栏图标的设置,大家可以自定义。比如 publish就是我定义的。
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", "||", "publish"];
},
// 自定义图标后,定义图标对应的文字
toolbarIconTexts: {
publish: "发布"
},
// 自定义图标的触发
toolbarHandlers : {
publish: function (cm, icon, cursor, selection) {
mdEditorForm.method = "post";
mdEditorForm.action = "/article/publish";//提交至服务器的路径
mdEditorForm.submit();
}
}
});
});
script>
body>
html>
article.html
:
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>文章title>
<link rel="stylesheet" th:href="@{/css/examples/style.css}" />
<link rel="stylesheet" th:href="@{/css/editormd.css}" />
<link rel="shortcut icon" href="https://pandao.github.io/editor.md/favicon.ico" type="image/x-icon" />
head>
<body>
<div id="layout">
<header>
<h1 th:text="${article.title}">h1>
<h2 th:text="${article.author}">h2>
header>
<div id="test-editormd">
<textarea style="display:none;" th:text="${article.content}">textarea>
div>
div>
// 一个JS文件都不能少,少一个便无法渲染。注意静态资源路径问题
<script th:src="@{/js/examples/jquery.min.js}">script>
<script th:src="@{/lib/marked.min.js}">script>
<script th:src="@{/lib/prettify.min.js}">script>
<script th:src="@{/lib/raphael.min.js}">script>
<script th:src="@{/lib/underscore.min.js}">script>
<script th:src="@{/lib/sequence-diagram.min.js}">script>
<script th:src="@{/lib/flowchart.min.js}">script>
<script th:src="@{/lib/jquery.flowchart.min.js}">script>
<script th:src="@{/js/editormd.min.js}">script>
<script type="text/javascript">
var testEditor;
$(function () {
testEditor = editormd.markdownToHTML("test-editormd", {
width: "90%",
height: 700,
path: "../lib/",
preview: true,
watch: true,
editor: false,
})
})
script>
body>
html>