微信开发网页弹出二维码

2019-12-20 11:45:18 java_ying 阅读数 1172

首先说下业务场景
需要从某个页面生成二维码,用户扫描二维码,如果已关注公众号,跳到公众号页面,推送小程序链接
如果还未关注公众号,跳转到关注页面,关注公众号后推送小程序链接。
当然从公众号跳转到小程序,多多少少是需要带一点业务相关参数的。
本篇主要将二维码生成,以及事件推送

一、二维码生成

根据官方文档介绍,目前公众号二维码主要有永久和临时两种,但是永久二维码是有数量限制的,临时二维码携带参数又有限制。
所以我们一般都使用临时二维码
官方介绍
生成二维码的动作主要有两步,第一步根据参数拿到二维码ticket,第二步根据ticket换取二维码

首先看获取二维码的参数
二维码参数
拼接结构如下:{“action_name”: “QR_LIMIT_SCENE”, “action_info”: {“scene”: {“scene_id”: 123}}}
注意scene是在action_info 里面的
请求URL为 :https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=TOKEN 类型为POST
返回数据是这样的
{“ticket”:“gQH47joAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL2taZ2Z3TVRtNzJXV1Brb3ZhYmJJAAIEZ23sUwMEmm
3sUw==”,“expire_seconds”:60,“url”:“http://weixin.qq.com/q/kZgfwMTm72WWPkovabbI”}
下面上具体代码

/**
     * 创建临时带参二维码
     *
     * @param accessToken   接口访问凭证
     * @param expireSeconds 二维码有效时间,单位为秒,最大不超过1800
     * @param sceneId       场景ID
     * @return WeixinQRCode
     */
    public WeixinQRCode createTemporaryQRCode(String accessToken, int expireSeconds, String sceneStr) {
        QRCodeParMapping byMappingValue = qrCodeParamMappingUtil.getQrcodeParMappingByMappingValue(sceneStr);
        Integer mappingID = null;
        if (byMappingValue == null) {
            byMappingValue = new QRCodeParMapping();
            byMappingValue.setMappingValue(sceneStr);
            qrCodeParamMappingUtil.save(byMappingValue);
        }
        mappingID = byMappingValue.getMappingID();
        sceneStr = mappingID.toString();
        System.out.println("二维码携带参数为" + sceneStr);
        WeixinQRCode weixinQRCode = null;
        // 拼接请求地址
        String requestUrl = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=ACCESS_TOKEN";
        requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken);
        // 需要提交的json数据
        String jsonMsg = "{\"expire_seconds\": %d, \"action_name\": \"QR_SCENE\", \"action_info\": {\"scene\": {\"scene_id\": %s}}}";
        // 创建临时带参二维码
        JSONObject jsonObject = WechatUtil.httpsRequest(requestUrl, "POST",
                String.format(jsonMsg, expireSeconds, sceneStr));

        if (null != jsonObject) {
            try {
                weixinQRCode = new WeixinQRCode();
                weixinQRCode.setTicket(jsonObject.getString("ticket"));
                weixinQRCode.setExpireSeconds(jsonObject.getInt("expire_seconds"));
                logger.info("创建临时带参二维码成功 ticket:{} expire_seconds:{}", weixinQRCode.getTicket(),
                        weixinQRCode.getExpireSeconds());
            } catch (Exception e) {
                weixinQRCode = null;
                int errorCode = jsonObject.getInt("errcode");
                String errorMsg = jsonObject.getString("errmsg");
                logger.error("创建临时带参二维码失败 errcode:{} errmsg:{}", errorCode, errorMsg);
            }
        }
        return weixinQRCode;
    }

	/**
     * 发起https请求并获取结果
     *
     * @param requestUrl    请求地址
     * @param requestMethod 请求方式(GET、POST)
     * @param outputStr     提交的数据
     * @return JSONObject(通过JSONObject.get ( key)的方式获取json对象的属性值)
     */
    public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {
        JSONObject jsonObject = null;
        StringBuffer buffer = new StringBuffer();
        try {
            // 创建SSLContext对象,并使用我们指定的信任管理器初始化
            TrustManager[] tm = {new MyX509TrustManager()};
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());
            // 从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();

            URL url = new URL(requestUrl);
            HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
            httpUrlConn.setSSLSocketFactory(ssf);

            httpUrlConn.setDoOutput(true);
            httpUrlConn.setDoInput(true);
            httpUrlConn.setUseCaches(false);
            // 设置请求方式(GET/POST)
            httpUrlConn.setRequestMethod(requestMethod);

            if ("GET".equalsIgnoreCase(requestMethod))
                httpUrlConn.connect();

            // 当有数据需要提交时
            if (null != outputStr) {
                OutputStream outputStream = httpUrlConn.getOutputStream();
                // 注意编码格式,防止中文乱码
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }

            // 将返回的输入流转换成字符串
            InputStream inputStream = httpUrlConn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

            String str = null;
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            bufferedReader.close();
            inputStreamReader.close();
            // 释放资源
            inputStream.close();
            inputStream = null;
            httpUrlConn.disconnect();
            jsonObject = JSONObject.fromObject(buffer.toString());
        } catch (ConnectException ce) {
            log.error("Weixin server connection timed out.");
        } catch (Exception e) {
            log.error("https request error:{}", e);
        }
        return jsonObject;
    }
