本文介绍微信公众号消息自动回复功能的开发,开发语言 java话不多说,直接上代码

1.控制器代码
package webapp.controller;import org.springframework.context.annotation.Scope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import webapp.ext.WechatSignUtil;
import webapp.ext.wechat.AuthProcess;
import webapp.ext.wechat.MessageUtil;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;@Scope("prototype")
@RestControllerpublic class NotifyController {@RequestMapping(value = "notify",method = { RequestMethod.GET, RequestMethod.POST })@ResponseBodypublic String wechatNotify(HttpServletRequest request, HttpServletResponse response, String signature, String timestamp,String nonce, String echostr) throws IOException {boolean isGet = request.getMethod().toLowerCase().equals("get");if (isGet) {boolean isOk = WechatSignUtil.checkSignature(signature, timestamp, nonce);if (isOk)return echostr;elsereturn null;} else {String resp = "";request.setCharacterEncoding("UTF-8");response.setCharacterEncoding("UTF-8");try {Map<String,String> map = MessageUtil.xmlToMap(request);String xml = "<xml><ToUserName>"+map.get("ToUserName")+"</ToUserName><Encrypt>" +map.get("Encrypt")+"</Encrypt></xml>";String result = AuthProcess.decryptMsg(request, xml);Map<String, Object> req = MessageUtil.xmlStr2Map(result);boolean hasEvent = req.containsKey("Event");String respXml = "";if (hasEvent) {String event = req.get("Event").toString();if ("subscribe".equals(event)) {//用户订阅公众号行为HashMap<String, Object> mapXml = new HashMap<>();mapXml.put("ToUserName",req.get("FromUserName"));mapXml.put("FromUserName",req.get("ToUserName"));mapXml.put("CreateTime",req.get("CreateTime"));mapXml.put("MsgType","text");mapXml.put("Content","感谢关注");respXml = MessageUtil.map2Xmlstring(mapXml);}} else {String msgType = req.get("MsgType").toString();String receive = "";if ("text".equals(msgType)){//普通文字消息receive = req.get("Content").toString();} else if ("voice".equals(msgType)){//语音消息//注意:这里Recognition拿到的直接就是语音消息转化之后的文字内容!!!直接用就好了receive = req.get("Recognition").toString();}respXml = sendMsg(req,receive);}resp = AuthProcess.encryptMsg(request, respXml.trim());return resp;} catch (Exception e) {e.printStackTrace();}return resp;}}private String sendMsg(Map<String, Object> req,String receive) {HashMap<String, Object> mapXml = new HashMap<>();mapXml.put("ToUserName",req.get("FromUserName"));mapXml.put("FromUserName",req.get("ToUserName"));mapXml.put("CreateTime",req.get("CreateTime"));mapXml.put("MsgType","text");//根据receive组装回复的内容mapXml.put("Content","回复的消息内容");return MessageUtil.map2Xmlstring(mapXml);}
}

2.杂七杂八的一些类,上面控制器用到的

package webapp.ext.wechat;@SuppressWarnings("serial")
public class AesException extends Exception {public final static int OK = 0;public final static int ValidateSignatureError = -40001;public final static int ParseXmlError = -40002;public final static int ComputeSignatureError = -40003;public final static int IllegalAesKey = -40004;public final static int ValidateAppidError = -40005;public final static int EncryptAESError = -40006;public final static int DecryptAESError = -40007;public final static int IllegalBuffer = -40008;//public final static int EncodeBase64Error = -40009;//public final static int DecodeBase64Error = -40010;//public final static int GenReturnXmlError = -40011;private int code;private static String getMessage(int code) {switch (code) {case ValidateSignatureError:return "签名验证错误";case ParseXmlError:return "xml解析失败";case ComputeSignatureError:return "sha加密生成签名失败";case IllegalAesKey:return "SymmetricKey非法";case ValidateAppidError:return "appid校验失败";case EncryptAESError:return "aes加密失败";case DecryptAESError:return "aes解密失败";case IllegalBuffer:return "解密后得到的buffer非法";
//        case EncodeBase64Error:
//            return "base64加密错误";
//        case DecodeBase64Error:
//            return "base64解密错误";
//        case GenReturnXmlError:
//            return "xml生成失败";default:return null; // cannot be
        }}public int getCode() {return code;}AesException(int code) {super(getMessage(code));this.code = code;}}

View Code

package webapp.ext.wechat;import javax.servlet.http.HttpServletRequest;public class AuthProcess {/*** 将加密后的原文进行解密重新封装* @param request* @param originalXml 原xml* @return    重新解密后的xml*/public static String  decryptMsg(HttpServletRequest request,String originalXml) {// 微信加密签名//String sVerifyMsgSig = request.getParameter("signature");String msgSignature = request.getParameter("msg_signature");// 时间戳String timestamp = request.getParameter("timestamp");// 随机数String nonce = request.getParameter("nonce");try {WXBizMsgCrypt pc = new WXBizMsgCrypt("your token", "your EncodingAESKey", "your appid");return pc.decryptMsg(msgSignature, timestamp, nonce, originalXml);} catch (AesException e) {// TODO Auto-generated catch block
            e.printStackTrace();}return null;}/*** 对需要回复的原文进行加密重新封装* @param request* @param replyXml 需要回复的xml* @return    重新加密后的xml*/public static String  encryptMsg(HttpServletRequest request, String replyXml) {// 时间戳String timestamp = request.getParameter("timestamp");// 随机数String nonce = request.getParameter("nonce");try {WXBizMsgCrypt pc = new WXBizMsgCrypt("your token", "your EncodingAESKey", "your appid");return pc.encryptMsg(replyXml, timestamp, nonce);} catch (AesException e) {// TODO Auto-generated catch block
            e.printStackTrace();}return null;}}

View Code

package webapp.ext.wechat;import java.util.ArrayList;class ByteGroup {ArrayList<Byte> byteContainer = new ArrayList<Byte>();public byte[] toBytes() {byte[] bytes = new byte[byteContainer.size()];for (int i = 0; i < byteContainer.size(); i++) {bytes[i] = byteContainer.get(i);}return bytes;}public ByteGroup addBytes(byte[] bytes) {for (byte b : bytes) {byteContainer.add(b);}return this;}public int size() {return byteContainer.size();}
}

View Code

package webapp.ext.wechat;import com.thoughtworks.xstream.XStream;
import org.apache.http.util.TextUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;public class MessageUtil {public static final String MESSAGE_TEXT = "text";public static final String MESSAGE_IMAGE = "image";public static final String MESSAGE_VOICE = "voice";public static final String MESSAGE_VIDEO = "video";public static final String MESSAGE_LINK = "link";public static final String MESSAGE_LOCATION = "location";public static final String MESSAGE_EVENT = "event";public static final String EVENT_SUB = "subscribe";public static final String EVENT_UNSUB = "unsubscribe";public static final String EVENT_CLICK = "CLICK";public static final String EVENT_VIEW = "VIEW";/*** xml转为map* @param request* @return* @throws DocumentException* @throws IOException*/public static Map<String, String> xmlToMap(HttpServletRequest request ) throws DocumentException, IOException{Map<String,String> map = new HashMap<String, String>();SAXReader reader = new SAXReader();InputStream ins = request.getInputStream();Document doc = reader.read(ins);Element root = doc.getRootElement();List<Element> list = root.elements();for (Element e : list) {map.put(e.getName(), e.getText());}ins.close();return map;}public static String textMessageToXml(TextMessage textMessage){XStream xstream = new XStream();xstream.alias("xml", textMessage.getClass());return xstream.toXML(textMessage);}public static Map<String,Object> xmlStr2Map(String xmlStr){Map<String,Object> map = new HashMap<String,Object>();Document doc;try {doc = DocumentHelper.parseText(xmlStr);Element root = doc.getRootElement();List children = root.elements();if(children != null && children.size() > 0) {for(int i = 0; i < children.size(); i++) {Element child = (Element)children.get(i);map.put(child.getName(), child.getTextTrim());}}} catch (DocumentException e) {e.printStackTrace();}return map;}public static String map2Xmlstring(Map<String,Object> map){StringBuffer sb = new StringBuffer("");sb.append("<xml>");Set<String> set = map.keySet();for(Iterator<String> it = set.iterator(); it.hasNext();){String key = it.next();Object value = map.get(key);sb.append("<").append(key).append(">");sb.append(value);sb.append("</").append(key).append(">");}sb.append("</xml>");return sb.toString();}public static String map2XmlstringWithHead(Map<String,Object> map,String head){StringBuffer sb = new StringBuffer("");if (!TextUtils.isEmpty(head)) {sb.append("<"+head+">");}Set<String> set = map.keySet();for(Iterator<String> it = set.iterator(); it.hasNext();){String key = it.next();Object value = map.get(key);sb.append("<").append(key).append(">");sb.append(value);sb.append("</").append(key).append(">");}if (!TextUtils.isEmpty(head)) {sb.append("</"+head+">");}return sb.toString();}}

View Code

/*** 对公众平台发送给公众账号的消息加解密示例代码.* * @copyright Copyright (c) 1998-2014 Tencent Inc.*/// ------------------------------------------------------------------------package webapp.ext.wechat;import java.nio.charset.Charset;
import java.util.Arrays;/*** 提供基于PKCS7算法的加解密接口.*/
class PKCS7Encoder {static Charset CHARSET = Charset.forName("utf-8");static int BLOCK_SIZE = 32;/*** 获得对明文进行补位填充的字节.* * @param count 需要进行填充补位操作的明文字节个数* @return 补齐用的字节数组*/static byte[] encode(int count) {// 计算需要填充的位数int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);if (amountToPad == 0) {amountToPad = BLOCK_SIZE;}// 获得补位所用的字符char padChr = chr(amountToPad);String tmp = new String();for (int index = 0; index < amountToPad; index++) {tmp += padChr;}return tmp.getBytes(CHARSET);}/*** 删除解密后明文的补位字符* * @param decrypted 解密后的明文* @return 删除补位字符后的明文*/static byte[] decode(byte[] decrypted) {int pad = (int) decrypted[decrypted.length - 1];if (pad < 1 || pad > 32) {pad = 0;}return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);}/*** 将数字转化成ASCII码对应的字符,用于对明文进行补码* * @param a 需要转化的数字* @return 转化得到的字符*/static char chr(int a) {byte target = (byte) (a & 0xFF);return (char) target;}}

View Code

/*** 对公众平台发送给公众账号的消息加解密示例代码.* * @copyright Copyright (c) 1998-2014 Tencent Inc.*/// ------------------------------------------------------------------------package webapp.ext.wechat;import java.security.MessageDigest;
import java.util.Arrays;/*** SHA1 class** 计算公众平台的消息签名接口.*/
class SHA1 {/*** 用SHA1算法生成安全签名* @param token 票据* @param timestamp 时间戳* @param nonce 随机字符串* @param encrypt 密文* @return 安全签名* @throws com.qq.weixin.mp.aes.AesException*/public static String getSHA1(String token, String timestamp, String nonce, String encrypt) throws AesException{try {String[] array = new String[] { token, timestamp, nonce, encrypt };StringBuffer sb = new StringBuffer();// 字符串排序
            Arrays.sort(array);for (int i = 0; i < 4; i++) {sb.append(array[i]);}String str = sb.toString();// SHA1签名生成MessageDigest md = MessageDigest.getInstance("SHA-1");md.update(str.getBytes());byte[] digest = md.digest();StringBuffer hexstr = new StringBuffer();String shaHex = "";for (int i = 0; i < digest.length; i++) {shaHex = Integer.toHexString(digest[i] & 0xFF);if (shaHex.length() < 2) {hexstr.append(0);}hexstr.append(shaHex);}return hexstr.toString();} catch (Exception e) {e.printStackTrace();throw new AesException(AesException.ComputeSignatureError);}}
}

View Code

package webapp.ext.wechat;public class TextMessage {public String ToUserName;public String FromUserName;public int CreateTime;public String MsgType;public String Content;public String getToUserName() {return ToUserName;}public void setToUserName(String toUserName) {ToUserName = toUserName;}public String getFromUserName() {return FromUserName;}public void setFromUserName(String fromUserName) {FromUserName = fromUserName;}public int getCreateTime() {return CreateTime;}public void setCreateTime(int createTime) {CreateTime = createTime;}public String getMsgType() {return MsgType;}public void setMsgType(String msgType) {MsgType = msgType;}public String getContent() {return Content;}public void setContent(String content) {Content = content;}
}

View Code

/*** 对公众平台发送给公众账号的消息加解密示例代码.* * @copyright Copyright (c) 1998-2014 Tencent Inc.*/// ------------------------------------------------------------------------/*** 针对org.apache.commons.codec.binary.Base64,* 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本)* 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi*/
package webapp.ext.wechat;import org.apache.commons.codec.binary.Base64;import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Random;/*** 提供接收和推送给公众平台消息的加解密接口(UTF8编码的字符串).* <ol>*     <li>第三方回复加密消息给公众平台</li>*     <li>第三方收到公众平台发送的消息,验证消息的安全性,并对消息进行解密。</li>* </ol>* 说明:异常java.security.InvalidKeyException:illegal Key Size的解决方案* <ol>*     <li>在官方网站下载JCE无限制权限策略文件(JDK7的下载地址:*      http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html</li>*     <li>下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt</li>*     <li>如果安装了JRE,将两个jar文件放到%JRE_HOME%\lib\security目录下覆盖原来的文件</li>*     <li>如果安装了JDK,将两个jar文件放到%JDK_HOME%\jre\lib\security目录下覆盖原来文件</li>* </ol>*/
public class WXBizMsgCrypt {static Charset CHARSET = Charset.forName("utf-8");Base64 base64 = new Base64();byte[] aesKey;String token;String appId;/*** 构造函数* @param token 公众平台上,开发者设置的token* @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey* @param appId 公众平台appid* * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息*/public WXBizMsgCrypt(String token, String encodingAesKey, String appId) throws AesException {if (encodingAesKey.length() != 43) {throw new AesException(AesException.IllegalAesKey);}this.token = token;this.appId = appId;aesKey = Base64.decodeBase64(encodingAesKey + "=");}// 生成4个字节的网络字节序byte[] getNetworkBytesOrder(int sourceNumber) {byte[] orderBytes = new byte[4];orderBytes[3] = (byte) (sourceNumber & 0xFF);orderBytes[2] = (byte) (sourceNumber >> 8 & 0xFF);orderBytes[1] = (byte) (sourceNumber >> 16 & 0xFF);orderBytes[0] = (byte) (sourceNumber >> 24 & 0xFF);return orderBytes;}// 还原4个字节的网络字节序int recoverNetworkBytesOrder(byte[] orderBytes) {int sourceNumber = 0;for (int i = 0; i < 4; i++) {sourceNumber <<= 8;sourceNumber |= orderBytes[i] & 0xff;}return sourceNumber;}// 随机生成16位字符串
    String getRandomStr() {String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";Random random = new Random();StringBuffer sb = new StringBuffer();for (int i = 0; i < 16; i++) {int number = random.nextInt(base.length());sb.append(base.charAt(number));}return sb.toString();}/*** 对明文进行加密.* * @param text 需要加密的明文* @return 加密后base64编码的字符串* @throws AesException aes加密失败*/String encrypt(String randomStr, String text) throws AesException {ByteGroup byteCollector = new ByteGroup();byte[] randomStrBytes = randomStr.getBytes(CHARSET);byte[] textBytes = text.getBytes(CHARSET);byte[] networkBytesOrder = getNetworkBytesOrder(textBytes.length);byte[] appidBytes = appId.getBytes(CHARSET);// randomStr + networkBytesOrder + text + appid
        byteCollector.addBytes(randomStrBytes);byteCollector.addBytes(networkBytesOrder);byteCollector.addBytes(textBytes);byteCollector.addBytes(appidBytes);// ... + pad: 使用自定义的填充方式对明文进行补位填充byte[] padBytes = PKCS7Encoder.encode(byteCollector.size());byteCollector.addBytes(padBytes);// 获得最终的字节流, 未加密byte[] unencrypted = byteCollector.toBytes();try {// 设置加密模式为AES的CBC模式Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16);cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);// 加密byte[] encrypted = cipher.doFinal(unencrypted);// 使用BASE64对加密后的字符串进行编码String base64Encrypted = base64.encodeToString(encrypted);return base64Encrypted;} catch (Exception e) {e.printStackTrace();throw new AesException(AesException.EncryptAESError);}}/*** 对密文进行解密.* * @param text 需要解密的密文* @return 解密得到的明文* @throws AesException aes解密失败*/String decrypt(String text) throws AesException {byte[] original;try {// 设置解密模式为AES的CBC模式Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES");IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));cipher.init(Cipher.DECRYPT_MODE, key_spec, iv);// 使用BASE64对密文进行解码byte[] encrypted = Base64.decodeBase64(text);// 解密original = cipher.doFinal(encrypted);} catch (Exception e) {e.printStackTrace();throw new AesException(AesException.DecryptAESError);}String xmlContent, from_appid;try {// 去除补位字符byte[] bytes = PKCS7Encoder.decode(original);// 分离16位随机字符串,网络字节序和AppIdbyte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);int xmlLength = recoverNetworkBytesOrder(networkOrder);xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);from_appid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length),CHARSET);} catch (Exception e) {e.printStackTrace();throw new AesException(AesException.IllegalBuffer);}// appid不相同的情况if (!from_appid.equals(appId)) {throw new AesException(AesException.ValidateAppidError);}return xmlContent;}/*** 将公众平台回复用户的消息加密打包.* <ol>*     <li>对要发送的消息进行AES-CBC加密</li>*     <li>生成安全签名</li>*     <li>将消息密文和安全签名打包成xml格式</li>* </ol>* * @param replyMsg 公众平台待回复用户的消息,xml格式的字符串* @param timeStamp 时间戳,可以自己生成,也可以用URL参数的timestamp* @param nonce 随机串,可以自己生成,也可以用URL参数的nonce* * @return 加密后的可以直接回复用户的密文,包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串* @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息*/public String encryptMsg(String replyMsg, String timeStamp, String nonce) throws AesException {// 加密String encrypt = encrypt(getRandomStr(), replyMsg);// 生成安全签名if (timeStamp == "") {timeStamp = Long.toString(System.currentTimeMillis());}String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt);// System.out.println("发送给平台的签名是: " + signature[1].toString());// 生成发送的xmlString result = XMLParse.generate(encrypt, signature, timeStamp, nonce);return result;}/*** 检验消息的真实性,并且获取解密后的明文.* <ol>*     <li>利用收到的密文生成安全签名,进行签名验证</li>*     <li>若验证通过,则提取xml中的加密消息</li>*     <li>对消息进行解密</li>* </ol>* * @param msgSignature 签名串,对应URL参数的msg_signature* @param timeStamp 时间戳,对应URL参数的timestamp* @param nonce 随机串,对应URL参数的nonce* @param postData 密文,对应POST请求的数据* * @return 解密后的原文* @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息*/public String decryptMsg(String msgSignature, String timeStamp, String nonce, String postData)throws AesException {// 密钥,公众账号的app secret// 提取密文Object[] encrypt = XMLParse.extract(postData);// 验证安全签名String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt[1].toString());// 和URL中的签名比较是否相等// System.out.println("第三方收到URL中的签名:" + msg_sign);// System.out.println("第三方校验签名:" + signature);if (!signature.equals(msgSignature)) {throw new AesException(AesException.ValidateSignatureError);}// 解密String result = decrypt(encrypt[1].toString());return result;}/*** 验证URL* @param msgSignature 签名串,对应URL参数的msg_signature* @param timeStamp 时间戳,对应URL参数的timestamp* @param nonce 随机串,对应URL参数的nonce* @param echoStr 随机串,对应URL参数的echostr* * @return 解密之后的echostr* @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息*/public String verifyUrl(String msgSignature, String timeStamp, String nonce, String echoStr)throws AesException {String signature = SHA1.getSHA1(token, timeStamp, nonce, echoStr);if (!signature.equals(msgSignature)) {throw new AesException(AesException.ValidateSignatureError);}String result = decrypt(echoStr);return result;}}

View Code

/*** 对公众平台发送给公众账号的消息加解密示例代码.* * @copyright Copyright (c) 1998-2014 Tencent Inc.*/// ------------------------------------------------------------------------package webapp.ext.wechat;import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;/*** XMLParse class** 提供提取消息格式中的密文及生成回复消息格式的接口.*/
class XMLParse {/*** 提取出xml数据包中的加密消息* @param xmltext 待提取的xml字符串* @return 提取出的加密消息字符串* @throws com.qq.weixin.mp.aes.AesException*/public static Object[] extract(String xmltext) throws AesException {Object[] result = new Object[3];try {DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);dbf.setXIncludeAware(false);dbf.setExpandEntityReferences(false);DocumentBuilder db = dbf.newDocumentBuilder();StringReader sr = new StringReader(xmltext);InputSource is = new InputSource(sr);Document document = db.parse(is);Element root = document.getDocumentElement();NodeList nodelist1 = root.getElementsByTagName("Encrypt");NodeList nodelist2 = root.getElementsByTagName("ToUserName");result[0] = 0;result[1] = nodelist1.item(0).getTextContent();result[2] = nodelist2.item(0).getTextContent();return result;} catch (Exception e) {e.printStackTrace();throw new AesException(AesException.ParseXmlError);}}/*** 生成xml消息* @param encrypt 加密后的消息密文* @param signature 安全签名* @param timestamp 时间戳* @param nonce 随机字符串* @return 生成的xml字符串*/public static String generate(String encrypt, String signature, String timestamp, String nonce) {String format = "<xml>\n" + "<Encrypt><![CDATA[%1$s]]></Encrypt>\n"+ "<MsgSignature><![CDATA[%2$s]]></MsgSignature>\n"+ "<TimeStamp>%3$s</TimeStamp>\n" + "<Nonce><![CDATA[%4$s]]></Nonce>\n" + "</xml>";return String.format(format, encrypt, signature, timestamp, nonce);}
}

View Code

package webapp.ext;import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;/*** @Author:Fei.chu* @Date:Created in 21:52 2018/08/17* @Description:微信签名校验*/
public class WechatSignUtil {/*** 校验签名* @param signature 微信加密签名.* @param timestamp 时间戳.* @param nonce 随机数.* @return*/public static boolean checkSignature(String signature, String timestamp, String nonce) {// 对token、timestamp、和nonce按字典排序.String[] paramArr = new String[] {"your token", timestamp, nonce};Arrays.sort(paramArr);// 将排序后的结果拼接成一个字符串.String content  = paramArr[0].concat(paramArr[1]).concat(paramArr[2]);String ciphertext = null;try {MessageDigest md = MessageDigest.getInstance("SHA-1");// 对拼接后的字符串进行sha1加密.byte[] digest = md.digest(content.toString().getBytes());ciphertext = byteToStr(digest);} catch (NoSuchAlgorithmException e) {e.printStackTrace();}// 将sha1加密后的字符串与signature进行对比.return ciphertext != null ? ciphertext.equals(signature.toUpperCase()) : false;}/*** 将字节数组转换为十六进制字符串.* @param byteArray* @return*/private static String byteToStr(byte[] byteArray) {String strDigest = "";for (int i = 0; i < byteArray.length; i++) {strDigest += byteToHexStr(byteArray[i]);}return strDigest;}/*** 将字节转换为十六进制字符串.* @param mByte* @return*/private static String byteToHexStr(byte mByte) {char[] Digit = { '0', '1' , '2', '3', '4' , '5', '6', '7' , '8', '9', 'A' , 'B', 'C', 'D' , 'E', 'F'};char[] tempArr = new char[2];tempArr[0] = Digit[(mByte >>> 4) & 0X0F];tempArr[1] = Digit[mByte & 0X0F];String s = new String(tempArr);return s;}//    //获取token
//    public static String getToken() throws Exception{
//        String token = DbGhostApi.tokenIsValid();
//        if (token != null) {
//            return token;
//        } else {
//            Date now = new Date();
//            String rsp = HttpUtil.getString("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + Config.appid + "&secret=" + Config.secret);
//            JSONObject obj = JSONObject.parseObject(rsp);
//            String access_token = obj.getString("access_token");
//            int expires_in = obj.getIntValue("expires_in");
//            DbGhostApi.updateToken(access_token, DateUtil.dateAddSecond(now,expires_in));
//            return access_token;
//        }
//    }
}

View Code

注意:语音消息识别需要在公众号后台开启相应功能

转载于:https://www.cnblogs.com/vicF/p/11230837.html

微信公众号开发java版-消息回复(普通文字消息和语音消息)相关推荐

  1. 微信公众号开发-Java版学习笔记

    微信公众号开发整体不难,主要是熟悉微信公众号常用的一些接口文档,然后会一门后端语言(比如java)即可. 罗召勇老师教程:微信公众号开发-Java版(蓝桥罗召勇) 微信公众号文档:微信公众号官方文档 ...

  2. 微信公众号开发-java版 腾讯课堂(开发接入)

    微信公众号开发-java版 腾讯课堂 微信测试号申请地址: 微信二维码直接扫描登录 1.新建web项目 2.内网穿透映射公网ip  (免费隧道需要支付宝实名认证) 3.微信接入验证签名 TOKEN自己 ...

  3. 微信公众号开发Java版

    源码地址: https://github.com/ishuaige/myWxMp https://gitee.com/niumazlb/myWxMp 一.申请微信开发者账号 注册账号 申请测试号 这里 ...

  4. 微信公众号开发Java版的学习笔记和操作demo!

    基本原理: 会用到微信服务器,调用自己的服务器,自己服务器的访问可以基于spring boot的部署,当然也可以基于其他,其本质就是类似于远程的接口调用: 为社么需要:比如第三方,银行或者独立公司的服 ...

  5. C#微信公众号开发系列教程五(接收事件推送与消息排重)

    C#微信公众号开发系列教程五(接收事件推送与消息排重) 原文:C#微信公众号开发系列教程五(接收事件推送与消息排重) 微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续 ...

