JAVA 웹개발 과정 국비 54일차 정리

54일차

※ 배우는 과정이므로 정확하지 않을 수 있습니다.
잘못된 점은 알려주시면 수정하도록 하겠습니다!


1. Dynamic Web Project

수정 사항은 보기 쉽게 commit 하여 github에 올려두었다. 블로그와 같이 보면 이해가 쉬울 것이다.

1) DBCP 사용하여 getConnection 메소드 수정

어제 만들었던 프로젝트는 DBCP 라이브러리를 사용하지 않았기 때문에 커넥션을 제한할 수 있는 기능이 없다. 따라서 DBCP 라이브러리를 이용하여 커넥션 풀을 생성해주었다.
native 프로그램을 만들었을 때는 라이브러리를 다운받았지만, DBCP는 톰캣 안에 내장되어 있어서 임포트를 해주면 사용이 가능하다.

2) Singleton 사용하여 인스턴스 제한

그러나 앞서 배웠듯이, 상황이 더 좋아진 것은 아니다. DAO가 생성될 때마다 커넥션 풀이 생성되기 때문에 인스턴스를 1개로 제한해줘야 한다.
여기서 SIngleton 디자인 패턴을 사용한다.

3) Tomcat에 DBCP 설정 코드 적용 (JNDI)

DAO가 많아진다면 어떻게 될까? DAO마다 모두 싱글톤을 적용할 것이다.
그러나 DAO 하나당 인스턴스가 하나씩 만들어지기 때문에 결국 커넥션이 초과되는 문제는 동일하게 발생할 위험이 있다.

그래서 DBCP를 어차피 한번만 적용하면 되는 것이기 때문에 톰캣한테 DBCP를 만들어달라고 하는 방법까지 결국 오게 된다.
톰캣의 기본적인 환경 설정 파일은 Servers 라는 폴더에 들어있다. 톰캣이 실행될 때 안에 있는 것들을 읽으면서 실행이 된다. 따라서 폴더 안의 context.xml 파일에 DBCP를 적용시키는 코드를 적어준다.

context.xml는 github에 push하지 않는 관계로 여기에 정리한다.

<Resource
name="jdbc/oracle"
auth="Container"
type="javax.sql.DataSource"
driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@localhost:1521:xe"
username="kh" 
password="kh" 
/>

getConnection 메소드를 바꿔주는 이유는 DBCP를 더이상 자바 코드가 가지고 있지 않고 톰캣이 가지고 있기 때문이다.
톰캣의 DBCP는 기본 커넥션을 8개를 default로 가지고 있다.
싱글톤은 있든없든 실행에 전혀 문제가 되지 않지만, 있는 것이 기본적으로 DAO를 한개만 생성해주기 때문에 메모리 효율이 좋다. 따라서 싱글톤은 남겨둔다.

4) Output의 controller와 view 분리

기존 코드는 output을 보여줄 때 servlet에서 append를 사용하여 일일히 html 코드를 보내주는 방식이었다.
비효율적인 방식이므로 controller(servlet) dao에서 가져온 output 데이터들을 jsp로 보내서 jsp에서 view(출력)하는 방식으로 바꿔준다.

이때, JSP(View 페이지)에서 데이터를 for-each문을 돌리기 위한 JSTL을 사용하므로 라이브러리를 추가하고, uri 코드를 추가한다.
JSTL의 forEach문에서 var에는 \$를 사용하지 않고, items에는 $를 사용하는 것에 주의한다.

2. JNDI (Java Naming and Directory Interface)

디렉터리 서비스에서 제공하는 데이터 및 객체를 발견하고 참고하기 위한 자바 API

위의 1번의 3번 과정처럼 톰캣이 가동시 특정자원(DBCP)을 만들어두고, 개발자가 필요에 따라 톰캣에게 lookup(참고)하여 해당자원(DBCP)를 사용하는 방식을 일컫는다.

3. JSP

HTML 쪽에서 자바를 쓰게 해주자!

서블릿에 html을 사용하려면 pw.append를 계속 사용해야하는 번거로움이 있었다.
이것을 쉽게 바꾸기 위해 JSP가 탄생했다. 쉽게 말하면 그냥 HTML을 작성하면 pw.append를 자동적으로 다 붙여준다고 생각하면 된다.

  • HTML 의 동작
    1. 클라이언트가 exam.html 를 요청
    2. WAS가 만들어진 exam.html 전달
  • JSP 의 동작
    1. 클라이언트가 JSP 요청
    2. 1차 - 자바 컴파일
    3. 2차 - 기계어 컴파일
    4. 실행 - response에 담음
    5. WAS가 response 클라이언트에 전달

