当前位置: 首页 > news >正文

【Django开发】0到1美多商城项目md教程第5篇:短信验证码,1. 避免频繁发送短信验证码逻辑分析【附代码文档】

美多商城完整教程(附代码资料)主要内容讲述:欢迎来到美多商城!,项目准备。展示用户注册页面,创建用户模块子应用。用户注册业务实现,用户注册前端逻辑。图形验证码,图形验证码接口设计和定义。短信验证码,避免频繁发送短信验证码。账号登录,用户名登录。登录,登录开发文档。用户基本信息,查询并渲染用户基本信息。收货地址,省市区三级联动。收货地址,展示地址前后端逻辑。商品数据库表设计,SPU和SKU。准备商品数据,容器化方案Docker。首页广告,展示首页商品频道分类。商品列表页,列表页面包屑导航。商品搜索,Haystack扩展建立索引。商品详情页,统计分类商品访问量。购物车管理,添加购物车。购物车管理,删除购物车。订单,结算订单。提交订单,使用乐观锁并发下单。对接系统,订单支付功能。页面静态化,首页广告页面静态化。MySQL读写分离,MySQL主从同步。

全套笔记资料代码移步: 前往gitee仓库查看

感兴趣的小伙伴可以自取哦,欢迎大家点赞转发~


全套教程部分目录:


部分文件图片:

短信验证码

避免频繁发送短信验证码

存在的问题:

  • 虽然我们在前端界面做了60秒倒计时功能。
  • 但是恶意用户可以绕过前端界面向后端频繁请求短信验证码。

解决办法:

  • 在后端也要限制用户请求短信验证码的频率。60秒内只允许一次请求短信验证码。
  • 在Redis数据库中缓存一个数值,有效期设置为60秒。

1. 避免频繁发送短信验证码逻辑分析

2. 避免频繁发送短信验证码逻辑实现

1.提取、校验send_flag

send_flag = redis_conn.get('send_flag_%s' % mobile)
if send_flag:return http.JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': '发送短信过于频繁'})

2.重新写入send_flag

# 保存短信验证码redis_conn.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)# 重新写入send_flagredis_conn.setex('send_flag_%s' % mobile, constants.SEND_SMS_CODE_INTERVAL, 1)

3.界面渲染频繁发送短信提示信息

if (response.data.code == '4001') {this.error_image_code_message = response.data.errmsg;this.error_image_code = true;
} else { // 4002this.error_sms_code_message = response.data.errmsg;this.error_sms_code = true;
}

pipeline操作Redis数据库

Redis的 C - S 架构:

  • 基于客户端-服务端模型以及请求/响应协议的TCP服务。
  • 客户端向服务端发送一个查询请求,并监听Socket返回。
  • 通常是以阻塞模式,等待服务端响应。
  • 服务端处理命令,并将结果返回给客户端。

存在的问题:

  • 如果Redis服务端需要同时处理多个请求,加上网络延迟,那么服务端利用率不高,效率降低。

解决的办法:

  • 管道pipeline

1. pipeline的介绍

管道pipeline

  • 可以一次性发送多条命令并在执行完后一次性将结果返回。
  • pipeline通过减少客户端与Redis的通信次数来实现降低往返延时时间。

实现的原理

  • 实现的原理是队列。
  • Client可以将三个命令放到一个tcp报文一起发送。
  • Server则可以将三条命令的处理结果放到一个tcp报文返回。
  • 队列是先进先出,这样就保证数据的顺序性。

2. pipeline操作Redis数据库

1.实现步骤

1. 创建Redis管道
2. 将Redis请求添加到队列
3. 执行请求

2.代码实现

# 创建Redis管道pl = redis_conn.pipeline()# 将Redis请求添加到队列pl.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
pl.setex('send_flag_%s' % mobile, constants.SEND_SMS_CODE_INTERVAL, 1)# 执行请求pl.execute()

异步方案RabbitMQ和Celery

生产者消费者设计模式

思考:

  • 下面两行代码存在什么问题?

问题:

  • 我们的代码是自上而下同步执行的。
  • 发送短信是耗时的操作。如果短信被阻塞住,用户响应将会延迟。
  • 响应延迟会造成用户界面的倒计时延迟。

解决:

  • 异步发送短信
  • 发送短信和响应分开执行,将发送短信从主业务中解耦出来。

