멀티캠퍼스 백엔드 과정41일차[8월 2일] - 네이버 검색 api, ajax, jquery, spring과 협업의 중요

GoldenDusk·2023년 8월 2일
0

spring과 spring boot

spring과 spring boot는 같은 거나 spring boot는 환경설정이 더 편하다.

JQuery

1. 개념

  • 화면의 동적 기능을 자바스크립트보다 좀 더 쉽고 편리하게 개발할 수 있게 해주는 자바스크립트 기반 라이브러리

2. 특징

  • CSS 선택자를 사용해 각 HTML 태그에 접근해서 작업하므로 명료하면서도 읽기 쉬운 형태로 표현함
  • 메서드 체인 방식으로 수행하므로 [메서드들끼리 연결돼서 통신함]여러 개의 동작(기능)이 한 줄로 수행할 수 있음
  • 풍부한 플러그인을 제공하므로 이미 개발된 많은 플러그인을 쉽고 빠르게 이용할 수 있음
  • 크로스 브라우징을 제공하므로 브라우저 종류에 상관 없이 동일하게 기능을 수행함

3. 제이쿼리 사용 방법

  • www.jquery.com에서 다운로드해서 사용하는 방법
  • 네트워크로 CDN 호스트를 설정해서 사용하는 방법
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="http://code.jquery.com/jquerylatest.min.js"></script>

4. 제이쿼리의 여러 가지 기능

선택 종류선택자 표현 방법설명
All selector$("*")모든 DOM을 선택합니다.
ID selector$("#id")해당되는 id를 가지는 DOM을 선택합니다.
Element selector$("elementName")해당되는 이름을 가지는 DOM을 선택합니다
class selector$(".className")CSS 중 해당되는 클래스 이름을 가지는 DOM을 선택합니다.
Multiple selector$("selector1,selector2,
selector3, ...., selectorN")해당되는 선택자를 가지는 모든 DOM을 선택합니다.

5. 예제

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>jQuery1</title>
<script src="http://code.jquery.com/jquery-2.2.1.min.js"></script>
<script>
	$(document).ready(function(){ //document는 문서 객체, body부분을 말함, ready() : 기능을 구현, DOM 객체 로드되는 이벤트 처리 함수
		alert($("#unique2").html()); //$ 일부 태그만 가져와서 처리하고 싶다.
		
	});

</script>
</head>
<body>
<div class="class1">안녕하세요</div>
<div id="unique2">제이쿼리 입니다.</div>
<div id="unique3">
<p>제이쿼리 어렵지 않음!</p>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>jQuery2</title>
<script src="http://code.jquery.com/jquery-2.2.1.min.js"></script>
<script>
	function addHtml(){
		$("#article").html('안녕하세요. 오늘의 뉴스입니다.'+'<br/>');
	}
</script>
</head>
<body>
<div>
<p id="article"></p>
</div>
<input type="button" value="추가하기" onClick="addHtml()"/>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>jQuery3</title>
<script src="http://code.jquery.com/jquery-2.2.1.min.js"></script>
<script>
	function addImage(){
		$(".class1").html("<img src='../img/duke.png'>");
	}	
</script>
</head>
<body>
<div class="class1"></div>
<div class="class2"></div>
<input type="button" value="이미지 추가" onClick="addImage()" />
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>jQuery4</title>
<script src="http://code.jquery.com/jquery-2.2.1.min.js"></script>
<script>
	function addImage(){
		$("div").html("<img src='../img/duke.png'>");
	}	
</script>
</head>
<body>
<div></div>
<div></div>
<input type="button" value="이미지 추가" onClick="addImage()" />
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>jQuery5</title>
<script src="http://code.jquery.com/jquery-2.2.1.min.js"></script>
<script>
	function input_process(){
		let value = $("#in1").val(); //아이디 값으로 가지고 옴
		$("#result").val(value);
	}	
</script>
</head>
<body>
<input type="text" id="in1" size="10"/>
<input type="button" value="입력하기" onClick="input_process()"/>

<div>
결과 : <br />
<input type="text" id="result" disabled="disabled"/>
</div>
</body>
</html>

제이쿼리 Ajax 기능

1. Ajax 정의

  • Asynchronous Javascript(비동기 자바스크립트) + XML의 의미로 자바스크립트를 사용한 비동기 통신
  • 클라이언트와 서버 간의 XML이나 JSON 데이터를 주고받는 기술
  • 기존 웹 페이지의 동작 방식 : 요청 페이지=> 웹 서버 => 결과 페이지
  • ajax 웹 페이지 동작 기술 : 요청페이지=> XMLHttpRequsest => 웹 서버 => 요청 페이지로 반환

2. Ajax의 속성

속성설명
type통신 타입을 설정합니다(post 또는 get 방식으로 선택합니다).
url요청할 url을 설정합니다.
async비동기식으로 처리할지의 여부를 설정합니다(false인 경우 동기식으로 처리합니다).
data서버에 요청할 때 보낼 매개변수를 설정합니다.
dataType응답 받을 데이터 타입을 설정합니다(XML, TEXT, HTML, JSON 등).
success요청 및 응답에 성공했을 때 처리 구문을 설정합니다.
error요청 및 응답에 실패했을 때 처리 구문을 설정합니다.
complete모든 작업을 마친 후 처리 구문을 설정합니다.

3. 예제

  • html

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>ajax 연습1</title>
  <script  src="http://code.jquery.com/jquery-latest.min.js"></script>
  <script type="text/javascript">
      function fn_process(){
       $.ajax({
    	  type : "get",
    	  datatype : "text",
    	  async : false,
    	  url : "http://localhost:8090/jquery/AjaxTest1",
    	  data : {param : "Hello, jquery"},
    	  success : function(data, textStatus){
    		  $("#message").append(data);
    	  },
    	  error : function(data, textStatus){
    		  alert("서버와 통신 중 에러 발생");
    	  },
    	  complete : function(data, textStatus){
    		  alert("서버와의 통신 완료");
    	  }
    	   
       });
   }		
</script>
</head>
<body>
<input type="button" value="전송하기" onClick="fn_process()" /><br><br>
<div id="message"></div>
</body>
</html>
  • 서블릿

package ex01;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/AjaxTest1")
public class AjaxTest1 extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    public AjaxTest1() {
        super();
        // TODO Auto-generated constructor stub
    }

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doHandler(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doHandler(request, response);
	}

	private void doHandler(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		response.setContentType("text/html; charset=UTF-8");
		String param = (String)request.getParameter("param"); //객체타입으로 넘어 오기 때문에 형변환
		System.out.println("param = "+param);
		PrintWriter writer = response.getWriter();
		writer.print("안녕 난 난... ajax");
	}

}

