当前位置: 首页 > news >正文

PageOffice实现文档并发控制

问题背景

在B/S架构下的办公系统中,用户访问请求都是并发的,也就是说经常会出现同时N个用户对一个服务器页面发出请求,这就有可能出现同一个文档被多个用户同时打开进行编辑的情况,那么,保存时文件就可能出现互相覆盖的问题。为什么会出现互相覆盖呢?举个简单例子,例如A用户先访问页面打开了一个文档开始编辑,这时B用户访问相同的页面打开了同一个文档也开始编辑,B用户可能很快就完成了文档修改工作并且保存到服务器。随后A用户也完成了工作并保存文档到服务器。这时,服务器上的这个文档已经变成了A用户修改的版本,B用户的修改被A用户的保存操作覆盖从而消失了。

两种解决方案

  • 引入工作流模块。文档流转到哪个环节,就由哪个环节的用户去操作,其他用户无法打开此文档,或无法以编辑模式打开此文档。(互联网上有专门的工作流产品,因此本文不对此方案进行介绍。)
  • 采用锁机制实现文档并发控制。在服务器端对文档进行加锁,只有被锁的用户才能打开此文档进行编辑,其他用户无法打开此文档,或无法以编辑模式打开此文档。

PageOffice V5及以前的版本自带了文档并发控制功能,设置PageOfficeCtrl对象的TimeSlice属性就可以保证同一时间同一篇文档只能由一个人打开,但是此功能仅限于单体Web项目且部署在一台服务器上。由于现在越来越多的项目使用了微服务架构或集群部署,因此就需要开发人员实现自定义的文档并发控制功能。下面我们以一个最简单的文档并发控制方案为例,介绍一下实现自定义的文档并发控制功能的主要步骤:

  1. 数据库设计调整,增加锁状态字段。在文档记录表中增加一个Editor字段,用于记录当前文档是否正被某用户编辑。如果该字段为空,表示文档未被任何用户编辑;如果非空,则字段值应为当前编辑者的用户名。
  2. 打开文件之前发送检查请求。当用户尝试打开文档时,前端应首先向后端发送一个请求,检查文档的Editor字段。
    • 如果Editor字段为空,说明文档当前未被任何用户编辑,可以安全地允许当前用户打开文档,并将当前用户的用户名写入文档记录表中的Editor字段,以此标记文档当前处于被编辑状态。
    • 如果Editor字段非空,即已经有其他用户正在编辑文档,则向用户显示提示信息,告知文档正在被他人编辑,建议稍后再试,或者以只读预览模式打开文档。
  3. 用户完成文档编辑并关闭文档时,前端应当通过Ajax请求通知后端,后端需将文档记录表中对应的Editor字段清空,从而释放文档的编辑锁。

后端代码

后端验证文档编辑状态的接口(比如:detectCurrentEditor.jsp),代码如下:

String id = request.getParameter("id");
String editor = "";Class.forName("org.sqlite.JDBC");
String strUrl = "jdbc:sqlite:" + this.getServletContext().getRealPath("BingFa/BingFa.db");
Connection conn=DriverManager.getConnection(strUrl);
Statement stmt = conn.createStatement();		ResultSet	rs = stmt.executeQuery("select * from doc where id="+id);
if(rs.next()){editor = rs.getString("Editor");
}
rs.close();
stmt.close();
conn.close();response.setContentType("application/json");
out.print("{\"editor\":\""+ editor +"\"}"); //返回当前文档的编辑者

后端释放文档编辑锁的接口(比如:clearCurrentEditor.jsp),代码如下:

String id = request.getParameter("id");Class.forName("org.sqlite.JDBC");
String strUrl = "jdbc:sqlite:" + this.getServletContext().getRealPath("BingFa/BingFa.db");
Connection conn=DriverManager.getConnection(strUrl);
Statement stmt2 = conn.createStatement();
stmt2.executeUpdate("Update doc set Editor='' where id="+id); //清空文档的编辑者
stmt2.close();
conn.close();response.setContentType("application/json");
out.print("{\"msg\":\"ok\"}");

