動態(tài)調(diào)用動態(tài)語言之Java腳本API_第1頁
動態(tài)調(diào)用動態(tài)語言之Java腳本API_第2頁
動態(tài)調(diào)用動態(tài)語言之Java腳本API_第3頁
動態(tài)調(diào)用動態(tài)語言之Java腳本API_第4頁
動態(tài)調(diào)用動態(tài)語言之Java腳本API_第5頁
已閱讀5頁,還剩4頁未讀, 繼續(xù)免費(fèi)閱讀

付費(fèi)下載

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

動態(tài)調(diào)用動態(tài)語言之Java腳本API

我們不需要將動態(tài)語言編譯為Java字節(jié)碼就可以在Java應(yīng)用程序中使用它們。使用JavaPlatform,StandardEdition6(JavaSE)中添加的腳本包(并且向后兼容JavaSE5),Java代碼可以在運(yùn)行時以一種簡單的、統(tǒng)一的方式調(diào)用多種動態(tài)語言。本系列文章共分兩個部分,第1部分將介紹Java腳本API的各種特性。文章將使用一個簡單的HelloWorld應(yīng)用程序展示Java代碼如何執(zhí)行腳本代碼以及腳本如何反過來執(zhí)行Java代碼。第2部分將深入研究Java腳本API的強(qiáng)大功能。

Java開發(fā)人員清楚Java并不是在任何情況下都是最佳的語言。今年,1.0版本的JRuby和Groovy的發(fā)行引領(lǐng)了一場熱潮,促使人們紛紛在自己的Java應(yīng)用程序中添加動態(tài)語言。Groovy、JRuby、Rhino、Jython和一些其他的開源項(xiàng)目使在所謂的腳本語言中編寫代碼并在JVM中運(yùn)行成為了可能(請參閱參考資料)。通常,在Java代碼中集成這些語言需要對各種解釋器所特有的API和特性有所了解。

JavaSE6中添加的javax.script包使集成動態(tài)語言更加容易。通過使用一小組接口和具體類,這個包使我們能夠簡單地調(diào)用多種腳本語言。但是,Java腳本API的功能不只是在應(yīng)用程序中編寫腳本;這個腳本包使我們能夠在運(yùn)行時讀取和調(diào)用外部腳本,這意味著我們可以動態(tài)地修改這些腳本從而更改運(yùn)行應(yīng)用程序的行為。

Java腳本API

腳本與動態(tài)的對比

術(shù)語腳本通常表示在解釋器shell中運(yùn)行的語言,它們往往沒有單獨(dú)的編譯步驟。術(shù)語動態(tài)通常表示等到運(yùn)行時判斷變量類型或?qū)ο笮袨榈恼Z言,往往具有閉包和連續(xù)特性。一些通用的編程語言同時具有這兩種特性。此處首選腳本語言是因?yàn)楸疚牡闹攸c(diǎn)是Java腳本API,而不是因?yàn)樘峒暗恼Z言缺少動態(tài)特性。

2006年10月,Java語言添加了腳本包,從而提供了一種統(tǒng)一的方式將腳本語言集成到Java應(yīng)用程序中去。對于語言開發(fā)人員,他們可以使用這個包編寫粘連代碼(gluecode),從而使人們能夠在Java應(yīng)用程序中調(diào)用他們的語言。對于Java開發(fā)人員,腳本包提供了一組類和接口,允許使用一個公共API調(diào)用多種語言編寫的腳本。因此,腳本包類似于不同語言(比如說不同的數(shù)據(jù)庫)中的JavaDatabaseConnectivity(JDBC)包,可以使用一致的接口集成到Java平臺中去。

以前,在Java代碼中,動態(tài)調(diào)用腳本語言涉及到使用各種語言發(fā)行版所提供的獨(dú)特類或使用Apache的JakartaBeanScriptingFramework(BSF)。BSF在一個API內(nèi)部統(tǒng)一了一組腳本語言(請參閱參考資料)。使用JavaSE6腳本API,二十余種腳本語言(AppleScript、Groovy、JavaScript、Jelly、PHP、Python、Ruby和Velocity)都可以集成到Java代碼中,這在很大程序上依賴的是BSF。

