使用springmvc,jsp,結合網頁文本編輯器kindEditor實現基本博客編輯功能

kindEditor官網:http://kindeditor.net/demo.phpjavascript

 

我的實踐:php

爲了在本身的項目中引入一個相似用戶寫博客的功能,在網上找到了kindeditor,真心又好又易用。css

1、準備工做html

一、下載kindeditor,在官網上點擊右上方的下載連接,我下載的是4.1.11版。因爲個人項目前端採用jsp,因此將解壓之後的asp,asp.net和php文件夾刪掉。前端

在jsp文件夾裏的就是在jsp下使用kindeditor的demo。須要注意的是,demo.jsp文件中有筆誤,須要首先將<script charset="utf-8" src="../kindeditor.js"></script>java

的src指向kindeditor-all-min.js才能夠。jquery

二、閱讀demo.jsp:kindeditor的js使用K.create方法,於頁面加載完畢之後,在name是content1的textarea前面自動建立博客編輯功能toolbar,最關鍵的uploadJson參數指定ajax

了用戶上傳圖片、動畫、文件等媒體文件的後臺處理controller。在demo.jsp中,表單提交給了demo.jsp本身,能夠在jsp代碼的開頭部分發現,程序從request中將content1的spring

內容取了出來,在body中,將內容展現在form表單以前。也就是說demo.jsp中的博客編輯器提交後的內容會在編輯器上方展現出來。須要注意的是htmlspecialchars方法,它數據庫

將html標籤中的相關字符進行轉義,目的是將用戶提交的內容在博客編輯器中顯示,方便用戶繼續編輯已經存在的內容。這個轉義的過程在項目中咱們實際上是放在後臺處理的,

作好之後直接傳給前臺展現。fileManagerJson參數指定了上傳後文件的編輯界面,因爲個人項目不須要這個功能,因此將這個參數捨去,將allowFileManager參數置false。

afterCreate參數指定了建立博客編輯功能toolbar之後作的事,就是當用戶使用ctrl+enter的時候提交表單。我不須要這功能因此也能夠捨去afterCreate。

三、閱讀完了demo.jsp之後,如何展現編輯工具欄,如何提交表單,如何在編輯框中顯示已經存在的內容,這幾個關鍵的基本問題就都找到答案了,下面就是實踐和解決細節問題。

主要是兩個後臺問題,一是如何處理uploadJson參數對應的文件上傳及給kindeditor返回準確的值,二是表單提交之後如何在後臺取到提交的內容,因爲我使用了springmvc的form

標籤庫,如何結合標籤庫也是個小問題。

2、編碼和實現

一、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="width: 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類的屬性值,內容在提交後同樣會被自動賦值給對應的屬性(經試驗證明)。

二、文件上傳處理程序片斷

   @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 = "上傳文件擴展名是不容許的擴展名。\n只容許[" + 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"這句若是不加,返回的中文內容會是亂碼。

 

三、表單提交內容處理程序片斷

@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(); }

3、補充

一、問題:在以後的項目中,我使用了jquery.easyui.min.js的.form()來間接提交表單,發現由kindeditor生成的textarea內容始終沒法被後臺接收到。

二、調查:查看頁面源碼我發現,kindeditor工做時,是在被它修飾的textarea的上方加了一個div,用戶輸入的全部內容其實都是在編輯div中的內容而不是直接寫在textarea裏,

當用戶使用傳統方式提交表單時,kindeditor必定是自動有一個將用戶輸入內容粘貼入textarea的動做,而當使用js間接提交表單時,kindeditor的這個自動的動做沒有被觸發,因此

後臺獲得的是還未被粘貼內容的textarea的文本。

三、解決:最直接的想辦法是手動調一下這個自動粘貼的程序。搜索了一下發現已有人解決。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>

相關文章
相關標籤/搜索