精华内容
下载资源
问答
  • 本文授权转载自:大古同学,https://juejin.cn/post/6940976355097985032在日常生活中,二维码出现在很多场景,比如超市支付、系统登录、应用下载等等。了解...

    本文授权转载自:大古同学,https://juejin.cn/post/6940976355097985032

    在日常生活中,二维码出现在很多场景,比如超市支付、系统登录、应用下载等等。了解二维码的原理,可以为技术人员在技术选型时提供新的思路。对于非技术人员呢,除了解惑,还可以引导他更好地辨别生活中遇到的各种二维码,防止上当受骗。

    二维码,大家再熟悉不过了

    购物扫个码,吃饭扫个码,坐公交也扫个码

    Reaf23573de7bac41f202d2fb0e0b9934.jpeg
    110_ba82eb278547ec279eaf835fb0f63b3f.png

    在扫码的过程中,大家可能会有疑问:这二维码安全吗?会不会泄漏我的个人信息?更深度的用户还会考虑:我的系统是不是也可以搞一个二维码来推广呢?

    这时候就需要了解一下二维码背后的技术和逻辑了!

    二维码最常用的场景之一就是通过手机端应用扫描PC或者WEB端的二维码,来登录同一个系统。比如手机微信扫码登录PC端微信,手机淘宝扫码登录PC端淘宝。那么就让我们来看一下,二维码登录是怎么操作的!

    二维码登录的本质

    二维码登录本质上也是一种登录认证方式。既然是登录认证,要做的也就两件事情!

    1. 告诉系统我是谁

    2. 向系统证明我是谁

    比如账号密码登录,账号就是告诉系统我是谁, 密码就是向系统证明我是谁; 比如手机验证码登录,手机号就是告诉系统我是谁,验证码就是向系统证明我是谁;

    那么扫码登录是怎么做到这两件事情的呢?我们一起来考虑一下

    手机端应用扫PC端二维码,手机端确认后,账号就在PC端登录成功了!这里,PC端登录的账号肯定与手机端是同一个账号。不可能手机端登录的是账号A,而扫码登录以后,PC端登录的是账号B。

    所以,第一件事情,告诉系统我是谁,是比较清楚的!

    通过扫描二维码,把手机端的账号信息传递到PC端,至于是怎么传的,我们后面再说

    第二件事情,向系统证明我是谁。扫码登录过程中,用户并没有去输入密码,也没有输入验证码,或者其他什么码。那是怎么证明的呢?

    有些同学会想到,是不是扫码过程中,把密码传到了PC端呢?但这是不可能的。因为那样太不安全的,客户端也根本不会去存储密码。我们仔细想一下,其实手机端APP它是已经登录过的,就是说手机端是已经通过登录认证。所说只要「扫码确认是这个手机且是这个账号操作的,其实就能间接证明我谁。」

    认识二维码

    那么如何做确认呢?我们后面会详细说明,在这之前我们需要先认识一下二维码!在认识二维码之前我们先看一下一维码!

    201211061549088595.png

    所谓一维码,也就是条形码,超市里的条形码--这个相信大家都非常熟悉,条形码实际上就是一串数字,它上面存储了商品的序列号。

    二维码其实与条形码类似,只不过它存储的不一定是数字,还可以是任何的字符串,你可以认为,它就是字符串的另外一种表现形式,

    在搜索引擎中搜索二维码,你可以找到很多在线生成二维码的工具网站,这些网站可以提供字符串与二维码之间相互转换的功能,比如 草料二维码网站[2]

    20210318103206.jpg

    在左边的输入框就可以输入你的内容,它可以是文本、网址,文件........。然后就可以生成代表它们的二维码

    你也可以把二维码上传,进行”解码“,然后就可以解析出二维码代表的含义

    系统认证机制

    认识了二维码,我们了解一下移动互联网下的系统认证机制。

    前面我们说过,为了安全,手机端它是不会存储你的登录密码的。但是在日常使用过程中,我们应该会注意到,只有在你的应用下载下来后,第一次登录的时候,才需要进行一个账号密码的登录, 那之后呢 即使这个应用进程被杀掉,或者手机重启,都是不需要再次输入账号密码的,它可以自动登录。

    其实这背后就是一套基于token的认证机制,我们来看一下这套机制是怎么运行的,

    阿萨德阿萨德.jpg
    1. 账号密码登录时,客户端会将设备信息一起传递给服务端,

    2. 如果账号密码校验通过,服务端会把账号与设备进行一个绑定,存在一个数据结构中,这个数据结构中包含了账号ID,设备ID,设备类型等等

    const token = {
      acountid:'账号ID',
      deviceid:'登录的设备ID',
      deviceType:'设备类型,如 iso,android,pc......',
    }
    复制代码
    

    然后服务端会生成一个token,用它来映射数据结构,这个token其实就是一串有着特殊意义的字符串,它的意义就在于,通过它可以找到对应的账号与设备信息,

    1. 客户端得到这个token后,需要进行一个本地保存,每次访问系统API都携带上token与设备信息。

    2. 服务端就可以通过token找到与它绑定的账号与设备信息,然后把绑定的设备信息与客户端每次传来的设备信息进行比较, 如果相同,那么校验通过,返回AP接口响应数据, 如果不同,那就是校验不通过拒绝访问

    从前面这个流程,我们可以看到,客户端不会也没必要保存你的密码,相反,它是保存了token。可能有些同学会想,这个token这么重要,万一被别人知道了怎么办。实际上,知道了也没有影响, 因为设备信息是唯一的,只要你的设备信息别人不知道, 别人拿其他设备来访问,验证也是不通过的。

    可以说,客户端登录的目的,就是获得属于自己的token。

    那么在扫码登录过程中,PC端是怎么获得属于自己的token呢?不可能手机端直接把自己的token给PC端用!token只能属于某个客户端私有,其他人或者是其他客户端是用不了的。在分析这个问题之前,我们有必要先梳理一下,扫描二维码登录的一般步骤是什么样的。这可以帮助我们梳理清楚整个过程,

    扫描二维码登录的一般步骤

    大概流程

    啊啊啊.jpg
    1. 扫码前,手机端应用是已登录状态,PC端显示一个二维码,等待扫描

    2. 手机端打开应用,扫描PC端的二维码,扫描后,会提示"已扫描,请在手机端点击确认"

    3. 用户在手机端点击确认,确认后PC端登录就成功了

    可以看到,二维码在中间有三个状态, 待扫描,已扫描待确认,已确认。那么可以想象

    666.jpg
    1. 二维码的背后它一定存在一个唯一性的ID,当二维码生成时,这个ID也一起生成,并且绑定了PC端的设备信息

    2. 手机去扫描这个二维码

    3. 二维码切换为 已扫描待确认状态, 此时就会将账号信息与这个ID绑定

    4. 当手机端确认登录时,它就会生成PC端用于登录的token,并返回给PC端

    好了,到这里,基本思路就已经清晰了,接下来我们把整个过程再具体化一下

    二维码准备

    按二维码不同状态来看, 首先是等待扫描状态,用户打开PC端,切换到二维码登录界面时。

    1111.jpg
    1. PC端向服务端发起请求,告诉服务端,我要生成用户登录的二维码,并且把PC端设备信息也传递给服务端

    2. 服务端收到请求后,它生成二维码ID,并将二维码ID与PC端设备信息进行绑定

    3. 然后把二维码ID返回给PC端

    4. PC端收到二维码ID后,生成二维码(二维码中肯定包含了ID)

    5. 为了及时知道二维码的状态,客户端在展现二维码后,PC端不断的轮询服务端,比如每隔一秒就轮询一次,请求服务端告诉当前二维码的状态及相关信息

    二维码已经准好了,接下来就是扫描状态

    扫描状态切换

    7777.jpg
    1. 用户用手机去扫描PC端的二维码,通过二维码内容取到其中的二维码ID

    2. 再调用服务端API将移动端的身份信息与二维码ID一起发送给服务端

    3. 服务端接收到后,它可以将身份信息与二维码ID进行绑定,生成临时token。然后返回给手机端

    4. 因为PC端一直在轮询二维码状态,所以这时候二维码状态发生了改变,它就可以在界面上把二维码状态更新为已扫描

    那么为什么需要返回给手机端一个临时token呢?临时token与token一样,它也是一种身份凭证,不同的地方在于它只能用一次,用过就失效。

    在第三步骤中返回临时token,为的就是手机端在下一步操作时,可以用它作为凭证。以此确保扫码,登录两步操作是同一部手机端发出的,

    状态确认

    最后就是状态的确认了。

    3333333332.jpg
    1. 手机端在接收到临时token后会弹出确认登录界面,用户点击确认时,手机端携带临时token用来调用服务端的接口,告诉服务端,我已经确认

    2. 服务端收到确认后,根据二维码ID绑定的设备信息与账号信息,生成用户PC端登录的token

    3. 这时候PC端的轮询接口,它就可以得知二维码的状态已经变成了"已确认"。并且从服务端可以获取到用户登录的token

    4. 到这里,登录就成功了,后端PC端就可以用token去访问服务端的资源了

    扫码动作的基础流程都讲完了,有些细节还没有深入介绍,

    比如二维码的内容是什么?

    • 可以是二维码ID

    • 可以是包含二维码ID的一个url地址

    在扫码确认这一步,用户取消了怎么处理?这些细节都留给大家思考

    总结

    6767676.jpg

    我们从登陆的本质触发,探索二维码扫码登录是如何做到的

    1. 告诉系统我是谁

    2. 向系统证明我谁

    在这个过程中,我们先简单讲了两个前提知识,

    • 一个是二维码原理,

    • 一个是基于token的认证机制。

    然后我们以二维码状态为轴,分析了这背后的逻辑: 通过token认证机制与二维码状态变化来实现扫码登录.

    需要指出的是,前面的讲的登录流程,它适用于同一个系统的PC端,WEB端,移动端。

    平时我们还有另外一种场景也比较常见,那就是通过第三方应用来扫码登录,比如极客时间/掘金  都可以选择微信/QQ等扫码登录,那么这种通过第三方应用扫码登录又是什么原理呢?

    感兴趣的同学可以思考研究一下,欢迎在评论区留下你的见解。

    Reference

    [1]

    极客时间一个二维码的视频:https://time.geekbang.org/dailylesson/detail/100044032?utm_source=u_nav_web&utm_medium=u_nav_web&utm_term=u_nav_web

    [2]

    草料二维码网站:https://cli.im/

    点个『在看』支持下 

    展开全文
  • 目前小程序推出了自己的识别,小程序,这个圆形的看起来比二维码好看。本文总结微信小程序的获取小程序二维码并生成二维码图片的接口开发。主要内容摘抄自微信小程序的API文档,java接口开发是自己总结...

    目前小程序推出了自己的识别码,小程序码,这个圆形的码看起来比二维码好看。本文总结微信小程序的获取小程序码和二维码并生成二维码图片的接口开发。主要内容摘抄自微信小程序的API文档,java接口开发是自己总结开发。

    微信小程序API文档获取二维码

    一、简介

    通过后台接口可以获取小程序任意页面的二维码,扫描该二维码可以直接进入小程序对应的页面。目前微信支持两种二维码,小程序码(左),小程序二维码(右),如下所示:
    这里写图片描述
    二、获取小程序码

    目前有两个接口可以生成小程序码,开发者可以根据自己的需要选择合适的接口。
    1 不带参数有限个数小程序码接口

    适用于需要的码数量较少的业务场景

    接口地址:

    https://api.weixin.qq.com/wxa/getwxacode?access_token=ACCESS_TOKEN

       

    注:获取accesstoken的方法跟微信公众获取accesstoken方法一致,不过小程序获取accesstoken需要小程序的appid和appsercet。登录 https://mp.weixin.qq.com ,就可以在网站的“设置”-“开发者设置”中,查看到微信小程序的 AppID 了,注意不可直接使用服务号或订阅号的 AppID 。
    这里写图片描述
    获取微信小程序的 AppID文章地址:小程序简易教程
    (1)POST 参数说明
    参数     类型     默认值     说明
    path     String         不能为空,最大长度 128 字节
    width     Int     430     二维码的宽度
    auto_color     Bool     false     自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调
    line_color     Object     {“r”:”0”,”g”:”0”,”b”:”0”}     auth_color 为 false 时生效,使用 rgb 设置颜色 例如 {“r”:”xxx”,”g”:”xxx”,”b”:”xxx”}

    注意:通过该接口生成的小程序码,永久有效,但数量有效,请谨慎使用。用户扫描该码进入小程序后,将直接进入 path 对应的页面。
    (2)请求接口测试

    使用http请求插件postman或者RESTClient请求测试。
    这里写图片描述
    请求测试结果返回一个小程序码图片,与微信公众平台生成二维码不同,小程序码直接返回文件流,不是微信公众平台的url和ticket。
    (3)java接口开发

    注:此接口是基于Spring RestTemplate进行http请求,进行http请求有很多方法和工具类,可自行百度或参考下面的参考文章。接口只是提供一个解决方法的思路。

        public Map getminiqrQr(String accessToken) {
            RestTemplate rest = new RestTemplate();
            InputStream inputStream = null;
            OutputStream outputStream = null;
            try {
                String url = "https://api.weixin.qq.com/wxa/getwxacode?access_token="+accessToken;
                Map<String,Object> param = new HashMap<>();
                param.put("page", "pages/index/index");
                param.put("width", 430);
                param.put("auto_color", false);
                Map<String,Object> line_color = new HashMap<>();
                line_color.put("r", 0);
                line_color.put("g", 0);
                line_color.put("b", 0);
                param.put("line_color", line_color);
                LOG.info("调用生成微信URL接口传参:" + param);
                MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
                HttpEntity requestEntity = new HttpEntity(param, headers);
                ResponseEntity<byte[]> entity = rest.exchange(url, HttpMethod.POST, requestEntity, byte[].class, new Object[0]);
                LOG.info("调用小程序生成微信永久小程序码URL接口返回结果:" + entity.getBody());
                byte[] result = entity.getBody();
                LOG.info(Base64.encodeBase64String(result));
                inputStream = new ByteArrayInputStream(result);

                File file = new File("C:/Users/wangqiulin/Desktop/1.png");
                if (!file.exists()){
                    file.createNewFile();
                }
                outputStream = new FileOutputStream(file);
                int len = 0;
                byte[] buf = new byte[1024];
                while ((len = inputStream.read(buf, 0, 1024)) != -1) {
                    outputStream.write(buf, 0, len);
                }
                outputStream.flush();
            } catch (Exception e) {
                LOG.error("调用小程序生成微信永久小程序码URL接口异常",e);
            } finally {
                if(inputStream != null){
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(outputStream != null){
                    try {
                        outputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return null;    
        }

       

    说明:accessToken的获取方法就不多说,因为小程序二维码很坑爹的返回文件流,导致我们必须对流进行处理转换成图片保存到本地,这样还有一个严重的后果就是无法将二维码保存到数据库中,每次想获取二维码必须请求接口,此接口最多生成不超过100000个,请大家谨慎使用。
    2 带参数无限个数小程序码接口

    适用于需要的码数量极多,或仅临时使用的业务场景

    接口地址:

    https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=ACCESS_TOKEN

       

    获取accessToken的方法跟接口1一致。
    (1)POST 参数说明
    参数     类型     默认值     说明
    scene     String         最大32个可见字符,只支持数字,大小写英文以及部分特殊字符:!#$&’()*+,/:;=?@-._~,其它字符请自行编码为合法字符(因不支持%,中文无法使用 urlencode 处理,请使用其他编码方式)
    page     String         必须是已经发布的小程序页面,例如 “pages/index/index” ,如果不填写这个字段,默认跳主页面
    width     Int     430     二维码的宽度
    auto_color     Bool     false     自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调
    line_color     Object     {“r”:”0”,”g”:”0”,”b”:”0”}     auto_color 为 false 时生效,使用 rgb 设置颜色 例如 {“r”:”xxx”,”g”:”xxx”,”b”:”xxx”}


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

    // 这是首页的 js
    Page({
      onLoad: function(options) {
        // options 中的 scene 需要使用 decodeURIComponent 才能获取到生成二维码时传入的 scene
        var scene = decodeURIComponent(options.scene)
      }
    })

     

    (2)请求接口测试

    这里写图片描述
    (3)java接口开发

        public Map getminiqrQr(String sceneStr, String accessToken) {
            RestTemplate rest = new RestTemplate();
            InputStream inputStream = null;
            OutputStream outputStream = null;
            try {
                String url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token="+accessToken;
                Map<String,Object> param = new HashMap<>();
                param.put("scene", sceneStr);
                param.put("page", "pages/index/index");
                param.put("width", 430);
                param.put("auto_color", false);
                Map<String,Object> line_color = new HashMap<>();
                line_color.put("r", 0);
                line_color.put("g", 0);
                line_color.put("b", 0);
                param.put("line_color", line_color);
                LOG.info("调用生成微信URL接口传参:" + param);
                MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
                HttpEntity requestEntity = new HttpEntity(param, headers);
                ResponseEntity<byte[]> entity = rest.exchange(url, HttpMethod.POST, requestEntity, byte[].class, new Object[0]);
                LOG.info("调用小程序生成微信永久小程序码URL接口返回结果:" + entity.getBody());
                byte[] result = entity.getBody();
                LOG.info(Base64.encodeBase64String(result));
                inputStream = new ByteArrayInputStream(result);

                File file = new File("C:/Users/wangqiulin/Desktop/1.png");
                if (!file.exists()){
                    file.createNewFile();
                }
                outputStream = new FileOutputStream(file);
                int len = 0;
                byte[] buf = new byte[1024];
                while ((len = inputStream.read(buf, 0, 1024)) != -1) {
                    outputStream.write(buf, 0, len);
                }
                outputStream.flush();
            } catch (Exception e) {
                LOG.error("调用小程序生成微信永久小程序码URL接口异常",e);
            } finally {
                if(inputStream != null){
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(outputStream != null){
                    try {
                        outputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return null;    
        }

     

    3 获取小程序二维码

    适用于需要的码数量较少的业务场景

    接口地址:

    https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=ACCESS_TOKEN

       

    (1)POST 参数说明
    参数     类型     默认值     说明
    path     String         不能为空,最大长度 128 字节
    width     Int     430     二维码的宽度


    注意:通过该接口生成的小程序二维码,永久有效,数量限制见文末说明,请谨慎使用。用户扫描该码进入小程序后,将直接进入 path 对应的页面。

    示例:

    {"path": "pages/index?query=1", "width": 430}

       

    注:pages/index 需要在 app.json 的 pages 中定义
    (2)请求接口测试

    这里写图片描述
    (3)java接口开发

        public Map getminiqrQr(String accessToken) {
            RestTemplate rest = new RestTemplate();
            InputStream inputStream = null;
            OutputStream outputStream = null;
            try {
                String url = "https://api.weixin.qq.com/wxaapp/createwxaqrcode?access_token="+accessToken;
                Map<String,Object> param = new HashMap<>();
                param.put("page", "pages/index/index");
                param.put("width", 430);
                LOG.info("调用生成微信URL接口传参:" + param);
                MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
                HttpEntity requestEntity = new HttpEntity(param, headers);
                ResponseEntity<byte[]> entity = rest.exchange(url, HttpMethod.POST, requestEntity, byte[].class, new Object[0]);
                LOG.info("调用小程序生成微信永久二维码URL接口返回结果:" + entity.getBody());
                byte[] result = entity.getBody();
                LOG.info(Base64.encodeBase64String(result));
                inputStream = new ByteArrayInputStream(result);

                File file = new File("C:/Users/wangqiulin/Desktop/1.png");
                if (!file.exists()){
                    file.createNewFile();
                }
                outputStream = new FileOutputStream(file);
                int len = 0;
                byte[] buf = new byte[1024];
                while ((len = inputStream.read(buf, 0, 1024)) != -1) {
                    outputStream.write(buf, 0, len);
                }
                outputStream.flush();
            } catch (Exception e) {
                LOG.error("调用小程序生成微信永久二维码URL接口异常",e);
            } finally {
                if(inputStream != null){
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if(outputStream != null){
                    try {
                        outputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return null;    
        }

     

    三、说明

    1:通过该接口,仅能生成已发布的小程序的二维码。
    2:可以在开发者工具预览时生成开发版的带参二维码。
    3:接口1加上接口2,总共生成的码数量限制为100,000,请谨慎调用。
    4 : POST 参数需要转成 json 字符串,不支持 form 表单提交。
    5 : auto_color line_color 参数仅对小程序码生效。
     

    展开全文
  • 最近在做一个扫码登录功能,为此我还在网上搜了一下关于微信的扫描登录的实现方式。当这个功能完成之后,我决定将整个实现思路整理出来,方便自己以后...换句话讲,如何让服务器知道扫码二维码的客户端是一个合法...

    最近在做一个扫码登录功能,为此我还在网上搜了一下关于微信的扫描登录的实现方式。当这个功能完成之后,我决定将整个实现思路整理出来,方便自己以后查看也方便其他有类似需求的程序员们。

    1. 在没有输入用户名及密码的情况下,如何解决权限安全问题?换句话讲,如何让服务器知道扫码二维码的客户端是一个合法的用户?

    2. 服务器根据用户在客户端的选择如何实时在网页上作出相应的响应?

    首先我们先理一下微信的实现思路,来方便我们理解解决这一难题的思路方向。微信登录的二维码实际上是将一个URL转换成二维码的形式,而通过微信客户端扫码后,无非就是打开了这个url, 我捕捉到的微信二维码的urlhttps://login.weixin.qq.com/l/YdmTu30I5A== ,这个url里的YdmTu30I5A==代表的是本次会话的唯一ID, 这个有点儿类似浏览器里的session id,通过这个ID,微信就能定向将确认结果反馈到网页上。使用微信二维码登录功能,需要有两个前提:一是客户端上需要安装微信app 二是用户需要登录到到微信apphttps://wx.qq.com/

     

     Python Web实时消息后台服务器推送技术

     

    为什么要有这两个条件呢?那是因为微信在确认是否允许登录到网页版的时候,微信需要提取当前app的登录信息并将上面的session ID一并发给服务器,这样服务器收到了登录信息和sessionID后就可以确认两件事:一是用来确认登录的客户端的用户是验证过的;二是通过session ID服务器知道将反馈结果推送到哪个网页。

       所以针对第一点,我们的关键在于,在扫描前要确保用户是已经被验证过且合法的用户(验证方式可以是用户名+密码,也可以是一个secure key),在选择是否登录时将这个结果一并推送到服务器端,就好了。如果用户没有验证是否合法,可以像微信的处理方式一样直接告诉用户二维码不可识别或提示请先登录到app

      有了身份验证,那么现在就解决第二个问题,如何将反馈结果实时地显示在网页上呢?有朋友可能会说,客户端这边很简单发一个请求到后台就好了,而网页上用ajax定时发送到服务器端看是否有反馈。我不赞成这种做法,因为ajax轮询方式十分消耗客户端和服务器端资源!这里涉及到另一个技术-web实时推送技术,使用推送技术可以节约服务器端和客户端的资源,可以稳定地推送和接收任何消息。我在实现的过程中我采用了第三方推送服务-GoEasy推送,用它是实现非常简单,我们项目里的其他功能也用到了GoEasy web实时推送服务,所以在此我直接就用的GoEasy推送来将登录反馈结果推送到服务器。我的实现步骤非常简单,将传送的session ID作为客户端与网页端的通信channel,网页端订阅用session ID作为值得channel,客户端将验证结果和session ID发送到服务器端,服务器端可以通过这个channel主动将结果推送给网页版!如果客户端也需要做相应的反馈的话,那么客户端也只需要订阅这个channel,然后服务器端会同时将结果推送给网页版和客户端,收到消息后,就可以根据需求在goeasy的回调函数里做你想做的事情了。关于goeasy推送的使用,大家可以参考这篇博客: http://www.cnblogs.com/jishaochengduo/articles/5552645.html 另外GoEasy推送官网上也有一个demoGoEasy二维码扫码登录demo,大家可以去看看效果.

      希望对大家有帮助,如有理解错误的地方,还请大家斧正。

    转载于:https://my.oschina.net/miaomiaogong/blog/777314

    展开全文
  • python 全栈开发,Day128(创建二维码,扫码,创建玩具的基本属性) 昨日内容回顾 1.app播放音乐 plus.audio.createPlayer(文件路径/URL) player.play() 播放音乐 player.pause() 暂停播放 ...

    python 全栈开发,Day128(创建二维码,扫码,创建玩具的基本属性)

    昨日内容回顾

    1.app播放音乐
        plus.audio.createPlayer(文件路径/URL)
        player.play()     播放音乐
        player.pause()    暂停播放
        player.resume()    继续播放
        player.stop()    停止播放,清空player对象 # 当停止之后,无法在使用play() resume()继续播放
    
    
    2.app遥控玩具播放内容
        Websocket通讯 实现手机遥控app
        app:{content_id:123,to_user:123456}    {music_name:"123.wav",to_user:123456}
        服务器端:拿到to_user的websocket 如果使用content_id做查询     music_name:直接返回
        玩具端:返回给玩具端{code:0,from_user:654321,data:music_name}
        
    
    3.玩具控制管理页面
    View Code

     

    下载代码:

    https://github.com/987334176/Intelligent_toy/archive/v1.1.zip

    注意:由于涉及到版权问题,此附件没有图片和音乐。请参考链接,手动采集一下!

    请参考链接:

    https://www.cnblogs.com/xiao987334176/p/9647993.html#autoid-3-4-0

    一、创建二维码

    为什么要创建二维码呢?主要是做防伪的!

    一个玩具,很容易就会被其他厂商复制处理。那么如何区分,一个玩具就是我生产的呢?

    出厂时,将设备id写入数据库。同时将设备id生成二维码,贴在玩具背后!那么用户扫码,就可以判断玩具的真伪了!

     

    打开联图的二维码官网:

    http://www.liantu.com/

     

    打开MongoDB,复制一条id,粘贴到官网。它会即时生成!

     

    它还有一个API接口,也可以生成二维码。

    比如将123,生成二维码

    http://qr.liantu.com/api.php?text=123

    浏览器直接访问上面这个地址,效果如下:

     

    接下来,就使用这个API生成二维码!

    进入flask后端,修改settings.py,增加二维码API以及保存目录

    import pymongo
    
    client = pymongo.MongoClient(host="127.0.0.1", port=27017)
    MONGO_DB = client["bananabase"]
    
    RET = {
        # 0: false 2: True
        "code": 0,
        "msg": "",  # 提示信息
        "data": {}
    }
    
    XMLY_URL = "http://m.ximalaya.com/tracks/"  # 喜马拉雅链接
    CREATE_QR_URL = "http://qr.liantu.com/api.php?text="  # 生成二维码API
    
    # 文件目录
    import os
    
    AUDIO_FILE = os.path.join(os.path.dirname(__file__), "audio")  # 音频
    AUDIO_IMG_FILE = os.path.join(os.path.dirname(__file__), "audio_img")  # 音频图片
    
    DEVICE_CODE_PATH = os.path.join(os.path.dirname(__file__), "device_code")  # 二维码
    View Code

    新建目录device_code

     

    新建一个文件QRcode.py,用来生成二维码图片

    from uuid import uuid4
    import hashlib, time,os
    import requests
    import setting
    
    
    # 生成唯一设备id,f-string是Python 3.6语法
    device_id = f"{uuid4()}{time.time()}"
    device_id_md5 = hashlib.md5(device_id.encode("utf8"))  # 生成md5对象
    
    qr_code = device_id_md5.hexdigest()  # 获取md5的值
    qr_url = f"{setting.CREATE_QR_URL}{qr_code}"  # 生成二维码访问链接
    res = requests.get(qr_url)  # 使用GET请求
    # 拼接二维码图片保存路径
    code_file = os.path.join(setting.DEVICE_CODE_PATH,f"{qr_code}.jpg")
    
    with open(code_file, "wb") as f:
        f.write(res.content)  # 写入文件
    View Code

    此时目录结构如下:

    ./
    ├── audio
    ├── audio_img
    ├── device_code
    ├── im_serv.py
    ├── manager.py
    ├── QRcode.py
    ├── serv
    │   ├── content.py
    │   └── get_file.py
    ├── setting.py
    ├── static
    │   └── recorder.js
    ├── templates
    │   └── index.html
    └── xiaopapa.py
    View Code

     

    执行QRcode.py,此时device_code目录会生成一个图片

     

    接下来,将这部分代码封装成函数。并写入MongoDB中

    修改 QRcode.py 

    from uuid import uuid4
    import hashlib, time,os
    import requests
    import setting
    
    def create_device_id(count=1):
        device_list = []
        for i in range(count):
    
            # 生成唯一设备id,f-string是Python 3.6语法
            device_id = f"{uuid4()}{time.time()}"
            device_id_md5 = hashlib.md5(device_id.encode("utf8"))  # 生成md5对象
    
            qr_code = device_id_md5.hexdigest()  # 获取md5的值
            qr_url = f"{setting.CREATE_QR_URL}{qr_code}"  # 生成二维码访问链接
            res = requests.get(qr_url)  # 使用GET请求
            # 拼接二维码图片保存路径
            code_file = os.path.join(setting.DEVICE_CODE_PATH,f"{qr_code}.jpg")
    
            with open(code_file, "wb") as f:
                f.write(res.content)  # 写入文件
    
            device_list.append({"device_id": qr_code})  # 追加到列表中
    
            time.sleep(0.2)  # 睡眠0.2秒,防止被封锁IP
    
        setting.MONGO_DB.devices.insert_many(device_list)  # 写入多条记录
    
    
    create_device_id(5)  # 生成5条记录
    View Code

     

    清空device_code目录,并执行QRcode.py。等待10秒左右,就会有5个图片了

     

    二、扫码

    barcode

    Barcode模块管理条码扫描,支持常见的条码(一维码及二维码)的扫描识别功能。可调用设备的摄像头对条码图片扫描进行数据输入,解码后返回码数据及码类型。通过plus.barcode可获取条码码管理对象。

    参考链接:

    http://www.html5plus.org/doc/zh_cn/barcode.html

     

    create

    创建Barcode对象

    Barcode plus.barcode.create(id, filters, styles);

    说明:

    调用此方法创建后并不会显示,需要调用Webview窗口的append方法将其添加到Webview窗口后才能显示。 注意:此时需要通过styles参数的top/left/width/height属性设置控件的位置及大小。

    参数:

      • id: String ) 必选 Barcode对象的全局标识
        可用于通过plus.barcode.getBarcodeById()方法查找已经创建的Barcode对象。
      • filters: ArrayNumber ] ) 可选 要识别的条码类型过滤器,为条码类型常量数组
        条码识别引擎可支持多种二维码及一维码类型,默认情况支持QR、EAN13、EAN8三种类型。 可通过此参数设置需要支持的更多条码类型(注意:设置支持的条码类型越多,扫码识别效率将会降低)。
      • styles: BarcodeStyles ) 可选 Barcode扫码控件的样式
        可定义Barcode扫码控件的样式,如扫码框、扫码条的颜色等。

     

    返回值:

    Barcode : Barcode扫码控件对象

    示例:

    <!DOCTYPE html>
    <html>
        <head>
        <meta charset="utf-8">
        <title>Barcode Example</title>
        <script type="text/javascript" >
    var barcode = null;
    // 扫码成功回调
    function onmarked(type, result) {
        var text = '未知: ';
        switch(type){
            case plus.barcode.QR:
            text = 'QR: ';
            break;
            case plus.barcode.EAN13:
            text = 'EAN13: ';
            break;
            case plus.barcode.EAN8:
            text = 'EAN8: ';
            break;
        }
        alert( text+result );
    }
    // 创建Barcode扫码控件
    function createBarcode() {
        if(!barcode){
            barcode = plus.barcode.create('barcode', [plus.barcode.QR], {
                top:'100px',
                left:'0px',
                width: '100%',
                height: '200px',
                position: 'static'
            });
            barcode.onmarked = onmarked;
            plus.webview.currentWebview().append(barcode);
        }
        barcode.start();
    }
        </script>
        <style type="text/css">
    *{
        -webkit-user-select: none;
    }
    html,body{
        margin: 0px;
        padding: 0px;
        height: 100%;
    }
        </style>
        </head>
        <body >
            <button οnclick="createBarcode()">创建扫码控件</button>
        </body>
    </html>
    View Code

     

    Barcode

    Barcode扫码控件对象

    interface plus.barcode.Barcode {
        // Methods
        function void start(options);
        function void cancel();
        function void close();
        function void setFlash(open);
    
        // Events
        function void onmarked();
        function void onerror();
    }

    说明:

    Barcode对象表示条码识别控件对象,在窗口中显示条码识别控件,使用此对象可自定义条码识别界面。

    构造:

    方法:

    • start: 开始条码识别
    • cancel: 结束条码识别
    • close: 关闭条码识别控件
    • setFlash: 是否开启闪光灯
    • setStyles: 设置Barcode扫码控件的配置参数

    事件:

    示例:

    <!DOCTYPE html>
    <html>
        <head>
        <meta charset="utf-8">
        <title>Barcode Example</title>
        <script type="text/javascript" >
    // 扩展API加载完毕后调用onPlusReady回调函数 
    document.addEventListener( "plusready", onPlusReady, false );
    // 扩展API加载完毕,现在可以正常调用扩展API
    function onPlusReady() {
        var e = document.getElementById("scan");
        e.removeAttribute( "disabled" );
    }
    var scan = null;
    function onmarked( type, result ) {
        var text = '未知: ';
        switch(type){
            case plus.barcode.QR:
            text = 'QR: ';
            break;
            case plus.barcode.EAN13:
            text = 'EAN13: ';
            break;
            case plus.barcode.EAN8:
            text = 'EAN8: ';
            break;
        }
        alert( text+result );
    }
    function startRecognize() {
        scan = new plus.barcode.Barcode('bcid');
        scan.onmarked = onmarked; 
    }
    function startScan() {
        scan.start();
    }
    function cancelScan() {
        scan.cancel();
    }
    function setFlash() {
        scan.setFlash();
    }
        </script>
        <style type="text/css">
    *{
        -webkit-user-select: none;
    }
    html,body{
        margin: 0px;
        padding: 0px;
        height: 100%;
    }
    #bcid {
        background:#0F0;
        height:480px;
        width:360px;
    }
        </style>
        </head>
        <body >
            <input type='button' οnclick='startRecognize()' value='创建扫码控件' />
            <input type='button' οnclick='startScan()' value='开始扫码' />
            <input type='button' οnclick='cancelScan()' value='取消扫码' />
            <input type='button' οnclick='setFlash()' value='开启闪光灯' />
            <div id= "bcid"></div>
            <input type='text' id='text'/>
        </body>
    </html>
    View Code

     

    参考链接:

    http://www.html5plus.org/doc/zh_cn/barcode.html#plus.barcode.create

     

    打开HBuilder项目MyApp,新建一个文件qrcode.html

     

    修改 toy_manager.html,将 扫描二维码.html 改成 qrcode.html

    <!doctype html>
    <html lang="en">
    
        <head>
            <meta charset="UTF-8" />
            <title>Document</title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link rel="stylesheet" type="text/css" href="css/mui.css" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
                <h1 class="mui-title">管理我的玩具</h1>
            </header>
            <div class="mui-content">
                <ul class="mui-table-view" id="toy_list">
                    <li class="mui-table-view-cell mui-media">
                        <a id="add_toy">
                            <img class="mui-media-object mui-pull-left" src="images/add.png">
                            <div class="mui-media-body">
                                你还没有玩具
                                <p class="mui-ellipsis">点击此处扫描二维码添加玩具</p>
                            </div>
                        </a>
                    </li>
                </ul>
            </div>
        </body>
        <script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            mui.init()
    
            document.getElementById("add_toy").addEventListener("tap", function() {
                mui.openWindow({
                    url: "qrcode.html",
                    id: "qrcode.html",
                })
            })
        </script>
    
    </html>
    View Code

     

    修改 qrcode.html,创建Barcode对象并开启扫码

    <!doctype html>
    <html lang="en">
    
        <head>
            <meta charset="UTF-8" />
            <title>Document</title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link rel="stylesheet" type="text/css" href="css/mui.css" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
                <h1 class="mui-title">扫描玩具二维码</h1>
            </header>
            <div class="mui-content">
                <div style="height: 550px;" id="qr"></div>
            </div>
    
        </body>
        <script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            mui.init()
    
            mui.plusReady(function() {
                // 创建Barcode对象
                var barcode = new plus.barcode.Barcode('qr');
                barcode.start();  // 开始条码识别
            })
        </script>
    
    </html>
    View Code

     

    连接真机

    由于模拟器调用摄像头,这里必须要用真实的手机连接才行!

    那么如何连接呢?使用360手机助手!

    360手机助手

    我的手机是华为P9,其实华为手机助手,也可以将手机屏幕映射到电脑上面!但是,由于演示时,是全屏的!

    无法缩小,不好做演示!所以我才选择了360手机助手!

     

    360手机助手下载地址:

    http://sj.360.cn/index.html

    注意:需要电脑和手机同时安装!使用电脑连接手机时,务必使用USB模式!因为演示模式时,只能使用USB!

     

    默认华为P9,在设置里面开启USB之后,过一会就关闭了!怎么解决呢?进入工程菜单,开启USB才行!

    详情,请参考链接:

    https://club.huawei.com/thread-10239881-1-1.html

    注意:先选择Google模式,再开启USB调试! 

     

    连接成功后,点击底部的小三角

     右侧,会显示手机画面,比如:

     

    打开HBuilder,连接自己的手机

    运行之后,它会在你的手机上面,自动安装HBuilder的APP。并自动打开HBuilder,效果如下:

    这里 没有加载图文列表,是因为 mui.js的IP不对。

    修改mui.js,改为本机IP地址

    window.ws_serv = "192.168.0.108:9528";
    window.serv = "http://192.168.0.108:9527";

    注意:请确保手机网络,能访问http://192.168.0.108:9528

    有2个解决办法:

    1. 电脑和手机连接同一wifi

    2. 电脑开启wifi。wind10自带就有!用手机连接这个wifi即可!

    请确保电脑的防火墙是关闭状态打开控制面板-->系统和安全-->Windows Defender 防火墙。关闭防火墙!

     

    关闭手机进程,再次访问,就可以了

     

    重新登录一次,点击 管理我的玩具,效果如下:

    点击添加按钮

    它会跳转到 扫描二维码页面。看到中间的会动的红色线条没?说明它在识别中!

     

    BarcodeSuccessCallback

    扫码识别成功回调函数

    说明:

    当Barcode控件扫码成功时的回调函数,返回识别成功的扫码数据。

    参数:

    • type: Number ) 必选 识别到的条码类型
      Number类型的值,与Barcode对象定义的条码类型常量一致。
    • code: String ) 必选 识别到的条码数据
      扫码识别出的数据内容,字符串类型,采用UTF8编码格式。
    • file: String ) 可选 扫码成功的截图文件路径
      扫码识别到的截图,png格式文件,如果设置为不保存截图,则返回undefined。

    返回值:

    void : 无

     

    参考链接:

    http://www.html5plus.org/doc/zh_cn/barcode.html#plus.barcode.BarcodeSuccessCallback

     

    修改qrcdoe.html,增加回调函数

    <!doctype html>
    <html lang="en">
    
        <head>
            <meta charset="UTF-8" />
            <title>Document</title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link rel="stylesheet" type="text/css" href="css/mui.css" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
                <h1 class="mui-title">扫描玩具二维码</h1>
            </header>
            <div class="mui-content">
                <div style="height: 550px;" id="qr"></div>
            </div>
    
        </body>
        <script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            mui.init()
            
            function chenggong(type, code) {  //扫码成功回调函数
                mui.toast(code);  // 显示二维码的内容
            }
            
            mui.plusReady(function() {
                // 创建Barcode对象
                var barcode = new plus.barcode.Barcode('qr');
                barcode.start();  // 开始条码识别
                barcode.onmarked = chenggong;  // 扫码成功后,执行函数chenggong
            })
        </script>
    
    </html>
    View Code

     

    进入flask项目,打开device_code目录。打开一张图片,使用真机,扫描一下二维码,效果如下:

     

     

    二维码3种情况

    用户扫描的二维码,有3种情况

    1.当前设备根本不是我们授权生产的玩具 无效二维码 code=2
    2.二维码有效,创建玩具,绑定用户 code=0
    3.二维码有效,且已绑定用户,加好友 code=1

     

    这3种情况,需要后端来校验!

    进入flask项目,在serv目录下,新建一个文件devices.py

    from flask import Blueprint, request, jsonify
    from setting import MONGO_DB
    from setting import RET
    from bson import ObjectId
    
    devs = Blueprint("devs", __name__)
    
    
    @devs.route("/yanzheng_qr", methods=["POST"])
    def yanzheng_qr():  # 验证二维码
        device_id = request.form.get("device_id")  # 获取设备id
        if MONGO_DB.devices.find_one({"device_id": device_id}):  # 从数据库中查询设备id
            # 查询该玩具是不是已被用户绑定
            toy_info = MONGO_DB.toys.find_one({"device_id": device_id})
            # 未绑定开启绑定逻辑
            if not toy_info:
                RET["code"] = 0
                RET["msg"] = "感谢购买本公司产品"
                RET["data"] = {}
    
            # 如果被绑定加好友逻辑开启
            if toy_info:
                pass
    
        else:
            RET["code"] = 2
            RET["msg"] = "二货,这不是本公司设备,快去买正版!"
            RET["data"] = {}
    
        return jsonify(RET)
    View Code

     

    修改 manager.py,注册蓝图

    from flask import Flask, request,jsonify,render_template
    from setting import MONGO_DB
    from setting import RET
    from bson import ObjectId
    from serv import get_file
    from serv import content
    from serv import devices
    
    app = Flask(__name__)
    
    app.register_blueprint(get_file.getfile)
    app.register_blueprint(content.cont)
    app.register_blueprint(devices.devs)
    
    @app.route('/')
    def hello_world():
        return render_template("index.html")
    
    
    @app.route('/login',methods=["POST"])
    def login():
        """
        登陆验证
        :return: settings -> RET
        """
        try:
            RET["code"] = 1
            RET["msg"] = "用户名或密码错误"
            RET["data"] = {}
    
            username = request.form.get("username")
            password = request.form.get("password")
    
            user = MONGO_DB.users.find_one({"username": username, "password": password})
    
            if user:
                # 由于user中的_id是ObjectId对象,需要转化为字符串
                user["_id"] = str(user.get("_id"))
                RET["code"] = 0
                RET["msg"] = "欢迎登陆"
                RET["data"] = {"user_id": user.get("_id")}
    
        except Exception as e:
            RET["code"] = 1
            RET["msg"] = "登陆失败"
    
        return jsonify(RET)
    
    
    @app.route('/reg',methods=["POST"])
    def reg():
        """
        注册
        :return: {"code":0,"msg":"","data":""}
        """
        try:
            username = request.form.get("username")
            password = request.form.get("password")
            age = request.form.get("age")
            nickname = request.form.get("nickname")
            gender = request.form.get("gender")
            phone = request.form.get("phone")
    
            user_info = {
                "username": username,
                "password": password,
                "age": age,
                "nickname": nickname,
                # 判断gender==2,成立时为girl.jpg,否则为boy.jpg
                "avatar": "girl.jpg" if gender == 2 else "boy.jpg",
                "gender": gender,
                "phone": phone
            }
    
            res = MONGO_DB.users.insert_one(user_info)
            user_id = str(res.inserted_id)
    
            RET["code"] = 0
            RET["msg"] = "注册成功"
            RET["data"] = user_id
        except Exception as e:
            RET["code"] = 1
            RET["msg"] = "注册失败"
    
        return jsonify(RET)
    
    
    @app.route('/user_info', methods=["POST"])
    def user_info():
        user_id = request.form.get("user_id")
    
        # "password": 0 表示忽略密码字段
        res = MONGO_DB.users.find_one({"_id": ObjectId(user_id)}, {"password": 0})
        if res:
            res["_id"] = str(res.get("_id"))
    
        RET["code"] = 0
        RET["msg"] = ""
        RET["data"] = res
    
        return jsonify(res)
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 9527, debug=True)
    View Code

    重启 manager.py

     

    进入HBuilder项目MyApp,修改qrcode.html,发送POST请求,将设备id发过去

    <!doctype html>
    <html lang="en">
    
        <head>
            <meta charset="UTF-8" />
            <title>Document</title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link rel="stylesheet" type="text/css" href="css/mui.css" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
                <h1 class="mui-title">扫描玩具二维码</h1>
            </header>
            <div class="mui-content">
                <div style="height: 550px;" id="qr"></div>
            </div>
    
        </body>
        <script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            mui.init()
            
            function chenggong(type, code) {  //扫码成功回调函数
                mui.post(
                    // 验证二维码
                    window.serv + "/yanzheng_qr", {
                        // 发送设备id
                        device_id: code
                    },
                    function(data) {
                        console.log(JSON.stringify(data));
                        mui.toast(data.msg);  //显示结果
                    }
                )
            }
            
            mui.plusReady(function() {
                // 创建Barcode对象
                var barcode = new plus.barcode.Barcode('qr');
                barcode.start();  // 开始条码识别
                barcode.onmarked = chenggong;  // 扫码成功后,执行函数chenggong
            })
        </script>
    
    </html>
    View Code

     

    先扫描一个冒牌的二维码

     

    再来扫描一个正版的

     

    修改 qrcode.html,判断3种情况。先写伪代码!

    <!doctype html>
    <html lang="en">
    
        <head>
            <meta charset="UTF-8" />
            <title>Document</title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link rel="stylesheet" type="text/css" href="css/mui.css" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
                <h1 class="mui-title">扫描玩具二维码</h1>
            </header>
            <div class="mui-content">
                <div style="height: 550px;" id="qr"></div>
            </div>
    
        </body>
        <script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            mui.init()
            
            function chenggong(type, code) {  //扫码成功回调函数
                mui.post(
                    // 验证二维码
                    window.serv + "/yanzheng_qr", {
                        // 发送设备id
                        device_id: code
                    },
                    function(data) {
                        console.log(JSON.stringify(data));
                        mui.toast(data.msg);  //显示结果
                        if(data.code == 2) {
                            mui.back();  //返回页面
                        }
                        if(data.code == 1) {
                            //加好友的小逻辑 跳转到加好友页面
                        }
                        if(data.code == 0) {
                            //今天的逻辑 创建玩具 绑定用户 成为玩具的第一个好友
                        }
                    }
                )
            }
            
            mui.plusReady(function() {
                // 创建Barcode对象
                var barcode = new plus.barcode.Barcode('qr');
                barcode.start();  // 开始条码识别
                barcode.onmarked = chenggong;  // 扫码成功后,执行函数chenggong
            })
        </script>
    
    </html>
    View Code

     

    三、创建玩具的基本属性

    扫描成功后,需要跳转到绑定玩具页面!

    新建文件bind_toy.html

     

    bind_toy.html

    <!doctype html>
    <html lang="en">
    
        <head>
            <meta charset="UTF-8" />
            <title>Document</title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link rel="stylesheet" type="text/css" href="css/mui.css" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
                <h1 class="mui-title">绑定我的玩具</h1>
            </header>
            <div class="mui-content">
                <form class="mui-input-group">
                    <div class="mui-input-row">
                        <label>玩具的昵称</label>
                        <input type="text" class="mui-input-clear" placeholder="请输入玩具的昵称" id="toy_name">
                    </div>
                    <div class="mui-input-row mui-radio mui-left">
                        <label>男</label>
                        <input name="gender" type="radio" value="1">
                    </div>
                    <div class="mui-input-row mui-radio mui-left">
                        <label>女</label>
                        <input name="gender" type="radio" value="2" checked>
                    </div>
                    <div class="mui-input-row">
                        <label>玩具的主人</label>
                        <input type="text" class="mui-input-clear" placeholder="请输入小主人的名字" id="baby_name">
                    </div>
                    <div class="mui-input-row">
                        <label>主人的称呼</label>
                        <input type="text" class="mui-input-clear" placeholder="玩具主人对您的称呼" id="remark">
                    </div>
                    <div class="mui-button-row">
                        <button type="button" class="mui-btn mui-btn-primary" id="bind">绑定</button>
                        <button type="button" class="mui-btn mui-btn-danger mui-action-back">取消</button>
                    </div>
                </form>
            </div>
        </body>
        <script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            mui.init()
            
            var Sdata = null;
            mui.plusReady(function() {
                Sdata = plus.webview.currentWebview();
    
            })
    
        </script>
    
    </html>
    View Code

     

    修改 qrcode.html,将设置id,传给bind_toy.html

    <!doctype html>
    <html lang="en">
    
        <head>
            <meta charset="UTF-8" />
            <title>Document</title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link rel="stylesheet" type="text/css" href="css/mui.css" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
                <h1 class="mui-title">扫描玩具二维码</h1>
            </header>
            <div class="mui-content">
                <div style="height: 550px;" id="qr"></div>
            </div>
    
        </body>
        <script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            mui.init()
            
            function chenggong(type, code) {  //扫码成功回调函数
                mui.post(
                    // 验证二维码
                    window.serv + "/yanzheng_qr", {
                        // 发送设备id
                        device_id: code
                    },
                    function(data) {
                        console.log(JSON.stringify(data));
                        mui.toast(data.msg);  //显示结果
                        if(data.code == 2) {
                            mui.back();  //返回页面
                        }
                        if(data.code == 1) {
                            //加好友的小逻辑 跳转到加好友页面
                        }
                        if(data.code == 0) {
                            //今天的逻辑 创建玩具 绑定用户 成为玩具的第一个好友
                            //1.创建玩具:打开创建玩具的页面
                            mui.openWindow({
                                url:"bind_toy.html",
                                id:"bind_toy.html",
                                extras:{
                                    device_id:code
                                }
                            })
                        }
                    }
                )
            }
            
            mui.plusReady(function() {
                // 创建Barcode对象
                var barcode = new plus.barcode.Barcode('qr');
                barcode.start();  // 开始条码识别
                barcode.onmarked = chenggong;  // 扫码成功后,执行函数chenggong
            })
        </script>
    
    </html>
    View Code

     

    修改 bind_toy.html,将表单数据传给后端

    <!doctype html>
    <html lang="en">
    
        <head>
            <meta charset="UTF-8" />
            <title>Document</title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link rel="stylesheet" type="text/css" href="css/mui.css" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
                <h1 class="mui-title">绑定我的玩具</h1>
            </header>
            <div class="mui-content">
                <form class="mui-input-group">
                    <div class="mui-input-row">
                        <label>玩具的昵称</label>
                        <input type="text" class="mui-input-clear" placeholder="请输入玩具的昵称" id="toy_name">
                    </div>
                    <div class="mui-input-row mui-radio mui-left">
                        <label>男</label>
                        <input name="gender" type="radio" value="1">
                    </div>
                    <div class="mui-input-row mui-radio mui-left">
                        <label>女</label>
                        <input name="gender" type="radio" value="2" checked>
                    </div>
                    <div class="mui-input-row">
                        <label>玩具的主人</label>
                        <input type="text" class="mui-input-clear" placeholder="请输入小主人的名字" id="baby_name">
                    </div>
                    <div class="mui-input-row">
                        <label>主人的称呼</label>
                        <input type="text" class="mui-input-clear" placeholder="玩具主人对您的称呼" id="remark">
                    </div>
                    <div class="mui-button-row">
                        <button type="button" class="mui-btn mui-btn-primary" id="bind">绑定</button>
                        <button type="button" class="mui-btn mui-btn-danger mui-action-back">取消</button>
                    </div>
                </form>
            </div>
        </body>
        <script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            mui.init()
            
            var Sdata = null;
            mui.plusReady(function() {
                Sdata = plus.webview.currentWebview();
                console.log(plus.storage.getItem("user"))
            })
    
            document.getElementById("bind").addEventListener("tap", function() {
                var toy_name = document.getElementById("toy_name").value;
                var baby_name = document.getElementById("baby_name").value;
                var remark = document.getElementById("remark").value;
                var gender_list = document.getElementsByName("gender");
                var gender = null;
                for(var i = 0; i < gender_list.length; i++) {
                    if(gender_list[i].checked) {
                        gender = gender_list[i].value;
                    }
                }
    
                mui.post(
                    window.serv + "/bind_toy", {
                        device_id: Sdata.device_id,
                        toy_name:toy_name,
                        baby_name:baby_name,
                        remark:remark,
                        gender:gender,
                        // 全局变量,从plus.storage中获取
                        user_id:plus.storage.getItem("user")
                        
                    },
                    function(data){
                        console.log(JSON.stringify(data));
                        mui.toast(data.msg);
                    }
                )
            })
        </script>
    
    </html>
    View Code

     

    bind_toy.html页面,效果是这个样子:

     

    创建玩具的基本属性

    进入flask项目,修改devices.py,新建一个视图函数bind_toy,用来绑定玩具

    from flask import Blueprint, request, jsonify
    from setting import MONGO_DB
    from setting import RET
    from bson import ObjectId
    
    devs = Blueprint("devs", __name__)
    
    
    @devs.route("/yanzheng_qr", methods=["POST"])
    def yanzheng_qr():  # 验证二维码
        device_id = request.form.get("device_id")  # 获取设备id
        if MONGO_DB.devices.find_one({"device_id": device_id}):  # 从数据库中查询设备id
            # 查询该玩具是不是已被用户绑定
            toy_info = MONGO_DB.toys.find_one({"device_id": device_id})
            # 未绑定开启绑定逻辑
            if not toy_info:
                RET["code"] = 0
                RET["msg"] = "感谢购买本公司产品"
                RET["data"] = {}
    
            # 如果被绑定加好友逻辑开启
            if toy_info:
                pass
    
        else:
            RET["code"] = 2
            RET["msg"] = "二货,这不是本公司设备,快去买正版!"
            RET["data"] = {}
    
        return jsonify(RET)
    
    @devs.route("/bind_toy", methods=["POST"])
    def bind_toy():  # 绑定玩具
    
        device_id = request.form.get("device_id")  # 设备id
        toy_name = request.form.get("toy_name")  # 玩具的昵称
        baby_name = request.form.get("baby_name")  # 小主人的名字
        remark = request.form.get("remark")  # 玩具主人对您的称呼
        gender = request.form.get("gender")  # 性别
    
        user_id = request.form.get("user_id")  # 用户id
        res = MONGO_DB.users.find_one({"_id": ObjectId(user_id)})  # 查询用户id是否存在
    
        toy_info = {
            "device_id": device_id,
            "toy_name": toy_name,
            "baby_name": baby_name,
            "gender": gender,
            "avatar": "boy.jpg" if gender == 1 else "girl.jpg",
            # 绑定用户
            "bind_user": str(res.get("_id")),
        }
    View Code

     

    用户和玩具的绑定关系

    玩具还有和APP进行通信,需要一个chat表,记录聊天id

     

    修改 devices.py,修改 bind_toy视图函数

    @devs.route("/bind_toy", methods=["POST"])
    def bind_toy():  # 绑定玩具
        chat_window = MONGO_DB.chat.insert_one({})  # 插入一个空数据
        chat_id = chat_window.inserted_id  # 获取聊天id
    
        user_id = request.form.get("user_id")  # 用户id
        res = MONGO_DB.users.find_one({"_id": ObjectId(user_id)})  # 查询用户id是否存在
    
        device_id = request.form.get("device_id")  # 设备id
        toy_name = request.form.get("toy_name")  # 玩具的昵称
        baby_name = request.form.get("baby_name")  # 小主人的名字
        remark = request.form.get("remark")  # 玩具主人对您的称呼
        gender = request.form.get("gender")  # 性别
    
        toy_info = {
            "device_id": device_id,
            "toy_name": toy_name,
            "baby_name": baby_name,
            "gender": gender,
            "avatar": "boy.jpg" if gender == 1 else "girl.jpg",
            # 绑定用户
            "bind_user": str(res.get("_id")),
        }
    View Code

     

    既然是聊天,需要有好友列表,并插入玩具表

    修改 devices.py,修改 bind_toy视图函数

    @devs.route("/bind_toy", methods=["POST"])
    def bind_toy():  # 绑定玩具
        chat_window = MONGO_DB.chat.insert_one({})  # 插入一个空数据
        chat_id = chat_window.inserted_id  # 获取聊天id
    
        user_id = request.form.get("user_id")  # 用户id
        res = MONGO_DB.users.find_one({"_id": ObjectId(user_id)})  # 查询用户id是否存在
    
        device_id = request.form.get("device_id")  # 设备id
        toy_name = request.form.get("toy_name")  # 玩具的昵称
        baby_name = request.form.get("baby_name")  # 小主人的名字
        remark = request.form.get("remark")  # 玩具主人对您的称呼
        gender = request.form.get("gender")  # 性别
    
        toy_info = {
            "device_id": device_id,
            "toy_name": toy_name,
            "baby_name": baby_name,
            "gender": gender,
            "avatar": "boy.jpg" if gender == 1 else "girl.jpg",
            # 绑定用户
            "bind_user": str(res.get("_id")),
            # 第一个好友
            "friend_list": [{
                "friend_id": str(res.get("_id")),  # 好友id
                "friend_name": res.get("nickname"),  # 好友昵称
                "friend_remark": remark,  # 好友称呼
                "friend_avatar": res.get("avatar"),  # 好友头像
                "friend_chat": str(chat_id),  # 好友聊天id
            }]
        }
    
        toy_res = MONGO_DB.toys.insert_one(toy_info)  # 插入数据
    View Code

     

    用户难道只有一个好友吗?当然不是,他可以有很多个。

    修改 devices.py,修改 bind_toy视图函数,做一个判断

    @devs.route("/bind_toy", methods=["POST"])
    def bind_toy():  # 绑定玩具
        chat_window = MONGO_DB.chat.insert_one({})  # 插入一个空数据
        chat_id = chat_window.inserted_id  # 获取聊天id
    
        user_id = request.form.get("user_id")  # 用户id
        res = MONGO_DB.users.find_one({"_id": ObjectId(user_id)})  # 查询用户id是否存在
    
        device_id = request.form.get("device_id")  # 设备id
        toy_name = request.form.get("toy_name")  # 玩具的昵称
        baby_name = request.form.get("baby_name")  # 小主人的名字
        remark = request.form.get("remark")  # 玩具主人对您的称呼
        gender = request.form.get("gender")  # 性别
    
        toy_info = {
            "device_id": device_id,
            "toy_name": toy_name,
            "baby_name": baby_name,
            "gender": gender,
            "avatar": "boy.jpg" if gender == 1 else "girl.jpg",
            # 绑定用户
            "bind_user": str(res.get("_id")),
            # 第一个好友
            "friend_list": [{
                "friend_id": str(res.get("_id")),  # 好友id
                "friend_name": res.get("nickname"),  # 好友昵称
                "friend_remark": remark,  # 好友称呼
                "friend_avatar": res.get("avatar"),  # 好友头像
                "friend_chat": str(chat_id),  # 好友聊天id
            }]
        }
    
        toy_res = MONGO_DB.toys.insert_one(toy_info)  # 插入玩具表数据
    
        if res.get("friend_list"):  # 判断用户好友列表是否为空
            # 追加好友
            res["bind_toy"].append(str(toy_res.inserted_id))
            res["friend_list"].append({
                "friend_id": str(toy_res.inserted_id),
                "friend_name": toy_name,
                "friend_remark": baby_name,
                "friend_avatar": toy_info.get("avatar"),
                "friend_chat": str(chat_id),
            })
        else:
            # 更新好友
            res["bind_toy"] = [str(toy_res.inserted_id)]
            res["friend_list"] = [{
                "friend_id": str(toy_res.inserted_id),
                "friend_name": toy_name,
                "friend_remark": baby_name,
                "friend_avatar": toy_info.get("avatar"),
                "friend_chat": str(chat_id),
            }]
    
        MONGO_DB.users.update_one({"_id": ObjectId(user_id)}, {"$set": res})  # 更新用户记录
    View Code

     

    玩具通讯录中的第一个好友

    那么 上面的chat_id是属于哪个用户的呢?需要更新chat表,做一个绑定!

    修改 devices.py,修改 bind_toy视图函数。完整代码如下:

    from flask import Blueprint, request, jsonify
    from setting import MONGO_DB
    from setting import RET
    from bson import ObjectId
    
    devs = Blueprint("devs", __name__)
    
    
    @devs.route("/yanzheng_qr", methods=["POST"])
    def yanzheng_qr():  # 验证二维码
        device_id = request.form.get("device_id")  # 获取设备id
        if MONGO_DB.devices.find_one({"device_id": device_id}):  # 从数据库中查询设备id
            # 查询该玩具是不是已被用户绑定
            toy_info = MONGO_DB.toys.find_one({"device_id": device_id})
            # 未绑定开启绑定逻辑
            if not toy_info:
                RET["code"] = 0
                RET["msg"] = "感谢购买本公司产品"
                RET["data"] = {}
    
            # 如果被绑定加好友逻辑开启
            if toy_info:
                pass
    
        else:
            RET["code"] = 2
            RET["msg"] = "二货,这不是本公司设备,快去买正版!"
            RET["data"] = {}
    
        return jsonify(RET)
    
    
    @devs.route("/bind_toy", methods=["POST"])
    def bind_toy():  # 绑定玩具
        chat_window = MONGO_DB.chat.insert_one({})  # 插入一个空数据
        chat_id = chat_window.inserted_id  # 获取聊天id
    
        user_id = request.form.get("user_id")  # 用户id
        res = MONGO_DB.users.find_one({"_id": ObjectId(user_id)})  # 查询用户id是否存在
    
        device_id = request.form.get("device_id")  # 设备id
        toy_name = request.form.get("toy_name")  # 玩具的昵称
        baby_name = request.form.get("baby_name")  # 小主人的名字
        remark = request.form.get("remark")  # 玩具主人对您的称呼
        gender = request.form.get("gender")  # 性别
    
        toy_info = {
            "device_id": device_id,
            "toy_name": toy_name,
            "baby_name": baby_name,
            "gender": gender,
            "avatar": "boy.jpg" if gender == 1 else "girl.jpg",
            # 绑定用户
            "bind_user": str(res.get("_id")),
            # 第一个好友
            "friend_list": [{
                "friend_id": str(res.get("_id")),  # 好友id
                "friend_name": res.get("nickname"),  # 好友昵称
                "friend_remark": remark,  # 好友称呼
                "friend_avatar": res.get("avatar"),  # 好友头像
                "friend_chat": str(chat_id),  # 好友聊天id
            }]
        }
    
        toy_res = MONGO_DB.toys.insert_one(toy_info)  # 插入玩具表数据
    
        if res.get("friend_list"):  # 判断用户好友列表是否为空
            # 追加好友
            res["bind_toy"].append(str(toy_res.inserted_id))
            res["friend_list"].append({
                "friend_id": str(toy_res.inserted_id),
                "friend_name": toy_name,
                "friend_remark": baby_name,
                "friend_avatar": toy_info.get("avatar"),
                "friend_chat": str(chat_id),
            })
        else:
            # 更新好友
            res["bind_toy"] = [str(toy_res.inserted_id)]
            res["friend_list"] = [{
                "friend_id": str(toy_res.inserted_id),
                "friend_name": toy_name,
                "friend_remark": baby_name,
                "friend_avatar": toy_info.get("avatar"),
                "friend_chat": str(chat_id),
            }]
    
        MONGO_DB.users.update_one({"_id": ObjectId(user_id)}, {"$set": res})  # 更新用户记录
    
        # 更新聊天表
        # user_list有2个值。第一个是玩具id,第2个是用户id
        # 这样,用户和玩具就能通讯了
        MONGO_DB.chat.update_one({"_id": chat_id},
                                 {"$set":
                                      {"user_list":
                                           [str(toy_res.inserted_id),
                                            str(res.get("_id"))]}})
    
        RET["code"] = 0
        RET["msg"] = "绑定成功"
        RET["data"] = {}
    
        return jsonify(RET)
    View Code

    重启 manager.py

     

    使用手机扫描正版的二维码。它会跳转到这个页面

    填写相关信息

    点击绑定,页面底部提示:绑定成功!

     

    先来查看用户表,会发现有一个id

    在看下面的好友列表

     

    看聊天表,只有一条记录

     

    看玩具表,只有一条记录

    看下面的好友列表

     

    绑定完成之后,需要跳转页面。跳转到哪里呢?跳转到 toy_manager.html页面

    这个页面,需要加载当前登录用户的玩具

    修改toy_manager.html,发送post请求

    <!doctype html>
    <html lang="en">
    
        <head>
            <meta charset="UTF-8" />
            <title>Document</title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link rel="stylesheet" type="text/css" href="css/mui.css" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
                <h1 class="mui-title">管理我的玩具</h1>
            </header>
            <div class="mui-content">
                <ul class="mui-table-view" id="toy_list">
                    <li class="mui-table-view-cell mui-media">
                        <a id="add_toy">
                            <img class="mui-media-object mui-pull-left" src="images/add.png">
                            <div class="mui-media-body">
                                你还没有玩具
                                <p class="mui-ellipsis">点击此处扫描二维码添加玩具</p>
                            </div>
                        </a>
                    </li>
                </ul>
            </div>
        </body>
        <script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            mui.init();
            mui.plusReady(function(){
                // 发送POST请求,访问玩具列表
                mui.post(
                    window.serv + "/toy_list",
                    {user_id:plus.storage.getItem("user")},
                    function(data){
                        console.log(JSON.stringify(data));
                    }
                )
            });
    
            document.getElementById("add_toy").addEventListener("tap", function() {
                mui.openWindow({
                    url: "qrcode.html",
                    id: "qrcode.html",
                })
            });
        </script>
    
    </html>
    View Code

     

    进入flask后端,在serv目录下,新建文件 toys.py

    from flask import Blueprint, request, jsonify
    from setting import MONGO_DB
    from setting import RET
    from bson import ObjectId
    
    toy = Blueprint("toy", __name__)
    
    
    @toy.route("/toy_list", methods=["POST"])
    def toy_list():  # 玩具列表
        user_id = request.form.get("user_id")  # 用户id
        # 查看用户信息
        user_info = MONGO_DB.users.find_one({"_id": ObjectId(user_id)})
        bind_toy = user_info.get("bind_toy")  # 获取绑定的玩具
        bind_toy_id = []  # 玩具列表
        for toy_id in bind_toy:  # 获取玩具列表中的所有玩具id
            bind_toy_id.append(ObjectId(toy_id))
    
        # 一次性查询多个玩具
        toys_list = list(MONGO_DB.toys.find({"_id": {"$in": bind_toy_id}}))
    
        for index,item in enumerate(toys_list):
            # 将_id转换为字符串
            toys_list[index]["_id"] = str(item.get("_id"))
    
        RET["code"] = 0
        RET["msg"] = ""
        RET["data"] = toys_list
    
        return jsonify(RET)
    View Code

     

    修改manager.py,注册蓝图

    from flask import Flask, request,jsonify,render_template
    from setting import MONGO_DB
    from setting import RET
    from bson import ObjectId
    from serv import get_file
    from serv import content
    from serv import devices
    from serv import toys
    
    app = Flask(__name__)
    
    app.register_blueprint(get_file.getfile)
    app.register_blueprint(content.cont)
    app.register_blueprint(devices.devs)
    app.register_blueprint(toys.toy)
    
    @app.route('/')
    def hello_world():
        return render_template("index.html")
    
    
    @app.route('/login',methods=["POST"])
    def login():
        """
        登陆验证
        :return: settings -> RET
        """
        try:
            RET["code"] = 1
            RET["msg"] = "用户名或密码错误"
            RET["data"] = {}
    
            username = request.form.get("username")
            password = request.form.get("password")
    
            user = MONGO_DB.users.find_one({"username": username, "password": password})
    
            if user:
                # 由于user中的_id是ObjectId对象,需要转化为字符串
                user["_id"] = str(user.get("_id"))
                RET["code"] = 0
                RET["msg"] = "欢迎登陆"
                RET["data"] = {"user_id": user.get("_id")}
    
        except Exception as e:
            RET["code"] = 1
            RET["msg"] = "登陆失败"
    
        return jsonify(RET)
    
    
    @app.route('/reg',methods=["POST"])
    def reg():
        """
        注册
        :return: {"code":0,"msg":"","data":""}
        """
        try:
            username = request.form.get("username")
            password = request.form.get("password")
            age = request.form.get("age")
            nickname = request.form.get("nickname")
            gender = request.form.get("gender")
            phone = request.form.get("phone")
    
            user_info = {
                "username": username,
                "password": password,
                "age": age,
                "nickname": nickname,
                # 判断gender==2,成立时为girl.jpg,否则为boy.jpg
                "avatar": "girl.jpg" if gender == 2 else "boy.jpg",
                "gender": gender,
                "phone": phone
            }
    
            res = MONGO_DB.users.insert_one(user_info)
            user_id = str(res.inserted_id)
    
            RET["code"] = 0
            RET["msg"] = "注册成功"
            RET["data"] = user_id
        except Exception as e:
            RET["code"] = 1
            RET["msg"] = "注册失败"
    
        return jsonify(RET)
    
    
    @app.route('/user_info', methods=["POST"])
    def user_info():
        user_id = request.form.get("user_id")
    
        # "password": 0 表示忽略密码字段
        res = MONGO_DB.users.find_one({"_id": ObjectId(user_id)}, {"password": 0})
        if res:
            res["_id"] = str(res.get("_id"))
    
        RET["code"] = 0
        RET["msg"] = ""
        RET["data"] = res
    
        return jsonify(res)
    
    if __name__ == '__main__':
        app.run("0.0.0.0", 9527, debug=True)
    View Code

     

    直接访问管理我的玩具页面,它会发起POST请求

    查看HBuilder控制台输出:

     {"code":0,"data":[{"_id":"5ba0f1f2e12532418089bf88","avatar":"girl.jpg","baby_name":"小甜甜","bind_user":"5b9bb768e1253281608e96eb","device_id":"01f9bf1bac93eddd8397d0455abbeddb","friend_list":[{"friend_avatar":"boy.jpg","friend_chat":"5ba0f1f2e12532418089bf87","friend_id":"5b9bb768e1253281608e96eb","friend_name":"xiao","friend_remark":"小鱼"}],"gender":"2","toy_name":"小可爱"}],"msg":""} at toy_manager.html:39

     

    那么拿到数据了,就可以渲染页面了!

    修改 toy_manager.html,渲染ul标签

    <!doctype html>
    <html lang="en">
    
        <head>
            <meta charset="UTF-8" />
            <title>Document</title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link rel="stylesheet" type="text/css" href="css/mui.css" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
                <h1 class="mui-title">管理我的玩具</h1>
            </header>
            <div class="mui-content">
                <ul class="mui-table-view" id="toy_list">
                    <li class="mui-table-view-cell mui-media">
                        <a id="add_toy">
                            <img class="mui-media-object mui-pull-left" src="images/add.png">
                            <div class="mui-media-body">
                                你还没有玩具
                                <p class="mui-ellipsis">点击此处扫描二维码添加玩具</p>
                            </div>
                        </a>
                    </li>
                </ul>
            </div>
        </body>
        <script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            mui.init();
            mui.plusReady(function(){
                // 发送POST请求,访问玩具列表
                mui.post(
                    window.serv + "/toy_list",
                    {user_id:plus.storage.getItem("user")},
                    function(data){
                        console.log(JSON.stringify(data));
                        // for循环玩具列表
                        for (var i = 0; i < data.data.length; i++) {
                            // 调用自定义函数,渲染玩具列表
                            create_content(data.data[i]);
                        }
                    }
                )
            });
            
            function create_content(content) {  //玩具列表
                var litag = document.createElement("li");
                litag.className = "mui-table-view-cell mui-media";
                var atag = document.createElement("a");
                atag.id = content._id;
                atag.onclick = function() {
                    console.log(this.id);
                    //openPlayer(this.id);
                }
    
                var imgtag = document.createElement("img");
                imgtag.className = "mui-media-object mui-pull-left";
                imgtag.style = "border-radius: 50%;width: 45px;height: 45px; "
                imgtag.src = "avatar/" + content.avatar;
    
                var divtag = document.createElement("div");
                divtag.className = "mui-media-body";
                divtag.innerText = content.baby_name;
                var ptag = document.createElement("p");
                ptag.className = "mui-ellipsis";
                ptag.innerText = content.toy_name;
    
                litag.appendChild(atag);
                atag.appendChild(imgtag);
                atag.appendChild(divtag);
                divtag.appendChild(ptag);
     
                document.getElementById("toy_list").appendChild(litag);
    
            }
    
            document.getElementById("add_toy").addEventListener("tap", function() {
                mui.openWindow({
                    url: "qrcode.html",
                    id: "qrcode.html",
                })
            });
        </script>
    
    </html>
    View Code

     

    重新访问 管理我的玩具页面,效果如下:

     

    这里有一个坑,绑定玩具之后,不要跳转到 管理我的玩具页面!它有可能会加载失败

    修改bind_toy.html,跳转改为user_info页面

    <!doctype html>
    <html lang="en">
    
        <head>
            <meta charset="UTF-8" />
            <title>Document</title>
            <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
            <link rel="stylesheet" type="text/css" href="css/mui.css" />
        </head>
    
        <body>
            <header class="mui-bar mui-bar-nav">
                <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a>
                <h1 class="mui-title">绑定我的玩具</h1>
            </header>
            <div class="mui-content">
                <form class="mui-input-group">
                    <div class="mui-input-row">
                        <label>玩具的昵称</label>
                        <input type="text" class="mui-input-clear" placeholder="请输入玩具的昵称" id="toy_name">
                    </div>
                    <div class="mui-input-row mui-radio mui-left">
                        <label>男</label>
                        <input name="gender" type="radio" value="1">
                    </div>
                    <div class="mui-input-row mui-radio mui-left">
                        <label>女</label>
                        <input name="gender" type="radio" value="2" checked>
                    </div>
                    <div class="mui-input-row">
                        <label>玩具的主人</label>
                        <input type="text" class="mui-input-clear" placeholder="请输入小主人的名字" id="baby_name">
                    </div>
                    <div class="mui-input-row">
                        <label>主人的称呼</label>
                        <input type="text" class="mui-input-clear" placeholder="玩具主人对您的称呼" id="remark">
                    </div>
                    <div class="mui-button-row">
                        <button type="button" class="mui-btn mui-btn-primary" id="bind">绑定</button>
                        <button type="button" class="mui-btn mui-btn-danger mui-action-back">取消</button>
                    </div>
                </form>
            </div>
        </body>
        <script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            mui.init()
            
            var Sdata = null;
            mui.plusReady(function() {
                Sdata = plus.webview.currentWebview();
                console.log(plus.storage.getItem("user"))
            })
    
            document.getElementById("bind").addEventListener("tap", function() {
                var toy_name = document.getElementById("toy_name").value;
                var baby_name = document.getElementById("baby_name").value;
                var remark = document.getElementById("remark").value;
                var gender_list = document.getElementsByName("gender");
                var gender = null;
                for(var i = 0; i < gender_list.length; i++) {
                    if(gender_list[i].checked) {
                        gender = gender_list[i].value;
                    }
                }
    
                mui.post(
                    window.serv + "/bind_toy", {
                        device_id: Sdata.device_id,
                        toy_name:toy_name,
                        baby_name:baby_name,
                        remark:remark,
                        gender:gender,
                        // 全局变量,从plus.storage中获取
                        user_id:plus.storage.getItem("user")
                        
                    },
                    function(data){
                        console.log(JSON.stringify(data));
                        mui.toast(data.msg);
                        // 绑定玩具成功之后
                        if(data.code==0){
                            // 跳转到用户信息页面
                            mui.openWindow({
                                url:"user_info.html",
                                id:"user_info.html",
                                styles:window.styles
                            })
                        }
                    }
                )
            })
        </script>
    
    </html>
    View Code

     

    今日总结:

    1.创建二维码
        device_id = f"{uuid4()}{time.time()}"
        device_id_md5 = hashlib.md5(device_id.encode("utf8"))
        requests.get("http://qr.liantu.com/api.php?text=%s" %(device_id_md5))
        
    2.扫码
        var barcode = new plus.barcode.Barcode('qr'); 创建HTML5PLUS的Barcode扫码对象
        var barcode = plus.barcode.create('qr',[plus.barcode.QR],sytles={top,left,weith,heigh}) 
        创建完成之后还得webview.append
        
        1.当前设备根本不是我们授权生产的玩具 无效二维码 2
        2.二维码有效,创建玩具,绑定用户 0
        3.二维码有效,且已绑定用户,加好友 1
        
    3.创建玩具的基本属性 
        toy_info = {
            "device_id": device_id,
            "toy_name": toy_name,
            "baby_name": baby_name,
            "gender": gender,
            "avatar": "boy.jpg" if gender == 1 else "girl.jpg",
            "bind_user":str(res.get("_id"))
        }
        玩具还要和 APP 进行通讯 ,chat chat_id
        详见代码
    
    4.用户和玩具的绑定关系 
        用户添加玩具为好友和绑定关系
        详见代码
        
    5.玩具通讯录中的第一个好友
        详见代码
    
    刚刚开机的时候:
    1.授权问题(MD5授权码)提示语 : 请联系玩具厂商
    2.绑定问题 提示语 : 快给我找一个小主人
    3.成功 提示语:欢迎使用
    View Code

     

    完整代码,请参考github:

    https://github.com/987334176/Intelligent_toy/archive/v1.2.zip

     

    posted @ 2018-09-18 17:13 肖祥 阅读(...) 评论(...) 编辑 收藏
    展开全文
  • nodejs二维码扫描—可辨别是哪个用户扫描背景实现概述开发环境相关依赖微信网页授权第一步:用户同意授权,获取code第二步:通过code换取网页授权access_token第三步...该文章主要是为了实现在没有扫码器的情况下,...
  • 提供两个发卡平台(可以修改成其他的) 先zc自己的发卡平台,填写地址,软件自动获取分类,商品,获取微信二维码扫码付款,返回购买的卡密
  • # Spring Boot微信开发,实现了简单的消息处理、生成二维码扫码事件处理(基于SDK-WxJava) 本 Demo 基于 Spring Boot 构建,实现微信公众号后端开发功能。 本项目修改自 WxJava 的 Demo 演示程序 weixin-java-mp-...
  • //条形高度 function Tab_height(tmp){ var dpi = Get_Dpi(); if(tmp.value%dpi==0){ document.getElementById("tab_height_mm").value = tmp.value/dpi; }else{ alert("注意...
  • 本文实例讲述了php实现微信扫码自动登陆与注册功能。分享给大家供大家参考,具体如下: 微信开发已经是现在程序员必须要掌握的一项基本的技术了,其实做过微信开发的都知道微信接口非常的强大做起来也非常的简单,...
  • 二维码简介: 二维码又称QR Code,QR全称Quick Response 3.2二维码优势 信息容量大, 可以容纳多达1850个大写字母或2710个数字或500多个汉字 应用范围广, 支持文字,声音,图片,指纹等等... 容错能力强, 即使图片...
  • 微信屏蔽了APP下载连接无非是想让大家将资源转移到自家平台,国人微信中毒过深,看到二维码首先想到的一定是微信(好强大的用户引导)。为了更好的用户体验,只能向腾讯屈服将应用转移到腾讯平台。当然如果是...
  • 2.微信群码有效期14天,过期必须将线下海报替换,否则群码失效,用户无法扫码加入微信群; 3.使用“草料二维码平台”的活码功能,把生成的活码加入海报,将微信群码作为活码的内容,用户扫描海报上的活码-打开实时的...
  • 发卡平台扫码-易语言

    2021-06-14 09:04:08
    调用了 精易模块 自己论坛下载,提供两个发卡平台(可以修改成其他的) 先zc自己的发卡平台,填写地址,软件自动获取分类,商品,获取微信二维码扫码付款,返回购买的卡密
  • 微信扫码支付

    千次阅读 2017-11-19 11:47:00
    1.二维码 2.微信扫码支付简要开发
  • //请填写串号/编码信息 codeInfo6 : true , //判断串号边框和编码边框隐藏,扫描,不可修改 detailInfo : [ ] , //录入手机串号编码 isSmHide : true , dataArr : [ ] , //模糊搜索数据 ...
  • 一、使用场景开发了一款App,包括iOS及Android版,到了推广阶段,准备生成二维码让用户扫码下载,那这个二维码该怎么生成?iOS及Andorid各自生成一个二维码让用户区分下载?当然这种方式是可行的,但却增加了用户的...
  • 微信屏蔽了APP下载连接无非是想让大家将资源转移到自家平台,国人微信中毒过深,看到二维码首先想到的一定是微信(好强大的用户引导)。为了更好的用户体验,只能向腾讯屈服将应用转移到腾讯平台。当然如果是...
  • 生成二维码与条形的各种方法

    万次阅读 2017-06-16 14:06:25
    二维码 方法1:将网址生成二维码的API调用接口 ...
  • 开发中常常遇到二维码扫码操作,前段时间做项目要实现该功能,于是网上查找资料实现了,现在把他做出来给各位分享一下,主要包含了二维码扫描和生成二维码名片,先来看看效果图:      生成的二维码,打开微信扫...
  • 一、 微信扫码支付 学习内容: 能够根据微信支付的开发文档调用微信支付的 api 完成统一下单生成微信支付二维码功能 完成支付回调的逻辑处理,掌握 EchoSite的使用 完成推送支付通知功能 微信支付快速入门 1.1 微信...
  • web项目对接钉钉扫码登录

    千次阅读 2020-10-28 10:37:43
    今天我们记录一下关于vue进行web开发的过程中对接钉钉的H5微应用的时候扫码登录的功能,你说他难吧,其实不难,很简单,你说他简单吧,看文档可能真的有点乱,不然您也不会来看我的帖子,我也看了别的大佬们写的关于...
  • 需求 解决方案 步骤 这里我们选择永久二维码 代码见第二章需求 用户通过微信扫码关注公众号获取...扫码是否关注公众号已关注,则微信会将带场景值扫描事件推送给开发者,根据场景判断当前二维码是否失效失效,公众号
  • 二维码后获得的内容是如下: 111111111111-22222--03 第一,二用'-'分开,第二,三用'--'分开,如何获取这三个字段 填充到页面上对应的文本框中..也就是说只要扫描二维码之后就要把这三个字段内容填充到页面对应的...
  • 同时当粉丝在通过不同渠道二维码扫码关注公众号以后,还可以添加渠道自定义标签,在选择推送消息时就可以根据标签进行精准推送。 渠道带参二维码最大的功能特点在于统计功能,可以针对各个渠道的引流效果进行自动
  • 微信公众号扫二维码事件相关 用户扫描微信公众号生成的带参数的二维码,可能推送两种不同的事件到微信公众号填写的地址上 如果用户还未关注公众号,则用户可以关注公众号,关注后微信会将带场景值关注事件推...
  • 实现从点击付费按钮、到弹出二维码、到用户用手机微信扫码支付、到手机上用户付费成功、web网页再自动调整到支付成功后的页面,这一个过程。 代码下载:http://www.demodashi.com/demo/10268.html
  • 通过微信客户端扫码登录即可登录。  登录完即可获取到一个测试公众账号的信息。主要有appId和appsecret两个参数,这将唯一标示一个公众号,并且需要将他们作为参数获取用户的信息。 2)、关注公众号  ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,545
精华内容 1,018
关键字:

二维码扫码自动填写