Fork me on GitHub

Programming Design Notes

Maven 使用 Jboss Embedded 去測試 Seam 元件 (Unit Test)

| Comments

Maven 的測試中要測試 Seam 元件是需要一個 Java EE 的環境去運行 Seam,而 Jboss 亦提供了一個 Java EE 的環境去幫助我們去測試 Seam 元件,這個就是 Jboss Embedded。使用 Jboss Embedded 加上 TestNG 這一套 Testing Framework,很簡單就可以做到全自動測試。

首先要在 pom.xml 去加入以下的 dependency:
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>5.14.2</version>
<type>jar</type>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.jboss.seam.embedded</groupId>
<artifactId>jboss-embedded-api</artifactId>
<version>beta3.SP12</version>
<type>jar</type>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.jboss.microcontainer</groupId>
<artifactId>jboss-deployers-client-spi</artifactId>
</exclusion>
<exclusion>
<groupId>org.jboss.microcontainer</groupId>
<artifactId>jboss-deployers-core-spi</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.jboss.seam.embedded</groupId>
<artifactId>jboss-embedded-all</artifactId>
<version>beta3.SP12</version>
<type>jar</type>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.jboss.seam.embedded</groupId>
<artifactId>thirdparty-all</artifactId>
<version>beta3.SP12</version>
<type>jar</type>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.jboss.seam.embedded</groupId>
<artifactId>hibernate-all</artifactId>
<version>beta3.SP12</version>
<type>jar</type>
<scope>test</scope>
</dependency>

<dependency>
<groupId>javax.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>1.2_13</version>
<type>jar</type>
<scope>test</scope>
</dependency>

加入後就到在 Seam 的下載檔案內找出 bootstrap 這個資料夾,然將這個資料夾複製到 Maven Project 的 src/test/resource 下,這個資料夾是起動 Jboss Embedded 的設定檔案。

再到 pom.xml 加入以下的 plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<useManifestOnlyJar>false</useManifestOnlyJar>
<forkMode>once</forkMode>
<argLine>-Dsun.lang.ClassLoader.allowArraySyntax=true</argLine>
<additionalClasspathElements>
<additionalClasspathElement>${basedir}/src/resource/bootstrap</additionalClasspathElement>
</additionalClasspathElements>
<suiteXmlFiles>
<suiteXmlFile>${project.build.testOutputDirectory}/testing.xml</suiteXmlFile>
</suiteXmlFiles>
<classpathDependencyExcludes>
<classpathDependencyExclude>javaee:javaee-api</classpathDependencyExclude>
<classpathDependencyExclude>javax.ejb:ejb-api</classpathDependencyExclude>
</classpathDependencyExcludes>
</configuration>
</plugin>

如果你的 pom.xml 有加入到 javaee-apiejb-api 的 dependency,在測試時不要將這 2 個 JAR 加到 Classpath 中,Jboss Embedded 會不能起動的。

如果要連接 Database,可以在 src/test/resource/META-INF 加入一個 xxx-ds.xml 去設定 Data SourceJboss Embedded 會自動加入此 Data Source

Data Source 的大概是以下的樣子:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE datasources
PUBLIC "-//JBoss//DTD JBOSS JCA Config 1.5//EN"
"http://www.jboss.org/j2ee/dtd/jboss-ds_1_5.dtd">
<datasources>

<local-tx-datasource>
<jndi-name>jdbc/ctlok</jndi-name>
<use-java-context>true</use-java-context>
<connection-url>jdbc:oracle:thin:@pro.ctlok.com:1521:ctlok</connection-url>
<driver-class>oracle.jdbc.OracleDriver</driver-class>
<user-name>ctlok</user-name>
<password>ctlok</password>
</local-tx-datasource>

</datasources>

persistence.xml 使用 java:jdbc/ctlokJNDI 就可以找到 Data Source 了。

設定大致上完成了,可以寫一些 Test Class 去測試一下。

相關書籍: Seam in ActionSeam Framework: Experience the Evolution of Java EE (2nd Edition)Practical JBoss® Seam Projects

將 Seam 的 Hibernate Persistence Provider 轉為 EclipseLink

| Comments

