본문 바로가기
안드로이드 자바

[JAVA][Android] 알라딘 도서 검색 Open API 사용하기 (Retrofit 사용)

by teamnova 2024. 7. 17.
728x90

 

안녕하세요

오늘은 알라딘에서 제공하는 오픈 API 를 사용하여

도서 검색 기능을 구현해보도록 하겠습니다. 

 

1) 키 발급 받기 

 

[알라딘서재]OpenAPI 안내

OpenAPI 안내 (최종 수정일 : 2022.7.13) OpenAPI는 크게 3가지로 나눠집니다. (1) 검색API (2) 상품API (하나의 상품을 열람하는 API) (3) 상품 리스트 API (베스트셀러 등 각종 상품 리스트 API) 상품API는 하나의

blog.aladin.co.kr

 

 

먼저 API 를 사용하기 위해 키를 발급 받아야 합니다. 

알라딘 오픈 API 안내 페이지 하단에 

 ▶ API 키 발급 및 URL 등록하기 를 클릭합니다.

( 알라딘 계정이 필요합니다 )

 

아래와 같은 화면이 등장합니다 

 

해당 API 를 사용하고자 하는 웹 페이지 주소, 혹은 앱 다운로드 링크 등을 입력해주세요 

둘 다 없는 경우 개인 SNS의 주소를 입력하시면 됩니다. (따로 인증 필요 x)  

 

URL 정보 등록이 완료되면 OpenAPI 인증키가 발급되며 즉시 사용이 가능합니다.

하루 쿼리 호출수는 5천건으로 제한됩니다. 

 

 

2) 메뉴얼 및 안내 사항 확인 - 요청 URL 양식 확인

저희가 오늘 사용할 API 는 <검색 API> 입니다. 

좌측 메뉴 목록에서 검색 API를 클릭합니다. 

 

 

알라딘 서버로 검색 요청을 보낼 때 필요한 서버 URL과 

알라딘으로부터 전달 받을 검색 결과의 형식을 확인합니다. 

오늘 이 글에서는 JSON 으로 응답을 받기 때문에 Javascript 형식을 확인해주세요.  

 

아래는 알라딘에서 제공하는 Open API 메뉴얼 파일입니다. 

각 API 별로 알라딘에서 어떤 정보를 제공하는지 확인할 수 있습니다. 

 

알라딘 Open API 매뉴얼

1. 요청 (Request) 1) 상품 검색 API 2) 상품 리스트 API 3) 상품 조회 API 4) 중고상품 보유 매장 검색 API 2. 응답 (Response) 1) 상품 검색/상품 리스트/상품 조회 API 2) 상품 조회 API : 부가정보 3) 중고상품 보

docs.google.com

 

 

3) 요청 Request 보내기 (Retrofit 라이브러리 사용) 

먼저 레트로핏 (Retrofit) 라이브러리를 사용하여 서버에 요청(Request)을 보내기 위해 

첫번째로 매니페스트에서 인터넷 사용에 대한 퍼미션을 주고, 두번째 레트로핏 라이브러리에 대한 의존성을 추가합니다. 

JSON으로 응답을 받기 위해 이를 자바 객체로 변환해주는 GSON 라이브러리 의존성도 추가합니다. 

왼: Manifest 파일 / 오: Gradle 파일

 

 

Retrofit 라이브러리 최신 버전은 아래 깃허브에서 확인하실 수 있습니다. 

 

GitHub - square/retrofit: A type-safe HTTP client for Android and the JVM

A type-safe HTTP client for Android and the JVM. Contribute to square/retrofit development by creating an account on GitHub.

github.com

 

 

먼저 레트로핏 객체 생성을 위한 클래스를 추가합니다. 

RetrofitClient_aladin.java

package com.example.myapplication.data.retrofit;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class RetrofitClient_aladin {

  // 알라딘 API 요청 URL - open api 메뉴얼 참고 
    private static final String BASE_URL = "http://www.aladin.co.kr/ttb/api/";
    private static Retrofit retrofit = null;

    static Gson gson = new GsonBuilder().setLenient().create(); //json 직렬/역직렬화.

    private RetrofitClient_aladin() {}
    public static Retrofit getClient(){
        if(retrofit==null) {

			// 필수 아님 
            HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
            logging.setLevel(HttpLoggingInterceptor.Level.BODY); 
			// 필수 아님 
            OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
            httpClient.addInterceptor(logging); // 로깅 인터셉터 추가


            retrofit = new Retrofit.Builder() // 레트로핏 빌더
                    .baseUrl(BASE_URL) //
                    .addConverterFactory(GsonConverterFactory.create(gson)) 
                    .build(); 
        }
        return retrofit;
    }
}

 

 

