【Java】微信公众号开发笔记

GitHub Repository:School-Assistant

一、准备工作

1.微信公众号的介绍

详情请看微信公众平台开发概述

2.开发环境的搭建

利用ngrok进行内网穿透,测试是否联通在本地内部如果想访问自己的程序是很容易的,在同一个IP地址下就可以访问同一个内网(局域网),但是如果不在该内网下的其他的用户是无法访问的。内网穿透顾名思义,就是打破这层“隔膜”,让外面的用户可以访问。当然在这个地方的话,这个主要是还是用来测试我们的微信公众号是不是打通了,传到服务器上就不必考虑这些事情了。

内网穿透的原理:传统的开发的软件的通信是网址---服务器---应用程序,ngrok的作用就是替代这个应用程序,通信地址换成一个分配好的二级地址,可以直接进行访问。这样的话,我们的开发的程序和软件就可以直接进行通信。

ngrok如何使用以及下载的地址:Sunny_ngrok,此处不再赘述。这个地方需要注意的是,如果ngrok和tomcat两个都没有开的,其他人是无法访问这个页面的,所以无需担心被入侵的问题。打开之后,输入sunny clientid xxxxx,这里的xxxxx就是你的隧道id,当发现状态为Tunnel Status变成online的时候,就可以了。在MyEclipse中有自带的tomcat可以使用,把接口调成80即可。

这个地方记录一下这个ngrok踩过的坑:因为这个地方的tomcat的端口号是8080,但是ngrok却是一个80端口,所以需要修改一下tomcat的端口号为80端口。MyEclipse中其实自带着一个tomcat,启动的时候要注意不要启动错了,否则启动了这个tomcat的话怎么改都改都改不对。链接:如何去修改tomcat的端口号?

 

3.开发接入

因为安全问题,微信的诸多功能是无法针对个人用户开发的,微信针对开发者开放了开发者账号用来测试接口。地址如下:接口测试号申请。以下是Java代码的实现各个功能。

微信打通实现:WxServlet.java

开发者通过检验signature对请求进行校验。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。

package servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import service.WxService;

public class WxServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		String signature = request.getParameter("signature");
		String timestamp = request.getParameter("timestamp");
		String nonce = request.getParameter("nonce");
		String echostr = request.getParameter("echostr");
		//登陆验证:如果接入成功原样返回一个数值//
		if(WxService.check(signature , timestamp , nonce)){
			//System.out.println("接入成功");
			PrintWriter out = response.getWriter();
			out.print(echostr);
			out.flush();
			out.close();
		}
		else{
			System.out.println("接入失败");
		}

	}

	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("post");
	}

}

sha1检验算法类:WxService.java

第一步:将token、timestamp、nonce三个参数进行字典序排序。 第二步:将三个参数字符串拼接成一个字符串进行sha1加密 。第三步:开发者获得加密后的字符串可与signature对比,标识该请求来源于微信。(暂时开坑sha1算法,这个地方值得学一下。在Java中已经有了MessageDigest这个类了,所以可以直接进行使用。sha1是一个加密算法,把数值转换成Byte型,然后进行16位的转换。)

package service;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

public class WxService {
	//微信服务的验证签名:
	private static final String TOKEN = "bonstop";//这里的Token的数值必须和微信开发的配置方式一致//
	private static String sha1(String s){ // 加密方法//
		try{
			//获取一个加密的对象//
			MessageDigest md = MessageDigest.getInstance("sha1");
			//加密//
			byte[] digest = md.digest(s.getBytes());
			char[] chars = {'0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f'};
			StringBuilder sb = new StringBuilder();
			//处理加密的结果//
			for(byte b : digest)
			{
				sb.append(chars[(b >> 4) & 15]);//取其高四位//
				sb.append(chars[b & 15]);//取其低四位//
			}
			return sb.toString();
		}
		catch(NoSuchAlgorithmException e){
			e.printStackTrace();
		}
		return null;
	}
	public static boolean check(String signature , String timestamp , String nonce){
		 //1)将token、timestamp、nonce三个参数进行字典序排序 
			String[] str = new String[] {TOKEN , timestamp , nonce};
			Arrays.sort(str);
		 //2)将三个参数字符串拼接成一个字符串进行sha1加密 
			String s = str[0] + str[1] + str[2];
			String mysig = sha1(s);
			System.out.println(mysig);
			System.out.println(signature);
		 //3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
		return mysig.equalsIgnoreCase(signature);
	}
}

微信用户发消息样例:test.xml

 这个是我从手机上发送一个“”得到的结果。拉取来自一个用户的消息。

<xml>

	<!-- 
		ToUserName : 开发者微信号
		FromUserName : 发送方帐号(一个OpenID : 只是随机放的一个数据)
		CreateTime : 消息创建时间 (整型)单位时间为秒
		MsgType : 消息类型,文本为text
		Content : 文本消息内容
		MsgId : 消息id,64位整型 
	-->

	<ToUserName><![CDATA[gh_c67e59e8f8c6]]></ToUserName>
	<FromUserName><![CDATA[oBzBC1Qwf-7-nxXs6ghXCrrxK13A]]></FromUserName>
	<CreateTime>1554984695</CreateTime>
	<MsgType><![CDATA[text]]></MsgType>
	<Content><![CDATA[浣犲ソ]]></Content><!-- 我发了一个“你好”,这个需要后序做一个解析才能使用 -->
	<MsgId>22262029333601665</MsgId>
