微信推广带id二维码生成详细解读

需求:登录用户产生一个二维码,下一个人扫描这个二维码之后关注公众号,登录之后自动成为第一个用户的粉丝

吐槽一把,这个需求很操蛋。。。。但是,操不操蛋那是你程序猿说的不?微信开发本来就相当操蛋了。。。都懂得,文档又少,限制又多,傻逼的很。。。。 

首先看下微信官方的文档,我们先了解下需要哪些东西


当然毫不犹豫的点开。。。 然后发现这个。。 



却发现,并没有神马卵用 。。。。。。。。  生成二维码需要token ,我们就按照他提供的方法来搞一搞了。。。 就按照他提供的方法搞一搞了。。 

二维码的几种生成方式,在这里就不解释了。。 

不够简单粗暴,我直接上java代码了。。。。。 


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;

import net.sf.json.JSONObject;

public class Test {

	static String wechatAppID = "";
	static String wechatAppSecret = "";
	static String wechatAccessTokenUrl = "";

	public static String getWechatAccessToken() {

		try {
			URL object = new URL(wechatAccessTokenUrl + "&appid=" + wechatAppID + "&secret=" + wechatAppSecret);
			HttpURLConnection con = (HttpURLConnection) object.openConnection();
			con.setDoOutput(true);
			con.setDoInput(true);
			con.setRequestProperty("Content-Type", "application/json");
			con.setRequestProperty("Accept", "application/json");
			con.setRequestMethod("GET");

			OutputStreamWriter wr = new OutputStreamWriter(con.getOutputStream(), "utf-8");
			wr.flush();
			// 显示 POST 请求返回的内容
			StringBuilder sb = new StringBuilder();
			int HttpResult = con.getResponseCode();
			if (HttpResult == HttpURLConnection.HTTP_OK) {
				BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "utf-8"));
				String line = null;
				while ((line = br.readLine()) != null) {
					sb.append(line + "\n");
				}
				br.close();
				System.out.println("" + sb.toString());
			} else {
				System.out.println(con.getResponseMessage());
			}

			return sb.toString();
		} catch (Exception e) {
			e.printStackTrace();
		}

		return "";
	}

	public static String getUserQRCode(Integer userId) {
		JSONObject jsonObject = JSONObject.fromObject(getWechatAccessToken());
		String access_token = jsonObject.getString("access_token");
		try {
			URL object = new URL("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + access_token);
			HttpURLConnection con = (HttpURLConnection) object.openConnection();
			con.setDoOutput(true);
			con.setDoInput(true);
			con.setRequestProperty("Content-Type", "application/json");
			con.setRequestProperty("Accept", "application/json");
			con.setRequestMethod("POST");
			JSONObject data = new JSONObject();
			data.put("action_name", "QR_LIMIT_SCENE");
			JSONObject dojb = new JSONObject();
			dojb.put("scene_id", userId);
			JSONObject cojb = new JSONObject();
			cojb.put("scene", dojb);
			data.put("action_info", cojb);
			OutputStreamWriter wr = new OutputStreamWriter(con.getOutputStream(), "utf-8");
			wr.write(data.toString());
			wr.flush();
			// 显示 POST 请求返回的内容
			StringBuilder sb = new StringBuilder();
			int HttpResult = con.getResponseCode();
			if (HttpResult == HttpURLConnection.HTTP_OK) {
				BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "utf-8"));
				String line = null;
				while ((line = br.readLine()) != null) {
					sb.append(line + "\n");
				}
				br.close();

				JSONObject jsonObj = JSONObject.fromObject(sb.toString());
				String ticket = jsonObj.getString("ticket");
				 生成二维码
				return "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + ticket;

			} else {
				System.out.println(con.getResponseMessage());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return "";
	}

}


运行这两段代码之后,我们发现我们的二维码居然生成了 ,第二个方法返回一个字符串就是二维码图片的绝对路径。。。。 生成的二维码我在这里就不解释了 。。 截出来也没有神马卵用。。。  我们回头看看方法。。。



我们发现我们用的是scene_id ,而没有使用字符串,为啥子????????  这个问题很关键二维码是生成了,但是怎么把二维码里面的id和下一个用户关联起来了?下一个用户关注上一个用户的二维码,我擦,我怎么知道啥时候关注了了 ???? 如果把上下级用户关联起来了 ?  重重问题 。。。 各种蛋疼。。。 

