天天看點

為JAXB和response設定編碼,解決wechat4j中文亂碼(1)

如果有哪一個做程式員的小夥伴說自己沒有遇到中文亂碼問題,我是不願意相信的。今天在做微信訂閱号的智能回複時,又一時迷亂的跳進了中文亂碼這個火坑。剛解決問題時,都歡呼雀躍了,完全忘記了她曾經帶給我的痛苦。

一、問題描述

為JAXB和response設定編碼,解決wechat4j中文亂碼(1)

看到沒,紅色框框内的亂碼赤裸裸的對我進行挑釁,而我卻無可奈何,真是糟糕透頂。

二、尋求解決之道

面對問題,隻有拿着刀逼自己去解決啊,能怎麼樣呢?

首先,必須搞清楚微信智能回複的機制,畫圖如下:

為JAXB和response設定編碼,解決wechat4j中文亂碼(1)

ps,工具用得不好,請見諒。

接下來,我們抓重點,看亂碼重要發生在什麼位置。

1.controller傳回給使用者

response.setHeader("content-type", "text/html;charset=UTF-8");// 浏覽器編碼

response.getOutputStream().write(result.getBytes());

就這段代碼了,指定response的編碼方式為UTF-8,按理說亂碼問題應該出現好轉,但是結果依然是沒有。

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);// 去掉封包頭

        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;
}      

這裡有三個關鍵的點:

1. m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");

2. getXMLSerializer(os)

3. os.toString("UTF-8");

可以看到以上三個地方均會涉及到轉碼,第1處,設定Marshaller的編碼;第二處,設定整個XMLSerializer的編碼;第三處,設定傳回的ByteArrayOutputStream的string編碼。三處缺一不可。

這次這麼透徹,應該解決了問題了吧,但是解決依然中文亂碼,那該如何是好呢?

繼續閱讀