需求大概是这个样子(项目架构为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
设置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('');
}
获取数据:
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;
}
}
下面是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
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;
}
}
}
取值用下面的代码:
webBrowser1.Document.GetElementById("content1").GetAttribute("value");//从webbrowser获取文档内容
主要代码大概就这些。
在实现功能的时候发现KindEditor有以下兼容性问题:
1:在webBrowser控件中无法粘贴剪切板中的图片(这个应该是webBrowser的问题,但是我改了内核版本没效果,不知道怎么解决)
2:在IE(包括webBrowser)中无法显示网络图片,看url是没问题的,但是图片不显示,火狐下面正常。