plainify

三行代码让你的git记录保持整洁

前言 笔者最近在主导一个项目的架构迁移工作,由于迁移项目的历史包袱较重,人员合作较多,在迁移过程中免不了进行多分支、多次 commit 的情况,时间一长,git 的提交记录便混乱不堪,随便截一个图形化的 git 提交历史给大家感受一下。 各种分支疯狂打架宛如后宫争宠的妃子们,之所以会出现这种情况,主要还是因为滥用 git merge 命令并且不考虑后续的理解成本导致的。如今在大厂工作的程序员们,频繁接受变更的需求,一旦一开始考虑不周到,就一定会出现了大量无意义的 commit log,加上“敏捷”理念的推广,产品的快速迭代上线变成了核心指标,这些无意义的 commit log 便被“下次再处理”,久而久之就混乱不堪了。 而我们在看一些开源仓库时,会发现他们的 commit 记录十分整洁,其实这并不是社区的程序员能力更强,而是因为他们没有 KPI 大棒的鞭笞,在提交代码前会花时间整理自己的 commit log。而这就是本文的主角了——“Git Rebase”。 git rebase 和 git merge git rebase,中文翻译为“变基”,通常用于分支合并。既然提到了分支合并,那就一定离不开git merge这个命令。 相信每个新手程序员刚进入职场的时候,都会听到“xxx 你把这个分支 merge 一下”这样的话。那么问题来了,假如你有 6 个程序员一起工作, 你就会有 6 个程序员的分支, 如果你使用 merge, 你的代码历史树就会有六个 branch 跟这个主的 branch 交织在一起。 上图是 git merge 操作的流程示意图,Merge 命令会保留所有 commit 的历史时间。每个人对代码的提交是各式各样的。尽管这些时间对于程序本身并没有任何意义。但是 merge 的命令初衷就是为了保留这些时间不被修改。于是也就形成了以 merge 时间为基准的网状历史结构。每个分支上都会继续保留各自的代码记录,主分支上只保留 merge 的历史记录。子分支随时都有可能被删除。子分子删除以后,你能够看到的记录也就是,merge 某 branch 到某 branch 上了。这个历史记录描述基本上是没有意义的。 而 git rebase 中文翻译为“变基”,变得这个基指的是基准。如何理解这个基准呢?我们看一下下图。...

2023-02-25 252 words 2 min
plainify

把你的IDE搬进浏览器里——JetBrains Projector 初体验

前言 对于云端编程,我想大多数人的第一想法应该是微软推出的 VSCode Remote,这个功能基于开源的 VSCode,通过 SSH 远程连接到服务器,开发者可以通过端口转发、SCP 等一系列实用功能快速实现远程开发。我曾体验过这种编程方式,极大减轻了电脑性能的压力,但我认为这并不是云端编程的最终形态,因为我仍然需要在自己的电脑上安装 VSCode 才可以使用这个功能。 最近 2021 款的 iPad Pro 上市了,这次搭载的是和 Mac 同款的 M1 芯片,性能强大到甚至有让人利用 iPad 编程的想法,只是迫于各大厂商没有推出适配 iPad 的 IDE,便也只能沦为“买钱生产力,买后爱奇艺”的工具了。那么有没有什么办法可以在不安装 IDE 的情况下使用 iPad 编程吗?自然是有的,JetBrains 公司提出了一种新的解决方案:把 IDE 搬进浏览器里。这便是本文的主角——JetBrains Projector。 发展 提起 JetBrains,你会想到什么?各路强大的 IDE,比如 Android Studio、IDEA、WebStorm……这些对于开发者来说耳熟能详的产品都出自这家公司,这些 IDE 的功能强大,但同时也只能运行在用户自己的电脑上,其“内存黑洞”的称号更是让开发者们又爱又恨。 事实上,目前所有的 JetBrains IDE 都使用 Java Swing 绘制 UI,其他基于 IntelliJ 的 IDE 也是如此,比如 Android Studio。鉴于 Swing 是 Java GUI 的一个库,而 Java 本身就是一门很吃内存的编程语言,虽然可以充分利用 Java 跨平台的特性,这也是这些 IDE 在 macOS、Windows 和 Linux 上 UI 几乎一致的原因。但现在,Swing 跨桌面平台的特性却也成为阻碍其发展的一个原因了,在一些瘦客户端的情况下,“内存黑洞”屡屡被人诟病,Swing 也无法发挥其优势,于是 Projector 便应运而生了。...

