주니어개발자_ฅʕ•̫͡•ʔฅ

기상청 날씨 api_엑셀파일에서 지역 격자값 가져와 날씨 가져오기 (feat.공공데이터포털) 본문

AndroidStudio

기상청 날씨 api_엑셀파일에서 지역 격자값 가져와 날씨 가져오기 (feat.공공데이터포털)

뚜비뚜밥_98 2021. 7. 23. 13:12

전에 날씨 api를 사용하여

날씨 정보 가져오기를 해봤다.

기상청 날씨 api 사용

 

기상청 날씨 api (feat.공공데이터포털)

날씨를 불러오는 기능을 android 프로젝트에 넣으려고 찾아보았다. 먼저 참고한 블로그는 이곳이다. Java 기상청 날씨 API 사용하기(동네예보조회) 기존 (신)동네예보정보조회서비스와 중기예보정

toubi-tobap.tistory.com

 

 

이번엔 여기에 좀 더 난이도를 높여서

현재 위치를 읽어와

해당 지역에 맞는 날씨를

조회하고자 한다.

 

먼저

공공데이터포털에서 날씨 api를 신청하지 않았다면

위에 첨부한 블로그를 보고 따라한 후에 시작하길 바란다.

 

그리고 공공데이터 포털에서

밑에 빨간 동그라미 친 파일을 다운 받아 압축을 풀어준다.

모든 지역의 격자값이 쓰여있는 파일입니다.

본인은 해당 엑셀 파일에서 격자값만 필요했기에

필요 없는 부분은 지워서 새로 저장했다.

엑셀 파일을 다운 받아 열면 나타나는 내용
필요한 부분만 남기고 나머지는 지운 상태

상단에 A,B,C 등 알파벳으로 열이 나뉘어져 있는데

필요하지 않은 부분은

알파벳 부분을 눌러 열(세로) 단위로 지웠다. 

하지만 굳이 지우지 않아도 괜찮다...

 

엑셀 파일이 준비가 되었다면

앱에 넣어줍니다.

 

먼저 프로젝트에 assets폴더를 만들어준다.

그럼 app\src\main 위치에 assets라는 폴더가 생성 되는데

그 폴더 안에 위에서 다운 받은 엑셀 파일을 넣어주면 된다.

 

이제 엑셀 파일을 읽어 올 준비를 해보자.

 

먼저 엑셀파일을 읽을 수 있게 해주는

jxl-2.6.12.jar 라이브러리를 다운 받아 준다.

jxl-2.6.12.jar
0.69MB

다운 받는 곳은 찾아보면 있겠지만

찾아서 넣는게 귀찮아서 그냥 파일 올렸습니다.

 

위의 파일을 다운받은 후

적용할 프로젝트 파일에 추가해줍니다.

 

파일 추가 순서는

다운 받은 jxl 파일을 프로젝트 app\libs\ 위치에 포함시킨 후

프로젝트로 돌아와 file -> Project Stucture 을 눌러

 

Project Stucture 창이 뜨면 Dependencies 항목을 선택한다.

+ 를 누른 후 jar Dependency 항목을 선택한다.

파일을 추가할 수 있게

밑에 이미지와 같은 창이 뜨면

libs\jxl-2.6.12.jar 입력 후

ok 버튼을 누르면

프로젝트에 jxl 라이브러리 적용이 끝난다.

여기까지 날씨를 가져오기 위한 준비가 완료되었다.

본격적으로 현재 위치의 날씨를 가져와 보자.

 

1. 현재 위치 가져오기

현재 위치를 가져오는 방법은 밑의 블로그를 참고했다.

https://webnautes.tistory.com/1315

 

Android 예제 - 현재 위치 주소 가져오기(Get current location without google map)

LocationManager와 Geocoder를 사용하여 현재 위치에 대한 주소를 가져오는 예제입니다. 구글맵을 사용하지 않고 현재 위치를 가져오는 방법입니다. 2019. 3. 3 - 최초작성 2019. 11. 21 - androidx로 변경 다음..

