1. 程式人生 > >基於SSM 的 Office 線上編輯

基於SSM 的 Office 線上編輯

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="#"onclick="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>