plainify

AI换脸——汝怎饰品如面

事先说明,该篇文章中的代码是我无意中发现的,这里仅做一个分享,文末会给出参考文章,不喜勿喷。 完整源码和预训练模型可在公众号:「01 二进制」后台回复:「AI 换脸」获取 前言 作为一个经常逛 b 站的肥宅,前段时间无意中看到了一个名为"换脸哥"做的换脸视频,让杨幂“穿越”到了 1994 年版的《射雕英雄传》里,“代替”了朱茵,“出演”了黄蓉这个角色。视频如下(b 站视频已经被删了,只能转载知乎的视频了,原地址是杨幂“换脸”,AI 换脸究竟有多可怕 - 科技富能量的文章 - 知乎): 看完我便虎躯一震,这也太厉害了吧,这种技术一旦流行起来,ab 不用去片场就能拍戏了啊,真的是躺着赚钱啊。这要是运用到 H 片上,岂不是 😅😅😅 言归正传,作为一个 coder,在看到这个视频之后我就很想知道这究竟是怎么做出来的,在查阅了一些资料后,我才发现最悲伤的事情莫过于,好不容易把源码找到了,数据集下载好了,结果显卡带不起来… Tips:这里给出我之前找到的两个有关视频换脸的仓库,有兴趣的自己去了解下: deepfakes_faceswap FaceIt 既然条件不允许,那我们只能降低成本,既然视频里的脸不好换,那就退而求其次,换一下图片里面的脸,果然在我的苦苦寻觅后,我找到了一个低配版的 Python 换脸大法: 《Switching Eds: Face swapping with Python, dlib, and OpenCV》 以下内容均参考上述所标注的文章,在这感谢原作者。 接下来我将会介绍如何通过一段简短的 Python 脚本(200 行左右)将一张图片中面部特征自动替换为另外一张图片中的面部特征。 具体过程分为四个步骤: 检测面部标志; 旋转、缩放和平移图 2 以适应图 1; 调整图 2 的白平衡以匹配图 1; 将图 2 的特征融合到图 1 中; 实验环境 MacOS 10....

plainify

AI画家第三弹——毕业设计大杀器之Flask

