Frontend/HTTP 통신

SOAP과 WSDL: REST와 비교 및 Java 예제

dddzr 2025. 7. 26. 17:20

📌 1. SOAP 개념과 REST와의 비교

REST와 SOAP는 각기 다른 두 가지의 온라인 데이터 전송 방식. 

SOAP는 프로토콜, REST는 아키텍처 스타일이다.

📌 1-1. SOAP (Simple Object Access Protocol)

✅ 1-1-1. SOAP 기본 개념

  • SOAPXML 기반의 메시징 프로토콜. 즉, 두 시스템이 데이터를 주고받는 방식에 대한 규격을 정해놓은 표준.
  • SOAP 메시지는 XML 포맷으로 요청과 응답을 주고받고, 이를 기반으로 시스템 간의 상호작용을 정의.

✅ 1-1-2. SOAP 특징

  • 프로토콜 기반: SOAP은 네트워크 프로토콜에 종속적이지 않지만, HTTP, SMTP, FTP 등 다양한 프로토콜을 사용할 수 있다.
  • 메시지 포맷: SOAP은 XML 포맷을 사용하여 데이터를 주고받는다. 이 XML 메시지는 고정된 구조를 가지며, 항상 헤더본문을 포함.
  • 보안: SOAP은 WS-Security 같은 보안 프로토콜을 지원하여, 인증, 메시지 암호화 및 무결성을 보장할 수 있다.
  • 상태 유지: SOAP은 상태를 유지하지 않는(stateless) 서비스이지만, 이를 위해 WS-ReliableMessaging 등의 확장 기능을 통해 상태 유지를 구현할 수 있다.
  • 정형화된 규격: WSDL(웹 서비스 설명 언어)을 사용해 서비스 인터페이스를 정의하고, 클라이언트는 WSDL을 기반으로 자동으로 코드가 생성될 수 있다.
  • 복잡성: SOAP은 복잡한 XML 메시지를 주고받기 때문에 상대적으로 설정과 코드가 복잡하고 무겁다.

📌  1-2. REST (Representational State Transfer)

✅ 1-2-1. REST 기본 개념

  • REST자원(Resource)을 URI로 식별하고, 이를 HTTP 메서드(GET, POST, PUT, DELETE 등)를 통해 다루는 아키텍처 스타일.
  • REST는 상태 비저장(stateless) 방식으로, 각 요청은 독립적이며 상태를 저장하지 않음.

✅ 1-2-2. REST 특징

  • HTTP 기반: REST는 HTTP를 기본 프로토콜로 사용하여 요청을 처리하고, URL을 통해 자원을 식별.
  • 메시지 포맷: REST는 XML, JSON(가장 많이 사용), HTML, 텍스트 등 다양한 포맷을 지원한다. 데이터 교환이 간단하고 사람이 읽기 쉬운 형태로 전달.
  • 간단한 통신: REST는 단순한 HTTP 요청/응답 모델을 따르기 때문에 SOAP보다 간단하고 직관적인 인터페이스를 제공.
  • 상태 비저장: 각 요청은 독립적이며, 클라이언트와 서버는 서로의 상태를 기억하지 않음.
  • 자원 지향: REST는 웹 자원(URI)을 기반으로 데이터를 주고받고, GET, POST, PUT, DELETE 등의 HTTP 메서드를 통해 자원에 대해 작업을 수행.
  • 성능: REST는 SOAP보다 가벼운 프로토콜을 사용하여 상대적으로 빠르고 효율적.

 

🔥 1-3. SOAP vs REST 비교

특성 SOAP REST
통신 프로토콜 독립적, HTTP, SMTP 등 여러 프로토콜 사용 HTTP만 사용
메시지 포맷 XML XML, JSON, HTML 등 다양한 포맷
보안 WS-Security 등을 통한 보안 제공 HTTPS를 통한 기본 보안 제공
상태 관리 상태 유지 가능 (특히 WS-ReliableMessaging 등) 상태 비저장 (stateless)
성능 상대적으로 무겁고 복잡하다 상대적으로 가볍고 빠르며, 효율적이다
표준화 WSDL로 서비스와 메서드 정의, 고정된 규격 자원 기반으로 자유롭고, HTTP 메서드로 정의
용도 트랜잭션, 보안이 중요한 서비스에서 사용 웹 서비스와 API에서 주로 사용, 간단한 통신에 적합
확장성 확장성 있음 (기능을 확장할 수 있는 다양한 표준 지원) 상대적으로 확장성이 낮지만, 간단하게 구현 가능

 

 

