使用mule生成WSDL中文亂碼問(wèn)題解決方法
在發(fā)布Web服務(wù) 的時(shí)候,WSDL 作為服務(wù)的描述,里面有一個(gè)標(biāo)簽可以寫(xiě)入中文,是用來(lái)作為注解來(lái)寫(xiě)入描述性信息的,這個(gè)標(biāo)簽就是。OECP平臺(tái)中使用開(kāi)源ESB總線mule 來(lái)做webService 發(fā)布使用.發(fā)布時(shí)就遇到了中文 描述亂碼 問(wèn)題,經(jīng)過(guò)一天多的時(shí)間來(lái)翻閱mule和cxf的源代碼,問(wèn)題最終被解決。這里記錄一下解決的過(guò)程和方法。
mule 內(nèi)使用的spring-cxf來(lái)將一個(gè)java方法轉(zhuǎn)換為webService 。cxf有一個(gè)annotation是生成wsdl 中的 標(biāo)簽用的,這個(gè)annotation就是@WSDLDocumentation 。但是這個(gè)標(biāo)簽使用后,生成的WSDL 文件,中文 卻顯示成了亂碼 。
經(jīng)過(guò)測(cè)試發(fā)現(xiàn),單純使用Spring-cxf時(shí),@WSDLDocumentation 不會(huì)產(chǎn)生亂碼 。這就說(shuō)明問(wèn)題出在mule 上。只能翻一下mule 的源代碼來(lái)查找原因了。由于找不到與當(dāng)前使用的jar包版本相同的源代碼,只能使用升級(jí)版的源碼,調(diào)試的時(shí)候發(fā)現(xiàn)升級(jí)的改動(dòng)比較大,刪掉的以前的一些方法和代碼修改也蠻多,錯(cuò)行缺行導(dǎo)致調(diào)試可讀性極差,讓我一直看了一天多。比較安慰的是最終還是找到了問(wèn)題原因并解決了。下面就具體說(shuō)一下原理。
我們知道發(fā)布WebService 以后,使用url+?wsdl的方式訪問(wèn),將會(huì)獲取到服務(wù)描述文件wsdl 文件.mule 中發(fā)布服務(wù)后,使用這種方式訪問(wèn)服務(wù)器將會(huì)啟動(dòng)一個(gè)線程,線程調(diào)用鏈如下圖:
標(biāo)記①下面,是http請(qǐng)求引起的mule 事件級(jí)聯(lián)鏈條,是mule 內(nèi)部的架構(gòu)機(jī)制,這個(gè)不是我們現(xiàn)在要所關(guān)注的.重點(diǎn)在第②行,紅色標(biāo)記出的OutputStream就是用來(lái)承載wsdl 文件流的對(duì)象,實(shí)際上它是一個(gè)ByteArrayOutputStream。在圖上⑥的位置執(zhí)行完后,這個(gè)Stream將被寫(xiě)入完成。前面的每一個(gè)步驟中文字符 的編碼都是正確的,即便是寫(xiě)入到Stream中,字符的byte編碼也沒(méi)有問(wèn)題。但是,此時(shí)我們發(fā)現(xiàn)查看這個(gè)Stream的內(nèi)容時(shí),卻看到了亂碼 。這是為什么呢?為什么Stream中存儲(chǔ)的byte沒(méi)錯(cuò),但是卻能看到亂碼呢?
經(jīng)常調(diào)試程序的朋友們知道,當(dāng)我們查看一個(gè)對(duì)象的內(nèi)容時(shí),對(duì)象查看器,將調(diào)用對(duì)象的toString方法。經(jīng)檢查發(fā)現(xiàn)ByteArrayOutputStream的toString方法果然被重寫(xiě):
java 代碼
- public synchronized String toString() {
- return new String(buf, 0 , count);
- }
ByteArrayOutputStream使用buffer中所有的byte創(chuàng)建并返回了一個(gè)String對(duì)象。這里注意,創(chuàng)建String的時(shí)候并沒(méi)有指定編碼格式。那么它用的是什么編碼格式?我們?nèi)tring中看看,String使用了StringCoding來(lái)轉(zhuǎn)化byte為char數(shù)組,而其中選用的編碼格式是從Charset.defaultCharset()得來(lái)的。從JDK的API中我們能找到了這個(gè)方法,上面是這么說(shuō)的:
在我們的服務(wù)器運(yùn)行環(huán)境中得到的默認(rèn)編碼 格式為GBK。于是亂碼形成的原因找到了:由于Spring-cxf生成服務(wù)的wsdl 時(shí)用的是UTF-8編碼,而被mule 錯(cuò)誤的使用了服務(wù)器運(yùn)行環(huán)境默認(rèn)編碼GBK,所以UTF-8下的正常顯示中文 最終被顯示為亂碼 了。
mule 中的類CxfInboundMessageProcessor第201行:
msg = out.toString();
這就是亂碼 產(chǎn)生的根源,在將字節(jié)流轉(zhuǎn)為字符串的時(shí)候,沒(méi)有指定編碼格式,而默認(rèn)使用了GBK,就是wsdl 文件亂碼 的原因。
解決這個(gè)問(wèn)題又兩種方案:
1. 改變jvm的默認(rèn)字符編碼。
2. 修改CxfInboundMessageProcessor類的源代碼。
第一種方案通過(guò)修改服務(wù)器的啟動(dòng)參數(shù),追加一段“-Dfile.encoding=UTF-8”,就可以改變服務(wù)器的java運(yùn)行環(huán)境。此時(shí)啟動(dòng)服務(wù)器時(shí)我們會(huì)發(fā)現(xiàn),雖然我們的WSDL中文不再出現(xiàn)亂碼了,但是服務(wù)器控制臺(tái)顯示的中文 卻全都成了亂碼 。我猜是服務(wù)器的日志輸出依賴于操作系統(tǒng)的默認(rèn)字符集吧。暫且不說(shuō)這個(gè)日志亂碼 問(wèn)題,即使不存在這個(gè)問(wèn)題我認(rèn)為這種方案也是不太合適的。wsdl 是否出現(xiàn)亂碼依賴于運(yùn)行服務(wù)器的默認(rèn)字符集,對(duì)于OECP平臺(tái)來(lái)說(shuō)是不可控的。OECP平臺(tái)使用什么樣的字符編碼應(yīng)該依賴于應(yīng)用自己的配置。
于是決定修改mule 的源代碼,比較幸運(yùn)的是CxfInboundMessageProcessor這個(gè)類,在升級(jí)的過(guò)程中沒(méi)有改動(dòng),不然就要反編譯來(lái)獲取源碼了。
將201行的msg = out.toString();修改為如下代碼:
java 代碼
- String enc = event.getMuleContext().getConfiguration().getDefaultEncoding();
- msg = out.toString(enc);
從mule 的配置中得到配置的編碼格式,并在將Stream轉(zhuǎn)換為String的時(shí)候指定使用此編碼格式.至此問(wèn)題解決了.
我們可以在使用mule發(fā)布服務(wù)時(shí),使用WSDLDocumentation 標(biāo)簽來(lái)為服務(wù)添加描述了.wsdl 作為WebService 的描述,如果沒(méi)有注釋性的文字,wsdl 描述可讀性實(shí)在不是很好. WSDLDocumentation 標(biāo)簽就是作為這種描述存在的,如果你想在WSDL 中加入中文 的描述這個(gè)標(biāo)簽應(yīng)該是唯一的選擇.如果你使用的也是mule ,也遇到了中文 的亂碼 問(wèn)題,希望可上面的內(nèi)容可以幫助你。
作者本人將原文轉(zhuǎn)發(fā)到此,原文地址為:http://www.oecp.cn/hi/slx/blog/2315
文章地址:http://songlixiao.iteye.com/blog/1085140
【編輯推薦】