개발 하다보면 외부 API를 서버에서 처리해야 할 일이 꽤 있습니다.
스마트 택배 API를 통해 외부 API 응답 주고받는 방법을 설명드리겠습니다.
스마트 택배 API의 apiKey 발급
https://tracking.sweettracker.co.kr
스마트택배 API 페이지로 가서 회원가입을 진행합니다.
(이용요금은 현재 월 1000건 무료입니다. 사용 전 꼭 확인하시기 바랍니다.)
로그인 후 이런 페이지가 뜰텐데요, 좌측 API KEY 관리 -> 이용권 구매 -> 하단 등급 프리로 선택, 새로운 API KEY 선택 후 생성합니다.
구매(사실 무료라 구매가 아니죠) 후 KEY 목록에서 APIKEY를 복사하여, 프로젝트의 ENV파일에 저장합니다.
WaybillNumber
@Entity
@Getter @NoArgsConstructor
public class WaybillNumber extends BaseTimeEntity {
@Id @GeneratedValue
private Long id;
/*
* 택배사 코드
* 스마트 택배 API 호출 용도
* 04 : CJ 대한통운
* 08 : 롯데택배
* 46 : CU 편의점택배
*/
private String code;
// 운송장 번호
private String waybillNumber;
// 주문 번호
private String orderNumber;
@Builder
public WaybillNumber(String code, String waybillNumber, String orderNumber) {
this.code = code;
this.waybillNumber = waybillNumber;
this.orderNumber = orderNumber;
}
}
저희가 사용할 엔티티입니다. 저희 서버 내부에서 사용할 주문번호와 주문건에 해당하는 운송장 번호, 그리고 택배사 코드를 받습니다.
BaseTimeEntity는 createdDate와 lastModifiedDate를 저장하는 클래스입니다.
WaybillNumberRepository
package repick.repickserver.domain.waybill.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import repick.repickserver.domain.waybill.domain.WaybillNumber;
public interface WaybillNumberRepository extends JpaRepository<WaybillNumber, Long> {
WaybillNumber findByOrderNumber(String orderNumber);
}
JPA를 사용하는 기본적인 레포지토리입니다.
주문번호로 WaybillNumber 엔티티를 찾는 findByOrderNumber를 선언해둡니다.
JPA는 함수 이름으로 알아서 이름에 맞는 기능을 구현해줍니다. (구현체를 직접 작성하지 않아도 됩니다.)
WaybillNumberController
@RestController
@RequestMapping("/waybill-number")
@RequiredArgsConstructor
public class WaybillNumberController {
private final WaybillNumberService waybillNumberService;
@Operation(summary = "운송장 번호 등록", description = "운송장 번호를 등록합니다.")
@PostMapping("/register")
public ResponseEntity<Boolean> postWaybillNumber(@RequestBody WaybillNumberRequest request) {
return ResponseEntity.ok()
.body(waybillNumberService.postWaybillNumber(request));
}
@Operation(summary = "운송장 번호 조회", description = "주문 번호로 운송장 번호를 조회합니다.")
@GetMapping("/get")
public ResponseEntity<WaybillNumberResponse> getWaybillNumber(@RequestParam String orderNumber) {
return ResponseEntity.ok()
.body(waybillNumberService.getWaybillNumber(orderNumber));
}
@Operation(summary = "운송장 번호 조회", description = "주문 번호로 운송장 번호를 조회합니다.")
@GetMapping("/get-status")
public ResponseEntity<String> getWaybillStatus(@RequestParam String orderNumber) throws JsonProcessingException {
return ResponseEntity.ok()
.body(waybillNumberService.getWaybillStatus(orderNumber));
}
}
컨트롤러입니다.
@Operation : Swagger 문서화를 위해 넣은것으로 생략하셔도 됩니다.
관리자가 주문번호에 맞는 운송장 번호를 기입하는 postWaybillNumber,
소비자가 직접 운송장 번호를 확인할 수 있는 getWaybillNumber와,
주문번호로 배송현황을 서버로부터 조회할 수 있는 getWaybillStatus가 있습니다.
WaybillNumberService
@Service
@Transactional
@RequiredArgsConstructor
public class WaybillNumberService {
private final WaybillNumberRepository waybillNumberRepository;
private final SweetTrackerProperties sweetTrackerProperties;
/**
* <h1>운송장 번호 등록</h1>
* @param request (code, waybillNumber, orderNumber)
* @return true
* @author seochanhyeok
*/
public Boolean postWaybillNumber(WaybillNumberRequest request) {
WaybillNumber waybillNumber = WaybillNumber.builder()
.code(request.getCode())
.waybillNumber(request.getWaybillNumber())
.orderNumber(request.getOrderNumber())
.build();
waybillNumberRepository.save(waybillNumber);
return true;
}
/**
* <h1>주문 번호로 운송장 번호 조회</h1>
* @param orderNumber (주문 번호)
* @return waybillNumberResponse (code, waybillNumber, orderNumber)
* @author seochanhyeok
*/
public WaybillNumberResponse getWaybillNumber(String orderNumber) {
WaybillNumber waybillNumber = waybillNumberRepository.findByOrderNumber(orderNumber);
return WaybillNumberResponse.builder()
.code(waybillNumber.getCode())
.waybillNumber(waybillNumber.getWaybillNumber())
.orderNumber(waybillNumber.getOrderNumber())
.build();
}
/**
* <h1>주문 번호로 배송조회</h1>
* @param orderNumber (주문 번호)
* @return 배송조회 결과 (json)
* @see SweetTracker API
* @author seochanhyeok
*/
public String getWaybillStatus(String orderNumber) {
WaybillNumber waybillNumber = waybillNumberRepository.findByOrderNumber(orderNumber);
HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(new HttpHeaders());
RestTemplate rt = new RestTemplate();
ResponseEntity<String> response = rt.exchange(
"http://info.sweettracker.co.kr/api/v1/trackingInfo?t_key=" + sweetTrackerProperties.getApiKey() +
"&t_code=" + waybillNumber.getCode() +
"&t_invoice=" + waybillNumber.getWaybillNumber(),
HttpMethod.GET,
httpEntity,
String.class
);
return response.getBody();
}
}
서비스입니다.
다른 메서드 설명은 생략하고, getWaybillStatus만 설명드리겠습니다.
SweetTrackerProperties는 뭔데요? -> 게시글 최하단에 설명 있습니다.
WaybillNumberService/getWaybillStatus
public String getWaybillStatus(String orderNumber) {
WaybillNumber waybillNumber = waybillNumberRepository.findByOrderNumber(orderNumber);
HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(new HttpHeaders());
RestTemplate rt = new RestTemplate();
ResponseEntity<String> response = rt.exchange(
"http://info.sweettracker.co.kr/api/v1/trackingInfo?t_key=" + sweetTrackerProperties.getApiKey() +
"&t_code=" + waybillNumber.getCode() +
"&t_invoice=" + waybillNumber.getWaybillNumber(),
HttpMethod.GET,
httpEntity,
String.class
);
return response.getBody();
}
WaybillNumber waybillNumber = waybillNumberRepository.findByOrderNumber(orderNumber);
먼저, JPA를 통해 구현체 없이 만든 findByOrderNumber로 waybillNumber 엔티티를 찾아옵니다.
HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(new HttpHeaders());
HttpEntity는 RestTemplate를 통해 타 API로 요청을 보낼 때 담는 매개변수 중 하나입니다.
HttpHeaders 예시
// HttpHeaders 예시
// 스프링 시큐리티 -> oauth 서비스에서, oauth 서버로 요청할 때 이런식으로 헤더가 요구되는 경우가 있다.
// HTTP Header 생성
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Bearer " + accessToken);
headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
저희가 구현할 스마트택배 API 요청에는 요구되는 헤더가 없기 때문에, new HttpHeaders()로 빈 헤더를 보내지만, 필요한 경우 예시처럼 담을 수 있습니다.
headers.add( "{헤더명}", "{헤더에 담을 내용"}); 를 통해 담으시면 됩니다.
RestTemplate rt = new RestTemplate();
ResponseEntity<String> response = rt.exchange(
"http://info.sweettracker.co.kr/api/v1/trackingInfo?t_key=" + sweetTrackerProperties.getApiKey() +
"&t_code=" + waybillNumber.getCode() +
"&t_invoice=" + waybillNumber.getWaybillNumber(),
HttpMethod.GET,
httpEntity,
String.class
);
Spring 5.0 이후 부터는 RestTemplate는 deprecated 되었습니다. (WebClient 사용 지향)
따라서 deprecated 된 경우 WebClient로 해당부분 구현 바랍니다.
다음으로, RestTemplate()를 선언합니다.
RestTemplate은 스프링의 HTTP 통신 템플릿으로, RESTful한 통신을 할 수 있는 Server to Server 템플릿입니다.
rt.exchange() 함수에 4개의 매개변수를 받습니다.
1. url
2. HTTP Method
3. HttpEntity
4. 반환받는 타입
String으로 반환타입을 지정한 이유는, 제 서비스에선 반환값을 그대로 프론트로 넘겨주고 파싱을 하도록 요구할 것이기 때문입니다.
이런식으로 response를 받습니다.
return response.getBody();
.getBody();를 통해 응답 내용을 return해주면 됩니다.
응답예시는 스마트 택배 API 문서에서 확인 가능합니다.
http://info.sweettracker.co.kr/apidoc/
SweetTrackerProperties는 뭔데요?
SweetTrackerProperties
@Component
@ConfigurationProperties("sweet-tracker")
@Data
public class SweetTrackerProperties {
private String apiKey;
}
별 거 아니고 apiKey를 담는 env파일과 연결시키는 클래스입니다.
이렇게 두고 application-properties.yaml 파일에 환경변수를 넣으면 됩니다.
application-properties.yaml 예시
...
sweet-tracker:
api-key: JBwQUiwAQwGimjQaMZpkEW
'Spring Boot' 카테고리의 다른 글
[Spring Boot] 로컬에서 application.yaml 에 .env 환경변수 주입하기 (1) | 2023.10.11 |
---|---|
[스프링부트] 배포환경에서 에러로그 Slack에 보내기 (0) | 2023.07.20 |
[스프링 부트] 효율적 주문 관리 시스템 (0) | 2023.07.14 |
[스프링 부트] '주문번호' 서비스 구현하기 (Jpa사용) (1) | 2023.07.13 |