流程
生成推广二维码,上面带参数(场景值)。
用户扫描带场景值二维码时,可能推送以下两种事件:
如果用户还未关注公众号,则用户可以关注公众号,关注后微信会将带场景值关注事件推送给开发者。(除了场景值,用户信息)
如果用户已经关注公众号,在用户扫描后会自动进入会话,微信也会将带场景值扫描事件推送给开发者。
- 相关文档
https://developers.weixin.qq.com/doc/offiaccount/Account_Management/Generating_a_Parametric_QR_Code.html
- 后台接收接口
https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html
前提
-
准备好账号信息包含
appId
,appsecret
。如果没有账号可以去申请一个沙盒https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index
-
编写好代码去把后台接口配置信息配一下
url
: 你后台接收服务的地址,get和post请求得全部支持,前者验证,后者接收消息token
: 拿来做验证的。微信服务器使用nonce来做sha1加密。 注意:没有端口,拿个
ngnix
或者负载均衡配置一下(微信服务器只支持443和80端口)。这只是最简单的后台接收微信消息(扫码登录,发消息,取消关注等等)
依赖
<!--hu-tool工具-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.11</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.24</version>
</dependency>
<!--编解码-->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
<!--解析xml-->
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.9</version>
</dependency>
代码
- 控制器
package com.test.wxproduction.controller;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/login")
public class LoginController {
// appId\appSecret 实际生产中应该配置到数据库
private static String appId = "wx017275cd59d7000";
private static String appSecret = "0eac664b6743decf9af7f5cca4810000";
//微信后台设置的token(用来做接口验证)
private static String TOKEN = "wx017275cd59d70000";
/**
* @Description : 生成二维码url
* @Return : java.lang.String
* @Author : 郝子樑
* @Date : 2023-02-03 14:00
*/
@GetMapping("/codeUrl")
public String codeUrl(){
//获取access_token
//先拿着自己的appid和appSecret 去查询在微信后台的token
String temp = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
temp = String.format(temp,appId,appSecret);
String s = HttpUtil.get(temp);
//提取token
JSONObject bb = JSON.parseObject(s);
String token = bb.getString("access_token");
//获取到token后问微信后台要求生成一个ticket(这个是作为二维码的标识id)
HashMap<String,Object> postBody = new HashMap<>();
//拼接参数
postBody.put("expire_seconds",604800);
postBody.put("action_name","QR_SCENE");
HashMap<String,Object> info = new HashMap<>();
HashMap<String,Object> scene = new HashMap<>();
scene.put("scene_id",123);
info.put("scene",scene);
postBody.put("action_info",info);
String jsonString = JSON.toJSONString(postBody);
//说明
// expire_seconds 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为60秒。
// action_name 二维码类型,QR_SCENE为临时的整型参数值,QR_STR_SCENE为临时的字符串参数值,QR_LIMIT_SCENE为永久的整型参数值,QR_LIMIT_STR_SCENE为永久的字符串参数值
// action_info 二维码详细信息
// scene_id 场景值ID,临时二维码时为32位非0整型,永久二维码时最大值为100000(目前参数只支持1--100000)
// scene_str 场景值ID(字符串形式的ID),字符串类型,长度限制为1到64
String res = HttpUtil.post("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token="+token, jsonString);
//JSON中可以取到ticket信息,拿着去换二维码
//拿着ticket就可以直接拼接个url,指向二维码图片
JSONObject object = JSON.parseObject(res);
System.out.println(res);
String ticket = object.getString("ticket");
//二维码地址
String url = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket="+ticket;
return url;
}
/**
* @Description : 微信后台初次设置时要验证接口是否连通,这里按照官方文档写一下验证规则就好
* @Params : [req, resp]
* @Return : java.lang.String
* @Author : 郝子樑
* @Date : 2023-02-03 16:30
*/
@GetMapping("/notify")
public String echo(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("接收到消息了!!!!!!!!!!!");
// 1.获取微信传入的4个参数
String signature = req.getParameter("signature");
String timestamp = req.getParameter("timestamp");
String nonce = req.getParameter("nonce");
String echostr = req.getParameter("echostr");
// 2.用timestamp, nonce, signature进行校验
boolean result = check(timestamp, nonce, signature);
if (result) {
// 3.校验成功返回echostr
return echostr;
}
return "error!";
}
/**
* @Description : 微信后台拿来接收消息的接口,设置时发送get,后续就是post,请求中带有xml文件,从xml文件中读取内容。
* @Params : [response, request]
* @Return : void
* @Author : 郝子樑
* @Date : 2023-02-03 16:32
*/
@PostMapping("/notify")
public void handleMsgIn(HttpServletResponse response, HttpServletRequest request) throws Exception {
// 从request中取得微信通知的消息
Map<String, String> msgMap = MessageUtil.parseXml(request);
System.out.println("微信收到的消息:"+msgMap);
}
public static boolean check(String timestamp, String nonce, String signature) {
// 1.按字典序对TOKEN, timestamp和nonce排序
String[] arr = new String[]{TOKEN,timestamp,nonce};
Arrays.sort(arr);
// 2.将3个参数拼成一个字符串进行sha1加密
String str = arr[0]+arr[1]+arr[2];
// 3.用commons-codec包中的工具类进行sha1加密
str = DigestUtils.sha1Hex(str);
// 4.将加密后的字符串和signature比较
System.out.println(signature);
return str.equalsIgnoreCase(signature);
}
}
- 工具类
package com.test.wxproduction.controller;
import java.io.InputStream;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
public class MessageUtil {
/**
* 解析微信发来的请求(XML)
*
* @param request
* @return
* @throws Exception
*/
public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
// 将解析结果存储在HashMap中
Map<String, String> map = new HashMap<String, String>();
// 从request中取得输入流
InputStream inputStream = request.getInputStream();
// 读取输入流
SAXReader reader = new SAXReader();
Document document = reader.read(inputStream);
// 得到xml根元素
Element root = document.getRootElement();
// 得到根元素的所有子节点
@SuppressWarnings("unchecked")
List<Element> elementList = root.elements();
// 遍历所有子节点
for (Element e : elementList)
map.put(e.getName(), e.getText());
// 释放资源
inputStream.close();
inputStream = null;
return map;
}
/**
* 扩展xstream,使其支持CDATA块
*
*/
private static XStream xstream = new XStream(new XppDriver() {
@Override
public HierarchicalStreamWriter createWriter(Writer out) {
return new PrettyPrintWriter(out) {
// 对所有xml节点的转换都增加CDATA标记
boolean cdata = true;
@Override
protected void writeText(QuickWriter writer, String text) {
if (cdata) {
writer.write("<![CDATA[");
writer.write(text);
writer.write("]]>");
} else {
writer.write(text);
}
}
};
}
});
}
标签:String,登录,微信,token,二维码,自行处理,注册,import,com
From: https://www.cnblogs.com/beamsoflight/p/17089802.html