/**
 * 临时二维码信息
 * 
 * @author liufeng
 * @date 2013-11-10
 */
public class WeixinQRCode {
	// 获取的二维码ticket
	private String ticket;
	// 二维码的有效时间,单位为秒,最大不超过1800
	private int expireSeconds;

	public String getTicket() {
		return ticket;
	}

	public void setTicket(String ticket) {
		this.ticket = ticket;
	}

	public int getExpireSeconds() {
		return expireSeconds;
	}

	public void setExpireSeconds(int expireSeconds) {
		this.expireSeconds = expireSeconds;
	}
}

一共两个方法  一个类
第一个方法是生成二维码的步骤,三个参数:1、accessToken 请自备2、过期时间 3、二维码携带参数
第二个方法是访问微信的GET请求
第三个二维码实体类

这里要额外说一个事情,
第一个查询映射的方法,是干什么的
首先上面参数有说过,二维码可携带参数有scene_id 和scene_str  但是临时二维码 只能用ID(关乎于后面的事件推送) 并且是32位非零整型,长度有限制,所以个人做了个参数映射,生成二维码码的参数在数据库关联一个ID,每次ID自增,每次传参要查询是否有对应的ID,没有就生成一个新的
这部分逻辑很简单先不上代码了,如不需要,可自行注释代码,有需要可能后面会补。

这样我们就拿到了二维码的ticket
获取二维码就很简单了
通过访问链接就可以直接拿到二维码
官方是这么写的:
HTTP GET请求(请使用https协议)https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=TICKET
提醒:TICKET记得进行UrlEncode
ticket正确的情况下,状态码200,是一张图片可以下载。错误的话可能是404

这里额外再说一句,那个携带参数,即使是它不支持或者超出限制了,二维码仍然会正常返回,但是参数不会正常携带到后面的事件里面

二、事件接收以及消息推送

首先说事件接收,这个事件接收是一个很广的概念,可以接收很多类型的事件,官方是这么写的
事件
事件推送的URL需要在公众号后台自行配置,是一个URL哦~不同的事件按照分类进行区别开发
二维码的推送参数如下:
事件参数
这是我代码中打印的 已关注用户推送的
在这里插入图片描述
根据这个我们能拿到二维码携带过来的参数 就是Eventkey。
未关注用户推送的:
在这里插入图片描述
注意未关注用户的参数前面带一个qrscene_ 获取时自行截取

事件到了 我们需要做处理
这里返回的不是模版消息,是客服消息
看官方文档
在这里插入图片描述
消息类型是这样,我的需求是要跳转到小程序 并没有链接类型
所以就使用文本类型,里面自己嵌入链接,官方给出了方法

发送文本消息时,支持插入跳小程序的文字链

文本内容<a href="http://www.qq.com" data-miniprogram-appid="appid" data-miniprogram-path="pages/index/index">点击跳小程序</a>
说明: 1.data-miniprogram-appid 项,填写小程序appid,则表示该链接跳小程序; 2.data-miniprogram-path项,填写小程序路径,路径与app.json中保持一致,可带参数; 3.对于不支持data-miniprogram-appid 项的客户端版本,如果有herf项,则仍然保持跳href中的网页链接; 4.data-miniprogram-appid对应的小程序必须与公众号有绑定关系。

