(轉)eclipse下 gradle構建項目

原文:http://www.ibm.com/developerworks/cn/opensource/os-cn-gradle/java

在 eclipse 下利用 gradle 構建系統

基本開發環境web

  • 操做系統:本教程使用的爲 Windows Vista Enterprise, 若是您的系統是 Linux 的,請選擇下載對應版本的其餘工具,包括開發工具、Java EE 服務器、Apache Ant、SoapUI。
  • 開發工具:Eclipse IDE for SOA Developers 版本,請到 http://www.eclipse.org/downloads/ 網站下載,固然任何版本的 eclipse 都是能夠的。
  • Java EE 服務器:Apache-Tomcat-6.0.18,能夠到 http://tomcat.apache.org/download-60.cgi 下載,使用 5.0 以上的任何版本均可以的,固然,您也可使用 Jboss 等其餘 Java EE 服務器。
  • Jdk:到 http://java.sun.com 下載 1.5.0_17 版本,下載後安裝便可。

Ant,Maven,Gradle 簡單比較

Ant 是咱們過去構建系統基本都會用到的,xml 腳本文件中包括若干 task 任務,任務之間能夠互相依賴,對於一個大的項目來講,這些 xml 文件維護起來的確不是一件容易的事情,還有那些項目依賴的而沒有版本號的 jar 包,有時真的讓人頭疼,後來 Maven 出現了,基於中央倉庫的編譯相對於 Ant 來講的確是好了不少,可是,是否是 Ant,Maven 就是咱們構建項目的惟一選擇呢?呵呵,固然不了,利用 Gradle 來構建系統我認爲將成爲 java 構建項目的最佳選擇,簡單,快速,對初學者無苛刻要求,能夠說是拿來就會用,並且咱們不再用看那些冗長而複雜的 xml 文件了,由於 Gradle 是基於 Groovy 語言的,Groovy 你們應該很熟悉吧,是基於 Java Virtual Machine 的敏捷開發語言,它結合了 Python、Ruby 和 Smalltalk 的許多強大的特性,若是你是一個 Ant 的徹底支持者,也沒有問題,由於 Gradle 能夠很平滑的來調用 Ant 文件的,我這樣說你可能不接受 Gradle,下面咱們就會經過一個個具體實例來說解 Ant,Maven,Gradle 構建項目的過程,經過例子咱們能很容易明白它們的差別。Let ’ s go。apache

用 Ant 來構建簡單系統

新建一個 Java project, 命名爲 ant_projectapi

圖 1. 新建 ant_project 項目

圖 1. 新建 ant_project 項目

而後新建一個 HelloWorld 類,咱們下面就是將這個項目經過 Ant 來編譯,打包,類的代碼列表如清單 1 所示:tomcat

清單 1. HelloWorld 類
 package org.ant.test; 

 public class HelloWorld { 
	 public String sayHello(String name){ 
		 return "Hello "+name; 
	 } 
 }

而後再新建一個 build 文件,命名爲 build.xml, 內容如清單 3 所示:服務器

清單 2. build.xml
 <?xml version="1.0" encoding="UTF-8"?> 
 <project name="project" default="default"> 
    <target name="default" depends="depends" description="description"> 
        <javac srcdir="src" destdir="bin" includes="org/**"></javac> 
    	 <jar basedir="bin" destfile="dist/ant_project.jar"></jar> 
    	 <war destfile="dist/ant_project.war" webxml="WEB-INF/web.xml"> 
    		 <classes dir="bin"></classes> 
    	 </war> 
    </target> 
    <!-- - - - - - - - - - - - - - - - - - 
          target: depends                      
         - - - - - - - - - - - - - - - - - --> 
    <target name="depends"> 
    </target> 
 </project>

熟悉 ant 的同窗們對於上面的腳本應該很容易看明白,這裏就不詳細解釋了,主要功能就是把這個工程編譯而後打成 jar 和 war 包。 到目前爲止 ant_project 的目錄結構如圖 2 所示:app

圖 2. ant_project 工程目錄結構

圖 2. ant_project 工程目錄結構

運行 ant 腳本。eclipse

 E:\gdcc\tools\apache-ant-1.6.5\bin\ant -f  E:\ws_IBM\ant_project\build.xml 
 