腳本API在Java應(yīng)用程序和外部腳本之間提供了雙向可見性。Java代碼不僅可以調(diào)用外部腳本,而且還允許那些腳本訪問選定的Java對象。比如說,外部Ruby腳本可以對Java對象調(diào)用方法,并訪問對象的屬性,從而使腳本能夠?qū)⑿袨樘砑拥竭\(yùn)行中的應(yīng)用程序中(如果在開發(fā)時無法預(yù)計(jì)應(yīng)用程序的行為)。

調(diào)用外部腳本可用于運(yùn)行時應(yīng)用程序增強(qiáng)、配置、監(jiān)控或一些其他的運(yùn)行時操作,比如說在不停止應(yīng)用程序的情況下修改業(yè)務(wù)規(guī)則。腳本包可能的作用包括:

·在比Java語言更簡單的語言中編寫業(yè)務(wù)規(guī)則,而不用借助成熟的規(guī)則引擎。

·創(chuàng)建插件架構(gòu),使用戶能夠動態(tài)地定制應(yīng)用程序。

·將已有腳本集成到Java應(yīng)用程序中,比如說處理或轉(zhuǎn)換文件文章的腳本。

·使用成熟的編程語言(而不是屬性文件)從外部配置應(yīng)用程序的運(yùn)行時行為。

·在Java應(yīng)用程序中添加一門特定于域的語言(domain-specificlanguage)。

·在開發(fā)Java應(yīng)用程序原型的過程中使用腳本語言。

·在腳本語言中編寫應(yīng)用程序測試代碼。

你好,腳本世界

HelloScriptingWorld類(本文中的相關(guān)代碼均可從下載部分獲得)演示了Java腳本包的一些關(guān)鍵特性。它使用硬編碼的JavaScript作為示例腳本語言。此類的main()方法(如清單1所示)將創(chuàng)建一個JavaScript腳本引擎,然后分別調(diào)用五個方法(在下文的清單中有顯示)用于突出顯示腳本包的特性。

清單1.HelloScriptingWorldmain方法publicstaticvoidmain(String[]args)throwsScriptException,NoSuchMethodException{

ScriptEngineManagerscriptEngineMgr=newScriptEngineManager();

ScriptEnginejsEngine=scriptEngineMgr.getEngineByName("JavaScript");

if(jsEngine==null){

System.err.println("NoscriptenginefoundforJavaScript");

System.exit(1);

}

System.out.println("CallinginvokeHelloScript...");

invokeHelloScript(jsEngine);

System.out.println("\nCallingdefineScriptFunction...");

defineScriptFunction(jsEngine);

System.out.println("\nCallinginvokeScriptFunctionFromEngine...");

invokeScriptFunctionFromEngine(jsEngine);

System.out.println("\nCallinginvokeScriptFunctionFromJava...");

invokeScriptFunctionFromJava(jsEngine);

System.out.println("\nCallinginvokeJavaFromScriptFunction...");

invokeJavaFromScriptFunction(jsEngine);

}

main()方法的主要功能是獲取一個javax.script.ScriptEngine實(shí)例(清單1中的前兩行代碼)。腳本引擎可以在特定的語言中加載并執(zhí)行腳本。它是Java腳本包中使用最為頻繁、作用最為重要的類。我們從javax.script.ScriptEngineManager獲取一個腳本引擎(第一行代碼)。通常,程序只需要獲取一個腳本引擎實(shí)例,除非使用了很多種腳本語言。

ScriptEngineManager類

ScriptEngineManager可能是腳本包中惟一一個經(jīng)常使用的具體類;其他大多數(shù)都是接口。它或許是腳本包中惟一的一個要直接或間接地(通過SpringFramework之類的依賴性注入機(jī)制)實(shí)例化的類。ScriptEngineManager可以使用以下三種方式返回腳本引擎:

·通過引擎或語言的名稱,比如說清單1請求JavaScript引擎。

·通過該語言腳本共同使用的文件擴(kuò)展名,比如說Ruby腳本的.rb。

