SpringMVC(五):EditorMD编辑器开发与文件上传

一.EditorMD编辑器的使用

1.1editor编辑器介绍

  • 支持“标准”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等平板设备;

1.2.下载editor编辑器

官网:http://pandao.github.io/editor.md/

1.3.下载完成后

这是目录信息,找到examples目录,里面有个simple.html文件,只需要改动这个文件就可以使用

1.4.更改配置

这是笔者下载后修改过后的配置

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="utf-8"/>
    <title>Simple example - Editor.md examples</title>
    <link rel="stylesheet" href="css/style.css"/>
    <link rel="stylesheet" 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 example</h1>
    </header>
    <div id="test-editormd">
        <textarea style="display:none;"></textarea>
        <textarea class="editor-md-html" name="editor-md-html"></textarea>
    </div>
</div>
<script src="js/jquery.min.js"></script>
<script src="../editormd.min.js"></script>
<script type="text/javascript">
    var testEditor;

    $(function () {
        testEditor = editormd("test-editormd", {
            width: "70%",//编辑器大小官方默认90%
            height: 640,
            syncScrolling: "single",
            path: "../lib/",//这个编辑器文件的lib路径
            saveHTMLToTextarea : true,//注意3:这个配置,textarea可以提交

            emoji: true,//emoji表情,默认关闭
            /**上传图片相关配置如下*/
            imageUpload : true,
            imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp"],
            imageUploadURL : "/editorMDUpload",//注意你后端的上传图片服务地址
            
            //editorTheme: "pastel-on-dark",//编辑器的主题颜色
            theme: "gray",//顶部的主题
            previewTheme: "dark"//显示的主题

            //editor.md期望得到一个json格式的上传后的返回值,格式是这样的:
            /*
            {
                success : 0 | 1,           // 0 表示上传失败,1 表示上传成功
                message : "提示的信息,上传成功或上传失败及错误信息等。",
                url     : "图片地址"        // 上传成功时才返回
            }
            */

        });

        /*
        // or
        testEditor = editormd({
            id      : "test-editormd",
            width   : "90%",
            height  : 640,
            path    : "../lib/"
        });
        */
    });
</script>
</body>
</html>

1.5.图片上传

这是图片上传的前端配置,如上代码中的一样

imageUpload : true,
            imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp"],
            imageUploadURL : "/editorMDUpload",//注意你后端的上传图片服务地址

1.6.SpringMVC文件上传

为了试下动态上传,笔者后台使用的是java SpringMVC框架,以下是修改后的jsp代码

<%--
  Created by IntelliJ IDEA.
  User: hly
  Date: 2018/8/15
  Time: 16:17
  github :github.com/SiriusHly
  blog :blog.csdn.net/Sirius_hly
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<% String path = request.getContextPath();%>
<html lang="zh">
<head>
    <meta charset="utf-8"/>
    <title>Simple example - Editor.md examples</title>
    <link rel="stylesheet" href="<%=path%>/static/html/editor/editor.md-master/examples/css/style.css"/>
    <link rel="stylesheet" href="<%=path%>/static/html/editor/editor.md-master/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 example</h1>
    </header>
    <div id="test-editormd">
        <textarea style="display:none;"></textarea>
        <textarea class="editor-md-html" name="editor-md-html"></textarea>
    </div>
</div>
<script src="<%=path%>/static/html/editor/editor.md-master/examples/js/jquery.min.js"></script>
<script src="<%=path%>/static/html/editor/editor.md-master/editormd.min.js"></script>
<script type="text/javascript">
    var testEditor;

    $(function () {
        testEditor = editormd("test-editormd", {
            width: "70%",//编辑器大小官方默认90%
            height: 640,
            syncScrolling: "single",
            path: "<%=path%>/static/html/editor/editor.md-master/lib/",
            saveHTMLToTextarea : true,//注意3:这个配置,textarea可以提交

            emoji: true,//emoji表情,默认关闭
            /**上传图片相关配置如下*/
            imageUpload : true,
            imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp"],
            imageUploadURL : "<%=path%>/fileUpload/editorMDUpload",//注意你后端的上传图片服务地址
            onload: function () { //上传成功之后的回调

            },

            //editorTheme: "pastel-on-dark",//编辑器的主题颜色
            theme: "gray",//顶部的主题
            previewTheme: "dark"//显示的主题
            
        });

    });
