开源软件名称(OpenSource Name):kentyeh/mavenStartup开源软件地址(OpenSource Url):https://github.com/kentyeh/mavenStartup开源编程语言(OpenSource Language):HTML 100.0%开源软件介绍(OpenSource Introduction):Ant build.xml,雖然有過去建立的範本,但是還是的根據不同狀況加以 改寫(比如不同的打包方式,如同時deploy 到tomcat 與jboss時用到不 同的log4J設定,或是像GWT必須加上一道Comple手續);當有新版本的 Liberary出來的時候,還得忙著下載新Jar,然後發現不相容時,還得改回來… Maven最大的好處,就是把上面的無聊事標準化,簡單化了,用久了,還真得 少不了它。
在命令視窗執行 mvn archetype:generate 命令,使用互動方式建立Project, 會依序問幾個問題
確定後建立Project的基本架構,如果您不要用互動的方式,上述動作可以以下指令完成相同的事 mvn archetype:create -DgroupId=idv.kentyeh.software -DartifactId=firstmaven \
-DpackageName=idv.kentyeh.software -DarchetypeArtifactId:maven-archetype-quickstart \
-Dversion=1.0-SNAPSHOT Maven的識別管理,分為三層 groupId:artifactId:version,一個組織(group) 可能存在多個Project(atrifact),每個Project也可能存在多個版本(version), 整個函式庫就以這種檔檔案架構進行處理,當使用的函式不存在時,Maven會到 http://repo1.maven.org/maven2/ 或是 http://repo2.maven.org/maven2/ 進行下載,下載後存到您電腦上的函式庫 Maven的管理設定主要靠Pom.xml進行,打開剛才建立的Project設定檔,內容說明如下: <project xmlns="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.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--本Project識別-->
<groupId>idv.kentyeh.software</groupId>
<artifactId>firstmaven</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging> <!--表示打包Project的型態,可能為Jar、war、ear或pom,若是使用了android 則為apk-->
<!--以下是給工具看的,主要是本Project的資訊-->
<name>第一個MavenProject</name>
<url>http://sites.google.com/site/gwtmemo</url>
<!--設定一些變數-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!--設定引用函式庫-->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>{{ book.junit }}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project> 首先要說明的是dependencies段落,比如說,Project內會用到 commons-loggin 的Library,我們可以在此加入新的dependency段落, <dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency> 不知道commons-loggin的識別資料?沒關係,到這裡查。至於scope可以不填,表示打包Project(如war,ear…)時, 引用的Library會一起被打包,Scope的值說明如下:
至於commons-loggin是否須要使用到其它的Library,根本完全不用在意,因為Maven會自動導入相關的Library 以建立web程式來說,其目錄架構說明如下:
之前有說過,Maven有專門存放函式的repository (檔案庫), 但是ASF再厲害,也不可能搜羅所有Library,所以必要的時候,我們必須引用第三方的函式檔案庫, 以下為可能會用到的來源(加入到Pom.xml): <repositories>
<repository><!--J2ee 最新的函式庫在此-->
<id>java.net2</id>
<name>Repository hosting the jee6 artifacts</name>
<url>http://download.java.net/maven/2</url>
</repository>
</repositories> #Maven Plugin 一開始的時候,我們執行 "mvn archetype:generate" 建立Project,mvn 後面接的指令 叫 goal由 "前置字:識別字" 表示要執行的作業。這些執業作業(命令)是由所謂的 plugin所提供,plugin是一種專供 Maven本身使用的Library,同一個plugin通常使用同一前置字,然後本身會帶有說明提供那些作業的自我解說檔(metadata), 通常這個自我解說檔,也會定義每種作業隸屬於那種phase(作業階段);Maven本身早已知道許許多多的goal的定義,當Maven執行特定的 goal時,缺少的Plugin,Maven就會自動去Repository下載相關的檔案。 Maven 的指令可以串接,例如以下指令 mvn clean package javadoc:javadoc exec:exec 表示,先刪除 target 目錄後再行打包Project,然後產生文件,再執行專案(需要額外設定)。 上述的 clean、package(打包)都很容易理解,可是為何又出現了 javadoc:javadoc、exec:exec 這樣的表示, 這是因為Plugin是Maven裡面的一種特殊專案,她裡面存在一些task,當這些Plugin被包含進專案的pom.xml時, 例如要執行maven-javadoc-plugin這個Plugin的javadoc task時,完整的命令下法應該是 mvn org.apache.maven.plugins:maven-javadoc-plugin:2.10.1:javadoc 但是因為在的Jar的Metadata中已經標注了它的prefix,在Maven執行時,會去讀取每個plugin java的metadata, 而maven-javadoc-plugin的metadata標記為javadoc,所以才省略為 javadoc:javadoc, 至於前面的clean package 等則是maven lifecycle的一部分,會綁定特定的Plugin,然後執行 該Plugin的task。 plugin的定義結構通常如下 : <project ...>
...
<build>
<plugins>
<!--可定義多個plugin-->
<plugin>
<groupId>org.apache.maven.plugins</groupId><!--若是此值,則可省略-->
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
...各種設定
</configuration>
</plugin>
<plugins>
<finalName>firstmvn</finalName>
...
<build>
...
</project> 我們建立的第一個 Project 的 pom.xml檔案內有一個段落,可以讓我們定義一些變數, 例如Spring 通常含有多種Library,其引用版本應該一致,所以我通常會定義一個變數 <org.springframework.version>4.2.0.RELEASE</org.springframework.version> 然後,定義版本別的地方會寫成 <version>${org.springframework.version}</version> 以後當版本變更的時候,只要修改<properties>下的<org.springframework.version>4.2.0.RELEASE</org.springframework.version>,就可以引用新的版本。 初建立時的pom.xml內已經有一個變數 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 為什麼沒有看到在那裡引用呢? 其實,前面已經提過,Maven的所有作業都是靠許多的Plugin來達成,雖然在這個pom.xml內沒有看到引用任何Plugin, 但當我們執行 "mvn compile"的時候,因為Maven已經內定很多指令所使用的Plugin,所以實際上該命令會去執行 mvn compiler:compile 而compiler Plugin,encoding會預設參考${project.build.sourceEncoding}這個變數, 所以我們在pom.xml的指定這個變數的值為"UTF-8",所以在編譯程式時,編譯器就會知道程式使用的編碼。 這邊有列出一些預設的變數,可以參考使用。 最後一提的是build內可放一個finalName,一般來說打包的最後檔名為artifactId-version.war(jar,ear),一般來說,web檔deploy時總希望固定一個名字,使用finalName與一些變數就可以將打包檔的名稱固定住, 例如,我們打包的名字不要有版本資料便可設定如下 <finalName>${project.artifact}.war</finalName> 以下是一些預設變數的列表
之前說過goal可是設定屬於某個phase,而phase則可組成lifecycle(生命週期),在Maven有三個LifeCycle?,分別是 clean 、 default 與 site , clean周期負責Project的清理,default周期負責Project的建置而site周期則是負責產生Project的文檔。 例如執行 "mvn package" 時,因為它是屬於 defulat 這個life cycle,所以從 phase validate 到 package 的所有相關的Goals都會被執行
例如 "mvn package"這個Goals,由內定的Goal可以知道, 它可能會執行Goal "mvn jar:jar" 、 "mvn ejb:ejb" 或是 "mvn ejb3:ejb3"(端看您的專案引用了那些Plugin,預設是"jar:jar"), 而 "package"這個Goal是屬於 "package" 這個Phase,所以如 ... "compile"..."test"這些Phase下的Goal(如 compile、test-compile、test...)會先被執行完成後, 才會輪到 "package"這個Goal,一旦之前某個goals執行失敗就會停止,必須等到所有的goals都沒有問題才可完成打包作業。 以下列舉一些常用的指令(goals)
<project ...>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project> 因為我不用JUnit,所以我會設定TestNG <project ...>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.16</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>${basedir}/src/test/resources/testng.xml</suiteXmlFile>
</suiteXmlFiles>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project> 像GWT用於Client Side Code的Liberary,明確要求要把源碼包入jar檔內,所以要把Source Code與gwt.xml一起包到jar檔內 <project ...>
<build>
<resources>
<resource>
<directory>${basedir}/src/main/java</directory><!--資源檔存放路徑-->
<filtering>false</filtering><!--不置換資源檔內容,如果要的話見http://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html-->
<includes>
<include>org/gwtwidgets/Stream.gwt.xml</include>
</includes>
</resource>
<resource>
<directory>${basedir}/src/main/java</directory>
<includes>
<include> **/client/*.java </include>
</includes>
</resource>
</resources>
</build>
</project> <project ...>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>完整類別名稱(有main方法的class)</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project> ##建立單一可執行Jar(把所有Library一起打成一包) <project ...>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifest>
<mainClass>完整類別名稱(有main方法的class)</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
</project> <project ...>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<configuration>
<executable>java</executable>
<arguments>
<argument>-classpath</argument>
<classpath />
<argument>完整類別名稱(有main方法的class)</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
</project> 設定好後便可以以 "mvn exec:exec"執行程式 上述直接執行程式的前題是,必須是在源碼已經編譯完成的情形下,如果源碼未經compile,則會因為沒有可執行的class而發生錯誤。 當然您也可以執行 "mvn compile exec:exec"來解決這個問題,而另外一種方式就是載 exec:exec 關聯到 test 這個 phase, 所以當我們執行 "mvn test" 時,就會先進行 compile然後再執行 "exec:exec"設定如下 <project ...>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution><!--設定Goal的執行方式-->
<phase>test</phase><!--將以下Goals關聯到 test Phase-->
<goals>
<goal>exec</goal> <!--要設定的goal-->
</goals>
</execution>
</executions>
<configuration>
<executable>java</executable>
<arguments>
<argument>-classpath</argument>
<classpath />
<argument>完整類別名稱(有main方法的class)</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
</project> 之前建立單一可執行Jar,並不會把Jar裡面的META-INF一起包進去,可是像Spring的把Schma等相關資料都放在META-INFO內, 所以必須使用其它的plugin一起將這些資料包進去,並設定關聯到"package" phase <project ...>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<excludes><!--用 mvn dependency:analyze 指令檢視並移除一些不需要的函式庫-->
<exclude>org.apache.logging.log4j:log4j-1.2-api:jar:</exclude>
<exclude>org.apache.logging.log4j:log4j-jcl:jar:</exclude>
<exclude>org.apache.logging.log4j:log4j-slf4j-impl:jar:</exclude>
<exclude>org.springframework:spring-context-support:jar:</exclude>
</excludes>
</artifactSet>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>完整類別名稱</mainClass>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.handlers</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project> 當我們開發Web程式的常常會碰的一個問題是,例如Tomcat有一個預設的系統變數${catalina.home}可指到Tomcat所在的目錄(Jboss則是${project.build.directory}), 所以我們可以在log4j.xml或是logback.xml內直接將appender log file輸出到 <project ...>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId><!--因為是測試時發生,所以設定這個Plugin-->
<version>2.16</version>
<configuration>
<systemProperties>
<property>
<name>catalina.home</name><!--要設定系統變數名稱-->
<value>${project.build.directory}</value><!--把這個變數指到輸出目錄-->
</property>
<property>
<name>jboss.server.home.dir</name><!--要設定系統變數名稱-->
<value>${project.build.directory}</value><!--把這個變數指到輸出目錄-->
</property>
</systemProperties>
<suiteXmlFiles>
<suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile><!--因為我是用testNG,所以指定testNG的設定檔-->
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
</project> 系統中常常必須要使用一些設定檔例如 .properties 或是 .xml結尾的檔案,常常我們會把一些設定放進裡面,例如資料庫的connection string, 以便在開發時期使用測試的資料庫而執行時期使用正式的資料庫,或者是某些暫存檔,例如除錯版本時將某些檔案放在本機路徑,而發佈版本時 則指定到主機路徑。 這個需求表示我們須要能夠在設定檔中放入一些變數,而這些變數的值要能夠在外部(如執行時的參數或是設定在pom.xml內)決定其值, 一個最簡單而通用的設定如下,預設會把.properties與.xml檔案內的變數替換為真正的值): <project ...>
<build>
<resources>
<resource>
<directory>${basedir}/src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<testResources>
<testResource>
<directory>${basedir}/src/test/resources</directory>
<filtering>true</filtering>
</testResource>
</testResources>
</build>
</project> 其中 directory 裝是資源檔的目錄所在,filtering設為true表示裡面的檔案要替換,例如,我常用的Log4j2.xml裡的設定 {% raw %} 全部评论
专题导读
热门推荐
热门话题
阅读排行榜
|
请发表评论