새소식

웹 프로그래밍(JSP)

웹 프로그래밍 시험 준비

  • -

이번 시간에는 나의 경험을 공유하는 시간이 아닌, 시험 과목을 공부하면서 배웠던 개념들에 대해 복습할 겸 글을 써보려 합니다. 도움되는 정보가 많이 빠져있을 수 있습니다. 

 

1. JSP 페이지의 처리 과정

JSP 페이지는 하나의 서블릿 프로그램으로 변환되어 실행된다. 순서를 보자면 아래와 같다.

⓵웹 브라우저가 웹 서버에 JSP 요청 (Hello.jsp) 웹 서버는 JSP 페이지임을 확인하고 웹 서버에 있는 JSP 컨테이너로 전달한다. JSP 컨테이너는 JSP 파일이 수정되었는지 확인하기 위해 서블릿 클래스가 JSP 페이지보다 오래된 것인지 확인한다.

⓶JSP 컨테이너는 JSP 페이지를 서블릿 프로그램인 Hello_jsp.java로 변환한다. (이때 JSP 파일이 수정된 경우에는 JSP 컨테이너는 다시 JSP 파일을 서블릿으로 변환하는 작업을 수행하고, 그렇지 않으면 성능 향상을 위해 변환 과정을 건너뛴다.)

⓷JSP 컨테이너가 서블릿 프로그램을 컴파일하여 Hello_jsp.class로 만들고 이를 웹 서버에 전달한다.

⓸웹 서버는 정적 웹 페이지처럼 *.class의 실행 결과를 웹 브라우저에 응답으로 전달하므로 웹 브라우저는 새로 가공된 HTML 페이지를 동적으로 처리한 결과를 보여준다.

 

즉, JSP 컨테이너는 JSP를 서블릿으로 변환하는 프로그램이다. 우리는 JSP 컨테이너를 톰캣을 통하여 활용하고 있다.

 

 위에서 만들어진 서블릿 프로그램과 서블릿 클래스는 프로젝트 이름이 JSPBook 이라고 했을 때 '톰캣설치ROOT\work\Catalina\localhost\JSPBook\org\apache\jsp\ 에 각각 Hello_jsp.java, Hello_jsp.class로 보관된다.

 이렇게 동작하는 동적 웹 프로그래밍은 실시간으로 새로운 정보를 추가시킬 수 있고, 웹 개발자가 소스코드를 추가하지 않아도 운영된다는 장점이 있다. 

 

2. JSP 생명주기 (25 page)

JSP 페이지를 컴파일한 *.class에는 jspInit(), _jspService(), jspDestory() 메소드가 존재하며, JSP 생성부터 파괴까지 다음과 같은 역할을 수행한다.

1. 번역(translation) 단계 - JSP 컨테이너가 JSP 소스 파일을 자바 코드(서블릿)로 변환환다.JSP 컨테이너는 파일을 읽고 구문을 분석하면서 구문의 정확성을 검증한다.

2. 컴파일(compilation) 단계 - 위의 생성된 서블릿을 컴파일하여 클래스 파일을 생성한다. 여기서는 자바 코드의 모든 구문을 검사하여 구문 오류를 검사한다.

3. 로딩(loading) 및 초기화(initialization) 단계 - 위에서 생성된 *.class를 로딩하고 클래스의 인스턴스를 작성한다. 이때 인수가 없는 생성자를 사용한다. 이때 JSP 컨테이너는 jspInit()를 호출하여 인스턴스가 된 객체를 초기화한다. 일반적으로 초기화는 한 번만 수행되고 DB 연결, 파일 열기, lookup 테이블 생성 등을 초기화한다.

4. 실행(execution) 단계 - 각 client 요청에 대해 JSP 컨테이너가 요청 및 응답 객체를 전달하는 _jspService() 메소드를 실행한다. 이는 요청 후 로딩 및 초기화될 때마다 _jspService() 메소드를 호출하여 응답 객체를 전달한다. 이 단계는 JSP 생명 주기가 끝날 때까지 모든 client의 요청에 대해 상호 작용한다.

5. 소멸(destruction) 단계 - JSP 컨테이너가 실행되고 있는 JSP를 jspDestroy() 메소드를 사용하여 제거한다. jspDestroy()메소드는 서블릿의 dsetroy() 메소드에 해당하며, DB연결 해제 또는 열려 있는 파일 닫기 등을 할 때 jspDestroy() 메소드를 오버라이딩한다. 즉, JSP 컨테이너가 해당 서블릿 인스턴스를 제거할 때 어떤 활동을 정리하기 위해 jspDestroy() 메소드를 호출한다.

 

* jspInit()와 jspDestroy() 메소드는 컨테이너가 기본 기능을 제공하기 때문에 오버라이딩이 선택 사항이지만, 기본적으로 _jspService() 메소드는 컨테이너가 추가하기 때문에 오버라이딩할 수 없다.

* 요청이 오면 JSP 컨테이너는 페이지를 변환할 필요가 있는지 확인한다. 수정된 파일이 있으면 다시 JSP 파일을 서블릿으로 변환하는 작업을 수행하고, 아니면 성능 향상을 위해 건너뛴다.

 

3. 스크립트 태그(스크립틀릿 태그&선언문 태그&표현문 태그)의 기능과 사용법(53 page)

(1). 선언문 태그

이는 변수나 메소드 등을 선언하는 태그이다. 선언문 태그에 선언된 변수와 메소드는 서블릿 프로그램으로 번역될 때 _jspService() 메소드 외부에 배치되므로 JSP 페이지 임의의 위치에서 선언할 수 있다. 심지어 스크립틀릿 태그보다 나중에 선언해도 스크립틀릿 태그에서 사용할 수 있다.

형식 : <%! 자바 코드; %>

선언문 태그로 선언된 변수 및 메소드는 서블릿 프로그램으로 번역될 때 클래스 수준의 멤버 변수가 되므로 전역변수 및 전역 메소드로 사용된다. 하지만 이를 스크립틀릿 태그에서 참조하면 _jspService() 메소드 내부에 들어가게 된다.

 

(2). 스크립틀릿 태그

스크립틀릿 태그는 자바 코드로 이루어진 로직 부분을 표현하며, out 객체를 사용하지 않고도 쉽게 HTML 응답을 만들어낼 수 있다. 이는 가장 일반적으로 사용되며 변수 또는 메소드 선언, 유효식 등 다수를 포함할 수 있다. 모든 텍스트, HTML 태그, 또는 JSP 요소는 스크립틀릿 태그 외부에 있어야 한다.

형식 : <% 자바 코드; %>

스크립틀릿 태그에 작성된 자바 코드는 서블릿 프로그램으로 변환될 때 _jspService() 메소드 내부에 복사된다. 이 태그에 선언된 변수는 지역변수가 되어 스크립틀릿 태그 내에서만 사용할 수 있다.

 

-선언문 태그와 스크립틀릿 태그의 차이점-

선언문 태그 스크립틀릿 태그
변수뿐만 아니라 메소드를 선언할 수 있다. 메소드 없이 변수만을 선언할 수 있다
서블릿 프로그램으로 변환될 때 _jspService() 메소드 외부에 배치된다. 서블릿 프로그램으로 변환될 때 _jspService() 메소드 내부에 배치된다.

(3). 표현문 태그