</script>
</body>
</html>

1.7.SpringMVC后台

package com.hly.ssm.controller.fileUploadController;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Calendar;

/**
 * @author :hly
 * @github :github.com/SiriusHly
 * @blog :blog.csdn.net/Sirius_hly
 * @date :2018/8/15
 */
@Controller
@RequestMapping(value = "/fileUpload" )
public class EditormdFileUploadController {
    
    @RequestMapping(value = "/editorMDUpload" ,method = RequestMethod.POST)
    public void editorMD(HttpServletRequest request, HttpServletResponse response,@RequestParam(value = "editormd-image-file", required = false) MultipartFile file) throws IOException {
        try {
            request.setCharacterEncoding( "utf-8" );
            /*这里返回格式是html/txt才能上传*/
            response.setHeader( "Content-Type" , "application/json" );
            //获得web项目的全路径
            String rootPath = request.getSession().getServletContext().getRealPath("/resource/upload/");
            //Calendar.getInstance()是获取一个Calendar对象并可以进行时间的计算,时区的指定
            Calendar date = Calendar.getInstance();
            //获得日期路径,MONTH个值的初始值是0,因此我们要用它来表示正确的月份时就需要加1。
            File dateFile = new File(date.get(Calendar.YEAR)+"/"+(date.get(Calendar.MONTH)+1)+"/"+(date.get(Calendar.DATE)));
            //获得文件最初的路径
            String originalFile = file.getOriginalFilename();
            //得到完整路径名
            File newFile = new File(rootPath+File.separator+dateFile+File.separator+originalFile);

            /*文件不存在就创建*/
            if(!newFile.getParentFile().exists()){
                newFile.getParentFile().mkdirs();
            }
            file.transferTo(newFile);
            //System.out.println("/resources/upload/"+dateFile+File.separator+originalFile);
            System.out.println(dateFile+"/"+file.getOriginalFilename());
            /*JSON格式*/
            response.getWriter().write("{\"success\":1,\"message\":\"上传成功\",\"url\":\"/resource/upload/"+date.get(Calendar.YEAR)+"/"+(date.get(Calendar.MONTH)+1)+"/"+date.get(Calendar.DATE)+"/"+file.getOriginalFilename()+"\"}");
            
        } catch (Exception e) {
            response.getWriter().write("{\"success\":0}");

        }
    }
    @RequestMapping("editorMD")
    public ModelAndView editormd(){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("/editor/simple");
        return mv;
    }
    
}

这里有几点需要注意:

@RequestParam(value = "editormd-image-file", required = false)

1.上面的value是特定的,这样才能接收到文件

2.图片被拦截

在上传后,图片无法再前端的预览区显示,是由于mvc拦截了图片,所以需要在web.xml文件中添加

 <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.css</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.xml</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.swf</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.zip</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.gif</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.jpg</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.png</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
  </servlet-mapping>

也可以放在webapp路径下,然后在springMVC中进行配置,如下

<!-- 静态资源映射 -->
    <!--路径后有/会认为是目录,没有认为是文件-->
    <!--location是工程路径地址,mapping是映射后的访问地址-->
    <!--/*所有文件夹不包括子文件夹,/**所有文件夹和里面的子文件夹-->
    <mvc:resources mapping="/static/**" location="/static/"/>

3.所传递的json字符串需要正确,如上

//editor.md期望得到一个json格式的上传后的返回值,格式是这样的:
            /*
            {
                success : 0 | 1,           // 0 表示上传失败,1 表示上传成功
                message : "提示的信息,上传成功或上传失败及错误信息等。",
                url     : "图片地址"        // 上传成功时才返回
            }
            */

