談?wù)劄镴AXB和response設(shè)置編碼,解決wechat4j中文亂碼的問題
如果有哪一個(gè)做程序員的小伙伴說自己沒有遇到中文亂碼問題,我是不愿意相信的。今天在做微信訂閱號(hào)的智能回復(fù)時(shí),又一時(shí)迷亂的跳進(jìn)了中文亂碼這個(gè)火坑。剛解決問題時(shí),都?xì)g呼雀躍了,完全忘記了她曾經(jīng)帶給我的痛苦。
一、問題描述
看到?jīng)],紅色框框內(nèi)的亂碼赤裸裸的對(duì)我進(jìn)行挑釁,而我卻無(wú)可奈何,真是糟糕透頂。
二、尋求解決之道
面對(duì)問題,只有拿著刀逼自己去解決啊,能怎么樣呢?
首先,必須搞清楚微信智能回復(fù)的機(jī)制,畫圖如下:
ps,工具用得不好,請(qǐng)見諒。
接下來(lái),我們抓重點(diǎn),看亂碼重要發(fā)生在什么位置。
1.controller返回給用戶
response.setHeader("content-type", "text/html;charset=UTF-8");// 瀏覽器編碼 response.getOutputStream().write(result.getBytes());
就這段代碼了,指定response的編碼方式為UTF-8,按理說亂碼問題應(yīng)該出現(xiàn)好轉(zhuǎn),但是結(jié)果依然是沒有。
2.JAXB的toXML
public String toXML(Object obj) { String result = null; try { JAXBContext context = JAXBContext.newInstance(obj.getClass()); Marshaller m = context.createMarshaller(); m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); m.setProperty(Marshaller.JAXB_FRAGMENT, true);// 去掉報(bào)文頭 ByteArrayOutputStream os = new ByteArrayOutputStream(); XMLSerializer serializer = getXMLSerializer(os); m.marshal(obj, serializer.asContentHandler()); result = os.toString("UTF-8"); } catch (Exception e) { e.printStackTrace(); } logger.info("response text:" + result); return result; } private XMLSerializer getXMLSerializer(OutputStream os) { OutputFormat of = new OutputFormat(); formatCDataTag(); of.setCDataElements(cdataNode); of.setPreserveSpace(true); of.setIndenting(true); of.setOmitXMLDeclaration(true); of.setEncoding("UTF-8"); XMLSerializer serializer = new XMLSerializer(of); serializer.setOutputByteStream(os); return serializer; }
這里有三個(gè)關(guān)鍵的點(diǎn):
1. m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
2. getXMLSerializer(os)
3. os.toString("UTF-8");
可以看到以上三個(gè)地方均會(huì)涉及到轉(zhuǎn)碼,第1處,設(shè)置Marshaller的編碼;第二處,設(shè)置整個(gè)XMLSerializer的編碼;第三處,設(shè)置返回的ByteArrayOutputStream的string編碼。三處缺一不可。
這次這么透徹,應(yīng)該解決了問題了吧,但是解決依然中文亂碼,那該如何是好呢?
3.tomcat的輸出環(huán)境作怪
針對(duì)這一點(diǎn),網(wǎng)上有人提供這樣的解決思路。
set JAVA_OPTS=%JAVA_OPTS% %LOGGING_MANAGER% -Dfile.encoding=UTF-8
設(shè)置后重啟tomcat,問題是能夠解決,但副作用是整個(gè)tomcat在服務(wù)器上運(yùn)行輸出(tomcat的cmd窗口)一直是亂碼,我認(rèn)為這種方案不可取。
在運(yùn)行的war中加入以下代碼
System.getProperty("file.encoding");
你會(huì)驚奇的發(fā)現(xiàn),tomcat的運(yùn)行環(huán)境(window server 2008)竟然是GBK,不知道你是否不驚奇,我是嚇到了,為什么不是UTF-8呢?如果是GBK的話,上面兩個(gè)步驟中我加入再多的UTF-8頁(yè)扯淡啊,不解。
三、解決問題
有了以上的經(jīng)驗(yàn),我們修改以下wechat4j的代碼,主要是第二點(diǎn)。
public String toXML(Object obj) { String result = null; try { JAXBContext context = JAXBContext.newInstance(obj.getClass()); Marshaller m = context.createMarshaller(); String encoding = Config.instance().getJaxb_encoding(); logger.debug("toXML encoding " + encoding + "System file.encoding " + System.getProperty("file.encoding")); m.setProperty(Marshaller.JAXB_ENCODING, encoding); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); m.setProperty(Marshaller.JAXB_FRAGMENT, true);// 去掉報(bào)文頭 ByteArrayOutputStream os = new ByteArrayOutputStream(); XMLSerializer serializer = getXMLSerializer(os); m.marshal(obj, serializer.asContentHandler()); result = os.toString(encoding); } catch (Exception e) { e.printStackTrace(); } logger.info("response text:" + result); return result; } private XMLSerializer getXMLSerializer(OutputStream os) { OutputFormat of = new OutputFormat(); formatCDataTag(); of.setCDataElements(cdataNode); of.setPreserveSpace(true); of.setIndenting(true); of.setOmitXMLDeclaration(true); String encoding = Config.instance().getJaxb_encoding(); of.setEncoding(encoding); XMLSerializer serializer = new XMLSerializer(of); serializer.setOutputByteStream(os); return serializer; }
這兩個(gè)方法中,對(duì)encoding我們加上可配置的編碼方式,可手動(dòng)設(shè)置GBK(我的服務(wù)器上配置了GBK)、GB2312、UTF-8。
如此,會(huì)發(fā)現(xiàn)wechat4j的后臺(tái)輸出就不再是中文亂碼了,但返回給用戶的信息更亂了。
怎么能這樣呢,耍我這枚程序員啊,真想吐兩句臟話。但別怕啊,既然wechat4j的logger日志不再中文亂碼,那么只能說是第1個(gè)環(huán)節(jié)又出現(xiàn)問題了。
調(diào)整嘛
response.setHeader("content-type", "text/html;charset=UTF-8");// 瀏覽器編碼 response.getOutputStream().write(result.getBytes("UTF-8"));
注意,這里不能是GBK,只能是UTF-8,我表示不清楚為什么,微信的產(chǎn)品經(jīng)理給出來(lái)解釋下。
重點(diǎn),JAXB和response合伙解決wechat4j中文亂碼的 方法再次聲明如下:
WeChatController.Java,就是你配給微信公眾開發(fā)平臺(tái)的URL處,response調(diào)整如下
response.setHeader("content-type", "text/html;charset=UTF-8");// 瀏覽器編碼 response.getOutputStream().write(result.getBytes("UTF-8"));
wechat4j的JaxbParser.java,分別調(diào)整toXML(Object obj)和getXMLSerializer(OutputStream os)方法:
public String toXML(Object obj) { String result = null; try { JAXBContext context = JAXBContext.newInstance(obj.getClass()); Marshaller m = context.createMarshaller(); String encoding = Config.instance().getJaxb_encoding();// GBK logger.debug("toXML encoding " + encoding + "System file.encoding " + System.getProperty("file.encoding")); m.setProperty(Marshaller.JAXB_ENCODING, encoding); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); m.setProperty(Marshaller.JAXB_FRAGMENT, true);// 去掉報(bào)文頭 ByteArrayOutputStream os = new ByteArrayOutputStream(); XMLSerializer serializer = getXMLSerializer(os); m.marshal(obj, serializer.asContentHandler()); result = os.toString(encoding); } catch (Exception e) { e.printStackTrace(); } logger.info("response text:" + result); return result; } private XMLSerializer getXMLSerializer(OutputStream os) { OutputFormat of = new OutputFormat(); formatCDataTag(); of.setCDataElements(cdataNode); of.setPreserveSpace(true); of.setIndenting(true); of.setOmitXMLDeclaration(true); String encoding = Config.instance().getJaxb_encoding();//GBK of.setEncoding(encoding); XMLSerializer serializer = new XMLSerializer(of); serializer.setOutputByteStream(os); return serializer; }
好了,萬(wàn)事大吉了。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java實(shí)現(xiàn)兩人五子棋游戲(四) 落子動(dòng)作的實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)兩人五子棋游戲,落子動(dòng)作的實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03Java基于深度優(yōu)先遍歷的隨機(jī)迷宮生成算法
今天小編就為大家分享一篇關(guān)于Java基于深度優(yōu)先遍歷的隨機(jī)迷宮生成算法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-02-02Java給實(shí)體每一個(gè)字段賦默認(rèn)值詳細(xì)代碼示例
這篇文章主要給大家介紹了關(guān)于Java給實(shí)體每一個(gè)字段賦默認(rèn)值的相關(guān)資料,在編程過程中有時(shí)會(huì)出現(xiàn)這樣一種情況,在查詢無(wú)結(jié)果時(shí)我們需要給實(shí)體賦默認(rèn)值,需要的朋友可以參考下2023-09-09java+Okhttp3調(diào)用接口的實(shí)例
這篇文章主要介紹了java+Okhttp3調(diào)用接口的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12Java數(shù)組優(yōu)點(diǎn)和缺點(diǎn)_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
本文給大家簡(jiǎn)單介紹下java數(shù)組的優(yōu)點(diǎn)和缺點(diǎn)知識(shí),需要的的朋友參考下吧2017-04-045個(gè)JAVA入門必看的經(jīng)典實(shí)例
這篇文章主要為大家詳細(xì)介紹了5個(gè)JAVA入門必看的經(jīng)典實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10springMVC前臺(tái)傳數(shù)組類型,后臺(tái)用list類型接收實(shí)例代碼
這篇文章主要介紹了springMVC前臺(tái)傳數(shù)組類型,后臺(tái)用list類型接收實(shí)例代碼,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-12-12