그래서 JSP가 좋은 점이 무엇인가? 라고 하면 HTML도 쓸 수 있고, 자바 코드도 쓸 수 있게 되면서 결국 서블릿이랑 똑같은 역할을 하게 된다는 것이다. 그래서 JSP를 서블릿의 또다른 이름이라고도 한다.

4. MVC 패턴

1) MVC 패턴이란?

  • MVC1 패턴
    • JSP가 View와 Controller의 역할을 담당.
    • DAO가 Model의 역할을 담당.
    • 문제점 : JSP가 백엔드 역할이냐 퍼블리셔 역할이냐 누가 맡아야 하느냐?
    • 이러한 문제로 현재는 잘 쓰지 않는다.
  • MVC2 패턴
    • JSP가 View의 역할을 담당.
    • Servlet이 Controller의 역할을 담당.
    • DAO가 Model의 역할을 담당.
    • 세 역할이 골고루 분배되어있어서 대부분 웹 어플리케이션에 쓰인다.

2) 페이지를 넘기는 두가지 방법

서블릿은 request의 처리와 response를 하는 Controller이다.
서블릿 안에 sendRedirectforward가 각각 있을 때 동작 방법을 알아보자.

① sendRedirect

아래와 같은 순서로 sendRedirect 는 클라이언트가 총 2번의 요청을 한다.

response.sendRedirect("inputView.jsp")
  1. 클라이언트 : servlet 요청합니다
  2. WAS : 서블릿아 너 부른다
  3. 서블릿 : 일처리 끝. WAS야 response 클라이언트 돌려줘
  4. WAS : (sendRedirect 확인) 클라이언트야 너 inputView.jsp로 가
  5. 클라이언트 : 어 알겠어
  6. 클라이언트 : inputView.jsp 요청합니다
  7. WAS : inputView.jsp 줌
  8. 클라이언트 : inputView.jsp를 본다(주소는 inputView.jsp)

② forward

아래와 같은 순서로 forward는 클라이언트가 총 1번의 요청을 한다.

request.getRequestDispatcher("inputView.jsp").forward(request, response);
  1. 클라이언트 : servlet 요청합니다
  2. WAS : 서블릿아 너 부른다
  3. 서블릿 : 일처리 끝. (inputView로 알아서 넘어감)
  4. 클라이언트 : inputView.jsp를 본다(주소는 servlet)

③ 두 방법의 차이점

두 방법 모두 같은 페이지를 본다는 것은 동일하다.
다른점이라면 sendRedirect는 2번의 요청을 하고, forward는 1번의 요청을 한다는 것인데, 이것이 바로 핵심이다.

서블릿은 요청을 처리한 결과값 result를 갖는다. sendRedirect는 View 페이지와 result 사이의 연결점이 존재하지 않는다. result가 첫번째 응답의 결과로 바로 클라이언트에게 넘어가버리기 때문이다.
그러나 forward는 result 값을 가지고 View 페이지로 넘어가기 때문에 결과값을 예쁘게 꾸며서 클라이언트에게 보여줄 수 있다.

④ setAttribute

JSP도 서블릿이기 때문에 request와 response를 받는 메소드가 존재한다.
따라서 JSP에 result 값을 전달하려면 request에 담아줘야 하는데 그 역할을 하는 메소드가 바로 setAttribute이다.
첫번째 파라미터에는 name을, 두번째 파라미터에는 값을 넣는다.

int result = dao.insert(name,contact);
request.setAttribute("result", result);

5. EL / JSTL

EL (Expression Language)
JSTL (Java Standard Tag Library)

1) EL (Expression Language)

  • MVC2를 위해서 만들어진 문법(표현 언어).
  • 컨트롤러에서 JSP로 데이터를 보냈을 때, 자바 안에 있는 데이터를 HTML 안에 표현하기 위해 만들어졌다.
  • 컨트롤러에서 넘어온 데이터를 출력하는 기본적인 기능 존재.

① 기본 출력

// Servlet
request.setAttribute("simple1", 10);  
request.setAttribute("simple2", "Hello");  
<%-- JSP --%>
${simple1 } : ${simple2 } <br>
10 : Hello

② 배열 출력

// Servlet
String[] arr = new String[] {"Apple","Mango","Orange"};
request.setAttribute("array", arr);
<%-- JSP --%>
${array[0] }<br>
${array[1] }<br>
${array[2] }<br>
Apple
Mango
Orange

③ 인스턴스 멤버필드 출력

ContactDTO가 멤버필드로 seq, name, contact를 가지고 있을 때, 각각의 멤버필드 값을 출력하려면 원래는 getter를 써서 값을 가져와야 하지만, EL에서는 쓰지 않는다.
그냥 key값을 써준 후 필드 명을 써주면 알아서 getter로 바뀐다.