注:ant 放在了 E:\gdcc\tools\apache-ant-1.6.5 目錄下。
執行結果以下:
 Buildfile: E:\ws_IBM\ant_project\build.xml 
 depends: 
 default: 
    [javac] Compiling 1 source file to E:\ws_IBM\ant_project\bin 
      [jar] Building jar: E:\ws_IBM\ant_project\dist\ant_project.jar 
      [war] Building war: E:\ws_IBM\ant_project\dist\ant_project.war 
 BUILD SUCCESSFUL 
 Total time: 859 milliseconds

這是個很是簡單的工程,咱們將他打成了 jar,war 包,所須要的 build 文件大約在 10 行左右,下面咱們再看看用 Gradle 的狀況。jsp

用 Gradle 來構建簡單系統

準備環境:

  1. 下載 gradle-0.9-preview-1 從 http://dist.codehaus.org/gradle/?ref=darwinports.com網站上選擇一個版本,而後解壓到指定目錄,將 Gradle 的 bin 目錄添加到 Path 變量中。
  2. 使用 cmd 命令,而後敲入 gradle – version,如出現如下信息,表示環境配置成功。
 C:\Documents and Settings\suchu>gradle -version 
 Gradle 0.9-preview-1 
 Gradle buildtime: Monday, March 29, 2010 4:51:14 PM CEST 
 Groovy: 1.7.1 
 Ant: Apache Ant version 1.8.0 compiled on February 1 2010 
 Ivy: 2.1.0 
 Java: 1.6.0_12 
 JVM: 11.2-b01 
 JVM Vendor: Sun Microsystems Inc.

注:以上信息根據不一樣版本的 Gradle 或者不一樣的環境也許不一樣,但都是正確的。maven

Gradle 經常使用的使用方法介紹

新建一個 Java project, 命名爲 gradle_project

圖 3. 新建 gradle_project 項目

圖 3. 新建 gradle_project 項目

而後新建一個 java bean 名爲 HelloWorld 內容和上面的同樣,能夠參考 ant_project。 爲了實現編譯,打包功能,咱們須要新建一個名爲 build.gradle 的文件。 文件內容見清單 3 所示:

清單 3. build.gradle 內容
 apply plugin: 'java'

是否是很驚訝,的確,真的就只要這麼短短的一行,而它的功能倒是至關的強大的,能編譯,打成 jar 包,運行測試腳本等。 到目前爲止,項目的結構如圖 4 所示:

圖 4. gradle_project 項目結構圖

圖 4. gradle_project 項目結構圖

這裏須要注意一點的是,項目包的結構最好是按照 Gradle 指望的來創建,固然也能夠經過配置來改變。 下面咱們來運行下 build.gradle 文件。 運行 cmd 命令,進入 gradle_project 項目路徑下,而後運行 gradle build 命令,命令顯示信息如清單 5 所示。

清單 5. build.gradle 運行顯示信息
 E:\ws_IBM\gradle_project>gradle build 
 :compileJava 
 :processResources 
 :classes 
 :jar 
 :assemble 
 :compileTestJava 
 :processTestResources 
 :testClasses 
 :test 
 :check 
 :build 

 BUILD SUCCESSFUL 

 Total time: 5.125 secs

咱們再看下生成物,這個命令首先在 gradle_project 下新建了 build 目錄,build 目錄包含 classes, dependency-cache, libs,tmp 四個目錄,libs 下包含 jar 包,jar 包包含 main 下的全部 java 文件和和資源文件。 一個簡單的例子到這裏就演示完了,怎麼樣是否是腳本很簡潔,用起來很簡單,產生想繼續學習的興趣了吧,別急,下面咱們會繼續來探究 Gradle 的神奇之處。

下面咱們來介紹幾個經常使用的命令,clean,這個命令是將剛纔產生的 build 目錄刪除掉; Assemble,這個命令是編譯 java 文件可是不運行檢查代碼質量等的命令,運行時顯示的信息如清單 6 所示:

清單 6. assemble 命令顯示的信息
 E:\ws_IBM\gradle_project>gradle assemble 
 :compileJava 
 :processResources UP-TO-DATE 
 :classes 
 :jar 
 :assemble 

 BUILD SUCCESSFUL