下一篇详细介绍怎么回消息以及代码~

2018-09-05 18:04:19 qq_38623459 阅读数 1041

微信官方文档与例子,我使用不了,查找相关文档无数,找了几个靠谱的

https://blog.csdn.net/qq_32574435/article/details/78952325

https://blog.csdn.net/rentian1/article/details/78807199

http://kf.qq.com/faq/170830jimmaa170830B7F7NJ.html

(恩,点赞)

选择模式二开发,好用又快

上来你应该有个配置文件WXpayConfig

商户id,公证号,被扫api地址:就是官方给的统一下单的网址:public static String PAY_QUERY_API = "https://api.mch.weixin.qq.com/pay/orderquery";

我只写被扫,还有回调函数,就是客户扫码支付成功了,会调用后台的地址,一个二维码包含了很多机制与信息

controller

@RequestMapping(value="/qrcodePay",produces="application/json;charset=UTF-8")
    public String qrcodePay(ForWXPay record,HttpServletRequest req,HttpServletResponse response){
        JSONObject json = new JSONObject();
        record.setTrade_type("NATIVE");
        record.setSpbill_create_ip(WXPayUtil.getIpAddr(req));
        Map<String, String> map = wXPayService.unifiedorder(record);
        if(map.get("return_code").equals("SUCCESS")){
            if(map.get("result_code").equals("SUCCESS")){
                String url = map.get("code_url");
                System.out.println(url);
                json.put("data", url);
                json.put("code", 1);
            }else{
                json.put("code", 0);
                System.out.println(map.get("err_code_des"));
            }
        }else{
            json.put("code", 0);
            System.out.println(map.get("return_msg"));
        }
        return json.toJSONString();    
    }

serviceimpl实现类:

@Override
    public Map<String, String> unifiedorder(ForWXPay record) {
        String key = WXPayConfig.key;
        String currTime = WXPayUtil.getCurrTime();
        String strTime = currTime.substring(8, currTime.length());
        String strRandom = WXPayUtil.buildRandom(4) + "";
        String nonce_str = strTime + strRandom;
        //TbOrderForm orderForm = tbOrderFormMapper.selectByOrderNum(record.getOut_trade_no());
        //String total_fee = orderForm.getOrderAmount().multiply(new BigDecimal("100")).intValue() + "";
        String trade_type = record.getTrade_type();
        String time_start =  new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        Calendar ca = Calendar.getInstance();
        ca.setTime(new Date());
        ca.add(Calendar.MINUTE, 10);         
        String time_expire =  new SimpleDateFormat("yyyyMMddHHmmss").format(ca.getTime());
        SortedMap<Object,Object> packageParams = new TreeMap<Object,Object>();
        packageParams.put("appid", WXPayConfig.appID);
        packageParams.put("mch_id", WXPayConfig.mchID);
        packageParams.put("nonce_str", nonce_str);
        packageParams.put("body", "aa");
        packageParams.put("out_trade_no", record.getOut_trade_no());
        packageParams.put("total_fee", "100");
        packageParams.put("spbill_create_ip", record.getSpbill_create_ip());
        packageParams.put("notify_url",WXPayConfig.NOTIFY_URL );
        packageParams.put("trade_type", trade_type);
        packageParams.put("time_start", time_start);
        packageParams.put("time_expire", time_expire);
        if(!StringUtils.isEmpty(record.getOpenid())){
            packageParams.put("openid", record.getOpenid());
        }
        String sign = WXPayUtil.createSign("UTF-8", packageParams,key);
        packageParams.put("sign", sign);
       
        String requestXML = WXPayUtil.getRequestXml(packageParams);
        System.out.println("请求xml::::"+requestXML);
 
        String resXml = WXPayUtil.postData(WXPayConfig.PAY_API, requestXML);
        System.out.println("返回xml::::"+resXml);
        
        Map<String, String> map = null;
        try {
            map = WXPayUtil.doXMLParse(resXml);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        return map;
    }

他需要的工具包,自己去找,请求与返回的都是xml的,解析之后拿到code_url,返回到前台,其实是一个网址,前台

js这么整:$("#img").attr("src","qrcode?code_url="+result.data);二维码出来了,支付调回调函数,这个我会在支付宝的通知里面一块写

   /**
     * 生成二维码图片 不存储 直接以流的形式输出到页面
     * @param content
     * @param response
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static void encodeQrcode(String content,HttpServletResponse response){
        if(content==null || "".equals(content))
            return;
       MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
       Map hints = new HashMap();
       hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); //设置字符集编码类型
       BitMatrix bitMatrix = null;
       try {
           bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, 300, 300,hints);
           BufferedImage image = toBufferedImage(bitMatrix);
           //输出二维码图片流
           try {
               ImageIO.write(image, "png", response.getOutputStream());
           } catch (IOException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
           }
       } catch (WriterException e1) {
           // TODO Auto-generated catch block
           e1.printStackTrace();
       }         
    }

 

2019-06-06 19:01:03 sanstu 阅读数 3972

一、如何生成小程序分享页面的二维码?

通过后台接口可以获取小程序任意页面的二维码,具体可以参考https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/qr-code.html

通过该接口生成的小程序码,永久有效,数量暂无限制。用户扫描该码进入小程序后,开发者需在对应页面获取的码中 scene 字段的值,再做处理逻辑。使用如下代码可以获取到二维码中的 scene 字段的值。调试阶段可以使用开发工具的条件编译自定义参数 scene=xxxx 进行模拟,开发工具模拟时的 scene 的参数值需要进行 urlencode

另外通过二维码扫进去的page是已经发布的小程序存在的页面

 

二、初始化自适应配置

这里我量了下背景图的宽高比,再根据设备宽高去计算生成图片的宽高,适配所有尺寸,水平居中点的话为了方便之后定位居中的二维码和文案,而文案和二维码的Y轴坐标都是自己量出来的比例。

 

 

注意展示出来的图片是通过image而不是canvas,canvas通过定位移出了可视区域,因为canvas不好控制位置和显示隐藏, canvas和image都要绑定初始化生成的宽高,不然展示的图片大小是会有问题的。

 

 

三、生成小程序二维码

 

再强调一遍,这里生成的二维码扫进去的页面必须是已发布小程序存在的页面!!!

 

四、获取图片展示图片的URL

通过微信api获取展示图片url数组。

 

五、绘制canvas

 

 

setTextAlign这个api可以通过坐标点来对齐文案,这样就方便很多了。

canvasToTempFilePath是把画出来的canvas转化成图片地址,到此通过canvas生成带图片的二维码就完成了,接下来让我们把生成的图片保存下来

 

 

六、保存图片

保存图片比较简单,这里就不多说了。

 

 

 

 

 

 

 

 

 

2018-09-27 11:02:00 weixin_30526593 阅读数 71

昨天有个小需求,在微信文章页面点击顶部固定的一段话弹出二维码,并且在上边加上关闭按钮,做完之后这个样子:

微信页面处理是比较麻烦的,在我的电脑上不管用微信开发者工具调还是浏览器手机模式调整都有点麻烦(可能微信者开发工具上有插件或者适配的编辑器,比较容易编辑,但是我刚开始做所以还没研究这个),而且跟在手机上看都有一定差别。自己就还是用编辑器写一个新的页面,实现功能再复制到项目中,然后再上传服务器看效果。

刚开始写了一个页面只有一个固定在顶部的一行红色,点击出现二维码,背景变暗用的是点击时给body添加rgba(0,0,0,.4),之后到微信上看发现文字部分是有这个颜色的背景,但是图片没变暗。后边到网上查了一下,在二维码弹框外边给了个div,设置属性

{

display: block;
position: absolute;
top: 0%;
left: 0%;
width: 100%;
height: 100%;
background-color: black;
z-index:1001;
-moz-opacity: 0.8;
opacity:.80;
filter: alpha(opacity=88);

}

这样图片也变暗了,但是弹出的二维码也变暗了,所以把背景色写成了rgba,去掉opacity相关设置,还有用absolute会导致文章超出手机屏幕再下拉别的地方还是没变,就改成了fixed。最终代码写的是

#bg{
position: fixed;
top: 0%;
left: 0%;
width: 100%;
height: 100%;
z-index:10;
}

这个z-index,只要大于文章部分,小于顶部固定部分就行。要在固定在顶部的部分上加上X,给点击事件就要用阻止事件冒泡了,event.stopPropagation()。完整代码在下边(当然了,图片要换成自己有的?,自己能力目前有限,只能这样了,可以用手机模式查看能好看点?)

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
    <link rel="stylesheet" href="//res.wx.qq.com/open/libs/weui/1.1.3/weui.min.css">
    <script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
    <style type="text/css">
        /*二维码*/
        #bg{
            position: fixed; 
            top: 0%; 
            left: 0%; 
            width: 100%; 
            height: 100%;
            z-index:10; 
        }
        #top{
            background-color: red;
            position:fixed;
            top:0;
            width: 100%;
            text-align: center;
            color:white;
            height: 40px;
            line-height: 40px;
            z-index: 20;
        }
        #qrcode{
            width: 56%;
            left: 22%;
            top: 20%;
            display: none;
            z-index: 20;
            position:fixed;
            text-align: center;
            padding: 20px;
            box-sizing: border-box;
            background-color: white;
        }
        #qrcode .one{
            font-size: 16px;
        }
        #qrcode .two{
            font-size: 16px;
            color: red;
        }
        #qrcode .three{
            font-size: 12px;
        }
        #qrcode img{
            width: 90%;
        }
        #close{
            position:absolute;
            top:5px;
            right:10px;
            cursor:pointer;
        }
        #closetop{
            position: absolute;
            right:20px;
        }
    </style>