·通過腳本引擎聲明的、知道如何處理的MIME類型。

本文示例為什么要使用JavaScript?

本文中的HelloWorld示例使用了部分JavaScript腳本,這是因?yàn)镴avaScript代碼易于理解,不過主要還是因?yàn)镾unMicrosystems和BEASystems所提供的Java6運(yùn)行時環(huán)境附帶有基于MozillaRhino開源JavaScript實(shí)現(xiàn)的JavaScript解釋器。使用JavaScript,我們無需在類路徑中添加腳本語言JAR文件。

ScriptEngineManager間接查找和創(chuàng)建腳本引擎。也就是說,當(dāng)實(shí)例化腳本引擎管理程序時,ScriptEngineManager會使用Java6中新增的服務(wù)發(fā)現(xiàn)機(jī)制在類路徑中查找所有注冊的javax.script.ScriptEngineFactory實(shí)現(xiàn)。這些工廠類封裝在Java腳本API實(shí)現(xiàn)中;也許您永遠(yuǎn)都不需要直接處理這些工廠類。

ScriptEngineManager找到所有的腳本引擎工廠類之后,它會查詢各個類并判斷是否能夠創(chuàng)建所請求類型的腳本引擎——清單1中為JavaScript引擎。如果工廠說可以創(chuàng)建所需語言的腳本引擎,那么管理程序?qū)⒁蠊S創(chuàng)建一個引擎并將其返回給調(diào)用者。如果沒有找到所請求語言的工廠,那么管理程序?qū)⒎祷豱ull,清單1中的代碼將檢查null返回值并做出預(yù)防。

ScriptEngine接口

如前所述,代碼將使用ScriptEngine實(shí)例執(zhí)行腳本。腳本引擎充當(dāng)腳本代碼和最后執(zhí)行代碼的底層語言解釋器或編譯器之間的中間程序。這樣,我們就不需要了解各個解釋器使用哪些類來執(zhí)行腳本。比如說,JRuby腳本引擎可以將代碼傳遞給JRuby的org.jruby.Ruby類的一個實(shí)例,首先將腳本編譯成中間形式,然后再調(diào)用它計(jì)算腳本并處理返回值。腳本引擎實(shí)現(xiàn)隱藏了一些細(xì)節(jié),包括解釋器如何與Java代碼共享類定義、應(yīng)用程序?qū)ο蠛洼斎?輸出流。

圖1顯示了應(yīng)用程序、Java腳本API和ScriptEngine實(shí)現(xiàn)、腳本語言解釋器之間的總體關(guān)系。我們可以看到,應(yīng)用程序只依賴于腳本API,它提供了ScriptEngineManager類和ScriptEngine接口。ScriptEngine實(shí)現(xiàn)組件處理使用特定腳本語言解釋器的細(xì)節(jié)。

圖1:腳本API組件關(guān)系

您可能會問:如何才能獲取腳本引擎實(shí)現(xiàn)和語言解釋器所需的JAR文件呢?最好的方法是在上托管的開源Scripting項(xiàng)目中查找腳本引擎實(shí)現(xiàn)(請參閱參考資料)。您可以在上找到許多語言的腳本引擎實(shí)現(xiàn)和其他網(wǎng)站的鏈接。Scripting項(xiàng)目還提供了各種鏈接,通過這些鏈接可以下載受支持的腳本語言的解釋器。

在清單1中,main()方法將ScriptEngine傳遞給各個方法用于計(jì)算該方法的JavaScript代碼。第一個方法如清單2所示。invokeHelloScript()方法調(diào)用腳本引擎的eval方法計(jì)算和執(zhí)行JavaScript代碼中的特定字符串。ScriptEngine接口定義了6個重載的eval()方法,用于將接收的腳本當(dāng)作字符串或java.io.Reader對象計(jì)算,java.io.Reader對象一般用于從外部源(例如文件)讀取腳本。

清單2.invokeHelloScript方法privatestaticvoidinvokeHelloScript(ScriptEnginejsEngine)throwsScriptException{

jsEngine.eval("println('HellofromJavaScript')");

}