和清單 5 比較下,他們的區別應該很容易看出來,那麼咱們怎麼樣來運行檢查代碼質量的命令而不須要打成 jar 包之類的額外工做呢,check 命令正好知足你的要求,此命令就是編譯 java 文件並運行那些相似 Checkstyle,PMD 等外部插件命令來檢查咱們本身的源代碼。Check 命令運行顯示的信息如清單 7 所示:

清單 7. check 命令運行時信息
 E:\ws_IBM\gradle_project>gradle check 
 :compileJava UP-TO-DATE 
 :processResources UP-TO-DATE 
 :classes UP-TO-DATE 
 :compileTestJava UP-TO-DATE 
 :processTestResources UP-TO-DATE 
 :testClasses UP-TO-DATE 
 :test UP-TO-DATE 
 :check UP-TO-DATE 

 BUILD SUCCESSFUL

這裏須要說明一點的是 Gradle 是增量式編譯的,只編譯那些有變更的 java 類或資源文件的,如 UP-TO-DATE 表示是有更新的。 如今 javadoc 愈來愈受到人們的重視,尤爲對於那些複雜的須要接口調用的的項目,javadoc 的地位就更加突出了,若是咱們使用 Ant 須要在 build 文件中增長清單 8 的片斷。

清單 8. 利用 Ant 生成 javadoc
	 <target name="javadoc"> 
       <!-- destdir 是 javadoc 生成的目錄位置 --> 
      <javadoc destdir="${distDir}" encoding="UTF-8" docencoding="UTF-8"> 
          <!-- dir 是你的源代碼位置,記住是 java 文件的位置而不是 class 文件的位置,
                       第一次用這個命令容易忽略這點 切記 --> 
                <packageset dir="${srcDir}"> 
           <!-- exclude 是去掉那些不想生成 javadoc 的類文件 --> 
                             <exclude name="${excludeClasses}" /> 
                                   </packageset> 
                           </javadoc> 
        </target>

而後咱們用 ant javadoc 命令來運行,便可生成 javadoc。那麼咱們 利用 Gradle 是怎樣來生成 javadoc 的呢,都須要作那些額外的工做呢? build.gradle 文件是否須要修改呢?咱們的回答是,不用,什麼都不用修改,什麼都不用作,只需利用 gradle javadoc 命令,便可生成咱們指望的 javadoc。 一般咱們新建一個項目,.classpath 文件的內容如清單 9 所示:

清單 9. .classpath 文件內容
 <?xml version="1.0" encoding="UTF-8"?> 
 <classpath> 
	 <classpathentry kind="src" path="src"/> 
	 <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER
	    /org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk1.6.0_12"/> 
	 <classpathentry kind="output" path="bin"/> 
 </classpath>

經過上面的知識咱們知道,Gradle 指望的目錄結構和自動生成的是有些差異的,好比源碼路徑,編譯後的文件放置目錄等,那麼咱們能不能經過 Gradle 命令來統一一下呢,使原項目結構與 Gradle 指望的一致,以避免開發者將代碼放置到了錯誤的目錄結構下,那樣 Gradle 是無論理它們的。下面咱們就經過一個簡單的方法來實現上面的需求,首先咱們來簡單修改下 build.gradle 文件,添加 apply plugin: 'eclipse'這麼一行,而後咱們使用命令 gradle eclipse 便可。.classpath 文件的變化如清單 9 所示。

清單 9. 修改後的 .classpath 文件內容
 <?xml version="1.0" encoding="UTF-8"?> 
 <classpath> 
  <classpathentry kind="src" path="src/main/java"/> 
  <classpathentry kind="output" path="build/classes/main"/> 
  <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> 
 </classpath>

War 包是咱們常常要用到的,上面咱們利用 Ant 腳本生成過 war 包,那麼 Gradle 又是怎樣來生成 war 包的呢?通過上面的學習或許你已經猜出來了,須要增長一個 plugin,徹底正確,只須要將 apply plugin: 'war' 這一行加入到 build.gradle 文件中,而後運行 gradle War 命令便可,簡單的簡直要命,是否是,呵呵!

如何在老項目上使用 Gradle

