微信小程序实现订阅消息功能(Node服务器篇)

news2024/11/15 21:33:11

         在上一篇内容当中在微信小程序中实现订阅消息功能,都在客户端(小程序)中来实现的,在客户端中模拟了服务器端来进行发送订阅消息的功能,那么本篇就将上一篇内容中仅在客户端中实现发送订阅消息功能进行一个分离,使用 Node.js 搭载后台服务器进行操作,客户端(小程序)通过请求提交数据信息到服务器,由服务器来发送订阅消息,如果你在没有读在客户端模拟服务器端的上一篇内容来此篇目的话可能需要有一些吃力,至少需要了解它的一个基本流程,那么本篇内容在客户端的内容不再从头开始讲起仅简单概述,重点还是在如何搭载后台以及完成客户端向服务器端进行提交数据请求处理后发送订阅消息,笔者建议小白从上一篇内容开始,再读本篇内容,可以知道在客户端模拟后端服务器和搭载后台服务器有哪些异同点,大大提高你的认识,下面进入正题。


完成效果

下面来看一下完成的效果: 


客户端页面编写

<!-- index.html -->
<!-- 顶部 -->
<view class="content">
  <view class="head">
    当前操作员:{{admin}}
  </view>
  <block wx:if="{{!hasUserInfo}}">
    <button bindtap="getUserProfile">获取</button>
  </block>
  <block wx:else>
    <form bindsubmit="formSubmit">
      <view class="log">
        <view class="log_title"> 
          <text>日志类型</text>
          <picker bindchange="changeTitle" name="title" value="{{index}}" range="{{logArray}}">
              <view class="nowing">{{logArray[index]}}</view>
          </picker>
        </view>
        <view class="log_date">
          <text>日期选择</text>
          <picker mode="date" name="date" value="{{date}}" bindchange="bindDateChange">
            <view class="nowing">{{date}}</view>   
          </picker>
        </view>
        <view class="log_person">
          <text>提醒人</text>
          <input type="text" name="remind" bindinput="bindRemindPer" bindtap ="allowSubscribeMessage" placeholder="例如:小明(参考)" value="{{remind}}"/>
        </view>
        <view class="log_tip">
          <text>温馨提示</text> 
          <input type="text" name="tip" bindinput="bindTipCont" value="{{tip}}"/>
        </view>
        <button form-type="submit" disabled="{{ remind == '' ? true : false}}">发送</button>
        <view class="errMsg">{{ remind == '' ? 'tips:需要填写提醒人名称才可发送!' : '' }}</view>
      </view>
    </form>
  </block>
</view>

客户端代码编写

        将前面客户端编写代码进行整理,在这里面需要填写你申请的订阅模板的id,以及form表单提交的内容待写,需要服务器端搭载编写请求接口供客户端发起请求。

// index.js
const app = getApp()
const time = require('../../utils/util')

const tempid = ''     // 填写上你自己的订阅模板id [未提交日志模板]

Page({
  data:{
    index: 0 ,                            // 默认为0,日报
    logArray:['日报','周报','月报'],
    admin:'',                             // 操作员
    lTitle:'未提交日志提醒',               // 提醒标题
    date: time.formateTime(new Date())    // 日期(格式化)
    remind:'',                            // 提醒人,默认admin              
    tip:'尚未提交日志',                    // 温馨提示内容
  },
  // 获取提醒标题
  changeTitle(e){
    this.setData({ index : e.detail.value })
  },
  // 获取日期选择
  bindDateChange(e){
    this.setData({ date : e.detail.value })
  },
  // 获取提醒人
  bindRemindPer(e){
    this.setData({ remind : e.detail.value })
  },
  // 获取提示内容
  bindTipCont(e){
    console.log(e)
    this.setData({ tip : e.detail.value })
  },
  // 获取用户信息
  getUserProfile(e) {
    // 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认,开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
    wx.getUserProfile({
      desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
      success: (res) => {
        this.setData({
          admin: res.userInfo.nickName,
          hasUserInfo: true
        })
      }
    })
  },
  // 获取用户权限 - 待写
  allowSubscribeMessage(){
    // hasSubscribeMessage 授权状态
    if (!app.globalData.hasSubscribeMessage) {
      wx.requestSubscribeMessage({
        tmplIds: [tempid], // 在此处填写模板id
        success(res) {
          console.log('获取权限:',res)
          app.globalData.hasSubscribeMessage = res.errMsg.split(':')[1]
        }
      })
    }
  },
  // 表单提交
  formSubmit(e){
    // e.detail.value 可以拿到用户提交表单的数据
    // console.log(e.detail.value)
    let formInfo = e.detail.value
    formInfo.title = this.data.logArray[formInfo.title]
    wx.login({
      timeout: 2000,
      // 成功后会返回code,将code提交给服务器
      success: res =>{
        // 获取到code
        console.log('获取到code:' + res.code)
        console.log(res)
        // 提交服务器 -- 待写
      }
    })
  }   
})