(필수 아님)

+ http  요청과 응답을 디버깅하기 위한 Http Logging Intercepter 사용을 위해 gradle 의존성 추가하기 

	// retrofit
	implementation("com.squareup.retrofit2:retrofit:2.11.0")
    implementation("com.squareup.retrofit2:converter-moshi:2.11.0")
    implementation("com.squareup.retrofit2:converter-gson:2.11.0")



    // okhttp3 & logging-interceptor
    implementation ("com.squareup.okhttp3:okhttp:3.2.0") // 2024.06 기준
    implementation ("com.squareup.okhttp3:logging-interceptor:4.12.0") // 2024.06 기준

 

okhttp 3 버전 확인 

https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp/3.2.0 

okhttp-logging-interceptor 버전 확인 

https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor 

 

 

아래는 도서 검색 시, 알라딘 서버에 전달해야 하는 파라미터 목록입니다. 

 

ttbkey : api 사용을 위해 발급받은 고유 key

Query : 사용자가 입력한 검색어 (책 제목, 저자)

QueryType : 검색어 종류 (제목저자, 제목, 저자, 출판사) 중 택1

MaxResults : 검색 결과 한페이지당 최대 출력개수 (검색 결과 총 개수랑 다름.)

start : 검색 결과 시작할 “페이지 수”

SearchTarget : 도서, 외국도서, 음반, dvd 등 중 택1

output : 출력할 방법, 기본은 XML, JS (Json으로 바꿈)

Version : 검색 api 의 버전 설정 해주기 (240508기준 최신: 20131101) 

 

 

RetrofitService.java 

 알라딘 서버에 요청을 보낼때 사용될 인터페이스 메소드입니다.  이 메소드는 검색 api 를 호출해 책 정보를 가져오기 위한 것입니다. 여기서 각 매개변수는 api 요청에 필요한 정보를 제공합니다. 

    // 알라딘 책 검색 api
    @GET("ItemSearch.aspx")
    Call<AladinResponse.AladinResponse2> getSearchBook(
            @Query("ttbkey") String ttbkey, //알라딘 api 키, 사용자 인증용
            @Query("Query") String Query, // 사용자가 입력한 검색어 (책제목, 글쓴이, 출판사 등)
            @Query("QueryType") String queryType, () //검색어 종류 (제목저자, 제목, 저자, 출판사) 중 택1
            @Query("MaxResults") int maxResults, // 최대 결과수 
            @Query("start") int start, // 검색 결과 중 가져올 시작 페이지의 수 
            @Query("SearchTarget") String searchTarget, //도서, 외국도서, 음반, dvd 등 중 택1 
            @Query("output") String output,// 출력할 방법, 기본은 XML, JS (json) 
            @Query("Version") String version // 검색 api 의 버전, (240508기준 최신: 20131101)
    );

 

 

 

AladinResponse.java 

 응답 클래스입니다. 알라딘으로부터 검색 결과를 가져오기 위해 사용합니다.  

내부 클래스를 만들어, 검색 결과가 1권 이상일 때, 각각의 책 정보를 하나의 목록(List)으로 가져올 수 있도록 합니다. 

package com.example.myapplication.data.retrofit.responsemodel;

import com.google.gson.annotations.SerializedName;

import java.util.List;

public class AladinResponse {
    @SerializedName("title")
    private String title; // 책 제목

    @SerializedName("author")
    private String author; // 책 지은이

    @SerializedName("description")
    private String description; // 책 설명

    @SerializedName("publisher")
    private String publisher; // 출판사

    @SerializedName("pubDate")
    private String pubDate; // 출판 날짜

    @SerializedName("cover")
    private String cover; // 표지 사진

    @SerializedName("isbn")
    private String isbn; // ISBN 국제 표준 도서 고유값

