Java 进行微信公众号开发遇到的一些坑

前言

最近试水了一下微信公众号,花了一天开发,记录下其中的坑,分享给大家。附上公众号二维码,实现讲笑话的功能,欢迎大家关注。
该公众号实现功能:
1、发送任意内容,随机返回笑话
2、笑话调用了网上开发接口
3、由于接口每日查询次数限制,所以查询后的笑话会保存在数据库中,便于后续使用

https://www.juhe.cn/register?tjc=B71E9316F62D8E95

微信公众号注册

注册公众号微信官方链接,注意配置一下 URL,Token。

  • URL必须以http://或https://开头,分别支持80端口和443端口。
  • Token 必须为英文或数字,长度为3-32字符。

https://www.juhe.cn/register?tjc=B71E9316F62D8E95

服务端使用的是 Java,感觉后台使用 PHP、Python 的多一些,把 Java 开发遇到的问题记录一下,方便自己也方便别人查阅。

微信第一次接入 验证有效性

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {
	request.setCharacterEncoding("UTF-8");
	response.setCharacterEncoding("UTF-8");

	PrintWriter out = response.getWriter();

	/** 判断是否是微信接入激活验证,只有首次接入验证时才会收到echostr参数,此时需要把它直接返回 */
	String signature = request.getParameter("signature");
	String timestamp = request.getParameter("timestamp");
	String nonce = request.getParameter("nonce");
	String echostr = request.getParameter("echostr");
	
	if (WechatSignUtil.checkSignature(signature, timestamp, nonce)) {
		// 验证 有效性
		out.write(echostr);
		out.flush();
		out.close();
	}
}

刚才微信公共平台配置的 token 这儿填写,保持一致。

public class WechatSignUtil2 {
	// 与接口配置信息中的 Token 要一致
	private static String token = "***";

	/** 
	 * 验证签名 
	 */
	public static boolean checkSignature(String signature, String timestamp, String nonce) {
		String[] arr = new String[] { token, timestamp, nonce };
		// 将 token、timestamp、nonce 三个参数进行字典序排序
		Arrays.sort(arr);
		StringBuilder content = new StringBuilder();
		for (int i = 0; i < arr.length; i++) {
			content.append(arr[i]);
		}
		MessageDigest md = null;
		String tmpStr = null;

		try {
			md = MessageDigest.getInstance("SHA-1");
			// 将三个参数字符串拼接成一个字符串进行 sha1 加密
			byte[] digest = md.digest(content.toString().getBytes());
			tmpStr = byteToStr(digest);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}

		content = null;
		// 将 sha1 加密后的字符串可与 signature 对比,标识该请求来源于微信
		return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
	}

	/** 
	 * 将字节数组转换为十六进制字符串 
	 */
	private static String byteToStr(byte[] byteArray) {
		String strDigest = "";
		for (int i = 0; i < byteArray.length; i++) {
			strDigest += byteToHexStr(byteArray[i]);
		}
		return strDigest;
	}

	/** 
	 * 将字节转换为十六进制字符串 
	 */
	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;
	}
}

微信事件处理

微信的事件包括以下几种,本文实现了最基本的关注后,回复一段简单的使用说明。

事件XML数据包示例:

<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[FromUser]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[subscribe]]></Event>
</xml>

参数说明

ToUserName	开发者微信号
FromUserName	发送方帐号(一个OpenID)
CreateTime	消息创建时间 (整型)
MsgType	消息类型,event
Event	事件类型,subscribe(订阅)、unsubscribe(取消订阅)

https://www.juhe.cn/register?tjc=B71E9316F62D8E95

1 . 关注/取消关注事件
2 . 扫描带参数二维码事件
3 . 上报地理位置事件
4 . 自定义菜单事件
5 . 点击菜单拉取消息时的事件推送
6 . 点击菜单跳转链接时的事件推送

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse resp) {
	try {
		Map<String, String> map = WechatMessageUtil.parseXml(request);
		String msgtype = map.get("MsgType");
		String result = "success";
		if (WechatMessageUtil.REQ_MESSAGE_TYPE_EVENT.equals(msgtype)) {
			result = WechatEventDispatcherHappy.processEvent(map); // 进入事件处理
		} else {
			result = WechatMsgDispatcherHappy.processMessage(map); // 进入消息处理
		}
		PrintWriter out = resp.getWriter();
		out.print(result);
	} catch (Exception e) {
	}
}

下面这个类处理了相关事件

public class WechatEventDispatcherHappy {
	public static String WechatValue = "success";

