SOAPとかWSDLとかの方のWeb Serviceをさわる。WildFly使うのは趣味。なんとなく新しいバージョン使った方がいいかな〜とかそういう雰囲気。目標は、サンプルのWeb Serviceをサーバ側で起動して、クライアント側からアクセスできるまで。
環境
準備
EclipseのServerビューからWildFlyを起動できるようにする。
JBoss AS 7.1 + EJB 3.1 + Arquillian動かすところまで - kagamihogeのblogとかを参照してJBoss Toolsいれる。
Serverの設定を↓みたいな感じにして作る。
まだプロジェクト作ってないんでココは空でOK
サンプルWeb Serviceを動かすところまで
Java EE Projectの作成
めんどいのでJBoss Toolsの雛形作成機能を使う。
Help -> JBoss Cenetralを開き、Java EE Web Projectを選択する。
Create a blank projectにチェックを入れる。今回はEJBとかJSFとかゴチャゴチャ入られても邪魔なだけなので。
Target RuntimeはWildFly 8を選択しておく。
この後はテキトーにクリックしていくだけ。プロジェクト名は、jboss8-wsにしておく。
これでプロジェクト作成完了。
サンプルWeb Serviceの作成
ここからWeb Service本体の作成に入っていく。
プロジェクト右クリック -> New -> Other -> Web Services -> Create a Sample Web Serviceを選択する。
次の画面でエラーが出る。プロジェクトはDynamic Web Projectじゃないとダメなのと、web.xmlがしかるべき場所に存在しない、と言っている。
よって、jboss8-ws\src\main\webapp\WEB-INF\web.xmlをつくる。適当なDynamic Web Projectを一個作って、web.xmlだけコピペしてきた。あと、welcome-fileとかは要らないんで消している。
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>jboss8-ws</display-name> </web-app>
作成されたサンプルWeb Serviceのコード
Javaのコード。
package org.jboss.samples.webservices; import javax.jws.WebMethod; import javax.jws.WebService; @WebService() public class HelloWorld { @WebMethod() public String sayHello(String name) { System.out.println("Hello: " + name); return "Hello " + name + "!"; } }
web.xmlも書き換えられる。↑のクラスとメソッドがサーブレットをエンドポイントにするWeb Serviceとして作られたっぽいことが分かります。
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>jboss8-ws</display-name> <servlet> <display-name>HelloWorld</display-name> <servlet-name>HelloWorld</servlet-name> <servlet-class>org.jboss.samples.webservices.HelloWorld</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloWorld</servlet-name> <url-pattern>/HelloWorld</url-pattern> </servlet-mapping> </web-app>
起動
デプロイして起動してみる。サーバーログを見る。さっき作ったWeb Serviceが起動したっぽいようなログが途中らへんに流れてきます。
INFO [org.jboss.ws.cxf.metadata] (MSC service thread 1-4) JBWS024061: Adding service endpoint metadata: id=HelloWorld address=http://localhost:8080/jboss8-ws/HelloWorld implementor=org.jboss.samples.webservices.HelloWorld serviceName={http://webservices.samples.jboss.org/}HelloWorldService portName={http://webservices.samples.jboss.org/}HelloWorldPort annotationWsdlLocation=null wsdlLocationOverride=null mtomEnabled=false
クライアントからは恐らく上記ログ中にもある http://localhost:8080/jboss8-ws/HelloWorld にアクセスするのだろうな、ということがわかる。とりあえずブラウザからアクセス。まぁエラーが返ってくるけど、なんかが動いていることは分かる。
<soap:Envelope><soap:Body><soap:Fault><faultcode>soap:Server</faultcode><faultstring>Fault occurred while processing.</faultstring></soap:Fault></soap:Body></soap:Envelope>
http://localhost:8080/jboss8-ws/HelloWorld?WSDL にブラウザからアクセス。何かが見える。
xmlはこんな感じ。こんな長ったらしいXML作った覚えは無いので、javaeeコンテナ側が勝手にWSDL作ってくれることが伺えます。
<wsdl:definitions name="HelloWorldService" targetNamespace="http://webservices.samples.jboss.org/"> <wsdl:types> <xs:schema elementFormDefault="unqualified" targetNamespace="http://webservices.samples.jboss.org/" version="1.0"> <xs:element name="sayHello" type="tns:sayHello" /> <xs:element name="sayHelloResponse" type="tns:sayHelloResponse" /> <xs:complexType name="sayHello"> <xs:sequence> <xs:element minOccurs="0" name="arg0" type="xs:string" /> </xs:sequence> </xs:complexType> <xs:complexType name="sayHelloResponse"> <xs:sequence> <xs:element minOccurs="0" name="return" type="xs:string" /> </xs:sequence> </xs:complexType> </xs:schema> </wsdl:types> <wsdl:message name="sayHelloResponse"> <wsdl:part element="tns:sayHelloResponse" name="parameters"> </wsdl:part> </wsdl:message> <wsdl:message name="sayHello"> <wsdl:part element="tns:sayHello" name="parameters"> </wsdl:part> </wsdl:message> <wsdl:portType name="HelloWorld"> <wsdl:operation name="sayHello"> <wsdl:input message="tns:sayHello" name="sayHello"> </wsdl:input> <wsdl:output message="tns:sayHelloResponse" name="sayHelloResponse"> </wsdl:output> </wsdl:operation> </wsdl:portType> <wsdl:binding name="HelloWorldServiceSoapBinding" type="tns:HelloWorld"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="sayHello"> <soap:operation soapAction="" style="document" /> <wsdl:input name="sayHello"> <soap:body use="literal" /> </wsdl:input> <wsdl:output name="sayHelloResponse"> <soap:body use="literal" /> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="HelloWorldService"> <wsdl:port binding="tns:HelloWorldServiceSoapBinding" name="HelloWorldPort"> <soap:address location="http://localhost:8080/jboss8-ws/HelloWorld" /> </wsdl:port> </wsdl:service> </wsdl:definitions>
サンプルWeb Serviceにアクセスするクライアント
サンプルWeb Serviceが動いたっぽいことは分かった。ので、それにアクセスするクライアントを作る。
まず、フツーのjavaプロジェクトを作る。
つぎに、Web ServiceのクライアントにアクセスするためのクラスをWSDLから自動生成する。
プロジェクト右クリック -> New -> Other -> Web Services -> Web Service Client
Service Destinationに http://localhost:8080/jboss8-ws/HelloWorld?WSDL を入力する。
Define custom mapping for namespace to packageにチェック入れれば適当なpackage作ってくれる(と思う)
Finishすると、なんだかしらんが色々なクラスが自動生成される。きっとこの辺のクラスをテキトーに呼び出せば、アレコレ面倒なXML作った解釈したりしなくてもよいのだろう、と感じる。
てなわけで、自動生成されたクラス使ってWeb Serviceにアクセスするコードを書く。なお、これで動いたってだけで、こーいう書き方が正しいのかどうかは調べてないんで分からない。
package wsclient.sample; import java.rmi.RemoteException; import org.jboss.samples.webservices.HelloWorld; import org.jboss.samples.webservices.HelloWorldProxy; public class Main { public static void main(String[] args) throws RemoteException { HelloWorld helloWorldWS = new HelloWorldProxy().getHelloWorld(); System.out.println(helloWorldWS.sayHello("kagamihoge")); } }
ログの確認
ホントーにサーバまでアクセスしにいってるかどうかとかを確認する。上記で作ったコードを実行してみる。
まず、サーバ側。届いてるっぽい。
INFO [stdout] (default task-10) Hello: kagamihoge
クライアント側。なんかwarningが出てますがソレを気にしないで末尾を見ると、Web Serviceの呼び出し結果が表示されていることが分かります。
org.apache.axis.utils.JavaUtils isAttachmentSupported WARNING: 要求されたクラス(javax.activation.DataHandler と javax.mail.internet.MimeMultipart)が見つかりません。Attachmentサポートが利用できません。 / [en]-(Unable to find required classes (javax.activation.DataHandler and javax.mail.internet.MimeMultipart). Attachment support is disabled.) Hello kagamihoge!
自前のWeb Serviceを動かすところまで
今度は自作のWeb Serviceを作ってみる。といっても、手順はほとんどサンプル動かすのと変わらないのだけど。
Web Serviceの作成
さっき作ったプロジェクトに下記のようなクラスを作る。
package org.jboss.samples.webservices; import javax.jws.WebMethod; import javax.jws.WebService; @WebService() public class CalcSum { @WebMethod() public int sum(CalcSumInput input) { int sum = 0; for (int i:input.getInputs()) { sum += i; } System.out.println(input.getName() + ":" + sum); return sum; } }
サンプルと違うのは、メソッドの引数に独自のクラスを取るところ。そのクラスは単純にデータ突っ込むためのものなので、実質的にgetter/setterだけ。あと、XmlRootElementアノテーションをつけておく。これをつけとくとXMLとJavaのクラスとのバインドを勝手にやってくれる。
import java.util.List; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class CalcSumInput { private String name; private List<Integer> inputs; public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Integer> getInputs() { return inputs; } public void setInputs(List<Integer> inputs) { this.inputs = inputs; } }
Web Serviceにアクセスするクライアント
ココの流れはサンプルのときと変わらない。まずWeb Serviceにアクセスするクラスを自動生成するために、プロジェクト右クリック -> New -> Other -> Web Services -> Web Service Clientをして、Destinationには http://localhost:8080/jboss8-ws/CalcSum?WSDL と入力する。と、自動生成される。
んで、テキトーにクライアントのコードを書く。
package wsclient.sample; import java.rmi.RemoteException; import org.jboss.samples.webservices.CalcSum; import org.jboss.samples.webservices.CalcSumInput; import org.jboss.samples.webservices.CalcSumProxy; public class Main { public static void main(String[] args) throws RemoteException { Integer[] nums = {1,2,3,4,5,6,7,8,9,10,}; CalcSum calcSum = new CalcSumProxy().getCalcSum(); CalcSumInput input = new CalcSumInput(nums, "kagamihoge"); System.out.println(calcSum.sum(input));; } }
55と返ってきたんでおっけー。
EJB Webサービスとして動かす
Statelessアノテーション付けるだけだけど。
package org.jboss.samples.webservices; import javax.ejb.Stateless; import javax.jws.WebMethod; import javax.jws.WebService; @Stateless @WebService() public class CalcSum { @WebMethod() public int sum(CalcSumInput input) { int sum = 0; for (int i:input.getInputs()) { sum += i; } System.out.println(input.getName() + ":" + sum); return sum; } }