webnautes.tistory.com

 

위의 블로그를 참고하여 현재 위치를 가져왔다면
현재 위치 내용은 밑에와 같이 구했을 것이다.

 

address = getCurrentAddress(latitude, longitude);

// address 변수는 현재 위치 정보(대한민국 서울특별시 xx구 xx동 xx-x) 넣을 변수, String형

 

여기서 나는 xx구 부분 추출을 위해

문자열 배열에 현재 위치를

띄어쓰기 기준으로 나누어 넣었다.

String[] local = address.split(" ");

// local[0] = 대한민국

// local[1] = 서울특별시

// local[2] = xx구

.

.

.

String localName = local[2]; //xx구 이름

 

2. 엑셀파일에서 현재 위치의 격자값 읽어오기

엑셀파일 읽어오는 것은 밑의 블로그를 참고했다.

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=gjdeveloper&logNo=220558182815 

 

안드로이드 Excel(엑셀) 읽기(JXL 사용)

이번에는 엑셀파일을 안드로이드에 불러오는 소스를 알려드리겠습니다. jxl 이라는 라이브러리를 사용하겠...

blog.naver.com

// 엑셀 파일에서 xx구 이름을 가지고 격자값 구하는 메소드 readExcel()

readExcel(localName); 

 

readExcel 소스코드

  public void readExcel(String localName) {

        try {
            InputStream is = getBaseContext().getResources().getAssets().open("local_name.xls");
            Workbook wb = Workbook.getWorkbook(is);

            if (wb != null) {
                Sheet sheet = wb.getSheet(0);   // 시트 불러오기
                if (sheet != null) {
                    int colTotal = sheet.getColumns();    // 전체 컬럼
                    int rowIndexStart = 1;                  // row 인덱스 시작
                    int rowTotal = sheet.getColumn(colTotal - 1).length;

                    for (int row = rowIndexStart; row < rowTotal; row++) {
                        String contents = sheet.getCell(0, row).getContents();
                        if (contents.contains(localName)) {
                            x = sheet.getCell(1, row).getContents();
                            y = sheet.getCell(2, row).getContents();
                            row = rowTotal;
                        }
                    }
                }
            }
        } catch (IOException e) {
            Log.i("READ_EXCEL1", e.getMessage());
            e.printStackTrace();
        } catch (BiffException e) {
            Log.i("READ_EXCEL1", e.getMessage());
            e.printStackTrace();
        }
        // x, y = String형 전역변수
        Log.i("격자값", "x = " + x + "  y = " + y);
    }

 

 

격자 값을 구했다면

현재 시간 및 날짜를 구해보자

이 부분은 밑의 블로그를 참고했다.

https://kiwinam.com/posts/6/android-simple-date-format/

 

[안드로이드] 현재 시간, 현재 날짜 구하기 (SimpleDateFormat) :: 키위남

현재 시간, 현재 날짜. simple date format

kiwinam.com

 

현재 시간은 시, 분, 초에서 시만 구한다.

만약 시간이 02:22:35 이렇게 된다면

0200으로 바꿔준다.

 

본인은 

time = time.substring(0, time.IndexOf(":"));

// time = String형 시간을 받아오는 변수

위와 같은 방법으로 바꿨지만

다른 편한 방법이 있다면 그렇게 해도 상관없다.

 

그리고 날짜는 20210101 같은 형식으로 있어야해서

date = date.replaceAll("-", "");

//date = String형 날짜 받아오는 변수

위와 같은 방법으로 "-" 부분을 없애준다.

 

마지막으로 밑에 했던 부분을 응용하여

현재 위치의 날씨를 받아오는

전체 소스 코드를 정리해 보면

(현재위치를 받아오는 GpsTracker 클래스와 퍼미션부분은 따로 포함하지 않았습니다.)

 

기상청 날씨 api 사용

 

기상청 날씨 api (feat.공공데이터포털)