4.笔者在定义上传文件夹时,使用了日期进行分类,造成了错误,导致图片无法上传成功,研究发现是

File.separator

的问题,json貌似不能传递\(反斜杠),所以我们可以用"/",在创建文件对象时即使用"/",也会被转化为\,所以我们可以在json字符串中再做改动。下面是上传的目录及效果截图。

二.编辑内容获取

1.html代码

这是获取内容的html代码,其他部分都一样

<input type="text" placeholder="请输入标题" id="title" name="title" autocomplete="off">
    <input name="my_submit" id="my_submit" value="提交" type="button">
    <div id="test-editormd">
        <textarea id="editor-md-doc" name="editor-md-doc" style="display:none;"></textarea>
        <textarea id="editor-md-html" name="editor-md-html"></textarea>
    </div>

2.js代码

JQ实现,获取编辑内容,然后ajax封装上传

<script>
    $("#my_submit").click(function () {
        alert("正在提交");
        submit_atricle();
    })

    function submit_atricle() {
        var title = $("#title").val();
        var htmlContent = $("#editor-md-html").val();
        var markdownContent = $("#editor-md-doc").val();
        $.ajax({
            url: "<%=path%>/fileUpload/editorContent",
            data: JSON.stringify({title: title, htmlContent: htmlContent, markdownContent: markdownContent}),
            type: "POST",
            contentType: 'application/json',
            success: function () {
                alert("发布成功");
            },
            error: function () {
                alert("发布失败");
            }
        })
    }
</script>

3.完整jsp前端代码

<%--
  Created by IntelliJ IDEA.
  User: hly
  Date: 2018/8/15
  Time: 16:17
  github :github.com/SiriusHly
  blog :blog.csdn.net/Sirius_hly
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<% String path = request.getContextPath();%>
<html lang="zh">
<head>
    <meta charset="utf-8"/>
    <title>Simple example - Editor.md examples</title>
    <link rel="stylesheet" href="<%=path%>/static/html/editor/editor.md-master/examples/css/style.css"/>
    <link rel="stylesheet" href="<%=path%>/static/html/editor/editor.md-master/css/editormd.css"/>
    <link rel="stylesheet" href="<%=path%>/static/assets/js/jquery-3.1.1.js"/>
    <link rel="shortcut icon" href="https://pandao.github.io/editor.md/favicon.ico" type="image/x-icon"/>
</head>
<body>
<div id="layout">
    <header></header>
    <%--页面提交表单内容--%>

    <input type="text" placeholder="请输入标题" id="title" name="title" autocomplete="off">
    <input name="my_submit" id="my_submit" value="提交" type="button">
    <div id="test-editormd">
        <textarea id="editor-md-doc" name="editor-md-doc" style="display:none;"></textarea>
        <textarea id="editor-md-html" name="editor-md-html"></textarea>
    </div>

</div>
<script src="<%=path%>/static/html/editor/editor.md-master/examples/js/jquery.min.js"></script>
<script src="<%=path%>/static/html/editor/editor.md-master/editormd.min.js"></script>
<script>
    $("#my_submit").click(function () {
        alert("正在提交");
        submit_atricle();
    })

    function submit_atricle() {
        var title = $("#title").val();
        var htmlContent = $("#editor-md-html").val();
        var markdownContent = $("#editor-md-doc").val();
        $.ajax({
            url: "<%=path%>/fileUpload/editorContent",
            data: JSON.stringify({title: title, htmlContent: htmlContent, markdownContent: markdownContent}),
            type: "POST",
            contentType: 'application/json',
            success: function () {
                alert("发布成功");
            },
            error: function () {
                alert("发布失败");
            }
        })
    }
