SpringBoot Retrofit 연동하기

By | 2021년 12월 18일
Table of Contents

SpringBoot Retrofit 연동하기

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

의존성 추가

retrofit2 버전은 2.7.X 로 합니다.
상위 버전을 이용하려면, JDK 를 8로 내리거나, 14로 올려야 합니다.

dependencies {
    implementation 'com.squareup.retrofit2:retrofit:2.7.2'
    implementation 'com.squareup.retrofit2:converter-jackson:2.7.2'
    implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
    implementation 'com.squareup.okhttp3:logging-interceptor'
}

소스코드 추가

public class ApiClient {

    private static final String BASE_URL = "https://dapi.kakao.com/";
    private static Retrofit retrofit;

    public static Retrofit getApiClient() {

//        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
//        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
//        OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();

        ObjectMapper mapper = Jackson2ObjectMapperBuilder.json()
                .featuresToDisable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
                .modules(new JavaTimeModule())
                .build();

        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    // .client(client)
                    .addConverterFactory(JacksonConverterFactory.create(mapper))
                    .build();
        }

        return  retrofit;
    }
}
public interface ApiInterface {

    // 장소이름으로 검색
    @GET("v2/local/search/keyword.json")
    Call<CategoryResult> getSearchLocation(
            @Header("Authorization") String token,
            @Query("query") String query,
            @Query("category_group_code") String categoryGroupCode,
            @Query("size") int size,            // 1 ~ 15
            @Query("page") int page,            // 1 ~ 45
            @Query("sort") String sort,         // distance 또는 accuracy (기본값: accuracy)
            @Query("x") String x,
            @Query("y") String y
    );
}
@Getter
public class CategoryResult {

    // private Meta meta;
    private List<Document> documents = null;
}
@Getter
@Setter
@NoArgsConstructor
public class Document {

    @JsonProperty("place_name")
    private String placeName;
}

테스트 코드 추가

@SpringBootTest
@SpringBootConfiguration
public class ApiClientTest {

    @Value("${kakao.restapi.key}")
    private String restApiKey;

    @BeforeEach
    public void setUp() throws Exception {
    }

    @Test
    public void getApiClient() {

        // given

        // when
        ApiInterface apiInterface = ApiClient.getApiClient().create(ApiInterface.class);

        Call<CategoryResult> call = apiInterface.getSearchLocation(
                restApiKey,
                "김치찌개",
                "FD6",          // 음식점
                15,
                1,
                "accuracy",                // distance
                "0",
                "0";

        // then
        try {
            Response<CategoryResult> response = call.execute();
            assertTrue(response.isSuccessful());

            CategoryResult result = response.body();
            assert result != null;

            List<Document> documents = result.getDocuments();
            assertTrue(documents.size() > 0);

            Document document = documents.get(0);

            System.out.println(document.getPlaceName());
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

비동기 호출

API 서버쪽은 비동기 호출이 앞뒤가 안맞는 듯 하다.
클라이언트에서 비동기 호출하는것이 맞는 듯 하다.

    @Test
    public void getApiClientAsync() throws InterruptedException {

        // given
        Map<String, String> params = new HashMap<>();
        params.put("p", "1");
        params.put("s", "15");
        params.put("q", "김치찌개");
        KakaoSearchDto searchDto = new KakaoSearchDto(params);

        // when
        ApiInterface apiInterface = ApiClient.getApiClient().create(ApiInterface.class);

        Call<CategoryResult> call = apiInterface.getSearchLocation(
                restApiKey,
                searchDto.getQueryString(),
                "FD6",          // 음식점
                searchDto.getPageSize(),
                searchDto.getPageNo(),
                "accuracy",                // distance
                searchDto.getLongitude().toString(),
                searchDto.getLatitude().toString());

        System.out.println("start async call : " + call.hashCode());

        call.enqueue(new Callback<>() {
            @Override
            public void onResponse(Call<CategoryResult> call, Response<CategoryResult> response) {

                System.out.println("onResponse called : " + call.hashCode());

                if (response.isSuccessful()) {
                    try {
                        CategoryResult result = response.body();
                        assert result != null;

                        List<Document> documents = result.getDocuments();
                        assertTrue(documents.size() > 0);

                        Document document = documents.get(0);

                        System.out.println(document.getPlaceName());
                        System.out.println(document.getCategoryName());
                    } catch (Exception e) {
                        System.out.println(e);
                    }
                } else {
                    System.out.println("Request Error :: " + response.errorBody());
                }
            }

            @Override
            public void onFailure(Call<CategoryResult> call, Throwable t) {
                System.out.println("onFailure called");
                System.out.println("Network Error :: " + t.getLocalizedMessage());
            }
        });

        System.out.println("sleep 5 seconds");

        Thread.sleep(5000);

        System.out.println("end main thread");

        // then
    }

답글 남기기