웹 브라우저에 출력할 부분을 표현한다. 이를 이용하여 선언문 태그 또는 스크립틀릿 태그에서 선언된 변수나 메소드의 반환 값을 외부로 출력할 수 있다. 표현문 태그는 스크립틀릿 태그에서 사용할 수 없으므로 이 경우에는 out.print() 메소드를 사용해야 한다. 표현문 태그에는 숫자, 문자, Boolean 등의 기본 데이터 타입과 자바 객체 타입도 사용 가능하다. 이에 작성된 모든 자바 코드의 값은 문자열로 반환되어 웹 브라우저에 출력된다. (기본 데이터 타입은 toString()을 통해 출력되고, 자바 객체 타입은 java.lang.Object 클래스의 toString() 메소드를 사용하거나 자체에서 선언한 toString()을 사용하여 출력된다.

형식 : <%= 자바 코드 %>

 

4.(1) forward 액션 태그의 페이지 흐름 처리 과정(107 page)

forward 액션 태그는 현재 JSP 페이지에서 다른 페이지로 이동하는 태그이다. JSP 컨테이너는 현재 JSP 페이지에서 forward 액션 태그를 만나면 그 전까지 출력 버퍼에 저장되어 있던 내용을 모두 삭제한다. 그리고 forward 액션 태그에 설정된 페이지로 프로그램의 제어가 이동한다.

형식 : <jsp:forward page = "파일명" />  또는  <jsp:forward page="파일명">   </jsp:forward> 

1. 웹 브라우저에서 웹 서버로 first.jsp 요청

2. JSP 컨테이너가 요청된 first.jsp 실행

3. first.jsp를 실행하다가 forward 액션 태그를 만나면 지금까지 저장된 출력 버퍼의 내용을 삭제하고 프로그램 제어를 page 속성에서 설정한 second.jsp로 이동

4. second.jsp 실행

5. JSP 컨테이너는 second.jsp를 실행한 결과를 웹 브라우저에 응답으로 보냄.

 

* 주의점 : 웹 서버는 forward 액션 태그를 수행할 때 출력 버퍼를 지우므로 현재 페이지에서 forward 액션 태그가 선언된 지점 이전까지 생성된 HTML 코드가 손실된다. 그러나 현재 페이지가 이미 전달 버퍼로 채워진 경우에는 전달이 중단될때까지 해당 내용을 웹 서버에 응답으로 보낸다. 이러면 잘못된 페이지가 클라이언트로 전송될 수 있다. 따라서 큰 출력을 생성하는 페이지에서 forward 액션 태그를 호출할 때는 신중해야 한다.

 

4.(2) include 액션 태그 기능과 사용법(111 page)

include 액션 태그는 include 디렉티브 태그처럼 현재 JSP 페이지의 특정 영역에 외부 파일의 내용을 포함하는 태그이다. 현재 JSP 페이지에 포함할 수 있는 외부 파일은 HTML, JSP, 서블릿 페이지 등이 있다.

형식 : <jsp:include page = "파일명"     flush="false" />

flush 속성 값은 설정한 외부 파일로 제어가 이동할 때 현재 JSP 페이지가 지금까지 출력 버퍼에 저장한 결과를 처리한다. 기본 값은 false인데, true로 설정하면 외부 파일로 제어가 이동할 때까지 현재 JSP 페이지가 지금까지 출력 버퍼에 저장된 내용을 웹 브라우저에 출력하고 출력 버퍼를 비운다. 이때 헤더 정보도 같이 전송되는데, 이후에는 헤더 정보를 추가해도 결과가 반영되지 않는다. 과정은 아래와 같다.

1. 웹 브라우저 -> 웹 서버로 first.jsp 요청

2. JSP 컨테이너는 요청받은 first.jsp를 처리하고 frist.jsp 내의 출력 내용이 출력 버퍼에 저장

3. 이때 <jsp:include page="second.jsp" flush="false"/> 문장을 만나면 하던 작업을 멈추고 프로그램 제어를 second.jsp로 이동.

4. second.jsp를 실행하고 second.jsp 내의 출력 내용이 출력 버퍼에 저장됨

5. second.jsp의 처리가 끝나면 다시 first.jsp로 프로그램 제어가 이동하는데, 이동 위치는 3번 ...false" />문장의 다음 행이 됨.

6. first.jsp의 나머지 부분을 처리하고, 출력할 내용이 있으면 출력 버퍼에 저장

7. JSP 컨테이너는 출력 버퍼의 내용을 웹 브라우저에 응답으로 보냄.

 

* include 액션 태그 vs forward 액션 태그

include 액션 태그는 forward 액션 태그처럼 외부 파일을 포함한다는 점이 비슷하지만 포함된 외부 파일이 실행된 후 현재 JSP 페이지로 제어를 반환한다는 것이 가장 큰 차이점이다. 또한 JSP 컨테이너는 현재 JSP 페이지에서 include 액션 태그를 만나면 include 액션 태그에 설정된 외부 파일의 실행 내용이 현재 JSP 페이지의 출력 버퍼에 추가 저장되어 출력된다.

 

*include 액션 태그 vs include 디렉티브 태그

 

5. 자바빈즈 (119 page)

자바빈즈는 동적 콘텐츠 개발을 위해 자바 코드를 사용하여 자바 클래스로 로직을 작성하는 방법이다. 즉, JSP 페이지에서 화면을 표현하기 위한 계산식이나 자료의 처리를 담당하는 자바 코드를 따로 분리하여 작성하는 것이 자바빈즈다. 따라서 JSP 페이지가 HTML과 같이 쉽고 간단한 코드만으로 구성되는데, 데이터를 담는 멤버 변수인 프로퍼티(property)와 데이터를 가져오거나 저장하는 메소드로 구성된다.

[규칙]

1. 자바 클래스는 java.io.Serializable 인터페이스를 구현해야 한다. (이는 자바빈즈에 저장된 프로퍼티를 포함한 채로 파일 시스템에 저장되거나 네트워크로 전송될 수 있도록 객체 직렬화를 제공해야 하므로 implement 해야 한다.)

2. 인수가 없는 기본 생성자가 있어야 한다. (추상 클래스 사용할 수 없음)

3. 모든 멤버 변수인 프로퍼티는 private 접근 지정자로 설정해야 한다,.

4. 모든 멤버 변수인 프로퍼티는 Getter/Setter() 메소드가 존재해야 한다. Getter() 메소드는 멤버 변수에 저장된 값을 가져올 수 있는 메소드이고, Setter() 메소드는 멤버 변수에 값을 저장할 수 있는 메소드이다.

 

이렇게 작성된 자바빈즈는 JSP 페이지에서 useBean, setProperty, getProperty 등의 자바빈즈 액션 태그와 스크립트 태그에 자바 코드와 같이 사용할 수 있다. 또한 폼 페이지의 입력 데이터나 HTML 페이지에서 넘어오는 데이터를 쉽게 자바빈즈 객체로 저장할 수 있다.

5.(1) useBean 액션 태그 (121 page)

JSP 페이지에서 자바빈즈를 사용하기 위해 실제 자바 클래스를 선언하고 초기화하는 태그이다. id 속성과 scope 속성을 바탕으로 자바빈즈의 객체를 검색하고, 객체가 발견되지 않으면 빈 객체를 생성한다.

형식 : <jsp:useBean id = "자바빈즈 식별이름" class = "자바빈즈 이름" scope = "범위" />

속성은 다음과 같다.

id : 자바빈즈를 식별하기 위한 이름이다.

class : 패키지 이름을 포함한 자바빈즈 이름이다. 자바빈즈는 인수가 없는 기존 생성자가 있어야 하며 추상 클래스를 사용할 수 없다.

scope : 자바빈즈가 저장되는 영역을 설정한다. page(기본 값), request, session, application 중 하나의 값을 사용한다.

 

** 객체 범위 종류 **  --> 웹 애플리케이션에는 4개의 객체 범위가 존재한다.

1. page 영역 : 한 번의 클라이언트 요청이 오면, 하나의 JSP 페이지가 응답된다.

2. request 영역 : 요청을 받아서 응답하기까지 객체가 유효한 영역이다. Servlet에서 forward 또는 include를 사용하면, request 요청 객체가 공유되어서 request 영역이 된다.

3. session 영역 : 하나의 브라우저 당 1개의 session 객체가 생성된다. 즉, 같은 브라우저 내에서 요청되는 페이지들은 같은 객체를 공유하게 되는데, 이를 세션 영역이라고 한다.

4. application 영역 : 하나의 애플리케이션 당 1개의 application 객체가 생성된다. 즉, 같은 애플리케이션 내에서 요청되는 페이지들은 같은 객체를 공유하게 되는데 이를 애플리케이션 영역이라고 한다.

 

scope 범위는 page < request < session < application 순이라는 것을 알 수 있다.

 

* DAO : Data Access Object. DB의 data에 접근하는 트랜잭션 객체

* DTO : Data Transfer Object. 계층 간 데이터 교환을 위한 자바 빈즈. DB 레코드의 data를 매핑하기 위한 데이터 객체. DTO는 로직을 가지지 않으며 getter, setter 메소드만 가지는 클래스이다. setter를 활용하므로 가변 속성이다

* VO : Value Object. Read Only 속성을 가진다.

 

* 자바 네이밍 툴 *

일반적 관례 : 클래스 이름은 대문자의 명사로 시작, 메소드 이름은 소문자의 동사, 변수는 소문자의 명사, 상수는 대문자의 명사이다. 

예 : 클래스 이름 - ClassName

      메소드 이름 : getValue, get_Value

      변수 이름 : $value, variable_Value

      상수 이름 : CONSTANT_VALUE

 

-- 공통 규칙 --

(1) 공통적으로 카멜 표기법(camelCase)을 사용한다. -> 기본적으로 변수명을 모두 소문자로 쓰고 여러 단어가 이어지는 경우 첫단어를 제외하고 각 단어의 첫글자만 대문자로 지정한다. ex) camelCase, memberInsert

(2) 약어는 최대한 쓰지 않으며 풀네임을 사용한다. (예외 : id, pw)

(3) 반의어는 반드시 대응되는 개념으로 사용한다. ex) start/finish, instert/delete, first/last ...

 

JSP(view)

파일명은 카멜 표기법을 사용한다.

- 목록 : list   ex) memberList.jsp

- 입력 : insert ex) memberInsert.jsp

- 수정 : update ex) memberUpdate.jsp

- 삭제 : delete ex) memberDelete.jsp

 

⓶ Package

(1) 모든 package는 하단에 표기된 상위 package를 가지며 영문소문자만을 사용한다.

- 상위 패키지명 com.smart.mobility

(2) 패키지명은 표준 패턴을 사용한다.

- com.smart.mobility.폴더명.controller

- com.smart.mobility.폴더명.service

(3) 패키지명은 한 단어의 명사만을 사용한다.

좋은 예 : com.smart.mobility.member.Insert