日期格式化文件

        引入 util/util.js 中存放着公共函数,有处理日期格式化函数,在index.js中来调用。

// 格式化日期
function formatTime(date) {
    var year = date.getFullYear()
    var month = date.getMonth() + 1
    var day = date.getDate()
    return [year, month, day].map(formatNumber).join('-') 
}

function formatNumber(n) {
  n = n.toString()
  return n[1] ? n : '0' + n
}

module.exports = {
  formatTime
}

下面开始进入本篇内容的一个重点部分,使用Node.js搭载后台服务器,那么对这块内容不熟悉的可以看一下这篇内容  微信小程序搭载node.js服务器(简),同时还可以到Node专栏学习一些关于Node.js的基础知识。

使用Node.js搭载后台服务器

        检查Node.js这些就不再讲了,在 微信小程序搭载node.js服务器(简) 当中已经讲过了!创建一个存放后台的文件夹,使用CMD命令切换到此目录之下,输入如下命令:

npm init -y 

        使用如下命令来安装 express 框架:

npm i express -S

         在目录下创建index.js文件作为启动文件。

         使用代码编译器 ( 这里使用的是VSCode ) 打开index.js进行代码编写如下代码:

const express = require('express')
const app = express()

// 解析表单 - 待写

app.get('/',(req,res)=>{
    res.send('ok')
})

// 监听 3000 端口号 | 127.0.0.1:3000
app.listen('3000',()=>{
    console.log('Server Running ...')
})

         测试一下,切出CMD命令窗口输入 node index.js (可安装nodemon)

         在浏览器的url地址上输入请求地址: http://127.0.0.1:3000/ ,会返回 res.send " ok "

        接下来开始编写客户端需要请求的接口。


解析表单

        body-parser是一个常用的express中间件,主要就是对 http 的请求体进行解析。否则前台发出请求所带的请求体无法被后端进行解析获取。

// 解析表单
app.use(express.json());
app.use(express.urlencoded({extended : false}))

        如果引入使用 bod-parser ,可以如下来引入编写(但没有必要,需要安装body-parser,可以使用express框架中的。)

npm i body-parser
const bodyParser = require('body-parser')

// 解析表单
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended : false}))

获取Openid

        获取Openid从上一篇内容就已然知道,获取Openid需要3个参数,分别是 code ,appid 和 appsecret ;appid 和 appsecret 可以在 微信公众平台 上登录获取,主要是 code 参数,code参数可以在客户端 (小程序) 通过 wx.login() 方法进行获取,然后发送到服务器端,再由服务器端发起请求小程序API拿到用户的Openid。

// index.js - 客户端
  ...
  // 表单提交
  formSubmit(e){
    // e.detail.value 可以拿到用户提交表单的数据
    // console.log(e.detail.value)
    let formInfo = e.detail.value
    formInfo.title = this.data.logArray[formInfo.title]
    wx.login({
      timeout: 2000,
      // 成功后会返回code,将code提交给服务器
      success: res =>{
        // 获取到code
        console.log('获取到code:' + res.code)
        console.log(res)
        // 提交服务器
        wx.request({
            url: 'http://127.0.0.1:3000/getOpenId',
            method: 'POST',
            data: {
                code: res.code
            },
            success: res=>{
                // 待写
            }
        })
      }
    })
  }  
