用云开发Cloudbase,实现小程序多图片内容安全监测
前言
相比于文本的安全检测,图片的安全检测要稍微略复杂一些,当您读完本篇,将get到
- 图片安全检测的应用场景
 - 解决图片的安全校验的方式
 - 使用云调用方式对图片进行检测
 - 如何对上传图片大小进行限制
 - 如何解决多图上传覆盖问题
 
示例效果
当用户上传敏感违规图片时,禁止用户上传发布,并且做出相对应的用户友好提示

应用场景
通常,在校验一张图片是否含有违法违规内容相比于文本安全的校验,同样重要,有如下应用
- 图片智能鉴黄:涉及拍照的工具类应用(如美拍,识图类应用)用户拍照上传检测;电商类商品上架图片检测;媒体类用户文章里的图片检测等
 - 敏感人脸识别:用户头像;媒体类用户文章里的图片检测;社交类用户上传的图片检测等,凡是有用户自发生产内容的都应当提前做检测
 
解决图片的安全手段
在小程序开发中,提供了两种方式
- HTTPS调用
 - 云调用
 
HTTPS 调用的请求接口地止
https://api.weixin.qq.com/wxa/img_sec_check?access_token=ACCESS_TOKEN
检测图片审核,根据官方文档得知,需要两个必传的参数:分别是:access_token(接口调用凭证),media(要检测的图片文件)
对于HTTPS调用方式,愿意折腾的小伙伴可以参考文本内容安全检测(上篇)的处理方式,处理大同小异,本篇主要以云开发的云调用为主
功能实现:小程序端逻辑
对于wxml与wxss,大家可以自行任意修改,本文重点在于图片安全的校验
<view class="image-list">
<!-- 显示图片 -->
   <block wx:for="{{images}}" wx:key="*this"><view class="image-wrap">
       <image class="image" src="{{item}}" mode="aspectFill" bind:tap="onPreviewImage" data-imgsrc="{{item}}"></image><i class="iconfont icon-shanchu" bind:tap="onDelImage" data-index="{{index}}"></i></view>
   </block>
   <!-- 选择图片 -->
   <view class="image-wrap selectphoto" hidden="{{!selectPhoto}}" bind:tap="onChooseImage"><i class="iconfont icon-add"></i></view>
   </view>
   <view class="footer"><button class="send-btn"  bind:tap="send">发布</button>
   </view>
对应的wxss代码
.footer {
  display: flex;
  align-items: center;
  width: 100%;
  box-sizing: border-box;
  background: #34bfa3;
}
.send-btn {
  width: 100%;
  color: #fff;
  font-size: 32rpx;
  background: #34bfa3;
}
button {
  border-radius: 0rpx;
}
button::after {
  border-radius: 0rpx !important;
}
/* 图片样式 */
.image-list {
  display: flex;
  flex-wrap: wrap;
  margin-top: 20rpx;
}
.image-wrap {
  width: 220rpx;
  height: 220rpx;
  margin-right: 10rpx;
  margin-bottom: 10rpx;
  position: relative;
  overflow: hidden;
  text-align: center;
}
.image {
  width: 100%;
  height: 100%;
}
.icon-shanchu {
  position: absolute;
  top: 0;
  right: 0;
  width: 40rpx;
  height: 40rpx;
  background-color: #000;
  opacity: 0.4;
  color: #fff;
  text-align: center;
  line-height: 40rpx;
  font-size: 38rpx;
  font-weight: bolder;
}
.selectphoto {
  border: 2rpx dashed #cbd1d7;
  position: relative;
}
.icon-add {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  color: #cbd1d7;
  font-size: 60rpx;
}
最终呈现的UI,由于只是用于图片检测演示,UI方面可忽略,如下所示