나쁜 예 : com.smart.mobility.memberInsert

 

⓷Class

(1) 모든 class는 영문자로만 구성하고 반드시 첫글자는 대문자로 시작하며 파스칼 식으로 표현한다

- DAO : 모든 DAO는 해당 테이블명을 파스칼식으로 표현하고 마지막에 DAO를 붙인다.

- DTO : 모든 DTO는 해당 테이블명(객체명)을 파스칼식으로 표현한다.

 

* 카멜 표기법

-단어가 여러 개 붙을 때, 앞 단어를 제외한 첫자를 대문자로 표기

- java, C# 등의 언어들에서 권장 (ex : dailyUserTable)

 

* 파스칼 표기법

- 모든 단어의 앞자가 대문자로 시작(단어의 수와 상관없음)

- 네임스페이스, 이벤트, 프로퍼티, 클래스 네임을 지정할 때 주로 사용

- 클래스 등에서 많이 사용 (ex : DailyUserTable)

 

5.(2) setProperty 액션 태그 (126 page)

useBean 액션 태그와 함께 자바빈즈의 setter() 메소드에 접근해 자바빈즈의 멤버 변수인 프로퍼티의 값을 저장하는 태그

형식 : <jsp:setProperty name="자바빈즈 식별이름" property="프로퍼티 이름" value="값" />

- 폼 페이지로부터 전달되는 요청 파라미터의 값을 직접 저장하거나 자바빈즈의 프로퍼티로 변경하여 값을 저장할 수 있다.

- 모든 자바빈즈 프로퍼티 이름과 동일하게 요청 파라미터를 설정할 수 있다.

 

속성은 아래와 같다.

name : useBean 태그에 id 속성 값으로 설정된 자바빈즈를 식별하기 위한 이름이다.

property : 자바빈즈의 property 이름이다. 만약 프로퍼티 이름에 '*'를 사용하면 모든 요청 파라미터가 자바빈즈 프로퍼티의 setter() 메소드에 전달됨을 의미한다.

value : 변경할 자바빈즈의 property 값이다. 만약 프로퍼티 값이 null이거나 존재하지 않는 요청 파라미터인 경우는 setProperty 액션 태그가 무시된다.

param : 자바빈즈의 프로퍼티 값을 전달하는 요청 파라미터의 이름이다. param과 value를 동시에 모두 사용할 수 없으며 하나를 선택하여 사용하는 것은 가능하다.

 

5.(3) getProperty 액션 태그 (129 page)

useBean 액션 태그와 함께 자바빈즈의 getter() 메소드에 접근하여 자바빈즈의 멤버 변수인 프로퍼티의 값을 가져오는 태그이다.

형식 : <jsp:getProperty name="자바빈즈 식별이름" property="프로퍼티 이름" />

 

속성은 아래와 같다.

name : useBean 태그에 id 속성 값으로 설정된 자바빈즈를 식별하기 위한 이름이다.

property : 자바빈즈의 프로퍼티 이름이다. 만약 프로퍼티 이름에 '*'를 사용하면 모든 요청 파라미터가 자바빈즈 프로퍼티의 getter() 메소드에 전달됨을 의미한다.

 

6. 내장 객체 (148 page) -> jspService() 내용이 꼭 포함되어야 한다. 

내장 객체는 JSP 페이지에서 사용할 수 있도록 JSP 컨테이너에 미리 정의된 객체이다. JSP 페이지가 서블릿 프로그램으로 번역될 때 JSP 컨테이너가 자동으로 내장 객체를 멤버 변수, 메소드 매개변수 등의 각종 참조 변수(객체)로 포함한다. 그래서 JSP 페이지에 별도의 import 문 없이 자유롭게 사용할 수 있다. 그리고 스크립틀릿 태그나 표현문 태그에 선언을 하거나 객체를 생성하지 않고도 직접 호출할 수 있다. jsp 파일을 보면 JSP페이지가 자바 서블릿 프로그램으로 번역될 때 내장 객체가 자동으로 포함된 것을 확인할 수 있다. 이러한 내장 객체는 서블릿 프로그램에서 모두 _jspService() 메소드 내부에 있다. 메소드 매개변수인 request,response, pageContext, session, application, config, out, page 등은 메소드 내에서 참조할 수 있는 참조 변수이다. 모든 내장 객체는 JSP 컨테이너가 관리하는 객체로, 이 중 request, session, application, pageContext로 속성을 관리할 수 있다. 속성은 각각의 내장 객체가 존재하는 동안 JSP 페이지 사이에서 정보를 주고받거나 공유하는데 사용된다.

위에서 만들어진 서블릿 프로그램과 서블릿 클래스는 프로젝트 이름이 JSPBook 이라고 했을 때 '톰캣설치ROOT\work\Catalina\localhost\JSPBook\org\apache\jsp\ 에 각각 Hello_jsp.java, Hello_jsp.class로 보관된다.

 

6.(1) request 내장 객체의 기능과 사용법. (150 page)

웹 브라우저에서 서버의 JSP 페이지로 전달하는 정보를 저장한다. 즉 폼 페이지로부터 입력된 데이터를 전달하는 요청 파라미터 값을  JSP 페이지로 가져온다. JSP 컨테이너는 웹 브라우저에서 서버로 전달되는 정보를 처리하기 위해 javax.servlet.http.HttpServletRequest 객체 타입의 request 내장 객체를 사용하여 사용자의 요구 사항을 얻어낸다. 이는 요청 파라미터 관련 메소드와 요청 HTTP 헤더 관련 메소드, 웹 브라우저/서버 메소드로 나뉜다.

 1.요청 파라미터는 사용자가 폼 페이지에 데이터를 입력한 후 서버에 전송할 때 전달되는 폼 페이지의 입력된 정보 형태를 말한다. 이러한 요청 파라미터는 <name=value> 형식으로 웹 브라우저에서 서버의 JSP 페이지로 전송한다. 이 때 폼 페이지에서 <input type="text"...>처럼 입력 양식이 텍스트 유형인 경우 값을 입력하지 않으면 서버로 빈 문자열이 전송된다. 하지만 체크 박스와 라디오 버튼 유형인 경우 선택하지 않고 전송하면 요청 파라미터 자체가 전달되지 않는다.

 2. 요청 HTTP 헤더 메소드를 통해 헤더 정보나 쿠키 관련 정보를 얻을 수 있는 메소드를 제공한다.

 3. 웹 브라우저/서버 메소드를 통해 웹 브라우저의 요청 및 서버 관련 정보를 얻을 수 있는 메소드를 제공한다.

 

6.(2) response 내장 객체의 기능과 사용법. (160 page)

사용자의 요청을 처리한 결과를 서버에서 웹 브라우저로 전달하는 정보를 저장한다. 즉 서버는 응답 헤더와 요청 처리 결과 데이터를 웹 브라우저로 보낸다. JSP 컨테이너는 서버에서 웹 브라우저로 응답하는 정보를 처리하기 위해 javax.servlet.http.HttpServletResponse 객체 타입의 response 내장 객체를 사용하여 사용자의 요청에 응답한다.

1. 페이지 이동 관련 메소드 - 리다이렉션(사용자가 새로운 페이지를 요청할 때와 같이 페이지를 강제로 이동하는 것)을 사용한다. 서버는 웹 브라우저에 다른 페이지로 강제 이동하도록 response 내장 객체의 리다이렉션 메소드를 제공한다. 페이지 이동 시 문자 인코딩을 알맞게 설정해야 한다. 

2. 응답 THTP 헤더 관련 메소드 - 서버가 웹 브라우저에 응답하는 정보에 헤더를 추가하는 기능을 제공한다. 헤더 정보에는 주로 서버에 대한 정보가 저장되어 있다.

3. 응답 콘텐츠 관련 메소드 - 웹 브라우저로 응답하기 위해 MIME유형, 문자 인코딩, 오류 메세지, 상태 코드 등을 설정하고 가져오는 메소드를 제공한다.

< 예 : 포워드 방식으로 페이지 이동하기 >

<%@page contentType="text/html; charset=utf-8" %>
<html>
<head>
<title>Action Tag</title>
</head>
<body>
	<%
	<h3>이 파일은 first.jsp입니다.</h3>
	<jsp:forward page=second.jsp" />
	<p>=== first.jsp의 페이지=====
	%>
</body>
</html>

 

< 예 : 리다이렉트 이용하여 페이지 이동하기 >

-사용법 : sendRedirect(String url)                         void                 설정한 URl 페이지로 강제 이동한다.

웹 브라우저에 response.jsp를 입력하면 이동된 페이지의 URL로 바뀌어 나타난다.

<html>
<head>
<title>Implicit Objects</title>
</head>
<body>
	<%
	response.sendRedirect("http://google.com");
	%>
</body>
</html>

 

< response 내장 객체로 5초마다 JSP 페이지 갱신하기 (165 page) >

<%@ page contentType="text/html; charset=utf-8"%>
<html>
<head>
<title>Implicit Objects</title>
</head>
<body>	   
	<p>이 페이지는 5초마다 새로고침 됩니다.     
		<%
			response.setIntHeader("Refresh", 5);
		%>
	<p>	<%=(new java.util.Date())%>