上一篇介绍了图像风格迁移的一个最基本实现,虽然在控制台实现了功能,但是想要实际使用,应用到一个app或者网页上光靠上一节的内容肯定是不行的。那怎么样才可以将风格迁移这个功能变成一个可以实际使用的小程序呢?不着急,在实现上述功能前,我们先来介绍一个小东西,也就是这篇文章的主角,我把他称为"毕业设计大杀器“的Flask框架。 前后端分离 在介绍Flask之前,我们先介绍下什么是前后端分离。因为如果不介绍前后端分离就不会理解为啥要选择Flask了。前后端分离是目前互联网项目开发的标准使用方式,其核心思想简单理解为是前端页面(或者app等多端)通过ajax(或者其他请求方式)调用后端的restuful api接口并使用json数据进行交互。其目的是为了将项目解耦合,达到**“术业有专攻”**的效果。因为在以往的web项目中,后端人员的工作量非常大,用过jsp的人都知道,那真的是又当爹又当妈,既要会写后台逻辑还要会弄样式。但是采用了前后端分离的架构之后,前后端人员就可以各司其职了。 前端人的追求 前端追求的是:页面表现,速度流畅,兼容性,用户体验等等。 把精力放在html5,css3,jquery,angularjs,bootstrap,reactjs,vuejs,webpack,less/sass,gulp,nodejs,Google V8引擎,javascript多线程,模块化,设计模式,浏览器兼容性,性能优化等等。 后端人的追求 后端追求的是:三高(高并发,高可用,高性能),安全,存储,业务等等。 把精力放在语言基础,设计模式,底层原理,linux,mysql事务隔离与锁机制,mongodb,http/tcp,多线程,分布式架构,弹性计算架构,微服务架构,性能优化,以及相关的项目管理等等。 应用服务器、Web服务器、Restful 应用服务器:一般指像tomcat,jetty这类的服务器可以解析动态资源也可以解析静态资源,但解析静态资源的能力没有web服务器好。 Web服务器:一般指像nginx,apache这类的服务器,他们一般只能解析静态资源。 静态资源就是类似于html、js、图片这些多次访问也不会变化的资源 一般都是只有web服务器才能被外网访问,应用服务器只能内网访问。 RESTful REST的全称是representational state transfer,即表征状态转移。在理解这个名词之前我们先来看几个名词(感觉需要知道的前置知识好多啊)。 资源(resources) 所谓的资源就是网络上的一个实体,它可以使一个图片,一个文本,一个服务,你可以用一个URI指向它,每种资源对应一个特定的URI,要获取这个资源访问它的URI就行了,所谓的上网,其实就是与网络上的资源进行一系列的互动就是了。 表征(representation) 怎么把资源表现出来就是表征的意义,比如一段文本是txt、html还是json,图片是jpg还是png,以http协议为例,就是Accept和content-type中的内容,说明了资源的类型。 状态转移(state tranfer) 访问一个网站,就是客户端和服务端的一个交互过程,客户端想要操作服务端,就必须通过某种手段让服务端的状态发生变化,具体到http协议中就是http的几种方法:GET用来获取资源,POST用来新建资源,PUT用来更新资源,DELETE用来删除资源。 理解RESTful 使用URI来表示每一个资源 为每一个资源确定它的表现形式 使用4个方法来操作这些资源 什么是Flask? 介绍完前后端分离后,我们就开始介绍下Flask是什么吧。 Flask是一个使用 Python 编写的轻量级 Web 应用框架。其 WSGI 工具箱采用 Werkzeug ,模板引擎则使用 Jinja2。Flask也被称为 “microframework” ,即**“微框架”**,因为它使用简单的核心,用 extension 增加其他功能。Flask没有默认使用的数据库、窗体验证工具。 理解下"微” “微"框架中的“微”(micro) 并不表示你需要把整个 Web 应用塞进单个 Python 文件(虽然确实可以 ),也不意味着 Flask 在功能上有所欠缺。微框架中的“微”意味着 Flask 旨在保持核心简单而易于扩展。Flask 不会替你做出太多决策——比如使用何种数据库。而那些 Flask 所选择的——比如使用何种模板引擎——则很容易替换。除此之外的一切都由可由你掌握。默认情况下,Flask 不包含数据库抽象层、表单验证,或是其它任何已有多种库可以胜任的功能。然而,Flask 支持用扩展来给应用添加这些功能,如同是 Flask 本身实现的一样。众多的扩展提供了数据库集成、表单验证、上传处理、各种各样的开放认证技术等功能。Flask 也许是“微小”的,但它已准备好在需求繁杂的生产环境中投入使用。...

plainify

AI画家第五弹——从0到1部署你的RESTful API

上一篇文章中我们已经利用 Flask 制作了一个 RESTful API,然而文中末尾我们我们将代码运行起来的时候确发现是 localhost:xxxx,这也就意味着我们没法通过外网访问我们提供的 API,所以这样做出来的程序即使部署到服务器上也没有任何用处。这一篇我们就来详细的说下怎么部署到服务器上然后实现外网访问吧。 环境准备 工欲善其事,必先利其器。还是老样子,既然要选择部署到服务器上,我们首先肯定得要有一个服务器,这里我选择 XX 云的学生机(别问为什么,问就是便宜)。系统选择 Ubuntu18.04,需要安装的东西有: Python 3.6 Nginx pyenv pipenv Flask + Gunicorn 这里我们用 pyenv 管理不同的 python 版本,这里可能就有人要问了,Ubuntu 不是自带 python2 和 python3 吗,为什么还要用 pyenv 来管理,之前的文章我们也说过,用 pyenv 管理 python 会非常的方便,方便到只需要一行代码就可以安装切换系统的 Python 版本,废话不多说,接下来就开始我们的操作吧。 连接到远程服务器 如何购买 XX 云的云主机我就不多说了,当你买好之后我们在后台查看到我们购买的云主机的外网 IP,比如我的服务器的外网 IP 地址就是94.191.9.43(希望各位大佬手下留情,别弄他): 接下来就是连接到服务器了,工具有很多,xshell、putty 或者 terminal 都可以,这里我推荐一个工具Termius,推荐他的原因有两个:颜值,作为一个颜控,Termius 是我见过的最好看的 SSH 客户端,没有之一。同时还是跨平台的,win/mac/linux/android/ios 都支持,这点不知道比 xshell 高到哪里去了。 连接也很简单,我们在 termius 中添加需要连接的 host,然后输入用户名和密码即可登录了,出现如下字样说明登录成功。 利用 pyenv 安装制定版本的 python 之前的文章介绍过如何在 mac 下安装 pyenv,虽然 linux 下的安装方法类似,但毕竟本文的题目是是从 0 到 1 部署,还是再详细说一下吧。...

