[웹 풀스택] 부스트코스 - 웹 프로그래밍 - 2. DB 연결 웹 앱

June·2021년 7월 16일
0

1. JavaScript - FE

1) 자바스크립트 변수 - 연산자 - 타입

브라우저마다 자바스크립트 실행 엔진이 있다.

변수

연산자

여기에 or 연산자가 사용되고 있는데 name이 있으면 name이 result에 들어가고 없으면 "codesquad"가 들어간다.

const는 한번 할당하고나면 변경이 안된다.

연산자 삼항 연산자

연산자 - 비교연산자

"==="는 정확히 타입까지 비교한다.
"=="는 타입을 상관하지 않고 비교한다.

자바스크립트의 Type

function run(a) {
  console.log(typeof a);
}

run("asdf")

정적 언어와 동적언어

2) 자바스크립트 비교-반복-문자열

비교문

삼항 연산자

var a = "";
var result = (a) ? "ok" : "not ok";
console.log(result);

반복

var arr = [1,2,3];
for(var i = 0, len = arr.length; i < len; i++) {
  ..
}

문자열 처리

문자열 뒤에 '.'을 붙여서 메소드를 쓸 수 있는 이유는 문자열이 객체로 변하기 때문이다.

3) 자바스크립트 함수-1

함수 - 함수의 선언

function printName(firstname) {
  var myname = "jisu";
  return "name is " + firstname;
}

console.log(printName());

name is undefined가 출력된다. 실제로 내부적으로 undefined가 할당이 된 것이다.

인자가 더 많아도 오류가 안난다. 인자가 많으면 처음것만 파라미터로 받는다.

함수 - 함수표현식

function printName(firstname) {

    var inner = function() {
        return "inner value";
    }
    var result = inner();
    console.log("name is " + result);
}

printName();

위에처럼 변수에 넣을 수도 있고 아래처럼 할 수도 있다.

function printName(firstname) {
    var result = inner();
    console.log("name is " + result);
  
    function inner() {
        return "inner value";
    }
}

printName();

함수식과 호이스팅

함수 - 반환값과 undefined

3) 자바스크립트 함수-2

함수 - arguments 속성

function a() {
    if (arguments.length < 3) return;
    console.log('my name is ', arguments[2]);
}

a(1, 2, "jisu");

좀더 알아볼 것 - arrow function

4) 자바스크립트 함수 호출 스택

함수 호출

WEB UI 개발 - FE

1) window 객체(setTimeout)

window 객체

setTimeout은 비동기 특성을 가진다.

setTimeout 활용

함수의 인자로 함수를 받고 있다.

function run() { 
    console.log("run start");

    setTimeout(function() {
        var msg = "hello codesquad";
        console.log(msg);
        console.log("run ....ing");
    }, 2000);
    console.log("run end");
}

run();

실행결과
run start
run end
hello codesquad
run ....ing

function run() { 
    setTimeout(function() {
        var msg = "hello codesquad";
        console.log(msg);
        console.log("run ....ing");
    }, 2000);
}
console.log("run start");
run();
console.log("run end");

실행결과
run start
run end
hello codesquad
run ....ing

function run() { 
    setTimeout(function() {
        var msg = "hello codesquad";
        console.log(msg);
    }, 2000);
    console.log("run function end");
}
console.log("run start");
run();
console.log("run end");

실행결과
run start
run function end
run end
hello codesquad

이것이 비동기 콜백함수인데, 스택이 비워지고 나서 마지막에 실행되는 것이다. 즉 run()이 실행되고 나서 function()이 실행되는 것이다. function()은 event queue에 저장되어있다.

DOM과 querySelector

DOM

getElementById()

Element.querySelector()

3) Browser Event, Event object, Event handler

Event

이벤트 등록

<html>
    <header></header>
    <body>
        <div class="outside">outside element</div>
    </body>
    <script src="lecture.js"></script>
</html>

lecture.js

var el = document.querySelector(".outside")

el.addEventListener("click", function(e) {
    console.log("clicked!!", e);
    var target = e.target;
    console.log(target.className, target.nodeName);
})

event 리스너를 통해서 객체에 대한 정보도 얻을 수 있다.

4) Ajax통신의 이해

AJAX

비동기로 서버로부터 데이터를 가져올 때 사용된다. 새로 고침 없이 페이지의 일부분만 데이터를 받아올 수도 있다.

JSON

AJAX 실행 코드

순서상 ajax 함수에서 open과 send 가 실행되고 그 다음 function()이 "load"가 실행될때 실행된다.

5) JavaScript Debugging

JSP - BE

1) JSP란?

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<%
	int total = 0;
	for (int i = 1; i <= 10; i++) {
		total +=  i;
	}
%>

1부터 10까지의 합: <%=total %>
</body>
</html>

<% %>는 선언부이다.
<% %>는 실제로 보이지는 않는다. 서블릿에서 PrintWriter의 print()와 같은 효과를 내는 부분은 <%= %>이다.

JSP는 결국 내부적으로 서블릿으로 전환되는 것이 포인트이다.

JSP 등장 배경

2) JSP 라이프싸이클

C:\Users\User\eclipse-workspace.metadata.plugins\org.eclipse.wst.server.core\tmp0\work\Catalina\localhost\firstweb\org\apache\jsp\jsp
sum10_jsp.java

      response.setContentType("text/html; charset=UTF-8");
      pageContext = _jspxFactory.getPageContext(this, request, response,
      			null, true, 8192, true);
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;

      out.write("\r\n");
      out.write("<!DOCTYPE html>\r\n");
      out.write("<html>\r\n");
      out.write("<head>\r\n");
      out.write("<meta charset=\"UTF-8\">\r\n");
      out.write("<title>Insert title here</title>\r\n");
      out.write("</head>\r\n");
      out.write("<body>\r\n");
      out.write("\r\n");

	int total = 0;
	for (int i = 1; i <= 10; i++) {
		total +=  i;
	}

      out.write("\r\n");
      out.write("\r\n");
      out.write("1부터 10까지의 합: ");
      out.print(total );
      out.write("\r\n");
      out.write("</body>\r\n");
      out.write("</html>");