날씨를 불러오는 기능을 android 프로젝트에 넣으려고 찾아보았다. 먼저 참고한 블로그는 이곳이다. Java 기상청 날씨 API 사용하기(동네예보조회) 기존 (신)동네예보정보조회서비스와 중기예보정

toubi-tobap.tistory.com

MainActivity

import부분과 날짜 및 시간 구하는 부분 간단한 부분으로 생략했다.

public class MainActivity extends AppCompatActivity {

    private GpsTracker gpsTracker;
    private String x = "", y = "", address = "";
    
    private date = "", time = "";
 
  @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        gpsTracker = new GpsTracker(this);

        double latitude = gpsTracker.getLatitude();
        double longitude = gpsTracker.getLongitude();

        address = getCurrentAddress(latitude, longitude);
        String[] local = address.split(" ");
        String localName = local[2];

        readExcel(localName); //행정시 이름으로 격자값 구하기
        
        String weather = "";
          WeatherData wd = new WeatherData();
            try {
            // date와 time에 값을 넣어야함
            // ex) date = "20210722", time = "0500"
                weather = wd.lookUpWeather(date, time, x, y);
            } catch (IOException e) {
                Log.i("THREE_ERROR1", e.getMessage());
            } catch (JSONException e) {
                Log.i("THREE_ERROR2", e.getMessage());
            }
            Log.i("현재날씨",weather);
    }
    
      public void readExcel(String localName) {

        try {
            InputStream is = getBaseContext().getResources().getAssets().open("local_name.xls");
            Workbook wb = Workbook.getWorkbook(is);

            if (wb != null) {
                Sheet sheet = wb.getSheet(0);   // 시트 불러오기
                if (sheet != null) {
                    int colTotal = sheet.getColumns();    // 전체 컬럼
                    int rowIndexStart = 1;                  // row 인덱스 시작
                    int rowTotal = sheet.getColumn(colTotal - 1).length;

                    for (int row = rowIndexStart; row < rowTotal; row++) {
                        String contents = sheet.getCell(0, row).getContents();
                        if (contents.contains(localName)) {
                            x = sheet.getCell(1, row).getContents();
                            y = sheet.getCell(2, row).getContents();
                            row = rowTotal;
                        }
                    }
                }
            }
        } catch (IOException e) {
            Log.i("READ_EXCEL1", e.getMessage());
            e.printStackTrace();
        } catch (BiffException e) {
            Log.i("READ_EXCEL1", e.getMessage());
            e.printStackTrace();
        }
        Log.i("격자값", "x = " + x + "  y = " + y);
    }
 }

 

WeatherData

날씨 구하는 클래스

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.WorkSource;
import android.util.Log;

import org.json.JSONException;
import org.json.JSONArray;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;

import jxl.Sheet;
import jxl.Workbook;
import jxl.read.biff.BiffException;

public class WeatherData{

    private String weather = "", tmperature = "";

