微信小程序云开发订单微信支付与小票和标签打印的完整高效流程

news2024/12/25 9:32:30

一个字“全”!!!

  • 前言
  • 一、流程设定
    • 1、如何开通云支付流程
    • 2、以订单下单为例的支付流程
      • 2.1 业务场景介绍
      • 2.2 业务场景流程图
  • 二、代码与代码文件组成
    • 1、页面JS
    • 2、云函数payPre
    • 3、支付回调函数pay_cb
      • 3.1 准备条件
      • 3.2 必要认知
      • 3.3 pay_cb 完整函数如下
    • 4、标签打印函数
    • 5、小票打印函数
  • 三、回调函数常见问题
    • 1、提高云开发数据库订单更新与查询效率
    • 2、避免阻塞与防止回调函数一直回调
  • 五、参考文档

前言

本片文章全文12000字,细致讲述从申请账户到小程序注册到打印机的选型最后到实现微信小程序云开发订单支付更新与小票,标签打印完整的高效流程。

一、流程设定

1、如何开通云支付流程

无论是云支付还是其他平台语言的原生支付接入都有共同一点:非个人,是组织,企
业,个体商家[1],说白了就是有合理合法经营的营业执照,具体可参考[1]。

1.1 开通商户,获取商户号,商户号获取指引文档[2]

1.2 注册微信小程序,微信小程序注册要是“组织,企业,个体商家”,并且主体要与注册
商户号的主体保持一致。注册完成后等待认证完成即可进入微信公众平台[3]

微信公众平台

1.3 进入微信小程序开发者平台后填写相关的资料并进行类目确定。再次有一次非常需要注意的事项。

注意:根据交易类小程序运营规范,对于小程序内提供珠宝玉石、3C 数码、盲盒、服饰内衣、海淘、美妆、酒类、家用电器、玩具、箱包皮具、鞋靴、运动户外等商品在线销售及配送服务时,不可使用云调用支付能力。

1.4 对接商户号,进行JASP支付相关确认,接入准备文档[4]

注意:微信小程序云开发支付是一种免鉴权,免密钥配置的安全的支付方式,所以不
需要配置相关的密钥,直接进行到下一步1.5

云函数支付的官网流程图

1.5 云开发控制台确认

此处请参考微信开发者文档[5],文档内容详细。

2、以订单下单为例的支付流程

2.1 业务场景介绍

客户A在我们的点餐平台上点了一杯咖啡,所以客户要在选好后付款,在付款完成后商家的小票打印机和标签打印机打印出本订单的相关信息。如下:图2.1为小票打印机,图2.2为标签打印机。

小票打印机
图2.1 小票打印机
在这里插入图片描述
图2.2 标签打印机

2.2 业务场景流程图

在这里插入图片描述

二、代码与代码文件组成

1、页面JS

作用:发起支付请求与回调后续相关逻辑操作,例如:返回上一级,或跳转到相关页面。

wx.cloud.database().collection('orderUser').add({
   data:{
         subTime:this.getDateandTime().time,/* 下单时间 */
         subDate:this.getDateandTime().date,/* 下单日期 */
         orderCode:hexiaoCode,//核销码
         orderRows:[this.data.rows],
         orderGroups:tempInfo,//点单详情
         status:'制作中', // 出餐情况
         style:"点餐", //用餐方式
         pre_title:'**** 微信支付点单',
         pay_status:'wait', //交易状态
         orderNumber:orderTemp, //交意单号
         order_price:this.data.priceAll, //价格
		 userName:wx.getStorageSync('userInfo').userName,
         phone:wx.getStorageSync('userInfo').phone,
         orderRemarks:this.data.orderRemarks
         },success:(event)=>{
           //支付接口
           /* 价格处理 */
           var price = parseFloat(this.data.priceAll)
           // 订单处理
           wx.cloud.callFunction({
              name:'payPre',
              data:{
                  pro_name:'***店自取订单',
                  pro_codeNum:orderTemp,
                  pro_price:price*100,
               },success:(res_3)=>{
                   wx.hideLoading()
                   console.log("支付接口",res_3);
                  // 调起支付
                  wx.requestPayment({
                       timeStamp: res_3.result.payment.timeStamp,
                       nonceStr: res_3.result.payment.nonceStr,
                       package: res_3.result.payment.package,
                       signType: 'MD5',//加密方式
                       paySign: res_3.result.payment.paySign,
                       success (res_4) {
                             //这里写付款完成后的逻辑函数
                       },fail (res_4) {
                             console.log('发起支付窗口失败');
                       }
                  })
                  },fail(res_3){
                      console.log('调用payPre失败:',res_3);
                  }
            })
       },fail:(res)=>{
            console.log("创建订单出错误",res);
         }
 })

