概述:emoji和文本混在一起该怎么解析?做过微信都知道,不能直接判断发过是文本还是其他事件?必须要解析出来,但是解析成字符串之后,你会发现emoji会产生异常,或者显示不出来,因为emoji都是\开头字符串代表emoji,但是在解析成字符串,无论你用utf-8都不可以满足要求。
你会想读取两遍,但InputStream不允许重复读,是否存在可以重复的流,把它缓存起来,ByteArrayOutputStream就可以重复读。
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>12345678</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[你好]]></Content>
</xml>
日志:
<?xml version="1.0" encoding="utf-8"?><xml> <ToUserName><![CDATA[33dfdfd]]></ToUserName> <FromUserName><![CDATA[3333-T_hZDR-YRjY]]></FromUserName> <CreateTime>1501751512</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[類峕]></Content> <MsgId>6449973631174700350</MsgId> <Encrypt><![ddfd]]></Encrypt></xml>
这个emoji最后把右号解析没了
首先整个缓存类:
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 缓存InputStream,以便InputStream的重复利用
*/
public class InputStreamCacher {
private static final Logger logger = LoggerFactory.getLogger(InputStreamCacher.class);
/**
* 将InputStream中的字节保存到ByteArrayOutputStream中。
*/
private ByteArrayOutputStream byteArrayOutputStream = null;
public InputStreamCacher(InputStream inputStream) throws IOException {
if(inputStream == null) {
return ;
}
byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
try {
while ((len = inputStream.read(buffer)) > -1 ) {
byteArrayOutputStream.write(buffer, 0, len);
}
byteArrayOutputStream.flush();
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
public InputStream getInputStream() {
if (byteArrayOutputStream == null || byteArrayOutputStream.size()<0)
return null;
return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
}
}
@Controller
@RequestMapping("/weixin")
public class WeiXinEventDispatchController {
@Autowired
private WeiXinTokenAndTicket weiXinToken;
@Autowired
private WeiXinMsgService weiXinMsgService;
Logger logger = LoggerFactory.getLogger(WeiXinEventDispatchController.class);
@ResponseBody
@RequestMapping(value="/event", method = {RequestMethod.POST,RequestMethod.GET})
public void event(HttpServletRequest request, HttpServletResponse response) throws IOException, JAXBException {
WeiXinRequestBaseParameter weiXinParameter = WeiXinUtil.installParamter(request);
InputStream is = request.getInputStream();
InputStreamCacher cache = new InputStreamCacher(is);
String data = XmlUtil.inputStream2Str(cache.getInputStream());
logger.info("============================data=======================================");
logger.info("=" + data);
if(data.contains("<MsgType><![CDATA[event]]></MsgType>")
&& data.contains("<Event><![CDATA[CLICK]]></Event>")){
String result = data.replace("<![CDATA[", "").replace("]]>", "").trim();
JAXBContext context = JAXBContext.newInstance(MenuClickEventDTO.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
MenuClickEventDTO obj = (MenuClickEventDTO)unmarshaller.unmarshal(new StringReader(result));
logger.info(obj.toString());
}else if(data.contains("<MsgType><![CDATA[event]]></MsgType>")
&& data.contains("<Event><![CDATA[VIEW]]></Event>")){
logger.info("发来了VIEW事件");
}else if(data.contains("<MsgType><![CDATA[event]]></MsgType>")
&& data.contains("<Event><![CDATA[subscribe]]></Event>")){
logger.info("订阅公众号");
weiXinMsgService.subscribe(weiXinParameter,data,response);
}else if(data.contains("<MsgType><![CDATA[event]]></MsgType>")
&& data.contains("<Event><![CDATA[unsubscribe]]></Event>")){
logger.info("取消公众号");
weiXinMsgService.unsubscribe(weiXinParameter,data,response);
}else if(data.contains("<MsgType><![CDATA[voice]]></MsgType>")){
logger.info("语言消息");
weiXinMsgService.voiceHandle(weiXinParameter,data,response);
}else if(data.contains("<MsgType><![CDATA[text]]></MsgType>")){
logger.info("文本消息");
weiXinMsgService.textHandle(data,response,cache.getInputStream());
//response.getOutputStream().write(new String(out.toString()).trim().getBytes("UTF-8"));
}else {
logger.info("未知事件");
if(SignUtil.checkSignature(weiXinParameter)) {
logger.info(weiXinParameter.toString());
response.getOutputStream().write(new String(weiXinParameter.getEchostr()).trim().getBytes("UTF-8"));
}
}
}
}
InputStreamCacher cache = new InputStreamCacher(is);可以看出我先将流缓存起来,然后再用。
把必须类或方法贴出来
/**
* 组装微信请求的数据
* @param request
* @return
*/
public static WeiXinRequestBaseParameter installParamter(HttpServletRequest request){
WeiXinRequestBaseParameter parameter = new WeiXinRequestBaseParameter();
//微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp,nonce参数
parameter.setSignature(request.getParameter("signature"));
//时间戳
parameter.setTimestamp(request.getParameter("timestamp"));
//获取openId
parameter.setOpenid( request.getParameter("openid"));
//随机数
parameter.setNonce(request.getParameter("nonce"));
parameter.setEchostr(request.getParameter("echostr"));
return parameter;
}
import java.io.Serializable;
/**
* @author jack
* @version 1.0
*
*/
public class WeiXinRequestBaseParameter implements Serializable {
/**
*
*/
private static final long serialVersionUID = 2297652335403982945L;
private String signature;
private String timestamp;
private String openid;
private String nonce;
private String echostr;
public WeiXinRequestBaseParameter(String signature, String timestamp, String openid, String nonce, String echostr) {
super();
this.signature = signature;
this.timestamp = timestamp;
this.openid = openid;
this.nonce = nonce;
this.echostr = echostr;
}
public WeiXinRequestBaseParameter() {
super();
}
public String getEchostr() {
return echostr;
}
public String getNonce() {
return nonce;
}
public String getOpenid() {
return openid;
}
public String getSignature() {
return signature;
}
public String getTimestamp() {
return timestamp;
}
public void setEchostr(String echostr) {
this.echostr = echostr;
}
public void setNonce(String nonce) {
this.nonce = nonce;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public void setSignature(String signature) {
this.signature = signature;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
@Override
public String toString() {
return "WeiXinRequestBaseParameter [signature=" + signature + ", timestamp=" + timestamp + ", openid=" + openid
+ ", nonce=" + nonce + ", echostr=" + echostr + "]";
}
}
/**
* @param input
* @return 返回一个xml
* @throws IOException
*/
public static String inputStream2Str(InputStream input) throws IOException{
StringBuffer sb = new StringBuffer("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
InputStreamReader inputReader = new InputStreamReader(input);
BufferedReader buffer = new BufferedReader(inputReader);
String str = "";
while ((str = buffer.readLine()) != null) {
sb.append(new String(str));
}
input.close();
return sb.toString().trim();
}
@Override
public void textHandle(String data, HttpServletResponse response,InputStream inputStream) throws JAXBException, IOException {
JAXBContext unmarshJc = JAXBContext.newInstance(MsgTextReqDTO.class);
JAXBContext marshJc = JAXBContext.newInstance(MsgTextRespDTO.class);
Unmarshaller unmarshaller = unmarshJc.createUnmarshaller();
MsgTextReqDTO msgTextReqDTO = (MsgTextReqDTO) unmarshaller.unmarshal(inputStream);
//MsgTextReqDTO msgTextReqDTO = (MsgTextReqDTO) unmarshaller.unmarshal(new StringReader(data));
logger.info("Unmarshal: " +msgTextReqDTO.toString());
Marshaller marshaller = marshJc.createMarshaller();
//marshaller.setProperty(Marshaller.JAXB_ENCODING, "gbk");
MsgTextRespDTO msgRespDTO = new MsgTextRespDTO();
//======================硬编码================
msgRespDTO.setContent(msgTextReqDTO.getContent());
msgRespDTO.setCreateTime(WeiXinUtil.createTimestamp());
msgRespDTO.setFromUserName(msgTextReqDTO.getToUserName());
msgRespDTO.setMsgType(msgTextReqDTO.getMsgType());
msgRespDTO.setToUserName(msgTextReqDTO.getFromUserName());
marshaller.marshal(msgRespDTO, response.getOutputStream());
}
实体类
import java.io.Serializable;
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.persistence.oxm.annotations.XmlCDATA;
import org.eclipse.persistence.oxm.annotations.XmlPath;
import com.rinlink.intelligent.weixin.entity.WeiXinBaseDTO;
/**
* 文本消息
* @author jack
*
*/
@XmlRootElement(name="xml")
public class MsgTextReqDTO extends WeiXinBaseDTO implements Serializable{
/**
*
*/
private static final long serialVersionUID = -1964882722743733100L;
@XmlCDATA
@XmlPath("Content/text()")
private String content;
@XmlCDATA
@XmlPath("Encrypt/text()")
private String encrypt;
@XmlPath("MsgId/text()")
private String msgId;
public MsgTextReqDTO() {
super();
}
public String getEncrypt() {
return encrypt;
}
public void setEncrypt(String encrypt) {
this.encrypt = encrypt;
}
public String getContent() {
return content;
}
public String getMsgId() {
return msgId;
}
public void setContent(String content) {
this.content = content;
}
public void setMsgId(String msgId) {
this.msgId = msgId;
}
}
import org.eclipse.persistence.oxm.annotations.XmlCDATA;
import org.eclipse.persistence.oxm.annotations.XmlPath;
public class WeiXinBaseDTO {
@XmlCDATA
@XmlPath("ToUserName/text()")
private String toUserName;
@XmlCDATA
@XmlPath("FromUserName/text()")
private String fromUserName;
@XmlPath("CreateTime/text()")
private String createTime;
@XmlCDATA
@XmlPath("MsgType/text()")
private String msgType;
public String getToUserName() {
return toUserName;
}
public String getFromUserName() {
return fromUserName;
}
public String getCreateTime() {
return createTime;
}
public String getMsgType() {
return msgType;
}
public void setToUserName(String toUserName) {
this.toUserName = toUserName;
}
public void setFromUserName(String fromUserName) {
this.fromUserName = fromUserName;
}
public void setCreateTime(String createTime) {
this.createTime = createTime;
}
public void setMsgType(String msgType) {
this.msgType = msgType;
}
@Override
public String toString() {
return "WeiXinBaseDTO [toUserName=" + toUserName + ", fromUserName=" + fromUserName + ", createTime="
+ createTime + ", msgType=" + msgType + "]";
}
}
import java.io.Serializable;
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.persistence.oxm.annotations.XmlCDATA;
import org.eclipse.persistence.oxm.annotations.XmlPath;
import com.rinlink.intelligent.weixin.entity.WeiXinBaseDTO;
/**
* 回复文本消息
* @author jack
*
*/
/**
* @author Administrator
*
*/
@XmlRootElement(name="xml")
public class MsgTextRespDTO extends WeiXinBaseDTO implements Serializable{
/**
*
*/
private static final long serialVersionUID = -1964882722743733100L;
@XmlCDATA
@XmlPath("Content/text()")
private String content;
public MsgTextRespDTO() {
super();
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "MsgTextRespDTO [content=" + content + "]" + " " + super.toString();
}
}
需要增加一个属性文件
名称:jaxb.properties
内容: javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
文件结构:
注意事项:
1.引入jar
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.moxy</artifactId>
<version>2.7.0-RC1</version>
</dependency>
2.这里采用SpringMVC+Maven工程,可以根据你自己改装一下
3.不需要设置字符编码。正如上面注释的
//marshaller.setProperty(Marshaller.JAXB_ENCODING, "gbk");