</body>
</html>

 

6.(3) out 내장 객체의 기능과 사용법 (168 page)

웹 브라우저에 데이터를 전송하는 출력 스트림 객체이다. JSP 컨테이너는 JSP 페이지에 사용되는 모든 표현문 태그와 HTML, 일반 텍스트 등을 out 내장 객체를 통해 웹 브라우저에 그대로 전달한다. 이는 스크립틀릿 태그에 사용하여 단순히 값을 출력하는 표현문 태그(<%= ...%/>)와 같은 결과를 얻을 수 있다.

 이때 우리가 아는 자바 로직으로는 system.println() 메소드를 생각했보았을 때, 이는 줄바꿈을 적용해주지만, out 내장 객체의println() 메소드에는 줄바꿈이 적용되지 않기 때문에 줄바꿈을 위해 <br> 태그를 사용하여야 한다.

 즉, println에서의 개행문자는 HTML 코드에 적용된 것이다. 예를 들어, 아래 코드로 JSP를 작성하고 HTML 소스를 보면 코드 상에서 개행문자가 (줄바꿈, println()) 작동하였지만, HTML에서는 줄을 바꾸면 띄워쓰기로 인식하기 때문에 줄바꿈이 아닌 공백이 생긴 것을 알 수 있다.

 

아래는 예시 코드이다.

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Test</title>
</head>
<body>
안녕
하세요.

<br/>
안녕하세요.
<br/>
<br/>
<%
	out.println("쉽게 배우는");
	out.println("JSP 웹 프로그래밍.");
	%>
	
	<br/>
	<%
		out.print("쉽게 배우는");
		out.print("JSP 웹 프로그래밍");
	%>
</body>
</html>

결과는 다음과 같다.

 

 

7. form 태그의 기능과 사용법 (183,184 page)

폼은 사용자가 웹 브라우저를 통해 입력된 모든 데이터를 한 번에 웹 서버로 전송하는 양식이다. 전송한 데이터는 웹 서버가 처리하고 처리 결과에 따라 다른 웹 페이지를 보여준다. 이는 사용자가 어떤 내용을 원하는지, 사용자의 요구 사항이 무엇인지 파악할 때 가장 많이 사용하는 웹 어플리케이션의 필수적인 요소이다.

 form 태그는 사용자가 다양한 정보를 입력하고 서로 전달할 때 사용하는 태그. 단독으로 쓰이지 않고 사용자가 다양한 정보를 입력하는 양식을 포함하는 최상위 태그이다.

형식 : <form 속성1="값1" [속성2="값2" ...]>

                      // 다양한 입력 양식 태그 (<input>, <select>, <textarea>)

         </form>

-> 속성을 이용하여 폼 데이터를 전송할 때 어디로 보낼지, 어떤 방식으로 보낼지 설정한다. form 태그의 모든 속성은 필수가 아니라 선택적으로 사용한다. 폼을 전송할 HTTP 방식의 기본 값이 GET이므로 method 속성을 생략할 수 있다. 

 

속성들 중 파일 업로드를 할 때에는 action, method, name, enctype 속성을 사용하였다.

form 태그의 method 속성은 웹 브라우저에서 웹 서버로 정보를 전송하는 방법으로 GET/POST 방식이 있다. 웹 브라우저에서 입력된 모든 데이터를 서버로 전송하는 기능은 동일하지만 방식이 다르다.

 GET 방식은 폼 데이터를 URL 끝에 붙여 전송하므로 웹 브라우저의 주소 표시 줄에 그대로 나타나여 데이터가 외부에 노출되므로, 보안에 취약하다. 또한 구분자로 물음표(?)를 사용하여 URL 뒤에 name=value와 같은 형식의 요청 파라미터를 붙이기 때문에 URL과 요청 파라미터를 구분한다. 또한 여러 개의 요청 파라미터를 전송할 경우 구분자 앰퍼샌드(&)를 사용하여 연결한다. 그러나 POST 방식은 GET 방식과 달리 내부적으로 전송하기 때문에 웹 브라우저의 주소 표시 줄에 구분자가 나타나지 않는다.

 

8. 폼 데이터 처리하기 (194 page)

(1) 요청 파라미터의 전체 값 받기

request 내장 객체는 웹 브라우저가 서버로 보낸 요청에 대한 다양한 정보를 담고 있어 getParameter() 메소드를 이용하여 요청 파라미터의 값을 얻을 수 있다. 텍스트 박스, 라디오 버튼, 드롭다운 박스와 같은 다양한 유형에 대해 한 번에 폼 데이터를 전달받을 수 있다.

 

 

연습문제 4장(7). 도서 목록 작성하기

(1). dto 패키지 - Book 클래스 작성

package dto;
 
public class Book implements java.io.Serializable{
    private String booktId;//도서 id
    private String name; //도서이름
    private Integer unitPrice;// 가격
    private String description;//설명
    private String author;
    private String publisher;//출판사
    private String category;//분류
    private long unitsInStock;//재고 수
    private long totalPages;//페이지 수 
    private String releaseDate;//출판일(월/년)
    private String condition; //신상품 중고품 재생품 
    public Book() {
        super();
        // TODO Auto-generated constructor stub
    }
    
    public Book(String booktId, String name, Integer unitPrice) {
        this.booktId = booktId;
        this.name = name;
        this.unitPrice = unitPrice;
    }
 
    public String getBooktId() {
        return booktId;
    }
    public void setBooktId(String booktId) {
        this.booktId = booktId;
    }
    
    public String getAuthor() {
        return author;
    }
 
    public void setAuthor(String author) {
        this.author = author;
    }
 
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getUnitPrice() {
        return unitPrice;
    }
    public void setUnitPrice(Integer unitPrice) {
        this.unitPrice = unitPrice;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public String getPublisher() {
        return publisher;
    }
    public void setPublisher(String publisher) {
        this.publisher = publisher;
    }
    public String getCategory() {
        return category;
    }
    public void setCategory(String category) {
        this.category = category;
    }
    public long getUnitsInStock() {
        return unitsInStock;
    }
    public void setUnitsInStock(long unitsInStock) {
        this.unitsInStock = unitsInStock;
    }
    public long getTotalPages() {
        return totalPages;
    }
    public void setTotalPages(long totalPages) {
        this.totalPages = totalPages;
    }
    public String getReleaseDate() {
        return releaseDate;
    }
    public void setReleaseDate(String releaseDate) {
        this.releaseDate = releaseDate;
    }
    public String getCondition() {
        return condition;
    }
    public void setCondition(String condition) {
        this.condition = condition;
    }
}

(2) dao 패키지 - BookRepository 클래스 작성

package dao;

import java.util.ArrayList;
import dto.Book;
import dto.Product;

public class BookRepository {
    ArrayList<Book>listOfBooks=new ArrayList<Book>();
    
