티스토리 뷰

📌 애플리케이션 명 : 특정 위치(키워드) 주변의 지정된 반경 내에서 💊 약국 💊 검색하는 Java 어플리케이션

📌 사용 언어 : JAVA

📌 빌드 : maven

📌 활용 API : 카카오 API - 키워드로 장소 검색하기, 카테고리로 장소 검색하기

 


 

💡 이 어플리케이션은,

키워드 입력에 기반하여 특정 위치 내의 장소를 검색할 수 있도록 합니다.
자신의 위치를 기반으로 특정위치에 있는 장소를 검색하여 지정된 반경 내에서 상위 10개의 약국들을 출력하는 어플리케이션입니다.

검색된 결과에서 장소 URL을 입력하면 브라우저에 해당 kakaomap이 출력되도록 합니다.

Kakao 로컬 REST API중 키워드로 장소 검색하기, 카테고리로 장소 검색하기 API를 활용하였습니다.

 

 

🥹  개발 후기

이 어플리케이션은 패스트캠퍼스 JAVA 심화 과제 1의 내용입니다. 카카오 API 연결하는데 방법을 찾느라 애 먹었지만, 오히려

HTTPClinet 와 OKHttp3 방법 둘다 실습해볼 수 있어 좋은 기회였습니다. 하나의 메소드에 한 개의 기능만 작동할 수 있도록 메소드를 분리하려고 노력했습니다. 다른 수강생분들의 코드를 보니 MVC로 하신 분들이 많아, 다음에는 저또한 MVC 구조를 활용해봐야 겠습니다.

 

 

💡 개발 특징 

  • 카카오 API 중 키워드로 장소 검색하기 , 카테고리로 장소 검색하기 를 이용하여 정보를 불러왔습니다.
  • 검색 결과 상위 10개의 주변 약국을 불러옵니다.
  • 입출력 역할을 하는 클래스 main 클래스와 카카오 api를 이용해 요청 처리를 하는 kakaoMapConnect 클래스로 분리하였습니다.
  •  또한 약국 객체를 만들 수 있도록 model 패키지 안에 Pharmacy 클래스를 정의하여 활용하였습니다. getter, setter, 생성자를 자동생성할 수 있도록 Lombok 라이브러리 적용하여 가독성을 높이고자 하였습니다.
  •  Rest API, Http 통신은 OkHTTP3 라이브러리를 활용하였습니다.
  •  위도 경도를 담는 loc(String[]) 은, 기본값은 서울 중구로 하여 잘못된 키워드를 입력하면 해당 위치의 주변 약국이 출력하도록 하였습니다.

 

 


 

0️⃣ 클래스 구조 바로 보기

⬇️ 펼쳐 보기

더보기
Main.java :입출력을 수행하는 메인 클래스
- input(): 위치 키워드, 반경 입력받음.
- printPharmacyList(ArrayList<Parmacy> parmacy_list): 약국 리스트 내용 출력
- displayUrlPage() : url을 입력하면 바로 창을 띄울 수 있도록 하는 메소드

KakaoMapConnect.java: 카카오 오픈 API을 이용하여 지도 검색 및 결과를 반환하도록 하는 클래스
- searchLocInfoByKeyword(String loc_keyword): 카카오 키워드 검색 api을 통해 위치정보(위도,경도)를 가져와 반환. 
- searchPharmacyList(String[] loc, String radius) : 카카오 지도 카테고리 검색 api를 통해 위도,경도,반경을 이용하여 주변 약국 리스트 반환.
- getBodyByOkHttpGet(HttpUrl url): url을 가지고 http 요청 및 응답을 수행하여 json 형식의 String을 반환.
- getLocationInfoByJson(String jsonBody): json 형식의 String에서 위도,경도를 반환.
- getPharmacyListByJson(String jsonBody): json 형식의 String에서 약국 리스트를 반환.
- getPharmacyByJsonObj(JSONObject pharmacyObj): json 객체에서 약국 객체를 만들어 반환.

model/Pharmacy.java: 약국 객체를 만들기 위한 자료형
- private String place_name, phone, address_name, place_url
- private double distance
- setDistance(double distance): 거리를 m에서 km으로 변환하여 저장.

 

1️⃣  위치 키워드를 통해 위치 정보(위도, 경도) 가져오는 방법 

1) searchLocInfoByKeyword(loc_keyword) 에서 키워드 query parameter로 사용하여 Url 생성
2) getBodyByOkHttpGet(url) 메소드를 통해 json 형식의 response body 가져옴.
3) getLocationInfoByJson(json_body) 메소드 통해 위치 정보(위도, 경도)를 담은 String 배열 담아와 main에 반환.

 

⬇️ 코드 보기

더보기