2、云函数payPre

作用调用云函数支付接口与返回支付的信息

// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init({ env: '' }) // 使用当前云环境
// 云函数入口函数
exports.main = async (event, context) => {
    const res = await cloud.cloudPay.unifiedOrder({
        "body" :event.pro_name, // 订单名称
        "outTradeNo" :event.pro_codeNum, // 订单号
        "spbillCreateIp" : "127.0.0.1",
        "subMchId" : "*****", //商户号ID
        "totalFee" : event.pro_price, // 价格
        "envId": "",//云环境ID
        "functionName": "pay_cb" //回调函数必须有
      })
      return res
}

3、支付回调函数pay_cb

作用:支付完成后的回调函数,这个函数很重要,所有的支付完成的云操作都在这里边进行。

3.1 准备条件

由于用到了第三方库:flatted,所有要下载好Node.js并且使用NPM命令进行远程下载

return {
      errcode: 0, //必须要写,否则微信服务器没有响应则会一直调用
      errmsg: "订单未找到",
};

3.2 必要认知

pay_cb作为回调函数,则必须要有一个固定返回形式,参考文档如[6]

在这里插入图片描述

npm install flatted

3.3 pay_cb 完整函数如下

const cloud = require('wx-server-sdk');
const { stringify, parse } = require('flatted');

// 此处的作用是:设置此函数的超时,主要是防止大量数据的处理时间造成的报错

cloud.init({ 
    env: '', // 云环境环境ID
    timeout: 10000 // 设置超时时间为10秒
});

const db = cloud.database();

// 更新订单状态并查询订单信息函数
const updateOrderStatusAndFetch = async (outTradeNo) => {
    try {
        // 更新订单状态
        await db.collection("orderUser").where({
            orderNumber: outTradeNo
        }).update({
            data: {
                pay_status: "订单完成"
            }
        });
        // 查询订单信息
        const res = await db.collection("orderUser").where({
            orderNumber: outTradeNo
        }).get();
        return res.data[0];
    } catch (error) {
        console.error("订单更新或查询出错", error);
        throw error;
    }
};

// 标签打印函数
const printLabel = async (allOrder) => {
    try {
        const result = await cloud.callFunction({
            name: 'printBiaoQian',
            data: {
                allOrder
            }
        });
        return { name: "标签打印", value: result.result };
    } catch (error) {
        console.error("标签打印出错", error);
        throw error;
    }
};

// 小票打印函数
const printTicket = async (printLabelObj) => {
    try {
        const result = await cloud.callFunction({
            name: 'printer',
            data: parse(stringify({
                payStyle: printLabelObj.payStyle,
                time: printLabelObj.time,
                ordercode: printLabelObj.ordercode,
                takecode: printLabelObj.takecode,
                info: printLabelObj.info,
                price: printLabelObj.price,
                phone: printLabelObj.phone,
                name: printLabelObj.name,
                remarks: printLabelObj.remarks
            }))
        });
        return { name: "小票打印", value: result.result };
    } catch (error) {
        console.error("小票打印出错", error);
        throw error;
    }
};

