1.公众号开发文档地址
2.测试用公众号,去申请一波
当然如果有自己的公众号的话用自己的,但是自己的公众号有些权限可能没用,比如消息模板等,测试的公众号权限更多。
3.一个具有外网地址的服务器。
如果没有外网地址,就没办法测试的。所以一定要具备。
ConnectWechatServiceWithAESKey
1.这个类是用来处理和微信消息对接的,也就是公众号上面要配置的url的地址。
2.这个类进行了内容的加解密处理的所以是支持安全模式的。
3.get方法就是和微信建立绑定关系的。然后post方法就是接收微信的通知的
这里只处理了待参二维码的事件然后进行用户绑定的,其他都是回复空,不进行处理。
package service;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.security.DigestException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.ParserConfigurationException;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import encoding.AesException;
import encoding.WXBizMsgCrypt;
import model.TextMessage;
import utl.EventUtil;
import utl.MessageFormatXml;
import utl.MessageUtil;
import utl.MyUtil;
import utl.Sha1;
import utl.WechatConfig;
/**
* Servlet implementation class ConnectWechatServiceWithAESKey
*/
@WebServlet("/ConnectWechatService")
public class ConnectWechatServiceWithAESKey extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* Default constructor.
*/
public ConnectWechatServiceWithAESKey() {
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// System.out.println("get---请求 ConnectWechatService");
// TODO Auto-generated method stub
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
String signature = request.getParameter("signature");
String nonce = request.getParameter("nonce");
String echostr = request.getParameter("echostr");
String timestamp = request.getParameter("timestamp");
if (signature != null) {
ArrayList array = new ArrayList();
array.add(WechatConfig.TOKEN);
array.add(nonce);
array.add(timestamp);
array.sort(new Comparator() {
@Override
public int compare(String o1, String o2) {
// TODO Auto-generated method stub
return o1.compareTo(o2);
}
});
String str = "";
for (int i = 0; i < array.size(); i++) {
str = str + array.get(i);
}
try {
String mySignature = Sha1.SHA1(str);
// System.out.println("参数"+signature+"我的"+mySignature);
if (mySignature.equals(signature)) {// 微信发的
response.getWriter().write(echostr);
}
} catch (DigestException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
//获取url中发来的获取必要的参数
String timestamp=request.getParameter("timestamp");
String nonce=request.getParameter("nonce") ;
String encryptType=request.getParameter("encrypt_type");
String msgSignature=request.getParameter("msg_signature");
WXBizMsgCrypt wXBizMsgCrypt=null;
TextMessage textMessage = null;
try {
SAXReader reader = new SAXReader();
InputStream ins = request.getInputStream();
Document doc = reader.read(ins);
//获取发来的xml
Map map = MessageFormatXml.xmlToMap(doc.asXML());
ins.close();
Set keySet = map.keySet();
System.out.println("加密或明文");
for (String key : keySet) {
String value = map.get(key).toString();
System.out.println("参数:" + key + " 值:" + value);
}
if(encryptType!=null&&msgSignature!=null) {//微信采用了加密
//解密获得实际的xml
wXBizMsgCrypt=new WXBizMsgCrypt(WechatConfig.TOKEN,WechatConfig.ENCODINGAESKEY,WechatConfig.APPID);
String afterDecrpt = wXBizMsgCrypt.decryptMsg(msgSignature, timestamp, nonce, doc.asXML());
map = MessageFormatXml.xmlToMap(afterDecrpt);
keySet = map.keySet();
for (String key : keySet) {
String value = map.get(key).toString();
System.out.println("参数:" + key + " 值:" + value);
}
}
// 开发者文档https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_event_pushes.html
// 只有这两个事件(未关注然后关注了之后的扫码事件扫码事件) 得到二维码的内容进行账号绑定
if (MessageUtil.MESSAGE_EVENT.equals(map.get("MsgType"))) {// 事件
if (map.get("Event").equals(EventUtil.EVENT_SCAN)) {// 扫描事件
String scene_value = map.get("EventKey");// 场景值 组织id,id
String[] ids = scene_value.split(",");
// 虚假绑定
textMessage = MyUtil.createTextMessage(map.get("FromUserName"), "账号绑定成功!");
} else if (map.get("Event").equals(EventUtil.EVENT_SUBSCRIBE) && (map.get("EventKey") != null)) {// 扫描事件
String _scene_value = map.get("EventKey");// 带多余内容的场景值 组织id,id
if (_scene_value != null) {// 想要绑定过来的关注的
String scene_value = _scene_value.substring(8, _scene_value.length());
String[] ids = scene_value.split(",");
// 虚假绑定
textMessage = MyUtil.createTextMessage(map.get("FromUserName"), "账号绑定成功!");
}
}
}
if (textMessage != null) {
String xml = MessageFormatXml.objToXml(textMessage, TextMessage.class);
response.getWriter().write(encryptMsg(wXBizMsgCrypt,xml,timestamp,nonce));
} else {// 其他都是回复空字符串 就是不处理
response.getWriter().write(encryptMsg(wXBizMsgCrypt,"",timestamp,nonce));
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (AesException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//对回复的消息进行加密
private static String encryptMsg(WXBizMsgCrypt wXBizMsgCrypt,String replyMsg, String timestamp,String nonce) throws AesException {
if(wXBizMsgCrypt==null) {
return replyMsg;
}else {
return wXBizMsgCrypt.encryptMsg(replyMsg, timestamp, nonce);
}
}
}
WechatConfig 是微信公众号里面得到的基本信息,比如账号啊,appid,token啊
package utl;
public class WechatConfig {
public static final String ACCOUNT = "XXX";// 公众号的微信号
public static final String TOKEN = "XXX";// 用来绑定服务器的token
//
public static final String APPID = "XXX";//id
public static final String APPSECRATE = "XXX";//
public static final String ENCODINGAESKEY = "XX";//加密用的
}
GetAccessTokenService 主要是其他系统来token获取的接口,否则大家一起去获取的话会导致token被刷新了。
里面的MyUtil.getAccessToken是主要的方法。
package service;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.gson.Gson;
import model.AccessToken;
import model.ResponseMsg;
import utl.HttpUtil;
import utl.MyUtil;
/**
* Servlet implementation class GetAccessTokenService
*/
//外部获取AccessToken
@WebServlet("/GetAccessTokenService")
public class GetAccessTokenService extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public GetAccessTokenService() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletContext servletContext = getServletContext();
ResponseMsg responseMsg = MyUtil.getAccessToken(servletContext, request, response);
response.getWriter().write(new Gson().toJson(responseMsg));
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
把WechatConfig里面的公众号相关信息变一下
然后把公众号的基本配置里面的url配成ConnectWechatServiceWithAESKey这个类的地址。
就可以用demo调试自己的公众号了。
demo下载地址,不需要积分
以http地址为例 因为这个指定80端口
1.项目地址是否正确,是否配置在80端口下面。
2.服务器是否是具有外网ip地址。
3.80端口是否开放。
4.服务器版本不对
如果以上3点都是对的,而且遇到自己用手机外网能够访问项目成功进入get请求,但是微信一直连不到。那么要考虑是不是服务器太低版本了。我遇到就是这样,自己的服务器不行,但是用云服务器就可以。
看看是不是post的时候写数据编码就有问题了
OutputStream os = con.getOutputStream();
DataOutputStream dos =new DataOutputStream(os);
String content = String.valueOf(new Gson().toJson(obj));
os.write(content.getBytes(StandardCharsets.UTF_8));//在这里编码搞一波