톰캣과 같은 WAS가 처음 나왔을 때 웹브라우저 요청을 스레드 방식으로 처리하는 기술이 서블릿. 모든 웹 프로그램은 6~7장의 기능을 뼈대로 하여 동작
6.1 서블릿의 세가지 기본 기능
서블릿 응답과 요청 수행 API
요청 API : javax.servlet.http.HttpServletRequest 클래스
응답 API : javax.servlet.http.HttpServletResponse 클래스
ex)
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
1. 클라이언트가 서블릿에 요청
2. 톰캣 컨테이너가 요청을 받아 사용자의 요청이나 응답에 대한 HttpServletRequest 객체와 HttpServletResponse 객체를 만듦(요청에 대한 정보를 HttpServletRequest 객체 속성으로 담아서 메서드로 전달)
3. 서블릿의 doGet()/doPost() 메서드를 호출하며 이 객체를 전달
<HttpServletRequest의 메서드들>
반환형 | 메서드 | 기능 |
boolean | authenticate(HttpServletResponse response) | 현재 요청한 사용자가 ServletContext 객체에 대한 인증을 하기 위한 컨테이너 로그인 메커니즘을 사용한다 |
String | changeSessionId() | 현재 요청과 연관된 현재 세션의 id를 변경 |
String | getContextPath() | 요청한 컨텍스트를 가리키는 URI 반환 |
Cookie[] | getCookies() | 클라이언트가 현재의 요청과 함께 보낸 쿠키 객체 배열 |
String | getHeader(String name) | 특정 요청에 대한 헤더 정보를 문자열로 반환 |
Enumeration <String> |
getHeaderNames() | 현재 요청에 포함된 헤더의 name 속성을 enumeration으로 반환 |
String | getMethod() | 현재 요청이 GET, POST, PUT 방식 중 어떤 HTTP 요청인지 반환 |
String | getRequestURI() | 요청한 URL의 컨텍스트 이름과 파일 경로 반환 |
String | getServletPath() | 요청한 URL에서 서블릿이나 JSP 이름을 반환 |
HttpSession | getSession() | 현재의 요청과 연관된 세션 반환(없으면 새로 만들어서 반환) |
<HttpServletResponse의 메서드들>
반환형 | 메서드 | 기능 |
void | addCookie(Cookie cookie) | 응답에 쿠키를 추가 |
void | addHeader(String name, String value) | name과 value를 헤더에 추가 |
String | encodeURL(String url) | 클라이언트가 쿠키를 지원하지 않을 때 세션 id를 포함한 특정 URL을 인코딩한다 |
Collection <String> |
getHeaderNames() | 현재 응답의 헤더에 포함된 name을 반환 |
void | sendRedirect(String location) | 클라이언트에게 리다이렉트 응답을 보낸 후 특정 URL로 다시 요청함 |
String | getPathInfo() | 클라이언트가 요청 시 보낸 URL과 관련된 추가 경로 정보 반환 |
출처 : https://park-story.tistory.com/28
6.2 <form> 태그 이용해 서블릿에 요청하기
- 서블릿과 JSP는 HTML,CSS,자바스크립트들과 자신의 기능을 추가해서 서로 연동하여 동작.
- 특히 사용자의 요청은 HTML의 <form> 태그나 자바스크립트로부터 전송 받아서 처리
* <form>, <input> : 클랑언트에서 서버로 데이터를 저송하는 기능 담당
웹브라우저에서 여러 가지 입력 서식을 이용해 전송 클릭 => 서블릿으로 데이터가 전송
서블릿은 여러가지 메서드를 이용해서 데이터를 받아 옴
ex) 로그인창의 HTML 코드
<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>
실 데이터는 input 태그의 name 속성의 값과 실제 입력한 데이터가 쌍으로 전송 됨, 서블릿은 이 데이터를 받아옴
<form> 태그의 속성
- name : <form> 태그의 이름, 여러 개의 <form>을 구분하는 역할(자바스크립트에서 <form>태그에 접근할 때 자주 사용)
- method : 데이터 전송 방법 지정(GET-디폴트 / POST)
- action : 데이터를 전송할 서블릿(매핑 이름 지정)이나 JSP를 지정
- encType : 전송할 데이터의 encoding 타입을 지정. 파일을 업로드할 때는 multipart/form-data로 지정
6.3 서블릿에서 클라이언트의 요청을 얻는 방법
<form> 태그로 전송된 데이터를 받아 오는 메서드
메서드 | 기능 |
String getParameter(String name) | name에 대한 전송된 값을 받아오는 데 사용 |
String[] getParameterValues(String name) | name에 대해 여러 개의 값을 받아 올 때 사용(배열) |
Enumeration getParametersNames() | name 값을 모를 때 사용 |
출처 : https://park-story.tistory.com/28
ex) LoginServlet.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8"); //전송된 데이터를 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);
}
<하나의 name으로 여러 개의 값을 서블릿으로 요청하기>
- 주로 checkbox를 많이 사용 >> checked된 checkbox만 서블릿으로 넘겨짐
- 하나의 name으로 여러개의 input 타입을 선언하면 서블릿으로 전송할 때 배열로 전송된다.
ex)
<form name="frmInput" method="get" action="input">
아이디: <input type="text" name="user_id"><br>
비밀번호 : <input type="password" name="user_pw"><br>
<input type="checkbox" name=subject value="java" checked>자바
<input type="checkbox" name=subject value="C언어">C언어
<br><br>
<input type="submit" value="전송">
<input type="reset" value="초기화">
</form>
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
...
String[] subject=request.getParameterValues("subject");
for(String str:subject) {
System.out.println("선택한 과목 : "+str);
}
}
일일이 name의 값을 기억하기 힘들 때는 getParameterName() 메서드 사용
ex)
Enumeration enu=request.getParameterNames();
while(enu.hasMoreElements()) {
String name=(String)enu.nextElement(); //name 속성 값을 가져 옴
String[] values=request.getParameterValues(name);
for(String value : values) {
System.out.println("name="+name+",value="+value);
}
}
6.4 서블릿의 응답 처리 방법
- doGet() / doPost() 메서드 안에서 처리
- HttpServletResponse 객체 이용
- setContentType()을 이용해서 클라이언트에게 전송할 데이터 종류(MINE-TYPE)을 지정
- 클라이언트와 서블릿 통신은 자바 I/O의 스트림을 이용
클라이언트 <-> 서블릿 : 서블릿은 데이터 입력 받고, 네트워크로 데이터를 출력(클라로 전송)
=> 자바 I/O 스트림 클래스의 입출력 기능을 이용하면 쉽게 웹 애플리케이션의 네트워크 기능 구현 가능
- 서버에서 클라로 데이터를 전송할 때는 어떤 종류의 데이터를 전송하는지 웹 브라우저에 알려줘야 함 >> 브라우저가 더 빠르게 처리 가능
- 톰캣 컨테이너에서 미리 제공하는 여러 가지 전송 데이터 종류(=MINE-TYPE) 중 하나를 지정해서 전송
MINE-TYPE 예
- HTML로 전송 > text/html ( 웹 브라우저는 기본적으로 HTML만 인식하므로 대부분의 데이터 타입이 이거임)
- 일반 텍스트 > text/plain
- XML > application/xml
새로운 종류의 데이터를 지정하고 싶으면 CATALINA_HOME\conf\web.xml에 추가
<서블릿이 클라이언트에 응답하는 과정>
1. setContentType()을 이용해 MINE-TYPE를 지정
2. 데이터를 출력할 PrintWriter 객체를 생성
3. 출력 데이터를 HTML 형식으로 만듦
4. PrintWriter의 print()/println()을 이용해 데이터 출력
출력예제)
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8"); //응답할 데이터 종류 설정(html)
PrintWriter out=response.getWriter(); //클라로 데이터를 출력해 줄 출력스트림 printWriter 객체
String id=request.getParameter("user_id");
String pw=request.getParameter("user_pw");
String data="<html> <body>";
data+="아이디 : "+id+"<br>패스워드 :"+pw;
data+="</body> </html>";
out.print(data); //HTML 태그 문자열을 웹 브라우저로 출력
}
계산기예제) >> 화면과 기능을 서블릿에 한번에 정의
public class CalcServlet extends HttpServlet {
private static float USD_RATE = 1124.70F;
private static float JPY_RATE = 10.113F;
private static float CNY_RATE = 163.30F;
private static float GBP_RATE = 1444.35F;
private static float EUR_RATE = 1295.97F;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html; charset=utf-8");
PrintWriter pw = response.getWriter();
//첫화면에서 계산 눌렀을 때, 즉 두번째 브라우저 화면
String command = request.getParameter("command");
String won = request.getParameter("won");
String operator = request.getParameter("operator");
if (command != null && command.equals("calculate")) {
String result = calculate(Float.parseFloat(won), operator); //계산 메서드 실행
pw.print("<html><font size=10>변환결과</font><br>");
pw.print("<html><font size=10>" + result + "</font><br>");
pw.print("<a href='/pro06/calc'>환율 계산기 </a>"); //command 속성의 값으로 지정x
return;
}
//첫화면(처음에는 command가 null이므로 위의 코드는 수행 x)
pw.print("<html><title>환율계산기</title>");
pw.print("<font size=5>환율 계산기</font><br>");
pw.print("<form name='frmCalc' method='get' action='/pro06/calc' /> ");
pw.print("원화: <input type='text' name='won' size=10 /> ");
pw.print("<select name='operator' >"); //셀렉트 박스@@ 선택된 애를 operator로 전송
pw.print("<option value='dollar'>달러</option>"); //셀렉트 박스 후보들
pw.print("<option value='en'>엔화</option>");
pw.print("<option value='wian'>위안</option>");
pw.print("<option value='pound'>파운드</option>");
pw.print("<option value='euro'>유로</option>");
pw.print("</select>");
pw.print("<input type='hidden' name='command' value='calculate' /> ");
//hidden 태그 : name에 value값 넣기(브라우저에는 안보임), 변수 정의와 비슷
pw.println("<input type='submit' value='변환' />");
pw.println("</form>");
pw.print("</html>");
pw.close();
}
private static String calculate(float won, String operator) {
String result = null;
if (operator.equals("dollar")) {
result = String.format("%.6f", won / USD_RATE);
} else if (operator.equals("en")) {
result = String.format("%.6f", won / JPY_RATE);
} else if (operator.equals("wian")) {
result = String.format("%.6f", won / CNY_RATE);
} else if (operator.equals("pound")) {
result = String.format("%.6f", won / GBP_RATE);
} else if (operator.equals("euro")) {
result = String.format("%.6f", won / EUR_RATE);
}
return result;
}
}
6.5 웹 브라우저에서 서블릿으로 데이터 전송하기
GET 방식 | POST 방식 |
- 브라우저 > 서블릿 전송 : URL 뒤에 전송하는 데이터가 보임(name=value 형태, 여러개는 &로 구분) - 보안 취약 - 전송할 수 있는 데이터 최대 255자 - 디폴트 전송 방식 - URL에 직접 입력해서 전송할 수도 있음 - 보안과 관련 없는 간단한 데이터를 주로 전송 - 서블릿에서는 doGet()을 이용해 처리 |
- 브라우저 > 서블릿 전송 : TCP/IP 프로토콜 데이터의 body 영역에 숨겨진 채 전송됨(주소창에 데이터가 보이지 않음) - 보안에 유리 - 전송 데이터의 용량이 무제한 - 서블릿에서는 또 다시 가져오는 작업을 해야하므로 처리 속도가 GET보다 느림 - 보안과 관련된 데이터를 전송하는데 많이 사용 됨 - 서블릿에서는 doPost()을 이용해 처리 |
<form> 태그의 method 속성으로 방식 설정
브라우저에서 전송되는 방식과 메서드(do~)를 잘 일치 시켜야 하고(doHandle()로 퉁치기 가능) 오로지 이 메서드에서만 사용할 수 있음
6.6 GET 방식과 POST 방식 요청 동시에 처리하기
doGet과 doPost 에 doHandle()를 호출헤서 이 doHandle() 안에 로직을 구현하면 GET/POST 구분 없이 쓸 수 있음
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request,response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request,response);
}
protected void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("doHanlde메서드 호출");
}
6.7 자바스크립트로 서블릿에 요청하기
전송 데이터에 대해 유효성 검사(ex. id/pw입력 유무) >> 자바스크립트로
따라서 <form> 태그에서 서블릿으로 요청하지 않고, 자바스크립트 함수에서 서블릿에 요청하기
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script type="text/javascript">
function fn_validate(){
var frmLogin=document.frmLogin; //form 태그의 name속성으로 <form>태그 객체 받아오기
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>
<title>로그인 창</title>
</head>
<body>
<form name="frmLogin" method="post" action="login" encType="UTF-8">
아이디 : <input type="text" name="user_id"><br>
비밀번호 : <input type="password" name="user_pw"><br>
<input type="button" onClick="fn_validate()" value="로그인">
<input type="reset" value="다시입력">
<input type="hidden" name="user_address" value="서울시 성북구"/>
</form>
</body>
</html>
6.8 서블릿을 이용한 여러가지 실습 예제
WebContent 내가 아닌 그 안의 폴더 안에 넣으면 프로젝트 명도 명시 해줘야 함
ex)
<form name="frmLogin" method="get" action="/pro06/guguTest3" encType="UTF-8">
넘겨받은 데이터를 int형 변수에 저장하기 >> 파싱 : Integer.parseInt("name")
ex)
int dan=Integer.parseInt(request.getParameter("dan"));
** 지금까지 한것을 토대로 보면 서블릿 응답 기능은 결국 웹 애플리케이션 화면을 구현하는 기능이다.
현재는 서블릿으로 화면을 구현하지는 않지만 서블릿이 처음 나왔을 때는 이런식으로 응답 기능을 이용해 화면을 구현함
'BackEnd > Servlet' 카테고리의 다른 글
10장. 서블릿의 필터와 리스너 기능 (0) | 2022.02.18 |
---|---|
9장. 쿠키와 세션 알아보기 (0) | 2022.02.17 |
8장. 서블릿 확장 API 사용하기 (0) | 2022.02.16 |
7장. 서블릿 비즈니스 로직 처리 (0) | 2022.02.15 |
5장. 서블릿 이해하기 (0) | 2022.02.13 |
Comment