    // Getters
    public String toString() {
        return "Title: " + title + ", Author: " + author + ", description: " + description +", Publisher: " + publisher + ", PubDate: " + pubDate + ", Cover: " + cover + ", ISBN: " + isbn;
    }

    public String getTitle() {
        return title;
    }

    public String getAuthor() {
        return author;
    }

    public String getDescription() {
        return description;
    }

    public String getPublisher() {
        return publisher;
    }

    public String getPubDate() {
        return pubDate;
    }

    public String getCover() {
        return cover;
    }

    public String getIsbn() { return isbn;
    }

    // 응답에서 책 목록을 포함하는 클래스
    public class AladinResponse2 {
        @SerializedName("totalResults")
        private int totalResults;

        @SerializedName("itemsPerPage")
        private int itemsPerPage;

        @SerializedName("item")
        private List<AladinResponse> books; // 책 목록

        // Getters...

        public int getTotalResults() {
            return totalResults;
        }

        public int getItemsPerPage() {
            return itemsPerPage;
        }

        public List<AladinResponse> getBooks() {
            return books;
        }
    }


}

 

 

리사이클러뷰를 사용하여 책 검색 결과를 보여주고자 합니다.  


SearchBookData.java

리사이클러뷰에 추가될 데이터를 나타낸 클래스입니다. 알라딘으로부터 받아온 책 검색 결과를 담는 데이터 클래스입니다. 

package com.example.myapplication;

public class SearchBookData { // 책 검색 결과 리사이클러뷰에 들어갈 데이터

    // 책 제목, 지은이, 책 설명, 출판사, 출판날짜, 표지 사진
    private String title; // 책 제목
    private String author; // 책 지은이
    private String description; // 책 설명
    private String publisher; // 출판사
    private String pubDate; // 출판 날짜
    private String cover; // 표지 사진
    private String isbn; // isbn


    // 생성자
    public SearchBookData(String title, String author, String description, String publisher, String pubDate, String cover, String isbn) {
        this.title = title;
        this.author = author;
        this.description = description;
        this.publisher = publisher;
        this.pubDate = pubDate;
        this.cover = cover;
        this.isbn = isbn;
    }

    // getter setter


    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getPublisher() {
        return publisher;
    }

    public void setPublisher(String publisher) {
        this.publisher = publisher;
    }

    public String getPubDate() {
        return pubDate;
    }

    public void setPubDate(String pubDate) {
        this.pubDate = pubDate;
    }

    public String getCover() {
        return cover;
    }

    public void setCover(String cover) {
        this.cover = cover;
    }

    public String getIsbn() { return isbn; }

    public void setIsbn(String isbn) { this.isbn = isbn; }
}

 

 

 

itemlist_book.xml

리사이클러뷰에 추가될 아이템 레이아웃 입니다. 책 표지, 책 제목, 작가, 책 설명 등 데이터를 표시합니다. 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="10dp"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >

        <ImageView
            android:id="@+id/book_cover"
            android:layout_width="100dp"
            android:layout_height="130dp"
            android:src="@drawable/ic_launcher_background"/>

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:paddingTop="3dp"
            android:paddingBottom="5dp"
            android:orientation="vertical">


            <TextView
                android:id="@+id/book_title"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="코스모스"
                android:textSize="22dp"
                android:textStyle="bold"
                android:maxLines="1"
                android:ellipsize="end"
                />

            <TextView
                android:id="@+id/book_author"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="칼 세이건"
                android:textSize="18dp"
                android:layout_marginTop="5dp"
                android:maxLines="1"
                android:ellipsize="end"
                />

            <TextView
                android:id="@+id/book_description"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="칼 세이건의 코스!@#$%^*모스 [] (특별판)이{} ()세이건의 서거 10주기를 기념하여 출간되었다. 이 특별판은 지 2004년 12월에 출간된 코스모스 양장본의 텍스트 전문"
                android:layout_marginTop="10dp"
                android:maxLines="3"
                android:ellipsize="end"
                />

        </LinearLayout>

    </LinearLayout>

</LinearLayout>

 

 

 

SearchBookAdapter.java

알라딘 API 를 통해 검색된 책 데이터를 리사이클러뷰에 표시하기 위한 어댑터입니다. 

뷰홀더를 사용하여 각 아이템의 뷰 요소를 설정합니다.  (책 제목, 책 표지 등) 

