容器持久化存储-容器有状态应用调研报告
前言本文通过调研主流开源社区、权威调研机构推荐总结了最常用的 TOP 有状态应用分布。同时基于使用容器持久化存储部署容器有状态应用总结了当前应用部署方案、数据类型、有状态应用类型占比,分析了容器持久化存储数据共享、弹性扩展、性能需求以及挑战。“从用户视角看云原生带来的存储变化,最明显的就是用户使用存储界面发生上移,和应用不直接相关的存储服务从应用层下沉到云平台,用户更关心应用。存储供给的特性更加高密、弹性、极速。”—— 徐立 阿里云文件存储负责人 1. 容器持久化存储-容器有状态应用调研说明TOP 有状态应用列表:- 通过调研主流开源社区推荐、调研 ACK 容器服务应用目录 & Gartner 推荐有状态应用目录、调研权威机构如 Bitnami 适合云上部署 Mulit-tier application & single-tier application 应用【请参考本文 “4.附录” 章节】- 总结最常用的 TOP 有状态应用列表如下:数据库:Cassandra、MariaDB、MongoDB、MySQL、Neo4j、PostgreSQL、Redis、etcd内容管理:Drupal、CKAN、MediaWIKI、DNN、Joomls持续集成部署:Jenkins、Gitlab、maven、Puppet大数据:Hadoop、Hypertable、Mesos、Presto、Solr、Spark、Storm分析搜索:Grafana、ElasticSearch、Prometheus、kibana、logstashWeb服务:NGINX、WordPress、Apache HTTP Server、Tomcat、httpdInfrastructure:RabbitMQ、Memcached、Kafka、ZooKeeper、Node.js、NATS、wildfly开发工具:LAMPAI:mxnet、Pytorch、tensorflow-notebook、tensorflow-resnet 2. 容器持久化存储-容器有状态应用调研总结:当前应用采用容器化部署比例:75.34%当前容器化部署环境占比:36.99% 选择阿里云容器服务 ACK12.33% 选择阿里云 Serverless 容器服务 ASK53.42% 选择自建容器服务当前容器环境使用持久化存储方案: 73.97% 使用文件存储43.84% 使用块存储方案当前数据的主要类型:结构化数据,例如数据库占比 79.45%非结构化数据,例如文件占比 49.32%当前容器的主要应用类型:选择有状态应用的用户占比 61.64% 选择无状态应用的用户占比 56.16%当前容器的有状态应用类型占比:TOP3 数据库 Web服务 持续集成部署数据库: 64.38%,其有状态应用的分布比例如下所示题目/选项CassandraMariaDBMongoDBMySQLNeo4jPostgreSQLRedisetcd数据库应用2.13%4.26%10.64%74.47%02.13%4.26%2.13%内容管理:10.96%,其有状态应用的分布比例如下所示题目/选项DrupalCKANMediaWIKIDNNJoomls其他内容管理37.50%37.50%50.00%37.50%25.00%12.50%持续集成部署:42.47%,其有状态应用的分布比例如下所示题目/选项JenkinsGitlabmavenPuppet其他持续集成部署80.65%48.39%48.39%9.68%12.90%大数据:12.33%,其有状态应用的分布比例如下所示题目/选项HadoopHypertableMesosPrestoSolrSparkStorm大数据77.78%11.11%00011.11%0分析搜索:10.96%,其有状态应用的分布比例如下所示题目/选项GrafanaElasticSearchPrometheuskibanalogstash其他分析搜索12.50%62.50%12.50%0012.50%Web服务:45.21%,其有状态应用的分布比例如下所示题目/选项NGINXWordPressApache HTTP ServerTomcathttpd其他Web 服务57.58%3.03%9.09%27.27%3.03%0Infrastructure:9.59%,其有状态应用的分布比例如下所示题目/选项RabbitMQMemcachedKafkaZooKeeperNode.jsNATSwildfly其他Infrastructure71.43%14.29%42.86%28.57%28.57%0042.86%开发工具:16.44%AI:8.22%,其有状态应用的分布比例如下所示题目/选项mxnetPytorchtensorflow-notebooktensorflow-resnet其他AI75.00%100.00%50.00%75.00%25.00%有容器持久化存储数据共享需求用户占比:64.38% 有容器持久化存储弹性扩展需求用户占比:60.27%当前结构化数据容量规模:500GB 以下:占比 15%500GB - 2TB:占比 70%2 - 10TB:占比 10%10TB 以上:占比 5%当前非结构化数据容量规模50TB 及以上占比:37%20-30TB 占比:15%1-10TB 占比:27%1TB 以下占比:21%当前非结构化数据访问的性能要求:Bandwidth:53%Latency:25%IOPS:26%当前在使用容器存储的过程中,面临的主要挑战有哪些?数据安全,如权限、加密:占比 18%性能:占比 12%学习实践,如技术迭代慢、缺少实战经验:占比 32%弹性伸缩:占比 10%简化开发运维,如部署复杂度高、开发难度高,问题排查困难:占比 14%数据共享高可用:占比 12%成本:占比 4%稳定性:占比 8% 3. 容器持久化存储-容器有状态应用调研问卷反馈详情:3.1 当前应用采用容器化部署比例:75.34%3.2 当前容器化部署环境占比:36.99% 选择阿里云容器服务 ACK12.33% 选择阿里云 Serverless 容器服务 ASK53.42% 选择自建容器服务3.3 当前容器环境使用持久化存储方案: 73.97% 使用文件存储43.84% 使用块存储方案3.4 当前数据的主要类型:结构化数据,例如数据库占比 79.45%非结构化数据,例如文件占比 49.32%3.5 当前容器的主要应用类型:有状态应用占比 61.64% 无状态应用占比 56.16%3.6 当前容器的有状态应用类型占比:选项比例数据库:Cassandra、MariaDB、MongoDB、MySQL、Neo4j、PostgreSQL、Reids、etcd64.38%内容管理:Drupal、CKAN、MediaWIKI、DNN、Joomls10.96%持续集成部署:Jenkins、Gitlab、maven、Puppet42.47%大数据:Hadoop、Hypertable、Mesos、Presto、Solr、Spark、Storm12.33%分析搜索:Grafana、ElasticSearch、Prometheus、kibana、logstash10.96%Web服务:NGINX、WordPress、Apache HTTP Server、Tomcat、httpd45.21%Infrastructure:RabbitMQ、Memcached、Kafka、ZooKeeper、Node.js、NATS、wildfly9.59%开发工具:LAMP16.44%AI:mxnet、Pytorch、tensorflow-notebook、tensorflow-resnet5.48%其他8.22%3.7 当前容器环境的【数据库】的应用类型:题目/选项CassandraMariaDBMongoDBMySQLNeo4jPostgreSQLRedisetcd数据库应用2.13%4.26%10.64%74.47%02.13%4.26%2.13%3.8 当前容器环境的【内容管理】的有状态应用类型题目/选项DrupalCKANMediaWIKIDNNJoomls其他内容管理37.50%37.50%50.00%37.50%25.00%12.50%3.9 当前容器环境的【持续集成部署】的有状态应用类型题目/选项JenkinsGitlabmavenPuppet其他持续集成部署80.65%48.39%48.39%9.68%12.90%3.10 当前容器环境的【大数据】的应用类型题目/选项HadoopHypertableMesosPrestoSolrSparkStorm大数据77.78%11.11%00011.11%03.11 当前容器环境的【分析搜索】的应用类型题目/选项GrafanaElasticSearchPrometheuskibanalogstash其他分析搜索12.50%62.50%12.50%0012.50%3.12 当前容器环境的【Web 服务】的有状态应用类型题目/选项NGINXWordPressApache HTTP ServerTomcathttpd其他Web 服务57.58%3.03%9.09%27.27%3.03%03.13 当前容器环境的【Infrastructure】的有状态应用类型题目/选项RabbitMQMemcachedKafkaZooKeeperNode.jsNATSwildfly其他Infrastructure71.43%14.29%42.86%28.57%28.57%0042.86%3.14 当前容器环境的【AI】的有状态应用类型题目/选项mxnetPytorchtensorflow-notebooktensorflow-resnet其他AI75.00%100.00%50.00%75.00%25.00%3.15 有容器持久化存储数据共享需求用户占比:64.38% 3.16 有容器持久化存储弹性扩展需求用户占比:60.27%3.17 当前结构化数据容量规模:500GB 以下:占比 15%500GB - 2TB:占比 70%2 - 10TB:占比 10%10TB 以上:占比 5%3.18 当前非结构化数据容量规模:50TB 及以上占比:37%20-30TB 占比:15%1-10TB 占比:27%1TB 以下占比:21%3.19 当前非结构化数据访问的性能要求Bandwidth:53%Latency:25%IOPS:26%3.20 当前在使用容器存储的过程中,面临的主要挑战有哪些?数据安全,如权限、加密:占比 18%性能:占比 12%学习实践,如技术迭代慢、缺少实战经验:占比 32%弹性伸缩:占比 10%简化开发运维,如部署复杂度高、开发难度高,问题排查困难:占比 14%数据共享高可用:占比 12%成本:占比 4%稳定性:占比 8%4. 附录4.1 附录1:容器开源应用调研大数据HadoopApache 主持的这个项目是最广为人知的大数据工具。众多公司为 Hadoop 提供相关产品或商业支持,包括亚马逊网络服务、Cloudera、Hortonworks、IBM、Pivotal、Syncsort 和 VMware。知名用户包括:阿里巴巴、美国在线、电子港湾、Facebook、谷歌、Hulu、领英、Spotify、推特和雅虎。 支持的操作系统:Windows、Linux 和 OS X 相关网站:http://hadoop.apache.orgHypertableHypertable 在互联网公司当中非常流行,它由谷歌开发,用来提高数据库的可扩展性。用户包括百度、电子港湾、Groupon 和 Yelp。它与 Hadoop 兼容,提供商业支持和培训。 支持的操作系统:Linux 和 OS X 相关网站:http://www.hypertable.comMesosApache Mesos 是一种资源抽象工具,有了它,企业就可以鼗整个数据中心当成一个资源池,它在又在运行 Hadoop、Spark 及类似应用程序的公司当中很流行。使用它的企业组织包括:Airbnb、欧洲原子核研究组织(CERN)、思科、Coursera、Foursquare、Groupon、网飞(Netflix)、推特和优步。 支持的操作系统:Linux 和 OS X 相关网站:http://mesos.apache.orgPrestoPresto 由 Facebook 开发,自称是“一款开源分布式 SQL 查询引擎,用于对大大小小(从 GB 级到 PB 级)的数据源运行交互式分析查询。”Facebook 表示,它将 Presto 用于对 300PB 大小的数据仓库执行查询,其他用户包括 Airbnb 和 Dropbox。 支持的操作系统:Linux 相关网站:https://prestodb.ioSolr这种“快若闪电”的企业搜索平台声称高度可靠、扩展和容错。使用它的公司包括:AT&T、Ticketmaster、康卡斯特、Instagram、网飞、IBM、Adobe 和 SAP Hybris。 支持的操作系统:与操作系统无关 相关网站:http://Lucene.apache.org/solr/SparkApache Spark 声称,“它在内存中运行程序的速度比 Hadoop MapReduce 最多快 100 倍,在磁盘上快 10 倍。”Spark“支持”的企业组织包括:亚马逊、百度、Groupon、日立解决方案、IBM、MyFitnessPal、诺基亚和雅虎。 支持的操作系统:Windows、Linux 和 OS X 相关网站:http://spark.apache.orgStorm正如 Hadoop 用来处理批量数据,Apache Storm 用来处理实时数据。官方网站上显示用户包括:天气频道、推特、雅虎、WebMD、Spotify、威瑞信(Verisign)、Flipboard 和 Klout。 支持的操作系统:Linux 相关网站:https://storm.apache.org版本控制BazaarBazaar 由 Canonical 管理,被许多开源项目所使用,包括 Ubuntu、 GNU 基金会、Linux 基金会、MySQL、Bugzilla、 Debian 和 Maria DB。它简单易学,支持任何工作流程和工作区间模式,承诺存储效率很高、速度很快。 支持的操作系统:Windows、Linux 和 OS X 相关网站:http://bazaar.canonical.com/en/ Git这个版本控制系统已变得极受欢迎,这一方面归功于 GitHub 服务的使用日益广泛。使用它的公司和项目包括:谷歌、Facebook、微软、推特、领英、网飞、Perl、PostgreSQL、安卓、Rails、QT、Gnome 和 Eclipse。 支持的操作系统:Windows、Linux 和 OS X 相关网站:http://git-scm.com MercurialMercurial 是一种分布式源代码控制管理工具,专注于帮助团队更轻松、更快速地协同工作。用户包括 OpenJDK 和 NetBeans 等各大项目。 支持的操作系统:Windows、Linux 和 OS X 相关网站:https://www.mercurial-scm.orgSubversion这个企业级版本控制系统得到 Apache 的支持,首次发布于 2000 年。使用它的企业组织包括 Apache 软件基金会自己、Hobby Lobby、Mono、Plone 和 GNU Enterprise。 支持的操作系统:Windows、Linux 和 OS X 相关网站:http://subversion.apache.orgWeb 服务Apache HTTP ServerApache 至今已有 20 年多的历史,专利是自 1996 年以来互联网上最受欢迎的 Web 服务器系统。据 W3Techs 声称,目前所有网站中 55.3% 是由 Apache 支持的。 支持的操作系统:Windows、Linux 和 OS X 相关网站:http://httpd.apache.orgNginxNginx 的人气也极旺,它被互联网上所有网站中的大约四分之一所使用。除了俄罗斯许多访问量很大的网站外,用户还包括网飞和 WordPress.com。 支持的操作系统:Windows、Linux 和 OS X 相关网站:http://nginx.org内容管理DNN这款内容管理解决方案之前名为 DotNetNuke,承诺构建丰富的交互式网站时,只要花较少的精力,就能收到显著的成效。用户包括佳能、时代华纳有线电视、德州仪器和美国银行。 支持的操作系统:Windows 相关网站:http://www.dnnsoftware.comDrupalDrupal 声称,98000 多个开发人员在为这个极其流行的内容管理系统积极贡献代码。支持者包括微软、Zend、Fastly 和 New Relic,其内容市场有数百家公司参与其中,它们提供了相关的产品和服务。 支持的操作系统:与操作系统无关 相关网站:https://www.drupal.orgJoomlaJoomla 为数百万个网站提供平台,其下载量超过了 5000 万人次。许多用户当中就有这些公司:电子港湾、巴诺书店、MTV 和标致。 支持的操作系统:与操作系统无关 相关网站:https://www.joomla.orgMediaWikiMediaWiki 以维基百科使用的软件而出名,它还为百度、Vistaprint、Novell、英特尔和美国宇航局支持网站。它是构建可编辑网页的不错选择,许多企业组织用它来构建内部知识库。 支持的操作系统:Windows、Linux/Unix 和 OS X 相关网站:https://www.mediawiki.org/wiki/MediaWiki数据库Cassandra这种 NoSQL 数据库由 Facebook 开发,其用户包括苹果、欧洲原子核研究组织(CERN)、康卡斯特、电子港湾、GitHub、GoDaddy、Hulu、Instagram、Intuit、网飞、Reddit 及其他科技公司。它支持极其庞大的数据集,声称拥有非常高的性能和出色的耐用性和弹性。可通过第三方获得支持。 支持的操作系统:与操作系统无关 相关网站:http://cassandra.apache.orgCouchDBCouchDB 为 Web 而开发,这种 NoSQL 数据库将数据存储在 JSON 文档中,这类文档可通过 HTTP 来加以查询,并用 JavaScript 来处理。Cloudant 现在归 IBM 所有,它提供一款专业人员支持的软件版本,用户包括:三星、Akamai、Expedia、微软游戏工作室及其他公司。 支持的操作系统:Windows、Linux、OS X 和安卓 相关网站:http://couchdb.apache.orgMongoDBMongoDB 是一种 NoSQL 数据库,声称“针对关键任务型部署环境进行了优化”,用户包括 Foursquare、《福布斯》、Pebble、Adobe、领英、eHarmony 及其他公司。提供收费的专业版和企业版。 支持的操作系统:Windows、Linux、OS X 和 Solaris 相关网站:http://www.mongodb.orgMySQLMySQL 自称是“世界上最流行的开源数据库”,备受众多互联网公司的青睐,比如 YouTube、贝宝、谷歌、Facebook、推特、电子港湾、领英、优步和亚马逊。除了免费社区版外,它还有多款收费版。最新更新版声称速度比老版本快三倍。 支持的操作系统:Windows、Linux、Unix 和 OS X 相关网站:http://www.mysql.comNeo4jNeo4J 自诩为“世界上领先的图形数据库”,用于欺诈检测、推荐引擎、社交网站、主数据管理及更多领域。用户包括电子港湾、沃尔玛、思科、惠普、埃森哲、CrunchBase、eHarmony、Care.com 及另外许多企业组织。 支持的操作系统:Windows 和 Linux 相关网站:http://neo4j.com中间件JBoss红帽的 JBoss 中间件包括各种轻量级、对云计算友好的工具,同时结合、集成和自动化各个企业应用程序和系统。用户包括:橡树岭国家实验室、日产、思科、冠群科技、AMD 及其他公司。 支持的操作系统:Linux 相关网站:http://www.redhat.com/en/technologies/jboss-middleware开发工具BugzillaBugzilla 是开源社区的宠儿,用户包括 Mozilla、Linux 基金会、GNOME、KDE、Apache、LibreOffice、Open Office、Eclipse、红帽、Novell 及其他公司。这款软件缺陷追踪系统(bugtracker)的重要功能包括:高级搜索功能、电子邮件通知、预定报告、时间追踪、出色的安全及更多特性。 支持的操作系统:Windows、Linux 和 OS X 相关网站:https://www.bugzilla.orgEclipseEclipse 项目最为知名的是,它是一种大受欢迎的面向 Java 的集成开发环境(IDE),它还提供面向C/C++和 PHP 的 IDE,此外提供另外一大批开发工具。主要支持者包括冠群科技、谷歌、IBM、甲骨文、红帽和 SAP。 支持的操作系统:与操作系统无关 相关网站:http://www.eclipse.orgEmber.js这种框架用于“构建野心勃勃的 Web 应用程序”,旨在为 JavaScript 开发人员提高工作效率。官方网站上显示用户包括雅虎、Square、Livingsocial、Groupon、Twitch、TED、网飞、Heroku 和微软。 支持的操作系统:与操作系统无关 相关网站: http://emberjs.comGruntGrunt 是一种 JavaScript 任务运行工具,有助于自动处理重复性的开发任务。使用它的知名科技公司包括:Adobe、推特、Mozilla、Cloudant 和 WordPress。 支持的操作系统:与操作系统无关 相关网站:http://gruntjs.comLoopBack这个 Node.js 框架旨在让用户很容易构建 REST API,并连接到后端数据存储区。知名用户包括 GoDaddy、美国能源部和赛门铁克。 支持的操作系统:Windows、Linux、OS X、安卓和 iOS 相关网站:http://loopback.ioNode.jsNode.js 的成名之处在于,它让开发人员可以使用 JavaScript,编写服务器端应用程序。开发工作之前由 Joyent 管控,现在交由 Node.js 基金会监管。用户包括 IBM、微软、雅虎、SAP、领英、贝宝和网飞。 支持的操作系统:Windows、Linux 和 OS X 相关网站:https://nodejs.org/en/PhoneGapApache Cordova 是一种开源框架,让开发人员可以使用 HTML、CSS 和 JavaScript 等 Web 技术,构建移动应用程序。PhoneGap 是最受欢迎的 Cordova 发行版。使用某一种 Cordova 发行版的科技公司包括:维基百科、Facebook、 Salesforce、IBM、微软、Adobe 和黑莓。 支持的操作系统:Window、Linux 和 OS X 相关网站:http://phonegap.comReact NativeReact Native 由 Facebook 开发,这种框架可用于使用 JavaScript 和 React JavaScript 库(同样由 Facebook 开发),构建原生移动应用程序。其他用户包括:《探索》频道和 CBS 体育新闻网。 支持的操作系统:OS X 相关网站:http://facebook.github.io/react-native/Ruby on Rails这个 Web 开发框架在开发人员当中极其流行,它声称“为确保编程员满意和持续高效地工作进行了优化”。用户包括 Basecamp、推特、Shopify 和 GitHub 等公司。 支持的操作系统:Windows、Linux 和 OS X 相关网站:http://rubyonrails.orgSencha TouchSencha Touch 自称是“一种用于构建通用移动应用程序的领先的跨平台移动 Web 应用程序框架,基于 HTML5 和 JavaScript”。它既有开源许可证版本,也有商业许可证版本。据官方网站声称,《财富》100 强中 60% 使用它。 支持的操作系统:与操作系统无关 相关网站:https://www.sencha.com/products/touch/ ZK索尼、Sun、IBM、Adobe、电子港湾、富士通、梦工厂和优利系统等公司使用这种 Java Web 框架来构建 Web 和移动应用程序。提供收费支付及相关工具。 支持的操作系统:与操作系统无关 相关网站:http://www.zkoss.org系统管理工具AnsibleAnsible 现在归红帽所有,它自称是“一种异常简单的 IT 自动化引擎,可以使云服务配置、配置管理、应用程序部署、服务内部的编排以及其他许多 IT 操作实现自动化。”使用它的科技公司包括:思科、瞻博网络、Evernote、推特、威瑞信、GoPro、EA Sports、Atlassian 和韦里逊。它既有免费版,也有收费版。 支持的操作系统:Linux 相关网站:http://www.ansibleworks.comChef作为另一款自动化工具,Chef 支持开发运维方法,同时改善了速度、协作和安全性。拥有免费版和收费版。官方网站上显示用户包括:塔吉特(Target)、诺德斯特龙(Nordstrom)、Facebook、Etsy、IGM、雅虎和彭博社。 支持的操作系统:Windows、Linux 和 OS X 相关网站:https://www.chef.io/chef/HudsonHudson 在使用敏捷和开发运维方法的企业当中很流行,它是一种可扩展的持续集成服务器系统,可以监控重复作业的执行。这个项目得到了 Eclipse 基金会、甲骨文、Atlassian 和 YourKit 的支持。 支持的操作系统:与操作系统无关 相关网站:http://hudson-ci.orgPuppetPuppet 号称“使用最广泛的开源 IT 管理系统”,它包括 40 多个基础设施管理方面的开源项目。除了开源版本外,它还有一款收费的企业版本。它声称,用户包括 25000 多家企业,比如迪士尼、沃尔玛、1-800-Flowers.com、Heartland Payment Systems、盖蒂图片社(Getty Images)和 Yelp。 支持的操作系统:Windows、Linux、Unix 和 OS X 相关网站:https://puppetlabs.com/puppet/open-source-projects4.2 附录2:容器服务应用目录 Gartner 应用调研容器服务 APP HUB已标签分类ApplicationSolution CatalogairflowWorkflowbitcoind数字货币bitcoind数字货币cassandra数据库cassandra-operator数据库cassandra-reaper数据库couchdb数据库elasticsearch分析搜索elasticsearch-curator分析搜索elasticsearch-exporter分析搜索elasticsearch-exporter分析搜索etcd数据库etcd-operator数据库grafana分析搜索grafana分析搜索hadoop大数据hadoop大数据IPFSJenkins持续集成jenkins-operator持续集成kafkaInfrastructurekibana分析搜索kibana分析搜索LAMP开发工具logstash分析搜索logstash分析搜索mariadb数据库mariadb数据库mariadb-galera数据库mediawiki内容管理memcachedInfrastructurememcachedInfrastructureMongoDB数据库mongodb数据库moodleeLearningmxnetAIMySQL数据库mysqldump数据库mysqldump数据库mysqlha数据库natsInfrastructurenatsInfrastructureneo4j数据库nginxWeb服务nginx-ingressWeb服务nginx-ingress-controllerWeb服务prometheus分析搜索prometheus-adapter分析搜索prometheus-adapter分析搜索prometheus-blackbox-exporter分析搜索prometheus-blackbox-exporter分析搜索prometheus-cloudwatch-exporter分析搜索prometheus-cloudwatch-exporter分析搜索prometheus-consul-exporter分析搜索prometheus-consul-exporter分析搜索prometheus-couchdb-exporter分析搜索prometheus-couchdb-exporter分析搜索prometheus-mysql-exporter分析搜索prometheus-mysql-exporter分析搜索prometheus-nats-exporter分析搜索prometheus-nats-exporter分析搜索prometheus-node-exporter分析搜索prometheus-node-exporter分析搜索prometheus-postgres-exporter分析搜索prometheus-postgres-exporter分析搜索prometheus-pushgateway分析搜索prometheus-pushgateway分析搜索prometheus-rabbitmq-exporter分析搜索prometheus-rabbitmq-exporter分析搜索prometheus-redis-exporter分析搜索prometheus-redis-exporter分析搜索prometheus-snmp-exporter分析搜索prometheus-snmp-exporter分析搜索prometheus-to-sd分析搜索prometheus-to-sd分析搜索pytorchAIrabbitmqInfrastructurerabbitmqInfrastructurerabbitmq-haInfrastructurerabbitmq-haInfrastructureredis数据库redis数据库redis-cache数据库redis-ha数据库redis-ha数据库spark大数据spark-history-server大数据spark-history-server大数据sparkoperator大数据tensorflow-notebookAItensorflow-resnetAItomcat中间件wordpressWeb服务wordpressWeb服务wildflyInfrastructurezeppelinInfrastructurezookeeperINfrastructure未标签分类aerospikeambassadorambassadorapacheapm-serverapm-serveratlantisatlantisauditbeataws-alb-ingress-controlleraws-cluster-autoscaleraws-iam-authenticatorburrowbuzzfeed-ssocentrifugocerebrocerebrochaoskubechaoskubechartmuseumchronografchronografclamavclamavcluster-autoscalercluster-autoscalercluster-overprovisionercluster-overprovisionercockroachdbcollabora-codecollabora-codeconsulcontourcorednscorednscosbenchcoscalecouchdbdaskdask-distributeddatadogdexdistributed-jmeterdistributed-tensorflowdmarc2logstashdocker-registrydocker-registrydokuwikidokuwikidronedronedrupalefs-provisionerefs-provisionerelastabotelastalertelastalertenvoyetcd-operatorethereumeventroutereventrouterexternal-dnsexternal-dnsfactoriofalcofalcofilebeatfilebeatfluent-bitfluent-bitfluentdfluentdfluentd-cloudwatchgangwaygangwaygce-ingressgcp-night-kingghostgocdgocdgogsgoldfishgoldpingerguestbookguestbook-kruisehaproxy-ingressharborhazelcasthazelcasthazelcast-jethazelcast-jetheapsterheapsterheartbeathelm-exporterhl-composerhlf-couchdbhlf-ordhlf-peerhlf-peerhoardhome-assistanthome-assistanthoneydipperhorovodhoverflyhubothubotigniteinbucketinfluxdbinfluxdbingressmonitorcontrollerinstana-agentinstana-agentjaegerjasperreportsjoomlak8s-spot-reschedulerk8s-spot-termination-handlerk8s-spot-termination-handlerkanister-operatorkapacitorkapacitorkarmakarmakatafygiokeycloak-proxykiamkiamkongkube-downscalerkube-hunterkube-hunterkube-legokube-registry-proxykube-slackkube-slackkube-state-metricskube-state-metricskube2iamkube2iamkubelesskuberhealthykubernetes-dashboardkubernetes-dashboardkubernetes-vaultkuberoskuberoskubewatchkubewatchkuredkuredlinkerdlocustlocustlogdna-agentlogdna-agentmagentomagic-ip-addressmagic-namespacemcroutermercuremetabasemetabasemetallbmetricbeatmetricbeatminecraftminecraftminiominiomsomsmssql-linuxnewrelic-infrastructurenewrelic-infrastructurenextcloudnfs-server-provisionernginx-legonode-problem-detectornode-problem-detectornode-rednode-redoauth-proxyoauth2-proxyoauth2-proxyodooopaopaopencartopenebsopenebsopenibanopenldapopenldapopenvpnopenvpnorangehrmorientdbosclassowncloudpachydermparseparseperconapercona-xtradb-clusterpgadminphabricatorphpbbphpmyadminpomeriumpomeriumpostgresqlpostgresqlpostgresql-haprestashopprestopuppet-forgeredminereloaderreloaderrethinkdbriemannrisk-advisorrookoutrundecksatisfyschema-registry-uisealed-secretssealed-secretsseleniumsematext-agentsentry-kubernetesseqsignalfx-agentsignalsciencessocat-tunnellersonatype-nexussonatype-nexusspartakusspotify-docker-gcstackdriver-exporterstackdriver-exportersuitecrmsupersetsupersetsysdigtelegraftelegrafterracottaterracottatestlinktraefiktraefikunboundunifivaultvaultingkubeverdaccioverdacciowavefrontweave-cloudweave-scopeweave-scopewebpagetest-agentwebpagetest-server4.3 附录3:容器应用调研 Bitnami Multi-Tier Single-Tier 应用调研Multi-Tier Single-Tier 应用调研Single-Tier 架构:适用于单节点server架构。所有服务部署在一台 Server上。Multi -Tier 架构:适用于多节点共享架构。把各个服务分别部署在多个 Server上,比如 web服务器,应用服务器,多实例数据库服务。Multi-Tier 提供多节点的更高性能,高可用,副本数据复制数据保护和数据安全。适用于云上部署 Multi-Tier 多节点 Server 共享架构的应用调研如下:分析搜索GrafanaMulti-Tier Single-Tiergrafana 是一款采用 go 语言编写的开源应用,主要用于大规模指标数据的可视化展现,是网络架构和应用分析中最流行的时序数据展示工具,目前已经支持绝大部分常用的时序数据库。 相关网站:http://docs.grafana.org/ElasticsearchMulti-Tier Single-TierElasticsearch 是一个分布式、RESTful 风格的搜索和数据分析引擎。 相关网站:https://www.elastic.co/cn/elasticsearch/持续集成部署JenkinsMulti-Tier Single-TierJenkins是一个开源的、提供友好操作界面的持续集成(CI)工具,起源于Hudson(Hudson是商用的),主要用于持续、自动的构建/测试软件项目、监控外部任务的运行。Jenkins用Java语言编写,可在Tomcat等流行的servlet容器中运行,也可独立运行。通常与版本管理工具(SCM)、构建工具结合使用。常用的版本控制工具有SVN、GIT,构建工具有Maven、Ant、Gradle。 相关网站:http://www.jenkins.org.cn/deLearningMoodle LMSMulti-Tier Single-Tier开源在线教育学习管理系统。以功能强大,而界面简单、精巧而著称。它是eLearning技术先驱,已成为全球大中学院校建立开放式课程系统的首选软件。 相关网站:https://moodle.com/lms/Web 服务NginxMulti-Tier Single-TierNginx 的人气也极旺,它被互联网上所有网站中的大约四分之一所使用。除了俄罗斯许多访问量很大的网站外,用户还包括网飞和 WordPress.com。 支持的操作系统:Windows、Linux 和 OS X 相关网站:http://nginx.orgWordPressMulti-Tier Single-TierWordPress是一款能让您建立出色网站、博客或应用程序的开源软件。WordPress是使用PHP语言开发的博客平台,用户可以在支持PHP和MySQL数据库的服务器上架设属于自己的网站。也可以把 WordPress当作一个内容管理系统(CMS)来使用。 相关网站:https://cn.wordpress.org/内容管理DrupalMulti-Tier Single-TierDrupal 声称,98000 多个开发人员在为这个极其流行的内容管理系统积极贡献代码。支持者包括微软、Zend、Fastly 和 New Relic,其内容市场有数百家公司参与其中,它们提供了相关的产品和服务。 支持的操作系统:与操作系统无关 相关网站:https://www.drupal.orgCKANMulti-TierCKAN是开源的Data Management System数据管理系统。 相关网站:https://ckan.org/ https://github.com/ckan/ckanMediaWikiMulti-TierMediaWiki 以维基百科使用的软件而出名,它还为百度、Vistaprint、Novell、英特尔和美国宇航局支持网站。它是构建可编辑网页的不错选择,许多企业组织用它来构建内部知识库。 支持的操作系统:Windows、Linux/Unix 和 OS X 相关网站:https://www.mediawiki.org/wiki/MediaWiki数据库CassandraMulti-Tier Single-Tier这种 NoSQL 数据库由 Facebook 开发,其用户包括苹果、欧洲原子核研究组织(CERN)、康卡斯特、电子港湾、GitHub、GoDaddy、Hulu、Instagram、Intuit、网飞、Reddit 及其他科技公司。它支持极其庞大的数据集,声称拥有非常高的性能和出色的耐用性和弹性。可通过第三方获得支持。 支持的操作系统:与操作系统无关 相关网站:http://cassandra.apache.orgMariaDBMulti-Tier Single-TierMariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可 MariaDB的目的是完全兼容MySQL,包括API和命令行,使之能轻松成为MySQL的代替品。在存储引擎方面,使用XtraDB(英语:XtraDB)来代替MySQL的InnoDB。 相关网站:https://mariadb.org/MongoDBMulti-Tier Single-TierMongoDB 是一种 NoSQL 数据库,声称“针对关键任务型部署环境进行了优化”,用户包括 Foursquare、《福布斯》、Pebble、Adobe、领英、eHarmony 及其他公司。提供收费的专业版和企业版。 支持的操作系统:Windows、Linux、OS X 和 Solaris 相关网站:http://www.mongodb.orgMySQLMulti-Tier Single-TierMySQL 自称是“世界上最流行的开源数据库”,备受众多互联网公司的青睐,比如 YouTube、贝宝、谷歌、Facebook、推特、电子港湾、领英、优步和亚马逊。除了免费社区版外,它还有多款收费版。最新更新版声称速度比老版本快三倍。 支持的操作系统:Windows、Linux、Unix 和 OS X 相关网站:http://www.mysql.comNeo4jMulti-Tier Single-TierNeo4J 自诩为“世界上领先的图形数据库”,用于欺诈检测、推荐引擎、社交网站、主数据管理及更多领域。用户包括电子港湾、沃尔玛、思科、惠普、埃森哲、CrunchBase、eHarmony、Care.com 及另外许多企业组织。 支持的操作系统:Windows 和 Linux 相关网站:http://neo4j.comPostgreSQLMulti-Tier Single-TierPostgreSQL是一个功能非常强大的、源代码开放的客户/服务器关系型数据库管理系统(RDBMS)。PostgreSQL支持大部分的SQL标准并且提供了很多其他现代特性,如复杂查询、外键、触发器、视图、事务完整性、多版本并发控制等。同样,PostgreSQL也可以用许多方法扩展,例如通过增加新的数据类型、函数、操作符、聚集函数、索引方法、过程语言等。 相关网站:https://www.postgresql.org/RedisMulti-Tier Single-TierNoSQL数据库 Redis 是一个开源的内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如字符串(strings),散列(hashes),列表(lists),集合(sets), 有序集合(sorted sets)与范围查询,bitmaps,hyperloglogs 和地理空间索引半径查询。Redis 内置了复制,LUA脚本,LRU驱动事件,事务和不同级别的磁盘持久化, 并通过Redis哨兵和自动分区提供高可用性。 相关网站:https://redis.io/etcdMulti-Tier Single-TierNoSQL数据库 etcd是一个分布式的、高可用的、一致的key-value存储数据库,基于Go语言实现,主要用于共享配置和服务发现 相关网站:https://etcd.io/MariaDB GaleraMulti-Tier相关网站:https://downloads.mariadb.org/mariadb-galera/InfrastructureRabbitMQMulti-Tier Single-TierRabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。RabbitMQ服务器是用Erlang语言编写的,而集群和故障转移是构建在开放电信平台框架上的。所有主要的编程语言均有与代理接口通讯的客户端库。 相关网站:https://www.rabbitmq.com/MemcachedMulti-Tier Single-Tiermemcached是一套分布式的高速缓存系统,由LiveJournal的Brad Fitzpatrick开发,但被许多网站使用。这是一套开放源代码软件,以BSD license授权发布。 相关网站:http://memcached.org/KafkaMulti-Tier Single-TierKafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者在网站中的所有动作流数据。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。Kafka的目的是通过Hadoop的并行加载机制来统一线上和离线的消息处理,也是为了通过集群来提供实时的消息。 相关网站:http://kafka.apache.org/ZooKeeperMulti-Tier Single-TierZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。 相关网站:https://zookeeper.apache.org/Node.jsMulti-Tier Single-TierNode.js 的成名之处在于,它让开发人员可以使用 JavaScript,编写服务器端应用程序。开发工作之前由 Joyent 管控,现在交由 Node.js 基金会监管。用户包括 IBM、微软、雅虎、SAP、领英、贝宝和网飞。 支持的操作系统:Windows、Linux 和 OS X 相关网站:https://nodejs.org/en/NATSMulti-Tier Single-Tiernats是一个开源的,云原生的消息系统。 核心基于EventMachine开发,原理是基于消息发布订阅机制,每台服务器上的每个模块会根据自己的消息类别向MessageBus发布多个消息主题,而同时也向自己需要交互的模块,按照需要的主题订阅消息。 相关网站:https://nats.io/开发工具LAMPMulti-Tier Single-TierLAMP是指一组通常一起使用来运行动态网站或者服务器的自由软件名称首字母缩写。Linux,操作系统,Apache,网页服务器,MariaDB或MySQL,数据库管理系统(或者数据库服务器),PHP、Perl或Python,脚本语言。
PHP对接苹果支付全流程
对接苹果支付流程上相较于微信或者支付宝来说 后端做的代码是非常少的 但是需要注意的点很多对于支付 最重要的是知道这笔支付到底是不是真正意义上成交了,以及成交价格是否对应我们的商品价格 这是我们需要去判断的苹果支付对于微信支付和支付宝支付来说,有本质的区别。苹果支付的商品需要现在appstore里面去上架。所以整个支付流程如下APP内请求苹果SDK发起支付。并完成购买。支付成功之后APP端会传一段receipt_data(同时需要带上APP支付成功的交易单号)给后端去做验证。后端拿到这个数据之后,会再次请求苹果服务器去解析数据。结构如下:{
"receipt": {
"receipt_type": "ProductionSandbox",
"adam_id": 0,
"app_item_id": 0,
"bundle_id": "申请苹果支付时的串号 固定的值",
"application_version": "24",
"download_id": 0,
"version_external_identifier": 0,
"receipt_creation_date": "2022-02-18 08:02:19 Etc/GMT",
"receipt_creation_date_ms": "1645171339000",
"receipt_creation_date_pst": "2022-02-18 00:02:19 America/Los_Angeles",
"request_date": "2022-02-23 13:21:51 Etc/GMT",
"request_date_ms": "1645622511107",
"request_date_pst": "2022-02-23 05:21:51 America/Los_Angeles",
"original_purchase_date": "2013-08-01 07:00:00 Etc/GMT",
"original_purchase_date_ms": "1375340400000",
"original_purchase_date_pst": "2013-08-01 00:00:00 America/Los_Angeles",
"original_application_version": "1.0",
"in_app": [
{
"quantity": "1",
"product_id": "10000",#产品ID
"transaction_id": "1000000972016787", ##交易单号
"original_transaction_id": "1000000972016787",
"purchase_date": "2022-02-18 08:02:19 Etc/GMT",
"purchase_date_ms": "1645171339000",
"purchase_date_pst": "2022-02-18 00:02:19 America/Los_Angeles",
"original_purchase_date": "2022-02-18 08:02:19 Etc/GMT",
"original_purchase_date_ms": "1645171339000",
"original_purchase_date_pst": "2022-02-18 00:02:19 America/Los_Angeles",
"is_trial_period": "false",
"in_app_ownership_type": "PURCHASED"#交易状态
},
{
"quantity": "1",
"product_id": "betterwe_camp_21",
"transaction_id": "1000000970947758",
"original_transaction_id": "1000000970947758",
"purchase_date": "2022-02-17 07:26:24 Etc/GMT",
"purchase_date_ms": "1645082784000",
"purchase_date_pst": "2022-02-16 23:26:24 America/Los_Angeles",
"original_purchase_date": "2022-02-17 07:26:24 Etc/GMT",
"original_purchase_date_ms": "1645082784000",
"original_purchase_date_pst": "2022-02-16 23:26:24 America/Los_Angeles",
"is_trial_period": "false",
"in_app_ownership_type": "PURCHASED"
},
]
},
"environment": "Sandbox",
"status": 0
}订单总共如下几种状态状态描述Purchased购买成功Restored恢复购买Failed失败Deferred等待确认,儿童模式需要询问家长同意1) app从服务器获取产品标识列表2) app从app store 获取产品信息3) 用户选择需要购买的产品4) app 发送 支付请求到app store5) app store 处理支付请求,返回transaction信息6) app 将transaction receipt 发送到服务器7) 服务器收到收据后发送到app stroe验证收据的有效性8) app store 返回收据的验证结果9) 根据app store 返回的结果决定用户是否购买成功基本的支付校验流程如下:下面贴上具体的业务逻辑代码 public function actionsApplepay($receipt_data, $order_number, $transaction_id, $order_info, $is_test){
$ret = array();
$ret['status'] = 200;
$ret['msg'] = "ok";
try{
//修改状态为校验中
(new Order())::updateAppleOrderIsPaying($order_number);
if ($is_test == 1) { //沙盒购买地址
$url = "https://sandbox.itunes.apple.com/verifyReceipt";
}else{ //正式购买地址
$url = "https://buy.itunes.apple.com/verifyReceipt";
}
$receipt_data = str_replace(' ',"+", $receipt_data);
$post_data = json_encode(array("receipt-data" => $receipt_data));
$response = https_request($url, $post_data);
$res = json_decode($response, true);
$err_msg = array(
'21000' => 'App Store不能读取你提供的JSON对象',
'21002' => 'receipt-data域的数据有问题',
'21003' => 'receipt无法通过验证',
'21004' => '提供的shared secret不匹配你账号中的shared secret',
'21005' => 'receipt服务器当前不可用',
'21006' => 'receipt合法,但是订阅已过期。服务器接收到这个状态码时,receipt数据仍然会解码并一起发送',
'21007' => 'receipt是Sandbox receipt,但却发送至生产系统的验证服务',
'21008' => 'receipt是生产receipt,但却发送至Sandbox环境的验证服务'
);
// 判断是否购买成功
if(intval($res['status']) === 0){
//支付成功 更改订单状态
if($res['receipt']['bundle_id'] != 'xxxx'){
throw new Exception('非法请求!', -1);
}
$pay_status = false;//默认支付为失败态
if(count($res['receipt']['in_app'])){
foreach ($res['receipt']['in_app'] as $apple_order){
//满足二次验证的商品和客户端的商品一致 且 apple订单号一致 且支付状态为 PURCHASED 方式
if($apple_order['product_id'] == $order_info['goods_id'] && $apple_order['transaction_id'] == $transaction_id && $apple_order['in_app_ownership_type'] == 'PURCHASED'){
//如果查询到里面有满足条件的 将状态置为true
$pay_status = true;
}
}
}
if($pay_status == true){
$update_order_info_res = (new Order())->updateOrderIsPaySuccess($order_number, 3, $transaction_id);
if($update_order_info_res['status'] != 200){
throw new Exception($update_order_info_res['msg'], $update_order_info_res['status']);
}
}else{
throw new Exception('未查询到当前订单的支付成功记录', -3);
}
}else{
//沙盒情况下直接走完流程
if($res['status'] == 21007){
$update_order_info_res = (new Order())->updateOrderIsPaySuccess($order_number, 3, 'XXXXXXXXXX-SANDBOX');
if($update_order_info_res['status'] != 200){
throw new Exception($update_order_info_res['msg'], $update_order_info_res['status']);
}
}else{
(new Order())::recordOrderErrorLog($order_number, '购买失败 status:'.$res['status'].' - '.@$err_msg[$res['status']].'receipt_data:'.$receipt_data);
throw new Exception('购买失败 status:'.$res['status'].' - '.@$err_msg[$res['status']], $res['status']);
}
}
}catch (Exception $e) {
//修改状态为校验中
(new Order())::updateAppleOrderIsNoPaying($order_number);
$ret['status'] = $e->getCode();
$ret['msg'] = $e->getMessage();
}
return $ret;
}上面为具体的业务逻辑代码
梦幻体育赛事直播系统的解决方案和技术分析
以确保用户能够享受到流畅的直播体验,梦幻体育赛事直播系统需要采用一个可靠且高效的解决方案,以下是我们对该系统所需的技术和框架的分析。一、解决方案总体架构1、ThinkPHP框架ThinkPHP框架是一款国产的轻量级PHP开发框架,易于学习和使用。该框架拥有完整的中文文档,具有很好的兼容性、清晰的架构和可扩展性,因此是一个适用于大型企业级Web应用系统的优秀软件架构。2、框架技术框架技术是从Java的Struts框架移植过来的中文PHP开发框架。该框架采用面向对象的开发结构和MVC模式,并模拟实现了Struts的标签库,使得该框架在各个方面都非常人性化。3、WEB层框架Vue是一个渐进式框架,它基于标准的HTML、CSS和JavaScript构建,并支持双向数据绑定、组件化、数据和结构的分离、虚拟DOM等特性,能够大幅度提高Web开发的效率。4、安卓:Java安卓系统由Java语言编写,具有良好的跨平台兼容性和程序兼容性。因此,该系统能够适配多个品牌的手机,并成为安卓应用程序制作的主流开发语言。Java的主要优势在于它能够兼顾应用程序界面和交互方式的多样性。5、苹果:Objective-CObjective-C是苹果应用程序制作的主流编程语言,是一种基于C语言的面向对象语言。Objective-C提供了丰富的工具和库以便开发者使用,还具有静态语言的特性,编译后就是机器码,因此具有非常高的执行效率。总之,采用ThinkPHP框架、框架技术、Vue WEB层框架以及Java和Objective-C等语言,是可以构建一个高效、稳定、可靠的体育赛事直播系统。这些技术和框架能够使体育赛事直播的系统具有良好的兼容性、可扩展性和维护性,同时提供流畅的用户体验。
【水果质量检测】基于机器视觉实现苹果疾病识别分类附matlab代码
✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。🍎个人主页:Matlab科研工作室🍊个人信条:格物致知。更多Matlab仿真内容点击👇智能优化算法 神经网络预测 雷达通信 无线传感器信号处理 图像处理 路径规划 元胞自动机 无人机 电力系统⛄ 内容介绍苹果梗蒂和缺陷的识别是苹果自动检测中的难点,两者的误分类会造成苹果质量等级的误判.介绍了一个基于机器视觉的苹果质量自动评价系统.通过梗蒂识别,缺陷分割,确定缺陷区域并移除梗蒂区域,形成新的兴趣区域;提取统计,纹理和几何特征,采用Pearson特征相关性分析和SFFS特征选择,删除冗余特征;采用模糊KNN分类器在富士苹果进行试验,得到的平均识别正确率为83%.这项技术可以用于苹果包装流水线作业,也可用于类似的农产品外观质量检测.⛄ 部分代码%XYZ = rgb2xyz(RGB)%%Output parameter: RGB must be an image having 3 channels, i.e. a 3D array.% Each channel of RGB should be in the range 0..255.%Input parameter: XYZ would be an image of the same dimension.%%Example: To convert an image in RGB format to L*a*b* format, one can%combine the calling to the rgb2xyz and xyz2lab functions:% rgbim = imread('yourImage.png'); % image in RGB format% labim = xyz2lab(rgb2xyz(rgbim));%The output labim has the following ranges of values:% - first channel L* 0..100% - the second channel a* -128..127% - the third channel b -128..127% %Other software packages, e.g. OpenCV, often applies a normalisation%process so that images in the L*a*b* format can be stored as 3-channel%greyscale images. The normalisation adopted by OpenCV is:% - the first channel L* is rescaled to the range 0..255. This can be done% easily by multiplying by 255 and dividing by 100.% - the second channel a* and third channel b* are added by 128 to bring% the range from -128..127 to 0..255.%%When comparing the pixel values of an L*a*b* image produced by the Matlab%function here and those from OpenCV, ensure that the above normalisation%procedure is taken into account.%%Also noted that images that are read from disk into OpenCV have their%channels specified in reverse order in the data structure. So, to compare%the Matlab function here with those in OpenCV, use the following OpenCV%functions:% source_rgb_image = cvLoadImage('yourImage.png', 1);% // make sure that the 3rd parameter is CV_BGR2Lab and not CV_RGB2Lab% cvCvtColor(source_rgb_image, destination_lab_image, CV_BGR2Lab);% // the resultant L*a*b* image is created within the program (i.e. not% // read from disk), so the channels are in the right order:% cvCvtPixToPlane(destination_lab_image, l_channel, a_channel, b_channel,% 0);%%References:%* http://www.easyrgb.com/index.php?X=MATH%* http://en.wikipedia.org/wiki/SRGB_color_space%%SEE ALSO% xyz2rgb, xyz2lab, lab2xyz%%Feb 2010%%Copyright Du Huynh%School of Computer Science and Software Engineering%The University of Western AustraliaRGB = RGB/255;index1 = find(RGB > 0.04045);index2 = find(RGB <= 0.04045);RGB(index1) = ((RGB(index1) + 0.055) / 1.055).^2.4;RGB(index2) = RGB(index2) / 12.92;%Observer. = 2°, Illuminant = D65XYZ = zeros(size(RGB));M = [ 0.4124 0.3576 0.1805; 0.2126 0.7152 0.0722; 0.0193 0.1192 0.9505 ];for i=1:3 XYZ(:,:,i) = RGB(:,:,1)*M(i,1) + RGB(:,:,2)*M(i,2) + RGB(:,:,3)*M(i,3);endXYZ = XYZ*100;end⛄ 运行结果⛄ 参考文献[1]蒋益女, 徐从富. 基于机器视觉的苹果质量等级识别方法的研究[J]. 计算机应用与软件, 2010, 27(11):3.[2]童旭. 基于机器视觉水果表面等级分类识别的研究[D]. 重庆交通大学, 2018.⛄ 完整代码❤️部分理论引用网络文献,若有侵权联系博主删除❤️ 关注我领取海量matlab电子书和数学建模资料
PHP学习笔记(观隅反三)
前言不知不觉距离上篇PHP的文章 PHP学习笔记(才贯二酉)已经过去好多天了,今天看到推送——1024程序员节,莫名还有些小激动(os:自知自己的一些雕虫小技肯定和程序员这个技术深似海的称号扯不上什么关系,但是奈何人菜瘾大,还是忍不住在各位 “关公” 面前浅耍一下小刀,如有不足,感谢指正呀!)也希望通过学习笔记巩固自己所学知识,学会举一反三,从一件事情类推而知道其他许多事情。数组(一)为什么要创建数组这里就不赘述了,在 PHP 中,有三种类型的数组:数值数组 - 带有数字 ID 键的数组关联数组 - 带有指定的键的数组,每个键关联一个值多维数组 - 包含一个或多个数组的数组创建数组在 PHP 中,定义数组的方式有:利用array[ ]函数来定义,这也是PHP中最常用定义数组的方法:$arr1=array("hello","world",1);
var_dump($arr1);
echo "<br>";
//输出 array(3) { [0]=> string(5) "hello" [1]=> string(5) "world" [2]=> int(1) }
利用中括号来定义数组:$arr2=["hello","world",1];
var_dump($arr2);
echo "<br>"
//输出 array(3) { [0]=> string(5) "hello" [1]=> string(5) "world" [2]=> int(1) }
通过键值对来定义隐形数组:$array[]='orange';
$array[2]='apple';
$array[]='banana';
$array['watermelon']='watermelon';
var_dump($array);
隐形数组的输出:由此可以简单总结一下PHP中数组的特点:数组的下标可以是整数下标(数组元素均为整数下标:索引数组);也可以是字符串类型的下标(数组元素均为字符串:关联数组);也可以是不同类型下标混合使用(混合数组);数组元素的顺序和元素放入的顺序有关,和下标无关;整数下标具有自增长性,如果手动添加一个较大的整数下标,后面的下标会根据最大的元素下标开始自增;特殊值的下标可以自动转换:true,false等5.数组元素没有类型限制,也没有长度限制,不需要提前指定数组长度,比较灵活,同时效率也不会那么高;存储的位置是在堆区,为数组分配一块连续的内存。PHP中根据索引的分类分为:索引数组、关联数组索引数组和关联数组的差别就在键名上,索引数组的键名是数字;关联数组的键名由字符串或字符串、数字混合的形式组成;如果一个数组中有一个键名不是数字,那么这个数组就是关联数组。索引数组//索引数组1 下标是可以不连续的,不给加下标默认下标是0
$arr3=array(
'2'=>"张三",
'3'=>"张四",
'4'=>"张五",
'5'=>"张六",
);
print_r($arr3);
var_dump($arr3);
echo $arr3[3];
//Array ( [2] => 张三 [3] => 张四 [4] => 张五 [5] => 张六 )
//array(4) { [2]=> string(6) "张三" [3]=> string(6) "张四" [4]=> string(6) "张五" [5]=> string(6) "张六" }
//张四
//索引数组2
$arr4 = array('张三','张四','张五','张六');
print_r($arr4);
echo "<br>";
echo '数组 $arr4 中的,键名为3的键值为:'.$arr4[3];
//Array ( [0] => 张三 [1] => 张四 [2] => 张五 [3] => 张六 )
//数组 $arr4 中的,键名为3的键值为:张六
//索引数组3
$arr5[0]='张三';
$arr5[1]='张四';
$arr5[2]='张五';
$arr5[3]='张六';
var_dump($arr5);
//array(4) { [0]=> string(6) "张三" [1]=> string(6) "张四" [2]=> string(6) "张五" [3]=> string(6) "张六" }
关联数组//关联数组的下标(键名)由数值和字符串混合的形式组成,如果一个数组中有一个键名不是数字,那么这个数组就是关联数组。
$arr6 = array(
'Apple' => '苹果',
'Banana' => '香蕉',
'Orange' => '橘子',
'Plum' => '李子',
'Strawberry' => '草莓'
);
print_r($arr6);
//Array ( [Apple] => 苹果 [Banana] => 香蕉 [Orange] => 橘子 [Plum] => 李子 [Strawberry] => 草莓 )
多维数组我们以二维数组为例,它的语法有:1、直接赋值法,语法 $array[一维下标][二维下标]="值";2、使用array()函数,语法array(array(key=>value...),array(key=>value...)....);比如//直接赋值法:
$stu[0]['姓名'] = '张三';
$stu[0]['年龄'] = '25';
$stu[0]['性别'] = '男';
$stu[1]['姓名'] = '李四';
$stu[1]['年龄'] = '21';
$stu[1]['性别'] = '男';
$stu[2]['姓名'] = '娜娜';
$stu[2]['年龄'] = '22';
$stu[2]['性别'] = '女';
var_dump($stu);
//array(3) { [0]=> array(3) { ["姓名"]=> string(6) "张三" ["年龄"]=> string(2) "25" ["性别"]=> string(3) "男" } [1]=> array(3) { ["姓名"]=> string(6) "李四" ["年龄"]=> string(2) "21" ["性别"]=> string(3) "男" } [2]=> array(3) { ["姓名"]=> string(6) "娜娜" ["年龄"]=> string(2) "22" ["性别"]=> string(3) "女" } }
//使用array()函数
$stu1=array(
array('张三','25','男'),
array('李四','21','男'),
array('娜娜','22','女'),
);
var_dump($stu1);
//array(3) { [0]=> array(3) { [0]=> string(6) "张三" [1]=> string(2) "25" [2]=> string(3) "男" } [1]=> array(3) { [0]=> string(6) "李四" [1]=> string(2) "21" [2]=> string(3) "男" } [2]=> array(3) { [0]=> string(6) "娜娜" [1]=> string(2) "22" [2]=> string(3) "女" } }
$stu2=array(
array('name'=>'lili','sex'=>'famale','age'=>12),
array('name'=>'tom','sex'=>'male','age'=>15),
array('name'=>'join','sex'=>'famale','age'=>10)
);
echo ($stu2[0]['name']);//输出指定数组元素 lili
echo "<br>";
数组的遍历PHP中遍历数组有三种常用的方法:1、使用for语句循环遍历数组;2、使用foreach语句遍历数组;3、联合使用list()、each()和while循环遍历数组(感觉挺有意思的,试一下)这三种方法中效率最高的是使用foreach语句遍历数组,在这里着重介绍一下foreach语句://for语句
$arr9 = array('tom','lili','join');
$num = count($arr9);//count用来获取数组的长度
for($i=0;$i<$num;++$i){
echo $arr9[$i].'<br />';
}
//foreach语句
//每次循环中,当前元素的值被赋给变量$value,并且把数组内部的指针向后移动一步。所以下一次循环中会得到数组的下一个元素,直到数组的结尾才停止循环,结束数组的遍历。
foreach($arr9 as $value){
echo $value."<br>";
}
//tom
//lili
//join
foreach($arr9 as $key=> $value){
echo $key.$value."<br>";
}
//打印出键名(下标)
//0tom
//1lili
//2join
//联合使用list()、each()和while循环遍历数组
$arr = array('Chinese'=>'沃和莱特','english'=>'varlet');
while(list($key,$value) = each($arr)){
echo $key.'=>'.$value.'<br />';
}
//Chinese=>沃和莱特
//english=>varlet
foreach语句遍历二维数组:// 二维数组的遍历
$employee=array(
"人事部"=>array('a','b','c'),
"研发部"=>array('d','e','f'),
);
//打印出人事部有abc,研发部有def;
foreach($employee as $key=>$value){
echo $key.":";
foreach($value as $keyin=>$valuein){
echo $valuein." ";
}
echo "<br>";
}
//人事部:a b c
//研发部:d e f
// 把一个数组遍历成一个表格
$people=array(
array('name'=>'张三','sex'=>'male','age'=>25,'ad'=>"济南"),
array('name'=>'李四','sex'=>'famale','age'=>27,'ad'=>"上海"),
array('name'=>'王五','sex'=>'male','age'=>21,'ad'=>"青岛")
);
echo "<table border='1'>";
echo "<tr><th>id</th><th>name</th><th>sex</th><th>age</th><th>ad</th></tr>";
foreach($people as $key=>$value){
echo "<tr>";
echo "<td>$key</td>";
foreach($value as $keyin=>$valuein){
echo "<td>$valuein</td>";
}
echo "</tr>";
}
echo "</table>";
echo "<br>";
简单总结一下foreach遍历的本质就是数组的内部有一颗指针,默认指向数组元素的第一个元素,foreach利用指针获取数组,同时移动指针;并且foreach会重置指针,让指针指向第一个元素;数组函数//返回数组元素的位置
$str2=["张三",23,"jinan"];
$res=array_search("张三",$str2);
echo $res;
// 0
// 删除数组最后一个元素
$str2=["张三",23,"jinan"];
$res1=array_pop($str2);
echo $res1;
// jinan
// 默认向数组尾部增加一个元素
$str2=["张三",23,"jinan"];
$res2=array_push($str2,"qingdao");
print_r($str2);
// Array ( [0] => 张三 [1] => 23 [2] => jinan [3] => qingdao )
//数组去重
$arr3=["join","jim","tom","tom"];
$res4=array_unique($arr3);
var_dump($res4);
// array(3) { [0]=> string(4) "join" [1]=> string(3) "jim" [2]=> string(3) "tom" }
// 数组排序 升序
$arr4=["mudan","meigui","huaihua"];
sort($arr4);
print_r($arr4);
// Array ( [0] => huaihua [1] => meigui [2] => mudan )
$arr5=[12,13,32,45,0];
sort($arr5);
print_r($arr5);
// Array ( [0] => 0 [1] => 12 [2] => 13 [3] => 32 [4] => 45 )
// 降序排序
$arr4=["mudan","meigui","huaihua"];
rsort($arr4);
print_r($arr4);
// Array ( [0] => mudan [1] => meigui [2] => huaihua )
$arr5=[12,13,32,45,0];
rsort($arr5);
print_r($arr5);
// Array ( [0] => 45 [1] => 32 [2] => 13 [3] => 12 [4] => 0 )
// 根据数组的值升序排序
$age=array(
"granderfather"=>110,
"grandermonther"=>100,
"father"=>42,
"mother"=>40,
"brother"=>10,
"me"=>19,
);
asort($age);
print_r($age);
// Array ( [brother] => 10 [me] => 19 [mother] => 40 [father] => 42 [grandermonther] => 100 [granderfather] => 110 )
// 根据键值进行升序排序
$age1=array(
"ben"=>11,
"lili"=>12,
"tom"=>13
);
ksort($age1);
print_r($age1);
// Array ( [ben] => 11 [lili] => 12 [tom] => 13 )
// 根据键值进行降序排序
$age1=array(
"ben"=>11,
"lili"=>12,
"tom"=>13
);
krsort($age1);
print_r($age1);
// Array ( [tom] => 13 [lili] => 12 [ben] => 11 )
// 打乱数组
$age=array(
"granderfather"=>110,
"grandermonther"=>100,
"father"=>42,
"mother"=>40,
"brother"=>10,
"me"=>19,
);
shuffle($age);
print_r($age);
// Array ( [0] => 100 [1] => 42 [2] => 19 [3] => 40 [4] => 10 [5] => 110 )
// 删除数组
$arr5=[12,13,32,45,0];
unset($arr5[0]);
print_r($arr5);
// Array ( [1] => 32 [2] => 13 [3] => 12 [4] => 0 )
// 返回所有元素并将其放在一个新的数组中
$age1=array(
"ben"=>11,
"lili"=>12,
"tom"=>13
);
$res9=array_values($age1);
print_r($res9);
// Array ( [0] => 11 [1] => 12 [2] => 13 )
// 返回一个包含从 "0" 到 "50" 之间并以 10 递增的元素的数组:
$number = range(0,50,10);
print_r ($number);
// Array ( [0] => 0 [1] => 10 [2] => 20 [3] => 30 [4] => 40 [5] => 50 )
// 返回指定范围的索引
$num=[12,13,32,45,0,7,8,10];
$Nu=array_slice($num,1,3);//从第一个元素到第三个元素
print_r($Nu);
// Array ( [0] => 13 [1] => 32 [2] => 45 )
总结以上就是这篇文章对php数组的介绍啦,后续还会持续更新~可爱的程序员大佬们1024快乐,你是电脑的灵魂,你是网络的主人,你是程序的化身,你是创意的天使,你是互联网的传说,期待创造与前进,加油!
无意苦争春,一任群芳妒!M1 Mac book(Apple Silicon)能否支撑全栈工程师的日常?(Python3/Ruby/PHP/Mysql/Redis/NPM/虚拟机/Docker)
就像大航海时代里突然诞生的航空母舰一样,苹果把玩着手心里远超时代的M1芯片,微笑着对Intel说:“不好意思,虽然你也玩桌面芯片,但是,从今天开始,游戏就已经结束了,X86?还是省省吧。”十五年前,iPhone横空出世,乔布斯告诉世人什么才叫做真正的智能手机,十年前,A4处理器粉墨出场,iPhone瞬间猛虎添翼,性能这两个字从此没有友商敢在苹果面前提及,iPad更是在业界呼风唤雨,几乎把整个平板市场都收入囊中,在人们的脑海中,Pad就是iPad的代名词,安卓平板?不存在的。今时今日,Apple Silicon华丽登台,不必说M1堪称恐怖到爆炸的性能,也不必说十个小时以上的超长续航以及丝滑无迟滞的FCPX极速剪辑体验,单是通过Rosetta 2 虚拟运行X86应用,就已经足以让人感到惊艳了。然而,这些福利只是苹果对于产品级用户的馈赠,作为一名开发者,而且是全栈(全干)开发,M1能否应对繁复的开发环境?就像一位研发同事说的那样:“Hi,哥儿们,你不会花一万大洋买了个ipad+秒控键盘吧?这智商税有点贵啊”。首先是Python3的开发环境,python官网已经释出适配M1芯片的3.9版本,https://www.python.org/downloads/release/python-392/ ,但其实目前生态和市场占有率最高的还是3.7,笔者是通过迁移助理将老mac book pro里的开发环境(x86)直接迁移过来的,也就是迁移了原电脑的python3.7.4,令人意外的是,通过Rosetta 2,大部分的基础库都可以使用,除了首次运行稍显迟滞以外:liuyue:~ liuyue$ python3
Python 3.7.4 (v3.7.4:e09359112e, Jul 8 2019, 14:54:52)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pandas
>>> import cv2
>>> import numpy
>>> import matplotlib
>>> import nltk
>>> import ssl
>>> from nltk.stem.lancaster import LancasterStemmer但是一些深度学习框架比如TensorFlow就不行了,解决方案还是得从官网下载适配M1的3.9版本,然后再下载支持M1芯片的Tensorflow2.4,下载链接:https://link.zhihu.com/?target=https%3A//www.cyberlight.xyz/static/file/download\_and\_install.sh,换句话说,想用TensorFlow训练模型你就得升级python版本,可是很多TensorFlow项目都是和Web应用结合使用的,如果单独为了TensorFlow升级python,就需要将原来的项目分开部署,接口也得重构,尤其一些“祖传项目”就更不好弄了,这无疑提高了开发者的开发成本。再来说说测试,自动化测试工具selenium是我们经常使用的工具之一,使用场景非常广泛,但是在M1系统里面我们通过Rosetta 2虚拟的python3.7能否控制arm64版本的chrome呢?答案是可以的,因为chromedriver已经对M1芯片进行了适配,下载驱动:http://npm.taobao.org/mirrors/chromedriver/88.0.4324.96/ 注意要选择m1版本的驱动,随后解压,将chromedriver文件拷贝到系统目录中:sudo mv chromedriver /usr/local/bin随后启动浏览器:from selenium import webdriver
import time
#selenium 截图
driver = webdriver.Chrome()
driver.get('https://v3u.cn')
time.sleep(3)
driver.close()问题并不大,所以如果单纯用M1 Mac用来写自动化测试脚本或者爬虫不会有太大压力,但是,如果涉及科学计算的结果测试,可能就得折腾一下了。再聊聊虚拟机,虚拟机无论是测试岗还是运维岗基本都会用到,因为有些应用在Win和Mac系统中展示出的效果不尽相同,目前虚拟机两大巨头Vmware和Parallels都在加紧适配,Parallels领先一步,首先释出了兼容M1芯片的测试版虚拟机,不过需要先注册获取注册码:https://b2b.parallels.com/apple-silicon随后在该页面下载安装包进行安装即可,需要注意的一点是,注册的时候一定要记录一下注册码,否则安装成功后没有码进行激活就尴尬了。与此同时微软也适时的发布了基于arm内核的win10测试版镜像,下载地址:https://www.microsoft.com/en-us/software-download/windowsinsiderpreviewARM64 当然了,因为一些众所周知的学术问题,导致下载速度不尽如人意,笔者已经将安装包和镜像上传网盘,在文章底部会贴出来。安装好Parallels以后,将arm版win10镜像导入即可安装,只需要5分钟左右就可以安装成功:虽然是测试版,但是整体上运行起来非常行云流水,别忘了在系统内添加中文默认语言包:在M1 Mac中玩虚拟机,几乎没有迟滞感,顺滑的令人咋舌,风扇纹丝不动,且能耗也并没有显著增加,续航也没有因为虚拟机的出现而减少太多,这是M1非常惊艳的一点。想要用Mac做开发,包管理工具Homebrew是无法绕过的一环,所以如果你是通过迁移助理把老的x86架构的直接迁移到M1的mac中,那么最好别用了,会出很多问题,解决方案就是安装 arm版的Homebrew执行安装命令:/bin/bash -c "$(curl -fsSL https://cdn.jsdelivr.net/gh/ineo6/homebrew-install/install.sh)"基于arm的Homebrew统一安装在系统的/opt/homebrew目录,主要是为了和老版的x86区别开。随后添加环境变量:echo export PATH=/opt/homebrew/bin:$PATH >> ~/.bash_profile
source ~/.bash_profile接着执行:liuyue:~ liuyue$ brew update
Already up-to-date.
liuyue:~ liuyue$如果返回Already up-to-date.就没问题了,基本上目前Homebrew大概有7成左右的软件支持M1芯片,具体适配列表可以参照:https://github.com/Homebrew/brew/issues/7857可以看到,像数据库如mysql、redis都进行了适配,mysql还有一些小bug,介意的同学可以考虑Rosetta,下面我们来看看用arm版的Homebrew来安装reids的流程:安装命令:brew install redis一般brew会获取最新稳定版,安装成功后,查看软件列表:liuyue:~ liuyue$ brew list
openssl@1.1 redis
liuyue:~ liuyue$此时启动服务:liuyue:bin liuyue$ redis-server
36148:C 24 Feb 2021 21:13:48.673 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
36148:C 24 Feb 2021 21:13:48.673 # Redis version=6.2.0, bits=64, commit=00000000, modified=0, pid=36148, just started
36148:C 24 Feb 2021 21:13:48.673 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
36148:M 24 Feb 2021 21:13:48.673 * Increased maximum number of open files to 10032 (it was originally set to 256).
36148:M 24 Feb 2021 21:13:48.673 * monotonic clock: POSIX clock_gettime
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 6.2.0 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 36148
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'然后开启另一个命令行连接服务:liuyue:~ liuyue$ redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379>可以看到和x86的brew用起来没有区别,只不过上面的软件或多或少有些bug,用起来要小心。如果你觉得arm版的brew速度过慢,可以单独设置国内源:git -C "$(brew --repo)" remote set-url origin https://mirrors.ustc.edu.cn/brew.git
git -C "$(brew --repo homebrew/core)" remote set-url origin https://mirrors.ustc.edu.cn/homebrew-core.git
git -C "$(brew --repo homebrew/cask)" remote set-url origin https://mirrors.ustc.edu.cn/homebrew-cask.git
echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles' >> ~/.bash_profile
source ~/.bash_profile中科大的镜像稍微靠谱一点。有同学说,那还有三成的软件怎么搞?另外看起来arm的brew并不打算适配老版本软件,比如python3.7,其实在M1 的mac系统也可以装一版x86的brew,安装 x86 的 Homebrew:arch -x86_64 /bin/bash -c "$(curl -fsSL https://cdn.jsdelivr.net/gh/ineo6/homebrew-install/install.sh)"装好之后,它还是在原来的/usr/local/bin/brew里面,这样就和/opt/homebrew/bin/brew 区分开了执行命令:
liuyue:~ liuyue$ /usr/local/bin/brew list
autoconf gmp libtool openssl@1.1 siege
automake icu4c libyaml perl sqlite
boost isl lua pkg-config thrift
coreutils libevent mkcert python@3.8 trash
gcc libgpg-error mpfr readline xz
gdbm libksba mtr redis yarn
gettext libmpc node ruby zlib
可以看到这些都是我从老的x86电脑中迁移过来的软件,大部分都用不了,比如redis,而基于arm的brew安装的新redis是可以使用的:liuyue:~ liuyue$ /opt/homebrew/bin/brew list
openssl@1.1 redis所以用M1 mac做开发,就有点分裂,新软件包记住用/opt/homebrew/bin/brew,老的用:/usr/local/bin/brew接着来看看Docker,Docker官方对于M1的适配还是很重视的,早些时候放出来一个测试版客户端:https://docs.docker.com/docker-for-mac/apple-m1/不仅可以拉取arm版的镜像,也可以操作Kubernetes,对于Kubernetes不熟悉的同学可以参照这篇文章:一寸宕机一寸血,十万容器十万兵|Win10/Mac系统下基于Kubernetes(k8s)搭建Gunicorn+Flask高可用Web集群。不过令人遗憾的是,Docker Hub 支持 arm 版本的镜像并不多,大抵在x86镜像的三、四成左右,但是可以看出来各大厂商对于M1都是比较看重的,基本上官方都有适配的消息流出。对于其他的语言来说,比如 go lang、ruby、以及php等,都有一个和python一样的通病,就是老版本不支持arm内核,只适配了最近的一个或者两个版本,这样也导致如果你换电脑的话,就得考虑向下兼容性问题。对于一些常用的开发软件,比如vscode 和 sublime 3 都可以正常运行,php套件xampp运行无障碍,版本控制客户端SourceTree、数据库客户端Navicat、微信、QQ、SSH客户端iTerm 4以及Ftp客户端FileZilla都可以正常运行,前端微信小程序开发工具还是会有几率闪退,腾讯一开始对big sur就适配的不好,M1就更别提了。值得一提的是,设计软件Photoshop最新版2021暂时还不支持M1芯片,只能凑合先用2019版的,与之形成对比的就是FCPX10.5的完美表现,看来还是亲儿子给力,Adobe还得加把劲了。综上,如果您是一个初学者,只是想学习一些语言的基础语法,没打算写一些复杂工业级项目,可以考虑入手M1,它将会是您入门的好帮手,但是如果您在业内已经混迹多年,经常编译一些复杂代码、各种库,甚至手里还有一些“祖传代码”项目在维护,那么x86的Mac可能还得陪您一两年。最后,上面提到的适配M1芯片的安装包和镜像请移步:链接: https://pan.baidu.com/s/12d7fHl\_ZYyx4Xk-v0R0N\_g 密码: 1fdc 需要的同学自行下载 结语:有时候,当我们称赞一项技术的时候,我们会称其为这样或者那样的行业标杆、教科书之类,但是对于M1的Mac book来说,它好像已经超越了所谓的标杆,而成为了跨越时代的不朽经典。苹果作为业内完美的六边形战士,还依然在探索,依然没有裹足不前,继续探索新的道路,继续钻研可行性,这是它带给我们的启示,然而,在2021年的这个春天里,面对开发者,M1芯片有点像悲情的俄尔普斯,它能用动人的绕梁琴声打动开发者们,却在最后一秒钟忍不住回眸,断送挽救爱妻欧莉蒂克的最后机会,很明显,它已经足够努力,但是还差那么一点点,就差一点了,但是我相信,神明早已在M1的命格中写下四个字:注定辉煌。
关于ios低版本在app store下载软件时由于版本低导致不能下载的解决办法
随着H5技术和VUE技术的流行,现在越来越多人喜欢试用hbuilder、uniapp或apicloud这些框架或工具来生成ios的app,这些工具会帮我们生成一个ipa文件。假如我们有MAC电脑,我们可以使用xcode这些工具将这个ipa文件上传去苹果开发者中心。但是我们假如没有MAC电脑,我们又如何将ipa文件上传去苹果开发者中心呢?下面,我们介绍下如何使用微链软件上传ipa文件:工具的地址如下:https://www.ipwas.cn/AppStore.htmlhttps://www.ipwas.cn/AppStore.html1、登录苹果开发者中心Apple Developer检查你有没有在app store connect里面创建好app。2、填写应用的其他资料,然后这时候会需要你选择构建版本。3.注册微链软件帐号(苹果(IOS)在线创建证书|微链开发技术文档交流|apicloud|h5开发|PHP开发-微链网https://www.ipwas.cn/)注册本站帐号进入个人中心即可看到同时程序保留了5分钟列队时间,在5分钟内你操作有误或者上传错误了或因为其他原因都可以撤回上传,最大支持1G文件上传。证书我们这边可以借助辅助工具appuploaderAppuploader可以辅助在Windows、linux或mac系统直接申请iOS证书p12,及上传ipa到App Store,最方便在Windows开发上架没有苹果Mac电脑的开发者!配合本教程使用,可以快速掌握如何真机测试及上架!点击苹果证书按钮点击新增输入证书密码,名称这个密码不是账号密码,而是一个保护证书的密码,是p12文件的密码,此密码设置后没有其他地方可以找到,忘记了只能删除证书重新制作,所以请务必记住密码。还有为了安全起见,密码不要太简单。 证书名称是你为了在证书列表里面便于区别的一个字符,自己好辨识就可以,尽量是是字母和数字之类选择证书类型带distribution的是发布类型,带development的是开发类型。apple类型=ios+mac,所以开发时选择ios app development和apple development 类型都是可以的选择bundle id只有部分类型的证书需要选择bundle id,例如推送证书。因为大部分证书是不和app关联的。而是通过描述文件profile文件关联app。
程序猿年薪3w到30w的必读书单
前言入行9年多了,一路走来也翻过各路各样的货,总觉得学习不够系统结构化,好些经典干货不够深入,因此结合自身经历和网上资料整理此针对java软件工程师(偏互联网)的必读书单,希望对您有所帮助,并在学习的路上少走弯路或陷入误区。从业界看优秀的程序员应具备两方面的能力:1.良好的程序设计能力:掌握常用的数据结构和算法(如链表,栈,堆,队列,排序和散列);理解计算机科学的核心概念(如计算机系统结构、操作系统、编译原理和计算机网络);熟悉互联网网络和服务器原理(如TCP/UDP,http)熟悉至少两门以上编程语言(例如Java、Python、php);2.专业的软件开发素养:具备良好的编程思想或思维(即是软件工程思想),如OOA、OOD、OOP、结构化思维等具备良好的编程实践,能够编写可测试,可扩展,可维护的代码;理解把握需求,按时按质交付用户所需要的产品;跟其它能力一样,程序设计和软件开发素养的能力源自书本知识和项目经验。项目经验因人而异(在不同领域的程序员项目经验的差异会比较大),但书本知识是相通的,尤其是经典书籍不仅能够拓宽程序员的视野且能提高成长速度,经典书籍经得住时间的考验,可反复读,技术框架有很多,我们不要陷入追求数量的误区,要追求质量,同类型的技术框架深入学习一种即可,比如mvc框架只需深入研究spring mvc或其他任一种即可,其他都是相通的,因此学习书本知识是一场没有终点的马拉松比赛,而阅读书籍的顺序一般从入门—经典—延伸的学习过程,此书单正是按照此规律并结合程序员修炼过程而制定。一.入门书籍程序设计:1.基础理论:《编码:隐匿在计算机软硬件背后的语言》(挑读)2.编程语言:JavaScript:《JavaScript DOM编程艺术(第2版)》、至少一js框架如jquery《jQuery开发从入门到精通》(细读)Java:《Java核心技术》(第9版)(细读)Python:《Python基础教程(第二版)》(细读)3.编程语言理论:《编程语言实现模式》(细读)4.程序设计:《程序设计方法》(细读)5.算法与数据结构:《算法(第4版)》(略读)6.程序调试:《调试九法——软硬件错误的排查之道》(细读)7.网络及系统:《http权威指南》、《鸟哥的Linux私房菜基础学习篇(第三版)》(挑读)8.数据库:《数据库原理(第5版)》(挑读)软件开发:1.编程实践:《程序设计实践》(细读)2.面向对象程序设计:《Head First设计模式》(细读)3.重构:《重构》(挑读)4.软件测试:《How to Break Software》(挑读)5.专业开发:《程序员修炼之道:从小工到专家》(细读)6.网络及系统:《TCP/IP入门经典(第5版)》(挑读)7.数据库:《SQL入门经典(第5版)》(细读)8.互联网:《拆掉互联网那堵墙》(略读)二.经典(进阶)书籍程序设计:1.基础理论:《深入理解计算机系统(第2版)》(细读)2.编程语言:Java:《Effective Java(第2版)》、《深入理解Java虚拟机 JVM高级特性与最佳实践》(细读)JavaScript:《JavaScript语言精粹》(细读)Python:《Python参考手册(第4版)》(细读)3.编程语言理论:《程序设计语言——实践之路》、《java编程思想 第4版》(第3版)(挑读)4.程序设计:《计算机程序的构造与解释(第2版)》(挑读)5.算法与数据结构:《编程珠玑(第2版)》(略读)6.程序调试:《调试九法——软硬件错误的排查之道》(挑读)7.网络及系统:《网络安全基础:应用与标准(第5版)》(挑读)8.数据库:《数据库设计指南-60个设计技巧》(挑读)软件开发:1.编程实践:《代码大全(第2版)》(细读)2.面向对象程序设计:《设计模式》(细读)3.重构:《修改代码的艺术》(细读)4.软件测试:《xUnit Test Patterns》(略读)5.专业开发:《程序员的思维修炼:开发认知潜能的九堂课》、《程序员职业素养》(挑读)6.网络及系统:《深入理解linux内核(第三版)》(挑读)7.数据库:《高可用MySQL:构建健壮的数据中心》(略读)8.互联网:《大型网站技术架构:核心原理与案例分析》《大规模Web服务开发技术》《大数据时代》(挑读)三.延伸(个人成长)1.职业规划:《软件开发者路线图》(挑读)2.工作思维方式:《如何把事情做到最好》(挑读)3.求职面试:《金领简历:敲开苹果微软谷歌的大门》、《程序员面试金典》(第5版)(挑读)4.自我管理:《德鲁克---自我管理》(挑读)学而不思则罔,思而不学则殆,如果以上书单你能全部读完,年薪3w到30w指日可待。点击“电子书 ”可下载书单对应的电子书籍。————————————————文/老猿,写代码写诗写职场的程序猿大叔,转载此文请联系老猿。
一文尽览 | 基于点云、多模态的3D目标检测算法综述!(Point/Voxel/Point-Voxel)(上)
原文首发微信公众号【自动驾驶之心】:一个专注自动驾驶与AI的社区(https://mp.weixin.qq.com/s/NK-0tfm_5KxmOfFHpK5mBA)目前3D目标检测领域方案主要包括基于单目、双目、激光雷达点云、多模态数据融合等方式,本文主要介绍基于激光雷达雷达点云、多模态数据的相关算法,下面展开讨论下~3D检测任务介绍3D检测任务一般通过图像、点云等输入数据,预测目标相比于相机或lidar坐标系的[x,y,z]、[h,w,l],[θ,φ,ψ](中心坐标,box长宽高信息,相对于xyz轴的旋转角度)。3D检测相关数据集下面汇总了领域常用的3D检测数据集,共计11种:KITTI-3D: http://www.cvlibs.net/datasets/kitti/eval_object.php?obj_benchmark=3dArgoverse:https://www.argoverse.org/data.html#download-linkLyft L5:https://level-5.global/download/H3D:https://usa.honda-ri.com//H3DA*3D:https://github.com/I2RDL2/ASTAR-3DnuScenes:https://www.nuscenes.org/nuscenes#downloadWaymo Open:https://waymo.com/open/download/CityScapes-3D:https://www.cityscapes-dataset.com/downloads/A2D2:https://www.a2d2.audi/a2d2/en/download.htmlKITTI-360:http://www.cvlibs.net/datasets/kitti-360/download.phpRope3D:https://thudair.baai.ac.cn/rope3D检测在数据格式上的分类基于激光雷达点云基于pointPointRCNN基于Point系列的3D点云检测器一般逐点检测采样,PointRCNN是领域中比较经典的一篇文章,基于原始密集点云数据直接进行特征提取和RPN操作。论文使用PointNet++网络实现前景与背景分割,主要分为两个阶段。第一阶段生成一大堆很冗余的bounding box。首先,对点云语义分割,对每个点的到一个预测label,比如现在:对所有判断是“车”的点(也叫做前景点),赋予label=1,其他点(也叫做背景点),赋予label=0。然后,用所有前景点生成bounding box,一个前景点对应一个bounding box,但是必须要保证语义分割结果的准确。作者使用了一些去除冗余的方法,继续减少bounding box的数目,这一阶段结束的时候只留下300个bounding box。第二阶段继续优化上一阶段生成的bounding box。首先,对前一阶段生成的bounding box做旋转平移,把这些bounding box转换到自己的正规划坐标系下(canonical coordinates)。然后通过点云池化等操作的到每个bounding box的特征,再结合第一阶段的到的特征,进行bounding box的修正和置信度的打分,从而的到最终的bounding box。网络结构如下所示(结果也是当年的SOTA!):3DSSD3DSSD作者提出像PointRCNN这种基于原始点云的二阶段3D检测方法,在第一阶段往往利用Set Abstraction层(SA)进行不断的下采样、分组与特征提取,然后利用Feature Propagation层(FP)对SA的输出进行不断上采样与特征传播。利用语义分割获得了前景点后,这些方法以每个前景点为中心进行3D检测框的提议(第一阶段的粗提议)。粗提议结束后,对这些粗提议检测框内部点进行特征提取与处理,微调检测框,获得更精确的检测框(第二阶段的精炼过程)。然而上述的二阶段方法中的FP层和精炼过程在模型前向推理过程中往往会消耗一半以上的时间。那简单地将这些模块删除后(只剩下SA层),然后基于SA提取的特征直接进行单阶段提议是否可行?事实证明有人确实这么做了,但是该简单直接的方法造成了检测精度降低了不少。可能的原因有:现有一些方法在SA层的下采样步骤中用到了D-FPS方法(基于距离的最远点采样法)。该采样方法的特点是:以空间距离最大为原则,不断迭代采样场景的点云,采样后的点云基本覆盖了整个场景(避免了随机采样对密度较高点云簇的青睐)。因为场景中背景点数量偏多,且有些较远目标中的前景点较少,这样的采样方式几乎会过滤掉距离较远的物体的所有前景点。前景点都过滤完了,检测精度自然不会高到哪儿去。因此,作者希望有一个采样方式使得采样的点(记做representative points)既能铺满整个采样空间,又能尽可能地包含更多的前景点,也就是论文中的F-FPS。3DSSD,在精度和效率之间实现了良好的平衡,比前期基于点的检测算法速度提升近1倍,也超越了当时的单阶段所有基于voxel的方法!Fast PointRCNNFast PointRCNN是PointRCNN的改进版,但是一种point-voxel方式检测器(为了方便先放置在这里一起讲了),PointRCNN在第一阶段太慢了,又是前景分割,又是前景点的RPN回归。Fast PointRCNN作者直接利用基于Voxel的数据处理方式进行点云结构化,然后利用三维卷积和二维卷积的堆叠实现Voxel特征的提取。(全三维卷积可以保留Z轴的信息,但是效率会比较低,因为运算量大。全二维卷积直接就忽略了Z轴的信息了,虽然速度快,但是精度也受到了影响。所以作者采用这种“三维卷积-二维卷积”的网络结构,先利用“三维卷积”保留Z轴的信息,然后为了提高效率,采用了"二维卷积”进行特征提取。实验表明,这种方式确实可以提高效率,而且精度也不会降低。)在基于图片的2D物体检测任务中,通常利用特征金字塔(FPN)的网络结构实现大小不同物体的proposal。YOLO V3的一个特点就是在三个不同尺度的特征图中,分别放置负责检测不同大小物体的预设框Anchor。底层的特征因为感受野小,负责小物体检测,因此放置较小的Anchor。反之,顶层的特征因感受野较大,负责大的物体的检测任务,因此放置较大的Anchor。受启于此,FastPointRCNN的作者也选择了这样的方式实现了对不同大小物体的同时检测,提出了一种叫做VoxelRPN的网络,实现第一阶段的候选框粗略提议。第一阶段完成proposal后,然后引入RefinerNet完成第二阶段的优化!网络流程如下图所示:Lidar RCNNLidar RCNN是一个两阶段检测器,通常可以改进任何现有的3D检测器(无需re-training)。为了在实践中满足实时性和高精度要求,论文采用了基于点(point)的方法,而不是流行的基于voxel的方法。但是论文在以前的工作中发现了一个被忽视的问题:天真地应用基于PointNet的基于点的方法可能会使学习到的特征忽略proposals的尺度。为此,论文详细分析此问题,并提出几种补救方法,以带来显著的性能改进,论文给出了性能和耗时分析,综合性能突出!IA-SSDIA-SSD是CVPR2022最新提出的网络,论文针对三维激光雷达点云的有效目标检测问题开展了研究,为了减少内存和计算成本,现有的基于point的pipeline通常采用任务无关随机采样或最远点采样来逐步向下采样输入pointset,然而并非所有点对目标检测任务都同等重要。对于detector来说,前景点本质上比背景点更重要。基于此,论文提出了一种高效的单级基于point的3D目标检测器,称为IA-SSD。IA-SSD利用两种可学习的,面向任务、实例感知的下采样策略来分层选择属于感兴趣对象的前景点。此外,还引入了上下文质心感知模块,以进一步估计精确的实例中心。最后,为了提高效率,论文按照纯编码器架构构建了IA-SSD。在多个大规模检测benckmark上进行的实验证明了IA-SSD的优势。由于低内存占用和高度并行性,在KITTI数据集上单个RTX2080Ti GPU实现了每秒80多帧的速度。基于VoxelVoxelNet基于Voxel的方法是领域研究热点,近年来也有非常多的paper,VoxelNet是开山之作,苹果公司提出!论文将三维点云划分为一定数量的Voxel,经过点的随机采样以及归一化后,对每一个非空Voxel使用若干个VFE(Voxel Feature Encoding)层进行局部特征提取,得到Voxel-wise Feature,然后经过3D Convolutional Middle Layers进一步抽象特征(增大感受野并学习几何空间表示),最后使用RPN(Region Proposal Network)对物体进行分类检测与位置回归。VoxelNet整个pipeline如下图所示:SECONDVoxelNet思路比较好,但速度上优势不大!SECOND全称为Sparsely Embedded Convolutional Detection,也就是稀疏卷积,SECOND的出现,让实时检测更近一步!考虑到VoxelNet通过Feature Learning Network后获得了稀疏的四维张量,而采用3D卷积直接对这四维的张量做卷积运算的话,确实耗费运算资源,SECOND作为VoxelNet的升级版,用稀疏3D卷积替换了普通3D卷积,如下图所示。PointPillarsPointPillars是2019年出自工业界的一篇Paper,意义很大,该模型最主要的特点是检测速度和精度的平衡,平均检测速度达到了62Hz,最快速度达到了105Hz,遥遥领先了其它的模型(也是目前落地较多的方案)。论文提出了一种新的点云编码方法用于给PointNet提取点云特征,再将提取的特征映射为2D伪图像以便用2D目标检测的方式进行3D目标检测。尽管只使用激光雷达,但PointPillars在3D和鸟瞰KITTI基准方面,甚至在融合方法中,都显著优于最新技术,模型结构如下图所示:Part-A2Part-A2将PointRCNN扩展到一个新的、强大的基于点云的三维对象检测框架,即部件感知和聚合神经网络(part-A2网络),整个框架由部件感知阶段和部件聚合阶段组成。部件感知阶段利用3D GT bbox提供的信息,生成3D 分割的标注信息,分割前景点和背景点;对于所有的前景点,估计每一个前景点的相对位置(intra-object part location,认为该信息隐式编码3D目标的形状);从原始点云生成3D proposals(包括anchor-free和anchor-based两种方法)。部件聚合阶段对于不同的proposals可能具有相同的点云信息,产生相同的特征带来的模糊性的问题,论文提出ROI-aware点云池化方案,它保留非空和空体素的所有信息,以消除点云池化方案的模糊性。利用空体素对bbox的几何图形信息进行编码,提升bbox的re-score和位置refine的性能。除此之外,进一步利用稀疏卷积和稀疏池化操作,逐步聚合每个3D proposals的池化后的part feature,实现准确预测;Part-A2网络优于当年所有的3D检测方法(仅利用激光雷达点云数据),在KITTI 3D目标检测数据集上实现了SOTA。CIA-SSDCIA-SSD这篇文章以SECOND为Backbone提出了一种基于体素的一阶段目标检测模型,其基本思想是校准单步目标检测中分类和定位两个任务,提出Confident IoU-Aware Single-Stage object Detector (CIA-SSD)。第一个是Spatial-Semantic Feature Aggregation(SSFA)模块,为了准确预测目标框和分类置信度,自适应地融合低端spatial feature和高端抽象semantic feature。而第二个是IoU-aware confidence rectification模块,对置信度进一步校准(rectified),使其和定位精度更加一致。最后采用Distance-variant IoU-weighted NMS获得更平滑的回归并避免冗余预测。SE-SSDSE-SSD提出了Self-Ensembling single-stage目标检测器(SE-SSD),在户外点云中进行精确检测,其关注点是利用soft(teacher模型预测的)和hard(标注信息)的目标以及制定的约束来共同优化模型,且不在推理中引入额外计算。具体地说,SE-SSD包含一对teacher和student的SSD,并设计了一个有效的IOU-based的匹配策略来过滤teacher的soft目标,并制定一致性损失来使student的预测与它们保持一致。此外,为了最大限度地运用teacher的蒸馏知识,设计了一种新的数据增强方案来产生形状感知的增强样本来训练student SSD,以推断完整的目标形状。最后,为了更好地利用hard目标,还设计了一个ODIoU损失来监督约束预测的box中心和方向的student,速度可达30.56ms。Voxel-RCNNVoxel-RCNN指出一般point-based精度高但特征计算量大,voxel-based结构更适合特征提取,但精度下降;作者认为,点云数据的精确定位并不需要,而粗voxel粒度也能产生充分检测精度。论文提出的Voxel R-CNN是一个两步法,仍然达到和当前point-based方法可比的检测性能,但计算量降低较多。Voxel R-CNN主要包括3D主干网络,2D BEV RPN和检测头,其中提出的voxel ROI pooling负责从voxel特征中提取ROI特征。如下图所示,通过3D backbone提取3D特征,然后映射到BEV空间,生成proposal,通过Voxel ROI Pooling方式提取特征做优化。与现有的基于体素的方法相比,Voxel R-CNN提供了更高的检测精度,同时保持了实时帧处理速率,在NVIDIA RTX 2080 Ti GPU帧率为25!CenterPointCenterPoint是Center-based系列工作(CenterNet、CenterTrack、CenterPoint)的扩展,于2020年作者在arxiv公开了第一版CenterPoint,后续进一步将CenterPoint扩充成了一个两阶段的3D检测追踪模型,相比单阶段的CenterPoint,性能更佳,额外耗时很少。本文的主要贡献是提出了一个两阶段的Center-based的目标检测追踪模型,在第一阶段(如下图中的a,b,c),使用CenterPoint检测三维目标的检测框中心点,并回归其检测框大小,方向和速度。在第二阶段(如下图中的d)设计了一个refinement模块,对于第一阶段中的检测框,使用检测框中心的点特征回归检测框的score并进行refinement。在nuScenes的3D检测和跟踪任务中,单阶段的CenterPoint效果很好,单个模型的NDS为65.5,AMOTA为63.8。模型性能很好,但是论文中说该模型的速度是在Waymo上11FPS,在nuScenes上为16FPS;同时模型的速度实验是在TiTan RTX上做的,也就是在所有边缘计算设备上均达不到实时计算。
微信小程序2|学习笔记
开发者学堂课程【高校精品课-上海交通大学 -互联网应用开发技术:微信小程序2】学习笔记,与课程紧密联系,让用户快速学习知识。课程地址:https://developer.aliyun.com/learning/course/76/detail/15777微信小程序2内容介绍:一、程序与页面-页面二、组件三、API四、事件五、兼容六、wx.request 接口七、设置超时时间八、请求前后的状态处理九、推荐学习资料十、总结 一、程序与页面-页面1、页面的用户行为:小程序宿主环境提供了四个和页面相关的用户行为回调-下拉刷新onPullDownRefresh监听用户下拉刷新事件 -上拉触底onReachBottom监听用户上拉触底事件 -页面滚动onPageScroll监听用户滑动页面事件-用户转发onShareAppMessage只有定义了此事件处理函数,右上角菜单才会显示“转发”按钮-代码清单3-13使用onShareAppMessage自定义转发字段// page.js Page({onShareAppMessage:function(){return {title:'自定义转发标题', path:'/page/user?id=123页面里面可以绑定一些动作,例如下拉刷新、上拉触底、页面滚动、用户转发等等,右上角菜单会显示转发按钮,对应的应该在配置的构造器里面写相应的函数的内容,比如说转发,就会写转发的题目是什么,把它转发到哪里去?2、页面跳转和路由-页面栈在多个页面构成的小程序栈里面,跟 web 不一样,它是靠手在手机上滑动,会有一个叫做 wx.navigateTo 导航到一个新的页面。但是整个所有页面全都在一个页面栈里,这就是它页面跳转的逻辑。每讲一个前端框架,都必须要讲页面跳转逻辑。它的页面跳转逻辑是通过页面栈来实现的,在页面栈里会记下来当前已经经历过的页面。3、(1)页面路由- 假设页面栈:[pageA,pageB,pageC ]-其中pageA在最底下,pageC在最顶上- 使用wx.navigateTo({url:'pageD'})可以往当前页面栈多推入一个pageD·此时页面栈变成[pageA,pageB,pageC,pageD]-使用wx.navigateBack()可以退出当前页面栈的最顶上页面·此时页面栈变成[pageA,pageB,pageC]-使用wx.redirectTo({url:'pageE'})是替换当前页变成pageE·此时页面栈变成[pageA,pageB,pageE],当页面栈到达10层没法再新增的时候,往往就是使用redirectTo这个API进行页面跳转(2)比如说在 pageA 页面是首页,首页登录之后进入第二个页面就是B页面。假如A是 login,B是图书的详情(booklist),C是具体的一本图书。往回页面上会有箭头,会按照栈的方式弹栈,所以不会从C一下弹到A,一定要经历B才能过来。navigateTo 的意思要从当前页面跳转到另一个页面,navigateTo 后面写了url:‘pageD’ 要跳转到D这个页面,就进入到这个栈里面,D再往前回翻的时候会翻到C,以此类推。navigateBack 和 navigateTo 的差别是 navigateBack 可以退出当前页面,栈不能一直不断增加,回退的时候可以把它彻底的从栈里面弹出去,然后退出当前页面栈的最顶上页面,就是把B直接弹出去。假如要找的商品不存在,通过编程的方式把它 back 又自动回到了C页面。这样访问的话有一个问题,当页面栈达到十层的时候,小程序有了限制,达到十层的时候就出错了,不能再增加了,不能再增加还想访问,可能不需要一页一页按照顺序翻过去,当前C页面直接让 redirectTo 那个页面不像 navigateTo 把C在栈里面的时候通知D进栈多一层,而是C本身在栈里面不要了,将来回不到C了,直接跳到E,丛E再往回回的时候进入C的页面,最后从B直接进入C,从C跳到E,然后E再往回退的时候只能退到B。4、路由的逻辑是下面看到的关系:它们跳来跳去的时候会触发页面的一些动作,比如说打开第一个页面 onLoad、onShow 就是在加载整个页面显示出来的两个方法,第一个页面的两个方法就会被调用。当调用 navigateTo 的时候,就是从A要跳到B的时候,A的 onHide 会被调用,隐藏起来,B的 onLoad、onShow 分别会在B渲染出来之后被调用。redirectTo的时候,是把当前的C页面直接退掉,就是销毁直接到E,E将来回不到C,只能回到B,这种时刻A这个页面 redirect 到B,那么A这个页面就 onUnload,被卸载之后调用的方法会被触发,然后B还是一样 。navigateBack 要退回到前一页,当前这个页会被卸载掉,刚才那个页 navigateTo 过来,只是被隐藏了,所以现在要onShow,再把它显示出来。微信的小程序重新用和由多个 Tab 页构成的一个页面怎样操作,这需要查看官方文档,但是我们在小程序里可能不太会用到切换、调用 API wx.switchTab 方式 ,它的交互方式比较麻烦,相当于在一个页面里还有很多个 tab 页,下面的是完整页面,上面的 tab 页是123,里面显示不同的内容,比较累赘。5、当前的页面在进入到每一个页面哪些函数会被调用,不在仔细讲解。 二、组件1、小程序的开发页面和 React 一个道理,一定要做构建化,无论是 react还是 vue 一定要做构建化,把前端的东西变成一些基本的元素,然后把它们用构建(component)呈现出来,组装成一个完整的页面。微信的小程序也是这个套路,组件就是小程序页面的基本组成单元,每一个组件都有id、class、style、hidden 等。2、举个例子,像 Image 图片的属性,除了刚才的还有一些别的,比如说它的图片在哪里,要做裁剪、缩放,可能给它留的空间并不是照片的大小,所以需要通过缩放和裁剪来呈现。lazy-load 一开始可能不加载,当访问到这个页面,下拉一个很长的页面,一开始只显示了上面一部分,下拉的时候下面有图片,一开始不加载,当下拉要显示到的时候再加载。binderror 表示出错的时候该怎么办,出错显示 event.detail={errMsg:‘something wrong’},bindload 表示图片加载完毕之后该怎么办,加载完毕之后其实什么也可以不显示,根据图片的内容在后台记录一个信息可以便于后面去访问。控件数量太多,不再讲每一个控件怎样使用。三、API1、(1)宿主环境提供了丰富的API,可以很方便调起微信提供的能力。https://mp.weixin.qq.com/debug/wxadoc/dev/api/小程序提供的API按照功能主要分为几大类:网络、媒体、文件、数据缓存、位置、设备、界面、界面节点信息还有一些特殊的开放接口。API一般调用的约定:- wx.on*开头的 API是监听某个事件发生的API接口,接受一个 Callback 函数作为参数。当该事件触发时,会调用Callback函数。- 如未特殊约定,多数 API接口为异步接口,都接受一个Object作为参数 - API的Object参数一般由success、fail、complete三个回调来接收接口调用结果- wx.get*开头的API是获取宿主环境数据的接口 - wx.set*开头的API是写入数据到宿主环境的接口(2)把小程序部署在微信客户端,微信本身提供大量 API,比如说打开摄像头或访问网络,或者是访问本地的照片等等。一般来说系统调用的 API,可以用到手机上的一些东西,然后这些 API 就屏蔽掉了手机的差异,不管是怎样的手机调这个 API 都能达到目的,底层的异构性靠 API 给屏蔽掉。微信里的API 一般都以 wx.on* 开头表示在监听某个事件,“*”代表事件,* 会在里面要求写进去一个回调函数。比如说在监听 onload,在页面被加载的时候可能要去回调一个函数,当这个事件被触发的时候调用 Callback 函数。大多数 API 接口多为异步接口,不能调用完以后立马判断里面的逻辑操作是否完成,有可能还没有完成。API 返回的结果一般是 Object 参数,有成功失败和完成这三个调用接口,成功、失败对应的是调用的两种结果,这两个不管怎样,最终都会调用 complete。wx.get* 开头的 API 对微信客户端本身的数据接口进行读;wx.set* 开头的 API 是写入数据到宿主环境的接口。2、举个例子,图的下面怎样跟后台Java 写的应用交互?需要用到微信的 API,微信的 API 有一个专门发请求的东西是 wx.request,它跟 fetdj 作用是类似的,用后台去访问。因为在后台做了跨域的动作,只允许本地跨域,所以调用起来是没问题的。第一个动作是 url,访问后台的 url 是什么,然后是 data,data 会通过 url 的 hp 请求传递给后台的页面,后台处理的 url 必须是一个 Controller,Controller 能得到 data 的内容;然后是 header,Header组装成了 hp requset的 header,它的内容是一个 json 对象,调用完以后会返回,返回的数据是 res。wx.request({ url: 'test.php’, data:{ },header:{'content-type':'application/json },需要看它是否成功,如果成功,执行下面函数,success:function(res){//收到https服务成功后返回 console.loglres.data)},如果失败执行下面逻辑,fail:function(){//发生网络错误等情况触发},不管成功还是失败,最后都要执行complete,要么执行 success complete,要么执行 fail complete,无论调用成功失败都会执行complete,这是后台发起网络连接的过程。complete: function(){//成功或者失败后触发3、API调用四、事件1、UI界面的程序与用户的互动用户在渲染层的行为反馈”以及“组件的部分状态反馈”抽象为渲染层传递给逻辑层的“事件”前端在 view 上用户会产生一个事件,用户触发事件,触发的事件会发送给 Js,Js 根据事件里定义的回调函数进行处理,产生的结果再发回来就刷新状态。2、在view上可以点击,点击的时候会产生一个事件,会调用叫 tapName的事件,tapName 事件在 js 文件里面写着函数,执行一些逻辑。有一个 data-* 的属性, 在调用后面的事件的时候可以当做参数传递过来,可以拿到。<!—page.wxml --><view id="tapTest" data-hi="WeChat" bindtap="tapName"> Click me! </view>// page.jsPage({tapName:function(event){console.log(event)}3、常见的事件类型和web上有很大差异,大量的针对手指来的,因为是用手指再进行操作。 4、事件对象属性事件触发之后,每一个事件都会有属性,包括它是什么事件,什么时候发生的,在点谁?比如说一个按钮,点击它,触发了一个事件,这个按钮就是 target,按完之后会影响到 curretTarget,比如说一点击就翻页到了下一view,下一个view就叫currentTarget。5、事件对象示例<!-- page,wxml --><view id="outer" catchtap="handleTap"><view id="inner">点击我</view></view>// page.js Page({handleTap:function(evt){//当点击inner节点时// evt.target 是inner view组件// evt.currentTarget是绑定了handleTap的outerview组件// evt.type ==“tap"// evt.timeStamp== 1542// evt.detail == {x: 270, y:63}// evt.touches == [{identifier: 0,pageX: 270,pageY: 63, clientX: 270, clientY: 63}]// evt.changedTouches == [{identifier: 0, pageX: 270, pageY: 63, clientX: 270, clientY; 63}]在 view里面,通过bindtap或 catchtap 进行操作,刚才是 bindtap,这里怎么变成了catchtap,catchtap 捕获清点动作,它们的区别涉及到冒泡原则。在这个例子里面比较简单,view没有捕捉到事件,事件就抛出到外面,到外面之后 outer 捕捉到它,调用 handleTap 方法处理事件,handleTap 方法里可以写相应的事情,拿到 evt 会把事件暴露进来,事件的 target 是 inner view 组件,点击之后没有处理,抛出来给我,我是真正处理事件的,outer 是真正处理事件的对象,就是所谓的currentTarget,是真正在处理事件的 view,这是在解释 target 和currentTarget 的区别,一个是事件确实在这发生的,一个是真正在处理事件。事件的类型是 tap,1542代表时间充是什么,{x:270,y:63}在哪个位置上点的,identifier: 0 是绝对位置,触摸点的信息包含了相对页面里的控件在什么位置上等等,具体的需要做一些实验才能看出来差异。touches 和 changedTouches 对应刚才说的一个是点,一个是拉动,会有一些变化,这是通过事件本身,通过它们的属性能得到的事件的信息。6、target 和currentTarget事件对象属性一个是产生事件的,一个是真正在处理事件的,在它们上面有一些属性,组件的类型、id、以 data-开头的数据集。data-hi 是可以传递到 tapName 函数里面进行处理,可以在属性上通过 dataset 拿到刚才通过 data-hi 传递的内容。7、touches 和 changedTouches对象属性“pageX,pageY” 和 “clientX,clientY” 可以理解为一个是整个屏幕,一个是小程序里眼睛看到的区域的坐标轴。8、事件绑定与冒泡捕获- 事件绑定的写法和组件属性一致,以key="value"的形式,其中:·key以bind或者catch开头,然后跟上事件的类型。·value是一个字符串,需要在对应的页面Page构造器中定义同名的函数。catch 和 bind 的区别:点了 inner 就没处理了,事件就传递出去到了外面的 outer 处理,就像一个事件在水底产生气泡往上冒,一直冒到上面某一个能捕捉到进行处理。一个是 bind 开头,一个是 catch 开头,也可以写一个 bindtap 处理,处理完之后这个事件不是到此结束,还是要给 outer 处理一下,inner 处理一下同时抛给 outer,outer 再处理一遍,如果是希望这种情况用 bind,后面跟事件类型;如果认为到 outer 就结束,就用 catch。如果外面还有一层叫 view id=“mostouter”,假设这里面会定义 bindtap,但是如果这个事件是从 inner 发出来的,inner 自己不处理交给了 outer,outer 处理完之后就结束了,不会再抛给 mostoutre。但是如果 outer 那里写的是 bindtap,也就是说它自己处理完之后会继续上抛,抛给上面的 mostouter,bindtap 再去处理。catch会截断冒泡的过程,bind 可以理解为像一个拦截器一样不管,于是事件就可以冒泡冒出去,catch就相当于彻底截断,不用在往上冒了。capture-bind* 表示捕获到信号表示的时间,bing* 把事件往上抛继续冒泡。9、下面写了一个稍微复杂点的例子,点击inner view会先后调用handleTap2 、handleTap4 、handleTap3、handleTap1。<viewid="outer"bind:touchstart="handleTap1"capture-bind:touchstart="handleTap2">outer view<viewid="inner"bind:touchstart="handleTap3"capture-bind:touchstart="handleTap4">inner view</view></view>outer 定义了一个 bind 和 capture-bind,刚按下去开始滑动事件。outer 里面内嵌了一个 inner,inner 也定义了 bind 和 capture-bind。如果真的在 inner view 点击一下,做 touchstart 的动作,后面定义的函数是怎样调用的?首先,这个事件会被 inner 捕获,捕获住是要往上抛的,用的是 bind,往上抛冒泡上去,冒泡上去之后到了上面一层,上面这一层按道理要在往上冒泡,但是没有了就到这,到这就捕获住了,捕获之后执行 handleTap2。捕获只是捕获到了,但是还没开始处理,紧跟着捕获住 handleTap4,捕获住之后开始处理,handleTap 3先处理,然后事件在告诉 handleTap 1,再去处理。 会一直冒泡到最外面,然后从外面开始一个一个捕获,然后都开始处理,这样一个顺序在进行执行,这就是所谓的事件的冒泡。一个事件为什么要冒泡呢?有可能在某个小程序里,某个地方划了一下,不光滑的地方要动,整个外围的都需要动一下。比如说一个地方要使劲划一下,划的目的是把整个页翻过去,而不是翻一小块内容,所以要给上面都要有一个机会进行处理,判断刚才滑动距离的长短,决定是要翻整个页,还是里面一部分内容,这就是冒泡事件的处理规则以及它的应用场景。10、事件绑定与冒泡-bind事件绑定不会阻止冒泡事件向上冒泡 -catch事件绑定可以阻止冒泡事件向上冒泡-如果将上面代码中的第一个capture- bind改为capture-catch,将只触发handleTap2(capture-catch将中断捕获阶段和取消冒泡阶段)。在下面可以看到,如果把上面划线地方改成 catch,handleTap4 就不会继续往上冒泡,到 handleTap2 就终止,取消冒泡阶段直接进入处理阶段。可以想一下 handleTap4 动作是否还能举行,因为 capture-catch:touchstart=“handleTap2” 表示不在继续冒泡,如果还有一层就更不会抛出去了。 五、兼容1、通 wx.getSystemInfoSync 获取宿主环境信息wx.getSystemInfgSync()/*{brand:"iPhone", // 手机品牌 model: "iPhone 6", // 手机型号 platform: "ios", //客户端平台 system:"i0s 9.3.4, // 操作系统版本version:"6.5.23", // 微信版本号 SDKVersion:“1.7.0", // 小程序基础库版本language:"zh_CN", //微信设置的语言 pixelRatio:2, // 设备像素比 screenWidth:667, // 屏幕宽度 screenHeight;375, // 屏幕高度 windowWidth:667, // 可使用窗口宽度 windowHeight;375, // 可使用窗口高度 fontSizeSetting:16 // 用户字体大小设置 }*/通过 wx.getSystemInfoSync 接口调别的属性可以看到手机的品牌、具体的型号、操作系统等等。2、小程序能否在所有手机上跑,跟 JS Browser 能否在所有浏览器里跑是一个道理,要去做一些判断,所以可以用 canIUse 这样的方式,它会返回一些值告诉我们是否能用。也就是说在开发一个微信程序的时候,第一不能假设用户的版本号(version),第二不能知道他的手机是什么,所以需要做一些访问性编程,如果用的是微信最新版本里面提供的功能,在编程的时候需要先看一看用户手机支不支持这个动作,如果不支持是不能用的,所以代码里必须要写,不能假设所有用户都升级到最新版本。 六、wx.request 接口1、如果我们需要从https://test.com/getinfo接口拉取用户信息,其代码示例如下所示:wx. request({url:'https://test.com/getinfo',success: function(res) {console.log(res)// 服务器回包信息重点是 request 接口,这个接口就是要去和后台访问,重要的是有一个 url,如果成功就调用 function(res)函数,这是一个回调函数。 2、wx.request 详细参数复杂一点的它的参数包括 url、请求要传递过去的参数、请求头、用什么方法去写,必须要大写。然后是 dataType,默认值是 json,不管成功还是失败都要用 complete。 3、请求参数(1)通过 wx.request 这个API,有两种方法把数据传递到服务器:通过url上的参数以及通过data参数。//通过url参数传递数据 wx.request({url:'https://test.com/getinfo?id=1&version=1.0.0’, success: function(res){console.log(res)//服务器回包信息}})//通过data参数传递数据 wx.request({url:'https://test.com/getinfo', data:{id:1,version:'1.0.0'}, success: function(res){console.log(res)//服务器回包信息}})要访问 data:{id:1,version:'1.0.0'} 页面,同时要给它传递的参数是 id:1,version:'1.0.0',传递的数据在这里面默认 json 的数据传过去,一旦返回成功,就调 console.log(res) 函数做相应的事情,这就是这个接口的内容。(2)-wx.request发起 POST 请求包体使用 json 格式//请求的包体为 {"a":{"b":[1,2,3],"c":{"d":"test"}}} wx.request({url:'https://test.com/postdata’, method: 'POST,header: {'content-type': 'application/json'}, data: { a:{b: [1, 2,3], c: { d: "test" }},success: function(res) {console.log(res)//服务器回包信息}method 设成 POST,POST 一定是带参数的,所以在 data 里面一定有内容,a里面是一个键值对的数组,就是一个 json 对象;b这个键对应“1,2,3”,c对应的又是一个键值对,这样的东西会封装起来,以 json 的方式传递到 https://test.com/postdata。所以前后台的信息,尤其是前两个要对起来。如果返了一个 json 出去,拿到res 之后,剩下的信息在 console.log(res) 里写,而这个代码就是 js 代码,跟之前在 react 里面解析,或者用原生的 js 解析 json 对象是一样的,这时候跟微信本身的语法就没关系了。 4、收到回包-wxrequest 的 success 返回参数success 会返回一个数据,这个数据就是封装到 result 里面的内容,有数据、状态码、header,就是 Response-Header。 七、设置超时时间app.json 指定 wx.requset 超时时间为3000毫秒"networkTimeout":{"request": 3000在访问的时候跟后台交互,可能会经历很长时间,可以在小程序的全局设置文件里设所有的请求在返回结果的时候不会等待超过三秒,这就是在微信里看到的,一点的时候速度很慢,过了一会网络不通或者超时等等。会出现这个就是因为设了时间,当超过这个时间点,还没有返回,不能让小程序死循环一直等,加上 Timeout 表示暂时无法访问,请稍候再试,这样至少给用户一个机会返回做别的操作,否则小程序就死机了。 八、请求前后的状态处理1、var hasClick= false; Page({tap: function(){ if(hasClick){ return}hasClick = true wx.showLoading() wx.request({url: 'https://test.com/getinfo', method: 'POST,header: {'content-type':'application/json'}, data: { },success: function(res){if(res.statusCode===200){console.log(res.data)//服务器回包内容}},fail: function (res){wx.showToast({title:'系统错误' })},complete:function(res){ wx.hideLoading()hasClick=false}这是一个比较复杂的请求,这个请求对 getinfo 页面发一个 POST 请求,失败之后调用微信的 showToast,显示系统错误,相当于弹窗显示。无论怎样,把当前页面隐掉,只要把成功或失败页面执行完,把里面的一些参数设置一下,这就是执行 tap 的时候的动作,一点就发了一个请求到后台,然后后台进行操作。九、推荐学习资料微信小程序开发文档:https://developers.weixin.qq.com/miniprogram/dev/framework/微信小程序开发者社区:https://developers.weixin.qq.com/讲的这些基本上涵盖了小程序开发的主要内容,更复杂的需要看看小程序的官方文档,大体上主要内容都介绍完了。 十、总结1、总结一下,它跟写一个前端 react 或 real 框架没什么本质区别,一样要有路由,路由就是在 app.json 里写的,会写出所有的页面的位置,然后每一个页面原来都是在 .js 里面写,现在要有四个,要有.js、.wxml、.wxss,还要有 .json 的配置,把它拆分为四个,然后在一个页面里 component 也没什么区别。然后需要用 SetData 改变状态,重新渲染,而且 SetData 是一个异步通信的方式(Async)。和以前框架一样的东西就是在这个里面还要考虑页面这四个在一个目录里,路由在这个里面只是所有的页面,他们的位置在哪里,真正的路由是用 navigateTo 或者是navigateBack 这样的东西进行操作,也就是说路由在操作页面栈,这是和前端 react 和 real 框架有点区别的地方。最大的区别是整套的事件系统,因为在手机上全部都是触屏,它的事件 click 没有了,把 click 点击动作拆分的很细,有单点一下,有点住它划动,有长时间长按等等,这是差异比较大的地方,其它的跟之前的概念没有什么本质区别,所以只要 react 写出来,有这个感受之后,在看微信的小程序没什么本质区别,而且这里面没有任何新意。wxml 标签不一样,语法接近于 xml,css 和 wxss 也很像,json 之前讲过,也没有什么新的语法需要去学,只是转换一下思想,考虑小程序的结构,去开发一个一个页面。2、把后台跑的之前的例子跑起来,没有发生然后变化。前端跑微信小程序的例子看一下,这个小程序的例子里面分了几个页面,开始是 index,在 app.json 里面,有三个主要的页面。"pages/index/index""pages/books/books","pages/addCartPage/book"第一个就是首页,访问 index。index用到了 部件,所以在 index.json 配置里会用到下面的控件。"usingComponents":{"van-field": “@vant/weapp/field","van-button":"@vant/weapp/button"在 index.wxml 页面里主要有一个用户名,当什么都不输入的时候,有一个占位符。底下是密码,也是 van-field,这里面有一个 password=ture,输入的是圆点,看不到本身的内容,显示的请输入密码,还有一个错误信息(errorMessage)。<van-field bindblur="bindNameInput” label="用户名" placcholder="谓输入用户名"/><van-field bindblur:"bindPasswordInput" passworda"true" label="密码” placeholdera"调输入密码" error-messagea="{{erroriessage}}" borderm true />错误信息在 json 文件里,这个 json 文件里会定义错误信息,是用户名密码错误。Index.wxml 页面就两个输入框,下面有个按钮,这个按钮比较长,可以定义它的尺寸,如果点击或绑定 bindViewTap 方法,这个方法往后发一个请求出去,这已经跨域了,后面允许跨域,发到8080的 login。</van-cell-group></view><view style:"width:15rem; height:6rem; margin: 5rem o " ><van-button bindtape="bindViewTap" type="primary" block>登录</van-button></view></view>3下面是之前的后台,反复用这一个后台。监听 login,所以就会发出去这样一个请求,发出这个请求用的是 POST 方式,需要把用户名、密码发出去。用户名和密码是怎样发出去的?回到 index.wxml 页面,当光标离开 bindNameInput 的时候调用它,在用户名输入的时候获取了焦点,一离开 bindblur,会调用 bindNameInput。input 把事件跟给我们,detail 就是在返回这个事件是哪个对象产生的,那个对象的值改写到 userName 里去,不能直接写 =event.detail.value,userName 要通过 SetData 设计,这样页面就会刷新;同样的道理 password input 也是,所以在这里面进行操作的时候,一旦离开焦点,点击光标就不在焦点,他俩的值就有了,有了之后点击登录。Success表示成功,判断返回的状态是什么?如果返回状态不是零就表示后台的信息出错,把 errorMessage 写成用户名密码错误。当 errorMessage 出错的时候显示。用户名密码输对之后,进入到首页,这和之前看到的前台一样,假如把 web 的前端打开,这两个前端显示的内容是一样的,除了广告语其它的内容都是从后台抓过来,广告语是在前台写的,其他它内容全是从后台抓的。用了一个后台,前端可以有多个,但是访问的方式都一样,通过页面来的,现在首页是怎样访问的就可以看到了。对着 POST 操作,把用户名和密码输进去,用户名和密码输进去光标离开后会绑定,通过下面两个方式绑定到用户名和密码里面去。//用户名输入bindNameInput: function(event){this.setdata({userName : event.detail.value})},//密码输入bindPasswordInput (property) password?: string this.setdatal{ password: event.detail.value })II一旦访问成功,response 判断里面的状态是零,就表示正常返回,页面就要跳转,除了跳转,还要在后端认证过之后,返给信息存到微信小程序的本地存储里面,后端要把 cookie 存一下。因为 cookie 里面有 sessionid,因为登录信息、购物车等都在sessionid 里 ,拿到 sessionid 后存到微信客户端本地,紧接着就是跳转,跳到 books 目录里的 books 上,跳到下面页面上。"pages/index/index""pages/books/books","pages/addCartPage/book"第一个就是首页,访问 index。index用到了 部件,所以在 index.json 配置里会用到下面的控件。"usingComponents":{"van-field": “@vant/weapp/field","van-button":"@vant/weapp/button"在 index.wxml 页面里主要有一个用户名,当什么都不输入的时候,有一个占位符。底下是密码,也是 van-field,这里面有一个 password=ture,输入的是圆点,看不到本身的内容,显示的请输入密码,还有一个错误信息(errorMessage)。错误信息在 json 文件里,这个 json 文件里会定义错误信息,是用户名密码错误。Index.wxml 页面就两个输入框,下面有个按钮,这个按钮比较长,可以定义它的尺寸,如果点击或绑定 bindViewTap 方法,这个方法往后发一个请求出去,这已经跨域了,后面允许跨域,发到8080的 login。登录3下面是之前的后台,反复用这一个后台。监听 login,所以就会发出去这样一个请求,发出这个请求用的是 POST 方式,需要把用户名、密码发出去。用户名和密码是怎样发出去的?回到 index.wxml 页面,当光标离开 bindNameInput 的时候调用它,在用户名输入的时候获取了焦点,一离开 bindblur,会调用 bindNameInput。input 把事件跟给我们,detail 就是在返回这个事件是哪个对象产生的,那个对象的值改写到 userName 里去,不能直写 =event.detail.value,userName 要通过 SetData 设计,这样页面就会刷新;同样的道理 password input 也是,所以在这里面进行操作的时候,一旦离开焦点,点击光标就不在焦点,他俩的值就有了,有了之后点击登录。Success表示成功,判断返回的状态是什么?如果返回状态不是零就表示后台的信息出错,把 errorMessage 写成用户名密码错误。当 errorMessage 出错的时候显示。用户名密码输对之后,进入到首页,这和之前看到的前台一样,假如把 web 的前端打开,这两个前端显示的内容是一样的,除了广告语其它的内容都是从后台抓过来,广告语是在前台写的,其他它内容全是从后台抓的。用了一个后台,前端可以有多个,但是访问的方式都一样,通过页面来的,现在首页是怎样访问的就可以看到了。对着 POST 操作,把用户名和密码输进去,用户名和密码输进去光标离开后会绑定,通过下面两个方式绑定到用户名和密码里面去。//用户名输入bindNameInput: function(event){this.setdata({userName : event.detail.value})},//密码输入bindPasswordInput (property) password?: string this.setdatal{ password: event.detail.value })II一旦访问成功,response 判断里面的状态是零,就表示正常返回,页面就要跳转,除了跳转,还要在后端认证过之后,返给信息存到微信小程序的本地存储里面,后端要把 cookie 存一下。因为 cookie 里面有 sessionid,因为登录信息、购物车等都在sessionid 里 ,拿到 sessionid 后存到微信客户端本地,紧接着就是跳转,跳到 books 目录里的 books 上,跳到下面页面上。这里面的内容靠刚才的内容得到,最简单的这里面有 wx.for,就是把全部的数据显示出来。这个例子开发完在跑的时候出了一个问题,这个工程在加载的时候,还有一种可能跑不起来,在项目设置的本地设置里面,看测试基础库,要选择正确,这里用的是稍微低一点的版本,是2.10.7,它可能有2.11,在 2.11.0里面跑这个例子可能会出错,如果出错需要改版本,默认按最新的加载。拿到例子之后要在配置信息里面,就是 project config.json 里面,把 appid 改成自己申请的 appid。给的例子前端都一样,后端就一个,开发出来就是这样一个套路。下节课会把这个例子详细讲解,接下去讲手机端的APP,手机端的APP在开发的时候需要装 win7,先把安卓 studio 装一下,如果是苹果,还有一个 x code,要能够在idea里面把两个模拟机启动起来。这里面的内容靠刚才的内容得到,最简单的这里面有 wx.for,就是把全部的数据显示出来。这个例子开发完在跑的时候出了一个问题,这个工程在加载的时候,还有一种可能跑不起来,在项目设置的本地设置里面,看测试基础库,要选择正确,这里用的是稍微低一点的版本,是2.10.7,它可能有2.11,在 2.11.0里面跑这个例子可能会出错,如果出错需要改版本,默认按最新的加载。拿到例子之后要在配置信息里面,就是 project config.json 里面,把 appid 改成自己申请的 appid。给的例子前端都一样,后端就一个,开发出来就是这样一个套路。下节课会把这个例子详细讲解,接下去讲手机端的APP,手机端的APP在开发的时候需要装 win7,先把安卓 studio 装一下,如果是苹果,还有一个 x code,要能够在idea里面把两个模拟机启动起来。