// 云函数入口函数
exports.main = async (event, context) => {
    const { outTradeNo, resultCode } = event;
    let resultAll = [];

    if (!outTradeNo || outTradeNo.length === 0) {
        return {
            errcode: 0, //必须要写,否则微信服务器没有响应则会一直调用
            errmsg: "订单未找到",
        };
    }
    try {
        console.log("开始处理订单支付");

        // 立即响应微信服务端
        const response = {
            errcode: 0,
            errmsg: event.returnCode,
        };

        // 异步处理订单更新和打印逻辑
        updateOrderStatusAndFetch(outTradeNo)
            .then(async (order) => {
                if (!order) {
                    console.error("订单未找到");
                    return;
                }

                console.log("订单信息查询完成");

                // 准备标签打印数据
                console.log("准备标签打印数据中...");
                const allOrderGroups = order.orderGroups;
                const tempNowTemp = allOrderGroups.map(element => {
                    const orderShuXingStr = element.orderShuXing.map(el => `#${el.value}`).join('');
                    return {
                        sumNum: element.orderNum,
                        title: element.goodGroups.shopTitle,
                        tuple: `(${orderShuXingStr})`,
                        order: order.orderCode,
                        time: order.subTime,
                        price: element.priceAll,
                        style: "小程序点单"
                    };
                });

                // 准备小票打印数据
                console.log("准备小票打印数据中...");
                const tupleInfoArray = allOrderGroups.map(element => {
                    const orderShuXingStr = element.orderShuXing.map(el => `#${el.value}`).join('');
                    return {
                        tuple: orderShuXingStr,
                        title: element.goodGroups.shopTitle,
                        num: element.orderNum
                    };
                });

                const printLabelObj = {
                    payStyle: "小程序微信支付",
                    time: order.subTime,
                    ordercode: order.orderNumber,
                    takecode: order.orderCode,
                    info: tupleInfoArray,
                    price: order.order_price,
                    phone: order.phone,
                    name: order.userName,
                    remarks: order.orderRemarks
                };

                // 标签打印
                console.log("标签打印中...");
                const printBiaoQianResult = await printLabel(tempNowTemp);
                resultAll.push(printBiaoQianResult);
                console.log("标签打印完成");

                // 小票打印
                console.log("小票打印中...");
                const printerResult = await printTicket(printLabelObj);
                resultAll.push(printerResult);
                console.log("小票打印完成");

                // 打印完成后的处理
                console.log("支付处理完成");
            })
            .catch((error) => {
                console.error("异步处理订单出错", error);
            });

        // 立即返回响应
        return response;
    } catch (error) {
        console.error("支付处理出错", error);
        return {
            errcode: 0,
            errmsg: "支付处理出错",
        };
    }
};

4、标签打印函数

在本文章当中,我所使用的标签打印机是“芯烨云”的打印机,SDK比较明确,主流打印机,使用后端语言比较多,具体请参考官网文档[7]。

// 引入云函数 SDK 和 axios
const cloud = require('wx-server-sdk');
const axios = require('axios'); //提前用npm下载此库

// 初始化云环境
cloud.init({
  env: '' //云开发云函数环境ID
});

// 生成签名的函数
function generateSignature(user, userKey, timestamp) {
  const crypto = require('crypto');
  const str = user + userKey + timestamp;
  return crypto.createHash('sha1').update(str).digest('hex');
}

// 打印标签的云函数
exports.main = async (event, context) => {
  // 获取传入的订单数组
  const allOrder = event.allOrder;
  // 设置相关参数
  const user = ''; //开放用户账户名
  const userKey = ''; // 用户密钥
  const timestamp = Math.floor(Date.now() / 1000);
  const sign = generateSignature(user, userKey, timestamp);

  // 添加打印机
  const addPrinterResponse = await axios.post('https://open.xpyun.net/api/openapi/xprinter/addPrinters', {
    user: user,
    timestamp: timestamp,
    sign: sign,
    items: [
      {sn: '打印机sn号', name: '店铺名称'}
    ]
  }, {
    headers: {
      'Content-Type': 'application/json;charset=UTF-8'
    }
  });
  if (addPrinterResponse.data.code !== 0) {
    // 添加打印机失败
    return addPrinterResponse.data;
  }

  // 遍历订单数组,生成打印内容并发送打印请求
  for (const order of allOrder) {
    for (let i = 1; i <= order.sumNum; i++) {
      // 初始化单个订单的打印内容
      let printContent = '';
      printContent += `<TEXT x="10" y="10" font="9" w="1" h="1" r="0">${order.style} #${i}/${order.sumNum}</TEXT>\n`;
      printContent += `<TEXT x="10" y="40" font="9" w="1" h="1" r="0">取餐号:${order.order}</TEXT>\n`;
      printContent += `<TEXT x="10" y="70" font="9" w="1" h="1" r="0">${order.title}</TEXT>\n`;
      printContent += `<TEXT x="10" y="100" font="9" w="1" h="1" r="0">${order.tuple}</TEXT>\n`;
      printContent += `<TEXT x="10" y="130" font="9" w="1" h="1" r="0">${order.price}元</TEXT>\n`;
      printContent += `<TEXT x="10" y="160" font="9" w="1" h="1" r="0">${order.time}</TEXT>\n`;
      printContent += `<TEXT x="10" y="190" font="9" w="1" h="1" r="0">NFIVE COFFEE</TEXT>\n`;
      // 构建打印请求体
      const printRequestBody = {
        sn: '',
        content: printContent,
        user: user,
        timestamp: timestamp,
        sign: generateSignature(user, userKey, timestamp), // 重新生成签名
        debug: '0'
      };
      // 发送打印请求
      const printResponse = await axios.post('https://open.xpyun.net/api/openapi/xprinter/printLabel', printRequestBody, {
        headers: {
          'Content-Type': 'application/json;charset=UTF-8'
        }
      });
      // 检查打印结果
      if (printResponse.data.code !== 0) {
        // 打印失败
        return printResponse.data;
      }
    }
  }
  // 所有订单打印成功
  return { code: 0, msg: 'All orders printed successfully' };
};

