[Spring] HttpURLConnection을 이용한 API 연동 방법

2021-09-26


Photo by eberhard 🖐 grossgasteiger on Unsplash

오늘은 오픈 API를 연동하는 과정을 알아보도록 하자. 예제는 https://open.assembly.go.kr/portal/openapi/main.do를 활용해서 진행할 예정이며, 가이드라인도 열린 국회 정보 API를 따른다.


- 예제

 

먼저 아래는 View를 구성하는 jsp 화면이다. api 연동으로 얻어진 정보를 openInfo라는 하나의 객체로 담아 간단히 나타낼 것이기 때문에 매우 간단하다.

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html>
<head>

<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>얻어온 Open API 정보</h3>

<p>${openInfo }</p>

<a href="/goods/goodsSearch"><button type="button">API화면</button></a>
</body>
</html>

아래는 api 정보를 받아올 dto 객체이다.

package com.test.test.dto;

public class ApiDto {
	private String billId;
	private String billNo;
	private String billName;
	private String committee;
	private String proposeDt;
	private String procResult;
	private String age;
	private String detailLink;
	private String proposer;
	private String memberList;
	private String rstProposer;
	private String publProposer;
	private String committeeId;
	public String getBillId() {
		return billId;
	}
	public void setBillId(String billId) {
		this.billId = billId;
	}
	public String getBillNo() {
		return billNo;
	}
	public void setBillNo(String billNo) {
		this.billNo = billNo;
	}
	public String getBillName() {
		return billName;
	}
	public void setBillName(String billName) {
		this.billName = billName;
	}
	public String getCommittee() {
		return committee;
	}
	public void setCommittee(String committee) {
		this.committee = committee;
	}
	public String getProposeDt() {
		return proposeDt;
	}
	public void setProposeDt(String proposeDt) {
		this.proposeDt = proposeDt;
	}
	public String getProcResult() {
		return procResult;
	}
	public void setProcResult(String procResult) {
		this.procResult = procResult;
	}
	public String getAge() {
		return age;
	}
	public void setAge(String age) {
		this.age = age;
	}
	public String getDetailLink() {
		return detailLink;
	}
	public void setDetailLink(String detailLink) {
		this.detailLink = detailLink;
	}
	public String getProposer() {
		return proposer;
	}
	public void setProposer(String proposer) {
		this.proposer = proposer;
	}
	public String getMemberList() {
		return memberList;
	}
	public void setMemberList(String memberList) {
		this.memberList = memberList;
	}
	public String getRstProposer() {
		return rstProposer;
	}
	public void setRstProposer(String rstProposer) {
		this.rstProposer = rstProposer;
	}
	public String getPublProposer() {
		return publProposer;
	}
	public void setPublProposer(String publProposer) {
		this.publProposer = publProposer;
	}
	public String getCommitteeId() {
		return committeeId;
	}
	public void setCommitteeId(String committeeId) {
		this.committeeId = committeeId;
	}
	@Override
	public String toString() {
		return "ApiDto [billId=" + billId + ", billNo=" + billNo + ", billName=" + billName + ", committee=" + committee
				+ ", proposeDt=" + proposeDt + ", procResult=" + procResult + ", age=" + age + ", detailLink="
				+ detailLink + ", proposer=" + proposer + ", memberList=" + memberList + ", rstProposer=" + rstProposer
				+ ", publProposer=" + publProposer + ", committeeId=" + committeeId + "]";
	}
	
	
}

다음은 openapi를 실제 연동하기 위한 controller 이다. outputstream으로 body에 파라미터를 정보를 보내려고 했으나 응답을 받아오지 않아 url에 직접 파라미터 정보를 넣어서 구현하였다.

 

일단은 API 연동은  https://open.assembly.go.kr/portal/data/service/selectAPIServicePage.do/OK7XM1000938DS17215

 

위의 국회의원 발의법률안 을 기준으로 진행하였다. 어떤 API를 사용하냐에 따라 DTO 및 url , 파라미터 정보가 달라질 수 있다.

 

package com.test.test.controller;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import javax.servlet.http.HttpServletRequest;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import com.test.test.dto.ApiDto;

@Controller
public class OpenApi {
	
	
	// 로거 객체
	private static final Logger logger = LoggerFactory.getLogger(OpenApi.class);
	

	@GetMapping(value="/openApi/result")
	public void openApiRes(HttpServletRequest request, Model model) {
		
		String age = request.getParameter("age");
		
		if(age == null) {
			age = "10";
		}
		
		//자신이 선택한 API 종류에 따라 달라지는 부분
		String strUrl = "https://open.assembly.go.kr/portal/openapi/자신이 선택한 API 주소"
				+ "?Key=자신이 전달받은 키정보"
				+ "&Type=json"
				+ "&pIndex=1"
				+ "&pSize=100"
				+ "&AGE=" + age;
		
		String line = "";
		String data = "";
		
		try {
			URL url = new URL(strUrl);
			HttpURLConnection con = (HttpURLConnection) url.openConnection();
			con.setConnectTimeout(5000); //서버에 연결되는 Timeout 시간 설정
			con.setReadTimeout(5000); // InputStream 읽어 오는 Timeout 시간 설정
			con.setRequestMethod("POST");
			con.setDefaultUseCaches(false);
			con.setDoInput(true);
			con.setDoOutput(true);	
			con.setRequestProperty("content-type", "application/x-www-form-urlencoded");

			StringBuilder sb = new StringBuilder();
			if (con.getResponseCode() == HttpURLConnection.HTTP_OK) {
				System.out.println("--공용 API 사이트 연결 성공 --");
				BufferedReader br = new BufferedReader(
						new InputStreamReader(con.getInputStream(), "utf-8"));

				while ((line = br.readLine()) != null) {
					sb.append(line).append("\n");
				}
				br.close();
				data = sb.toString(); // 최종 데이터 저장
				JSONParser jsonParser = new JSONParser();
				JSONObject jsonObject = (JSONObject) jsonParser.parse(data);
				JSONArray allList = (JSONArray) jsonObject.get("nzmimeepazxkubdpn");
				JSONObject jsonObject2 = (JSONObject) allList.get(1);
				for(int i =0; i < allList.size(); i++) {
					System.out.println("json all 정보 -> " + allList.get(i));	
				}
				System.out.println();
				System.out.println("json Object2 정보 : " + jsonObject2);
				JSONArray rowList = (JSONArray) jsonObject2.get("row");
				for(int i =0; i < rowList.size(); i++) {
					ApiDto apiDto = new ApiDto();
					JSONObject tempJson = (JSONObject) rowList.get(i);	
					apiDto.setBillName((String)tempJson.get("BILL_NAME"));
					apiDto.setAge((String)tempJson.get("AGE"));
					apiDto.setBillId((String)tempJson.get("BILL_ID"));
					apiDto.setBillNo((String)tempJson.get("BILL_No"));
					System.out.println(apiDto);
				}
				
				
				
				System.out.println();
				
				System.out.println("저장된 데이터 -> " + sb.toString());
			} else {
				System.out.println("응답메시지 ->  "+con.getResponseMessage());
			}
		} catch (Exception e){
			System.err.println("예외발생 ->  "+e.toString());
		}

		System.out.println("받은 정보 : " + data);
		model.addAttribute("openInfo", data);
		
	}
	
}

 

기본적으로 XML 형태와 json 형태의 리턴 값을 지원하는데, 보통은 json 빠르고 데이터 효율이 좋기 때문에 json을 많이 사용한다.


메인 이미지 출처 :Photo by eberhard 🖐 grossgasteiger on Unsplash