... 

        通过 wx.request() 方法请求接口 http://127.0.0.1:3000/getOpenId ,请求参数就是 wx.login 获取到的code,下面来后台编写这个请求接口。

// index.js - 服务端
const express = require('express')
const app = express()

// 解析表单
app.use(express.json());
app.use(express.urlencoded({extended : false}))

// 用户信息
var user = {
    appid: '',    // 填写你自己的appid ( 微信公众平台获取 )
    secret: '',   // 填写你自己的appsecret密钥 ( 微信公众平台获取 )
    openid: ''
}

// 模板ID - template_id
const temp_id = ''        // 填写你申请选用的模板id

app.get('/',(req,res)=>{
    res.send('ok')
})

// 获取Openid请求接口
app.get('/getOpenId',(req,res)=>{
    // 待写
})

// 监听 3000 端口号 | 127.0.0.1:3000
app.listen('3000',()=>{
    console.log('Server Running ...')
})
...
// 获取Openid请求接口
app.get('/getOpenId',(req,res)=>{
    // console.log(req.body) 含有code参数
    console.log("客户端发来:",req.query.code)
    let data = req.query.code
    // 获取Openid函数
    getOpenid(data,(result)=>{
        // 保存openid待用
        console.log('用户OpenId:',result.data.openid)
        user.openid = result.data.openid
        res.send({ 'request' : 'ok' })
    })
})

// 监听 3000 端口号 | 127.0.0.1:3000
app.listen('3000',()=>{
    console.log('Server Running ...')
})

// 获取Openid处理函数 - 待写

         getOpenid(data,callback) ,通过req.body可以拿到客户端发过来的请求参数code,结合服务器端的appid参数和secrest参数就可以向往小程序API发起请求返回 Openid进行保存。可以看一下官方文档内容 小程序登录 | 微信开放文档 ,如下请求小程序API

GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code 

         在编写接口之前这三个参数是可以获取到的,我们可以使用这个API接口测试工具测试一下,测试API工具有很多像Postman,Apifox 等这些,然后将这个三个参数携带过去看能够获取这个Openid 。

        在客户端中拿到了code,appid和appsecret已经有了的,测试一下向微信API接口发起请求是否能够拿到Openid.

        下面在服务端安装一个在Vue中常讲到的HTTP数据请求库axios,使用这个可能大家会比较熟悉一些,使用如下命令安装:

npm i axios -S

const express = require('express')
const app = express()
const axios = require('axios')

// 解析表单
// 用户信息
// 模板ID - template_id

app.get('/',(req,res)=>{ ... })

// 获取Openid请求接口
app.get('/getOpenId',(req,res)=>{ ... })

// 监听 3000 端口号 | 127.0.0.1:3000
app.listen(3000,()=>{ ... })

// 获取Openid处理函数 - 通过code获取openid
function getOpenid(data,success){
    axios({
        url:'https://api.weixin.qq.com/sns/jscode2session?appid=' + user.appid + '&secret=' + user.secret + '&js_code=' + data + '&grant_type=authorization_code',
        method: 'GET',
    })
    .then((res)=>{
        // 成功返回 openid 
        // console.log(res.data.openid)
        user.openid = res.data.openid
        success(res)
    })
    .catch((err)=>{ console.log(err) })
}

        通过向微信API请求获取登陆凭证校验返回Openid进行保存。获取Openid之后下面进行发布订阅消息。 


发布订阅消息

        客户端请求 http://127.0.0.1:3000/getOpenId,请求成功之后返回 res.send({ 'request' : 'ok' }),客户端可以进行一个判断成功之后将表单数据进行一个提交。