腳本執(zhí)行上下文

HelloScriptingWorld應(yīng)用程序中的示例腳本使用JavaScriptprintln()函數(shù)向控制臺輸出結(jié)果,但是我們擁有輸入和輸出流的完全控制權(quán)。腳本引擎提供了一個選項(xiàng)用于修改腳本執(zhí)行的上下文,這意味著我們可以修改標(biāo)準(zhǔn)輸入流、標(biāo)準(zhǔn)輸出流和標(biāo)準(zhǔn)錯誤流,同時還可以定義哪些全局變量和Java對象對正在執(zhí)行的腳本可用。

invokeHelloScript()方法中的JavaScript將HellofromJavaScript輸出到標(biāo)準(zhǔn)輸出流,在本例中為控制臺窗口。(清單6含有運(yùn)行HelloScriptingWorldApplication時的完整輸出。)

注意,類中的這一方法和其他方法都聲明拋出了javax.script.ScriptException。這個選中的異常(腳本包中定義的惟一一個異常)表示引擎無法解析或執(zhí)行給定的代碼。所有腳本引擎eval()方法都聲明拋出一個ScriptException,因此我們的代碼需要適當(dāng)處理這些異常。

清單3顯示了兩個有關(guān)的方法:defineScriptFunction()和invokeScriptFunctionFromEngine()。defineScriptFunction()方法還使用一段硬編碼的JavaScript代碼調(diào)用腳本引擎的eval()方法。但是有一點(diǎn)需要注意,該方法的所有工作只是定義了一個JavaScript函數(shù)sayHello()。并沒有執(zhí)行任何代碼。sayHello()函數(shù)只有一個參數(shù),它會使用println()語句將這個參數(shù)輸出到控制臺。腳本引擎的JavaScript解釋器將這個函數(shù)添加到全局環(huán)境,以供后續(xù)的eval調(diào)用使用(該調(diào)用發(fā)生在invokeScriptFunctionFromEngine()方法中,這并不奇怪)。

清單3.defineScriptFunction和invokeScriptFunctionFromEngine方法privatestaticvoiddefineScriptFunction(ScriptEngineengine)throwsScriptException{

//Defineafunctioninthescriptengine

engine.eval(

"functionsayHello(name){"+

"println('Hello,'+name)"+

"}"

);

}

privatestaticvoidinvokeScriptFunctionFromEngine(ScriptEngineengine)

throwsScriptException

{

engine.eval("sayHello('World!')");

}

這兩個方法演示了腳本引擎可以維持應(yīng)用程序組件的狀態(tài),并且能夠在后續(xù)的eval()方法調(diào)用過程中使用其狀態(tài)。invokeScriptFunctionFromEngine()方法可以利用所維持的狀態(tài),方法是調(diào)用定義在eval()調(diào)用中的sayHello()JavaScript函數(shù)。

許多腳本引擎在eval()調(diào)用之間維持全局變量和函數(shù)的狀態(tài)。但是有一點(diǎn)值得格外注意,Java腳本API并不要求腳本引擎提供這一特性。本文中所使用的JavaScript、Groovy和JRuby腳本引擎確實(shí)在eval()調(diào)用之間維持了這些狀態(tài)。

清單4中的代碼在前一個示例的基礎(chǔ)上做了幾分修改。原來的invokeScriptFunctionFromJava()方法在調(diào)用sayHello()JavaScript函數(shù)時沒有使用ScriptEngine的eval()方法或JavaScript代碼。與此不同,清單4中的方法使用Java腳本API的javax.script.Invocable接口調(diào)用由腳本引擎所維持的函數(shù)。invokeScriptFunctionFromJava()方法將腳本引擎對象傳遞給Invocable接口,然后對該接口調(diào)用invokeFunction()方法,最終使用給定的參數(shù)調(diào)用sayHello()JavaScript函數(shù)。如果調(diào)用的函數(shù)需要返回值,則invokeFunction()方法會將值封裝為Java對象類型并返回。

清單4.invokeScriptFunctionFromJava方法privatestaticvoidinvokeScriptFunctionFromJava(ScriptEngineengine)

