服务端WORD文件模板书签替换-word书签替换内容

文章最后提供源码下载地址
市面上处理文字的的办公软件有很多,包括WPS、MSOffice、永中OFFICE , 当然还有开源的openoffice、liboffice等 。我们在项目开发过程中经常会遇到预览word文件 , 数据库中数据自动填充word模板等需求 。现在能够满足以上需求的技术有很多 , 服务端可通过POIaspose等处理,也可通过客户端调用OFFICE组件处理,本人曾经在这方便做了很多测试,最终发现兼容性最好的、接口对JAVA程序员最友好的就属永中OFFICE,因为它基本就是JAVA实现的,使用起来非常方便 。
我的测试环境使用的是永中2016版本,它运行要求JRE1.6,且我发现它应该是对JRE进行过重构,按永中SDK要求编写代码通过自ORACAL官网下载的jdk1.6编译后运行是失败的,现在都2021年了 , 我们的项目绝大多数都JDK1.8以上版本了,那么怎么让SDK兼容我们的项目呢?怎么实现标题中提到的两个需求呢?下面我说说我的处理方法吧:
1、下载永中软件并安装(官网下载即可)
2、安装后打开安装路径可以看到如下图

服务端WORD文件模板书签替换-word书签替换内容

永中软件安装目录
JRE:即永中软件的运行环境
Yozo_Office.jar: 即永中为开发者提供的SDK,可以将jar导入到工程中
3、编写WORD文件处理服务组件
处理word文件的代码片段,详细代码请在文后下载源码查阅 /*** 将word文件转换为对应格式的文件的字节数组* @param type 将word文件转换成的文件格式 pdf、htmlofdtxtxml* @return* @throws IOException*/ public byte[]convertFile(String type) throws IOException {int typePdf = FileConstants.TYPE_PDF;if("html".equals(type.toLowerCase())) {//此功能转换后乱码,后期可采用 this.workbook.saveAs("D:/2.html"); 方式存储html后,将字节返回typePdf= FileConstants.FILETYPE_HTML;}else if("ofd".equals(type.toLowerCase())) {typePdf= FileConstants.TYPE_OFD; // 这个是不成功的,应该是版本太低}else if("txt".equals(type.toLowerCase())) {typePdf = FileConstants.TYPE_TXT;}else if("xml".equals(type.toLowerCase())) {typePdf = FileConstants.FILETYPE_XML;}else if("doc".equals(type.toLowerCase())||"xls".equals(type.toLowerCase())||"ppt".equals(type.toLowerCase())) {typePdf = FileConstants.TYPE_MS;}else if("docx".equals(type.toLowerCase())||"xlsx".equals(type.toLowerCase())||"pptx".equals(type.toLowerCase())) {typePdf = FileConstants.TYPE_MS_EX;}return this.workbooks.getWorkbookAsByteArray(workbook, typePdf); }/*** 替换word模板中的书签* @param jsonObject 数据内容 {“bookmarkname”:”test“}*/ public void replaceBookMark(JSONObject jsonObject) {BookMarks bookMarks = this.document.getBookMarks();BookMark[] allBookmarks = bookMarks.getAllBookmarks();for(BookMark bookMark:allBookmarks){String name = bookMark.getName();TextRange range = bookMark.getRange();//if(name!=null)name=name.replace("PO_","");String valuehttps://www.itzhengshu.com/wps/= "";Object o = jsonObject.get(name);if(o!=null){value=https://www.itzhengshu.com/wps/jsonObject.get(name).toString();}try {range.insertText(value);}catch (Exception e){range.insertText(value);}} }/*** 导出数据成excel文件* @param jsonObject 数据内容 {“bookmarkname”:”test“}*/public byte[] exportData2File(JSONArray taskArray,int allrow) {}
【服务端WORD文件模板书签替换-word书签替换内容】4、(重点)解决word文件处理组件与我们的项目文件交互问题
本人通过SOCKET即时通讯服务解决数据交互问题
/** * 文件传输Server端
* 功能说明:* @Author 空中智囊 * @Date 2016年09月01日 * @version 1.0 */public class SocketService extends ServerSocket {private static final int SERVER_PORT = 8899; // 服务端端口private WordUtil wordUtil=null;public SocketService() throws Exception {super(SERVER_PORT);this.wordUtil=new WordUtil();}/*** 使用线程处理每个客户端传输的文件* @throws Exception*/public void load() throws Exception {System.out.println("服务端启动,监听端口为:" SERVER_PORT);while (true) {// server尝试接收其他Socket的连接请求,server的accept方法是阻塞式的Socket socket = this.accept();socket.setSoTimeout(1200000);/*** 我们的服务端处理客户端的连接请求是同步进行的,每次接收到来自客户端的连接请求后,* 都要先跟当前的客户端通信完之后才能再处理下一个连接请求 。这在并发比较多的情况下会严重影响程序的性能,* 为此,我们可以把它改为如下这种异步处理与客户端通信的方式*/// 每接收到一个Socket就建立一个新的线程来处理它new Thread(new Task(socket,wordUtil)).start();}}/*** 入口* @param args*/public static void main(String[] args) {try {SocketService server = new SocketService(); // 启动服务端server.load();} catch (Exception e) {e.printStackTrace();}}}/** * 处理客户端传输过来的文件线程类 */public class Task implements Runnable {@Overridepublic void run() {System.out.println("===客户端连接成功=====");System.out.println("****************************************************************");SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");/*** 转换要求的格式*/try {/********************************读取文件信息********************************/dis = new DataInputStream(socket.getInputStream());// 文件名和长度String fileName = dis.readUTF();//1、文件名字long fileLength = dis.readLong();//2、长度String toext = dis.readUTF();//3、扩展名String taskType=dis.readUTF();//4、文件操作类型System.out.println("针对文件的操作类型=====" taskType);String valueObject=dis.readUTF();//5、替换书签的值System.out.println(format.format(new Date()) ":开始接收文件");ByteArrayOutputStream bos = new ByteArrayOutputStream((int)fileLength);byte[] bytes = new byte[1024];int length = 0;while((length = dis.read(bytes, 0, bytes.length)) != -1) {bos.write(bytes, 0, length);}byte[] filebytes = bos.toByteArray();System.out.println("原始文件大小=====" fileLength ",实际接收文件大小=" filebytes.length);/********************************读取文件信息结束********************************/dos = new DataOutputStream(socket.getOutputStream());/********************************校验文件信息********************************/boolean process=true;if(fileLength>0){}else{dos.writeUTF("error");dos.flush();dos.writeUTF("文件没有任何内容,请重新传送");dos.flush();process=false;}if(filebytes.length!=fileLength){dos.writeUTF("error");dos.flush();dos.writeUTF("接受文件与实际文件大小不符合,请重新传送文件");dos.flush();process=false;}/********************************校验文件信息结束********************************//********************************处理文件********************************/if(process){byte[] fileBytes=null;this.wordUtil.openFile(filebytes,fileName);//打开院文件//workbook =workbooks.createWorkbookFromByteArray(filebytes,fileName);String lowerExt = toext.toLowerCase();if("convertFile".equals(taskType)){System.out.println("开始将文件[" fileName "]转换成====" lowerExt);fileBytes=this.wordUtil.convertFile(lowerExt);System.out.println(format.format(new Date()) ":转换" toext "完成");}else if("replaceBookMark".equals(taskType)){System.out.println("开始将文件[" fileName "]书签进行替换====");JSONObject jsonObject = JSONObject.fromObject(valueObject);this.wordUtil.replaceBookMark(jsonObject);fileBytes = this.wordUtil.convertFile(lowerExt);System.out.println("===============替换书签完成============");}else if("exportTask".equals(taskType)) {//处理业务数据 导出任务数据System.out.println("开始导出业务数据====" valueObject);ServiceUtil serviceUtil = new ServiceUtil(this.wordUtil);JSONObject jsonObject = JSONObject.fromObject(valueObject);fileBytes = serviceUtil.exportData2File(jsonObject.getJSONArray("datalist"), jsonObject.getInt("size"));System.out.println("===============导出业务数据完成============");}/********************************处理文件结束********************************/if(fileBytes==null){dos.writeUTF("error");dos.flush();dos.writeUTF("处理文件过程中错误");dos.flush();process=false;}/********************************返回处理过的文件********************************/if(process){dos.writeUTF("info");//文件处理完成,将信息返回到客户端dos.flush();int fileBytelength = fileBytes.length;//转换后的文件长度System.out.println(format.format(new Date()) ":======== 服务端开始发送文件流,文件大?。? getFormatFileSize(fileBytelength) ") ========");dos.writeLong(fileBytelength);dos.flush();dos.write(fileBytes, 0, fileBytelength);//将文件一起写入到输出流发送dos.flush();System.out.println(format.format(new Date()) ":======== 发送文件流成功 ========");}/********************************返回处理过的文件完成********************************/}} catch (Exception e) {String error = e.toString();System.out.println("error===================" error);StackTraceElement[] stackTrace = e.getStackTrace();for(StackTraceElement s:stackTrace){int lineNumber = s.getLineNumber();String methodName = s.getMethodName();String className = s.getClassName();String filename = s.getFileName();System.out.print("err:" filename "" className "" methodName "" lineNumber);System.out.println("");}try {dos.writeUTF("error");dos.flush();dos.writeUTF("处理文件过程中错误==" e.toString());dos.flush();}catch (Exception ex){String exrror =ex.toString();System.out.println("返回数据处理错误信息===================" exrror);}}finally {System.out.println("关闭资源");try {if(wordUtil!=null)wordUtil.close();socket.close();} catch (Exception e) {String error = e.toString();System.out.println(error);e.printStackTrace();}System.out.println("****************************************************************");}}/** * 文件传输Clinet端
* 功能说明: * @Author 空中智囊 * @Date 2016年09月01日 * @version 1.0 */public class SocketClient extends Socket {public static final Logger LOGGER = LoggerFactory.getLogger(SocketClient.class);private static final String SERVER_IP = "127.0.0.1"; // word文件组件处理服务IP地址private static final int SERVER_PORT = 8899; // word文件组件处理服务端口private int soTimeout = 60000; // 服务链接超时时间 60sprivate Socket client = this;private FileInputStream fis;private DataOutputStream dos;private DataInputStream dis;private FileOutputStream fos;public SocketClient(String listenip, int listenport) throws Exception {super(listenip, listenport);this.setSoTimeout(this.soTimeout);LOGGER.info("Cliect[port:"this.client.getLocalPort()"] 成功连接服务端");}public SocketClient() throws Exception {super(SERVER_IP, SERVER_PORT);this.setSoTimeout(this.soTimeout);LOGGER.info("Cliect[port:"this.client.getLocalPort()"] 成功连接服务端");}public SocketClient(String listenip, int listenport, int soTimeout) throws Exception {super(listenip, listenport);this.setSoTimeout(soTimeout);LOGGER.info("Cliect[port:"this.client.getLocalPort()"] 成功连接服务端");}/*** 处理word文件* @param srcRealPath模板word文件路径绝对地址* @param descRealPath处理后的文件存放地址绝对路径* @param taskType处理文件的类型 convertFile/replaceBookMark/exportTask* @param jsonObject传给服务端的数据对象,这个参数可根据服务端需求进行调整* @return处理结果*/public JSONObject processOffice(String srcRealPath, String descRealPath, String taskType, JSONObject jsonObject) {JSONObject rtnObject = new JSONObject();String code = "200";String message = "";try {File file = new File(srcRealPath);if (!file.exists() || !file.canWrite()) {code = "200";message = "文件不存在,或已被占用";rtnObject.element("code", code);rtnObject.element("message", message);JSONObject var41 = rtnObject;return var41;}LOGGER.info(srcRealPath"===>"descRealPath);if (file.exists() && file.canWrite()) {String filename = file.getName();this.fis = new FileInputStream(file);this.dos = new DataOutputStream(this.client.getOutputStream());this.dos.writeUTF(filename);//文件名字this.dos.flush();this.dos.writeLong(file.length());//文件长度this.dos.flush();String ext = descRealPath.substring(descRealPath.lastIndexOf(".")1, descRealPath.length());this.dos.writeUTF(ext);//源文件后缀名字this.dos.flush();this.dos.writeUTF(taskType);//任务类型this.dos.flush();if (YOZOOfficeUtil.PROCESS_TYPE_CONVERTFILE.equals(taskType)) {this.dos.writeUTF(jsonObject.toString());this.dos.flush();}LOGGER.info("======== 开始向服务端传送源文件"srcRealPath" ========");byte[] bytes = new byte[1024];long progress = 0L;int length;while((length = this.fis.read(bytes, 0, bytes.length)) != -1) {this.dos.write(bytes, 0, length);this.dos.flush();progress= (long)length;LOGGER.info("| "100L * progress / file.length()"% |");}LOGGER.info("======== 文件传输成功 ("file.length() / 1048576L")M========");this.client.shutdownOutput();LOGGER.info("======== 开始转换"ext" ========");InputStream inputStream = this.client.getInputStream();this.dis = new DataInputStream(inputStream);String result = this.dis.readUTF();if ("error".equals(result)) {String reason = this.dis.readUTF();LOGGER.info(reason);code = "500";message = reason;} else if ("info".equals(result)) {long l = this.dis.readLong();LOGGER.info("======== 转换"ext"完成,文件大?。?l / 1048576L")M ========");LOGGER.info("======== 开始接受"ext" ========");File newFile = new File(descRealPath);if (newFile.exists()) {newFile.delete();}this.fos = new FileOutputStream(newFile);progress = 0L;bytes = new byte[1048576];while((length = this.dis.read(bytes, 0, bytes.length)) != -1) {this.fos.write(bytes, 0, length);this.fos.flush();}LOGGER.info("======== 接受"ext"文件成功========");this.dis.close();} else {code = "500";message = "链接被强制关闭....";}} else {code = "404";message = "文件不存在,或已被占用:"srcRealPath;}} catch (Exception e) {code = "500";message = "客户端报错:"e.toString();LOGGER.error("异常:",e);} finally {if (this.fis != null) {try {this.fis.close();} catch (Exception var38) {;}}if (this.fos != null) {try {this.fos.close();} catch (Exception var37) {;}}try {this.client.close();} catch (Exception var36) {;}}rtnObject.element("code", code);rtnObject.element("message", message);return rtnObject;}public static void main(String[] args) {try {SocketClient socketClient = new SocketClient();// 将文档转换成pdf文件socketClient.processOffice("D:/2.doc","D:/2.pdf",YOZOOfficeUtil.PROCESS_TYPE_CONVERTFILE,null);// 将文档转换成pdf文件JSONObject dataObject = new JSONObject();dataObject.element("bookmarkname","这个是测试呢日哦那个");socketClient.processOffice("D:/2.doc","D:/2.pdf",YOZOOfficeUtil.PROCESS_TYPE_REPLACEBOOKMARK,dataObject);} catch (Exception e) {LOGGER.error("异常:",e);}}}

5、启动word文件处理组件服务端
服务端WORD文件模板书签替换-word书签替换内容

组件启动脚本
nohup ./ofdServer.sh &


6、调用服务端对word文件处理
public static void main(String[] args) {try {SocketClient socketClient = new SocketClient();// 将文档转换成pdf文件socketClient.processOffice("D:/2.doc","D:/2.pdf",YOZOOfficeUtil.PROCESS_TYPE_CONVERTFILE,null);// 替换模板中的书签值,word中插入书签自行百度JSONObject dataObject = new JSONObject();dataObject.element("bookmarkname","这个是测试呢日哦那个");socketClient.processOffice("D:/2.doc","D:/3.doc",YOZOOfficeUtil.PROCESS_TYPE_REPLACEBOOKMARK,dataObject);} catch (Exception e) {LOGGER.error("异常:",e);}}
7、资源下载
word文件处理组件服务端(开箱即用):
链接: https://pan.baidu.com/s/1_ZgjoX_nuv3a7_SKkJ_D7w 提取码: hn2r


服务端WORD文件模板书签替换-word书签替换内容

服务端资源内容


将文件复制到linux服务器,并解压,执行 ./ofdServer.sh ,输出:服务端启动,监听端口为:8899,即运行成功
word文件处理组件客户端(开箱即用processOffice):
链接: https://pan.baidu.com/s/1mtabGY87RuAGGkwKrBIvfQ 提取码: mqxf
服务端WORD文件模板书签替换-word书签替换内容

客户端资源文件内容
将源文件复制到项目指定包名,运行SocketClient.java中的main方法,可查看运行结果 。
最重要的一点:服务器要安装永中OFFICE客户端

相关经验推荐