思考:

  • 如何将发送短信从主业务中解耦出来。

生产者消费者设计模式介绍

  • 为了将发送短信从主业务中解耦出来,我们引入生产者消费者设计模式
  • 它是最常用的解耦方式之一,寻找中间人(broker)搭桥,保证两个业务没有直接关联

总结:

  • 生产者生成消息,缓存到消息队列中,消费者读取消息队列中的消息并执行。
  • 由美多商城生成发送短信消息,缓存到消息队列中,消费者读取消息队列中的发送短信消息并执行。

RabbitMQ介绍和使用

1. RabbitMQ介绍

  • 消息队列是消息在传输的过程中保存消息的容器
  • 现在主流消息队列有:RabbitMQActiveMQKafka等等。

  • RabbitMQActiveMQ比较

    • 系统吞吐量:RabbitMQ好于ActiveMQ
    • 持久化消息:RabbitMQActiveMQ都支持
    • 高并发和可靠性:RabbitMQ好于ActiveMQ
  • RabbitMQKafka

    • 系统吞吐量:RabbitMQ弱于Kafka
    • 可靠性和稳定性:RabbitMQ好于Kafka比较
    • 设计初衷:Kafka是处理日志的,是日志系统,所以并没有具备一个成熟MQ应该具备的特性。
  • 综合考虑,本项目选择RabbitMQ作为消息队列。

2. 安装RabbitMQ(ubuntu 16.04)

1.安装Erlang

  • 由于 RabbitMQ 是采用 Erlang 编写的,所以需要安装 Erlang 语言库。
# 1. 在系统中加入 erlang apt 仓库$ wget 
$ sudo dpkg -i erlang-solutions_1.0_all.deb# 2. 修改 Erlang 镜像地址,默认的下载速度特别慢$ vim /etc/apt/sources.list.d/erlang-solutions.list# 替换默认值$ deb  xenial contrib# 3. 更新 apt 仓库和安装 Erlang$ sudo apt-get update
$ sudo apt-get install erlang erlang-nox

2.安装RabbitMQ

  • 安装成功后,默认就是启动状态。
# 1. 先在系统中加入 rabbitmq apt 仓库,再加入 rabbitmq signing key$ echo 'deb  testing main' | sudo tee /etc/apt/sources.list.d/rabbitmq.list
$ wget -O-  | sudo apt-key add -# 2. 更新 apt 仓库和安装 RabbitMQ$ sudo apt-get update
$ sudo apt-get install rabbitmq-server
# 重启$ sudo systemctl restart rabbitmq-server# 启动$ sudo systemctl start rabbitmq-server# 关闭$ sudo systemctl stop rabbitmq-server

3.Python访问RabbitMQ

  • RabbitMQ提供默认的administrator账户。
  • 用户名和密码:guestguest
  • 协议:amqp
  • 地址:localhost
  • 端口:5672
  • 查看队列中的消息:sudo rabbitctl list_queues
# Python3虚拟环境下,安装pika$ pip install pika
# 生产者代码:rabbitmq_producer.pyimport pika# 链接到RabbitMQ服务器credentials = pika.PlainCredentials('guest', 'guest')
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost',5672,'/',credentials))#创建频道channel = connection.channel()# 声明消息队列channel.queue_declare(queue='zxc')# routing_key是队列名 body是要插入的内容channel.basic_publish(exchange='', routing_key='zxc', body='Hello RabbitMQ!')
print("开始向 'zxc' 队列中发布消息 'Hello RabbitMQ!'")# 关闭链接connection.close()
# 消费者代码:rabbitmq_customer.py import pika# 链接到rabbitmq服务器credentials = pika.PlainCredentials('guest', 'guest')
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost',5672,'/',credentials))# 创建频道,声明消息队列channel = connection.channel()
channel.queue_declare(queue='zxc')# 定义接受消息的回调函数def callback(ch, method, properties, body):print(body)# 告诉RabbitMQ使用callback来接收信息channel.basic_consume(callback, queue='zxc', no_ack=True)# 开始接收信息channel.start_consuming()

3. 新建administrator用户

# 新建用户,并设置密码$ sudo rabbitmqctl add_user admin your_password # 设置标签为administrator$ sudo rabbitmqctl set_user_tags admin administrator# 设置所有权限$ sudo rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"# 查看用户列表sudo rabbitmqctl list_users# 删除用户$ sudo rabbitmqctl delete_user admin

