借助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