对应的JS代码
/*
* 涉及到的API:wx.chooseImage  从本地相册选择图片或使用相机拍照
*(https://developers.weixin.qq.com/miniprogram/dev/api/media/image/wx.chooseImage.html)
*
*
*/// 最大上传图片数量
const MAX_IMG_NUM = 9;
const db = wx.cloud.database(); // 初始化云数据库
Page({
  /**
   * 页面的初始数据
   */
  data: {
    images: [],  // 把上传的图片存放在一个数组对象里面
    selectPhoto: true, // 添加+icon元素是否显示
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
  },
  // 选择图片
  onChooseImage() {
    // 还能再选几张图片,初始值设置最大的数量-当前的图片的长度
    let max = MAX_IMG_NUM - this.data.images.length;
    wx.chooseImage({
      count: max,               // count表示最多可以选择的图片张数
      sizeType: ['original', 'compressed'], //  所选的图片的尺寸
      sourceType: ['album', 'camera'],  // 选择图片的来源
      success: (res) => {                     // 接口调用成功的回调函数console.log(res)
        this.setData({                       // tempFilePath可以作为img标签的src属性显示图片,下面是将后添加的图片与之前的图片给追加起来
          images: this.data.images.concat(res.tempFilePaths)
        })
        // 还能再选几张图片
        max = MAX_IMG_NUM - this.data.images.length
        this.setData({
          selectPhoto: max <= 0 ? false : true  // 当超过9张时,加号隐藏
        })
      },
    })
  },
  // 点击右上方删除图标,删除图片操作
  onDelImage(event) {
    const index = event.target.dataset.index;
    // 点击删除当前图片,用splice方法,删除一张,从数组中移除一个
    this.data.images.splice(index, 1)
    this.setData({
      images: this.data.images
    })
    // 当添加的图片达到设置最大的数量时,添加按钮隐藏,不让新添加图片
    if (this.data.images.length == MAX_IMG_NUM - 1) {
      this.setData({
        selectPhoto: true,
      })
    }
  },
})
最终实现的前端UI效果如下所是:

您现在看到的效果,没有任何云函数代码,只是前端的纯静态展示,对于一些涉嫌敏感图片,是有必要进行做过滤处理的
功能实现:云函数侧逻辑
在cloudfunctions目录文件夹下创建云函数imgSecCheck

并在该目录下创建config.json,配置参数如下所示
{
  "permissions": {
    "openapi": [
      "security.imgSecCheck"
    ]
  }
}
配置完后,在主入口index.js中,如下所示,通过security.imgSecCheck接口,并传入media对象
// 云函数入口文件
const cloud = require('wx-server-sdk');
cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV
})
// 云函数入口函数
exports.main = async (event, context) => {
  const wxContext = cloud.getWXContext()
  try {
    const result = await cloud.openapi.security.imgSecCheck({
      media: {
        contentType: 'image/png',
        value: Buffer.from(event.img)   // 这里必须要将小程序端传过来的进行Buffer转化,否则就会报错,接口异常
      }
    })
    if (result && result.errCode.toString() === '87014') {
      return { code: 500, msg: '内容含有违法违规内容', data: result }
    } else {
      return { code: 200, msg: '内容ok', data: result }
    }
  } catch (err) {
    // 错误处理
    if (err.errCode.toString() === '87014') {
      return { code: 500, msg: '内容含有违法违规内容', data: err }
    }
    return { code: 502, msg: '调用imgSecCheck接口异常', data: err }
  }
}
您会发现在云函数端,就这么几行代码,就完成了图片安全校验
而在小程序端,代码如下所示
// miniprogram/pages/imgSecCheck/imgSecCheck.js
// 最大上传图片数量
const MAX_IMG_NUM = 9;
const db = wx.cloud.database()
Page({
  /**
   * 页面的初始数据
   */
  data: {
    images: [],
    selectPhoto: true, // 添加图片元素是否显示
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
  },
  // 选择图片
  onChooseImage() {
    // const that = this;  // 如果下面用了箭头函数,那么这行代码是不需要的,直接用this就可以了的// 还能再选几张图片,初始值设置最大的数量-当前的图片的长度
    let max = MAX_IMG_NUM - this.data.images.length;
    wx.chooseImage({
      count: max,
      sizeType: ['original', 'compressed'],
      sourceType: ['album', 'camera'],
      success: (res) => {  // 这里若不是箭头函数,那么下面的this.setData的this要换成that上面的临时变量,作用域的问题,不清楚的,可以看下this指向相关的知识
       console.log(res)
       // tempFilePath可以作为img标签的src属性显示图片
        const  tempFiles = res.tempFiles;
        this.setData({
          images: this.data.images.concat(res.tempFilePaths)
        })
        // 在选择图片时,对本地临时存储的图片,这个时候,进行图片的校验,当然你放在最后点击发布时,进行校验也是可以的,只不过是一个前置校验和后置校验的问题,我个人倾向于在选择图片时就进行校验的,选择一些照片时,就应该在选择时阶段做安全判断的, 小程序端请求云函数方式// 图片转化buffer后,调用云函数
        console.log(tempFiles);
        tempFiles.forEach(items => {
          console.log(items);
          // 图片转化buffer后,调用云函数
          wx.getFileSystemManager().readFile({
            filePath: items.path,
            success: res => {
                  console.log(res);
                   wx.cloud.callFunction({  // 小程序端请求imgSecCheck云函数,并传递img参数进行检验
                    name: 'imgSecCheck',
                    data: {
                      img: res.data
                    }
            })
            .then(res => {
               console.log(res);
               let { errCode } = res.result.data;
               switch(errCode) {
                 case 87014:
                   this.setData({
                      resultText: '内容含有违法违规内容'
                   })
                   break;
                 case 0:
                   this.setData({
                     resultText: '内容OK'
                   })
                   break;
                 default:
                   break;
               }
            })
            .catch(err => {
               console.error(err);
            })
            },
            fail: err => {
              console.error(err);
            }
          })
        })
        // 还能再选几张图片
        max = MAX_IMG_NUM - this.data.images.length
        this.setData({
          selectPhoto: max <= 0 ? false : true  // 当超过9张时,加号隐藏
        })
      },
    })
  },
  // 删除图片
  onDelImage(event) {
    const index =  event.target.dataset.index;
    // 点击删除当前图片,用splice方法,删除一张,从数组中移除一个
    this.data.images.splice(index, 1);
    this.setData({
      images: this.data.images
    })
    // 当添加的图片达到设置最大的数量时,添加按钮隐藏,不让新添加图片
    if (this.data.images.length == MAX_IMG_NUM - 1) {
      this.setData({
        selectPhoto: true,
      })
    }
  },
})
示例效果如下所示:

至此,关于图片安全检测就已经完成了,您只需要根据检测的结果,做一些友好的用户提示,或者做一些自己的业务逻辑判断即可
常见问题
如何对上传的图片大小进行限制
有时候,您需要对用户上传图片的大小进行限制,限制用户任意上传超大图片,那怎么处理呢,在微信小程序里面,主要借助的是wx.chooseImage这个接口成功返回后临时路径的res.tempFiles中的size大小判断即可进行处理
具体实例代码如下所示
// 选择图片
  onChooseImage() {
    // 还能再选几张图片,初始值设置最大的数量-当前的图片的长度
    let max = MAX_IMG_NUM - this.data.images.length;
    wx.chooseImage({
      count: max,
      sizeType: ['original', 'compressed'],
      sourceType: ['album', 'camera'],
      success: (res) => {
        console.log(res)
        const  tempFiles = res.tempFiles;
        this.setData({
          images: this.data.images.concat(res.tempFilePaths)  // tempFilePath可以作为img标签的src属性显示图片
        })
        // 在选择图片时,对本地临时存储的图片,这个时候,进行图片的校验,当然你放在最后点击发布时,进行校验也是可以的,只不过是一个前置校验和后置校验的问题,我个人倾向于在选择图片时就进行校验的,选择一些照片时,就应该在选择时阶段做安全判断的, 小程序端请求云函数方式// 图片转化buffer后,调用云函数
        console.log(tempFiles);
        tempFiles.forEach(items => {
          if (items && items.size > 1 * (1024 * 1024)) {  // 限制图片的大小
            wx.showToast({
              icon: 'none',
              title: '上传的图片超过1M,禁止用户上传',
              duration: 4000
            })
            // 超过1M的图片,禁止用户上传
          }
          console.log(items);
          // 图片转化buffer后,调用云函数
          wx.getFileSystemManager().readFile({
            filePath: items.path,
            success: res => {
                  console.log(res);
                   wx.cloud.callFunction({   // 请求调用云函数imgSecCheck
                    name: 'imgSecCheck',
                    data: {
                      img: res.data
                    }
            })
            .then(res => {
               console.log(res);
               let { errCode } = res.result.data;
               switch(errCode) {
                 case 87014:
                   this.setData({
                      resultText: '内容含有违法违规内容'
                   })
                   break;
                 case 0:
                   this.setData({
                     resultText: '内容OK'
                   })
                   break;
                 default:
                   break;
               }
            })
            .catch(err => {
               console.error(err);
            })
            },
            fail: err => {
              console.error(err);
            }
          })
        })
        // 还能再选几张图片
        max = MAX_IMG_NUM - this.data.images.length
        this.setData({
          selectPhoto: max <= 0 ? false : true  // 当超过9张时,加号隐藏
        })
      },
    })
  },