📌 2. SOAP 통신을 위한 구성 요소 

  • SOAP 서버: 웹 서비스를 제공하는 쪽
  • SOAP 클라이언트: 서버에서 제공하는 기능을 사용하는 쪽 -> 이 예제만 보여줄거다!
  • WSDL: 웹 서비스의 인터페이스를 정의하는 파일 (SOAP 서비스를 설명하는 문서)
  • 서버WSDL 파일을 제공하고, 클라이언트는 이 파일을 이용해 요청을 보내고 응답을 받음.

 

📌 3. SOAP 클라이언트 구현 방식 (Java)

자바에서는 SOAP 기반 웹 서비스를 구현하는 API인 JAX-RPC와 JAX-WS를 사용한다.
*JAX-RPC는 오래된 기술이고, JAX-WS가 그 후속 버전.

 

3-1. JAX-RPC (Java API for XML-Based RPC)

 ❌ 인터페이스 기반, 복잡함.

 ❌ 메시지 처리 방식이 고정적(RPC(Remote Procedure Call) 스타일만 지원)이라 유연성이 떨어짐
❌ RESTful 웹 서비스 지원이 불가능

📖 예제

ServiceFactory factory = ServiceFactory.newInstance();
Service service = factory.createService(wsdlURL, serviceQName);
Call call = service.createCall();
call.setOperationName("sayHello");
String response = (String) call.invoke(new Object[] {"ChatGPT"});

 

✅ 3-2. JAX-WS (Java API for XML Web Services)

 ✔️ 어노테이션 기반, 간편함.  (@WebService, @WebMethod 등)
✔️ 메시지를 XML 문서 스타일로 처리 가능(문서 스타일(Document Style)과 RPC 스타일 모두 지원)

✔️ REST 호환 (JAX-RS와 함께 사용 가능)

📖 예제 (JAX-WS 서버)

@WebService
public class HelloService {
    @WebMethod
    public String sayHello(String name) {
        return "Hello, " + name;
    }
}

 

📖 JAX-WS 클라이언트 (wsimport 사용)

HelloService service = new HelloService();
HelloServicePort port = service.getHelloServicePort();
String response = port.sayHello("ChatGPT");

 

✅ 3-3. 프레임워크

각 API를 기반으로 하는 라이브러리를 이용하여 구현한다!!

  • wsimport: JAX-WS 기반 (최신 SOAP 표준)
  • Axis1, Axis2: JAX-RPC 기반, 2.x는 JAX-WS 일부 지원
  • CXF: JAX-RPC + JAX-WS 지원

 

📌 4. (JAX-WS) wsimport 이용 예제

나는 JAX-WS방식을 지원하는 wsimport 이용하여 구현 코드를 생성했다.

✅ 4-1. WSDL 파일 가져오기

WSDL 파일을 받았다면, 해당 파일이 웹 서비스의 인터페이스 역할을 한다. WSDL 파일은 서비스의 메서드, 데이터 타입, 엔드포인트 등을 정의한다.

✅ 4-2. 프로젝트 생성

SOAP 클라이언트를 구현하려면 Dynamic Web Project를 사용하는 것이 일반적!!

웹 서비스와 관련된 처리가 필요하고, SOAP 메시지를 HTTP를 통해 주고받아야 하기 때문. Dynamic Web Project는 이를 위한 특화된 환경을 제공한다.

*spring 등 다른 프로젝트와 비교 다음에 해보기

 

✅ 4-3. WSDL로부터 클라이언트 코드 생성 (wsimport )

wsimport 툴을 통해 WSDL로부터 자바 클라이언트 코드를 자동으로 생성할 수 있다.

*wsimport 명령어는 java8에서만 가능하다.

