基于SSM 的 Office 在线编辑

3 篇文章 0 订阅
3 篇文章 0 订阅

Office在线编辑功能在OA系统中经常被使用。本文主要介绍在SSM框架下利用Java整合Office Online Server 2016 (OOS) 进行office 在线编辑。OOS的环境搭建之前文章有过介绍,在这里不进行过多的阐述。具体的代码实现如下:

Java 实现WOPI协议:

package com.officeonline;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URLDecoder;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import javax.servlet.Filter;
import javax.servlet.FilterConfig;

/**
 * Servlet implementation class wopi
 */
@WebFilter("/wopi/*")
public class OfficeFilter implements Filter {
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		// System.out.println("权限"+request.getParameterValues("power"));
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		HttpServletResponse httpResponse = (HttpServletResponse) response;
		String power = httpRequest.getParameter("power");
		String uri = httpRequest.getRequestURI(); //获取完整的Url请求路径
		// 解决中文乱码问题
		String fileUri = URLDecoder.decode(uri.substring(uri.indexOf("/wopi/") + 1, uri.length()), "UTF-8");
		String filePath = request.getServletContext().getRealPath("/") + fileUri;
		if (fileUri.endsWith("/contents")) { // GetFile :返回文件流
			filePath = filePath.substring(0, filePath.indexOf("/contents"));
			String method = httpRequest.getMethod();
			if (method.equals("GET")) {
				getFile(filePath, httpResponse);
			}
			if (method.equals("POST")) {
				postFile(filePath, httpRequest);
			}
		} else { // CheckFileInfo :返回json
			response.setCharacterEncoding("UTF-8");
			response.setContentType("application/json;charset=UTF-8");
			PrintWriter out = null;
			try {
				out = response.getWriter();
				out.write(FileUtils.checkFileInfo(filePath, power));
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if (out != null) {
					out.close();
				}
			}
		}
		return;
	}

	private HttpServletResponse getFile(String path, HttpServletResponse response) {
		try {
			// path是指欲下载的文件的路径。
			File file = new File(path);
			// 取得文件名。
			String filename = file.getName();
			String contentType = "application/octet-stream";
			// 以流的形式下载文件。
			InputStream fis = new BufferedInputStream(new FileInputStream(path));
			byte[] buffer = new byte[fis.available()];
			fis.read(buffer);
			fis.close();
			// 清空response
			response.reset();
			// 设置response的Header

			response.addHeader("Content-Disposition",
					"attachment;filename=" + new String(filename.getBytes("utf-8"), "ISO-8859-1"));
			response.addHeader("Content-Length", "" + file.length());
			OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
			response.setContentType(contentType);
			toClient.write(buffer);
			toClient.flush();
			toClient.close();
		} catch (IOException ex) {
			ex.printStackTrace();
		}
		return response;
	}

	public static byte[] getRequestPostBytes(HttpServletRequest request) throws IOException {
		int contentLength = request.getContentLength();
		if (contentLength < 0) {
			return null;
		}
		byte buffer[] = new byte[contentLength];
		for (int i = 0; i < contentLength;) {

			int readlen = request.getInputStream().read(buffer, i, contentLength - i);
			if (readlen == -1) {
				break;
			}
			i += readlen;
		}
		return buffer;
	}

	public void postFile(String path, HttpServletRequest request) {
		// 文件的路径
		File file = new File(path);

		try {
			if (!file.exists()) {
				file.createNewFile();// 构建文件
			}
			String submitMehtod = request.getMethod();
			if (submitMehtod.equalsIgnoreCase("post")) {
				byte[] bytes = getRequestPostBytes(request);
				FileOutputStream fop = new FileOutputStream(file);
				fop.write(bytes);
				fop.flush();
				fop.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub

	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		// TODO Auto-generated method stub

	}
}

OfficeFilter 中引用的FileUtils类:

package com.officeonline;

import java.io.File;

public class FileUtils {
	/**
	 * 获取文件基本信息
	 * 
	 * @param filePath
	 *            文件路径
	 * @return
	 */
	public static String checkFileInfo(String filePath, String power) {
		File file = new File(filePath);
		// String hash=null;
		String baseFileName = null; // 文件名
		String ownerId = null; // 文件所有者的唯一编号
		long size = 0; // 文件大小,以bytes为单位
		String sha256 = null; // 文件的256位bit的SHA-2编码散列内容
		long version = 0; // 文件版本号,文件如果被编辑,版本号也要跟着改变
		boolean Write = false;
		boolean Print = true;
		// 在网页中获取用户是否有权限编辑和打印,根据获取的参数设置office的功能
		if (power == null) {
			Write = false;
			Print = true;
		} else {
			if (power.equals("write")) {
				Write = true;
			}
			if (power.equals("print")) {
				Print = false;
			}
			if (power.equals("writeprint") || power.equals("printwrite")) {
				Write = true;
				Print = false;
			}
		}
		if (file.exists()) {
			// 取得文件名。
			baseFileName = file.getName();
			size = file.length();
			// 取得文件的后缀名。

			ownerId = "admin";
			version = file.lastModified();
			sha256 = new Encrypt().SHA256(baseFileName);
		}

		return "{\"DisablePrint\":\"" + Print + "\",\"SupportsLocks\":\"" + true + "\",\"Sha256\":\"" + sha256
				+ "\",\"SupportsUpdate\":\"" + true + "\",\"UserCanWrite\":\"" + Write + "\",\"BaseFileName\":\""
				+ baseFileName + "\",\"OwnerId\":\"" + ownerId + "\",\"Size\":\"" + size
				+ "\",\"AllowExternalMarketplace\":\"" + true + "\",\"Version\":\"" + version + "\"}";
	}
}
FileUtils类中的Encrypt类:

package com.officeonline;

import java.security.MessageDigest;  
import java.security.NoSuchAlgorithmException;  
  
public class Encrypt  
{  
  
  /** 
   * 传入文本内容,返回 SHA-256 串 
   *  
   * @param strText 
   * @return 
   */  
  public String SHA256(final String strText)  
  {  
    return SHA(strText, "SHA-256");  
  }  
  
  /** 
   * 传入文本内容,返回 SHA-512 串 
   *  
   * @param strText 
   * @return 
   */  
  public String SHA512(final String strText)  
  {  
    return SHA(strText, "SHA-512");  
  }  
  
  /** 
   * 字符串 SHA 加密 
   *  
   * @param strSourceText 
   * @return 
   */  
  private String SHA(final String strText, final String strType)  
  {  
    // 返回值  
    String strResult = null;  
  
    // 是否是有效字符串  
    if (strText != null && strText.length() > 0)  
    {  
      try  
      {  
        // SHA 加密开始  
        // 创建加密对象 并傳入加密類型  
        MessageDigest messageDigest = MessageDigest.getInstance(strType);  
        // 传入要加密的字符串  
        messageDigest.update(strText.getBytes());  
        // 得到 byte 類型结果  
        byte byteBuffer[] = messageDigest.digest();  
  
        // 將 byte 轉換爲 string  
        StringBuffer strHexString = new StringBuffer();  
        // 遍歷 byte buffer  
        for (int i = 0; i < byteBuffer.length; i++)  
        {  
          String hex = Integer.toHexString(0xff & byteBuffer[i]);  
          if (hex.length() == 1)  
          {  
            strHexString.append('0');  
          }  
          strHexString.append(hex);  
        }  
        // 得到返回結果  
        strResult = strHexString.toString();  
      }  
      catch (NoSuchAlgorithmException e)  
      {  
        e.printStackTrace();  
      }  
    }  
  
    return strResult;  
  }  
}  

controller层实现对word(模板)的复制和对复制后文件的修改:

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import util.UrlCode;

@Controller
public class OfficeController {
	@RequestMapping(value = "/openmodle.do")
	@ResponseBody
	public String openmodel(HttpServletRequest request, HttpServletResponse response) throws IOException {
		String filePath = request.getServletContext().getRealPath("/");
		FileInputStream fis = new FileInputStream(filePath + "wopi/files/fs/t1.docx");//t1.docx为模板文件
		FileOutputStream fos = new FileOutputStream(filePath + "wopi/files/fs/t2.docx");//t2.docx为按照末班新建的文件
		BufferedInputStream bis = new BufferedInputStream(fis);
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		int by = 0;
		byte[] buf = new byte[104857600];//默认上传最大文件为100M
		while ((by = bis.read(buf)) != -1) {
			bos.write(buf, 0, by);
		}
		fis.close();
		fos.close();
		bis.close();
		bos.close();
		String Wopisrc=UrlCode.url("http://xx.xx.xx.xx:8080/SmartSchool/wopi/files/fs/t2.docx?power=write");
		return "http://xx.xx.xx.xx/we/wordeditorframe.aspx?WOPISrc="+Wopisrc;
	}
}

Html页面的实现:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Office 在线</title>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript">
	function openmodle() {
		filename = prompt("请输入新建文件名:","新建文件");
		if (filename != null){
			alert(">>>>>>>>>>>>>>>>>>>>>"+filename+">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
			$.ajax({
				url : "openmodle.do",
				data : JSON.stringify(filename),//用户新建文件的文件名传到前台
				type : "POST",
				success : function(msg) {
					console.log("成功");
					console.log(msg);
					window.open(msg);
				},
				error : function(data, textStatus, errorThrown) {
					console.log("失败");
				},
			});

		}else{
		alert("你按了[取消]按钮");
		}
		
	}
</script>
</head>
<body>
<a href="#"οnclick="openmodle()">通过模板发布文件</a>
<table>
<tr><td>Word<td><td><a href="http://xx.xx.xx.xx/wv/wordviewerframe.aspx?WOPISrc=http%3A%2F%2Fxx.xx.xx.xx%3A8080%2FSmartSchool%2Fwopi%2Ffiles%2F1.docx">预览</a><td><td><a href="http://xx.xx.xx.xx/we/wordeditorframe.aspx?WOPISrc=http%3A%2F%2Fxx.xx.xx.xx%3A8080%2FSmartSchool%2Fwopi%2Ffiles%2F1.docx%3Fpower%3Dwrite">编辑</a><td></tr>
<tr><td>Excel<td><td><a href="http://xx.xx.xx.xx/x/_layouts/xlviewerinternal.aspx?WOPISrc=http%3A%2F%2Fxx.xx.xx.xx%3A8080%2FSmartSchool%2Fwopi%2Ffiles%2F1.xlsx">预览</a><td><td><a href="http://xx.xx.xx.xx/x/_layouts/xlviewerinternal.aspx?edit=1&WOPISrc=http%3A%2F%2Fxx.xx.xx.xx%3A8080%2FSmartSchool%2Fwopi%2Ffiles%2F1.xlsx%3Fpower%3Dwrite">编辑</a><td></tr>
<tr><td>Ppt<td><td><a href="http://xx.xx.xx.xx/p/PowerPointFrame.aspx?WOPISrc=http%3A%2F%2Fxx.xx.xx.xx%3A8080%2FSmartSchool%2Fwopi%2Ffiles%2F1.pptx">预览</a><td><td><a href="http://xx.xx.xx.xx/p/PowerPointFrame.aspx?PowerPointView=EditView&WOPISrc=http%3A%2F%2Fxx.xx.xx.xx%3A8080%2FSmartSchool%2Fwopi%2Ffiles%2F1.pptx%3Fpower%3Dwrite">编辑</a><td></tr>
<tr><td>Pdf<td><td><a href="http://xx.xx.xx.xx/wv/wordviewerframe.aspx?PdfMode=1&WOPISrc=http%3A%2F%2Fxx.xx.xx.xx%3A8080%2FSmartSchool%2Fwopi%2Ffiles%2F1.pdf">预览</a><td><td></tr>
</table>
</body>
</html>


评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值