Model 1 설계 방식
- 클라이언트가 브라우저를 통해 요청
- 서버측 JSP 에서 요청을 받아서 변수에 저장하고, JavaBean (DTO) 객체 생성해서 값을 저장
- DAO로 DB 연동을 처리
- 많은 부분을 JSP 코드로 처리
Model 1 설계 특징
- JSP 만 이용하여 개발하는 경우
- JSP + Java Bean (DTO)을 이용하여 개발하는 경우
- Model2의 Controller 개념이 모호함
Model 1 장점
- 개발속도가 빠름
- 개발자의 기술적인 숙련도가 낮아도 배우기 쉬워서 빠르게 적용이 가능함
Model 1 단점
- JSP 페이지에서 프레젠테이션 로직과 비즈니스 로직이 혼재되어서 복잡함
- 로직의 혼재(한 파일안에 Java, JSP, HTML 혼용)로 인해서 개발자와 디자이너의 작업 분리가 어려움
- JSP 코드의 복잡도로 인해서 수정, 유지보수가 어려워짐
- 단점들로 인해 Model 1 방식을 잘 사용하지 않음
Model 2 설계 방식 1
- 클라이언트가 브라우저를 통해 요청
- 3가지 영역으로 기능을 분리시켜 개발
- 모든 요청의 진입점 역할을 하는 Controller Class, 중간의 흐름을 제어함, 요청을 어떤 클래스로 넘겨줄지를 처리
- JavaBean 사이에, 즉 2번에 Service Class 를 만들것
+ 위 사진은 대략적인 그림임
+ Java Servlet
- Java Servlet 으로 Controller Class 를 만든다
- Java Servlet : 자바로 만들어진 웹 프로그램, HTML, JS 코드도 포함됨, 웹 상에서 사용가능한 서버 기능도 가지고 있다
+ 자바시간에 만든 자바는 Java Application, 내 컴, 자바 가상먼신 에서만 실행된다
Model 2 설계 특징
- GUI 개발모델인 MVC를 웹 애플리케이션에 적용하여 구현한 방식
- Application의 역할을 Model – View – Controller로 분리시켜서 개발하는 방식
Model 2 장점
- 비즈니스 로직(개발)과 프리젠테이션(디자인)의 분리로 인해 애플리케이션이 명료해지며 유지보수와 확장이 용이함
- 디자이너와 개발자의 작업을 분리해 줌
Model 2 단점
- 개발 초기에 아키텍처 디자인을 위한 시간의 소요로 개발 기간이 늘어남
- MVC 구조에 대한 개발자들의 이해가 필요
MVC 패턴
- MVC는 Model / View / Controller 의 약자로 애플리케이션을 세 역할로 나누어서 개발하는 개발 방법론
- View 페이지는 디자이너가 처리, Model 과 Controller Class 는 개발자가 처리
- Spring 등의 프레임워크들도 모두 MVC 패턴으로 되어있다
Model
- 애플리케이션의 데이터 처리를 담당함
- Service 클래스 + DAO 클래스로 구현함
View
- 화면에 출력되는 페이지
- 사용자 인터페이스를 처리함
- JSP 를 이용해서 구현함 : EL(Expression Language, 표현언어) + JSTL(JSP Standard Tag Library)
Controller
- 클라이언트의 요청을 받아 Model과 View사이에서 흐름을 제어한다.
- Java Servlet으로 구현
+ Model 2 보다 빠르게 개발하기 위한 프레임 워크 : 쟝고, Spring
+ Model, Controller 는 Java 로 구현
Model 2 MVC 패턴 아키텍처
- 클라이언트가 서버측에 요청함
Controller Class
- 모든 요청의 진입점 역할을하는 Controller 클래스가 요청을 받음
- Controller 클래스는 중간의 흐름을 제어
- Java Servlet 으로 Controller Class 를 만든다
- 어떤 Service Class 로 요청을 넘길건지 결정, Controller 에서 Service 로 넘어간다
- 또한 어떤 VIew 페이지로 포워딩 할 것인지 결정
Service Class
- 자바로 만들어짐
- Service 클래스를 만들때 상속 사용
- Service 클래스는 여러개를 만드는데 공통적인 내용을 부모 인터페이스로 만들고 나머지는 공통적인 내용을 부모 인터페이스로부터 상속받아서 서비스 클래스를 여러개 만듬
- Service Class에서 DAO Class로 넘어간다
DAO
- Model 1 의 코드와 같다
- DB 처리는 모두 DAO 에서 한다
- Service Class + DAO Class = Model = 실제 요청을 처리해줌
DTO
- Model 1 의 코드와 같다
- Controller -> Service -> DAO 에서 이동할때 값의 전달은 DTO 객체를 사용함
- 반대로 DAO -> Service -> Controller 로 값을 DTO 객체로 돌려줄 수도 있다
공유 설정
- DB에서 검색한 데이터들 DAO에서 Service 로 리턴하고, Service Class 에서 그 데이터를 request 영역 객체로 공유 설정
- 공유한 값들은 Controller 클래스, View 페이지에서 사용(출력)한다
- 이때 표현언어(EL), JSTL 로 출력하면 다운캐스팅을 할 필요 없는 장점이 있다
+ 표현식 태그 대신 표현언어와 JSTL 사용
값의 흐름
- 값이 넘어가는 순서 : Controller -> Service -> DAO
- 값을 리턴할때 ( DAO 에서 검색결과를 돌려줄때 ) : DAO -> Service -> Controller -> View에서 출력
Model 2 개발을 위해 학습 할 것
- Java Servlet 으로 Controller 클래스 만드므로 Java Servlet
- 결과 출력시 표현식 태그를 대신하는 표현 언어(EL)
- JSTL 도 같이 사용되므로 JSTL
+ EL, JSTL 은 Model 2 뿐 아니라 Spring, Spring Boot 에도 똑같이 사용됨
Java Servlet 클래스
- Java로 작성된 웹프로그램을 의미함
- Java Servlet 클래스에는 HTML, JavaScript 코드를 포함할 수 있다
- Java Servlet 클래스는 웹브라우저로 실행 결과를 출력할 수 있다
- JSP 파일이 내부적으로 Java Servlet 으로 변환됨, 이젠 직접 Java Servlet 을 작성하는 것
- Controller 클래스를 만들때 사용함
- 모든 요청의 진입점 역할
Java Servlet 클래스 특징
- 확장자가 java 이므로 src 폴더 안에 넣어야한다.
- 실행시 웹 브라우저에 결과가 바로 나타난다
+ 실습 준비
- 새 프로젝트 jsppro 생성
- 이 프로젝트 내에서 Java Servlet, EL, JSTL 실습할 것
- 클라우드의 servlet 폴더를 jsppro/WebContnet 로 복사
- .java 파일은 src 파일에 생성해야함, WebContent 안에선 정상작동하지 않음
- src 폴더에 직접 Java Servlet 파일을 만들어보자
- Perspective 가 Java EE 여야 Java Servlet Class 생성 가능
Java Servlet 클래스 생성 / 실습 준비
- Java 이므로 Class 명이 파일명이 된다
- Superclass : 부모 클래스가 된다, HttpServlet가 부모클래스로 자동으로 만들어짐
- Helloworld Class 는 HttpServlet Class 를 내부적으로 상속받음
- Constructors from superclass 체크 해제 : 부모 클래스로 생성자가 만들어지는데, 필요하지 않으므로 체크 해제
- Inherited abstract methods 체크시 : 상속받을 메소드인 부모클래스 HttpServlet 중에서 필요한 메소드만 체크 가능
- 그 메소드 중 doGet 메소드와 doPost 메소드가 필요하므로 체크, 체크시 오버라이딩 됨
- doGet 메소드 체크 시 : 클라이언트가 get방식 요청시 자동으로 실행
- doPost 메소드 체크 시 : 클라이언트가 post방식 요청시 자동으로 실행
- Finish 누르면 src 폴더 내에 java 파일이 완성됨
- 예제 ex111 폴더
- HelloWorld.java
package send;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class Helloworld
*/
@WebServlet(description = "처음 작성하는 자바 서블릿", urlPatterns = { "/Helloworld" })
public class Helloworld extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("Served at: ").append(request.getContextPath());
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
<상속>
- Servlet Class 들은 기본적으로 HttpServlet Class 를 상속함
- 이 클래스는 HttpServlet Class의 doGet, doPost 메소드를 오버라이딩 해서 만들어짐
- extends 로 HttpServlet 클래스를 상속받아서 사용함, import javax.servlet.http.HttpServlet; 를 import 해야함
- import 되어있는 HttpServlet, WebServlet, HttpServletRequest Class 들은 Java EE 클래스로서 Apache Tomcat 에 저장되어있다
- Apache Tomcat 의 servlet-api.jar 라이브러리에 있는 클래스들임
- Java Servlet 클래스 생성 및 실행을 위해서는 반드시 아파치 톰캣이 있어야함
<메소드>
- doGet 메소드 : 클라이언트가 Get 방식 요청시 오버라이딩 메소드가 자동으로 실행됨
- doPost 메소드 : 클라이언트가 Post 방식 요청시 오버라이딩 메소드가 자동으로 실행됨
- 이 클래스 HelloWorld 그냥 실행시, Get 방식이 디폴트이므로, doGet 메소드만 자동 실행됨, doGet 메소드 안의 코드가 브라우저에 출력됨
@WebServlet
- 웹 서블릿 어노테이션이라고 부름
- 웹 서블릿 어노테이션, 실행시 이것 덕분에 찾아올 수 있다
- import javax.servlet.annotation.WebServlet; 클래스를 import 해서 사용가능
urlPatterns
- 현재 클래스명과 동일하게 자동으로 만들어짐
- 반드시 클래스명과 일치할 필요는 없음, 나중엔 값을 바꿀것
description
- 아까 생성시 작성함
- HelloWorld.java 실행시
- 기본전송방식이 get 이므로 doGet 메소드 안의 내용이 실행되어서 출력되었다
doGet() 오버라이딩 메소드
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("Served at: ").append(request.getContextPath());
}
<형식>
- 이 형식을 그대로 사용해야함
- 매개변수가 request 와 response 객체로 되어있고 throws 로 예외를 던짐
- Java Servlet 에는 JSP 와 달리 내장객체가 없다
- 객체 request 와 객체 response 만 받아서 사용 가능하고, out 등의 다른 내장 객체는 없으므로 만들어서 사용해야한다
- 이 HttpServletRequest, HttpServletResponse 클래스를 사용하고 있다, 찾아보면 메소드를 찾아볼 수 있음
<내용>
1. 매개변수로 받은 response 객체의 response.getWriter() 로 out 객체를 구해와서 출력스트림 객체를 만듬
2. 내용(Served at:)을 append 시키고, request.getContextPath() 로 현재 프로젝트명(jsppro)을 구해서 append 로 추가해서 출력시키고 있음
- doGet() 메소드를 수정해보자
- WebContent에 있던 HelloWorld.java 의 내용을 src의 HelloWorld.java 로 일부 복사
- HelloWorld.java (doGet() 메소드 수정)
package send;
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;
/**
* Servlet implementation class Helloworld
*/
@WebServlet(description = "처음 작성하는 자바 서블릿", urlPatterns = { "/Helloworld" })
public class Helloworld extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
// 현재 문서의 한글값을 인코딩(utf-8)을 시켜준다.
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter(); // 출력 스트림 객체 생성
out.println("<html>");
out.println("<head>");
out.println("<title>Hello World!</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>안녕 하세요!!</h1>");
out.println("<h1>안녕 하세요!!</h1>");
out.println("</body>");
out.println("</html>");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
+ 주의 : @WebServlet 때문에 WebContent 의 HelloWorld.java 가 실행되어있으면 src의 HellowWorld.java 가 실행 안됨
- 현재 클래스를 그냥 실행시 기본 전송방식이 get 방식이므로 오버라이딩 된 doGet() 메소드가 자동 실행됨
doGet() 형식
- 이 형식을 그대로 사용해야함
- 매개변수가 request 와 response 객체로 되어있고 throws 로 예외를 던짐
- Java Servlet 에는 JSP 와 달리 내장객체가 없다
- 객체 request 와 객체 response 만 받아서 사용 가능하고, out 등의 다른 내장 객체는 없으므로 만들어서 사용해야한다
- 객체 request 와 객체 response 는 HttpServletRequest, HttpServletResponse 클래스를 사용하고 있다, 찾아보면 메소드를 찾아볼 수 있음
+ JSP의 내장객체
- Java Servlet 에는 내장객체가 없다, 쓸 수 있는 것은 doGet 과 doPost 에서 지원되어 매개변수로 전달되는 request, response 만 사용 가능
- 나머지 객체들은 만들어서 사용해야함
- 브라우저에 출력하고자 하면, out 객체를 생성해야함
out 객체 생성 방법
PrintWriter out = response.getWriter();
- response.getWriter() 로 출력스트림 객체를 만듬, 이름을 out 으로 함
- 결과를 돌려줄때는 PrintWriter 클래스로 돌려줌
+ PrintWriter 클래스는 java.io 패키지 안에 있다, import 되어있음
- 브라우저에 출력할때는 out 객체를 생성해야함, JSP 가 아니므로 표현식 태그 사용 불가
화면 출력
out.println("<html>");
out.println("<head>");
out.println("<title>Hello World!</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>안녕 하세요!!</h1>");
out.println("</body>");
out.println("</html>");
- out.print 나 out.println() 사용해서 출력
- 소스코드에 HTML 코드도 들어갈 수 있고 Javascript 코드도 들어갈 수 있다
+ 한글이 들어가므로 한글 인코딩을 시켜야함
한글 인코딩
- 한글이 깨지지 않게 하기 위해 여태껏 JSP 에서는 page 태그의 이 코드를 사용했음
- contentType 속성의 charset 으로 인코딩
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
- 이 역할을 Java Servlet Class 에서는 이 코드를 사용해서 인코딩
// 현재 문서의 한글값을 인코딩(utf-8)을 시켜준다.
response.setContentType("text/html;charset=utf-8");
- 이 코드가 있어야 현재 문서의 한글값이 깨지지 않고 utf-8 로 인코딩되어 출력됨
- 이 코드가 없으면 한글값이 깨짐
+ get 방식과 post 방식 두가지 중 한가지로 요청이 들어오므로 각각의 경우 실행될 내용을 doGet() 과 doPost() 메소드 안에 작성
만들어서 사용할 객체
- 출력을 위해 out 객체 (출력스트림 객체) 만들기 (검색어 : out 객체 생성 방법)
- 회원관리에서 사용하기 위해 session 객체 만들기
session 객체 생성 방법
HttpSession session = request.getSession(); // 세션 객체 생성
- request 객체로 만든다
- HttpSession 클래스로 결과를 돌려준다
- 로그인 성공 후 공유 설정할때 session 객체를 주로 사용
- 예제 ex222 폴더
form 을 통해서 요청하기
- 클라이언트가 html 에서 폼을 통해서 get/post 방식으로 Java Servlet 클래스로 찾아간다
- WebContent/ex222 의 Method.html 파일에서 src 폴더의 Method.java Java Servlet Class 로 찾아갈 것
- src 폴더에 Method.java 를 만들자
실습 준비
- Method.java (수정 전)
- 웹 서블릿 어노테이션이 만들어져있고 이 이름값 "/Method" 로 찾아오는 것임
- 기본적으로 HttpServlet Class 를 상속함
- 이제 WebContent/ex222 안의 Method.java doGet(), doPost() 안의 내용을 복붙해서 src 안의 Method.java 로 복사
- Method.java (수정 후)
package send;
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;
/**
* Servlet implementation class Method
*/
@WebServlet("/Method")
public class Method extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<h1>get 방식으로 처리됨</h1>");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<h1>post 방식으로 처리됨</h1>");
}
}
- 클라이언트에서 get 방식 요청시 오버라이딩 된 doGet() 메소드 자동 실행
- 클라이언트에서 get 방식 요청시 오버라이딩 된 doPost() 메소드 자동 실행
- 두 메소드의 내용에서 공통적으로 한글 인코딩, 출력스트림 객체 out 생성, 출력 을 하고 있다
웹 서블렛 어노테이션
@WebServlet("/Method")
- 클라이언트가 폼에서 요청할 때 이 이름값 "/Method"을 가지고 찾아옴
- 이름값은 기본으로는 자기 클래스와 같은 이름, 이름 바꿔도 된다
@WebServlet(description = "값전달 연습", urlPatterns = { "/QueryString" })
- 또는 이런 형식도 있다
- 이름값은 urlPatterns 안의 값 "/QueryString" 이다
- 이제 폼에서 Servlet Class 로 요청해보자
- WebContent/ex222/Method.html
<html lang="ko">
<head>
<meta charset="utf-8">
</head>
<body>
<!-- action = "/프로젝트명/서블릿파일명"
패키지명은 기술안함.
-->
<form method="get" action="/jsppro/Method">
<input type="submit" value="get 방식으로 호출하기">
</form>
<form method="post" action="/jsppro/Method">
<input type="submit" value="post 방식으로 호출하기">
</form>
</body>
</html>
- 폼 태그가 2개이고, 첫번째 form 태그는 get 방식, 두번째 form 태그는 post 방식
+ 한 파일에 여러개의 form 태그 쓸 수 있다, 중첩은 되지 않는다
- 버튼 2개가 있고 첫번째 버튼 클릭시 해당 Servlet 클래스로 get 방식 요청, 두번째 버튼 클릭시 해당 Servlet 클래스로 post 방식 요청함
- 이때 찾아가는 방법은 action 에 적힌 어노테이션 이름값으로 찾아간다
- Model 1에서는 action 값에 jsp 파일을 입력했지만, 지금 Model 2에서는 WebServlet 어노테이션 이름값으로 찾아감
ex)
- 사용자가 'post 방식으로 호출하기' 버튼을 클릭시 두번째 폼이 post 방식으로 전송됨
- 이때 어노테이션이 "/Method" 인 곳으로 찾아감
- post 방식으로 요청했으므로 그 클래스 Method Class 에서 doPost() 메소드가 실행됨
WebServlet 어노테이션으로 찾아가기 (Method.html 부분)
<form method="get" action="/jsppro/Method">
<input type="submit" value="get 방식으로 호출하기">
</form>
<form method="post" action="/jsppro/Method">
<input type="submit" value="post 방식으로 호출하기">
</form>
- /jsppro 는 프로젝트명 으로 인식, 이름값만으로 잘 못찾아가는 경우가 있으므로 현재 프로젝트 명을 붙임
- /Method 가 이름값 으로 인식
- action 값 지정시 패키지명은 경로상에 포함되지 않음.
+ 나중엔 현재 프로젝트명인 /jsppro 를 직접 쓰지 않고 request 객체 제공 메소드 현재 프로젝트명을 구해주는request.getContextPath() 사용함
+ 이 파일은 확장자가 HTML 이라서 JSP 코드 못쓰므로 직접 /jsppro 썼다
WebServlet 어노테이션 이름값 변경
- 원래 이름값은 클래스명과 동일하지만 이름값을 임의로 변경 가능하다
- Method.java 의 WebServlet 어노테이션을 "/test" 로 변경
@WebServlet("/test")
- 그럼 form 태그 안의 action 도 "/jsppro/test" 로 바꿔야함
<form method="get" action="/jsppro/test">
<input type="submit" value="get 방식으로 호출하기">
</form>
<form method="post" action="/jsppro/test">
<input type="submit" value="post 방식으로 호출하기">
</form>
- 이름값만 맞으면 찾아간다
- Method.html 실행시 잘 처리된다
+ Java Servlet 클래스 여러개 만들때 WebServlet 어노테이션 이름값이 다른 값이어야함
- 예제 ex333 폴더
- QueryString.html : 회원가입 양식
- QueryString.java : Java Servlet 클래스 명
- ex333/QueryString.java 를 src 폴더의 send 패키지 안으로 복붙
- QueryString.html
<html lang="ko">
<head>
<meta charset="utf-8">
</head>
<body>
<form method="get" action="/jsppro/QueryString">
아 이 디 : <input type="text" name="id" size="20"> <br>
비밀번호 : <input type="password" name="pw" size="20"> <br>
회원이름 : <input type="text" name="name" size="20"> <br>
회원구분 : <input type="radio" name="class" value="일반회원"> 일반회원
<input type="radio" name="class" value="교수님"> 교수님<br>
전화번호 : <select name="phone1">
<option value="010" selected> 010 </option>
<option value="011"> 011 </option>
<option value="016"> 016 </option>
<option value="017"> 017 </option>
<option value="018"> 018 </option>
<option value="019"> 019 </option>
</select>
- <input type="text" name="phone2" size="4" maxlangth="4">
-
<input type="text" name="phone3" size="4" maxlangth="4"><br>
<input type="submit" value="전송">
</form>
</body>
</html>
- action 으로 지정된 어노테이션으로 이동뿐 아니라 값까지 전달한다
- WebServlet 어노테이션 이름값이 "/QueryString" 인 곳 으로 찾아가고 값을 전달
- get 방식으로 전송하고 있다
- name 값은 사용자가 입력한 값을 전달하기 위한 변수역할을 한다
+ 받는 쪽에서는 request.getParamter() 로 값을 받음
- 라디오 값의 value 값이 한글값임
- 가입을 시켜보자
+ 서버 중지 후 실행해야함
+ '다시' 누르면 다시 폼으로 돌아감
- 한글 값이 넘어가고 있다, 한글 인코딩이 어떻게 되는지도 자세히 보자
- Model 1 때 처럼 get 방식으로 "한글 값" 전달시 아파치 톰캣에서 자동으로 utf-8 로 인코딩 시킴
- QueryString.java
- src 폴더 안에 있다
package send;
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;
/**
* Servlet implementation class QueryString
*/
@WebServlet(description = "값전달 연습", urlPatterns = { "/QueryString" })
public class QueryString extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
String id = "", name = "", vclass = "", phone1 = "", phone2 = "", phone3 = "";
id = request.getParameter("id");
name = request.getParameter("name");
vclass = request.getParameter("class");
phone1 = request.getParameter("phone1");
phone2 = request.getParameter("phone2");
phone3 = request.getParameter("phone3");
out.println("<html><head></head><body>");
out.println("당신이 입력한 정보(get방식)입니다.<br> 아 이 디 : <b>");
out.println(id);
out.println("</b><br> 이름 : <b>");
out.println(name);
out.println("</b><br> 구분 : <b>");
out.println(vclass);
out.println("</b><br> 전화번호 : <b>");
out.println(phone1);
out.println("-");
out.println(phone2);
out.println("-");
out.println(phone3);
out.println("</b><br><a href='javascript:history.go(-1)'>다시</a>");
out.println("</body></html>");
out.close();
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
response.setContentType("text/html;charset=utf-8");
// 한글값이 post 방식으로 전송될 때 인코딩
request.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
String id = "", name = "", vclass = "", phone1 = "", phone2 = "", phone3 = "";
String pw = "";
id = request.getParameter("id");
id = request.getParameter("pw");
name = request.getParameter("name");
vclass = request.getParameter("class");
phone1 = request.getParameter("phone1");
phone2 = request.getParameter("phone2");
phone3 = request.getParameter("phone3");
out.println("<html><head></head><body>");
out.println("당신이 입력한 정보(post방식)입니다.<br> 아 이 디 : <b>");
out.println(id);
out.println("</b><br> 이름 : <b>");
out.println(name);
out.println("</b><br> 구분 : <b>");
out.println(vclass);
out.println("</b><br> 전화번호 : <b>");
out.println(phone1);
out.println("-");
out.println(phone2);
out.println("-");
out.println(phone3);
out.println("</b><br><a href='javascript:history.go(-1)'>다시</a>");
out.println("</body></html>");
out.close();
QueryDTO query = new QueryDTO();
}
}
- form 에서 get 방식으로 요청했으므로 doGet() 메소드가 자동 호출됨
- form 에서 넘어온 값을 request.getParameter() 로 양식의 name 값을 사용해서 받는다
- 받은 값을 출력하고 있음
+ doGet(), doPost() 메소드들은 오버라이딩되었으므로 이름 및 형식은 바꿀 수 없다, 내용은 바꿀 수 있다
+
out.println("</b><br><a href='javascript:history.go(-1)'>다시</a>");
- 여기선 HTML 코드도 쓸 수 있고 JS 코드도 쓸 수 있음
현재 문서 한글 인코딩 (QueryString.java 부분)
response.setContentType("text/html;charset=utf-8");
- 이 코드는 "한글 값"과는 상관없이 "현재 문서의 한글"을 인코딩 시키는 것임
- QueryString.html 에서 form 의 method 를 "post" 로 변경시 QueryString.java 의 doPost() 메소드가 실행됨
- post 방식으로 한글 값이 전달될 때는 아파치 톰캣이 자동으로 한글 인코딩 해주지 않는다!
- response.setContentType() 으로 직접 인코딩 해주면 된다
한글 값 인코딩
// 한글값이 post 방식으로 전송될 때 인코딩
request.setCharacterEncoding("utf-8");
- "한글 값" 인코딩은 request 객체 사용
- post 방식으로 한글값이 전송될때 인코딩 해야한다
- DTO 클래스 및 DAO 클래스도 다 만들어져 있다
- WebContent/ex333 폴더 안에 있는 QueryDTO.java, QueryDAO.java 를 src 의 send 패키지 안으로 넣기
- QueryDTO.java
package send;
public class QueryDTO {
private String id;
private String pw;
private String name;
private String vclass;
private String phone;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPw() {
return pw;
}
public void setPw(String pw) {
this.pw = pw;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getVclass() {
return vclass;
}
public void setVclass(String vclass) {
this.vclass = vclass;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
- QueryDAO.java
package send;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
public class QueryDAO {
private static QueryDAO instance = new QueryDAO();
public static QueryDAO getInstance(){
return instance;
}
public void insert(QueryDTO dto){
Connection conn = null;
PreparedStatement pstmt = null;
String url = "jdbc:oracle:thin:@localhost:1521:xe";
String sql="";
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection(url,"totoro","totoro123");
sql="insert into query values(?,?,?,?,?)";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, dto.getId());
pstmt.setString(2, dto.getPw());
pstmt.setString(3, dto.getName());
pstmt.setString(4, dto.getVclass());
pstmt.setString(5, dto.getPhone());
pstmt.executeUpdate();
}catch(Exception e){
}finally{
if(pstmt != null){
try{
pstmt.close();
}catch(Exception e){
}
}
if(conn != null){
try{
conn.close();
}catch(Exception e){
}
}
}
}
}
- 다 만들어져있으므로 테이블 생성 후 실행하면 연동처리 되고 실행됨
- DAO의 insert() 메소드를 사용해보자
- src/send 로 옮겨진 DTO, DAO 클래스를 QueryString.java 에서 사용해 보자
- QueryString.java 의 doPost() 안에서 DTO 객체 생성후 폼에서 넘어온 값을 저장 (메모리상에 저장)
- 저장 후, 그 DTO 객체를 DAO 클래스의 삽입 메소드 매개변수로 전달해서 insert 시도 (DB 테이블에 저장)
- QueryString.java (수정, doPost() 아래 코드 추가됨)
package send;
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;
/**
* Servlet implementation class QueryString
*/
@WebServlet(description = "값전달 연습", urlPatterns = { "/QueryString" })
public class QueryString extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
String id = "", name = "", vclass = "", phone1 = "", phone2 = "", phone3 = "";
id = request.getParameter("id");
name = request.getParameter("name");
vclass = request.getParameter("class");
phone1 = request.getParameter("phone1");
phone2 = request.getParameter("phone2");
phone3 = request.getParameter("phone3");
out.println("<html><head></head><body>");
out.println("당신이 입력한 정보(get방식)입니다.<br> 아 이 디 : <b>");
out.println(id);
out.println("</b><br> 이름 : <b>");
out.println(name);
out.println("</b><br> 구분 : <b>");
out.println(vclass);
out.println("</b><br> 전화번호 : <b>");
out.println(phone1);
out.println("-");
out.println(phone2);
out.println("-");
out.println(phone3);
out.println("</b><br><a href='javascript:history.go(-1)'>다시</a>");
out.println("</body></html>");
out.close();
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
response.setContentType("text/html;charset=utf-8");
// 한글값이 post 방식으로 전송될 때 인코딩
request.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
String id = "", name = "", vclass = "", phone1 = "", phone2 = "", phone3 = "";
String pw = "";
id = request.getParameter("id");
pw = request.getParameter("pw");
name = request.getParameter("name");
vclass = request.getParameter("class");
phone1 = request.getParameter("phone1");
phone2 = request.getParameter("phone2");
phone3 = request.getParameter("phone3");
out.println("<html><head></head><body>");
out.println("당신이 입력한 정보(post방식)입니다.<br> 아 이 디 : <b>");
out.println(id);
out.println("</b><br> 이름 : <b>");
out.println(name);
out.println("</b><br> 구분 : <b>");
out.println(vclass);
out.println("</b><br> 전화번호 : <b>");
out.println(phone1);
out.println("-");
out.println(phone2);
out.println("-");
out.println(phone3);
out.println("</b><br><a href='javascript:history.go(-1)'>다시</a>");
out.println("</body></html>");
out.close();
QueryDTO query = new QueryDTO();
query.setId(id);
query.setPw(pw);
query.setName(name);
query.setVclass(vclass);
query.setPhone(phone1 + "-" + phone2 + "-" + phone3); // 결합해서 저장
QueryDAO dao = QueryDAO.getInstance();
dao.insert(query); // 회원 가입
}
}
- 수정한 부분만
- 이제 폼에서 넘어온 값을 QueryString.java 에서 받고 그 값들을 DB 에 삽입 insert 함
- 폼 실행 전에 query 라는 테이블을 먼저 생성해야함
- WebContent 하위에 sql 폴더를 만들고 그 하위에 myoracle.sql 파일 생성
- myoracle.sql 에서 커넥션 프로파일 선택 후 테이블 create 문 작성
+ 이때 DAO 에 작성되어있는 insert 문을 참고하면
+ 컬럼이 5개여야함
- myoracle.sql
-- 모델2와 연동
select * from tab;
select * from query;
create table query(
id varchar2(20),
pw varchar2(20),
name varchar2(20),
vclass varchar2(20),
phone varchar2(30)
);
- 테이블 생성하기
- 이제 최종 연동을 확인하기 위해 QueryString.html 을 실행해서 회원가입 시키기
- 이건 그냥 출력이고 가입이 DB 에 저장되었는지는 sql 파일에서 확인
- 지금은 Java Servlet 클래스 내에서 DTO, DAO 사용했다
- 나중엔 중간에 Service 클래스를 만들어서 처리한다
- 예제 ex555 폴더
- multiPara.html
<html lang="ko">
<head>
<meta charset="UTF-8">
</head>
<body>
<form method="post" action="/jsppro/multiPara">
<h2>액사서리</h2><br>
관심항목을 선택하세요...<br>
<hr>
<input type="checkbox" name="item" value="신발"> 신발
<input type="checkbox" name="item" value="가방"> 가방
<input type="checkbox" name="item" value="벨트"> 벨트<br>
<input type="checkbox" name="item" value="모자"> 모자
<input type="checkbox" name="item" value="시계"> 시계
<input type="checkbox" name="item" value="쥬얼리"> 쥬얼리<br>
<input type="submit" value="전송">
</form>
</body>
</html>
- 체크박스를 통해 하나의 name 값에 여러개의 value 값이 넘어감
- name 인 "item" 에 value 값들이 여러개 넘어간다, 이때 value 값들이 한글값이므로 받는쪽에서 한글값 인코딩해야함
+ 값을 받는 쪽에선 Model 1 때 처럼 request.getParamteterValues() 를 사용하고 배열에 저장하면 된다
- jsppro 프로젝트의 WebServlet 어노테이션 이름값이 multiPara 인 곳으로 찾아가서 값을 전달함
- WebContent/ex555 안의 multiPara.java 를 src 의 send 패키지 안으로 복사
- multiPara.html 파일을 실행
- multiPara.java
- scr 폴더 안에 있다
package send;
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;
/**
* Servlet implementation class multiPara
*/
@WebServlet(description = "값전달 연습", urlPatterns = { "/multiPara" })
public class multiPara extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String[] item;
item = request.getParameterValues("item");
out.println("선택된 항목이");
try {
for (int i = 0; i < item.length; i++)
out.println(" : " + item[i]);
// out.println(" : " + HanConv.toKor(item[i]));
out.println("입니다.");
} catch (Exception e) {
out.println(" 없습니다.");
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
response.setContentType("text/html;charset=UTF-8");
request.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
String[] item;
item = request.getParameterValues("item");
out.println("선택된 항목이");
try {
for (int i = 0; i < item.length; i++)
out.println(" : " + item[i]);
// out.println(" : " + HanConv.toKor(item[i]));
out.println("입니다.");
} catch (Exception e) {
out.println(" 없습니다.");
}
}
}
- post 방식으로 넘어왔으므로 doPost() 메소드 내용이 실행됨
현재 문서 한글 인코딩 vs 한글 값 인코딩
현재 문서 한글 인코딩 (multiPara.java 부분)
response.setContentType("text/html;charset=UTF-8");
값(value)이 post 방식으로 넘어왔을때 인코딩 (multiPara.java 부분)
request.setCharacterEncoding("UTF-8");
하나의 name 값에 여러개 value 가 넘어왔을때 처리 (multiPara.java 부분)
String[] item;
item = request.getParameterValues("item");
- request.getParamterValues() 로 값을 받아서 1차원 배열에 저장
for (int i = 0; i < item.length; i++)
out.println(" : " + item[i]);
- 출력하고 싶다면 반복문으로 출력
+ 서버 재구동 하는 방법 : java 파일에 아무곳에서 스페이스바, 한깐 띄우기, 다시 컴파일해야하므로 서버 재구동됨
- 예제 ex666 폴더
- src 폴더 하위에 login 패키지 생성
- WebContent/ex666 폴더의 LoginServlet.java 파일을 src의 login 패키지에 복사
- LoginServlet.java
package login;
import java.io.IOException;
import java.io.PrintWriter;
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;
import javax.servlet.http.HttpSession;
/**
* Servlet implementation class LoginServlet
*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public LoginServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter(); // 출력 스트림 객체 생성
String id=request.getParameter("id");
String passwd = request.getParameter("passwd");
if(id.equals("java")&& passwd.equals("java")){ // 회원 인증 성공
// 세션 객체 생성
HttpSession session = request.getSession();
session.setAttribute("id", id); // 세션 공유 설정
// 1. Dispatcher 방식으로 포워딩
// RequestDispatcher dispatcher =
// request.getRequestDispatcher("./servlet/ex666/loginSuccess.jsp");
// dispatcher.forward(request, response);
// 2. Redirect 방식으로 포워딩
response.sendRedirect("./servlet/ex666/loginSuccess.jsp");
}
else{ // 회원 인증 실패
out.println("<script>");
out.println("alert('아이디나 비밀번호가 일치하지 않습니다.')");
out.println("history.back()");
out.println("</script>");
}
}
}
- WebServlet 어노테이션 이름값이 "/login"
- 아이디가 "java" 고 비밀번호가 "java"면 로그인 성공, 로그인 성공시 session 으로 id 를 공유함
포워딩
RequestDispatcher dispatcher =
request.getRequestDispatcher("/ex666/loginSuccess.jsp");
dispatcher.forward(request, response);
- 아이디 비번 일치시 loginSuccess.jsp 로 포워딩 시킨다
- ex666/index.html 을 보자
- index.html
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
</head>
<frameset cols="30%,*">
<frame src="/jsppro/servlet/ex666/menu.jsp" name="leftFrame" />
<frame src="/jsppro/servlet/ex666/login.jsp" name="rightFrame" />
</frameset>
<body>
</body>
</html>
- frameset 태그로 프레임을 나눔, cols 속성은 세로방향으로 프레임을 나누겠다는 의미, 좌측 30% 우측은 나머지
- fram src 의 경로는 패키지명을 적고, WebContent 를 기준으로 파일까지 경로를 적기
- index.html 실행시
- 좌측엔 menu.jsp, 우측엔 login.jsp 가 나타남
- menu.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
</head>
<%
String id = (String)session.getAttribute("id");
%>
<body>
<%
if(id == null){
%>
<a href="login.jsp" target="rightFrame" />로그인</a>
<%
}
else{
%>
<%=id %> 님 환영합니다.
<%
}
%>
</body>
</html>
- 세션 id 값을 구해옴
- 로그인을 하지 않으면 session 값이 null 이므로 로그인 링크만 뜬다
- 로그인을 하면 session 값이 null 이 아니므로 ~님 환영합니다 가 나옴
- login.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
</head>
<body>
<form action="/jsppro/login" method="post">
아이디 : <input type="text" name="id"/>
비밀번호 : <input type="password" name="passwd"/><br>
<input type="submit" value="로그인"/>
</form>
</body>
</html>
- 아이디, 비번 입력양식이 있고 로그인이 가능한 페이지
- form 을 통해 WebServlet 어노테이션 이름값이 "/login" 인 곳으로 찾아가서 post 방식으로 값을 전달한다
- 어노테이션 이름값이 "/login"인 LoginServlet.java 에서 doPost()가 실행됨
- LoginServlet.java (중복)
package login;
import java.io.IOException;
import java.io.PrintWriter;
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;
import javax.servlet.http.HttpSession;
/**
* Servlet implementation class LoginServlet
*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public LoginServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter(); // 출력 스트림 객체 생성
String id=request.getParameter("id");
String passwd = request.getParameter("passwd");
if(id.equals("java")&& passwd.equals("java")){ // 회원 인증 성공
// 세션 객체 생성
HttpSession session = request.getSession();
session.setAttribute("id", id); // 세션 공유 설정
// 1. Dispatcher 방식으로 포워딩
// RequestDispatcher dispatcher =
// request.getRequestDispatcher("./servlet/ex666/loginSuccess.jsp");
// dispatcher.forward(request, response);
// 2. Redirect 방식으로 포워딩
response.sendRedirect("./servlet/ex666/loginSuccess.jsp");
}
else{ // 회원 인증 실패
out.println("<script>");
out.println("alert('아이디나 비밀번호가 일치하지 않습니다.')");
out.println("history.back()");
out.println("</script>");
}
}
}
- WebServlet 어노테이션으로 요청을 받음
- doPost() 메소드가 자동으로 실행됨
<doPost() 내용>
- 한글 값 인코딩, 현재 문서 한글 인코딩
- 아이디나 비번이 틀렸을때 브라우저에 메세지 출력위한 out 객체(출력스트림 객체) 생성
- 전달된 값 받기
전달된 값 받기 (LoginServlet.java 부분)
String id=request.getParameter("id");
String passwd = request.getParameter("passwd");
- form 에서 넘어온 데이터를 request.getParamter() 로 받고 있다
- 여기선 DB연동 대신 아이디, 비밀번호 값이 "java" 인 경우 로그인 성공으로 간주
- 로그인(회원 인증) 성공시 세션으로 공유 설정
세션 객체 생성 & 세션 공유 설정 (LoginServlet.java 부분)
HttpSession session = request.getSession();
session.setAttribute("id", id);
- session 이 내장 객체가 아니므로 session 객체를 만들어서 사용해야함
- 로그인 성공시 session 객체를 만들어서 공유해야함
- session 으로 setAttribute() 로 공유설정함
- 여기서부터 세션 영역 시작, 로그인 성공 부터 세션 영역 시작
- session value 값이 id 값이다, 즉 "java"
포워딩 (LoginServlet.java 부분)
RequestDispatcher dispatcher =
request.getRequestDispatcher("./servlet/ex666/loginSuccess.jsp");
dispatcher.forward(request, response);
- 포워딩하는 2가지 방법 중 Dispatcher 를 통한 포워딩 방법이다
- request.getRequestDispatcher() 로 경로 설정 후 포워딩할 파일을 불러오고 dispatcher.forward() 사용
- 즉, loginSuccess.jsp 로 포워딩하겠다는 의미, 이동하겠다는 의미
- loginSuccess.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
<script>
top.leftFrame.location.href="/jsppro/servlet/ex666/menu.jsp";
</script>
</head>
<body>
로그인 성공
</body>
</html>
- index.html 의 좌측 프레임 name 값이 "LeftFrame" 이었다
- 즉 loginSuccess.jsp 의 코드는 좌측 프레임 쪽(menu.jsp)으로 이동하겠다는 의미
- menu.jsp 로 이동
- menu.jsp 에서 이젠 session 값을 받아올 수 있으므로 더이상 null 이 아님
- java님 환영합니다가 나타나게 된다
- 이제 index.html 실행해보자
- 우측 화면에서 로그인해보자
- 맞는 아이디, 비밀번호 입력시
- 좌측에 ~님 환영하였습니다. 가 나타난다.
- menu.jsp 파일에도 세션이 잘 공유되었음을 확인 가능
- 틀린 아이디나 비밀번호 입력시
포워딩 2가지 방법
- Java Servlet 클래스에서 JSP페이지로 포워딩 방법
1. Dispatcher 방식
RequestDispatcher dispatcher = request.getRequestDispatcher("dispatcher.jsp");
dispatcher.forward(request, response);
- 경로 설정 후 dispatcher 객체로 forward() 함
2. Redirect 방식
response.sendRedirect("redirect.jsp");
포워딩과 공유 주의
- 세션의 경우엔 어느방식으로 포워딩 되더라도 포워딩된 페이지에서도 세션으로 공유한 값이 유지됨
- request 객체로 공유했을때는, dispatcher 방식으로 포워딩 되어야만 포워딩 된 곳에서 request 객체로 공유한 값을 구해올 수 있다
request.setAttribute("request","requestValue"); // 공유 설정
- request 객체로 공유 설정시 포워딩 방법 2가지 중 Dispatcher 방식의 포워딩만 가능
RequestDispatcher dispatcher = request.getRequestDispatcher("dispatcher.jsp");
dispatcher.forward(request, response);
- session 으로 공유 설정시 포워딩 방법 2가지 모두 사용 가능
// 세션 객체 생성
HttpSession session = request.getSession();
session.setAttribute("id", id); // 세션 공유 설정
// 1. Dispatcher 방식으로 포워딩
RequestDispatcher dispatcher =
request.getRequestDispatcher("./servlet/ex666/loginSuccess.jsp");
dispatcher.forward(request, response);
// 2. Redirect 방식으로 포워딩
response.sendRedirect("./servlet/ex666/loginSuccess.jsp");
- Java Servlet 클래스에서 2번 Redirect 방식으로 포워딩 한 후 index.html 실행
- session 으로 공유설정했으므로 어떤 방식으로 포워딩되더라도 session 공유값이 계속 유지됨
- request 객체로 공유했을때도 두가지 방법으로 포워딩했을때 되는지 실험해보자
- request 객체로 공유시 Dispatcher 방식의 포워딩 방법만 가능
- 그렇게 포워딩해서 View 페이지에 출력하는 것
예제 전체 흐름 정리
- index.html 을 실행해서 오른쪽 프레임인 login.jsp 에서 로그인 시도 (왼쪽 프레임 menu.jsp 에는 세션이 없으므로 '로그인'만뜸)
- login.jsp 의 form 의 action 을 통해 "/login" 이 WebServlet 어노테이션 이름값인 곳으로 찾아감 (LoginServlet.java 이다)
- LoginServlet.java 에서 로그인 성공시(id 와 pw 가 "java"일때) loginSuccess.jsp 로 포워딩함
- loginSuccess.jsp 에서 좌측 프레임을 menu.jsp 로 이동함(location.href 로 이동)
- menu.jsp 로 가서 이번엔 세션값이 있으므로 'java 님 환영합니다' 메세지를 띄움
- 예제 ex777 폴더
- DispatcherServlet.java 와 RedirectServlet.java 를 src의 send 패키지로 복사
- DispatcherServlet.java
- src 폴더 안에 있다
package send;
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;
/**
* Servlet implementation class DispatcherServlet
*/
@WebServlet("/DispatcherServlet")
public class DispatcherServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public DispatcherServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
request.setAttribute("request","requestValue"); // 공유 설정
RequestDispatcher dispatcher =
request.getRequestDispatcher("./servlet/ex777/dispatcher.jsp");
dispatcher.forward(request, response);
}
}
- 바로 이 DispatcherServlet.java 실행시 디폴트가 get 방식이므로 doGet() 메소드 실행됨
- request 영역으로 공유를 설정하고, dispatcher.jsp 로 포워딩을 하고 있다
- 포워딩시 작성하는 경로값은 WebContent 폴더 하위폴더부터 작성해야한다
- request 영역으로 공유 설정했으므로 포워딩 2가지 방법 중 Dispatcher 방법으로만 포워딩 가능
- forward action tag 대신 Model 2에서는 Dispatcher 방식으로 포워딩 시킴
- 여기서부터 request 영역이 시작된다, 일반적으로 request 영역은 포워딩된 다음페이지까지
+ 생성자는 필요 없다
dispatcher 방식으로 포워딩 특징
1. 포워딩된 페이지에서는 request 객체로 공유한 값을 사용할 수 있다.
2. 포워딩이 되면 브라우저의 URL주소가 변경되지 않는다.
- 포워딩을 해도 현재 문서명 그대로 나타나고 url 이 dispatcher.jsp 로 바뀌지 않음
- ex777/dispatcher.jsp 에서 공유되는 값을 받아서 잘 출력하고 있다
- dispatcher.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
</head>
<body>
request 속성 값 : <%=request.getAttribute("request") %>
</body>
</html>
- request.getAttribute("request") 로 공유값을 잘 받아서 출력하고 있다
- DispatcherServlet.java 실행시 doGet()이 실행되고 포워딩하면서 request 로 공유설정함
- DispatcherServlet.java 실행해보자
- 공유값을 잘 가져와서 출력한다
- dispatcher.jsp 로 포워딩(이동)되었지만 URL주소가 dispatcher.jsp 로 바뀌어 있지 않음
- 다음은 RedirectServlet.java
package send;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class RedirectServlet
*/
@WebServlet("/RedirectServlet")
public class RedirectServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public RedirectServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
// request 객체로 공유 설정
request.setAttribute("request", "requestValue");
response.sendRedirect("./servlet/ex777/redirect.jsp");
}
}
- 이번에는 request 객체로 공유 설정 후 Redirect 방식으로 포워딩 하고 있다
- 포워딩은 잘 되지만, request 객체로 공유 설정했을때 Redirect 방식으로 포워딩했다면, 포워딩 된 페이지에서 공유 설정한 값을 가져올 수 없다
- 즉 포워딩은 되지만 포워딩 된 페이지에서 공유값을 가져올 수 없는 문제 생김
- request 객체로 공유 설정시 Dispatcher 방식으로 포워딩해야 포워딩된 페이지에서 공유값 사용 가능
- redirect.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
</head>
<body>
request 속성 값 : <%=request.getAttribute("request") %>
</body>
</html>
redirect 방식으로 포워딩 특징
1. 포워딩된 페이지에서는 request 객체로 공유한 값을 사용할 수 없다.
2. 포워딩된 JSP페이지에서는 자바 서블릿 클래스에서 request 영역의 공유한 속성값에 접근 할 수 없다.
- 공유 영역을 벗어나게되기 때문이다.
3. 포워딩이 되면 브라우저의 URL주소가 포워딩된 JSP 파일명으로 바뀐다.
- RedirectServlet.java 파일 실행하자
- 포워딩은 되지만 공유값을 가져오지 못해 null 임
- URL주소가 redirect.jsp 로 변경되어있음
MVC 패턴 흐름 정리
- MVC의 Controller 클래스를 Java Servlet Class 로 만들어야한다
- 요청이 찾아오는 것은 WebServlet 어노테이션으로 찾아온다
- DAO 에서 DB에서 검색하고 검색한 값을 Service 클래스에서 공유 수행
- 이때 request 방식으로 공유설정했다면 Dispatcher 방식으로 포워딩 해야함
ex)
- Service 클래스에서 페이징에 필요한 6개 변수를 request 객체로 공유 설정
- View 페이지에서 결과를 EL, JSTL 로 출력
표현 언어 (Express Language)
- 기존 Model 1 표현식 태그의 역할을 대신함
- JSP의 표현식 태그와 비슷한 역할을 수행한다
- Spring, Spring Boot 에서도 사용
- 표현언어는 ${ } 기호를 사용한다, 이 사이에 코드를 씀
- 표현언어에 JSP의 네가지 영역 객체로 공유한 값을 구해올 수 있다.
ex) ${ sessionScope.id } // sessionScope는 내장 객체 중 하나
- 표현언어에 산술연산자(+,-,*,/,%), 비교연산자(>,>=,<,<=,==,!=), 논리연산자(&&, ||, !), 조건연산자, empty 연산자 등을 사용할 수 있다. ex) ${ 10 + 20 }
- 표현언어에 자바빈 클래스의 getter 메소드를 호출할 수 있다.
ex) ${ article.id } // article 은 DTO 객체, article.getId() 와 같은 의미
- Service 클래스에서 request 객체로 공유 설정한 뒤,
- Controller 클래스를 통해 View 페이지로 출력할때 getParameter() 이나, 형변환 등을 하지 않아도바로 결과를 EL로 출력 가능
- EL 과 JSTL 이 View 페이지에서 결합되어 결과를 출력함
EL 지원되는 내장 객체
- EL 안에서만 사용 가능, 즉 ${} 안에서만 사용 가능
1. param
${param.name}
- name 은 값을 전달하기위한 변수명
- 아래의 코드와 같다
<%=request.getParamter("name")%>
2. sessionScope
${sessionScope.id}
- id 는 세션 네임
- 아래의 코드와 같다
<%= session.getAttribute("id")%>
표현 언어 예제
실습 준비
- 클라우드의 el 폴더를 jsppro 의 WebContent 폴더에 복붙
표현 언어 예제 1
- el/ex11 폴더의 eLEx1.jsp 파일을 보자
- eLEx1.jsp
<%@ page contentType="text/html;charset=utf-8"%>
<HTML>
<HEAD>
<TITLE>간단한 표현언어(EL)예제</TITLE>
</HEAD>
<BODY>
<H3>간단한 표현언어(EL)예제</H3>
<P>
연산자를 사용한 예와 내장객체의 사용한 예:
<TABLE BORDER="1">
<THEAD>
<TD><B>표현식</B></TD>
<TD><B>값</B></TD>
</THEAD>
<TR>
<TD>\${2 + 5}</TD>
<TD>${2 + 5}</TD>
</TR>
<TR>
<TD>\${4/5}</TD>
<TD>${4/5}</TD>
</TR>
<TR>
<TD>\${5 div 6}</TD>
<TD>${5 div 6}</TD>
</TR>
<TR>
<TD>\${5 mod 7}</TD>
<TD>${5 mod 7}</TD>
</TR>
<TR>
<TD>\${2 < 3}</TD>
<TD>${2 < 3}</TD>
</TR>
<TR>
<TD>\${2 gt 3}</TD>
<TD>${2 gt 3}</TD>
</TR>
<TR>
<TD>\${3.1 le 3.2}</TD>
<TD>${3.1 le 3.2}</TD>
</TR>
<TR>
<TD>\${(5 > 3) ? 5 : 3}</TD>
<TD>${(5 > 3) ? 5 : 3}</TD>
</TR>
<TR>
<TD>\${header["host"]}</TD>
<TD>${header["host"]}</TD>
</TR>
<TR>
<TD>\${header["user-agent"]}</TD>
<TD>${header["user-agent"]}</TD>
</TR>
</TABLE>
</BODY>
</HTML>
- EL 안에서 각종 연산자를 사용하는 내용이다
- EL ${} 안에 산술연산자, 비교연산자, 논리연산자, 조건연산자, empty 연산자 등을 쓸 수 있다
브라우저에 그대로 출력 vs 연산해서 출력 (eLex1.jsp 부분)
<TR>
<TD>\${2 + 5}</TD>
<TD>${2 + 5}</TD>
</TR>
- \(역슬래시) 가 있으면 \ 다음의 내용을 특수문자로 인식해서 브라우저에 그대로 출력함
- ${2 + 5} 면 연산결과 7 이 출력됨
나누기 연산시 결과 주의 1 (eLex1.jsp 부분)
<TR>
<TD>\${4/5}</TD>
<TD>${4/5}</TD>
</TR>
- 자료형이 따로 없기떄문에 4/5 연산을 수행시 정수형으로 결과가 나오지 않고, 0.8 실수로 출력됨
나누기 연산시 결과 주의 2 (eLex1.jsp 부분)
<TR>
<TD>\${5 div 6}</TD>
<TD>${5 div 6}</TD>
</TR>
- / 기호 대신 div 를 적어도 같은 역할, 5/6 과 같다
- 마찬가지로 0.83333.. 실수로 결과가 나옴
비교 연산 1 (eLex1.jsp 부분)
<TR>
<TD>\${2 < 3}</TD>
<TD>${2 < 3}</TD>
</TR>
- 결과는 true 또는 false
비교 연산 2 (eLex1.jsp 부분)
<TR>
<TD>\${2 gt 3}</TD>
<TD>${2 gt 3}</TD>
</TR>
<TR>
<TD>\${3.1 le 3.2}</TD>
<TD>${3.1 le 3.2}</TD>
</TR>
- 부등호 모양의 비교연산자를 사용해도 되고, gt (greater than) 또는 lt(less than) 을 사용해도 된다
- 2 gt 3 은 2 > 3 과 같은 의미임
삼항 연산자 (eLex1.jsp 부분)
<TR>
<TD>\${(5 > 3) ? 5 : 3}</TD>
<TD>${(5 > 3) ? 5 : 3}</TD>
</TR>
- 첫번째 식이 참이면 5가 , 거짓이면 3 이 결과가 됨
header["user-agent"] (eLex1.jsp 부분)
<TR>
<TD>\${header["user-agent"]}</TD>
<TD>${header["user-agent"]}</TD>
</TR>
- 브라우저에 대한 정보를 가져옴
- eLEx1.jsp 실행시
- 연산자들의 연산결과가 출력된다.
표현 언어 예제 2
- WebContent/el/ex22/eLEx2.jsp
<%@ page contentType="text/html;charset=utf-8"%>
<% request.setCharacterEncoding("utf-8");%>
<HTML>
<HEAD>
<TITLE>표현언어의 사용예제2</TITLE>
</HEAD>
<BODY>
<H3>표현언어의 사용예제2 -파라미터값 처리</H3>
<P>
<FORM action="eLEx2.jsp" method="post">
이름 : <input type="text" name="name" value="${param['name']}">
<input type="submit" value="확인">
</FORM>
<P>
이름은: <%=request.getParameter("name") %> <br>
이름은: ${param.name} 입니다. <br>
이름은: ${param['name']} 입니다.
</BODY>
</HTML>
- action 이 자기 자신으로 되어있다
- 원래 이름값을 받을때는 request.getParameter() 로 받아야하지만, EL 을 사용해서 %{param.name} 으로 더 간단하게 값을 받고 출력까지 시켜줌
+ 한글값 깨지지 않도록 가장 위에서 한글값 인코딩을 하고 있다
- 실행시 이름 입력 양식이 나타나고 '확인'누르면 자기 자신의 파일을 다시 실행해서 다시 입력창을 띄움, 그리고 받은 이름값을 아래에 출력
EL 내장 객체 param
이름은: <%=request.getParameter("name") %> <br>
이름은: ${param.name} 입니다. <br>
이름은: ${param['name']} 입니다.
- 세 줄이 모두 같은 코드
- EL 은 표현식 태그 대신이므로 출력까지 시킴
+ EL 내장 객체 sessionScope
+ Session 영역 공유 설정시에는 기존처럼 한다, setAttribute() 사용
- Session 영역 공유값 받아오기는 sessionScope 내장객체로 쉽게 가능
${sessionScope.id}
- 아래와 같다
<%=session.getAttribute("id")%>
+ EL 내장 객체 requestScope
- Request 영역 공유값 받아오기를 requestScope 내장객체로 쉽게 가능
${requestScope.page}
- 이렇게 써도 되지만 이렇게 requestScope 를 생략해도 바로 ${page} 로 출력 가능 하므로 잘 쓰지 않음
${page}
- 두 코드는 아래와 같다
<%=request.getAttribute("page")%>
+ EL 은 JSTL 과 결합되어 사용된다
+ 지금 다 설명하지 못한 EL 기능도 JSTL 하면서 같이 할 것
표현 언어 예제 3
실습 준비
- WebContent/el/ex33 의 Product.java 는 자바파일이므로 src 폴더 하위에 jspbook 패키지를 만들어서 그곳으로 복사
표현 언어 예제 3
- src/jspbook/Product.java
package jspbook;
public class Product {
// 상품 목록을 저장할 배열
private String[] productList = {"item1","item2","item3","item4","item5"};
// 변수 설정
private int num1 = 10;
private int num2 = 20;
public int getNum1() {
return num1;
}
public int getNum2() {
return num2;
}
public String[] getProductList() {
return productList;
}
}
- 메소드를 통해서 Product 클래스의 필드들을 돌려주고 있음
- 일종의 DTO 클래스이다.
- WebContent/el/ex33/productList.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
%>
<html>
<head>
<meta charset="utf-8">
<title>EL 예제</title>
</head>
<body>
<center>
<H2>EL 예제-상품목록</H2>
<HR>
<form method="post" action="productSel.jsp">
<jsp:useBean id="product" class="jspbook.Product" scope="session"/>
<select name="sel">
<%
// session 에서 가져온 Product 객체로 부터 저장되어 있는 목록을 가져와 출력함.
for(String item : product.getProductList()) {
out.println("<option>"+item+"</option>");
}
%>
</select>
<input type="submit" value="선택"/>
</form>
</center>
</body>
</html>
- Model 1 으로 되어있다, action 에서 productSel.jsp 파일로 값을 전달함
- useBean action tag 를 써서 Product 객체 product 를 생성, 생성된 객체를 scope 속성을 통해서 사용 범위 지정
- scope 속성으로는 영역명이 들어가는데, 여기선 session 이 적혀있으므로, 세션이 끊기기 전까지 이 객체가 계속 공유됨
- scope 속성값 생략시 기본값이 page, 여기서 session 이므로 다음 페이지 productSel.jsp 로 넘어가도 세션이 끊기기 전까지 이 객체 product 를 계속 쓸 수 있다.
- 객체 product 에서 getProductList() 메소드를 사용해서 String형 배열을 가져옴
- 향상된 for 문으로 getProductList() 에서 "item1", "item2", "item3".. 를 차례로 가져와서 item 변수에 저장, 그 item 변수를 차례로 출력하고 있음
- option 태그 안에 value 속성이 없으면사이의 값이 select 의 name 인 sel 에 저장되어 넘어감
- 객체의 scope 값이 session 으로 되어있으면 session 으로 공유된 것과 같다
+ 향상된 for 문 오른쪽에는 배열이나 List 가 온다
- productList.jsp 실행시
- 'item3' 선택 후 '선택' 버튼 클릭시
- WebContent/el/ex33/productSel.jsp
<%@page import="jspbook.Product"%>
<%@ page language="java" contentType="text/html; charset=utf-8"%>
<html>
<head>
<meta charset="utf-8">
<title>EL 예제</title>
</head>
<body>
<center>
<H2>EL 예제-상품선택</H2>
<HR>
<!-- 표현 언어로 출력 -->
1. 선택한 상품은 : ${param.sel} <br>
<!-- 표현식 태그로 출력 -->
1. 선택한 상품은 : <%=request.getParameter("sel") %> <br>
<!-- 표현 언어로 출력 -->
2. num1 + num2 = ${product.num1 + product.num2} <br>
<!-- 표현식 태그로 출력 -->
<%
Product pro = (Product) session.getAttribute("product");
%>
2. num1 + num2 = <%=pro.getNum1() + pro.getNum2()%>
</center>
</body>
</html>
- 페이지가 넘어왔지만 세션이 끊어지기전까지 객체 product 는 계속 사용가능하므로 이 페이지에서도 Product 객체 product 사용 가능
- ${param.sel} 과 request.getParamteter("sel") 로 select 옵션의 선택된 값을 구해올 수 있다, 같은 의미이다.
+ productList.jsp 에서 option 태그 안에 value 속성이 없으므로 사이의 값인 "item1", "item2", "item3" ..중 선택한 것이 sel 변수에 저장되어서 넘어옴
주의 1 (productSel.jsp 부분)
<!-- 표현 언어로 출력 -->
2. num1 + num2 = ${product.num1 + product.num2} <br>
- 객체 product 의 num1, num2 값을 product.num1, product.num2 로 구해오는데, Product 클래스에서 num1, num2 는 private 이다
- 표기만 product.num1 으로 필드명으로 표기하고, 의미는 product.getNum1() 을 리턴받아 출력한다는 의미
- EL 안에서는 메소드를 표기하지 않음
- 즉 product.num1 은 표기일 뿐 실질적으로는 product.getNum1() 을 의미한다.
- 아래의 코드와 위의 코드는 같다.
주의 2 (productSel.jsp 부분)
<!-- 표현식 태그로 출력 -->
<%
Product pro = (Product) session.getAttribute("product");
%>
2. num1 + num2 = <%=pro.getNum1() + pro.getNum2()%>
- 위의 코드와 같다
- 객체의 scope 값이 session 으로 되어있으면 session 으로 공유된 것과 같다
- 공유 네임값도 그 객체 이름으로 되어있다.
- getAttribute("product") 로 가져올때 다운캐스팅을 해야한다
- productList.jsp 에서
<jsp:useBean id="product" class="jspbook.Product" scope="session"/>
- 이렇게 product 객체를 만들면서 scope 를 "session" 으로 설정했다
- EL 태그에서는 바로 ${product.num1} 으로 사용 가능하다
- EL 이 아닌 표현식 태그로 다른 페이지에서 이 객체 product 를 사용하려면 session 에 공유된 값으로부터 객체를 가져와서 사용해야 한다.
- 위의 useBean action tag 중 scope="session" 부분은 아래 코드와 같다
session.setAttribute("product");
- 객체 product 가 session 영역에 공유 설정되어있는 것이므로, EL 에서는 바로 사용 가능
표현 언어 (EL) 정리
- 표현 언어는 현재 공유된 값을 출력하는 것이다!
- 현재 페이지에서 공유된 값을 사용할 수 있으면 EL 태그로 쉽게 출력할 수 있다.
ex) 이전 페이지에서 session 영역에 어떤 값을 공유 설정해둠, 다음 페이지에서 그 값을 구해올 수 있다, 이때 EL 태그로 쉽게 출력 가능
String str = "jsp";
표현식 태그 : <%=str %>
<%=article.getId()%>
<%=session.getAttribute("test")%>
<%=request.getParameter("name")%>
<%=request.getParameterValues("choice")%>
request.setAttribute("str",str);
표현언어(EL) : ${str}
${article.id}
${sessionScope.test}
${param.name}
${paramValues.choice}
<표현식 태그>
- 단순히 String str = "jsp" 일때, ${str} 로 "jsp" 를 출력하는 것도 가능하다.
<표현언어(EL)>
- 표현 언어는 현재 공유된 값을 출력하는 것이다!
- 단순히 String str = "jsp" 일때, ${str} 로 "jsp" 를 출력하는 것은 불가능하다
- str 와 article 이 request 객체로 공유가 되어야만 ${str}, ${article.id} 을 EL로 이렇게 출력 가능하다
ex) request.setAttribute("str",str) 로 공유되어있어야만 공유 네임 "str" 로 ${str} 사용 가능
- article 또한 request 객체로 공유되어있어야만 ${article.id} 사용 가능
- ${article.id} 는 <표현식 태그>의 <%=article.getId()%> 와 같은 의미
- ${sessionScope.test} 는 표현식 태그의 <%=session.getAttribute("test")%> 와 같다
- sessionScope 내장객체로 쉽게 session 의 공유값을 가져오는 것이다.
+ 또한 get/post 방식으로 전달되는 값을 받을때도 param 내장객체를 이용해서 쉽게 받을 수 있다.
+ Session 이 끊어지는 때
1. 세션을 강제로 invalid()로 끊을때
2. 브라우저 창을 닫을때 Session 끊김