*vscode는 java버전 선택해서 터미널 열수있어서 거기서 명령어 수행 후 이클립스로 이후 작업함.

📖 예시 명령어
#원격
wsimport -s src -d bin http://example.com/service?wsdl

#로컬

wsimport -s src -d bin file:///C:/wsdl/myservice.wsdl #프로젝트 내에 wsdl폴더 저장하여 상대경로 써도 된다. (추천!!)

 

-s 옵션: 소스 파일(Java 클래스)생성, 지정한 src 폴더에 생성.

예: C:\wsdl\src\com\example\myservice (패키지 경로에 맞춰서 생성됨)
-d 옵션: 컴파일된 클래스 파일생성, 지정한 bin 폴더에 생성. -> 나는 class사용x

예: C:\wsdl\bin\com\example\myservice

 

👉추가 옵션

파일 이름의 대소문자 규칙, _로 단어 구별, 인코딩 설정

📌 1. 파일 이름의 대소문자 및 _ 구별 설정
wsimport가 생성하는 Java 클래스의 네이밍 규칙을 직접 변경할 수는 없다.
하지만 JAX-WS 바인딩 파일을 사용하면 클래스 이름을 커스터마이징할 수 있다.

방법
1️⃣ 바인딩 파일(XML) 생성 (custom-binding.xml)

<jaxws:bindings
    xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
    jaxws:package="com.example.ws"
    jaxws:enableWrapperStyle="true"
    jaxws:enableAsyncMapping="false">
    
    <jaxws:class name="My_Service"/>
</jaxws:bindings>

2️⃣ wsimport 실행 시 -b 옵션 추가
wsimport -s src -d bin -b custom-binding.xml file:///C:/wsdl/myservice.wsdl

효과
  • MyService→ My_Service형식으로 클래스명을 변경할 수 있어.





📌 2. 파일 인코딩 설정
기본적으로 wsimport플랫폼 기본 인코딩을 사용하지만, -encoding 옵션으로 변경할 수 있어.

예제
wsimport -s src -d bin -encoding UTF-8 file:///C:/wsdl/myservice.wsdl
-encoding UTF-8 → 소스 코드의 문자 인코딩을 UTF-8로 설정




📌 3. 기타 유용한 옵션
패키지명을 직접 지정

wsimport -s src -d bin -p com.lg.hremployee file:///C:/wsdl/myservice.wsdl

-p com.lg.hremployee → 생성된 Java 클래스가 com.lg.hremployee 패키지에 포함됨
경고 무시 (Strict 모드 비활성화)
wsimport -s src -d bin -Xnocompile file:///C:/wsdl/myservice.wsdl
-Xnocompile → Java 코드만 생성하고 컴파일하지 않음

기존 코드 덮어쓰기 방지
wsimport -s src -d bin -keep file:///C:/wsdl/myservice.wsdl
-keep → 기존 생성된 파일을 유지함

📌5. (JAX-RPC) axis, cxf 이용 참고

2025.04월 기준 Apache Axis는 더 이상 공식 지원되지 않는다.
가능하면 Apache CXF나 다른 라이브러리로 전환하는 게 좋다고 한다.

그럼에도 검색해봤을 때 axis를 이용한게 젤 많이 나오고 이클립스에서 선택하도록(선택만 하고 라이브러리 jar을 자동으로 받아주지 못 한다!!) 되어있다.

Axis나 CXF는 구글에 검색해서 수동으로 jar파일을 다운로드 해야함!!

Axis 1.x 다운로드: https://axis.apache.org/axis/java/releases.html

Axis 2.x 다운로드: https://axis.apache.org/axis2/java/core/download.html

이때 java, Dynamic Web Module, Tomcat 버전을 모두 체크하여 맞는 라이브러리를 다운로드 해야한다. -> 나는 버전 맞추다가 때려치고 wsimport를 찾아서 했다.😭

  • Axis2CXF웹 서비스 클라이언트 및 서버를 처리하기 위한 라이브러리.
  • 주로 웹 서비스의 서버 측이나 프레임워크를 활용하려는 경우에 더 유용!

✔️ (JAX-RPC) Axis 준비 파일

Axis 샘플코드를 제공받아서 Axis 기준으로 JAX-RPC방식도 간단히 설명한다.