咱們上面講過,Gradle 對其所能控制的目錄結構是有必定的要求的,那麼若是咱們的項目已經開始很長時間了,如今的項目結構不知足 Gradle 的要求,那麼咱們還能不能利用 Gradle 呢?答案固然是確定的,下面咱們就介紹怎樣在老項目上使用 Gradle,方法很簡單,固然若是過於複雜咱們也不必再這裏介紹它了,直接使用 Ant 就行了。首先咱們須要在 build.gradle 文件中增長如清單 10 所示的內容。

清單 10. 匹配老項目的結構
 sourceSets { 
	 main { 
		 java.srcDir "$projectDir/src"
	 } 
 }

而後咱們就可使用 Gradle 提供的全部命令和方法了。

如何加入項目所依賴的 jar 包

你們都知道,一個項目在編譯過程當中要依賴不少 jar 包的,在 Ant 中咱們經過添加 classpath 來實現的,如清單 11 所示。

清單 11. ant 中添加依賴的 jar 包
 <path id="j2ee"> 
		 <pathelement location="${servlet.jar}" /> 
		 <pathelement location="${jsp-api.jar}" /> 
		 <pathelement location="${ejb.jar}" /> 
		 <pathelement location="${jms.jar}" /> 
 </path> 
 <javac destdir="${build.classes}" srcdir="${src.dir}" debug="${javac.debug}" 
                 deprecation="${javac.deprecation}"> 
			 <include name=" "/> 
			 <classpath refid="j2ee"/> 
		 </javac>

那麼 Gradle 又是怎樣來作的呢?經過上面的知識的學習,你是否有一個大概的思路呢?假如咱們如今有一個 java 類叫 HelloWorldTest,這個類中引用了 junit 這個 jar 包中的類,這時候咱們用 Gradle 要怎樣來編譯這個類呢? 首先咱們新建一個目錄叫 libs,這個目錄就是放置項目所依賴的全部 jar 包,固然包括 HelloWorldTest 類所依賴的 junit-4.4.jar 包,而後咱們要修改下 build.gradle 文件,增長內容見清單 12。

清單 12. 工程所依賴 jar 包添加方法
repositories { 
	 flatDir(dirs: "$projectDir/libs") 
 } 
 dependencies { 
	 compile ':junit:4.4'
 }

注:repositories 至關一個存儲 jar 包的倉庫,咱們能夠指定本地的依賴 jar 包,也能夠利用 Maven 所指定的倉庫,如 mavenCentral(); 經過 dependencies 來包含全部真正要依賴的 jar 包,格式爲 goup:name:version,':junit:4.4:' 就是表示 dirs 路徑下的 junit-4.4.jar 這個包。

如何實現 copy 工做

Copy 是咱們常常要用到的一個命令,java 類的 copy,資源文件的 copy 等等。若是是 Ant 咱們會在 build.xml 文件中加入清單 13 中的內容。

清單 13. Ant 中的 copy 任務
複製單個文件到另外一個文件
  <copy file="myfile.txt" tofile="mycopy.txt"/> 
複製單個文件到一個目錄
  <copy file="myfile.txt" todir="../some/other/dir"/> 
複製一個目錄到另外一個目錄
  <copy todir="../new/dir"> 
    <fileset dir="src_dir"/> 
  </copy> 
複製一部分文件到一個目錄下
  <copy todir="../dest/dir"> 
    <fileset dir="src_dir"> 
      <exclude name="**/*.java"/> 
    </fileset> 
  </copy> 
  <copy todir="../dest/dir"> 
    <fileset dir="src_dir" excludes="**/*.java"/> 
  </copy>

咱們知道 copy 任務中有不少屬性,這裏咱們就不一一列出了,咱們仍是主要看下 Gradle 是如何來實現這些功能的。

使用 Gradle 實現目錄之間 copy 文件任務

咱們只須要在 build.gradle 文件中加入清單 14 中的內容。

清單 14. gradle 中實現目錄間複製文件
 task copyOne(type: Copy) { 
	 from 'src/main/test'
	 into 'build/anotherDirectory'
 }

注:把 test 目錄下的全部文件複製到 anotherDirectory 目錄下。 而後咱們利用命令 E:\ws_IBM\gradle_project>gradle copyOne 來執行便可。

對 copy 文件的過濾

有時候一個目錄下的文件數目不少,而咱們只想複製某一部分文件,好比只複製 java 文件或資源文件等,這時候咱們就要用到 copy 任務的 include 屬性,這一點和 Ant 是同樣的。好比只複製 java 文件到某一指定目錄,實現這個需求咱們要在 build.gradle 文件中增長清單 15 的內容。