4. 예제 2

  • java
package ex01;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/ajaxTest2")
public class AjaxTest2 extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    public AjaxTest2() {
        super();
        // TODO Auto-generated constructor stub
    }

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doHandler(request,response);
	}
		

	private void doHandler(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
		    
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html; charset=utf-8");
		String result ="";
		PrintWriter writer = response.getWriter();
		// CDATA 섹션은 " 파서가 마크업이 아닌 문자 데이터로만 해석하도록 표시된 요소 콘텐츠 섹션 " 
		result ="<main><book>"
				+ "<title><![CDATA[초보자를 위한 자바 프로그래밍]]></title>"
				+ "<writer><![CDATA[인포북스 저 | 이병승 ]]></writer>"
				+ "<image><![CDATA[http://localhost:8090/jquery/img/image1.jpg]]></image>"
				+ "</book>"
				+ "<book>"
				+ "<title><![CDATA[모두의 파이썬]]></title>"
				+ "<writer><![CDATA[길벗 저 | 이승찬 ]]></writer>"
				+ "<image><![CDATA[http://localhost:8090/jquery/img/image2.jpg]]></image>"
				+ "</book></main>";
		
		     System.out.println(result);
		     writer.print(result);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doHandler(request,response);
	}

}
  • html
<!DOCTYPE html>
<html>
<head>
   <meta charset="UTF-8">
   <title>도서 정보 출력창</title>
   <script  src="http://code.jquery.com/jquery-latest.min.js"></script>
   <script type="text/javascript">
      function fn_process(){
          $.ajax({
                  type :"post",   	  
        	      async:"false",
        	      url:"http://localhost:8090/jquery/ajaxTest2",
        	      dataType:"xml",
        	      success:function(info,textStatus){
        	    	  $(info).find("book").each(function(){
        	    		 let title = $(this).find("title").text();
        	    		 let writer = $(this).find("writer").text();
        	    		 var image=$(this).find("image").text();
       	              $("#bookInfo").append(
       	                  	"<p>" +title+ "</p>" +
       		                "<p>" +writer + "</p>"+
       	 	                "<img src="+image + "   />"				
       	              );
        	    	  });  	 //받은 것에서 book 태그를 찾음  	  
        	      },
        	      error: function(data,textStatus){
        	    	  alert("에러 발생");
        	      },
        	      complete: function(data,textStatus){
        	    	  alert("작업 완료");
        	      }
          }); 
     }
  </script>