注意: 使用微信官方的图片内容安全接口进行校验,限制图片大小限制:1M,否则的话就会报错

也就是说,对于超过1M大小的违规图片,微信官方提供的这个图片安全接口是无法进行校验的
这个根据自己的业务而定,在小程序端对用户上传图片的大小进行限制如果您觉得微信官方提供的图片安全接口满足不了自己的业务需求,那么可以选择一些其他的图片内容安全校验的接口的
这个图片安全校验是非常有必要的,用户一旦上传非法图片,一旦通过网络进行传播,产生了社会影响,平台是有责任的,这种前车之鉴是有的
如何解决多图上传覆盖的问题
对于上传图片来说,这个wx.cloud.uploadFileAPI接口只能上传一张图片,但是很多时候,是需要上传多张图片到云存储当中的,当点击发布的时候,我们是希望将多张图片都上传到云存储当中去的
这个API虽然只能每次上传一张,但您可以循环遍历多张图片,然后一张一张的上传的
在cloudPath上传文件的参数当中,它的值:需要注意:文件的名称
那如何保证上传的图片不被覆盖,文件不重名的情况下就不会被覆盖
而在选择图片的时候,不应该上传,因为用户可能有删除等操作,如果直接上传的话会造成资源的浪费
而应该在点发布按钮的时候,才执行上传操作,文件不重名覆盖的示例代码如下所示
      let promiseArr = []
      let fileIds = []      // 将图片的fileId存放到一个数组中
      let imgLength = this.data.images.length;
      // 图片上传
      for (let i = 0; i < imgLength; i++) {
        let p = new Promise((resolve, reject) => {
        let item = this.data.images[i]
          // 文件扩展名
          let suffix = /\.\w+$/.exec(item)[0]; // 取文件后拓展名
          wx.cloud.uploadFile({      // 利用官方提供的上传接口
            cloudPath: 'blog/' + Date.now() + '-' + Math.random() * 1000000 + suffix,  // 云存储路径,您也可以使用es6中的模板字符串进行拼接的
            filePath: item,   // 要上传文件资源的路径
            success: (res) => {
              console.log(res);
              console.log(res.fileID)
              fileIds = fileIds.concat(res.fileID)       // 将新上传的与之前上传的给拼接起来
              resolve()
            },
            fail: (err) => {
              console.error(err)
              reject()
            }
          })
        })
        promiseArr.push(p)
      }
      // 存入到云数据库,其中这个Promise.all(),等待里面所有的任务都执行之后,在去执行后面的任务,也就是等待上传所有的图片上传完后,才能把相对应的数据存到数据库当中,具体与promise相关问题,可自行查漏
      Promise.all(promiseArr).then((res) => {
          db.collection('blog').add({ // 查找blog集合,将img,时间等数据添加到这个集合当中
            data: {
              img: fileIds,
              createTime: db.serverDate(), // 服务端的时间
            }
          }).then((res) => {
            console.log(res);
            this._hideToastTip();
            this._successTip();
          })
        })
        .catch((err) => {
          // 发布失败console.error(err);
        })
上面通过利用当前时间+随机数的方式进行了一个区分,规避了上传文件同名的问题
因为这个上传接口,一次性只能上传一张图片,所以需要循环遍历图片,然后一张张的上传
一个是上传到云存储中,另一个是添加到云数据库集合当中,要分别注意下这两个操作,云数据库中的图片是从云存储中拿到的,然后再添加到云数据库当中去的
示例效果如下所示:


将上传的图片存储到云数据库中
注意:添加数据到云数据库中,需要手动创建集合,不然是无法上传不到云数据库当中的,会报错
至此,关于敏感图片的检测,以及多图片的上传到这里就已经完成了
如下是完整的小程序端逻辑示例代码
// miniprogram/pages/imgSecCheck/imgSecCheck.js
// 最大上传图片数量
const MAX_IMG_NUM = 9;
const db = wx.cloud.database()
Page({
  /**
   * 页面的初始数据
   */
  data: {
    images: [],
    selectPhoto: true, // 添加图片元素是否显示
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
  },
  // 选择图片
  onChooseImage() {
    // 还能再选几张图片,初始值设置最大的数量-当前的图片的长度
    let max = MAX_IMG_NUM - this.data.images.length;
    wx.chooseImage({
      count: max,
      sizeType: ['original', 'compressed'],
      sourceType: ['album', 'camera'],
      success: (res) => {
        console.log(res)
        const tempFiles = res.tempFiles;
        this.setData({
          images: this.data.images.concat(res.tempFilePaths) // tempFilePath可以作为img标签的src属性显示图片
        })
        // 在选择图片时,对本地临时存储的图片,这个时候,进行图片的校验,当然你放在最后点击发布时,进行校验也是可以的,只不过是一个前置校验和后置校验的问题,我个人倾向于在选择图片时就进行校验的,选择一些照片时,就应该在选择时阶段做安全判断的, 小程序端请求云函数方式
        // 图片转化buffer后,调用云函数
        console.log(tempFiles);
        tempFiles.forEach(items => {
          if (items && items.size > 1 * (1024 * 1024)) {
            wx.showToast({
              icon: 'none',
              title: '上传的图片超过1M,禁止用户上传',
              duration: 4000
            })
            // 超过1M的图片,禁止上传
          }
          console.log(items);
          // 图片转化buffer后,调用云函数
          wx.getFileSystemManager().readFile({
            filePath: items.path,
            success: res => {
              console.log(res);
              this._checkImgSafe(res.data); // 检测图片安全校验
            },
            fail: err => {
              console.error(err);
            }
          })
        })
        // 还能再选几张图片
        max = MAX_IMG_NUM - this.data.images.length
        this.setData({
          selectPhoto: max <= 0 ? false : true // 当超过9张时,加号隐藏
        })
      },
    })
  },
  // 删除图片
  onDelImage(event) {
    const index = event.target.dataset.index;
    // 点击删除当前图片,用splice方法,删除一张,从数组中移除一个
    this.data.images.splice(index, 1);
    this.setData({
      images: this.data.images
    })
    // 当添加的图片达到设置最大的数量时,添加按钮隐藏,不让新添加图片
    if (this.data.images.length == MAX_IMG_NUM - 1) {
      this.setData({
        selectPhoto: true,
      })
    }
  },
  // 点击发布按钮,将图片上传到云数据库当中
  send() {
    const images = this.data.images.length;
    if (images) {
      this._showToastTip();
      let promiseArr = []
      let fileIds = []
      let imgLength = this.data.images.length;
      // 图片上传
      for (let i = 0; i < imgLength; i++) {
        let p = new Promise((resolve, reject) => {
          let item = this.data.images[i]
          // 文件扩展名
          let suffix = /\.\w+$/.exec(item)[0]; // 取文件后拓展名
          wx.cloud.uploadFile({   // 上传图片至云存储,循环遍历,一张张的上传
            cloudPath: 'blog/' + Date.now() + '-' + Math.random() * 1000000 + suffix,
            filePath: item,
            success: (res) => {
              console.log(res);
              console.log(res.fileID)
              fileIds = fileIds.concat(res.fileID)
              resolve()
            },
            fail: (err) => {
              console.error(err)
              reject()
            }
          })
        })
        promiseArr.push(p)
      }
      // 存入到云数据库
      Promise.all(promiseArr).then((res) => {
          db.collection('blog').add({ // 查找blog集合,将数据添加到这个集合当中
            data: {
              img: fileIds,
              createTime: db.serverDate(), // 服务端的时间
            }
          }).then((res) => {
            console.log(res);
            this._hideToastTip();
            this._successTip();
          })
        })
        .catch((err) => {
          // 发布失败
          console.error(err);
        })
    } else {
      wx.showToast({
        icon: 'none',
        title: '没有选择任何图片,发布不了',
      })
    }
  },
  // 校验图片的安全
  _checkImgSafe(data) {
    wx.cloud.callFunction({
        name: 'imgSecCheck',
        data: {
          img: data
        }
      })
      .then(res => {
        console.log(res);
        let {
          errCode
        } = res.result.data;
        switch (errCode) {
          case 87014:
            this.setData({
              resultText: '内容含有违法违规内容'
            })
            break;
          case 0:
            this.setData({
              resultText: '内容OK'
            })
            break;
          default:
            break;
        }
      })
      .catch(err => {
        console.error(err);
      })
  },
  _showToastTip() {
    wx.showToast({
      icon: 'none',
      title: '发布中...',
    })
  },
  _hideToastTip() {
    wx.hideLoading();
  },
  _successTip() {
    wx.showToast({
      icon: 'none',
      title: '发布成功',
    })
  },
})
完整的示例wxml,如下所示
<view class="image-list">
<!-- 显示图片 -->
<block wx:for="{{images}}" wx:key="*this">
     <view class="image-wrap"><image class="image" src="{{item}}" mode="aspectFill" bind:tap="onPreviewImage" data-imgsrc="{{item}}"></image><i class="iconfont icon-shanchu" bind:tap="onDelImage" data-index="{{index}}"></i>
     </view>
