[SAP] Odata API JAVA 호출 예제(Example)
SAP OData는 Advanced Business Application Programming(ABAP)을 사용하여 SAP에 있는 데이터를 쿼리 및 업데이트하는 데 사용되는 표준 웹 프로토콜로, HTTP와 같은 웹 기술을 적용 및 빌드하여 다양한 외부 애플리케이션, 플랫폼 및 디바이스의 정보에 대한 액세스를 제공합니다.
SAP OData API를 Java로 호출하는 과정은 일반적인 REST API 호출과 유사하지만, SAP 시스템 특성상 인증(Authentication)과 데이터 변경(POST, PUT, DELETE) 시 요구되는 CSRF 토큰(Cross-Site Request Forgery Token) 처리가 가장 중요합니다.
Java 11부터 기본으로 제공되는 java.net.http.HttpClient를 사용하여, 외부 라이브러리 의존성을 최소화한 A to Z 가이드를 작성해 드립니다.
1단계: 사전 준비 (Prerequisites)
코드를 작성하기 전에 SAP 담당자(BC 또는 ABAP 개발자)로부터 다음 정보를 확인해야 합니다.
- OData Service URL: (예: https://<sap-host>:<port>/sap/opu/odata/sap/<SERVICE_NAME>/)
- Entity Set Name: 조회/생성할 대상 (예: Users, SalesOrders 등)
- Authentication: Basic Auth (ID/Password) 또는 OAuth 2.0
- 응답 포맷: OData는 기본적으로 XML(Atom)을 반환하므로, JSON으로 받으려면 HTTP Header에 Accept: application/json을 반드시 추가해야 합니다.
2단계: 핵심 개념 이해 (GET vs POST)
- 데이터 조회 (GET): 인증 정보(Basic Auth 등)만 헤더에 넣어서 호출하면 됩니다.
- 데이터 생성/수정/삭제 (POST, PUT, DELETE): SAP는 보안을 위해 2-Step 호출을 강제합니다.
- Token Fetch: GET 메서드로 헤더에 X-CSRF-Token: Fetch를 넣어 호출합니다.
- Session & Token Extract: 응답 헤더에서 X-CSRF-Token 값과 Set-Cookie (세션 쿠키) 값을 추출합니다.
- Actual Request: 추출한 토큰과 쿠키를 헤더에 담아 실제 POST 요청을 보냅니다.
3단계: Java 구현 코드 (A to Z)
아래 코드는 조회(GET)와 생성(POST)을 모두 포함하는 완전한 예제( Basic Auth )입니다.
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Base64;
import java.util.List;
import java.util.Map;
public class SapODataClient {
// SAP 연결 정보 (실제 정보로 변경하세요)
private static final String SAP_URL = "https://sap.example.com:443/sap/opu/odata/sap/ZMY_SERVICE_SRV";
private static final String USERNAME = "sap_user";
private static final String PASSWORD = "sap_password";
// HTTP Client 생성 (연결 타임아웃 설정)
private static final HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.build();
public static void main(String[] args) {
try {
System.out.println("=== 1. 데이터 조회 (GET Request) ===");
readData();
System.out.println("\n=== 2. 데이터 생성 (POST Request with CSRF) ===");
createData();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* [GET] OData 데이터 조회
*/
public static void readData() throws Exception {
String targetUrl = SAP_URL + "/MyEntitySet?$top=5"; // 상위 5개만 조회 예시
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(targetUrl))
.header("Authorization", getBasicAuthHeader())
.header("Accept", "application/json") // JSON 형태로 응답 받기
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Status Code: " + response.statusCode());
System.out.println("Response Body: " + response.body());
}
/**
* [POST] OData 데이터 생성 (CSRF 토큰 처리 포함)
*/
public static void createData() throws Exception {
// Step 1: CSRF 토큰 및 쿠키 가져오기
SapSessionInfo sessionInfo = fetchCsrfToken();
System.out.println("Fetched CSRF Token: " + sessionInfo.csrfToken);
// Step 2: 실제 POST 요청 보내기
String targetUrl = SAP_URL + "/MyEntitySet";
// 보낼 JSON 데이터 (보통 Jackson/Gson 라이브러리로 객체를 변환합니다)
String jsonPayload = "{\n" +
" \"Name\": \"Test User\",\n" +
" \"Age\": 30\n" +
"}";
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
.uri(URI.create(targetUrl))
.header("Authorization", getBasicAuthHeader())
.header("Accept", "application/json")
.header("Content-Type", "application/json")
.header("X-CSRF-Token", sessionInfo.csrfToken) // 추출한 토큰 세팅
.POST(HttpRequest.BodyPublishers.ofString(jsonPayload));
// 추출한 쿠키들 세팅 (SAP는 토큰과 발급 당시의 세션을 매칭합니다)
for (String cookie : sessionInfo.cookies) {
requestBuilder.header("Cookie", cookie);
}
HttpRequest request = requestBuilder.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("POST Status Code: " + response.statusCode());
System.out.println("POST Response Body: " + response.body());
}
/**
* CSRF 토큰을 발급받는 헬퍼 메서드
*/
private static SapSessionInfo fetchCsrfToken() throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(SAP_URL)) // 보통 서비스 루트 URL로 토큰을 요청합니다.
.header("Authorization", getBasicAuthHeader())
.header("X-CSRF-Token", "Fetch") // SAP에게 토큰을 요구하는 헤더
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
throw new RuntimeException("Failed to fetch CSRF token. HTTP " + response.statusCode());
}
Map<String, List<String>> headers = response.headers().map();
// 1. 토큰 추출
List<String> tokenHeader = headers.get("x-csrf-token");
String csrfToken = (tokenHeader != null && !tokenHeader.isEmpty()) ? tokenHeader.get(0) : "";
// 2. 쿠키 추출 (세션 유지용)
List<String> cookies = headers.get("set-cookie");
return new SapSessionInfo(csrfToken, cookies);
}
/**
* Basic Auth Header 생성 헬퍼 메서드
*/
private static String getBasicAuthHeader() {
String valueToEncode = USERNAME + ":" + PASSWORD;
return "Basic " + Base64.getEncoder().encodeToString(valueToEncode.getBytes());
}
/**
* CSRF 토큰과 쿠키를 담아두기 위한 내부 클래스
*/
private static class SapSessionInfo {
String csrfToken;
List<String> cookies;
SapSessionInfo(String csrfToken, List<String> cookies) {
this.csrfToken = csrfToken;
this.cookies = (cookies != null) ? cookies : List.of();
}
}
}
[OData] CSRF Token 받기
CSRF Token 받기 POST, PUT, DELETE와 같이 데이터 변경이 필요한 Method를 호출할 경우 CSRF Token 값을 이용하여 API를 호출해야 합니다. 참고로, 아래 방법으로 CSRF 인증을 비활성화 할수 있습니다. 2023.10.31
playabap.tistory.com
참고) Get a Valid CSRF Token https://help.sap.com/docs/SAP_ANALYTICS_CLOUD/14cac91febef464dbb1efce20e3f1613/500b6ce3aea34c5483dcd98c9048e4e3.html?locale=en-US
SAP Help Portal | SAP Online Help
help.sap.com
4단계: 실무 적용 시 주의사항
- JSON 파싱: 위 예제는 String으로 직접 페이로드를 만들고 응답을 받지만, 실무에서는 Jackson (ObjectMapper)이나 Gson 라이브러리를 사용하여 Java DTO 클래스와 JSON 간의 직렬화/역직렬화를 처리하는 것이 유지보수에 좋습니다.
- 토큰 캐싱 (Token Caching): 매번 POST 요청을 할 때마다 fetchCsrfToken()을 호출하면 네트워크 낭비가 발생합니다. 발급받은 쿠키와 CSRF 토큰을 메모리에 캐싱해두고 사용하다가, 403 (Forbidden - CSRF token validation failed) 에러가 발생하면 그때 다시 갱신하는 로직을 구현하는 것이 좋습니다.
- 포맷 헤더 필수: OData URL 끝에 ?$format=json을 붙이거나, 위 예제처럼 HTTP Header에 Accept: application/json을 넣지 않으면 방대한 양의 XML이 반환되므로 주의해야 합니다.
'ERP(SAP)' 카테고리의 다른 글
| 📅 SAP 날짜·주차 계산 함수(Function) 완벽 가이드 (0) | 2026.05.06 |
|---|---|
| SAP BAPI의 모든 것: 개념부터 S/4HANA 실무까지 (0) | 2026.04.23 |
| [MM] SAP 수입 프로세스에서 제비용 원가 반영 이슈와 개선 방안 (0) | 2026.04.22 |
| [SAP] ST04 에러 DYNPRO_FIELD_CONVERSION FX015: Sign lost (1) | 2026.04.10 |
| [SAP] Fiori(피오리)란 무엇인가? - 개념, 학습, 강의 추천 (0) | 2026.04.09 |