// index.js - 客户端
  ...
  // 表单提交
  formSubmit(e){
    // e.detail.value 可以拿到用户提交表单的数据
    // console.log(e.detail.value)
    let formInfo = e.detail.value
    formInfo.title = this.data.logArray[formInfo.title]
    wx.login({
      timeout: 2000,
      // 成功后会返回code,将code提交给服务器
      success: res =>{
        // 获取到code
        console.log('获取到code:' + res.code)
        console.log(res)
        // 提交服务器
        wx.request({
            url: 'http://127.0.0.1:3000/getOpenId',
            method: 'POST',
            data: {
                code: res.code
            },
            success: res=>{
                if(res.data.request === 'ok'){
                    wx.request({
                        url: 'http://127.0.0.1:3000/sendTempMsg',
                        methods: 'POST',
                        data:{
                            formInfo : formInfo
                        },
                        success: res=>{
                            if(res.data.request === 'ok'){
                                wx.showToast({
                                    title: '订阅消息发送成功',
                                    icon: 'success'
                                })
                            }
                        }
                    })
                }
            }
        })
      }
    })
  }  
... 

        通过客户端使用wx.login拿到code参数之后向后端发起请求http://127.0.0.1:3000/getOpenId,后端响应请求后并发起请求微信API做登录凭证校验,请求成功后会返回session_key和openid,此时可以将拿到的openid进行保存,同时响应客户端res.send({ 'request': 'ok' }). 下面来编写由服务器发送订阅模板消息的接口。

const express = require('express')
const app = express()
const axios = require('axios')

// 解析表单
// 用户信息
// 模板ID - template_id

app.get('/',(req,res)=>{ ... })

// 获取Openid请求接口
app.get('/getOpenId',(req,res)=>{ ... })

// 发送订阅消息接口
app.post('/sendTempMsg',(req,res)=>{
    //  待写
})

// 监听 3000 端口号 | 127.0.0.1:3000
app.listen(3000,()=>{ ... })

// 获取Openid处理函数 - 通过code获取openid

        客户端提交表单数据信息,在服务器通过req.body.formInfo获取

// 发送订阅消息接口
app.post('/sendTempMsg',(req,res)=>{
    console.log("客户端发来:" ,req.body)
    lef formInfo = req.body.formInfo
    sendTempMsg(formInfo,(result)=>{
        console.log('订阅消息发送结果:', result.data)
        res.send({ 'request': 'ok' })
    })
})


// 发送订阅消息函数处理
sendTempMsg(formInfo,success){
    // 待写
}

        发送订阅消息模板还需要的参数有access_token,access_token是后台接口调用凭据,获取之后可以通过发送订阅消息API实现订阅消息的发送。下面先来获取access_token,这里附上官方文档的获取接口调用凭据 | 微信开放文档。

GET https://api.weixin.qq.com/cgi-bin/token

        这里可以使用这个API接口测试工具进行测试,测试是否可以拿到这个access_token.