// Servlet
ContactDTO dto = new ContactDTO(100,"ABC","DEF");
request.setAttribute("contact", dto);
<%-- JSP --%>
${contact.seq } : ${contact.name } : ${contact.contact }<br>
100 : ABC : DEF

④ ArrayList 출력

ContactDTO를 가지는 리스트 list가 있을 때, list를 setAttribute로 넘겨주면 jsp에서 인덱스로 각각의 요소의 멤버필드 값을 꺼낼 수 있다.

// Servlet
List<ContactDTO> list = new ArrayList<>();
list.add(new ContactDTO(1, "ABC", "DEF"));
list.add(new ContactDTO(2, "GHI", "JKL"));
list.add(new ContactDTO(3, "MNO", "PQR"));
request.setAttribute("list", list);
<%-- JSP --%>
${list[0].seq } : ${list[0].name } : ${list[0].contact }<br> 
${list[1].seq } : ${list[1].name } : ${list[1].contact }<br> 
${list[2].seq } : ${list[2].name } : ${list[2].contact }<br>
1 : ABC : DEF 
2 : GHI : JKL 
3 : MNO : PQR

2) JSTL (Java Standard Tag Library)

EL이 가지고 있지 않은 (예를 들면 제어문) 기능들을 가지고 있는 추가 라이브러리
확장 가능하지만 기본적인 if, for 등의 기능만 알아도 문제 없다.

① 사용 방법

JSTL을 사용할 때마다 아래 코드를 넣어줘야한다.
CDN은 아니며, 라이브러리 안에서 받아오는 것이다. import와 비슷하다.
그룹명이라고 생각하면 된다. 일종의 제목?

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
  1. 구글에 maven repository 검색 후 사이트 접속
  2. jstl 검색
  3. usages가 제일 많은 걸로 들어감
  4. 사용빈도 높은 버전으로 들어감
  5. jar 파일 다운로드
  6. (나의) library 폴더로 옮기기
  7. 라이브러리 파일을 WEB-INF 안에 lib 폴더에 넣어준다.

위에 쓴 코드를 지웠다가 다시 써야 에러가 사라진다. 그냥 라이브러리를 받았다고 코드를 내버려두면 에러가 사라지지 않았던 경험이 있다.

② if문

퍼블리셔들이 주로 사용하기 때문에 태그 형태를 띄고 있고, 위의 코드의 prefix를 보면 c가 있는 것을 알 수 있다. 이 것을 이용하는데 prefix는 언제든 바꿀 수 있다.
그런데 core 관련은 대부분 c를 쓰니 그냥 두자.
test 안의 표현은 if문의 조건이 된다.
주의할 점은 test안에 들어가는 표현은 반드시 “ “를 적어주어야 한다!!

// Servlet
request.setAttribute("simple1", 10);
<%-- JSP --%>
<c:if test="${simple1==10}">
	simple1 안에 저장된 값은 10 입니다.
</c:if>
simple1 안에 저장된 값은 10 입니다.

③ if-else문

JSTL의 if문은 else가 없다.
else if를 쓰고싶다면 c:choose를 쓴다. when과 같이 쓴다.
when이 if문, else if문의 역할을 하고, otherwise가 else문의 역할을 한다.

// Servlet
request.setAttribute("simple1", 15);
<%-- JSP --%>
<c:choose>
	<c:when test="${simple1==10}">
		simple1 안에 저장된 값은 10 입니다.
	</c:when>
	<c:when test="${simple1==11}">
		simple1 안에 저장된 값은 11 입니다.
	</c:when>
	<c:otherwise>
		simple1 안에 저장된 값은 10도 11도 아닙니다.
	</c:otherwise>
</c:choose>
simple1 안에 저장된 값은 10도 11도 아닙니다.

④ for-each문

var가 꺼내오는 변수를 뜻하고, items가 for문을 돌릴 대상을 뜻한다.
var는 $를 쓰지 않고, items는 $를 쓴다는 점에 유의.

// Servlet
List<ContactDTO> list = new ArrayList<>();
list.add(new ContactDTO(1, "ABC", "DEF"));
list.add(new ContactDTO(2, "GHI", "JKL"));
list.add(new ContactDTO(3, "MNO", "PQR"));
request.setAttribute("list", list);
<%-- JSP --%>
<c:forEach var="dto" items="${list }">
	${dto.seq } : ${dto.name } : ${dto.contact }
</c:forEach>
1 : ABC : DEF 
2 : GHI : JKL 
3 : MNO : PQR

6. 소스 코드

소스 코드 보러가기

댓글남기기