JBoss Seam Framework 預設的 Persistence ProviderHibernate,但 Hibernate 未必能夠滿足不同 Database 的需求,Seam 亦提供了一種方法將 Hibernate 轉為 OpenJPA 或其他 Persistence Provider

如果你需要將 Hibernate 轉為使用 OpenJPA 可參考這篇: http://seamframework.org/Documentation/UsingOpenJPAAsPersistenceProviderInsteadOfHibernate

以下的是將 Hibernate 轉為使用 EclipseLink 的方法。

首先要更改 persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
<persistence-unit name="ctlok" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<non-jta-data-source>jdbc/oracle</non-jta-data-source>
<class>com.ctlok.pro.entity.User</class>
<class>com.ctlok.pro.entity.UserInfo</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="eclipselink.target-server" value="Websphere" />
<property name="eclipselink.target-database" value="Oracle" />
<property name="eclipselink.logging.level" value="INFO" />
<property name="eclipselink.logging.timestamp" value="true" />
<property name="eclipselink.logging.session" value="true" />
<property name="eclipselink.logging.thread" value="false" />
<property name="eclipselink.logging.exceptions" value="true" />
<property name="eclipselink.cache.type.default" value="NONE" />
</properties>
</persistence-unit>
</persistence>

properties 的設定請自行更改。

重要的是:
  • transaction-type 一定要是 RESOURCE_LOCAL
  • provider 改成是 EclipseLinkPersistenceProvider
  • 一定要是 non-jta-data-source
  • 將所有 Entity Class 也加到 persistence.xml

設定好 persistence.xml 後,要設定 components.xml:

components.xml 加入以下的設定:
<transaction:entity-transaction
entity-manager="#{entityManager}" />

<persistence:entity-manager-factory
persistence-unit-name="ctlok" name="entityManagerFactory" startup="false" />

<persistence:managed-persistence-context
name="entityManager" auto-create="true" entity-manager-factory="#{entityManagerFactory}" />

<component class="org.jboss.seam.persistence.PersistenceProvider"
name="org.jboss.seam.persistence.persistenceProvider" scope="stateless" />

請記得要更改 persistence-unit-namepersistence.xml 所設定的名稱。

這樣就可以將 Hibernate 轉為使用 EclipseLink 了。