throwsScriptException,NoSuchMethodException

{

InvocableinvocableEngine=(Invocable)engine;

invocableEngine.invokeFunction("sayHello","fromJava");

}

使用代理實(shí)現(xiàn)高級腳本調(diào)用

當(dāng)腳本函數(shù)或方法實(shí)現(xiàn)了一個Java接口時,就可以使用高級Invocable。Invocable接口定義了一個getInterface()方法,該方法使用接口做為參數(shù)并且將返回一個實(shí)現(xiàn)該接口的Java代碼對象。從腳本引擎獲得代理對象之后,可以將它作為正常的Java對象對待。對該代理調(diào)用的方法將委托給腳本引擎通過腳本語言執(zhí)行。

注意,清單4中沒有JavaScript代碼。Invocable接口允許Java代碼調(diào)用腳本函數(shù),而無需知道其實(shí)現(xiàn)語言。如果腳本引擎無法找到給定名稱或參數(shù)類型的函數(shù),那么invokeFunction()方法將拋出一個java.lang.NoSuchMethodException。

Java腳本API并不要求腳本引擎實(shí)現(xiàn)Invocable接口。實(shí)際上,清單4中的代碼應(yīng)該使用instanceof運(yùn)算符確保腳本引擎在轉(zhuǎn)換(cast)之前實(shí)現(xiàn)了Invocable接口。

通過腳本代碼調(diào)用Java方法

清單3和清單4中的示例展示了Java代碼如何調(diào)用腳本語言中定義的函數(shù)或方法。您可能會問:腳本語言中編寫的代碼是否可以反過來對Java對象調(diào)用方法呢?答案是可以。清單5中的invokeJavaFromScriptFunction()方法顯示了如何使腳本引擎能夠訪問Java對象,以及腳本代碼如何才能對這些Java對象調(diào)用方法。明確的說,invokeJavaFromScriptFunction()方法使用腳本引擎的put()方法將HelloScriptingWorld類的實(shí)例本身提供給引擎。當(dāng)引擎擁有Java對象的訪問權(quán)之后(使用put()調(diào)用所提供的名稱),eval()方法腳本中的腳本代碼將使用該對象。

清單5.invokeJavaFromScriptFunction和getHelloReply方法privatestaticvoidinvokeJavaFromScriptFunction(ScriptEngineengine)

throwsScriptException

{

engine.put("helloScriptingWorld",newHelloScriptingWorld());

engine.eval(

"println('InvokinggetHelloReplymethodfromJavaScript...');"+

"varmsg=helloScriptingWorld.getHelloReply(vJavaScript');"+

"println('Javareturned:'+msg)"

);

}

/**Methodinvokedfromtheabovescripttoreturnastring.*/

publicStringgetHelloReply(Stringname){

return"JavamethodgetHelloReplysays,'Hello,"+name+"'";

}

清單5中的eval()方法調(diào)用中所包含的JavaScript代碼使用腳本引擎的put()方法調(diào)用所提供的變量名稱helloScriptingWorld訪問并使用HelloScriptingWorldJava對象。清單5中的第二行JavaScript代碼將調(diào)用getHelloReply()公有Java方法。getHelloReply()方法將返回JavamethodgetHelloReplysays,'Hello,'字符串。eval()方法中的JavaScript代碼將Java返回值賦給msg變量,然后再將其打印輸出給控制臺。

Java對象轉(zhuǎn)換

當(dāng)腳本引擎使運(yùn)行于引擎環(huán)境中的腳本能夠使用Java對象時,引擎需要將其封裝到適用于該腳本語言的對象類型中。封裝可能會涉及到一些適當(dāng)?shù)膶ο螅缔D(zhuǎn)換,比如說允許JavaInteger對象直接在腳本語言的數(shù)學(xué)表達(dá)式中使用。關(guān)于如何將Java對象轉(zhuǎn)換為腳本對象的研究是與各個腳本語言的引擎特別相關(guān)的,并且不在本文的討論范圍之內(nèi)。但是,您應(yīng)該意識到轉(zhuǎn)換的發(fā)生,因?yàn)榭梢酝ㄟ^測試來確保所使用的腳本語言執(zhí)行轉(zhuǎn)換的方式符合您的期望。