</head>
<body>
<div id="bookInfo"></div>
<input type=button value="도서정보 요청"  onclick="fn_process()">
</body>
</html>

✋어제 안된 것과 참고하자

문제 상황

  • 어제 자꾸 오픈 API 하다가 서블릿 예외가 났다. 그래서 강사님이랑 오타 찾아보다가 서버문제 인것 같다고 강사님이 말하셔서 어제 하루종일 서버만 붙잡고 있었으나.. 문제를 찾지 못했다.
  • Servlet.service() 호출 예외, NumberFormatException이 남

해결 방안

  • 두 분이 도와주셨다. 협업의 이유를 알 것 같다.
  • 진짜 간단한 부분이었다. input type을 빼먹은 거…그리고 아래 부분 url startNum을 start로 되어 있어서 나는 문제였다.
String apiURL = "https://openapi.naver.com/v1/search/blog?query=" + text
+ "&display=10&startNum=" + startNum;

느낌점

  • 나는 NumberForException이 나길래 다른 곳만 들여다 봤는데… 이렇게 어제 삽질 하던 것을 알아 내다니… 이게 협업을 하는 이유구나 싶었다. 정말 감사한 마음 뿐...
  • 멋지다.. 나도 열심히 해야지 라는 생각이 들었다.

코드

  • java(서블릿)
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.ServletException;
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 ServletException, IOException {
        // 1. 인증 정보 설정
        String clientId = "네이버에서 발급 받은 거";
        String clientSecret = "네이버에서 발급 받은 거";

        // 2. 검색 조건 설정
        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);
        } 

        // 3. API URL 조합
        String apiURL = "https://openapi.naver.com/v1/search/blog?query=" + text
                        + "&display=10&startNum=" + startNum;  // json 결과
        //String apiURL = "https://openapi.naver.com/v1/search/blog.xml?query=" + text;  // xml 결과

        // 4. API 호출
        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);

        // 5. 결과 출력
        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);
        }
    }
}
  • jsp
<%@ 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>
// [검색요청] 버튼 클릭 시 실행할 메서드를 정의
$(function(){
	/* id라 # 
	1. 검색 요청 버튼(id=“searchBtn”)을 눌렀을 때 $.ajax 메서드를 호출하도록 정의 */
	$('#searchBtn').click(function(){ //function인 ajax을 예전에 form 태그에서 했던 action을 ajax로 함
		$.ajax({
			url : "NaverSearchAPI.do", //요청 URL
			type : "get", //HTTP 메서드
			data : { //data는 json형태로 묶어, 매개변수로 전달할 데이터
				keyword : $('#keyword').val(), //검색어, 값을 가져옴
				/* 선택된 옵션의 값을 가져와라 */
				startNum : $('#startNum option:selected').val() //검색 시작 위치
			},
			dataType : "json", //응답 데이터 형식
			success : sucFuncJson, //요청 성공 시 호출할 메서드 설정
			error : errFunc
		});	
	});	
});
/* 
검색 성공시 결과를 화면에 출력 */

