Preface
이번 장에선 네이버의 검색 API를 활용하여 검색 결과를 출력하는 화면을 만들었다.
오픈 API를 활용하는 방법은 이미 유튜브에서 여러 번 접해서 익숙하지만,
자바스크립트와 jQeury Ajax를 사용하는 코드는 아직도 조금씩 헷갈린다.
1. API란?
- API(Application Programming Interface): 응용 프로그램 간에 상호 작용하기 위한 규칙과 기능을 제공하는 인터페이스
→ 소프트웨어 개발에서 다른 응용 프로그램이나 서비스와 상호 작용할 수 있도록 도와주는 중간 계층
- 오픈 API: 서비스를 제공하는 업체에서 외부 개발자가 자사 서비스의 기능을 간단히 호출해 이용할 수 있도록 공개해둔 API
1) 주로 HTTP 프로토콜로 통신한다.
2) 응답 데이터의 형태는 JSON 포맷을 주로 사용한다.
- 네이버 검색 API는 검색 결과를 XML이나 JSON으로 반환한다.
- JSON(JavaScript Object Notation): JS에서 객체나 배열을 만들 때 사용하는 표현 방식
→ 중괄호는 객체를, 대괄호는 배열을 뜻한다.
- JSON의 형식: 4가지의 기본 형식을 조합하여 사용할 수 있다.
1) '객체'는 키와 값으로 구분
{
"name" : "k-mozzi", "age" : 24, "address" : "Daejeon"
}
2) '배열'은 값만으로 구성
[
"Java". "Oracle", "HTML", "JSP"
]
3) 객체의 값으로 배열을 사용
{
"firstName" : "Must", "lastName" : "Have",
"Books" : ["JAVA", "JSP", "GO"]
}
4) 배열의 값으로 객체를 사용
[
{"City" : "서울", "HotPlace" : "이태원"},
{"City" : "부산", "HotPlace" : "해운대"},
{"City" : "대구", "HotPlace" : "삼덕동"},
]
2. 오픈 API 이용 신청
- '네이버 개발자센터'에 접속하여 'Products'에서 원하는 API를 클릭한 후 애플리케이션 등록을 완료하면 된다.
1) ClientID와 ClientSecret은 따로 메모해두는 것이 좋다.
2) '상세 설명'에서 해당 API에 대한 자세한 정보를 얻을 수 있다.
3) 요청 변수: 요청 URL에 쿼리스트링으로 덧붙일 수 있는 변수
3. 구현
- 검색 서블릿
→ API 예제의 main 메소드 코드는 service 메소드로 복사한 후 수정했고, 나머지 코드는 그대로 가져와 사용했다.
package api;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/NaverSearchAPI.do")
public class SearchAPI extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws SecurityException, IOException {
String clientId = ""; // 애플리케이션 클라이언트 아이디
String clientSecret = ""; // 애플리케이션 클라이언트 시크릿
int startNum = 0;
String text = null;
try {
startNum = Integer.parseInt(req.getParameter("startNum"));
String searchText = req.getParameter("keyword");
text = URLEncoder.encode(searchText, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("검색어 인코딩 실패", e);
}
String apiURL = "https://openapi.naver.com/v1/search/blog?query=" + text + "&display=10&start=" + startNum; // JSON
// 결과
// String apiURL = "https://openapi.naver.com/v1/search/blog.xml?query="+ text;
// // XML 결과
Map<String, String> requestHeaders = new HashMap<>();
requestHeaders.put("X-Naver-Client-Id", clientId);
requestHeaders.put("X-Naver-Client-Secret", clientSecret);
String responseBody = get(apiURL, requestHeaders);
System.out.println(responseBody);
resp.setContentType("text/html; charset=utf-8");
resp.getWriter().write(responseBody); // 서블릿에서 즉시 출력
}
private static String get(String apiUrl, Map<String, String> requestHeaders) {
HttpURLConnection con = connect(apiUrl);
try {
con.setRequestMethod("GET");
for (Map.Entry<String, String> header : requestHeaders.entrySet()) {
con.setRequestProperty(header.getKey(), header.getValue());
}
int responseCode = con.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) { // 정상 호출
return readBody(con.getInputStream());
} else { // 오류 발생
return readBody(con.getErrorStream());
}
} catch (IOException e) {
throw new RuntimeException("API 요청과 응답 실패", e);
} finally {
con.disconnect();
}
}
private static HttpURLConnection connect(String apiUrl) {
try {
URL url = new URL(apiUrl);
return (HttpURLConnection) url.openConnection();
} catch (MalformedURLException e) {
throw new RuntimeException("API URL이 잘못되었습니다. : " + apiUrl, e);
} catch (IOException e) {
throw new RuntimeException("연결이 실패했습니다. : " + apiUrl, e);
}
}
private static String readBody(InputStream body) {
InputStreamReader streamReader = new InputStreamReader(body);
try (BufferedReader lineReader = new BufferedReader(streamReader)) {
StringBuilder responseBody = new StringBuilder();
String line;
while ((line = lineReader.readLine()) != null) {
responseBody.append(line);
}
return responseBody.toString();
} catch (IOException e) {
throw new RuntimeException("API 응답을 읽는 데 실패했습니다.", e);
}
}
}
- 검색 화면 페이지
1) HTML, CSS, JS, JSP(jQuery Ajax)를 사용했다.
2) JS 코드에 있는 $.each( ) 메소드는 반복문을 생성하는 메소드이다.
1. DOM 요소를 선택한 후 반복 실행
$('선택자').each(function(index, item) { <!-- 선택한 요소의 반복 실행 문장 --> } <!-- 선택자: DOM 선택 후 반복 --> <!-- index: 반복 요소의 인덱스(0부터 시작) --> <!-- item: 반복 요소의 데이터 -->
2. 배열을 첫 번째 인수로 받아 반복 실행
$.each(배열, function(index, item)) { <!-- 선택한 요소의 반복 실행 문장 --> } <!-- index: 배열 요소의 인덱스(0부터 시작) --> <!-- item: 배열 요소의 데이터 -->
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>검색 API</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
// [검색 요청] 버튼 클릭 시 실행할 메서드를 정의합니다.
// HTML 문서의 로딩이 완료된 후에 내부의 코드가 실행되도록 하는 역할
$(function() {
$('#searchBtn').click(function() {
$.ajax({
url : "../../NaverSearchAPI.do", // 요청 URL
type : "get", // HTTP 메서드
data : { // 매개변수로 전달할 데이터
keyword : $('#keyword').val(), // 검색어
startNum : $('#startNum option:selected').val() // 검색 시작 위치
},
dataType : "json", // 응답 데이터 형식
success : sucFuncJson, // 요청 성공 시 호출할 메서드 설정
error : errFunc // 요청 실패 시 호출할 메서드 설정
});
});
});
// 검색 성공 시 결과를 화면에 뿌려줍니다.
function sucFuncJson(d) {
var str = "";
$.each(d.items, function(index, item) {
str += "<ul>";
str += " <li>" + (index + 1) + "</li>";
str += " <li>" + item.title + "</li>";
str += " <li>" + item.description + "</li>";
str += " <li>" + item.bloggername + "</li>";
str += " <li>" + item.bloggerlink + "</li>";
str += " <li>" + item.postdate + "</li>";
str += " <li><a href='" + item.link + "' target='_blank'>바로가기</a></li>";
str += "</ul>";
});
$('#searchResult').html(str);
}
// 실패 시 경고창을 띄워줍니다.
function errFunc(e) {
alert("실패: " + e.status);
}
</script>
<style>
ul{border:2px #cccccc solid;}
</style>
</head>
<body>
<div>
<div>
<form id="searchFrm">
한 페이지에 10개씩 출력됨 <br />
<select id="startNum">
<option value="1">1페이지</option>
<option value="11">2페이지</option>
<option value="21">3페이지</option>
<option value="31">4페이지</option>
<option value="41">5페이지</option>
</select>
<input type="text" id="keyword" placeholder="검색어를 입력하세요." />
<button type="button" id="searchBtn">검색 요청</button>
</form>
</div>
<div class="row" id="searchResult">
여기에 검색 결과가 출력됩니다.
</div>
</div>
</body>
</html>
'JSP > 성낙현의 JSP 자바 웹 프로그래밍' 카테고리의 다른 글
(Fin) 로컬 웹 서버에 배포하기 (0) | 2023.07.06 |
---|---|
SMTP를 활용한 메일 전송하기 (0) | 2023.07.05 |
웹소켓으로 채팅 프로그램 만들기 (0) | 2023.06.30 |
JSP, Oracle을 사용한 자료실형 게시판(MVC 패턴) (0) | 2023.06.29 |
서블릿(Servlet) (0) | 2023.06.26 |
댓글