清單 15. copy java 文件到指定目錄
 task copyTwo(type: Copy) { 
	 from 'src/main/test'
	 into 'build/anotherDirectory'
	 include '**/*.java'
 }

若是咱們只想排除一些文件,不想把這一類文件 copy 過去,這時候咱們要用到 exclude 屬性,好比咱們不想把 java 文件複製到指定目錄中,那麼咱們只須要將上面清單 15 中的 include 替換成 exclude 便可。

發佈 jar 文件

作項目時常常會遇到一個 project 中的類依賴另外一個 project 中類的狀況,若是用 Ant,咱們會這樣作,首先將被依賴的類文件打成 jar 包,而後利用 copy 命令將這個 jar 包複製到指定目錄下,咱們能夠想象到要向 build.xml 添加好多行代碼,這裏咱們就不一一列出了,不會的同窗們能夠參考上面的知識。下面咱們看下 Gradle 是怎樣來完成這一需求的,Gradle 不但能夠講 jar 包發佈到本地的指定目錄中,並且還能夠發佈到遠程目錄中,咱們看下清單 16 的內容。

清單 16. 發佈 jar 包到本地目錄
 publishJarFile { 
	 repositories { 
		 flatDir(dirs: file('jarsDerectory')) 
	 } 
 }

而後咱們利用 gradle publishJarFile 命令便可。 注:清單 16 是將工程下的 java 類文件所有打成 jar 包,而後放到工程目錄下的 jarsDerectory 子目錄中。

Maven 對於 jar 包的倉庫管理方法給咱們提供了不少方便,Gradle 徹底能夠利用 Maven 的這一優勢的,咱們在上面已經講過了如何來使用,那麼咱們又是怎麼來作到將項目所須要的 jar 包更新到倉庫中呢?具體解決方法見清單 17。

清單 17. 發佈 jar 文件到 Maven 的倉庫中
 apply plugin: 'maven'
 publishToMaven { 
 repositories.mavenDeployer { 
 repository(url: "file://localhost/tmp/myRepo/") 
 } 
 }

Gradle 在多個工程中的應用

作項目時候,常常會碰到多個工程的狀況,最一般的狀況咱們也分爲服務器端和客戶端兩部分,這種狀況咱們過去用 Ant 時候會在每一個工程下面都創建個 build.xml 文件或者創建一個 build.xml 文件,而後在這個 build.xml 文件中創建不一樣工程的 target,將將被引用的工程打成 jar 包來供其餘工程引用,那麼 Gradle 是怎樣來完成這樣的需求的呢?下面咱們舉個具體的例子來詳細演示下。首先咱們新建一個主工程命名爲 gradle_multiProject, 而後在主工程下在新建一個子工程命名爲 sub_projectOne, 在兩個工程下面都有一個各自獨立的 src 而且符合 Gradle 要求的目錄結構,在每一個工程下面都建個類命名爲 HelloWorld,類內容同清單 1. 而後咱們新建個 settings.gradle 文件,內容見清單 18。

清單 18. settings.gradle 文件內容
 include "sub_projectone"

而後在新建一個咱們熟悉的 build.gradle 文件,文件內容見清單 19。

清單 19. 主工程目錄下 build.gradle 文件內容
 Closure printProjectName = { task -> println "I'm $task.project.name" } 
 task hello << printProjectName 
 project(':sub_projectone') { 
	 task hello << printProjectName 
 }

而後咱們使用命令 gradle – q hello 運行一下,運行結果如清單 20 所示。

清單 20. 命令運行結果
 E:\ws_IBM\gradle_multiProject>gradle -q hello 
 I'm gradle_multiProject 
 I'm sub_projectone

咱們會發現,這個命令將主工程和子工程的名字都打印出來了,爲何會這樣呢?我想你必定猜對了,由於咱們在 build.gradle 文件中使用了 project() 方法,方法內傳入的是子工程的名稱,若是咱們子工程不止一個,那麼咱們又該怎樣來調用呢?這時候咱們只須要調用另外一個方法 allprojects 便可,注意 allprojects 方法是不須要傳入參數的,它返回的是當前工程和當前工程下面的全部子工程的列表。上面演示的內容其實咱們不常常用到的,這裏簡單的介紹下就是爲了說明 gradle 給咱們提供了好多方法來供咱們調用,在多工程的環境下咱們能夠靈活的使用它們來達到咱們的要求,下面咱們就步入正題來看看在多工程狀況下,gradle 是如何來編譯,打包各自工程的。這裏咱們添加些內容到 build.gradle 文件,內容見清單 21。

