1.原因分析
Onlyoffice的保存文件的机制是靠回调接口保存文件的。文件一但保存成功。再次以上一次的key和最新的文档url地址为参数打开编辑器时,编辑器服务根据key去找redis中去找缓存并进行验证判断文件的版本是否发生了变化,如果一样就从缓存中读取文档数据。否则提示文件版本发生变化的提示。
2.解决方案
知道了Onlyoffice编辑器的验证机制后就好解决问题了。
我们可以创建一张表用于管理文件的版本号。版本号的创建规则自己定。
思路:
编辑器每次回调,我们都在 文件的版本 表中判断一下文件是否存在,不存在创建一条记录,存在的话版本号加1.
再增加一个获取编辑器KEY的接口,接口逻辑:在表中找是否有对应的文档数据,如果有就在原来的版本号上加1.如果没有以1开始。
这样的话,又可以解决文件版本问题的提示又可以解决应该动态KEY后文档无法协同的问题。
3.代码
OnlyOfficeFile 表名,表结构如下:
这里要说明一下我这里的key的组成: type_id_VersionNo 例 FlowTask_00018de2895742fb8edba512db6f619c_1
回调接口代码:
/// <summary>
/// 回调接口 CallbackApiHandler 的摘要说明
/// </summary>
public class CallbackApiHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
//context.Response.AddHeader("Access-Control-Allow-Origin", "*");
//context.Response.AddHeader("Access-Control-Allow-Headers", " x-www-form-urlencoded, Content-Type,x-requested-with");
//context.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
string errorMsg = string.Empty;
string body = string.Empty;
var fileDataJson = string.Empty;
bool isSucceed = false;
string search1 = string.Empty;
string search2 = string.Empty;
string status = string.Empty;
var ip = CommonHelpLD.ServiceIp;
var model = new OnlyOfficeFileModel();
try
{
body = HttpContextHelper.GetRequestBody(context);
var result1 = new LawcaseTaskService().AddLog(string.Empty, string.Empty, "CallbackApi", body, string.Empty, string.Empty, "回调接口1", ip);
//LogHelper.WriteLog("回调接口1 开始 CallbackApiHandler 是否成功:" + isSucceed + " 接口信息:" + errorMsg + ",收到的请求参数" + body + ",fileDataJson:" + fileDataJson);
if (!string.IsNullOrEmpty(body))
{
var endIndex = body.IndexOf("fileDataJson");//, fileDataJson:
if (endIndex > 0)
{
body = body.Substring(0, endIndex - 15);
body = body.Trim().TrimEnd(',');
var result2 = new LawcaseTaskService().AddLog(string.Empty, string.Empty, "CallbackApi", body, string.Empty, string.Empty, "回调接口2", ip);
//LogHelper.WriteLog("回调接口2 开始 CallbackApiHandler 是否成功:" + isSucceed + " 接口信息:" + errorMsg + ",收到的请求参数" + body + ",fileDataJson:" + fileDataJson);
}
var fileData = new JavaScriptSerializer().Deserialize<CallbackApiReqModel>(body);
//var fileData = JsonConvert.DeserializeObject<CallbackApiReqModel>(body);
errorMsg = "try 0";
if (fileData != null && (fileData.status == 2 || fileData.status == 6))
{
status = fileData.status.ToString();
try
{
errorMsg += "try 1";
//fileData.Id = fileData.key.Contains("_") ? fileData.key.Substring(0, fileData.key.IndexOf("_")) : fileData.key;
if (fileData.key.Contains("_"))
{
var keys = fileData.key.Split('_');
if (keys.Length >= 3)
{
fileData.Id = string.Format("{0}_{1}", keys[0], keys[1]);
}
else
{
fileData.Id = keys[1];//FlowTask_8160b1f7efa64cdba7d4bd37e843d638
}
}
else
{
fileData.Id = fileData.key;
}
errorMsg += "try 2," + fileData.key;
var fileModel = FileHelper.GetFileObjModel(fileData.key);//(fileData.Id);
var sFilePath = FileHelper.GetFilePath(fileModel.FileType);
string sFileName = string.Format("{0}.docx", fileModel.Key);
var PATH_FOR_SAVE = sFilePath + "/" + sFileName; //文件的绝对路径
//if (File.Exists(PATH_FOR_SAVE))
//{
// File.Delete(PATH_FOR_SAVE);
// errorMsg += "try 1.1";
//}
search1 = fileModel.Key;
search2 = fileData.key;
model.FileKey = fileData.key;
model.Type = fileModel.FileType;
model.Name = sFileName;
model.DisplayName = sFileName;
model.TaskId = search1;
model.CreatedBy = "CallbackApi";
model.VersionNo = 1;
var model_o = OnlyOfficeFileService.GetModelByTaskId(model.TaskId, model.Type);
if (model_o != null)
{
model.VersionNo = model_o.VersionNo + 1;
}
var result3 = new LawcaseTaskService().AddLog(search1, search2, "CallbackApi", body, PATH_FOR_SAVE, "status:" + status, "回调接口3", ip);
var req = WebRequest.Create(fileData.url);
errorMsg += "try 2.1,PATH_FOR_SAVE:" + PATH_FOR_SAVE;
using (var stream = req.GetResponse().GetResponseStream())
{
errorMsg += "try 3";
using (var fs = File.Open(PATH_FOR_SAVE, FileMode.Create))
{
var buffer = new byte[4096];
int readed;
errorMsg += "try 4";
while ((readed = stream.Read(buffer, 0, 4096)) != 0)
{
fs.Write(buffer, 0, readed);
//errorMsg = "try 5";
}
}
}
isSucceed = true;
model.FilePath = PATH_FOR_SAVE.Replace(AppDomain.CurrentDomain.BaseDirectory, string.Empty);
errorMsg += " try 6";
try
{
if (fileModel.FileType.Equals("FlowTask"))
{
var result = new LawcaseTaskService().UpdateTaskStatus(fileModel.Key, 1);
errorMsg += " try 7 更新任务 修改文书任务为进行中...1,更新结果:" + result.Item1 + ",消息:" + result.Item2;
}
}
catch (Exception ex)
{
errorMsg += " try 7 更新任务 修改文书任务为进行中...1 异常:" + ex.Message;
}
errorMsg += " try 8";
}
catch (Exception ex)
{
isSucceed = false;
errorMsg += "异常2:" + ex.Message;
}
}
else
{
errorMsg += "try 66";
isSucceed = true;
}
fileDataJson = JsonConvert.SerializeObject(fileData);
}
else
{
isSucceed = true;
}
}
catch (Exception ex)
{
isSucceed = false;
errorMsg += "异常1:" + ex.Message;
}
var rspJosn = "{\"error\":0}";//返回保存成功
if (isSucceed)
{
OnlyOfficeFileService.SaveModel(model);
}
else
{
rspJosn = "{\"error\":1}";//返回保存失败
}
//LogHelper.WriteLog("回调接口4 结束 CallbackApiHandler 是否成功:" + isSucceed + " 接口信息:" + errorMsg + ",收到的请求参数" + body + ",fileDataJson:" + fileDataJson);
var result4 = new LawcaseTaskService().AddLog(search1, search2, "CallbackApi", body, rspJosn, "status:" + status, "回调接口4," + errorMsg, ip);
context.Response.Write(rspJosn);
}
public bool IsReusable
{
get
{
return false;
}
}
}
上面的代码中主要看这几句。找到后结合上下文去理解一下.
model.FileKey = fileData.key;
model.Type = fileModel.FileType;
model.Name = sFileName;
model.DisplayName = sFileName;
model.TaskId = search1;
model.CreatedBy = "CallbackApi";
model.VersionNo = 1;
var model_o = OnlyOfficeFileService.GetModelByTaskId(model.TaskId, model.Type);
if (model_o != null)
{
model.VersionNo = model_o.VersionNo + 1;
}
var result = new LawcaseTaskService().UpdateTaskStatus(fileModel.Key, 1);
这个问题在实际项目中已解决问题。