5、小票打印函数

在本文章当中,我所使用的小票打印机是“优声云”的打印机,SDK比较明确,使用后端语言比较多,具体请参考官网SDK文档链接[8]。

// 云函数入口文件
const cloud = require('wx-server-sdk')
const crypto = require('crypto');  //提前用npm下载此库
//axios版本
const axios = require('axios')  //提前用npm下载此库
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV })
// 云函数入口函数
exports.main = async (event, context) => {
    //event为客户端上传的参数
    console.log('event : ', event)
    //通用参数
    var appid = ''; //应用ID,申请的ID,值为number类型
    var appsecret = ''; //申请的appsecret
    var sign = ''; //签名,不需要填写,会自动生成。
    var timestamp = parseInt((new Date().getTime()) / 1000); //当前时间戳,不需要填写
    var deviceid = ''; //设备号
    var devicesecret = ''; //设备密钥
    // 构建打印内容
    var printdata = '<B1><C>小程序订单</C></B1>\n';
    printdata += '<B1><C></C></B1>\n';
    printdata += '--------------------------------\n';
    printdata += '<B1><C>' + event.payStyle + '</C></B1>\n';
    printdata += '下单时间:' + event.time + '\n';
    printdata += '订单编号:' + event.ordercode + '\n';
    printdata += '取餐码:' + event.takecode + '\n';
    printdata += '--------------------------------\n';
    event.info.forEach(item => {
        printdata += item.title + ' x ' + item.num + '\n';
        printdata += item.tuple + '\n';
    });
    printdata += '--------------------------------\n';
    printdata += '实付金额:' + event.price + '\n';
    printdata += '下单手机号:' + event.phone + '\n';
    printdata += '客户姓名:' + event.name + '\n';
    printdata += '备注:' + event.remarks + '\n';
    //打印
    var parameter = {
        appid: appid,
        timestamp: timestamp,
        deviceid: deviceid,
        devicesecret: devicesecret,
        printdata: printdata,
        //请在此添加您需要的参数,格式为上面定义的变量名为key值和value值
    }
    //键值排序
    function objKeySort(obj) { //排序的函数
        var newkey = Object.keys(obj).sort();
        //先用Object内置类的keys方法获取要排序对象的属性名,再利用Array原型上的sort方法对获取的属性名进行排序,newkey是一个数组
        var newObj = {}; //创建一个新的对象,用于存放排好序的键值对
        for (var i = 0; i < newkey.length; i++) { //遍历newkey数组
            newObj[newkey[i]] = obj[newkey[i]]; //向新创建的对象中按照排好的顺序依次增加键值对
        }
        return newObj; //返回排好序的新对象
    }
    var newObj = objKeySort(parameter); //函数执行
    var valueJian = '';
    for (var x in newObj) {
        if (!newObj[x]) {
            break;
        }
        valueJian += x + newObj[x]
    }
    valueJian += appsecret;
    //console.log(valueJian);
    sign = crypto.createHash('md5').update(valueJian).digest("hex")
    //需要的参数对象列表
    parameter.sign = sign;
    try {
        const response = await axios.post('https://open-api.ushengyun.com/printer/print', parameter);
        // 处理循环引用
        const data = JSON.parse(JSON.stringify(response, (key, value) => {
            if (typeof value === 'object' && value !== null) {
                const seen = new WeakSet();
                if (seen.has(value)) {
                    return;
                }
                seen.add(value);
            }
            return value;
        }));

        console.log(data);
        return data;
    } catch (error) {
        console.error('Error:', error);
        return { errorCode: 1, errorMessage: error.message };
    }
}

三、回调函数常见问题

在接下来的回调函数我们统一使用pay_cb表示

