• 使用springmvc,jsp,结合网页文本编辑器kindEditor实现基本博客编辑功能


    kindEditor官网:http://kindeditor.net/demo.php

    个人实践:

    为了在自己的项目中引入一个类似用户写博客的功能,在网上找到了kindeditor,真心又好又易用。

    一、准备工作

    1、下载kindeditor,在官网上点击右上方的下载链接,我下载的是4.1.11版。由于我的项目前端采用jsp,所以将解压以后的asp,asp.net和php文件夹删掉。

    在jsp文件夹里的就是在jsp下使用kindeditor的demo。需要注意的是,demo.jsp文件中有笔误,需要首先将<script charset="utf-8" src="../kindeditor.js"></script>

    的src指向kindeditor-all-min.js才可以。

    2、阅读demo.jsp:kindeditor的js使用K.create方法,于页面加载完毕以后,在name是content1的textarea前面自动创建博客编辑功能toolbar,最关键的uploadJson参数指定

    了用户上传图片、动画、文件等媒体文件的后台处理controller。在demo.jsp中,表单提交给了demo.jsp自己,可以在jsp代码的开头部分发现,程序从request中将content1的

    内容取了出来,在body中,将内容展示在form表单之前。也就是说demo.jsp中的博客编辑器提交后的内容会在编辑器上方展示出来。需要注意的是htmlspecialchars方法,它

    将html标签中的相关字符进行转义,目的是将用户提交的内容在博客编辑器中显示,方便用户继续编辑已经存在的内容。这个转义的过程在项目中我们其实是放在后台处理的,

    做好以后直接传给前台展示。fileManagerJson参数指定了上传后文件的编辑界面,由于我的项目不需要这个功能,所以将这个参数舍去,将allowFileManager参数置false。

    afterCreate参数指定了创建博客编辑功能toolbar以后做的事,就是当用户使用ctrl+enter的时候提交表单。我不需要这功能所以也可以舍去afterCreate。

    3、阅读完了demo.jsp以后,如何展示编辑工具栏,如何提交表单,如何在编辑框中显示已经存在的内容,这几个关键的基本问题就都找到答案了,下面就是实践和解决细节问题。

    主要是两个后台问题,一是如何处理uploadJson参数对应的文件上传及给kindeditor返回准确的值,二是表单提交以后如何在后台取到提交的内容,由于我使用了springmvc的form

    标签库,如何结合标签库也是个小问题。

    二、编码和实现

    1、jsp文件片段

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
    <%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>${pageTitle }</title>
    <link href="/Public/media/css/new/page.css" rel="stylesheet"
        type="text/css" />
    <link rel="stylesheet"
        href="/Public/kindeditor/themes/default/default.css" />
    <link rel="stylesheet"
        href="/Public/kindeditor/plugins/code/prettify.css" />
    <script charset="utf-8" src="/Public/kindeditor/kindeditor-all-min.js"></script>
    <script charset="utf-8" src="/Public/kindeditor/lang/zh-CN.js"></script>
    <script charset="utf-8"
        src="/Public/kindeditor/plugins/code/prettify.js"></script>
    <script>
        KindEditor.ready(function(K) {
            var editor1 = K.create('textarea[name="content"]', {
                cssPath : '/Public/kindeditor/plugins/code/prettify.css',
                uploadJson : '${pageContext.request.contextPath}/workConfig/updateContent',
                allowFileManager : false
            });
            prettyPrint();
        });
    </script>
    </head>
    <body>
    <form:form action="${formActionURL}" method="post" commandName="work">
                <div class="formDiv">
                    <table width="1020" border="0">
                <tr>
                            <td align="right">展示页面:</td>
                            <td align="left">
                                <textarea name="content" rows="20" cols="100" style=" 700px; height: 200px; visibility: hidden;">
                                    ${work.content }
                                </textarea>
                            </td>
                        </tr>
              </table>
                </div>
            </form:form>
    </body>
    </html>

    1.1:曾尝试过使用springmvc的textarea标签库<form:textarea,虽然只要将kindeditor的K.create里textarea的name改为<form:textarea的name即可(假设form:textarea的path值为"content",那么这个标签库在被翻译成html时,textarea的name和id会被自动赋值为"content"),但由于textarea的内容会被springmvc自动赋值给表单代表的Model类的相应值,所以htmlspecialchars的转义过程就没法进行了,当然你也可以修改JavaBean的

    getContent方法中加入转义过程,但这么做稍显繁琐,不如就不用form:textarea标签库,只要将其name值设置为表单Model类的属性值,内容在提交后一样会被自动赋值给对应的属性(经试验证实)。

    2、文件上传处理程序片段

       @RequestMapping(value="/updateContent",produces = "application/json; charset=utf-8")
        @ResponseBody
        public String updateContent(MultipartHttpServletRequest request) {
            MultipartFile realMediaFile = null;
            Iterator<String> iter = request.getFileNames();
            JSONObject obj = new JSONObject();
            while (iter.hasNext()) {
                // 取得上传文件
                MultipartFile file = request.getFile(iter.next());
                if (file != null) {
                    realMediaFile = file;
                }
                if (realMediaFile != null) {
    
                    // 定义允许上传的文件扩展名
                    String extStr = "gif,jpg,jpeg,png,bmp,swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb,doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2";
                    List<String> extList = Arrays.asList(extStr.split(","));
    
                    // 最大文件大小
                    long maxSize = 1000000;
    
                    // 准备好路径参数
                    String uploadMediaSavePath = pathUtil.getYgbhUploadMediaDiskFolderPath(request);
                    String urlRootPath = pathUtil.getYgbhUploadMediaUrlFolderPath();
                    List<MultipartFile> files = new ArrayList<MultipartFile>();
                    files.add(realMediaFile);
    
                    // 保存
                    String message = "";
                    if (realMediaFile.getSize() > maxSize) {
                        message = "上传文件大小超过限制。";
                    }
                    String originalfileName = realMediaFile.getOriginalFilename();
                    String suffixName = originalfileName.substring(originalfileName.lastIndexOf(".") + 1).toLowerCase();
                    if (!extList.contains(suffixName)) {
                        message = "上传文件扩展名是不允许的扩展名。
    只允许[" + extStr + "]格式。";
                    }
                    String newFileName = "";
                    try {
                        newFileName = MultipartFileUtil.saveMediaFiles(files, uploadMediaSavePath, urlRootPath).get(0);
                    } catch (Exception e) {
                        message = "上传文件失败。";
                    }
                    try {
                        if (!message.isEmpty()) {
                            obj.put("error", 1);
                            obj.put("message", message);
                        } else {
                            obj.put("error", 0);
                            obj.put("url", urlRootPath + newFileName);
                        }
                    } catch (Exception e) {
                        log.error("上传文件[" + originalfileName + "]失败。");
                        e.printStackTrace();
                    }
                } else {
                    try {
                        obj.put("error", 1);
                        obj.put("message", "找不到文件。");
                    } catch (JSONException e) {
                        log.error("上传文件失败。");
                        e.printStackTrace();
                    }
                }
                return obj.toString();
            }
            return obj.toString();
        }

    2.1:使用@ResponseBody的返回值为String类型的方法,在试验后被证明是可以使用的。如果不标识@ResponseBody,返回String类型的Controller方法会将返回值视为jsp文件的路径去寻找jsp文件。而如果你打算

    将返回值类型用某JavaBean来代替,心想反正使用了@ResponseBody,springmvc会将对象转换成正确的JSON格式,结果是kindeditor拿不到返回值。

    2.2:由于kindeditor生成的博客编辑工具栏有批量上传按钮,所以在取得用户提交内容时,需要用iterator的方式。

    2.3:看到urlRootPath变量了吗,它指向我的系统的静态资源工程,是一个只能在本系统内可以访问的不跨域url。这也牵扯到后面的一个问题。需求是:用户自己编写的博客内容,会以html的方式保存在系统的数据库中,

    该段html代码必须在它被从数据库里取出并放置在一个html页面的body片段中时能够完整地展示所有内容,包括图片、动画等媒体资源内容。那么问题来了,无论我怎么设置,就算是我直接在urlRootPath前拼接“http://

    XXX.XXX.XX.XX:8080”,等到内容显示在textarea编辑框中时,图片等媒体资源的src依然被kindeditor自动改为不跨域的url,也就是说,只能在系统内展示时才能看见这些非文本的内容。如何优雅地解决该问题我至今

    还没找到很好的办法,只是暂时在保存博客内容html时,将所有包含不跨域url的内容前面自动加上类似“http://XXX.XXX.XX.XX:8080”的前缀,以保证该资源在任何地方都能被访问。

    补充,上面划线部分的问题已经得到解决(参考资料:http://www.111cn.net/wy/255/64719.htm),给KindEditor加一个与uploadJson同级别的运行参数,urlType:'domain',

    urlTypeY有四种值,""表示不修改URL,"relative"表示相对路径,"absolute"表示绝对路径,"domain表示带域名的绝对路径"。

    由于该问题已解决,所以3中的replace过程可以去掉了。

    2.4:produces = "application/json; charset=utf-8"这句如果不加,返回的中文内容会是乱码。

    3、表单提交内容处理程序片段

    @RequestMapping(value = "/editWork", method = RequestMethod.POST)
        public ModelAndView editWork(@Valid @ModelAttribute("work") DesignerWorks work, BindingResult br,
                HttpServletRequest request) {
            ModelAndView mv = new ModelAndView();
            mv.addObject("work", work);
            if (br.hasErrors()) {
                mv.addObject("currentMenuDesc", "当前目录:首页>系统管理>作品管理>编辑作品");
                mv.addObject("backToURL", request.getContextPath() + "/workConfig/openWorkConfig");
                mv.addObject("formActionURL", request.getContextPath() + "/workConfig/editWork");
                mv.addObject("pageTitle", "编辑作品");
                mv.setViewName("editWork");
            } else {
                try {
                    DesignerWorks workToSave = work;
                    workToSave.setContent(workToSave.getContent().replace(pathUtil.getServerUrl(request), ""));
                    workToSave.setContent(workToSave.getContent().replace(pathUtil.getUploadMediaRootUrl(),
                            pathUtil.getServerUrl(request) + pathUtil.getUploadMediaRootUrl()));
                    designerService.updateWork(work);
                } catch (Exception e) {
                    mv.addObject(ConstantsUtil.ERROR_STACK, ExceptionUtils.getStackTrace(e));
                    mv.setViewName("error");
                    return mv;
                }
                mv.addObject(ConstantsUtil.BACK_TO_URL, request.getContextPath() + "/workConfig/openWorkConfig");
                mv.setViewName("success");
            }
            return mv;
        }

    3.1:可以看到媒体文件url的replace的过程,getServerUrl的代码片段如下:

    
    

    import java.io.File;
    import java.net.InetAddress;

    import javax.servlet.http.HttpServletRequest;


    public
    static String getServerUrl(HttpServletRequest request) throws Exception{ return "http://"+InetAddress.getLocalHost().getHostAddress()+":"+request.getServerPort(); }

    三、补充

    1、问题:在之后的项目中,我使用了jquery.easyui.min.js的.form()来间接提交表单,发现由kindeditor生成的textarea内容始终无法被后台接收到。

    2、调查:查看页面源码我发现,kindeditor工作时,是在被它修饰的textarea的上方加了一个div,用户输入的所有内容其实都是在编辑div中的内容而不是直接写在textarea里,

    当用户使用传统方式提交表单时,kindeditor一定是自动有一个将用户输入内容粘贴入textarea的动作,而当使用js间接提交表单时,kindeditor的这个自动的动作没有被触发,所以

    后台得到的是还未被粘贴内容的textarea的文本。

    3、解决:最直接的想办法是手动调一下这个自动粘贴的程序。搜索了一下发现已有人解决。http://lxy.me/ajax-kindeditor-content-to-textarea.html

    <script type="text/javascript">
    KindEditor.ready(function(K){
    K.create('textarea[name="content"]', {
    themeType: 'simple',
    resizeType: 1,
    uploadJson: 'common/KEditor/upload_json.php',
    fileManagerJson: 'common/KEditor/file_manager_json.php',
    allowFileManager: true,
    //下面这行代码就是关键的所在,当失去焦点时执行this.sync(),同步输入的值到textarea中;
    afterBlur: function(){this.sync();}
    });
    });
    </script>

  • 相关阅读:
    前后端分离的若依(ruoyi)基本使用
    Redis (error) NOAUTH Authentication required.解决方法
    Creating Server TCP listening socket 127.0.0.1:6379: bind: No error。。。启动遇到问题的解决办法
    持续集成
    Java compiler level does not match the version of the installed Java project facet问题解决
    控制台报错:Unknown database 'xxxxx'
    走进docker-machine
    走进docker-compose
    java新手学习路线
    Spring WebFlux 教程:如何构建反应式 Web 应用程序
  • 原文地址:https://www.cnblogs.com/mabaishui/p/5553010.html
Copyright © 2020-2023  润新知