微信公众号开发

一 准备

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<String> array = new ArrayList<String>();
			array.add(WechatConfig.TOKEN);
			array.add(nonce);
			array.add(timestamp);

			array.sort(new Comparator<String>() {

				@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<String, String> map = MessageFormatXml.xmlToMap(doc.asXML());
			ins.close();
			Set<String> 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<AccessToken> 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);
	}

}

三 demo

把WechatConfig里面的公众号相关信息变一下
然后把公众号的基本配置里面的url配成ConnectWechatServiceWithAESKey这个类的地址。
就可以用demo调试自己的公众号了。
demo下载地址,不需要积分

四 遇到的问题

1. 自己的公众号配置服务器地址报url超时,改用测试的公众号配置连反应都没有。

以http地址为例 因为这个指定80端口
1.项目地址是否正确,是否配置在80端口下面。
2.服务器是否是具有外网ip地址。
3.80端口是否开放。
4.服务器版本不对
如果以上3点都是对的,而且遇到自己用手机外网能够访问项目成功进入get请求,但是微信一直连不到。那么要考虑是不是服务器太低版本了。我遇到就是这样,自己的服务器不行,但是用云服务器就可以。

2.调用模板消息发送json的时候,中文乱码,或者一直报data format error,但是你确定参数是对的。例如用postman可以,但是自己的程序不行。

看看是不是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));//在这里编码搞一波
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值