  6. 微信公众号开发——Java

    微信公众号开发--Java 步骤一:需要先进入公众号平台进行JS接口安全域名的设置. 步骤二:引入微信jssdk.js文件 生成JS-SDK权限验证签名 步骤三:通过config接口注入权限验证配置 ...

  7. 使用Python进行微信公众号开发(三)回复消息

    写在前面 <使用Python进行微信公众号开发>系列文章将与大家分享如何使用Python一步步搭建微信公众号后台服务器. 效果体验 扫码"是雯子吖"公众号进行体验 配置 ...

  8. 微信公众号开发java流程_微信公众号开发教程java 编程语言的特点及选择

    微信公众号开发教程java 编程语言的特点及选择 微信公众号为用户提供了相关的工具,来对微信公众号进行一个简单的开发.但是如果想实现一些复杂的功能,其实还是要借助于一些编程语言的使用.所以要了解,在微 ...

  9. 微信公众号开发(JAVA)-环境搭建与开发接入

    使用JAVA开发微信公众平台(一)--环境搭建与开发接入 一. 初始微信公众平台 微信公众平台,即我们平时所说的"公众号",曾用名"官方平台"."媒体 ...

最新文章

  1. 从 Android 静音看正确的查bug的姿势?
  2. 发现一个木马,竟然偷传我珍藏几十G的视频!
  3. 2016-6-28 工作总结
  4. java事件大全_JavaScript事件大全
  5. jsp加载常量的探讨
  6. 电子与通信工程专硕考分_考研专业学校推荐之电子与通信工程~
  7. ios--小结系列三
  8. Android第三方开源水面波浪波形view:WaveView(电量、能量、容量指示)
  9. 存储远程复制缺点_远程医疗有一个隐藏的缺点
  10. win7忘记密码解决,Administrator账号密码忘记 解决办法
  11. VMware虚拟机全屏状态下如何快速切换回原主机界面
  12. css实现鼠标悬停效果
  13. 基于分数阶傅里叶变换的车载多用户雷达通信一体化系统
  14. ArcGIS 实验理论基础十五 空间查询
  15. 华为人报:实事求是科研方向与20年艰苦努力
  16. 哈工大计算机网络考研题,哈工大计算机考研历年复试试题(完全版).PDF
  17. Autoware介绍
  18. 小米球ngrok 给你惊喜
  19. codecs.open 和一般的open 区别~
  20. 自学虚幻引擎图文笔记:颜色混合、法线强度调整及选择、归一化、点积、常量偏差比例、规范化等节点

热门文章

  1. 多行 toast android,Android 提示信息Toast
  2. J2EE,Java EE,Jakarta EE 命名之间的恩恩怨怨
  3. 计算机连接游戏手柄,win7系统怎么连接游戏手柄?wi7校准和设置游戏手柄的教程...
  4. hive 异常ClassCastException
  5. 【项目设计】高并发内存池(一)[项目介绍|内存池介绍|定长内存池的实现]
  6. 上海宝付分享面试之前这四点一定要准备好
  7. apply的几种用法
  8. 面向对象贪吃蛇游戏源码
  9. Linux:tar命令详解
  10. 前端JS面试题2021及答案