function sucFuncJson(d){
	let str ="";
	$.each(d.items, function(index, item){ //each = resultset과 같다.
		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(request,status,error){
	   alert("code"+request.status+"\n"+"message"+request.responseText+"\n"+"error"+error);
}

</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="2">2페이지</option>
		<option value="3">3페이지</option>
		<option value="4">4페이지</option>
		<option value="5">5페이지</option>
		</select>
		<input type="text" id="keyword" placeholder="검색어를 입력하시오" />
		<input type ="button" id="searchBtn">검색요청</button>
		</form>	
	</div>
	
	<div>
	<div class="row" id="searchResult">
	결과값 출력
	</div>
	</div>
</div>
</body>
</html>

프레임워크 시작하기

프레임워크

프레임워크 정의

  • 어떤 것을 구성하는 구조 또는 뼈대
  • 소프트웨어적 의미로는 기능을 미리 클래스나 인터페이스 등으로 만들어 제공하는 반제품

프레임워크 장점

  • 일정한 기준에 따라 개발이 이루어지므로 개발 생산성과 품질이 보장된 애플리케이션을 개발할 수 있음
  • 개발 후 유지보수 및 기능의 확장성에서도 고품질 보장

스프링 프레임워크

  • 스프링 프레임워크(이하 스프링)는 자바 웹 애플리케이션 개발을 위한 오프 소스
    프레임워크
  • EJB(Enterprise Java Bean,엔터프라이즈 자바 빈즈)보다 가벼운 경량 프레임워크(lightWeight Framework)

컨테이너(Container)란?

  • 톰캣은 서블릿 컨테이너라고 부르는데, 그 이유는 톰캣을 실행하면 톰캣은 서블릿의 생성, 초기화, 서비스 실행, 소멸에 관한 모든 권한을 가지고 서블릿을 관리
  • 스프링은 애플리케이션에서 사용되는 여러 가지 빈(클래스 객체)을 개발자가 아닌 스프링이 권한을 가지고 직접 관리

스프링의 특징

  • EJB보다 가볍고 배우기도 쉬우며 경량 컨테이너의 기능을 수행
  • 제어 역행(IoC, Inversion of Control) 기술을 이용해 애플리케이션 갂의 느슨한
    결합을 제어함
  • 의존성 주입(DI, Dependency Injection) 기능을 지원함
  • 영속성과 관련된 다양한 서비스를 지원함
  • 수 많은 라이브러리와의 연동 기능을 지원함
  • POJO 방식 프레임워크

용어 정리

  • 의존성 주입: 클래스 객체를 개발자가 코드에서 생성하지 않고 프레임워크가 생성하여 사용하는 방법
  • 제어 역행: 서블릿이나 빈 등을 개발자가 코드에서 생성하지 않고 프레임워크가 직접 수행하는 방법
  • 관점 지향: 핵심 기능 외 부수 기능들을 분리 구현함으로써 모듈성을 증가시키는 방법

스프링의 주요 기능

스프링 기능설명
Core다른 기능과 설정을 분리하기 위한 IoC 기능을 제공합니다.
Context스프링의 기본 기능으로서 애플리케이션의 각 기능을 하는 빈(Bean)에대한 접근 방법을 제공합니다.
DAOJDBC 기능을 좀 더 편리하게 사용할 수 있도록 합니다.
ORM하이버네이트나 마이바티스 같은 영속성 관련 프레임워크와 연동된 기능을 제공합니다
AOP관점 지향 기능을 제공합니다
Web웹 애플리케이션 개발에 필요한 기능을 제공합니다
WebMVC스프링에서 MVC 구현에 관련된 기능을 제공합니다

회고

사실 별거 아닌걸로 틀려서 부끄러운 마음도 컸다.. 근데 에러 메세지를 보는 방법이라던지 주의사항 같은 걸 알게 되니 부끄럽더라도 공유하고 알고 넘어가는것이 중요한 것 같다.

트위터에서도 봤는데 다른 사람한테 물어보기 부끄러워서 혼자 끙끙 앓다가 나중에는 그냥 타임리밋 걸어두고 안되면 다른 사람한테 물어봄으로 인해 일의 효율이 올라가서 나중에 1주일 휴가쓰고 그랬다고 한다.

부끄럽고 물어보기 무서워도 물어보는 거를 두려워하지 말자!!!

profile
내 지식을 기록하여, 다른 사람들과 공유하여 함께 발전하는 사람이 되고 싶다. 참고로 워드프레스는 아직 수정중

0개의 댓글