前端代码

打开文件之前发送ajax请求到后端接口(比如:detectCurrentEditor.jsp)验证,检查当前文档是否有用户正在编辑。

// 编辑文件
function editFile(id){var user = loginName; // 假设loginName为当前登录用户的用户名// 检查当前文档是否有用户正在编辑$.ajax({url: 'detectCurrentEditor.jsp?id=' + id, type: 'GET', dataType: 'json', success: function(data) {if(data.editor == user || data.editor == ''){POBrowser.openWindow('word.jsp?id='+id+'&user='+encodeURIComponent(user) , 'width=1200px;height=800px;');}else{alert('用户“'+data.editor+'”正在编辑此文档,请稍后重试,或点击“查看”只读打开。');}},error: function(xhr, status, error) {console.error('请求失败:', error);}});
}

 关闭文件时,通过PageOffice的OnBeforeBrowserClosed()事件函数,发送ajax请求到后端接口(比如:clearCurrentEditor.jsp),将文档的Editor字段清空,释放编辑锁。

// 通知服务器端,用户已停止编辑文档
function SendCloseMsg(){$.ajax({url: 'clearCurrentEditor.jsp?id=<%=id%>', type: 'GET', dataType: 'json', success: function(data) {console.log('请求成功:', data);},error: function(xhr, status, error) {console.error('请求失败:', error);}});
}function OnBeforeBrowserClosed() {// 此处可以执行窗口关闭前需要执行的业务逻辑代码if(pageofficectrl.IsDirty){if (confirm("提示:文档已被修改,是否继续关闭放弃保存 ?")) {SendCloseMsg();pageofficectrl.CloseWindow(true);//必须。否则窗口不会关闭。} }else{SendCloseMsg();pageofficectrl.CloseWindow(true);//必须。否则窗口不会关闭。}}

原文档:自定义文档并发控制 | PageOffice 开发者中心

http://www.lryc.cn/news/605712.html

相关文章:

  • 2025年人形机器人动捕技术研讨会将在本周四召开
  • JVM面试通关指南:内存区域、类加载器、双亲委派与GC算法全解析
  • 暑期算法训练.11
  • wpf之ControlTemplate
  • RabbitMQ 消费者确认 (Ack/Nack) (With Spring Boot)
  • HUD抬头显示器-杂散光测试设备 太阳光模拟器
  • FastGPT + Kymo AI生态创新平台,搭建企业智能化知识管理
  • TTS语音合成|GPT-SoVITS语音合成服务器部署,实现http访问
  • 自动驾驶控制算法——PID算法
  • Linux进程创建,终止与等待
  • 运作管理学习笔记1-运作管理基础
  • Docker 初学者需要了解的几个知识点 (五):建容器需要进一步了解的概念
  • 蓝牙 BR/EDR 与 BLE PHY
  • c# net6.0+ 安装中文智能提示
  • JSX语法
  • LPC2132GPIO
  • elk部署加日志收集
  • mac环境配置rust
  • CentOS 7 上使用 Docker 安装 Jenkins 完整教程
  • 【数据结构初阶】--二叉树选择题专辑
  • 佳维视工业显示器在除尘与过滤设备中的应用
  • 操作系统系统面试常问(内存、快表、相关知识)
  • 关于npm前端项目编译时栈溢出 Maximum call stack size exceeded的处理方案
  • 专业鼠标点击器,自定义间隔次数
  • NPM打包时,报reason: getaddrinfo ENOTFOUND registry.nlark.com
  • 从Excel到工时管理系统:企业如何选择更高效的工时记录工具?
  • Verilog实现RPC从机(配合AXI_Slave使用)
  • 金融专题|某跨境支付机构:以榫卯企业云平台 VPC 功能保障业务主体安全
  • 查询目前服务器所占的带宽的命令(上传和下载)
  • TTS语音合成|f5-tts语音合成服务器部署,实现http访问