为JAXB和response设置编码,解决wechat4j中文乱码
如果有哪一个做程序员的小伙伴说自己没有遇到中文乱码问题,我是不愿意相信的。今天在做微信订阅号的智能回复时,又一时迷乱的跳进了中文乱码这个火坑。刚解决问题时,都欢呼雀跃了,完全忘记了她曾经带给我的痛苦。
一、问题描述
看到没,红色框框内的乱码赤裸裸的对我进行挑衅,而我却无可奈何,真是糟糕透顶。
二、寻求解决之道
面对问题,只有拿着刀逼自己去解决啊,能怎么样呢?
首先,必须搞清楚微信智能回复的机制,画图如下:
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编码。三处缺一不可。
这次这么透彻,应该解决了问题了吧,但是解决依然中文乱码,那该如何是好呢?
3.tomcat的输出环境作怪
针对这一点,网上有人提供这样的解决思路。
set JAVA_OPTS=%JAVA_OPTS% %LOGGING_MANAGER% -Dfile.encoding=UTF-8
设置后重启tomcat,问题是能够解决,但副作用是整个tomcat在服务器上运行输出(tomcat的cmd窗口)一直是乱码,我认为这种方案不可取。
在运行的war中加入以下代码
System.getProperty("file.encoding");
你会惊奇的发现,tomcat的运行环境(window server 2008)竟然是GBK,不知道你是否不惊奇,我是吓到了,为什么不是UTF-8呢?如果是GBK的话,上面两个步骤中我加入再多的UTF-8页扯淡啊,不解。
三、解决问题
有了以上的经验,我们修改以下wechat4j的代码,主要是第二点。
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);// 去掉报文头
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;
}
这两个方法中,对encoding我们加上可配置的编码方式,可手动设置GBK(我的服务器上配置了GBK)、GB2312、UTF-8。
如此,会发现wechat4j的后台输出就不再是中文乱码了,但返回给用户的信息更乱了。
怎么能这样呢,耍我这枚程序员啊,真想吐两句脏话。但别怕啊,既然wechat4j的logger日志不再中文乱码,那么只能说是第1个环节又出现问题了。
调整嘛
response.setHeader("content-type", "text/html;charset=UTF-8");// 浏览器编码
response.getOutputStream().write(result.getBytes("UTF-8"));
注意,这里不能是GBK,只能是UTF-8,我表示不清楚为什么,微信的产品经理给出来解释下。
重点,JAXB和response合伙解决wechat4j中文乱码的 方法再次声明如下:
WeChatController.java,就是你配给微信公众开发平台的URL处,response调整如下
response.setHeader("content-type", "text/html;charset=UTF-8");// 浏览器编码
response.getOutputStream().write(result.getBytes("UTF-8"));
wechat4j的JaxbParser.java,分别调整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);// 去掉报文头
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;
}
好了,万事大吉了。
为JAXB和response设置编码,解决wechat4j中文乱码的更多相关文章
- Servlet学习(五)——通过response设置响应体及中文乱码问题
1.响应体设置文本 PrintWriter writer=response.getWriter(); 获得字符流,通过字符流的write(String s)方法可以将字符串设置到response 缓冲 ...
- Linux Centos7设置UTF-8编码,防止中文乱码
Linux Centos7设置UTF-8编码,防止中文乱码 # localeLANG=zh_CN.gb2312LC_CTYPE="zh_CN.gb2312"LC_NUMERIC=& ...
- Ubuntu14.04安装中文输入法以及解决Gedit中文乱码问题
1 设置中文显示环境 1. 打开System Settings 2. 打开Personal-> Language Support. 会弹出如下对话框,提示你“语言支持没安装完整”. 点击“Rem ...
- Ubuntu14.04安装中文输入法以及解决Gedit中文乱码问题[转载]
转载自:http://www.cnblogs.com/zhcncn/p/4032321.html 写在前面:解决gedit 在txt文件格式出现乱码的问题,在我自己的操作中是需要把系统设置成中文显示环 ...
- 解决mysql中文乱码问题?
mysql是我们项目中非常常用的数据型数据库.但是因为我们需要在数据库保存中文字符,所以经常遇到数据库乱码情况.下面就来介绍一下如何彻底解决数据库中文乱码情况. 1.中文乱码 1.1.中文乱码 cre ...
- 彻底解决mysql中文乱码
mysql是我们项目中非常常用的数据型数据库.但是因为我们需要在数据库保存中文字符,所以经常遇到数据库乱码情况.下面就来介绍一下如何彻底解决数据库中文乱码情况. 1.中文乱码 1.1.中文乱码 cre ...
- 如何解决PHP中文乱码问题
如何解决PHP中文乱码问题 一.解决HTML中中文乱码问题方法 1.在head标签里面加入UTF8编码(国际化编码):UTF-8是没有国家的编码,也就是独立于任何一种语言,任何语言都可以使用的. ...
- 解决URL中文乱码问题--对中文进行加密、解密处理
解决URL中文乱码问题--对中文进行加密.解密处理 情景:在资源调度中,首先用户需要选择工作目标,然后跟据选择的工作目标不同而选择不同的账号和代理ip.处理过程如下:点击选择账号,在js中获取工作目标 ...
- request.getParameter()及解决数据库中文乱码问题——实习第七天
今天老师让我们自己做一个小项目,我开始着手于实现这个小项目.途中遇到过几个小问题,在此做个小记录, 相信后期还是会借鉴的. 1,从前台传入数据给后台传入数据,并没有传入成功: 输出的为Null. 当然 ...
随机推荐
- java的double类型如何精确到一位小数?
java的double类型如何精确到一位小数? //分钟转小时vacationNum = (double)Math.round(vacationNum/60*10)/10.0;overTimeNum ...
- winsxs清理
win7的网友经常问:C:Windowswinsxs文件夹下是什么文件,可以删除吗? 答案是不建议你删除的,如果你特别想删除的话我推荐你一个工具. 本人亲测系统正常运行. 可以为C盘剩下将近4G空间 ...
- 微软MVP Round Table
2017年7月7日,微软VS圈子的老大兼女神Julia(潘正磊)以及Peter Hu等人,和若干MVP一起在进行了一次Round Table讨论. 讨论过程中主要针对VS和TFS/VSTS相关的功能. ...
- 穿透Session 0 隔离(一)
服务(Service)对于大家来说一定不会陌生,它是Windows 操作系统重要的组成部分.我们可以把服务想像成一种特殊的应用程序,它随系统的“开启-关闭”而“开始-停止”其工作内容,在这期间无需任何 ...
- IE11上登陆oracle OEM时报:“证书错误,导航已阻止”且无继续浏览此网站(不推荐)的错误
问题原因:oracle oem证书的密钥小于1024 解决方案:在cmd中执行命令:certutil -setreg chain\EnableWeakSignatureFlags 8 出现以下提示: ...
- visual studio 下 C++生成dump文件
1 lib配置 项目-->属性-->配置属性-->链接器-->输入-->附加依赖项 增加dbghelp.lib 2 头文件 #include <imagehlp.h ...
- VS2008里的代码如何格式化
选中要格式化的代码, 先按Ctrl+K 再按Ctrl+F 从菜单中也可以 "编辑"->"高级"->"设置文档的格式Ctrl+K Ctrl+ ...
- 10.php引用(&)详解及注意事项
<?php function &test() { static $b=0;//申明一个静态变量 $b=$b+1; echo $b; return $b; } $a=test();//这条 ...
- 解决:function in namespace ‘std’ does not name a type + allocator_/nullptr/dellocator_ was not declared + base operand of ‘->’ has non-pointer type ‘std::vector<cv::Mat>’ 错误编译时报错(caffe)
解决方法,用到了c++11,g++命令需要加上-std=c++11选项 附:g++默认的c++标准 gcc-6.4.0 gcc-7.2.0 默认是 -std=gnu++14gcc-4.3.6 gcc- ...
- 解锁Opera浏览器新姿势:【Surf The Internet In Right Ways】
下载Opera浏览器 官网下载:https://www.opera.com/zh-cn 更改PC系统区域 我的本子是win10,其他系统未测. 进入: 设置 → 区域和语言 将国家或地区设置为:中国台 ...