</block>
<!-- 选择图片 -->
<view class="image-wrap selectphoto" hidden="{{!selectPhoto}}" bind:tap="onChooseImage"><i class="iconfont icon-add"></i></view>
</view>
<view class="footer">
   <button class="send-btn"  bind:tap="send">发布</button>
</view>
<view>
    检测结果显示: {{ resultText }}
</view>
您可以根据自己的业务逻辑需要,一旦检测到图片违规时,禁用按钮状态,或者给一些用户提示,都是可以的,在发布之前或者点击发布时,进行图片内容安全的校验都可以,一旦发现图片有违规时,就不让继续后面的操作的
结语
本文主要通过借助官方提供的图片security.imgSecCheck
接口,实现了对图片安全的校验,实现起来,是相当的方便的,对于基础性的校验,利用官方提供的这个接口,已经够用了的,但是如果想要更加严格的检测,可以引入一些第三方的内容安全强强校验,确保内容的安全
实现了如何对上传的图片大小进行限制,以及解决同名图片上传覆盖的问题
如果大家对文本内容安全校验以及图片安全校验仍然有什么问题,可以在下方留言,一起探讨。
公众号:腾讯云云开发
腾讯云云开发:https://cloudbase.net
云开发控制台:https://console.cloud.tencent.com/tcb?from=12304
更多精彩
扫描二维码了解更多

用云开发Cloudbase,实现小程序多图片内容安全监测的更多相关文章
- 微信小程序云开发-从0打造云音乐全栈小程序
		
第1章 首门小程序“云开发”课程,你值得学习本章主要介绍什么是小程序云开发以及学习云开发的重要性,并介绍项目的整体架构,真机演示项目功能,详细介绍整体课程安排.课程适用人群以及需要掌握的前置知识.通过 ...
 - 基于云开发 CloudBase 搭建在线视频会议应用教程
		
基于云开发 CloudBase 搭建在线视频会议应用 在线视频会议应用是基于浏览器的能力 WebRTC 以及 腾讯云开发 CloudBase 能力构建而成的应用. 在云开发的助力下, 一个复杂的在线会 ...
 - 有哪些适合个人开发的微信小程序
		
微信小程序提供了一个简单.高效的应用开发框架和丰富的组件及API,帮助开发者在微信中开发具有原生 APP 体验的服务. 微信小程序支持采用云开发模式,无需后台服务,十分的方便快捷,适合个人开发一些工具 ...
 - 开发一个微信小程序教程
		