AI画家第六弹——终章

Photo by Tim Gouw from Pexels 正如文章标题所言,本文是我的**《AI画家》**系列的终章,从4月16号开始的第一篇文章《介绍一下我的毕业设计》到今天已经过了将近2个月了(2个月就更新7篇文章我也是服了我自己了😂),其实这个系列就是我的毕业设计,如今我的毕设做完了,论文也定稿了,想着也该给这个系列画个句号了。 在公众号上发系列文章是我的一次尝试,因为知道自己的文笔不好,写不好什么感悟感想,只能水水技术文了,然而即使要写技术文也得找个切入点,可事实上哪会有那么多切入点,无奈只能靠弄个技术文系列,吸引下路人的眼球,勉强度日了。 既然是终章,那就对整个系列做个简单的总结吧,希望这篇不会是烂尾文。 开题 在《介绍一下我的毕业设计》一文中我提到,刚开始我单纯因为觉得好玩才开始研究图像风格迁移,后来认为名字逼格够高,足够唬住老师才把这个课题作为我的毕设,现在回过头来结合最后的答辩觉得自己选这个题目的毕设是真的傻X,不是因为这个选题不好,而是把这个选题作为毕业设计的题目真的傻X,说到这就想起一些在答辩现场不好的事情了,溜了溜了。 过程 作者自认为在这个系列中思路还是比较清晰的。 首先是第一弹,想要做深度学习有关的东西,刚开始肯定是要搭建好一个深度学习的环境的。在这篇文章中,详细的介绍了在我的游戏本上利用GPU搭建深度学习环境的过程,包括安装nvidia drive、CUDA、cuDNN和TensorFlow的GPU版本,以及简单介绍了如何利用Pyenv和Pipenv管理自己电脑上的Python虚拟环境。 然后是第二弹,介绍了什么是图像风格迁移,以及如何用TensorFlow实现了一个基本的图像风格迁移的程序,在这篇文章中我只是简单的介绍了图像风格迁移的原理,一方面是因为公式实在是有点多,公众号对于公式的支持不是很好,另一方面作为一个入门介绍,放太多的数学公式的话估计本来人数不多的公众号又要取关一批人了。 第三弹介绍了一个目前非常流行的Python web框架Flask,介绍他的原因不仅仅是因为我的毕业设计就是用这玩意做的,而且在开题的时候我也提到了最后要将这个深度学习算法落地,能够做出一个可用的RESTful API,而相较于其他Web框架,Flask有着得天独厚的优势:首先TensorFlow的首选语言是Python,Flask也是用Python写的,调用起来非常方便;相对于Django,Flask非常轻便,使用起来也非常的灵活。然而在用Flask之前,必须要有些基础知识,因此在这篇文章开篇,我又介绍了前后端分离,介绍了什么是RESTful API,如果对这些概念没有理解的话就算把代码写出来了也很难知道是干嘛的。 既然在第三弹介绍了一个用来编写RESTful API的工具,那第四弹自然就是如何编写这个RESTful API了。其实在第二弹中就指出了那个算法的不足之处——“慢”,所以在这篇文章中就使用了第二个算法训练出来的模型,之所以不介绍新的风格迁移算法,主要是因为这个算法有点难度,我理解的时候也花了好长时间,等到基本上理解了,第四弹都已经写完了😂。所以在这篇文章中我干脆直接用别人训练好的现成的模型了。其中介绍了如何利用蓝图(BluePrint)进行模块化开发,并给出了我自己认为的比较好的分层方法,然后利用七牛云存储为服务器减压,最后利用Postman请求该API完成测试。 第五弹的主要内容就是介绍如何将第四弹中已经在本地测试成功的项目发布到服务器上实现公网访问,介绍了如何使用了XX云主机,并在上面安装配置了项目所需要使用到的环境的过程,介绍了Termius、FileZilla等工具。在这篇文章中我希望会有些和别的文章不一样的东西,因此我不仅把实现过程展现了出来,还分享了一些我在实际使用过程中产生的疑问,踩到的坑以及我个人在部署过程中总结的一些经验。 最后 总的来说,这个系列不仅仅是我在做毕业设计时的一个缩影,也是我自己对于公众号运营的一个探索。期间也收到了很多读者的支持与鼓励,感谢你们的一路陪伴🙏 推荐阅读 《介绍一下我的毕业设计》 《AI 绘画第一弹——用GPU为你的训练过程加速》 《AI绘画第二弹——图像风格迁移》 《AI画家第三弹——毕业设计大杀器之Flask》 《AI画家第四弹——利用Flask发布风格迁移API》 《AI画家第五弹——从0到1部署你的RESTful API》