* REST_API_KEY 는 상단에 final 변수로 선언. 

   	public String[] searchLocInfoByKeyword(String loc_keyword) {

        //req_url = "https://dapi.kakao.com/v2/local/search/keyword.json";
        HttpUrl url = new HttpUrl.Builder()
                .scheme("https")
                .host("dapi.kakao.com")
                .addPathSegment("v2/local/search/keyword.json")
                .addQueryParameter("query", loc_keyword)
                .build();

        String json_body = getBodyByOkHttpGet(url);
        String[] loc = getLocationInfoByJson(json_body);

        return loc;

    }
    
    private String getBodyByOkHttpGet(HttpUrl url) {
        String json_body = "";
        try {
            //인스턴스를 생성합니다.
            OkHttpClient client = new OkHttpClient();

            //GET요청을 위한 build 작업을 합니다.
            Request.Builder builder = new Request.Builder().url(url).get();

            //헤더에 카카오 요청 인증값 추가
            builder.addHeader("Authorization", REST_API_KEY); //KEY 입력

            //request 객체를 생성합니다.
            Request request = builder.build();

            //request를 요청하고 그 결과를 response 객체로 응답을 받습니다.
            Response response = client.newCall(request).execute();

            //응답처리
            if(response.isSuccessful()){
                ResponseBody body = response.body();
                json_body = body.string();
                body.close();
            }

        } catch(Exception e){
            System.err.println(e.toString());
        }

        return json_body;
    }
    

    private String[] getLocationInfoByJson(String jsonBody) {
        //json -> loc(위도, 경도)
        JSONObject jsonObject = new JSONObject(jsonBody);
        JSONArray documents = jsonObject.getJSONArray("documents");
        String[] loc = {"126.997555182293", "37.5638077703601"}; //default : 서울중구 위도,경도
        if (documents.isEmpty()) return loc;

        JSONObject address = documents.getJSONObject(0);
        loc[0] = address.getString("x"); //위도
        loc[1] = address.getString("y"); //경도
        return loc;
    }



2️⃣ 가져온 위치정보를 이용하여 주변 약국 리스트 가져오는 방법

1) searchPharmacyList(loc,radius) 에서 위도,경도,약국 카테고리 번호를 이용해 url 생성.
2) getBodyByOkHttpGet(url) 메소드를 통해 json 형식의 response body 가져옴.
3) getPharmacyListByJson(json_body) 메소드를 통해 주변 약국 리스트를 담아 main에 반환.

 

⬇️ 코드 보기 (getBodyByOkHttpGet(url) 은 위에 있음. 

더보기
    public ArrayList<Pharmacy> searchPharmacyList(String[] loc, String radius) {
        ArrayList<Pharmacy> pharmacy_list = new ArrayList<>();
        //req_url = "https://dapi.kakao.com/v2/local/search/category.json";

        HttpUrl url = new HttpUrl.Builder()
                .scheme("https")
                .host("dapi.kakao.com")
                .addPathSegment("v2/local/search/category.json")
                .addQueryParameter("x",loc[0])
                .addQueryParameter("y", loc[1])
                .addQueryParameter("radius", radius)
                .addQueryParameter("size", "10")
                .addQueryParameter("category_group_code", "PM9") //약국 category_code
                .build();

        String json_body = getBodyByOkHttpGet(url);
        pharmacy_list = getPharmacyListByJson(json_body);
        return pharmacy_list;
    }


    private ArrayList<Pharmacy> getPharmacyListByJson(String jsonBody) {
        //json -> pharmacy list
        JSONObject jsonObject = new JSONObject(jsonBody);
        JSONArray documents = jsonObject.getJSONArray("documents");

        ArrayList<Pharmacy> pharmacy_list = new ArrayList<>();
        for (int i = 0; i < documents.length(); i++) {
            JSONObject pharmacyObj = documents.getJSONObject(i);
            pharmacy_list.add(getPharmacyByJsonObj(pharmacyObj));
        }

        return pharmacy_list;
    }

	//약국 json 객체에서 약국 객체로 만들기 
    private Pharmacy getPharmacyByJsonObj(JSONObject pharmacyObj) {
        Pharmacy pharmacy = new Pharmacy();

        pharmacy.setPlace_name(pharmacyObj.getString("place_name"));
        pharmacy.setPlace_url(pharmacyObj.getString("place_url"));
        pharmacy.setDistance(Double.parseDouble(pharmacyObj.getString("distance")));
        pharmacy.setPhone(pharmacyObj.getString("phone"));
        pharmacy.setAddress_name(pharmacyObj.getString("address_name"));

        return pharmacy;
    }

 

 

3️⃣  콘솔창에 링크 입력하면 바로 브라우저에 창 뜨게 하는 방법 

1) displayUrlPage() 호출
2) Desktop.getDesktop().browse() 메소드 이용.

 

⬇️ 코드 보기 

더보기
    public static void displayUrlPage() {

        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

            System.out.print("\nkakaomap URL(장소 URL): ");
            String ans = "";
            while (!(ans = br.readLine()).equals("exit")) {
            	//콘솔에 링크 입력하면 바로 브라우저에 창 띄어줌.
                Desktop.getDesktop().browse(new URI(ans));
                System.out.print("kakaomap URL(장소 URL): ");
            }

            br.close();
        } catch (Exception e) {
            System.err.println(e.toString());
        }

    }

 

 

4️⃣ Lombok 을 활용한 사용자 커스텀 자료형인 약국 (Pharmacy.class)

1) setDistance() : 카카오에서 제공하는 거리는 m이므로, 이 곳에서 m->km 로 바꾸는 작업을 처리.
2) @All/NoArgsConstuctor => 생성자 자동 생성.
3) @Data => getter, setter 자동 생성.

⬇️ 코드 보기

더보기
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Pharmacy {
    private String place_name, phone, address_name, place_url;
    private double distance;
    public void setDistance(double distance) {
        // km 으로 나타내기 위해 1000으로 나눠줌. 555m -> 0.555km
        this.distance = distance / 1000;
    }
}

 


 

📝 실행 결과 화면