</head>
<body>
    <div id="top">
        <span>马上关注好方妆扮,领取100元新手礼包</span><span id="closetop">×</span>
    </div>
    <div id="bg">
        <div id="qrcode">
            <span id="close">×</span>
            <p class="one">马上关注好方装扮</p>
            <p class="two">领取100元新手礼包</p>
            <img src="images/qr.jpg">
            <p class="three">扫描或长按识别二维码关注</p>
        </div>
    </div>
    <img src="images/1.jpg">
</body>
<script type="text/javascript">
    $('#top').on('click',function(){
        $('#qrcode').show();
        $('#bg').css('background-color','rgba(0,0,0,.5)');
    })
    $('#close').on('click',function(){
        $('#qrcode').hide();
        $('#bg').css('background-color','rgba(0,0,0,0)');
    })
    $('#closetop').on('click',function(event){
        event.stopPropagation();
        $('#top').hide();
    })
</script>
</html>

转载于:https://www.cnblogs.com/demeter/p/9711991.html

2018-10-10 09:30:00 weixin_30265103 阅读数 205

1.首先页面中有两个二维码的兄弟别忙活了,一个页面中只可以识别其中一个二维码,两个的话需提示用户双击放大二维码进行二维码识别.
2.网页内有一张图片进行二维码识别时长按没有反应(长按图片无法弹出识别二维码)这个就是我所遇到的问题。需要调到特别大才能识别,但是特别大就会影响到背景图片,就会有问题,在网上搜了一下结合自己的思路给大家一个解决方案,因需求而异

解决思路
首先要把这张二维码添加到body的子元素 放在最后或者是最前都可以
注意这可能影响你的布局 需要注意的是opacity需要设为0而不是设置display属性

 
<img style="height: 100%;width: 100%;opacity: 0" src="二维码图片地址">
 



其次 在你应该放置的div里设置你正常二维码图片的大小

 

<img class="你的正常大小(bootstrap可设置居中)" src="二维码图片地址" />
 


注意:真实二维码图片的位置会改变,因此需要相应的设置  position:abslute 位置太偏移,有可能会造成二维码无法识别。

 

至此你就会发现长按图片会识别二维码

--------------------- 作者:代码界吴彦祖 来源:CSDN 原文:https://blog.csdn.net/lzx_victory/article/details/51979532?utm_source=copy 版权声明:本文为博主原创文章,转载请附上博文链接!

转载于:https://www.cnblogs.com/php-no-2/p/9764508.html