相關書籍: JBoss(R) Seam: Simplicity and Power Beyond Java(TM) EEBeginning JSF&trade; 2 APIs and JBoss® Seam (Expert's Voice in Java)Beginning JSF&trade; 2 APIs and JBoss® Seam

Eclipse + Maven 2 開發 Java SE 專案 - 3

| Comments

上一篇: Eclipse + Maven 2 開發 Java SE 專案 - 2

上一篇已經體驗過 Maven 強大的程式庫管理,在這一篇會使用到 Maven 另一個功能 - 測試。不可以小看這個測試功能,測試功能能確保你的程式正確,如果你更改了某部份程式碼,可能會影響到整個程式運作,運行一個測試程式可以確保系統其他組件不受影響。Maven 在打包前會自動執行一次測試程式。

使用上一編文章的 Project 再去進行 Maven 練習,打開 pom.xml,然後選擇 Dependenices 標籤,按下 Add 然後輸入 junit 找到一大堆 junit 的程式庫,選擇以下圖片那一個:


按下 OK 後在旁邊的 Dependency DetailsScope 選擇 test,因為在主程式內不需要 JUnit,只需在測試程式內使用。

加入一個測試程式去測試 HelloWorldBean 的 getHelloWorld() 是不是返回 “Hello World” 的 String Object:
package com.ctlok.pro.tutorial.maven.javase.test;

import junit.framework.Assert;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.ctlok.pro.tutorial.maven.javase.bean.HelloWorldBean;

public class SimpleTest {

private ApplicationContext ctx;

@Before
public void initSpring() {
ctx = new ClassPathXmlApplicationContext(new String[] { "beans.xml" });
}

@Test
public void testHelloWorld() {
HelloWorldBean bean = (HelloWorldBean) ctx
.getBean(HelloWorldBean.class);
Assert.assertEquals("Hello World", bean.getHelloWorld());
}

}

因為我們使用的 JUnit4.8 版本,並使用注解的方式,Java 版本一定要 1.5 或以上才支援,所以加入一個 Plugin 去將程序碼編譯成 Java 1.5 的程式。

現在到 pom.xml 的 Plugins ,加入 maven-compiler-plugin,然後設定以下的 XML:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>

完整的 pom.xml:
<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>
<groupId>com.ctlok.pro.tutorial.maven.javase</groupId>
<artifactId>javase</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>Maven Tutorial</name>
<description>Maven Tutorial</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<archive>
<manifest>
<mainClass>com.ctlok.pro.tutorial.maven.javase.Main</mainClass>
<packageName>com.ctlok.pro.tutorial.maven.javase</packageName>
<addClasspath>false</addClasspath>
</manifest>
<manifestEntries>
<mode>development</mode>
<url>${pom.url}</url>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<id>ud</id>
<phase>prepare-package</phase>
<goals>
<goal>unpack-dependencies</goal>
</goals>
</execution>
</executions>
<configuration>
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.0.4.RELEASE</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.0.4.RELEASE</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.0.4.RELEASE</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<type>jar</type>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
</dependencies>
</dependencyManagement>
</project>

現在執行 Run as -> Maven testConsole 會打印出以下內容:
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Tutorial 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.4.1:resources (default-resources) @ javase ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 1 resource
[INFO]
[INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ javase ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:2.4.1:testResources (default-testResources) @ javase ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:2.3.2:testCompile (default-testCompile) @ javase ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-surefire-plugin:2.4.3:test (default-test) @ javase ---
[INFO] Surefire report directory: D:\testing\javase\target\surefire-reports

-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.ctlok.pro.tutorial.maven.javase.test.SimpleTest
Sep 20, 2010 4:22:06 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@18d107f: startup date [Mon Sep 20 04:22:06 GMT 2010]; root of context hierarchy
Sep 20, 2010 4:22:07 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [beans.xml]
Sep 20, 2010 4:22:07 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1a33d48: defining beans [helloWorldBean]; root of factory hierarchy
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.354 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.885s
[INFO] Finished at: Mon Sep 20 04:22:07 GMT 2010
[INFO] Final Memory: 2M/4M
[INFO] ------------------------------------------------------------------------

出現這個訊息代表測試成功,你可以試試更改測試程式碼出現不合預期的結果去看看 Maven 會出現什麼訊息。

例如將 SimpleTest.testHelloWorld() 改為以下內容:
HelloWorldBean bean = (HelloWorldBean) ctx
.getBean(HelloWorldBean.class);
Assert.assertEquals("hello world", bean.getHelloWorld());

執行 “Maven clean” 去清理 target 資料夾內所有東西,然後再執行 “Maven test”Console 會打印出以下內容:
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Tutorial 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.4.1:resources (default-resources) @ javase ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 1 resource
[INFO]
[INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ javase ---
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 2 source files to D:\testing\javase\target\classes
[INFO]
[INFO] --- maven-resources-plugin:2.4.1:testResources (default-testResources) @ javase ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:2.3.2:testCompile (default-testCompile) @ javase ---
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 1 source file to D:\testing\javase\target\test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.4.3:test (default-test) @ javase ---
[INFO] Surefire report directory: D:\testing\javase\target\surefire-reports

-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.ctlok.pro.tutorial.maven.javase.test.SimpleTest
Sep 20, 2010 4:26:33 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@ad3ba4: startup date [Mon Sep 20 04:26:33 GMT 2010]; root of context hierarchy
Sep 20, 2010 4:26:33 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [beans.xml]
Sep 20, 2010 4:26:33 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1b09468: defining beans [helloWorldBean]; root of factory hierarchy
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.323 sec <<< FAILURE!

Results :

Failed tests:
testHelloWorld(com.ctlok.pro.tutorial.maven.javase.test.SimpleTest)

Tests run: 1, Failures: 1, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.812s
[INFO] Finished at: Mon Sep 20 04:26:33 GMT 2010
[INFO] Final Memory: 2M/8M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.4.3:test (default-test) on project javase: There are test failures.

Please refer to D:\testing\javase\target\surefire-reports for the individual test results.
-> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

這就是測試失敗的訊息了,使用 “Maven package” 時,Maven 也會自動去執行一次測試的。現在可以執行 “Maven clean” 去清理 target 資料夾內所有東西,然後再執行 “Maven package” 去打包整個程式。

以上就是簡單的 Maven 應用,你現在應該掌握到 Maven 的基本使用方法,接下來可以試試在沒有 Eclipsem2eclipse 的情況下使用 Maven 去管理 Jave 項目。

Apache Maven 網址: http://maven.apache.org/

相關書籍: Java Power ToolsMaven: The Definitive GuideApache Maven 2 Effective Implementation

Eclipse + Maven 2 開發 Java SE 專案 - 2

| Comments

上一編: Eclipse + Maven 2 開發 Java SE 專案 - 1

在上一篇已經成功使用 Maven 製作出一個 Hello World 程式出來,但仍然未能體驗到 Maven 有什麼好處。在這一編文章,程式需要用到 Spring FrameworkSpring 的依賴程式庫就交由 Maven 去管理,令各位可以體驗到 Maven 強大之處。

使用上一編文章的 Project 再去進行 Maven 練習,打開 pom.xml,然後選擇 Dependenices 標籤,按下 Add 然後輸入 org.spring 找到一大堆 Spring Framework 的程式庫:


總共要加入 3 個程式庫,分別是 spring-context, spring-beansspring-core,如下圖所示:


儲存 pom.xml,然後發現 Console 顯示下載所需的程式庫,等到下載完成後,打開 Maven Dependenices 發現不是 3 個程式庫,而是有 9 個程式庫,分別是 spring-context, spring-aop, aopilliance, spring-asm, spring-beans, sprng-core, commons-logging, spring-expression。原來那 3 個 Spring 程式庫要依賴另外那 6 個程式庫,而這些程式庫已經由 Maven 管理好,我們根本不需要去理會那些依賴程式庫,只要知道自己的程式需要用什麼程式庫就可以了,實在非常方便。

現在製作一個 HelloWorldBean.java:
package com.ctlok.pro.tutorial.maven.javase.bean;

public class HelloWorldBean {

public String getHelloWorld(){
return "Hello World";
}

}

再到 src/main/resources 加入一個 beans.xml 檔案:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

<bean id="helloWorldBean"
class="com.ctlok.pro.tutorial.maven.javase.bean.HelloWorldBean" />

</beans>

現在修改 Main.java 為以下內容:
package com.ctlok.pro.tutorial.maven.javase;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.ctlok.pro.tutorial.maven.javase.bean.HelloWorldBean;

public class Main {

public static void main(String[] args) {

ApplicationContext ctx = new ClassPathXmlApplicationContext(
new String[] { "beans.xml" });
HelloWorldBean bean = (HelloWorldBean) ctx
.getBean(HelloWorldBean.class);
System.out.println(bean.getHelloWorld());

}

}

程式方面已經製作完成,現在需要打包成 Runnable JAR 檔案,但因為這個程式依賴了 9 個程式庫,我們需要將自己的 Class 檔案連同程式庫一起打包到同一個 JAR 內才可以執行到。打包部份可使用 Maven Plugin 去幫助我們連同程式庫一起打包到同一個 JAR 內。

打開 pom.xml 到 並按下 Plugins 標籤,按下 Add 然後輸入 maven-dependency-plugin,加入這個 Plugin,現在 pom.xml 內一共有 2 個 Plugin,一個是 maven-dependency-plugin,另一個是 maven-jar-plugin

現在去設定 maven-dependency-plugin,按下 pom.xml 標籤,將 maven-dependency-plugin 改為以下內容:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<id>ud</id>
<phase>prepare-package</phase>
<goals>
<goal>unpack-dependencies</goal>
</goals>
</execution>
</executions>
<configuration>
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
</configuration>
</plugin>

execution 內的 phase 是設定何時執行這個 Plugin,我設定為準備打包前。
goals 則可以設定這個 Plugin 執行時會使用的方法,可設定多於一種方法。我設定為將程式庫的 JAR 拆解開。

configuration 內的 outputDirectory 是設定將這些程式庫複製到那一個資料夾內。

完整的 pom.xml:
<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>
<groupId>com.ctlok.pro.tutorial.maven.javase</groupId>
<artifactId>javase</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>Maven Tutorial</name>
<description>Maven Tutorial</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<archive>
<manifest>
<mainClass>com.ctlok.pro.tutorial.maven.javase.Main</mainClass>
<packageName>com.ctlok.pro.tutorial.maven.javase</packageName>
<addClasspath>false</addClasspath>
</manifest>
<manifestEntries>
<mode>development</mode>
<url>${pom.url}</url>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<id>ud</id>
<phase>prepare-package</phase>
<goals>
<goal>unpack-dependencies</goal>
</goals>
</execution>
</executions>
<configuration>
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.0.4.RELEASE</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.0.4.RELEASE</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.0.4.RELEASE</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

現在執行 Run as -> Maven package,完成後發現 target 出現一個 javase-1.0.0-SNAPSHOT.jar,使用指令去執行程式:

C:\>java -jar javase-1.0.0-SNAPSHOT.jar

出現以下訊息即代表成功:
Sep 17, 2010 4:50:02 PM org.springframework.context.support.AbstractApplicationC
ontext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationCont
ext@758fc9: startup date [Fri Sep 17 16:50:02 CST 2010]; root of context hierarc
hy
Sep 17, 2010 4:50:02 PM org.springframework.beans.factory.xml.XmlBeanDefinitionR
eader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [beans.xml]
Sep 17, 2010 4:50:04 PM org.springframework.beans.factory.support.DefaultListabl
eBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.
DefaultListableBeanFactory@bfc8e0: defining beans [helloWorldBean]; root of fact
ory hierarchy
Hello World

下一編再說。

相關書籍: Power & Distance II: Advanced Techniques and Drills for the Perfect SwingMaven: A Developer's Notebook (Developer's Notebooks)Maven: The Definitive Guide

Eclipse + Maven 2 開發 Java SE 專案 - 1

| Comments

轉了新工作,所以比較忙碌,今天拿一點時間寫寫文章。新公司需要用到 Maven 這一套專案管理系統,以前我也想去學習一下,但因為要設定 XML 檔案或一些指令,最後又打消了念頭。現在因為新公司要用到 Maven,不學不行,只好硬著頭皮去學,在學習過程中真的覺得 Maven 是一套非常強大的管理系統,有點後悔太遲學。

Maven 是一套專案管理系統,Maven 使用一個 POM.xml (POM = Project Object Model) 去設定整個專案,Maven 不是只能管理單一專案,在一個專案內可能包括了數個不同組件的專案,Maven 也一樣支援。而 Maven 亦能替專案管理好依賴程式庫 (Library),就算是程式庫的依賴程式庫也一樣可以管理好,我認為這個是 Maven 最強大的功能。在還未學懂使用 Maven 之前,使用 Spring Framework 時,可能會不知道原來 Spring 是需要 Common Logging 這一個程式庫的,到運行程式發覺有錯誤,上網找找才知道要加入 Common Logging 這個程式庫。使用了 Maven 便不用再擔心這個問題,你只需要關心你的專案需要那一個程式庫,不用去關心程式庫依賴那一個程式庫,以下我會使用一個簡單例子去幫助各位去學習 Maven

學習 Maven 前請先準備 Eclipse,為什麼要用 Eclipse 呢,因為 Eclipse 有一個 MavenPlugin,這個 Plugin 可以幫助你去設定 Mavenpom.xml 又可以不用使用指令去操作 Maven。我認為學習 Maven 的最大阻力是設定 POM.xml 和指令部份,首先借助 Plugin 去了解 Maven 的基本結構,才慢慢去記一些指令和學習手動設定 POM.xml,會令學習更容易。

Eclipse 下載網址: http://www.eclipse.org/downloads/
m2eclipse (Plugin) 下載網址: http://m2eclipse.sonatype.org/installing-m2eclipse.html

安裝完成後請將 Eclipse 使用的 JRE 轉為 JDK

新增一個 Maven Project,如下圖所示:


選擇 Create a simple project,然後按 Next:


填上下圖的資料,然後按 Finish:


應該會見到 Project 的結構和下圖一樣:


因為是開發 Java SE 的項目,將 Perspective 轉為 Java:


變成以下樣子:


最後將 JRE System Library [J2SE-1.4] 改為你使用中的 Java SDK

Maven 的主要結構是由 2 個資料夾加上一個 pom.xml 所組成,src 這個資料夾是存放所有檔案的地方,項目所有檔案都是在這個資料夾內,而 target 這個資料夾可以不用理,因為是 Maven 存放完成檔案的地方,例如: JAR, WAR, EAR 等等。pom.xml 是存放 Maven 設定的地方,例如專案名稱,版本等等。

src 資料夾內又有 2 個檔案,一個是 main,一個是 testmain 資料夾用來存放項目的檔案,而 test 是存放測試程式的程式,例如 JUnit 的測試檔案。

maintest 資料夾都有 javaresource 這 2 個資料夾,java 資料夾是存放 Java Class 的地方,Resource 是存放程式需要用到的檔案,例如: 文字檔案,XML 檔案等等。

先試試寫一個 Hello World 的程式,在 src/main/java 內新增一個 Class:
package com.ctlok.pro.tutorial.maven.javase;

public class Main {

public static void main(String[] args) {

System.out.println("Hello World");

}

}

因為這個項目包括了 main methodMaven 在預設打包成的 JAR 是不會指定那一個 Classmain method,所以打包好的 JAR 不能直接執行。但我們可以靠一些 Maven Plugin 去變更 Maven 預設行為。

打開 pom.xml,在編輯器下面會有一些標籤,選擇 Plugin 標籤,然後在 Plugins 這個框架下按下 Add 這個按鈕,然後輸入 maven-jar,程式會搜尋到 2 個 plugins,選擇第一個再按下 OK 就可以了。


m2eclipse 這個 Plugin 不支援輸入 Maven Plugin 的設定,一定要手動加入才可以,在編輯器下面選擇 pom.xml 標籤,將 maven-jar-plugin 改為:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<archive>
<manifest>
<mainClass>com.ctlok.pro.tutorial.maven.javase.Main</mainClass>
<packageName>com.ctlok.pro.tutorial.maven.javase</packageName>
</manifest>
<manifestEntries>
<mode>development</mode>
<url>${pom.url}</url>
</manifestEntries>
</archive>
</configuration>
</plugin>

完整的 pom.xml:
<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>
<groupId>com.ctlok.pro.tutorial.maven.javase</groupId>
<artifactId>javase</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>Maven Tutorial</name>
<description>Maven Tutorial</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<archive>
<manifest>
<mainClass>com.ctlok.pro.tutorial.maven.javase.Main</mainClass>
<packageName>com.ctlok.pro.tutorial.maven.javase</packageName>
</manifest>
<manifestEntries>
<mode>development</mode>
<url>${pom.url}</url>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

選取 Project,然後 Run As -> Maven package,將會在 Console 出現以下資訊:
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Tutorial 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.4.1:resources (default-resources) @ javase ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:2.0.2:compile (default-compile) @ javase ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:2.4.1:testResources (default-testResources) @ javase ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:2.0.2:testCompile (default-testCompile) @ javase ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-surefire-plugin:2.4.3:test (default-test) @ javase ---
[INFO] Surefire report directory: D:\testing\javase\target\surefire-reports

-------------------------------------------------------
T E S T S
-------------------------------------------------------
There are no tests to run.

Results :

Tests run: 0, Failures: 0, Errors: 0, Skipped: 0

[INFO]
[INFO] --- maven-jar-plugin:2.3.1:jar (default-jar) @ javase ---
[INFO] Building jar: D:\testing\javase\target\javase-1.0.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.500s
[INFO] Finished at: Thu Sep 16 03:32:33 GMT 2010
[INFO] Final Memory: 2M/4M
[INFO] ------------------------------------------------------------------------

你會發現在 target 資料夾內出現一個 javase-1.0.0-SNAPSHOT.jar,可以試試用指令去執行這個 JAR:
C:\>java -jar javase-1.0.0-SNAPSHOT.jar

出現 Hello World 即代表打包成功。

下一篇: Eclipse + Maven 2 開發 Java SE 專案 - 2

相關書籍: Apache Maven 2 Effective ImplementationMaven: The Definitive GuideMaven: A Developer's Notebook (Developer's Notebooks)