王龍軍
(成都工業(yè)學(xué)院,四川 成都 611730)
微信公眾平臺(tái)[1]在高校圖書(shū)館中應(yīng)用越來(lái)越廣泛,讀者通過(guò)關(guān)注圖書(shū)館微信公眾號(hào),可以能使得讀者方便可以實(shí)時(shí)查詢到館藏書(shū)目和電子資源等信息,同時(shí)也能夠通過(guò)微信公眾平臺(tái)了解最新的新聞、通知、講座等信息,當(dāng)然,還有跟其他平臺(tái)整合的功能,比如讀者利用公眾平臺(tái)實(shí)時(shí)查詢進(jìn)館人數(shù),可以實(shí)時(shí)查詢圖書(shū)館座位使用情況和剩余數(shù)量。
微信公眾平臺(tái)能夠與讀者進(jìn)行消息交互,主要是由于微信公眾平臺(tái)消息接口的功勞,它為開(kāi)發(fā)者提供了與讀者進(jìn)行消息交互的能力。對(duì)于成功接入消息接口的公眾賬號(hào),當(dāng)讀者發(fā)消息給公眾賬號(hào)時(shí),微信公眾平臺(tái)服務(wù)器會(huì)使用HTTP請(qǐng)求對(duì)接入的URL地址進(jìn)行消息推送,公眾號(hào)服務(wù)器可通過(guò)響應(yīng)包返回個(gè)性的回復(fù),從而達(dá)到回復(fù)消息的目的??偟膩?lái)說(shuō),就是微信公眾號(hào)可以使用自己的程序來(lái)和讀者對(duì)話。
圖書(shū)館微信公眾平臺(tái)交互詳細(xì)過(guò)程如下:①公眾平臺(tái)要與讀者進(jìn)行交互,讀者要在微信客戶端發(fā)送消息給微信服務(wù)器,微信服務(wù)器接收到用戶的消息處理之后,通過(guò)開(kāi)發(fā)者配置的URL和Token 來(lái)找到公眾號(hào)服務(wù)器,并以XML形式向公眾號(hào)服務(wù)器發(fā)送消息;②公眾號(hào)服務(wù)器獲取這些消息之后,需要按照微信服務(wù)器傳過(guò)來(lái)的XML的語(yǔ)言進(jìn)行解析,獲取到信息之后,根據(jù)讀者的內(nèi)容和自己的服務(wù)器邏輯;③然后以XML形式封裝消息,傳回到微信服務(wù)器上去;④微信服務(wù)器解析這些消息,并把相應(yīng)的內(nèi)容還回給用戶。
Kotlin[2~3]是JetBrains在2011年推出的一門(mén)全新的編程語(yǔ)言,可運(yùn)行在JVM(Java 虛擬機(jī))上。Kotlin 程序可以編譯成字節(jié)碼文件,字節(jié)碼文件可以直接在 JVM 上運(yùn)行,因此 Kotlin非常適合開(kāi)發(fā)后端Web應(yīng)用程序。Kotlin 與現(xiàn)有的 Java[4]語(yǔ)言包保持完全兼容,它完全可以利用Java領(lǐng)域現(xiàn)有的各種技術(shù)框架。
微信公眾平臺(tái)的處理程序?qū)嵸|(zhì)上是一個(gè)Web項(xiàng)目,主要對(duì)微信服務(wù)器發(fā)送的HTTP請(qǐng)求進(jìn)行接收和響應(yīng),支持微信公眾平臺(tái)開(kāi)發(fā)的語(yǔ)言有Java、PHP、ASP.NET等。選擇Java與Kotlin,主要原因在于Java在開(kāi)發(fā)服務(wù)器方面具有無(wú)可比擬的安全性、穩(wěn)定性,而Kotlin可以與現(xiàn)有的Java 語(yǔ)言保持100% 的兼容性,而且 Kotlin 代碼比 Java代碼更簡(jiǎn)潔、更富有表現(xiàn)力。 簡(jiǎn)單來(lái)說(shuō),微信公眾平臺(tái)每個(gè)分類的消息都有至少4個(gè)及以上的字段,用Java來(lái)封裝消息時(shí)就會(huì)大量書(shū)寫(xiě)getter和setter方法,而此時(shí)采用Kotlin來(lái)封裝消息,只需要定義字段屬性,而Kotlin會(huì)默認(rèn)生成getter和setter方法,這樣會(huì)減少不必要的相似代碼的重復(fù),提高開(kāi)發(fā)效率。
2.1.1 消息的分類。 微信服務(wù)器與公眾號(hào)服務(wù)器交互的消息[5]可以分為三大類:請(qǐng)求消息、事件和響應(yīng)消息。在這里,微信服務(wù)器傳遞給公眾號(hào)服務(wù)器是請(qǐng)求信息、事件,而公眾號(hào)服務(wù)器返回信息給微信公眾號(hào)服務(wù)器是響應(yīng)消息。
請(qǐng)求消息指的是當(dāng)普通用戶向公眾賬號(hào)發(fā)消息時(shí),微信服務(wù)器將POST消息的XML數(shù)據(jù)包到開(kāi)發(fā)者填寫(xiě)的URL上,即這里定義的是用戶能夠發(fā)送哪些類型的消息、消息有哪些字段、消息被微信服務(wù)器以什么方式轉(zhuǎn)發(fā)給我們的公眾號(hào)服務(wù)器。
事件指的是當(dāng)用戶對(duì)公眾平臺(tái)做出某種操作后,微信服務(wù)器會(huì)將相應(yīng)的事件消息以XML格式通過(guò)POST方式發(fā)送到我們填寫(xiě)的URL上,事件也可以說(shuō)成“接收事件推送”。在微信用戶和公眾號(hào)產(chǎn)生交互的過(guò)程中,用戶的某些操作會(huì)使得微信服務(wù)器通過(guò)事件推送的形式通知到開(kāi)發(fā)者在開(kāi)發(fā)者中心處設(shè)置的服務(wù)器地址,從而開(kāi)發(fā)者可以獲取到該信息。其中,某些事件推送在發(fā)生后,是允許開(kāi)發(fā)者回復(fù)用戶的,某些則不允許。
響應(yīng)消息指的是公眾號(hào)服務(wù)器在接收到用戶發(fā)送的消息后,會(huì)產(chǎn)生一個(gè)POST請(qǐng)求,可以通過(guò)返回特定的XML結(jié)構(gòu)對(duì)消息進(jìn)行響應(yīng),現(xiàn)支持回復(fù)文本、圖片、圖文、語(yǔ)音、視頻、音樂(lè),嚴(yán)格來(lái)說(shuō),發(fā)送被動(dòng)響應(yīng)消息其實(shí)并不是一種接口,而是對(duì)微信服務(wù)器發(fā)過(guò)來(lái)消息的一次回復(fù)。
2.1.2 消息的封裝。 微信公眾平臺(tái)官方文檔對(duì)于消息類型都指定為XML數(shù)據(jù)格式,要用Java語(yǔ)言對(duì)消息中的字段進(jìn)行封裝,由于請(qǐng)求消息、事件和響應(yīng)消息具有共有的字段,可以使用Java類對(duì)三者的公共字段進(jìn)行封裝,形成一個(gè)公共的基類Message,這個(gè)基類具有3種消息的公共字段,包括ToUserName(開(kāi)發(fā)者微信號(hào))、FromUserName(發(fā)送方賬號(hào),OPEN_ID)、CreateTime(消息的創(chuàng)建時(shí)間)、MsgType(消息類型)。采用Kotlin來(lái)封裝這個(gè)消息,Message類內(nèi)容如下:
open class Message {
var ToUserName:String?=null; //開(kāi)發(fā)者微信號(hào)
var FromUserName:String?=null; //發(fā)送方賬號(hào)(OpenID)
var CreateTime:int=0;//消息創(chuàng)建時(shí)間(整型)
var MsgType:String?=null; //消息類型
}
請(qǐng)求消息可以細(xì)分為文本消息、圖片消息、語(yǔ)音消息、視頻消息、小視頻消息、地理位置消息、鏈接消息七類,用Java類封裝請(qǐng)求信息時(shí),讓請(qǐng)求信息類RequestMessage繼承消息基類Message,這七類請(qǐng)求消息都添加一個(gè)共同的字段MsgId(消息ID)。Message類內(nèi)容如下:
open class RequestMessage:Message(){
MsgID:int=0;//消息ID
}
請(qǐng)求消息中文本消息主要展示文本消息內(nèi)容,即用戶向微信公眾平臺(tái)發(fā)送一段文字時(shí),微信服務(wù)器會(huì)向公眾號(hào)服務(wù)器發(fā)送XML格式的消息,用Java對(duì)其進(jìn)行消息封裝,建立文字消息類TextMessage,繼承請(qǐng)求消息基類RequestMessage,增加一個(gè)表示文本消息的內(nèi)容字段Content,增加Content字段的getter、setter方法。請(qǐng)求消息中圖片消息、語(yǔ)音消息、視頻消息等消息的封裝跟文本消息封裝類似,就不再一一贅述。
事件消息包括關(guān)注/取消關(guān)注事件、掃描帶參數(shù)二維碼事件、上報(bào)地理位置事件、自定義菜單事件五類消息,跟封裝請(qǐng)求消息一樣,建立事件消息EventMessage,繼承于Message,該類添加一個(gè)字段Event,其內(nèi)容不再展示。事件消息的子方法跟請(qǐng)求消息的子方法在建立時(shí)類似,這里就不再一一闡述。
響應(yīng)消息也可稱為回復(fù)消息,包括回復(fù)文本消息、回復(fù)圖片消息、回復(fù)語(yǔ)音消息、回復(fù)視頻消息、回復(fù)音樂(lè)消息、回復(fù)圖文消息五類消息,跟前面兩類消息一樣,建立響應(yīng)消息ResponseMessage,繼承于Message,其子消息的封裝跟請(qǐng)求消息類似。響應(yīng)消息的子方法跟請(qǐng)求消息的子方法在建立時(shí)類似,這里就不再一一闡述。
2.1.3 Java與Kotlin相互調(diào)用。 Kotlin和Java是兩種不同的語(yǔ)言,所以在互相調(diào)用的時(shí)候,會(huì)有一些特殊的語(yǔ)法。Kotlin中對(duì)象屬性默認(rèn)就帶有setter和getter方法,所以在Kotlin中調(diào)用Java時(shí)直接變量名點(diǎn)屬性就可獲取到屬性的setter和getter的一些操作。Kotlin可以自動(dòng)識(shí)別Java中的getter/setter方法;在Java中可以過(guò)getter/setter操作Kotlin屬性。
舉個(gè)簡(jiǎn)單的例子來(lái)說(shuō)明,現(xiàn)在系統(tǒng)要用Java調(diào)用Kotlin封裝的消息Message類,代碼如下:
Message message=new Message();
message.setToUserName(“zhangsan”);
message.getToUserName();
如果Kotlin在類中封裝其他方法,那么在Java中可以同樣的調(diào)用,本系統(tǒng)主要以Java為主的Web項(xiàng)目,輔助Kotlin對(duì)消息進(jìn)行封裝,當(dāng)然在系統(tǒng)中可以讓Kotlin對(duì)消息進(jìn)行各種處理,然后Java調(diào)用Kotlin的方法。
接收消息和回復(fù)消息是相互關(guān)聯(lián)的動(dòng)作,在一個(gè)交互場(chǎng)景中接收消息、回復(fù)消息,一般情況就是公眾平臺(tái)通過(guò)分析接收到的消息,會(huì)給出對(duì)應(yīng)的回復(fù)。具體到項(xiàng)目實(shí)踐中是這樣的,當(dāng)圖書(shū)館讀者向圖書(shū)館公眾賬號(hào)發(fā)消息時(shí),微信服務(wù)器會(huì)先接收到用戶發(fā)送的消息,然后將讀者消息按照指定的XML格式組裝好數(shù)據(jù),最后POST消息的XML數(shù)據(jù)包到開(kāi)發(fā)者填寫(xiě)的URL上。
接收消息的過(guò)程其實(shí)就是獲取微信服務(wù)器通過(guò)post請(qǐng)求的發(fā)送給我們公眾號(hào)服務(wù)器的XML數(shù)據(jù),然后我們的公眾號(hào)服務(wù)器再對(duì)這個(gè)XML進(jìn)行解析處理的過(guò)程。具體過(guò)程如下:在request對(duì)象中封裝微信服務(wù)器發(fā)來(lái)的請(qǐng)求消息,可以從request對(duì)象中取出請(qǐng)求中包含的數(shù)據(jù),使用request對(duì)象的getInputStream()方法獲取請(qǐng)求中的參數(shù)。為了方便解析XML數(shù)據(jù),使用Kotlin寫(xiě)一個(gè)函數(shù)xmlToMap(request),讀取輸入流,解析XML消息,最后將處理的消息放到HashMap中。在處理微信請(qǐng)求的入口servlet的doPost方法中調(diào)用xmlToMap(request)方法來(lái)解析微信請(qǐng)求信息,然后根據(jù)消息類型返回相應(yīng)的方法。
回復(fù)消息的過(guò)程剛好跟接收消息的過(guò)程相反,對(duì)于每個(gè)POST請(qǐng)求,需要返回XML結(jié)構(gòu),對(duì)該消息進(jìn)行響應(yīng)。Kotlin將各種類型的響應(yīng)消息封裝成對(duì)象,現(xiàn)在需要把響應(yīng)的對(duì)象轉(zhuǎn)換成XML字符串,寫(xiě)一個(gè)函數(shù)messageToXml(textMessage)實(shí)現(xiàn)這個(gè)功能。
部分關(guān)鍵代碼如下:
fun buildResponseMessage(map:Map):String {
var responseMessage = "" //響應(yīng)消息
val msgType = map.get("MsgType").toString()//得到消息類型
println("MsgType:$msgType")
//消息類型
val messageEnumType = MessageType.valueOf(MessageType::class.java,msgType.toUpperCase())
when (messageEnumType) {
TEXT -> responseMessage = handleTextMessage(map) //處理文本消息
IMAGE -> responseMessage = handleImageMessage(map) //處理圖片消息
VOICE -> responseMessage = handleVoiceMessage(map)//處理語(yǔ)音消息
VIDEO -> responseMessage = handleVideoMessage(map)//處理視頻消息
SHORTVIDEO ->responseMessage = handleSmallVideoMessage(map)//處理小視頻消息
LOCATION -> responseMessage = handleLocationMessage(map)//處理位置消息
LINK -> responseMessage = handleLinkMessage(map)//處理鏈接消息
EVENT -> responseMessage = handleEventMessage(map)//處理事件消息
}
return responseMessage//返回響應(yīng)消息
}
筆者詳細(xì)介紹了微信公眾平臺(tái)交互原理,選擇Java與Kotlin作為開(kāi)發(fā)語(yǔ)言的理由,以及如何利用Java與Kotlin實(shí)現(xiàn)圖書(shū)館微信公眾平臺(tái)消息的接收和回復(fù),該平臺(tái)能夠?yàn)閳D書(shū)館提供實(shí)時(shí)交互服務(wù)、拓展服務(wù)空間、提高讀者的滿意程度以及增加讀者的黏度。