第一步:配置微信公众号
进入微信公众平台地址
进入基本配置
这里需要填写的有服务器的URL、Token两个地方
URL
是一个公网地址,只能接收80端口的(http默认端口)
http://公网地址/项目名称/请求路径
Token
在校验的时候需要用到,随便输入一个字符串就可以了
开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带四个参数
参数 描述
signature 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
timestamp 时间戳
nonce 随机数
echostr 随机字符串
所以需要编写相应的Controller(采用spring MVC)
/**
* 验证微信服务器
*
* @param response
* @param signature
* @param timestamp
* @param nonce
* @param echostr
*/
@RequestMapping(value = "/wechat", method = RequestMethod.GET)
public void wechatService(PrintWriter out, HttpServletResponse response,
@RequestParam(value = "signature", required = false) String signature, @RequestParam String timestamp,
@RequestParam String nonce, @RequestParam String echostr) {
if (CheckUtil.checkSignature(signature, timestamp, nonce)) {
out.print(echostr);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
CheckUtil.Java
package com.wechat.utils;
import java.util.Arrays;
/**
*
* 校验工具类
* 开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,
* 成为开发者成功,否则接入失败。
*
* @author GWCheng
*
*/
public class CheckUtil {
private static final String token = "chenggaowei";
public static boolean checkSignature(String signature, String timestamp, String nonce) {
String[] arr = new String[] { token, timestamp, nonce };
Arrays.sort(arr);
StringBuffer content = new StringBuffer();
for (int i = 0; i < arr.length; i++) {
content.append(arr[i]);
}
String tmp = DecriptUtil.SHA1(content.toString());
return tmp.equals(signature);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
DecriptUtil.Java
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
/**
* 各种加密解密
*
*/
public class DecriptUtil {
public static String SHA1(String decript) {
try {
MessageDigest digest = java.security.MessageDigest
.getInstance("SHA-1");
digest.update(decript.getBytes());
byte messageDigest[] = digest.digest();
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < messageDigest.length; i++) {
String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
if (shaHex.length() < 2) {
hexString.append(0);
}
hexString.append(shaHex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
public static String SHA(String decript) {
try {
MessageDigest digest = java.security.MessageDigest
.getInstance("SHA");
digest.update(decript.getBytes());
byte messageDigest[] = digest.digest();
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < messageDigest.length; i++) {
String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
if (shaHex.length() < 2) {
hexString.append(0);
}
hexString.append(shaHex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
public static String MD5(String input) {
try {
MessageDigest mdInst = MessageDigest.getInstance("MD5");
mdInst.update(input.getBytes());
byte[] md = mdInst.digest();
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < md.length; i++) {
String shaHex = Integer.toHexString(md[i] & 0xFF);
if (shaHex.length() < 2) {
hexString.append(0);
}
hexString.append(shaHex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
/**
* 加密
*
* @param content
* 需要加密的内容
* @param password
* 加密密码
* @return
*/
public static byte[] encryptAES(String content, String password) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(password.getBytes()));
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] result = cipher.doFinal(byteContent);
return result;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
/**
* 解密
*
* @param content
* 待解密内容
* @param password
* 解密密钥
* @return
*/
public static byte[] decryptAES(byte[] content, String password) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(password.getBytes()));
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] result = cipher.doFinal(content);
return result;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
/**
* BASE64解密
*
* @param key
* @return
* @throws Exception
*/
public static String decryptBASE64(String key) {
return "";
}
/**
* BASE64加密
*
* @param key
* @return
* @throws Exception
*/
public static String encryptBASE64(String key) {
return "";
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
验证写好了就可以点击提交了
配置成功之后会有如下的提示信息
下面是微信发过来的四个参数,以及给微信回复的echostr
至此开发环境已经配置好了!
第二步:接收消息
环境配置好之后就可以开发了
微信会将发往公众账号的消息发到我们配置的URL中,以POST的方式
当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。
以下是debug的信息
微信已经将发往公众账号的消息发到了我们配置的服务器地址
xml消息不太利于编写程序,所以需要对xml消息进行相应的转换,这里将其转会为map
将xml转换为map
/**
* 将xml转化为Map集合
*
* @param request
* @return
*/
public static Map<String, String> xmlToMap(HttpServletRequest request) {
Map<String, String> map = new HashMap<String, String>();
SAXReader reader = new SAXReader();
InputStream ins = null;
try {
ins = request.getInputStream();
} catch (IOException e1) {
e1.printStackTrace();
}
Document doc = null;
try {
doc = reader.read(ins);
} catch (DocumentException e1) {
e1.printStackTrace();
}
Element root = doc.getRootElement();
@SuppressWarnings("unchecked")
List<Element> list = root.elements();
for (Element e : list) {
map.put(e.getName(), e.getText());
}
try {
ins.close();
} catch (IOException e1) {
e1.printStackTrace();
}
return map;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
用到的jar包
dom4j.jar
这个方法写好之后就可以调用了:
Controller如下,微信发过来的消息用POST接收
/**
* 接收来自微信发来的消息
*
* @param out
* @param request
* @param response
*/
@ResponseBody
@RequestMapping(value = "/wechat", method = RequestMethod.POST)
public void wechatServicePost(PrintWriter out, HttpServletRequest request, HttpServletResponse response) {
String responseMessage = wechatService.processRequest(request);
out.print(responseMessage);
out.flush();
}
Controller调用Service的方法(给用户返回消息,也是一个xml格式的字符串)
Service关键代码如下
@Service
public class WechatService {
private static Logger log = Logger.getLogger(WechatService.class);
public String processRequest(HttpServletRequest request) {
Map<String, String> map = WechatMessageUtil.xmlToMap(request);
log.info(map);
String fromUserName = map.get("FromUserName");
String toUserName = map.get("ToUserName");
String msgType = map.get("MsgType");
String responseMessage = "success";
if (WechatMessageUtil.MESSAGE_TEXT.equals(msgType)) {
TextMessage textMessage = new TextMessage();
textMessage.setMsgType(WechatMessageUtil.MESSAGE_TEXT);
textMessage.setToUserName(fromUserName);
textMessage.setFromUserName(toUserName);
textMessage.setCreateTime(System.currentTimeMillis());
textMessage.setContent("我已经受到你发来的消息了");
responseMessage = WechatMessageUtil.textMessageToXml(textMessage);
}
log.info(responseMessage);
return responseMessage;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
Servie调用WechatMessageUtil将reques中的xml转换为map
WechatMessageUtil.java如下
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.thoughtworks.xstream.XStream;
import com.wechat.entity.vo.wechat.message.TextMessage;
public class WechatMessageUtil {
/**
* 文本消息
*/
public static final String MESSAGE_TEXT = "text";
/**
* 图片消息
*/
public static final String MESSAtGE_IMAGE = "image";
/**
* 图文消息
*/
public static final String MESSAGE_NEWS = "news";
/**
* 语音消息
*/
public static final String MESSAGE_VOICE = "voice";
/**
* 视频消息
*/
public static final String MESSAGE_VIDEO = "video";
/**
* 小视频消息
*/
public static final String MESSAGE_SHORTVIDEO = "shortvideo";
/**
* 地理位置消息
*/
public static final String MESSAGE_LOCATION = "location";
/**
* 链接消息
*/
public static final String MESSAGE_LINK = "link";
/**
* 事件推送消息
*/
public static final String MESSAGE_EVENT = "event";
/**
* 事件推送消息中,事件类型,subscribe(订阅)
*/
public static final String MESSAGE_EVENT_SUBSCRIBE = "subscribe";
/**
* 事件推送消息中,事件类型,unsubscribe(取消订阅)
*/
public static final String MESSAGE_EVENT_UNSUBSCRIBE = "unsubscribe";
/**
* 事件推送消息中,上报地理位置事件
*/
public static final String MESSAGE_EVENT_LOCATION_UP = "LOCATION";
/**
* 事件推送消息中,自定义菜单事件,点击菜单拉取消息时的事件推送
*/
public static final String MESSAGE_EVENT_CLICK = "CLICK";
/**
* 事件推送消息中,自定义菜单事件,点击菜单跳转链接时的事件推送
*/
public static final String MESSAGE_EVENT_VIEW = "VIEW";
/**
* 将xml转化为Map集合
*
* @param request
* @return
*/
public static Map<String, String> xmlToMap(HttpServletRequest request) {
Map<String, String> map = new HashMap<String, String>();
SAXReader reader = new SAXReader();
InputStream ins = null;
try {
ins = request.getInputStream();
} catch (IOException e1) {
e1.printStackTrace();
}
Document doc = null;
try {
doc = reader.read(ins);
} catch (DocumentException e1) {
e1.printStackTrace();
}
Element root = doc.getRootElement();
@SuppressWarnings("unchecked")
List<Element> list = root.elements();
for (Element e : list) {
map.put(e.getName(), e.getText());
}
try {
ins.close();
} catch (IOException e1) {
e1.printStackTrace();
}
return map;
}
/**
* 文本消息转化为xml
*
* @param textMessage
* @return
*/
public static String textMessageToXml(TextMessage textMessage) {
XStream xstream = new XStream();
xstream.alias("xml", textMessage.getClass());
return xstream.toXML(textMessage);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
用到的jar包有
log4j
xstream
xmlpull
用户发来的消息
{MsgId=6241406265466888851, FromUserName=od_Ldw8_rwcGiFsaCeF74Vsc-qz4, CreateTime=1453190638, Content=你好, ToUserName=gh_8f6a0cd44617, MsgType=text}
给用户回复的消息
<xml>
<ToUserName>od_Ldw8_rwcGiFsaCeF74Vsc-qz4</ToUserName>
<FromUserName>gh_8f6a0cd44617</FromUserName>
<CreateTime>1453190640848</CreateTime>
<MsgType>text</MsgType>
<Content>我已经受到你发来的消息了</Content>
</xml>