4. RabbitMQ配置远程访问

1.准备配置文件

  • 安装好 RabbitMQ 之后,在 /etc/rabbitmq 目录下面默认没有配置文件,需要单独下载。
$ cd /etc/rabbitmq/
$ wget 
$ sudo cp rabbitmq.config.example rabbitmq.config

2.设置配置文件

$ sudo vim rabbitmq.config# 设置配置文件结束后,重启RabbitMQ服务端$ sudo systemctl restart rabbitmq-server

配置完成后,使用rabbitmq_producer.pyrabbitmq_customer.py测试。

Celery介绍和使用

思考:

  • 消费者取到消息之后,要消费掉(执行任务),需要我们去实现。
  • 任务可能出现高并发的情况,需要补充多任务的方式执行。
  • 耗时任务很多种,每种耗时任务编写的生产者和消费者代码有重复。
  • 取到的消息什么时候执行,以什么样的方式执行。

结论:

  • 实际开发中,我们可以借助成熟的工具Celery来完成。
  • 有了Celery,我们在使用生产者消费者模式时,只需要关注任务本身,极大的简化了程序员的开发流程。

1. Celery介绍

  • Celery介绍:

  • 一个简单、灵活且可靠、处理大量消息的分布式系统,可以在一台或者多台机器上运行。

  • 单个 Celery 进程每分钟可处理数以百万计的任务。
  • 通过消息进行通信,使用消息队列(broker)客户端消费者之间进行协调。

  • 安装Celery:

$ pip install -U Celery
  • [Celery官方文档](

2. 创建Celery实例并加载配置

1.定义Celery包

2.创建Celery实例

celery_tasks.main.py

# celery启动文件from celery import Celery# 创建celery实例celery_app = Celery('meiduo')

3.加载Celery配置

celery_tasks.config.py

# 指定消息队列的位置broker_url= 'amqp://guest:guest@192.168.103.158:5672'

celery_tasks.main.py

# celery启动文件from celery import Celery# 创建celery实例celery_app = Celery('meiduo')# 加载celery配置celery_app.config_from_object('celery_tasks.config')

3. 定义发送短信任务

1.注册任务:celery_tasks.main.py

# celery启动文件from celery import Celery# 创建celery实例celery_app = Celery('meiduo')# 加载celery配置celery_app.config_from_object('celery_tasks.config')# 自动注册celery任务celery_app.autodiscover_tasks(['celery_tasks.sms'])

2.定义任务:celery_tasks.sms.tasks.py

# bind:保证task对象会作为第一个参数自动传入# name:异步任务别名# retry_backoff:异常自动重试的时间间隔 第n次(retry_backoff×2^(n-1))s# max_retries:异常自动重试次数的上限@celery_app.task(bind=True, name='ccp_send_sms_code', retry_backoff=3)
def ccp_send_sms_code(self, mobile, sms_code):"""发送短信异步任务:param mobile: 手机号:param sms_code: 短信验证码:return: 成功0 或 失败-1"""try:send_ret = CCP().send_template_sms(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES // 60], constants.SEND_SMS_TEMPLATE_ID)except Exception as e:logger.error(e)# 有异常自动重试三次raise self.retry(exc=e, max_retries=3)if send_ret != 0:# 有异常自动重试三次raise self.retry(exc=Exception('发送短信失败'), max_retries=3)return send_ret

4. 启动Celery服务

$ cd ~/projects/meiduo_project/meiduo_mall
$ celery -A celery_tasks.main worker -l info
  • -A指对应的应用程序, 其参数是项目中 Celery实例的位置。
  • worker指这里要启动的worker。
  • -l指日志等级,比如info等级。

5. 调用发送短信任务

# 发送短信验证码# CCP().send_template_sms(mobile,[sms_code, constants.SMS_CODE_REDIS_EXPIRES // 60], constants.SEND_SMS_TEMPLATE_ID)# Celery异步发送短信验证码ccp_send_sms_code.delay(mobile, sms_code)

6. 补充celery worker的工作模式

  • 默认是进程池方式,进程数以当前机器的CPU核数为参考,每个CPU开四个进程。
  • 如何自己指定进程数:celery worker -A proj --concurrency=4
  • 如何改变进程池方式为协程方式:celery worker -A proj --concurrency=1000 -P eventlet -c 1000
# 安装eventlet模块$ pip install eventlet# 启用 Eventlet 池$ celery -A celery_tasks.main worker -l info -P eventlet -c 1000

用户登录

账号登录

未完待续, 同学们请等待下一期

全套笔记资料代码移步: 前往gitee仓库查看

感兴趣的小伙伴可以自取哦,欢迎大家点赞转发~

相关文章:

【Django开发】0到1美多商城项目md教程第5篇:短信验证码,1. 避免频繁发送短信验证码逻辑分析【附代码文档】

美多商城完整教程(附代码资料)主要内容讲述:欢迎来到美多商城!,项目准备。展示用户注册页面,创建用户模块子应用。用户注册业务实现,用户注册前端逻辑。图形验证码,图形验证码接口设…...

云原生:应用敏捷,华为视角下的应用现代化

Gartner 也提出,到 2023 年,新应用新服务的数量将达到 5 亿,也即是说:“每个企业都正在成为软件企业”。据IDC 预测,到 2025 年三分之二的企业将成为多产的“软件企业”,每天都会发布软件版本。越来越多的企…...

【测试篇】接口测试

接口测试,可以用可视化工具 postman。 如何做接口测试?? 我们可以先在浏览器中随机进入一个网页,打开开发者工具(F12)。 随便找一个接口Copy–>Copy as cURL(bash) 打开postman 复制地址 进行发送。 …...

突破校园网限速:使用 iKuai 多拨分流负载均衡 + Clash 代理(内网带宽限制通用)

文章目录 1. 简介2. iKuai 部署2.1 安装 VMware2.2 安装 iKuai(1) 下载固件(2) 安装 iKuai 虚拟机(3) 配置 iKuai 虚拟机(4) 配置 iKuai(5) 配置多拨分流 2.3 测试速度 3. Clash 部署(1) 配置磁盘分区(2) 安装 Docker(3) 安装 Clash(4) 设置代理 4. 热点:一起瓜分互…...

03-JAVA设计模式-工厂模式详解

工厂模式 工厂设计模式是一种创建型设计模式,它提供了一种封装对象创建过程的机制,将对象的创建与使用分离。 这种设计模式允许我们在不修改客户端代码的情况下引入新的对象类型。 在Java中,工厂设计模式主要有三种形式:简单工厂…...

百度文心大模型推理成本降至1% / 马斯克起诉OpenAI |魔法半周报

我有魔法✨为你劈开信息大海❗ 高效获取AIGC的热门事件🔥,更新AIGC的最新动态,生成相应的魔法简报,节省阅读时间👻 🔥资讯预览 百度文心大模型推理成本降至1%,与三星、荣耀等企业达成合作 马斯…...

Struts2的入门:新建项目——》导入jar包——》jsp,action,struts.xml,web.xml——》在项目运行

文章目录 配置环境tomcat 新建项目导入jar包新建jsp界面新建action类新建struts.xml,用来配置action文件配置Struts2的核心过滤器:web.xml 启动测试给一个返回界面在struts.xml中配置以实现页面的跳转:result再写个success.jsp最后在项目运行 配置环境 …...

git 标签功能操作以及回退

Git 标签功能允许开发者为特定的提交打上标签,以便后续能够方便地引用这些提交。标签通常用于标记重要的版本或里程碑,例如软件发布的版本号。与分支不同,标签指向的是固定的提交,一旦设置,就不能轻易更改。下面是一些…...

利用python实现文字转语音

代码如下: import pathlib import tkinter as tk import tkinter.ttk as ttk import tkinter.filedialog as filedialog import tkinter.messagebox as msgbox import pyttsx3class Application(tk.Tk):def __init__(self):super().__init__()self.title("文本…...

拾光坞N3 ARM 虚拟主机 i茅台项目

拾光坞N3 在Dcoker部署i茅台案例 OS:Ubuntu 22.04.1 LTS aarch64 cpu:RK3566 ram:2G 部署流程——》mysql——》java8——》redis——》nginx mysql # 依赖 apt update apt install -y net-tools apt install -y libaio* # 下载mysql wg…...

docker安装nacos,单例模式(standalone),使用mysql数据库

文章目录 前言安装创建文件夹"假装"安装一下nacos拷贝文件夹删除“假装”安装的nacos容器生成nacos所需的mysql表获取mysql-schema.sql文件创建一个mysql的schema 重新生成新的nacos容器 制作docker-compose.yaml文件查看网站 前言 此处有本人写得简易版本安装&…...

【运输层】传输控制协议 TCP

目录 1、传输控制协议 TCP 概述 (1)TCP 的特点 (2)TCP 连接中的套接字概念 2、可靠传输的工作原理 (1)停止等待协议 (2)连续ARQ协议 3、TCP 报文段的首部格式 1、传输控制协议…...

深入浅出 -- 系统架构之Keepalived搭建双机热备

Keepalived重启脚本双机热备搭建 ①首先创建一个对应的目录并下载keepalived安装包(提取码:s6aq)到Linux中并解压: [rootlocalhost]# mkdir /soft/keepalived && cd /soft/keepalived [rootlocalhost]# wget https://www.keepalived.…...

如何做好产业园运营?树莓集团:响应政府号召,规划,注重大局观

随着经济的发展和产业结构的调整,产业园区的建设和发展已经成为推动地方经济的重要力量。如何做好产业园运营,提高行业竞争力,现已成为了一个亟待解决的问题。树莓集团作为一家有着丰富产业园运营经验的企业,积极响应政府号召&…...

NIO与BIO

当谈到 Java 网络编程时,经常会听到两个重要的概念:BIO(Blocking I/O,阻塞 I/O)和 NIO(Non-blocking I/O,非阻塞 I/O)。它们都是 Java 中用于处理 I/O 操作的不同编程模型。 一、介…...

YOLOv5实战记录05 Pyside6可视化界面

个人打卡,慎看。 指路大佬:【手把手带你实战YOLOv5-入门篇】YOLOv5 Pyside6可视化界面_哔哩哔哩_bilibili 零、虚拟环境迁移路径后pip报错解决 yolov5-master文件夹我换位置后,无法pip install了。解决如下: activate.bat中修改…...

HTML5.Canvas简介

1. Canvas.getContext getContext(“2d”)是Canvas元素的方法,用于获取一个用于绘制2D图形的绘图上下文对象。在给定的代码中,首先通过getElementById方法获取id为"myCanvas"的Canvas元素,然后使用getContext(“2d”)方法获取该Ca…...

excel统计分析——多项式回归

参考资料:生物统计学 多项式回归属于单变量曲线回归,但其形式和求解方法与多元线性回归相似。多项式回归的数学模型为: 令,,,,则 由于X不可逆,两边同时乘以X得,&#xff…...

SQLyog连接数据库8.0版本解析错误问题解决方案

问题描述: 解决方案: alter userrootlocalhostidentified with mysql_native_password by 密码; 再次连接就可以了。...

【数据库】SQL简介

SQL(Structured Query Language,结构化查询语言)是一种用于管理关系型数据库管理系统(RDBMS)的标准化语言。它用于访问和操作数据库中的数据,执行各种任务,如插入、更新、删除和检索数据&#x…...

AWS入门实践-利用S3构建一个静态网站

使用Amazon S3托管静态网站是一个流行的选择,因为它简单、成本效益高,并且易于维护。静态网站由不含服务器端脚本的文件组成,如HTML、CSS和JavaScript文件。下面是使用S3托管静态网站的操作步骤: 如果大家没有AWS免费账号&#x…...

使用Linux strace追踪系统调用: 一个详细指南

使用Linux strace追踪系统调用: 一个详细指南 Linux strace是一个强大的命令行工具,用于监视和调试进程中发生的系统调用和信号。它对于系统管理员和开发人员来说是理解程序行为和解决问题的重要工具。 什么是strace? strace是一种跟踪运行中的进程执…...

python 笔记

文章目录 pdbpdb开始调试pythonpdb设置断点单步执行进入到函数的内部执行到下一个断点或程序结束调用栈查看命令查看当前函数调用堆栈向上一层函数查看调用堆栈查看源代码 importimport 用法 numpy导入numpy模块numpy常用函数np.argmaxnp.sum range生成连续序列生成不连续序列 …...

软考 系统架构设计师系列知识点之数据库基本概念(4)

接前一篇文章:软考 系统架构设计师系列知识点之数据库基本概念(3) 所属章节: 第6章. 数据库设计基础知识 第1节 数据库基本概念 6.1.3 数据库管理系统 DBMS(DataBase Management System,数据库管理系统&am…...

Vue - 3( 15000 字 Vue 入门级教程)

一:初识 Vue 1.1 收集表单数据 收集表单数据在Vue.js中是一个常见且重要的任务,它使得前端交互变得更加灵活和直观。 Vue中,我们通常使用v-model指令来实现表单元素与数据之间的双向绑定,从而实现数据的收集和更新。下面总结了…...

上位机图像处理和嵌入式模块部署(qmacvisual图像清晰度)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 做过isp的同学都知道,图像处理里面有一个3A,即自动曝光、自动白平衡和自动对焦。其中自动对焦这个,就需要用输入…...

数据结构和算法:分治

分治算法 分治(divide and conquer),全称分而治之,是一种非常重要且常见的算法策略。分治通常基于递归实现,包括“分”和“治”两个步骤。 1.分(划分阶段):递归地将原问题分解为两个…...

增强Java技能:使用OkHttp下载www.dianping.com信息

在这篇技术文章中,我们将探讨如何使用Java和OkHttp库来下载并解析www.dianping.com上的商家信息。我们的目标是获取商家名称、价格、评分和评论,并将这些数据存储到CSV文件中。此外,我们将使用爬虫代理来绕过任何潜在的IP限制,并实…...

用友 NC saveXmlToFIleServlet 任意文件上传漏洞复现

0x01 产品简介 用友NC是一款企业级ERP软件。作为一种信息化管理工具,用友NC提供了一系列业务管理模块,包括财务会计、采购管理、销售管理、物料管理、生产计划和人力资源管理等,帮助企业实现数字化转型和高效管理。 0x02 漏洞概述 用友 NC saveXmlToFIleServlet接口处存在…...

JS第九天

今天是第九天,学习了JS中的设置日期和倒计时,计时器以及验证码倒计时,那么话不多说我们开始今天的学习吧 一、日期设置 1.1日期创建 调用 new Date() 来创建一个新的 Date 对象。在调用时可以带有一些参数,创建一个 Date 对象&…...

网站链接提交/推广哪些app最挣钱

本文是根据自己的理解翻译组织了glog的manual,鉴于自身的理解能力和英语水平,可能存在谬误,欢迎大家指出!英文原文见http://google-glog.googlecode.com/svn/trunk/doc/glog.html1. 概述Google glog是一个基于程序级记录日志信息…...

哈尔滨企业网站开发报价/seo高级优化方法

该日历是用GridView来写的,其实跟普通的日历相比就增加了一个通过手势来拖动页面的效果,那这个手势gesture在android里是如何实现的呢?接下来我就为大家展示一下改程序的主要核心代码以及解析. 首先看一下效果图: 首先要创建一个GestureListener类来继承…...

曲阳有没有做网站里/网站设计论文

传统透水砖存在透水性差、易破碎、易风化等缺点,而陶瓷透水砖以废旧陶瓷、玻璃为原料,经高温烧结而成,提高了陶瓷透水砖的强度、透水性、装饰性等,并将部分废弃物变废为宝。1.陶瓷透水砖(1)透水保水性陶瓷透水砖的特殊颗粒结构和生…...

bbc wordpress 0day/南京响应式网站建设

原文:https://www.jianshu.com/p/9395c90e0055 一直都说,Threed.sleep是不会释放锁,而wait是释放锁的(对象锁),现理论上来分析一下啊。 由于CPU分配的每个线程的时间片极为短暂(一般为几十毫秒),所以,CPU…...

公司网站大全/友情链接样式

前言 今天我来全面总结一下Android开发中最常用的设计模式 - 适配器模式。 目录 1. 介绍 1.1 定义 适配器模式,即定义一个包装类,用于包装不兼容接口的对象 包装类 适配器Adapter; 被包装对象 适配者Adaptee 被适配的类 1.2 主要作用 …...

静态网站建设的流程/网站设计是做什么的

华为“迷茫”:领跑者的孤独 只有当你走在所有人前面的时候,才有可能迷茫。 而敢于说出“迷茫”二字,正表明任正非的清醒。 在2016年5月30日召开的全国科技创新大会上,华为创始人、总裁任正非有一个著名的讲话,其中一段…...