plainify

AI画家第四弹——利用Flask发布风格迁移API

上篇文章介绍了python web开发中经常使用到的一个框架flask,如果有遗忘的,可以点此回顾👉AI画家第三弹——毕业设计大杀器之Flask,本文的主要任务就是完成上篇文章末尾的要求,利用Flask发布你自己的风格迁移API。 本文源码可在微信公众号「01二进制」后台回复「风格迁移API」获得 需求分析 我们知道软件工程的第一步就是需求分析,放在这里就是要知道我们需要实现的功能是什么样的。我画了一张简陋的图来描述这次的需求: 真的是很简陋的一张图啊,其实理解起来很容易,就是用户上传一张图片,Flask获取到这张图片,调用风格迁移的模型,然后生成结果图,在传递回前端即可。 环境准备 既然明白了需求,那么接下来要做的事情自然是环境搭建了,老样子,这里我们仍然使用Pipenv来创建虚拟环境,如何搭建pipenv环境我就不说了,在微信公众号「01二进制」后台回复「风格迁移API」获得源码之后直接在终端输入pipenv install即可。 开始 hello world 我们首先在项目根目录创建一个main.py的文件作为整个项目的启动文件,上文我们说过,为了简化大型应用并为扩展提供集中的注册入口,我们并不会将所有的视图函数直接写在main.py,而是采用蓝图的方式分模块开发,因此我们需要在项目根目录新建app/文件夹,在其中的__init__.py中编写如下代码: from flask import Flask def create_app(): app = Flask(__name__) return app 这样我们就可以通过在main.py中编写如下代码实现一个hello world应用了。 from app import create_app app = create_app() @app.route('/') def hello(): return 'hello,world' if __name__ == '__main__': app.run(port=8080, debug=True) 启动main.py即可发现项目启动了,在浏览器输入localhost:8080即可看到hello,world字样。 蓝图编写 我们肯定是不能满足于小小的hello world的,既然说到了模块化开发,那怎么个模块法? 这里每个人的想法都是不一样的,其实也没有一个统一的标准,这里我就说下我自己的分级方法吧。 stylize是项目根路径 app是项目 app/api是项目的api部分,一个项目肯定不只有api,还可能会有web等页面内容 app/api/v1表明该api的版本是v1,当然日后也有可能会有v2、v3等等 app/api/v1/img表明这里存放的都是和img有关的api app/api/v1/img/stylize.py表明这个文件存放的是风格迁移的视图函数 认识完结构的划分之后,就来编写我们的蓝图吧。 首先我们需要在app/api/v1/img/__init__.py中编写如下代码: from flask import Blueprint # 定义一个蓝图 img = Blueprint('img', __name__) from app....

