前端技术
HTML
CSS
Javascript
前端框架和UI库
VUE
ReactJS
AngularJS
JQuery
NodeJS
JSON
Element-UI
Bootstrap
Material UI
服务端和客户端
Java
Python
PHP
Golang
Scala
Kotlin
Groovy
Ruby
Lua
.net
c#
c++
后端WEB和工程框架
SpringBoot
SpringCloud
Struts2
MyBatis
Hibernate
Tornado
Beego
Go-Spring
Go Gin
Go Iris
Dubbo
HessianRPC
Maven
Gradle
数据库
MySQL
Oracle
Mongo
中间件与web容器
Redis
MemCache
Etcd
Cassandra
Kafka
RabbitMQ
RocketMQ
ActiveMQ
Nacos
Consul
Tomcat
Nginx
Netty
大数据技术
Hive
Impala
ClickHouse
DorisDB
Greenplum
PostgreSQL
HBase
Kylin
Hadoop
Apache Pig
ZooKeeper
SeaTunnel
Sqoop
Datax
Flink
Spark
Mahout
数据搜索与日志
ElasticSearch
Apache Lucene
Apache Solr
Kibana
Logstash
数据可视化与OLAP
Apache Atlas
Superset
Saiku
Tesseract
系统与容器
Linux
Shell
Docker
Kubernetes
[Vector容器末尾高效插入元素技巧]的搜索结果
这里是文章列表。热门标签的颜色随机变换,标签颜色没有特殊含义。
点击某个标签可搜索标签相关的文章。
点击某个标签可搜索标签相关的文章。
Saiku
...》详尽介绍了如何借助容器化技术,使Saiku在云端环境下的部署更为灵活高效,同时确保服务稳定性和资源利用率的最大化。 此外,对于Saiku背后的Mondrian OLAP引擎,也有专家撰写了关于其在多维数据分析性能提升方面的研究论文,通过引经据典,从理论层面解析Mondrian的查询优化算法,以及未来可能影响Saiku性能表现的技术趋势。此类专业解读不仅能够帮助用户进一步挖掘Saiku潜力,也为开发者提供了改进与创新的方向。 总之,紧跟大数据分析行业的前沿动态,深入了解相关工具和技术的发展历程与最新实践,将有助于您更好地运用Saiku进行数据探索与决策支持,从而在数字化转型的大潮中抢占先机,创造更多价值。
2023-08-17 15:07:18
166
百转千回
MySQL
...dera公司推出了在容器化环境下优化的Sqoop 2.0版本,支持Kubernetes等云平台部署,增强了其在混合云和多云场景下的数据迁移能力。 与此同时,对于大规模数据导入导出性能优化的研究也在不断深入。有研究人员探讨了如何结合Spark或Flink等现代大数据处理框架与Sqoop进行协同工作,以提升数据迁移效率并确保数据一致性。此外,业界也在探索通过引入并发控制策略、改进分区算法等方式来进一步优化Sqoop的工作负载管理。 值得注意的是,虽然Sqoop在关系型数据库与Hadoop之间架起了一座桥梁,但在数据迁移过程中,安全性与合规性问题同样不容忽视。因此,关于Sqoop的数据加密传输、权限管理和审计日志等相关功能的使用与配置教程,成为了许多企业和组织关注的焦点。 总之,在大数据时代背景下,Apache Sqoop的重要性不言而喻,而随着技术进步和行业需求的变化,Sqoop将继续发展和完善,为企业在复杂IT架构下实现高效、安全的数据流动提供有力支持。
2023-04-12 16:50:07
247
素颜如水_t
Saiku
... - 布局混乱:界面元素分布缺乏逻辑性,导致用户在寻找特定功能时费时费力。 - 信息密度高:大量的配置选项集中在一个页面上,容易造成视觉疲劳,降低操作效率。 二、案例分析 以“时间序列分析”为例 假设我们正在为一家零售公司构建一个销售趋势分析仪表板,需要配置时间序列数据进行展示。在Saiku配置文件编辑器中,用户可能首先会面临以下挑战: 1. 选择维度与度量 - 用户可能不清楚如何在众多维度(如产品类别、地区、时间)和度量(如销售额、数量)中做出最佳选择来反映他们的分析需求。 - 缺乏直观的提示或预览功能,使得用户难以预见到不同选择的最终效果。 2. 配置时间序列 - 在配置时间序列时,用户可能会遇到如何正确设置时间粒度(如日、周、月)以及如何处理缺失数据的问题。 - 缺乏可视化的指导,使得用户在调整时间序列设置时感到迷茫。 三、改进建议 增强直观性和用户友好性 针对上述挑战,我们可以从以下几个方面着手改进Saiku配置文件编辑器: 1. 简化术语 引入更易于理解的语言替换专业术语,例如将“维度”改为“视角”,“度量”改为“指标”。 2. 优化布局与导航 采用更加清晰的分层结构,将相关功能模块放置在一起,减少跳转次数。同时,增加搜索功能,让用户能够快速定位到需要的配置项。 3. 提供可视化预览 在用户进行配置时,实时展示配置结果的预览图,帮助用户直观地理解设置的效果。 4. 引入动态示例 在配置页面中嵌入动态示例,通过实际数据展示不同的配置效果,让用户在操作过程中学习和适应。 5. 增加教程与资源 开发一系列针对不同技能水平用户的教程视频、指南和在线问答社区,帮助用户更快掌握Saiku的使用技巧。 四、结语 从实践到反馈的闭环 改进Saiku配置文件编辑器的直观性是一个持续的过程,需要结合用户反馈不断迭代优化。哎呀,听我说啊,要是咱们按照这些建议去操作,嘿,那可是能大大提升大家用咱们Saiku的体验感!这样一来,不光能让更多的人知道并爱上Saiku,还能让数据分析这块儿的整体发展更上一层楼呢!你懂我的意思吧?就像是给整个行业都添了把火,让数据这事儿变得更热乎,更受欢迎!哎呀,兄弟!在咱们这项目推进的过程中,得保持跟用户之间的交流超级通畅,听听他们在使用咱们产品时遇到的具体难题,还有他们的一些建议。这样咱们才能对症下药,确保咱们改进的措施不是空洞的理论,而是真正能解决实际问题,让大家都满意的好办法。毕竟,用户的反馈可是我们优化产品的大金矿呢! --- 通过这次深入探讨,我们不仅认识到Saiku配置文件编辑器在直观性上的挑战,也找到了相应的解决路径。哎呀,希望Saiku在将来能给咱们的数据分析师们打造一个既温馨又高效的工具平台,就像家里那台超级好用的咖啡机,让人一上手就爱不释手。这样一来,大家就能专心挖出数据背后隐藏的金矿,而不是老是跟那些烦人的技术小难题过不去,对吧?
2024-10-12 16:22:48
73
春暖花开
Shell
...开始采用微服务架构和容器化技术来提升系统的灵活性,例如使用Kubernetes动态调整资源池,以满足不同时间段的需求波动。此外,AI驱动的自动化运维工具也被越来越多地应用于资源管理中,通过实时监控和预测分析,提前识别潜在风险并采取预防措施。 从长远来看,加强基础设施建设与技术创新同样不可或缺。例如,引入更高效的存储方案,如分布式文件系统或对象存储,可以有效缓解传统存储方式面临的性能瓶颈。同时,制定严格的权限管理和访问控制策略,避免非必要权限滥用,也是防止类似事件再次发生的重要手段。 总之,在信息技术飞速发展的今天,无论是个人还是企业,都需要不断提升自身的IT能力,以适应复杂多变的环境。希望这次事件能引起更多人对资源分配问题的关注,共同推动行业的健康发展。
2025-05-10 15:50:56
93
翡翠梦境
转载文章
...在线服务的影响。随着容器化和Kubernetes等云原生技术的发展,如何在分布式环境下高效运用mysqldump进行数据迁移与灾备也成为IT专业人士关注的新课题。 综上所述,掌握mysqldump的基本操作仅仅是开始,不断跟进最新的数据库管理技术和最佳实践,深入理解和灵活应用不同备份恢复策略,才能确保在复杂多变的业务场景中,有效保障数据的安全性和系统的稳定性。
2023-02-01 23:51:06
265
转载
Kylin
...数据驱动的时代,如何高效地处理和分析海量数据是企业面临的关键挑战之一。哎呀,你听说过Kylin这个家伙没?这家伙在Apache开源项目里可是个大明星!它凭借着超棒的性能和超灵活的特性,在大数据分析这块地盘上可是独领风骚呢!就像是在数据这片海洋里,Kylin就是那条游得最快、最灵活的大鱼,让人不得不佩服它的实力和魅力!哎呀,你知道的,当Kylin碰上了MySQL这种关系型数据库,俩人之间的联接优化问题可真是个大课题啊!这事儿得好好琢磨琢磨,不然数据跑起来可就慢了不止一点点。你得想想怎么能让它们配合得天衣无缝,让数据查询快如闪电,用户体验棒棒哒!这背后涉及到的技术细节可多了去了,比如索引优化、查询语句的编写技巧,还有就是数据库配置的调整,每一步都得精心设计,才能让整个系统运行得既高效又稳定。所以,这不仅仅是个理论问题,更是一场实战演练,考验的是咱们对数据库知识的掌握和运用能力呢!本文将带你一起揭开这个谜题的面纱,从理论到实践,全方位解析Kylin与MySQL联接优化的关键点。 二、理论基础 理解Kylin与MySQL的联接机制 在深入讨论优化策略之前,我们首先需要理解两者之间的基本联接机制。Kylin是一个基于Hadoop的列式存储OLAP引擎,它通过预先计算并存储聚合数据来加速查询速度。而MySQL作为一个广泛使用的SQL数据库管理系统,提供了丰富的查询语言和存储能力。嘿,兄弟!你听过数据联接这事儿吗?它通常在咱们把数据从一个地方搬进另一个地方或者在查询数据的时候出现。就像拼图一样,对了,就是那种需要精准匹配才能完美组合起来的拼图。用对了联接策略,那操作效率简直能嗖的一下上去,比火箭还快呢!所以啊,小伙伴们,别小瞧了这个小小的联接步骤,它可是咱们大数据处理里的秘密武器! 三、策略一 优化联接条件 实践示例: sql -- 原始查询语句 SELECT FROM kylin_table JOIN mysql_table ON kylin_table.id = mysql_table.id; -- 优化后的查询语句 SELECT FROM kylin_table JOIN mysql_table ON kylin_table.id = mysql_table.id AND kylin_table.date >= '2023-01-01' AND kylin_table.date <= '2023-12-31'; 通过在联接条件中加入过滤条件(如时间范围),可以减少MySQL服务器需要处理的数据量,从而提高联接效率。 四、策略二 利用索引优化 实践示例: 在MySQL表上为联接字段创建索引,可以大大加速查询速度。同时,在Kylin中,确保相关维度的列已经进行了适当的索引,可以进一步提升性能。 sql -- MySQL创建索引 CREATE INDEX idx_kylin_table_id ON kylin_table(id); -- Kylin配置维度索引 id long true 通过这样的配置,不仅MySQL的查询速度得到提升,Kylin的聚合计算也更加高效。 五、策略三 批量导入与增量更新 实践示例: 对于大型数据集,考虑使用批量导入策略,而不是频繁的增量更新。哎呀,你瞧,咱们用批量导入这招,就像是给MySQL服务器做了一次减压操,让它不那么忙碌,喘口气。同时,借助Kylin的离线大法,我们就能让那些实时查询快如闪电,不拖泥带水。这样一来,不管是数据处理还是查询速度,都大大提升了,用户满意度也蹭蹭往上涨呢! bash 批量导入脚本示例 $ hadoop fs -put data.csv /input/ $ bin/hive -e "LOAD DATA INPATH '/input/data.csv' INTO TABLE kylin_table;" 六、策略四 优化联接模式 选择合适的联接模式(如内联接、外联接等)对于性能优化至关重要。哎呀,你得知道,在咱们实际干活的时候,选对了数据联接的方式,就像找到了开锁的金钥匙,能省下不少力气,避免那些没必要的数据大扫荡。比如说,你要是搞个报表啥的,用对了联接方法,数据就乖乖听话,找起来快又准,省得咱们一个个文件翻,一个个字段找,那得多费劲啊!所以,挑对工具,效率就是王道! 实践示例: 假设我们需要查询所有在特定时间段内的订单信息,并且关联了用户的基本信息。这里,我们可以使用内联接: sql SELECT FROM orders o INNER JOIN users u ON o.user_id = u.user_id WHERE o.order_date BETWEEN '2023-01-01' AND '2023-12-31'; 七、总结与展望 通过上述策略的实施,我们能够显著提升Kylin与MySQL联接操作的性能。哎呀,你知道优化数据库操作这事儿,可真是个门道多得很!比如说,调整联接条件啊,用上索引来提速啊,批量导入数据也是一大妙招,还有就是选对联接方式,这些小技巧都能让咱们的操作变得顺畅无比,响应速度嗖嗖的快起来。就像开车走高速,不堵车不绕弯,直奔目的地,那感觉,爽歪歪!哎呀,随着咱手里的数据越来越多,就像超市里的货物堆积如山,技术这玩意儿也跟咱们的手机更新换代一样快。所以啊,要想让咱们的系统运行得又快又好,就得不断调整和改进策略。就像是给汽车定期加油、保养,让它跑得既省油又稳定。这事儿,可得用心琢磨,不能偷懒!未来,随着更多高级特性如分布式计算、机器学习集成等的引入,Kylin与MySQL的联接优化将拥有更广阔的应用空间,助力数据分析迈向更高层次。
2024-09-20 16:04:27
104
百转千回
Spark
...ug的过程变得快捷又高效,简直就像开了挂一样爽快!哎呀,咱们这篇文章啊,就是要好好聊聊在Spark这个超级棒的大数据处理工具里,咱们可能会遇到的各种小麻烦,还有呢,怎么用那些日志记录来帮咱们找到问题的根儿。你想象一下,就像你在厨房里做饭,突然发现菜炒糊了,这时候你就会看看锅底,找找是火开太大了还是调料放多了,对吧?这文章呢,就是想教你用同样的方法,在大数据的世界里,通过查看日志,找出你的Spark程序哪里出了问题,然后迅速解决它,让一切恢复正常。是不是听起来既实用又有趣?咱们这就开始吧! 二、Spark错误类型概述 Spark应用程序可能遭遇多种错误类型,从内存溢出、任务失败到网络通信异常等。这些错误通常由日志系统捕获并记录下来,为后续分析提供依据。下面,我们将通过几个具体的错误示例来了解如何阅读和解析Spark日志文件。 三、实例代码 简单的Spark Word Count应用 首先,让我们构建一个简单的Spark Word Count应用作为起点。这个应用旨在统计文本文件中单词的频率。 scala import org.apache.spark.SparkConf import org.apache.spark.SparkContext object WordCount { def main(args: Array[String]) { val conf = new SparkConf().setAppName("Word Count").setMaster("local") val sc = new SparkContext(conf) val textFile = sc.textFile("file:///path/to/your/textfile.txt") val counts = textFile.flatMap(line => line.split(" ")) .map(word => (word, 1)) .reduceByKey(_ + _) counts.saveAsTextFile("output") sc.stop() } } 四、错误日志分析 内存溢出问题 在实际运行上述应用时,如果输入文本文件过大,可能会导致内存溢出错误。日志文件中可能会出现类似以下的信息: org.apache.spark.SparkException: Job aborted due to stage failure: Task 0 in stage 37.0 failed 1 times, most recent failure: Lost task 0.3 in stage 37.0 (TID 208, localhost): java.lang.OutOfMemoryError: Java heap space 这段日志信息清晰地指出错误原因(OutOfMemoryError: Java heap space),并提供了关键细节,包括任务编号、所在节点以及错误类型。针对这一问题,可以通过增加Spark集群的内存资源或者优化数据处理逻辑来解决。 五、调试策略与最佳实践 1. 使用日志级别 调整日志级别(如INFO、DEBUG)可以帮助开发者在日志中获取更多详细信息。 2. 定期检查日志 通过自动化工具定期检查日志文件,可以及时发现潜在问题。 3. 利用Spark UI Spark自带的Web UI提供了详细的作业监控界面,直观显示任务状态和性能指标。 4. 错误重试机制 合理配置Spark任务的重试策略,避免因一次失败而影响整体进程。 5. 性能监控工具 集成性能监控工具(如Prometheus、Grafana)有助于实时监控系统性能,预防内存泄漏等严重问题。 六、总结与展望 日志记录是Spark应用程序开发和维护过程中的关键环节。哎呀,你知道吗?程序员们在遇到bug(小错误)的时候,那可是得使出浑身解数了!他们可不是对着电脑屏幕发呆,而是会仔细地分析问题,就像侦探破案一样。找到问题的源头后,他们就开始了他们的“调试大作战”,就像是医生给病人开药一样精准。通过这些努力,他们能优化代码,让程序跑得更顺畅,就像给汽车加了润滑剂,不仅跑得快,还稳当当的。这样,我们的应用就能更加可靠,用户用起来也更舒心啦!哎呀,你懂的,随着咱们每天产生的数据就像自来水一样哗哗流,那处理这些数据的大数据工具就得越来越厉害才行。特别是那些记录我们操作痕迹的日志管理系统,不仅要快得跟闪电一样,操作起来还得像玩手机游戏一样简单,最好还能自己动脑筋分析出点啥有价值的信息来。这样,未来日志记录这事儿就不仅仅是记录,还能帮我们找到问题、优化流程,简直就是一大神器嘛!所以,你看,这发展方向就是越来越智能、好用、高效,让科技真正服务于人,而不是让人被科技牵着鼻子走。 --- 通过本文的探讨,我们不仅学习了如何理解和利用Spark的日志信息来诊断问题,还了解了一些实用的调试技巧和最佳实践。希望这些内容能帮助你更有效地管理你的Spark应用程序,确保其在复杂的数据处理场景下稳定运行。
2024-09-07 16:03:18
141
秋水共长天一色
转载文章
在探讨了如何通过插入字符 'a' 来构造非回文字符串这一编程问题后,我们可以进一步了解字符串处理与算法优化的最新研究进展。近日,《自然》杂志子刊《自然-通讯》发表了一篇关于“在线字符串编辑与动态回文判定”的研究报告。研究者提出了一种新颖的在线算法,能够在字符串实时更新过程中高效地判断其是否为回文,并能快速找到使字符串变为非回文所需的最少编辑操作。这一成果不仅对于文本处理、数据压缩等领域具有重要价值,也对解决类似的编程挑战提供了新的思路。 此外,在ACM国际大学生程序设计竞赛(ACM-ICPC)和谷歌代码 Jam 等全球顶级编程赛事中,频繁出现与回文串相关的题目,参赛者需灵活运用算法知识来解决实际问题。比如,有题目要求选手在最短时间内编写程序,找出将一个字符串转换为非回文串的最小操作次数,这与我们讨论的文章主题不谋而合,展现了理论与实践相结合的重要性。 同时,回文串在密码学、遗传学以及文学创作等多个领域均有应用。例如,在DNA序列分析中,回文结构往往关联着基因调控的重要区域;在密码学中,特定类型的回文串可用于构建加密算法的关键部分。深入理解并熟练掌握回文串的相关性质及处理方法,无疑有助于我们在这些领域取得更多的技术突破。 总之,从基础的编程题出发,我们可以洞察到字符串处理与算法优化在前沿科研和实际应用中的深远影响。通过持续关注和学习此类问题的最新研究成果与应用案例,我们能够不断提升自身的算法设计和问题解决能力。
2023-10-05 13:54:12
228
转载
MemCache
...存对象缓存系统,以其高效性和灵活性赢得了广大开发者的青睐。哎呀,用着用着,咱们可能会碰到一些意料之外的小麻烦,比如说MutexException。这事儿可不简单,它通常说明在咱们同时操作好几个线程的时候,遇到了锁的冲突,或者是怎么也拿不到那个关键的锁。就像是在厨房里,好几个人都想同时用同一把刀切菜,结果就乱了套,谁都得等着。这可得小心点,不然程序就可能卡住不动了。这篇文章将带你深入理解MemCache的工作原理,并探讨如何解决此类问题。 2. MemCache基础概念 MemCache通过在内存中存储数据来提供快速访问。哎呀,这个家伙可真能玩转各种数据类型啊!不管是那些字母串、一长串的数字清单,还是乱七八糟的集合,它都能轻松驾驭。而且,它还提供了一套超简单的操作工具,就像给小孩子们准备的玩具一样,简单易懂,轻轻松松就能搞定这些数据,真是太贴心了!MemCache这种玩意儿啊,就像是你跟朋友玩游戏,你负责喊口号出招,朋友负责听你的指挥去打怪兽或者抢金币。这游戏里头,MemCache的服务器就是那个强大的后盾,它负责把所有东西都记下来,还有找你要的东西。所以,简单来说,你就是客户端,是操作者;MemCache服务器呢,就是那个后台,负责处理一切数据的事情。这样子,你们俩配合起来,游戏玩得又快又好! 3. MutexException问题剖析 当多个线程同时尝试访问或修改同一数据时,MutexException的出现往往是因为互斥锁管理不当。哎呀,互斥锁就像是共享空间的门神,它负责在任何时候只让一个小伙伴进入这个共享区域,比如图书馆或者厨房,这样大家就不会抢着用同一本书或者同一把锅啦。这样就能避免发生混乱和冲突,保证大家都能平平安安地享受公共资源。在MemCache中,这种冲突可能发生在读取、写入或删除数据的操作上。 4. 实战案例 MemCache使用示例 为了更好地理解MemCache的工作流程及其可能出现的问题,我们通过一个简单的示例来展示其基本用法: python from pymemcache.client import base 创建MemCache客户端连接 client = base.Client(('localhost', 11211)) 缓存一个值 client.set('key', 'value') 从缓存中获取值 print(client.get('key')) 删除缓存中的值 client.delete('key') 5. 避免MutexException的策略 解决MutexException的关键在于正确管理互斥锁。以下是一些实用的策略: a. 使用原子操作 MemCache提供了原子操作,如add、replace、increment等,可以安全地执行更新操作而无需额外的锁保护。 b. 线程安全编程 确保所有涉及到共享资源的操作都是线程安全的。这意味着避免在多线程环境中直接访问全局变量或共享资源,而是使用线程本地存储或其他线程安全的替代方案。 c. 锁优化 合理使用锁。哎呀,你懂的,有时候网站或者应用里头有些东西经常被大家看,但是实际上内容变动不多。这时候,为了不让系统在处理这些信息的时候卡壳太久,我们可以用个叫做“读锁”的小技巧。简单来说,读锁就像是图书馆里的书,大家都想翻阅,但是不打算乱动它,所以不需要特别紧锁起来,这样能提高大家看书的效率,也避免了不必要的等待。此外,考虑使用更高效的锁实现,比如使用更细粒度的锁或非阻塞算法。 d. 锁超时 在获取锁时设置超时时间,避免无限等待。哎呀,如果咱们在规定的时间内没拿到钥匙(这里的“锁”就是需要获得的权限或资源),那咱们就得想点别的办法了。比如说,咱们可以先把手头的事情放一放,退一步海阔天空嘛,回头再试试;或者干脆来个“再来一次”,看看运气是不是转了一把。别急,总有办法解决问题的! 6. 结语 MemCache的未来与挑战 随着技术的发展,MemCache面临着更多的挑战,包括更高的并发处理能力、更好的跨数据中心一致性以及对新兴数据类型的支持。然而,通过持续优化互斥锁管理策略,我们可以有效地避免MutexException等并发相关问题,让MemCache在高性能缓存系统中发挥更大的作用。嘿,小伙伴们!在咱们的编程路上,要记得跟紧时代步伐,多看看那些最棒的做法和新出炉的技术。这样,咱们就能打造出既稳固又高效的超级应用了!别忘了,技术这玩意儿,就像个不停奔跑的小兔子,咱们得时刻准备着,跟上它的节奏,不然可就要被甩在后面啦!所以,多学习,多实践,咱们的编程技能才能芝麻开花节节高!
2024-09-02 15:38:39
38
人生如戏
转载文章
...念的普及以及云计算、容器化技术的广泛应用,Nagios也在不断迭代升级以适应新的运维场景。 例如,Nagios XI作为Nagios系列的旗舰产品,不仅继承了原有的强大监控功能,更提供了直观易用的Web界面和实时仪表板,方便用户快速定位问题并作出响应。此外,它支持大规模分布式环境下的监控,并能够无缝集成各类第三方工具和服务,如Prometheus、Grafana等,实现全方位的监控解决方案。 与此同时,开源社区对Nagios的贡献也日益丰富,涌现出了像Icinga、Naemon等基于Nagios核心的衍生项目,它们在保持兼容性的同时,引入更多现代化特性,比如灵活的插件体系、API驱动的自动化运维能力等,进一步提升了监控系统的灵活性和可扩展性。 而在最新的行业实践案例中,许多大型企业已成功运用Nagios搭建起高效稳定的监控平台,通过精细化的配置管理,有效预防潜在故障,确保业务连续性和稳定性。因此,对于任何想要提升IT基础设施监控管理水平的组织来说,深入研究Nagios的配置技巧并跟进其最新发展动态,无疑是一项极具价值的工作。
2023-11-16 20:48:42
483
转载
Redis
...这些都是非常实用的小技巧。 不过呢,我也希望大家能记住一点——技术永远不是一成不变的。业务越做越大,技术也日新月异的,咱们得不停地充电,学点新鲜玩意儿,试试新招数才行啊!就像今天的分布式锁一样,也许明天就会有更高效、更优雅的解决方案出现。所以,保持好奇心,勇于探索未知领域,这才是程序员最大的乐趣所在! 好了,今天就聊到这里啦,祝大家在编程的路上越走越远!如果有任何疑问或者想法,欢迎随时找我交流哦~
2025-04-22 16:00:29
58
寂静森林
转载文章
...ative; /父元素,为了使之后的子元素都相对于他进行定位,此处设为relative/color:white;background-size: cover; /使背景图片保持比例覆盖整个背景区域/}/ 以下三个元素为现实面板,其样式相同 /targetScore{width: 100%;height: 50px;position: relative;line-height: 50px;text-align: center;font-size: 20px;background-size: cover;}nowScore{width: 100%;height: 50px;position: relative;line-height: 50px;text-align: center;font-size: 20px;background-size: cover;}selectScore{width: 100%;height: 50px;position: relative;line-height: 50px;text-align: center;font-size: 20px;background-size: cover;opacity:0;/不透明度/} js var table; //游戏桌面var squareWidth = 50; //方块宽高var boardWidth = 10; //行列数var squareSet = []; //方块信息集合(二维数组)每个元素保存该方块的全部信息function createSquare(value,row,col){ //创建小方块,传入参数为颜色、行、列,初始化时使用。var temp = document.createElement('div'); //创建div dom对象temp.style.height = squareWidth + "px";temp.style.width = squareWidth + "px";temp.style.position = "absolute"; //相对于背景绝对定位temp.num = value;temp.col = col;temp.row = row;return temp; //返回这个创建出来的对象}function refresh(){ //重绘画板,每次鼠标点击后刷新for(var i = 0 ; i < squareSet.length ; i ++){for(var j = 0 ; j < squareSet[i].length ; j ++){squareSet[i][j].style.backgroundImage = "url(./pic/" + squareSet[i][j].num + ".png)"squareSet[i][j].style.left = squareSet[i][j].col squareWidth + "px"; // 别忘了加"px"squareSet[i][j].style.bottom = squareSet[i][j].row squareWidth + "px";} }}function init(){ // JS调用入口table = document.getElementById('pop_star'); // 获取到最外层的父元素作为桌面for(var i = 0 ; i < boardWidth; i ++){squareSet[i] = new Array(); //二维数组的创建,对每一个元素new Array()创建新数组for(var j = 0 ; j < boardWidth ; j ++){var square = createSquare(Math.floor(Math.random() 5) , i , j);squareSet[i][j] = square; //必须将新创建的方块放回到数组中table.appendChild(square); //需要将创建的新元素添加到桌面上} }refresh(); //每次页面内容发生变化需要重绘页面}window.onload = function(){init();} // window.onload 保证了在页面全部加载完毕后再执行JS代码 效果 第二阶段:鼠标选中后,闪烁 只有JavaScript需要修改 var table; //游戏桌面var squareWidth = 50; //方块宽高var boardWidth = 10; //行列数var squareSet = []; //方块信息集合(二维数组)每个元素保存该方块的全部信息var baseScore = 5; //第一块的分数var stepScore = 10; //每多一块的累加分数var totalScore = 0; //当前总分var targetScore = 1500; //目标分var choose = []; //选中的连通小方块var timer = null; //闪烁定时器var flag = true; //锁,防止点击事件中响应其他点击或移入时间var tempSquare = null; //临时方块function refresh(){for (var i = 0; i < squareSet.length; i++) {for (var j = 0; j < squareSet[i].length; j++) {squareSet[i][j].style.background="url(pic/"+squareSet[i][j].num+".png)"squareSet[i][j].style.left=squareSet[i][j].colsquareWidth+"px";squareSet[i][j].style.bottom=squareSet[i][j].rowsquareWidth+"px";} }}function createSquare(value,row,col){ //创建小方块,传入参数为颜色、行、列,初始化时使用。var temp = document.createElement('div'); //创建div dom对象temp.style.height = squareWidth + "px";temp.style.width = squareWidth + "px";temp.style.position = "absolute"; //相对于背景绝对定位temp.num = value;temp.col = col;temp.row = row;return temp; //返回这个创建出来的对象}function goBack(){ //还原样式if(timer != null){ //清空计时器clearInterval(timer);}for(var i = 0 ; i < squareSet.length ; i ++){for(var j = 0 ; j < squareSet[i].length ; j ++){squareSet[i][j].style.border = "0px solid white";squareSet[i][j].style.transform = "scale(0.95)";} }}function checkLinked(square , arr){ // 递归连通图算法arr.push(square); // 将当前方块放入选中数组中// check leftif( square.col > 0 && //未到边界squareSet[square.row][square.col - 1].num == square.num && //颜色相同arr.indexOf(squareSet[square.row][square.col - 1]) == -1) { //不在choose中,避免循环判断checkLinked(squareSet[square.row][square.col - 1] , arr);}// check rightif( square.col < boardWidth - 1 &&squareSet[square.row][square.col + 1].num == square.num &&arr.indexOf(squareSet[square.row][square.col + 1]) == -1) {checkLinked(squareSet[square.row][square.col + 1] , arr);}// check upif( square.row < boardWidth - 1 &&squareSet[square.row + 1][square.col].num == square.num &&arr.indexOf(squareSet[square.row + 1][square.col]) == -1) {checkLinked(squareSet[square.row + 1][square.col] , arr);}// check downif( square.row > 0 &&squareSet[square.row - 1][square.col].num == square.num &&arr.indexOf(squareSet[square.row - 1][square.col]) == -1) {checkLinked(squareSet[square.row - 1][square.col] , arr);} }function flicker(arr){ // 选中连通的小方块可以闪烁var num = 0;timer = setInterval(function(){for(var i = 0 ; i < arr.length ; i ++){arr[i].style.border = "3px solid BFEFFF";//有个框arr[i].style.transform = "scale(" + (0.9 + (0.05 Math.pow(-1 , num))) + ")";//一闪一闪}num ++; // 注意这里所采用的数学技巧,仍然使用transform:scale(val)来进行缩放。},300);//闪烁的时间}function mouseOver(obj){ //鼠标移入区域响应// 还原所有样式goBack();// 检查相邻choose = [];checkLinked(obj , choose);// 闪烁flicker(choose);// 显示分数selectScore();}function init(){ // JS调用入口table = document.getElementById('pop_star'); // 获取到最外层的父元素作为桌面document.getElementById('targetScore').innerHTML = "Target Score : " + targetScore; //显示目标分数用innerHTML// 循环初始化星星区域for(var i = 0 ; i < boardWidth ; i ++){squareSet[i] = new Array(); //二维数组的创建,对每一个元素new Array()创建新数组for(var j = 0 ; j < boardWidth ; j ++){var square = createSquare(Math.floor(Math.random() 5) , i , j);// 鼠标移入事件square.onmouseover = function(){mouseOver(this);}squareSet[i][j] = square; //必须将新创建的方块放回到数组中table.appendChild(square); //需要将创建的新元素添加到桌面上} }refresh(); //每次页面内容发生变化需要重绘页面}window.onload = function(){init();} // window.onload 保证了在页面全部加载完毕后再执行JS代码 效果2.1 加入这段代码,便会计算闪烁方块得分 function selectScore(){ //可以显示当前选中小方块的得分var score = 0;for(var i = 0 ; i < choose.length ; i ++){score += (baseScore + i stepScore);}document.getElementById('selectScore').innerHTML = choose.length + " blocks " + score + " points";document.getElementById('selectScore').style.opacity = 1;// 设置时间间隔1秒后显示消失的过渡动画setTimeout(function(){document.getElementById('selectScore').style.opacity = 0;document.getElementById('selectScore').style.transition = "opacity 1s";},1000);} 完整代码为: var table; //游戏桌面var squareWidth = 50; //方块宽高var boardWidth = 10; //行列数var squareSet = []; //方块信息集合(二维数组)每个元素保存该方块的全部信息var baseScore = 5; //第一块的分数var stepScore = 10; //每多一块的累加分数var totalScore = 0; //当前总分var targetScore = 1500; //目标分var choose = []; //选中的连通小方块var timer = null; //闪烁定时器var flag = true; //锁,防止点击事件中响应其他点击或移入时间var tempSquare = null; //临时方块function refresh(){for (var i = 0; i < squareSet.length; i++) {for (var j = 0; j < squareSet[i].length; j++) {squareSet[i][j].style.background="url(pic/"+squareSet[i][j].num+".png)"squareSet[i][j].style.left=squareSet[i][j].colsquareWidth+"px";squareSet[i][j].style.bottom=squareSet[i][j].rowsquareWidth+"px";} }}function createSquare(value,row,col){ //创建小方块,传入参数为颜色、行、列,初始化时使用。var temp = document.createElement('div'); //创建div dom对象temp.style.height = squareWidth + "px";temp.style.width = squareWidth + "px";temp.style.position = "absolute"; //相对于背景绝对定位temp.num = value;temp.col = col;temp.row = row;return temp; //返回这个创建出来的对象}function goBack(){ //还原样式if(timer != null){ //清空计时器clearInterval(timer);}for(var i = 0 ; i < squareSet.length ; i ++){for(var j = 0 ; j < squareSet[i].length ; j ++){squareSet[i][j].style.border = "0px solid white";squareSet[i][j].style.transform = "scale(0.95)";} }}function checkLinked(square , arr){ // 递归连通图算法arr.push(square); // 将当前方块放入选中数组中// check leftif( square.col > 0 && //未到边界squareSet[square.row][square.col - 1].num == square.num && //颜色相同arr.indexOf(squareSet[square.row][square.col - 1]) == -1) { //不在choose中,避免循环判断checkLinked(squareSet[square.row][square.col - 1] , arr);}// check rightif( square.col < boardWidth - 1 &&squareSet[square.row][square.col + 1].num == square.num &&arr.indexOf(squareSet[square.row][square.col + 1]) == -1) {checkLinked(squareSet[square.row][square.col + 1] , arr);}// check upif( square.row < boardWidth - 1 &&squareSet[square.row + 1][square.col].num == square.num &&arr.indexOf(squareSet[square.row + 1][square.col]) == -1) {checkLinked(squareSet[square.row + 1][square.col] , arr);}// check downif( square.row > 0 &&squareSet[square.row - 1][square.col].num == square.num &&arr.indexOf(squareSet[square.row - 1][square.col]) == -1) {checkLinked(squareSet[square.row - 1][square.col] , arr);} }function flicker(arr){ // 选中连通的小方块可以闪烁var num = 0;timer = setInterval(function(){for(var i = 0 ; i < arr.length ; i ++){arr[i].style.border = "3px solid BFEFFF";//有个框arr[i].style.transform = "scale(" + (0.9 + (0.05 Math.pow(-1 , num))) + ")";//一闪一闪}num ++; // 注意这里所采用的数学技巧,仍然使用transform:scale(val)来进行缩放。},300);//闪烁的时间}function selectScore(){ //可以显示当前选中小方块的得分var score = 0;for(var i = 0 ; i < choose.length ; i ++){score += (baseScore + i stepScore);}document.getElementById('selectScore').innerHTML = choose.length + " blocks " + score + " points";document.getElementById('selectScore').style.opacity = 1;// 设置时间间隔1秒后显示消失的过渡动画setTimeout(function(){document.getElementById('selectScore').style.opacity = 0;document.getElementById('selectScore').style.transition = "opacity 1s";},1000);}function mouseOver(obj){ //鼠标移入区域响应// 还原所有样式goBack();// 检查相邻choose = [];checkLinked(obj , choose);// 闪烁flicker(choose);// 显示分数selectScore();}function init(){ // JS调用入口table = document.getElementById('pop_star'); // 获取到最外层的父元素作为桌面document.getElementById('targetScore').innerHTML = "Target Score : " + targetScore; //显示目标分数用innerHTML// 循环初始化星星区域for(var i = 0 ; i < boardWidth ; i ++){squareSet[i] = new Array(); //二维数组的创建,对每一个元素new Array()创建新数组for(var j = 0 ; j < boardWidth ; j ++){var square = createSquare(Math.floor(Math.random() 5) , i , j);// 鼠标移入事件square.onmouseover = function(){mouseOver(this);}squareSet[i][j] = square; //必须将新创建的方块放回到数组中table.appendChild(square); //需要将创建的新元素添加到桌面上} }refresh(); //每次页面内容发生变化需要重绘页面}window.onload = function(){init();} // window.onload 保证了在页面全部加载完毕后再执行JS代码 效果2.2 第三阶段:消灭星星(只消灭一次) 只消除选中的星星,但是不会掉下来。 在function init(){}里面添加以下代码: // 鼠标点击事件square.onclick = function(){//为移除增加一个延迟动画,为了防止闭包,这里采用立即执行函数for(var i = 0 ; i < choose.length ; i ++){(function(i){setTimeout(function(){squareSet[choose[i].row][choose[i].col] = null; //为状态数组置空table.removeChild(choose[i]); //将其从桌面上移除} , i 100);})(i);} } 效果 使得星星移动(原作者这里出现错误) function move(){//纵向下落,采用快慢指针算法for(var i = 0 ; i < boardWidth ; i ++){var pointer = 0; //慢指针for(var j = 0 ; j < boardWidth ; j ++){if(squareSet[j][i] != null){ //按行遍历if(pointer != j){ //快慢指针不同步说明中间有空元素squareSet[pointer][i] = squareSet[j][i]; //慢指针设成快指针元素squareSet[j][i].row = pointer;squareSet[j][i] = null; //快指针处置空}pointer ++; //该行非空时慢指针增加} }} 完整代码如下: var table; //游戏桌面var squareWidth = 50; //方块宽高var boardWidth = 10; //行列数var squareSet = []; //方块信息集合(二维数组)每个元素保存该方块的全部信息var baseScore = 5; //第一块的分数var stepScore = 10; //每多一块的累加分数var totalScore = 0; //当前总分var targetScore = 1500; //目标分var choose = []; //选中的连通小方块var timer = null; //闪烁定时器var flag = true; //锁,防止点击事件中响应其他点击或移入时间var tempSquare = null; //临时方块function refresh(){for (var i = 0; i < squareSet.length; i++) {for (var j = 0; j < squareSet[i].length; j++) {squareSet[i][j].style.background="url(pic/"+squareSet[i][j].num+".png)"squareSet[i][j].style.left=squareSet[i][j].colsquareWidth+"px";squareSet[i][j].style.bottom=squareSet[i][j].rowsquareWidth+"px";} }}function createSquare(value,row,col){ //创建小方块,传入参数为颜色、行、列,初始化时使用。var temp = document.createElement('div'); //创建div dom对象temp.style.height = squareWidth + "px";temp.style.width = squareWidth + "px";temp.style.position = "absolute"; //相对于背景绝对定位temp.num = value;temp.col = col;temp.row = row;return temp; //返回这个创建出来的对象}function goBack(){ //还原样式if(timer != null){ //清空计时器clearInterval(timer);}for(var i = 0 ; i < squareSet.length ; i ++){for(var j = 0 ; j < squareSet[i].length ; j ++){squareSet[i][j].style.border = "0px solid white";squareSet[i][j].style.transform = "scale(0.95)";} }}function checkLinked(square , arr){ // 递归连通图算法arr.push(square); // 将当前方块放入选中数组中// check leftif( square.col > 0 && //未到边界squareSet[square.row][square.col - 1].num == square.num && //颜色相同arr.indexOf(squareSet[square.row][square.col - 1]) == -1) { //不在choose中,避免循环判断checkLinked(squareSet[square.row][square.col - 1] , arr);}// check rightif( square.col < boardWidth - 1 &&squareSet[square.row][square.col + 1].num == square.num &&arr.indexOf(squareSet[square.row][square.col + 1]) == -1) {checkLinked(squareSet[square.row][square.col + 1] , arr);}// check upif( square.row < boardWidth - 1 &&squareSet[square.row + 1][square.col].num == square.num &&arr.indexOf(squareSet[square.row + 1][square.col]) == -1) {checkLinked(squareSet[square.row + 1][square.col] , arr);}// check downif( square.row > 0 &&squareSet[square.row - 1][square.col].num == square.num &&arr.indexOf(squareSet[square.row - 1][square.col]) == -1) {checkLinked(squareSet[square.row - 1][square.col] , arr);} }function flicker(arr){ // 选中连通的小方块可以闪烁var num = 0;timer = setInterval(function(){for(var i = 0 ; i < arr.length ; i ++){arr[i].style.border = "3px solid BFEFFF";//有个框arr[i].style.transform = "scale(" + (0.9 + (0.05 Math.pow(-1 , num))) + ")";//一闪一闪}num ++; // 注意这里所采用的数学技巧,仍然使用transform:scale(val)来进行缩放。},300);//闪烁的时间}function selectScore(){ //可以显示当前选中小方块的得分var score = 0;for(var i = 0 ; i < choose.length ; i ++){score += (baseScore + i stepScore);}document.getElementById('selectScore').innerHTML = choose.length + " blocks " + score + " points";document.getElementById('selectScore').style.opacity = 1;// 设置时间间隔1秒后显示消失的过渡动画setTimeout(function(){document.getElementById('selectScore').style.opacity = 0;document.getElementById('selectScore').style.transition = "opacity 1s";},1000);}function mouseOver(obj){ //鼠标移入区域响应// 还原所有样式goBack();// 检查相邻choose = [];checkLinked(obj , choose);// 闪烁flicker(choose);// 显示分数selectScore();}function move(){//纵向下落,采用快慢指针算法for(var i = 0 ; i < boardWidth ; i ++){var pointer = 0; //慢指针for(var j = 0 ; j < boardWidth ; j ++){if(squareSet[j][i] != null){ //按行遍历if(pointer != j){ //快慢指针不同步说明中间有空元素squareSet[pointer][i] = squareSet[j][i]; //慢指针设成快指针元素squareSet[j][i].row = pointer;squareSet[j][i] = null; //快指针处置空}pointer ++; //该行非空时慢指针增加} }}// 横向移动(当出现一列为空时)for(var i = 0 ; i < squareSet[0].length ;){ //必须注意循环结束条件的判断if(squareSet[0][i] == null){ //逻辑:只需判断最低层为空,该行则全为空for(var j = 0 ; j < boardWidth ; j ++){squareSet[j].splice(i , 1); //splice删除数组squareSet[j]中从i开始的1个元素}continue;//注意移动后i不应改变了}i ++;}refresh();}function init(){ // JS调用入口table = document.getElementById('pop_star'); // 获取到最外层的父元素作为桌面document.getElementById('targetScore').innerHTML = "Target Score : " + targetScore; //显示目标分数用innerHTML// 循环初始化星星区域for(var i = 0 ; i < boardWidth ; i ++){squareSet[i] = new Array(); //二维数组的创建,对每一个元素new Array()创建新数组for(var j = 0 ; j < boardWidth ; j ++){var square = createSquare(Math.floor(Math.random() 5) , i , j);// 鼠标移入事件square.onmouseover = function(){mouseOver(this);}// 鼠标点击事件square.onclick = function(){//对锁进行控制if(!flag || choose.length == null){return;}flag = false;tempSquare = null;//更新分数var score = 0;for(var i = 0 ; i < choose.length ; i ++){score += (baseScore + i stepScore);}totalScore += score;document.getElementById('nowScore').innerHTML = "Current Score : " + totalScore;//为移除增加一个延迟动画,为了防止闭包,这里采用立即执行函数for(var i = 0 ; i < choose.length ; i ++){(function(i){setTimeout(function(){squareSet[choose[i].row][choose[i].col] = null; //为状态数组置空table.removeChild(choose[i]); //将其从桌面上移除} , i 100);})(i);}//需要等星星消除完毕后再移动,故需增加一个延迟setTimeout(function(){move(); //调用移动函数},choose.length 100);}squareSet[i][j] = square; //必须将新创建的方块放回到数组中table.appendChild(square); //需要将创建的新元素添加到桌面上} }refresh(); //每次页面内容发生变化需要重绘页面}window.onload = function(){init();} // window.onload 保证了在页面全部加载完毕后再执行JS代码 效果(下降成功,但是有点小bug只有部分下降了) 解决方案:只需要在function refresh(){}的双循环里面增加以下代码: if(squareSet[i][j] == null) continue; 完整代码如下: var table; //游戏桌面var squareWidth = 50; //方块宽高var boardWidth = 10; //行列数var squareSet = []; //方块信息集合(二维数组)每个元素保存该方块的全部信息var baseScore = 5; //第一块的分数var stepScore = 10; //每多一块的累加分数var totalScore = 0; //当前总分var targetScore = 1500; //目标分var choose = []; //选中的连通小方块var timer = null; //闪烁定时器var flag = true; //锁,防止点击事件中响应其他点击或移入时间var tempSquare = null; //临时方块function refresh(){for (var i = 0; i < squareSet.length; i++) {for (var j = 0; j < squareSet[i].length; j++) {if(squareSet[i][j] == null) continue; // 点击后数组中可能有空值需要跳过squareSet[i][j].style.background="url(pic/"+squareSet[i][j].num+".png)"squareSet[i][j].style.left=squareSet[i][j].colsquareWidth+"px";squareSet[i][j].style.bottom=squareSet[i][j].rowsquareWidth+"px";} }}function createSquare(value,row,col){ //创建小方块,传入参数为颜色、行、列,初始化时使用。var temp = document.createElement('div'); //创建div dom对象temp.style.height = squareWidth + "px";temp.style.width = squareWidth + "px";temp.style.position = "absolute"; //相对于背景绝对定位temp.num = value;temp.col = col;temp.row = row;return temp; //返回这个创建出来的对象}function goBack(){ //还原样式if(timer != null){ //清空计时器clearInterval(timer);}for(var i = 0 ; i < squareSet.length ; i ++){for(var j = 0 ; j < squareSet[i].length ; j ++){squareSet[i][j].style.border = "0px solid white";squareSet[i][j].style.transform = "scale(0.95)";} }}function checkLinked(square , arr){ // 递归连通图算法arr.push(square); // 将当前方块放入选中数组中// check leftif( square.col > 0 && //未到边界squareSet[square.row][square.col - 1].num == square.num && //颜色相同arr.indexOf(squareSet[square.row][square.col - 1]) == -1) { //不在choose中,避免循环判断checkLinked(squareSet[square.row][square.col - 1] , arr);}// check rightif( square.col < boardWidth - 1 &&squareSet[square.row][square.col + 1].num == square.num &&arr.indexOf(squareSet[square.row][square.col + 1]) == -1) {checkLinked(squareSet[square.row][square.col + 1] , arr);}// check upif( square.row < boardWidth - 1 &&squareSet[square.row + 1][square.col].num == square.num &&arr.indexOf(squareSet[square.row + 1][square.col]) == -1) {checkLinked(squareSet[square.row + 1][square.col] , arr);}// check downif( square.row > 0 &&squareSet[square.row - 1][square.col].num == square.num &&arr.indexOf(squareSet[square.row - 1][square.col]) == -1) {checkLinked(squareSet[square.row - 1][square.col] , arr);} }function flicker(arr){ // 选中连通的小方块可以闪烁var num = 0;timer = setInterval(function(){for(var i = 0 ; i < arr.length ; i ++){arr[i].style.border = "3px solid BFEFFF";//有个框arr[i].style.transform = "scale(" + (0.9 + (0.05 Math.pow(-1 , num))) + ")";//一闪一闪}num ++; // 注意这里所采用的数学技巧,仍然使用transform:scale(val)来进行缩放。},300);//闪烁的时间}function selectScore(){ //可以显示当前选中小方块的得分var score = 0;for(var i = 0 ; i < choose.length ; i ++){score += (baseScore + i stepScore);}document.getElementById('selectScore').innerHTML = choose.length + " blocks " + score + " points";document.getElementById('selectScore').style.opacity = 1;// 设置时间间隔1秒后显示消失的过渡动画setTimeout(function(){document.getElementById('selectScore').style.opacity = 0;document.getElementById('selectScore').style.transition = "opacity 1s";},1000);}function mouseOver(obj){ //鼠标移入区域响应// 还原所有样式goBack();// 检查相邻choose = [];checkLinked(obj , choose);// 闪烁flicker(choose);// 显示分数selectScore();}function move(){//纵向下落,采用快慢指针算法for(var i = 0 ; i < boardWidth ; i ++){var pointer = 0; //慢指针for(var j = 0 ; j < boardWidth ; j ++){if(squareSet[j][i] != null){ //按行遍历if(pointer != j){ //快慢指针不同步说明中间有空元素squareSet[pointer][i] = squareSet[j][i]; //慢指针设成快指针元素squareSet[j][i].row = pointer;squareSet[j][i] = null; //快指针处置空}pointer ++; //该行非空时慢指针增加} }}// 横向移动(当出现一列为空时)for(var i = 0 ; i < squareSet[0].length ;){ //必须注意循环结束条件的判断if(squareSet[0][i] == null){ //逻辑:只需判断最低层为空,该行则全为空for(var j = 0 ; j < boardWidth ; j ++){squareSet[j].splice(i , 1); //splice删除数组squareSet[j]中从i开始的1个元素}continue;//注意移动后i不应改变了}i ++;}refresh();}function init(){ // JS调用入口table = document.getElementById('pop_star'); // 获取到最外层的父元素作为桌面document.getElementById('targetScore').innerHTML = "Target Score : " + targetScore; //显示目标分数用innerHTML// 循环初始化星星区域for(var i = 0 ; i < boardWidth ; i ++){squareSet[i] = new Array(); //二维数组的创建,对每一个元素new Array()创建新数组for(var j = 0 ; j < boardWidth ; j ++){var square = createSquare(Math.floor(Math.random() 5) , i , j);// 鼠标移入事件square.onmouseover = function(){mouseOver(this);}// 鼠标点击事件square.onclick = function(){//对锁进行控制if(!flag || choose.length == null){return;}flag = false;tempSquare = null;//更新分数var score = 0;for(var i = 0 ; i < choose.length ; i ++){score += (baseScore + i stepScore);}totalScore += score;document.getElementById('nowScore').innerHTML = "Current Score : " + totalScore;//为移除增加一个延迟动画,为了防止闭包,这里采用立即执行函数for(var i = 0 ; i < choose.length ; i ++){(function(i){setTimeout(function(){squareSet[choose[i].row][choose[i].col] = null; //为状态数组置空table.removeChild(choose[i]); //将其从桌面上移除} , i 100);})(i);}//需要等星星消除完毕后再移动,故需增加一个延迟setTimeout(function(){move(); //调用移动函数},choose.length 100);}squareSet[i][j] = square; //必须将新创建的方块放回到数组中table.appendChild(square); //需要将创建的新元素添加到桌面上} }refresh(); //每次页面内容发生变化需要重绘页面}window.onload = function(){init();} // window.onload 保证了在页面全部加载完毕后再执行JS代码 第四阶段:消灭全部星星,返回结果 最终完整版代码如下: var table; //游戏桌面var squareWidth = 50; //方块宽高var boardWidth = 10; //行列数var squareSet = []; //方块信息集合(二维数组)每个元素保存该方块的全部信息var baseScore = 5; //第一块的分数var stepScore = 10; //每多一块的累加分数var totalScore = 0; //当前总分var targetScore = 1500; //目标分var choose = []; //选中的连通小方块var timer = null; //闪烁定时器var flag = true; //锁,防止点击事件中响应其他点击或移入时间var tempSquare = null; //临时方块function refresh(){ //重绘画板,每次鼠标点击后刷新for(var i = 0 ; i < squareSet.length ; i ++){for(var j = 0 ; j < squareSet[i].length ; j ++){if(squareSet[i][j] == null) continue; // 点击后数组中可能有空值需要跳过squareSet[i][j].row = i; //更新当前的行列数squareSet[i][j].col = j;squareSet[i][j].style.backgroundImage = "url(./pic/" + squareSet[i][j].num + ".png)"squareSet[i][j].style.backgroundSize = "cover"; //占满范围squareSet[i][j].style.transform = "scale(0.95)"; //美观效果让不同星星之间留出空隙(缩小至0.95倍大小)squareSet[i][j].style.left = squareSet[i][j].col squareWidth + "px"; // 别忘了加"px"squareSet[i][j].style.bottom = squareSet[i][j].row squareWidth + "px";squareSet[i][j].style.transition = "left 0.3s, bottom 0.3s";} }}function createSquare(value,row,col){ //创建小方块,传入参数为颜色、行、列,初始化时使用。var temp = document.createElement('div'); //创建div dom对象temp.style.height = squareWidth + "px";temp.style.width = squareWidth + "px";temp.style.display = "inline-block"; //需要让对象元素能排列一排temp.style.position = "absolute"; //相对于背景绝对定位temp.style.boxSizing = "border-box"; //重要:不会使增加的边框溢出覆盖到旁边的元素temp.style.borderRadius = "12px";temp.num = value;temp.col = col;temp.row = row;return temp; //返回这个创建出来的对象}function goBack(){ //还原样式if(timer != null){ //清空计时器clearInterval(timer);}for(var i = 0 ; i < squareSet.length ; i ++){for(var j = 0 ; j < squareSet[i].length ; j ++){if(squareSet[i][j] == null) continue;squareSet[i][j].style.border = "0px solid white";squareSet[i][j].style.transform = "scale(0.95)";} }}function checkLinked(square , arr){ // 递归连通图算法if(square == null) return; // 递归边界arr.push(square); // 将当前方块放入选中数组中// check leftif( square.col > 0 && //未到边界squareSet[square.row][square.col - 1] && //左侧有块squareSet[square.row][square.col - 1].num == square.num && //颜色相同arr.indexOf(squareSet[square.row][square.col - 1]) == -1) { //不在choose中,避免循环判断checkLinked(squareSet[square.row][square.col - 1] , arr);}// check rightif( square.col < boardWidth - 1 &&squareSet[square.row][square.col + 1] &&squareSet[square.row][square.col + 1].num == square.num &&arr.indexOf(squareSet[square.row][square.col + 1]) == -1) {checkLinked(squareSet[square.row][square.col + 1] , arr);}// check upif( square.row < boardWidth - 1 &&squareSet[square.row + 1][square.col] &&squareSet[square.row + 1][square.col].num == square.num &&arr.indexOf(squareSet[square.row + 1][square.col]) == -1) {checkLinked(squareSet[square.row + 1][square.col] , arr);}// check downif( square.row > 0 &&squareSet[square.row - 1][square.col] &&squareSet[square.row - 1][square.col].num == square.num &&arr.indexOf(squareSet[square.row - 1][square.col]) == -1) {checkLinked(squareSet[square.row - 1][square.col] , arr);} }function flicker(arr){ // 选中连通的小方块可以闪烁var num = 0;timer = setInterval(function(){for(var i = 0 ; i < arr.length ; i ++){arr[i].style.border = "3px solid BFEFFF";arr[i].style.transform = "scale(" + (0.9 + (0.05 Math.pow(-1 , num))) + ")";}num ++; // 注意这里所采用的数学技巧,仍然使用transform:scale(val)来进行缩放。},300);}function selectScore(){ //可以显示当前选中小方块的得分var score = 0;for(var i = 0 ; i < choose.length ; i ++){score += (baseScore + i stepScore);}if(score == 0) return;document.getElementById('selectScore').innerHTML = choose.length + " blocks " + score + " points";document.getElementById('selectScore').style.opacity = 1;document.getElementById('selectScore').style.transition = null;// 设置时间间隔1秒后显示消失的过渡动画setTimeout(function(){document.getElementById('selectScore').style.opacity = 0;document.getElementById('selectScore').style.transition = "opacity 1s";},1000);}function mouseOver(obj){ //鼠标移入区域响应// 加锁,点击事件过程中不允许其他点击事件与移入事件if(!flag){tempSquare = obj;return;}// 还原所有样式goBack();// 检查相邻choose = [];checkLinked(obj , choose);if(choose.length <= 1){choose = [];return;}// 闪烁flicker(choose);// 显示分数selectScore();}function move(){ //下落移动控制//纵向下落,采用快慢指针算法for(var i = 0 ; i < boardWidth ; i ++){var pointer = 0; //慢指针for(var j = 0 ; j < boardWidth ; j ++){if(squareSet[j][i] != null){ //按行遍历if(pointer != j){ //快慢指针不同步说明中间有空元素squareSet[pointer][i] = squareSet[j][i]; //慢指针设成快指针元素squareSet[j][i].row = pointer;squareSet[j][i] = null; //快指针处置空}pointer ++; //该行非空时慢指针增加} }}// 横向移动(当出现一列为空时)for(var i = 0 ; i < squareSet[0].length ;){ // 注意循环终止条件的判断!!!因为数组长度会更新if(squareSet[0][i] == null){ //逻辑:只需判断最低层为空,该行则全为空for(var j = 0 ; j < boardWidth ; j ++){squareSet[j].splice(i , 1); //splice删除数组squareSet[j]中从i开始的1个元素}continue;//注意移动后i不应改变了}i ++;}refresh();}function isFinish(){ //判断游戏结束flag = true; //重要:需要先解锁,保证后续鼠标事件可以被响应for(var i = 0 ; i < squareSet.length ; i ++){for(var j = 0 ; j < squareSet[i].length ; j ++){if(squareSet[i][j] == null) continue; //遍历每一元素判断连通var temp = [];checkLinked(squareSet[i][j] , temp);if(temp.length > 1) return false; //若有某一元素仍有多块连通,则游戏未结束} }return flag;}function init(){ // JS调用入口table = document.getElementById('pop_star'); // 获取到最外层的父元素作为桌面document.getElementById('targetScore').innerHTML = "Target Score : " + targetScore; //显示目标分数用innerHTML// 循环初始化星星区域for(var i = 0 ; i < boardWidth ; i ++){squareSet[i] = new Array(); //二维数组的创建,对每一个元素new Array()创建新数组for(var j = 0 ; j < boardWidth ; j ++){var square = createSquare(Math.floor(Math.random() 5) , i , j);// 鼠标移入事件square.onmouseover = function(){mouseOver(this);}// 鼠标点击事件square.onclick = function(){//对锁进行控制if(!flag || choose.length == null){return;}flag = false;tempSquare = null;//更新分数var score = 0;for(var i = 0 ; i < choose.length ; i ++){score += (baseScore + i stepScore);}totalScore += score;document.getElementById('nowScore').innerHTML = "Current Score : " + totalScore;//为移除增加一个延迟动画,为了防止闭包,这里采用立即执行函数for(var i = 0 ; i < choose.length ; i ++){(function(i){setTimeout(function(){squareSet[choose[i].row][choose[i].col] = null; //为状态数组置空table.removeChild(choose[i]); //将其从桌面上移除} , i 50);})(i);}//需要等星星消除完毕后再移动,故需增加一个延迟setTimeout(function(){move(); //调用移动函数setTimeout(function(){var judge = isFinish();if(judge){ //游戏达到结束条件if(totalScore > targetScore){alert('Congratulations! You win!');}else{alert('Mission Failed!');} }else{flag = true;choose = [];mouseOver(tempSquare); //处理可能存在的冲突} },300 + choose.length 75); //需要一个判断延迟},choose.length 50);}squareSet[i][j] = square; //必须将新创建的方块放回到数组中table.appendChild(square); //需要将创建的新元素添加到桌面上} }refresh(); //每次页面内容发生变化需要重绘页面}window.onload = function(){init();} // window.onload 保证了在页面全部加载完毕后再执行JS代码 效果 本篇文章为转载内容。原文链接:https://blog.csdn.net/weixin_56471396/article/details/128681321。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-06-08 15:26:34
516
转载
转载文章
...据结构,用于判断一个元素是否在一个集合中。在文章的上下文中,Bloom Filter通过使用多个独立的哈希函数将元素映射到一个固定长度的位数组上,当插入元素时,会在相应位置置为1。查询时,如果所有哈希函数对应的位置均为1,则该元素可能存在集合中;若存在某个位置为0,则该元素一定不在集合中。因此,Bloom Filter有可能产生误报(False Positive),但不会漏报(False Negative)。在处理海量数据时,因其占用内存小且查询速度快,常被用于判重、过滤等场景。 Trie树(前缀树) , Trie树是一种有序字典树,也称为前缀树或数码查找树,特别适用于存储和检索字符串集合。在本文语境下,Trie树通过字符在树中的路径表示一个字符串,并且相同前缀的字符串在树中有公共前缀路径。利用这种特性,可以高效地统计词频、进行字符串搜索和去重等操作,尤其在处理大量字符串数据时优势明显。 MapReduce , MapReduce是Google提出的一种分布式编程模型,主要应用于大数据并行计算领域。在文中提到,面对海量数据处理难题时,MapReduce提供了一种解决方案。它将复杂的计算任务分解成两个阶段。
2024-03-01 12:40:17
541
转载
转载文章
...议先 OFF) 在末尾添加一个cmake的编译宏,确保编译出来的是debug版本set(CMAKE_BUILD_TYPE Debug) 编译tvm,这里开启了16个线程: cd buildcmake ..make -j 16 建议开多个线程,否则编译速度很慢哦 大约5分钟,即可生成我们需要的两个共享链接库:libtvm.so 和 libtvm_runtime.so 1.4 验证安装是否成功 tvm版本验证: import tvmprint(tvm.__version__) pytorch模型验证: from_pytorch.py https://tvm.apache.org/docs/how_to/compile_models/from_pytorch.html ps: TVM supports PyTorch 1.7 and 1.4. Other versions may be unstable.import tvmfrom tvm import relayfrom tvm.contrib.download import download_testdataimport numpy as np PyTorch importsimport torchimport torchvision Load a pretrained PyTorch model -------------------------------model_name = "resnet18"model = getattr(torchvision.models, model_name)(pretrained=True) or model = torchvision.models.resnet18(pretrained=True) or pth_file = 'resnet18-f37072fd.pth' model = torchvision.models.resnet18() ckpt = torch.load(pth_file) model.load_state_dict(ckpt)model = model.eval() We grab the TorchScripted model via tracinginput_shape = [1, 3, 224, 224]input_data = torch.randn(input_shape)scripted_model = torch.jit.trace(model, input_data).eval() Load a test image ----------------- Classic cat example!from PIL import Image img_url = "https://github.com/dmlc/mxnet.js/blob/main/data/cat.png?raw=true" img_path = download_testdata(img_url, "cat.png", module="data")img_path = 'cat.png'img = Image.open(img_path).resize((224, 224)) Preprocess the image and convert to tensorfrom torchvision import transformsmy_preprocess = transforms.Compose([transforms.Resize(256),transforms.CenterCrop(224),transforms.ToTensor(),transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),])img = my_preprocess(img)img = np.expand_dims(img, 0) Import the graph to Relay ------------------------- Convert PyTorch graph to Relay graph. The input name can be arbitrary.input_name = "input0"shape_list = [(input_name, img.shape)]mod, params = relay.frontend.from_pytorch(scripted_model, shape_list) Relay Build ----------- Compile the graph to llvm target with given input specification.target = tvm.target.Target("llvm", host="llvm")dev = tvm.cpu(0)with tvm.transform.PassContext(opt_level=3):lib = relay.build(mod, target=target, params=params) Execute the portable graph on TVM --------------------------------- Now we can try deploying the compiled model on target.from tvm.contrib import graph_executordtype = "float32"m = graph_executor.GraphModule(lib["default"](dev)) Set inputsm.set_input(input_name, tvm.nd.array(img.astype(dtype))) Executem.run() Get outputstvm_output = m.get_output(0) Look up synset name ------------------- Look up prediction top 1 index in 1000 class synset. synset_url = "".join( [ "https://raw.githubusercontent.com/Cadene/", "pretrained-models.pytorch/master/data/", "imagenet_synsets.txt", ] ) synset_name = "imagenet_synsets.txt" synset_path = download_testdata(synset_url, synset_name, module="data") https://raw.githubusercontent.com/Cadene/pretrained-models.pytorch/master/data/imagenet_synsets.txtsynset_path = 'imagenet_synsets.txt'with open(synset_path) as f:synsets = f.readlines()synsets = [x.strip() for x in synsets]splits = [line.split(" ") for line in synsets]key_to_classname = {spl[0]: " ".join(spl[1:]) for spl in splits} class_url = "".join( [ "https://raw.githubusercontent.com/Cadene/", "pretrained-models.pytorch/master/data/", "imagenet_classes.txt", ] ) class_name = "imagenet_classes.txt" class_path = download_testdata(class_url, class_name, module="data") https://raw.githubusercontent.com/Cadene/pretrained-models.pytorch/master/data/imagenet_classes.txtclass_path = 'imagenet_classes.txt'with open(class_path) as f:class_id_to_key = f.readlines()class_id_to_key = [x.strip() for x in class_id_to_key] Get top-1 result for TVMtop1_tvm = np.argmax(tvm_output.numpy()[0])tvm_class_key = class_id_to_key[top1_tvm] Convert input to PyTorch variable and get PyTorch result for comparisonwith torch.no_grad():torch_img = torch.from_numpy(img)output = model(torch_img) Get top-1 result for PyTorchtop1_torch = np.argmax(output.numpy())torch_class_key = class_id_to_key[top1_torch]print("Relay top-1 id: {}, class name: {}".format(top1_tvm, key_to_classname[tvm_class_key]))print("Torch top-1 id: {}, class name: {}".format(top1_torch, key_to_classname[torch_class_key])) 2. 配置vscode 安装两个vscode远程连接所需的两个插件,具体如下图所示: 安装完成之后,在左侧工具栏会出现一个图标,点击图标进行ssh配置: ssh yourname@yourip -A 然后右键选择在当前窗口进行连接: 除此之外,还可以设置免费登录,具体可参考这篇文章。 当然,也可以使用windows本地的WSL2,vscode连接WSL还需要安装WSL和Dev Containers这两个插件。 在服务器端执行code .会自动安装vscode server,安装位置在用户的根目录下: 3. 安装FFI Navigator 由于TVM是由Python和C++混合开发,且大多数的IDE仅支持在同一种语言中查找函数定义,因此对于跨语言的FFI 调用,即Python跳转到C++或者C++跳转到Python,vscode是做不到的。虽然解决这个问题在技术上可能非常具有挑战性,但我们可以通过构建一个与FFI注册码模式匹配并恢复必要信息的项目特定分析器来解决这个问题,FFI Navigator就这样诞生了,作者仍然是陈天奇博士。 安装方式如下: 建议使用源码安装git clone https://github.com/tqchen/ffi-navigator.git 安装python依赖cd ffi-navigator/pythonpython setyp.py install vscode需要安装FFI Navigator插件,直接搜索安装即可(安装到服务器端)。 最后需要在.vscode/setting.json进行配置,内容如下: {"python.analysis.extraPaths": ["${workspaceFolder}/python"], // 添加额外导入路径, 告诉pylance自定义的python库在哪里"ffi_navigator.pythonpath": "/home/liyanpeng/anaconda3/envs/tvmenv/bin/python", // 配置FFI Navigator"python.defaultInterpreterPath": "/home/liyanpeng/anaconda3/envs/tvmenv/bin/python","files.associations": {"type_traits": "cpp","fstream": "cpp","thread": "cpp",".tcc": "cpp"} } 更详细内容可以参考项目链接。 结束语 对于vscode的使用技巧及C/C++相关的配置,这里不再详细的介绍了,感兴趣的小伙伴们可以了解下。 本篇文章为转载内容。原文链接:https://blog.csdn.net/qq_42730750/article/details/126723224。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-12-12 20:04:26
87
转载
转载文章
...至tomcat或其他容器。 第二种,作业类不继承特定基类。 Spring能够支持这种方式,归功于两个类: org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean 这两个类分别对应spring支持的两种实现任务调度的方式,即前文提到到java自带的timer task方式和Quartz方式。这里我只写MethodInvokingJobDetailFactoryBean的用法,使用该类的好处是,我们的任务类不再需要继承自任何类,而是普通的pojo。 第一步:编写任务类 Java代码 public class Job2 { public void doJob2() { System.out.println("不继承QuartzJobBean方式-调度进行中..."); } } 可以看出,这就是一个普通的类,并且有一个方法。 第二步:配置作业类 Xml代码 <bean id="job2" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject"> <bean class="com.gy.Job2" /> </property> <property name="targetMethod" value="doJob2" /> <property name="concurrent" value="false" /><!-- 作业不并发调度 --> </bean> 说明:这一步是关键步骤,声明一个MethodInvokingJobDetailFactoryBean,有两个关键属性:targetObject指定任务类,targetMethod指定运行的方法。往下的步骤就与方法一相同了,为了完整,同样贴出。 第三步:配置作业调度的触发方式(触发器) Quartz的作业触发器有两种,分别是 org.springframework.scheduling.quartz.SimpleTriggerBean org.springframework.scheduling.quartz.CronTriggerBean 第一种SimpleTriggerBean,只支持按照一定频度调用任务,如每隔30分钟运行一次。 配置方式如下: Xml代码 <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> <property name="jobDetail" ref="job2" /> <property name="startDelay" value="0" /><!-- 调度工厂实例化后,经过0秒开始执行调度 --> <property name="repeatInterval" value="2000" /><!-- 每2秒调度一次 --> </bean> 第二种CronTriggerBean,支持到指定时间运行一次,如每天12:00运行一次等。 配置方式如下: Xml代码 <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="job2" /> <!—每天12:00运行一次 --> <property name="cronExpression" value="0 0 12 ?" /> </bean> 以上两种调度方式根据实际情况,任选一种即可。 第四步:配置调度工厂 Xml代码 <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="cronTrigger" /> </list> </property> </bean> 说明:该参数指定的就是之前配置的触发器的名字。 第五步:启动你的应用即可,即将工程部署至tomcat或其他容器。 到此,spring中Quartz的基本配置就介绍完了,当然了,使用之前,要导入相应的spring的包与Quartz的包,这些就不消多说了。 其实可以看出Quartz的配置看上去还是挺复杂的,没有办法,因为Quartz其实是个重量级的工具,如果我们只是想简单的执行几个简单的定时任务,有没有更简单的工具,有! 四、Spring-Task 上节介绍了在Spring 中使用Quartz,本文介绍Spring3.0以后自主开发的定时任务工具,spring task,可以将它比作一个轻量级的Quartz,而且使用起来很简单,除spring相关的包外不需要额外的包,而且支持注解和配置文件两种 形式,下面将分别介绍这两种方式。 第一种:配置文件方式 第一步:编写作业类 即普通的pojo,如下: Java代码 import org.springframework.stereotype.Service; @Service public class TaskJob { public void job1() { System.out.println(“任务进行中。。。”); } } 第二步:在spring配置文件头中添加命名空间及描述 Xml代码 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:task="http://www.springframework.org/schema/task" 。。。。。。 xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"> 第三步:spring配置文件中设置具体的任务 Xml代码 <task:scheduled-tasks> <task:scheduled ref="taskJob" method="job1" cron="0 ?"/> </task:scheduled-tasks> <context:component-scan base-package=" com.gy.mytask " /> 说明:ref参数指定的即任务类,method指定的即需要运行的方法,cron及cronExpression表达式,具体写法这里不介绍了,详情见上篇文章附录。 <context:component-scan base-package="com.gy.mytask" />这个配置不消多说了,spring扫描注解用的。 到这里配置就完成了,是不是很简单。 第二种:使用注解形式 也许我们不想每写一个任务类还要在xml文件中配置下,我们可以使用注解@Scheduled,我们看看源文件中该注解的定义: Java代码 @Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Scheduled { public abstract String cron(); public abstract long fixedDelay(); public abstract long fixedRate(); } 可以看出该注解有三个方法或者叫参数,分别表示的意思是: cron:指定cron表达式 fixedDelay:官方文档解释:An interval-based trigger where the interval is measured from the completion time of the previous task. The time unit value is measured in milliseconds.即表示从上一个任务完成开始到下一个任务开始的间隔,单位是毫秒。 fixedRate:官方文档解释:An interval-based trigger where the interval is measured from the start time of the previous task. The time unit value is measured in milliseconds.即从上一个任务开始到下一个任务开始的间隔,单位是毫秒。 下面我来配置一下。 第一步:编写pojo Java代码 import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component(“taskJob”) public class TaskJob { @Scheduled(cron = "0 0 3 ?") public void job1() { System.out.println(“任务进行中。。。”); } } 第二步:添加task相关的配置: Xml代码 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd" default-lazy-init="false"> <context:annotation-config /> <!—spring扫描注解的配置 --> <context:component-scan base-package="com.gy.mytask" /> <!—开启这个配置,spring才能识别@Scheduled注解 --> <task:annotation-driven scheduler="qbScheduler" mode="proxy"/> <task:scheduler id="qbScheduler" pool-size="10"/> 说明:理论上只需要加上<task:annotation-driven />这句配置就可以了,这些参数都不是必须的。 Ok配置完毕,当然spring task还有很多参数,我就不一一解释了,具体参考xsd文档http://www.springframework.org/schema/task/spring-task-3.0.xsd。 附录: cronExpression的配置说明,具体使用以及参数请百度google 字段 允许值 允许的特殊字符 秒 0-59 , - / 分 0-59 , - / 小时 0-23 , - / 日期 1-31 , - ? / L W C 月份 1-12 或者 JAN-DEC , - / 星期 1-7 或者 SUN-SAT , - ? / L C 年(可选) 留空, 1970-2099 , - / - 区间 通配符 ? 你不想设置那个字段 下面只例出几个式子 CRON表达式 含义 "0 0 12 ?" 每天中午十二点触发 "0 15 10 ? " 每天早上10:15触发 "0 15 10 ?" 每天早上10:15触发 "0 15 10 ? " 每天早上10:15触发 "0 15 10 ? 2005" 2005年的每天早上10:15触发 "0 14 ?" 每天从下午2点开始到2点59分每分钟一次触发 "0 0/5 14 ?" 每天从下午2点开始到2:55分结束每5分钟一次触发 "0 0/5 14,18 ?" 每天的下午2点至2:55和6点至6点55分两个时间段内每5分钟一次触发 "0 0-5 14 ?" 每天14:00至14:05每分钟一次触发 "0 10,44 14 ? 3 WED" 三月的每周三的14:10和14:44触发 "0 15 10 ? MON-FRI" 每个周一、周二、周三、周四、周五的10:15触发 Cron 表达式包括以下 7 个字段: 秒 分 小时 月内日期 月 周内日期 年(可选字段) 特殊字符 Cron 触发器利用一系列特殊字符,如下所示: 反斜线(/)字符表示增量值。例如,在秒字段中“5/15”代表从第 5 秒开始,每 15 秒一次。 问号(?)字符和字母 L 字符只有在月内日期和周内日期字段中可用。问号表示这个字段不包含具体值。所以,如果指定月内日期,可以在周内日期字段中插入“?”,表示周内日期值无关紧要。字母 L 字符是 last 的缩写。放在月内日期字段中,表示安排在当月最后一天执行。在周内日期字段中,如果“L”单独存在,就等于“7”,否则代表当月内周内日期的最后一个实例。所以“0L”表示安排在当月的最后一个星期日执行。 在月内日期字段中的字母(W)字符把执行安排在最靠近指定值的工作日。把“1W”放在月内日期字段中,表示把执行安排在当月的第一个工作日内。 井号()字符为给定月份指定具体的工作日实例。把“MON2”放在周内日期字段中,表示把任务安排在当月的第二个星期一。 星号()字符是通配字符,表示该字段可以接受任何可能的值。 字段 允许值 允许的特殊字符 秒 0-59 , - / 分 0-59 , - / 小时 0-23 , - / 日期 1-31 , - ? / L W C 月份 1-12 或者 JAN-DEC , - / 星期 1-7 或者 SUN-SAT , - ? / L C 年(可选) 留空, 1970-2099 , - / 表达式意义 "0 0 12 ?" 每天中午12点触发 "0 15 10 ? " 每天上午10:15触发 "0 15 10 ?" 每天上午10:15触发 "0 15 10 ? " 每天上午10:15触发 "0 15 10 ? 2005" 2005年的每天上午10:15触发 "0 14 ?" 在每天下午2点到下午2:59期间的每1分钟触发 "0 0/5 14 ?" 在每天下午2点到下午2:55期间的每5分钟触发 "0 0/5 14,18 ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发 "0 0-5 14 ?" 在每天下午2点到下午2:05期间的每1分钟触发 "0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44触发 "0 15 10 ? MON-FRI" 周一至周五的上午10:15触发 "0 15 10 15 ?" 每月15日上午10:15触发 "0 15 10 L ?" 每月最后一日的上午10:15触发 "0 15 10 ? 6L" 每月的最后一个星期五上午10:15触发 "0 15 10 ? 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15触发 "0 15 10 ? 63" 每月的第三个星期五上午10:15触发 每天早上6点 0 6 每两个小时 0 /2 晚上11点到早上8点之间每两个小时,早上八点 0 23-7/2,8 每个月的4号和每个礼拜的礼拜一到礼拜三的早上11点 0 11 4 1-3 1月1日早上4点 0 4 1 1 本篇文章为转载内容。原文链接:https://zhanghaiyang.blog.csdn.net/article/details/51397459。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-10-27 18:50:19
344
转载
转载文章
...(老方案是,屏幕越大元素越大;此方案是,屏幕越大,看的越多) 有效解决移动端真实1px问题(这里的1px 是设备屏幕上的物理像素) 如何使用 重要的事情说三遍! 绝不是每个地方都要用rem,rem只适用于固定尺寸! 绝不是每个地方都要用rem,rem只适用于固定尺寸! 绝不是每个地方都要用rem,rem只适用于固定尺寸! 在相当数量的布局情境中(比如底部导航元素平分屏幕宽,大尺寸元素),你必须使用百分比或者flex才能完美布局! 看过 《手机端页面自适应解决方案—rem布局》的朋友,应该对rem有所了解,这里不再赘述, 此方案也是默认 1rem = 100px,所以你布局的时候,完全可以按照设计师给你的效果图写各种尺寸啦。 比如你在效果图上量取的某个按钮元素长 55px, 宽37px ,那你直接可以这样写样式: .myBtn {width: 0.55rem;height: 0.37rem;} rem布局(进阶版)实践应用 iPhone5 下页面效果.png iPhone 6 Plus 下页面效果.png 为了让朋友们更清晰感受此方案的巨大优势,下面是源码和Demo 实践应用1(请在手机端或者手机模式下浏览效果更佳!) 实践应用2(请在手机端或者手机模式下浏览效果更佳!) 线上项目(请在手机端或者手机模式下浏览效果更佳!) 示例源码 在线Demo 常见问题说明,新手很有必要看一下(2017/1/19) 许多同学对该方案存在不少误解导致使用出现各种问题,这里统一回复下。 1.问:为啥手机网页效果图宽度是要640或者750的,我非得弄个666的不行咩? 答:老实说当然可以,不过为了规范,640或者750是相对合适的。 拿Iphone 5s 举例,它的css像素宽度是320px,由于它的dpr=2,所以它的物理像素宽度为320 × 2 = 640px,这也就是为什么,你在5s上截了一张图,在电脑上打开,它的原始宽度是640px的原因。 那 iphone 6 的截图宽度呢? 375 × 2 = 750 那 iphone 6 sp 的截图宽度呢? 414 × 3 = 1242 以此类推,你现在能明白效果图为什么一般是 640 ,750 甚至是 1242 的原因了么?(真没有歧视安卓机的意思。。。) 2.问:宽度用rem写的情况下, 在 iphone6 上没问题, 在 iphone5上会有横向滚动条,何解? 答:假设你的效果图宽度是750,在这个效果图上可能有一个宽度为7rem(高清方案默认 1rem = 100px)的元素。我们知道,高清方案的特点就是几乎完美还原效果图,也就是说,你写了一个宽度为 7rem 的元素,那么在目前主流移动设备上都是7rem。然而,iphone 5 的宽度为640,也就是6.4rem。于是横向滚动条不可避免的出现了。 怎么办呢? 这是我目前推荐的比较安全的方式:如果元素的宽度超过效果图宽度的一半(效果图宽为640或750),果断使用百分比宽度,或者flex布局。就像把等屏宽的图片宽度设为100%一样。 3.问:不是 1rem = 100px吗,为什么我的代码写了一个宽度为3rem的元素,在电脑端的谷歌浏览器上宽度只有150px? 答:先说高清方案代码,再次强调咱们的高清方案代码是根据设备的dpr动态设置html 的 font-size, 如果dpr=1(如电脑端),则html的font-size为50px,此时 1rem = 50px 如果dpr=2(如iphone 5 和 6),则html的font-size为100px,此时 1rem = 100px 如果dpr=3(如iphone 6 sp),则html的font-size为150px,此时 1rem = 150px 如果dpr为其他值,即便不是整数,如3.4 , 也是一样直接将dpr 乘以 50 。 再来说说效果图,一般来讲,我们的效果图宽度要么是640,要么是750,无论哪一个,它们对应设备的dpr=2,此时,1 rem = 50 × 2 = 100px。这也就是为什么高清方案默认1rem = 100px。而将1rem默认100px也是好处多多,可以帮你快速换算单位,比如在750宽度下的效果图,某元素宽度为53px,那么css宽度直接设为53/100=0.53rem了。 然而极少情况下,有设计师将效果图宽定为1242px,因为他手里只有一个iphone 6 sp (dpr = 3),设计完效果图刚好可以在他的iphone 6 sp里查看调整。一切完毕之后,他将这个效果图交给你来切图。由于这个效果图对应设备的dpr=3,也就是1rem = 50 × 3 = 150px。所以如果你量取了一个宽度为90px的元素,它的css宽度应该为 90/150=0.6rem。由于咱们的高清方案默认1rem=100px,为了还原效果图,你需要这样换算。当然,一个技巧就是你可以直接修改咱们的高清方案的默认设置。在代码的最后 你会看到 flex(false, 100, 1) ,将其修改成flex(false, 66.66667, 1)(感谢简友:V旅行指出此处错误! 2017/3/24)就不用那么麻烦的换算了,此时那个90px的直接写成0.9rem就可以了。 4.问:在此方案下,我如果引用了别的UI库,那些UI库的元素会显得特别小,如何解决? 答:可以这样去理解问题的原因,如果不用高清方案,别的UI库的元素在移动设备上(假设这个设备是iphone 5好了)显示是正常的,这没有问题,然后我们在这个设备上将该页面截图放到电脑上看,发现宽度是640(问答1解释过了),根据你的像素眼大致测量,你发现这个设备上的某个字体大小应该是12px,而你在电脑上测量应该是24px。 现在我们使用高清方案去还原这个页面,那么字体大小应该写为 0.24rem 才对! 所以,如果你引用了其他的UI库,为了兼容高清方案,你需要对该UI库里凡是应用px的地方做相应处理,即: a px => a0.02 rem (具体处理方式因人而异,有模块化开发经验的同学可使用类似的 px2rem 的插件去转化,也可以完全手动处理) (2017/9/9更新)然而真实情况往往更为复杂,比如,你引入了百度地图(N个样式需要处理转换);或者你引入了一个 framework;又或者你使用了 video 标签,上面默认的尺寸样式很难处理。等等这些棘手问题 面对这些情况,此时我们的高清方案如果不再压缩页面,那么以上问题将迎刃而解。 基于这样的思路,笔者对高清方案的源码做了如下修改,即添加一个叫做 normal 的参数,由它来控制页面是否压缩。 在文章顶部代码的最后,你会看到 flex(false, 100, 1),默认情况下页面是开启压缩的。 如果你需要禁止压缩,由于我们的源码执行后,直接将flex函数挂载到全局变量window上了,此时你直接在需要禁止压缩的页面执行 window.flex(true) 就可以了,而rem的用法保持不变。 有一点美中不足的是,如果禁止了页面压缩,高清屏的1像素就不能实现了,如果你必须要实现1像素,那么自行谷歌:css 0.5像素,有N多的解决方案,这里不再赘述。 5.问:有时候字体会不受控制的变大,怎么办? 答:在X5新内核Blink中,在排版页面的时候,会主动对字体进行放大,会检测页面中的主字体,当某一块字体在我们的判定规则中,认为字号较小,并且是页面中的主要字体,就会采取主动放大的操作。然而这不是我们想要的,可以采取给最大高度解决 解决方案: , :before, :after { max-height: 100000px } 补充:有同学反映,在一些情况下 textarea 标签内的字体大小即便加上上面的方案,字体也会变大,无法控制。此时你需要给 textarea 的 display 设为 table 或者 inline-table 即可恢复正常。(感谢 程序媛喵喵 对此的补充!2017/7/7) 6.问:我在底部导航用的flex感觉更合适一些,请问这样子混着用可以吗? 答:咱们的rem适合写固定尺寸。其余的根据需要换成flex或者百分比。源码示例中就有这三种的综合运用。 7.问:在高清方案下,一个标准的,较为理想的宽度为640的页面效果图应该是怎样的? 点击浏览:一个标准的640手机页面设计稿参考(没错,在此方案中,你可以完全按照这张设计稿的尺寸写布局了。就是这么简单!) 8.问:用了这个方案如何使用媒体查询呢? 一般来讲,使用了这个方案是没必要用媒体查询了,如果你必须要用,假设你要对 iphone5 (css像素宽度320px, 这里需要取其物理像素,也就是640)宽度下的类名做处理,你可以这样 @media screen and (max-width: 640px) {.yourLayout {width:100%;} } 9.问:可以提供下这个高清方案的源码吗? 'use strict';/ @param {Boolean} [normal = false] - 默认开启页面压缩以使页面高清; @param {Number} [baseFontSize = 100] - 基础fontSize, 默认100px; @param {Number} [fontscale = 1] - 有的业务希望能放大一定比例的字体;/const win = window;export default win.flex = (normal, baseFontSize, fontscale) => {const _baseFontSize = baseFontSize || 100;const _fontscale = fontscale || 1;const doc = win.document;const ua = navigator.userAgent;const matches = ua.match(/Android[\S\s]+AppleWebkit\/(\d{3})/i);const UCversion = ua.match(/U3\/((\d+|\.){5,})/i);const isUCHd = UCversion && parseInt(UCversion[1].split('.').join(''), 10) >= 80;const isIos = navigator.appVersion.match(/(iphone|ipad|ipod)/gi);let dpr = win.devicePixelRatio || 1;if (!isIos && !(matches && matches[1] > 534) && !isUCHd) {// 如果非iOS, 非Android4.3以上, 非UC内核, 就不执行高清, dpr设为1;dpr = 1;}const scale = normal ? 1 : 1 / dpr;let metaEl = doc.querySelector('meta[name="viewport"]');if (!metaEl) {metaEl = doc.createElement('meta');metaEl.setAttribute('name', 'viewport');doc.head.appendChild(metaEl);}metaEl.setAttribute('content', width=device-width,user-scalable=no,initial-scale=${scale},maximum-scale=${scale},minimum-scale=${scale});doc.documentElement.style.fontSize = normal ? '50px' : ${_baseFontSize / 2 dpr _fontscale}px;}; 10.问:我在使用 rem 布局进阶方案的时候遇到了XXX的问题,如何解决? 此方案久经考验,具有普遍适用性,自身出致命问题的情况很少,至少笔者是没遇到过。 绝大多数你遇到的问题,都是由于对rem布局理解不到位导致的。本文对rem布局做了大量的解释说明,配置了若干 demo,你可以把你遇到的问题放到demo里测试。遇到问题时,首先问自己,为什么这明显的错误大家没遇到就我遇到了?? 如果你真的经过充分验证,比对,确实是rem布局自身出了问题,那么请私信我,把还原问题场景的 demo 或者文件发给我。谢谢! 本篇文章为转载内容。原文链接:https://blog.csdn.net/hjhfreshman/article/details/88864894。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-03-23 12:01:53
133
转载
转载文章
...以说蕴含着一种深入的技巧在其中。 下面我来举一个例子。 首先我们来回顾一下软件生命周期中各个阶段的成本消耗占比。以下是来一个知名统计机构的分析报告。我们可以看到占比最大的是维护部分,对于这一部分的简化将最具有全局意义。 我曾经开发过一个设备管理系统,移动运营商通过这个系统来管理移动设备,实现包括设备的自动注册、固件和软件的同步等管理功能。这些功能是通过一些管理系统与移动设备间的预定义的交互协议来完成的。 电信专家们会根据业务场景及需求来调整和新增这些交互协议。起初我们采用了一种容易实现的方式,即团队中的软件工程会根据电信专家的说明,将协议实现为对应代码。 之后我们很快发现这样的方式,让我们的工作变得没那么简单。 “I believe that the hardest part of software projects, the most common source of project failure, is communication with the customers and users of that software.” –Martin Fowler 正如软件开发大师 MartinFowler 提到的,“沟通”往往是导致软件项目失败的主要原因。前面这个项目最大的问题是在系统上线后的运行维护阶段,电信专家和开发工程师之间会不断就新的协议修改和增加进行持续的沟通,而他们的领域知识和词汇都有很大的差别,这会大大影响沟通的效率。因此这期间系统的运行维护(协议的修改)变得十分艰难,不仅协议更新上线时间慢,而且由于软件工程对于电信协议理解程度有限,很多问题都要在实际上线使用后才能被电信专家发现,导致了很多的交换和反复。 针对上面提到的问题,后来我们和电信专家一起设计了一种协议设计语言(并提供可视化的工具),这种设计语言使用的电信专家所熟悉的词汇。然后通过一个类似于编译器的程序将电信专家定义好的协议模型转换为内存中的 Java 结构。这样整个项目的运行和维护就变得简单高效了,省去了低效的交流和不准确人工转换。 我们可以看到一开始按电信专家的说明直接实现协议是更为容易的办法,但就整个软件生命周期来看却并不是一个简单高效的方法。 永远不要停止编码 架构师也是程序员,代码是软件的最终实现形态,停止编程会逐渐让你忘记作为程序员的感受,更重要的是忘记其中的“痛”,从而容易产生一些不切实际的设计。 大家可能听说过在 Amazon,高级副总裁级别的 Distinguish Engineer(如:James Gosling,Java 之父),他们每年的编码量也非常大,常在 10 万行以上。 风险优先 架构设计很重要的一点是识别可能存在的风险,尤其是非功能性需求实现的风险。因为这些风险往往没有功能性需求这么容易在初期被发现,但修正的代价通常要比修正功能性需求大非常多,甚至可能导致项目的失败,前面我们也提到了非功能性需求决定了架构,如数据一致性要求、响应延迟要求等。 我们应该通过原型或在早期的迭代中确认风险能够通过合理的架构得以解决。 绝对不要把风险放到最后,就算是一个项目要失败也要让它快速失败,这也是一种敏捷。 从“问题”开始,而不是“技术” 技术人员对于新技术的都有着一种与身俱来的激情,总是乐于去学习新技术,同时也更有激情去使用新技术。但是这也同样容易导致一个通病,就是“当我们有一个锤子的时候看什么都是钉子”,使用一些不适合的技术去解决手边的问题,常常会导致简单问题复杂化。 我曾经的一个团队维护过这样一个简单的服务,起初就是一个用 MySQL 作数据存储的简单服务,由团队的一个成员来开发和维护。后来,这位成员对当时新出的 DynamoDB 产生了兴趣,并学习了相关知识。 然后就发生下面这样的事: 用DynamoDB替换了MySQL。 很快发现DynamoDB并不能很好的支持事务特性,在当时只有一个性能极差的客户端类库来支持事物,由于采用客户端方式,引入了大量的额外交互,导致性能差别达7倍之多。这时候,这个同学就采用了当时在NoSQL领域广泛流行的最终一致技术,通过一个Pub-Sub消息队列来实现最终一致(即当某对象的值发生改变后会产生一个事件,然后关注这一改变的逻辑,就会订阅这个通知,并改变于其相关数据,从而实现不同数据的最终一致)。 接着由于DynamoDB无法提供SQL那样方便的查询机制,为了实现数据分析就又引入了EMR/MapReduceJob。 到此,大家可以看到实现一样的功能,但是复杂性大大增加,维护工作也由一个人变成了一个团队。 过度忙碌使你落后 对于 IT 人而言忙碌已成为了习惯,加班常挂在嘴边。“996”工作制似乎也变成了公司高效的标志。而事实上过度的忙碌使你落后。经常遇见一些朋友,在一个公司没日没夜的干了几年,没有留一点学习时间给自己。几年之后倒是对公司越来越“忠诚”了,但忙碌的工作同时也导致了没有时间更新知识,使得自己已经落后了,连跳槽的能力和勇气都失去了。 过度忙碌会导致没有时间学习和更新自己的知识,尤其在这个高速发展的时代。我在工作经历中发现过度繁忙通常会带来以下问题: 缺乏学习导致工作能力没有提升,而面对的问题却变得日益复杂。 技术和业务上没有更大的领先优势,只能被动紧紧追赶。试想一下,要是你都领先同行业五年了,还会在乎通过加班来早一个月发布吗? 反过来上面这些问题会导致你更加繁忙,进而更没有时间提高自己的技术技能,很快就形成了一个恶性循环。 练过健身的朋友都知道,光靠锻炼是不行的,营养补充和锻炼同样重要。个人技术成长其实也一样,实践和学习是一样重要的,当你在一个领域工作了一段时间以后,工作对你而言就主要是实践了,随着你对该领域的熟悉,能学习的到技术会越来越少。所以每个技术人员都要保证充足的学习时间,否则很容易成为井底之蛙,从而陷入前面提到的恶性循环。 最后,以伟大诗人屈原的诗句和大家共勉:“路漫漫其修远兮,吾将上下而求索“。希望我们大家都可以不忘初心,保持匠心! 作者简介: 蔡超,Mobvista 技术 VP 兼首席架构师,SpotMax 云服务创始人。拥有超过 15 年的软件开发经验,其中 9 年任世界级 IT 公司软件架构师/首席软件架构师。2017 年加入 Mobvista,任公司技术副总裁及首席架构师,领导公司的数字移动营销平台的开发,该平台完全建立于云计算技术之上,每天处理来自全球不同 region 的超过 600 亿次的请求。 在加入 Mobvista 之前,曾任亚马逊全球直运平台首席架构师,亚马逊(中国)首席架构师,曾领导了亚马逊的全球直运平台的开发,并领导中国团队通过 AI 及云计算技术为中国客户打造更好的本地体验;曾任 HP(中国)移动设备管理系统首席软件架构师,该系统曾是全球最大的无线设备管理系统(OMA DM)(客户包括中国移动,中国联通,中国电信等);曾任北京天融信网络安全技术公司,首席软件架构师,领导开发的网络安全管理系统(TopAnalyzer)至今仍被政府重要部门及军队广为采用,该系统也曾成功应用于 2008 北京奥运,2010 上海世博等重要事件的网络安全防护。 本篇文章为转载内容。原文链接:https://blog.csdn.net/Honnyee/article/details/111896981。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-09-19 14:55:26
78
转载
转载文章
...愈发关键。近期,随着容器化技术和微服务架构的广泛应用,内存映射机制对于提高系统资源利用率、实现高效的数据共享与交换具有重要意义。 例如,在Docker和Kubernetes等容器平台中,mmap系统调用被用于实现容器内部进程与宿主机文件系统的高效交互,以及容器间共享内存通信。通过内存映射,容器可以将宿主机上的持久化存储直接加载到内存中,实现数据的快速读取与更新,极大地提升了I/O性能。 此外,针对云原生环境下的大规模并行计算和实时数据处理场景,研究者们正在探索如何优化mmap以适应更高的并发需求和更低延迟的要求。2021年,有研究人员提出了一种改进的内存映射策略,旨在减少在高负载环境下由于频繁的内存映射操作导致的系统开销,并已在分布式数据库和大数据分析应用中取得了显著效果。 同时,内存映射的安全性问题也引起了业界的关注。今年早些时候,一项安全研究报告揭示了利用mmap进行提权攻击的新方法,再次提醒开发者在享受内存映射带来的便利时,也需要关注其潜在的安全风险,并采取相应的防御措施。 总之,内存映射作为底层系统调用的重要组成部分,其发展与优化将持续影响着整个软件生态系统的性能表现与安全性,值得广大开发者和技术研究者深入探究和实践。
2023-09-20 22:49:12
464
转载
转载文章
...面对异常情况时能够更高效地释放资源,从而提升了程序的健壮性和稳定性。此外,.NET 6引入了一个名为“Global Exception Filters”的新特性,允许开发者在应用程序级别定义统一的异常筛选和处理逻辑,这为全局异常处理提供了更加灵活和强大的工具。 同时,针对自定义异常类的设计原则,社区专家建议遵循SOLID设计原则,确保异常类具备良好的可扩展性和易用性。例如,通过实现Exception基类并提供丰富的上下文信息,可以帮助开发团队和API用户更快定位问题根源,进而提升软件质量及维护效率。 另外,关于何时抛出或捕获异常的讨论也在持续进行中。有文章深度剖析了《Effective C》一书中提出的异常使用准则,并结合实际案例分析了过度使用异常可能导致的性能损耗和代码可读性下降等问题。因此,提倡在编写代码时采用防御性编程策略,如预先检查参数的有效性、合理运用Try-Parse等方法,以减少不必要的异常抛出。 综上所述,随着.NET技术的发展和业界最佳实践的不断演进,深入学习和掌握最新的异常处理技巧,将有助于我们在日常开发工作中构建更为稳定、高效的软件系统。
2023-04-13 13:38:26
59
转载
转载文章
...DOM 树 二.获取元素的方法 1.根据ID获取 2.根据标签名获取 3.通过 HTML5 新增的方法获取(注意兼容) 4.获取特殊元素(body,html) 三.事件基础 1.事件概述 2.执行事件的步骤 3.常见的鼠标事件 四.操作元素 1.操作元素内容(改变元素内容) 2. 操作常见元素属性 3.操作表单元素属性 4.操作元素样式属性 5.自定义属性的操作 6.H5自定义属性 五.节点操作 1.为什么要学习节点操作 2.节点概述 3.节点层级 一.DOM简介 1.什么是DOM 文档对象模型(简称DOM) 是W3C组织推荐的处理可扩展标记语言的标准编程接口 W3C已经定义来一系列DOM接口,通过这些DOM接口可以改变网页的内容、结构样式。 2.DOM 树 文档:一个页面就是一个文档,DOM 中使用 document 表示 元素:页面中的所有标签都是元素,DOM 中使用 element 表示 节点:网页中的所有内容都是节点(标签、属性、文本、注释等),DOM 中使用 node 表示 文档树(Dom树):以html为根节点,形成的一颗倒立的树状结构,我们成为DOM树;这个树上所有的东西都叫节点,节点有很多类,比如文本节点,元素节点等等,这些节点如果我们通过DOM方法去获取或者其他的操作去使用就叫做DOM对象,所有节点都是DOM对象 二.获取元素的方法 1.获取页面中的元素可以使用以下几种方式 根据ID获取 根据标签名获取 通过HTML5新增的方法获取 特殊元素获取 1.根据ID获取 使用getElementByld()方法可以获取带有ID的元素对象 getElementByld(),是document下的一个方法 代码演示 <body><div id="time">2020-11-26</div><script>// 1.因为我们文档页面从上往下加载,所以先得有标签 所以我们的script写在标签下面// 2. document文档 get 获得 element 元素 by 通过 驼峰命名法// 3.参数 id是大小写敏感的字符串// 4.返回的是一个对象var timer = document.getElementById('time');console.log(timer);// 5.console.dir 打印我们返回得的元素对象 更好的查看里面的属性和方法console.dir(timer);</script></body> 2.根据标签名获取 使用getElementsByTagName()方法可以返回带有指定标签名的对象的集合 语法如下 document.getElementsByTagName('标签名') 注意: 1.因为得到的是一个对象的集合,使用我们想要操作里面的元素就需要遍历 得到元素对象是动态的 代码演示 <body><ul><li>我们的征程是星辰大海</li><li>我们的征程是星辰大海</li><li>我们的征程是星辰大海</li><li>我们的征程是星辰大海</li><li>我们的征程是星辰大海</li></ul><ul id="nav"><li>心存感恩,所遇皆美好~</li><li>心存感恩,所遇皆美好~</li><li>心存感恩,所遇皆美好~</li><li>心存感恩,所遇皆美好~</li><li>心存感恩,所遇皆美好~</li></ul><script>// 1.返回的是 获取过来元素对象的集合 以伪数组的形式存储的var lis = document.getElementsByTagName('li')console.log(lis);// 2.如果想要依次打印里面的元素对象我们可以采取遍历方式for (var i = 0; i < lis.length; i++) {console.log(lis[i]);}// 3.这里可以是可以获取标签的.getElementsByTagName()可以得到这个元素里面的某些标签var nav1 = document.getElementById('nav') //这个获取nav元素var navli = nav.getElementsByTagName('li') //这里是获取nav 里面的li标签 要先获取 nav元素在获取里面的liconsole.log(navli);</script></body> 3.通过 HTML5 新增的方法获取(注意兼容) 1. document.getElementsByClassName(‘类名’);// 根据类名返回元素对象集合 2. document.querySelector('选择器'); // 根据指定选择器返回第一个元素对象 3. document.querySelectorAll('选择器'); // 根据指定选择器返回所有元素对象集合 注意:querySelector 和 querySelectorAll里面的选择器需要加符号,比如:document.querySelector(’nav’); 代码演示 <body><div class="box">盒子1</div><div class="box">盒子2</div><div id="nav"><ul><li>首页</li><li>产品</li></ul></div><script>// 1. getElementsByClassName 根据类名获得某些元素集合var boxs = document.getElementsByClassName('box');console.log(boxs);// 2. querySelector 返回指定选择器的第一个元素对象 切记 里面的选择器需要加符号 .box navvar firstBox = document.querySelector('.box');console.log(firstBox);var nav = document.querySelector('nav');console.log(nav);var li = document.querySelector('li');console.log(li);// 3. querySelectorAll()返回指定选择器的所有元素对象集合var allBox = document.querySelectorAll('.box');console.log(allBox);var lis = document.querySelectorAll('li');console.log(lis);</script> 4.获取特殊元素(body,html) 获取body元素 - doucumnet.body // 返回body元素对象 获取html元素 . document.documentElement // 返回html元素对象 代码演示 <body><script>// 获取bdoy元素var bodyEle = document.bodyconsole.log(bodyEle); //返回body元素// 获取html元素var htmlEle = document.documentElementconsole.log(htmlEle); //返回html元素</script></body> 三.事件基础 1.事件概述 JavaScript 使我们有能力创建动态页面,而事件是可以被 JavaScript 侦测到的行为。 简单理解: 触发— 响应机制。 网页中的每个元素都可以产生某些可以触发 JavaScript 的事件,例如,我们可以在用户点击某按钮时产生一个 事件,然后去执行某些操作。 代码演示 <body><button id="btn">浩哥</button><script>// 点击一个按钮,弹出一个对话框// 1.事件是有三部分组成的 1.事件源 2.事件类型 3.事件处理程序 也称为事件三要素// (1).事件源 事件被触发的对象 var but = document.getElementById('btn')// (2).事件类型 如何触发 什么事件 比如鼠标点击(onclick) 还是鼠标经过还是????// (3).事件处理程序 通过一个函数赋值的方式 完成 因为函数就是实现某种功能的but.onclick = function() {alert('浩哥爱编程')}</script></body> 2.执行事件的步骤 1. 获取事件源DOM对象(意思是你要获取那个元素) 2. 注册事件(绑定事件 意思是通过什么方式来处理比如是鼠标经过还是鼠标点击等等行为) 3. 添加事件处理程序(采取函数赋值形式 意思是你想做啥) 代码演示 <body><div>123</div><script>// 事件执行步骤 点击div 控制台输出我被选中了// 1.获取事件源var div = document.querySelector('div')// 2.绑定事件 注册事件// div.onclick// 3.添加事件处理程序div.onclick = function() {console.log('我被点击了');}</script></body> 3.常见的鼠标事件 onmouseenter鼠标移入事件 onmouseleave鼠标移出事件 四.操作元素 JS的DOM操作可以改变网页内容、结构和样式,利用DOM操作元素来改变元素里面的内容、属性等。注意以下都是属性 1.操作元素内容(改变元素内容) elemeny.innerText 从起始位置到终止位置的内容,但它去除html标签,同时空格和换行也会去掉 elemernt.innerHTML 起始位置到终止位置的全部内容,包括html标签,同时保留空格和换行 elemernt.Content可以获取隐藏元素的文本,包含换行和空白 代码演示 <title>Document</title><style>div,p {height: 30px;width: 300px;line-height: 30px;text-align: center;color: fff;background-color: pink;}</style></head><body><button>显示当前系统时间</button><div>某个时间</div><p>123</p><script>// 当我们点击了按钮,div里面的文字会发生变化// 1.获取元素 注意这里的按钮 和div都要获取到 因为 点击按钮div里面要发生变化所以都要获取var but = document.querySelector('button');var div = document.querySelector('div');// 2.绑定事件// but.onclick// 3.程序处理but.onclick = function() {// 改变元素内容 element(元素).innerTextdiv.innerText = '2020-11-27'}// 4.我们元素可以不用添加事件,就可以直接显示日期var p = document.querySelector('p');p.innerText = '2020-11-27';</script> elemeny.innerText和elemeny.innerHTML的区别 代码演示 <body><div></div><p></p><ul><li> 文字</li><li>123</li></ul><script>// innertText 和 innertHTML 的区别// 1. innerText 不识别html标签 非标准 去除空格和换行var div = document.querySelector('div');div.innerText = '<strong>今天是:</strong> 2020';// 2.innertHTML 识别html标签 W3C标准 保留空格和换行的 推荐尽量使用这个 因为这个是标准var p = document.querySelector('p')p.innerHTML = '<strong>今天是:</strong> 2020';// 3.这俩个属性是可读写的 意思是 除了改变内容还可以元素读取里面的内容的var ul = document.querySelector('ul')console.log(ul.innerText);console.log(ul.innerHTML);// .4innerHtml innerText 之间的区别:设置内容的时候,如果内容当中包含标签字符串 innerHtml会有标签的特性,也就是说标签会在页面上生效如果内容当中包含标签字符串 innerText会把标签原样展示在页面上,不会让标签生效读取内容的时候,如果标签内部还有其它标签,innerHtml会把标签内部带着其它的标签全部输出如果标签内部还有其它标签,innerText只会输出所有标签里面的内容或者文本,不会输出标签如果标签内部没有其它标签,他们两个一致;都是读取文本内容,innerHtml会带空白和换行</script></body> 2. 操作常见元素属性 innerText、innerHTML 改变元素内容 src、href id、alt、title 代码演示 <body><button id="ldh">刘德华</button><button id="zxy">张学友</button><br><img src="./images/ldh.jpg" alt="" width="200px" height="200px" title="刘德华" id="img"><script>// 修改属性 src// 我们可以操作元素得方法 来修改元素得属性 就是 元素的是什么属性 在重新给值就可以完成相应的赋值操作了// 1.获取元素var ldh = document.getElementById('ldh')var zxy = document.getElementById('zxy')var img = document.getElementById('img')// 2.注册事件 程序处理zxy.onclick = function() {// 当我们点击了图片的时候图片路径就发生变化 这里的.表示 的 得意思 img对象下的src属性img.src = './images/zxy.jpg';// 当我们变换图片得同时里面得title也要跟着变 所以前面要加上img.img.title = '张学友';}ldh.onclick = function() {img.src = './images/ldh.jpg';img.title = '刘德华';}</script> 3.操作表单元素属性 利用DOM可以操作如下表单元素的属性 type、value、checked、selected、disabled 代码演示: <body><button>按钮</button><input type="text" value="输入内容"><script>// 我想把value里面的输入内容改变为 被点击了// 1.获取元素var but = document.querySelector('button')var input = document.querySelector('input')// 2.注册事件 处理程序but.onclick = function() {// input.innerHTML = '被点击了'; 这个是 普通盒子 比如 div 标签里面的内容// 表单里面的值 文字内容是通过value来修改的input.value = '被点击了'// 如果需要某个表单被禁用 不能再点击了使用 disabled 我们想要这个按钮 button禁用// but.disabled = true// 还有一种写法// this指向的是事件函数的调用者 谁调用就指向谁 这里调用者是btnthis.disabled = true}</script></body> 4.操作元素样式属性 我们可以通过 JS 修改元素的大小、颜色、位置等样式。 1.element.style 行内样式操作 注意: JS 里面的样式采取驼峰命名法 比如 fontSize、 backgroundColor JS 修改 style 样式操作,产生的是行内样式,所以行内式比内嵌式高 代码演示 <style>div {width: 200px;height: 200px;background-color: red;}</style></head><body><div></div><script>// 要求点击div变成粉色 height变为250px// 1.获取元素var div = document.querySelector('div');// 2.注册事件 处理程序div.onclick = function() {// div.style里面的属性 采取的是驼峰命名法// this等于div this调用者 谁调用谁执行this.style.backgroundColor = 'pink'this.style.height = '250px'}</script> 2.element.className 类名样式操作 注意: 如果样式修改较多,可以采取操作类名方式更改元素样式。 class因为是个保留字,因此使用className来操作元素类名属性 className 会直接更改元素的类名,会覆盖原先的类名。 代码演示 <style>div {width: 100px;height: 100px;background-color: pink;}.change {background-color: purple;color: fff;font-size: 25px;margin-top: 100px;}</style></head><body><div class="first">文本</div><script>// 1. 使用 element.style 获得修改元素样式 如果样式比较少 或者 功能简单的情况下使用var test = document.querySelector('div');test.onclick = function() {// this.style.backgroundColor = 'purple';// this.style.color = 'fff';// this.style.fontSize = '25px';// this.style.marginTop = '100px';// 让我们当前元素的类名改为了 change// 2. 我们可以通过 修改元素的className更改元素的样式 适合于样式较多或者功能复杂的情况 如果想继续添加样式即在change添加即可// 3. 如果想要保留原先的类名,我们可以这么做 多类名选择器// this.className = 'change';this.className = 'first change';}</script> 5.自定义属性的操作 js给我们规定了可以自己添加属性 在操作元素属性的时候,元素.语法只能操作元素天生具有的属性,如果是自定义的属性,通过.语法是无法操作的只能通过getAttribute和setAttribute去操作,他俩是通用的方法,无论元素天生的还是自定义的都可以可以操作 1.获取属性值 element.属性 获取属性值。 element.getAttribute(‘属性’); 区别: element.属性 获取内置属性值(元素本身自带的属性 如果是自定义属性不能被获取) element.getAttribute(‘属性’);主要获得自定义的属性 (标准) 我们自定义的属性 2.设置属性值 element.属性 = ‘值’ 设置内置属性值 element.setAttribute(‘属性’,‘值’) 区别: element.属性 设置内置属性值 element.setAttribute(‘属性’);主要设置自定义的属性(标准) 3.移除属性 element.removeAttribute(‘属性’); 代码演示 <body><div id="demo" index="1" class="nav"></div><script>var div = document.querySelector('div');// 1.获取元素的属性值// (1) element.属性console.log(div.id);// (2) element.getAttribute('属性') get获取得到 attribute属性的意思 我们自己添加的属性称之为自定义属性console.log(div.getAttribute('id')); //democonsole.log(div.getAttribute('index')); // 1// 2.设置元素的属性值// (1) element.属性 = '值' div.id = 'test'div.className = 'navs'// (2) element.setAttribute('属性','值')div.setAttribute('index', 2);div.setAttribute('class', 'footer') //这里就是class 不是className 比较特殊// 3.移除属性 removeAttribute(属性)div.removeAttribute('index');</script></body> 只要是自定义属性最好都是用element.setAttribute(‘属性’,‘值’)来设置 如果是自带属性用element.属性来设置 6.H5自定义属性 自定义属性的目的:第一、是为了保存属性 第二、并且使用数据。有一些数据可以保存到页面中而不用保存到数据库中。 自定义属性获取是通过getAttribute(‘属性’) 获取的 但是有些自定义属性很容易引起歧义,不容易判断是元素还是自定义属性 H5给我们新增了自定义属性: 1.设置H5自定义属性 H5规定自定义属性data-开头做为属性名并且赋值 比如<div data-index:“1”> 或者使用JS设置element.setAttribute(‘deta-index’,2) 2.获取H5自定义属性 兼容性获取 element.getAttribute(‘data-index’) 推荐开发中使用这个 H5新增element.dataset.index 或者element.datase[‘index’] ie 11以上才支持 代码演示 <body><div getTime="10" data-index="20" data-name-list="40"></div><script>// 获取元素var div = document.querySelector('div');console.log(div.geTime); //undefined getTime是自定义属性不能直接通过元素的属性来获取 而是用自定义属性来获取的getAttribute(‘属性’)console.log(div.getAttribute('getTime')); //10// H5添加自定义属性的写法以data-开头div.setAttribute('data-time', 30)// 1.兼容性获取H5自定义属性console.log(div.getAttribute('data-time')); // 30// 2.H5新增的获取自定义属性的方法 它只能获取data-开头的// dataset 是一个集合的意思存放了所有以data开头的自定义属性 如果你想取其中的某一个只需要在dataset.的后面加上自定义属性名即可console.log(div.dataset);console.log(div.dataset.time); // 30// 还有一种方法dataset['属性']console.log(div.dataset['time']); // 30// 如果自定义属性里面有多个-链接的单词 我们获取的时候采取驼峰命名法 不用要-了console.log(div.dataset.nameList); // 40console.log(div.dataset['nameList']); // 40</script></body> 五.节点操作 1.为什么要学习节点操作 获取元素通常使用俩种方式 (1)利用DOM提供的方法获取元素 但是逻辑性不强 繁琐 (2)利用节点层级关系获取元素 如 利用父子,兄弟关系获取元素 逻辑性强,但是兼容性不怎么好 2.节点概述 网页中的所有内容都是节点(标签、属性、文本、注释等等) ,在DOM中,节点使用node表示。HTML DOM 树中的所有节点均可通过javascript进行访问,所有HTML元素(节点) 均可被修改,也可以创建或删除 一般地,节点至少拥有nade Type(节点类型)、nodeName(节点名称)和nodeValue(节点值) 这三个基本属性 元素节点 nodeType 为 1 属性节点 node Name为 2 文本节点 nodeValue为 3 (文本节点包含文字、空格、换行等等) 实际开发中,节点操作主要操作的是元素节点 3.节点层级 利用DOM树可以把节点划分为不同得层级关系,常见得是父子兄层级关系 1.父级节点 1.node.parentNode parenNode属性可以返回某节点得父节点,注意是最近的父节点哟!!! 如果指定的节点没有父节点就返回null 代码演示 <body><div class="box"><div class="box1"></div></div><script>var box1 = document.querySelector('.box1')// 得到的是离元素最近的父节点(亲爸爸) 得不到就返回得是nullconsole.log(box1.parentNode); // parentNode 翻译过来就是父亲的节点</script></body> 2.子级节点操作 1.parentNode.children(非标准) parentNode.children 是一个只读属性,返回所有的子元素节点。它只返回子元素节点,其余节点不返回(重点记住这个就好,以后重点使用) 虽然children是一个非标准,但是得到了各个浏览器的支持,我们大胆使用即可!!! 代码演示 <body><ul><li>1</li><li>1</li><li>1</li><li>1</li></ul><script>// DOM 提供的方法(APL)获取 这样获取比较麻烦var ul = document.querySelector('ul')var lis = ul.querySelectorAll('li')// children子节点获取 ul里面所有的小li 放心使用没有限制兼容性 实际开发中经常使用的console.log(ul.children);</script> 如何返回子节点的第一个和最后一个? 2.parentNode.firstElementChild firstElementChild返回第一个子元素节点,找不到则返回unll 3.parentNode.lastElementChild lastElementChild返回最后一个子元素节点,找不到则返回null 注意:这俩个方法有兼容性问题,IE9以上才支持 谨慎使用 但是我们有解决方案 如果想要第一个子元素节点,可以使用 parentNode.chilren[0] 如果想要最后一个子元素节点,可以使用 parentNode.chilren[parentNode.chilren.length - 1] 代码演示 <body><ul><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul><script>var ul = document.querySelector('ul')// 1.firstElementChild 返回第一个子元素节点 ie9 以上才支持注意兼容console.log(ul.firstElementChild);// 2.lastElementChild返回最后一个子元素节点console.log(ul.lastElementChild);// 3.实际开发中用到的既没有兼容性问题又可以返回子节点的第一个和最后一个console.log(ul.children[0]);console.log(ul.children[ul.children.length - 1]); //ul.children.length - 1获取的永远是子节点最后一个</script></body> 3.兄弟节点 1.node.nextSibling nextSibling 返回当前元素的下一个兄弟节点,找不到则返回null。注意包含所有的节点 2.node.previousSibling previousSibling 返回当前元素上一个兄弟节点,找不到则返回null。注意包含所以有的节点 代码演示 <body><div>我是div</div><span>我是span</span><script>var div = document.querySelector('div')// 返回当前元素的下一个兄弟节点nextSibling,找不到返回null。注意包含元素节点或者文本节点等等console.log(div.nextSibling); //这里返回的是text 因为它的下一个兄弟节点是换行// 返回的是当前元素的上一个节点previousSibling,找不到返回null。注意包含元素节点或者文本节点等等console.log(div.previousSibling); //这里返回的是text 因为它的上一个兄弟节点是换行</script></body> 3.node.nexElementSibling nexElementSibling 返回当前元素下一个兄弟元素节点,找不到返回null 4.node.previousElementSibling previousElementSibling返回当前元素上一个兄弟节点,找不到返回null 注意:这俩个方法有兼容性问题,IE9以上才支持 代码演示 <body><div>我是div</div><span>我是span</span><script>var div = document.querySelector('div')// nextElementSiblingd得到下一个兄弟元素节点console.log(div.nextElementSibling); // span // previousElementSibling 得到的是上一个兄弟元素节点console.log(div.previousElementSibling); // null 因为它上面没有兄弟元素了返回空的</script></body> 怎么解决兼容性问题呢? 可以封装一个兼容性函数(简单了解即可 在实际开发中用的不多) function getNextElementSibling(element) {var el = element;while (el = el.nextSibling) {if (el.nodeType === 1) {return el;} }return null;} 4.创建节点 1.document.createElement('tagName') document.createElement( ) 方法创建由 tagName 指定的 HTML 元素。因为这些元素原先不存在的是根据我们的需求动态生成的,所有我们也称为动态创建元素节点 我们创建了节点要给添加到节点里面去 称为 添加节点 1.node.appendChild(child) node.appendChild( )方法将一个节点添加到指定父节点的子节点列表末尾 2.node.insertBefore(child,指定添加元素位置) node.insertBefore( ) 方法将一个节点添加到父节点的指定子节点前面 代码演示 <body><ul><li>1</li></ul><script>// 1.创建节点 createElementvar li = document.createElement('li')// 2.添加节点 创建了节点要添加到某一个元素身上去 叫添加节点 node.appendChild(child) done 父级 child 子级 如果前面有元素了则在后面追加元素类似数组中的push依次追加var ul = document.querySelector('ul')ul.appendChild(li)// 3.添加节点 node.insertBefore(child,指定元素) 在子节点前面添加子节点 child子级你要添加的元素var lili = document.createElement('li')ul.insertBefore(lili, ul.children[0]) //ul.children 这句话的意思是添加到ul父亲的子节点第一个// 总结 如果想在页面中添加元素分为俩步骤1.创建元素 2.添加元素</script></body> 5.删除节点 node.removeChild(child) node.removeChlid()方法从DOM 中删除一个子节点,返回删除的节点 简单点就是从父元素中删除某一个孩子node就是父亲child就是孩子 删除的节点.remove(没有参数) 注意:ie不支持 代码演示 <body><button>按钮</button><ul><li>熊大</li><li>熊二</li><li>熊三</li></ul><script>// 1.获取元素var ul = document.querySelector('ul')var but = document.querySelector('button');// 2.删除元素// but.onclick = function() {// ul.removeChild(ul.children[0])// }// 3.点击按钮键依次删除,最后没有删除内容了 就禁用按钮 disabled = true 禁用按钮语法but.onclick = function() {if (ul.children.length == 0) {this.disabled = true} else {ul.removeChild(ul.children[0])} }</script></body> 6.复制节点(克隆节点) node.cloneNode() node.dloneNode()方法返回调用该方法节点得一个副本,也称为克隆节点/拷贝节点 注意 1.如果括号参数为空或者为false,则是浅拷贝,只复制里面得标签,不复制内容 2.如果括号参数为true,则是深度拷贝,会复制节点本身以及里面所有的内容 代码演示 <body><ul><li>1</li><li>2</li><li>3</li></ul><script>// 1.获取元素var ul = document.querySelector('ul');// 2.复制元素 node.cloneNode() 如果参数括号为空或者false则只会复制元素不会复制内容,如果待有参数true则内容和元素都会被复制var lis = ul.children[0].cloneNode(true);// 3.获取元素ul.appendChild(lis)</script></body> 7.替换(改)节点 node.replaceChild(新节点,替换到什么位置) 代码演示 <body><ul class="list"><li>1</li><li>2</li></ul><script>// 替换(改)节点 父节点.replaceChild(新元素, 替换到什么位置)// (1)获取父元素var ulNode = document.querySelector('.list');// (2)创建新的元素var liRead = document.createElement('li')// (3)给新元素添加内容liRead.innerHTML = '5';// (4)替换元素ulNode.replaceChild(liRead, ulNode.children[1])</script></body> 8.三种动态创建元素区别 document.write() element.innerHTML document.createElement() 区别 document.write()是直接将内容写入页面的内容流,但是文档流执行完毕,它则会导致页面全部重绘 element.innerHTML是将内容写入某个DOM节点,不会导致页面全部重绘 element.innerHTML 创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结果有点复杂 createElement()创建多个元素效率低一点点,但是结果更加清晰 总结:不同浏览器下,innerHTML效率要比createElement()高 代码演示 <body><button>点击</button><p>abc</p><div class="inner"></div><div class="create"></div><script>// window.onload = function() {// document.write('<div>123</div>');// }// 三种创建元素方式区别 // 1. document.write() 创建元素 如果页面文档流加载完毕,再调用这句话会导致页面重绘// var btn = document.querySelector('button');// btn.onclick = function() {// document.write('<div>123</div>');// }// 2. innerHTML 创建元素var inner = document.querySelector('.inner');// for (var i = 0; i <= 100; i++) {// inner.innerHTML += '<a href="">百度</a>'// }var arr = [];for (var i = 0; i <= 100; i++) {arr.push('<a href="">百度</a>');}inner.innerHTML = arr.join('');// 3. document.createElement() 创建元素var create = document.querySelector('.create');for (var i = 0; i <= 100; i++) {var a = document.createElement('a');create.appendChild(a);}</script></body> 本篇文章为转载内容。原文链接:https://blog.csdn.net/m0_46978034/article/details/110190352。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-08-04 13:36:05
247
转载
转载文章
...计、数据一致性问题 容器:容器的设计原理等技术 二面题目: 参与的项目,选一个,技术难度在哪里? Collections.sort底层排序方式 负载均衡的原理设计模式与重构,谈谈你对重构的理解 谈谈redis相关的集群有哪些成熟方案? 再谈谈一致hash算法(redis)? 数据库索引,B+树的特性和建树过程 Mysql相关的行锁,表锁;乐观锁,悲观锁 谈谈多线程和并发工具的使用 谈谈redis的架构和组件 Redis的数据一致性问题(分布式多节点环境&单机环境) Docker容器 1.3 Java中间件三面 技术三面考察范围: 主要谈到了高并发的实现方案 以及中间件:redis、rocketmq、kafka等的架构设计思路 最后问了平时怎么提升技术的技术 三面题目 高并发情况下,系统是如何支撑大量的请求的? 接着上面的问题,延伸到了中间件,kafka、redis、rocketmq、mycat等设计思路和适用场景等 最近上过哪些技术网站;最近再看那些书。 工作和生活中遇见最大的挑战,怎么去克服? 未来有怎样的打算 1.4 Java中间件四面 最后,你懂的,主要就是HR走流程了,主要问了未来的职业规划。 02 头条Java后台3面 2.1 头条一面 讲讲jvm运行时数据库区 讲讲你知道的垃圾回收算法 jvm内存模型jmm 内存泄漏与内存溢出的区别 select、epool 的区别?底层的数据结构是什么? mysql数据库默认存储引擎,有什么优点 优化数据库的方法,从sql到缓存到cpu到操作系统,知道多少说多少 什么情景下做分表,什么情景下做分库 linkedList与arrayList区别 适用场景 array list是如何扩容的 volatile 关键字的作用?Java 内存模型? java lock的实现,公平锁、非公平锁 悲观锁和乐观锁,应用中的案例,mysql当中怎么实现,java中的实现 2.2 头条二面 Java 内存分配策略? 多个线程同时请求内存,如何分配? Redis 底层用到了哪些数据结构? 使用 Redis 的 set 来做过什么? Redis 使用过程中遇到什么问题? 搭建过 Redis 集群吗? 如何分析“慢查询”日志进行 SQL/索引 优化? MySQL 索引结构解释一下?(B+ 树) MySQL Hash 索引适用情况?举下例子? 2.3 头条三面 如何保证数据库与redis缓存一致的Redis 的并发竞争问题是什么? 如何解决这个问题? 了解 Redis 事务的 CAS 方案吗? 如何保证 Redis 高并发、高可用? Redis 的主从复制原理,以及Redis 的哨兵原理? 如果让你写一个消息队列,该如何进行架构设计啊?说一下你的思路。 MySQL数据库主从同步怎么实现? 秒杀模块怎么设计的,如何压测,抗压手段 03 今日头条Java后台研发三面 3.1 一面 concurrent包下面用过哪些? countdownlatch功能实现 synchronized和lock区别,重入锁thread和runnable的区别 AtomicInteger实现原理(CAS自旋) java并发sleep与wait、notify与notifyAll的区别 如何实现高效的同步链表 java都有哪些加锁方式(synchronized、ReentrantLock、共享锁、读写锁等) 设计模式(工厂模式、单例模式(几种情况)、适配器模式、装饰者模式) maven依赖树,maven的依赖传递,循环依赖 3.2 二面 synchronized和reentrantLock的区别,synchronized用在代码快、方法、静态方法时锁的都是什么? 介绍spring的IOC和AOP,分别如何实现(classloader、动态代理)JVM的内存布局以及垃圾回收原理及过程 讲一下,讲一下CMS垃圾收集器垃圾回收的流程,以及CMS的缺点 redis如何处理分布式服务器并发造成的不一致OSGi的机制spring中bean加载机制,bean生成的具体步骤,ioc注入的方式spring何时创建- applicationContextlistener是监听哪个事件? 介绍ConcurrentHashMap原理,用的是哪种锁,segment有没可能增大? 解释mysql索引、b树,为啥不用平衡二叉树、红黑树 Zookeeper如何同步配置 3.3 三面 Java线程池ThreadPoolEcecutor参数,基本参数,使用场景 MySQL的ACID讲一下,延伸到隔离级别 dubbo的实现原理,说说RPC的要点 GC停顿原因,如何降低停顿? JVM如何调优、参数怎么调? 如何用工具分析jvm状态(visualVM看堆中对象的分配,对象间的引用、是否有内存泄漏,jstack看线程状态、是否死锁等等) 描述一致性hash算法 分布式雪崩场景如何避免? 再谈谈消息队列 04 抖音Java 三面 4.1 一面: hashmap,怎么扩容,怎么处理数据冲突? 怎么高效率的实现数据迁移? Linux的共享内存如何实现,大概说了一下。 socket网络编程,说一下TCP的三次握手和四次挥手同步IO和异步IO的区别? Java GC机制?GC Roots有哪些? 红黑树讲一下,五个特性,插入删除操作,时间复杂度? 快排的时间复杂度,最坏情况呢,最好情况呢,堆排序的时间复杂度呢,建堆的复杂度是多少 4.2 二面: 自我介绍,主要讲讲做了什么和擅长什么 设计模式了解哪些? AtomicInteger怎么实现原子修改的? ConcurrentHashMap 在Java7和Java8中的区别? 为什么Java8并发效率更好?什么情况下用HashMap,什么情况用ConcurrentHashMap? redis数据结构? redis数据淘汰机制? 4.3 三面(约五十分钟): mysql实现事务的原理(MVCC) MySQL数据主从同步是如何实现的? MySQL索引的实现,innodb的索引,b+树索引是怎么实现的,为什么用b+树做索引节点,一个节点存了多少数据,怎么规定大小,与磁盘页对应。 如果Redis有1亿个key,使用keys命令是否会影响线上服务? Redis的持久化方式,aod和rdb,具体怎么实现,追加日志和备份文件,底层实现原理的话知道么? 遇到最大困难是什么?怎么克服? 未来的规划是什么? 你想问我什么? 05 百度三面 5.1 百度一面 自我介绍 Java中的多态 为什么要同时重写hashcode和equals Hashmap的原理 Hashmap如何变线程安全,每种方式的优缺点 垃圾回收机制 Jvm的参数你知道的说一下 设计模式了解的说一下啊 手撕一个单例模式 手撕算法:反转单链表 手撕算法:实现类似微博子结构的数据结构,输入一系列父子关系,输出一个类似微博评论的父子结构图 手写java多线程 手写java的soeket编程,服务端和客户端 手撕算法: 爬楼梯,写出状态转移方程 智力题:时针分针什么时候重合 5.2 百度二面(现场) 自我介绍 项目介绍 服务器如何负载均衡,有哪些算法,哪个比较好,一致性哈希原理,怎么避免DDOS攻击请求打到少数机器。 TCP连接中的三次握手和四次挥手,四次挥手的最后一个ack的作用是什么,为什么要time wait,为什么是2msl。 数据库的备份和恢复怎么实现的,主从复制怎么做的,什么时候会出现数据不一致,如何解决。 Linux查看cpu占用率高的进程 手撕算法:给定一个数字三角形,找到从顶部到底部的最小路径和。每一步可以移动到下面一行的相邻数字上。 然后继续在这个问题上扩展 求出最短那条的路径 递归求出所有的路径 设计模式讲一下熟悉的 会不会滥用设计模式 多线程条件变量为什么要在while体里 你遇到什么挫折,怎么应对和处理 5.3 百度三面(现场) 自我介绍 项目介绍 Redis的特点 Redis的持久化怎么做,aof和rdb,有什么区别,有什么优缺点。 Redis使用哨兵部署会有什么问题,我说需要扩容的话还是得集群部署。 说一下JVM内存模型把,有哪些区,分别干什么的 说一下gc算法,分代回收说下 MySQL的引擎讲一下,有什么区别,使用场景呢 分布式事务了解么 反爬虫的机制,有哪些方式 06 蚂蚁中间件团队面试题 6.1 蚂蚁中间件一面: 自我介绍 JVM垃圾回收算法和垃圾回收器有哪些,最新的JDK采用什么算法。 新生代和老年代的回收机制。 讲一下ArrayList和linkedlist的区别,ArrayList与HashMap的扩容方式。 Concurrenthashmap1.8后的改动。 Java中的多线程,以及线程池的增长策略和拒绝策略了解么。 Tomcat的类加载器了解么 Spring的ioc和aop,Springmvc的基本架构,请求流程。 HTTP协议与Tcp有什么区别,http1.0和2.0的区别。 Java的网络编程,讲讲NIO的实现方式,与BIO的区别,以及介绍常用的NIO框架。 索引什么时候会失效变成全表扫描 介绍下分布式的paxos和raft算法 6.2 蚂蚁中间件二面 你在项目中怎么用到并发的。 消息队列的使用场景,谈谈Kafka。 你说了解分布式服务,那么你怎么理解分布式服务。 Dubbo和Spring Clound的区别,以及使用场景。 讲一下docker的实现原理,以及与JVM的区别。 MongoDB、Redis和Memcached的应用场景,各自优势 MongoDB有事务吗 Redis说一下sorted set底层原理 讲讲Netty为什么并发高,相关的核心组件有哪些 6.3 蚂蚁中间件三面 完整的画一个分布式集群部署图,从负载均衡到后端数据库集群。 分布式锁的方案,Redis和Zookeeper哪个好,如果是集群部署,高并发情况下哪个性能更好。 分布式系统的全局id如何实现。 数据库万级变成亿级,你如何来解决。 常见的服务器雪崩是由什么引起的,如何来防范。 异地容灾怎么实现 常用的高并发技术解决方案有哪些,以及对应的解决步骤。 07 京东4面(Java研发) 7.1 一面(基础面:约1小时) 自我介绍,主要讲讲做了什么和擅长什么 springmvc和spring-boot区别 @Autowired的实现原理 Bean的默认作用范围是什么?其他的作用范围? 索引是什么概念有什么作用?MySQL里主要有哪些索引结构?哈希索引和B+树索引比较? Java线程池的原理?线程池有哪些?线程池工厂有哪些线程池类型,及其线程池参数是什么? hashmap原理,处理哈希冲突用的哪种方法? 还知道什么处理哈希冲突的方法? Java GC机制?GC Roots有哪些? Java怎么进行垃圾回收的?什么对象会进老年代?垃圾回收算法有哪些?为什么新生代使用复制算法? HashMap的时间复杂度?HashMap中Hash冲突是怎么解决的?链表的上一级结构是什么?Java8中的HashMap有什么变化?红黑树需要比较大小才能进行插入,是依据什么进行比较的?其他Hash冲突解决方式? hash和B+树的区别?分别应用于什么场景?哪个比较好? 项目里有个数据安全的,aes和md5的区别?详细点 7.2 二面(问数据库较多) 自我介绍 为什么MyISAM查询性能好? 事务特性(acid) 隔离级别 SQL慢查询的常见优化步骤? 说下乐观锁,悲观锁(select for update),并写出sql实现 TCP协议的三次握手和四次挥手过程? 用到过哪些rpc框架 数据库连接池怎么实现 Java web过滤器的生命周期 7.3 三面(综合面;约一个小时) 自我介绍。 ConcurrentHashMap 在Java7和Java8中的区别?为什么Java8并发效率更好?什么情况下用HashMap,什么情况用ConcurrentHashMap? 加锁有什么机制? ThreadLocal?应用场景? 数据库水平切分,垂直切分的设计思路和切分顺序 Redis如何解决key冲突 soa和微服务的区别? 单机系统演变为分布式系统,会涉及到哪些技术的调整?请从前面负载到后端详细描述。 设计一个秒杀系统? 7.4 四面(HR面) 你自己最大优势和劣势是什么 平时遇见过什么样的挑战,怎么去克服的 工作中遇见了技术解决不了的问题,你的应对思路? 你的兴趣爱好? 未来的职业规划是什么? 08 美团java高级开发3面 8.1 美团一面 自我介绍 项目介绍 Redis介绍 了解redis源码么 了解redis集群么 Hashmap的原理,增删的情况后端数据结构如何位移 hashmap容量为什么是2的幂次 hashset的源码 object类你知道的方法 hashcode和equals 你重写过hashcode和equals么,要注意什么 假设现在一个学生类,有学号和姓名,我现在hashcode方法重写的时候,只将学号参与计算,会出现什么情况? 往set里面put一个学生对象,然后将这个学生对象的学号改了,再put进去,可以放进set么?并讲出为什么 Redis的持久化?有哪些方式,原理是什么? 讲一下稳定的排序算法和不稳定的排序算法 讲一下快速排序的思想 8.2 美团二面 自我介绍 讲一下数据的acid 什么是一致性 什么是隔离性 Mysql的隔离级别 每个隔离级别是如何解决 Mysql要加上nextkey锁,语句该怎么写 Java的内存模型,垃圾回收 线程池的参数 每个参数解释一遍 然后面试官设置了每个参数,给了是个线程,让描述出完整的线程池执行的流程 Nio和IO有什么区别 Nio和aio的区别 Spring的aop怎么实现 Spring的aop有哪些实现方式 动态代理的实现方式和区别 Linux了解么 怎么查看系统负载 Cpu load的参数如果为4,描述一下现在系统处于什么情况 Linux,查找磁盘上最大的文件的命令 Linux,如何查看系统日志文件 手撕算法:leeetcode原题 22,Generate Parentheses,给定 n 对括号,请- 写一个函数以将其生成新的括号组合,并返回所有组合结果。 8.3 美团三面(现场) 三面没怎么问技术,问了很多技术管理方面的问题 自我介绍 项目介绍 怎么管理项目成员 当意见不一致时,如何沟通并说服开发成员,并举个例子 怎么保证项目的进度 数据库的索引原理 非聚簇索引和聚簇索引 索引的使用注意事项 联合索引 从底层解释最左匹配原则 Mysql对联合索引有优化么?会自动调整顺序么?哪个版本开始优化? Redis的应用 Redis的持久化的方式和原理 技术选型,一个新技术和一个稳定的旧技术,你会怎么选择,选择的考虑有哪些 说你印象最深的美团点评技术团队的三篇博客 最近在学什么新技术 你是怎么去接触一门新技术的 会看哪些书 怎么选择要看的书 最后 由于篇幅限制,小编在此截出几张知识讲解的图解,有需要的程序猿(媛)可以点赞后戳这里免费领取全部资料获取哦 子 怎么保证项目的进度 数据库的索引原理 非聚簇索引和聚簇索引 索引的使用注意事项 联合索引 从底层解释最左匹配原则 Mysql对联合索引有优化么?会自动调整顺序么?哪个版本开始优化? Redis的应用 Redis的持久化的方式和原理 技术选型,一个新技术和一个稳定的旧技术,你会怎么选择,选择的考虑有哪些 说你印象最深的美团点评技术团队的三篇博客 最近在学什么新技术 你是怎么去接触一门新技术的 会看哪些书 怎么选择要看的书 最后 由于篇幅限制,小编在此截出几张知识讲解的图解,有需要的程序猿(媛)可以点赞后戳这里免费领取全部资料获取哦 [外链图片转存中…(img-SFREePIJ-1624074891834)] [外链图片转存中…(img-5kF3pkiC-1624074891834)] [外链图片转存中…(img-HDVXfOMR-1624074891835)] [外链图片转存中…(img-RyaAC5jy-1624074891836)] [外链图片转存中…(img-iV32C5Ok-1624074891837)] 本篇文章为转载内容。原文链接:https://blog.csdn.net/m0_57285325/article/details/118051767。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-11-13 23:43:59
85
转载
转载文章
...时往message表插入消息 2、message表有message_id(流水id,标识夸系统的一次转账操作),status(confirm,unconfirm) 3、timer扫描message表的unconfirm状态记录往activemq插入消息 4、余额宝收到消息消费消息时先查询message表如果有记录就不处理如果没记录就进行数据库增款操作 5、如果余额宝数据库操作成功往余额宝message表插入消息,表字段跟支付宝message一致 6、如果5操作成功,回调支付宝接口修改message表状态,把unconfirm状态转换成confirm状态 问题描述: 1、支付宝设计message表的目的 如果支付宝往activemq插入消息而余额宝消费消息异常,有可能是消费消息成功而事务操作异常,有可能是网络异常等等不确定因素。如果出现异常而activemq收到了确认消息的信号,这时候activemq中的消息是删除了的,消息丢失了。设置message表就是有一个消息存根,activemq中消息丢失了message表中的消息还在。解决了activemq消息丢失问题 2、余额宝设计message表的目的 当余额宝消费成功并且数据库操作成功时,回调支付宝的消息确认接口,如果回调接口时出现异常导致支付宝状态修改失败还是unconfirm状态,这时候还会被timer扫描到,又会往activemq插入消息,又会被余额宝消费一边,但是这条消息已经消费成功了的只是回调失败而已,所以就需要有一个这样的message表,当余额宝消费时先插入message表,如果message根据message_id能查询到记录就说明之前这条消息被消费过就不再消费只需要回调成功即可,如果查询不到消息就消费这条消息继续数据库操作,数据库操作成功就往message表插入消息。 这样就解决了消息重复消费问题,这也是消费端的幂等操作。 基于消息中间件的分布式事务是最理想的分布式事务解决方案,兼顾了安全性和并发性! 接下来贴代码: 支付宝代码: @Controller@RequestMapping("/order")public class OrderController {/ @Description TODO @param @return 参数 @return String 返回类型 @throws userID:转账的用户ID amount:转多少钱/@Autowired@Qualifier("activemq")OrderService orderService;@RequestMapping("/transfer")public @ResponseBody String transferAmount(String userId,String messageId, int amount) {try {orderService.updateAmount(amount,messageId, userId);}catch (Exception e) {e.printStackTrace();return "===============================transferAmount failed===================";}return "===============================transferAmount successfull===================";}@RequestMapping("/callback")public String callback(String param) {JSONObject parse = JSONObject.parseObject(param);String respCode = parse.getString("respCode");if(!"OK".equalsIgnoreCase(respCode)) {return null;}try {orderService.updateMessage(param);}catch (Exception e) {e.printStackTrace();return "fail";}return "ok";} } public interface OrderService {public void updateAmount(int amount, String userId,String messageId);public void updateMessage(String param);} @Service("activemq")@Transactional(rollbackFor = Exception.class)public class OrderServiceActivemqImpl implements OrderService {Logger logger = LoggerFactory.getLogger(getClass());@AutowiredJdbcTemplate jdbcTemplate;@AutowiredJmsTemplate jmsTemplate;@Overridepublic void updateAmount(final int amount, final String messageId, final String userId) {String sql = "update account set amount = amount - ?,update_time=now() where user_id = ?";int count = jdbcTemplate.update(sql, new Object[]{amount, userId});if (count == 1) {//插入到消息记录表sql = "insert into message(user_id,message_id,amount,status) values (?,?,?,?)";int row = jdbcTemplate.update(sql,new Object[]{userId,messageId,amount,"unconfirm"});if(row == 1) {//往activemq中插入消息jmsTemplate.send("zg.jack.queue", new MessageCreator() {@Overridepublic Message createMessage(Session session) throws JMSException {com.zhuguang.jack.bean.Message message = new com.zhuguang.jack.bean.Message();message.setAmount(Integer.valueOf(amount));message.setStatus("unconfirm");message.setUserId(userId);message.setMessageId(messageId);return session.createObjectMessage(message);} });} }}@Overridepublic void updateMessage(String param) {JSONObject parse = JSONObject.parseObject(param);String messageId = parse.getString("messageId");String sql = "update message set status = ? where message_id = ?";int count = jdbcTemplate.update(sql,new Object[]{"confirm",messageId});if(count == 1) {logger.info(messageId + " callback successfull");} }} activemq.xml <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:amq="http://activemq.apache.org/schema/core"xmlns:jms="http://www.springframework.org/schema/jms"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.1.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.1.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-4.1.xsdhttp://www.springframework.org/schema/jmshttp://www.springframework.org/schema/jms/spring-jms-4.1.xsdhttp://activemq.apache.org/schema/corehttp://activemq.apache.org/schema/core/activemq-core-5.12.1.xsd"><context:component-scan base-package="com.zhuguang.jack" /><mvc:annotation-driven /><amq:connectionFactory id="amqConnectionFactory"brokerURL="tcp://192.168.88.131:61616"userName="system"password="manager" /><!-- 配置JMS连接工长 --><bean id="connectionFactory"class="org.springframework.jms.connection.CachingConnectionFactory"><constructor-arg ref="amqConnectionFactory" /><property name="sessionCacheSize" value="100" /></bean><!-- 定义消息队列(Queue) --><bean id="demoQueueDestination" class="org.apache.activemq.command.ActiveMQQueue"><!-- 设置消息队列的名字 --><constructor-arg><value>zg.jack.queue</value></constructor-arg></bean><!-- 配置JMS模板(Queue),Spring提供的JMS工具类,它发送、接收消息。 --><bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"><property name="connectionFactory" ref="connectionFactory" /><property name="defaultDestination" ref="demoQueueDestination" /><property name="receiveTimeout" value="10000" /><!-- true是topic,false是queue,默认是false,此处显示写出false --><property name="pubSubDomain" value="false" /></bean></beans> spring-dispatcher.xml <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xmlns:task="http://www.springframework.org/schema/task" xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util-3.2.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.2.xsdhttp://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"><!-- 引入同文件夹下的redis属性配置文件 --><!-- 解决springMVC响应数据乱码 text/plain就是响应的时候原样返回数据--><import resource="../activemq/activemq.xml"/><!--<context:property-placeholder ignore-unresolvable="true" location="classpath:config/core/core.properties,classpath:config/redis/redis-config.properties" />--><bean id="propertyConfigurerForProject1" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="order" value="1" /><property name="ignoreUnresolvablePlaceholders" value="true" /><property name="location"><value>classpath:config/core/core.properties</value></property></bean><mvc:annotation-driven><mvc:message-converters register-defaults="true"><bean class="org.springframework.http.converter.StringHttpMessageConverter"><property name="supportedMediaTypes" value = "text/plain;charset=UTF-8" /></bean></mvc:message-converters></mvc:annotation-driven><!-- 避免IE执行AJAX时,返回JSON出现下载文件 --><bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"><property name="supportedMediaTypes"><list><value>text/html;charset=UTF-8</value></list></property></bean><!-- 开启controller注解支持 --><!-- 注:如果base-package=com.avicit 则注解事务不起作用 TODO 读源码 --><context:component-scan base-package="com.zhuguang"></context:component-scan><mvc:view-controller path="/" view-name="redirect:/index" /><beanclass="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" /><bean id="handlerAdapter"class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"></bean><beanclass="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"><property name="mediaTypes"><map><entry key="json" value="application/json" /><entry key="xml" value="application/xml" /><entry key="html" value="text/html" /></map></property><property name="viewResolvers"><list><bean class="org.springframework.web.servlet.view.BeanNameViewResolver" /><bean class="org.springframework.web.servlet.view.UrlBasedViewResolver"><property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /><property name="prefix" value="/" /><property name="suffix" value=".jsp" /></bean></list></property></bean><!-- 支持上传文件 --> <!-- 控制器异常处理 --><bean id="exceptionResolver"class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"><property name="exceptionMappings"><props><prop key="java.lang.Exception">error</prop></props></property></bean><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"><property name="driverClass"><value>${jdbc.driverClassName}</value></property><property name="jdbcUrl"><value>${jdbc.url}</value></property><property name="user"><value>${jdbc.username}</value></property><property name="password"><value>${jdbc.password}</value></property><property name="minPoolSize" value="10" /><property name="maxPoolSize" value="100" /><property name="maxIdleTime" value="1800" /><property name="acquireIncrement" value="3" /><property name="maxStatements" value="1000" /><property name="initialPoolSize" value="10" /><property name="idleConnectionTestPeriod" value="60" /><property name="acquireRetryAttempts" value="30" /><property name="breakAfterAcquireFailure" value="false" /><property name="testConnectionOnCheckout" value="false" /><property name="acquireRetryDelay"><value>100</value></property></bean><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property></bean><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean><tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" /><aop:aspectj-autoproxy expose-proxy="true"/></beans> logback.xml <?xml version="1.0" encoding="UTF-8"?><!--scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒当scan为true时,此属性生效。默认的时间间隔为1分钟。debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。--><configuration scan="false" scanPeriod="60 seconds" debug="false"><!-- 定义日志的根目录 --><!-- <property name="LOG_HOME" value="/app/log" /> --><!-- 定义日志文件名称 --><property name="appName" value="netty"></property><!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出 --><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"><Encoding>UTF-8</Encoding><!--日志输出格式:%d表示日期时间,%thread表示线程名,%-5level:级别从左显示5个字符宽度%logger{50} 表示logger名字最长50个字符,否则按照句点分割。 %msg:日志消息,%n是换行符--><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern></encoder></appender><!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 --> <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"><Encoding>UTF-8</Encoding><!-- 指定日志文件的名称 --> <file>${appName}.log</file><!--当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。--><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!--滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动 %i:当文件大小超过maxFileSize时,按照i进行文件滚动--><fileNamePattern>${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern><!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动,且maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除。--><MaxHistory>365</MaxHistory><!-- 当日志文件超过maxFileSize指定的大小是,根据上面提到的%i进行日志文件滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy--><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>100MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><!--日志输出格式:%d表示日期时间,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %logger{50} 表示logger名字最长50个字符,否则按照句点分割。 %msg:日志消息,%n是换行符--> <encoder><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern></encoder></appender><!-- logger主要用于存放日志对象,也可以定义日志类型、级别name:表示匹配的logger类型前缀,也就是包的前半部分level:要记录的日志级别,包括 TRACE < DEBUG < INFO < WARN < ERRORadditivity:作用在于children-logger是否使用 rootLogger配置的appender进行输出,false:表示只用当前logger的appender-ref,true:表示当前logger的appender-ref和rootLogger的appender-ref都有效--><!-- <logger name="edu.hyh" level="info" additivity="true"><appender-ref ref="appLogAppender" /></logger> --><!-- root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个logger对应,要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。 --><root level="debug"><appender-ref ref="stdout" /><appender-ref ref="appLogAppender" /></root></configuration> 2、余额宝代码 package com.zhuguang.jack.controller;import com.alibaba.fastjson.JSONObject;import com.zhuguang.jack.service.OrderService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;@Controller@RequestMapping("/order")public class OrderController {/ @Description TODO @param @return 参数 @return String 返回类型 @throws 模拟银行转账 userID:转账的用户ID amount:转多少钱/@AutowiredOrderService orderService;@RequestMapping("/transfer")public @ResponseBody String transferAmount(String userId, String amount) {try {orderService.updateAmount(Integer.valueOf(amount), userId);}catch (Exception e) {e.printStackTrace();return "===============================transferAmount failed===================";}return "===============================transferAmount successfull===================";} } 消息监听器 package com.zhuguang.jack.listener;import com.alibaba.fastjson.JSONObject;import com.zhuguang.jack.service.OrderService;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.client.SimpleClientHttpRequestFactory;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import org.springframework.web.client.RestTemplate;import javax.jms.JMSException;import javax.jms.Message;import javax.jms.MessageListener;import javax.jms.ObjectMessage;@Service("queueMessageListener")public class QueueMessageListener implements MessageListener {private Logger logger = LoggerFactory.getLogger(getClass());@AutowiredOrderService orderService;@Transactional(rollbackFor = Exception.class)@Overridepublic void onMessage(Message message) {if (message instanceof ObjectMessage) {ObjectMessage objectMessage = (ObjectMessage) message;try {com.zhuguang.jack.bean.Message message1 = (com.zhuguang.jack.bean.Message) objectMessage.getObject();String userId = message1.getUserId();int count = orderService.queryMessageCountByUserId(userId);if (count == 0) {orderService.updateAmount(message1.getAmount(), message1.getUserId());orderService.insertMessage(message1.getUserId(), message1.getMessageId(), message1.getAmount(), "ok");} else {logger.info("异常转账");}RestTemplate restTemplate = createRestTemplate();JSONObject jo = new JSONObject();jo.put("messageId", message1.getMessageId());jo.put("respCode", "OK");String url = "http://jack.bank_a.com:8080/alipay/order/callback?param="+ jo.toJSONString();restTemplate.getForObject(url,null);} catch (JMSException e) {e.printStackTrace();throw new RuntimeException("异常");} }}public RestTemplate createRestTemplate() {SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();simpleClientHttpRequestFactory.setConnectTimeout(3000);simpleClientHttpRequestFactory.setReadTimeout(2000);return new RestTemplate(simpleClientHttpRequestFactory);} } package com.zhuguang.jack.service;public interface OrderService {public void updateAmount(int amount, String userId);public int queryMessageCountByUserId(String userId);public int insertMessage(String userId,String messageId,int amount,String status);} package com.zhuguang.jack.service;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.client.SimpleClientHttpRequestFactory;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import org.springframework.web.client.RestTemplate;@Service@Transactional(rollbackFor = Exception.class)public class OrderServiceImpl implements OrderService {private Logger logger = LoggerFactory.getLogger(getClass());@AutowiredJdbcTemplate jdbcTemplate;/ 更新数据库表,把账户余额减去amountd/@Overridepublic void updateAmount(int amount, String userId) {//1、农业银行转账3000,也就说农业银行jack账户要减3000String sql = "update account set amount = amount + ?,update_time=now() where user_id = ?";int count = jdbcTemplate.update(sql, new Object[] {amount, userId});if (count != 1) {throw new RuntimeException("订单创建失败,农业银行转账失败!");} }public RestTemplate createRestTemplate() {SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();simpleClientHttpRequestFactory.setConnectTimeout(3000);simpleClientHttpRequestFactory.setReadTimeout(2000);return new RestTemplate(simpleClientHttpRequestFactory);}@Overridepublic int queryMessageCountByUserId(String messageId) {String sql = "select count() from message where message_id = ?";int count = jdbcTemplate.queryForInt(sql, new Object[]{messageId});return count;}@Overridepublic int insertMessage(String userId, String message_id,int amount, String status) {String sql = "insert into message(user_id,message_id,amount,status) values(?,?,?)";int count = jdbcTemplate.update(sql, new Object[]{userId, message_id,amount, status});if(count == 1) {logger.info("Ok");}return count;} } activemq.xml <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:amq="http://activemq.apache.org/schema/core"xmlns:jms="http://www.springframework.org/schema/jms"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.1.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.1.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-4.1.xsdhttp://www.springframework.org/schema/jmshttp://www.springframework.org/schema/jms/spring-jms-4.1.xsdhttp://activemq.apache.org/schema/corehttp://activemq.apache.org/schema/core/activemq-core-5.12.1.xsd"><context:component-scan base-package="com.zhuguang.jack" /><mvc:annotation-driven /><amq:connectionFactory id="amqConnectionFactory"brokerURL="tcp://192.168.88.131:61616"userName="system"password="manager" /><!-- 配置JMS连接工长 --><bean id="connectionFactory"class="org.springframework.jms.connection.CachingConnectionFactory"><constructor-arg ref="amqConnectionFactory" /><property name="sessionCacheSize" value="100" /></bean><!-- 定义消息队列(Queue) --><bean id="demoQueueDestination" class="org.apache.activemq.command.ActiveMQQueue"><!-- 设置消息队列的名字 --><constructor-arg><value>zg.jack.queue</value></constructor-arg></bean><!-- 显示注入消息监听容器(Queue),配置连接工厂,监听的目标是demoQueueDestination,监听器是上面定义的监听器 --><bean id="queueListenerContainer"class="org.springframework.jms.listener.DefaultMessageListenerContainer"><property name="connectionFactory" ref="connectionFactory" /><property name="destination" ref="demoQueueDestination" /><property name="messageListener" ref="queueMessageListener" /></bean><!-- 配置JMS模板(Queue),Spring提供的JMS工具类,它发送、接收消息。 --><bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"><property name="connectionFactory" ref="connectionFactory" /><property name="defaultDestination" ref="demoQueueDestination" /><property name="receiveTimeout" value="10000" /><!-- true是topic,false是queue,默认是false,此处显示写出false --><property name="pubSubDomain" value="false" /></bean></beans> OK~~~~~~~~~~~~大功告成!!!, 如果大家觉得满意并且对技术感兴趣请加群:171239762, 纯技术交流群,非诚勿扰。 本篇文章为转载内容。原文链接:https://blog.csdn.net/luoyang_java/article/details/84953241。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-04-16 22:34:52
499
转载
站内搜索
用于搜索本网站内部文章,支持栏目切换。
知识学习
实践的时候请根据实际情况谨慎操作。
随机学习一条linux命令:
ifconfig 或 ip addr show
- 查看网络接口配置信息。
推荐内容
推荐本栏目内的其它文章,看看还有哪些文章让你感兴趣。
2023-04-28
2023-08-09
2023-06-18
2023-04-14
2023-02-18
2023-04-17
2024-01-11
2023-10-03
2023-09-09
2023-06-13
2023-08-07
2023-03-11
历史内容
快速导航到对应月份的历史文章列表。
随便看看
拉到页底了吧,随便看看还有哪些文章你可能感兴趣。
时光飞逝
"流光容易把人抛,红了樱桃,绿了芭蕉。"