Skip to content

Feign client 이용하여 tour API 호출 #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,17 @@ repositories {
mavenCentral()
}

ext {
set('springCloudVersion', "2022.0.4")
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-batch'
implementation 'org.springframework.cloud:spring-cloud-starter'
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
implementation 'org.json:json:20230227'
runtimeOnly 'org.mariadb.jdbc:mariadb-java-client:3.1.2'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
annotationProcessor 'org.projectlombok:lombok'
Expand All @@ -33,7 +40,7 @@ dependencies {

dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:2022.0.3"
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/main/java/com/catcher/batch/BatchApplication.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package com.catcher.batch;

import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableBatchProcessing
@EnableScheduling
@EnableFeignClients(basePackages = "com.catcher.batch.external")
public class BatchApplication {

public static void main(String[] args) {
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/com/catcher/batch/annotation/CatcherJson.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.catcher.batch.annotation;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface CatcherJson {
String path();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.catcher.batch.core.converter;

import com.catcher.batch.annotation.CatcherJson;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.json.JSONObject;
import org.springframework.stereotype.Component;

@Component
public class CatcherConverter {
private final ObjectMapper objectMapper = new ObjectMapper();

public <T> T parse(String jsonMessage, Class<T> responseType) {
String path = getPath(responseType);
JSONObject jsonObject = getJsonObject(jsonMessage, path);

try {
return objectMapper.readValue(jsonObject.toString(), responseType);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}

private <T> String getPath(Class<T> responseType) {

CatcherJson annotation = responseType.getAnnotation(CatcherJson.class);
if(annotation == null) {
throw new IllegalStateException();
}
return annotation.path();
}

private JSONObject getJsonObject(String json, String jsonPath) {
if(jsonPath == null) {
throw new IllegalStateException();
}

JSONObject jsonObject = new JSONObject(json);
String[] subPath = jsonPath.split("\\.");

for (String path : subPath) {
jsonObject = jsonObject.getJSONObject(path);
}
return jsonObject;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.catcher.batch.external;

import com.catcher.batch.external.config.CatcherFeignClientCommonConfig;
import com.catcher.batch.external.vo.request.TourApiRequest;
import com.catcher.batch.external.vo.response.TourApiResponse;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.web.bind.annotation.GetMapping;

@FeignClient(name = "TOUR-API-SERVICE", url = "http://apis.data.go.kr/B551011/KorService1", configuration = CatcherFeignClientCommonConfig.class)
public interface TourApiServiceExternalCallService {

@GetMapping("/searchFestival1")
TourApiResponse callTourList(@SpringQueryMap TourApiRequest request);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.catcher.batch.external.config;

import com.catcher.batch.core.converter.CatcherConverter;
import feign.RequestInterceptor;
import feign.ResponseInterceptor;
import feign.Util;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;

public class CatcherFeignClientCommonConfig {

public static final String APPLICATION_FORM_URLENCODED_UTF8_VALUE =
MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=utf-8";

@Bean
public RequestInterceptor requestInterceptor() {

return requestTemplate -> requestTemplate.header(HttpHeaders.CONTENT_TYPE, APPLICATION_FORM_URLENCODED_UTF8_VALUE);
}

@Bean
public ResponseInterceptor responseInterceptor(CatcherConverter catcherConverter) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

홍근님께서 올려주신 PR 참고하여 response converter를 적용해보았습니다

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feign Inteceptor를 통한 공통처리 좋네요!!


return invocationContext -> {
Class<?> responseType = (Class<?>) invocationContext.returnType();
String responseBody = Util.toString(invocationContext.response().body().asReader());
return catcherConverter.parse(responseBody, responseType);
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.catcher.batch.external.vo.request;

import lombok.Getter;

/* TODO: 하드코딩된 값 바꾸기 */

@Getter
public class TourApiRequest {

private Integer numOfRows = 100;

private Integer pageNo = 1;

private String MobileOS = "ETC";

private String MobileApp = "AppTest";

private String _type = "json";

private String listYN = "Y";

private String arrange = "A";

private String eventStartDate = "20230901";

private String serviceKey = "your_service_key";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.catcher.batch.external.vo.response;

import com.catcher.batch.annotation.CatcherJson;
import lombok.Getter;

import java.util.List;

@Getter
@CatcherJson(path = "response.body.items")
public class TourApiResponse {

private List<TourApiItem> item;

// private InnerTourAPiResponse response;
//
// @Getter
// public static class InnerTourAPiResponse {
//
// private TourApiHeader header;
//
// private TourApiBody body;
// }
//
// @Getter
// public static class TourApiHeader {
// private String resultCode;
// private String resultMsg;
// }
//
// @Getter
// public static class TourApiBody {
//
// private TourApiItems items;
// private Integer numOfRows;
// private Integer pageNo;
// private Integer totalCount;
// }
//
// @Getter
// public static class TourApiItems {
// private List<TourApiItem> item;
// }

/* TODO: JsonProperty 어노테이션 이용하여 적당한 변수명으로 바꾸기 */
@Getter
public static class TourApiItem {
private String addr1;
private String addr2;
private String booktour;
private String cat1;
private String cat2;
private String cat3;
private String contentid;
private String contenttypeid;
private String createdtime;
private String eventstartdate;
private String eventenddate;
private String firstimage;
private String firstimage2;
private String cpyrhtDivCd;
private String mapx;
private String mapy;
private String mlevel;
private String modifiedtime;
private String areacode;
private String sigungucode;
private String tel;
private String title;
}
}
10 changes: 10 additions & 0 deletions src/main/java/com/catcher/batch/job/config/CommonJobConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.catcher.batch.job.config;

import lombok.RequiredArgsConstructor;
import org.springframework.batch.core.launch.JobLauncher;

@RequiredArgsConstructor
public class CommonJobConfig {

protected final JobLauncher jobLauncher;
}
22 changes: 22 additions & 0 deletions src/main/java/com/catcher/batch/job/config/TourApiJob.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.catcher.batch.job.config;

import com.catcher.batch.external.TourApiServiceExternalCallService;
import com.catcher.batch.external.vo.request.TourApiRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class TourApiJob {

private final TourApiServiceExternalCallService tourApiServiceExternalCallService;

/* TODO: Spring batch 이용하도록 변경? */
@Scheduled(fixedDelay = 1000000) //TODO: 시간대 정해서 하루에 1번으로 변경
public void tourApiJob() {

final var response = tourApiServiceExternalCallService.callTourList(new TourApiRequest());
}

}
27 changes: 27 additions & 0 deletions src/main/resources/application-dev.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver

## spring datasource
spring.datasource.url=${DATASOURCE_URL}
spring.datasource.username=${DATASOURCE_USERNAME}
spring.datasource.password=${DATASOURCE_PASSWORD}


## ssh
ssh.host=${SSH_HOST}
ssh.port=${SSH_PORT}
ssh.username=${SSH_USERNAME}
ssh.password=${SSH_PASSWORD}
ssh.local-port=${SSH_LOCAL_PORT}
ssh.datasource.origin=${SSH_DATASOURCE_ORIGIN}

#update the schema with the given values.
spring.jpa.hibernate.ddl-auto=update
#To beautify or pretty print the SQL
spring.jpa.properties.hibernate.format_sql=true
#show sql
spring.jpa.properties.hibernate.show-sql=true
#show parameter binding
logging.level.org.hibernate.type.descriptor.sql=DEBUG

logging.level.org.hibernate.SQL=DEBUG
spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MariaDBDialect
27 changes: 27 additions & 0 deletions src/main/resources/application-local.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver

## spring datasource
spring.datasource.url=${DATASOURCE_URL}
spring.datasource.username=${DATASOURCE_USERNAME}
spring.datasource.password=${DATASOURCE_PASSWORD}


## ssh
ssh.host=${SSH_HOST}
ssh.port=${SSH_PORT}
ssh.username=${SSH_USERNAME}
ssh.password=${SSH_PASSWORD}
ssh.local-port=${SSH_LOCAL_PORT}
ssh.datasource.origin=${SSH_DATASOURCE_ORIGIN}

#update the schema with the given values.
spring.jpa.hibernate.ddl-auto=update
#To beautify or pretty print the SQL
spring.jpa.properties.hibernate.format_sql=true
#show sql
spring.jpa.properties.hibernate.show-sql=true
#show parameter binding
logging.level.org.hibernate.type.descriptor.sql=DEBUG

logging.level.org.hibernate.SQL=DEBUG
spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MariaDBDialect
27 changes: 27 additions & 0 deletions src/main/resources/application-prod.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver

## spring datasource
spring.datasource.url=${DATASOURCE_URL}
spring.datasource.username=${DATASOURCE_USERNAME}
spring.datasource.password=${DATASOURCE_PASSWORD}


## ssh
ssh.host=${SSH_HOST}
ssh.port=${SSH_PORT}
ssh.username=${SSH_USERNAME}
ssh.password=${SSH_PASSWORD}
ssh.local-port=${SSH_LOCAL_PORT}
ssh.datasource.origin=${SSH_DATASOURCE_ORIGIN}

#update the schema with the given values.
spring.jpa.hibernate.ddl-auto=update
#To beautify or pretty print the SQL
spring.jpa.properties.hibernate.format_sql=true
#show sql
spring.jpa.properties.hibernate.show-sql=true
#show parameter binding
logging.level.org.hibernate.type.descriptor.sql=DEBUG

logging.level.org.hibernate.SQL=DEBUG
spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MariaDBDialect
Loading