一.注册小程序账号 1.进入微信公众平台(https://mp.weixin.qq.com/),注册小程序账号,根据提示填写对应的信息即可. 2.注册成功后进入首页,在 小程序发布流程->小程序 ...
 - 开发一个微信小程序项目教程
		
一.注册小程序账号 1.进入微信公众平台(https://mp.weixin.qq.com/),注册小程序账号,根据提示填写对应的信息即可.2.注册成功后进入首页,在 小程序发布流程->小程序开 ...
 - 如何快速地开发一个微信小程序
		
如何快速地开发一个微信小程序呢?我觉得作为初学者,最好能有一个模板,然后改这个模板. 同样作为初学者,刚开始的时候我有下面的几个问题,后来通过问同学,我弄清楚了. 微信小程序可以连接MySQL或者Sq ...
 - Java可视化日历(Date类、DATe Format类、Calendar类综合运用),开发可视化日历小程序
		
Java时间日期类综合运用,开发可视化日历小程序 由键盘输入指定格式的日期,打印这个月的日历 1.代码 import java.text.DateFormat; import java.text.Pa ...
 - 全栈开发工程师微信小程序-中(下)
		
全栈开发工程师微信小程序-中(下) 微信小程序视图层 wxml用于描述页面的结构,wxss用于描述页面的样式,组件用于视图的基本组成单元. // 绑定数据 index.wxml <view> ...
 - 全栈开发工程师微信小程序-中(中)
		
全栈开发工程师微信小程序-中(中) 开放能力 open-data 用于展示微信开放的数据 type 开放数据类型 open-gid 当 type="groupName" 时生效, ...
 
随机推荐
- Spring全家桶之springMVC(四)
			
路径变量PathVariable PathVariable Controller除了可以接收表单提交的数据之外,还可以获取url中携带的变量,即路径变量,此时需要使用@PathVariable ...
 - 如何用尾插法建立双链表(C语言,非循环)
			
如何用尾插法建立双链表 其实本来是想完成汪队给的链表快排的作业,但是我写完建立双链表以后就12点了龟龟,明天还要早起QAQ,我菜死了 一,为啥要有双链表 先说单链表吧单链表长这样 他的一个结点结构就是 ...
 - Spring初学笔记(二):Bean的注入
			
关于Bean的注入 在上一篇中,已经说到虽然注入确实可以降低类与类之间的耦合,但并没有解决调用者必须知道类的创建方法的问题,也可以说是没有实现调用者与类实现的解耦,我们也提到,为了实现两者的解耦,可以 ...
 - Nginx初步入门
			
1.Nginx介绍 官网:nginx.org Nginx ("engine x") 是一个开源的.支持高性能.高并发的WWW服务和代理服务软件. 它是由俄罗斯人IgorSysoev ...
 - Copy与mutableCopy的个人理解
			
Copy与mutableCopy的个人理解 1. 相同点 都是将原有对象进行深拷贝(狭义) 这里的狭义上的深拷贝指的是在不考虑编译器在编译时对不可变对象进行copy时采取的优化策略:即将不可变对象的地 ...
 - Bootstrap响应式布局介绍
			
一.响应式布局 1.什么是响应式网页 2.响应式网页必须做到的几件事 1.布局,使用流式布局(默认文档流+浮动)+弹性布局+栅格布局 2.文字和图片大小随着容器大小改变 3.媒体查询技术(css3) ...
 - Django认证系统之自定义认证表
			
models.py from django.db import models from django.contrib.auth.models import AbstractUser class Use ...
 - PG 更新统计信息
			
http://blog.chinaunix.net/uid-24774106-id-3802225.html 一.vacuum的效果: 1.1释放,再利用 更新/删除的行所占据的磁盘空间. 第一点的原 ...
 - orcle报错:ORA-12737:Instant Client Light:unsupported server character set ZHS16GBK
			
我们用Navacat连接Oracle数据库的时候,会提示ORA-12737:Instant Client Light:unsupported server character set ZHS16GBK ...
 - iframe中有ajax,设置iframe自适应高度
			
------------------------------------------------------------------- http://www.jb51.net/article/1578 ...