</script>
<script type="text/javascript">
    var testEditor;

    $(function () {
        testEditor = editormd("test-editormd", {
            /*上面div的值*/
            width: "70%",//编辑器大小官方默认90%
            height: 640,
            syncScrolling: "single",
            path: "<%=path%>/static/html/editor/editor.md-master/lib/",
            saveHTMLToTextarea: true,//注意3:这个配置,textarea可以提交

            emoji: true,//emoji表情,默认关闭
            tocm: true, // Using [TOCM]
            tex: true, // 开启科学公式TeX语言支持,默认关闭
            flowChart: true, // 开启流程图支持,默认关闭
            /**上传图片相关配置如下*/
            imageUpload: true,
            imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp"],
            imageUploadURL: "<%=path%>/fileUpload/editorMDUpload",//注意你后端的上传图片服务地址
            onload: function () { //上传成功之后的回调

            },

            //editorTheme: "pastel-on-dark",//编辑器的主题颜色
            theme: "gray",//顶部的主题
            previewTheme: "dark"//显示的主题

        });

    });
</script>
</body>
</html>

4.后端获取代码

@RequestMapping(value = "editorContent",method = RequestMethod.POST)
    public ModelAndView articleContent(@RequestBody Article article){
        System.out.println("MD文本");
        System.out.println(article.getMarkdownContent());
        System.out.println("HTML文本");
        System.out.println(article.getHtmlContent());

        ModelAndView mv = new ModelAndView();
        mv.addObject("html",article.getHtmlContent());
        mv.addObject("md",article.getMarkdownContent());
        mv.setViewName("editor/article");
        return  mv;
    }

文章实体类,关于@Requestbody的使用方法,https://blog.csdn.net/Sirius_hly/article/details/80302060 请看笔者者篇文章。

public class Article {
    private String title;
    private String htmlContent;
    private String markdownContent;
}

5.处理获得的文本

       后端获得文本后,我们可以先创建一个html,因为传过来的是markdown文本,我们需要把他们转化为html文本。下面是完整代码,需要引入一些js文件和css文件,基本上都在lib下。

<!--@author :hly
@github :github.com/SiriusHly
@blog :blog.csdn.net/Sirius_hly
@date :2018/8/4
-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="../../../static/html/editor/editor.md-master/examples/css/style.css"/>

    <link rel="stylesheet" href="../../../static/html/editor/css/editormd.css"/>

    <link rel="shortcut icon" href="https://pandao.github.io/editor.md/favicon.ico" type="image/x-icon"/>
</head>
<body>
<div id="content">
    <textarea style="display:none;">```html
 $("#my_submit").click(function () {
        alert("正在提交");
        submit_atricle();
    })

```
## 提交代码</textarea>
</div>

<script src="../../../static/html/editor/editor.md-master/examples/js/jquery.min.js"></script>
<script src="../../../static/html/editor/editor.md-master/editormd.min.js"></script>
<script src="../../../static/html/editor/editor.md-master/lib/flowchart.min.js"></script>
<script src="../../../static/html/editor/editor.md-master/lib/jquery.flowchart.min.js"></script>
<script src="../../../static/html/editor/editor.md-master/lib/marked.min.js"></script>
<script src="../../../static/html/editor/editor.md-master/lib/prettify.min.js"></script>
<script src="../../../static/html/editor/editor.md-master/lib/raphael.min.js"></script>
<script src="../../../static/html/editor/editor.md-master/lib/sequence-diagram.min.js"></script>
<script src="../../../static/html/editor/editor.md-master/lib/underscore.min.js"></script>
<script type="text/javascript">
    var testEditor;
    $(function () {
        testEditor = editormd.markdownToHTML("content", {//注意:这里是上面DIV的id
            htmlDecode: "style,script,iframe",
            emoji: true,
            taskList: true,
            tex: true, // 默认不解析
            flowChart: true, // 默认不解析
            sequenceDiagram: true, // 默认不解析
            codeFold: true,
            //editorTheme: "pastel-on-dark",//编辑器的主题颜色
            theme: "gray",//顶部的主题
            previewTheme: "dark"//显示的主题
        });});
