配置步骤
1.我用的是测试号,如果没有测试号的小伙伴可以去注册 http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
2.注册完成后可以按照网上的将信息配置成功
3.进入基本配置, 这里需要填写的有服务器的url Token俩个地方,这边的原理呢就是点击提交的时候微信公众平台会回调url中配置的路径,然后验证token的有效性 ,从而配置成功。
微信公众平台开发者配置参考这篇:https://blog.csdn.net/tangthh123/article/details/105288990
URL:是一个公网地址(http://公网地址/项目名称/请求路径)
Token :此时的token是可以随意定义的。
4.验证Token(此时的token可以随便定义的)
WeixinController类中
@RequestMapping(value="/wechat")
public @ResponseBody String getNews(HttpServletRequest request,HttpServletResponse response) throws Exception{
2018-05-08 14:57:02,775 INFO [com.bos.controller.WeiXinController:44]
//[signature: e71f4f0c8b5c626089d0fc939ce2a2db66897319]
* [timestamp: 1525762622]
* [nonce: 559220466]
* [echostr: 970164183845924479]
微信验证成功
//微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp,nonce参数
String signature = request.getParameter("signature");
//时间戳
String timestamp = request.getParameter("timestamp");
//随机数
String nonce = request.getParameter("nonce");
//随机字符串
String echostr = request.getParameter("echostr");
System.out.println(signature+"-----"+timestamp+"-----"+""+nonce);
String method=request.getMethod();
if("GET".equals(method)){
if (SignUtil.checkSignature(signature, timestamp, nonce)) {
logger.info("[signature: "+signature + "]<-->[timestamp: "+ timestamp+"]<-->[nonce: "+nonce+"]<-->[echostr: "+echostr+"]");
response.getOutputStream().println(echostr);
System.out.println("微信验证成功");
Map<String, Object> map=WeiXinController.getAccessToken();
System.out.println(map.get("access_token"));
return echostr;
}
return "";
}if("POST".equals(method)){
System.out.println("请求方式"+method);
}
return "";
}
5.接下来我将代码中涉及的类都贴出来,供参考
package com.bos.util;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
public class SignUtil {
private static String token = "Chenggaowei";
/**
* 校验签名
* @param signature 签名
* @param timestamp 时间戳
* @param nonce 随机数
* @return 布尔值
*/
public static boolean checkSignature(String signature,String timestamp,String nonce){
String checktext = null;
if (null != signature) {
//对ToKen,timestamp,nonce 按字典排序
String[] paramArr = new String[]{token,timestamp,nonce};
Arrays.sort(paramArr);
//将排序后的结果拼成一个字符串
String content = paramArr[0].concat(paramArr[1]).concat(paramArr[2]);
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
//对接后的字符串进行sha1加密
byte[] digest = md.digest(content.toString().getBytes());
checktext = byteToStr(digest);
} catch (NoSuchAlgorithmException e){
e.printStackTrace();
}
}
//将加密后的字符串与signature进行对比
return checktext !=null ? checktext.equals(signature.toUpperCase()) : false;
}
/**
* 将字节数组转化我16进制字符串
* @param byteArrays 字符数组
* @return 字符串
*/
private static String byteToStr(byte[] byteArrays){
String str = "";
for (int i = 0; i < byteArrays.length; i++) {
str += byteToHexStr(byteArrays[i]);
}
return str;
}
/**
* 将字节转化为十六进制字符串
* @param myByte 字节
* @return 字符串
*/
private static String byteToHexStr(byte myByte) {
char[] Digit = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char[] tampArr = new char[2];
tampArr[0] = Digit[(myByte >>> 4) & 0X0F];
tampArr[1] = Digit[myByte & 0X0F];
String str = new String(tampArr);
return str;
}
以上俩点就可以将环境搭好,从第五点开始就做接收发送文本消息
5,接收消息发送文本消息,(WeixinController)有必要说一下就是我上面那个方法是我用来验证token的,只需验证一遍Token,验证成功后我就把这个方法的代码改成了这个,直接是我下面这个方法
@RequestMapping(value="/wechat")
public void getAccessToken(PrintWriter out, HttpServletRequest request, HttpServletResponse response) throws Exception{
//第五步:后面加上用来回复消息
WechatService wechatService=new WechatService();
String respMessage= wechatService.weixinPost(request);
System.out.println("回复的消息为:"+respMessage);
out.print(respMessage); // 将回应发送给微信服务器
}
6.WeChatService,我目前做的是客户发的是什么消息,那么返回给客户的就是什么数据
然后服务器与测试号之间是通过xml来进行传输数据的
package com.wei.util;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dom4j.DocumentException;
import org.springframework.web.socket.TextMessage;
import com.wei.pojo.TextMeaasge;
/*
*
* 只是消息的自动回复
*
* */
public class WechatService {
/**
* 处理微信发来的请求
*
* @param request
* @return
* @throws DocumentException
* @throws IOException
*/
public String weixinPost(HttpServletRequest request) throws IOException, DocumentException {
//response.setCharacterEncoding("UTF-8");
Map<String, String> map = MessageUtil.xmlToMap(request);
// 发送方帐号(一个OpenID)
String fromUserName = map.get("FromUserName");
// 开发者微信号
String toUserName = map.get("ToUserName");
// 消息类型
String msgType = map.get("MsgType");
// 默认回复一个"success"
String responseMessage = "success";
//用户输入的消息
String message=map.get("Content");
// 对文本消息进行处理
if (MessageUtil.RESP_MESSAGE_TYPE_TEXT.equals(msgType)) {// 文本消息
TextMeaasge textMessage=new TextMeaasge();
textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);
textMessage.setToUserName(fromUserName);//注意这里的toUserName 是刚才接收xml中的FromUserName
textMessage.setFromUserName(toUserName);
textMessage.setCreateTime(System.currentTimeMillis());
String str = new String(message);
System.out.println("str-------"+str);
textMessage.setContent(str);
responseMessage = MessageUtil.textMessageToXML(textMessage);
}else if(MessageUtil.REQ_MESSAGE_TYPE_VOICE.equals(msgType)){
//对语音消息进行处理
responseMessage="你发送了一个消息";
}
return responseMessage;
}
}
7.MessageUtil类中,这是一个工具类
package com.wei.util;
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.wei.pojo.TextMeaasge;
/*
* 按照微信的接口文档编写的文本消息实体类
*
* */
public class MessageUtil {
/**
* 返回消息类型:文本
*/
public static final String RESP_MESSAGE_TYPE_TEXT = "text";
/**
* 返回消息类型:音乐
*/
public static final String RESP_MESSAGE_TYPE_MUSIC = "music";
/**
* 返回消息类型:图文
*/
public static final String RESP_MESSAGE_TYPE_NEWS = "news";
/**
* 请求消息类型:文本
*/
public static final String REQ_MESSAGE_TYPE_TEXT = "text";
/**
* 请求消息类型:图片
*/
public static final String REQ_MESSAGE_TYPE_IMAGE = "image";
/**
* 请求消息类型:链接
*/
public static final String REQ_MESSAGE_TYPE_LINK = "link";
/**
* 请求消息类型:地理位置
*/
public static final String REQ_MESSAGE_TYPE_LOCATION = "location";
/**
* 请求消息类型:音频
*/
public static final String REQ_MESSAGE_TYPE_VOICE = "voice";
/**
* 请求消息类型:推送
*/
public static final String REQ_MESSAGE_TYPE_EVENT = "event";
/**
* 事件类型:subscribe(订阅)
*/
public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";
/**
* 事件类型:unsubscribe(取消订阅)
*/
public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";
/**
* 事件类型:CLICK(自定义菜单点击事件)
*/
public static final String EVENT_TYPE_CLICK = "CLICK";
/*
*
* 将xml转换成map集合
*
* */
public static Map<String, String> xmlToMap(HttpServletRequest request) throws IOException, DocumentException{
Map<String, String> map=new HashMap<String,String>();
SAXReader reader=new SAXReader();//使用dom4j解析xml
InputStream ins=request.getInputStream();//从request中获取输入流
Document doc=reader.read(ins);
Element root=doc.getRootElement(); //获取根元素
List<Element> list=root.elements(); //获取所有的节点
for(Element e:list){
map.put(e.getName(), e.getText());
System.out.println(e.getName()+"----->"+e.getText());
}
ins.close(); //关流
return map;
}
/*s
* 将文本消息对象转换成xml
*
*
* */
public static String textMessageToXML(TextMeaasge textMessage){
XStream xstream = new XStream(); // 使用XStream将实体类的实例转换成xml格式
xstream.alias("xml", textMessage.getClass()); // 将xml的默认根节点替换成“xml”
return xstream.toXML(textMessage);
}
}
8.TestMessage类,
注意:由于推送消息xml数据包格式是这样的,那么我们的实体类也要按照这个来,切忌不要改属性名,不要因为属性值一个大 写觉得不规范。(被坑过)
<xml>
<ToUserName>< ![CDATA[toUser] ]></ToUserName>
<FromUserName>< ![CDATA[fromUser] ]></FromUserName>
<CreateTime>1348831860</CreateTime>
<MsgType>< ![CDATA[text] ]></MsgType>
<Content>< ![CDATA[this is a test] ]></Content>
<MsgId>1234567890123456</MsgId> </xml>
package com.wei.pojo;
public class TextMeaasge {
private String FromUserName;
private String ToUserName;
private String MsgType;
private long CreateTime;
private String Content;
public String getFromUserName() {
return FromUserName;
}
public void setFromUserName(String fromUserName) {
FromUserName = fromUserName;
}
public String getToUserName() {
return ToUserName;
}
public void setToUserName(String toUserName) {
ToUserName = toUserName;
}
public String getMsgType() {
return MsgType;
}
public void setMsgType(String msgType) {
MsgType = msgType;
}
public long getCreateTime() {
return CreateTime;
}
public void setCreateTime(long createTime) {
CreateTime = createTime;
}
public String getContent() {
return Content;
}
public void setContent(String content) {
Content = content;
}
}
最后给大家看一下页面效果