View Javadoc
1   package com.foxinmy.weixin4j.socket;
2   
3   import java.util.List;
4   
5   import com.foxinmy.weixin4j.response.WeixinResponse;
6   import com.foxinmy.weixin4j.type.EncryptType;
7   import com.foxinmy.weixin4j.util.AesToken;
8   import com.foxinmy.weixin4j.util.HttpUtil;
9   import com.foxinmy.weixin4j.util.MessageUtil;
10  import com.foxinmy.weixin4j.util.ServerToolkits;
11  
12  import io.netty.channel.ChannelHandler;
13  import io.netty.channel.ChannelHandlerContext;
14  import io.netty.handler.codec.MessageToMessageEncoder;
15  import io.netty.util.internal.logging.InternalLogger;
16  import io.netty.util.internal.logging.InternalLoggerFactory;
17  
18  /**
19   * 微信回复编码类
20   *
21   * @className WeixinResponseEncoder
22   * @author jinyu(foxinmy@gmail.com)
23   * @date 2014年11月13日
24   * @since JDK 1.6
25   * @see <a href=
26   *      "http://mp.weixin.qq.com/wiki/0/61c3a8b9d50ac74f18bdf2e54ddfc4e0.html">加密接入指引</a>
27   * @see com.foxinmy.weixin4j.response.WeixinResponse
28   */
29  @ChannelHandler.Sharable
30  public class WeixinResponseEncoder extends MessageToMessageEncoder<WeixinResponse> {
31  
32      protected final InternalLogger logger = InternalLoggerFactory.getInstance(getClass());
33  
34      private final String XML_START = "<xml>";
35      // ---------------明文节点
36      private final String ELEMENT_TOUSERNAME = "<ToUserName><![CDATA[%s]]></ToUserName>";
37      private final String ELEMENT_FROMUSERNAME = "<FromUserName><![CDATA[%s]]></FromUserName>";
38      private final String ELEMENT_CREATETIME = "<CreateTime><![CDATA[%d]]></CreateTime>";
39      private final String ELEMENT_MSGTYPE = "<MsgType><![CDATA[%s]]></MsgType>";
40      // ---------------密文节点
41      private final String ELEMENT_MSGSIGNATURE = "<MsgSignature><![CDATA[%s]]></MsgSignature>";
42      private final String ELEMENT_ENCRYPT = "<Encrypt><![CDATA[%s]]></Encrypt>";
43      private final String ELEMENT_TIMESTAMP = "<TimeStamp><![CDATA[%s]]></TimeStamp>";
44      private final String ELEMENT_NONCE = "<Nonce><![CDATA[%s]]></Nonce>";
45      private final String XML_END = "</xml>";
46  
47      @Override
48      protected void encode(ChannelHandlerContext ctx, WeixinResponse response, List<Object> out) {
49          WeixinMessageTransfer messageTransfer = ctx.channel().attr(ServerToolkits.MESSAGE_TRANSFER_KEY).get();
50          EncryptType encryptType = messageTransfer.getEncryptType();
51          StringBuilder content = new StringBuilder();
52          content.append(XML_START);
53          content.append(String.format(ELEMENT_TOUSERNAME, messageTransfer.getFromUserName()));
54          content.append(String.format(ELEMENT_FROMUSERNAME, messageTransfer.getToUserName()));
55          content.append(String.format(ELEMENT_CREATETIME, System.currentTimeMillis() / 1000l));
56          content.append(String.format(ELEMENT_MSGTYPE, response.getMsgType()));
57          content.append(response.toContent());
58          content.append(XML_END);
59          if (encryptType == EncryptType.AES) {
60              AesToken aesToken = messageTransfer.getAesToken();
61              String nonce = ServerToolkits.generateRandomString(32);
62              String timestamp = Long.toString(System.currentTimeMillis() / 1000l);
63              String encrtypt = MessageUtil.aesEncrypt(aesToken.getWeixinId(), aesToken.getAesKey(), content.toString());
64              String msgSignature = MessageUtil.signature(aesToken.getToken(), nonce, timestamp, encrtypt);
65              content.delete(0, content.length());
66              content.append(XML_START);
67              content.append(String.format(ELEMENT_NONCE, nonce));
68              content.append(String.format(ELEMENT_TIMESTAMP, timestamp));
69              content.append(String.format(ELEMENT_MSGSIGNATURE, msgSignature));
70              content.append(String.format(ELEMENT_ENCRYPT, encrtypt));
71              content.append(XML_END);
72          }
73          ctx.writeAndFlush(HttpUtil.createHttpResponse(content.toString(), ServerToolkits.CONTENTTYPE$APPLICATION_XML));
74          logger.info("{} encode weixin response:{}", encryptType, content);
75      }
76  }