清單 21. 添加到 build.gradle 文件中的內容
 subprojects{ 
 apply plugin: 'java'
 }

而後咱們用命令 gradle build,發現主工程下面的全部子工程都新增了一個 build 文件夾,這個文件夾下包含編譯生成的 class 文件和 jar 文件,而主工程的 src 下的代碼卻沒有被編譯,打包。那麼咱們怎樣作能讓主工程和子工程同時被編譯,打包呢?方法很簡單,咱們只須要在 build.gradle 文件中增長 apply plugin: 'java' 這麼一行代碼,如今完整的 build.gradle 內容見清單 22。

清單 22. 完整的 build.gradle 文件內容
 apply plugin: 'java'
 subprojects{ 
 apply plugin: 'java'
 }

是否是很難想象,就這麼幾行代碼就完成了將全部工程中的代碼都編譯了而且都打成了 jar 文件。有的朋友會問了,若是子工程與主工程他們打成的包不同,有的是須要 jar 包,有的須要打成 war 包等等,這樣的需求咱們該怎樣作呢,很簡單咱們只須要在須要打成 war 包的工程下面新創建個 build.gradle 文件,該文件內容爲 apply plugin: 'war',而後咱們咱們在主工程目錄下使用 gradle build 命令便可生成咱們須要的 war 包了,Gradle 就是使用這種方法來知足那種差別性的需求的。

使用 Ant 的朋友們必定會深有感觸的吧!也許有些朋友會有反面的一些聲音,尤爲對那些 Ant 的熱愛者們,必定會說,Ant 若是你使用的好,封裝的好同樣能夠很簡潔而且也能達到這個效果的,的確是這樣的,Gradle 只不過是把咱們常常要使用的一些功能項給封裝成了方法,而後咱們調用這些方法便可了,再說了,Gradle 調用 Ant 腳本也是能夠的,若是你必定要用 Ant, 那麼你用 Gradle 來組織一下邏輯也是不錯的選擇。下面咱們簡單看下在 Gradle 中式怎樣來調用 Ant 腳本的。

Gradle 中調用 Ant 腳本

首先咱們創建 Ant 文件 build.xml, 文件詳細內容見清單 23.

清單 23. build.xml 文件內容
 <project> 
    <target name="hello"> 
        <echo>Hello, from Ant</echo> 
    </target> 
 </project>

而後咱們在創建個 build.gradle 文件,文件詳細內容見清單 24。

清單 24. build.gradle 文件內容
 ant.importBuild 'build.xml'

簡單吧,一句話的事情而已,呵呵。而後咱們使用 gradle hello 命令來看下結果,結果見清單 25。

清單 25. Gradle 調用 Ant 文件的運行結果
 E:\gdcc\me\gradle-0.9-preview-1\samples\userguide\ant\hello>gradle hello 
 :hello 
 [ant:echo] Hello, from Ant 

 BUILD SUCCESSFUL 

 Total time: 9.734 secs

能夠看出,的確調用的是 Ant 的 build.xml 文件吧。

總結

本教程通具體實例來說解如何使用 Gradle 來構建工程的,並在具體實例中引入咱們熟悉的 Ant 來對比完成,這樣能使 Ant 的愛好者們能更快的上手,並能一目瞭然的看到二者的優缺點,最後並講解了怎樣和 Ant 來集成,每個實例都是經過重新建工程開始一步一步的帶領你們來繼續的,咱們知道僅僅經過一片文章來很詳細的將 Gradle 的方方面面都闡述的很清楚,那是不可能的,本教程提供了最基本,最基礎的開發過程,任何複雜的事務歸根結底仍是源於基礎,我一貫倡導,「授之以魚,不如授之以漁」,我想只要方向對了,知道如何下手了,就不會有大的失誤。最後祝你們工做順利。

相關文章
相關標籤/搜索