얘네가 다 있으면 정상동작 할거다.

 

✅ 5-1. 프로젝트 생성

4-1과 동일. 

*axis2, cxf 사용 시 Configuration modfiy에서 체크 (axis1은 선택x)

(이건 나중에 windw > properties > project facets에서 수정가능)

 

✅ 5-2. WSDL로부터 클라이언트 코드 생성 

✅ 5-2-1. 이클립스에서

프로젝트 우클릭 > new > others

 

✅ 5-2-2. Cmd에서

라이브러리를 한 폴더에 모두 넣어두고 해당 경로에서 실행한다.

java -cp axis.jar;commons-discovery-0.5.jar;commons-logging-1.2.jar;jaxrpc.jar;saaj.jar;wsdl4j.jar org.apache.axis.wsdl.WSDL2Java -o ./src -p com.example.client -s -v file:///C:{wsdl파일 경로}/example.wsdl

⭐ 옵션 설명: 옵션은 빼고 실행해도 된다!

  • -s : 생성된 소스코드를 서비스 클래스 구조로 만듦 (stub/proxy 포함)
  • -v : verbose 모드로, 어떤 파일 생성 중인지 콘솔에 출력됨
  • -p com.lg.hrphoto.client : 패키지 지정

 

📌6.  (JAX-WS) 테스트 코드 작성

자동으로 생성된 클라이언트 코드를 사용하여 웹 서비스와 통신할 수 있다. 

예를 들어, ServiceName이라는 웹 서비스가 있다고 하면, 생성된 ServiceName_Service 클래스를 사용해서 웹 서비스에 접근하고 메서드를 호출할 수 있음.

ServiceName_Service service = new ServiceName_Service();

ServiceName port = service.getServiceNamePort();  // 포트 생성

String response = port.someWebServiceMethod();  // 메서드 호출

 

생성된 코드 활용 과정은 아래와 같다.

1. 생성된 파일을 참고하여 api호출하는 main class 생성해서 임피 파라미터로 테스트 해보기 (예제에서는  ServiceRequest)

2. 실제 api를 호출할 프로젝트에 생성된 파일 복사, 테스트 내용 + 실제파라미터 받게 컨트롤러 작성해서 사용

 

✅ 6-1. Main class 생성

나는 이클립스에서 메인클래스 인식이 안 되어서 com/example/client/를 src/java 밑으로 이동했다. 

✅ 6-1-1. 프로젝트 구조

📖 구조확인 명령어: tree /F 


C:.
│  .classpath             # Eclipse 프로젝트 클래스 경로 설정 파일
│  .project               # Eclipse 프로젝트 설정 파일

├─.settings               # Eclipse 관련 설정 폴더

├─bin                     # 컴파일된 .class 파일 저장 폴더
│  └─myservice
│      └─mysvc_request
│          └─mysvc_provider                  

├─build                    # 빌드된 클래스 파일 저장 폴더
│  └─classes               # 빌드된 .class 파일이 저장되는 폴더
│      ├─com               # 클라이언트 실행 관련 클래스 저장 폴더
│      ├─myservice           # 서비스 관련 클래스 저장 폴더

└─src                      # 소스 코드 폴더
    └─main
        ├─java              # Java 소스 코드 폴더
        │  ├─com
        │  │  └─example
        │  │      └─client
        │  │              MainClient.java          # 클라이언트 실행 파일
        │  │
        │  └─myservice # service 서비스와 관련된 코드나 기능 모듈을 포함.
        │      └─mysvc_request # 서비스 요청 관련 폴더
        │          └─mysvc_provider # 서비스 제공자(Provider) 관련 폴더
        │                  Data.java # 데이터 모델 클래스
        │                  ServiceRequest.java  # 직접 작성
        │                  MySvcFL.java # 서비스 로직 클래스
        │                  MySvcFLResponse.java # 응답 클래스
        │                  MySvcProviderPortType.java  # WSDL 인터페이스
        │                  ObjectFactory.java # JAXB Object Factory
        │                  package-info.java  # 패키지 정보
        │                  REQ.java  # 요청 객체 클래스
        │                  RES.java  # 응답 객체 클래스
        │                  MySvcRequestMySvcProvider.java  # 서비스 클래스 or MySvcRequestService.java
        │                  Message.java  # 메시지 처리 클래스
        │
        ├─resources          # 리소스 폴더
        │  └─wsdl
        │          MySvc.wsdl             # WSDL 파일 (하나만 유지)
        │
        └─webapp             # 웹 애플리케이션 폴더
            ├─META-INF
            │      MANIFEST.MF                    # JAR 관련 메타데이터
            │
            └─WEB-INF
                │  web.xml                        # 웹 애플리케이션 설정 파일
                │
                └─lib                            # 필요한 라이브러리 폴더

 