	public static String processEvent(Map<String, String> map) {
		if (map.get("Event").equals(WechatMessageUtil.EVENT_TYPE_SUBSCRIBE)) { // 订阅
			
			String result = "你关注我了哈~\n\n发送任意内容获取笑话,天天开心哦~";
			 
			String openid = map.get("FromUserName"); // 用户 openid
			String mpid = map.get("ToUserName"); // 公众号原始 ID

			// 普通文本消息 回复的消息
			WechatRespTextMessage txtmsg = new WechatRespTextMessage();
			txtmsg.setToUserName(openid);
			txtmsg.setFromUserName(mpid);
			txtmsg.setCreateTime(new Date().getTime());
			txtmsg.setMsgType(WechatMessageUtil.RESP_MESSAGE_TYPE_TEXT);

			txtmsg.setContent(result);			
			return WechatMessageUtil.textMessageToXml(txtmsg);
		}
		return WechatValue;
	}
}

微信消息处理

消息分为 文本消息、语音消息、图片消息、视频消息、小视频消息等,本文实现发送任意消息,都给回复一条随机笑话。

public class WechatMsgDispatcherHappy {	 
	static DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");

	public static String processMessage(Map<String, String> map) {
		if (map.get("MsgType").equals(WechatMessageUtil.REQ_MESSAGE_TYPE_TEXT)) { // 文本消息
			// System.out.println("==============这是文本消息!");
			String openid = map.get("FromUserName"); // 用户 openid
			String mpid = map.get("ToUserName"); // 公众号原始 ID
			String createTime = map.get("CreateTime"); // 公众号原始 ID
			String myDate = formatter.format(new Date(Long.parseLong(createTime) * 1000L));
			String content = map.get("Content").trim(); // 文本内容

			// 普通文本消息 回复的消息
			WechatRespTextMessage txtmsg = new WechatRespTextMessage();
			txtmsg.setToUserName(openid);
			txtmsg.setFromUserName(mpid);
			txtmsg.setCreateTime(new Date().getTime());
			txtmsg.setMsgType(WechatMessageUtil.RESP_MESSAGE_TYPE_TEXT);
			// 随机数
			Random random = new Random();
			// 获取随机笑话
			InfoHash result = JuheUtil.getRequest1(random.nextInt(400000) + "");

			txtmsg.setContent(result.getRes());
			return WechatMessageUtil.textMessageToXml(txtmsg);
		}

		if (map.get("MsgType").equals(WechatMessageUtil.REQ_MESSAGE_TYPE_IMAGE)) { // 图片消息
			// System.out.println("==============这是图片消息!");
		}
		
		return "success"; // 默认回复 success,立刻回复消息
	}
}

数据接口

本来想找自己写个笑话随机接口,后来搜了一下,网上有现成的接口,而且还是免费的。

可以通过我的邀请码
https://www.juhe.cn/register?tjc=B71E9316F62D8E95 注册该接口。

http://blog.csdn.net/never_cxb

接口地址:http://japi.juhe.cn/joke/content/list.from
支持格式:json
请求方式:http get
请求示例:http://japi.juhe.cn/joke/content/list.from?key=您申请的KEY&page=2&pagesize=10&sort=asc&time=1418745237
接口备注:根据时间戳返回该时间点前或后的笑话列表

JSON返回示例:

{
    "error_code": 0,
    "reason": "Success",
    "result": {
        "data": [
            {
                "content": "某日我坐高铁从杭州去上海,半路停下来了几十分钟一直没有开动,这个时候列车员来到我们车厢解释原因。  有一乘客见状故意询问,列车为何还不开车。  列车解释列车出现故障。乘客见状很是担心说了一句,你们再不开,后面的车追上来怎么办?车厢乘客无一不笑!!",
                "hashId": "d4698e565a18d099be731ba53d18d8e4",
                "unixtime": 1486254830,
                "updatetime": "2017-02-05 08:33:50"
            }
        ]
    }
}

JSON 数据解析

使用 GSON 对 JSON 数据解析,注意该 JSON 比较复杂,result是一个对象,其中data是一个数组。

Gson gson = new Gson();
HappyGetResult happy = gson.fromJson(result, HappyGetResult.class);	
List<HappyData> data = happy.getResult().getData();
String content = d.get(0).getContent();
String	hash = d.get(0).getHashId();

其中

public class HappyGetResult {

	@SerializedName("error_code")
	public int errorCode;
	
	@SerializedName("reason")
	public String reason;
	
	@SerializedName("result")
	public HappyInfo result;
}
public class HappyInfo {
	List<HappyData> data;

	public class HappyData {
		String content;
		String hashId;
		String unixtime;
		String updatetime;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值