package com.example.myapplication;

public class SearchBookAdapter extends RecyclerView.Adapter<SearchBookAdapter.SearchBookViewHolder> {

    // search book adapter 구성순서
    // 1. 생성자
    // 2. view holder
    // 3. on create view holder - 레이아웃 setting
    // 4. bind view holder


    private Activity mContext;

    private List<SearchBookData> bookList = new ArrayList<SearchBookData>();

    // 1. 생성자
    public SearchBookAdapter(Activity context) { mContext = context; } // 기본생성자


    // 2. 뷰홀더 먼저
    public class SearchBookViewHolder extends RecyclerView.ViewHolder {
        public ImageView book_cover_img;
        public TextView book_title_tv, book_author_tv, book_description_tv;

        public SearchBookViewHolder(View view) {
            super(view);
            book_cover_img = view.findViewById(R.id.book_cover);
            book_title_tv = view.findViewById(R.id.book_title);
            book_author_tv = view.findViewById(R.id.book_author);
            book_description_tv =  view.findViewById(R.id.book_description);
        }

        public void setItem (SearchBookData item) {
            //book_cover_img.setImageResource(item.getCover());
            book_title_tv.setText(item.getTitle());
            book_author_tv.setText(item.getAuthor());
            book_description_tv.setText(item.getDescription());

            // Glide 추가
            Glide.with(itemView.getContext()) // 현재 View의 context
                    .load(item.getCover())  // 서버 사진 이미지
                    .into(book_cover_img); // Imgage View에 표시해주기.

        }
    } // 뷰홀더


    // 3. on create view holder
    @NonNull
    @Override
    public SearchBookAdapter.SearchBookViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

        Context context = parent.getContext();
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        View view = inflater.inflate(R.layout.itemlist_book, parent, false);
        SearchBookAdapter.SearchBookViewHolder holder = new SearchBookAdapter.SearchBookViewHolder(view);
        return holder;

    } // on create


    // 4. bind view holder
    @Override
    public void onBindViewHolder (@NonNull SearchBookAdapter.SearchBookViewHolder holder, final int position) {
        // bh1. view에 아이템 setting 하기
        SearchBookData item = bookList.get(position);
        holder.setItem(item);

    }


    @Override
    public int getItemCount() {
        return bookList.size();
    }


    // 아이템 추가
    public void addItem(SearchBookData bookitem) {
        Log.i("search book adapter - additem", "책 제목: " + bookitem.getTitle() + "책 작가: " + bookitem.getAuthor());
        bookList.add(bookitem);
        notifyDataSetChanged(); // 리사이클러뷰 갱신
    }

    // 아이템 삭제
    public void clearItem() {bookList.clear();}

}

 

 

 

MainActivity.java 

마지막으로 메인 액티비티입니다. 사용자가 검색어를 입력하고 검색 결과를 받아온뒤, 리사이클러뷰에 표시합니다.  

package com.example.myapplication;


public class MainActivity extends AppCompatActivity {


    // import
    RetrofitService service; // 레트로핏 서비스


    // 책 목록을 출력하기 위한 리사이클러뷰 및 어댑터
    private LinearLayoutManager linearLayoutManager; // 리사이클러뷰를 위한 리니어 레이아웃
    private RecyclerView recyclerView;
    SearchBookAdapter bookAdapter; // 책검색 결과 리사이클러뷰 어댑터


    // int
    private int currentPage = 1; // 현재 페이지 번호
    private final int maxResults = 10; // 한 페이지당 결과 개수
    int total_page =0; // 결과 값에 대한 총 페이지 수. // 문제가 생겼을때 결과값이 0이 되도록.



	// string
    String ttbkey = "ttbnncn98631409001"; // 알라딘 인증 키


    // view
    EditText book_search; // 책 검색어 입력창



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // ----------------- 초기화
        // 레트로핏 객체 생성
        service =  com.example.myapplication.data.retrofit.RetrofitClient_aladin.getClient().create(RetrofitService.class);

        // 책 검색어 입력창
        book_search = findViewById(R.id.book_search); // 책 검색어 입력창


        // 리사이클러뷰 세팅

        // adapter
        bookAdapter = new SearchBookAdapter(MainActivity.this);

