tag 标签: 完结

相关资源
  • 所需E币: 0
    时间: 2024-9-24 14:14
    大小: 2.82KB
    上传者: huangyasir1990
    一、MQ是什么MQ全称为MessageQueue,即消息队列,是一种提供消息队列服务的中间件,也称为消息中间件,是一套提供了消息生产、存储、消费全过程的软件系统,遵循FIFO原则。二、为什么用MQ上下班高峰期使用天府通刷码的人非常多,以为做并发量很高,一个出站请求到后台需要做费用结算,或者积分赠送等业务。由于并发很高,并且费用结算和积分等业务本来就耗时,况且支付服务也不一定能承担那么大的请求量。当服务器线程耗尽,后续请求会等待变慢,再加上高并发请求就会导致后续请求越来越慢,请求长时间等待,导致大量请求超时。并发太高,可能会导致服务器的内存上升,CPU使用率急速上升,甚至导致服务器宕掉。加入MQ后的效果高并发请求在MQ中排队,达到了消除峰值的目的,不会有大量的请求同时怼到支付系统服务异步调用,“天府通出站API”把结算消息放入MQ就可以返回“出站成功,费用稍后结算”给用户,响应时间很快服务彻底解耦,即使支付服务挂掉,也不影响“天府通出站API”正常工作,当支付系统再启动仍然可以继续消费MQ中的消息。三、MQ的使用场景1异步&解耦笔者曾经负责某电商公司的用户服务,该服务提供用户注册,查询,修改等基础功能。用户注册成功之后,需要给用户发送短信。2消峰高并发场景下,面对突然出现的请求峰值,非常容易导致系统变得不稳定,比如大量请求访问数据库,会对数据库造成极大的压力,或者系统的资源CPU、IO出现瓶颈。3消息总线所谓总线,就是像主板里的数据总线一样,具有数据的传递和交互能力,各方不直接通信,使用总线作为标准通信接口。笔者曾经服务于某彩票公司订单团队,在彩票订单的生命周期里,经过创建,拆分子订单,出票,算奖等诸多环节。每一个环节都需要不同的服务处理,每个系统都有自己独立的表,业务功能也相对独立。假如每个应用都去修改订单主表的信息,那就会相当混乱了。4延时任务用户在美团APP下单,假如没有立即支付,进入订单详情会显示倒计时,如果超过支付时间,订单就会被自动取消。非常优雅的方式是:使用消息队列的延时消息。四、RabbitMQ主要特性: 1.可靠性:提供了多种技术可以让你在性能和可靠性之间进行权衡。这些技术包括持久性机制、投递确认、发布者证实和高可用性机制; 2.灵活的路由:消息在到达队列前是通过交换机进行路由的。RabbitMQ为典型的路由逻辑提供了多种内置交换机类型。如果你有更复杂的路由需求,可以将这些交换机组合起来使用,你甚至可以实现自己的交换机类型,并且当做RabbitMQ的插件来使用;  3.消息集群:在相同局域网中的多个RabbitMQ服务器可以聚合在一起,作为一个独立的逻辑代理来使用;  4.队列高可用:队列可以在集群中的机器上进行镜像,以确保在硬件问题下还保证消息安全; 5.多种协议的支持:支持多种消息队列协议; 6.服务器端用Erlang语言编写,支持只要是你能想到的所有编程语言; 7.管理界面:RabbitMQ有一个易用的用户界面,使得用户可以监控和管理消息Broker的许多方面; 8.跟踪机制:如果消息异常,RabbitMQ提供消息跟踪机制,使用者可以找出发生了什么; 9.插件机制:提供了许多插件,来从多方面进行扩展,也可以编写自己的插件五、生产者代码示例importpika#连接到RabbitMQ服务器connection=pika.BlockingConnection(pika.ConnectionParameters('localhost'))channel=connection.channel()#声明一个队列channel.queue_declare(queue='hello')#发送消息channel.basic_publish(exchange='',           routing_key='hello',           body='HelloWorld!')print("[x]Sent'HelloWorld!'")#关闭连接connection.close()六、消费者代码示例importpika#连接到RabbitMQ服务器connection=pika.BlockingConnection(pika.ConnectionParameters('localhost'))channel=connection.channel()#声明一个队列channel.queue_declare(queue='hello')#定义消息处理函数defcallback(ch,method,properties,body):  print("[x]Received%r"%body)#设置消费者channel.basic_consume(queue='hello',           auto_ack=True,           on_message_callback=callback)print('[*]Waitingformessages.ToexitpressCTRL+C')channel.start_consuming()
  • 所需E币: 0
    时间: 2024-8-26 12:23
    大小: 3.46KB
    上传者: huangyasir1990
    一、什么是流媒体流媒体是一种以流的形式在网络上进行数字媒体(音频、视频)传输的技术。它将频、音视频之类的连续媒体经压缩编码、数据打包后按照一定的时间间隔要求连续地发送给接收方,接收方在后续数据不断到达的同时对接收到的数据进行重组、解码和播放。如果你对流媒体感兴趣的话,可以看一下Live555,一个更流行且更专业的流媒体库。它支持了各种标准流媒体传输协议,如RTP/RTCP、RTSP、SIP,实现了对多种音视频编码格式的音视频数据的流化、接收和处理等支持。播放VLC和MPlayer都是基于它来实现流媒体播放的功能,并且非常适合嵌入式领域。二、视频编码 是指压缩编码。在计算机的世界中,一切都是0和1组成的,音视频的数据量庞大,如果按照裸流数据存储的话,那将需要耗费非常大的存储空间,也不利于传送。而音视频中,其实包含了大量0和1的重复数据,因此可以通过一定的算法来压缩这些0和1的数据。特别在视频中,由于画面是逐渐过渡的,因此整个视频中,包含了大量画面/像素的重复,这正好提供了非常大的压缩空间。因此,编码可以大大减小音视频数据的大小,让音视频更容易存储和传送。三、simple-rtmp-server[多种类型直播]一个简单高效的实时视频服务器,使用C++开发,支持RTMP/WebRTC/HLS/HTTP-FLV/SRT/GB28181。SRS定位是运营级的互联网直播服务器集群,追求更好的概念完整性和最简单实现的代码。SRS提供了丰富的接入方案将RTMP流接入SRS,包括推送RTMP到SRS、推送RTSP/UDP/FLV到SRS、拉取流到SRS。SRS还支持将接入的RTMP流进行各种变换,譬如将RTMP流转码、流截图、转发给其他服务器、转封装成HTTP-FLV流、转封装成HLS、转封装成HDS、录制成FLV四、音视频处理框架1.OpenCVOpenCV全称是OpenSourceComputerVisionLibrary,是一个跨平台的计算机视觉库,是由英特尔公司发起并参与开发,以BSD许可证授权发行,可以在商业和研究领域中免费使用。可用于开发实时的图像处理、计算机视觉以及模式识别程序。OpenCV用C++语言编写,有大量的Python,JavaandMATLAB(版本2.5)的接口。2.GstreamerGStreamer是一个基于管道的多媒体框架,基于GObject,以C语言写成。可以很容易地创建各种多媒体功能组件,包括简单的音频回放,音频和视频播放,录音,流媒体和音频编辑。适用于所有主要操作系统,例如Linux、Android、Windows、MaxOSX、iOS,以及大多数BSD、商业Unix、Solaris和Symbian。GStreamers功能可以通过新插件进行扩展。3.FFmpeg一套开源的音视频处理的框架,可以运行音频和视频多种格式的录影、转换、流功能,包含了libavcodec(用于多个项目中音频和视频的解码器库)以及libavformat(音频与视频格式转换库)五、多媒体处理功能  多媒体视频处理工具FFmpeg有非常强大的功能[1]包括视频采集功能、视频格式转换、视频抓图、给视频加水印等。视频采集功能    FFmpeg是在Linux下开发出来的,但它可以在包括Windows在内的大多数操作系统中编译。这个项目是由FabriceBellard发起的,现在由MichaelNiedermayer主持。    ffmpeg视频采集功能非常强大,不仅可以采集视频采集卡或USB摄像头的图像,还可以进行屏幕录制,同时还支持以RTP方式将视频流传送给支持RTSP的流媒体服务器,支持直播应用。    ffmpeg在Linux下的视频采集    在Linux平台上,ffmpeg对V4L2的视频设备提高了很好的支持,如:    ./ffmpeg-t10-fvideo4linux2-s176*144-r8-i/dev/video0-vcodech263-frtprtp://192.168.1.105:5060>/tmp/ffmpeg.sdp    以上命令表示:采集10秒钟视频,对video4linux2视频设备进行采集,采集QCIF(176*144)的视频,每秒8帧,视频设备为/dev/video0,视频编码为h263,输出格式为RTP,后面定义了IP地址及端口,将该码流所对应的SDP文件重定向到/tmp/ffmpeg.sdp中,将此SDP文件上传到流媒体服务器就可以实现直播了。六、视频会议传输模块的开发选择视频会议主要是开发音视频、数据的传输的软件,在这些开发过程中,最核心的模块是传输模块,传输模块的性能直接影响到视频会议的最终质量,因此传输模块的选择在视频会议开发当中尤其重要。传输模块在开发过程中,由于考虑到QOS的影响,一般都会使用数据重发的技术,因此传输模块以及成为视频会议底层开发的一个重点,我们开发的传输模块,可以选择用TCP、UDP直接进行开发或者利用开源的传输库,因为一些开源传输库以及比较成熟,直接拿来用就可以,如果自己开发传输模块,估计也是一个巨大工程。现在我们介绍一下传输模块的开发选择。七、商用流媒体软件的选用如果项目在稳定性、安全性和责任约束上比较苛刻,还是建议选用商用产品。商用流媒体服务器软件的选择范围不大,基本上是国内外几家专业的公司在做,可选产品包括:Wowza、AdobeFlashMediaServer和国内NTVMediaServerG3等。Wowza是一个美国WowzaMediaSystems公司的产品,也是目前应用最广泛的一款流媒体服务器产品,在国内也有它的代理商。通过发放软件授权证书进行授权,可以按月、按年度购买使用授权,官网上有明确的报价。国内代理商加上自己的包装和技术支持费用,价格不一。AdobeFlashMediaServer是早些年使用最广泛的一款产品,产品成熟,价格相对高昂,随着Adobe公司退出中国市场,技术支持也主要有一些国内代理商负责。和Wowza一样,由于由国内厂商支持,加上语言、技术能力和时差等问题,在技术支持上并不尽人意。
  • 所需E币: 0
    时间: 2024-6-27 09:52
    大小: 3.32KB
    上传者: 开心就很好了
    智能语音系统是一种能够理解和处理人类语音的技术,其中语音识别是实现这一目标的关键技术之一。语音识别技术是将人类语音转换为文本或命令的过程,它在许多现代应用领域如语音助手、语音控制和语音翻译等方面发挥着重要作用。一、智能语音项目开发需要哪些技术?1.自然语言处理(NLP):NLP是实现机器人语音交互的核心技术之一,包括语音识别、语音合成、文本理解和生成等子领域。2.对话管理系统(DialogueManagement):对话管理系统负责管理和维护语音交互中用户与机器人之间的对话流程。3.情感识别技术:情感识别技术可以帮助机器人理解用户的情感状态,从而更好地回应和调整交互方式。4.人机交互设计(HCI):人机交互设计考虑用户体验和界面设计,确保语音交互界面对用户友好、易用和直观。5.知识图谱和语义网技术:知识图谱和语义网技术可以帮助机器人构建丰富的知识库,以支持语义理解、知识推理和信息检索。6.远场语音识别技术:远场语音识别技术可以实现在远距离或有噪音环境下的语音识别,使语音交互更具灵活性和便利性。7.增强学习(ReinforcementLearning):增强学习是一种人工智能训练方法,通过代理(机器人)在与环境交互中获得奖励来改善决策策略。二、首先我们分析下智能语音需要些什么东西:1.语音输入:想要智能对话肯定需要语音的输入,输出。2.语音识别:将语音识别成文字。3.智能问答服务:将语音识别结果,输入该服务,并得到结果。4.语音合成:将智能问答服务回答生成音频5.语音播报:将智能问答服务回答的问题,用语音的形式播报给您听。三、智能语音项目开发需要什么编程语言?智能语音主要涉及Python、Java、C++、JavaScript和Swift。例如,Python是开发语音助手时常用的编程语言,它支持各种音频和机器学习库,如PyAudio、SpeechRecognition和TensorFlow,能够处理语音信号、实现自然语言理解与交互。这些库提供了从录音到特征提取、模式识别和自然语言处理的一系列工具和功能。1、PYTHON在智能语音中的作用Python因其简洁的语法和强大的库支持,在语音助手开发中占据了举足轻重的地位。该语言的以数据为中心的设计哲学使其在处理音频信号、执行语音到文本的转换和自然语言理解(NLU)方面表现卓越。深度学习库如TensorFlow和Keras的整合,为开发者提供了训练语音识别和理解模型所需的工具。2、JAVA的重要性及应用场景Java一直以来都是Android平台的主力编程语言。它对内存管理、网络编程的强大支持以及跨平台特性,使其在语音助手的移动端开发中非常有用。通过Java,可以轻松访问Android系统API,以及集成GoogleAssistantSDK之类的工具。Java的强类型系统有利于大型项目的管理,特别是在需要多人协作的环境中。静态类型的特性能够减少运行时错误,从而提高语音助手软件的稳定性。3、C++在性能要求高的环境中的应用C++以其执行效率和对底层资源的访问能力在高性能的语音助手系统中发挥着重要作用。许多音频处理和机器学习的库都提供了C++的接口,使开发者能够对性能进行微调,以满足实时语音处理的高要求。对于嵌入式设备和资源受限的环境,C++能够提供优化的性能。在这些场景下,每一个计算周期和内存字节都至关重要,而C++能够让开发者充分利用硬件的能力。四、代码解释以下是项目的一个基本示例代码,展示了如何使用预训练模型进行文本到语音的转换:importtorchfromtransformersimportT5Tokenizer,T5ForConditionalGeneration#安装SentencePiece库#pipinstallsentencepiece#加载预训练的模型和分词器model_name="t5-small"tokenizer=T5Tokenizer.from_pretrained(model_name)model=T5ForConditionalGeneration.from_pretrained(model_name)#示例输入input_text="translateEnglishtoFrench:Thehouseiswonderful."input_ids=tokenizer(input_text,return_tensors="pt").input_ids#生成输出outputs=model.generate(input_ids)#解码输出output_text=tokenizer.decode(outputs[0],skip_special_tokens=True)print(output_text)该代码演示了如何加载一个预训练的T5模型并进行简单的文本翻译。通过对输入文本进行编码、生成和解码,可以得到翻译后的结果。类似的方法可以用于文本到语音转换,具体实现则需调用相应的语音合成模型。五、语音到文本API您可以使用AzureAISpeechtotextAPI将音频实时或批量转录为文本格式。转录的音频源可以是来自麦克风或音频文件的实时音频流。语音转文本API使用的模型基于微软训练的通用语言模型。该模型的数据由微软拥有,并部署到MicrosoftAzure。该模型针对两种场景进行了优化,即对话和听写。如果微软的预构建模型没有提供您需要的内容,您还可以创建和训练自己的自定义模型,包括声学、语言和发音。六、语音特征提取语音特征提取是将语音信号转换为数字信号的过程。常见的语音特征提取方法包括:1、时域特征:时域特征是用来描述语音信号在时域上的特性。常见的时域特征包括:平均能量、峰值能量、零驻波能量、波形变化率等。2、频域特征:频域特征是用来描述语音信号在频域上的特性。常见的频域特征包括:快速傅里叶变换(FFT)、谱密度(PSD)、调制比(CEP)等。3、时频特征:时频特征是用来描述语音信号在时域和频域上的特性。常见的时频特征包括:波形比(WB)、波形相似度(WSD)、波形相关系数(WCC)等。
  • 所需E币: 0
    时间: 2024-6-25 10:16
    大小: 2.75KB
    上传者: 开心就很好了
    一、StableDiffusion是什么?StableDiffusion是一个文本到图像的潜在扩散模型,由CompVis、StabilityAI和LAION的研究人员和工程师创建。它使用来自LAION-5B数据库子集的512x512图像进行训练。使用这个模型,可以生成包括人脸在内的任何图像,因为有开源的预训练模型,所以我们也可以在自己的机器上运行它。近几年,随着算力的增长,一些过去算力无法满足的复杂算法得以实现,其中有一种方法叫“扩散模型”——一种从气体扩散的物理过程中汲取灵感并试图在多个科学领域模拟相同现象的方法。该模型在图像生成领域展现了巨大的潜力,成为今天StableDiffusion的基础。二、StableDiffusion如何工作?StableDiffusion是一种深度学习模型。我们将深入探讨StableDiffusion是如何工作的。你为什么需要知道这部分内容?除了它本身就是一个引人入胜的主题之外,对内在机制的一些理解将使您成为更好的艺术家。您可以正确使用该工具以获得更高精度的结果。文本到图像(text-to-image)与图像到图像(image-to-image)有何不同?什么是CFG价值?什么是降噪强度?您将在本文中找到答案。三、StableDiffusion能做什么?在最简单的形式中,StableDiffusion是一种文本到图像模式。给它一个文本提示(TextPrompt)。它将返回与文本匹配的图像。StableDiffusion将文本提示转换为图像。四、StableDiffusion的优势1、提供了一个基于网页浏览器的前端交互WebUI,用户只需要简单的输入prompt和设置参数就可以生成难以置信的图片(傻瓜式操作);2、只需文本提示输入就能够模拟和重建几乎任何以视觉形式表达的概念3、提供了多种功能,如文本到图片转换txt2img、图片到图片转换img2img等,能满足使用者的多种需求4、通过调节相关参数可以生成不同的效果,用户可以根据自己的需要在和喜好在本地客户端进行AI创作;5、可扩展性极强,用户可以自由地下载SD模型,LoRA模型,ControlNet模型,还包括模型融合等高级功能6、AI绘图社区支持,专门的模型下载网站HuggingFace和绘画分享网站Civitai(C站)五、扩散模型扩散模型是一种生成模型,用于生成与训练数据相似的数据。简单的说,扩散模型的工作方式是通过迭代添加高斯噪声来“破坏”训练数据,然后学习如何消除噪声来恢复数据。一个标准扩散模型有两个主要过程:正向扩散和反向扩散。在正向扩散阶段,通过逐渐引入噪声来破坏图像,直到图像变成完全随机的噪声。在反向扩散阶段,使用一系列马尔可夫链逐步去除预测噪声,从高斯噪声中恢复数据六、StableDiffusion组成StableDiffusion的核心思想是,由于每张图片满足一定规律分布,利用文本中包含的这些分布信息作为指导,把一张纯噪声的图片逐步去噪,生成一张跟文本信息匹配的图片。它其实是一个比较组合的系统,里面包含了多个模型子模块,接下来把黑盒进行一步步拆解。stablediffusion最直接的问题是,如何把人类输入的文字串转换成机器能理解的数字信息。这里就用到了文本编码器textencoder(蓝色模块),可以把文字转换成计算机能理解的某种数学表示,它的输入是文字串,输出是一系列具有输入文字信息的语义向量。有了这个语义向量,就可以作为后续图片生成器imagegenerator(粉黄组合框)的一个控制输入,这也是stablediffusion技术的核心模块。图片生成器,可以分成两个子模块(粉色模块+黄色模块)来介绍。七、StableDiffusion的应用前景StableDiffusion在图像处理、艺术创作、广告设计等领域具有广泛的应用前景。图像处理:StableDiffusion可以用于图像的生成、去噪、增强等任务。通过调整模型的参数和输入,我们可以生成符合特定需求的图像,如风格迁移、超分辨率重建等。艺术创作:StableDiffusion为艺术家提供了一种全新的创作方式。他们可以通过输入文字描述,让模型自动生成符合其想象的图像。这种方式不仅可以提高创作的效率,还可以帮助艺术家探索新的创作灵感。广告设计:StableDiffusion可以根据广告的需求,自动生成符合要求的图像素材。这不仅可以节省设计师的时间和精力,还可以提高广告的吸引力和效果。此外,StableDiffusion还可以与其他技术结合使用,如自然语言处理(NLP)技术,实现更复杂的任务,如文本到视频的转换等
  • 所需E币: 0
    时间: 2024-6-24 15:24
    大小: 3.05KB
    虽然Flutter的成长曲线和未来前景看起来都很好,但不可否认的是,目前Flutter仍处在发展阶段,很多大型互联网企业都无法毫无顾虑地让全线App接入,而其中最主要的顾虑是包大小与动态化。动态化代表着更短的需求上线路径,代表着大大压缩了原始包的大小,从而获得更高的用户下载意向,也代表着更健全的线上质量维护体系。当明白这些意义后,我们也就不难理解,在Flutter的应用与适配趋近完善时,动态化自然就成为了一个无法避开的话题。RN和Weex等成熟技术甚至让大家认为动态化是跨端技术的标配。一、什么是动态化?目前移动端应用的版本更新,最常见的方式是定期发版,无论是安卓还是iOS,都需要提交新的安装包到应用市场进行审核。审核通过后,用户在应用市场进行App的下载更新。而动态化,就是不依赖更新程序安装包,就能动态实时更新页面的技术。二、动态化的必要性为什么需要动态化技术呢?因为上述定期发版更新应用的方式存在一些问题,比如:1、审核周期长,且可能审核不通过。周期长导致发版本不够灵活,紧急的业务需求不能及时上线。2、线上出现急需修复的bug时,需要较长修复周期,影响用户体验。3、安装包过大,动辄几十兆几百兆的应用升级可能会让用户比较抗拒。4、即使上线了,也无法达到全部用户升级,服务端存在兼容多版本App的问题。三、Flutter的动态化可以通过在Flutter应用程序中集成可编程的UI组件来实现,例如将Dart代码作为字符串从服务器端下载并评估,从而生成新的UI元素。下面是一些设计思路和代码实现:1、使用Flutter的自定义渲染器(CustomRenderer):您可以编写一个自定义渲染器,该渲染器将解析从服务器或其他来源下载的UI描述,并使用FlutterFrameworkAPI构建UI元素。这种方法需要更多的开发工作,但它提供了更大的灵活性和控制权。2、使用FlutterWidget树序列化:FlutterWidget树可以序列化为JSON格式,并可以发送到移动设备上的Flutter应用程序。您可以使用此功能,从远程服务器下载UI树并将其反序列化为真实的Flutter组件树。3、使用Flutter插件:在Flutter中,插件是一个独立的、客户端库,在Flutter应用程序中运行。您可以编写一个插件,使其可以从云服务器下载所有UI元素并展示给用户四、实现思路 按道理iOS上也可以采取跟Android同样的思路,但是由于苹果开发者协议的规定,不允许动态更新、运行可执行代码;所以在Flutter资源的处理上,我们可以采用同Android一样的思路,但是对代码的处理,我们需要寻找新的方案。回顾之前的这些跨端方案,我们可以参照RN的实现,只不过N不再是Native了,而是Flutter。RN是通过JS控制Native渲染,我们要实现的是通过JS控制Flutter渲染。五、Flutter发展前景随着移动应用市场的不断扩大,跨平台开发框架的需求也越来越大。Flutter框架可以帮助开发者在不同平台上快速开发高质量的移动应用程序,这种趋势将进一步推动Flutter的发展和普及。作为一名Android开发工程师,学习Flutter框架是非常有必要的。因为现在的前端开发已经不仅仅局限于网页开发,而是需要涉及到多个平台的应用开发。如果掌握了Flutter框架的开发技能,就可以更好地满足前端开发的多样化需求。从19年过去的几年时间,Flutter在Google带领各大厂商的引领下,飞速发展。fluttersdk官方也在快速的迭代升级,从1.0到现在的3.1,从底层引擎到适配层再到框架层都有比较大的更新。六、Flutter动态化解决方案的两种方法:1.热重载(HotReload):热重载是Flutter框架的一项独特功能,它允许开发者在应用运行时快速预览代码更改的效果,而无需重新启动整个应用。热重载使开发人员可以实时查看界面、布局和功能等变化,并立即在应用中看到这些变化的效果。2.插件化(FlutterPlugin):插件化是一种在Flutter应用中集成动态化插件的方法,可以在应用运行时动态加载新的功能模块或代码。开发人员可以编写自定义插件,将其集成到应用中,以实现动态化更新和扩展功能的目的。七、动态化方案调研在Flutter实践层面,简单来说分为三个流派:方案一:JavaScript是最好的语言(碰瓷PHP)主要思路:利用Flutter做渲染,开发使用js,逻辑层通过v8/jscore解释运行。代表框架是腾讯的MXFlutter。这个框架是开源的,大写的。方案二:DSL+JS主要思路:基于模板实现动态化,主要布局层采用Dart转DSL的方式,逻辑层使用JS。代表框架是58同城开源的Fair。方案三:布局,逻辑,一把梭主要思路:与方案一最主要的区别是,逻辑层也是使用dart,增加了一层语法解析和运行时。有一个代表,美团的MTFlutter,然而没有开源动向,无从考察更多。
  • 所需E币: 0
    时间: 2024-4-19 15:55
    大小: 2.43KB
    上传者: 开心就很好了
    随着国内越来越多的企业开始使用Go语言,Go语言一度变得火热,成为不少程序员朋友的首选语言。Go语言最早诞生于谷歌,出自谷歌的三位大牛之手,自2009年发布以来,Go语言已经度过了第12个年头,相比于其它语言,可谓是语言界的新生儿。Go是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易Go是从2007年末由RobertGriesemer,RobPike,KenThompson主持开发,后来还加入了IanLanceTaylor,RussCox等人,并最终于2009年11月开源,在2012年早些时候发布了Go1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。Go是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。Go的语法接近C语言,但对于变量的声明有所不同,Go支持垃圾回收功能。Go是从2007年末由RobertGriesemer,RobPike,KenThompson主持开发,后来还加入了IanLanceTaylor,RussCox等人,并最终于2009年11月开源,在2012年早些时候发布了Go1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。目前Go语言支持Windows、Linux等多个平台,也可以直接在Android和iOS等移动端执行,从业务角度来看,Go语言在云计算、微服务、大数据、区块链、物联网、人工智能等领域都有广泛的应用。所以当下学习正当时。go语言特点天生支持并发语法简单,容易上手内置runtime,支持垃圾回收可直接编译成机器码,不依赖其他库丰富的便准库可跨平台编译部署维护成本低go语言应用领域服务器编程开发云平台区块链分布式系统网络编程Go语言用途Go语言被设计成一门应用于搭载Web服务器,存储集群或类似用途的巨型中央服务器的系统编程语言。对于高性能分布式系统领域而言,Go语言无疑比大多数其它语言有着更高的开发效率。它提供了海量并行的支持,这对于游戏服务端的开发而言是再好不过了。命名Go语言中的函数名、变量名、常量名、类型名、语句标号和包名等所有的命名,都遵循一个简单的命名规则:一个名字必须以一个字母(Unicode字母)或下划线开头,后面可以跟任意数量的字母、数字或下划线。大写字母和小写字母是不同的:heapSort和Heapsort是两个不同的名字。Go语言中类似if和switch的关键字有25个;关键字不能用于自定义名字,只能在特定语法结构中使用。声明声明语句定义了程序的各种实体对象以及部分或全部的属性。Go语言主要有四种类型的声明语句:var、const、type和func,分别对应变量、常量、类型和函数实体对象的声明。一个Go语言编写的程序对应一个或多个以.go为文件后缀名的源文件。每个源文件中以包的声明语句开始,说明该源文件是属于哪个包。包声明语句之后是import语句导入依赖的其它包,然后是包一级的类型、变量、常量、函数的声明语句,包一级的各种类型的声明语句的顺序无关紧要(译注:函数内部的名字则必须先声明之后才能使用)简短变量声明在函数内部,有一种称为简短变量声明语句的形式可用于声明和初始化局部变量。它以“名字:=表达式”形式声明变量,变量的类型根据表达式来自动推导。下面是lissajous函数中的三个简短变量声明语句:anim:=gif.GIF{LoopCount:nframes}freq:=rand.Float64()*3.0t:=0.0packagemainimport"fmt"funcmain(){name:="yjh"age:=18  //:=自动推导  fmt.Println(name,age)}这是Go语言的推导声明写法,编译器会自动根据右值类型推断出左值的对应类型。它可以自动的推导出一些类型,但是使用也是有限制的;定义变量,同时显示初始化。不能提供数据类型只能在函数内部。不能随便到处定义
  • 所需E币: 0
    时间: 2024-5-21 11:04
    大小: 2.9KB
    上传者: 开心就很好了
    一、nextjs基本介绍Next.js是一个基于React的轻量级框架,用于构建React应用程序。它在React的基础上提供了一些增强功能,包括服务器渲染(SSR)、静态生成(SSG)、路由等。Next.js的目标是简化React应用程序的开发流程,并提供更好的性能和开发体验。Nextjs是一个使用react作为前端框架底层的支持SSR(请求时渲染)、SSG(构建时渲染)等技术的全栈框架,在2022年的服务端框架中排名第一。它的优点非常明显,既支持react的虚拟dom形式快捷完成开发,又支持访问即可看到完整内容,友好的SEO/浏览器直出形式。结合了静态分离和服务器渲染的双重优势。同时在服务端也非常容易做缓存相关的处理,甚至是做一些中间件的开发,简直是前端开发的神兵利器。当前缺点也有一些,包括跳转的时候会重复下载内容,开发的时候需要一些服务端开发能力,甚至是部署的时候没点本事都部署不明白。以上这些都是Nextjs的内容,作为一个合格的开发者,研究未来趋势的开发能力,使用更有成长潜力的技术,都是我辈需要实践的真理。二、RedwoodJS和NextJS的相似之处这两个框架的设计都使开发人员能够轻松创建快速、安全和可扩展的web应用程序。这两个框架都使用ReactJS库来构建用户界面(UI)。这意味着熟悉ReactJS库的开发人员会发现使用这两种框架中的任何一种构建应用程序都很容易。这两个框架都支持服务器端渲染,允许开发人员在服务器而不是浏览器上渲染网页,从而提高web应用程序的性能。此外,RedwoodJS和NextJS支持自动代码分割,允许开发人员将他们的web应用程序分割成更小的块,可以根据需要加载。三、Next.js主要解决了以下问题:SEO和首屏加载性能:传统的客户端渲染的React应用可能不利于搜索引擎爬虫的抓取,且首次加载时间较长。Next.js提供服务端渲染作为默认行为,这意味着页面在服务器上被渲染为HTML,然后发送给客户端。这样做可以显著提升首屏加载速度,并对搜索引擎优化友好。开发效率:在使用React开发大型应用时,开发者通常需要配置路由、代码拆分、构建优化等。Next.js通过约定大于配置的方式,减少了这些常见任务的手动设置,提供了简易的文件系统路由、自动的代码拆分和热加载,提高了开发效率。构建和部署:Next.js提供现成的构建系统和对持续集成的优化,使得将应用从开发阶段迁移到生产变得简单。此外,与Vercel平台的无缝集成也让部署变得异常轻松。灵活的数据获取策略:Next.js提供了灵活的数据获取方法,如getStaticProps和getServerSideProps,使得开发者可以根据页面的需求选择不同的数据预渲染策略,例如静态生成或服务器端渲染。无需额外设置的TypeScript支持:Next.js从一开始就考虑了对TypeScript的支持,让开发者能够享受到强类型语言带来的好处,而无需复杂的配置。API路由:Next.js允许开发者在同一个项目中构建前端页面和API接口,简化了全栈应用的开发过程。生态系统和社区支持:Next.js随着时间的推移建立起了一个健康的插件生态系统,并且得到了强大的社区支持,这为开发者提供了各种资源和第三方库的集成。总之,Next.js的出现是为了简化和优化基于React的应用开发流程,同时提供了高性能和SEO友好的解决方案,它代表了当代Web应用开发的一个重要趋势。四、主要功能:路由:基于文件系统的路由器构建在服务器组件之上,支持布局、嵌套路由、加载状态、错误处理等。渲染:使用客户端和服务器组件进行客户端和服务器端渲染。使用Next.js在服务器上进一步优化静态和动态渲染。在Edge和Node.js运行时上进行流式传输。数据获取:通过服务器组件中的async/await简化数据获取,以及用于请求记忆、数据缓存和重新验证的扩展获取API。样式:支持您首选的样式方法,包括CSS模块、TailwindCSS和CSS-in-JS优化:图像、字体和脚本优化,以改善应用程序的核心网络生命和用户体验。TypeScript:改进了对TypeScript的支持,具有更好的类型检查和更高效的编译,以及自定义TypeScript插件和类型检查器。五、Next.js可以带给我们什么?Next.js是一个Reactweb应用框架,这是官方对自己的定义,然后它主要做的事情有以下几点:1、完善的工程化机制2、良好的开发和构建性能3、智能文件路由系统4、多种渲染模式来保证页面性能体验5、可扩展配置6、提供其他多方面性能优化方案7、提供性能数据,让开发者更好的分析性能。8、提供的其他常用功能或者扩展,比如使用mdx来编写页面的功能等等
  • 所需E币: 0
    时间: 2024-3-15 13:57
    大小: 2.96KB
    信息系统项目管理师是属于计算机技术与软件专业技术资格(水平)考试(即软考)高级资格考试里面的一项考试。通过该考试的合格人员能够掌握信息系统项目管理的知识体系,具备管理大型、复杂信息系统项目和多项目的经验和能力;能根据需求组织制订可行的项目管理计划;能够组织项目实施,对项目的人员、资金、设备、进度和质量等进行管理,并能根据实际情况及时做出调整,系统地监督项目实施过程的绩效,保证项目在一定的约束条件下达到既定的项目目标;能分析和评估项目管理计划和成果。信息是指音讯、消息、信息系统传输和处理的对象,泛指人类社会传播的一切内容。信息是物质、能力及其属性的标示的集合,是确定性的增加,以物质介质为载体,传递和反映世界各种事务存在方式、运动状态等的表征;信息不是物质,不是能力,是一种普遍形式,表达物质运动规律。香农定理,信息是消除随机不确定的东西/因素,单位为bit信息的特征:客观、普遍、无限、动态、相对、依附、变换、传递、层次、系统、转化;信息的质量属性:精确性、完整性、可靠性、及时性、经济性、可验证性、安全性;信息系统是由相互联系、相互依赖、相互作用的事物或过程组成的具有整体功能和综合行为的统一体。信息系统项目管理师是属于软考高级科目中的一科,是具备高级工程师9的实际工作能力和业务水平,从事信息系统项目管理的高级管理人员、高级项目经理9等。报考人群:一般是适用于社会各界从事计算机应用技术9、软件、网络、信息系统和信息服务9等专业技术工作的人员。报考条件:信息系统项目管理师由于考试向社会开放,不设学历资历条件,都可以报考。而且知识和能力各个科目都及格才能合格,因此合格率并不高。软考有五大专业方向和三个等级,一共有27个资格认证,如果没有进行深入了解的情况下从这27个中选择一个可能会为难。一般情况下,我们进行选择的时候都会结合自己所学的专业方向、所在的工作岗位发展方向去选择,但是我给大家的建议是最好选择偏向管理的岗位,如信息系统项目管理师(高项),因为它有技术需求性不高、管理属性等,适合学生考更适合在工作中遇到瓶颈的人群。考试内容考试内容大致包括信息系统开发基础、信息化与集成技术、系统安全管理、信息系统服务管理、相关法律法规、项目管理基础、管理科学等;别看需要掌握这么多方向,其实仅项目管理就占了大部分,考过PMP认证的同志们学高项就非常有优势,简单学习一下其他方位的理论知识,学学论文写作方式就能参加考试,问题不大。软考的信息系统项目管理师好考吗?说实话信息系统项目管理师考试是一项相对较难的考试,因为它是属于软考高级资格,一看到高级就知道考试难度不小。在2019年重庆市计算机技术与软件专业技术资格(考试)报名网曾发布过2018年和2019年的考试通过率数据,通过对比计算考试通过率在17%左右。但是,不要过于担心,下面我为大家总结一下不好考的三个难点在哪,希望在大家备考的时候有所帮助。难点1:涉及的知识领域较于广泛这是因为信息系统项目管理师的考试是要求考生全面项目管理的基础理论知识和项目实践的能力,考试的内容是包含整个项目从头到尾所有的知识。所以就要求考生需要对整个项目管理过程中的流程有全面的了解和理解难点2:对考生的综合能力要求较高1)要全面掌握项目管理知识信息系统项目管理师需要掌握全面的项目管理知识,包括项目生命周期、项目范围管理、时间管理、成本管理、风险管理等方面的知识。因为这些理论知识为项目管理活动提供了基础动力,并能指导实际项目的管理和执行。2)具备与项目干系人沟通与协调的能力信息系统项目管理师需要与项目团队、客户以及其他相关利益相关者进行有效的沟通与协调。不但需要清晰地传达客户的项目目标、需求和计划,而且要能够倾听和理解各方的需求与反馈,协调解决问题并保持良好的合作关系。3)需要具备领导与团队管理能力一个成功的信息系统项目管理师应具备领导能力,能够激发团队成员的积极性和工作动力,指导和引导团队成员完成各项任务,并有效地管理团队资源和冲突。在项目管理过程中,对产生的冲突进行有效的分析,找到合适的解决方案,并迅速采取行动。4)对项目风险的管理能力信息系统项目管理师需要具备有效的风险管理能力,能够识别潜在的风险,并制定相应的风险应对策略。他们需要评估和监控项目风险,并及时做出调整,确保项目能够按时、按质量要求完成。作为信息系统项目管理师,对相关的技术与工具的了解和熟悉是必要的。需要能够在项目管理活动过程中合理地应用相关技术或工具来支持和管理项目工作。5)项目进度管理与优先级排序能力信息系统项目管理师需要拥有良好的时间管理与优先级排序能力,能够根据项目的紧急程度和重要性,合理安排工作时间,并保证项目进度的按时完成。
  • 所需E币: 0
    时间: 2024-3-22 14:24
    大小: 1.99KB
    Spring能做什么Spring具有哪些能力呢?这点在Spring的官网上有比较详情的描述,我们可以在Spring的项目里看到Spring的生态涵盖了web开发、数据访问、安全控制、分布式、消息服务、移动开发、批处理等等SpringBoot优点SpringBoot的优点我可以在https://spring.io/projects/spring-boot这里看到,下面我把优点复制过来了如下:●Createstand-aloneSpringapplications○创建独立Spring应用●EmbedTomcat,JettyorUndertowdirectly(noneedtodeployWARfiles)○内嵌web服务器●Provideopinionated‘starter’dependenciestosimplifyyourbuildconfiguration○自动starter依赖,简化构建配置●AutomaticallyconfigureSpringand3rdpartylibrarieswheneverpossible○自动配置Spring以及第三方功能●Provideproduction-readyfeaturessuchasmetrics,healthchecks,andexternalizedconfiguration○提供生产级别的监控、健康检查及外部化配置●AbsolutelynocodegenerationandnorequirementforXMLconfiguration○无代码生成、无需编写XMLSpringBoot是整合Spring技术栈的一站式框架SpringBoot是简化Spring技术栈的快速开发脚手架在SpringBoot项目中,正常来说是不存在XML配置,这是因为SpringBoot不推荐使用XML,注意,排不支持,SpringBoot推荐开发者使用Java配置来搭建框架,SpringBoot中,大量的自动化配置都是通过Java配置来实现的,这一套实现方案,我们也可以自己做,即自己也可以使用纯Java来搭建一个SSM环境,即在项目中,不存在任何XML配置,包括web.xml。下面我们开始代码实战:创建maven工程引入依赖<parent>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-parent</artifactId>    <version>2.3.4.RELEASE</version>  </parent>  <dependencies>    <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-web</artifactId>    </dependency>  </dependencies>创建主程序/** *主程序类 *@SpringBootApplication:这是一个SpringBoot应用 */@SpringBootApplicationpublicclassMainApplication{  publicstaticvoidmain(String[]args){    SpringApplication.run(MainApplication.class,args);  }}启动类,启动就可以了packagecom.urthink.upfs.springbootdemo; importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplicationpublicclassSpringBootDemoApplication{   publicstaticvoidmain(String[]args){    SpringApplication.run(SpringBootDemoApplication.class,args);  } }我们将这个依赖拷贝到我们自己的项目pom文件里,粘贴后的pom文件如下<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd">  <modelVersion>4.0.0</modelVersion>  <groupId>com.atguigu</groupId>  <artifactId>boot-01-helloworld</artifactId>  <version>1.0-SNAPSHOT</version>  <parent>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-parent</artifactId>    <version>2.3.4.RELEASE</version>  </parent><dependencies>    <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-web</artifactId>    </dependency>  </dependencies></project>
  • 所需E币: 0
    时间: 2024-3-22 11:17
    大小: 2.63KB
    上传者: 开心就很好了
    SpringBoot一直是开发者比较青睐的一款轻量级框架,他不仅继承了Spring框架原有的优秀特性,而且还通过简化配置来进一步简化了Spring应用的整个搭建和开发过程。现在很多Java系的软件开发都是基于SpringBoot的,这就要求开发人员都要掌握基于SpringBoot的开发。由于SpringBoot体系非常庞大,导致很多人并不能完全掌握如何使用,尤其是涉及分布式相关的开发时,如何和其他框架整合更是让很多程序员无从下手。在此,我给大家整理了几个优质SpringBoot开源项目给大家参考,希望能够帮助到正在学习SpringBoot的小伙伴!小伙伴简历中不知道写什么项目的或者项目没有亮点的,我只能帮你们到这了!随着技术框架的不断更新,一些公司摒弃了原先的技术框架模式。而springboot慢慢取代了原有的ssm框架开发。为什么选择springboot呢?配置简单不需要编写太多的xml;基于spring构建,容易上手;独立运行不依赖于容器;内置服务器tomcat不需要打war包;提供maven极简配置;对于各种框架有很好的集成;为SpringCloud微服务奠定基础,使微服务构建变得简单;下面让我们使用idea一起搭建完整版的SpringBoot项目:首先,确定项目结构现在后端开发都是基于springboot的web项目,web项目一般都是使用MVC的模式,所以这里也采用类似的模式。在项目maven结构组成上,采用父子项目,也就是一个主项目下有多个子module,分为下面几个,p-admin   p-web--》负责项目启动   p-facade --》控制层,写controller   p-service--》服务层,具体的业务处理   p-dao--》持久化层,负责和数据库打交道   p-common--》公共层,util类\入参、出参等   p-api--》提供给第三方的接口大体的项目结构给出来了,下面看子项目间的依赖关系哈,  p-web依赖于p-service、p-common  p-service依赖于p-dao、p-common  p-api依赖于p-common其他的依赖第三方的库暂时不看,下面再说。接下来就可以进行实际操作创建项目了。接着,创建项目创建父项目(p-admin)这里使用maven的父子项目结构,父项目是这样创建的,在idea中file-->new-->project出现下面的界面,直接next就好一、mallmall项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyBatis实现。前台商城系统包含首页门户、商品推荐、商品搜索、商品展示、购物车、订单流程、会员中心、客户服务、帮助中心等模块。后台管理系统包含商品管理、订单管理、会员管理、促销管理、运营管理、内容管理、统计报表、财务管理、权限管理、设置等模块。二、Cloud-Platform(微服务的)Cloud-Platform是国内首个基于SpringCloud微服务化开发平台,具有统一授权、认证后台管理系统,其中包含具备用户管理、资源权限管理、网关API管理等多个模块,支持多业务系统并行开发,可以作为后端服务的开发脚手架。代码简洁,架构清晰,适合学习和直接项目中使用。核心技术采用SpringBoot2.1.2以及SpringCloud(Greenwich.RELEASE)相关核心组件,采用Nacos注册和配置中心,集成流量卫兵Sentinel,前端采用vue-element-admin组件。三、微人事微人事是一个前后端分离的人力资源管理系统,项目采用SpringBoot+Vue开发,项目加入常见的企业级应用所涉及到的技术点,例如Redis、RabbitMQ等。后端技术栈:SpringBoot、SpringSecurity、MyBatis、MySQL、Redis、RabbitMQ、SpringCache、WebSocket前端技术栈Vue、ElementUI、axios、vue-router、Vuex、WebSocket、vue-cli4四、web-flashweb-flash是一个基于SpringBoot和Vue.js的web系统,包含了基于element搭建的后台管理系统和基于vux搭建的手机端h5站点web-flash具备后台管理类系统的通用的基础功能,而且提供了基于ideaintellij的的代码生成插件,可以一键生成前后端页面。核心框架:SpringBoot数据库层:Springdatajpa数据库连接池:Druid缓存:Ehcache前端:基于Vue.js的Element(后端)和vux(手机端)工作流:activiti
  • 所需E币: 0
    时间: 2024-3-1 10:24
    大小: 3.2KB
    上传者: 开心就很好了
    深入学习小程序框架底层原理,培养双线程思维——前端高手特训从0到1带你手写一个微信小程序底层框架!无论你是一位新手,还是一位有经验的开发者,能够自研一套小程序底层框架,都是你突破技术瓶颈有效途径。我将通过本篇文章带领大家从架构设计,原理剖析,再到源码的实现,一步步地实战构建一个完整的微信小程序底层框架,让大家深度掌握小程序双线程原理,助力大家具备把握最佳机会的能力和提升获取心仪Offer的成功率,成为一个真正有实力的技术人才!! 一、首先,我们先来认识小程序,那么什么是小程序呢?小程序是一种不需要下载安装即可使用的应用,它基于某个平台(如微信)运行,用户可以通过扫描二维码或搜索关键词来打开小程序。小程序的特点包括体积小、启动速度快、使用便捷,以及能够实现“用完即走”的理念,减少了用户安装应用的数量。小程序的开发通常采用前端技术,如HTML5、CSS3和JavaScript,并通过封装和提供丰富的API接口,实现与微信生态系统的高度整合。小程序可以提供各种服务,如游戏、购物、地图、社交和学习等,同时帮助商家展示产品、推广服务以及实现线上支付等功能。二、设计思路-渲染层小程序使用的是Exparser组件模型,Exparser组件模型与WebComponents中的shadowDOM高度相似,微信为什么使用自定义组件框架,而不使用WebComponents呢?主要还是出于安全考虑,并且方便管控。既然Exparser组件框架与shadowDOM高度相似,那么我们首先来了解一下shadowDOM。shadowDOM:WebComponents的一个重要属性是封装-可以将标记结构、样式和行为隐藏起来,并与页面上的其他代码相隔离,保证不同的部分不会混在一起,可使代码更加干净、整洁。其中,shadowDOM接口是关键所在,它可以将一个隐藏的,独立的DOM附加到一个元素上。三、Exparser组件模型Exparser组件模型参考了shadowDOM并进行了一些修改,像事件系统就是完全复刻的,slot插槽,属性传递等都基本一致。但同时它又具有一些特点:基于shadowDOM模型:模型上与WebComponents的shadowDOM高度相似,但不依赖浏览器的原生支持,也没有其他依赖库;实现时,还针对性地增加了其他API以支持小程序组件编程;可在纯JS环境中运行:这意味着逻辑层也具有一定的组件树组织能力;高效轻量:性能表现好,在组件实例极多的环境下表现尤其优异,同时代码尺寸也较小;四、逻辑层与视图层通信在小程序中,逻辑层只有一个,但是渲染层有多个,渲染层和逻辑层之间是通过微信客户端进行桥接通信的。那具体是怎么实现的呢?其实它使用的就是WeixinJSBridge通信机制。在小程序执行的过程中,微信客户端分别向渲染层和逻辑层注入WeixinJSBridge,WeixinJSBridge主要提供了以下几个方法:invoke:调用nativeAPI;invokeCallbackHandler:Native传递invoke方法回调结果;publish:渲染层用来向逻辑业务层发送消息,也就是说要调用逻辑层的事件方法;subscribe:订阅逻辑层消息;subscribeHandler:视图层和逻辑层消息订阅转发;setCustomPublishHandler:自定义消息转发;五、微信小程序主流框架有哪些?微信小程序是一种特殊的应用程序,它使用微信平台提供的JavaScript框架来构建。目前,微信小程序主要有以下三个主流框架:1、原生框架(VanillaFramework):原生框架是微信小程序的最基础、最原始的框架,它使用原生的JavaScript、WXML和WXSS来开发小程序。2、MiniprogramFramework(小程序框架):小程序框架是由微信团队提供的官方框架,用于简化小程序的开发过程。它提供了更高层次的抽象和封装,使得开发者可以更快速地构建小程序。3、mpvue:mpvue是一个基于Vue.js的小程序开发框架。它允许开发者使用Vue.js的语法和特性来开发小程序,从而降低了学习成本和提高了开发效率。六、小程序的底层实现原理主要涉及以下几个方面:框架架构:小程序框架通常采用前端框架,如微信小程序使用的是基于JavaScript的框架。这些框架提供了一套开发和运行环境,包括对视图层、逻辑层和数据层的管理和处理。渲染机制:小程序通过渲染引擎将开发者编写的代码转化为可视化界面。渲染引擎负责解析和处理小程序的标记语言,如HTML、XML等,并将其转换为浏览器可以显示的界面。数据通信:小程序需要与服务器进行数据通信,包括获取数据、上传数据等。通常使用HTTP协议进行网络请求,通过发送和接收数据来实现与服务器的交互。安全机制:为了保障用户数据的安全和隐私,小程序实现了一系列安全机制。例如,小程序在沙箱环境中运行,限制了对系统资源的访问权限;小程序代码签名和校验机制确保代码的完整性和安全性;同时,小程序还采用了数据加密、身份验证等措施来保护用户数据的传输和存储安全。跨平台适配:小程序需要在不同的操作系统和设备上运行,因此需要进行跨平台适配。框架会处理不同平台的差异,以确保小程序在不同设备上有一致的运行效果和用户体验。总的来说,小程序底层的实现原理是基于前端技术栈和相关技术,通过框架架构、渲染机制、数据通信、安全机制等来实现小程序的功能和特性。
  • 所需E币: 0
    时间: 2024-2-26 10:46
    大小: 2.97KB
    上传者: 开心就很好了
    一、Spark3.0.0运行环境安装Spark常见部署模式:Local模式:在本地部署单个Spark服务所谓的Local模式,就是不需要其他任何节点资源就可以在本地执行Spark代码的环境,一般用于教学,调试,演示等。在IDEA中运行代码的环境称之为开发环境,和Local模式还是有区别的。Standalone模式:Spark自带的任务调度模式。(国内常用)YARN模式:Spark使用Hadoop的YARN组件进行资源与任务调度。(国内常用)Windows模式:为了方便在学习测试spark程序,Spark提供了可以在windows系统下启动本地集群的方式,这样,在不使用虚拟机或服务器的情况下,也能满足Spark的基本使用。Mesos&K8S模式:(了解)。Mesos是Apache下的开源分布式资源管理框架,它被称为是分布式系统的内核,在Twitter得到广泛使用,管理着Twitter超过30,0000台服务器上的应用部署,但是在国内,依然使用着传统的Hadoop大数据框架,所以国内使用Mesos框架的并不多,但是原理都差不多。容器化部署是目前业界很流行的一项技术,基于Docker镜像运行能够让用户更加方便地对应用进行管理和运维。容器管理工具中最为流行的就是Kubernetes(k8s),而Spark也在最近的版本中支持了k8s部署模式。1、配置javajdk1.8环境变量配置路径:电脑→属性→高级系统设置→环境变量path中加入:%JAVA_HOME%/bin。注:jdk版本不宜过高。2、配置scala2.12.0下载scala安装包,选择对应版本,这里我选择的是scala2.12.0版本。3、配置scala环境环境变量配置路径:此电脑→属性→高级系统设置→环境变量path中加入:%SCALA_HOME%/bin。验证配置cmd验证配置:scala-version4、配置Hadoop3.1.0Hadoop下载从Apache官网下载Hadoop,官网下载速度较慢,也可使用国内镜像下载。Hadoop环境变量配置,配置步骤同Scala配置。注意:需要把%HADOOP_HOME%\bin与%HADOOP_HOME%\sbin一同加入path中。5、配置Spark3.0.3Spark下载Spark环境配置,配置步骤同scala配置。注意:需要把%SPARK_HOME%\bin与%SPARK_HOME%\sbin一同加入path中。配置验证cmd命令:spark-shellSpark配置成功。二、spark实战Spark是用于大规模数据处理的统一分析引擎,也可以说是目前用于可伸缩计算的最广泛的引擎,成千上万的公司包括财富500强中的80%都在使用。Spark生态系统集成了丰富的数据科学、机器学习、SQL分析和BI、存储和基础设施等框架,并将这个生态使用可以扩展到数千台机器大规模数据使用。Spark提供了Java、Scala、Python和R的高级api,以及支持通用执行图的优化引擎。Spark支持一系列丰富的高级工具,包括用于SQL和结构化数据处理的SparkSQL,用于pandas工作负载的Spark上的pandasAPI,用于机器学习的MLlib,用于图形处理的GraphX,以及用于增量计算和流处理的StructuredStreaming。Spark自身节点运行的集群模式,也就是我们所谓的独立部署(Standalone)模式,Spark的Standalone模式体现了经典的master-slave模式。#拷贝一个部署spark-standalone目录cp-rspark-3.3.0-bin-hadoop3spark-standalone#进入目录cdspark-standalone/cdconf#准备workers配置文件mvworkers.templateworkers#修改workers内容为viworkershadoop1hadoop2hadoop3#准备spark-env.sh配置文件mvspark-env.sh.templatespark-env.sh#spark-env.sh添加如下内容vispark-env.sexportJAVA_HOME=/home/commons/jdk8SPARK_MASTER_HOST=hadoop1SPARK_MASTER_PORT=7077#分发到其他两台上scp-r/home/commons/spark-standalonehadoop2:/home/commons/scp-r/home/commons/spark-standalonehadoop3:/home/commons/#进入根目录下sbin执行目录和启动cdsbin/./start-all.sh由于spark-shell停止掉后,集群监控页面就看不到历史任务的运行情况,所以开发时都配置历史服务器记录任务运行情况。#先停止前面启动的集群./stop-all.sh#准备spark-defaults.confcd../confmvspark-defaults.conf.templatespark-defaults.conf#修改spark-defaults.confvimspark-defaults.confspark.eventLog.enabled     truespark.eventLog.dir       hdfs://myns:8020/sparkhis#需要启动Hadoop集群,HDFS上的目录需要提前存在hadoopfs-mkdir/sparkhis#修改spark-env.sh文件,添加如下配置:vispark-env.shexportSPARK_HISTORY_OPTS="-Dspark.history.ui.port=18080 -Dspark.history.fs.logDirectory=hdfs://myns:8020/sparkhis-Dspark.history.retainedApplications=30"#参数1含义:WEBUI访问的端口号为18080#参数2含义:指定历史服务器日志存储路径(读)#参数3含义:指定保存Application历史记录的个数,如果超过这个值,旧的应用程序信息将被删除,这个是内存中的应用数,而不是页面上显示的应用数。由于hadoop是HA模式因此配置为hdfs-site.xml下的dfs.nameservices的value值  <property>    <name>dfs.nameservices</name>    <value>myns</value><!--core-site.xml的fs.defaultFS使用该属性值-->  </property>#分发配置到另外两台上scpspark-defaults.confspark-env.shhadoop2:/home/commons/spark-standalone/conf/scpspark-defaults.confspark-env.shhadoop3:/home/commons/spark-standalone/conf/#启动集群./start-all.sh#启动历史服务./start-history-server.sh
  • 所需E币: 0
    时间: 2024-1-9 14:40
    大小: 2.77KB
    在现如今的信息化时代,相信各位读者对于“操作系统”这四个字并不陌生。例如我们常常使用的Windows、安卓、IOS、MacOS以及Linux等,都属于操作系统。操作系统,是现如今信息化时代中不可或缺的一种软件。Linux操作系统是一种开源的、基于Unix的操作系统。它最初由芬兰计算机科学家LinusTorvalds在1991年开发,并得到了全球范围内广泛的应用和支持。Linux操作系统具有稳定性、安全性、可靠性和灵活性等特点,广泛应用于服务器领域,也被许多个人用户选择作为他们的主要操作系统。Linux提供了丰富的命令行工具和图形界面,支持各种编程语言和软件开发环境,是一个非常强大而且自由开放的操作系统。操作系统是指控制和管理整个计算机系统的硬件与软件资源,合理地组织、调度计算机的工作与资源的分配,进而为用户和其他软件提供方便接口与环境的程序集合,操作系统是计算机系统中最基本的系统软件。操作系统(OperatingSystem,OS):是管理计算机硬件与软件资源的系统软件,同时也是计算机系统的内核与基石。操作系统需要处理管理与配置内存、决定系统资源供需的优先次序、控制输入与输出设备、操作网络与管理文件系统等基本事务。操作系统也提供一个让用户与系统交互的操作界面。下面我们进行代码实战,让大家更深入的理解操作系统的本质:<divclass="site-content__wrapper">  <mainclass="site-content"    :class="{'site-content--tabs':$route.meta.isTab}">    <el-tabsv-if="$route.meta.isTab"      v-model="siteContent.mainTabsActiveName":closable="true"      @tab-click="selectedTabHandle"      @tab-remove="removeTabHandle">      <el-tab-panev-for="iteminsiteContent.mainTabs"        :label="item.title":name="item.name">        <el-card:body-style="siteContent.siteContentViewHeight">          <router-view:key="router.currentRoute.value.query.random"/>        </el-card>      </el-tab-pane>    </el-tabs>    <el-cardv-else:body-style="siteContent.siteContentViewHeight">      <router-view:key="router.currentRoute.value.query.random"/>    </el-card>  </main></div>在框架页面的模型层中,定义removeTabHandle()封装函数。functionremoveTabHandle(tabName){  //让mainTabs数组剔除要关闭的Tab  siteContent.mainTabs=siteContent.mainTabs.filter(item=>item.name!==tabName);  //如果还存在剩余的Tab,就切换到最后的Tab上面  if(siteContent.mainTabs.length>=1){    //获取mainTabs数组最后一个元素    lettab=siteContent.mainTabs[siteContent.mainTabs.length-1];    //选中这个Tab控件    siteContent.mainTabsActiveName=tab.name;    //内容区切换引用的页面    router.push({name:tab.name});  }else{    siteContent.mainTabsActiveName='';    router.push({name:'MisHome'});  }}这个注解会拦截Web方法的请求,让SaToken验证客户端提交的Token令牌。如果令牌合法就允许调用Web方法,反之就拒绝HTTP请求,返回401状态码。@RestController@RequestMapping("/mis/user")publicclassUserController{  ……     @GetMapping("/searchUserSummary")  @SaCheckLogin  publicRsearchUserSummary(){    ……  }}在user.vue页面中,添加<el-dialog>标签,它可以实现弹窗的效果。<selectid="searchUsernameById"parameterType="int"resultType="String">  SELECTusername  FROMtb_user  WHEREid=#{userId}</select><updateid="updatePassword"parameterType="Map">  UPDATEtb_user  SETpassword=#{newPassword}  WHEREid=#{userId}   ANDpassword=#{password}</update>在com.example.his.api.mis.service.impl包UserServiceImpl.java类中,实现抽象方法。@ServicepublicclassUserServiceImplimplementsUserService{  ……  @Override  publicintupdatePassword(Mapparam){    intuserId=MapUtil.getInt(param,"userId");    Stringusername=userDao.searchUsernameById(userId);    MD5md5=MD5.create();    Stringpassword=MapUtil.getStr(param,"password");    Stringtemp=md5.digestHex(username);    StringtempStart=StrUtil.subWithLength(temp,0,6);    StringtempEnd=StrUtil.subSuf(temp,temp.length()-3);    password=md5.digestHex(tempStart+password+tempEnd).toUpperCase();    param.replace("password",password);    StringnewPassword=MapUtil.getStr(param,"newPassword");    newPassword=md5.digestHex(tempStart+newPassword+tempEnd).toUpperCase();    param.replace("newPassword",newPassword);    introws=userDao.updatePassword(param);    returnrows;  }}在com.example.his.api.mis.controller包UserController.java类中,声明Web方法。@RestController@RequestMapping("/mis/user")publicclassUserController{  ……  @PostMapping("/updatePassword")  @SaCheckLogin  publicRupdatePassword(@Valid@RequestBodyUpdatePasswordFormform){    intuserId=StpUtil.getLoginIdAsInt();    HashMapparam=newHashMap(){{      put("userId",userId);      put("password",form.getPassword());      put("newPassword",form.getNewPassword());    }};    introws=userService.updatePassword(param);    returnR.ok().put("rows",rows);  }}
  • 所需E币: 0
    时间: 2023-12-21 16:08
    大小: 3.22KB
    目前主流的Java分布式框架有哪些,学起来难不难?Java的框架主要有:SpringMVC、Spring、Mybatis、Dubbo、Maven、RabbitMQ、Log4j、Ehcache、Redis、Shiro等等今天就给大家讲讲关于Java主流分布式的一些解决方法,内容包括:JVM锁和MySql锁解决库存超卖问题、基于Redisson框架实现分布式锁及实战&源码深入剖析、基于ZooKeeper实现分布式锁、分布式存储系统Etcd实现分布式锁、实现分布式锁通用SDK与集成、七种分布式事务解决方案、分布式事务Seata框架深入剖析、分库分表利器一-Sharding-JDBC实战等等内容。我将分别从源码、手撸框架、实战演练等多个方面进行多维度深入讲解,让大家轻松掌握分布式各种解决方案。首先我要问大家一个问题:大型项目分布式系统核心问题你能解决多少?1、分布式锁1.你知道Etcd如何实现分布式锁的吗?2.你知道Redis实现的分布式锁存在什么问题吗?3.不同分布式锁实现方案的优缺点你清楚了吗?4.如果让你手撸实现Redis分布式锁,你可以做到吗?2、分布式事务1.你知道为什么CAP不能同时满足吗?2.你了解不同分布式事务解决方案对应什么样的应用场景么?3.你知道为什么大多数业务场景都选择了最终一致性实现方案么?4.你了解Seata框架为什么当下如此受欢迎么?3、分布式ID1.这么多种分布式ID生成方式,应该选择哪种呢?2.雪花算法底层实现原理是什么?4、分库分表1.当数据量大了之后,我们应该如何选择分库分表的解决方案?2.做分库分表,是应该垂直切分还是水平切分?带着这些问题,我们一起来展开代码实战:新增和修改我们封装一个通用方法updateItem(),该方法传入两个参数:storeName、data,storeName表示对象仓库名称,data是一个对象,包含主键和索引,在调用indexedDB所提供的put()方法,在新增操作的时候不需要传入索引的键值对,修改操作的时候在该方法中另外多传递一个主键的键值对,这样才能根据id去修改对应的某一条数据。updateItem(storeName:string,data:any){  console.log(this.db)  conststore=this.db.transaction([storeName],'readwrite').objectStore(storeName)  constrequest=store.put({   ...data,   updateTIme:newDate().getTime()  })  request.onsuccess=(event:any)=>{   console.log('数据写入成功')   console.log(event)  }  request.onerror=(event:any)=>{   console.log('数据写入失败')   console.log(event)  }}关键点是根据传入key即为主键id的值来查询某一条数据,需要使用到indexedDB提供的get()方法来实现查询操作。getItem(storeName:string,key:number|string){  conststore=this.db.transaction([storeName],'readwrite').objectStore(storeName)  constrequest=store.get(key)  request.onsuccess=(event:any)=>{   console.log('查询某一条数据成功')   console.log(event.target.result)  }  request.onerror=(event:any)=>{   console.log('查询某一条数据失败')   console.log(event)  }}为了更好的获取indexedD事务中的返回结果,我们使用promise来包装一下上一小节indexedDB.ts中定义的几个方法:openStore、updateItem、deleteItem、getList、getItem。下面代码片段为getList() //查询所有数据 getList(storeName:string){  conststore=this.db.transaction(storeName).objectStore(storeName)  constrequest=store.getAll()  returnnewPromise((resolve,reject)=>{   request.onsuccess=(event:any)=>{    console.log('查询所有数据成功')    console.log(event.target.result)    resolve(event.target.result)   }   request.onerror=(event:any)=>{    console.log('查询所有数据失败')    console.log(event)    reject(event)   }  }) }在第一步中,首先使用Typescript的interface为store中的所有state声明类型,然后将interface放置在InjectionKeyd的泛型类型中,代码片段如下://src/store/index.tsimport{createStore,Store}from'vuex'import{InjectionKey}from'vue'//为storestate声明类型exportinterfaceAllStateTypes{ count:number, locale:any, userStatus:Number}//定义injectionkeyexportconstkey:InjectionKey<Store<AllStateTypes>>=Symbol('storeKey')exportconststore=createStore<AllStateTypes>({ //...})通过环境变量区分server.js中的一些代码片段,因为有些代码需要运行在开发环境,而有些代码需要运行在生产环境。本小节在server.js中一共对3个地方进行了环境区分,代码片段如下://server.jsif(!isProd){ //1.读取index.html template=fs.readFileSync(  path.resolve(__dirname,'index.html'),  'utf-8' ) //2.应用ViteHTML转换。这将会注入ViteHMR客户端, //  同时也会从Vite插件应用HTML转换。 //  例如:@vitejs/plugin-react-refresh中的globalpreambles template=awaitvite.transformIndexHtml(url,template) //3.加载服务器入口。vite.ssrLoadModule将自动转换 //  你的ESM源码使之可以在Node.js中运行!无需打包 //  并提供类似HMR的根据情况随时失效。 render=(awaitvite.ssrLoadModule('/src/entry-server.ts')).render}else{ //1.读取index.html template=fs.readFileSync(  path.resolve(__dirname,'dist/client/index.html'),  'utf-8' ) //3.加载服务器入口 render=require('./dist/server/entry-server.ts').render}fetchElephant()接口中有两个await,分别依次执行连接数据库和查询数据的操作,我们接下来在home.vue中引入这个Mock接口,然后调用,代码片段如下所示://home.vue//Mock接口functiongetElephant(){ fetchElephant().then(res=>{  console.log('Mock接口',res) })}getElephant()通过emit触发父组件上的事件,将language传递给父组件,并赋值给父组件中的全局组件<ElConfigProvider/>上的locale属性,同样也赋值给useI18n()实例上的locale属性,这样就可以实现在子组件headearCommon.vue中进行国际化切换操作并作用到父组件App.vue中
  • 所需E币: 0
    时间: 2023-12-22 10:13
    大小: 3.93KB
    上传者: 开心就很好了
    Java并发编程从入门到进阶多场景实战,众所周知,并发编程是优秀工程师的标准之一,但知识庞杂,复杂性高,常常让人望而却步。但如果没有掌握背后的核心原理,你开发的代码可能会成为难以调试和优化的头疼问题。在此,我将通过上百个案例场景驱动教学+动画直观演示,帮助大家深入、直观地理解并发编程核心概念和底层原理。助力大家在实际工作和面试中都能尽早脱颖而出。首先,我们先来了解关于并发的基本概念。并发情况主要会引出三个基本概念,分别是原子性、可见性、有序性三个基本概念Java中线程的状态分为6种:1.初始(NEW):新创建了一个线程对象,但还没有调用start()方法。2.运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。3.阻塞(BLOCKED):表示线程阻塞于锁。4.等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。5.超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。6.终止(TERMINATED):表示该线程已经执行完毕。其实我们可以通过job.setPartitionerClass来设置分区类,不过目前我们是没有设置的,那框架中是不是有默认值啊,是有的,我们可以通过job.getPartitionerClass方法看到默认情况下会使用HashPartitioner这个分区类那我们来看一下HashPartitioner的实现是什么样子的/**Partitionkeysbytheir{@linkObject#hashCode()}.*/@InterfaceAudience.Public@InterfaceStability.StablepublicclassHashPartitioner<K,V>extendsPartitioner<K,V>{ /**Use{@linkObject#hashCode()}topartition.*/ publicintgetPartition(Kkey,Vvalue,             intnumReduceTasks){  return(key.hashCode()&Integer.MAX_VALUE)%numReduceTasks; }}下面我们来具体跑一个这份数据,首先复制一份WordCountJob的代码,新的类名为WordCountJobSkewpackagecom.imooc.mr;importorg.apache.hadoop.conf.Configuration;importorg.apache.hadoop.fs.Path;importorg.apache.hadoop.io.LongWritable;importorg.apache.hadoop.io.Text;importorg.apache.hadoop.mapreduce.Job;importorg.apache.hadoop.mapreduce.Mapper;importorg.apache.hadoop.mapreduce.Reducer;importorg.apache.hadoop.mapreduce.lib.input.FileInputFormat;importorg.apache.hadoop.mapreduce.lib.output.FileOutputFormat;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importjava.io.IOException;/** *数据倾斜-增加Reduce任务个数 * *Createdbyxuwei */publicclassWordCountJobSkew{  /**   *Map阶段   */  publicstaticclassMyMapperextendsMapper<LongWritable,Text,Text,LongWritable>{    Loggerlogger=LoggerFactory.getLogger(MyMapper.class);    /**     *需要实现map函数     *这个map函数就是可以接收<k1,v1>,产生<k2,v2>     *@paramk1     *@paramv1     *@paramcontext     *@throwsIOException     *@throwsInterruptedException     */    @Override    protectedvoidmap(LongWritablek1,Textv1,Contextcontext)        throwsIOException,InterruptedException{      //输出k1,v1的值      //System.out.println("<k1,v1>=<"+k1.get()+","+v1.toString()+">");      //logger.info("<k1,v1>=<"+k1.get()+","+v1.toString()+">");      //k1代表的是每一行数据的行首偏移量,v1代表的是每一行内容      //对获取到的每一行数据进行切割,把单词切割出来      String[]words=v1.toString().split("");      //把单词封装成<k2,v2>的形式      Textk2=newText(words[0]);      LongWritablev2=newLongWritable(1L);      //把<k2,v2>写出去      context.write(k2,v2);    }  }  /**   *Reduce阶段   */  publicstaticclassMyReducerextendsReducer<Text,LongWritable,Text,LongWritable>{    Loggerlogger=LoggerFactory.getLogger(MyReducer.class);    /**     *针对<k2,{v2...}>的数据进行累加求和,并且最终把数据转化为k3,v3写出去     *@paramk2     *@paramv2s     *@paramcontext     *@throwsIOException     *@throwsInterruptedException     */    @Override    protectedvoidreduce(Textk2,Iterable<LongWritable>v2s,Contextcontext)        throwsIOException,InterruptedException{      //创建一个sum变量,保存v2s的和      longsum=0L;      //对v2s中的数据进行累加求和      for(LongWritablev2:v2s){        //输出k2,v2的值        //System.out.println("<k2,v2>=<"+k2.toString()+","+v2.get()+">");        //logger.info("<k2,v2>=<"+k2.toString()+","+v2.get()+">");        sum+=v2.get();//模拟Reduce的复杂计算消耗的时间        if(sum%200==0){          Thread.sleep(1);        }      }      //组装k3,v3      Textk3=k2;      LongWritablev3=newLongWritable(sum);      //输出k3,v3的值      //System.out.println("<k3,v3>=<"+k3.toString()+","+v3.get()+">");      //logger.info("<k3,v3>=<"+k3.toString()+","+v3.get()+">");      //把结果写出去      context.write(k3,v3);    }  }  /**   *组装Job=Map+Reduce   */  publicstaticvoidmain(String[]args){    try{      if(args.length!=3){        //如果传递的参数不够,程序直接退出        System.exit(100);      }      //指定Job需要的配置参数      Configurationconf=newConfiguration();      //创建一个Job      Jobjob=Job.getInstance(conf);      //注意了:这一行必须设置,否则在集群中执行的时候是找不到WordCountJob这个类的      job.setJarByClass(WordCountJobSkew.class);      //指定输入路径(可以是文件,也可以是目录)      FileInputFormat.setInputPaths(job,newPath(args[0]));      //指定输出路径(只能指定一个不存在的目录)      FileOutputFormat.setOutputPath(job,newPath(args[1]));      //指定map相关的代码      job.setMapperClass(MyMapper.class);      //指定k2的类型      job.setMapOutputKeyClass(Text.class);      //指定v2的类型      job.setMapOutputValueClass(LongWritable.class);      //指定reduce相关的代码      job.setReducerClass(MyReducer.class);      //指定k3的类型      job.setOutputKeyClass(Text.class);      //指定v3的类型      job.setOutputValueClass(LongWritable.class);      //设置reduce任务个数      job.setNumReduceTasks(Integer.parseInt(args[2]));      //提交job      job.waitForCompletion(true);    }catch(Exceptione){      e.printStackTrace();    }  }}针对这个操作我们需要去修改代码,在这里我们再重新复制一个类,基于WordCountJobSkew复制,新的类名是WordCountJobSkewRandKeypackagecom.imooc.mr;importorg.apache.hadoop.conf.Configuration;importorg.apache.hadoop.fs.Path;importorg.apache.hadoop.io.LongWritable;importorg.apache.hadoop.io.Text;importorg.apache.hadoop.mapreduce.Job;importorg.apache.hadoop.mapreduce.Mapper;importorg.apache.hadoop.mapreduce.Reducer;importorg.apache.hadoop.mapreduce.lib.input.FileInputFormat;importorg.apache.hadoop.mapreduce.lib.output.FileOutputFormat;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importjava.io.IOException;importjava.util.Random;/** *数据倾斜-把倾斜的数据打散 * *Createdbyxuwei */publicclassWordCountJobSkewRandKey{  /**   *Map阶段   */  publicstaticclassMyMapperextendsMapper<LongWritable,Text,Text,LongWritable>{    Loggerlogger=LoggerFactory.getLogger(MyMapper.class);    Randomrandom=newRandom();    /**     *需要实现map函数     *这个map函数就是可以接收<k1,v1>,产生<k2,v2>     *@paramk1     *@paramv1     *@paramcontext     *@throwsIOException     *@throwsInterruptedException     */    @Override    protectedvoidmap(LongWritablek1,Textv1,Contextcontext)        throwsIOException,InterruptedException{      //输出k1,v1的值      //System.out.println("<k1,v1>=<"+k1.get()+","+v1.toString()+">");      //logger.info("<k1,v1>=<"+k1.get()+","+v1.toString()+">");      //k1代表的是每一行数据的行首偏移量,v1代表的是每一行内容      //对获取到的每一行数据进行切割,把单词切割出来      String[]words=v1.toString().split("");      //把单词封装成<k2,v2>的形式      Stringkey=words[0];      if("5".equals(key)){        //把倾斜的key打散,分成10份        key="5"+"_"+random.nextInt(10);      }      Textk2=newText(key);      LongWritablev2=newLongWritable(1L);      //把<k2,v2>写出去      context.write(k2,v2);    }  }  /**   *Reduce阶段   */  publicstaticclassMyReducerextendsReducer<Text,LongWritable,Text,LongWritable>{    Loggerlogger=LoggerFactory.getLogger(MyReducer.class);    /**     *针对<k2,{v2...}>的数据进行累加求和,并且最终把数据转化为k3,v3写出去     *@paramk2     *@paramv2s     *@paramcontext     *@throwsIOException     *@throwsInterruptedException     */    @Override    protectedvoidreduce(Textk2,Iterable<LongWritable>v2s,Contextcontext)        throwsIOException,InterruptedException{      //创建一个sum变量,保存v2s的和      longsum=0L;      //对v2s中的数据进行累加求和      for(LongWritablev2:v2s){        //输出k2,v2的值        //System.out.println("<k2,v2>=<"+k2.toString()+","+v2.get()+">");        //logger.info("<k2,v2>=<"+k2.toString()+","+v2.get()+">");        sum+=v2.get();        //模拟Reduce的复杂计算消耗的时间        if(sum%200==0){          Thread.sleep(1);        }      }      //组装k3,v3      Textk3=k2;      LongWritablev3=newLongWritable(sum);      //输出k3,v3的值      //System.out.println("<k3,v3>=<"+k3.toString()+","+v3.get()+">");      //logger.info("<k3,v3>=<"+k3.toString()+","+v3.get()+">");      //把结果写出去      context.write(k3,v3);    }  }  /**   *组装Job=Map+Reduce   */  publicstaticvoidmain(String[]args){    try{      if(args.length!=3){        //如果传递的参数不够,程序直接退出        System.exit(100);      }      //指定Job需要的配置参数      Configurationconf=newConfiguration();      //创建一个Job      Jobjob=Job.getInstance(conf);      //注意了:这一行必须设置,否则在集群中执行的时候是找不到WordCountJob这个类的      job.setJarByClass(WordCountJobSkewRandKey.class);      //指定输入路径(可以是文件,也可以是目录)      FileInputFormat.setInputPaths(job,newPath(args[0]));      //指定输出路径(只能指定一个不存在的目录)      FileOutputFormat.setOutputPath(job,newPath(args[1]));      //指定map相关的代码      job.setMapperClass(MyMapper.class);      //指定k2的类型      job.setMapOutputKeyClass(Text.class);      //指定v2的类型      job.setMapOutputValueClass(LongWritable.class);      //指定reduce相关的代码      job.setReducerClass(MyReducer.class);      //指定k3的类型      job.setOutputKeyClass(Text.class);      //指定v3的类型      job.setOutputValueClass(LongWritable.class);      //设置reduce任务个数      job.setNumReduceTasks(Integer.parseInt(args[2]));      //提交job      job.waitForCompletion(true);    }catch(Exceptione){      e.printStackTrace();    }  }}调用parallelize()时,有一个重要的参数可以指定,就是将集合切分成多少个partition。Spark会为每一个partition运行一个task来进行处理。Spark默认会根据集群的配置来设置partition的数量。我们也可以在调用parallelize()方法时,传入第二个参数,来设置RDD的partition数量,例如:parallelize(arr,5)scala代码如下:packagecom.imooc.scalaimportorg.apache.spark.{SparkConf,SparkContext}/** *需求:使用集合创建RDD *Createdbyxuwei */objectCreateRddByArrayScala{ defmain(args:Array[String]):Unit={  //创建SparkContext  valconf=newSparkConf()  conf.setAppName("CreateRddByArrayScala")//设置任务名称  .setMaster("local")//local表示在本地执行  valsc=newSparkContext(conf)  //创建集合  valarr=Array(1,2,3,4,5)  //基于集合创建RDD  valrdd=sc.parallelize(arr)  valsum=rdd.reduce(_+_)  println(sum)  //停止SparkContext  sc.stop() }}
  • 所需E币: 0
    时间: 2023-12-25 11:06
    大小: 3.48KB
    LinuxSocket网络编程框架主要由3大模块组成:BSDSocketAPIsSocketAbstractionLayerVFSLayerTCP/IP协议在设计和实现上并没有客户端和服务器的概念,在通信过程中所有机器都是对等的。但由于资源(视频、新闻、软件等)都被数据提供者所垄断,所以几乎所有的网络应用程序都很自然地用了客户端/服务器模型,即所有客户端都通过访问服务器来获取所需的资源。BS和CS服务器架构(1)CS架构介绍(clientserver,客户端服务器架构)(2)BS架构介绍(broswerserver,浏览器服务器架构)TCP协议(1)建立连接需要三次握手(2)建立连接的条件:服务器listen时客户端主动发起connect(3)关闭连接需要四次握手(4)服务器或者客户端都可以主动发起关闭packagecom.example.emos.wx.controller.form;importio.swagger.annotations.ApiModel;importlombok.Data;importjavax.validation.constraints.NotBlank;importjavax.validation.constraints.Pattern;@Data@ApiModelpublicclassRegisterForm{  @NotBlank(message="注册码不能为空")  @Pattern(regexp="^[0-9]{6}$",message="注册码必须是6位数字")  privateStringregisterCode;  @NotBlank(message="微信临时授权不能为空")  privateStringcode;  @NotBlank(message="昵称不能为空")  privateStringnickname;  @NotBlank(message="头像不能为空")  privateStringphoto;}在UserController.java中创建login()方法。@PostMapping("/login")@ApiOperation("登陆系统")publicRlogin(@Valid@RequestBodyLoginFormform){intid=userService.login(form.getCode());  Stringtoken=jwtUtil.createToken(id);  Set<String>permsSet=userService.searchUserPermissions(id);  saveCacheToken(token,id);  returnR.ok("登陆成功").put("token",token).put("permission",permsSet);}在CheckinServiceImpl类中,实现抽象方法……publicclassCheckinServiceImplimplementsCheckinService{……publicvoidcreateFaceModel(intuserId,Stringpath){    HttpRequestrequest=HttpUtil.createPost(createFaceModelUrl);    request.form("photo",FileUtil.file(path));    HttpResponseresponse=request.execute();    Stringbody=response.body();    if("无法识别出人脸".equals(body)||"照片中存在多张人脸".equals(body)){      thrownewEmosException(body);    }else{      TbFaceModelentity=newTbFaceModel();      entity.setUserId(userId);      entity.setFaceModel(body);      faceModelDao.insert(entity);    }  }}在CheckinServiceImpl.java类中,实现三个抽象方法。publicclassCheckinServiceImplimplementsCheckinService{……@Override  publicHashMapsearchTodayCheckin(intuserId){    HashMapmap=checkinDao.searchTodayCheckin(userId);    returnmap;  }  @Override  publiclongsearchCheckinDays(intuserId){    longdays=checkinDao.searchCheckinDays(userId);    returndays;  }  @Override  publicArrayList<HashMap>searchWeekCheckin(HashMapparam){    ArrayList<HashMap>checkinList=checkinDao.searchWeekCheckin(param);    ArrayList<String>holidaysList=holidaysDao.searchHolidaysInRange(param);    ArrayList<String>workdayList=workdayDao.searchWorkdayInRange(param);    DateTimestartDate=DateUtil.parseDate(param.get("startDate").toString());    DateTimeendDate=DateUtil.parseDate(param.get("endDate").toString());    DateRangerange=DateUtil.range(startDate,endDate,DateField.DAY_OF_MONTH);    ArrayListlist=newArrayList();    range.forEach(one->{      Stringdate=one.toString("yyyy-MM-dd");      //查看今天是不是假期或者工作日      Stringtype="工作日";      if(one.isWeekend()){        type="节假日";      }      if(holidaysList!=null&&holidaysList.contains(date)){        type="节假日";      }elseif(workdayList!=null&&workdayList.contains(date)){        type="工作日";      }      Stringstatus="";      if(type.equals("工作日")&&DateUtil.compare(one,DateUtil.date())<=0){        status="缺勤";booleanflag=false;        for(HashMap<String,String>map:checkinList){          if(map.containsValue(date)){            status=map.get("status");flag=true;            break;          }        }DateTimeendTime=DateUtil.parse(DateUtil.today()+""+constants.attendanceEndTime);Stringtoday=DateUtil.today();if(date.equals(today)&&DateUtil.date().isBefore(endTime)&&flag==false){          status="";        }      }      HashMapmap=newHashMap();      map.put("date",date);      map.put("status",status);      map.put("type",type);      map.put("day",one.dayOfWeekEnum().toChinese("周"));      list.add(map);    });    returnlist;  }}在EmosWxApiApplicationTests.java类中提供了contextLoads()测试用例方法,我们把生成大量系统消息记录的代码写在其中,程序运行的时候这些消息记录就会写入到MongoDB里面。@SpringBootTestclassEmosWxApiApplicationTests{  @Autowired  privateMessageServicemessageService;  @Test  voidcontextLoads(){    for(inti=1;i<=100;i++){      MessageEntitymessage=newMessageEntity();      message.setUuid(IdUtil.simpleUUID());      message.setSenderId(0);      message.setSenderName("系统消息");      message.setMsg("这是第"+i+"条测试消息");      message.setSendTime(newDate());      Stringid=messageService.insertMessage(message);      MessageRefEntityref=newMessageRefEntity();      ref.setMessageId(id);      ref.setReceiverId(11);//注意:这是接收人ID      ref.setLastFlag(true);      ref.setReadFlag(false);      messageService.insertRef(ref);    }  }}在该页面的模型层里面声明静态数据。list数组保存的是后端Java返回的成员数据,内容上按照部门进行分组。members数组保存的是页面上选择的成员id。#include<stdio.h>#include<sys/socket.h>#include<sys/types.h>#include<stdlib.h>#include<arpa/inet.h>#include<unistd.h>#include<string.h> #defineBACKLOG5 intmain(intargc,char*argv[]){  intfd;  structsockaddr_inaddr;  charbuf[BUFSIZ]={};   if(argc<3){    fprintf(stderr,"%s<addr><port>\n",argv[0]);    exit(0);  }   /*创建套接字*/  fd=socket(AF_INET,SOCK_STREAM,0);  if(fd<0){    perror("socket");    exit(0);  }   addr.sin_family=AF_INET;  addr.sin_port=htons(atoi(argv[2]));  if(inet_aton(argv[1],&addr.sin_addr)==0){    fprintf(stderr,"Invalidaddress\n");    exit(EXIT_FAILURE);  }   /*向服务端发起连接请求*/  if(connect(fd,(structsockaddr*)&addr,sizeof(addr))==-1){    perror("connect");    exit(0);  }  while(1){    printf("Input->");    fgets(buf,BUFSIZ,stdin);    write(fd,buf,strlen(buf));  }  close(fd);  return0;}
  • 所需E币: 0
    时间: 2023-12-25 10:31
    大小: 2.57KB
    上传者: 开心就很好了
    今天我将给大家讲解基于C++的Linux高性能事件驱动网络编程框架的设计方法及技巧,我在文中采取渐进迭代的方式,配合C++11新特性的使用,以及网络编程理论的深度讲解,并手把手带着大家落地实现,助力在网络编程领域有更大的技术提升!Linux系统的性能是指操作系统完成任务的有效性、稳定性和响应速度。Linux系统管理员可能经常会遇到系统不稳定、响应速度慢等问题,例如在Linux上搭建了一个web服务,经常出现网页无法打开、打开速度慢等现象,而遇到这些问题,就有人会抱怨Linux系统不好,其实这些都是表面现象。Linux提供三个「点分十进制字符串表示的IPv4地址和用网络字节序整数表示的IPv4地址之间转换」的接口 publicGraceJSONResultdoLogin(HttpServletRequestrequest,                  HttpServletResponseresponse,                  RegisterLoginBOregisterLoginBO,                  BindingResultresult){  //判断BindingResult是否保存错误的验证信息,如果有,则直接return  if(result.hasErrors()){    Map<String,String>errorMap=getErrors(result);    returnGraceJSONResult.errorMap(errorMap);  }  //获得前端传来的基本信息  StringsmsCode=registerLoginBO.getSmsCode();  Stringmobile=registerLoginBO.getMobile();  //0.校验验证码是否匹配  StringredisSMSCode=redis.get(MOBILE_SMSCODE+mobile);  if(StringUtils.isBlank(redisSMSCode)||!redisSMSCode.equalsIgnoreCase(smsCode)){    returnGraceJSONResult.errorCustom(ResponseStatusEnum.SMS_CODE_ERROR);  }  returnGraceJSONResult.ok();}用户信息其实并不会经常发生变动,所以这块内容完全可以放入缓存,这么一来可以大大减少对数据库的压力。privateAppUsergetUser(StringuserId){  //1.查询redis中是否包含用户信息,如果包含则查询redis返回,如果不包含则查询数据库  StringuserJson=redis.get(REDIS_USER_INFO+":"+userId);  AppUseruser=null;  if(StringUtils.isNotBlank(userJson)){    user=JsonUtils.jsonToPojo(userJson,AppUser.class);  }else{    user=userService.getUser(userId);    //2.由于用户信息不怎么会变动,对于千万级别的网站,这类信息数据不会去查询数据库,完全可以把用户信息存入redis    //哪怕修改信息,也不会立马体现,这也是弱一致性,在这里有过期时间,比如1天以后,用户信息会更新到页面显示,或者缩短到1小时,都可以    //基本信息在新闻媒体类网站是属于数据一致性优先级比较低的,用户眼里看的主要以文章为主,至于文章是谁发的,一般来说不会过多关注    redis.set(REDIS_USER_INFO+":"+userId,JsonUtils.objectToJson(user),1);  }  returnuser;}虽然在表设计的时候把文章阅读数字段进行了设计,但是在大数据量下,文章阅读的累计并发是很高的,在这里我们也是采用redis的计数功能来进行实现。@OverridepublicGraceJSONResultlist(StringarticleId,Integerpage,IntegerpageSize){  if(page==null){    page=COMMON_START_PAGE;  }  if(pageSize==null){    pageSize=COMMON_PAGE_SIZE;  }  PagedGridResultgridResult=         commentPortalService.queryArticleComments(articleId,                           page,                           pageSize);  returnGraceJSONResult.ok(gridResult);}生成html的步骤分为以下几步:定义freemarker生成的html位置配置freemarker基本环境获得ftl模板获得动态数据融合ftl和动态数据,并输出到html@Value("${freemarker.html.target}")privateStringhtmlTarget;@GetMapping("/createHTML")@ResponseBodypublicStringcreateHTML(Modelmodel)throwsException{  //0.配置freemarker基本环境  Configurationcfg=newConfiguration(Configuration.getVersion());  //声明freemarker模板所需要加载的目录的位置  Stringclasspath=this.getClass().getResource("/").getPath();  cfg.setDirectoryForTemplateLoading(newFile(classpath+"templates"));//    System.out.println(htmlTarget);//    System.out.println(classpath+"templates");  //1.获得现有的模板ftl文件  Templatetemplate=cfg.getTemplate("stu.ftl","utf-8");  //2.获得动态数据  Stringstranger=;  model.addAttribute("there",stranger);  model=makeModel(model);  //3.融合动态数据和ftl,生成html  FiletempDic=newFile(htmlTarget);  if(!tempDic.exists()){    tempDic.mkdirs();  }  Writerout=newFileWriter(htmlTarget+File.separator+"10010"+".html");  template.process(model,out);  out.close();  return"ok";}
  • 所需E币: 0
    时间: 2023-12-16 12:41
    大小: 4.12KB
    一站式通关CKA证书-Kubernetes管理员认证(CKA)-Kubernetes管理员认证(CKA)计划的目的是提供CKA管理员具有执行Kubernetes管理员职责的技能﹑知识和能力的保证。这个CKA证书是云原生计算基金会CNCF组织的,比国内的一些含水量很大的证书强太多了。CKA证书是云原生计算基金会CNCF组织的,它考察的是你是否具备足够管理Kubernetes集群的必备知识。考试形式是上机直接在集群上操作,限时3小时,非常考验个人知识的扎实程度和Kubernetes实践经验。无论你上了什么课,考试报名费都是交给CNCF的,证书也是他们发的,只要考上75分,你就能拿到证书,也能学到不少知识。我们的配置文件已经写好了,后续新增的一些配置,都可以写在这个文件里,我们只要按需读取就可以了,那怎么来读取yaml文件中的数据呢?我们在common包下新建一个py文件,叫yaml_config.py,这个文件里会写一些读取配置文件相关的方法。一般在python中读取文件的内容,都是使用open这个方法。file=open("environment.yaml",encoding='utf-8')try: a=file.read() print(a)exceptExceptionase: print(e)finally: file.close()安装好以后我们开始正式写yaml_config中的方法。pyyaml读取了yaml后,会把yaml文件的内容转成python中字典的形式,这样我们就可以很方便的读取其中的某个值了。importyamlclassGetConf:  def__init__(self):    #withopen的第一个参数填写environment.yaml的绝对路径    withopen("/Users/fengzhaoxi/imooc/code/trading_system_autotest/config/environment.yaml","r")asenv_file:      self.env=yaml.load(env_file,Loader=yaml.FullLoader)      print(self.env)  defget_username_password(self):    returnself.env["username"],self.env["password"]    if__name__=='__main__':  GetConf().get_username_password()第二点:获取到了项目目录,下面我们需要把项目目录跟environment.yaml在项目中的相对路径拼接,拼接成environment.yaml的绝对路径。因为不同操作系统中的文件分隔符是不同的,所以在python中最好不要通过字符串去拼接分隔符,否则换了操作系统去运行可能就会出错,需要使用os.sep来添加分隔符,所以我们写一个方法defsep(path,add_sep_before=False,add_sep_after=False):  """  系统分隔符  Args:    path:路径列表,类型为数组    add_sep_before:是否需要在拼接的路径前加一个分隔符    add_sep_after:是否需要在拼接的路径后加一个分隔符  Returns:  """  all_path=os.sep.join(path)  ifadd_sep_before:    all_path=os.sep+all_path  ifadd_sep_after:    all_path=all_path+os.sep  returnall_path我们再回到yaml_config.py,我们获取environment.yaml的绝对路径,就是项目目录加上environment.yaml在项目中的项目目录。最后修改的完整方法如下importyamlfromtoolsimportget_project_path,sepclassGetConf:  def__init__(self):    project_dir=get_project_path()    withopen(project_dir+sep(['config','environment.yaml'],add_sep_before=True),"r")asenv_file:      self.env=yaml.load(env_file,Loader=yaml.FullLoader)      print(self.env)  defget_username_password(self):    returnself.env["username"],self.env["password"]if__name__=='__main__':  GetConf().get_username_password()备考难度不低,所以相关培训课程都不便宜。如果决心要考,准备一段时间反复看文档、做实验是必须的,CKA的学习曲线很陡峭,它更多靠的是个人自觉和毅力classLeftMenuBase:  deflevel_one_menu(self,menu_name):    """    一级菜单    :parammenu_name:    :return:    """    return"//aside[@class='el-aside']//span[text()='"+menu_name+"']/ancestor::li"  deflevel_two_menu(self,menu_name):    """    二级菜单    :parammenu_name:    :return:    """    return"//aside[@class='el-aside']//span[text()='"+menu_name+"']/ancestor::li[1]"我们来举一个场景的例子,我们之前有个用例,是进入到已买到的宝贝页面,然后依次点击页面上的按钮,比如”全部“、”待付款“、”待发货“、”运输中“等等,我们当时是通过一个list,然后循环来点击。我们也可以通过pytest.mark.parametrize来修改这个用例fromtimeimportsleepimportpytestfrompage.LeftMenuPageimportLeftMenuPagefrompage.LoginPageimportLoginPagefrompage.OrderPageimportOrderPagetab_list=["全部","待付款","待发货","运输中","待确认","待评价"]classTestOrderBuy:  @pytest.mark.parametrize("tab",tab_list)  deftest_order_buy(self,driver,tab):    LoginPage().login(driver,"william")    LeftMenuPage().click_level_one_menu(driver,"我的订单")    sleep(1)    LeftMenuPage().click_level_two_menu(driver,"已买到的宝贝")    sleep(2)    OrderPage().click_order_tab(driver,tab)    sleep(2)我们再来写一个用例,将我们的订单发布参数化fromtimeimportsleepimportpytestfrompage.LoginPageimportLoginPagefrompage.LeftMenuPageimportLeftMenuPagefrompage.GoodsPageimportGoodsPagegoods_info_list=[  {    "goods_title":"新增批量商品测试1",    "goods_details":"新增商品测试详情1",    "goods_num":1,    "goods_pic_list":["商品图片一.jpg"],    "goods_price":100,    "goods_status":"上架",    "bottom_button_name":"提交"  },  {    "goods_title":"新增批量商品测试2",    "goods_details":"新增商品测试详情2",    "goods_num":2,    "goods_pic_list":["商品图片一.jpg"],    "goods_price":200,    "goods_status":"上架",    "bottom_button_name":"提交"  }]classTestParametrizeAddGoods:  @pytest.mark.parametrize("goods_info",goods_info_list)  deftest_parametrize_add_goods(self,driver,goods_info):    LoginPage().login(driver,"jay")    LeftMenuPage().click_level_one_menu(driver,"产品")    sleep(1)    LeftMenuPage().click_level_two_menu(driver,"新增二手商品")    sleep(2)    GoodsPage().add_new_goods(      driver,      goods_title=goods_info["goods_title"],      goods_details=goods_info["goods_details"],      goods_num=goods_info["goods_num"],      goods_pic_list=goods_info["goods_pic_list"],      goods_price=goods_info["goods_price"],      goods_status=goods_info["goods_status"],      bottom_button_name=goods_info["bottom_button_name"]    )    sleep(3)底下我们想要测试用例执行的时候就更新测试进度,存储对应的测试结果我们在common下新建一个py文件叫process_redis,我们把可能的情况都写好fromcommon.toolsimportget_now_timefromcommon.redis_operationimportRedisOperationclassProcess:  def__init__(self):    self.redis_client=RedisOperation().redis_client    self.UI_AUTOTEST_PROCESS="ui_autotest_process"    self.FAILED_TESTCASE_NAMES="failed_testcase_names"    self.RUNNING_STATUS="running_status"  defreset_all(self):    #删除所有进度    self.redis_client.delete(self.UI_AUTOTEST_PROCESS)    #删除所有失败用例的名称    self.redis_client.delete(self.FAILED_TESTCASE_NAMES)  definit_process(self,total):    """    初始化进度,包括总数、成功数、失败数、开始时间,运行状态    :paramtotal:    :return:    """    self.redis_client.hset(self.UI_AUTOTEST_PROCESS,"total",total)    self.redis_client.hset(self.UI_AUTOTEST_PROCESS,"success",0)    self.redis_client.hset(self.UI_AUTOTEST_PROCESS,"fail",0)    self.redis_client.hset(self.UI_AUTOTEST_PROCESS,"start_time",get_now_time())    self.redis_client.hset(self.UI_AUTOTEST_PROCESS,"end_time","")    self.redis_client.set(self.RUNNING_STATUS,1)  defupdate_success(self):    """    成功用例个数+1    Returns:    """    self.redis_client.hincrby(self.UI_AUTOTEST_PROCESS,"success")  defupdate_fail(self):    """    失败用例个数+1    Returns:    """    self.redis_client.hincrby(self.UI_AUTOTEST_PROCESS,"fail")  definsert_into_fail_testcase_names(self,fail_testcase_name):    """    增加失败用例名称    Returns:    """    self.redis_client.lpush(self.FAILED_TESTCASE_NAMES,fail_testcase_name)  defget_process(self):    """    获取进度,计算百分比    Returns:    """    total,success,fail,_=self.get_result()    iftotal==0:      return0    else:      result="%.1f"%((int(success)+int(fail))/int(total)*100)+"%"      returnresult  defget_result(self):    """    获取测试结果    Returns:    """    total=self.redis_client.hget(self.UI_AUTOTEST_PROCESS,"total")    iftotalisNone:      total=0    success=self.redis_client.hget(self.UI_AUTOTEST_PROCESS,"success")    ifsuccessisNone:      success=0    fail=self.redis_client.hget(self.UI_AUTOTEST_PROCESS,"fail")    iffailisNone:      fail=0    start_time=self.redis_client.hget(self.UI_AUTOTEST_PROCESS,"start_time")    ifstart_timeisNone:      start_time='-'    returntotal,success,fail,start_time  defget_fail_testcase_names(self):    """    获取所有失败的用例名称    Returns:    """    fail_testcase_names=self.redis_client.lrange(self.FAILED_TESTCASE_NAMES,0,-1)    returnfail_testcase_names  defwrite_end_time(self):    """    把测试结束时间写入redis    Returns:    """    self.redis_client.hset(self.UI_AUTOTEST_PROCESS,"end_time",get_now_time())  defwrite_jenkins_build_number(self,build_number):    """    把jenkins执行的build_number写入redis    Args:      build_number:
  • 所需E币: 0
    时间: 2023-12-14 10:32
    大小: 2.41KB
    上传者: 开心就很好了
    今天给大家讲讲关于多级网关与多级缓存架构的相关知识,在文章里面,我将从0到1带着大家构建基础服务接口,通过层层递进优化服务,使得服务具备多级缓存的特性,并融合OpenResty拓展一个强大的多级网关+多级缓存的技术架构。以下就是代码实战展示:引入springboot3的maven依赖,本质上作为pom引入,直接管理他的版本号,后续用到啥组件直接拿来即用:<dependencies>  <!--引入SpringBoot依赖-->  <dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter</artifactId>  </dependency>  <dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-web</artifactId>  </dependency>  <dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-configuration-processor</artifactId>  </dependency>  <dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-aop</artifactId>  </dependency>  <dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-jdbc</artifactId>  </dependency></dependencies>dependencyManagement依赖管理全代码依赖配置如下:<!--  使用dependencyManagement的目的是为了保证当前父工程的干净,  也就是说父工程他只负责对依赖(坐标)的管理,以及依赖的版本管理,而不会去引入额外的jar依赖  如此一来,父工程的职责就相当的单一了,而且也符合面向对象的理念,是一种父子一来继承的关系  依赖的导入只有在各自的子工程中才会导入。--><dependencyManagement>  <dependencies>    <!--mysql驱动-->    <dependency>      <groupId>mysql</groupId>      <artifactId>mysql-connector-java</artifactId>      <version>8.0.33</version>    </dependency>    <!--持久层mybatis-->    <dependency>      <groupId>com.baomidou</groupId>      <artifactId>mybatis-plus-boot-starter</artifactId>      <version>3.5.0</version>    </dependency>    <dependency>      <groupId>com.github.pagehelper</groupId>      <artifactId>pagehelper-spring-boot-starter</artifactId>      <version>1.4.1</version>    </dependency>    <!--jackson-->    <dependency>      <groupId>com.fasterxml.jackson.core</groupId>      <artifactId>jackson-core</artifactId>      <version>2.14.2</version>    </dependency>    <dependency>      <groupId>com.fasterxml.jackson.core</groupId>      <artifactId>jackson-annotations</artifactId>      <version>2.14.2</version>    </dependency>    <dependency>      <groupId>com.fasterxml.jackson.core</groupId>      <artifactId>jackson-databind</artifactId>      <version>2.14.2</version>    </dependency>    <!--apache工具类-->    <dependency>      <groupId>commons-codec</groupId>      <artifactId>commons-codec</artifactId>      <version>1.15</version>    </dependency>    <dependency>      <groupId>org.apache.commons</groupId>      <artifactId>commons-lang3</artifactId>      <version>3.12.0</version>    </dependency>    <dependency>      <groupId>commons-fileupload</groupId>      <artifactId>commons-fileupload</artifactId>      <version>1.4</version>    </dependency>    <dependency>      <groupId>commons-io</groupId>      <artifactId>commons-io</artifactId>      <version>2.11.0</version>    </dependency>    <dependency>      <groupId>org.apache.httpcomponents</groupId>      <artifactId>httpclient</artifactId>      <version>4.5.13</version>    </dependency>    <!--google工具类-->    <dependency>      <groupId>com.google.guava</groupId>      <artifactId>guava</artifactId>      <version>28.2-jre</version>    </dependency>  </dependencies></dependencyManagement>使用zaddzset10value120value230value3:设置member和对应的分数zrangezset0-1:查看所有zset中的内容zrangezset0-1withscores:带有分数zrankzsetvalue:获得对应的下标zscorezsetvalue:获得对应的分数zcardzset:统计个数zcountzset分数1分数2:统计个数zrangebyscorezset分数1分数2:查询分数之间的member(包含分数1分数2)zrangebyscorezset(分数1(分数2:查询分数之间的member(不包含分数1和分数2)zrangebyscorezset分数1分数2limitstartend:查询分数之间的member(包含分数1分数2),获得的结果集再次根据下标区间做查询zremzsetvalue:删除member在common中引入的坐标依赖<dependency>  <groupId>org.apache.commons</groupId>  <artifactId>commons-lang3</artifactId></dependency><dependency>  <groupId>com.fasterxml.jackson.core</groupId>  <artifactId>jackson-core</artifactId></dependency><dependency>  <groupId>com.fasterxml.jackson.core</groupId>  <artifactId>jackson-annotations</artifactId></dependency><dependency>  <groupId>com.fasterxml.jackson.core</groupId>  <artifactId>jackson-databind</artifactId></dependency><dependency>  <groupId>com.fasterxml.jackson.datatype</groupId>  <artifactId>jackson-datatype-jsr310</artifactId></dependency>迭代查询代码,一级缓存与二级缓存结合:@GetMapping("query")publicObjectquery(Stringid){  StringarticleKey="article:"+id;  StringarticleKeyRedis="REDIS_ARTICLE:"+id;  Articlearticle=cache.get(articleKey,s->{    System.out.println("文章id为"+id+"的没有查询到,则从Redis中查询后返回...");    ArticlearticleReal=null;    StringarticleJsonStr=redis.get(articleKeyRedis);    //判断从redis中查询到的文章数据是否为空    if(StringUtils.isBlank(articleJsonStr)){      System.out.println("Redis中不存在该文章,将从数据库中查询...");      //如果为空,则进入本条件,则从数据库中查询数据      articleReal=articleService.queryArticleDetail(id);      //手动把文章数据设置到redis中,后续再次查询则有值      StringarticleJson=JsonUtils.objectToJson(articleReal);      redis.set(articleKeyRedis,articleJson);    }else{      System.out.println("Redis中存在该文章,将直接返回...");      //如果不为空,则直接转换json类型article再返回即可      articleReal=JsonUtils.jsonToPojo(articleJsonStr,Article.class);    }    returnarticleReal;  });  returnarticle;}本文到此结束,感谢大家的阅读!
  • 所需E币: 0
    时间: 2023-12-1 16:19
    大小: 3.49KB
    实际搭建流程:下载鸿蒙源码→docker拉取镜像→创建容器→进入容器→下载hb编译工具(也可使用build.sh、build.py脚本编译,但是不如hb辅助工具指令好用)→编译(内核、芯片厂商的uboot、系统镜像...)1.准备开发环境:首先,您需要设置用于鸿蒙应用程序开发的开发环境。2.学习鸿蒙应用程序开发:了解鸿蒙应用程序开发的基础知识,包括鸿蒙应用程序的架构、UI设计和鸿蒙系统的特性。3.开发应用程序:使用鸿蒙开发工具,开始编写您的应用程序代码。您可以创建各种类型的应用程序,包括手机应用、平板电脑应用、电视应用、手表应用等。4.设计用户界面:使用鸿蒙的UI组件和工具,设计用户界面。鸿蒙提供了一套UI框架,可以帮助您创建吸引人的用户界面。5.数据处理和功能开发:根据您的应用程序需求,编写数据处理逻辑和应用程序功能。鸿蒙支持多种编程语言,包括Java、C、C++和JS。6.测试和调试:在真机或模拟器上测试您的应用程序,以确保它正常运行。鸿蒙提供了调试工具,以帮助您发现和解决问题。7.发布应用程序:一旦应用程序准备就绪,您可以将其发布到鸿蒙应用程序商店或其他应用程序分发渠道。8.更新和维护:定期更新和维护您的应用程序,以确保它与鸿蒙系统的最新版本兼容,并提供新功能和修复问题。使用store.commit方法来调用:store.commit('事件类型/函数名'),代码片段如下所示:1)在Vue中调用mutations:exportconststore=createStore({   //...   mutations:{   setCount(state,payload){   state.count+=payload   returnstate.count   }   }   //...  })action中可以通过提交**mutation**来修改状态,不直接修改状态action中可以做一些异步操作提供一个上下文,可以直接使用commit、state、getters等,代码片段如下所示:exportconststore=createStore({   //...   actions:{   fetchCount({commit,state,getters},payload){//{commit,state,getters}为上下文   setTimeout(()=>{   commit('setCount',5)   console.log(state.count)   console.log(getters.getCount)   },3000);   }   }  })getter类似与Vue中的computed计算属性,它的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算getters里可以处理一些array、object的查询、过滤、遍历、重构或者做一些字符拼接的操作,方便直接生成一些可以直接使用的数据。如下代码片段展示了如何在getter中进行过滤查询:exportconststore=createStore({   state:{   todos:[  //定义一个对象数组   {   id:1,   done:true   },   {   id:2,   done:false   }   ]   }   getters:{   doneTodosCount(){ //查询已完成的个数   returnstore.state.todos.filter(todo=>todo.done).length //返回值:1   }   }  })首先使用Typescript的interface为store中的所有state声明类型,然后将interface放置在InjectionKeyd的泛型类型中,代码片段如下://src/store/index.tsimport{createStore,Store}from'vuex'import{InjectionKey}from'vue'//为storestate声明类型exportinterfaceAllStateTypes{ count:number, locale:any, userStatus:Number}//定义injectionkeyexportconstkey:InjectionKey<Store<AllStateTypes>>=Symbol('storeKey')exportconststore=createStore<AllStateTypes>({ //...})我们使用Nodejs框架Express来快速搭建一个后端服务,首选需要安装一下Express,在终端运行npminstallexpress--save-dev,Vite官方提供一个基于服务端渲染的NodeServer模板,代码片段如下://server.jsconstfs=require('fs')constpath=require('path')constexpress=require('express')const{createServer:createViteServer}=require('vite')asyncfunctioncreateServer(){ constapp=express() //以中间件模式创建Vite应用,这将禁用Vite自身的HTML服务逻辑 //并让上级服务器接管控制 // //如果你想使用Vite自己的HTML服务逻辑(将Vite作为 //一个开发中间件来使用),那么这里请用'html' constvite=awaitcreateViteServer({  server:{middlewareMode:'ssr'} }) //使用vite的Connect实例作为中间件 app.use(vite.middlewares) app.use('*',async(req,res)=>{  consturl=req.originalUrl  try{   //1.读取index.html   lettemplate=fs.readFileSync(    path.resolve(__dirname,'index.html'),    'utf-8'   )   //2.应用ViteHTML转换。这将会注入ViteHMR客户端,   //  同时也会从Vite插件应用HTML转换。   //  例如:@vitejs/plugin-react-refresh中的globalpreambles   template=awaitvite.transformIndexHtml(url,template)   //3.加载服务器入口。vite.ssrLoadModule将自动转换   //  你的ESM源码使之可以在Node.js中运行!无需打包   //  并提供类似HMR的根据情况随时失效。   const{render}=awaitvite.ssrLoadModule('/src/entry-server.ts')   //4.渲染应用的HTML。这假设entry-server.ts导出的`render`   //  函数调用了适当的SSR框架API。   //  例如ReactDOMServer.renderToString()   constappHtml=awaitrender(url)   //5.注入渲染后的应用程序HTML到模板中。   consthtml=template.replace('<!--ssr-outlet-->',appHtml)   //6.返回渲染后的HTML。   res.status(200).set({'Content-Type':'text/html'}).end(html)  }catch(e){   //如果捕获到了一个错误,让Vite来修复该堆栈,这样它就可以映射回   //你的实际源码中。   vite.ssrFixStacktrace(e)   console.error(e)   res.status(500).end(e.message)  } }) app.listen(3000)}createServer()在终端执行命令:npminstall-Dunplugin-vue-componentsunplugin-auto-import,接着在vite.config.ts中做如下配置://vite.config.tsimportAutoImportfrom'unplugin-auto-import/vite'importComponentsfrom'unplugin-vue-components/vite'import{ElementPlusResolver}from'unplugin-vue-components/resolvers'exportdefault{ plugins:[  //...  AutoImport({   resolvers:[ElementPlusResolver()],  }),  Components({   resolvers:[ElementPlusResolver()],  }), ],}