• 微信公众号开发之生成带参数的二维码(六)


    为了满足用户渠道推广分析和用户帐号绑定等场景的需要,公众平台提供了生成带参数二维码的接口。使用该接口可以获得多个带不同场景值的二维码,用户扫描后,公众号可以接收到事件推送。

    目前有2种类型的二维码:

    1、临时二维码,是有过期时间的,最长可以设置为在二维码生成后的30天(即2592000秒)后过期,但能够生成较多数量。临时二维码主要用于帐号绑定等不要求二维码永久保存的业务场景 2、永久二维码,是无过期时间的,但数量较少(目前为最多10万个)。永久二维码主要用于适用于帐号绑定、用户来源统计等场景。

    用户扫描带场景值二维码时,可能推送以下两种事件:

    如果用户还未关注公众号,则用户可以关注公众号,关注后微信会将带场景值关注事件推送给开发者。

    如果用户已经关注公众号,在用户扫描后会自动进入会话,微信也会将带场景值扫描事件推送给开发者。

    获取带参数的二维码的过程包括两步,首先创建二维码ticket,然后凭借ticket到指定URL换取二维码。

    http请求方式: POST
    URL: https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=TOKEN
    POST数据格式:json
    POST数据例子:{"expire_seconds": 604800, "action_name": "QR_SCENE", "action_info": {"scene": {"scene_id": 123}}}
    
    或者也可以使用以下POST数据创建字符串形式的二维码参数:
    {"expire_seconds": 604800, "action_name": "QR_STR_SCENE", "action_info": {"scene": {"scene_str": "test"}}}

    参数说明

    参数说明
    expire_seconds 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒。
    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

    返回说明

    正确的Json返回结果:

    {"ticket":"gQH47joAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL2taZ2Z3TVRtNzJXV1Brb3ZhYmJJAAIEZ23sUwMEmm
    3sUw==","expire_seconds":60,"url":"http://weixin.qq.com/q/kZgfwMTm72WWPkovabbI"}
    
    参数说明
    ticket 获取的二维码ticket,凭借此ticket可以在有效时间内换取二维码。
    expire_seconds 该二维码有效时间,以秒为单位。 最大不超过2592000(即30天)。
    url 二维码图片解析后的地址,开发者可根据该地址自行生成需要的二维码图片

    通过ticket换取二维码

    获取二维码ticket后,开发者可用ticket换取二维码图片。请注意,本接口无须登录态即可调用。

    请求说明

    HTTP GET请求(请使用https协议)https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=TICKET
    提醒:TICKET记得进行UrlEncode

     一、新建一个QrCodeUtil里面包含三个方法,分别是封装请求的参数,产生二维码和获得二维码

    QrCodeUtil.java
    package com.xu.wemall.components.weixin;

    import com.alibaba.fastjson.JSONObject;
    import com.xu.wemall.commons.constants.URIConstant;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.web.client.RestTemplate;

    import java.io.UnsupportedEncodingException;
    import java.net.URLEncoder;
    import java.util.TreeMap;

    @Slf4j
    @Component
    public class QrCodeUtil {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private AccessTokenUtil accessTokenUtil;

    private String createQrCodeString(String sceneStr) {

    TreeMap<String, String> params = new TreeMap<>();
    // output data
    JSONObject data = new JSONObject();
    data.put("action_name", "QR_SCENE");
    data.put("expire_seconds", 3600);//一小时

    JSONObject scene = new JSONObject();
    scene.put("scene_str", sceneStr);
    JSONObject actionInfo = new JSONObject();
    actionInfo.put("scene", scene);
    data.put("action_info", actionInfo);

    return data.toJSONString();

    }

    public JSONObject createQrCode(String sceneId) {

    String qrCodeString = this.createQrCodeString(sceneId);
    log.info("qrCodeString:{}", qrCodeString);

    String accessToken = accessTokenUtil.getAccessToken();
    if (accessToken != null) {
    log.info("URL{}", URIConstant.CREATE_QRCODE_URL);
    String url = URIConstant.CREATE_QRCODE_URL.replace("ACCESS_TOKEN", accessToken);
    log.info("URL_ACCESS_TOKEN:{}", url);
    //将菜单对象转换成JSON字符串

    //发起POST请求创建菜单
    JSONObject jsonObject = restTemplate.postForObject(url, qrCodeString, JSONObject.class);

    return jsonObject;
    }
    return null;

    }

    public void showQrCode(String ticket) throws UnsupportedEncodingException {

    String TICKET = URLEncoder.encode(ticket, "utf-8");

    log.info("URL{}", URIConstant.SHOW_QRCODE_URL);
    String url = URIConstant.SHOW_QRCODE_URL.replace("TICKET", TICKET);
    log.info("SHOW_QRCODE_URL:{}", url);
    //将菜单对象转换成JSON字符串

    //发起POST请求创建菜单
    restTemplate.getForObject(url, JSONObject.class);

    }

    }

    二、我们新建一个controller用来提交我们的请求

    QrCodeWxController.java
    package com.xu.wemall.controller.weixin;

    import com.alibaba.fastjson.JSONObject;
    import com.xu.wemall.components.weixin.QrCodeUtil;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;

    import java.io.UnsupportedEncodingException;

    /**
    * 类名称: LoginController
    * 类描述: 与微信对接登陆验证
    *
    * @author yuanjun
    * 创建时间:2017年12月5日上午10:52:13
    */
    @Slf4j
    @RestController
    @Api(tags = "微信生成带参的二维码接口")
    @RequestMapping(value = "/weixin/qrcode")
    public class QrCodeWxController {

    @Autowired
    private QrCodeUtil qrCodeUtil;

    @ApiOperation(value = "创建带参的二维码")
    @RequestMapping(value = "/createQrCode", method = RequestMethod.POST)
    public Object createQrCode(String sceneId) {

    JSONObject jsonObject = qrCodeUtil.createQrCode(sceneId);
    return jsonObject;

    }

    @ApiOperation(value = "获取带参的二维码")
    @RequestMapping(value = "/showQrCode", method = RequestMethod.GET)
    public void showQrCode(String ticket) throws UnsupportedEncodingException {
    qrCodeUtil.showQrCode(ticket);

    }

    }

    三、我们打开我们的swagger页面提交一下请求试试看

    四、根据ticket获取二维码

    https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=gQEd7zwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyYlo5NXRyR0ljZ2oxOFVkZHh1MWQAAgQofw1eAwQQDgAA

    五、【One More Thing!!!】

    那这个二维码别人扫了我们怎么知道呢?回答:如果别人扫了我们生成的二维码就会触发我们的扫码事件,微信服务器就会给我们推送如下的消息包

    <xml>
      <ToUserName><![CDATA[toUser]]></ToUserName>
      <FromUserName><![CDATA[FromUser]]></FromUserName>
      <CreateTime>123456789</CreateTime>
      <MsgType><![CDATA[event]]></MsgType>
      <Event><![CDATA[SCAN]]></Event>
      <EventKey><![CDATA[SCENE_VALUE]]></EventKey>
      <Ticket><![CDATA[TICKET]]></Ticket>
    </xml> 

    到这里你应该清楚了吧,我们在我们的微信对接接口的POST方法里增加如下代码即可:

    WeiXinController.java
    package com.xu.wemall.controller.weixin;

    import com.alibaba.fastjson.JSONObject;
    import com.xu.wemall.commons.utils.CheckUtil;
    import com.xu.wemall.components.weixin.MessageUtil;
    import com.xu.wemall.components.weixin.WeiXinUserUtil;
    import io.swagger.annotations.Api;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.PrintWriter;
    import java.util.Map;

    /**
    * 类名称: LoginController
    * 类描述: 与微信对接登陆验证
    *
    * @author yuanjun
    * 创建时间:2017年12月5日上午10:52:13
    */
    @Slf4j
    @RestController
    @Api(tags = "接入验证接口")
    @RequestMapping(value = "/weChart")
    public class WeiXinController {

    @Autowired
    private WeiXinUserUtil weiXinUserUtil;

    @Autowired
    private MessageUtil messageUtil;

    @RequestMapping(value = "/connect", method = RequestMethod.GET)
    public String connect(@RequestParam(value = "signature") String signature,
    @RequestParam(value = "timestamp") String timestamp,
    @RequestParam(value = "nonce") String nonce,
    @RequestParam(value = "echostr") String echostr) {

    log.info("-----开始校验签名-----");
    PrintWriter out = null;
    if (CheckUtil.checkSignature(signature, timestamp, nonce)) {
    log.info("-----签名校验通过-----");
    return echostr;
    } else {
    log.info("-----校验签名失败-----");
    return null;
    }

    }

    @RequestMapping(value = "connect", method = RequestMethod.POST)
    public String dopost(HttpServletRequest request, HttpServletResponse response) throws Exception {

    response.setCharacterEncoding("utf-8");

    //将微信请求xml转为map格式,获取所需的参数
    Map<String, String> map = MessageUtil.parseXml(request);
    String ToUserName = map.get("ToUserName");
    String FromUserName = map.get("FromUserName");
    String MsgType = map.get("MsgType");
    String Content = map.get("Content");
    String Event = map.get("Event");

    if(MessageUtil.REQ_MESSAGE_TYPE_EVENT.equals(MsgType)){

    if(MessageUtil.EVENT_TYPE_SUBSCRIBE.equals(Event)){
    String xmlString = messageUtil.subscribeForText(ToUserName,FromUserName);

    //关注了公众号,调用接口获得用户的详细信息并保存到后台
    JSONObject jsonObject = weiXinUserUtil.handdleWeixinUserInfo(FromUserName);
    log.info("获取用户的详细信息:{}",jsonObject.toJSONString());

    return xmlString;

    }else if(MessageUtil.EVENT_TYPE_UNSUBSCRIBE.equals(Event)){

    String xmlString = messageUtil.unsubscribeForText(ToUserName,FromUserName);
    return xmlString;

    }else if(MessageUtil.EVENT_TYPE_SCAN.equals(Event)){
    JSONObject jsonObject = weiXinUserUtil.handdleWeixinUserInfo(FromUserName);
    log.info("获取用户的详细信息:{}",jsonObject.toJSONString());

    }

    }

    //处理文本类型,实现输入1,回复相应的封装的内容
    if (MessageUtil.REQ_MESSAGE_TYPE_TEXT.equals(MsgType)) {
    String xmlString = messageUtil.replyForText(ToUserName,FromUserName,"你发送的是:" + Content);
    log.info(xmlString);
    return xmlString;

    }

    if (MessageUtil.REQ_MESSAGE_TYPE_IMAGE.equals(MsgType)) {

    String filePath = "C:\Users\RonnieXu\Pictures\2.jpg";
    String xmlString = messageUtil.replyForImage(ToUserName,FromUserName,filePath);
    return xmlString;
    }

    return null;
    }

    }
    WeiXinUserUtil.java
    package com.xu.wemall.components.weixin;

    import com.alibaba.fastjson.JSONObject;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.xu.wemall.commons.constants.URIConstant;
    import com.xu.wemall.entry.WxUser;
    import com.xu.wemall.service.IWxUserService;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.web.client.RestTemplate;

    @Slf4j
    @Component
    public class WeiXinUserUtil {

    @Autowired
    private IWxUserService iWxUserService;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private AccessTokenUtil accessTokenUtil;

    public JSONObject handdleWeixinUserInfo(String openId) {

    String accessToken = accessTokenUtil.getAccessToken();
    if (accessToken != null) {
    log.info("URL{}", URIConstant.OPENID_USERINFO_URL);
    String url = URIConstant.OPENID_USERINFO_URL.replace("ACCESS_TOKEN", accessToken)
    .replace("OPENID", openId);
    log.info("OPENID_USERINFO_URL:{}", url);

    //发起POST请求创建菜单
    JSONObject jsonObject = restTemplate.getForObject(url, JSONObject.class);

    //表示订阅了该公众号
    if (jsonObject.getIntValue("subscribe") == 1) {
    //保存
    WxUser wxUser = JSONObject.parseObject(jsonObject.toJSONString(), WxUser.class);

    //先查一下是否曾经查询过(查看数据库数据)
    QueryWrapper<WxUser> queryWrapper = new QueryWrapper();
    queryWrapper.lambda().eq(WxUser::getOpenid, openId);
    WxUser wxUserExist = iWxUserService.getOne(queryWrapper);
    if (wxUserExist == null) {
    boolean result = iWxUserService.saveOrUpdate(wxUser);
    }

    }

    return jsonObject;
    }

    return null;
    }

    }

    打完收工,下回再见!

    ========================================================================================================================================================================================================

    如果您觉得此文有帮助,可以小小打赏一下,持续更新更有动力哟!

  • 相关阅读:
    使用脚本进入一个命令行控制台,并预设执行的命令列表
    cifs挂载远程文件出现 No such device or address错误
    longtable 跨越多个页面时,如何在跨页时自动断行并加上横线及去掉页眉
    matplotlib中文显示-微软雅黑
    latex编译过程-关于嵌入所有字体
    python做图笔记
    linux启动全过程
    连接并同步windows下的git仓库
    反向ssh
    Ubuntu更改启动内存
  • 原文地址:https://www.cnblogs.com/xulijun137/p/12213604.html
Copyright © 2020-2023  润新知