        // recycler view
        recyclerView = (RecyclerView) findViewById(R.id.book_list);
        linearLayoutManager = new LinearLayoutManager(MainActivity.this, LinearLayoutManager.VERTICAL, false);
        recyclerView.setLayoutManager(linearLayoutManager); 
        recyclerView.setAdapter(bookAdapter);



        // ---------------- 초기화 끝



        // event1. 책 검색 기능
        book_search.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if(actionId == EditorInfo.IME_ACTION_SEARCH ||
                        (event != null && event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) {
                    String searchQuery = book_search.getText().toString().trim(); // 검색어 입력값
                    if(!searchQuery.isEmpty()) { // 입력값 있을 때 엔터 누를 경우.
                        // 에디트 텍스트 "" 빈값 만들지 않기.

                        if(bookAdapter.getItemCount() > 0) { // 검색할 때 마다 기존 검색 결과 clear 하기.
                            bookAdapter.clearItem();
                        }

                        currentPage = 1;
                        total_page = 0; // 재검색시 결과 페이지 다시 0으로.
                        search_send(ttbkey, searchQuery, currentPage);
                        Toast.makeText(MainActivity.this, "입력한 검색어 : " + searchQuery, Toast.LENGTH_SHORT).show();

                    } else {
                        Toast.makeText(MainActivity.this, "검색어를 입력하세요", Toast.LENGTH_SHORT).show();
                    }
                    return true; // 엔터키 처리 완료
                }
                return false; //  엔터 키 처리 안함.
            }
        }); // 책 검색 끝
    } // on create 끝



    // method 1. 책 검색 메소드 - 레트로핏 사용하여 알라딘 api 호출
    private void search_send (String ttbkey, String keyword, int page) {
        Log.e("알라딘검색메소드", "키: " + ttbkey + " 검색어 keyword : "+keyword + "요청 페이지: " + page);
        service.getSearchBook(ttbkey,
                keyword,
                "Keyword",
                maxResults,
                page,
                "Book",
                "JS",
                "20131101").enqueue(new Callback<AladinResponse.AladinResponse2>() {
            @Override
            public void onResponse(Call<AladinResponse.AladinResponse2> call, Response<AladinResponse.AladinResponse2> response) {
                AladinResponse.AladinResponse2 result = response.body();
                Log.e("알라딘api 검색 성공", "onResponse: " + response.body());

                // 책 목록 가져오기.
                List<AladinResponse> books = result.getBooks(); // 검색 결과 책 목록
                int result_total = result.getTotalResults(); // 검색 결과 개수
                int item_perpage_cnt = result.getItemsPerPage(); // 한 페이지에 출력할 책의 개수
                Log.i("검색결과 개수 및 페이지수 ", "총 개수: " + result_total + " , 페이지당 아이템개수: " + item_perpage_cnt );

                // 총 페이지수
                total_page = (int) Math.ceil((double) result_total/(double) maxResults);

                // 책 목록 - 각 책 정보 출력
                for (AladinResponse book : books ) {
                    Log.i("검색결과책 정보 >>>  ", "Title: " + book.getTitle() + ", Author: " + book.getAuthor() +
                            "Description: " + book.getDescription() + ", Publisher: " + book.getPublisher() +
                            ", PubDate: " + book.getPubDate() + ", Cover: " + book.getCover() + ", ISBN: "+ book.getIsbn());
                    String title = book.getTitle();
                    String author =  book.getAuthor();
                    String description = book.getDescription();
                    String publisher =  book.getPublisher();
                    String pubDate = book.getPubDate();
                    String cover = book.getCover();
                    String isbn = book.getIsbn();
                    // add search book adapter
                    bookAdapter.addItem(new SearchBookData(title, author, description, publisher, pubDate, cover, isbn));
                    //   Log.i("검색책목록개수!! ", "getItemCount: " + bookAdapter.getItemCount());
                }
                isLoading = false; // 로딩 완료 후 플래그 초기화. / 페이징용.



            }

            @Override
            public void onFailure(Call<AladinResponse.AladinResponse2> call, Throwable throwable) {
                throwable.getMessage();
                Log.e("알라딘api 검색", "onFailure: " + throwable.getMessage());
            }
        });

    }




}

 

 

 

 

시연 영상입니다.