jax-ws 웹서비스 서버 구축하기
웹서비스는 서비스에 대한 정의서(WSDL)를 발행하여 클라이언트가 그 서비스를 어떻게 이용하면 되는지 보다 쉽게 알 수 있다.
자바 웹서비스는 자바 스펙 요구서(Java Specification Request) 224번에 기재되어있다. JSR 224에 보면 자바 1.5 이상에서 사용할 수 있다고 한다. 어노테이션도 1.5 이상부터 지원.
It will run on JavaTM 2 Platform, Standard Edition (J2SE) 1.5. |
자바 웹서비스를 제공하는 심플 모듈 예제는 다음과 같은 순서로 구현하겠다.
- 요청 value object 구현.
package test.server.webservice.vo;
/**
* 요청 메세지 value object.
* @author ijyoon
*/
public class ReqInfo {
// 이름.
private String name;
// 주소.
private String address;
// 나이.
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
웹서비스 이용자가 제공자에게 어떤 요청 값을 보낼지 정의한 클래스이다. 이름, 주소, 나이 세 가지 정보를 제공자에게 보내도록 하였다.
- 응답 value object 구현.
package test.server.webservice.vo;
/**
* 응답 메시지 value object.
* @author ijyoon
*/
public class ResInfo {
// 응답 메세지.
private String resultMessage;
public String getResultMessage() {
return resultMessage;
}
public void setResultMessage(String resultMessage) {
this.resultMessage = resultMessage;
}
}
웹서비스는 제공자는 이용자에게 resultMessage란 값만 응답값으로 보내기로 한다.
- 웹서비스 서버 구현.
package test.server.webservice;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
import test.server.webservice.vo.ReqInfo;
import test.server.webservice.vo.ResInfo;
/**
* 개인정보 서비스
* @author ijyoon
*/
@WebService
public class PersonalInfoService {
/**
* 개인정보를 등록한다.
* Attach file 포함.
* @param req
* @return res
*/
@WebMethod
public @WebResult(name="resInfo")ResInfo
register(@WebParam(name="reqInfo")ReqInfo req){
// 요청값 출력.
System.out.println("request message.");
System.out.println(req.getName());
System.out.println(req.getAge());
System.out.println(req.getAddress());
// 응답 메세지 생성.
String resMessage = req.getName() +" : "+ req.getAge() +" : " + req.getAddress();
// 응답 객체 생성
ResInfo res = new ResInfo();
res.setResultMessage(resMessage);
return res;
}
/**
* simple webservice test.
* @param args
*/
public static void main(String[] args){
System.out.println("start web service.");
Endpoint.publish("http://192.168.0.210:8080/personalInfoService", new PersonalInfoService());
}
}
눈여겨 봐야 할 곳이 어노테이션으로 정의된 부분이다.
16line에 @WebService라는 어노테이션이 정의되었다. @WebService 어노테이션 API를 참조하면 6가지 엘리먼트가 존재한다. 지정하지 않을 경우 클래스명을 따라간다. 다음은 @WebService에 대한 6가지 엘리먼트를 설명한 것이다.
@WebService
– name
웹서비스의 이름을 정의하는 엘리먼트이다. WSDL 발행 시 portType 엘리먼트에 정의되는 이름이다.
– targetNamespace
타켓네임스페이스를 정의하는 엘리먼트이다. WSDL 발행 시 definitions 엘리먼트의 targetNamespace 속성과 연관이 있다.
– serviceName
WSDL 발행시 service 엘리먼트에 정의되는 이름이다.
– portName
WSDL 발행시 port 엘리먼트에 정의되는 이름이다.
– wsdlLocation
기존에 발행된 WSDL 파일이나 URL을 참조한다.
– endpointInterface
구현클래스와 인터페이스를 분리할 수 있으며 분리된 인터페이스에 풀 패키지를 값으로 설정한다.
@WebMethod 어노테이션은 target value가 메소드이기 때문에 메서드에만 선언할 수 있다. 앞서 본 예제의 25 line에 해당한다.
@WebMethod
– operationName
WSDL 발행시 operation 엘리먼트에 정의되는 이름이다.
– action
soap:operation엘리먼트의 soapAction 속성 값을 정의한다.
– exclude
웹메소드에 포함하지 않는다. exclude=true 설정을 하면 WSDL발행 시 해당 메서드(오퍼레이션)는 제외된다.
위의 내용을 참조하여 구현했던 클래스의 @WebService, @WebMethod(16,25 line)의 엘리먼트를 수정하여 WSDL을 확인해 보자.
/**
* 개인정보 서비스
* @author ijyoon
*/
@WebService(name="PInfo_by_ijyoon", portName="PInfoPort", serviceName="PInfoService", targetNamespace="http://malchooni.name/PInfo")
public class PersonalInfoService {
/**
* 개인정보를 등록한다.
* Attach file 포함.
* @param req
* @return res
*/
@WebMethod(operationName="PInfoOpr",action="PInfoAction")
public @WebResult(name="resInfo")ResInfo
register(@WebParam(name="reqInfo")ReqInfo req){
// 요청값 출력.
System.out.println("request message.");
}
}
– 수정 전 WSDL
<definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://webservice.server.test/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://webservice.server.test/" name="PersonalInfoServiceService">
<types>
<xsd:schema>
<xsd:import namespace="http://webservice.server.test/" schemaLocation="http://192.168.0.210:8080/personalInfoService?xsd=1" />
</xsd:schema>
</types>
<message name="register">
<part name="parameters" element="tns:register" />
</message>
<message name="registerResponse">
<part name="parameters" element="tns:registerResponse" />
</message>
<portType name="PersonalInfoService">
<operation name="register">
<input wsam:Action="http://webservice.server.test/PersonalInfoService/registerRequest" message="tns:register" />
<output wsam:Action="http://webservice.server.test/PersonalInfoService/registerResponse" message="tns:registerResponse" />
</operation>
</portType>
<binding name="PersonalInfoServicePortBinding" type="tns:PersonalInfoService">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
<operation name="register">
<soap:operation soapAction="" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
</binding>
<service name="PersonalInfoServiceService">
<port name="PersonalInfoServicePort" binding="tns:PersonalInfoServicePortBinding">
<soap:address location="http://192.168.0.210:8080/personalInfoService" />
</port>
</service>
</definitions>
– 수정 후 WSDL
<definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://malchooni.name/PInfo" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://malchooni.name/PInfo" name="PInfoService">
<types>
<xsd:schema>
<xsd:import namespace="http://malchooni.name/PInfo" schemaLocation="http://192.168.0.210:8080/personalInfoService?xsd=1" />
</xsd:schema>
</types>
<message name="PInfoOpr">
<part name="parameters" element="tns:PInfoOpr" />
</message>
<message name="PInfoOprResponse">
<part name="parameters" element="tns:PInfoOprResponse" />
</message>
<portType name="PInfo_by_ijyoon">
<operation name="PInfoOpr">
<input wsam:Action="PInfoAction" message="tns:PInfoOpr" />
<output wsam:Action="http://malchooni.name/PInfo/PInfo_by_ijyoon/PInfoOprResponse" message="tns:PInfoOprResponse" />
</operation>
</portType>
<binding name="PInfoPortBinding" type="tns:PInfo_by_ijyoon">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
<operation name="PInfoOpr">
<soap:operation soapAction="PInfoAction" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
</binding>
<service name="PInfoService">
<port name="PInfoPort" binding="tns:PInfoPortBinding">
<soap:address location="http://192.168.0.210:8080/personalInfoService" />
</port>
</service>
</definitions>
@WebParam과 @WebResult는 요청,응답 xml 스키마 발행 시 엘리먼트의 이름과 연관이 깊다. 두 어노테이션은 따로 언급하지 않겠다.
마지막으로 만든 모듈을 서비스 해 보겠다. was 기반이 아닌 간단하게 서비스 발행하려면 javax.xml.ws.Endpoint 클래스의 publish 메서드를 사용하면 프로바이더를 생성하여 준다.
/**
* simple binding test.
* @param args
*/
public static void main(String[] args){
System.out.println("start web service.");
Endpoint.publish("http://192.168.0.198:8080/personalInfoService", new PersonalInfoService());
}
파라미터로 URL과 해당 웹서비스의 객체를 넘겨주었다. 서비스 주소 끝에 ?wsdl 파라미터를 넘겨주면 서비스의 WSDL을 열람할 수 있다.
http://192.168.0.198:8080/personalInfoService?wsdl |
was기반에 올려야 할 경우 구현된 서블릿클래스가 있는 라이브러리를 참조한다. 대표적으로 apache cxf와 metro, apache axis 여러가지가 있다. 라이브러리 별로 web.xml(servlet class설정)과 그 종속적인 설정 파일이 존재한다.
wsdl2java 간편한 웹서비스 클라이언트 생성
웹서비스 제공자가 발행하는 WSDL만 있으면 손쉽게 웹서비스 클라이언트를 생성할 수 있다. Apache CXF 라이브러리를 다운로드하고 wsdl2java 명령어를 사용하여 손쉽게 자바 코드를 생성할 수 있다. �
malchooni.name