실제로 내부적으로 서블릿으로 바뀌어져있는 것을 알 수 있다.

sum10.jsp가 실행될 때 벌어지는 일

JSP의 실행순서

최초로 요청했을 때만 클래스를 생성한다. 존재하면 서블릿 컨테이너에서 주고 그렇지 않으면 생성한다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
hello~~
<%
	System.out.print("jspService()");
%>

<%!
	public void jspInit() {
	    System.out.print("jspInit()");
    }
%>

<%!
	public void jspDestroy() {
	    System.out.print("jspDestroy()");
    }
%>
</body>
</html>

내부적으로 변경된 자바코드를 보면 작성한 코드는 다 service()메소드 내에서 실행된다. 만약 선언을 <%! %>로 하면 메서드나 필드를 선언할 수 있는데 이때 service 메소드가 아닌 밖에 생성된다

코드 변경이 일어나면 Destroy()가 호출되어서 다시 생성된다.

3) JSP 문법

스크립트 요소의 이해

선언문

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
id: <%=getId() %>
<%!
	String id = "u00l"; //멤버변수 선언
	public String getId() { //메소드 선언
		return id;
	}
%>
</body>
</html>

선언문을 사용하면 servlet으로 전환됐을 때 service메서드가 아닌 클래스 바디에 생성된다.

스크립트릿(Scriptlet)

스크립트릿 안에서 선언되는 변수는 service 메소드 안에서 선언되는 것이므로 지역변수이다.

exam2.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
	for (int i = 1; i <= 5; i++) {
%>
<H<%=i %>>아름다운 한글</H<%=i %>>
<%
	}
%>
</body>
</html>

표현식(Expression)

주석(Comment)

jsp의 주석은 아예 서블릿으로 바뀌지 않는다.
자바 주석은 자바로는 바뀌나 실행이 되지 않고
html 주석은 자바로 바뀌고 실행도되나 브라우저에서 주석으로 인지해서 안보여주는 것이다.

exam3.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%-- jsp 주석입니다!!
	여러줄로 사용 가능합니다
 --%>
 <!-- html 주석입니다 -->
<%
	// 자바 주석입니다
	for (int i = 1; i <= 5; i++) {
%>
<H<%=i %>>아름다운 한글</H<%=i %>>
<%
	}
%>
</body>
</html>

4) JSP 내장객체

JSP 내장 객체란?

내장객체 종류

ImplicitObjects.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
	StringBuffer url = request.getRequestURL();

	out.print("url: " + url.toString());
	out.print("<br>");
%>
</body>
</html>

request 같은 것들을 선언하지 않았어도 바로 사용할 수 있는 이유는 내장객체이기 때문인데, 서블릿 코드를 보면 service 메소드 위에서 선언되어있다.

redirect & forward - BE

1) redirect

리다이렉트(redirect)

redirect01.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<% 
	response.sendRedirect("redirect02.jsp");
%>

redirect02.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	redirect된 페이지 입니다 ^^
</body>
</html>

브라우저에서 리아티렉트 확인

예제 동작 설명

WAS를 벗어나서 클라이언트에게 응답을 주고 다시 다른 곳으로 클라이언트가 요청을 하는 것이다. 즉 요청을 두 번 보내는 것이다.

2) forward

forward란?

리다이렉트랑 달리 클라이언트의 입장에서는 어떻게 요청이 처리되는지 알 필요가 없다. 리다이렉트랑 달리 url이 변경되지 않는다. forward 같은 경우는 request와 response가 하나씩만 만들어지지만 redirect는 두 개씩 만들어진다.

forward에서 request와 response를 하나만 사용하기 때문에 Servlet1은 요청을 처리하고 HttpServletRequest에 저장한다.

FrontServlet.java

package examples;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
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("/front")
public class FrontServlet extends HttpServlet {
       
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		int diceValue = (int)(Math.random() *  6) + 1;
		request.setAttribute("dice", diceValue);
		
		RequestDispatcher requestDispatcher = request.getRequestDispatcher("/next");
		requestDispatcher.forward(request, response);
		
	}
}

request.setAttribute의 인자값으로 처음 키는 String이 들어가지만 뒤의 값에는 Object가 들어간다. 그래서 나중에 꺼낼때 캐스팅해줘야 한다.

NextServlet.java

@WebServlet("/next")
public class NextServlet extends HttpServlet {
       
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html");
		PrintWriter htmlPrintWriter = response.getWriter();
		htmlPrintWriter.println("<html>");
		htmlPrintWriter.println("<head><title></title></haed>");
		htmlPrintWriter.println("<body>");
		
		int dice = (Integer)request.getAttribute("dice");
		htmlPrintWriter.println("dice : " + dice);
		for(int i = 0 ; i < dice; i++) {
			htmlPrintWriter.print("hello</br>");
		}
		htmlPrintWriter.println("</body>");
		htmlPrintWriter.println("</html>");		
	}
}

실제 url에 전혀 변경이 없다.

3) servlet & jsp 연동

Servlet과 JSP 연동

각각의 장점을 살려 Servlet에서 로직을, 그 결과를 JSP에게 포워딩한다

LogicServlet.java

package examples;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
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("/logic")
public class LogicServlet extends HttpServlet {

	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		int v1 = (int)(Math.random() * 100) + 1;
		int v2 = (int)(Math.random() * 100) + 1;
		int result = v1 + v2;
		
		request.setAttribute("v1", v1);
		request.setAttribute("v2", v2);
		request.setAttribute("result", result);
		
		RequestDispatcher rd = request.getRequestDispatcher("/jsp/result.jsp");
		rd.forward(request, response);
	}
}

