[SpringBoot+JPA] 공공데이터 db저장과 API만들기-1

ttomy·2022년 1월 11일
4

Spring

목록 보기
1/4

현재 springboot로 게시판과 jpa,mariadb를 연동해 crud기능과 간단한 ui를 구현을 해본 상태이다. 이때 네이버 부스트 코스의 백엔드 강의를 보게 되었는데 명세대로 api를 만드는 프로젝트를 하면 학습에 도움이 될 것 같았다. 그래서 공공api 데이터를 db에 저장하고 간단한 요구사항에 따라 rest api를 제공하는 프로그램을 만들어보려한다. springboot,mariadb,jpa,swagger를 사용하고 의존성 관리는 gradle을 이용했다. 기본적인 요구사항은 아래와 같다.

요구사항

1.mvc모델로 레이어드 아키텍쳐로 구성되어야 함.
2.mariadb, jpa활용.
3.swagger를 이용한 web api테스트 페이지를 제공해야함
4.web api를 JUnit을 이용해 test해야함.
5.서울열린 데이터 지하철노선별 승하차 인원 정보 활용
6. /8080/api에서 조회할 날짜 입력(해당날짜의 데이터 db저장됨) -> 8080/findname에서 조회할 역이름 입력 -> 8080/result에서 해당정보 보여줌
7.rest api:

  • 8080/result?station_name
    파라미터명:station_name/ 필수유뮤:yes/ 타입:String
    해당 역이름의 모든 호선 정보 보여줌

  • 8080/result/line?line_num
    파라미터명:line_num/ 필수유무:yes/타입:String
    -해당 호선의 모든 역 정보 보여줌

공공데이터 불러오기

1. 서울열린데이터 광장 회원가입

https://data.seoul.go.kr/

2. api인증키 신청

https://data.seoul.go.kr/together/guide/useGuide.do
https://data.seoul.go.kr/dataList/OA-12914/S/1/datasetView.do

위 화면에서 인증키 신청을 클릭해 인증키를 발급받는다.

3. 스프링 부트 프로젝트 생성

4. 처음 화면 mapping

  • HomeController 클래스 생성

resouces의 templates디렉토리 안에 index.html을 생성한다.
스프링부트는 html을 매핑할때 자동으로 templates 디렉토리부터 찾기 때문에 이 위치에 html을 생성한다.

  • index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Home</title>
</head>
<body>
<h2>Input date you want to see</h2>
<h3>Example: 20220101</h3>
<form method="POST" action="/api">
    <input type="text" name="date" th:value="${date}"/>
    <input type="submit" value="CLick"/>
</form>
</body>
</html>

위와 같이 데이터를 얻으려는 날짜를 입력하는 form을 생성한다.

5. 공공데이터 불러오기

이제 입력받은 날짜를 인자로 공공데이터api를 이용해 데이터를 불러와야한다. index.html에서 post메소드로 날짜를 input했으니 @Postmapping으로 해당 날짜를 가져와 그 날짜의 json형식 정보들을 가져와 보자. 우선 제공해준 url에 접속해 어떤 구조로 json데이터를 보내는지 확인한다.

  • 제공 공공데이터 확인

샘플 url을 보고 해당 url로 들어가 제공 데이터의 구조를 볼 수 있다.

인증키부분에 내가 받은 인증키를 입력해 url로 들어가면 위와 같은 구조의 데이터를 볼 수 있을 것이다.
CardSubwayStatsNew객체 안에 list_total_count라는 값과 Result라는 객체, row라는 객체배열이 있다. 위 url에서 json대신에 xml을 입력하면 더 보기 편하게 정리된 구조를 볼 수 있다.

Dto 생성

위에서 살펴본 row안에 담긴 데이터를 담을 객체가 필요하다. row안의 객체들과 같은 변수형을 가진 class를 생성한다.

SubstationInfo