plainify

AI绘画第二弹——图像风格迁移

这篇文章是我的《AI 绘画系列》的第三篇,点击此处可以查看整个系列的文章 本篇文章的源码可以在微信公众号「01 二进制」后台回复「图像风格迁移」获得 简介 所谓图像风格迁移,是指将一幅内容图 A 的内容,和一幅风格图 B 的风格融合在一起,从而生成一张具有 A 图风格和 B 图内容的图片 C 的技术。目前这个技术已经得到了比较广泛的应用,这里安利一个 app——“大画家”,这个软件可以将用户的照片自动变换为具有艺术家的风格的图片。 准备 其实刚开始写这篇文章的时候我是准备详细介绍下原理的,但是后来发现公式实在是太多了,就算写了估计也没什么人看,而且这篇文章本来定位的用户就是只需要实现功能的新人。此外,有关风格迁移的原理解析的博客实在是太多了,所以这里我就把重点放在如何使用 TensorFlow 实现一个快速风格迁移的应用上,原理的解析就一带而过了。如果只想实现这个效果的可以跳到**“运行”**一节。 第一步我们需要提前安装好 TensorFlow,如果有 GPU 的小伙伴可以参考我的这篇文章搭建一个 GPU 环境:《AI 绘画第一弹——用 GPU 为你的训练过程加速》,如果打算直接用 CPU 运行的话,执行下面一行话就可以了 pip install numpy tensorflow scipy 原理 本篇文章是基于A Neural Algorithm of Artistic Style一文提出的方法实现的,如果嫌看英文论文太麻烦的也可以查看我对这篇文章的翻译【译】一种有关艺术风格迁移的神经网络算法。 为了将风格图的风格和内容图的内容进行融合,所生成的图片,在内容上应当尽可能接近内容图,在风格上应当尽可能接近风格图,因此需要定义内容损失函数和风格损失函数,经过加权后作为总的损失函数。 预训练模型 CNN 具有抽象和理解图像的能力,因此可以考虑将各个卷积层的输出作为图像的内容,这里我们采用了利用 VGG19 训练好的模型来进行迁移学习,一般认为,卷积神经网络的训练是对数据集特征的一步步抽取的过程,从简单的特征,到复杂的特征。训练好的模型学习到的是对图像特征的抽取方法,而该模型就是在 imagenet 数据集上预训练的模型,所以理论上来说,也可以直接用于抽取其他图像的特征,虽然效果可能没有在原有数据集上训练出的模型好,但是能够节省大量的训练时间,在特定情况下非常有用。 加载预训练模型 def vggnet(self): # 读取预训练的vgg模型 vgg = scipy.io.loadmat(settings.VGG_MODEL_PATH) vgg_layers = vgg['layers'][0] net = {} # 使用预训练的模型参数构建vgg网络的卷积层和池化层 # 全连接层不需要 # 注意,除了input之外,这里参数都为constant,即常量 # 和平时不同,我们并不训练vgg的参数,它们保持不变 # 需要进行训练的是input,它即是我们最终生成的图像 net['input'] = tf....

plainify

Docker 安装 RocketMQ 并结合 SpringBoot 使用实例

在之前的《浅入浅出消息队列》一文中,我们了解了消息队列的作用、优缺点和使用场景,相信你对消息队列已经有了一个大致的概念,文末给自己埋的坑说日后会写一篇实战教程,正好现在实习结束了,也许久没有写实战教程了,于是这就来填坑了。 前置知识 阅读本文前,建议有一些前置知识,包括且不限于: 常见的 Linux 命令 消息队列的相关知识 Docker 的基本使用 docker-compose 的基础知识 SpringBoot 的基本使用 那废话不多说,我们就开始吧。 本文的所涉及到的代码可在微信公众号「01 二进制」后台回复「rocketmq」获得。 为什么要以 RocketMQ 为例? 本文主要是为了通过实例的方式直观的了解消息队列。那么问题来了,消息队列那么多(ActiveMQ、RabbitMQ、Kafka),我为什么要选择 RocketMQ 呢?这里我们不谈原理,只说说体验,仅是个人选择,不喜勿喷。 背靠阿里,不看测评,纯粹看他经历过多次双十一的检验就已经知道其性能是处于第一批次的。 作为一个 Java 程序员,如果选择一个纯 Java 编写的软件,后期阅读其源码难度也会小很多。(RabbitMQ 底层是 Erlang,kafka 底层是 Scala) 在阿里实习的时候一直都是使用 RocketMQ 的内部版本,于我而言,RocketMQ 更熟悉。 初识 RocketMQ 在使用消息队列前,我们要知道消息队列是什么,这一块内容参考之前的文章《浅入浅出消息队列》,这里不再赘述。 本段节来讲解 RocketMQ 所涉及到的相关概念,我们先来简单看下官方给出的 RocketMQ 架构图 从上图我们可以很直观的看出,一个完整的 RocketMQ 架构包含四个部分:NameServer、Broker、Producer 和 Consumer。 NameServer:主要用作注册中心,用于管理 Topic 信息和路由信息的管理 Broker:负责存储、消息 tag 过滤和转发。需将自身信息上报给注册中心 NameServer Producer:生产者 Consumer:消费者 从寄信的角度理解 上面的解释可能难以理解,我们从寄信这一实例来看以下四个部分所承担的责任。 Producer 和 Consumer 不必多说,消息的生产者和消费者,生产者负责投递消息,消费者负责接收消息,是我们要编写的应用程序。可以理解为寄信人和收信人。 Broker 负责消息存储,以 Topic(主题)为维度,以队列的形式存储消息。可以理解为信箱,专门存储信件,收信人(Consumer)可以从这里获取信件。 NameServer 负责对源数据进行管理,包括了对 Topic 和 Broker 的管理。可以理解为邮局,负责管理邮件的分发,维护信箱(Broker)的状态。 由上各部分角色的功能可知,我们需要先安装启动 NameServer,再启动 Broker 即可搭建完 RocketMQ...

Flutter主题切换——让你的APP也能一键换肤

为了让你的 App 更美观,主题切换已经是一个必不可少的功能了,但如果想在传统的 Android 和 iOS 上分别适配不同的主题相当繁琐。但这一切,在 Flutter 中都非常容易实现。今天我们就来看看,如何在 Flutter 中给你的 App 添加换肤功能。我们要实现的效果如下: 添加依赖 在该案例中,我使用到了 provider 和 flustars 两个库,简单介绍一下这两个库: provider 官方推荐的状态管理库,相比其他状态管理库使用起来比较方便。 状态管理:通俗的讲,当我们想在多个页面(组件/Widget)之间共享状态(数据),或者一个页面(组件/Widget)中的多个子组件之间共享状态(数据),这个时候我们就可以用 Flutter 中的状态管理来管理统一的状态(数据),实现不同组件直接的传值和数据共享。 flustars 号称“Flutter 全网最全常用工具类”,其中包括了SpUtil、ScreenUtil、TimelineUtil等常见工具类,这里我们要使用的是SpUtil这个部分,用于存储用户所选择的主题信息。 以上就是关于我们使用的两个第三方库的介绍,如果想要使用,我们需要在pubspec.yaml文件中添加如下内容: provider:^4.0.5flustars:^0.2.6+1准备工作做好了,接下来我们就开始编码吧。 添加主题样式 我们需要先想好自己所需要切换的主题样式列表,如果觉得麻烦的可以直接用下面的内容: Map<String, Color> themeColorMap = { 'gray': Colors.grey, 'blue': Colors.blue, 'blueAccent': Colors.blueAccent, 'cyan': Colors.cyan, 'deepPurple': Colors.purple, 'deepPurpleAccent': Colors.deepPurpleAccent, 'deepOrange': Colors.orange, 'green': Colors.green, 'indigo': Colors.indigo, 'indigoAccent': Colors.indigoAccent, 'orange': Colors.orange, 'purple': Colors.purple, 'pink': Colors.pink, 'red': Colors.red, 'teal': Colors.teal, 'black': Colors....