result.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
	int v1 = (int)request.getAttribute("v1");
	int v2 = (int)request.getAttribute("v2");
	int result = (int)request.getAttribute("result");
%>
<%=v1 %> + <%=v2 %> = <%=result %>
</body>
</html>

forward기 때문에 실제 요청은 서블릿이 받았고, 요청을 출력결과를 만들어내는 것이 무엇이든 알 필요가 없다. 그래서 url이 바뀌지 않는다.

하지만 jsp에 자바 코드가 많이 섞여 있으니 헷갈린다. 최대한 분리하기 위해 사용하는 것이 el, jstl이다. 나중에 나온다.

scope - BE

1) scope란?

  • page scope은 선언된 페이지 내에서만 쓸 수 있다.
  • request scope은 클라이언트로부터 하나의 요청을 받아서 응답을 보낼 때 까지 쓸 수 있는 스코프이다. forward할 때 스코프가 같았다.
  • Session 스코프는 세션이 생겨서 세션이 소멸될 때 까지이다. 그래서 여러 개의 요청을 받아도 유지된다.
  • Application은 어플리케이션이 작동하는 동안의 범위다.

2) page scope

Page scope

foward가 되면 page가 달라지므로 page scope가 달라진다. 그래서 지역 변수와 거의 비슷하므로 변수를 생성해서 쓰는 것과 비슷하다.

3) request scope

모든 요청이 들어올 때 WAS는 request, response라는 객체를 만들고, 서비스 메소드에 인자로 넘겨준다. 다른 서블릿이나 jsp에서 이용가능하도록 범위를 지정해준다. 요청이 들어와서 응답이 나갈때까지 유지가 된다.

4) session scope

클라이언트는 브라우저인데, 클라이언트마다 관리를 하는 것이 session이다. 웹브라우저의 탭간에는 세션정보가 공유된다.

세션은 요청이 들어오고 나가도 사라지지 않는다. 클라이언트마다 생성되고 유지된다.

5) application scope - 1

Application Scope

서버에는 application이 여러개 있을 수 있다. 우리가 이때까지 진행한 프로젝트 하나하나가 웹 어플리케이션이다. (firstweb, exam31, exam25 ...)

어플리케이션 스코프는 어플리케이션 당 하나만 생성되는 것이다. 어떤 클라이언트가 접근해도 하나에 접근하는 것이다. 따라서 모든 클라이언트가 공통으로 사용해야할 값들이 있을때만 사용한다.

5) application scope-2

ApplicationScope01.java

@WebServlet("/ApplicationScope01")
public class ApplicationScope01 extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html; charset=UTF-8");
		
		PrintWriter htmlPrintWriter = response.getWriter();
		
		ServletContext application = getServletContext();
		int value = 1;
		application.setAttribute("value", value);
		
		htmlPrintWriter.println("<h1>value: " + value + "</h1>");
	}
}

ApplicationScope02.java

