版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、iOS網(wǎng)絡(luò)層架構(gòu)設(shè)計(jì)分享前言前些天幫公司做了網(wǎng)絡(luò)層的重構(gòu),當(dāng)時(shí)就想做好了就分享給大家,后來接著做了新版本的需求,現(xiàn)在才有時(shí)間整理一下。之前的網(wǎng)絡(luò)層使用的是直接拖拽導(dǎo)入項(xiàng)目的方式導(dǎo)入了AF,然后還修改了大量的源碼,時(shí)隔2年,AF已經(jīng)更新?lián)Q代很多次了,導(dǎo)致整個(gè)重構(gòu)遷移非常的麻煩。不過看著前輩寫的代碼,肯定也是一個(gè)高人,許多思路和我的一樣,但是實(shí)現(xiàn)方式又不同,給我很好的參考。在做網(wǎng)絡(luò)層架構(gòu)的時(shí)候也參考了Casa大神的架構(gòu)思想,但是還是有所不同。本文沒有太多的理論,沒有太多的專業(yè)術(shù)語,一來是方便大家閱讀,二來我的基礎(chǔ)也沒那么好,沒有太多華麗的詞匯,對(duì)于架構(gòu)來說主要是思路,有思路在,具體的實(shí)現(xiàn)就沒有問題
2、了。本文主要介紹以下幾點(diǎn):1.網(wǎng)絡(luò)接口規(guī)范2.多服務(wù)器多環(huán)境設(shè)置3.網(wǎng)絡(luò)層數(shù)據(jù)傳遞(請(qǐng)求和返回)4.業(yè)務(wù)層對(duì)接方式5.網(wǎng)絡(luò)請(qǐng)求怎么自動(dòng)取消6.網(wǎng)絡(luò)層錯(cuò)誤處理無Demo無文章,Demo下載:網(wǎng)絡(luò)接口規(guī)范demo里面的請(qǐng)求示例是在網(wǎng)上找的,不符合我說的這套規(guī)范,僅作示例用規(guī)范很重要,有合理的規(guī)范就可以精簡很多代碼邏輯,特別是接口的兼容,是最底層最基礎(chǔ)的設(shè)計(jì),把接口規(guī)范放在前面來說在做這次重構(gòu)時(shí),我提出了一些規(guī)范點(diǎn),可以給大家參考1.兩層三部分?jǐn)?shù)據(jù)結(jié)構(gòu)接口返回?cái)?shù)據(jù)第一次為字典,分為兩層三部分:code、msg、data1. "code": 0, 2. &quo
3、t;msg": "", 3. "data": 4. "upload_log": true, 5. "has_update": false, 6. "admin_id": "529ecfd64" 7. ·
4、 code:錯(cuò)誤碼,可以記錄下來快速定位接口錯(cuò)誤原因,可以定義一套錯(cuò)誤碼,比如200正常,1重新登錄.· msg:接口文案提示,包括錯(cuò)誤提示,用來直接顯示給用戶,所以這一套錯(cuò)誤提示就不能是什么一串英文錯(cuò)誤了· data:需要返回的數(shù)據(jù),可以是字典,可以是數(shù)組接口幫我們定義了code和msg,是不是我們就不需要做錯(cuò)誤處理了?當(dāng)然不是,服務(wù)端的錯(cuò)誤邏輯畢竟是簡單的,具體到data里面的數(shù)據(jù)處理可能還有錯(cuò)誤,所以錯(cuò)誤的處理是必不可少的,下面會(huì)單獨(dú)對(duì)錯(cuò)誤處理做介紹2.網(wǎng)絡(luò)請(qǐng)求參數(shù)上傳方式統(tǒng)一這里一般都能做到,也有額外的,比如我們的一個(gè)服務(wù)器接口做的比較早,當(dāng)時(shí)POST接口使用的就不
5、規(guī)范,普通的應(yīng)用信息channelID、device_id使用的是拼接在字符串后面的方式,而真正的請(qǐng)求參數(shù)則需要轉(zhuǎn)成json放在一個(gè)字段里面?zhèn)鬟f,就是接口GET、POST并存的方式,造成網(wǎng)絡(luò)層需要做特殊處理所以說標(biāo)準(zhǔn)的GET、POST請(qǐng)求方式是很有必要的3.關(guān)于Null類型大家都知道Null類型在iOS里面是很特殊的,我的建議是放在客戶端來做,原因有很多:1)接口的規(guī)范定義并不是每個(gè)公司都是從一開始就能定義好的,老接口如果要把Null字段去掉的改動(dòng)非常大2)客戶端用過一個(gè)接口過濾也可以解決,一勞永逸,不用再擔(dān)心因?yàn)槟程旖涌诘膯栴}出現(xiàn)崩潰,而且通過一些Model的第三方庫也可以很好的解決這個(gè)問題
6、。這里不得說下swift的類型檢測真是太方便了,之前一個(gè)項(xiàng)目用swift寫的,代碼規(guī)范一點(diǎn),根本不會(huì)出現(xiàn)因?yàn)閰?shù)類型問題引起崩潰多服務(wù)器多環(huán)境設(shè)置這部分基本上是照搬casa大神的設(shè)計(jì),這里我延伸了一個(gè)多環(huán)境的設(shè)計(jì),小的項(xiàng)目一般都是一個(gè)服務(wù)器,但是像淘寶之類的項(xiàng)目一個(gè)服務(wù)器顯然是不可能的,多個(gè)服務(wù)器的設(shè)計(jì)還是非常普遍的。根據(jù)一個(gè)枚舉變量通過ServerFactory單例生成獲取對(duì)應(yīng)的服務(wù)器配置1.服務(wù)器環(huán)境標(biāo)準(zhǔn)的APP是有4個(gè)環(huán)境的,開發(fā)、測試、預(yù)發(fā)、正式,特別是服務(wù)器的代碼,不能說所有的代碼更改都在正式環(huán)境下,應(yīng)該從開發(fā)->測試->預(yù)發(fā)->正式做代碼的更新,開發(fā)就是新需求和優(yōu)
7、化的時(shí)候的更改,測試就是提交給測試人員后的更改,這個(gè)時(shí)候更改是在一個(gè)新的分支上,完成后要和合并到測試分支上并合并到開發(fā)分支上,預(yù)發(fā)這時(shí)候的變動(dòng)就比較小了,一般會(huì)在測試人員完成后發(fā)布給全公司的人來測試,有問題了才會(huì)更改,更改后同樣合并到開發(fā)分支,正式則是線上發(fā)布版本的緊急BUG修復(fù),修改完后同樣合并到開發(fā)分支上。所以開發(fā)分支是一直都是最新的。在此基礎(chǔ)上可能會(huì)有其他的環(huán)境,比如hotfix環(huán)境,自定義的h5/后臺(tái)本地調(diào)試的環(huán)境。客戶端同樣存在這些環(huán)境,并且要提供切換的入口。在我的demo中提供了兩套設(shè)置,一套是第一次安裝應(yīng)用的初始化環(huán)境(宏定義),另外是手動(dòng)切換環(huán)境的設(shè)置(枚舉Environmen
8、tType)。這里有一個(gè)比較繞的邏輯,宏定義的正式環(huán)境設(shè)置高于手動(dòng)切換環(huán)境設(shè)置,手動(dòng)切換環(huán)境設(shè)置高于宏定義其他環(huán)境1. /宏定義環(huán)境設(shè)置 2. #if !defined YA_BUILD_FOR_DEVELOP && !defined YA_BUILD_FOR_TEST && !defined YA_BUILD_FOR_RELEASE && !defined YA_BUILD_FOR_PRERELEASE 3. #de
9、fine YA_BUILD_FOR_DEVELOP 4. /#define YA_BUILD_FOR_TEST 5. /#define YA_BUILD_FOR_PRERELEASE 6. /#define YA_BUILD_FOR_HOTFIX 7. /#define YA_BUILD_FOR_RELEASE /該環(huán)境的優(yōu)先級(jí)最高 8. #endif 9. /手動(dòng)環(huán)境切換設(shè)置 10. #ifdef
10、0;YA_BUILD_FOR_RELEASE 11. /優(yōu)先宏定義正式環(huán)境 12. self.environmentType = EnvironmentTypeRelease; 13. #else 14. /手動(dòng)切換環(huán)境后會(huì)把設(shè)置保存 15. NSNumber *type = NSUserDefaults standardUserDefaults objectForKey:"environmentType" 16. if (type)&
11、#160; 17. /優(yōu)先讀取手動(dòng)切換設(shè)置 18. self.environmentType = (EnvironmentType)type integerValue; 19. else 20. #ifdef YA_BUILD_FOR_DEVELOP 21. self.environmentT
12、ype = EnvironmentTypeDevelop; 22. #elif defined YA_BUILD_FOR_TEST 23. self.environmentType = EnvironmentTypeTest; 24. #elif defined YA_BUILD_FOR_PRERELEASE 25.
13、160; self.environmentType = EnvironmentTypePreRelease; 26. #elif defined YA_BUILD_FOR_HOTFIX 27. self.environmentType = EnvironmentTypeHotFix; 28. #endif 29. 30.
14、 #endif 所以當(dāng)宏定義正式環(huán)境存在的時(shí)候是不能手動(dòng)切換環(huán)境的,用于普通用戶的發(fā)布版本,但是其他宏定義環(huán)境時(shí)是可以切換到正式環(huán)境的。半個(gè)坑另外手動(dòng)切換自定義的環(huán)境是在基類中實(shí)現(xiàn)的,而其他的環(huán)境配置是在協(xié)議中實(shí)現(xiàn)的,這就和其他環(huán)境地址的配置不統(tǒng)一了??梢赃@樣理解,這里的基類是為了提供已返回值,協(xié)議是為了返回值的靈活,既然自定義環(huán)境的地址配置不需要靈活性,自然是放在基類好。思路是大方向,實(shí)現(xiàn)是靈活的,如果非要放在協(xié)議中實(shí)現(xiàn)也無不可以,無非是賦值粘貼幾次一樣的代碼,但是一模一樣的代碼是我最不喜歡看到的,所以就放在基類了。如果有更好的解決方案歡迎提供2.擴(kuò)展性model提供的是高擴(kuò)展性,
15、針對(duì)不同的不服務(wù)器添加更多的配置,比如加密方法,比如數(shù)據(jù)解析方法.前面提到了,統(tǒng)一的規(guī)范有的時(shí)候不是一時(shí)半會(huì)就能做好的,兼容就成了需求,這個(gè)時(shí)候不同服務(wù)器的個(gè)性化設(shè)置就可以在協(xié)議中聲明并實(shí)現(xiàn)了,基類提供返回值就好網(wǎng)絡(luò)層數(shù)據(jù)傳遞(請(qǐng)求和返回)網(wǎng)絡(luò)層數(shù)據(jù)傳遞Client、BaseEngine/DataEngine、RequestDataModel數(shù)據(jù)傳遞網(wǎng)絡(luò)請(qǐng)求的發(fā)生在我理解中分兩步,一步是數(shù)據(jù)的整理,一步是生成Request并發(fā)起請(qǐng)求,基于這個(gè)思想我拆分出了Client和Engine,然后又把URLRequestGenerator從Client中拆分出來,Engine拆分出了下層的BaseEng
16、ine和面向不同業(yè)務(wù)的DataEngine,而從BaseEngine到Client,再到URLRequestGenerator是要做數(shù)據(jù)傳遞的,請(qǐng)求參數(shù)和返回參數(shù),所以又有了RequestDataModelRequestDataModel1. interface YAAPIBaseRequestDataModel : NSObject 2. /* 3. * 網(wǎng)絡(luò)請(qǐng)求參數(shù) 4. */ 5. property (nonatomic, strong) NSString
17、*apiMethodPath; /網(wǎng)絡(luò)請(qǐng)求地址 6. property (nonatomic, assign) YAServiceType serviceType; /服務(wù)器標(biāo)識(shí) 7. property (nonatomi
18、c, strong) NSDictionary *parameters; /請(qǐng)求參數(shù) 8. property (nonatomic, assign) YAAPIManagerRequestType requestType; /網(wǎng)絡(luò)請(qǐng)求方式 9. property (nonatomic, copy) Co
19、mpletionDataBlock responseBlock; /請(qǐng)求著陸回調(diào) 10. / upload 11. / upload file 12. property (nonatomic, strong) NSString *dataFilePath; 13. property (nonatomic, strong) NSString *dataName;
20、0;14. property (nonatomic, strong) NSString *fileName; 15. property (nonatomic, strong) NSString *mimeType; 16. / download 17. / download file 18. / progressBlock 19. property (nonatomic, copy) Progre
21、ssBlock uploadProgressBlock; 20. property (nonatomic, copy) ProgressBlock downloadProgressBlock; 21. end 可以看出來RequestDataModel屬性都是網(wǎng)絡(luò)請(qǐng)求發(fā)起和返回的必要參數(shù),這樣做的好處真的是太大了,不知道大家有沒有這樣的場景:因?yàn)檎?qǐng)求參數(shù)的不同做了好多方法接口暴露出去,最后調(diào)起的還是同一個(gè)方法,而且一旦方法寫的多了,最后連應(yīng)該調(diào)用哪個(gè)方法都不知道了。我就遇到過,所以現(xiàn)在我的網(wǎng)絡(luò)請(qǐng)求調(diào)起是這樣的:1.
22、 /沒有回調(diào),沒有其他的參數(shù),只有一個(gè)dataModel,節(jié)省了你所有的方法 2. YAAPIClient sharedInstance callRequestWithRequestModel:dataModel; 生成NSURLRequest是這樣的:1. NSURLRequest *request = YAAPIURLRequestGenerator sharedInstance generateWithYAAPIRequestWithRequestDataModel:requestModel;
23、60;可以看到我的demo里面的YAAPIClient類和YAAPIURLRequestGenerator類方法至少,方法少就意味著邏輯簡單明了,方便閱讀,兩個(gè)類的代碼行數(shù)都是120行,120行實(shí)現(xiàn)了網(wǎng)絡(luò)請(qǐng)求的發(fā)起和著陸,你能想象嗎另外RequestDataModel帶來的另外一個(gè)好處就是高擴(kuò)展性,你有沒有遇到網(wǎng)絡(luò)層需要添加刪除一個(gè)參數(shù)導(dǎo)致調(diào)用方法修改了,然后很多地方都要修改方法?用RequestDataModel只需要添加刪除參數(shù)就行了,只需要改方法體,這個(gè)改方法體和同時(shí)改方法名方法體是完全兩個(gè)工作量。哈哈,有點(diǎn)賣虎皮膏藥的感覺。這個(gè)的確是我的得意創(chuàng)新點(diǎn)ClientClient做兩個(gè)操作,一
24、個(gè)是生成NSURLRequest,一個(gè)是生成NSURLSessionDataTask并發(fā)起,另外還要暴露取消操作給Engine,URLRequestGenerator是生成NSURLRequest,URLRequestGenerator會(huì)對(duì)dataModel進(jìn)行加工解析,生成對(duì)應(yīng)服務(wù)器的NSURLRequest然后Client通過NSURLRequest生成NSURLSessionDataTaskClient和URLRequestGenerator都是單例1. - (void)callRequestWithRequestModel:(YAAPIBaseRequestDataModel
25、 *)requestModel 2. NSURLRequest *request = YAAPIURLRequestGenerator sharedInstance 3. generateWithRequestDataModel:requestModel; 4. AFURLSessionManager *sessionManager = sel
26、f.sessionManager; 5. NSURLSessionDataTask *task = sessionManager 6. dataTaskWithRequest:request 7. uploadProgress:requestModel.uploadProgressBlock 8. downloadProgress:re
27、questModel.downloadProgressBlock 9. completionHandler:(NSURLResponse * _Nonnull response, 10. id _Nullable responseObject, 11. NSError * _Nullable error) 12.
28、0; 13. /請(qǐng)求著陸 14. 15. task resume; 16. 取消接口參考了casa大神的設(shè)計(jì),使用NSNumber *requestID來做task的綁定,就不多做介紹了BaseEngine/DataEngineEngine或者說是APIManager在我的設(shè)計(jì)中既不是離散的也不是集約的ca
29、sa大神的理論集約型API調(diào)用其實(shí)就是所有API的調(diào)用只有一個(gè)類,然后這個(gè)類接收API名字,API參數(shù),以及回調(diào)著陸點(diǎn)(可以是target-action,或者block,或者delegate等各種模式的著陸點(diǎn))作為參數(shù)。然后執(zhí)行類似startRequest這樣的方法,它就會(huì)去根據(jù)這些參數(shù)起飛去調(diào)用API了,然后獲得API數(shù)據(jù)之后再根據(jù)指定的著陸點(diǎn)去著陸。比如這樣:1. APIRequest startRequestWithApiName:"itemList.v1" params:params success:selector(success:)
30、 fail:selector(fail:) target:self; 離散型API調(diào)用是這樣的,一個(gè)API對(duì)應(yīng)于一個(gè)APIManager,然后這個(gè)APIManager只需要提供參數(shù)就能起飛,API名字、著陸方式都已經(jīng)集成入APIManager中。比如這樣:1. property (nonatomic, strong) ItemListAPIManager *itemListAPIManager; 2. / getter 3. -(ItemListAPIManager *)itemLis
31、tAPIManager 4. 5. if (_itemListAPIManager = nil) 6. _itemListAPIManager = ItemListAPIManager alloc init; 7. _itemListA
32、PIManager.delegate = self; 8. 9. return _itemListAPIManager; 10. 11. / 使用的時(shí)候就這么寫: 12. self.itemListAPIManager loadDataWithParams:params; 各自的優(yōu)點(diǎn)就不說了,但是由此延伸出幾個(gè)問題:1.參數(shù)的傳遞使用字典對(duì)于網(wǎng)絡(luò)層來說是不可知的,而且業(yè)務(wù)層需要去關(guān)注接口
33、字段的變化,其實(shí)是沒有必要的2.離散型API會(huì)造成Manager大爆炸3.集約型會(huì)造成取消操作不方便4.取消操作并不是每個(gè)接口必須的,如果寫成部分離散的部分集約的,代碼的整體結(jié)構(gòu).我是個(gè)有強(qiáng)迫癥的人,看不得這樣的代碼所以我的設(shè)計(jì)主要就解決了上面的這些問題1.面向業(yè)務(wù)層的DataEngine只傳遞必要的參數(shù)進(jìn)來,不使用字典,比如1. interface SearchDataEngine : NSObject 2. + (YABaseDataEngine *)control:(NSObject *)control 3.
34、 searchKey:(NSString *)searchKey 4. complete:(CompletionDataBlock)responseBlock; 5. end control暫時(shí)先不管,是做自動(dòng)取消的,后面再介紹。searchKey就是搜索的關(guān)鍵字在調(diào)用的時(shí)候就是這樣1. self.searchDataEngine = SearchDataEngine control:self searchKey:"關(guān)鍵字" complete:(id data, N
35、SError *error) 2. if (error) 3. NSLog("%",error.localizedDescription); 4. else 5. NSLog(&quo
36、t;%",data); 6. 7. ; 2.我按業(yè)務(wù)層來劃分DataEngine,比如BBSDataEngine、ShopDataEngine、UserInforDataEngine.每個(gè)DataEngine里面包含各自業(yè)務(wù)的所有網(wǎng)絡(luò)請(qǐng)求接口,這樣就不會(huì)出現(xiàn)DataEngine大爆炸,像我們的項(xiàng)目有300多個(gè)接口,拆分后有十幾個(gè)DataEngine,如果使用離散型API設(shè)計(jì),那畫面太美我不敢看?3.BaseEngine提供取消操作每個(gè)接口生成一個(gè)BaseEngine實(shí)例,持有Client返回的reques
37、tID,所以就可以做取消操作,簡單的使用場景1. #import "ViewController.h" 2. #import "SearchDataEngine.h" 3. interface ViewController () 4. property (nonatomic, strong) YABaseDataEngine *searchDataEngine; 5. end 6. implementation Vi
38、ewController 7. - (void)viewDidLoad 8. super viewDidLoad; 9. / Do any additional setup after loading the view, typically from a nib. 10. &
39、#160;self.searchDataEngine cancelRequest; 11. self.searchDataEngine = SearchDataEngine control:self searchKey:"關(guān)鍵字" complete:(id data, NSError *error) 12. if (error)
40、;13. NSLog("%",error.localizedDescription); 14. else 15. NSLog("%",data); 16. 17.
41、60; 18. 19. end 4.返回的YABaseDataEngine實(shí)例ViewController不是必須持有的,當(dāng)有需要取消操作的時(shí)候再去持有就行了這樣的設(shè)計(jì)就集成了集約型和離散型的有點(diǎn),又解決了集約型和離散型的缺點(diǎn)網(wǎng)絡(luò)請(qǐng)求怎么自動(dòng)取消當(dāng)一個(gè)頁面的請(qǐng)求正在天上飛的時(shí)候,用戶等了好久不耐煩了,小手點(diǎn)了個(gè)back,然后ViewController被pop被回收。此時(shí)請(qǐng)求的著陸點(diǎn)就沒了。這是很危險(xiǎn)的情況,著陸點(diǎn)要是沒了,就很容易crash的。casa大神說在BaseDataEngine的dealloc里面做取消網(wǎng)絡(luò)請(qǐng)求操作,我也是這樣想的,但是casa大神說
42、要把BaseDataEngine綁定給ViewController,當(dāng)ViewController銷毀時(shí)BaseDataEngine也就跟著銷毀了,這樣我也是同意的,但是要讓我不管什么情況都要給ViewController添加BaseDataEngine變量來保存BaseDataEngine這是我萬萬不能接受的,而且有的ViewController會(huì)發(fā)起兩三種網(wǎng)絡(luò)請(qǐng)求,難道要我添加兩三個(gè)變量?代碼入侵太大,所以這里偷偷使用了一個(gè)巧,使用了runtime,給ViewController添加一個(gè)字典,來保存requestID和BaseDataEngine,這樣對(duì)于ViewController來說就
43、不是必須要寫變量來持有BaseDataEngine了,所以就出現(xiàn)了上面的DataEngine里面要把control傳遞進(jìn)來的樣子在發(fā)起請(qǐng)求的時(shí)候進(jìn)行綁定1. workingAutoCancelRequests setEngine:self requestID:self.requestID; 在請(qǐng)求完成的時(shí)候進(jìn)行刪除1. weakCworkingAutoCancelRequests removeEngineWithRequestID:engine.requestID; 公司上個(gè)大神的做法雖然使用control的做法很方便,但是如果說要把現(xiàn)在已有的
44、接口都添加一個(gè)control字段的工作量也是很大的,如果已有的接口是使用字典傳遞給DataEngine的,這里給大家一個(gè)公司上個(gè)大神的做法,使用內(nèi)存地址,將內(nèi)存地址添加到字典中去,用內(nèi)存地址做key綁定,也是可以的。如果是像我這樣直接把關(guān)鍵參數(shù)傳遞過來的,不是用的字典,就不行了。1. NSString *memoryAddress = NSString stringWithFormat:"%p", self; 網(wǎng)絡(luò)層錯(cuò)誤處理說實(shí)話,錯(cuò)誤處理該放在按個(gè)地方我也是糾結(jié)了好久,也和公司同事討論了好久,最終定下來了一套方案,僅供大家參考。我們將錯(cuò)誤處理分為兩個(gè)步驟,一個(gè)是錯(cuò)誤解析,一個(gè)是錯(cuò)誤的UI展示大家可以看到我設(shè)計(jì)的接口返回?cái)?shù)據(jù)是標(biāo)準(zhǔn)的id data, NSError *error,所以我的想法是Client就把error處理好,不管你是網(wǎng)絡(luò)超時(shí)錯(cuò)誤也好,或者是數(shù)據(jù)格式不正確也好,都error解析完整,把code錯(cuò)誤碼定義好
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年機(jī)動(dòng)車質(zhì)押借款合同解除及賠償條款3篇
- 二零二五年度零食店收銀員食品安全責(zé)任承諾合同4篇
- 二零二五年度大型工業(yè)鍋爐設(shè)備采購合同2篇
- 2025年度塔吊操作人員勞務(wù)派遣及技能培訓(xùn)合同
- 二零二五年度企業(yè)項(xiàng)目管理培訓(xùn)服務(wù)合同標(biāo)準(zhǔn)3篇
- 2025年度航空器租賃及操作培訓(xùn)合同4篇
- 2025年度農(nóng)機(jī)零部件定制加工合同范本4篇
- 二零二五年度房地產(chǎn)開發(fā)貸款擔(dān)保合同
- 二零二五年度智慧城市版委托貸款合同
- 2025年度體育賽事組織策劃人員勞動(dòng)合同規(guī)范文本4篇
- 電化學(xué)儲(chǔ)能電站安全規(guī)程
- 幼兒園學(xué)習(xí)使用人民幣教案教案
- 2023年浙江省紹興市中考科學(xué)真題(解析版)
- 語言學(xué)概論全套教學(xué)課件
- 大數(shù)據(jù)與人工智能概論
- 《史記》上冊(cè)注音版
- 2018年湖北省武漢市中考數(shù)學(xué)試卷含解析
- 測繪工程產(chǎn)品價(jià)格表匯編
- 《腎臟的結(jié)構(gòu)和功能》課件
- 裝飾圖案設(shè)計(jì)-裝飾圖案的形式課件
- 護(hù)理學(xué)基礎(chǔ)教案導(dǎo)尿術(shù)catheterization
評(píng)論
0/150
提交評(píng)論