// 发送订阅消息函数处理
sendTempMsg(formInfo,success){
    // 获取接口调用凭据
    getAccessToken((res)=>{
        // 待写
    }
}

// 获取access_token函数
function getAccessToken(success){
    let url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' +  user.appid + '&secret=' + user.secret
    axios({
        url,
        method: 'GET',
    }).then((res)=>{ 
        // console.log(res.data.access_token) // access_token
        success(res)
    }).catch((err)=>{
        console.log(err)
    })
}

        拿到 access_token 之后,订阅模板内容信息,然后请求微信API接口发送订阅消息。

// 发送订阅消息函数处理
sendTempMsg(formInfo,success){
    // 获取接口调用凭据
    getAccessToken((res)=>{
        // 订阅模板
        var temp = {
            "touser": user.openid,
            "template_id": temp_id,
            "data": {
                "phrase1": { "value": formInfo.title },
                "date2": { "value": formInfo.date },
                "name3": {"value": formInfo.remind },
                "thing4": { "value": formInfo.tip }
            },
            "miniprogram_state": "developer",
            "lang": "zh_CN"
        }
        console.log("模板信息",temp)
        let token = res.data.access_token
        console.log('获取到的access_token:',token)
        // 发送订阅API
        let url = 'https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=' + token
        axios({
            url,
            method: 'POST',
            data: temp
        }).then((res)=>{
            success(res) 
        }).catch((err)=>{ 
            console.log(err)
        })
    }
}

        到这里已经代码已经全部编写完成了,下面来测试一下。


测试效果

1. 启动后台服务器端

        使用 node index.js 命令(安装了 nodemon 可以使用命令 nodemon index.js)

2. 获取用户信息进入界面

3. 填写提醒人获取订阅消息权限  

4. 点击发送,成功会返回提示

5. 查看服务器端信息(发送成功)

6. 查看手机或者电脑微信的服务通知

         到这里我们就完成了对服务器端的编写,如果你仅是对服务器端的内容做了解的话到这里就已经结束了,下面是对客户端的一些内容做调整。


客户端接口封装

        可以看一下客户端的请求方式,下面来将其进行一个接口的封装,这里可以结合之前关于封装接口的文章 : 封装小程序request请求[接口函数]

wx.request({
  url: 'http://127.0.0.1:3000/getOpenId',
  method: 'GET',
  data:{
    code:res.code
  },
  success: res=>{
    console.log(res)
    if(res.data.request === 'ok' && res.statusCode === 200){
      wx.request({
        url: 'http://127.0.0.1:3000/sendTempMsg',
        method:'POST',
        data:{
          formInfo : formInfo
        },
        success: res=>{
          if(res.data.request === 'ok'){
            wx.showToast({
              title: '订阅消息发送成功',
              icon: 'success'
            })
          }
        }
      })
    }
  }
})

         下面来对接口进行一个封装,在util目录下创建request.js文件来封装request请求模块,这里暂不对封装内容进行修改,延用之前已经封装过的模块。

// request.js
// 封装数据请求request
const BASE_URL = 'http://127.0.0.1:3000';  // 基础地址

export default function request(url,params={}){
  return new Promise((resolve,reject)=>{
  wx.showLoading({  // 请求提示
    title: '正在加载中...',
  })
  wx.request({
    url: BASE_URL + url,  // 请求url地址
    data: params.data || {},  // 请求参数
    header: params.header || {},  // 请求头
    method: params.method || 'GET', // 请求方式
    dataType: 'json', // 返回数据类型
    success: (res)=> { // 成功调用
      console.log(res)
      wx.hideLoading(); // 关闭请求提示
      resolve(res.data) // 成功处理res.data中的数据
    },
    fail: (err)=> { // 失败调用
      wx.hideLoading(); // 关闭请求提示
      wx.showToast({  // 提示错误信息
        title: err.errMsg || '请求错误!',
      })
      reject(err) // 失败处理err
    }
  })
})
}

        封装完成之后需要来在 util 目录下来创建 wxApi.js 文件来封装各个接口模块:

// wxApi.js
import request from './request'

// 获取OpenId
export const reqOpenId = (code)=> request('/getOpenId',{ data:{code} })
// 发送订阅消息
export const reqSendTempMsg = (formInfo)=> request('/sendTempMsg',{data:{formInfo},method:'POST'})

        在客户端的 index.js 文件中来引入接口并使用:

const {reqOpenId,reqSendTempMsg } = require('../../utils/wxApi')

...
formSubmit(e){
    ...
        // 提交服务器
        reqOpenId(res.code).then((res)=>{
          if(res.request === 'ok'){
            reqSendTempMsg(formInfo).then((res)=>{
              if(res.request === 'ok'){
                wx.showToast({
                  title: '订阅消息发送成功',
                  icon: 'success'
                })
              }
            })
          }
        })
}

        当然这里还可以更简洁一下,那么剩下就留给读者来进行发挥,感谢大家的支持!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/487702.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

吧佬联手抵制奸商,百元级游戏电脑横出江湖

最近小忆闲得在电商平台搜索了下关键词「游戏主机」&#xff0c;不出意外销量榜前列清一色全是「i9 级高端游戏主机」。 这些主机不论配置单介绍还是十万百万级销量宣传标语&#xff0c;都给人一种血赚不亏的「豪华」感。 咱就说时代在变&#xff0c;唯一不变的是奸商们的套路与…

什么样的台灯灯光是好的?推荐中性色温的护眼台灯

台灯的灯光指的是白光和黄光&#xff0c;就是台灯的色温&#xff0c;而色温也是也会影响我们的直观感受的。 低色温&#xff08;>3000K&#xff09;光源偏黄&#xff0c;属于暖色调&#xff0c;适合休息高色温&#xff08;<5000K&#xff09;光源偏白&#xff0c;属于冷…

MWORKS.Sysplorer 2023a前瞻版上线——面向MBD全流程的覆盖

信息物理融合系统&#xff08;CPS&#xff09;的设计、建模与仿真是装备数字化的核心技术。MWORKS.Sysplorer经过多年的发展&#xff0c;已经支持机械、电气、流体、热力学等多个物理域的统一建模和统一仿真求解&#xff0c;解决了物理域统一表达与统一建模问题。为了支持完整的…

嘉立创EDA元件库开发环境及设计介绍

一、元件符号概述 如图1所示&#xff0c;元件符号是元件在原理图中的表现形式&#xff0c;主要由元件边框、管脚&#xff08;包括管脚符号和管脚名称&#xff09;、元件名称及说明组成&#xff0c;通过放置的管脚来建立电气连接关系。元件符号中管脚序号是和电子元件实物的管脚…

Node 11会话控制

会话控制 介绍 所谓会话控制就是 对会话进行控制 HTTP 是一种无状态的协议&#xff0c;它没有办法区分多次的请求是否来自于同一个客户端&#xff0c;无法区分用户 而产品中又大量存在的这样的需求&#xff0c;所以我们需要通过 会话控制 来解决该问题 常见的会话控制技术有…

ChatGPT被淘汰了?Auto-GPT到底有多强

大家好&#xff0c;我是可夫小子&#xff0c;关注AIGC、读书和自媒体。解锁更多ChatGPT、AI绘画玩法。 说Auto-GPT淘汰了ChatGPT了&#xff0c;显然是营销文案里面的标题党。毕竟它还是基于ChatGPT的API&#xff0c;某种意义只是基于ChatGPT能力的应用。但最近&#xff0c;Auto…

大型央企集团财务经营分析框架系列(二)

01集团化的数字化项目为什么会失败深度原因&#xff1a;方向性错误 这几年见过一些央企、国企、大型企业集团尝试过一些数字化的项目&#xff1a;数据中台、大数据分析、BI 分析项目&#xff0c;投入很大、周期也很长&#xff0c;甚至有的在项目开始前也找了专业的咨询公司来规…

按键外部中断

文章目录 运行环境&#xff1a;1.1 按键外部中断1)按键检测2)外部中断的3中触发方式 2.1配置1)原理图2)引脚配置3)中断配置4)RCC和SYS 3.1代码分析3.2添加代码1)中断处理函数IRQ中添加电平转换代码2)launch设置 5.1实验效果 运行环境&#xff1a; ubuntu18.04.melodic 宏基暗影…

如何用ChatGPT做团队绩效管理?根据员工的个人优势、不足、目标来生成更具体的绩效反馈

该场景对应的关键词库&#xff1a;&#xff08;25个&#xff09; 绩效管理、目标设定、绩效评估、员工优势、员工弱点、反馈机制、个人发展计划、职业规划、评估工具、数据分析、绩效考核、评分标准、KPI指标、成果目标、个人任务、团队任务、激励机制、晋升机会、增量奖励、培…

你的个人AI助理Pi来了

还记得之前的文章《不要老盯着ChatGPT&#xff0c;这几家公司的产品同样不容小觑》提到的Inflection AI公司吗&#xff1f;通过其官方推文了解到&#xff0c;前期我们关注的个人AI助理有了新的进展&#xff0c;Pi开始对外发布。 Pi是什么 Pi 是一种 AI&#xff0c;一种旨在提供…

使用crontab定时自动更新DDNS

需求说明&#xff1a; N1盒子的armbian系统配置好了 ipv6 的ddns&#xff0c;实现了域名访问本机&#xff0c;但是本地ipv6可能会发生变化&#xff0c;当发生变化后&#xff0c;需要手动执行指令&#xff0c;将新的ip与域名绑定&#xff0c;现在我们采用定时任务&#xff0c;每…

18 线性表的查找

查找的基本概念 **查找&#xff1a;**在数据集合中寻找满足某种条件数据元素的过程&#xff0c;称之为查找。 查找的结果 分别两种&#xff1a; 查找成功 即在数据集合中找到了满足条件的数据元素。查找结果给出整个记录的信息&#xff0c;或者改记录在查找表中的位置。查找失…

vivo积分任务体系的架构演进-平台产品系列05

作者&#xff1a;vivo 互联网平台产品研发团队- Mu JunFeng 积分体系作为一种常见营销工具&#xff0c;几乎是每一家企业会员营销的必备功能之一&#xff0c;在生活中随处可见&#xff0c;随着vivo互联网业务发展&#xff0c;vivo积分体系的能力也随之得到飞速提升&#xff0c;…

Java字符串的用法、原理、性能分析和总结

本文介绍了Java字符串的创建方式、拼接、比较、查找和替换等常见操作&#xff0c;并解析了Java字符串在内存中的存储方式及常量池的作用。文章还提到了Java字符串的性能问题&#xff0c;建议在进行大量的字符串操作时&#xff0c;应该尽量避免使用""号操作符和concat…

【模拟IC学习笔记】 Widlar电流源

原理分析 M3、M4工作在饱和区&#xff0c;M1、M2可以工作在饱和区也可以工作在亚阈值区。 两边电流相等&#xff0c;M3、M4尺寸相等&#xff0c;Vgs2&#xff1c;Vgs1&#xff0c;所以M2的尺寸应该比M1的尺寸大才能保证两边电流相等。K为M2和M1的尺寸比。 当M1和M2工作在饱和…

springboot集成Validated实现参数检验,分组校验,嵌套检验等

一&#xff0c;开发前工作 引入依赖 <dependency> <!--新版框架没有自动引入需要手动引入--><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId> </dependency> 二&#xff0c…

spring之ioc初见

maven创建 mvn archetype:generate # 选择7&#xff0c;创建快速启动项目然后idea打开即可 idea创建 点击创建 使用IOC pom.xml添加依赖 <dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><…

pytorch实战9:基于pytorch简单实现u-net

基于pytorch简单实现u-net 前言 ​ 最近在看经典的卷积网络架构&#xff0c;打算自己尝试复现一下&#xff0c;在此系列文章中&#xff0c;会参考很多文章&#xff0c;有些已经忘记了出处&#xff0c;所以就不贴链接了&#xff0c;希望大家理解。 ​ 完整的代码在最后。 本系列…

组件等比例放大——scale和zoom

scale和zoom的区别 zoom的缩放是相对于左上角的&#xff1b;而scale默认是居中缩放&#xff0c;可以通过transform-origin修改基准点zoom的缩放改变了元素占据的空间大小&#xff1b;而scale的缩放占据的原始尺寸不变&#xff0c;页面布局不会发生变化。对文字的缩放规则不一致…

K8s基础2——部署单Master节点K8s集群、切换containerd容器运行时、基本命令

文章目录 一、部署K8S集群方式二、kubeadm工具搭建K8s集群2.1 资源配置2.2 服务器规划2.3 搭建流程2.3.1 操作系统初始化2.3.2 安装docker容器引擎2.3.3 安装cri-dockerd2.3.4 安装kubeadm&#xff0c;kubelet和kubectl2.3.5 master节点初始化2.3.6 加入node节点2.3.7 部署网络…