</script>
</body>
</html>

6.文本显示

        运行html,显示的文本是这样的,由于觉得代码样式太丑,笔者修改了一下editormd.css背景和颜色,具体在格式化后的3千多行。

这是修改过后的css代码:https://github.com/SiriusHly/SSM/tree/master/MySSM/src/main/webapp/static/html/editor/css

7.最后附上后端完整代码

package com.hly.ssm.controller.fileUploadController;

import com.hly.ssm.pojo.Article;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Calendar;

/**
 * @author :hly
 * @github :github.com/SiriusHly
 * @blog :blog.csdn.net/Sirius_hly
 * @date :2018/8/15
 */
@Controller
@RequestMapping(value = "/fileUpload" )
public class EditormdFileUploadController {

    /**
     * 边界页面
     * @return
     */
    @RequestMapping("editorMD")
    public ModelAndView editormd(){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("/editor/simple");
        return mv;
    }

    /**
     * 图片上传
     * @param request
     * @param response
     * @param file
     * @throws IOException
     */
    @RequestMapping(value = "/editorMDUpload" ,method = RequestMethod.POST)
    public void editorMD(HttpServletRequest request, HttpServletResponse response,@RequestParam(value = "editormd-image-file", required = false) MultipartFile file) throws IOException {
        try {
            request.setCharacterEncoding( "utf-8" );
            /*这里返回格式是html/txt才能上传*/
            response.setHeader( "Content-Type" , "application/json" );
            //获得web项目的全路径
            String rootPath = request.getSession().getServletContext().getRealPath("/resource/upload/");
            //Calendar.getInstance()是获取一个Calendar对象并可以进行时间的计算,时区的指定
            Calendar date = Calendar.getInstance();
            //获得日期路径,MONTH个值的初始值是0,因此我们要用它来表示正确的月份时就需要加1。
            File dateFile = new File(date.get(Calendar.YEAR)+"/"+(date.get(Calendar.MONTH)+1)+"/"+(date.get(Calendar.DATE)));
            //获得文件最初的路径
            String originalFile = file.getOriginalFilename();
            //得到完整路径名
            File newFile = new File(rootPath+File.separator+dateFile+File.separator+originalFile);

            /*文件不存在就创建*/
            if(!newFile.getParentFile().exists()){
                newFile.getParentFile().mkdirs();
            }
            file.transferTo(newFile);
            //System.out.println("/resources/upload/"+dateFile+File.separator+originalFile);
            System.out.println(dateFile+"/"+file.getOriginalFilename());
            /*JSON格式*/
            response.getWriter().write("{\"success\":1,\"message\":\"上传成功\",\"url\":\"/resource/upload/"+date.get(Calendar.YEAR)+"/"+(date.get(Calendar.MONTH)+1)+"/"+date.get(Calendar.DATE)+"/"+file.getOriginalFilename()+"\"}");

        } catch (Exception e) {
            response.getWriter().write("{\"success\":0}");

        }
    }

    /**
     * 获取文章内容
     */

    @RequestMapping(value = "editorContent",method = RequestMethod.POST)
    public ModelAndView articleContent(@RequestBody Article article){
        System.out.println("MD文本");
        System.out.println(article.getMarkdownContent());
        System.out.println("HTML文本");
        System.out.println(article.getHtmlContent());

        ModelAndView mv = new ModelAndView();
        mv.addObject("html",article.getHtmlContent());
        mv.addObject("md",article.getMarkdownContent());
        mv.setViewName("editor/article");
        return  mv;
    }
    
}

猜你喜欢

转载自blog.csdn.net/Sirius_hly/article/details/81709370
今日推荐