返回顶部
首页 > 资讯 > 精选 >springboot+websocket怎样实现并发抢红包功能
  • 223
分享到

springboot+websocket怎样实现并发抢红包功能

2023-06-22 04:06:11 223人浏览 安东尼
摘要

这期内容当中小编将会给大家带来有关SpringBoot+websocket怎样实现并发抢红包功能,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。概述抢红包功能作为几大高并发场景中典型,应该如何实现?分析参考

这期内容当中小编将会给大家带来有关SpringBoot+websocket怎样实现并发抢红包功能,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

概述

抢红包功能作为几大高并发场景中典型,应该如何实现?

分析

参考微信抢红包功能,将抢红包分成一下几个步骤:

  • 发红包;主要填写红包信息,生成红包记录

  • 红包支付回调;用户发红包支付成功后,收到微信支付付款成功的回调,生成指定数量的红包。

  • 抢红包;用户并发抢红包。

  • 拆红包;记录用户抢红包记录,转账抢到的红包金额。

 效果展示

项目使用sessionId模拟用户,示例打开俩个浏览器窗口模拟两个用户。

springboot+websocket怎样实现并发抢红包功能

设计开发

表结构设计

红包记录在 redpacket 表中,用户领取红包详情记录在 redpacket_detail 表中。

CREATE DATABASE  `redpacket`;use `redpacket`;CREATE TABLE `redpacket`.`redpacket` (  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',  `packet_no` varchar(32) NOT NULL COMMENT '订单号',  `amount` decimal(5,2) NOT NULL COMMENT '红包金额最高10000.00元',  `num` int(11) NOT NULL COMMENT '红包数量',  `order_status` int(4) NOT NULL DEFAULT '0' COMMENT '订单状态:0初始、1待支付、2支付成功、3取消',  `pay_seq` varchar(32) DEFAULT NULL COMMENT '支付流水号',  `create_time` datetime NOT NULL COMMENT '创建时间',  `user_id` varchar(32) NOT NULL COMMENT '用户ID',  `update_time` datetime NOT NULL COMMENT '更新时间',  `pay_time` datetime DEFAULT NULL COMMENT '支付时间',  PRIMARY KEY (`id`)) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='红包订单表';CREATE TABLE `redpacket`.`redpacket_detail` (  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',  `packet_id` bigint(20) NOT NULL COMMENT '红包ID',  `amount` decimal(5,2) NOT NULL COMMENT '红包金额',  `received` int(1) NOT NULL DEFAULT '0' COMMENT '是否领取0未领取、1已领取',  `create_time` datetime NOT NULL COMMENT '创建时间',  `update_time` datetime NOT NULL COMMENT '更新时间',  `user_id` varchar(32) DEFAULT NULL COMMENT '领取用户',  `packet_no` varchar(32) NOT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='红包详情表';

发红包设计

用户需要填写红包金额、红包数量、备注信息等,生成红包记录,微信收银台下单,返回用户支付。

public RedPacket generateRedPacket(ReqSendRedPacketsVO data,String userId) {    final BigDecimal amount = data.getAmount();    //红包数量    final Integer num = data.getNum();    //初始化订单    final RedPacket redPacket = new RedPacket();    redPacket.setPacketNo(UUID.randomUUID().toString().replace("-", ""));    redPacket.setAmount(amount);    redPacket.setNum(num);    redPacket.setUserId(userId);    Date now = new Date();    redPacket.setCreateTime(now);    redPacket.setUpdateTime(now);    int i = redPacketMapper.insertSelective(redPacket);    if (i != 1) {        throw new ServiceException("生成红包出错", ExceptionType.SYS_ERR);    }    //模拟收银台下单    String paySeq = UUID.randomUUID().toString().replace("-", "");    //拿到收银台下单结果,更新订单为待支付状态    redPacket.setOrderStatus(1);//待支付    redPacket.setPaySeq(paySeq);    i = redPacketMapper.updateByPrimaryKeySelective(redPacket);    if (i != 1) {        throw new ServiceException("生成红包出错", ExceptionType.SYS_ERR);    }    return redPacket;}

springboot+websocket怎样实现并发抢红包功能

红包支付成功回调设计

用户支付成功后,系统接收到微信回调接口。

更新红包支付状态
二倍均值法生成指定数量红包,并批量入库。 红包算法参考:Java实现4种微信抢红包算法
红包总数入redis,设置红包过期时间24小时
WEBSocket通知在线用户收到新的红包

@Transactional(rollbackFor = Exception.class)public void dealAfterOrderPayCallback(String userId,ReqOrderPayCallbackVO data) {    RedPacketExample example = new RedPacketExample();    final String packetNo = data.getPacketNo();    final String paySeq = data.getPaySeq();    final Integer payStatus = data.getPayStatus();    example.createCriteria().andPacketNoEqualTo(packetNo)            .andPaySeqEqualTo(paySeq)            .andOrderStatusEqualTo(1);//待支付状态    //更新订单支付状态    Date now = new Date();    RedPacket updateRedPacket = new RedPacket();    updateRedPacket.setOrderStatus(payStatus);    updateRedPacket.setUpdateTime(now);    updateRedPacket.setPayTime(now);    int i = redPacketMapper.updateByExampleSelective(updateRedPacket, example);    if (i != 1) {        throw new ServiceException("订单状态更新失败", ExceptionType.SYS_ERR);    }    if (payStatus == 2) {        RedPacketExample query = new RedPacketExample();        query.createCriteria().andPacketNoEqualTo(packetNo)                .andPaySeqEqualTo(paySeq)                .andOrderStatusEqualTo(2);        final RedPacket redPacket = redPacketMapper.selectByExample(query).get(0);        final List<BigDecimal> detailList = getRedPacketDetail(redPacket.getAmount(), redPacket.getNum());        final int size = detailList.size();        if (size <= 100) {            i = detailMapper.batchInsert(detailList, redPacket);            if (size != i) {                throw new ServiceException("生成红包失败", ExceptionType.SYS_ERR);            }        } else {            int times = size % 100 == 0 ? size / 100 : (size / 100 + 1);            for (int j = 0; j < times; j++) {                int fromIndex = 100 * j;                int toIndex = 100 * (j + 1) - 1;                if (toIndex > size - 1) {                    toIndex = size - 1;                }                final List<BigDecimal> subList = detailList.subList(fromIndex, toIndex);                i = detailMapper.batchInsert(subList, redPacket);                if (subList.size() != i) {                    throw new ServiceException("生成红包失败", ExceptionType.SYS_ERR);                }            }        }        final String RedisKey = REDPACKET_NUM_PREFIX + redPacket.getPacketNo();        String lua = "local i = redis.call('setnx',KEYS[1],ARGV[1])\r\n" +                "if i == 1 then \r\n" +                "   local j = redis.call('expire',KEYS[1],ARGV[2])\r\n" +                "end \r\n" +                "return i";        //优化成lua脚本        final Long execute = redisTemplate.execute(new DefaultRedisScript<>(lua, Long.class), Arrays.asList(redisKey), size, 3600 * 24);        if (execute != 1L) {            throw new ServiceException("生成红包失败", ExceptionType.SYS_ERR);        }        //websocket通知在线用户收到新的红包        Websocket.sendMessageToUser(userId, JSONObject.tojsONString(redPacket));    }}private List<BigDecimal> getRedPacketDetail(BigDecimal amount, Integer num) {    List<BigDecimal> redPacketsList = new ArrayList<>(num);    //最小红包金额    final BigDecimal min = new BigDecimal("0.01");    //最少需要红包金额    final BigDecimal bigNum = new BigDecimal(num);    final BigDecimal atLastAmount = min.multiply(bigNum);    //出去最少红包金额后剩余金额    BigDecimal remain = amount.subtract(atLastAmount);    if (remain.compareTo(BigDecimal.ZERO) == 0) {        for (int i = 0; i < num; i++) {            redPacketsList.add(min);        }        return redPacketsList;    }    final Random random = new Random();    final BigDecimal hundred = new BigDecimal("100");    final BigDecimal two = new BigDecimal("2");    BigDecimal redPacket;    for (int i = 0; i < num; i++) {        if (i == num - 1) {            redPacket = remain;        } else {            //100内随机获得的整数            final int rand = random.nextInt(100);            redPacket = new BigDecimal(rand).multiply(remain.multiply(two).divide(bigNum.subtract(new BigDecimal(i)), 2, RoundingMode.CEILING)).divide(hundred, 2, RoundingMode.FLOOR);        }        if (remain.compareTo(redPacket) > 0) {            remain = remain.subtract(redPacket);        } else {            remain = BigDecimal.ZERO;        }        redPacketsList.add(min.add(redPacket));    }    return redPacketsList;}

页面加载成功后初始化websocket,监听后端新红包生成成功,动态添加红包到聊天窗口。

$(function (){    var websocket;    if('WebSocket' in window) {        console.log("此浏览器支持websocket");        websocket = new WebSocket("ws://127.0.0.1:8082/websocket/${session.id}");    } else if('MozWebSocket' in window) {        alert("此浏览器只支持MozWebSocket");    } else {        alert("此浏览器只支持SockJS");    }    websocket.onopen = function(evnt) {        console.log("链接服务器成功!")    };    websocket.onmessage = function(evnt) {        console.log(evnt.data);        var json = eval('('+evnt.data+ ')');        obj.addPacket(json.id,json.packetNo,json.userId)    };    websocket.onerror = function(evnt) {};    websocket.onclose = function(evnt) {        console.log("与服务器断开了链接!")    }});

抢红包设计

抢红包设计高并发,本地单机项目,通过原子Integer控制抢红包接口并发限制为20,

private AtomicInteger receiveCount = new AtomicInteger(0);@PostMapping("/receive")public CommonJsonResponse receiveOne(@Validated @RequestBody CommonJsonRequest<ReqReceiveRedPacketVO> vo) {    Integer num = null;    try {        //控制并发不要超过20        if (receiveCount.get() > 20) {            return new CommonJsonResponse("9999", "太快了");        }        num = receiveCount.incrementAndGet();        final String s = orderService.receiveOne(vo.getData());        return StringUtils.isEmpty(s) ? CommonJsonResponse.ok() : new CommonJsonResponse("9999", s);    } finally {        if (num != null) {            receiveCount.decrementAndGet();        }    }}

对于没有领取过该红包的用户,在红包没有过期且红包还有剩余的情况下,抢红包成功,记录成功标识入redis,设置标识过期时间为5秒。

public String receiveOne(ReqReceiveRedPacketVO data) {    final Long redPacketId = data.getPacketId();    final String redPacketNo = data.getPacketNo();    final String redisKey = REDPACKET_NUM_PREFIX + redPacketNo;    if (!redisTemplate.hasKey(redisKey)) {        return "红包已经过期";    }    final Integer num = (Integer) redisTemplate.opsForValue().get(redisKey);    if (num <= 0) {        return "红包已抢完";    }    RedPacketDetailExample example = new RedPacketDetailExample();    example.createCriteria().andPacketIdEqualTo(redPacketId)            .andReceivedEqualTo(1)            .andUserIdEqualTo(data.getUserId());    final List<RedPacketDetail> details = detailMapper.selectByExample(example);    if (!details.isEmpty()) {        return "该红包已经领取过了";    }    final String receiveKey = REDPACKET_RECEIVE_PREFIX + redPacketNo + ":" + data.getUserId();    //优化成lua脚本    String lua = "local i = redis.call('setnx',KEYS[1],ARGV[1])\r\n" +            "if i == 1 then \r\n" +            "   local j = redis.call('expire',KEYS[1],ARGV[2])\r\n" +            "end \r\n" +            "return i";    //优化成lua脚本    final Long execute = redisTemplate.execute(new DefaultRedisScript<>(lua, Long.class), Arrays.asList(receiveKey), 1, 5);    if (execute != 1L) {        return "太快了";    }    return "";}

拆红包设计

在用户抢红包成功标识未过期的状态下,且红包未过期红包未领完时,从数据库中领取一个红包,领取成功将领取记录写入redis以供查询过期时间为48小时。

@Transactional(rollbackFor = Exception.class)public String openRedPacket(ReqReceiveRedPacketVO data) {    final Long packetId = data.getPacketId();    final String packetNo = data.getPacketNo();    final String userId = data.getUserId();    final String redisKey = REDPACKET_NUM_PREFIX + packetNo;    Long num = null;    try {        final String receiveKey = REDPACKET_RECEIVE_PREFIX + packetNo + ":" + userId;        if (!redisTemplate.hasKey(receiveKey)) {            log.info("未获取到红包资格,packet:{},user:{}", packetNo, userId);            throw new ServiceException("红包飞走了", ExceptionType.SYS_ERR);        }        redisTemplate.delete(receiveKey);        if (!redisTemplate.hasKey(redisKey)) {            log.info("红包过期了,packet:{}", packetNo);            throw new ServiceException("红包飞走了", ExceptionType.SYS_ERR);        }        num = redisTemplate.opsForValue().increment(redisKey, -1);        if (num < 0L) {            log.info("红包领完了,packet:{}", packetNo);            throw new ServiceException("红包飞走了", ExceptionType.SYS_ERR);        }        final int i = detailMapper.receiveOne(packetId, packetNo, userId);        if (i != 1) {            log.info("红包真的领完了,packet:{}", packetNo);            throw new ServiceException("红包飞走了", ExceptionType.SYS_ERR);        }        RedPacketDetailExample example = new RedPacketDetailExample();        example.createCriteria().andPacketIdEqualTo(packetId)                .andReceivedEqualTo(1)                .andUserIdEqualTo(userId);        final List<RedPacketDetail> details = detailMapper.selectByExample(example);        if (details.size() != 1) {            log.info("已经领取过了,packet:{},user:{}", packetNo, userId);            throw new ServiceException("红包飞走了", ExceptionType.SYS_ERR);        }        //处理加款        log.info("抢到红包金额{},packet:{},user:{}", details.get(0).getAmount(), packetNo, userId);        final String lisTKEy = REDPACKET_LIST_PREFIX + packetNo;        redisTemplate.opsForList().leftPush(listKey,details.get(0));        redisTemplate.expire(redisKey, 48, TimeUnit.HOURS);        return "" + details.get(0).getAmount();    } catch (Exception e) {        if (num != null) {            redisTemplate.opsForValue().increment(redisKey, 1L);        }        log.warn("打开红包异常", e);        throw new ServiceException("红包飞走了", ExceptionType.SYS_ERR);    }}

其中 detailMapper.receiveOne(packetId, packetNo, userId); sql如下,将指定红包记录下未领取的红包更新一条未当前用户已经领取,若成功更新一条则表示领取成功,否则领取失败。

update redpacket_detail dset received = 1,update_time = now(),user_id = #{userId,jdbcType=VARCHAR}where received = 0and packet_id = #{packetId,jdbcType=BIGINT}and packet_no = #{packetNo,jdbcType=VARCHAR}and user_id is nulllimit 1

获取红包领取记录设计

直接充redis中获取用户领取记录,没有则直接获取数据库并同步至redis。

public RespReceiveListVO receiveList(ReqReceiveListVO data) {    //红包记录redisKey    final String packetNo = data.getPacketNo();    final String redisKey = REDPACKET_LIST_PREFIX + packetNo;    if (!redisTemplate.hasKey(redisKey)) {        RedPacketDetailExample example = new RedPacketDetailExample();        example.createCriteria().andPacketNoEqualTo(packetNo)                .andReceivedEqualTo(1);        final List<RedPacketDetail> list = detailMapper.selectByExample(example);        redisTemplate.opsForList().leftPushAll(redisKey, list);        redisTemplate.expire(redisKey, 24, TimeUnit.HOURS);    }    List retList = redisTemplate.opsForList().range(redisKey, 0, -1);    final Object collect = retList.stream().map(item -> {        final JSONObject packetDetail = (JSONObject) item;        return ReceiveRecordVO.builder()                .amount(packetDetail.getBigDecimal("amount"))                .receiveTime(packetDetail.getDate("updateTime"))                .userId(packetDetail.getString("userId"))                .packetId(packetDetail.getLong("redpacketId"))                .packetNo(packetDetail.getString("redpacketNo"))                .build();    }).collect(Collectors.toList());    return RespReceiveListVO.builder().list((List) collect).build();}

jmeter并发测试抢红包、查红包接口

设置jmeter参数1秒中并发请求50个抢11个红包,可以看到,前面的请求都是成功的,中间并发量上来后有部分达到并发上限被拦截,后面红包抢完请求全部失败。

springboot+websocket怎样实现并发抢红包功能

springboot+websocket怎样实现并发抢红包功能

springboot+websocket怎样实现并发抢红包功能

springboot+websocket怎样实现并发抢红包功能

上述就是小编为大家分享的springboot+websocket怎样实现并发抢红包功能了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注编程网精选频道。

--结束END--

本文标题: springboot+websocket怎样实现并发抢红包功能

本文链接: https://lsjlt.com/news/302407.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • springboot+websocket怎样实现并发抢红包功能
    这期内容当中小编将会给大家带来有关springboot+websocket怎样实现并发抢红包功能,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。概述抢红包功能作为几大高并发场景中典型,应该如何实现?分析参考...
    99+
    2023-06-22
  • springboot+websocket实现并发抢红包功能
    目录概述分析 效果展示设计开发表结构设计发红包设计红包支付成功回调设计抢红包设计拆红包设计获取红包领取记录设计jmeter并发测试抢红包、查红包接口概述 抢红包功能作为几大高并发场...
    99+
    2024-04-02
  • asp.net如何开发微信派发现金红包/H5网页抢红包功能
    这篇文章将为大家详细讲解有关asp.net如何开发微信派发现金红包/H5网页抢红包功能,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、网页版抢红包功能,前端先做好抢红包的页面;后台配置微信公众号的app...
    99+
    2023-06-14
  • asp.net开发微信派发现金红包/H5网页抢红包功能(思路详解)
    临近节日,公司里为了给广大老客户赠福利,以及来一波拉新活动:搞了一个营销活动,大概活动规则如下: 1、老客户通过网页抢红包,中奖会派发微信支付的红包; 2、新客户只要关注后就可以中奖...
    99+
    2024-04-02
  • Android微信抢红包功能的实现原理浅析
    快到过农历年了,微信红包也越来越多了,出现了好多红包外挂程序,就很好奇如何实现的,于是自己研究了一番,亲自写了个微信抢红包的APP。现在就一步一步来实现它。 实现思路 微信抢红...
    99+
    2022-06-06
    抢红包 Android
  • Android辅助功如何实现自动抢红包
    这篇文章主要介绍Android辅助功如何实现自动抢红包,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、描述最近看到同事有用抢红包的软件,就想看看抢红包的具体实现是如何的,所以了解了一下,有用辅助功能实现的,所以在下...
    99+
    2023-05-30
    android
  • 通过redis的脚本lua实现抢红包功能的方法
    这篇文章主要讲解了通过redis的脚本lua实现抢红包功能的方法,内容清晰明了,对此有兴趣的小伙伴可以学习一下,相信大家阅读完之后会有帮助。redis 脚本介绍Redis从2.6版本开始,通过内嵌支持Lua...
    99+
    2024-04-02
  • 使用JAVA怎么实现一个红包分发功能
    本篇文章为大家展示了使用JAVA怎么实现一个红包分发功能,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。代码import java.util.Arrays;import java....
    99+
    2023-06-14
  • php代码怎么实现红包功能
    本文操作环境:Windows7系统、PHP7.1版、DELL G3电脑php代码怎么实现红包功能PHP 红包功能代码前段时间被问这个问题,最近有空就写写啦,还是挺有趣的首先做下抢红包方法分类:对于发红包的人来说,一共有大致3类(其他的我暂时...
    99+
    2018-08-18
    php 红包
  • Python怎么实现抢红包提醒助手
    这篇文章主要讲解了“Python怎么实现抢红包提醒助手”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python怎么实现抢红包提醒助手”吧!1、安装库pip install wxpy2、启动...
    99+
    2023-06-16
  • redis+mysql+quartz 一种红包发送功能的实现
    概要: 这篇文章主要是对半年前开发的红包模块进行整理,把其中主要的设计思想以及具体的实现方案进行介绍,如有设计以及实现上的缺陷,或是存在漏洞,请大家批评指正! 红包功能大家都很熟悉了,那在这里就简单的对红包...
    99+
    2022-06-04
    红包 功能 redis
  • Springboot+WebSocket实现在线聊天功能
    目录一、后端二、Websocket三、前端一、后端 1.在Springboot项目的pom.xml中添加依赖 <!--websocket协议--> <depende...
    99+
    2023-02-14
    Springboot WebSocket在线聊天 Springboot WebSocket聊天 Springboot WebSocket
  • SpringBoot+WebSocket实现消息推送功能
    目录背景WebSocket简介协议原理WebSocket与HTTP协议的区别WebSocket特点应用场景系统集成Websocketjar包引入Websocket配置具体实现测试示例...
    99+
    2022-11-13
    SpringBoot WebSocket消息推送 SpringBoot 消息推送 SpringBoot WebSocket
  • 怎么用PHP+Ajax实现手机移动端发红包功能
    本篇内容介绍了“怎么用PHP+Ajax实现手机移动端发红包功能”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!基本流程:当输入完红包数量和总金...
    99+
    2023-06-04
  • php代码如何实现红包功能
    这篇文章主要介绍“php代码如何实现红包功能”,在日常操作中,相信很多人在php代码如何实现红包功能问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”php代码如何实现红包功能”的疑惑有所帮助!接下来,请跟着小编...
    99+
    2023-06-25
  • Redis分布式缓存怎么实现微信抢红包
    本篇内容主要讲解“Redis分布式缓存怎么实现微信抢红包”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Redis分布式缓存怎么实现微信抢红包”吧!一、场景分析微信抢红包已经在我们生活中很常见的场...
    99+
    2023-06-22
  • 怎么在SpringBoot中利用WebSocket实现一个群聊功能
    本篇文章为大家展示了怎么在SpringBoot中利用WebSocket实现一个群聊功能,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。消息群发创建新项目:添加依赖:<dependency>...
    99+
    2023-06-06
  • php结合redis实现高并发下的抢购、秒杀功能的实例
    抢购、秒杀是如今很常见的一个应用场景,主要需要解决的问题有两个: 1 高并发对数据库产生的压力 2 竞争状态下如何解决库存的正确减少("超卖"问题) 对于第一个问题,已经很容易想到用缓存来处理抢购,避免直接...
    99+
    2022-06-04
    实例 功能 秒杀
  • PHP Websocket开发指南,实现实时任务分发功能
    PHP Websocket开发指南,实现实时任务分发功能,需要具体代码示例引言:在现代Web应用程序中,实时任务分发功能变得越来越重要。通过实时任务分发,可以实现实时通信和实时更新,为用户提供更良好的交互体验。PHP Websocket是一...
    99+
    2023-12-09
    PHP websocket 实时任务分发
  • 使用python怎么实现抢购功能
    本篇文章给大家分享的是有关使用python怎么实现抢购功能,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。python是什么意思Python是一种跨平台的、具有解释性、编译性、互...
    99+
    2023-06-06
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作