由于步骤太多,字数太多,废话也太多,所以前后端分开讲了,后端文章请看:

超详细 anji-captcha滑块验证springboot+uniapp微信小程序前后端组合https://blog.csdn.net/new_public/article/details/149116742


anji-captcha开源项目地址:https://github.com/anji-plus/captcha

anji-captcha开源文档地址:在线体验暂时下线 !!! | AJ-Captcha


写完后端代码,开始写前端,首选肯定又是一顿各种网上查资料搬砖,发现基本清一色用了anji-captcha开源文档介绍的【Verify】组件,这组件是anji-captcha开源项目里面有的,在view文件夹下面,选择自己对应的前端类型,里面有下面几种类型。

比如:/view/vue/src/components/verifition/Verify 


 不过我没去看,是自己写了一个,毕竟只有自己写的才是最适合自己的。


效果如下:


每次滑动有广告语出现,比如视频里的,【大怨种】【纯牛马】。

获取次数和验证次数超限,会显示提示等。


组件代码

<template><modal ref="$captchaModal" :width="modalWidth" :padding="modalPadding"><template #body><view class="captcha-modal-content" :style="{ height: 'calc(' + slideImageHeight + 'px + ' + slideBlockWidth + 'px + 12rpx)' }"><template v-if="sliderCaptchaBackBase64"><image class="captcha-back-image":style="{ width: slideImageWidth + 'px', height: slideImageHeight + 'px' }":src="sliderCaptchaBackBase64" /><image class="captcha-slider-image" :src="sliderCaptchaBlockBase64":style="{ width: slideBlockWidth + 'px', height: slideImageHeight + 'px', transform: 'translate3d(' + lastLeft + 'px,0,0)' }" /></template><image v-else src="/static/images/svg/null_data.svg" class="captcha-back-image" style="height: 300rpx;"/><view class="slide-parent" :style="{ width: slideImageWidth + 'px', height: slideBlockWidth + 'px',backgroundColor: sliderCaptchaBackBase64 ? 'rgb(233, 233, 233)' : 'transparent' }"><template  v-if="sliderCaptchaBackBase64"><view class="slide-tip tui-text-flashover">拖动滑块验证</view><view class="slide-cover" :style="{ width: lastLeft + 'px' }"><view class="slide-cover-content" :style="{ width: slideImageWidth + 'px' }">{{ slideCoverText }}</view></view><view class="slide-view" :style="{ width: slideBlockWidth + 'px', height: slideBlockWidth + 'px', transform: 'translate3d(' + lastLeft + 'px,0,0)' }"@touchstart="touchstart" @touchmove="touchmove" @touchend="touchend"><tui-icon name="up" :size="19" style="transform: rotate(90deg);" /></view></template><view v-else class="tui-flex-center" style="height: 100%;":class="{ 'tui-underline': captChaGetRepCode !== '6201' }"@click="delayedGenerateSlideCaptchaImage">{{ errorMsg }}</view></view></view></template></modal>
</template>
<script>// 这里用到util是防抖动方法和四舍五入方法,自己写一个吧,或者问api给一个import util from '@/utils/util'// npm i crypto-js -s 引入,这里用的是4.2.0版本import CryptoJS from 'crypto-js/crypto-js'export default {data () {return {// 滑块宽高度 pxslideBlockWidth: 47,// 背景图宽度 pxslideImageWidth: 310,// 背景图高度 pxslideImageHeight: 155,// 弹窗占据屏幕 90%modalWidth: 90,// 弹窗内部左右边距20pxmodalLRpadding: 20,// 缩放比率,不同屏幕的手机,必须适配scaleRatio: 0,// 滑动起始X位置 pxstartX: 0,// 滑动停止位置,也就是距离起始位置长度 pxlastLeft: 0,// 后端返回的验证码参数captchaOption: {},// 父页面参数parentOption: {},// 获取滑块验证码返回的结果码,用来显示错误信息的captChaGetRepCode: void (0),// 广告语,每次随机取slideCoverTextList: ['大怨种', '纯牛马', '肝吧', '挤上牛马传送带', '这就是命啊']}},created () {// 初始化背景图和滑块缩放this.handlerCaptchaScale()// 手动获取滑块验证码的方法,加上防抖动,350毫秒this.delayedGenerateSlideCaptchaImage = util.debounce(this.delayedGenerateSlideCaptchaImage, 350)},computed: {modalPadding () {return `40rpx ${this.modalLRpadding}px 20rpx ${this.modalLRpadding}px`},// 广告语,随机取,为了能随机,故跟startX绑定上了slideCoverText () {const initIndex = Math.floor(Math.random() * this.slideCoverTextList.length)const startXStr = String(this.startX)const finalIndex = initIndex + (startXStr.length > 1 ? Number(startXStr.substring(startXStr.length - 1)) : this.startX)return this.slideCoverTextList[finalIndex > this.slideCoverTextList.length - 1 ? initIndex : finalIndex]},// 背景图base64sliderCaptchaBackBase64 () {const { originalImageBase64 } = this.captchaOptionif (!originalImageBase64) {return ''}return 'data:image/png;base64,' + originalImageBase64},// 滑块base64sliderCaptchaBlockBase64 () {const { jigsawImageBase64 } = this.captchaOptionif (!jigsawImageBase64) {return ''}return 'data:image/png;base64,' + jigsawImageBase64},errorMsg () {if (this.captChaGetRepCode === '6201') {return '获取图形验证码频繁,请稍后再试'} else if (this.captChaGetRepCode !== '0000') {return '啊哦,加载失败了,点击这里刷新'}return ''}},methods: {// 显示滑块验证码弹窗,父页面通过ref通用show (option = {}) {this.resetSlideCaptcha()this.parentOption = optionthis.generateSlideCaptchaImage().then(_ => {this.$nextTick(() => {// 调用弹窗组件方法,显示弹窗this.$refs.$captchaModal.show({title: option.title || '验证',maxHeight: 800,hideCancel: true,confirmText: '关闭',// 弹窗关闭按钮点击回调callback: _ => {// 如果父页面有关闭回调,则这里调用this.parentOption.closeCallback && this.parentOption.closeCallback()}})})})},close () {this.resetSlideCaptcha()// 关闭弹窗this.$refs.$captchaModal.onClose()},// 初始化缩放比率,以及设置滑块背景和滑块宽高handlerCaptchaScale () {const { windowWidth } = uni.getSystemInfoSync()const modalWidthPx = windowWidth * (this.modalWidth / 100)const modalLRpaddingSum = this.modalLRpadding * 2const modalInternalWidth = modalWidthPx - modalLRpaddingSumconst onePercentagePx = windowWidth * 0.01if (modalInternalWidth > this.slideImageWidth) {// 如果屏幕宽度大于初始化滑块背景图宽度,则不缩放this.modalWidth = util.toFixed((this.slideImageWidth + modalLRpaddingSum) / onePercentagePx, 2)} else if (modalInternalWidth < this.slideImageWidth) {// 否则缩放滑块背景图和滑块this.scaleRatio = modalInternalWidth / this.slideImageWidththis.slideImageWidth = modalInternalWidththis.slideImageHeight = this.slideImageHeight * this.scaleRatiothis.slideBlockWidth = this.slideBlockWidth * this.scaleRatio}},// 手动重新获取delayedGenerateSlideCaptchaImage () {if (this.captChaGetRepCode === '6201') {return}this.generateSlideCaptchaImage()},// 获取滑块验证码generateSlideCaptchaImage () {return new Promise((resolve, reject) => {// request 基于uni.request封装,总之就是调获取验证码接口request('/captcha/get', 'POST', { 'captchaType' : 'blockPuzzle' }, true).then(({ repData = {}, repCode }) => {this.captChaGetRepCode = repCodethis.captchaOption = repData}).finally(() => {resolve()})})},// 按中滑块,记录起始位置touchstart (e) {const touch = e.touches[0] || e.changedTouches[0]this.startX = touch.clientX},// 开始滑动,计算当前滑动位置touchmove (e) {const touch = e.touches[0] || e.changedTouches[0]const pageX = touch.clientXconst width = this.slideImageWidth - this.slideBlockWidth - 1let left = pageX - this.startXleft = left < 0 ? 0 : (left >= width ? width : left)this.lastLeft = left},// 滑动结束(松手),验证touchend () {/*** callback 父页面验证结果回调* verifyCaptchaCallback 整个验证由父页面处理* verifyApi 验证后端接口* * callback 和 verifyCaptchaCallback 二选一* 选callback,verifyApi必传,让这个这个组件调用验证接口*/const { callback, verifyCaptchaCallback, verifyApi } = this.parentOptionif (callback || verifyCaptchaCallback) {if (verifyCaptchaCallback) {verifyCaptchaCallback(this.captchaOption).then(flag => {if (flag) {this.close()} else {this.resetSlideCaptcha(true)}})} else {this.verifyCaptcha(verifyApi).then(res => {if (res) {// 验证成功,记录本次验证码的aes密匙,给后面后端二次验证使用res.secretKey = this.captchaOption.secretKeythis.close()} else {// 验证失败重新获取this.resetSlideCaptcha(true)}callback(res)})}} else {this.resetSlideCaptcha(true)}},// 重置resetSlideCaptcha (generateFlag) {this.lastLeft = 0this.startX = 0generateFlag && this.generateSlideCaptchaImage()},// 验证滑动是否正确verifyCaptcha (verifyApi) {return new Promise((resolve, reject) => {const originalPointJson = this.generatePointJson()const param = {captchaType: 'blockPuzzle',token: this.captchaOption.token,pointJson: this.pointEncrypted(originalPointJson)}// request 基于uni.request封装,总之就是调验证接口request(verifyApi || '/captcha/check', 'POST', param, true).then(res => {const { repCode, repData = {}, repMsg } = resif (repCode === '0000' && repData.result) {resolve({ ...repData, originalPointJson })} else {// toast 等同 uni.showToast()toast(repMsg || '验证失败')resolve(false)}}).catch(_ => {resolve(false)})})},// 生成当前滑动完成的坐标点,加密的原文generatePointJson () {const x = this.scaleRatio > 0 ? ((this.lastLeft - 1) / this.scaleRatio) : this.lastLeft - 1return JSON.stringify({x,y:0})},// aes加密坐标点pointEncrypted (originalPointJson) {const key = CryptoJS.enc.Utf8.parse(this.captchaOption.secretKey)const encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(originalPointJson),key,{mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7})return encrypted.toString()},// 生成后端二次验证的密文captchaVerificationEncrypted ({ originalPointJson, token, secretKey }) {const key = CryptoJS.enc.Utf8.parse(secretKey)const dataToEncrypt = token + '---' + originalPointJsonconst encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(dataToEncrypt),key,{mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7})return encrypted.toString()}}}
</script>
<style scoped lang="scss">.captcha-modal-content {position: relative;.captcha-back-image {width: 100%;border-radius: 10rpx;}.captcha-slider-image {position: absolute;left: 0;top: 0;z-index: 1;}.slide-parent {width: 100%;background-color: rgb(233, 233, 233);position: relative;padding: 1px 0;.slide-tip {position: absolute;top: 0;left: 0;right: 0;bottom: 0;color: #616161;font-size: 30rpx;display: flex;align-items: center;justify-content: center;}.slide-cover {width: 0;height: 100%;position: absolute;left: 0;top: 0;z-index: 1;display: flex;align-items: center;justify-content: center;overflow: hidden;.slide-cover-content {height: 100%;color: #FFF;background-color: #0081ff;font-size: 30rpx;display: flex;align-items: center;justify-content: center;position: absolute;left: 0;top: 0;}}.slide-view {position: absolute;left: 1px;z-index: 2;background: #FFF;display: flex;align-items: center;justify-content: center;}}}.tui-text-flashover {background: -webkit-gradient(linear, left top, right top, color-stop(0, #444), color-stop(.4, #444), color-stop(.5, white), color-stop(.6, #444), color-stop(1, #444));-webkit-background-clip: text !important;-webkit-text-fill-color: transparent !important;-webkit-animation: animate 1.8s infinite;}.tui-flex-center {display: flex;align-items: center;justify-content: center;}.tui-underline {text-decoration: underline;}@-webkit-keyframes animate {from {background-position: -90rpx;}to {background-position: 90rpx;}}@keyframes animate {from {background-position: -90rpx;}to {background-position: 90rpx;}}
</style>

注意:组件代码不可直接复制使用,里面使用了一些我项目的封装代码(下面这些)。

  • toast方法,是输出提示。
  • request方法,是调后端接口。
  • <modal>是我封装的一个弹窗组件,弹窗组件UI库大把,自己套一个。参数width是百分比,我的modal组件接收的是Number,所以这里初始90,代表占屏幕90%宽度。然后再根据屏幕大小决定弹窗大小的。
  • 两个import上面有注释说明。

最好看一遍代码的里面的注释,上面说的几个地方需要自己改一下


使用流程

功能引入此组件并定义ref,通过ref调用组件的show方法即可,传入参数,例如:

this.$refs.$sliderCaptcha.show({// 验证接口verifyApi: '/xxx/yyy',callback: res => {if (res) {// 验证成功,生成后端二次验证密文(也就是二次验证的redisKey)(不是必须,看自己业务,如有需要的话)const captchaVerification = this.$refs.$sliderCaptcha.captchaVerificationEncrypted(res)}}
})

其他罗里吧嗦

1:滑块滑动到缺口后,取哪里的x值?

正确缺口的开始位置,这个开始位置x值是正确的,对应后端缓存,基本大差不差。

2:怎么取?

触摸滑块时,touchstart方法记录触摸位置,滑动触发touchmove方法,获取当前滑动x值,然后减去起始触摸位置,就是正确的x值。


代码里面那个null_data.svg

我直接把源码粘贴出来,复制到文本文件里面,然后后缀改成svg就可以用了

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="122px" height="104px" viewBox="0 0 122 104" version="1.1"><!-- Generator: Sketch 55 (78076) - https://sketchapp.com --><title>暂无相关搜索</title><desc>Created with Sketch.</desc><g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g id="空白页" transform="translate(-40.000000, -508.000000)"><g id="暂无相关搜索" transform="translate(40.000000, 508.000000)"><g id="分组"><g id="背景/线" fill="#C3CBD6"><g id="-"><g id="编组" transform="translate(14.200000, 9.200000)" fill-rule="nonzero"><path d="M0.8,73.1 C0.3581722,73.1 -5.68434189e-14,72.7418278 -5.68434189e-14,72.3 C-5.68434189e-14,71.8581722 0.3581722,71.5 0.8,71.5 L70.8,71.5 C71.2418278,71.5 71.6,71.8581722 71.6,72.3 C71.6,72.7418278 71.2418278,73.1 70.8,73.1 L0.8,73.1 Z M74.8,73.1 C74.3581722,73.1 74,72.7418278 74,72.3 C74,71.8581722 74.3581722,71.5 74.8,71.5 L77.3,71.5 C77.7418278,71.5 78.1,71.8581722 78.1,72.3 C78.1,72.7418278 77.7418278,73.1 77.3,73.1 L74.8,73.1 Z M83.8,73.1 C83.3581722,73.1 83,72.7418278 83,72.3 C83,71.8581722 83.3581722,71.5 83.8,71.5 L92.8,71.5 C93.2418278,71.5 93.6,71.8581722 93.6,72.3 C93.6,72.7418278 93.2418278,73.1 92.8,73.1 L83.8,73.1 Z M23.8,80.6 C23.3581722,80.6 23,80.2418278 23,79.8 C23,79.3581722 23.3581722,79 23.8,79 L30.8,79 C31.2418278,79 31.6,79.3581722 31.6,79.8 C31.6,80.2418278 31.2418278,80.6 30.8,80.6 L23.8,80.6 Z M35.3,80.6 C34.8581722,80.6 34.5,80.2418278 34.5,79.8 C34.5,79.3581722 34.8581722,79 35.3,79 L65.8,79 C66.2418278,79 66.6,79.3581722 66.6,79.8 C66.6,80.2418278 66.2418278,80.6 65.8,80.6 L35.3,80.6 Z M80,52.8 C80,51.7333333 81.6,51.7333333 81.6,52.8 L81.6,55.8 C81.6,56.2418278 81.2418278,56.6 80.8,56.6 L77.8,56.6 C76.7333333,56.6 76.7333333,55 77.8,55 L80,55 L80,52.8 Z M81.6,58.8 C81.6,59.8666667 80,59.8666667 80,58.8 L80,55.8 C80,55.3581722 80.3581722,55 80.8,55 L83.8,55 C84.8666667,55 84.8666667,56.6 83.8,56.6 L81.6,56.6 L81.6,58.8 Z M4,28.8 C4,27.7333333 5.6,27.7333333 5.6,28.8 L5.6,31.8 C5.6,32.2418278 5.2418278,32.6 4.8,32.6 L1.8,32.6 C0.733333333,32.6 0.733333333,31 1.8,31 L4,31 L4,28.8 Z M78.1,3.5 L80.8,3.5 C81.8666667,3.5 81.8666667,5.1 80.8,5.1 L78.1,5.1 L78.1,7.8 C78.1,8.86666667 76.5,8.86666667 76.5,7.8 L76.5,5.1 L73.8,5.1 C72.7333333,5.1 72.7333333,3.5 73.8,3.5 L76.5,3.5 L76.5,0.8 C76.5,-0.266666667 78.1,-0.266666667 78.1,0.8 L78.1,3.5 Z M5.6,34.8 C5.6,35.8666667 4,35.8666667 4,34.8 L4,31.8 C4,31.3581722 4.3581722,31 4.8,31 L7.8,31 C8.86666667,31 8.86666667,32.6 7.8,32.6 L5.6,32.6 L5.6,34.8 Z" id="Path-2"></path><path d="M14.0928932,61.1431458 C14.5642977,60.6717412 15.2714045,61.378848 14.8,61.8502525 L13.7393398,62.9109127 C13.5440777,63.1061748 13.2274952,63.1061748 13.032233,62.9109127 L11.9715729,61.8502525 C11.5001684,61.378848 12.2072751,60.6717412 12.6786797,61.1431458 L13.3857864,61.8502525 L14.0928932,61.1431458 Z M12.6786797,63.9715729 C12.2072751,64.4429774 11.5001684,63.7358706 11.9715729,63.2644661 L13.032233,62.2038059 C13.2274952,62.0085438 13.5440777,62.0085438 13.7393398,62.2038059 L14.8,63.2644661 C15.2714045,63.7358706 14.5642977,64.4429774 14.0928932,63.9715729 L13.3857864,63.2644661 L12.6786797,63.9715729 Z M22.9213203,8.8 C23.3927249,8.32859548 24.0998316,9.03570226 23.6284271,9.50710678 L22.567767,10.567767 C22.3725048,10.7630291 22.0559223,10.7630291 21.8606602,10.567767 L20.8,9.50710678 C20.3285955,9.03570226 21.0357023,8.32859548 21.5071068,8.8 L22.2142136,9.50710678 L22.9213203,8.8 Z M21.5071068,11.6284271 C21.0357023,12.0998316 20.3285955,11.3927249 20.8,10.9213203 L21.8606602,9.86066017 C22.0559223,9.66539803 22.3725048,9.66539803 22.567767,9.86066017 L23.6284271,10.9213203 C24.0998316,11.3927249 23.3927249,12.0998316 22.9213203,11.6284271 L22.2142136,10.9213203 L21.5071068,11.6284271 Z" id="Path复制"></path></g></g></g><g id="Group-6" transform="translate(37.000000, 29.000000)"><g id="分组" stroke="#C3CBD6"><path d="M3,-1.0658141e-14 L35,-1.0658141e-14 C36.6568542,-1.09625002e-14 38,1.34314575 38,3 L38,42 C38,43.6568542 36.6568542,45 35,45 L3,45 C1.34314575,45 2.02906125e-16,43.6568542 0,42 L0,3 C-2.02906125e-16,1.34314575 1.34314575,-1.03537818e-14 3,-1.0658141e-14 Z" id="矩形" stroke-width="1.6" fill="#FFFFFF"></path><path d="M7.8,26.8 L12.8,26.8 L7.8,26.8 Z M7.8,19.8 L11.8,19.8 L7.8,19.8 Z M7.8,12.8 L13.8,12.8 L7.8,12.8 Z" id="Stroke-16" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"></path></g><g id="分组-2" transform="translate(15.000000, 4.000000)"><path d="M26.8450231,25.0101574 L32.8450231,25.0101574 L32.8370236,35.9124666 C32.8358076,37.5696764 31.4920325,38.9124658 29.8348223,38.9124658 L29.8348223,38.9124658 C28.1791833,38.9124658 26.8370228,37.5703052 26.8370228,35.9146662 C26.8370228,35.913933 26.837023,35.9131998 26.8370236,35.9124666 L26.8450231,25.0101574 Z" id="矩形" stroke="#C3CBD6" stroke-width="1.6" fill="#F5F7F9" transform="translate(29.839923, 31.961312) rotate(-42.000000) translate(-29.839923, -31.961312) "></path><circle id="椭圆形" stroke="#C3CBD6" stroke-width="1.6" fill="#F5F7F9" cx="16.5" cy="16.5" r="16.5"></circle><circle id="椭圆形-copy" stroke="#C3CBD6" stroke-width="1.6" fill="#FFFFFF" cx="16.5" cy="16.5" r="12.5"></circle><path d="M17.6131592,19.685 C17.3091168,19.7925464 15.7049189,19.8010303 15.4349189,19.685 C15.1649189,19.5689697 15.1349189,19.43 15.1349189,18.995 C15.1349189,17.96 15.3149189,17.36 15.7949189,16.775 C16.1549189,16.355 16.2749189,16.265 17.3399189,15.62 C18.0749189,15.185 18.3149189,14.87 18.3149189,14.375 C18.3149189,13.67 17.7899189,13.25 16.8899189,13.25 C16.2149189,13.25 15.7199189,13.49 15.4349189,13.955 C15.2849189,14.195 15.1949189,14.2841284 15.1649189,14.87 C15.1349189,15.4558716 11.9819336,15.62 12.0749189,14.585 C12.1679042,13.55 12.4649189,12.92 13.0349189,12.29 C13.9049189,11.3 15.2399189,10.79 16.9649189,10.79 C19.7249189,10.79 21.4499189,12.095 21.4499189,14.165 C21.4499189,15.08 21.1499189,15.785 20.5199189,16.37 C20.1599189,16.7 20.0099189,16.805 18.7049189,17.615 C18.0749189,18.02 17.8499189,18.41 17.8499189,19.1 C17.8499189,19.28 17.9172016,19.5774536 17.6131592,19.685 Z M16.4174189,20.705 L16.5974189,20.705 C17.3802825,20.705 18.0149189,21.3396364 18.0149189,22.1225 L18.0149189,22.1225 C18.0149189,22.9053636 17.3802825,23.54 16.5974189,23.54 L16.4174189,23.54 C15.6345553,23.54 14.9999189,22.9053636 14.9999189,22.1225 L14.9999189,22.1225 C14.9999189,21.3396364 15.6345553,20.705 16.4174189,20.705 Z" id="?" fill="#C3CBD6" fill-rule="nonzero"></path></g></g></g></g></g></g>
</svg>


码字不易,于你有利,勿忘点赞

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

面向对象编程篇

文章目录一、思维导图二、详细内容第 6 章&#xff1a;面向对象编程基础6.1 面向对象编程的概念和优势6.2 类和对象的定义与创建6.3 类的属性和方法6.4 构造函数&#xff08;__init__&#xff09;和析构函数&#xff08;__del__&#xff09;6.5 封装、继承和多态的实现第 7 章&…

虚拟商品自动化实践:闲鱼订单防漏发与模板化管理的技术解析

最近阿灿发现了一款闲鱼虚拟商品卖家必备神器&#xff01;告别手动发货&#xff0c;订单自动处理&#xff0c;防错防漏&#xff0c;支持课程、激活码、电子书等多种商品&#xff0c;预设模板更省心。文末获取工具&#xff01;最厉害的是&#xff0c;你完全不用一直开着电脑。以…

【Zephyr开发实践系列】08_NVS文件系统调试记录

文章目录前言一、NVS原理介绍&#xff1a;二、BUG-NO1&#xff1a;将NVS运用在NAND-Flash类大容量存储设备2.1 情况描述&#xff1a;2.2 BUG复现&#xff1a;文件系统设备树构建测试应用编写&#xff08;导致错误部分&#xff09;&#xff1a;问题呈现&#xff1a;2.3 问题简述…

网络安全第二次作业

靶场闯关1~8 1. 在url后的name后输入payload ?name<script>alert(1)</script> 2. 尝试在框中输入上一关的payload,发现并没有通过&#xff0c;此时我们可以点开页面的源代码看看我们输入的值被送到什么地方去了 从图中可以看到&#xff0c;我们输入的值被送到i…

LangChain 源码剖析(七)RunnableBindingBase 深度剖析:给 Runnable“穿衣服“ 的装饰器架构

每一篇文章都短小精悍&#xff0c;不啰嗦。一、功能定位&#xff1a;Runnable 的 "增强包装器"RunnableBindingBase 是 LangChain 中实现装饰器模式的核心组件。它就像给原有 Runnable 套上一件 "功能外套"—— 不改变原有 Runnable 的核心逻辑&#xff0c…

为 Git branch 命令添加描述功能

写在最前面的使用方式 查看 所有分支的备注 git branch.notes创建分支并为分支添加备注 git co -b feat/oauth -m 第三方用户登录对分支描述的添加与清除 添加 git branch.note --add 清除 git branch.note --clear &#x1f4dd; 为 Git branch 命令添加描述功能 &#x…

LeetCode|Day18|20. 有效的括号|Python刷题笔记

LeetCode&#xff5c;Day18&#xff5c;20. 有效的括号&#xff5c;Python刷题笔记 &#x1f5d3;️ 本文属于【LeetCode 简单题百日计划】系列 &#x1f449; 点击查看系列总目录 >> &#x1f4cc; 题目简介 题号&#xff1a;20. 有效的括号 难度&#xff1a;简单 题目…

使⽤Pytorch构建⼀个神经⽹络

关于torch.nn:使⽤Pytorch来构建神经⽹络, 主要的⼯具都在torch.nn包中.nn依赖于autograd来定义模型, 并对其⾃动求导.构建神经⽹络的典型流程:定义⼀个拥有可学习参数的神经⽹络遍历训练数据集处理输⼊数据使其流经神经⽹络计算损失值将⽹络参数的梯度进⾏反向传播以⼀定的规则…

网络爬虫的详细知识点

基本介绍 什么是网络爬虫 网络爬虫&#xff08;Web Crawler&#xff09;是一种自动化程序&#xff0c;用于从互联网上抓取、解析和存储网页数据。其核心功能是模拟人类浏览行为&#xff0c;通过HTTP/HTTPS协议访问目标网站&#xff0c;提取文本、链接、图片或其他结构化信息&…

AndroidX中ComponentActivity与原生 Activity 的区别

一、AndroidX 与原生 Activity 的区别 1. 概念与背景 原生 Activity&#xff1a;指 Android 早期&#xff08;API 1 起&#xff09;就存在于 android.app 包下的 Activity 类&#xff08;如 android.app.Activity&#xff09;&#xff0c;是 Android 最初的 Activity 实现&…

Spring AI 使用 Elasticsearch 作为向量数据库

前言 嗨&#xff0c;大家好&#xff0c;我是雪荷&#xff0c;最近在公司开发 AI 知识库&#xff0c;同时学到了一些 AI 开发相关的技术&#xff0c;这期先与大家分享一下如何用 ES 当做向量数据库。 安装ES 第一步我们先安装 Elasticsearch&#xff0c;这里建议 Elasticsear…

TypeScript 配置全解析:tsconfig.json、tsconfig.app.json 与 tsconfig.node.json 的深度指南

前言在现代前端和后端开发中&#xff0c;TypeScript 已经成为许多开发者的首选语言。然而&#xff0c;TypeScript 的配置文件&#xff08;特别是多个配置文件协同工作时&#xff09;常常让开发者感到困惑。本文将深入探讨 tsconfig.json、tsconfig.app.json 和 tsconfig.node.j…

读书笔记(学会说话)

1、一个人只有会说话&#xff0c;才会有好人缘&#xff0c;做事才会顺利。会说话的人容易成功。善于说话的人易成功&#xff0c;而不善说话的人往往寸步难行。我们要把话说得好听&#xff0c;同时更要把事做得漂亮。或许一句话&#xff0c;一件事&#xff0c;就可能使人生的旅途…

私有服务器AI智能体搭建-大模型选择优缺点、扩展性、可开发

以下是主流 AI 框架与模型的对比分析&#xff0c;涵盖其优缺点、扩展性、可开发性等方面。 文章目录一、AI 框架对比二、主流大模型对比三、扩展性对比总结四、可开发性对比总结五、选择建议&#xff08;按场景&#xff09;六、未来趋势一、AI 框架对比 框架优点缺点扩展性可开…

OpenCV直线段检测算法类cv::line_descriptor::LSDDetector

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 该类用于实现 LSD (Line Segment Detector) 直线段检测算法。LSD 是一种快速、准确的直线检测方法&#xff0c;能够在不依赖边缘检测的前提下直接从…

Go语言流程控制(if / for)

分支结构package mainimport ("fmt""strconv" )/* 1.顺序结构 2.分支结构 3.循环结构 *//* if 条件1 {// 条件1为真时执行的代码 } else if 条件2 {// 条件1为假但条件2为真时执行的代码 } else {// 所有条件均为假时执行的代码 }一种特殊的条件分支结构if…

wx小程序设置沉浸式导航文字高度问题

第一步&#xff1a;在app.json中设置"navigationStyle": "custom"第二步骤&#xff1a;文件的home.js中// pages/test/test.js Page({/*** 页面的初始数据*/data: {statusBarHeight: 0,navBarHeight: 44 // 自定义导航内容区高度(单位px)},/*** 生命周期函…

C++算法竞赛篇:DevC++ 如何进行debug调试

C算法竞赛篇&#xff1a;DevC 如何进行debug调试前言一、准备工作&#xff1a;编译生成可执行程序二、核心步骤&#xff1a;设置断点与启动调试1. 设置断点2. 启动调试模式三、调试操作&#xff1a;逐步执行与变量监控1. 逐步执行代码2. 监控变量值变化四、调试结束前言 在算法…

语音大模型速览(三)- cosyvoice2

CosyVoice 2: Scalable Streaming Speech Synthesis with Large Language Models 论文链接&#xff1a;https://arxiv.org/pdf/2412.10117代码链接&#xff1a;https://github.com/FunAudioLLM/CosyVoice 一句话总结 CosyVoice 2 是一款改进的流式语音合成模型&#xff0c;其…

-lstdc++与-static-libstdc++的用法和差异

CMakeLists.txt 里写了&#xff1a; target_link_libraries(${PROJECT_NAME} PRIVATEgccstdc ) target_link_options(${PROJECT_NAME} PRIVATE -static-libstdc)看起来像是“链接了两次 C 标准库”&#xff0c;其实它们的作用完全不同&#xff1a;1. target_link_libraries(...…