    public BookRepository(){
        
        Book book1=new Book("Num1","HTML5+CSS",15000);
        book1.setDescription("워드나 PPT문서를 만들수 있나요? 그러면 문제 없습니다. 지금 바로 웹페이지에 도전하세요.");
        book1.setCategory("Hello Coding");
        book1.setPublisher("한빛미디어");
        book1.setAuthor("황재호");
        
        Book book2=new Book("Num2","쉽게 배우는 자바 프로그래밍",27000);
        book2.setDescription("객체 지향의 핵심과 자바의 현대적 기능을 다루면서 초보자가 쉽게 학습할 수 있습니다.");
        book2.setCategory("IT모바일");
        book2.setPublisher("한빛아카데미");
        book2.setAuthor("우종중");
        
        Book book3=new Book("Num3","스프링4 입문",27000);
        book3.setDescription("스프링은 단순히 사용 방법만 익히는것보다 아키텍쳐를 이해하는게 중요합니다!");
        book3.setCategory("IT모바일");
        book3.setPublisher("한빛미디어");
        book3.setAuthor("하세가와 유이치,오오노 와타루,토키 코헤이(권은철,전민수)");
        
        listOfBooks.add(book1);
        listOfBooks.add(book2);
        listOfBooks.add(book3);
    }
    public ArrayList<Book> getAllProducts(){
        return listOfBooks;
    }
}

(3) welcome.jsp 작성

<%@ page contentType="text/html; charset=UTF-8"%>
<%@ page import="java.util.ArrayList" %>
<%@ page import="dto.Book" %>
<jsp:useBean id="BookDAO" class="dao.BookRepository" scope="session"/>
<html>
<head>
<link rel="stylesheet"
    href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<title>Welcome</title>
</head>    
<body>
 
<nav class="navbar navbar-expand navbar-dark bg-dark">
    <div class="container">
        <div class="navbar-header">    
            <a class="navbar-brand" href="./welcome.jsp">Home</a>
        </div>
    </div>
</nav>
 
<%! String greeting="도서 목록";%>
<div class="jumbotron">
    <div class="container">
        <h1 class="display-3">
        <%=greeting %>
        </h1>
    </div>
</div>
<%ArrayList<Book> listOfBooks=BookDAO.getAllProducts(); %>
<div class="container">
        <div class="col" align="left">
            <%for(int i=0;i<listOfBooks.size();i++){
                Book book=listOfBooks.get(i);
            %>
            <div class="col-lg">
                <h4>[<%=book.getCategory() %>] <%=book.getName() %></h4><p>
                <p><%=book.getDescription()%>
                <p><%=book.getAuthor() %>|<%=book.getPublisher() %>|<%=book.getUnitPrice() %>
            </div>
            <hr>
            <%} %>            
        </div> 
        
<footer class="container">
    <p>&copy; BookMarket</p>
</footer>
</body>
</html>

예제 6-5. 회원 가입에서 폼 데이터 전송받기. (form05.jsp)

<%@ page contentType="text/html; charset=utf-8"%>
<html>
<head>
<title>Form Processing</title>
</head>
<body>
	<h3>회원가입</h3>
	<form action="form05_process.jsp" name="member" method="post">
		<p>	아이디 : <input type="text" name="id"> <input type="button"	value="아이디 중복검사">
		<p>	비밀번호 : <input type="password" name="passwd">
		<p>	이름 : <input type="text" name="name">
		<p>	연락처 : <select name="phone">
				<option value="010">010</option>
				<option value="011">011</option>
				<option value="016">016</option>
				<option value="017">017</option>
				<option value="019">019</option>
			</select> - <input type="text" maxlength="4" size="4" name="phone2"> -
			<input type="text" maxlength="4" size="4" name="phone3">
		<p>	성별 : <input type="radio" name="sex" value="남성" checked>남성 <input
				type="radio" name="sex" value="여성">여성
		<p>	취미 : 독서<input type="checkbox" name="hobby" value="독서" checked>
			운동<input type="checkbox" name="hobby" value="운동" > 
			영화<input type="checkbox" name="hobby" value="영화">
		<p>	<textarea name="comment" cols="30" rows="3"	placeholder="가입인사를 입력해주세요"></textarea>
		<p>	<input type="submit" value="가입하기"> 
			<input type="reset" 	value="다시쓰기">
	</form>
</body>
<html>

form05_process.jsp는 아래와 같다.

<%@ page contentType="text/html; charset=utf-8"%>
<html>
<head>
<title>Form Processing</title>
</head>
<body>
	<%
		request.setCharacterEncoding("UTF-8");		

		String id = request.getParameter("id");
		String passwd = request.getParameter("passwd");
		String name = request.getParameter("name");
		String phone1 = request.getParameter("phone1");
		String phone2 = request.getParameter("phone2");
		String phone3 = request.getParameter("phone3");
		String sex = request.getParameter("sex");
		String[] hobby = request.getParameterValues("hobby");
		String comment = request.getParameter("comment");
	%>
	<p> 아이디 : <%=id%>
	<p>	비밀번호 : <%=name%>
	<p>	이름 : <%=passwd%>
	<p>	연락처 : <%=phone1%>-<%=phone2%>-<%=phone3%>
	<p>	성별 : <%=sex%>
	<p>	취미 : 
		<%
			if (hobby != null) {
				for (int i = 0; i < hobby.length; i++) {
					out.println(" " + hobby[i]);
				}
			}
		%>
	
	<p>	가입인사 : <%=comment%>
</body>
</html>

예제 6.6 - 폼 데이터를 한 번에 전송받기.

-form06.jsp

<%@ page contentType="text/html; charset=utf-8"%>
<html>
<head>
<title>Form Processing</title>
</head>
<body>
	<h3>회원가입</h3>
	<form action="form06_process.jsp" name="member" method="post">
		<p>	아이디 : <input type="text" name="id"> <input type="button"	value="아이디 중복검사">
		<p>	비밀번호 : <input type="password" name="passwd">
		<p>	이름 : <input type="text" name="name">
		<p>	연락처 : <select name="phone">
				<option value="010">010</option>
				<option value="011">011</option>
				<option value="016">016</option>
				<option value="017">017</option>
				<option value="019">019</option>
			</select> - <input type="text" maxlength="4" size="4" name="phone2"> -
			<input type="text" maxlength="4" size="4" name="phone3">
		<p>	성별 : <input type="radio" name="sex" value="남성" checked >남성 
				<input  type="radio" name="sex" value="여성">여성
		<p>	취미 : 독서<input type="checkbox" name="hobby" value="독서" checked >
			운동<input type="checkbox" name="hobby" value="운동" > 
			영화<input type="checkbox" name="hobby" value="영화">
		<p>	<textarea name="comment" cols="30" rows="3"	placeholder="가입인사를 입력해주세요"></textarea>
		<p>	<input type="submit" value="가입하기"> 
			<input type="reset"	value="다시쓰기">
	</form>
</body>
<html>

- form06_process.jsp

<%@ page contentType="text/html; charset=utf-8"%>
<html>
<head>
<title>Form Processing</title>
</head>
<body>
	<h3>회원가입</h3>
	<form action="form06_process.jsp" name="member" method="post">
		<p>	아이디 : <input type="text" name="id"> <input type="button"	value="아이디 중복검사">
		<p>	비밀번호 : <input type="password" name="passwd">
		<p>	이름 : <input type="text" name="name">
		<p>	연락처 : <select name="phone">
				<option value="010">010</option>
				<option value="011">011</option>
				<option value="016">016</option>
				<option value="017">017</option>
				<option value="019">019</option>
			</select> - <input type="text" maxlength="4" size="4" name="phone2"> -
			<input type="text" maxlength="4" size="4" name="phone3">
		<p>	성별 : <input type="radio" name="sex" value="남성" checked >남성 
				<input  type="radio" name="sex" value="여성">여성
		<p>	취미 : 독서<input type="checkbox" name="hobby" value="독서" checked >
			운동<input type="checkbox" name="hobby" value="운동" > 
			영화<input type="checkbox" name="hobby" value="영화">
		<p>	<textarea name="comment" cols="30" rows="3"	placeholder="가입인사를 입력해주세요"></textarea>
		<p>	<input type="submit" value="가입하기"> 
			<input type="reset"	value="다시쓰기">
	</form>
</body>
<html>

 

9. import 와 useBean 의 차이 (209 page)

useBean을 썼을 때는 데이터가 자동으로 mapping 되기 때문에 import 를 썼을 때보다 훨씬 더 가독성 있게 코드를 작성할 수 있다. 하지만 우리 책에서 새로운 상품을 추가하거나 수정할 때는 getter(), setter() 메소드를 이용하여 instance() 메소드를 활용하는 것이 더 편리하기에, 상품 접근 클래스 dao.ProductRepository 패키지로 import 하였다. ProductRepository 클래스의 객체 변수 instance를 호출하는 getInstance(). 메소드를 작성하여 getAllProducts() 메소드를 호출하고, 반환 결과 값을 ArrayList<Product> 객체 타입의 변수 listOfProducts에 저장한다.

 

10. 파일 업로드 - MultipartRequest  -> cos.jar 라이브러리 필요 (218 page)

MultipartRequest는 웹 페이지에서 서버로 업로드되는 파일 자체만 다루는 클래스이다. 웹 브라우저가 전송한 multipart/form-data 유형과 POST 방식의 요청 파라미터 등을 분석한 후 일반 데이터와 파일 데이터를 구분하여 파일 데이터에 접근한다. 또한 한글 인코딩 값을 얻기 쉽고, 서버의 파일 저장 폴더에 동일한 파일명이 있으면 파일명을 자동으로 변경한다. MultipartRequest 클래스는 cos(com.oreilly.servlet) 패키지에 포함되어 있는 파일 업로드 컴포넌트로, 오픈 라이브러리 cos.jar를 다음 배포 사이트에서 직접 다운로드해서 사용한다. 그리고 JSP 페이지에 page 디렉티브 태그의 import 속성을 사용하여 패키지 com.oreilly.servlet.*을 설정해야 한다.

- 배포 사이트 : http://servlets.com/cos/

- 다운로드 파일 : cos-26Dec2008.zip

- 웹 애플리케이션의 /WebContent/WEB_INF/lib 폴더에 cos.jar 파일 붙여넣기

MultipartRequest 클래스를 이용하여 파일을 업로드하려면 먼저 MultipartRequest 객체를 생성한다. 그리고 생성된 객체를 통해 MultipartRequest 클래스가 제공하는 메소드를 사용하 여 웹 브라우저가 전송한 multipart/form-data 유형의 요청 파라미터를 읽어오고 파일을 업로드한다.

 

MultipartReqeust 메소드는 웹 브라우저에서 전송되는 요청 파라미터 중 일반 데이터는 getParameter() 메소드로 값을 받고, 파일은 getFileNames() 메소드로 데이터를 받는다. 

 

MultipartRequest를 이용한 파일 업로드 방식은 내부 처리에 의해 뒤에 숫자를 붙이는 등 중복을 피할 수 있다.

 

MultipartRequest 생성자의 매개변수에는 다음이 있다.

request - Request 내장 객체를 설정한다.

saveDirectory - 서버의 파일 저장 경로를 설정한다.

maxPostSize - 파일의 최대 크기(바이트 단위)를 설정한다. 최대 크기를 초과하면 IOException이 발생한다.

encoding - 인코딩 유형을 설정한다.

policy - 파일명 변경 정책을 설정한다. saveDirectory에 파일명이 중복되는 경우 덮어쓰기 여부를 설정하며, 설정하지 않으면 덮어쓴다.

 

예제 7-2. MultipartRequest 클래스를 이용하여 여러 파일 업로드 및 정보 출력하기. -> getParameter(String name), getFileNames(), getFilesystenName(String name) 필요. process_jsp 에서 23번째 줄 multi.getFileNames(); 이후에 역순으로 해줘야 하는 것!!!

- fileupload02.jsp

<%@ page contentType="text/html; charset=utf-8"%>
<html>
<head>
<title>File Upload</title>
</head>
<body>
	<form name="fileForm" method="post" enctype="multipart/form-data" action="fileupload02_process.jsp">
		<p>	이 름1  : <input type="text" name="name1"> 
			제 목1 : <input type="text" name="subject1"> 
			파 일1 : <input type="file" name="filename1">
		<p>	이 름2  : <input type="text" name="name2"> 
			제 목2 : <input type="text" name="subject2"> 
			파 일2 : <input type="file" name="filename2">
		<p>	이 름3 : <input type="text" name="name3"> 
			제 목3 : <input type="text" name="subject3"> 
			파 일3 : <input type="file" name="filename3">
		<p>	<input type="submit" value="파일 올리기">
		</p>
	</form>
</body>
</html>

-fileupload02_process.jsp

<%@ page contentType="text/html; charset=utf-8"%>
<%@ page import="com.oreilly.servlet.*"%>
<%@ page import="com.oreilly.servlet.multipart.*"%>
<%@ page import="java.util.*"%>
<%@ page import="java.io.*"%>
<html>
<head>
<title>File Upload</title>
</head>
<body>
	<%
		MultipartRequest multi = new MultipartRequest(request, "C:\\upload", 5 * 1024 * 1024, "utf-8", 	new DefaultFileRenamePolicy());