首先,当用户点击微信公众号关注的时候,后台是如何知道哪个用户点击了关注了 ? 那么就有这么一个问题,那就是通信的问题,当用户点击关注,微信公众号如何跟我们自己的后台通信了 ???? 这个很关键

你需要在微信公众号的后台做一些配置,打开后台




IP白名单,就是哪些IP有权限调用这些接口,一般配置你服务器的IP和你开发电脑的公网IP(不是192.168.0.111),好吧,来张图吧。。 



然后启动这东西 。。。 



然后填写以下配置。。。 



URL:其实就是一个外网可以访问的接口,注意:必须是80或443端口,做过后台都懂得。。。 这个接口的作用是,被微信调用,然后产生回调。。。。。也就是微信通过这个接口你的服务器发送消息。这个很重要

Token:自己定义的一个字符串,加密的要是,你写jinsanpang都可以;可以参考我的另外一篇文章了解token(http://blog.csdn.net/chmod_r_755/article/details/75554735

EncodeKey:随机生成,干啥子用的,不知道,问微信

模式:明文模式,你想怎样? 加密? 搞得跟真的似的 ,有意思吗?金融机构自己看着办 。。。。 

到这里,我们就明白了,用户关注微信我们的后台是怎么知道的。。。原来是有通信的 。。。这块我们就必须搞一个接口了,让微信回调。。。。。。 

说太抽象了 。。。。  我们首先来张图 。。 



当我扫码关注的时候, 微信会回调这个接口,注意我这边日志是json格式的,但是网上有xml版本的



这种格式的,因为我把xml转json了,xml看着都蛋疼 ,来段代码压压惊


@RequestMapping(value = "/wx.do")
	public void get(@RequestBody(required = false) String body, HttpServletRequest request,
			HttpServletResponse response) throws Exception {

		org.json.JSONObject jsonObject = JSONML.toJSONObject(body);
		logger.info("请求进来了..." + jsonObject);

		org.json.JSONArray jsonArray = jsonObject.getJSONArray("childNodes");

		org.json.JSONObject fromUser = null;
		org.json.JSONObject event = null;
		org.json.JSONObject eventKey = null;

		for (int i = 0; i < jsonArray.length(); i++) {
			org.json.JSONObject obj = jsonArray.getJSONObject(i);

			String tagName = obj.getString("tagName");

			if ("FromUserName".equals(tagName)) {
				fromUser = obj;
			} else if ("Event".equals(tagName)) {
				event = obj;
			} else if ("EventKey".equals(tagName)) {
				eventKey = obj;
			}
		}

		logger.info("请求进来了...fromUser=" + fromUser.toString() + "    event=" + event.toString() + "    eventKey="
				+ eventKey.toString());

		if (event != null && eventKey != null && fromUser != null) {

			org.json.JSONArray eventArray = event.getJSONArray("childNodes");
			org.json.JSONArray eventKeyArray = eventKey.getJSONArray("childNodes");
			org.json.JSONArray fromUserNameArray = fromUser.getJSONArray("childNodes");

			logger.info("请求进来了...eventArray=" + eventArray.toString() + "    eventKeyArray=" + eventKeyArray.toString()
					+ "    fromUserNameArray=" + fromUserNameArray.toString());
			if (eventArray.length() > 0 && fromUserNameArray.length() > 0 && eventKeyArray.length() > 0) {
				String subscribeString = eventArray.getString(0); // 动作
				String fromUserString = fromUserNameArray.getString(0); // openId
				String eventKeyString = eventKeyArray.getString(0); // 带入的信息

				logger.info("请求进来了...subscribeString=" + subscribeString + "    fromUserString=" + fromUserString
						+ "    eventKeyString=" + eventKeyString);

				if ("subscribe".equals(subscribeString)) {
					// 点击关注, 保存上级的id 且保存openId
					// 点击取消关注,删除这条记录
					// 如果 eventKeyString 为空字符串 ,表示关注官方二维码关注的
					/// 包含上级Id ,则保存到数据库中
					if (eventKeyString.contains("qrscene_")) {
						String userIdString = eventKeyString.replaceAll("qrscene_", "");
						Integer userId = Integer.parseInt(userIdString);
						WechatKey wechatKey = new WechatKey();
						wechatKey.setOpenId(fromUserString);
						wechatKey.setUserId(userId);
						wechatKeyManager.saveWechatkey(wechatKey);

					}

				} else if ("unsubscribe".equals(subscribeString)) {
					WechatKey wechatKey = wechatKeyManager.getWechatKeyByOpenId(fromUserString);
					if (wechatKey != null) {
						wechatKeyManager.deleteByOpenId(fromUserString);
					}
				}

			}

		}

		Enumeration pNames = request.getParameterNames();
		while (pNames.hasMoreElements()) {
			String name = (String) pNames.nextElement();
			String value = request.getParameter(name);
			// out.print(name + "=" + value);

			String log = "name =" + name + "     value =" + value;
			logger.error(log);
		}

		String signature = request.getParameter("signature");/// 微信加密签名
		String timestamp = request.getParameter("timestamp");/// 时间戳
		String nonce = request.getParameter("nonce"); /// 随机数
		String echostr = request.getParameter("echostr"); // 随机字符串
		PrintWriter out = response.getWriter();

		if (CheckUtil.checkSignature(signature, timestamp, nonce)) {
			out.print(echostr);
		}
		out.close();
		out = null;

	}


关注的时候微信会给服务器推送一条消息


subscribe:表示开始关注

fromUser:表示哪个用户关注的,这里返回的是当前用户的openId ,唯一的 

EventKey:qrscene_20 前面的qrscene_是固定的,后面的20 也就是上个用户的id

那么到了这一步, 上个用户和下一个用户就联系在一起了。。。。。。如果扫的码是系统生成的。。。EventKey:就为空字符串了。。

扯到这里了 。。。。  其他的不解释,自己理解。。。。 







  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
要生成微信支付二维码,可以使用微信支付官方提供的接口,以下是基于 Spring Boot 的简单实现步骤: 1. 引入相关依赖 ```xml <dependency> <groupId>com.github.wxpay</groupId> <artifactId>wxpay-sdk</artifactId> <version>3.0.9</version> </dependency> <dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>3.3.3</version> </dependency> <dependency> <groupId>com.google.zxing</groupId> <artifactId>javase</artifactId> <version>3.3.3</version> </dependency> ``` 2. 配置微信支付相关参数 ```java @Configuration public class WxPayConfig { // 微信支付分配的商户号 @Value("${wxpay.mchId}") private String mchId; // 微信支付分配的终端设备号 @Value("${wxpay.deviceInfo}") private String deviceInfo; // 微信支付分配的公众账号ID @Value("${wxpay.appId}") private String appId; // 微信支付分配的商户密钥 @Value("${wxpay.key}") private String key; // 微信支付异步通知地址 @Value("${wxpay.notifyUrl}") private String notifyUrl; // 微信支付统一下单接口地址 @Value("${wxpay.unifiedOrderUrl}") private String unifiedOrderUrl; // 微信支付查询订单接口地址 @Value("${wxpay.orderQueryUrl}") private String orderQueryUrl; // 微信支付关闭订单接口地址 @Value("${wxpay.closeOrderUrl}") private String closeOrderUrl; // 微信支付申请退款接口地址 @Value("${wxpay.refundUrl}") private String refundUrl; // 微信支付查询退款接口地址 @Value("${wxpay.refundQueryUrl}") private String refundQueryUrl; // 微信支付下载对账单接口地址 @Value("${wxpay.downloadBillUrl}") private String downloadBillUrl; // 微信支付交易保障接口地址 @Value("${wxpay.reportUrl}") private String reportUrl; // 签名类型 private final String SIGN_TYPE = "MD5"; // 连接超时时间 private final int CONNECT_TIMEOUT = 5000; // 读取超时时间 private final int READ_TIMEOUT = 10000; // 微信支付API证书路径 @Value("${wxpay.certPath}") private String certPath; // 微信支付API证书密码 @Value("${wxpay.certPassword}") private String certPassword; /** * 初始化微信支付配置 */ @Bean public WXPay wxPay() throws Exception { WXPayConfigImpl config = new WXPayConfigImpl(); config.setAppID(appId); config.setMchID(mchId); config.setKey(key); config.setDeviceInfo(deviceInfo); config.setSignType(SIGN_TYPE); config.setUnifiedOrderUrl(unifiedOrderUrl); config.setOrderQueryUrl(orderQueryUrl); config.setCloseOrderUrl(closeOrderUrl); config.setRefundUrl(refundUrl); config.setRefundQueryUrl(refundQueryUrl); config.setDownloadBillUrl(downloadBillUrl); config.setReportUrl(reportUrl); return new WXPay(config, notifyUrl, true, true); } /** * 微信支付配置类 */ class WXPayConfigImpl extends WXPayConfig { private String appId; private String mchId; private String key; private String deviceInfo; private String signType; private String unifiedOrderUrl; private String orderQueryUrl; private String closeOrderUrl; private String refundUrl; private String refundQueryUrl; private String downloadBillUrl; private String reportUrl; public void setAppID(String appId) { this.appId = appId; } public void setMchID(String mchId) { this.mchId = mchId; } public void setKey(String key) { this.key = key; } public void setDeviceInfo(String deviceInfo) { this.deviceInfo = deviceInfo; } public void setSignType(String signType) { this.signType = signType; } public void setUnifiedOrderUrl(String unifiedOrderUrl) { this.unifiedOrderUrl = unifiedOrderUrl; } public void setOrderQueryUrl(String orderQueryUrl) { this.orderQueryUrl = orderQueryUrl; } public void setCloseOrderUrl(String closeOrderUrl) { this.closeOrderUrl = closeOrderUrl; } public void setRefundUrl(String refundUrl) { this.refundUrl = refundUrl; } public void setRefundQueryUrl(String refundQueryUrl) { this.refundQueryUrl = refundQueryUrl; } public void setDownloadBillUrl(String downloadBillUrl) { this.downloadBillUrl = downloadBillUrl; } public void setReportUrl(String reportUrl) { this.reportUrl = reportUrl; } @Override public String getAppID() { return appId; } @Override public String getMchID() { return mchId; } @Override public String getKey() { return key; } @Override public InputStream getCertStream() { try { return new FileInputStream(new File(certPath)); } catch (FileNotFoundException e) { e.printStackTrace(); } return null; } @Override public int getHttpConnectTimeoutMs() { return CONNECT_TIMEOUT; } @Override public int getHttpReadTimeoutMs() { return READ_TIMEOUT; } @Override public String getDeviceInfo() { return deviceInfo; } @Override public String getSignType() { return signType; } @Override public String getUnifiedOrderUrl() { return unifiedOrderUrl; } @Override public String getOrderQueryUrl() { return orderQueryUrl; } @Override public String getCloseOrderUrl() { return closeOrderUrl; } @Override public String getRefundUrl() { return refundUrl; } @Override public String getRefundQueryUrl() { return refundQueryUrl; } @Override public String getDownloadBillUrl() { return downloadBillUrl; } @Override public String getReportUrl() { return reportUrl; } } } ``` 3. 调用微信支付统一下单接口,获取支付二维码 ```java @RestController @RequestMapping("/wxpay") public class WxPayController { @Autowired private WXPay wxPay; /** * 生成微信支付二维码 * * @param orderId 订单ID * @param amount 支付金额 * @return 二维码图片Base64编码字符串 */ @GetMapping("/qrcode") public String generateQrCode(@RequestParam("order_id") String orderId, @RequestParam("amount") int amount) { try { Map<String, String> data = new HashMap<>(); data.put("body", "xxxx"); // 商品描述 data.put("out_trade_no", orderId); // 订单号 data.put("total_fee", String.valueOf(amount)); // 支付金额,单位为分 data.put("spbill_create_ip", "127.0.0.1"); // 发起支付的客户端IP data.put("notify_url", "http://localhost/wxpay/notify"); // 支付成功的回调地址 data.put("trade_type", "NATIVE"); // 交易类型,JSAPI:公众号支付;NATIVE:扫码支付;APP:APP支付 data.put("product_id", orderId); // 商品ID,trade_type=NATIVE时必填 // 调用微信支付统一下单接口 Map<String, String> result = wxPay.unifiedOrder(data); String return_code = result.get("return_code"); String result_code = result.get("result_code"); if ("SUCCESS".equals(return_code) && "SUCCESS".equals(result_code)) { String codeUrl = result.get("code_url"); // 生成二维码 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); BitMatrix bitMatrix = new MultiFormatWriter().encode(codeUrl, BarcodeFormat.QR_CODE, 300, 300); MatrixToImageWriter.writeToStream(bitMatrix, "png", outputStream); byte[] bytes = outputStream.toByteArray(); return Base64.getEncoder().encodeToString(bytes); } else { String err_code_des = result.get("err_code_des"); throw new RuntimeException(err_code_des); } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e.getMessage()); } } } ``` 以上就是基于 Spring Boot 的微信支付二维码生成的简单实现了。需要注意的是,微信支付二维码的有效期为2小时,超过时间后需要重新生成。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值