IBM®
메인 컨텐츠로 가기
    Korea [국가변경]    이용약관
 
 
   
        제품    서비스 & 솔루션    고객지원 & 다운로드    회원 서비스    
메인 컨텐츠로 가기

한국 developerWorks  >  SOA와 웹서비스 | 오픈 소스  >

스프링과 아파치 CXF를 이용해 POJO 웹 서비스를 디자인하고 구현하기, Part 2: RESTful 웹 서비스 만들기

developerWorks
문서 옵션

JavaScript가 필요한 문서 옵션은 디스플레이되지 않습니다.

토론

샘플 코드

영어원문

영어원문


제안 및 의견
피드백

난이도 : 중급

Rajeev Hathi, 선임 소프트웨어 컨설턴트
Naveen Balani, 소프트웨어 아키텍트, IBM

옮긴이: 박찬욱 dwkorea@kr.ibm.com

2008 년 11 월 18 일

오픈 소스 웹 서비스 프레임워크인 아파치 CXF를 사용해 스프링 빈으로 등록되는 RESTful 웹 서비스를 만들어보겠습니다. 이번 글은 REST(Representational State Transfer)를 사용할 때의 특징과 효과를 찾아보고, 쉽게 RESTful 서비스를 개발할 수 있도록 CXF에서 REST API를 사용하는 방법을 설명합니다.

소개

이번 글에서 우리는 주문 애플리케이션을 구축한다. 주문 애플리케이션 기능은 CXF와 스프링을 사용하는 RESTful 웹 서비스를 경험하게 해준다. 이 웹 서비스는 주문 자원에 대한 readadd 연산을 수행한다. 이 글을 읽은 후에는 웹 서비스를 구축하고, 개발하는 데 REST 아키텍처 유형의 개념과 특징을 적용하고, RESTful CXF 기반 REST API를 사용할 수 있을 것이다.

시스템 요구사항

이번 글에 나오는 예제를 실행하려면 컴퓨터에 다음 소프트웨어가 설치되어 있는지 확인해야 한다.

  • 자바(Java™) 5 이상
  • 톰캣(Tomcat) 5 이상
  • 앤트(Ant) 빌드 도구
  • CXF 바이너리 배포판 2.1

위 배포판을 설치하고 나면 다음 환경 변수를 설정하자.

  • JAVA_HOME(자바)
  • CATALINA_HOME(톰캣)
  • ANT_HOME(앤트)
  • CXF_HOME(CXF)

예제를 위해 CXF_HOME=C:\apache-cxf-2.1로 설정하고, PATH 환경 변수에 다음 내용을 추가하자.

  • JAVA_HOME\bin
  • CATALINA_HOME\bin
  • ANT_HOME\bin



위로


REST - 웹 아키텍처

웹 서비스 개발은 다양한 여러 표준이 차례로 연계되는 WSDL(Web Service Description Language)과 SOAP 같은 인프라스트럭처에 해당하는 다양한 컴포넌트 구현을 포함하기 때문에 매우 복잡해질 수 있다. 웹 서비스 솔루션을 제공하는 모든 웹 서버는 견고한 웹 서비스 인프라스트럭처 모델의 생성이라는 관점에서 많은 투자를 해야 한다. 개발자 관점에서 보면 배워야 할 기술이 점차 복잡해진 것이지만, 걱정하지 않아도 된다! REST가 우리를 구하러 왔기 때문이다.

RESTful 웹 서비스는 단순한 XML에 의한 HTTP(XML-over-HTTP) 서비스였다. 보통 웹 서비스와는 다르게 RESTful 서비스는 간단한 XML 형식에 데이터를 캡슐화해, 웹 서버의 웹 페이지 요청처럼 HTTP로 전송한다.