		String name1 = multi.getParameter("name1");
		String subject1 = multi.getParameter("subject1");		

		String name2 = multi.getParameter("name2");
		String subject2 = multi.getParameter("subject2");		

		String name3 = multi.getParameter("name3");
		String subject3 = multi.getParameter("subject3");
		
		Enumeration files = multi.getFileNames();

		String file3 = (String) files.nextElement();
		String filename3 = multi.getFilesystemName(file3);

		String file2 = (String) files.nextElement();
		String filename2 = multi.getFilesystemName(file2);

		String file1 = (String) files.nextElement();
		String filename1 = multi.getFilesystemName(file1);				
	%>
	<table border="1">
		<tr>
			<th width="100">이름</th>
			<th width="100">제목</th>
			<th width="100">파일</th>
		</tr>
		<%
			out.print("<tr><td>" + name1 + " </td>");
			out.print("<td>" + subject1 + " </td>");
			out.println("<td> " + filename1 + "</td></tr>\n");

			out.print("<tr><td>" + name2 + " </td>");
			out.print("<td>" + subject2 + " </td>");
			out.println("<td> " + filename2 + "</td></tr>\n");

			out.print("<tr><td>" + name3 + " </td>");
			out.print("<td>" + subject3 + " </td>");
			out.println("<td> " + filename3 + "</td></tr>\n");			
		%>
	</table>
</body>
</html>

11. 파일 업로드 - Commons-FileUpload(아파치 API) ->commons-fileupload.jar, commons-io.jar 라이브러리 필요 (229 page)

파일 업로드 패키지인 Commons-FileUpload는 서버의 메모리상에서 파일 처리가 가능하도 록 지원한다. 이 패키지는 Commons-io 패키지를 바탕으로 작성되었기 때문에 웹 브라우저 에서 서버로 파일을 업로드하기 위해 오픈 라이브러리 commons-fileupload.jar, commonsio.jar 파일을 다음 배포 사이트에서 직접 다운로드해서 사용한다. 그리고 JSP 페이지에 page 디렉티브 태그의 import 속성을 이용하여 패키지 org.apache.commons.fileupload.* 를 설정해야 한다.

- 배포 사이트 : http://commons.apache.org/downloads/

- 다운로드 파일 : commos-fileupload-1.4-bin.zip, commons-io-2.11.0-bin.zip

- 웹 애플리케이션의 /WebContent/WEB_INF/lib 폴더에 두 jar 파일 붙여넣기

 

압축을 푼 후 jar, kar 파일을 서버 톰캣의 /common/lib폴더와 자바 JDK/lib폴더에 추가한다. Commons-FileUpload를 이용하여 파일을 업로드하려면 먼저 Commons-FileUpload 패키지 에 포함되어 있는 DIskFileUpload 객체를 생성한다. 생성된 객체를 통해 DiskFileUpload 클 래스가 제공하는 메소드를 사용하여 웹 브라우저가 전송한 multipart/form-data 유형의 요 청 파라미터를 가져온다. 그리고 FileItem 클래스의 메소드를 사용하여 요청 파라미터가 일 반 데이터인지 파일인지 분석 및 처리하여 파일을 업로드한다.

 

Commons-FileUpload를 이용하여 파일을 업로드하기 위해 필요한 절차는 다음과 같다.1. 먼저 Commons-FileUpload 패키지에 포함되어 있는 DiskFileUpload 객체를 생성한다.DiskFileUpload upload = new DiskFileUpload();

 

2. 생성된 객체를 통해 DiskFileUpload 클래스가 제공하는 메소드를 사용하여 웹 브라우저가 전송한 multipart/form-data 유형의 요청 파라미터를 가져온다.

List items = upload.parseRequest(request);

 

3. Fileitem 클래스의 메소드를 사용하여 요청 파라미터가 일반 데이터인지 파일인지 분석 및 처리하여 파일을 업로드한다. 

if (item.isFormField() {....}

 

이때 사용하는 DiskFileUpload 클래스의 메소드 중 parseRequest(HttpServletRequest req)는 List<FileItem> 유형이며, multipart/form-data. 유형의 요청 파라미터를 가져온다.

또한 FileItem 클래스 메소드 중 isFormField()는 boolean 유형이며 요청 파라미터가 파일이 아니라 일반 데이터인 경우 true를 반환한다.

 

Commons-FileUpload를 방식을 이용할 때, 같은 이름으로 중복해서 파일업로드를 하게 되면 오류가 발생한다.

[fileupload04.jsp]

<%@ page contentType="text/html; charset=utf-8"%>
<html>
<head>
<title>File Upload</title>
</head>
<body>
	<form name="fileForm" method="post" enctype="multipart/form-data" action="fileupload04_process.jsp">
		<p>	이 름  : <input type="text" name="name">
		<p>	제 목 : <input type="text" name="subject">
		<p>	파 일 : <input type="file" name="filename">
		<p>	<input type="submit" value="파일 올리기">
		</p>
	</form>
</body>
</html>

[fileupload04_process.jsp]

<%@page contentType="text/html; charset=utf-8"%>
<%@page import="org.apache.commons.fileupload.*"%>
<%@page import="java.io.*"%>
<%@page import="java.util.*"%>
<html>
<head>
<title>File Upload</title>
</head>
<body>
	<%
		String path = "C:\\upload";

		DiskFileUpload upload = new DiskFileUpload();
		
		upload.setHeaderEncoding("utf-8"); // 한글 인코딩 추가
		upload.setSizeMax(1000000); //업로드할 최대 크기
		upload.setSizeThreshold(4096); //메모리 상에 저장할 최대 크기
		upload.setRepositoryPath(path); // 업로드된 파일을 임시 저장할 경로

		List items = upload.parseRequest(request);
		Iterator params = items.iterator();

		while (params.hasNext()) { //홈페이지에서 전송된 요청 파라미터가 없을 때까지 반복
			FileItem item = (FileItem) params.next();

			if (item.isFormField()) { //일반 값일 때
				String name = item.getFieldName();
				String value = item.getString("utf-8");
				out.println(name + "=" + value + "<br>");
			} else { // 파일일 때
				String fileFieldName  = item.getFieldName();				
				String fileName = item.getName();
				String contentType = item.getContentType();

				fileName = fileName.substring(fileName.lastIndexOf("\\") + 1);
				long fileSize = item.getSize();

				File file = new File(path + "/" + fileName);
				item.write(file);

				out.println("-----------------------------------<br>");
				out.println("요청 파라미터 이름 : " + fileFieldName  + "<br>");
				out.println("저장 파일 이름 : " + fileName + "<br>");
				out.println("파일 콘텐츠 타입 : " + contentType + "<br>");
				out.println("파일 크기 : " + fileSize);
			}
		}
	%>
</body>
</html>

 

12. 상품 이미지 등록하기(238 page)

1. 상품 이미지를 저장 및 관리하기 위해 Product 클래스에 필드를 선언한다.,

2. 추가된 멤버 변수의 Setter/Getter() 메소드 작성하기

3. 상품 데이터 접근 클래스 수정하기 : ProductRepository 클래스의 기본 생성자에 상품 이미지를 설정하도록 다음과 같이 추가 작성한다.

4. 정적 리소스 관리 폴더 만들기 : /WebContent/ 폴더에 resources 폴더를 생성하고, 여기에 이미지 파일을 관리하는 images 폴더와 부트스트랩 파일(bootstra.css)을 관리하는 css폴더를 생성한다.

- http://getbootstrap.com/에서 서 bootstrap-4.0.0-dist.zip 파일 다운로드 -> 압축 푼 후 css 폴더에서 bootstrap.min.css 파일을 /WebContent/resources/css/ 폴더에 넣는다.

5. 상품 목록 페이지 수정하기 : products.jsp 파일에 부트스트랩 CSS를 포함하고 상품 이미지를 출력하기 위해 수정이 필요하다. (241 page)

6. 상품 상세 정보 페이지 수정하기 : product.jsp 파일에 부트스트랩 CSS를 포함하고 상품 이미지를 출력하기 위해 다음과 같이 수정한 후 실행한다.

 

예제 7-6 상품 이미지 업로드하기

C의 upload 폴더에 저장 위치 만들기 -> 오픈 라이브러리 cos.jar 파일을 /WebContent/WEB-INF/lib/ 폴더에 cos.jar파일 등록 -> product.jsp, products.jsp, addProduct.jsp 파일 수정

 

연습문제 3번

[fileupload01.jsp]

<%@ page contentType="text/html; charset=utf-8"%>
<html>
<head>
<title>File Upload</title>
</head>
<body>
	<form name="fileForm" method="post" enctype="multipart/form-data"
		action="fileupload01_process.jsp">
		<p> 파 일 : <input type="file" name="filename">
		<p>	<input type="submit" value="파일 올리기">
		</p>
	</form>
</body>
</html>

[fileupload01_process.jsp]

<%@ page contentType="text/html; charset=utf-8"%>
<%@ page import="com.oreilly.servlet.*"%>
<%@ page import="com.oreilly.servlet.multipart.*"%>
<%@ page import="java.util.*"%>
<%@ page import="java.io.*"%>
<html>
<head>
<title>File Upload</title>
</head>
<body>
<%
	MultipartRequest multi = new MultipartRequest(request, "C:\\upload", 5 * 1024 * 1024, "utf-8",
	new DefaultFileRenamePolicy());
	
	Enumeration files = multi.getFileNames();
	
	String name = (String) files.nextElement();
	String filename = multi.getFilesystemName(name);
	String original = multi.getOriginalFileName(name);
	String type = multi.getContentType(name);
	File file = multi.getFile(name);

	out.println("요청 파라미터 이름 : " + name + "<br>");
	out.println("실제 파일 이름 : " + original + "<br>");
	out.println("저장 파일 이름 : " + filename + "<br>");
	out.println("파일 콘텐츠 유형 : " + type + "<br>");

	if (file != null) {
		out.println(" 파일 크기 : " + file.length());
		out.println("<br>");
	}
%>
</body>
</html>

 

도서 목록 및 추가 (실습)

1. dao - BookRepository.java

package dao;

import java.util.ArrayList;
import dto.Book;


public class BookRepository{
	
	private static BookRepository instance = new BookRepository();

	public static BookRepository getInstance(){
		return instance;
	} 
	
	private ArrayList<Book> listOfBooks = new ArrayList<Book>();
	
	public BookRepository() {
	
		Book book1= new Book("ISBN1234"," HTML5+CSS3 ", 15000);
		book1.setAuthor("황재호");
		book1.setDescription("워드나 PPT 문서를 만들 수 있나요? 그러면 문제 없습니다. 지금 바로 웹페이지 제작에 도전해보세요. 지금 당장 컴퓨터가 없어도 괜찮습니다. 코드와 실행 화면이 바로 보여서 눈으로만 읽어도 어떻게 작동하는지 쉽게 파악할 수 있는 것은 기본이고, 중간중간 퀴즈를 추가하여 재미있게 게임하듯 복습할 수 있습니다.");
		book1.setPublisher("한빛미디어");
		book1.setCategory("Hello Coding");
		book1.setUnitsInStock(1000);
		book1.setTotalPages(288);
		book1.setReleaseDate("2018/03/02");
		book1.setFilename("ISBN1234.jpg");
		
		
		Book book2 = new Book("ISBN1235","쉽게 배우는 자바 프로그래밍", 27000);
		book2.setAuthor("우종중");
		book2.setDescription("객체 지향의 핵심과 자바의 현대적 기능을 충실히 다루면서도초보자가 쉽게 학습할 수 있게 구성했습니다. 시각화 도구를 활용한 개념 설명과 군더더기 없는 핵심 코드를 통해 개념과 구현을 한 흐름으로 학습할 수 있습니다. 또한 ‘기초 체력을 다지는 예제 → 셀프 테스트 → 생각을 논리적으로 정리하며 한 단계씩 풀어 가는 도전 과제 → 스토리가 가미된 흥미로운 프로그래밍 문제’ 등을 통해 프로그래밍 실력을 차근차근 끌어올릴 수 있습니다");
		book2.setPublisher("한빛아카데미");
		book2.setCategory("IT모바일");
		book2.setUnitsInStock(1000);
		book2.setTotalPages(692);
		book2.setReleaseDate("2017/08/02");
		book2.setFilename("ISBN1235.jpg");
		
		
		Book book3= new Book("ISBN1236","스프링4 입문 ",27000);
		book3.setAuthor("하세가와 유이치 , 오오노 와타루 , 토키 코헤이(권은철 , 전민수 ) ");
		book3.setDescription("스프링은 단순히 사용 방법만 익히는 것보다 아키텍처를 어떻게 이해하고 설계하는지가 더 중요합니다. 예제를 복사해 붙여넣는 식으로는 실제 개발에서 스프링을 제대로 활용할 수 없습니다. 이 책에서는 웹 애플리케이션의 기초를 다지고 스프링 코어를 살펴보며 클라우드 네이티브 입문까지 다룹니다. 이제 막 실무에 뛰어든 웹 애플리케이션 초급자나 개발 경험은 있지만 스프링은 사용해본 적 없는 분을 대상으로 가능한 한 쉽게 설명합니다 ");
		book3.setPublisher("한빛미디어");
		book3.setCategory("IT모바일");
		book3.setUnitsInStock(1000);
		book3.setTotalPages(520);
		book3.setReleaseDate("2017/11/01");
		book3.setFilename("ISBN1236.jpg");
		
		
		
		listOfBooks.add(book1);
		listOfBooks.add(book2);
		listOfBooks.add(book3);
		
		
	}
	public ArrayList<Book> getAllBooks() {
		return listOfBooks;
	}

	public Book getBookById(String bookId) {
		Book bookById = null;

		for (int i = 0; i < listOfBooks.size(); i++) {
			Book book = listOfBooks.get(i);
			if (book != null && book.getBookId() != null && book.getBookId().equals(bookId)) {
				
				bookById = book;
				break;
			}
		}
		return bookById;
	}
	
	public void addBook(Book book) {
		listOfBooks.add(book);
	}
	

}

 

2. dto - Book.java

package dto;

import java.io.Serializable;

public class Book implements Serializable {

	private static final long serialVersionUID = -4274700572038677000L;

	private String bookId; 		    //책 ID
	private String name;			//책이름
	private Integer  unitPrice; 	//가격
	private String author;			//저자
	private String description; 	//설명
	private String publisher;	    //출판사
	private String category; 		//분류
	private long   unitsInStock; 	//재고개수
	private long   totalPages; 		//페이지수
	private String releaseDate;   //출판일(월/년)
	private String condition; 		//신제품 or 구제품 or 리퍼브제품
	private String filename;

	public Book() {
		super();
}

	public Book(String bookId, String name, Integer unitPrice) {
		this.bookId = bookId;
		this.name = name;
		this.unitPrice = unitPrice;
	}

	public String getBookId() {
		return bookId;
	}

	
	public void setBookId(String bookId) {
		this.bookId = bookId;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer  getUnitPrice() {
		return unitPrice;
	}

	public void setUnitPrice(Integer  unitPrice) {
		this.unitPrice = unitPrice;
	}

	
	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

	
	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public String getPublisher() {
		return publisher;
	}

	public void setPublisher(String publisher) {
		this.publisher = publisher;
	}

	public String getCategory() {
		return category;
	}

	public void setCategory(String category) {
		this.category = category;
	}

	public long getUnitsInStock() {
		return unitsInStock;
	}

	public void setUnitsInStock(long unitsInStock) {
		this.unitsInStock = unitsInStock;
	}

	public long getTotalPages() {
		return totalPages;
	}

	public void setTotalPages(long totalPages) {
		this.totalPages = totalPages;
	}

	public String getReleaseDate() {
		return releaseDate;
	}

	public void setReleaseDate(String releaseDate) {
		this.releaseDate = releaseDate;
	}
	
	public String getCondition() {
		return condition;
	}

	public void setCondition(String condition) {
		this.condition = condition;
	}
	public String getFilename() {
		return filename;
	}

	public void setFilename(String filename) {
		this.filename = filename;
	}


}

 

3. addBook.jsp

<%@ page contentType="text/html; charset=utf-8"%>
<html>
<head>
<link rel="stylesheet" href="./resources/css/bootstrap.min.css" />
<title>도서 등록</title>
</head>
<body>
	<jsp:include page="menu.jsp" />	
	<div class="jumbotron">
		<div class="container">
			<h1 class="display-4">도서 등록</h1>
		</div>
	</div>
	<div class="container">
		<form name="newBook" action="./processAddBook.jsp"
			class="form-horizontal" method="post" enctype="multipart/form-data">
			<div class="form-group row">
				<label class="col-sm-2">도서코드</label>
				<div class="col-sm-3">
					<input type="text" name="bookId" class="form-control" >
				</div>
			</div>
			<div class="form-group row">
				<label class="col-sm-2">도서명</label>
				<div class="col-sm-3">
					<input type="text" name="name" class="form-control" >
				</div>
			</div>
			<div class="form-group row">
				<label class="col-sm-2">가격</label>
				<div class="col-sm-3">
					<input type="text" name="unitPrice" class="form-control" >
				</div>
			</div>
			<div class="form-group row">
				<label class="col-sm-2">저자</label>
				<div class="col-sm-3">
					<input type="text" name="author" class="form-control">
				</div>
			</div>
				<div class="form-group row">
				<label class="col-sm-2">출판사</label>
				<div class="col-sm-3">
					<input type="text" name="publisher" class="form-control">
				</div>
			</div>
			<div class="form-group row">
				<label class="col-sm-2">출판일</label>
				<div class="col-sm-3">
					<input type="text" name="releaseDate" class="form-control">
				</div>
			</div>
			<div class="form-group row">
				<label class="col-sm-2">총페이지 수</label>
				<div class="col-sm-3">
					<input type="text" name="totalPages" class="form-control">
				</div>
			</div>			
			<div class="form-group row">
				<label class="col-sm-2">상세정보</label>
				<div class="col-sm-5">
					<textarea name="description" cols="50" rows="2"
						class="form-control" placeholder="100자 이상 적어주세요"></textarea>
				</div>
			</div>			
			<div class="form-group row">
				<label class="col-sm-2">분류</label>
				<div class="col-sm-3">
					<input type="text" name="category" class="form-control" >
				</div>
			</div>
			<div class="form-group row">
				<label class="col-sm-2">재고수</label>
				<div class="col-sm-3">
					<input type="text" name="unitsInStock" class="form-control" >
				</div>
			</div>
			<div class="form-group row">
				<label class="col-sm-2">상태</label>
				<div class="col-sm-5">
					<input type="radio" name="condition" value="New " > 신규도서 
					<input type="radio" name="condition" value="Old" > 중고도서 
					<input type="radio" name="condition" value="EBook" > E-Book
				</div>
			</div>
			<div class="form-group row">
				<label class="col-sm-2">이미지 </label>
				<div class="col-sm-5">
					<input type="file" name="bookImage" class="form-control">
				</div>
			</div>
			<div class="form-group row">
				<div class="col-sm-offset-2 col-sm-10 ">
					<input type="submit" class="btn btn-primary" value="등록" >
				</div>
			</div>
		</form>
	</div>
</body>
</html>

 

4. book.jsp

<%@ page contentType="text/html; charset=utf-8"%>
<%@ page import="dto.Book"%>
<%@ page import="dao.BookRepository"%>

<html>
<head>
<link rel="stylesheet" href="./resources/css/bootstrap.min.css" />
<title>도서 정보</title>
</head>
<body>
	<jsp:include page="menu.jsp" />
	<div class="jumbotron">
		<div class="container">
			<h1 class="display-4">도서 정보</h1>
		</div>
	</div>
	<%
		String id = request.getParameter("id");
		BookRepository dao = BookRepository.getInstance();
		Book book = dao.getBookById(id);
	%>
	<div class="container">
		<div class="row">
			<div class="col-md-4">
				<img src="c:/upload/<%=book.getFilename()%>" style="width: 100%" />
			</div>
			<div class="col-md-8">
				<h4><b>[<%=book.getCategory()%>]<%=book.getName()%></b></h4>
				<p><%=book.getDescription()%>
				<p><b>도서코드 : </b><span class="badge badge-danger"> <%=book.getBookId()%></span>						
				<p><b>저자</b> : <%=book.getAuthor()%>				
				<p><b>출판사</b> : <%=book.getPublisher()%>
				<p><b>출판일</b> : <%=book.getReleaseDate()%>		
				<p><b>총 페이지수</b> : <%=book.getTotalPages()%>			
				<p><b>재고수</b> : <%=book.getUnitsInStock()%>				
				<h4><%=book.getUnitPrice()%>원</h4>
				<p><a href="#" class="btn btn-info"> 도서주문 &raquo;</a> 
					<a href="./books.jsp" class="btn btn-secondary"> 도서목록 &raquo;</a>
			</div>
		</div>
		<hr>
	</div>
	<jsp:include page="footer.jsp" />
</body>
</html>

 

5. books.jsp

<%@ page contentType="text/html; charset=utf-8"%>
<%@ page import="java.util.ArrayList"%>
<%@ page import="dto.Book"%>
<%@ page import="dao.BookRepository"%>


<html>
<head>
<link rel="stylesheet" href="./resources/css/bootstrap.min.css" />
<title>도서 목록</title>
</head>
<body>
	<jsp:include page="menu.jsp" />
	
	<div class="jumbotron">
		<div class="container">
			<h1 class="display-4">도서 목록</h1>
		</div>
	
	</div>
	<%
		BookRepository dao = BookRepository.getInstance();
		ArrayList<Book> listOfBooks = dao.getAllBooks();
	%>
      
	<div class="container">	
	<%
		for (int i = 0; i < listOfBooks.size(); i++) {
			Book book = listOfBooks.get(i);
	%>
		<div class="row" >
			<div class="col-md-3" align="center">	
			<img src="c:/upload/<%=book.getFilename()%>" width="60%">
			</div>			
			<div class="col-md-7">	
				<p><h5 ><b>[<%=book.getCategory()%>] <%=book.getName()%></b></h5>
				<p style="padding-top: 20px"><%=book.getDescription().substring(0, 100)%>... 
				<p><%=book.getAuthor()%> | <%=book.getPublisher()%> | <%=book.getUnitPrice()%>원
			</div>	
			<div class="col-md-2"  style="padding-top: 70px">						    			 
				<a href="./book.jsp?id=<%=book.getBookId()%>" class="btn btn-secondary" role="button"> 상세정보 &raquo;></a>
				
			</div>				
		</div>
		<hr>
	<%
		}
	%>
	</div>	
	<jsp:include page="footer.jsp" />
</body>
</html>

 

6. processAddBook.jsp

<%@ page contentType="text/html; charset=utf-8"%>
<%@ page import="dto.Book"%>
<%@ page import="dao.BookRepository"%>
<%@ page import="com.oreilly.servlet.*"%>
<%@ page import="com.oreilly.servlet.multipart.*"%>
<%@ page import="java.util.*"%>

<%
	request.setCharacterEncoding("UTF-8");

	String filename = "";
	String realFolder = "C:\\upload"; //웹 어플리케이션상의 절대 경로
	String encType = "utf-8"; //인코딩 타입
	int maxSize = 5 * 1024 * 1024; //최대 업로드될 파일의 크기5Mb

	MultipartRequest multi = new MultipartRequest(request, realFolder, maxSize, encType,
		new DefaultFileRenamePolicy());

	String bookId = multi.getParameter("bookId");
	String name = multi.getParameter("name");
	String unitPrice = multi.getParameter("unitPrice");
	String author = multi.getParameter("author");
	String publisher = multi.getParameter("publisher");
	String releaseDate = multi.getParameter("releaseDate");
	String totalPages = multi.getParameter("totalPages");
	String description = multi.getParameter("description");	
	String category = multi.getParameter("category");
	String unitsInStock = multi.getParameter("unitsInStock");
	String condition = multi.getParameter("condition");
	
	
	Integer price;

	if (unitPrice.isEmpty())
		price = 0;
	else
		price = Integer.valueOf(unitPrice);

	long stock;

	if (unitsInStock.isEmpty())
		stock = 0;
	else
		stock = Long.valueOf(unitsInStock);

	Enumeration files = multi.getFileNames();
	String fname = (String) files.nextElement();
	String fileName = multi.getFilesystemName(fname);
	
	
	BookRepository dao = BookRepository.getInstance();

	Book newBook = new Book();
	newBook.setBookId(bookId);
	newBook.setName(name);
	newBook.setUnitPrice(price);
	newBook.setAuthor(author);
	newBook.setPublisher(publisher);
	newBook.setPublisher(releaseDate);
	newBook.setPublisher(totalPages);
	newBook.setDescription(description);
	newBook.setCategory(category);
	newBook.setUnitsInStock(stock);
	newBook.setCondition(condition);
	newBook.setFilename(fileName);

	dao.addBook(newBook);

	response.sendRedirect("books.jsp");
%>
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.