@WebServlet("/ApplicationScope02")
public class ApplicationScope02 extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html; charset=UTF-8");
		
		PrintWriter htmlPrintWriter = response.getWriter();
		
		ServletContext application = getServletContext();
		try {
			int value = (int)application.getAttribute("value");
			value++;
			application.setAttribute("value", value);
			
			htmlPrintWriter.println("<h1>value: " + value + "</h1>");
		} catch (NullPointerException e) {
			htmlPrintWriter.print("value의 값이 설정되지 않았습니다.");
		}
	}
}
``` html
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
	try {
		int value = (int)application.getAttribute("value");
		value = value + 2;
		application.setAttribute("value", value);
%>
	<h1><%=value %></h1>
<%
	}catch(NullPointerException ex) {
%>
	<h1>설정된 값이 없습니다.</h1>
<%
	}
%>
</body>
</html>

6. JSTL & EL - BE

1) EL(Expression Language)-1

표현 언어란

앞의 jsp에는 자바 코드와 html이 다 섞여있었다. 이를 보완하기 위해서 사용된다.

표현 언어의 표현 방법

표현언어의 기본 객체

표현 언어의 기본 객체 사용 예

자바코드보다 더 심플하게 사용되고 있는 것을 알 수 있다.

표현 언어의 데이터 타입

객체 접근 규칙

표현 언어의 수치 연산자

비교 연산자

html 태그와 섞이지 않게 비교연산자들을 영어로 표현

논리연산자

empty 연산자, 비교선택 연산자

연산자 우선 순위

표현 언어 비활성화: JSP에 병시하기

1) EL(Expression Language)-2

el01.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<%
	pageContext.setAttribute("p1", "page scope value");
	request.setAttribute("r1", "request scope value");
	session.setAttribute("s1", "session scope value");
	application.setAttribute("a1", "application scope value");
%>

<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
pageContext.getAttribute("p1") : <%=pageContext.getAttribute("p1") %>
pageContext.getAttribute("p1") : ${pageScope.p1}<br>
request.getAttribute("r1") : ${requestScope.r1}<br>
session.getAttribute("s1") : ${sessionScope.s1}<br>
application.getAttribute("a1") : ${applicationScope.a1}<br>

pageContext.getAttribute("p1") : ${p1}<br>
request.getAttribute("r1") : ${r1}<br>
session.getAttribute("s1") : ${s1}<br>
application.getAttribute("a1") : ${a1}<br>

</body>
</html>

body에서 첫줄은 jsp코드를 이용한 것이다.
그 밑에 줄들은 각 스코프에 맞게 선언한 변수들을 꺼내는 코드다.

맨 밑의 단락은 만약 겹치지 않는다면 저렇게 간편하게 쓸 수도 있다는 것을 나타내는 것이다.

1) EL(Expression Language)-3

el02.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<% 
request.setAttribute("k", 10); 
request.setAttribute("m", true); 
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
b: ${k } <br>
k + 5 : ${k + 5} <br>
k - 5 : ${k - 5} <br>
k * 5 : ${k * 5} <br>
k / 5 : ${k div 5} <br>

k : ${k } <br>
m : ${m } <br>

k > 5: ${k > 5 } <br>
k < 5: ${k < 5 } <br>
k <= 10: ${k <= 10 } <br>
k >= 10: ${k >= 10 } <br>
m : ${m } <br>
!m: ${!m } <br>
</body>
</html>

만약 el을 사용하기 싫으면 <%@ page isELIgnored = "true" %> 를 써야한다.

2) JSTL(JSP Standard Tag Library)-1

JSTL이란?

기존에는 스크립트릿의 자바코드와 html 코드가 섞여있어서 프론트 개발자가 유지보수하기 어려웠다. 이 문제를 해결하기 위해 JSTL이 등장하였다.

JSTL을 사용하려면?

JSTL이 제공하는 태그이 종류

코어 태그

코어태그: 변수 지원 태그 - set, remove

jstl01.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 
<c:set var="value1" scope="request" value="kang"/>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>:" ${value1 } <br>
<c:remove var="value1" scope="request"/>:" ${value1 } <br>
</body>
</html>

2) JSTL(JSP Standard Tag Library)-2

코어태그: 변수 지원 태그 - 프로퍼티 , 맵의 처리

실제 코드가 실행될 때 setPropertyName()이 실행된다. 그래서 이름을 지켜줘야한다.

코어 태그: 흐름제어 태그 - if

jstl02.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 
<%--
	<%
		request.setAttribute("n", 10);
	%>
--%>
<c:set var="n" scope="request" value="10"/>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<c:if test="${n == 0}">
	n과 0은 같습니다.
</c:if>
<c:if test="${n == 10}">
	n과 10은 같습니다.
</c:if>
</body>
</html>

코어 태그: 흐름제어 태그 - choose

jsl03.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
	request.setAttribute("score", 83);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<c:choose>
    <c:when test="${score >=90 }">
    A학점입니다.
    </c:when>
    <c:when test="${score >=80 }">
    B학점입니다.
    </c:when>
    <c:when test="${score >=70 }">
    C학점입니다.
    </c:when>
    <c:when test="${score >=60 }">
    D학점입니다.
    </c:when>
    <c:otherwise>
    F학점입니다.
    </c:otherwise>            
</c:choose>
</body>
</html>

2) JSTL(JSP Standard Tag Library)-3

코어 태그: 흐름제어 태그 - forEach

jstl04.jsp

<%@page import="java.util.ArrayList"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
	List<String> list = new ArrayList<>();
	list.add("hello");
	list.add("world");
	list.add("!!!!");
	
	request.setAttribute("list", list);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<c:forEach items= "${list }" var ="item" begin="1">
	${item } <br>
</c:forEach>
</html>

코어 태그: 흐름제어 태그 - import

jstlValue.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
kang kyungmi

jstl05.jsp

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

<c:import url="http://localhost:8080/firstweb/jsp/jstlValue.jsp" var="urlValue" scope="request"/>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
${urlValue }
</body>
</html>

2) JSTL(JSP Standard Tag Library)-4

코어 태그: 흐름제어 태그 - redirect

jstl06.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:redirect url="http://localhost:8080/firstweb/jsp/jstl05.jsp"></c:redirect>>

코어 태그: 기타 태그 - out

jstl07.jsp

<%@ 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="fn" uri="http://java.sun.com/jsp/jstl/functions"%> 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<c:set var="t" value="<script type='text/javascript'>alert(1);</script>" />
${t}
<c:out value="${t}" escapeXml="true" />
<c:out value="${t}" escapeXml="false" />
</body>
</html>

escapeXml = true이면 그냥 문자그대로 출력된다.

7. MySQL - BE

1) intro

데이터베이스의 기본개념 (정의)

데이터베이스의 특성

데이터 베이스 관리 시스템

데이터 베이스 관리 시스템 장/단점

2) MySQL 다운로드 및 설치

https://downloads.mysql.com/archives/installer/

나머지는 똑같다

3) MySQL 실행

4) MySQL 종료

8. SQL - BE

1) SQL이란?-1

SQL(Structured Query Language) 1/2

SQL(Structured Query Language) 2/2

Database 생성하기 1/3

Database 생성하기 3/3

Database 사용자 생성과 권한 주기 1/3

Database 사용자 생성과 권한 주기 2/3

mysql> grant all privileges on connectdb.* to connectuser @'%' identified by 'connect123!@#';
Query OK, 0 rows affected (0.04 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.03 sec)

생성한 Database에 접속하기 1/2

MySQL 연결끊기

MySQL 버전과 현재 날짜 구하기

키워드는 대소문자를 구별하지 않는다.

쿼리를 이용해서 계산식의 결과도 구할 수 있다.

여러 문장을 한 줄에 연속으로 붙여서 실행가능하다

하나의 SQL은 여러 줄로 입력가능하다

SQL을 입력하는 도중에 취소할 수 있다.

DBMS에 존재하는 데이터베이스 확인하기

사용중인 데이터베이스 전환하기

1) SQL이란?-2

테이블(table)의 구성 요소

현재 데이터베이스에 존재하는 테이블 목록 확인하기

SQL 연습을 위한 테이블 생성과 값의 저장 1/3

data>mysql -uconnectuser -p connectdb < examples.sql

2) DML(select, insert, update, delete)-1

데이터 조작어의 오류

2) DML(select, insert, update, delete)-2

SELECT 구문 예제 (특정 행 검색 - where 절)

와일드카드

UCASE, UPPER

LCASE, LOWER

substring

시작 인덱스가 1번부터인 것에 유의하자

LPAD, RPAD

2) DML(select, insert, update, delete)-3

SELECT 구문 (CAST 형변환)

SELECT 구문 (그룹함수)

SELECT 구문 예제 (그룹함수와 groupby절)

2) DML(select, insert, update, delete)-4

데이터 입력 (INSERT 문)

데이터 입력 (UPDATE 문)

데이터 삭제 (DELETE 문)

3) DDL(create, drop)

MySQL 데이터 타입

테이블 생성

CREATE TABLE EMPLOYEE2(   
            empno      INTEGER NOT NULL PRIMARY KEY,  
           name       VARCHAR(10),   
           job        VARCHAR(9),   
           boss       INTEGER,   
           hiredate   VARCHAR(12),   
           salary     DECIMAL(7, 2),   
           comm       DECIMAL(7, 2),   
          deptno     INTEGER);

테이블 수정 (컬럼 추가 / 삭제)

alter table 테이블명
          add  필드명 타입 [NULL | NOT NULL][DEFAULT ][AUTO_INCREMENT];

alter table 테이블명
         drop  필드명;

테이블 수정

실습 – EMPLOYEE2 테이블에 생일(birthdate)칼럼을 varchar(12)형식으로 추가하시오.

alter table EMPLOYEE2

add birthdate varchar(12);

테이블 이름 변경

alter table 테이블명 rename 변경이름

테이블 삭제하기

9. Maven - BE

1) Maven 이란?

앞에서 JSTL에 대해서 배울 때 JSTL과 관련된 라이브러리를 다운로드 하여, WEB-INF/lib폴더에 복사하여 설치했었습니다. 프로젝트가 복잡해질수록 사용하는 라이브러리가 많아지게 됩니다.

프로젝트에 참여하는 사용자가 많아질수록 라이브러리의 관리는 어려워집니다.
또한, 프로젝트가 복잡해질수록 소스를 컴파일하고 배포하는 것도 점점 어려워집니다. 이러한 문제를 해결하기 위해 다양한 도구들이 존재하는데, 그중에서 Maven에 대해 배워보도록 하겠습니다.

Maven이란?

Maven은 지금까지 애플리케이션을 개발하기 위해 반복적으로 진행해왔던 작업들을 지원하기 위하여 등장한 도구입니다.

Maven을 사용하면 빌드(Build), 패키징, 문서화, 테스트와 테스트 리포팅, git, 의존성관리, svn등과 같은 형상관리서버와 연동(SCMs), 배포 등의 작업을 손쉽게 할 수 있습니다.

Maven을 이해하려면 CoC(Convention over Configuration)라는 단어를 먼저 이해해야 합니다.

CoC란 일종의 관습을 말하는데, 예를 들자면 프로그램의 소스파일은 어떤 위치에 있어야 하고, 소스가 컴파일된 파일들은 어떤 위치에 있어야 하고 등을 미리 정해놨다는 것입니다.

이 말은 관습에 이미 익숙한 사용자는 쉽게 Maven을 사용할 수 있는데, 관습에 익숙하지 않은 사용자는 이러한 제약사항에 대해서 심한 거부감을 느낄 수 있습니다.

Maven을 사용한다는 것은 어쩌면 이러한 관습 즉 CoC에 대해서 알아나가는 것이라고도 말할 수 있습니다.

Maven을 사용할 경우 얻게 되는 이점은?

Maven을 사용할 경우, 굉장히 편리한 점들이 많습니다.

많은 사람이 손꼽는 장점 중에는 편리한 의존성 라이브러리 관리가 있습니다.

앞에서 JSTL을 학습할 때, 몇 가지 파일을 다운로드 하여 /WEB-INF/lib폴더에 복사하여 사용했었습니다.

관련된 라이브러리가 많아질수록 이러한 방식은 상당히 불편해집니다.

Maven을 사용하면 설정 파일에 몇 줄 적어줌으로써 직접 다운로드 받거나 하는 것을 하지 않아도 라이브러리를 사용할 수 있습니다.

프로젝트에 참여하는 개발자가 많아지게 되면, 프로젝트를 빌드하는 방법에 대하여 가이드하는 것도 쉬운 일이 아닙니다.

Maven을 사용하게 되면 Maven에 설정한 대로 모든 개발자가 일관된 방식으로 빌드를 수행할 수 있게 됩니다.

Maven은 또한 다양한 플러그인을 제공해줘서, 굉장히 많은 일들을 자동화시킬 수 있습니다.

Maven 기본

Archetype을 이용하여 Maven 기반 프로젝트를 생성할 경우 생성된 프로젝트 하위에 pom.xml 파일이 생성됩니다.
pom.xml 파일을 살펴보면 다음과 같습니다.

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>kr.or.connect</groupId>
    <artifactId>examples</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>mysample</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

각각의 태그의 의미는 다음과 같습니다.

  • project : pom.xml 파일의 최상위 루트 엘리먼트(Root Element)입니다.
  • modelVersion : POM model의 버전입니다.
  • groupId : 프로젝트를 생성하는 조직의 고유 아이디를 결정합니다. 일반적으로 도메인 이름을 거꾸로 적습니다.
  • artifactId : 해당 프로젝트에 의하여 생성되는 artifact의 고유 아이디를 결정합니다. Maven을 이용하여 pom.xml을 빌드할 경우 다음과 같은 규칙으로 artifact가 생성됩니다. artifactid-version.packaging. 위 예의 경우 빌드할 경우 examples-1.0-SNAPSHOT.jar 파일이 생성됩니다.
  • packaging : 해당 프로젝트를 어떤 형태로 packaging 할 것인지 결정합니다. jar, war, ear 등이 해당됩니다.
  • version : 프로젝트의 현재 버전. 추후 살펴보겠지만 프로젝트가 개발 중일 때는 SNAPSHOT을 접미사로 사용합니다. Maven의 버전 관리 기능은 라이브러리 관리를 편하게 합니다.
  • name : 프로젝트의 이름입니다.
  • url : 프로젝트 사이트가 있다면 사이트 URL을 등록하는 것이 가능합니다.
    Maven 을 이용할 경우 얻게 되는 큰 이점 중의 하나는 Dependency Management 기능입니다.

위 pom.xml 파일에서 엘리먼트가 Dependency Management 기능의 핵심이라고 할 수 있습니다.

해당 엘리먼트 안에 필요한 라이브러리를 지정하게 됩니다.

2) Maven을 이용한 웹 어플리케이션 실습

maven 환경 설치 링크

에러 났을 때 해결한 링크: https://devlimk1.tistory.com/10

10. JDBC - BE

1) JDBC란?

개요 - 정의

개요 - 환경 구성

JDBC 사용 - 단계별 정리

statement도 인터페이스이다.
접속을 끊어주지 않으면 다른 클라이언트가 접속을 못할 수도 있다.

JDBC 클래스의 생성관계

이런 순서를 가지고 있기 때문에 열었던 반대 순서로 닫아줘야 한다.

JDBC 사용 - 단게별 설명 1

Class.forName()은 클래스를 메모리에 올리는 것이다.

소스코드

각각 베넏마다 방식을 다르게 정의해놨으므로, 아까 MySQL과 oracle 차이가 있는 것을 알 수 있다.

JDBC 사용 - 단계별 설명2

커넥션 객체에서 statement객체를 얻어내는 것을 볼 수 있다.

JDBC 사용 - 단계별 설명2

결과셋을 가리킬 수 있는 reference를 갖게되는 것이다. 왜냐하면 결과가 아주 크면 서버에 문제가 생길 수 있으므로 데이터를 가리키는 것을 가지고 오는 것이다.

소스코드

위와 아래에서 같은 코드가 반복적으로 나오는 것을 알 수 있다. 이것을 프레임워크가 도와줘서 반복을 줄여준다. 그래서 스프링 JDBC를 사용할 것이다.

2) JDBC 실습-1

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>kr.or.connect</groupId>
  <artifactId>jdbcexam</artifactId>
  <version>0.0.1-SNAPSHOT</version>

  <name>jdbcexam</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
  	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<version>5.1.45</version>
	</dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
        <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
        <plugin>
          <artifactId>maven-site-plugin</artifactId>
          <version>3.7.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-project-info-reports-plugin</artifactId>
          <version>3.0.0</version>
        </plugin>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-compiler-plugin</artifactId>
			<version>3.6.1</version>
			<configuration>
				<source>1.8</source>
				<target>1.8</target>
			</configuration>
		</plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

mysql 드라이브 추가와 자바 버전을 1.8로 변경했다.

프로젝트 우클릭 -> maven -> update project

Role

package kr.or.connect.jdbcexam.dto;

public class Role {
	private Integer roleId;
	private String description;
	
	public Role() {
		
	}
	
	public Role(Integer roleId, String description) {
		super();
		this.roleId = roleId;
		this.description = description;
	}
	
	public Integer getRoleId() {
		return roleId;
	}
	
	public void setRoleId(Integer roleId) {
		this.roleId = roleId;
	}
	
	public String getDescription() {
		return description;
	}
	
	public void setDescription(String description) {
		this.description = description;
	}
	
	@Override
	public String toString() {
		return "Role [roleId=" + roleId + ", description=" + description + "]";
	}
}

RoleDao

package kr.or.connect.jdbcexam.dao;

import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.mysql.jdbc.Connection;
import com.mysql.jdbc.PreparedStatement;

import kr.or.connect.jdbcexam.dto.Role;

public class RoleDao {
	
	private static String dburl = "jdbc:mysql://localhost:3306/connectdb";
	private static String dbUser = "connectuser";
	private static String dbpasswd = "connect123!@#";
	
	public Role getRole(Integer roleId) {
		Role role = null;
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		
		try {
			Class.forName("com.mysql.jdbc.Driver");
			conn = (Connection) DriverManager.getConnection(dburl, dbUser, dbpasswd);
			String sql = "SELECT description, role_id FROM role WHERE role_id = ?";
			ps = (PreparedStatement) conn.prepareStatement(sql);
			ps.setInt(1, roleId);
			rs = ps.executeQuery();
			
			if(rs.next()) {
				String description = rs.getString(1);
				int id = rs.getInt("role_id");
				role = new Role(id, description);
			}
		}catch (Exception e) {
			e.printStackTrace();
		}finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			if (ps != null) {
				try {
					ps.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			if (conn != null) {
				try {
					conn.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		
		return role;
	}
}

finally는 반드시 수행되므로 이 부분에 닫아주는 코드들을 넣어준다. 하지만 close 자체도 예외를 처리해야하는 로직이다.

rs가 null이 아닐때 실행되게하므로 nullpointerexception 예외 가능성을 조금줄인 것이다.

ps.setInt(1, roleId)는 물음표로 나타낸 곳에 첫번째 물음표에 roleId를 전달하는 것이다.

rs.getString(1)은 첫 번째 컬럼의 값을 가져오는 것이다.
rs.getInt("role_id")는 컬럼 이름으로 가져오는 방식을 보여주는 것이다.

JDBCExam1.java

public class JDBCExam1 {
	public static void main(String[] args) {
		RoleDao dao = new RoleDao();
		Role role = dao.getRole(100);
		System.out.println(role);
	}
}

2) JDBC 실습-3

addRole 추가

	public int addRole(Role role) {
		int insertCount = 0;
			
		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
		String sql = "INSERT INTO role(role_id, description) VALUES (?, ?)";
		
		try (Connection conn = (Connection) DriverManager.getConnection(dburl, dbUser, dbpasswd);
				PreparedStatement ps = (PreparedStatement) conn.prepareStatement(sql)) {
			
			ps.setInt(1,  role.getRoleId());
			ps.setString(2,  role.getDescription());
			
			insertCount = ps.executeUpdate();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return insertCount;
	}

try-with-resource를 사용하는데 try 괄호안에서 자원을 얻어오는 코드를 넣으면 알아서 close 해준다.

JDBCexam2.java

public class JDBCExam2 {
	public static void main(String[] args) {
		int roleId = 501;
		String description = "CTO";
		
		Role role = new Role(roleId, description);
		
		RoleDao dao = new RoleDao();
		int insertCount = dao.addRole(role);
		
		System.out.println(insertCount);
	}
}

getRoles 추가

	public List<Role> getRoles() {
		List<Role> list = new ArrayList<>();
		
		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
		String sql = "SELECT description, role_id FROM role order by role_id desc";
		try (Connection conn = (Connection) DriverManager.getConnection(dburl, dbUser, dbpasswd);
				PreparedStatement ps = (PreparedStatement) conn.prepareStatement(sql)) {
			
			try (ResultSet rs = ps.executeQuery()) {
				
				while(rs.next()) {
					String description = rs.getString(1);
					int id = rs.getInt("role_id");
					Role role = new Role(id, description);
					list.add(role);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return list;
	}

JDBCExam3.java

public class JDBCExam3 {
	public static void main(String[] args) {
		
		RoleDao dao = new RoleDao();
		
		List<Role> list = dao.getRoles();
		
		for(Role role : list) {
			System.out.println(role);
		}
	}
}

deleteRole 추가

	public int deleteRole(Integer roleId) {
		int deleteCount = 0;
		
		Connection conn = null;
		PreparedStatement ps = null;
		
		try {
			Class.forName("com.mysql.jdbc.Driver");
			
			conn = (Connection) DriverManager.getConnection(dburl, dbUser, dbpasswd);
			String sql = "DELETE FROM role WHERE rold_id = ?";
			
			ps = (PreparedStatement) conn.prepareStatement(sql);
			
			ps.setInt(1, roleId);
			deleteCount = ps.executeUpdate();
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			if (ps != null) {
				try {
					ps.close();
				} catch (Exception ex) {
					
				}
			}
			
			if (conn != null) {
				try {
					conn.close();
				} catch (Exception ex) {
					
				}
			}
		}
		return deleteCount;
	}

JDBCExam4.java

public class JDBCExam4 {
	public static void main(String[] args) {
		
		//삭제 테스트
		int roleId = 500;
		
		RoleDao dao = new RoleDao();
		int deleteCount = dao.deleteRole(roleId);
		
		System.out.println(deleteCount);
	}
}

updateRole 추가

	public int updateRole(Role role) {
		int updateCount = 0;
		
		Connection conn = null;
		PreparedStatement ps = null;
		
		try {
			Class.forName("com.mysql.jdbc.Driver");
			
			conn = (Connection) DriverManager.getConnection(dburl, dbUser, dbpasswd);
			
			String sql = "update role set description = ? where role_id = ?";
			
			ps = (PreparedStatement) conn.prepareStatement(sql);
			
			ps.setString(1,  role.getDescription());
			ps.setInt(2,  role.getRoleId());
			
			updateCount = ps.executeUpdate();
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			if(ps != null) {
				try {
					ps.close();
				}catch(Exception ex) {}
			} 
			
			if(conn != null) {
				try {
					conn.close();
				}catch(Exception ex) {}
			} 
		} 
		return updateCount;
	}

JDBCExam5.java

public class JDBCExam5 {
	public static void main(String[] args) {
		//수정테스트
		int roleId = 500;
		String description = "CEO";
				
		Role role = new Role(roleId, description);
				
		RoleDao dao = new RoleDao();
		int updateCount = dao.updateRole(role);

		System.out.println(updateCount);
	}
}

11. WEB API - BE

클라이언트의 종류가 웹 브라우저, 안드로이드 앱, iOS 앱 등 다양해지면서 이러한 클라이언트들에게 정보를 제공하는 방식을 하나로 일원화시키고 싶어졌습니다.

일원화시키는 방식 중에 대표적인 방식이 HTTP프로토콜로 API를 제공하는 것입니다.

HTTP프로토콜로 제공하는 API를 REST API라고 합니다.

API란?

API는 Application Programming Interface의 약자입니다.

wiki를 보면 API에 대한 설명이 다음과 같이 되어 있습니다.

“API(Application Programming Interface, 응용 프로그램 프로그래밍 인터페이스)는 응용 프로그램에서 사용할 수 있도록, 운영 체제나 프로그래밍 언어가 제공하는 기능을 제어할 수 있게 만든 인터페이스를 뜻합니다.

주로 파일 제어, 창 제어, 화상 처리, 문자 제어 등을 위한 인터페이스를 제공합니다.

REST API란?

REST는 REpresentational State Transfer라는 용어의 약자로서 2000년도에 로이 필딩 (Roy Fielding)의 박사학위 논문에서 최초로 소개되었습니다.

REST API란 말 그대로 REST형식의 API를 말합니다.

REST API란 핵심 컨텐츠 및 기능을 외부 사이트에서 활용할 수 있도록 제공되는 인터페이스입니다.

예를 들어, 네이버에서 블로그에 글을 저장하거나, 글 목록을 읽어갈 수 있도록 외부에 기능을 제공하거나 우체국에서 우편번호를 조회할 수 있는 기능을 제거하거나, 구글에서 구글 지도를 사용할 수 있도록 제공하는 것들을 말합니다.

웹 브라우저 뿐만 아니라 앱 등 다양한 클라이언트가 등장하면서 그러한 클라이언트들에게 대응하기 위해 REST API가 널리 사용되기 시작하였습니다.

서비스 업체들이 다양한 REST API를 제공함으로써, 클라이언트는 이러한 REST API들을 조합한 어플리케이션을 만들 수 있게 되었습니다.

이를 매시업(Mashup)이라고 합니다.

이것은 REST가 아니다.

이렇게 REST API가 널리 사용되었지만, REST를 논문으로 최초 소개한 로이필딩은 대부분의 REST API라고 하는 것들이 REST API가 아니라고 말합니다.

REST는 다음과 같은 스타일을 반드시 지켜야 한다고 말합니다.

  • client-server
  • stateless
  • cache
  • uniform interface
  • layered system
  • code-on-demand (optional)

여기서 스타일이란 제약조건의 집합을 의미합니다.

즉, 위에서 언급한 내용을 잘 지켜야만 REST라고 말할 수 있다는 의미입니다.

HTTP프로토콜을 사용한다면 client-server, stateless, cache, lared system, code-on-demand 등에 대해서는 모두 쉽게 구현 가능합니다.

하지만, 문제는 uniform interface입니다.

uniform interface의 스타일

  • 리소스가 URI로 식별되야 합니다.
  • 리소스를 생성,수정,추가하고자 할 때 HTTP메시지에 표현을 해서 전송해야 합니다.
  • 메시지는 스스로 설명할 수 있어야 합니다. (Self-descriptive message)
  • 애플리케이션의 상태는 Hyperlink를 이용해 전이되야 합니다.(HATEOAS)

첫 번째와 두 번째 항목은 지키기 어렵지 않은데, 메시지가 스스로 설명할 수 있어야 하는 부분과 HATEOAS를 지원하는 것은 웹과는 다르게 API로는 쉽지가 않습니다.

응답 결과에 보통 JSON 메시지(다음 시간에 간단히 다루게 됩니다.)를 사용하게 되는데, 이 JSON메시지가 어디에 전달되는지 그리고 JSON메시지를 구성하는 것이 어떤 의미를 표현해야만 메시지 스스로 설명할 수 있다고 말할 수 있는데, 그게 쉽지 않습니다.

우리가 웹 게시판을 사용할 때, 리스트 보기를 보면, 상세보기나 글쓰기로 이동할 수 있는 링크가 있습니다.

상세보기에서는 글 수정이나 글 삭제로 갈 수 있는 링크가 있습니다.

이렇게 웹 페이지를 보면, 웹 페이지 자체에 관련된 링크가 있는것을 알 수 있는데 이를 HATEOAS라고 말합니다.

이런 HATEOAS를 API에서 제공하는 것은 쉽지 않습니다.

REST API는 쉽지 않다. 그래서, 보통은 Web API(혹은 HTTP API)를 사용한다.

REST의 uniform interface를 지원하는 것은 쉽지 않기 때문에, 많은 서비스가 REST에서 바라는 것을 모두 지원하지 않고 API를 만들게 됩니다.

  • REST의 모든 것을 제공하지 않으면서 REST API라고 말하는 경우도 있습니다.
  • REST의 모든 것을 제공하지 않고 Web API 혹은 HTTP API라고 부르는 경우가 있습니다.

우리는 2번째 방식을 따르려고 합니다.

그런 REST API로 괜찮은가
당신의 API가 Restful 하지 않은 5가지 증거

2) Web API란?

Web API 디자인 가이드

자원에 대한 행위는 HTTP Method로 표현

URI는 정보의 자원을 표현해야 한다.

자원에 대한 행위는 HTTP Method로 표현

슬래시 구분자(/)는 계층을 나타낼 때 사용

상태 코드 (성공)

상태 코드 (클라이언트로 인한 오류)

403보다는 다른걸 쓰기를 권고된다. 이유는 테이블에 나와있다.

상태 코드 (서버로 인한 오류)

3) Web API 실습-1

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>kr.or.connect</groupId>
  <artifactId>webapiexam</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>webapiexam Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<version>5.1.45</version>
	</dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
	<!-- json 라이브러리 databind jackson-core, jackson-annotaion에 의존성이 있다. -->
	<dependency>
		<groupId>com.fasterxml.jackson.core</groupId>
		<artifactId>jackson-databind</artifactId>
		<version>2.9.4</version>
	</dependency>

	<dependency>
		<groupId>javax.servlet</groupId>
		<artifactId>javax.servlet-api</artifactId>
		<version>3.1.0</version>
		<scope>provided</scope>
	</dependency>
	
	<dependency>
		<groupId>javax.servlet</groupId>
		<artifactId>jstl</artifactId>
		<version>1.2</version>
	</dependency>
  </dependencies>

  <build>
    <finalName>webapiexam</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-compiler-plugin</artifactId>
			<version>3.6.1</version>
			<configuration>
				<source>1.8</source>
				<target>1.8</target>
			</configuration>
		</plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

RolesServlet.java

@WebServlet("/roles")
public class RolesServlet extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setCharacterEncoding("utf-8");	
		response.setContentType("application/json");
		
		RoleDao dao = new RoleDao();
		
		List<Role> list = dao.getRoles();
		
		ObjectMapper objectMapper = new ObjectMapper();
		String json = objectMapper.writeValueAsString(list);
		
		PrintWriter out = response.getWriter();
		out.println(json);
		out.close();
	}

}

ObjectMapper를 사용하면 객체를 json 문자열로 바꾸거나 json 문자열을 객체로 바꿀 수 있다 (jackson library)

3) Web API 실습-2

RoleByIdServlet.java

package kr.or.connect.webapiexam.api;

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;

import com.fasterxml.jackson.databind.ObjectMapper;

import kr.or.connect.jdbcexam.dao.RoleDao;
import kr.or.connect.jdbcexam.dto.Role;

@WebServlet("/roles/*")
public class RoleByIdServlet extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setCharacterEncoding("utf-8");
		response.setContentType("application/json");
		
		String pathInfo = request.getPathInfo();
		String[] pathParts = pathInfo.split("/");
		String idStr = pathParts[1];
		int id = Integer.parseInt(idStr);
		
		RoleDao dao = new RoleDao();
		
		Role role = dao.getRole(id);
		
		ObjectMapper objectMapper = new ObjectMapper();
		String json = objectMapper.writeValueAsString(role);
		
		PrintWriter out = response.getWriter();
		out.println(json);
		out.close();
	}
}

0개의 댓글