1、提高云开发数据库订单更新与查询效率

面临大量的数据并发,会造函数执行超时,对于这个云数据库操作我们有以下方法

1.1 在云开发数据库集合当中增加索引,对于经常使用的查询键,可以增加到索引当中去。如图
在这里插入图片描述 1.2 减少数据库调用

将查询和更新操作合并为一个操作,减少数据库调用的次数。具体请仔细查看pay_cb

回调函数中的订单更新与查询操作语句写的方法。

1.3 提高云函数超时时间

在云函数的配置中增加超时时间,可以在调用 cloud.init 时设置 timeout 参数。

cloud.init({ 
    env: '',
    timeout: 10000 // 设置超时时间为10秒
});

2、避免阻塞与防止回调函数一直回调

由于在付款完成后,回调函数执行当中很多时间浪费在云数据库操作查询更新上,更新的时候使用了await,阻塞了应答微信服务端的应答,应答晚了,微信服务端认为你没有应答,所以就造成微信服务器一直在回调
所以我们可以按照pay_cb完整代码当中那样的结构去写,通过在接收支付回调时立即返回响应,然后异步更新数据库,这样做可以避免阻塞微信服务端的响应时间。

五、参考文档

1. 云调用对接微信支付
2. 商户号获取指引文档
3. 微信公众平台
4. 接入准备文档
5. 微信开发者文档云支付确认
6. 芯烨云标签打印机参考官网文档
7. 优声云小票打印机参考官网文档

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

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

相关文章

day03 3.文件IO 4.文件属性函数

作业 1> 使用文件IO完成&#xff0c;将源文件中的所有内容进行加密&#xff08;大写转小写、小写转大写&#xff09;后写入目标文件中 源文件内容不变 #include <myhead.h>int main(int argc, const char *argv[]) {if(argc ! 3) //判断打开的文件个数{printf(&quo…

【Python学习手册(第四版)】学习笔记10-语句编写的通用规则

个人总结难免疏漏&#xff0c;请多包涵。更多内容请查看原文。本文以及学习笔记系列仅用于个人学习、研究交流。 本文较简单&#xff0c;5-10分钟即可阅读完成。介绍Python基本过程语句并讨论整体语法模型通用规则&#xff08;冒号、省略、终止、缩进、其他特殊情况&#xff0…

JavaFX布局-StackPane

JavaFX布局-StackPane 常用属性alignmentpadding 实现方式Java实现fxml实现 所有子节点堆叠在一起&#xff0c;通常最后一个添加的子节点会显示在最上面 常用属性 alignment 对齐方式 stackPane.setAlignment(Pos.CENTER_RIGHT); public enum Pos {/*** Represents positioni…

LeYOLO,一种用于目标检测的新型可扩展且高效的CNN架构

摘要 在目标检测中&#xff0c;深度神经网络的计算效率至关重要&#xff0c;尤其是随着新型模型越来越注重速度而非有效计算量&#xff08;FLOP&#xff09;。这一发展趋势在某种程度上忽视了嵌入式和面向移动设备的AI目标检测应用。在本文中&#xff0c;我们基于FLOP关注于高…

马斯克的Memphis AI超级计算中心:全球最强AI训练集群的诞生

引言 近期&#xff0c;马斯克宣布其最新的Memphis AI超级计算中心正式启动&#xff0c;这一新闻引发了科技界的广泛关注。该中心配备了10万块液冷H100 GPU&#xff0c;成为全球最强大的AI训练集群。本文将深入探讨Memphis AI超级计算中心的建设过程、技术细节、以及其对未来人…

Unity多客户端位置同步信息

书接上文&#xff0c;有了一个基本的网络同步消息的服务器&#xff0c;客户端这边其实要做的工作就简单许多。 如果对位置信息的保密程度没那么高的话&#xff0c;可以放在客户端处理这部分的逻辑。 即一个客户端移动的时候&#xff0c;另一个客户端跟着移动&#xff0c;基本…

在Java中利用GeoHash实现高效的‘附近xxx‘功能

GeoHash的介绍 GeoHash是一种高效的地理编码系统&#xff0c;它通过将地球表面划分为网格并用字母数字组合的字符串来表示每个区域。 这种编码方法将二维的经纬度坐标转换为一维的字符串&#xff0c;使得地理位置的存储和检索变得更加简单。GeoHash的核心原理是将经纬度坐标转…

后端开发工程师vue2初识的学习

