서블릿
- 자바 기반 (자바 API를 모두 사용 가능)
- 개발된 application은 다양한 서버 환경에서 실행 가능(운영체제나 HW의 영향을 받지 않음)
- 웹 어플리케이션에서 효율적인 자료 공유 방법을 제공
- 다양한 오픈소스 라이브러리와 개발도구
- 하지만 HTML 응답을 위해 출력문으로 문자열결합을 사용해야한다.
- 서블릿에서의 HTML은 수정이 어렵다 (그리고HTML 폼(form)의 데이터 처리가 어렵다)
- 기본적으로 단일 요청과 응답을 처리하는 구조이므로, 다양한 경로의 URL 접근을 하나의 클래스에서 처리하기 어렵다.
서블릿 클래스
- 자바로 구현, 서블릿 컨테이너에 해당 클래스가 서블릿인 것을 알려야 한다. 또한 어떤 URL 접근에 실행해야 하는지 등록하는 과정 필요
- 서블릿 2.0 이상부터. (2.0은 웹 애플리케이션 구조를 컨테이너에 알려주기 위한 배포 서술자 web.xml에 등록해야 한다.)
(3.0은 자바 애너테이션을 이용)
- GenericServlet 클래스와 HttpServlet 클래스 중 하나를 상속해 구현
(javax.servlet.Servlet 인터페이스를 구현한 추상 클래스)
(HTTP 프로토콜에 최적화되어 있는 HttpServlet 클래스를 상속해 구현하는 것이 좋음)
- HttpServlet을 상속받아 doGet( ), doPost( ) 메서드를 오버라이딩한 구조
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);
}
- GenericServlet 추상클래스는 Servlet과 ServletConfig 인터페이스를 구현함
- HttpServlet은 GenericServlet 추상클래스를 상속받음
서블릿 정보 등록
- 2.0버전은 서블릿 클래스만으로 톰캣 실행이 불가능 -> web.xml 이나 annotation으로 서블릿임을 선언해야한다.
서블릿 정보 등록 - web.xml으로 서블릿임을 선언
<?xml version="1.0" encoding="utf-8">
<web-app ...>
<servlet>
<servlet-name> Hello </servlet-name> // servlet 이름
<servlet-class>jwbook.servlet.HelloServlet</servlet-class> // 서블릿 클래스 지정
</servlet>
<servlet-mapping>
<servlet-name> Hello </servlet-name> // servlet name을 매핑
<url-pattern> /hello </url-pattern> // 서블릿 요청 주소 매핑
</servlet-mapping>
</web-app>
- 위의 코드는 web.xml 작성 예시
- Dynamic Web Project로 웹 폴더를 생성할 때, next-next해서 제일 마지막 페이지에서 Generate web.xml deployment descriptor 에 꼭 체크를 하여야 web.xml이 생성된다.
서블릿 정보 등록 - 3.0에서 자바 애너테이션 등록
- web.xml 사용보다 애너테이션 사용이 권장됨
- 서블릿 생성
- 꼭 URL mapping에서 Edit을 눌러 ThirtSerVlet 에서 /Third로 변경
- 우선 기본 URL mapping 이름을 선택한 후 매핑 이름을 수정하기 위해 Edit...를 클릭
- Constructors from superclass 꼭 체크 해제!, init, destroy, doGet 체크!
- init : 메모리에 적재하기 위한 생성자
- destroy : 메모리에 삭제하기 위한 파괴자
- 생성된 코드에서 드래그한부분 없애기(주민등록번호나 마찬가지,, serial number가 충돌되어 오류가 날 수 있다.)
package sec01.ex01;
import java.io.IOException;
import javax.servlet.ServletConfig;
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 ThirdSerVlet
*/
@WebServlet("/Third")
public class ThirdSerVlet extends HttpServlet {
/* private static final long serialVersionUID = 1L; */
/**
* @see Servlet#init(ServletConfig)
*/
public void init(ServletConfig config) throws ServletException {
// TODO Auto-generated method stub
}
/**
* @see Servlet#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* @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);
}
}
- 여기서 필요한 메소드만 선택하여 사용하면 된다.
- init : ServletConfig형식의 데이트를 받아 메모리에 업로드(throws ServletException 필수!!)
- doGet : 요청된, 응답한,, 상위클래스에서 제공되는 (HttpServletRequest request) 요청, (HttpServletResponse response) 응답 ==> 요청request받아 응답할 것을 response에 넣어주기
- (위와 같은 코드) 여기서 @WebServlet("/Third")가 생성되어 있는 것을 확인할 수 있다.
서블릿 생명주기
1. 서블릿 초기화 : init() ==> 초기에 한 번 실행
2. 요청, 응답 : service(), doGet(), doPost() ==> 스레드를 통하여 동시 실행
3. 서블릿 종료 : destroy() ==> 종료할 때 한 번 실행
클라이언트 요청 -> public service() -> protected service() -> doXXX()
init() 함수
- 서블릿 초기화
- 클라이언트 요청이 들어오면 컨테이너는 해당 서블릿이 메모리에 있는지 확인
- 서블릿을 메모리에 적재해야 하는데, 이때 서블릿의 init( ) 메서드가 호출
- 각종 초기화 작업을 수행
- 처음 한번만 실행
- 만일 실행 중 서블릿이 변경되는 경우 기존 서블릿은 종료 Destroy되고 다시 시작되 면서 init( ) 메서드가 호출
service() 함수
- 요청/응답
- init()이후, 요청은 스레드로 실행
- serviec()를 통해 doGet()이나 doPost()
- 매개변수로 HttpServletRequest랑 HttpServletResponse 클래스 타입인 request와 response 객체가 제공된다.
destroy() 함수
- 서블릿 종료
- 컨테이너로부터 서블릿 종료 요청시 실행
- 한 번만 실행
사용자 정의 서블릿 클래스 만들기->
서블릿 생명주기 메서드 구현->
서블릿 매핑 작업->
웹브라우저에서 서블릿 매핑 이름으로 요청
사용자 정의 서블릿 만들기
1. init(), doGet() 또는 doPost(), destroy() 메서드를 오버라이딩해서 구현합니다.
2. 톰캣 servlet-api.jar 클래스 패스 설정
이클립스 상단의 New 아이콘을 클릭한 후 Dynamic Web Project를 선택
프로젝트 입력 후, 경로 설정, Generate web.xml deployment descripter 옵션 체크, Finish
프로젝트 이름 선택, 오른쪽 마우스, Build Path, Configure BuildPath... 선택
설정창에서 Libraries 탭을 클릭하고 Classpath를 선택한 후 Add External JARs...를 클릭
CATALINA_HOME(톰캣 루트 디렉터리)의 lib 디렉터리에 있는 servlet-api.jar을 선택, 열기 클릭
servlet-api.jar 클래스의 패스 설정을 확인, Apply and Close를 클릭해 종료
3. 첫번째 서블릿 생성
프로젝트의 Java Resources-src를 선택하고 마우스 오른쪽 버튼을 클릭한 후 New-Package를 선택
원하는 이름으로 패키지 생성
생성한 패키지 이름위에 마우스 대고 오른쪽 클릭-New-Class
클래스 이름 설정
**여기서 @WebServlet("/first")를 꼭 삭제(주석처리)해주어야한다 => 충돌 방지
4. 서블릿 매핑
http://주소:포트번호/프로젝트명/패키지명이 포함된 클래스명
클래스 이름이 길어지면 불편하고, 클래스 이름을 사용하면 보안에도 좋지않으므로,
서블릿 클래스에 대응하는 서블릿 매핑 이름으로 요청하기!!!
web.xml에서
<servlet> </servlet> 태그 안에 <servlet-name>과 <servlet-class> 태그를 넣어
<servlet-mapping> </servlet-mapping>태그 안에 <servlet-name>과 <url-pattern> 태그를 넣어 매핑
여기서 여러 개의 서블릿을 매핑하기 위해서는 <servlet>태그 나열 후, <servlet-mapping>태그 나열! (순서 중요)
<servlet> // 브라우저에서 요청하는 매핑 이름에 대해 실제로 실행하는 서블릿 클래스를 설정
<servlet-name>aaa</servlet-name> // <servlet-mapping>태그의 <servlet-name>태그와 동일
<servlet-class>sec01.ex01.FirstServlet</servlet-class> // 브라우저에서 요청하는 매핑 이름에 대해 실제로 기능을 수행하는 서블릿 클래스 설정
</servlet>
<servlet-mapping> // 브라우저에서 요청하는 논리적인 서블릿 설정
<servlet-name>aaa</servlet-name> // 매핑 이름으로 요청 시, 값이 같은 <servlet>태그의 <servlet-name>태그와 연결
<url-pattern>/first</url-pattern> // 브라우저에서 해당 서블릿을 요청하는 논리적인 서블릿 이름
</servlet-mapping>
5. 톰캣 프로젝트 실행
6. 브라우저에서 서블릿 요청
http://IP주소:포트번호/프로젝트이름(컨텍스트이름)/서블릿매핑이름
(나의 경우 포트번호 : 8080)
** 나의 IP 주소를 확인하려면 명령 프롬프트창에서 ipconfig 명령을 입력하여 확인
다수의 서블릿을 매핑하기 위해서는
새로운 서블릿을 같은 방법으로 생성
web.xml 파일에서 여러 개의 서블릿을 매핑하기 위해서는
<servlet>태그 나열 후, <servlet-mapping>태그 나열! (순서 중요)
로그파일 대체
web.xml 파일의 doGet에서 있던 실행문을 삭제하고, 로그파일로,,
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("hahee"); // 로그 파일 대체
}
콘솔에서 확인 가능
HttpServletRequest
- HTTP 프로토콜의 request 정보를 서블릿에 전달하기 위해 사용
- 서블릿 컨테이너에서 생성
- 클라이언트 요청이 doGet( ), doPost( )로 전달될 때 매개변수로 함께 전달
- 서블릿에서 클라이언트와 연결해 처리할 작업은 모두 HttpServletRequest로
https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html
여기서 메서드확인
- getParameter(name), getRequestURL(), getContextPath() 등이 있다.
서블릿 세 가지 기본 기능
<form>태그로 서블릿에 요청
- 해당 이벤트(클릭과 같은) 시, <form>태그의 action속성에 지정한 JSP나 서블릿으로 해당데이터 전송
- <form>태그의 name 속성 : 폼 이름 지정, 구분자역할, 자바스크립트에서 접근할 때 사용
- <form>태그의 method 속성 : 데이터를 전송할 때 전송방법 지정 (GET, POST 둘 중 하나, 기본:GET)
- <form>태그의 action 속성 : 데이터를 전송할 서블릿이나 JSP 지정. 서블릿으로 전송할 때는 매핑 이름 사용
- <form>태그의 encType 속성: 전송할 데이터의 encoding 타입 지정, 파일 업로드 시 multipart/form-data로 지정
- HttpServletRequest 클래스의 여러가지 메서드를 이용해서 전송된 데이터를 얻음
- String getParameter(String name) : name값 알고있을 때, name에 전송된 값 받아올 때 사용
- String[] getParameterValues(String name) : 같은 name에 여러 개의 값을 받아올 때 사용 (배열로 받기)
- Enumeration getParameterNames() : name값 모를 때
실습해보기 ( getParameter() 메서드 )
HTML 파일 생성
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>로그인 창</title>
</head>
<style>
* {
margin: 5px;
}
form {
width: 500px;
height: 500px;
text-align: center;
}
</style>
<body>
<form name="frmLogin" method="get" action="login" encType="UTF-8">
아이디 : <input type="text" name="user_id"><br>
비밀번호 : <input type="password" name="user_pw"><br>
<input type="submit" value="로그인"> <input type="reset" value="다시입력">
</form>
</body>
</html>
login.html
package sec01.ex01;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
/* private static final long serialVersionUID = 1L; */
public void init(ServletConfig config) throws ServletException {
System.out.println("init 메서드 호출");
}
public void destroy() {
System.out.println("destroy 메서드 호출");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
String user_id = request.getParameter("user_id");
String user_pw = request.getParameter("user_pw");
System.out.println("아이디 : " + user_id);
System.out.println("비밀번호 : " + user_pw);
}
}
LoginServlet.java
file:///C:/디렉토리이름/pro01/src/main/webapp/login.html 으로 html 실행 후 데이터 입력
입력했던 값을 Console창에서 확인할 수 있다.
getParameter() 메서드
- 변수 받아오기
getParameterValues() 메서드
- 요청 처리
- 배열로 받기!
- checkbox와 같은 것.
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
String user_id = request.getParameter("user_id");
String user_pw = request.getParameter("user_pw");
System.out.println("아이디 : " + user_id);
System.out.println("비밀번호 : " + user_pw);
String[] subject = request.getParameterValues("subject");
for(String str : subject) {
System.out.println("선택된 과목 : " + str);
}
}
getParameterNames() 메서드
- 요청 처리
- 전송되는 데이터가 많은 경우
- name의 값을 하나하나 기억할 필요 없이 getParameterNames() 메서드를 호출하여 일괄처리
- Enumeration 으로 받기!
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
Enumeration enu = request.getParameterNames();
while(enu.hasMoreElements()) {
String name = (String) enu.nextElement();
String[] values = request.getParameterValues(name);
for(String value : values) {
System.out.println("name = " + name + ", value = " + value);
}
}
}
HttpServletResponse
- HttpServletRequest와 마찬가지로 클라이언트와 연결된 처리가 가능
- 서버에서 클라이언트로 전달하려는 목적을 위한 기능 (클라이언트에서 서버가 아님!)
- HttpServletResponse 객 체를 생성하여 서블릿에 전달 (서블릿 컨테이너는 요청 클라이언트에 응답을 보내기 위해)
- 서블릿은 객체를 사용하여 content type, 응답코드, 메세지 등을 전송
https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html
↑↑↑↑HttpServletResponse 메소드 확인↑↑↑↑↑
서블릿 응답 처리
1. doGet() 혹은 doPost()에서 처리
2. javax.servlet.http.HttpServletResponse 객체 사용
3. setContentType()을 사용하여 클라이언트에게 전송할 MIME-TYPE(데이터종류)를 지정
4. 클라이언트(웹 브라우저)와 서블릿으 ㅣ통신은 자바I/O의 stream 사용
MIME-TYPE
- 톰캣 컨테이너에 미리 지정해 놓은 데이터 종류
- 서블릿에서 브라우저로 전송 시 설정해서 사용
- HTML로 전송 : text/html
- 일반 텍스트로 전송 : text/plain
- XML 데이터로 전송 : application/xml
setContentType()로 MIME-TYPE 설정 ->
데이터 출력할 PrintWriter 객체 생성 ->
출력 데이터를 HTML 형식으로->
PrintWriter의 print() /println()으로 데이터 출력
서블릿 응답 실습해보기
<body>
<form name="frmLogin" method="get" action="login2" encType="UTF-8">
아이디 : <input type="text" name="user_id"><br>
비밀번호 : <input type="password" name="user_pw"><br>
<input type="submit" value="로그인"> <input type="reset" value="다시입력">
</form>
</body>
html 파일
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
String id = request.getParameter("user_id");
String pw = request.getParameter("user_pw");
String data = "<html>";
data += "<body>";
data += "아이디 : " + id;
data += "<br>";
data += "패스워드 : " + pw;
data += "</html>";
data += "</body>";
out.print(data);
}
서블릿 파일(doGet()메소드)
- setContentType() : 응답할 데이터 종류가 HTML임을 설정
response.setContentType("text/html;charset=utf-8");
- HttpServletResponse 객체의 getWriter()를 이용해 출력 스트림 PrintWriter객체를 받아옴 (import하기)
PrintWriter out = response.getWriter();
- String data에 브라우저로 출력할 데이터를 문자열로 연결해 HTML태그로 만들어줌
html 실행창(run on server)
로그인을 누르면
서블릿이 id와 비밀번호를 전달받아 브라우저에 출력해준다.
GET/POST 전송방식
GET | POST |
- 서블릿에 데이터를 전송할 때 : 데이터가 URL뒤 "name=value"형태로 전송 - 데이터가 여러개라면 '&'로 구분 - 보안 취약 - 최대 전송 데이터 255자 - 기본 전송방식 - 사용하기 편함 - 웹브라우저에 직접 입력해 전송 가능 - 서블릿 : doGet()으로 전송된 데이터 처리 |
- 서블릿에 데이터를 전송할 때 : TCP/IP 프로토콜 데이터의 HEAD 영역에 숨겨진 채 전송 - 보안에 유리 - 전송 데이터 용량 : 무제한 - 처리 속도가 GET 방식보다 느리다. (전송할 때 서블릿에서 또 가지고 와야해서) - 서블릿 : doPost()가 데이터 처리 - 대량의 데이터는 POST로! |
POST
- 꼭 html (jsp파일)을 만들어야 한다.
POST 방식 실습해보기
<form name="frmLogin" method="post" action="login3" encType="UTF-8">
html파일
@WebServlet("/login3")
public class LoginServlet3 extends HttpServlet {
public void init(ServletConfig config) throws ServletException {
System.out.println("init 메서드 호출");
}
public void destroy() {
System.out.println("destroy 메서드 호출");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
String user_id = request.getParameter("user_id");
String user_pw = request.getParameter("user_pw");
System.out.println("아이디 : " + user_id);
System.out.println("비밀번호 : " + user_pw);
}
}
서블릿 파일
Console창
POST형식으로 데이터를 전송해도 URL에 나오지 않음
GET & POST 요청 동시 처리
서블릿에서는 웹 브라우저에서 전송되는 방식에 따라
doGet() 혹은 doPost() 메소드로 대응&처리 해야한다.
@WebServlet("/login4")
public class LoginServlet4 extends HttpServlet {
public void init(ServletConfig config) throws ServletException {
System.out.println("init 메서드 호출");
}
public void destroy() {
System.out.println("destroy 메서드 호출");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("doGet 메서드 호출");
doHandle(request, response); // GET 방식으로 요청 시 다시 doHandler()를 호출
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("doPost 메서드 호출");
doHandle(request, response); // POST 방식으로 요청 시 다시 doHandler()를 호출
}
private void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
String user_id = request.getParameter("user_id");
System.out.println("doHandler 메서드 호출");
String user_pw = request.getParameter("user_pw");
System.out.println("아이디 : " + user_id);
System.out.println("비밀번호 : " + user_pw);
}
}
서블릿 파일
doGet()과 doPost() 메소드에서 doHandler()메소드를 재호출해서 두 가지 방식의 요청을 처리
1. html에 GET 형식으로 : <form name="frmLogin" method="get" action="login4" encType="UTF-8">
콘솔창
2. html에 POST 형식으로 : <form name="frmLogin" method="post" action="login4" encType="UTF-8">
마찬가지로 창이 실행되며, 콘솔창에 데이터가 출력된다.
(URL에는 "name=value"형태로 나오지 않는다.)
자바스크립트로 서블릿 요청
자바스크립트에서 먼저 입력한 값에 유효성 검사를 하고,
자바스크립트에서 서블릿에 요청하는 형태
...
<script type="text/javascript">
function fn_validate() {
var frmLogin = document.frmLogin;
var user_id = frmLogin.user_id.value;
var user_pw = frmLogin.user_pw.value;
if((user_id.length == 0 || user_id == "") || (user_pw.length == 0 || user_pw == "")) {
alert("아이디와 비밀번호는 필수입니다.");
} else {
frmLogin.method = "post";
frmLogin.action = "login5";
frmLogin.submit();
}
}
</script>
</head>
<body>
<form name="frmLogin" method="post" action="login5" encType="utf-8">
...
</form>
</body>
</html>
html 파일 (자바스크립트 파일)
...
@WebServlet("/login5")
public class LoginServlet5 extends HttpServlet {
...
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
String id = request.getParameter("user_id");
String pw = request.getParameter("user_pw");
String address = request.getParameter("user_address");
System.out.println("아이디 : " + id);
System.out.println("비밀번호 : " + pw);
String data = "<html>";
data += "<body>";
data += "아이디 : " + id;
data += "<br>";
data += "비밀번호 : " + pw;
data += "<br>";
data += "주소 : " + address;
data += "</html>";
data += "</body>";
out.print(data);
}
}
서블릿 파일
아이디와 비밀번호에 값을 입력하지 않으면
alert창으로 알려준다.
값을 입력하면 출력되는 모습
웹 브라우저에 하이퍼링크 넣기
...
PrintWriter out = response.getWriter();
...
out.print("<html>");
out.print("<body>");
out.print("아이디를 입력하세요!!!");
out.print("<br>");
out.print("<a href='http://localhost:8080/pro01/login6.html'>로그인 창으로 이동</a>");
out.print("</html>");
out.print("</body>");
서블릿 파일 doPost(...) 메소드
- 웹 폴더에서 작동이 안된다면 properties- Java Build Path에 들어가서 edit과 같은 것을 수정
- 톰캣입장에서는 서블릿이 여러개.
url mapping으로 서블릿들을 호출. 이때 네트워크를 이용
http : 정보전달, 투명성 보장
(출처 : 짧고 굵게 배우는 JSP 웹 프로그래밍과 스프링 프레임워크(황희정))
'JSP 웹프로그래밍' 카테고리의 다른 글
JSP : 계산기 (html, jsp파일) (0) | 2023.01.04 |
---|---|
JSP #4 : 속성관리 (230104)1 (0) | 2023.01.04 |
JSP #3 : 페이지 이동 & 정보 공유 (230103)1 (0) | 2023.01.03 |
JSP : GET방식으로 구구단 출력 실습 (0) | 2023.01.03 |
JSP #1 : 웹 프로그래밍 (230102)0 (0) | 2023.01.02 |
댓글