JSF 2.0 + CXF でWebサービス呼び出し
前回 の続き。クライアントをWebアプリケーションにしてみる。Webアプリケーションフレームワークは、最近気になるJSF2。環境はこんな感じ。
- JDK 1.6
- Eclipse 3.5 (Pleiades) + m2eclipse 0.9.8 (+ WTP Integration)
- Apache CXF 2.2.5
- Mojarra 2.0.1
- Tomcat 6.0.20
プロジェクトの作成
- Eclispeで普通に「動的Webプロジェクト」を作成(とりあえず ws-webclient というプロジェクト名)。ただしソースフォルダは src/main/java と src/main/resources を作り、出力先は target/classes に変更、Webコンテンツフォルダも src/main/webapp に変更。
- プロジェクトを右クリックして「Maven」→「依存関係管理を使用可能にする」。グループIDは前と同じ example.cxf、アーティファクトIDは ws-webclient。
- プロジェクトを右クリックして「プロパティー」→「Javaのビルド・パス」→「順序およびエクスポート」で、「Maven Dependencies」にチェック(不要?)。
- pom.xml に以下のように依存関係と build 要素を追加。
<version>0.0.1-SNAPSHOT</version> <!-- ここから追加 --> <properties> <cxf.version>2.2.5</cxf.version> </properties> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.0.2</version> <configuration> <encoding>UTF-8</encoding> <source>1.6</source> <target>1.6</target> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>${cxf.version}</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>${cxf.version}</version> </dependency> <dependency> <groupId>example.cxf</groupId> <artifactId>ws-contract</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> <dependency> <groupId>com.sun.faces</groupId> <artifactId>jsf-api</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>com.sun.faces</groupId> <artifactId>jsf-impl</artifactId> <version>2.0.1</version> </dependency> </dependencies> <repositories> <repository> <id>maven2-repository.dev.java.net</id> <name>Java.net Repository for Maven</name> <url>http://download.java.net/maven/2/</url> </repository> </repositories> <!-- ここまで追加 --> </project>
追加したら、プロジェクトを右クリックして「Maven」→「プロジェクト構成の更新」を行う。
Springでのスタブ生成の設定
JSFの管理対象BeanにインジェクションするためのサービススタブをSpringで管理するため、src/main/resources フォルダに applicationContext.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" xmlns:cxf="http://cxf.apache.org/core" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <import resource="classpath:META-INF/cxf/cxf.xml" /> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" /> <import resource="classpath:META-INF/cxf/cxf-extension-http.xml" /> <cxf:bus> <cxf:features> <cxf:logging /> </cxf:features> </cxf:bus> <jaxws:client id="helloWorldService" address="http://localhost:8080/ws-server/HelloWorld" serviceClass="example.cxf.HelloWorldService" /> </beans>
中身は、ほぼ前回の Main クラスの中身をXMLで書いているだけ。ただし、サーバ側と同じく全てのメッセージをログに出力するように cxf:bus の設定を追加している。
web.xml にも Spring の初期化用の設定を追加。
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener>
JSF
src/main/java 以下に example/cxf/managed フォルダを作成し、管理対象bean HelloWorld.java を作成。
package example.cxf.managed; import java.io.Serializable; import javax.faces.bean.ManagedBean; import javax.faces.bean.ManagedProperty; import javax.faces.bean.RequestScoped; import example.cxf.HelloWorldService; @ManagedBean @RequestScoped public class HelloWorld implements Serializable { private static final long serialVersionUID = 1L; @ManagedProperty(value="#{helloWorldService}") private HelloWorldService helloWorldService; private String name; private String result; public String greet(){ result = helloWorldService.sayHi(name); return null; } public void setHelloWorldService(HelloWorldService helloWorldService) { this.helloWorldService = helloWorldService; } public String getResult() { return result; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
上の @ManagedProperty(value="#{helloWorldService}") に指定されたEL変数 helloWorldService を Spring の bean からも探すようにするため、src/main/resources フォルダに META-INF フォルダを作成し、その中に faces-config.xml ファイルを以下のような内容で作成する。
<?xml version="1.0"?> <faces-config version="2.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"> <application> <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver> </application> </faces-config>
テンプレートファイル index.xhtml を src/main/webapp フォルダに作成。"Greet" ボタンを押すと、Ajaxで管理対象Bean HelloWorldのgreetメソッドを呼び出し、結果を p#result 要素の中身にセットする。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets"> <head jsfc="h:head"> <title>HelloWorld</title> <h:outputScript name="jsf.js" library="javax.faces" /> </head> <body> <form jsfc="h:form"> <p> <input jsfc="h:inputText" id="name" value="#{helloWorld.name}" /> <input jsfc="h:commandButton" id="greetButton" action="#{helloWorld.greet}" value="Greet"> <f:ajax execute="name" render="result" /> </input> </p> <p id="result" jsfc="h:outputText" value="#{helloWorld.result}" /> </form> </body> </html>
最後に、web.xml にJSF用の設定を追加し、以下のようにする。
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <context-param> <param-name>javax.faces.PROJECT_STAGE</param-name> <param-value>Development</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>faces/index.xhtml</welcome-file> </welcome-file-list>
完成
ws-webclient プロジェクトを右クリックし、「実行」→「サーバーで実行」でTomcat上で動かす。
しかるのちに http://localhost:8080/ws-webclient/ にアクセスするとテキスト入力とGreetボタンがあるだけの画面が表示される。
テキストに hoge と入力しGreetボタンを押せば、前回と同じく HelloWorld Webサービスが呼び出され、"Hello hoge" が画面に返される。
めでたしめでたし。
TODO
- 単なる文字列でなくオブジェクトのやりとりをする
- サービス側をDBを使うような本格的なものにする
- クライアント側にユーザ認証を追加し、さらに認証情報をサービス側に受け渡す