博客主页&#xff1a;音符犹如代码系列专栏&#xff1a;JavaWeb关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 什么是Vue&#xff1f; Vue &#xff08;通常指 Vue.js&#xff09;是一个用…

权限管理的概述以及vue开发前端的路由、菜单、按钮权限控制实现方案

1. 权限管理概念 1.1 权限定义 权限管理是确保用户只能访问被授权资源的机制。在计算机系统中&#xff0c;权限通常指对特定数据或功能的访问权。权限的设置和控制对于保护数据安全和系统安全至关重要。 1.2 前端权限控制重要性 前端权限控制是用户与应用交互的第一道防线。…

超级好用的免费在线流程图软件

超级好用的免费在线流程图软件 Draw io 是一款免费开源的流程图绘制工具&#xff0c;可在浏览器中使用或下载安装。它提供了简单易用的界面和丰富的图形元素&#xff0c;支持创建各种类型的流程图、组织结构图、网络图等。Draw io 支持导入和导出多种格式&#xff0c;包括 PDF…

从零开始,快速打造API:揭秘 Python 库toapi的神奇力量

在开发过程中&#xff0c;我们常常需要从不同的网站获取数据&#xff0c;有时候还需要将这些数据转化成API接口提供给前端使用。传统的方法可能需要大量的时间和精力去编写代码。但今天我要介绍一个神奇的Python库——toapi&#xff0c;它可以让你在几分钟内创建API接口&#x…

数据库练习——处理表

新建数据库 mysql> create database mydb15_indexstu; Query OK, 1 row affected (0.00 sec)mysql> use mydb15_indexstu; Database changed 新建表 建立student表 mysql> create table student(Sno int primary key auto_increment,-> Sname varchar(30) not …

社区团购系统搭建开发,前端uniapp。社区团购搭建开发定制

目录 前言&#xff1a; 一、社区团购系统有哪些功能&#xff1f; 二、社区团购管理端 三、社区团购的基本流程如下&#xff1a; 总结 &#xff1a; 前言&#xff1a; 社区团购是一种以社区为单位进行的集体购物模式。这种模式利用了互联网平台来组织同一社区内的居民一起购…

Linux I/O 体系结构与访问设备

I/O 体系结构 与外设的通信通常称之为输入输出&#xff0c;一般都缩写为I/O。 在实现外设的I/O时&#xff0c;内核必须处理3个可能出现的问题&#xff1a; &#xff08;1&#xff09;必须根据具体的设备类型和模型&#xff0c;使用各种方法对硬件寻址&#xff1b; &#xff08…

26.x86游戏实战-寻找公共call

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 工具下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd6tw3 提…

KeePass密码管理工具部署

KeePass密码管理工具部署 安装包下载入口 双击执行&#xff0c;根据提示完成安装&#xff1a; 安装完成后如图&#xff1a;

RCE和php文件上传

一、远程命令执行&#xff08;RCE&#xff09; RCE漏洞概述 RCE漏洞允许攻击者通过某种方式在目标服务器上执行任意命令。这种漏洞通常出现在服务器端语言中&#xff0c;如PHP。 RCE漏洞原理 PHP中的一些函数可以执行命令或代码&#xff0c;但如果对这些函数的输入未加限制&a…

Java并发(十五)Java并发工具类

CountDownLatch 字面意思为 递减计数锁。用于控制一个线程等待多个线程。 **CountDownLatch**** 维护一个计数器 count&#xff0c;表示需要等待的事件数量。**countDown 方法递减计数器&#xff0c;表示有一个事件已经发生。调用 await 方法的线程会一直阻塞直到计数器为零&a…

程序员如何准备既符合“八股文“又展现实力的面试?

在当今竞争激烈的IT行业中,面试已成为程序员求职路上的一道重要关卡。而在这个过程中,"八股文"这个词频频出现,引发了业内人士的热议。本文将深入探讨"八股文"在程序员面试中的角色,以及它对实际工作的影响。 目录 1. 程序员面试八股文的利弊分析什么是&q…

Unity 预制动态绑定光照贴图遇到变白问题

预制绑定光照贴图&#xff0c;网上解决方案很多&#xff0c;已下是要点&#xff1a; //烘培完场景之后&#xff0c;保存光照贴图信息 void StoreLightmapData() {lightMap.Clear();LightmapData[] lds LightmapSettings.lightmaps;foreach (LightmapData data in lds){Custom…