ScriptEngine.put及其相關(guān)get()方法是在運(yùn)行于腳本引擎中的Java代碼和腳本之間共享對象和數(shù)據(jù)的主要途徑。(有關(guān)這一方面的詳細(xì)論述,請參閱本文后面的Script-executionscope一節(jié)。)當(dāng)我們調(diào)用引擎的put()方法時,腳本引擎會將第二個參數(shù)(任何Java對象)關(guān)聯(lián)到特定的字符串關(guān)鍵字。大多數(shù)腳本引擎都是讓腳本使用特定的變量名稱來訪問Java對象。腳本引擎可以隨意對待傳遞給put()方法的名稱。比如說,JRuby腳本引擎讓Ruby代碼使用全局$helloScriptingWorld對象訪問helloScriptingWorld,以符合Ruby全局變量的語法。

腳本引擎的get()方法檢索腳本環(huán)境中可用的值。一般而言,Java代碼通過get()方法可以訪問腳本環(huán)境中的所有全局變量和函數(shù)。但是只有明確使用put()與腳本共享的Java對象才可以被腳本訪問。

外部腳本在運(yùn)行著的應(yīng)用程序中訪問和操作Java對象的這種功能是擴(kuò)展Java程序功能的一項(xiàng)強(qiáng)有力的技巧。(第2部分將通過示例研究這一技巧)。

運(yùn)行HelloScriptingWorld應(yīng)用程序

您可以通過下載和構(gòu)建源代碼來運(yùn)行HelloScriptingWorld應(yīng)用程序。此.zip中文件含有一個Ant腳本和一個Maven構(gòu)建腳本,可以幫助大家編譯和運(yùn)行示例應(yīng)用程序。請執(zhí)行以下步驟:

·下載此.zip文件。

·創(chuàng)建一個新目錄,比如說java-scripting,并將步驟1中所下載的文件解壓到該目錄中。

·打開命令行shell并轉(zhuǎn)到該目錄。

·運(yùn)行antrun-hello命令。

您應(yīng)該可以看到類似于清單6的Ant控制臺輸出。注意,defineScriptFunction()函數(shù)沒有產(chǎn)生任何輸出,因?yàn)樗m然定義了輸出但是卻沒有調(diào)用JavaScript函數(shù)。

清單6.運(yùn)行HelloScriptingWorld時的輸出CallinginvokeHelloScript...

HellofromJavaScript

CallingdefineScriptFunction...

CallinginvokeScriptFunctionFromEngine...

Hello,World!

CallinginvokeScriptFunctionFromJava...

Hello,fromJava

CallinginvokeJavaFromScriptFunction...

InvokinggetHelloReplymethodfromJavaScript...

Javareturned:JavamethodgetHelloReplysays,'Hello,JavaScript'

Java5兼容性

JavaSE6引入了Java腳本API,但是您也可以使用JavaSE5運(yùn)行此API。只需要提供缺少的javax.script包類的一個實(shí)現(xiàn)即可。所幸的是,JavaSpecificationRequest223參考實(shí)現(xiàn)中含有這個實(shí)現(xiàn)(請參閱參考資料獲得下載鏈接。)JSR223對Java腳本API做出了定義。

如果您已經(jīng)下載了JSR223參考實(shí)現(xiàn),解壓下載文件并將script-api.jar、script-js.jar和js.jar文件復(fù)制到您的類路徑下。這些文件將提供腳本API、JavaScript腳本引擎接口和JavaSE6中所附帶的JavaScript腳本引擎。

腳本執(zhí)行作用域

與簡單地調(diào)用引擎的get()和put()方法相比,如何將Java對象公開給運(yùn)行于腳本引擎中的腳本具有更好的可配置性。當(dāng)我們在腳本引擎上調(diào)用get()或put()方法時,引擎將會在javax.script.Bindings接口的默認(rèn)實(shí)例中檢索或

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論