在WEB API项目中使用KindEditor富文本编辑器

需求大概是这个样子(项目架构为WEB API+WEB端+Winform端+Android端):

WEB端和Winform端使用KindEditor来编辑和查看文档内容,文档内容保存到数据库,插入的图片保存到API服务器。保存和上传图片的动作整合到

API中。Android端可以查看文档内容,不过不是我负责就不管了。

先研究API。有中文文档看起来很舒服,不过配套的DEMO太少,文档也不够详细。

http://kindeditor.net/doc.php

再找DEMO。

http://www.cnblogs.com/shaoming01/archive/2012/02/03/winformhtmleditor.html

然后开始往自己的项目里面加东西。

先把下载的压缩包解压加到项目里面,最好放在根目录,这样加引用的时候省事一点。

API:添加一个新控制器,用来上传图片。(其实就是把官方DEMO里面的upload_json.ashx拿过来)

代码里面高亮了一句,这个URL一定要是形如http://abc.com/123.jpg这样可以直接访问的URL,否则编辑器没法读取。

然后服务器上自己建立一下文件夹。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Collections;
using System.Configuration;
using System.Web;
using System.IO;
using System.Globalization;
using LitJson;

namespace DocManagerAPI.Controllers
{
    public class DocImageController : ApiController
    {
        [FormAuth]
        [AcceptVerbs("GET", "POST")]
        [WebApiTracker]
        public void upLoadDocImage()
        {//上传文档内容中的文件
            String aspxUrl = HttpContext.Current.Request.Path.Substring(0, HttpContext.Current.Request.Path.LastIndexOf("/") + 1);

            //文件保存目录路径
            String savePath = "/DocImage/";

            //文件保存目录URL
            String saveUrl = System.Configuration.ConfigurationManager.AppSettings["serverUrl"] + "DocImage/";

            //定义允许上传的文件扩展名
            Hashtable extTable = new Hashtable();
            extTable.Add("image", "gif,jpg,jpeg,png,bmp");
            //extTable.Add("flash", "swf,flv");
            //extTable.Add("media", "swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb");
            //extTable.Add("file", "doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2");

            //最大文件大小
            int maxSize = 1000000;
            //this.ControllerContext =HttpContext.Current.Session;

            HttpPostedFile imgFile = HttpContext.Current.Request.Files["imgFile"];
            if (imgFile == null)
            {
                showError("请选择文件。");
            }

            String dirPath = HttpContext.Current.Server.MapPath(savePath);
            if (!Directory.Exists(dirPath))
            {
                showError("上传目录不存在。");
            }

            String dirName = HttpContext.Current.Request.QueryString["dir"];
            if (String.IsNullOrEmpty(dirName))
            {
                dirName = "image";
            }
            if (!extTable.ContainsKey(dirName))
            {
                showError("目录名不正确。");
            }

            String fileName = imgFile.FileName;
            String fileExt = Path.GetExtension(fileName).ToLower();

            if (imgFile.InputStream == null || imgFile.InputStream.Length > maxSize)
            {
                showError("上传文件大小超过限制。");
            }

            if (String.IsNullOrEmpty(fileExt) || Array.IndexOf(((String)extTable[dirName]).Split(','), fileExt.Substring(1).ToLower()) == -1)
            {
                showError("上传文件扩展名是不允许的扩展名。\n只允许" + ((String)extTable[dirName]) + "格式。");
            }

            //创建文件夹
            dirPath += dirName + "/";
            saveUrl += dirName + "/";
            if (!Directory.Exists(dirPath))
            {
                Directory.CreateDirectory(dirPath);
            }
            String ymd = DateTime.Now.ToString("yyyyMMdd", DateTimeFormatInfo.InvariantInfo);
            dirPath += ymd + "/";
            saveUrl += ymd + "/";
            if (!Directory.Exists(dirPath))
            {
                Directory.CreateDirectory(dirPath);
            }

            String newFileName = DateTime.Now.ToString("yyyyMMddHHmmss_ffff", DateTimeFormatInfo.InvariantInfo) + fileExt;
            String filePath = dirPath + newFileName;

            imgFile.SaveAs(filePath);

            String fileUrl = saveUrl + newFileName;

            Hashtable hash = new Hashtable();
            hash["error"] = 0;
            hash["url"] = fileUrl;
            HttpContext.Current.Response.AddHeader("Content-Type", "text/html; charset=UTF-8");
            HttpContext.Current.Response.Write(JsonMapper.ToJson(hash));
            HttpContext.Current.Response.End();
        }


        private void showError(string message)
        {
            Hashtable hash = new Hashtable();
            hash["error"] = 1;
            hash["message"] = message;
            HttpContext.Current.Response.AddHeader("Content-Type", "text/html; charset=UTF-8");
            HttpContext.Current.Response.Write(JsonMapper.ToJson(hash));
            HttpContext.Current.Response.End();
        }
    }
}
WEB端:把官方的demo.aspx改一改就能用了。
重点关注的几个地方:

ValidateRequest="false"
不加会报错。

var s = System.Web.HttpContext.Current.Request.Cookies;
这一段是身份验证用的。因为上传图片的API需要验证身份(我的API里是要求提供SessionID的cookie),在WEB项目中请求这个界面是没问题的,系统会自动把Cookie带过去,用Winform请求的话就会出现身份验证失败的问题,所以要加上这么一段。

function bindData(data)
初始化页面的时候加载数据用。

uploadJson: '/api/DocImage/upLoadDocImage',//处理上传图片的程序路径
这个参数指定处理上传图片请求的程序路径,就是之前API的路径。

textarea id="content1"
记下这个ID,之后会用到。

<%@ Page Language="C#" AutoEventWireup="true" ValidateRequest="false" %>







    
    KindEditor ASP.NET
    
    
    
    
    
    


    


因为WEB端已经有了管理文档的界面,所以在之前的页面中用iframe加载这个aspx。

设置iframe的大小:

        function iFrameHeight() {
            //文档内容 大小自适应
            var ifm = document.getElementById("iframepage");
            var subWeb = document.frames ? document.frames["iframepage"].document : ifm.contentDocument;
            if (ifm != null && subWeb != null) {
                ifm.height = subWeb.body.scrollHeight;
                ifm.width = subWeb.body.scrollWidth;
            }
        }

初始化页面:

(doctext是API中获取到的文档内容,由于是公司项目就不贴全部代码了)

                if ($('#iframepage').attr('src') == null)
                {
                    $('#iframepage').attr('src', '../KindEditor/asp.net/demo.aspx');
                    document.getElementById('iframepage').onload = function () {
                        if (doctext != null)//第一次加载页面是在加载完成后刷新数据
                            document.getElementById("iframepage").contentWindow.bindData(doctext);
                        else
                            document.getElementById("iframepage").contentWindow.bindData('');
                    };
                }
                else
                {//如果页面已经加载则刷新数据
                    if (doctext != null)
                        document.getElementById("iframepage").contentWindow.bindData(doctext);
                    else
                        document.getElementById("iframepage").contentWindow.bindData('');
                }

WEB端的初始化分两种,一种是第一次打开,要指定iframe的src属性从而初始化页面,因为加载页面要花点时间,所以在onload事件里面写数据。第二种是页面已经加载了,直接写数据。

获取数据:

        function getKindValue()
        {//获取iframe中kindeditor控件的值
            var ofrm1 = document.getElementById("iframepage").document;    
            if (ofrm1==undefined)
            {
                ofrm1 = document.getElementById("iframepage").contentWindow.document;
                var ff = ofrm1.getElementById("content1").value;
                return ff;
            }
            else
            {
                var ie = document.frames["iframepage"].document.getElementById("content1").value;
                return ie;
            } 
        }

WEB端基本就这些,保存文档的时候把编辑器里获取到的字符串存到数据库里就行了,展示的时候再取出来。

下面是Winform端。

首先拖一个WebBrowser到窗体上,然后设置以下参数:

窗体的class上面加上

    [ComVisible(true)]
否则会报错。

        [DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool InternetSetCookie(string lpszUrlName, string lbszCookieName, string lpszCookieData);//设置webbrowser的cookie

因为要做身份验证,所以要使用这个方法设置cookie。

                InternetSetCookie(url, "ASP.NET_SessionId", PublicCode.userinfo.cookie.Substring(25, 24));//设置cookie
                webBrowser1.Navigate(url);
url是web项目中那个demo.aspx的url。这样在winform项目里面就不需要引用kindeditor的文件了。

                if(doc.F_DocText!="")
                {//等待页面加载完成后绑定文档内容
                    //因为这个操作比较耗时,所以只在确实有内容的时候进行
                    while (true)
                    {
                        Thread.Sleep(50);
                        Application.DoEvents();
                        if (webBrowser1.Document.GetElementById("content1") != null)
                        {
                            object[] objs = new object[1];
                            objs[0] = doc.F_DocText;
                            webBrowser1.Document.InvokeScript("bindData", objs);
                            break;
                        }
                    }
                }

上面的代码是加载数据用的,因为webbrowser自带的DocumentCompleted事件比较坑(触发这个事件的时候页面其实没有加载完,多半还在执行JS),所以只能用这个比较笨的办法,循环判断控件是否已经初始化。代码中的doc.F_DocText是文档内容。

取值用下面的代码:

webBrowser1.Document.GetElementById("content1").GetAttribute("value");//从webbrowser获取文档内容
主要代码大概就这些。


在实现功能的时候发现KindEditor有以下兼容性问题:

1:在webBrowser控件中无法粘贴剪切板中的图片(这个应该是webBrowser的问题,但是我改了内核版本没效果,不知道怎么解决)

2:在IE(包括webBrowser)中无法显示网络图片,看url是没问题的,但是图片不显示,火狐下面正常。

你可能感兴趣的:(在WEB API项目中使用KindEditor富文本编辑器)