이 외에 여러가지 이유가 있지만 RestTemplate를 사용해봤는데 코드 가독성이 너무 떨어지고 WebClient는 Spring WebFlux 에서 HTTP Client로 사용되는 비동기적으로 작동하는 모듈인데 굳이 비동기가 지원될 필요가 없다고 판단했고 Feign을 사용했다
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:3.1.3'
runtimeOnly 'io.github.openfeign:feign-httpclient:12.1'
implementation 'com.netflix.feign:feign-jackson:8.18.0'
@SpringBootApplication
@EnableFeignClients
public class TripComesTrueServerApplication {
public static void main(String[] args) {
SpringApplication.run(TripComesTrueServerApplication.class, args);
}
}
이렇게 해도 되고 따로 Config 클래스 만들어서 @Configuration @EnableFeignClients 해도된다
[
{
"item": [
{
"idx": 12086,
"title": "[마이 리틀 콘텐츠 5회] "앨범 커버 속에 담아놓은 다채로운 나만의 상상" 그래픽 아티스트 로지킴의 그래픽 디자인 특강",
"link": "https://iq.ifac.or.kr/culture/view.do?key=m2102173814702&category=CUL03&eventSn=12086",
"category": "행사/축제",
"sdate": "20231121",
"edate": "20231121",
"place": "틈 문화창작지대",
"placeSido": "인천광역시",
"placeGugun": "인천광역시 미추홀구",
"management": "문화체육관광부, 인천광역시",
"feeCase": "유료",
"fee": "",
"tel": "인천콘텐츠코리아랩",
"homepage": "https://www.inckl.or.kr/user/program/view.do?prgrm_ifmt_sq=606",
"poster": "https://iq.ifac.or.kr/fileManager/www/cultureEvent/poster/12086/1696908689402.png",
"posterThumb": "https://iq.ifac.or.kr/fileManager/www/cultureEvent/poster/12086/1696908689402.png",
"description": "[마이 리틀 콘텐츠 5회]\r\n"앨범 커버 속에 담아놓은 다채로운 나만의 상상" 그래픽 아티스트 로지킴의 그래픽 디자인 특강\r\n\r\n콘텐츠 제작 과정을 실시간으로 시청하고 채팅으로 소통하며 함께 즐기는 온라인 강연 프로그램 마이 리틀 콘텐츠! \r\n\r\n다채로운 나만의 상상력을 통해 콘텐츠를 만들어 내는 그래픽 아티스트 로지킴님과 함께 그래픽 디자인 작업 노하우를 알아보고, 작업 과정을 함께 살펴봐요!\r\n\r\n▶ 일시: 2023. 11. 21. (화), 19:00 ~ 20:00 (약 1시간 예정)\r\n▶ 장소: [ON-LINE] 인천콘텐츠코리아랩 유튜브 채널 라이브 스트리밍\r\n▶ 신청: 인천콘텐츠코리아랩 홈페이지 ‘프로그램 신청’ 또는 구글 폼을 통한 신청(https://zrr.kr/eVCR)\r\n▶ 문의: 032) 876-6426 / inckl2023@gmail.com (인천콘텐츠코리아랩 운영사무국)\r\n\r\n",
"reserveInfo": "",
"reserveUrl": "",
"pubDate": "2023-11-07 17:08"
},
{
"idx": 12085,
"title": "크리스마스 콘서트 퍼니밴드",
"link": "https://iq.ifac.or.kr/culture/view.do?key=m2102173812856&category=CUL01&eventSn=12085",
"category": "공연",
"sdate": "20231225",
"edate": "20231225",
"place": "엘림아트센터 엘림홀(대공연장)",
"placeSido": "인천광역시",
"placeGugun": "인천광역시 서구",
"management": "엘림아트센터",
"feeCase": "무료",
"fee": "전석 30,000원",
"tel": "032-289-4275",
"homepage": "www.elimartcenter.co.kr/sub/performance/guide_view.asp?b_idx=991",
"poster": "https://iq.ifac.or.kr/fileManager/www/cultureEvent/poster/12085/1696908689394.png",
"posterThumb": "https://iq.ifac.or.kr/fileManager/www/cultureEvent/poster/12085/1696908689394.png",
"description": "2023년 12월25일\r\n월요일 오후 4시 30분",
"reserveInfo": "",
"reserveUrl": "https://tickets.interpark.com/goods/23016081",
"pubDate": "2023-11-07 16:25"
},
{
"idx": 12084,
"title": "이강호 첼로 독주회",
"link": "https://iq.ifac.or.kr/culture/view.do?key=m2102173812856&category=CUL01&eventSn=12084",
"category": "공연",
"sdate": "20231223",
"edate": "20231223",
"place": "엘림아트센터 엘림홀(대공연장)",
"placeSido": "인천광역시",
"placeGugun": "인천광역시 서구",
"management": "엘림아트센터",
"feeCase": "무료",
"fee": "전석 10,000원",
"tel": "032-289-4275",
"homepage": "www.elimartcenter.co.kr/sub/performance/guide_view.asp?b_idx=1030",
"poster": "https://iq.ifac.or.kr/fileManager/www/cultureEvent/poster/12084/1696908689390.png",
"posterThumb": "https://iq.ifac.or.kr/fileManager/www/cultureEvent/poster/12084/1696908689390.png",
"description": "2023년 12월 23일\r\n토요일 오후 4시 30분\r\n",
"reserveInfo": "",
"reserveUrl": "https://tickets.interpark.com/goods/23016366?app_tapbar_state=hide&",
"pubDate": "2023-11-07 16:22"
}
],
"totalCnt": 10400,
"resultCode": "0000",
"errorMsg": "",
"resultMsg": "정상 처리되었습니다."
}
]
공공데이터 api와는 살짝 다른느낌이다 그래도 json depth만 잘 파악하면 쉽다
@Service
@RequiredArgsConstructor
public class FestivalService {
private final FestivalClient festivalClient;
@Value("${iq.api.apikey}")
private String apikey;
public List<FestivalResponse> getFestival(int page, int size) {
List<FestivalResponse> festivalDataList = festivalClient.getFestivalInfo(
apikey,
"culture",
"json",
page,
size);
return festivalDataList;
}
}
@FeignClient(value = "tour-api", url = "${iq.api.url}", configuration = FeignMapperConfig.class)
public interface FestivalClient {
@GetMapping(value = "")
List<FestivalResponse> getFestivalInfo(@RequestParam("apiKey") String apiKey,
@RequestParam("svID") String svID,
@RequestParam("resultType") String resultType,
@RequestParam("cPage") int cPage,
@RequestParam("pSize") int pSize);
}
@Data
public class FestivalList {
private FestivalData item;
private int totalCnt;
private String resultCode;
private String errorMsg;
private String resultMsg;
}
@Data
public class FestivalData {
private Long idx;
private String title;
private String link;
private String category;
private String sdate;
private String edate;
private String place;
private String placeSido;
private String placeGugun;
private String management;
private String feeCase;
private String fee;
private String tel;
private String homepage;
private String poster;
private String posterThumb;
private String description;
private String reserveInfo;
private String reserveUrl;
private String pubDate;
}
이런식으로 하면 된다
그리고
public class FeignMapperConfig {
private ObjectMapper customObjectMapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
@Bean
public Decoder feignDecoder() {
return new ResponseEntityDecoder(new JacksonDecoder(customObjectMapper)); // 디코딩 과정에서 사용할 수 있는 Decoder Bean을 생성
}
@Bean
public Encoder feignEncoder() {
return new JacksonEncoder(customObjectMapper); //인코딩 과정에서 사용할 수 있는 Encoder Bean을 생성
}
}
이코드도 추가해주는데 page를 너무 크게 보내거나 데이터가 더 없으면 오지 않은 데이터들을 못읽는것을 방지하기 위해서 저런 코드를 추가했는데
customObjectMapper: 이 부분은 Jackson ObjectMapper를 구성. ObjectMapper는 JSON 데이터를 Java 객체로 변환하거나 Java 객체를 JSON으로 직렬화하는 데 사용. 여기에서는 다음과 같은 설정을 수행:
이 설정을 통해 Feign 클라이언트는 외부 API와의 통신 시 JSON 데이터를 요청하고 응답을 처리하며, 불일치하는 프로퍼티를 무시하고 빈 문자열을 null로 처리한다
그리고 @Configuration이 없는 이유는 컴포넌트 스캔이 발생할때 빈으로 등록되서 모든 FeignClient에 적용된다 그러면 다른 api를 연동할때 또 뜯어고쳐야되서
@FeignClient(value = "tour-api", url = "${iq.api.url}", configuration = FeignMapperConfig.class)
이렇게 해서 직접 Config를 읽어오게했다