目前百度的umeditor已经停止维护了,net版本的分支源码包也停留在了net farmework4左右的版本,对于想要集成这款富文本编辑器到net5平台,具有较大难度,主要体现在以下几个方面:
umeditor源码需要改造,需要具有熟练掌握js技术、调试技术
net5相对于net framework部分类库更新或者移除了,需要能够看懂提供的源码的具体意义后进行修改。需要掌握c#编程。
下面,我来说说怎么去集成。
一、下载umeditor源码
我提供了百度网盘链接:http://t.zoukankan.com/feigao-p-4608844.html,从这个链接拉倒最下面,感谢这位作者的无私奉献。方便大家下载。
二、新建一个html页面,方便调用ajax访问后端接口的那种,有开发经验的朋友都懂,搞一套基础环境出来!然后在html页面应用下面截图中的文件,我同时集成了layui框架,不过不影响!
然后打开页面,就会出现你想要的富文本编辑器,如下:
当你内心很兴奋的时候,可以说一声,好简单啊。。。😄
但是当你打开f12浏览器调试模式的时候,你就会一脸懵逼,因为提示你:“后台配置项返回格式出错,上传功能将不能正常使用!”,此时你除了可以在富文本上输入文本之外,其他都没用😭,具体如下图:
这将是你面对的第一个棘手的问题:“后台配置项返回格式出错,上传功能将不能正常使用!”
下面我来说明下原因:原来想要使用umeditor,你得首先在web api写个接口,让编辑器的前端能够获取到一大批配置文件。下面,我来写下步骤和源码。
2.1、把源码中的config.json复制一份,放到后端项目,和appsettings.json在同级目录,如下图:
2.2 写个接口,让之前新建的h5页面可以通过ajax调用到。我写成了一个通用接口,不要标记[HttpPost]或者[HttpGet]特性,这样get请求和post请求都可以使用。代码如下:
public void TestApi()
{
var queryParam = HttpContext.Request.QueryString;
string queryData = queryParam.Value.Remove(0,1);
var targetWord = queryData.Split("&")[0].Split("=")[1];
Handler action = null;
switch (targetWord)
{
case "config":
action = new ConfigHandler(HttpContext);
action.Process();
break;
//case "uploadimage":
//action = new UploadHandler(HttpContext, new UploadConfig()
//{
// AllowExtensions = Config.GetStringList("imageAllowFiles"),
//PathFormat = Config.GetString("imagePathFormat"),
// SizeLimit = Config.GetInt("imageMaxSize"),
// UploadFieldName = Config.GetString("imageFieldName")
// });
// action.Process();
//break;
#region 下面的是其他类型的每天文件,按需添加
//case "uploadscrawl":
// action = new UploadHandler(context, new UploadConfig()
// {
// AllowExtensions = new string[] { ".png" },
// PathFormat = Config.GetString("scrawlPathFormat"),
// SizeLimit = Config.GetInt("scrawlMaxSize"),
// UploadFieldName = Config.GetString("scrawlFieldName"),
// Base64 = true,
// Base64Filename = "scrawl.png"
// });
// break;
//case "uploadvideo":
// action = new UploadHandler(context, new UploadConfig()
// {
// AllowExtensions = Config.GetStringList("videoAllowFiles"),
// PathFormat = Config.GetString("videoPathFormat"),
// SizeLimit = Config.GetInt("videoMaxSize"),
// UploadFieldName = Config.GetString("videoFieldName")
// });
// break;
//case "uploadfile":
// action = new UploadHandler(context, new UploadConfig()
// {
// AllowExtensions = Config.GetStringList("fileAllowFiles"),
// PathFormat = Config.GetString("filePathFormat"),
// SizeLimit = Config.GetInt("fileMaxSize"),
// UploadFieldName = Config.GetString("fileFieldName")
// });
// break;
//case "listimage":
// action = new ListFileManager(context, Config.GetString("imageManagerListPath"), Config.GetStringList("imageManagerAllowFiles"));
// break;
//case "listfile":
// action = new ListFileManager(context, Config.GetString("fileManagerListPath"), Config.GetStringList("fileManagerAllowFiles"));
// break;
//case "catchimage":
// action = new CrawlerHandler(context);
// break;
//default:
// action = new NotSupportedHandler(context);
// break;
#endregion
}
}
/// <summary>
/// Config 的摘要说明
/// </summary>
public static class Config
{
private static bool noCache = true;
private static JObject BuildItems()
{
var json = File.ReadAllText(Environment.CurrentDirectory + "/" + "config.json");
return JObject.Parse(json);
}
public static JObject Items
{
get
{
if (noCache || _Items == null)
{
_Items = BuildItems();
}
return _Items;
}
}
private static JObject _Items;
public static T GetValue<T>(string key)
{
return Items[key].Value<T>();
}
public static string[] GetStringList(string key)
{
return Items[key].Select(x => x.Value<string>()).ToArray();
}
public static string GetString(string key)
{
return GetValue<string>(key);
}
public static int GetInt(string key)
{
return GetValue<int>(key);
}
}
#region 配置项请求处理模块
/// <summary>
/// Config 的摘要说明
/// </summary>
public class ConfigHandler : Handler
{
public ConfigHandler(HttpContext context) : base(context) { }
public override void Process()
{
WriteJson(Config.Items);
}
}
/// <summary>
/// Handler 的摘要说明
/// </summary>
public abstract class Handler
{
public Handler(HttpContext context)
{
this.Request = context.Request;
this.Response = context.Response;
this.Context = context;
//this.Server = context.Server;
}
public abstract void Process();
protected void WriteJson(object response)
{
var queryParam = Request.QueryString;
string queryData = queryParam.Value.Remove(0, 1);
var targetList = queryData.Split("&").ToList();
string jsonpCallback = "";
foreach (var target in targetList)
{
if (target.Split("=")[0] == "callback")
{
jsonpCallback = target.Split("=")[1];
}
}
string json = JsonConvert.SerializeObject(response);
if (string.IsNullOrWhiteSpace(jsonpCallback))
{
Response.Headers.Add("Content-Type", "text/plain");
Response.WriteAsync(json);
}
else
{
Response.Headers.Add("Content-Type", "application/javascript");
Response.WriteAsync(string.Format("{0}({1});", jsonpCallback, json));
}
}
public HttpRequest Request { get; private set; }
public HttpResponse Response { get; private set; }
public HttpContext Context { get; private set; }
//public HttpServerUtility Server { get; private set; }
}
#endregion
然后需要在ueditor.config.js修改下请求地址 ,这个每个人可以自己配置。
等这一步做完,你会发现上面的问题就解决了。但是又会出现一个新的问题,也就是上传图片、视频等文件失败。如下:
2.3下面说一下这个问题的解决方案:
首先,将上面控制器中的部分代码取消注释:
2.4、然后修改下,修改图片的保存路径和http链接路径。
2.5、图片文件上传后端代码如下:你需要在保存路径那边自己做点修改。
#region 上传图片配置
/// <summary>
/// UploadHandler 的摘要说明
/// </summary>
public class UploadHandler : Handler
{
public UploadConfig UploadConfig { get; private set; }
public UploadResult Result { get; private set; }
public UploadHandler(HttpContext context, UploadConfig config)
: base(context)
{
this.UploadConfig = config;
this.Result = new UploadResult() { State = UploadState.Unknown };
}
public override void Process()
{
byte[] uploadFileBytes = null;
string uploadFileName = null;
if (UploadConfig.Base64)
{
uploadFileName = UploadConfig.Base64Filename;
uploadFileBytes = Convert.FromBase64String(Request.Form[UploadConfig.UploadFieldName]);
Result.OriginFileName = uploadFileName;
var savePath = PathFormatter.Format(uploadFileName, UploadConfig.PathFormat);
var localPath = Environment.CurrentDirectory + "/wwwroot" + savePath;
try
{
if (!Directory.Exists(Path.GetDirectoryName(localPath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(localPath));
}
File.WriteAllBytes(localPath, uploadFileBytes);
Result.Url = savePath;
Result.State = UploadState.Success;
}
catch (Exception e)
{
Result.State = UploadState.FileAccessError;
Result.ErrorMessage = e.Message;
}
finally
{
WriteResult();
}
}
else
{
var file = Request.Form.Files[UploadConfig.UploadFieldName];
StreamReader reader = new StreamReader(file.OpenReadStream());
string content = reader.ReadToEnd();
uploadFileName = file.FileName;
var savePath = PathFormatter.Format(uploadFileName, UploadConfig.PathFormat);
var localPath = Environment.CurrentDirectory + "/wwwroot" + savePath;
if (!CheckFileType(uploadFileName))
{
Result.State = UploadState.TypeNotAllow;
WriteResult();
return;
}
if (!CheckFileSize(file.Length))
{
Result.State = UploadState.SizeLimitExceed;
WriteResult();
return;
}
try
{
//查看该物理路径是否存在,如果不存在则新建对应文件夹
if (!Directory.Exists(Path.GetDirectoryName(localPath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(localPath));
}
//File.WriteAllBytes(localPath, uploadFileBytes);
using (FileStream fs = System.IO.File.Create(localPath))
{
// 复制文件
file.CopyTo(fs);
// 清空缓冲区数据
fs.Flush();
}
Result.Url = savePath;
Result.State = UploadState.Success;
}
catch (Exception e)
{
Result.State = UploadState.FileAccessError;
Result.ErrorMessage = e.Message;
}
finally
{
WriteResult();
}
}
}
private void WriteResult()
{
this.WriteJson(new
{
state = GetStateMessage(Result.State),
url = Result.Url,
title = Result.OriginFileName,
original = Result.OriginFileName,
error = Result.ErrorMessage
});
}
private string GetStateMessage(UploadState state)
{
switch (state)
{
case UploadState.Success:
return "SUCCESS";
case UploadState.FileAccessError:
return "文件访问出错,请检查写入权限";
case UploadState.SizeLimitExceed:
return "文件大小超出服务器限制";
case UploadState.TypeNotAllow:
return "不允许的文件格式";
case UploadState.NetworkError:
return "网络错误";
}
return "未知错误";
}
private bool CheckFileType(string filename)
{
var fileExtension = Path.GetExtension(filename).ToLower();
return UploadConfig.AllowExtensions.Select(x => x.ToLower()).Contains(fileExtension);
}
private bool CheckFileSize(long size)
{
return size < UploadConfig.SizeLimit;
}
}
public class UploadConfig
{
/// <summary>
/// 文件命名规则
/// </summary>
public string PathFormat { get; set; }
/// <summary>
/// 上传表单域名称
/// </summary>
public string UploadFieldName { get; set; }
/// <summary>
/// 上传大小限制
/// </summary>
public int SizeLimit { get; set; }
/// <summary>
/// 上传允许的文件格式
/// </summary>
public string[] AllowExtensions { get; set; }
/// <summary>
/// 文件是否以 Base64 的形式上传
/// </summary>
public bool Base64 { get; set; }
/// <summary>
/// Base64 字符串所表示的文件名
/// </summary>
public string Base64Filename { get; set; }
}
public class UploadResult
{
public UploadState State { get; set; }
public string Url { get; set; }
public string OriginFileName { get; set; }
public string ErrorMessage { get; set; }
}
public enum UploadState
{
Success = 0,
SizeLimitExceed = -1,
TypeNotAllow = -2,
FileAccessError = -3,
NetworkError = -4,
Unknown = 1,
}
#endregion
/// <summary>
/// PathFormater 的摘要说明
/// </summary>
public static class PathFormatter
{
public static string Format(string originFileName, string pathFormat)
{
if (String.IsNullOrWhiteSpace(pathFormat))
{
pathFormat = "{filename}{rand:6}";
}
var invalidPattern = new Regex(@"[\\\/\:\*\?\042\<\>\|]");
originFileName = invalidPattern.Replace(originFileName, "");
string extension = Path.GetExtension(originFileName);
string filename = Path.GetFileNameWithoutExtension(originFileName);
pathFormat = pathFormat.Replace("{filename}", filename);
pathFormat = new Regex(@"\{rand(\:?)(\d+)\}", RegexOptions.Compiled).Replace(pathFormat, new MatchEvaluator(delegate (Match match)
{
var digit = 6;
if (match.Groups.Count > 2)
{
digit = Convert.ToInt32(match.Groups[2].Value);
}
var rand = new Random();
return rand.Next((int)Math.Pow(10, digit), (int)Math.Pow(10, digit + 1)).ToString();
}));
pathFormat = pathFormat.Replace("{time}", DateTime.Now.Ticks.ToString());
pathFormat = pathFormat.Replace("{yyyy}", DateTime.Now.Year.ToString());
pathFormat = pathFormat.Replace("{yy}", (DateTime.Now.Year % 100).ToString("D2"));
pathFormat = pathFormat.Replace("{mm}", DateTime.Now.Month.ToString("D2"));
pathFormat = pathFormat.Replace("{dd}", DateTime.Now.Day.ToString("D2"));
pathFormat = pathFormat.Replace("{hh}", DateTime.Now.Hour.ToString("D2"));
pathFormat = pathFormat.Replace("{ii}", DateTime.Now.Minute.ToString("D2"));
pathFormat = pathFormat.Replace("{ss}", DateTime.Now.Second.ToString("D2"));
return pathFormat + extension;
}
}
这样,百度富文本编辑器基本上图文操作就搞定了。如果还有不清楚的,可以加我微信:1057359832