    public String lookUpWeather(String baseDate, String time, String nx, String ny) throws IOException, JSONException {

//        String baseDate = date;//"20210531";//date	//조회하고싶은 날짜
        String baseTime = timeChange(time); //"0500";//timeChange(time);	//조회하고싶은 시간
        String type = "json";    //조회하고싶은 시간

        String apiUrl = "http://apis.data.go.kr/1360000/VilageFcstInfoService/getVilageFcst";
//         홈페이지에서 받은 키
        String serviceKey = "홈페이지에서 받은 키를 이곳에 넣어주세요";

        StringBuilder urlBuilder = new StringBuilder(apiUrl);
        urlBuilder.append("?" + URLEncoder.encode("ServiceKey", "UTF-8") + "=" + serviceKey);
        urlBuilder.append("&" + URLEncoder.encode("nx", "UTF-8") + "=" + URLEncoder.encode(nx, "UTF-8")); //경도
        urlBuilder.append("&" + URLEncoder.encode("ny", "UTF-8") + "=" + URLEncoder.encode(ny, "UTF-8")); //위도
        urlBuilder.append("&" + URLEncoder.encode("base_date", "UTF-8") + "=" + URLEncoder.encode(baseDate, "UTF-8")); /* 조회하고싶은 날짜*/
        urlBuilder.append("&" + URLEncoder.encode("base_time", "UTF-8") + "=" + URLEncoder.encode(baseTime, "UTF-8")); /* 조회하고싶은 시간 AM 02시부터 3시간 단위 */
        urlBuilder.append("&" + URLEncoder.encode("dataType", "UTF-8") + "=" + URLEncoder.encode(type, "UTF-8"));    /* 타입 */

        /*
         * GET방식으로 전송해서 파라미터 받아오기
         */
        URL url = new URL(urlBuilder.toString());
        //어떻게 넘어가는지 확인하고 싶으면 아래 출력분 주석 해제
        //System.out.println(url);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        conn.setRequestProperty("Content-type", "application/json");

        BufferedReader rd;
        if (conn.getResponseCode() >= 200 && conn.getResponseCode() <= 300) {
            rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        } else {
            rd = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
        }
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = rd.readLine()) != null) {
            sb.append(line);
        }
        rd.close();
        conn.disconnect();
        String result = sb.toString();


        // response 키를 가지고 데이터를 파싱
        JSONObject jsonObj_1 = new JSONObject(result);
        String response = jsonObj_1.getString("response");

        // response 로 부터 body 찾기
        JSONObject jsonObj_2 = new JSONObject(response);
        String body = jsonObj_2.getString("body");

        // body 로 부터 items 찾기
        JSONObject jsonObj_3 = new JSONObject(body);
        String items = jsonObj_3.getString("items");
        Log.i("ITEMS", items);

        // items로 부터 itemlist 를 받기
        JSONObject jsonObj_4 = new JSONObject(items);
        JSONArray jsonArray = jsonObj_4.getJSONArray("item");

        for (int i = 0; i < jsonArray.length(); i++) {
            jsonObj_4 = jsonArray.getJSONObject(i);
            String fcstValue = jsonObj_4.getString("fcstValue");
            String category = jsonObj_4.getString("category");

            if (category.equals("SKY")) {
                weather = "현재 날씨는 ";
                if (fcstValue.equals("1")) {
                    weather += "맑은 상태로";
                } else if (fcstValue.equals("2")) {
                    weather += "비가 오는 상태로 ";
                } else if (fcstValue.equals("3")) {
                    weather += "구름이 많은 상태로 ";
                } else if (fcstValue.equals("4")) {
                    weather += "흐린 상태로 ";
                }
            }

            if (category.equals("T3H") || category.equals("T1H")) {
                tmperature = "기온은 " + fcstValue + "℃";
            }

            Log.i("날씨", fcstValue);
            Log.i("카테고리", category);

            Log.i("지금 날씨는", weather + tmperature);
        }

        return weather + tmperature;
    }

    public String timeChange(String time)
    {
        // 현재 시간에 따라 데이터 시간 설정(3시간 마다 업데이트) //
        /**
        시간은 3시간 단위로 조회해야 한다. 안그러면 정보가 없다고 뜬다.
        0200, 0500, 0800 ~ 2300까지
        그래서 시간을 입력했을때 switch문으로 조회 가능한 시간대로 변경해주었다.
        **/
        switch(time) {

            case "0200":
            case "0300":
            case "0400":
                time = "0200";
                break;
            case "0500":
            case "0600":
            case "0700":
                time = "0500";
                break;
            case "0800":
            case "0900":
            case "1000":
                time = "0800";
                break;
            case "1100":
            case "1200":
            case "1300":
                time = "1100";
                break;
            case "1400":
            case "1500":
            case "1600":
                time = "1400";
                break;
            case "1700":
            case "1800":
            case "1900":
                time = "1700";
                break;
            case "2000":
            case "2100":
            case "2200":
                time = "2000";
                break;
            default:
                time = "2300";

        }
        return time;
    }

}