✅ 6-1-2. 테스트 코드 작성

📖 Main class 예제1

package com.example.client;

import java.net.URL;
import javax.xml.ws.WebServiceException;

public class MainClient {
    public static void main(String[] args) {
        try {
            // WSDL 경로 설정
            URL wsdlURL = new URL("http://localhost:8080/myservice?wsdl");

            // 서비스 객체 생성
            MySvcRequestMySvcProvider service = new MySvcRequestMySvcProvider(wsdlURL);

            // 서비스 포트 가져오기
            MySvcProviderPortType port = service.getMySvcRequestProviderPort();

            // 웹 서비스 호출
            String response = port .sayHello("");

            // 결과 출력
            System.out.println("Server Response: " + response);
        } catch (WebServiceException e) {
            System.err.println("SOAP Web Service 호출 실패: " + e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

📖 Main class 예제2

나는 메인 클래스 내용을 아래와 같이 수정.ServiceRequest 파일을 별도로 작성함.

import myservice.mysvc_request.mysvc_provider.ServiceRequest;

public class MainClient {
   public static void main(String[] args) {
       try {
    //service1 test
    ServiceRequest.call();
   
    ///service2 test
    Service2Request.call();


//여러개 테스트 해볼 때 유용함.
       } catch (WebServiceException e) {
           System.err.println("SOAP Web Service 호출 실패: " + e.getMessage());
       } catch (Exception e) {
           e.printStackTrace();
       }
   }
}

 

📖 ServiceRequest 파일 예제

  • 1. 실 프로젝트 반영전 임시파라미터로 테스트 코드 작성한 것.
  • 2. 메인 클래스에서 ServiceRequest.call();로 사용.
package myservice.mysvc_request.mysvc_provider;


public class ServiceRequest {
public static void call() {
       MySvcRequestMySvcProvider service =
               new MySvcRequestMySvcProvider();
       MySvcProviderPortType port = service.getMySvcRequestProviderPort();
      
RES res = new RES();
REQ req = new REQ();
try {


String targetUrl = "https://{soap-server-url}";
String apiKey    = "apikeyexample";
String userId= "user1";
String param1 = "example";


req.setTargetURL(targetUrl);
req.setKEY(apiKey);
req.setUserId(userId);
req.setParam1(param1);


System.out.println("##################### REQ #####################");


res = port.hrEmployeePictureApiSendFL(req);


Data data = res.getData();


System.out.println("##################### Data #####################");


} catch(Exception e) {
e.printStackTrace();


}
MESSAGE message = res.getMESSAGE().getValue();
String mType = message.getMTYPE();
String mText = message.getMTEXT();


System.out.println();
System.out.println("####### MTEXT =>> 전송결과 응답값(MTYPE='00', MTEXT='Success', MTYPE='01', MTEXT=Match data is nothing, Skip, MTYPE='02', MTEXT=에러메세지) #######");
System.out.println("##################### MTYPE : " + mType + " #####################");
System.out.println("##################### MTEXT : " + mText + " #####################");
}
}

 

📌 7. (JAX-RPC) axis를 이용할 경우 참고!!

✅ 7-1. Axis 사용 결과

  • axis이용시에 JAX-RPC 기반의 클래스를 자동으로 생성 (3개)
  • 이 파일들은 Axis에서 웹 서비스 클라이언트를 설정하고 호출하는 데 필요한 다양한 설정을 처리하며, SOAP 요청 및 응답을 다루기 위해 필요한 클래스들

1️⃣ MySvcProviderPortTypeProxy.java

  • 클라이언트의 프록시 역할.
  • 실제로 웹 서비스 메서드를 호출할 때 이 클래스의 메서드를 사용하고, 내부에서 Axis의 Stub 객체와 통신해.
  • 주로 웹 서비스 엔드포인트 주소 설정과 같은 작업을 처리하며, 실제 서비스의 구현체와 연결을 관리해.

2️⃣ MySvcRequestMySvcProviderBinderStub.java

  • Axis의 Stub 클래스로, 실제 웹 서비스와 SOAP 요청을 주고받는 부분을 담당.
  • createCall() 메서드를 통해 SOAP 요청을 준비하고, MySvc_FL 메서드를 통해 웹 서비스 메서드를 호출하는 역할을 해.
  • Stub 클래스는 클라이언트 측에서 서비스 호출과 관련된 모든 SOAP 메시지 처리를 관리하고, 웹 서비스에 대한 정보를 담고 있어.

3️⃣ MySvcRequestMySvcProviderLocator.java

  • 서비스 위치자(Locator)로, 클라이언트가 웹 서비스의 실제 엔드포인트를 찾을 수 있도록 도와주는 역할.
  • 웹 서비스의 주소를 찾고 이를 클라이언트 코드에서 사용할 수 있도록 서비스 객체를 반환해.
  • 주로 서비스의 URL을 동적으로 가져와서 엔드포인트를 설정하거나, 웹 서비스의 WSDL에서 정보를 기반으로 클라이언트가 호출할 수 있게 연결을 해.

✅7-2. 테스트 코드

📖 ServiceRequest.java

package myservice.mySvc_request.MySvcRequestMySvcProvider;
public class ServiceRequest {
public static void call() {
MySvcProviderPortTypeProxy proxy = new MySvcProviderPortTypeProxy();
MySvcRequestMySvcProviderBinderStub stub = (MySvcRequestMySvcProviderBinderStub) proxy.getMySvcProviderPortType();
       
RES res = new RES();
REQ req = new REQ();
try {


String targetUrl = "https://{soap-server-url}";
String apiKey    = "apikeyexample";
String userId= "user1";
String param1 = "example";


req.setTargetURL(targetUrl);
req.setKEY(apiKey);
req.setUserId(userId);
req.setParam1(param1);


System.out.println("##################### REQ #####################");




res = stub.MySvcFL(req);


Data data = res.getData();


System.out.println("##################### Data #####################");


} catch(Exception e) {
e.printStackTrace();
}


String mType = res.getMESSAGE().getMTYPE();
String mText = res.getMESSAGE().getMTEXT();


System.out.println();
System.out.println("####### MTEXT =>> 전송결과 응답값(MTYPE='00', MTEXT='Success', MTYPE='01', MTEXT=Match data is nothing, Skip, MTYPE='02', MTEXT=에러메세지) #######");
System.out.println("##################### MTYPE : " + mType + " #####################");
System.out.println("##################### MTEXT : " + mText + " #####################");
}
}

 

📌 8. 테스트 코드 실행

Main class를 실행한다.

✅ 1. 이클립스에서 실행
1️⃣ MainClient.java에서 우클릭

2️⃣ Run > Run As > Java Application 선택

✅ 2. 명령어로 실행 (CLI)
1️⃣ cd C:\{project 경로}\soapClient에서 

2️⃣ 컴파일 (필요한 경우)

javac -cp .;lib/* src/myservice/mySvc_request/mySvc_provider/MainClient.java

⚠️ lib/* 부분에 필요한 JAR 라이브러리를 포함해야 함.

3️⃣실행

java -cp .;lib/* myservice.mySvc_request.mySvc_provider.MainClient



'Frontend > HTTP 통신' 카테고리의 다른 글

HTTP 상태 코드 정리  (0) 2025.08.09
쿠키(Cookie), 세션(Session), 캐시(Cache)  (0) 2024.06.05
[axios] defaults 설정 방법 및 옵션  (0) 2023.09.14
RESTful API란? (+예시)  (0) 2023.09.12
다양한 형태의 axios  (0) 2023.07.18