最近公司原本的公众号要发布3.0版本,所以自己申请了一个微信公众号进行测试,第一步就是实现了通过微信接收信息转发至java后台解析并回复的消息的简单功能,经过一番研究终于实现,现在贡献出代码和大家一起分享。
首先百度微信公众平台,进入官网进行公众号的注册,企业可与注册服务号,个人订阅号即可满足大部分功能,申请成功后即可进入到公众平台的相关功能界面
自动回复有两种实现方法,一种是平台自带的回复功能,另一种就是连接后台进行功能实现,如果需要连接后台并在本地调试就需要一款端口映射工具,可以将本地localhost端口映射到外网上,方便进行在公众号服务上的部署,我这里使用的是ngrok,免费下载,使用方便,这个我们后续会讲解如何使用
在进本配置中我们可以看到公众平台给我们的开发者id,需要我们自己配置的:
1.服务器地址URL:这里就是本地服务器部署成功后,通过ngrok映射出的外网地址,当项目部署到发布机上后,就可以改为正式的地址,但必须以http://或https://开头,分别支持80端口和443端口。
2.令牌:令牌是微信端和服务器端配对的基本,令牌只要满足是英文或数字,长度为3-32字符就可以,这里的令牌稍后在服务器端的要相同才可以请求成功
3.秘钥:随机生成就可以
本人使用的是intellij下的springboot框架实现的相关功能,各部分代码如下
在controller首先进入controller中的/movie/getSpecMovie方法中,此方法即是URL的方法地址,在开头定义我们的Token,和平台上的token对应,通过判断是get方法还是post方法进入不同分支方法,get方位为提交服务器配置时的验证使用,post是接收到公众号内消息进行的逻辑处理
Controller
package com.borya.controller;
private String Token = "123456";
@RestController
@RequestMapping("/movie")
public class movieController {
@RequestMapping(value = "/getSpecMovie" , method = {RequestMethod.GET,RequestMethod.POST})
public void getSpecMovie(HttpServletRequest request , HttpServletResponse response){
response.setContentType("text/html;charset=utf-8");
System.out.println("进入方法");
Boolean isGet = request.getMethod().toLowerCase().equals("get");
if (isGet){
String signature = request.getParameter("signature");
String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String echostr = request.getParameter("echostr");
System.out.println(signature);
System.out.println(timestamp);
System.out.println(nonce);
System.out.println(echostr);
access(request, response);
}else{
// 进入POST聊天处理
System.out.println("enter post");
try {
// 接收消息并返回消息
acceptMessage(request, response);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 验证url真实性
* @param request
* @param response
* @return
*/
private String access(HttpServletRequest request , HttpServletResponse response){
// 验证URL真实性
System.out.println("进入验证access");
String signature = request.getParameter("signature");// 微信加密签名
String timestamp = request.getParameter("timestamp");// 时间戳
String nonce = request.getParameter("nonce");// 随机数
String echostr = request.getParameter("echostr");// 随机字符串
List<String> params = new ArrayList<String>();
params.add(Token);
params.add(timestamp);
params.add(nonce);
// 1. 将token、timestamp、nonce三个参数进行字典序排序
Collections.sort(params, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
// 2. 将三个参数字符串拼接成一个字符串进行sha1加密
String temp = SHA1.encode(params.get(0) + params.get(1) + params.get(2));
if (temp.equals(signature)) {
try {
response.getWriter().write(echostr);
System.out.println("成功返回 echostr:" + echostr);
return echostr;
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("失败 认证");
return null;
}
private void acceptMessage(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 处理接收消息
ServletInputStream in = request.getInputStream();
// 将POST流转换为XStream对象
XStream xs = SerializeXmlUtil.createXstream();
xs.processAnnotations(wechatInputMessage.class);
xs.processAnnotations(wechatOutputMessage.class);
// 将指定节点下的xml节点数据映射为对象
xs.alias("xml", wechatInputMessage.class);
// 将流转换为字符串
StringBuilder xmlMsg = new StringBuilder();
byte[] b = new byte[4096];
for (int n; (n = in.read(b)) != -1;) {
xmlMsg.append(new String(b, 0, n, "UTF-8"));
}
// 将xml内容转换为InputMessage对象
wechatInputMessage inputMsg = (wechatInputMessage) xs.fromXML(xmlMsg.toString());
String servername = inputMsg.getToUserName();// 服务端
String custermname = inputMsg.getFromUserName();// 客户端
long createTime = inputMsg.getCreateTime();// 接收时间
Long returnTime = Calendar.getInstance().getTimeInMillis() / 1000;// 返回时间
// 取得消息类型
String msgType = inputMsg.getMsgType();
// 根据消息类型获取对应的消息内容
if (msgType.equals(MsgType.Text.toString())) {
// 文本消息
System.out.println("开发者微