</xml>

 

 

Day2:接入用户消息

接入用户消息:WxServlet.Java

Post可以接入从微信上发过来的消息。

package servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import service.WxService;

public class WxServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		String signature = request.getParameter("signature");
		String timestamp = request.getParameter("timestamp");
		String nonce = request.getParameter("nonce");
		String echostr = request.getParameter("echostr");
		//登陆验证:如果接入成功原样返回一个数值//
		if(WxService.check(signature , timestamp , nonce)){
			//System.out.println("接入成功");
			PrintWriter out = response.getWriter();
			out.print(echostr);
			out.flush();
			out.close();
		}
		
		else{
			System.out.println("接入失败");
		}
	}
	/*
	 * doPost用来接收消息和事件的推送
	 * */
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//处理消息和事件推送
		Map<String , String> requestMap = WxService.parseRequest(request.getInputStream());
		System.out.println(requestMap);
	}

}

添加parseRequest 方法:WxService.Java

parseRequest这个功能就是让XML信息可以被传回来。这里用了dom4j.jar包进行进行解析XML。dom4j.jar放在WebROOT/Web-INF/lib下的文件内。注意不要下载错了jar包(dom4j-1.6.1),否则会报错。下载地址:<dom4j>

public class WxService {
	//微信服务的验证签名:
	private static final String TOKEN = "bonstop";//这里的Token的数值必须和微信开发的配置方式一致//
	private static String sha1(String s){ // 加密方法//
		try{
			//获取一个加密的对象//
			MessageDigest md = MessageDigest.getInstance("sha1");
			//加密//
			byte[] digest = md.digest(s.getBytes());
			char[] chars = {'0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f'};
			StringBuilder sb = new StringBuilder();
			//处理加密的结果//
			for(byte b : digest)
			{
				sb.append(chars[(b >> 4) & 15]);//取其高四位//
				sb.append(chars[b & 15]);//取其第四位//
			}
			return sb.toString();
		}
		catch(NoSuchAlgorithmException e){
			e.printStackTrace();
		}
		return null;
	}
	public static boolean check(String signature , String timestamp , String nonce){
		 //1)将token、timestamp、nonce三个参数进行字典序排序 
			String[] str = new String[] {TOKEN , timestamp , nonce};
			Arrays.sort(str);
		 //2)将三个参数字符串拼接成一个字符串进行sha1加密 
			String s = str[0] + str[1] + str[2];
			String mysig = sha1(s);
			System.out.println(mysig);
			System.out.println(signature);
		 //3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
		return mysig.equalsIgnoreCase(signature);
	}
	
	public static Map<String, String> parseRequest(InputStream is) {
		Map<String , String> map = new HashMap();
		SAXReader reader = new SAXReader();
		try{
			//读取输入流,获取文档对象//
			Document document = reader.read(is);
			//根据文档对象获取根节点//
			Element root = document.getRootElement();
			//获取根节点下的所有子节点//
			List<Element> elements = root.elements();
			for(Element e : elements){
				map.put(e.getName(), e.getStringValue());
			}
		}
		catch(DocumentException e){
			e.printStackTrace();
		}
		return map;
	}
}

 

Day3:封装用户消息

第一步:将传送回来的数据进行分类处理。把map的数据拿出来,放入switch分类判断。

public static String getResponse(Map<String, String> requestMap) {
		BaseMessage msg = null;
		String msgType = requestMap.get("MsgType");
		switch(msgType) {
			case "text":
				msg = dealTextMessage(requestMap);
				break;
			case "image":
				break;
			case "voice":
				break;
			case "video":
				break;
			case "shortvideo":
				break;
			case "link":
				break;
			default :
				break;
		}
		//把消息对象处理为XML数据包
		if(msg != null){
			return beanToXMl(msg);
		}
		return null;
	}

第二步:利用dealTextMessage函数将数据传送 “还好” 回来。

private static BaseMessage dealTextMessage(Map<String, String> requestMap) {
		TextMessage tm = new TextMessage(requestMap , "pretty good");
		return tm;	
}

TestMessage.java: 封装这个"还好"这个词汇。当然返还回来的是一个string类型的语句。

public class TextMessage extends BaseMessage{
	@XStreamAlias("Content")
	private String content;
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public TextMessage(Map<String , String> requestMap , String content){
	    super(requestMap);
		this.setMsgType("text");
		this.content = content;
	}
	@Override
	public String toString() {
		return "TextMessage [content=" + content + ", getToUserName()="
				+ getToUserName() + ", getFromUserName()="    +
                getFromUserName()+ ", getCreateTime()=" + getCreateTime() + "]";
	}
}

第三步:将string语句转化成XML语言。

这个地方利用了一个XStream包,可以转换成xml语言。XStream的包位置依旧放在文件lib下。

XStream下载链接:XStream

//把对象转换成XML代码
	private static String beanToXMl(BaseMessage msg) {
		XStream stream = new XStream();
		//设置需要处理XStreamAlias("xml")注释的类
		stream.processAnnotations(TextMessage.class);
		stream.processAnnotations(NewsMessage.class);
		stream.processAnnotations(MusicMessage.class);
		stream.processAnnotations(ImageMessage.class);
		stream.processAnnotations(VideoMessage.class);
		stream.processAnnotations(VoiceMessage.class);
		String xml = stream.toXML(msg);
		//System.out.println(xml);
		return xml;
	}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值