office web apps 整合到自己項目中(wopi實現在線預覽編輯)


借助office web apps實現在線預覽和在線編輯

我所有的代碼都是用go語言編寫,你可以直接編譯后使用,不用再有其他的操作。
最近項目實在太忙,這幾天才有時間,這次是重頭戲,要好好琢磨一下怎么寫,才能更簡潔的說清楚一切。
上一節,我們已經安裝完畢,安裝好了office web apps。大家只要打開瀏覽器,訪問自己的域地址,我的是app.datrix3.com,如果可以看見這個界面

那就說明你安裝無問題了。接下來就要通過Wopi協議將OWA集成到自己的項目中了。

實現在線預覽和編輯的Wopi協議

首先你要明白什么是wopi協議,相關的資料中,WOPI的全稱是“Web Application Open PlatformInterface”,中文名為“Web應用程序開放平台接口協議”。
要知道,office web apps 可不會允許你直接去調用它相關的接口,網上的一張圖就很好的說明了這點:

你可以看見,在WOPI中,存在WOPI Server(或者稱之為WOPI Host)和WOPI Client兩種角色,我們可以將WOPI-Client看作我們搭建的OWA服務器,
而WOPI Server就是我們要自己開發的Wopi服務,在圖里可以看見,WOPI Client共向WOPI Server進行了兩次請求,分別是Tell me about the file以及Give me the file,所以如果需要實現最簡單的在線預覽,你需要提供兩個接口,如果要實現在線編輯,你還需要一個寫入保存的接口。

第一個接口為:Tell me about the file,我將它定義為GetFileInfo,它的url為
http://{你自己的owa地址}/api/wopi/files/{file_name}
這里需要你以JSON形式OWA傳參,參數至少要包括如下信息:

{  
  "BaseFileName": "Sample Document.docx",  
  "OwnerId": "tylerbutler",  
  "Size": 300519,  
  "SHA256":"+17lwXXN0TMwtVJVs4Ll+gDHEIO06l+hXK6zWTUiYms=",  
  "Version":"GIYDCMRNGEYC2MJREAZDCORQGA5DKNZOGIZTQMBQGAVTAMB2GAYA===="  
  }  

BaseFileName: 文件名。
OwnerId: 文件所有者的唯一編號。
Size: 文件大小,以bytes為單位。
SHA256: 文件的256位bit的SHA-2編碼散列內容。(Wordweb app必有,excel和ppt可以為null)
Version: 文件版本號,文件如果被編輯,版本號也要跟着改變。
下面是我的參數:

type fileInfo struct {
	BaseFileName   string `json:"BaseFileName"`
	OwnerId        string `json:"OwnerId"`
	Size           int64  `json:"Size"`
	SHA256         string `json:"SHA256"`
	Version        string `json:"Version"`
	SupportsUpdate bool   `json:"SupportsUpdate,omitempty"`
	UserCanWrite   bool   `json:"UserCanWrite,omitempty"`
	SupportsLocks  bool   `json:"SupportsLocks,omitempty"`
}

你可以看見,這里有文件的size,sha256,這里要用代碼去獲取:

//獲取單個文件的大小
func getSize(path string) int64 {
	fileInfo, err := os.Stat(path)
	if err != nil {
		panic(err)
	}
	fileSize := fileInfo.Size()
	return fileSize
}
//獲取sha256
func SHA256File(path string) (string, error) {
	buf, err := ioutil.ReadFile(path)
	if err != nil {
		return "", err
	}
	h := sha256.Sum256(buf)
	return base64.StdEncoding.EncodeToString(h[:]), nil
}

GetFileInfo接口代碼:

func GetFileInfo(w http.ResponseWriter, r *http.Request) {
	log.Println("GetFileInfo")

	vals := r.URL.Query()
	tmp, ok := vals["access_token"]
	if !ok || len(tmp[0]) == 0 {
		log.Println("access_token not found!")
	}

	vars := mux.Vars(r)
	fileName := vars["file_name"]
	if len(fileName) == 0 {
		log.Println("file_name empty!")
	}
	log.Println("file_name: ", fileName)

	testFilePath := path.Join(".", fileName)

	log.Println("PATH: ", testFilePath)

	var info fileInfo
	info.BaseFileName = fileName
	info.OwnerId = "admin"
	info.Size = getSize(testFilePath)
	info.SHA256, _ = SHA256File(testFilePath)
	log.Println("debug: sha256_b42: ", info.SHA256)
	// String value: eIMevgBhTd8Iqh1VjWbfWx7wd5vQvmDxlABMfz+pTiI=
	//info.SHA256 = "eIMevgBhTd8Iqh1VjWbfWx7wd5vQvmDxlABMfz+pTiI="

	info.Version = "2222"
	info.UserCanWrite = true
	info.SupportsLocks = true

	w.Header().Set("Content-Type", "application/json")

	json.NewEncoder(w).Encode(info)

	log.Println("GetFileInfo done...")
}

接下來是第二個接口Give me the file,我將它定義為GetFileContent,用於WOPI Client獲取文件,這個接口的url為:
http://owa服務器地址/api/wopi/files/{file_name}/contents
這個接口通過文件流的方式返回文件,代碼如下

func GetFileContent(w http.ResponseWriter, r *http.Request) {
	log.Println("GetFileContent start.......")

	vals := r.URL.Query()
	tmp, ok := vals["access_token"]
	if !ok || len(tmp[0]) == 0 {
		log.Println("access_token not found!")
	}

	vars := mux.Vars(r)
	fileName := vars["file_name"]
	if len(fileName) == 0 {
		log.Println("file_name empty!")
	}
	log.Println("file_name: ", fileName)

	testFilePath := path.Join(".", fileName)

	data, err := ioutil.ReadFile(testFilePath)
	if err != nil {
		log.Println("read file err: ", err)
		return
	}

	w.Header().Set("Content-type", "application/octet-stream")
	w.Write(data)
	//json.NewEncoder(w).Encode(info)
	log.Println("GetFileContent done !")
}

如果你需要實現編輯的功能,你需要實現一個上傳接口POSTfile,這個接口和上面那個url除了請求方式不同,其他都是一樣的。
http://owa服務器地址/api/wopi/files/{file_name}/contents
代碼如下

func PostFileContent(w http.ResponseWriter, r *http.Request) {
	log.Println("PostFileContent start..........")

	vals := r.URL.Query()
	tmp, ok := vals["access_token"]
	if !ok || len(tmp[0]) == 0 {
		log.Println("access_token not found!")
	}

	vars := mux.Vars(r)

	fileName := vars["file_name"]

	if len(fileName) == 0 {
		log.Println("file_name empty!")
	}

	log.Println("file_name: ", fileName)

	testFilePath := path.Join(".", fileName)

	log.Println("PATH: ", testFilePath)

	body, err := ioutil.ReadAll(r.Body)

	if err != nil {
		log.Println("body empty")
	}

	ioutil.WriteFile(testFilePath, body, os.ModeAppend)

	w.Header().Set("Content-type", "application/octet-stream")

	// get Path,get file

}

現在三個接口都已經實現了,我們來看一下路由和具體的實現代碼:

func main() {

	router := mux.NewRouter()
	router.HandleFunc("/api/wopi/files/{file_name}", GetFileInfo).Methods(http.MethodGet)
	router.HandleFunc("/api/wopi/files/{file_name}/contents", GetFileContent).Methods(http.MethodGet)
	router.HandleFunc("/api/wopi/files/{file_name}/contents", PostFileContent).Methods(http.MethodPost)
    //開啟8080端口
	err := http.ListenAndServe(":8080", router)
	log.Println(router)
	if err != nil {
		log.Println("http listen err: ", err)
	}
}

接下來你就可以go build,然后跑服務了,我這里設置的文件路徑都是本目錄下的,也就是說,服務在test文件夾下跑起來,那么你的office文件也要放在test文件夾下。

最后,跑起來服務,應該訪問的url如下:

http://owa服務器地址/we/WordEditorFrame.aspx?WOPISrc=http//本地ip:8080/api/wopi/files/1.docx

http:/owa服務器地址/p/PowerPointFrame.aspx?PowerPointView=ReadingView&WOPISrc=http//本地ip:8080/api/wopi/files/1.pptx

http://owa服務器地址/x/_layouts/xlviewerinternal.aspx?WOPISrc=http//本地ip:8080/api/wopi/files/1.xlsx


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM