首页 文章 精选 留言 我的

精选列表

搜索[移动端],共10011篇文章
优秀的个人博客,低调大师

移动端基于动态路由的架构设计

好久好久没写过文章了,一是最近项目太忙了,没时间写。二是也没有时间学习新的东西,想写点什么却又无从下笔。一味的去写这个API怎么用,那个新技术怎么用,又显的没意思。没有项目经验总结的技术知识讲解,总感觉有些苍白。 最近在做混合App开发这块,从开始的ionic 框架,到后来的mui框架,让我在混合开发这块有了更深的理解,如果在这块要写点什么无非漫天盖地的这个指令怎么用,那个模版怎么用,数据怎么进行双向绑定,等等,但是这些网上已经很多资料了,等不太忙了,我想我会总结一篇这些框架的使用心得吧。但是我今天不讲这个,我们来谈一谈在原生app中(iOS android)如何使用动态路由机制来搭建整个app的框架。 路由机制在web开发中是比较常见的,app开发中还是很少听到这种概念的,目前有些大公司采用的组件化开发(手淘,携程,蘑菇街等),倒是跟我们讲的有很多相同之处,不过它们的比较复杂,而且网上很多组件化开发,路由机制,没有一个能给出完整代码示例的,看着让人云里雾里的。索性自己就借鉴它们的思想,加上一点个人的理解,搞出了一个简单实用的可行性demo出来。我们主要介绍以下三方面内容: 1 什么是动态路由 2 它能解决我们什么问题 3 如何在项目中实现 一 什么是动态路由 原生开发没这概念,我们借助angular路由机制来解释这一概念,所谓路由,就是一套路径跳转机制,事先通过配置文件定义好一个路径映射文件,跳转时根据key去找到具体页面,当然angular会做一些缓存,页面栈的管理等等一些操作,它大致的定义是这样的 angular.module('app',[]) .config('$routeProvider',function($routeProvider){ $routeProvider .when('/',{ templateUrl:'view/home.html', controller:'homeCtrl' } ) .when('/',{ templateUrl:'view/home.html', controller:'homeCtrl' } ) .when('/',{ templateUrl:'view/home.html', controller:'homeCtrl' } ) .ontherwise({ redirective:'/' }) }) config函数是一个配置函数。在使用 $routeProvider这样的一个服务。when:代表当你访问这个“/”根目录的时候 去访问 templateUrl中的那个模板。 controller可想已知,就是我们配套的controller,就是应用于根目录的这个 模板时的controller。 ontherwise 就是当你路径访问错误时,找不到。最后跳到这个默认的 页面。 为此我们可以总结一下几个特点: 1 一个映射配置文件 2 路径出错处理机制 这就是路由的基本意思,我们看看,在原生开发中,采用此种方式,他能解决我们什么问题。 二 它能解决我们什么问题 首先我们来比较一下我们以前的结构模式以及与 加入路由机制后的项目结构,实现路由机制,不仅需要一个映射文件,还需要一套路由管理机制,那么采用路由机制,我们的项目架构就跟原来不一样了,如下图: 原先业务之间的调用关系.png 加入路由后的页面调用关系.png 接下来我们看一下平时我们采用的页面跳转方法: iOS 下 [selfpresentViewController:controlleranimated:YEScompletion:nil]; [self.navigationControllerpushViewController:controlleranimated:YES]; android 下 Intentintent=newIntent(this,A.class);startActivity(intent);startActivityForResult(Intentintent,IntrequestCode) 我们看一下它有哪些缺点: (1)都要在当前页面引入要跳转页面的class 类。这就造成了页面的耦合性很高。 (2)遇到重大bug,不能够及时的修复问题,需要等待更新发版后才能解决。 (3)推送消息,如果入口没有关与页面的引入处理,则不能跳转到指定页面。 引入路由机制后我们能否解决这些问题呢? 试想一下,如果我们通过一个配置文件来映射页面跳转关系,而且通过反射机制来取消头文件的引入问题,是不是我们就可以解决以上那些弊端了呢,比如,我们线上应用出现bug, 导致某个页面一打开,app就跪了,那我们是不是就可以通过更新路由配置文件,把它映射到另一个页面去:一个错误提示文件,或者一个线上H5能实现相同功能的页面。这样的话,原生app也具有了一定的动态更新能力,其实想想还有很多好处,比如项目功能太多原生开发要很长时间,但是领导又急着要上线,那么我们是不是就可以先开发一个网页版的模块,app路由映射到这个web页面,让用户先用着,等我们原生开发完了,然后再改一下映射文件,没升级的依旧用H5的路由,升级的就用原生的路由,如果H5页面我们要废弃了,那我们整体就可以路由到一个升级提升的页面去了。 总结一下路由机制能解决我们哪些问题: 1 避免引入头文件,是页面之间的依赖大大变少了(通过反射动态生成页面实例)。 2 线上出现重大bug,给我们提供了一个及时修补的入口 3 网页和原生切换更方便,更自由。 4 可以跳转任意页面 例如我们常用的推送,要打开指定的页面,以前我们怎么做的,各种启动判断,现在呢,我们只要给发送消息配个路由路径就行了,打开消息,就能够跳转到我们指定的页面。 等等,其它好处自行发掘。 三 如何在项目中实现 说了这么多概念性问题,下面我们就用代码来实现我们的构想, 下面先以IOS平台为例: 我们先看一下demo结构 iOS demo结构图.png 说明:WXRouter 路由管理文件 demo 路由使用示例 urlMap.plist 路由配置文件 我们主要讲解一下 WXRouter里面的几个文件,以及ViewController文件,还有urlmap.plist文件,其他请下载示例demo,文末我会给出demo地址。 #import #import @interfaceWXRouter:NSObject +(id)sharedInstance; -(UIViewController*)getViewController:(NSString*)stringVCName; -(UIViewController*)getViewController:(NSString*)stringVCNamewithParam:(NSDictionary*)paramdic; @end #import"WXRouter.h" #import"webView.h" #import"RouterError.h" #import"PlistReadUtil.h" #defineSuppressPerformSelectorLeakWarning(Stuff)\ do{ _Pragma("clangdiagnosticpush")\ _Pragma("clangdiagnosticignored\"-Warc-performSelector-leaks\"")\ Stuff;\ _Pragma("clangdiagnosticpop")\ } while(0) @implementationWXRouter +(id)sharedInstance{ staticdispatch_once_tonceToken; staticWXRouter*router; dispatch_once(&onceToken,^{ router=[[WXRouteralloc]init]; }); returnrouter; } -(UIViewController*)controller:(UIViewController*)controllerwithParam:(NSDictionary*)paramdicandVcname:(NSString*)vcName{ SELselector=NSSelectorFromString(@"iniViewControllerParam:"); if(![controllerrespondsToSelector:selector]){//如果没定义初始化参数方法,直接返回,没必要在往下做设置参数的方法 NSLog(@"目标类:%@未定义:%@方法",controller,@"iniViewControllerParam:"); returncontroller; } if(paramdic==nil){ //如果参数为空URLKEY页面唯一路径标识别 paramdic=[[NSMutableDictionaryalloc]init]; [paramdicsetValue:vcNameforKey:@"URLKEY"]; SuppressPerformSelectorLeakWarning([controllerperformSelector:selectorwithObject:paramdic]); } else{ [paramdicsetValue:vcNameforKey:@"URLKEY"]; } SuppressPerformSelectorLeakWarning([controllerperformSelector:selectorwithObject:paramdic]); returncontroller; } -(UIViewController*)getViewController:(NSString*)stringVCName{ NSString*viewControllerName=[PlistReadUtilplistValueForKey:stringVCName]; Classclass=NSClassFromString(viewControllerName); UIViewController*controller=[[classalloc]init]; if(controller==nil){//此处可以跳转到一个错误提示页面 NSLog(@"未定义此类:%@",viewControllerName); returnnil; } returncontroller; } -(UIViewController*)getViewController:(NSString*)stringVCNamewithParam:(NSDictionary*)paramdic{ UIViewController*controller=[selfgetViewController:stringVCName]; if(controller!=nil){ controller=[selfcontroller:controllerwithParam:paramdicandVcname:stringVCName]; } else{ //异常处理可以跳转指定的错误页面 controller=[[RouterErrorsharedInstance]getErrorController]; } returncontroller; } @end 说明:通过反射机制根据传入的string来获取 viewcontroller实例,实现了两个方法,一个是不需要传入参数的,一个是需要传入参数的,当跳转到第二个页面需要传值 就使用第二个带参数的方法,所传的值通过NSDictionary来进行封装,跳转后的页面通过实现 -(void)iniViewControllerParam:(NSDictionary *)dic 方法来获取传过来的参数。 #import @interfacePlistReadUtil:NSObject @property(nonatomic,strong)NSMutableDictionary*plistdata; +(id)sharedInstanceWithFileName:(NSString*)plistfileName; +(NSString*)plistValueForKey:(NSString*)key; @end #import"PlistReadUtil.h" @implementationPlistReadUtil +(id)sharedInstanceWithFileName:(NSString*)plistfileName{ staticdispatch_once_tonceToken; staticPlistReadUtil*plistUtil; dispatch_once(&onceToken,^{ plistUtil=[[PlistReadUtilalloc]init]; NSString*plistPath=[[NSBundlemainBundle]pathForResource:plistfileNameofType:@"plist"]; plistUtil.plistdata=[[NSMutableDictionaryalloc]initWithContentsOfFile:plistPath]; }); returnplistUtil; } +(NSString*)plistValueForKey:(NSString*)key{ PlistReadUtil*plist=[PlistReadUtilsharedInstanceWithFileName:@"urlMap"]; return[plist.plistdataobjectForKey:key]; } @end 说明:路由配置文件读取工具类,我这里读取的是plist 文件,我这里也可以读取json,或则访问网络获取后台服务器上的路由配置文件,这个根据我们业务需求的不同,可以添加不同的读取方法。 #import<Foundation/Foundation.h> #import<UIKit/UIKit.h> @interfaceRouterError:NSObject +(id)sharedInstance; -(UIViewController*)getErrorController; @end #import"RouterError.h" #import"WXRouter.h" @implementationRouterError +(id)sharedInstance{ staticdispatch_once_tonceToken; staticRouterError*routerError; dispatch_once(&onceToken,^{ routerError=[[RouterErroralloc]init]; }); returnrouterError; } #pragmamark自定义错误页面此页面一定确保能够找到,否则会进入死循环 -(UIViewController*)getErrorController{ NSDictionary*diction=[[NSMutableDictionaryalloc]init]; [dictionsetValue:@"https://themeforest.net/item/octopus-error-template/2562783"forKey:@"url"]; UIViewController*errorController=[[WXRoutersharedInstance]getViewController:@"MSG003"withParam:diction]; returnerrorController; } @end 说明:在读取配置文件时如果没有读到相应的路径,或者未定义相应的class,我们可以在这里处理,我这边处理的是如果出现错误,就返回一个webview页面,我们可以在项目里写一个统一的错误处理webview页面,其实每个页面默认都添加了一个参数[paramdic setValue:vcName forKey:@"URLKEY"]; 就是这个URLKEY,这个key标示配置文件中每个跳转动作的key,这个key是唯一的,我们可以根据不同的URLKEY然后通过后台统一的一个接口来判断跳转到不同的错误处理H5页面。 #import"ViewController.h" #import"view2.h" #import"WXRouter.h" #import"PlistReadUtil.h" @interfaceViewController() @end @implementationViewController -(void)viewDidLoad{ [superviewDidLoad]; UILabel*lable=[[UILabelalloc]initWithFrame:CGRectMake(0,0,100,50)]; lable.textColor=[UIColorblueColor]; lable.text=@"helloword"; [self.viewaddSubview:lable]; UIButton*button=[[UIButtonalloc]initWithFrame:CGRectMake(0,50,200,50)]; [buttonsetTitle:@"访问view1"forState:UIControlStateNormal]; [buttonsetTitleColor:[UIColorblackColor]forState:UIControlStateNormal]; button.tag=1; [buttonaddTarget:selfaction:@selector(back:)forControlEvents:UIControlEventTouchUpInside]; [self.viewaddSubview:button]; UIButton*button2=[[UIButtonalloc]initWithFrame:CGRectMake(0,110,200,50)]; [button2setTitle:@"访问view3"forState:UIControlStateNormal]; [button2setTitleColor:[UIColorblackColor]forState:UIControlStateNormal]; button2.tag=2; [button2addTarget:selfaction:@selector(back:)forControlEvents:UIControlEventTouchUpInside]; [self.viewaddSubview:button2]; UIButton*butto3=[[UIButtonalloc]initWithFrame:CGRectMake(0,170,200,50)]; [butto3setTitle:@"访问webview"forState:UIControlStateNormal]; [butto3setTitleColor:[UIColorblackColor]forState:UIControlStateNormal]; butto3.tag=3; [butto3addTarget:selfaction:@selector(back:)forControlEvents:UIControlEventTouchUpInside]; [self.viewaddSubview:butto3]; UIButton*button4=[[UIButtonalloc]initWithFrame:CGRectMake(0,230,200,50)]; [button4setTitle:@"访问wei定义的页面"forState:UIControlStateNormal]; [button4setTitleColor:[UIColorblackColor]forState:UIControlStateNormal]; button4.tag=4; [button4addTarget:selfaction:@selector(back:)forControlEvents:UIControlEventTouchUpInside]; [self.viewaddSubview:button4]; } -(void)back:(UIButton*)btn{ switch(btn.tag){ case1:{ NSMutableDictionary*dic=[[NSMutableDictionaryalloc]init]; [dicsetValue:@"nihaoshijie"forKey:@"title"]; UIViewController*controller=[[WXRoutersharedInstance]getViewController:@"MSG001"withParam:dic]; [selfpresentViewController:controlleranimated:YEScompletion:nil]; } break; case2:{ NSMutableDictionary*dic=[[NSMutableDictionaryalloc]init]; [dicsetValue:@"nihaoshijie"forKey:@"title"]; UIViewController*controller=[[WXRoutersharedInstance]getViewController:@"MSG002"withParam:dic]; [selfpresentViewController:controlleranimated:YEScompletion:nil]; } break; case3:{ NSMutableDictionary*dic=[[NSMutableDictionaryalloc]init]; [dicsetValue:@"https://www.baidu.com"forKey:@"url"]; UIViewController*controller=[[WXRoutersharedInstance]getViewController:@"MSG003"withParam:dic]; [selfpresentViewController:controlleranimated:YEScompletion:nil]; } break; case4:{ UIViewController*controller=[[WXRoutersharedInstance]getViewController:@"MSG005"withParam:nil]; [selfpresentViewController:controlleranimated:YEScompletion:nil]; } default: break; } } -(void)didReceiveMemoryWarning{ [superdidReceiveMemoryWarning]; //Disposeofanyresourcesthatcanberecreated. } @end 说明:这个是使用示例,为了获取最大的灵活性,这里我并没有把跳转动作presentViewcontroller,pushViewController,以及参数的组装封装在路由管理类里。看过很多大神写的路由库,有些也通过url schema的方式。类似于:xml:id/123/name/xu,这样的路径方式,但是个人感觉,如果界面之间传递图片对象,或者传嵌套的类对象,就有点麻烦了。因为怕麻烦,所以就先写个简单的吧。 #import"view3.h" @interfaceview3() @end @implementationview3 -(void)viewDidLoad{ [superviewDidLoad]; UILabel*lable=[[UILabelalloc]initWithFrame:CGRectMake(0,0,100,50)]; lable.textColor=[UIColorblueColor]; lable.text=@"我是view3"; [self.viewaddSubview:lable]; UIButton*button=[[UIButtonalloc]initWithFrame:CGRectMake(200,200,200,200)]; [buttonsetTitle:@"back"forState:UIControlStateNormal]; [buttonsetTitleColor:[UIColorblackColor]forState:UIControlStateNormal]; [buttonaddTarget:selfaction:@selector(back)forControlEvents:UIControlEventTouchUpInside]; [self.viewaddSubview:button]; } -(void)back{ [selfdismissViewControllerAnimated:YEScompletion:nil]; } -(void)iniViewControllerParam:(NSDictionary*)dic{ self.title=[dicobjectForKey:@"title"]; } 说明:这个是要跳转的页面我们可以通过iniViewControllerParam:(NSDictionary *)dic方法获取上一个界面传过来的参数。 urlMap.plist 说明:路由配置文件,key:value的形式,页面里的每个跳转动作都会对应一个唯一的key,这里如果两个页面都跳转到同一个页面,就会产生不同的key 对应相同的value,感觉是有点冗余了,如果有更好的优化,我会更新下文章的,这里的配置文件我们可以怎么玩,由于我在android的这块的描述已经很详细了,所以这里就不再赘述。只是android的配置有点坑,类前需要加上包名,这点就没有iOS方便灵活了,至此iOS示例我就讲完了。 总结:代码是简陋的,只是简单的实现了自己的构想,还有很多值得细细琢磨的地方,关键是架构思路,通过中间路由根据下发的路由配置文件来动态跳转页面,解决原生开发的遇到的一些问题,不同的项目有不同的业务逻辑,这种思路有什么缺陷,或者解决不了什么问题,大家一起讨论分享。基于这种思路搭建架子的话,对于将来的组件化开发,应该也会很方便转换吧。 本文作者:佚名 来源:51CTO

优秀的个人博客,低调大师

Fastlane 2.232.2 发布,移动端自动化流程工具

Fastlane 是一个针对 iOS 和 Android 全方位开发自动化流程的工具。利用目前支持的工具可以做包含自动化和可持续化构建的每个环节,比如单元测试、截图、分发渠道、上传元数据和 ipa 包提交审核等等。 Fastlane 2.232.2现已发布,具体更新内容包括: [sigh] 修复:防止在 VERBOSE 模式下将空字符串作为 codesign 输入 (#29910) 修复控制台命令与 Ruby 3.3+ 的兼容性 (#29925) cli:在 ensure 代码块中失败时,不要隐藏原始异常(#29923) [core] 修复 gemspec bin/console exclusion,使其排除“console”而不是“bin/console”(#29914) [core] 升级racktransitive dep 以满足 Dependabot 的要求 (#29911) bulid:迁移到 faraday 1.10.5 (#29906) 更新说明:https://github.com/fastlane/fastlane/releases/tag/2.232.2

优秀的个人博客,低调大师

Fastlane 2.231.0 发布,移动端自动化流程工具

Fastlane 是一个针对 iOS 和 Android 全方位开发自动化流程的工具。利用目前支持的工具可以做包含自动化和可持续化构建的每个环节,比如单元测试、截图、分发渠道、上传元数据和 ipa 包提交审核等等。 Fastlane 2.231.0 现已发布,具体更新内容包括: [core] 任务:重命名 key (ruby_min) key 以从中删除“VERSION”(#29864) [scan] 处理 Xcode26 测试失败问题 (#29854) [spaceship] 在portal client中添加对 key creation scope 的支持(#29458) [ci] chore:移除 Slack Train 插件(#29830) [action] 修复get_version_number中的目标选择逻辑(#22178) [core] feat:在不支持的 Ruby 版本上向输出添加警告(#2984) [snapshot] 修复状态栏时间格式,使其使用 HH:MM 而不是 ISO8601 (#29846) [core] build:从 1.22.0 迁移到 xcodeproj 1.27.0 (#29836) [action] increment_build_number 支持 xros (#29827) [spaceship] feat:支持 webhook integration API (#29844) [spaceship] 添加对 legacy 2sk_fo (SRP) logins的支持 (#27461) docs:移除 IMAGE_GUIDELINES 作为 Google 残留项 (#29835) [spaceship] 添加对 sirp api 调用的 robust handling(#29821 ) [spaceship, match] 修复:developer_id_application_g2 certificate filter(#29784) [core] build:支持 bundler v4 (#29813) [snapshot] 修复 iOS+Mac 项目中设备配置被覆盖的问题 (#29834) [ci] build:自动在已发布 PR 中添加消息(#29819) [produce] 向 commands generator 添加 declared age range 选项 (#29815 ) [ci] build:通过重命名来减少编译中的混乱(#29826) [action] 添加xros到 upload_to_app_store.rb (#29460) [ci] 将 SLACK_URL 恢复到 Automation pipeline(#29825 ) [ci] 移除未使用的发布通道。(#29785) [GitHub Actions] 启用 pull-requests.yml 工作流 (#29823) 更新说明:https://github.com/fastlane/fastlane/releases/tag/2.231.0

优秀的个人博客,低调大师

Fastlane 2.229.0 发布,移动端自动化流程工具

Fastlane 是一个针对 iOS 和 Android 全方位开发自动化流程的工具。利用目前支持的工具可以做包含自动化和可持续化构建的每个环节,比如单元测试、截图、分发渠道、上传元数据和 ipa 包提交审核等等。 Fastlane 2.229.0 现已发布,具体更新内容包括: [ci] 将标准 gem openssl 锁定到不受影响的版本,以支持 OpenSSL 3.6.0+ (#29763) [ci] 将 bundler 降级到 2.4.22 版本以支持 2.6.x Ruby (#29762) 通过 dependabot[bot] 将 actions/checkout 版本从 2 提升到 4 (#22089) [ci] 修复 CircleCI 并更新 AppVeyor 并添加 Ruby 3.4 CI (#29753) chore(workflows):移除tags(#29665) 支持 Ruby 3.4 (#29184) [match] 修复Aws::S3::Object#download_file弃用问题 (#29704) 文档:更新 fastlane 与 MNF 的关联部分(#29747) 修复:将生成的可用操作存储在文档的 /generated 目录中(#29729) [deliver] 更新 ageRatingDeclaration(#29643) 更新说明:https://github.com/fastlane/fastlane/releases/tag/2.229.0

优秀的个人博客,低调大师

Fastlane 2.212.2 发布,移动端自动化流程工具

Fastlane 是一个针对 iOS 和 Android 全方位开发自动化流程的工具。利用目前支持的工具可以做包含自动化和可持续化构建的每个环节,比如单元测试、截图、分发渠道、上传元数据和 ipa 包提交审核等等。 Fastlane 2.212.2 发布了,此版本带来一些修复,具体更新细项如下: [ci] 仅在 master 和 version bump 分支上运行所有 mac 作业(#21088) [spaceship] 从应用程序请求中删除不推荐使用的属性(#21187) [snapshot] 修复LatestOsVersion#version_for_os 中的死锁 (#20329) [deliver]为 Xcode 14 验证实现verify和altool(#20738) [action][ensure_git_status_clean]修复不正确的“忽略”参数处理 (#20976) [spaceship] 增加分发中构建查询的限制,以处理多平台问题 (#21087) 更新公告:https://github.com/fastlane/fastlane/releases/tag/2.212.2

优秀的个人博客,低调大师

Fastlane 2.211.0 发布,移动端自动化流程工具

Fastlane 是一个针对 iOS 和 Android 全方位开发自动化流程的工具。利用目前支持的工具可以做包含自动化和可持续化构建的每个环节,比如单元测试、截图、分发渠道、上传元数据和 ipa 包提交审核等等。 Fastlane 2.211.0 发布了,此版本带来许多改进,具体更新细项如下: [发布] 修复更宽容的更新日志生成发布 (#20851) [match][sigh] 在 iOS/iPadOS 配置文件中添加对 Apple Silicon Mac 的支持(#20676) [snapshot] 修复 SnapshotHelper.swift 上的编译器错误 (#20689) [match] 修复 match nuke 不删除解密文件 (#20776) [docs] 为 Fastlane.swift 更新 iTMSTransporter 的路径 (#20795) [action][update_code_signing_settings] 将 sdk 密钥添加到 update_code_signing_settings (#20655) [pilot][deliver] 修复在上传应用程序时调用的私有方法克隆 (#20662) [spaceship] 在 Spaceship::ConnectAPI 中实现解析中心 API (#20726) [action] 添加 xcodes 操作,弃用 xcversion 和 xcode-install (#20672) [frameit] 修复将首先匹配不太具体的设备的设备检测 (#20642) [deliver] 支持检测和上传 6.7" (iPhone 14 Pro Max) 截图 (#20694) 更新公告:https://github.com/fastlane/fastlane/releases/tag/2.211.0

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册