@Entity
@Data
public class SubstationInfo {
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private Long id;
   private String USE_DT;
   private SubstationInfo() {}
   private String LINE_NUM;
   private String SUB_STA_NM;
   private double RIDE_PASGR_NUM;
   private double ALIGHT_PASGR_NUM;
   private String WORK_DT;

   public SubstationInfo(Long id, String USE_DT, String LINE_NUM, 
   String SUB_STA_NM, double RIDE_PASGR_NUM, double ALIGHT_PASGR_NUM, 
   String WORK_DT) {
       this.id = id;
       this.USE_DT = USE_DT;
       this.LINE_NUM = LINE_NUM;
       this.SUB_STA_NM = SUB_STA_NM;
       this.RIDE_PASGR_NUM = RIDE_PASGR_NUM;
       this.ALIGHT_PASGR_NUM = ALIGHT_PASGR_NUM;
       this.WORK_DT = WORK_DT;
   }

6. Json데이터 객체로 변환

어떠한 데이터를 다른 데이터 형식으로 다루기 위해 변환을 하는 것을 파싱(parsing)이라 한다. json 데이터를 java에서 다루기 위해 json parser가 필요한다. 이를 위해 json.simple 라이브러리를 사용하겠다. json,simple 의존성 주입을 위해 build.gradle에 dependencies에

  • implementation group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1'
    위와 같이 입력한다. vesion은 갱신될 수 있다.
    HomeController안에서 postmapping을 하며 그 메소드 안에서 parsing까지 한다면 아래와 같은 코드가 된다.

    -HomeController

    @Controller
    public class HomeController {
    
       @Autowired
       private SubstationInfoRepository infoRepository;
    
       @GetMapping("/api")
       public String index(){
           return "index";
       }
    
       @PostMapping("/api")
       public String load_save(@RequestParam("date") String date, Model model){
           String result = "";
         
           try {
               String requestDate=date;
               URL url = new URL("http://openapi.seoul.go.kr:8088/" + "받은인증키/" +
                       "json/CardSubwayStatsNew/1/700/"+requestDate);
               BufferedReader bf;
               bf = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"));
               result = bf.readLine();
    
               JSONParser jsonParser = new JSONParser();
               JSONObject jsonObject = (JSONObject)jsonParser.parse(result);
               JSONObject CardSubwayStatsNew = (JSONObject)jsonObject.get("CardSubwayStatsNew");
               Long totalCount=(Long)CardSubwayStatsNew.get("list_total_count");
    
               JSONObject subResult = (JSONObject)CardSubwayStatsNew.get("RESULT");
               JSONArray infoArr = (JSONArray) CardSubwayStatsNew.get("row");
               
               for(int i=0;i<infoArr.size();i++){
                   JSONObject tmp = (JSONObject)infoArr.get(i);
                   SubstationInfo infoObj=new SubstationInfo(i+(long)1, (String)tmp.get("USE_DT"),(String)tmp.get("LINE_NUM"),(String)tmp.get("SUB_STA_NM"),
                           (double)tmp.get("RIDE_PASGR_NUM"), (double)tmp.get("ALIGHT_PASGR_NUM"),(String)tmp.get("WORK_DT"));
               }
    
           }catch(Exception e) {
               e.printStackTrace();   
           }
           return "redirect:/findname";
       }
    }

api 통신이 정상적이고 파싱도 잘 되었다면 for문 안에서 JSONObject를 출력해 봄으로써 정상적으로 json객체를 받아온 걸 확인할 수 있을 것이다. 다음 포스트에서 이 json객체를 DB에 저장해보겠다

1개의 댓글

comment-user-thumbnail
2022년 2월 9일

안녕하세요, 글 잘 봤습니다. 팀플에서 백엔드 담당하시는 분들이 올리신 포스트 내용을 보고 따라했는데 {"code":"INVALID_TOKEN", "message":"Invalid authorization header"}과 같은 에러가 발생한다고 하시더라구요. 혹시 CORS와 같은 보안 관련 설정을 프로젝트에 별도로 해주셨을까요?

답글 달기