REST는 구현이나 표준보다는 아키텍처가 더 중요하다. REST 아키텍처 유형은 URI(Uniform Resource Indicator, 예를 들어 http://myweb.com/myresource)에 의해 식별되는 표현(representation)인 웹 자원과 관련 있다. 자원은 Order, Customer, Employee 등을 포함하는 어떠한 영속화 엔티티도 될 수 있다. 클라이언트는 URI를 통해 자원을 쿼리하거나 갱신하며, 이를 통해 해당 표현의 상태 변경에 영향을 준다. 간단히 말하자면 클라이언트 프로그램은 다양한 HTTP 메서드를 사용하는 URI를 통해 웹 자원에 접근하고, 갱신하며, 추가와 삭제가 가능하며, 이에 따라 해당 표현의 상태를 변경한다. HTTP 메서드는 GET, POST, PUT, DELETE를 포함한다.

정리해 보면 REST는 웹 서비스 방법으로 사용자가 HTTP 요청 메서드를 사용해 웹 자원의 연산을 호출할 수 있게 해주는 표준 접근 방법을 지정하는 단순한 명세다. REST는 HTTP와 밀접하게 연관을 맺고 있으며, 이를테면 메서드, 헤더, 타입 같은 모든 HTTP 특징을 활용한다.

REST와 CXF

CXF는 손쉽게 웹 서비스를 구축하고, 개발할 수 있는 간단한 API를 제공하는 오픈 소스 웹 서비스 프레임워크다. 이 연재Part 1에서는 스프링 기반 CXF 환경 구성을 사용해서 간단하게 웹 서비스를 개발하는 방법을 살펴봤다. 두 번째 글에서는 마찬가지로 RESTful 서비스를 개발하는 방법을 살펴본다.

CXF는 세 가지 특색을 갖는 RESTful 유형의 웹 서비스 구현체를 제공한다.

  • JAX-RS(JSR-311)
  • HTTP 바인딩
  • XML 웹 서비스를 위한 자바 API인 ProviderDispatch API들



위로


주문 애플리케이션

이제 사용자가 주문을 생성하거나 읽고, 주문을 상세 조회할 수 있게 해주는 주문 애플리케이션을 만들 수 있다. 이런 기능을 호출해 주문 애플리케이션을 관리하는 데 CXF를 사용하는 RESTful 아키텍처 유형을 사용한다. 애플리케이션을 개발하기 전에 쓰임새를 정의해 보자.

  1. 사용자가 주문(유일한 주문 ID 생성)
  2. 사용자가 주문 상세 내용을 쿼리(주문 ID를 기반으로)
  3. 사용자가 모든 주문을 쿼리

각 연산은 일반적으로 웹 서비스가 호출되는 방법처럼 URI를 사용해서 호출한다. 각 연산은 GET, POST, PUT, DELETE 중 하나의 HTTP 요청 메서드와 관련된다. API는 연산을 HTTP/URI 동사 조합으로 매핑하는 데 JRA(Java Rest Annotation)를 사용한다. 표 1은 JRA/동사 조합을 보여준다.


표1. JRA/동사 매핑 표
JRAHTTP 요청 메서드동사
@GetGETget
@PostPOSTadd /create
@PutPUTupdate
@DeleteDELETEdelete

RESTful 서비스 개발

RESTful 웹 서비스 개발은 서비스 종단 인터페이스(Service Endpoint Interface: SEI)와 구현 클래스 생성으로 시작한다. 이어서 스프링 기반 CXF 환경 설정 파일을 사용해 엮으면 된다. 다음 단계에 맞춰 해 보자.

  1. SEI를 만들고, REST 애노테이션을 붙인다.
  2. 구현 클래스를 생성한다.
  3. beans.xml을 만들고, HTTP 바인딩을 사용하는 스프링 빈으로 서비스 클래스를 정의해 JAX-WS 종단(endpoint)으로 발행하자.
  4. web.xml을 생성하자.

자원 표현 인터페이스 역할을 하는 OrderProcess라는 SEI를 만들자. Order 클래스는 자원 클래스가 된다. Listing 1은 OrderProcess SEI를 보여준다.


Listing 1. OrderProcess SEI
@WebService(targetNamespace = "http://demo.order")
public interface OrderProcess {

  // Get all the orders
  @Get
 @HttpResource(location = "/orders")
 @WebResult(name = "Orders")
 public Orders getOrders();

  // Get order data based on the specified order ID
  @Get
 @HttpResource(location = "/orders/{id}")
 public Order getOrder(@WebParam(name = "GetOrder") GetOrder getOrder);

  // Add an order
  @Post
 @HttpResource(location = "/orders")
 public void addOrder(@WebParam(name = "Order") Order order);
}

OrderProcess SEI는 메서드 세 개를 갖는다.

  • getOrder는 지정한 주문 ID를 기반으로 단일 주문 데이터를 반환
  • getOrders는 모든 주문을 반환
  • addOrder는 주문을 추가할 수 있게 해 준다. 이 메서드는 매개변수로 Order 빈을 받는다.

이 메서드들을 REST 애노테이션을 사용해서 정의하고, URI로 식별한다. @GET 애노테이션은 getOrdergetOrders 메서드에서 사용했고, @POST는 addOrder 메서드에서 사용했다. 각 메서드는 @HttpResource 애노테이션으로 정의한 URI에 의해 식별된다. 이제 표 2에서 볼 수 있는 것처럼 URI 매핑을 갖게 됐다.


표 2. 메서드/URI 매핑 표
메서드URI
getOrder/orders/{id}
getOrders/orders
addOrder/orders

이제 Listing 2에서 보는 것처럼 OrderProcessImpl 구현 클래스를 만들 수 있다.


Listing 2. OrderProcessImpl 서비스 구현
@WebService(endpointInterface = "demo.order.OrderProcess")
public class OrderProcessImpl implements OrderProcess {

 Map<String, Order> orders = new HashMap<String, Order>();
  private int i;

  public Orders getOrders() {
   Orders o = new Orders();
   o.setOrder(orders.values());
   return o;
  }

  public Order getOrder(GetOrder order) {
   String orderID = order.getId();
   return orders.get(orderID);

  }

  public void addOrder(Order order) {
   String orderID = "ORD0" + (++i);
   // Added as a POST request
   String customerName = order.getName(); 

   Order newOrder = new Order();
   newOrder.setOrderID(orderID);
   newOrder.setName(customerName);

   orders.put(orderID, newOrder);
   System.out.println("Order added successfully");
 }
}

REST 인터페이스는 준비됐다. 이번에는 구현을 함께 해보자. OrderProcessImpl 클래스는 SEI를 구현하므로, SEI에 있는 메서드를 모두 구현한다. addOrder 메서드는 주문 ID를 키로, Order 인스턴스를 값으로 사용하는 HashMap으로 주문 상세 정보를 넘긴다. Order 빈은 orderId와 고객 이름을 프로퍼티로 갖는다. 고객 이름은 주문 ID가 생성되는 동안 POST 요청 메서드를 사용해 추가된다. getOrder 메서드는 매개변수로 주문 ID를 받아, HashMap에서 해당 주문을 받아 반환한다. getOrders 메서드는 HashMap에서 모든 주문을 반환한다.

다음 단계는 Listing 3에서 볼 수 있는 beans.xml 환경 설정 파일을 만드는 것이다.


Listing 3. beans.xml 환경 설정 파일
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:jaxws="http://cxf.apache.org/jaxws"
 xsi:schemaLocation="
http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.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-http-binding.xml" />
 <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> 

 <jaxws:endpoint 
  id="orderProcess" 
  implementor="demo.order.OrderProcessImpl" 
  address="/"
  bindingUri="http://apache.org/cxf/binding/http" >
    <jaxws:serviceFactory > 
   <bean class="org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean">
 <property name="wrapped" value="false" />
   </bean>
    </jaxws:serviceFactory > 
 </jaxws:endpoint >
	  
</beans>

OrderProcessImpl에 대한 빈 정의는 JAX-WS 종단으로 래핑되며, URI는 http://apache.org/cxf/binding/http로 바인딩된다. 바인딩 URI는 HTTP 바인딩 메서드를 사용해 자원을 묶어주는 서비스를 의미한다. 주소 /는 웹 컨텍스트(web context)와 관련 있다. JaxWsServiceFactoryBean은 래핑된 속성을 지정한다. 즉 빈의 요청/응답 XML 기반 데이터는 연산 이름으로 루트 요소와 래핑되면 안 된다는 것을 의미한다.


Listing 4. web.xml 웹 환경 설정 파일
<web-app>
 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>WEB-INF/beans.xml</param-value>
 </context-param>

 <listener>
  <listener-class>
   org.springframework.web.context.ContextLoaderListener
  </listener-class>
 </listener>

 <servlet>
  <servlet-name>CXFServlet</servlet-name>
  <display-name>CXF Servlet</display-name>
  <servlet-class>
   org.apache.cxf.transport.servlet.CXFServlet
  </servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>

 <servlet-mapping>
  <servlet-name>CXFServlet</servlet-name>
  <url-pattern>/*</url-pattern>
 </servlet-mapping>
</web-app>

마지막으로 CXF 환경 설정 파일을 불러들이는 web.xml을 만든다. 그러기 위해서는 환경 설정 파일을 불러와 주는 스프링 컨텍스트 로더(Spring context loader)를 사용해야 한다. 클라이언트 프로그램에서 오는 모든 요청을 다루는 CXFServlet도 등록해야 한다.

클라이언트 개발하기

POST 요청에 대한 클라이언트 클래스인 Client를 만들자. Listing 5는 새로운 주문을 추가하는 Client 클래스를 보여준다.


Listing 5. POST 요청을 다루는 클라이언트 클래스
public final class Client {

 public static void main(String[] args) throws Exception {
  String xml = null;
  try {
   // Make an HTTP connection to the server
   URL u = new URL("http://localhost:8080/orderapp_rest/orders");
   HttpURLConnection httpCon = (HttpURLConnection) 
   u.openConnection();
   // Set the request method as POST
   httpCon.setRequestMethod("POST"); 
   httpCon.setDoOutput(true);

   OutputStream os = httpCon.getOutputStream();
   // XML encoded in UTF-8 format
   OutputStreamWriter wout = new OutputStreamWriter(os, "UTF-8"); 
   wout.write("<?xml version=\"1.0\"?>\r\n");  
   // Add customer name as XML fragment
   wout.write("<order xmlns=\"http://demo.order\">
   <name>Rajeev</name></order>r\n"); 
   wout.flush();

   // Make implicit connection to the server
   httpCon.getContentLength(); 
   httpCon.disconnect();
   
   os.close();
  } catch (IOException e) { 
   e.printStackTrace();
  }
 }
}

이 클래스는 http://localhost:8080/orderapp_rest/orders에 대한 HTTP 연결을 만들어, POST 요청으로 XML 데이터를 보낸다. XML은 추가되는 주문 상세 정보로 이루어져 있다. 우리는 주문 ID가 자동으로 생성되는 동안에 고객 이름을 추가한다. 일단 URL이 호출되고 나면 주문 ID와 고객 이름은 Map 컬렉션에 추가된다.

GET 요청에서는 단순히 주문 상세 정보를 받기 위해 브라우저가 http://localhost:8080/orderapp_rest/orders/ORD01으로 이동한다. 주문 ID ORD01에 대한 주문 데이터를 포함하는 XML 요소가 보인다. 비슷하게 고객이 주문한 모든 주문을 보려면 브라우저를 http://localhost:8080/orderapp_rest/orders로 이동하면 된다.

그림 1은 브라우저에 http://localhost:8080/orderapp_rest/orders/ORD01이 입력됐을 때 URI 출력 내용을 보여준다.


그림 1. GET 요청에 대한 브라우저 출력
GET 요청에 대한 브라우저 출력



위로


결론

이번 글에서는 GETPOST 사용을 설명했다. 우리는 REST 아키텍처 유형의 특징과 개념, 그리고 어떻게 CXF를 사용해 RESTful 서비스를 만드는지를 배워봤다.

RESTful HTTP는 자원에 접근하고, 조정하는 방법에 대한 유일한 접근 방법과 웹 서비스 개발에 대한 완전히 새로운 영역을 제공한다. 웹 기반 개발이 좀 더 대중화되고, 일반화되면서 계속 나아지고 있는 기술로는 REST밖에 없을 것이다.





위로


다운로드 하십시오

설명이름크기다운로드 방식
주문 애플리케이션orderapp_rest.zip12KBHTTP
다운로드 방식에 대한 정보


참고자료

교육

제품 및 기술 얻기
  • IBM 제품 평가판을 다운로드하고, 애플리케이션 개발 도구와 DB2®, Lotus®, Rational®, Tivoli®, WebSphere®와 같은 미들웨어 제품을 직접 다뤄보자.


토론


필자소개

Rajeev Hathi's photo

Rajeev Hathi는 J2EE 플랫폼의 소프트웨어 컨설턴트로 일해왔다. 그의 관심사는 J2EE 기반 애플리케이션의 아키텍처 수립과 설계다. Rajeev는 자바와 J2EE 기술(웹, EJB, 아키텍처)에서 썬 자격증을 가지고 있다. 그는 Ajax, 웹 서비스, DB2와 XML에 대한 글을 IBM developerWorks에 기고한다. 그 외에도 자바 6 적용과 직접 따라 해보는 웹 서비스에 대한 책을 집필하는 데 참여했다. 지금은 인도 뭄베이에 거주하며, 스포츠를 보고, 록 음악을 듣는 걸 즐긴다.


Naveen Balani's photo

Naveen Balani는 IBM 인도 소프트웨어 랩(ISL)에서 아키텍트로 일하며 ISL의 WebSphere Business Services Fabric에 대한 설계와 개발 활동을 이끌고 있다. 새로운 기술을 연구하길 좋아하며 웹 서비스, ESB, JMS, SOA, 아키텍처, 오픈 소스 프레임워크, 시맨틱 웹, J2ME, 편재형 컴퓨팅(pervasive computing), 스프링, Ajax와 다양한 IBM 제품 등의 주제에 대해 IBM developerWorks에 지속적으로 기고하고 있다. 또한 그는 Beginning Spring Framework 2Getting Started with IBM WebSphere Business Services Fabric V6.1의 공동저자이기도 하다.




기사에 대한 평가


보다 나은 서비스를 제공하기 위함이오니 잠시 짬을 내어 이 양식을 제출하여 주십시오.



 


 


 


이 문서 북마킹 하기

mar.gar.in mar.gar.in naver naver eolin eolin del.icio.us del.icio.us





위로


IBM, the IBM logo, ibm.com, DB2, developerWorks, Lotus, Rational, Tivoli, and WebSphere are trademarks or registered trademarks of International Business Machines Corporation in the United States, other countries, or both. These and other IBM trademarked terms are marked on their first occurrence in this information with the appropriate symbol (® or ™), indicating US registered or common law trademarks owned by IBM at the time this information was published. Such trademarks may also be registered or common law trademarks in other countries. See the current list of IBM trademarks. Adobe, the Adobe logo, PostScript, and the PostScript logo are either registered trademarks or trademarks of Adobe Systems Incorporated in the United States, and/or other countries. Java and all Java-based trademarks are trademarks of Sun Microsystems, Inc. in the United States, other countries, or both. 기타 회사, 제품, 및 서비스명은 다른 상표나 서비스 마크일 수 있습니다.

developerWorks 콘텐트를 다른 사이트에 전재하기:
developerWorks 콘텐트에 대한 저작권은 IBM에 있습니다. IBM의 서면 허가나 원본 저자의 허락이 없이는 전재를 금합니다. 저희 콘텐트를 전재하시려면 IBM developerWorks 담당자 에게 문의하십시오.
    IBM 소개 개인정보 보호정책 문의