Servlet의 정의와 GET 방식에 대해 알아보자
*Servlet(서블릿)
== controller 역할을 하는 자바 클래스
👉🏻 웹 서비스를 위한 "자바 클래스"를 말하며 자바를 이용해서 웹을 만들기 위해 필요한 기술
👉🏻 사용자의 요청을 받아 처리하고 그에 해당되는 응답 페이지를 만들어서 다시 사용자에게 전송하는 역할을 하는 자바 클래스 (Controller기능)
👉🏻 즉, 웹에서 동적인 페이지를 JAVA로 구현할 수 있게 도와주는 서버측 프로그램 (WAS 서버에서 구동됨)
JAVA 클래스에서 웹 페이지 구현을 위한 HTML 코드가 들어간 구조라고 할 수 있음(Java 코드로 HTML 구현)
GET 방식 테스트
👉🏻 특징1. GET 방식으로 요청하면 URL의 Header 영역에 데이터들을 포함시켜서 요청함
=> 사용자가 입력한 값(데이터)들이 URL에 노출됨
=> 보안 유지가 불가능함
=> 즉, 로그인이나 회원가입 같은 경우 GET 방식이 부적합함
👉🏻 특징2. URL의 Header 영역은 전송하는 데이터의 길이에 제한이 있음
=> 방대한 데이터를 담았을 경우 초과된 데이터는 절단돼서 넘어감
=> 즉, 게시판 작성 같은 경우 GET 방식 부적합함
👉🏻 특징3. 장점이라고 한다면 URL에 데이터가 노출되기 때문에 즐겨찾기 (북마크) 기능이 가능
(즐겨찾기 해 놨다가 그냥 그 URL 재요청 가능)
=> 즉, 검색 기능 같은 경우 GET 방식에 적합
html 파일명: requestTest_GET.html
<index.html>
<body>
<h1>어서 와 WEB은 처음이지 ㅋ</h1>
<h2>*Servlet</h2>
<p>
서블릿이란? <br>
웹 서비스를 위한 "자바 클래스"를 말하며 <br>
자바를 이용해서 웹을 만들기 위해 필요한 기술임 <br>
- 사용자의 요청을 받아 처리하고 그에 해당되는 응답 페이지를 만들어서 다시 사용자에게 전송하는 역할을 하는 자바 클래스 (Controller의 기능) <br>
- 즉, 웹에서 동적인 페이지를 JAVA로 구현할 수 있게 도와주는 서버측 프로그램 (WAS 서버에서 구동됨) <br>
JAVA 클래스에서 웹 페이지 구현을 위한 HTML 코드가 들어간 구조라고 할 수 있음(Java 코드로 HTML 구현)
</p>
<h3><a href="views\requestTest_GET.html">GET 방식 테스트</a></h3>
<!--
경로 오타나면 404 오류 뜸!!! 주의할 것!
현재 위치: WebContent\index.html
찾아갈 위치: WebContent\views\requestTest_GET.html
-->
</body>
<requestTest_GET.html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>GET 방식으로 요청 후 응답 페이지 받아 보기</h1>
</body>
</html>
개인정보 입력 - GET
👉🏻 보안상 부적합!! 정보가 다 보여지기 때문에 절대 이러면 안 됨! 이건 그냥 테스트일 뿐
👉🏻 form 내의 submit 버튼을 클릭 시
form 태그 속성 중 action에 작성된 url로 method 속성에 작성된 방식으로 데이터들이 넘어감 (key-value 세트로)
=> action에 작성된 url로 요청이 들어감 == Controller (Servlet) 를 호출함
👉🏻 Servlet 요청 같은 경우 반드시 그 요청이 현재 웹 애플리케이션의 Context root(== Context Path) 뒤에 붙어야 함
(/1_Servlet 뒤에 작성되어야 함)
=> http://localhost:8888/1_Servlet/test1.do
👉🏻 action 속성을 작성하는 방식
1. 절대 경로 방식 (action 속성값이 /(슬래시)로 시작하는 경우)
localhost:8888 뒤에 action에 작성된 값이 붙어지면서 곧바로 요청이 되는 꼴
2. 상대 경로 방식 (action 속성값이 문구로 시작하는 경우)
현재 이 페이지가 보여질 때의 URL 경로 중 마지막 /로부터 그 뒤에 action에 작성한 값이 붙으면서 요청됨
프리뷰어를 활용하고 싶다면 VSCode를 사용해도 무방!
아무래도 훨씬 익숙하니까,,
(이클립스에서 작업하다가 저장 후 넘어와서 폴더 지정하니 그대로 넘어옴)
입력 후 이클립스로 돌아와 com.kh.controller 패키지 생성
서버 관련 클래스인 Servlet 생성하여 클래스 이름 변경 후 Next
클래스 이름: RequestGetServlet
URL Mappings: 클래스 이름을 대신해 주는 별칭 같은 존재
Pattern: /test1.do
<상대 경로 방식>
현재 url: http://localhost:8888/1_Servlet/views/test1.do?name=&age=&city=%EA%B2%BD%EC%83%81%EB%8F%84&height=170
=> views가 없어야 하는데 붙어 있어서 404 오류 남
<절대 경로 방식>
출력해 보기
<requestTest_GET.html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style>
ul {
list-style-type : none;
line-height : 200%;
}
</style>
</head>
<body>
<h1>GET 방식으로 요청 후 응답 페이지 받아 보기</h1>
<form action="../test1.do" method="get"> <!-- ../ : 한 겹 빠져 나가겠다 -->
<!-- <form action="/1_Servlet/test1.do" method="get"> -->
<ul>
<li>이름: <input type="text" name="name"></li>
<!-- input 태그 사용 시 key값은 반드시 넘겨야 함 (name 속성) -->
<li>성별:
남자 <input type="radio" name="gender" value="M">
여자 <input type="radio" name="gender" value="F">
<!-- radio의 경우 같은 묶음으로 묶어 줄 경우에는 name 속성을 동일하게 지정 -->
</li>
<li>나이: <input type="number" name="age"></li>
<li>사는 도시:
<select name="city">
<option>서울시</option> <!-- option value 값을 적지 않으면 태그 사이 값이 자동으로 value로 넘어감 -->
<option>경기도</option>
<option>강원도</option>
<option>충청도</option>
<option selected>경상도</option>
<option>전라도</option>
</select>
</li>
<li>키: <input type="range" name="height" min="140" max="200"></li>
<li>좋아하는 음식(모두 고르시오):
햄버거 <input type="checkbox" name="food" value="햄버거">
만두 <input type="checkbox" name="food" value="만두">
떡볶이 <input type="checkbox" name="food" value="떡볶이">
샐러드 <input type="checkbox" name="food" value="샐러드">
건포도라지무침 <input type="checkbox" name="food" value="건포도라지무침">
<!-- checkbox의 경우 같은 묶음으로 묶어 줄 경우에는 name 속성을 동일하게 지정
여러 개의 선택지 중에서 여러 개 선택 가능 -->
</li>
<li>
<input type="submit">
<input type="reset">
</li>
</ul>
</form>
</body>
</html>
<RequestGetServlet.java>
package com.kh.controller; // 패키지 선언부
// import 선언부
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 RequestGetServlet
*/
@WebServlet("/test1.do") // 어노테이션
// 지정해 준 /test1.do는 RequestGetServlet이라는 이름을 대변할 이름이 됨!
public class RequestGetServlet extends HttpServlet { // RequestGetServlet 클래스 영역 시작
// 필드부
private static final long serialVersionUID = 1L; // 상수필드
// 생성자부
// 생성자: 클래스명과 이름이 같고 반환형이 없는 일종의 메소드
/**
* @see HttpServlet#HttpServlet()
*/
public RequestGetServlet() { // 매개변수가 없는 기본 생성자
super();
// TODO Auto-generated constructor stub
}
// 메소드부
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // doGet() 메소드 영역 시작
// TODO Auto-generated method stub
response.getWriter().append("Served at: ").append(request.getContextPath());
// System.out.println("잘 출력이 되나...?");
String name = request.getParameter("name"); // "홍길동" / "" (텍스트 상자가 빈 경우 빈 문자열이 넘어감)
String gender = request.getParameter("gender"); // 라디오 버튼을 하나도 체크하지 않으면 null값이 넘어감
// String age = request.getParameter("age"); // "20" (무조건 문자열로 넘어감)
// "20" -> 20
// "20a" -> NumberFormatException 발생 (주의할 것!)
// 근데 난 무조건 number type으로 넘기고 싶어!
int age = Integer.parseInt(request.getParameter("age")); // Wrapper 클래스를 이용해서 파싱
String city = request.getParameter("city"); // "서울시" / "경기도" / ...
// String height = request.getParameter("height"); // "170" (무조건 문자열로 넘어감)
double height = Double.parseDouble(request.getParameter("height")); // "170" -> 170.0
// 체크박스와 같은 복수 개의 정보를 받을 때는 배열로 받아야 함
String[] foods = request.getParameterValues("food"); // ["햄버거", "만두", "떡볶이", "샐러드", "건포도라지무침"] // null (체크박스 또한 체크된 것이 없을 때는 null값 넘어옴)
System.out.println("name: " + name + ", gender: " + gender +
", age: " + age + ", city: " + city +
", height: " + height /* + ", food: " + foods*/ ); // 주소값 출력됨
if(foods == null) {
System.out.println("foods: 좋아하는 음식이 없습니다.");
} else {
/*
for(int i = 0; i < foods.length; i++) {
System.out.println(foods[i]);
}
*/
System.out.println("foods: " + String.join(", ", foods));
// String.join("구분자", 배열명);
// 배열에 있는 모든 값들을 구분자를 통해서 하나의 문자열로 연이어서 반환해 주는 메소드
}
} // doGet() 메소드 영역 끝
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // doPost() 메소드 영역 시작
// TODO Auto-generated method stub
doGet(request, response);
} // doPost() 메소드 영역 끝
} // RequestGetServlet 클래스 영역 끝
👉🏻 form 태그에서 GET 방식으로 요청했다면 이 doGet() 메소드가 호출됨
👉🏻 첫 번째 매개변수인 HttpServletRequest request 매개변수에는 요청 시 전달된 내용물들이 담김
(사용자가 입력한 값, 요청 전송 방식, 요청한 사용자의 ip 주소 등등)
👉🏻 두 번째 매개변수인 HttpServletResponse response 매개변수에는 요청을 처리 후 응답을 할 때 사용하는 객체
(응답 시 필요한 메소드들을 호출)
=> request 객체로부터 요청 시 전달값들을 뽑아서 처리 후에 response 객체로 응답
👉🏻 우선, 요청을 처리하기 위해 요청 시 전달된 값 (사용자가 입력한 값)들을 뽑음
request 객체의 parameter 라는 영역 안에 사용자가 입력한 값들이 key-value 세트로 담겨 있음 (name-value)
👉🏻 따라서 request의 parameter 영역으로부터 전달된 데이터를 뽑는 메소드를 이용
request.getParameter("키값"): String 형태의 밸류값 리턴
=> 무조건 문자열 형으로 반환되기 때문에 다른 자료형으로 변경하려면 파싱해야 함
request.getParameterValues("키값"): String[] 형태의 밸류값들을 리턴
=> 하나의 key 값으로 여러 개의 values 값들을 받는 경우 (체크박스) 문자열 배열형으로 반환 가능
👉🏻 텍스트 상자가 빈 경우 빈 문자열이 넘어감
👉🏻 라디오 버튼이 하나도 눌러지지 않을 경우 빈 문자열이 아닌 null 값이 넘어감
👉🏻 문자열로만 넘길 수 있기 때문에 number로 가지고 오고 싶다면 Wrapper 클래스를 이용해 파싱해 줘야 함!
👉🏻 배열을 출력하고 싶다면 반복문을 활용해야 하며, 하나도 클릭하지 않을 경우 오류남!
👉🏻 String.join("구분자", 배열명);
👉🏻 배열에 있는 모든 값들을 구분자를 통해서 하나의 문자열로 연이어서 반환해 주는 메소드
👉🏻 이 뽑아낸 값들을 가지고 VO 객체로 가공 후 Service 단으로 요청 처리해야 함 (DB와 상호작용)
보통의 흐름: Service의 메소드 호출 시 뽑은 값들을 VO로 가공하여 전달 => DAO 호출 -> DB SQL문 실행 -> 결과 반환
👉🏻 DB가 있다는 가정 하에 아래의 구문이 실행됐을 것!
int result = new MemberService().insertMember(m); // 성공: 1, 실패: 0
👉🏻 if(result > 0) : 성공 시 성공 화면, 실패 시 실패 화면을 호출
Service와 DAO단은 앞으로 거의 변동이 없음 => View 와 Controller단의 소스코드만 변경
위와 같은 요청 처리를 다 했다는 가정 하에 사용자가 보게 될 응답 페이지를 만들어서 전달
요청에 대한 응답 페이지 반환하기
✔️ 자바를 이용하는 방법: Java 코드 내에 HTML 코드를 기술
✔️ JSP를 이용하는 방법: HTML 코드 내에 Java 코드를 기술
*자바를 이용하는 방법
장점: Java 코드 내에 작성하기 때문에 반복문이나 조건문, 유용한 메소드들을 활용 가능
단점: 복잡, 혹시라도 후에 HTML 코드를 수정할 경우 Java 코드를 건드려야 함
수정된 내용을 다시 반영하고자 한다면 서버를 재실행(restart) 해 줘야 함
👉🏻 사실상 자바를 이용한 방법은 너무 복잡해서 거의 쓰이지 않지만 알기는 해야 하잖음,,, 그래서 해요,,,
👉🏻 response 객체를 통해 사용자에게 html (응답화면) 전달
1) 이제부터 내가 출력할 내용은 문서 형태의 html이고, 인코딩 방식은 utf-8이라는 것을 지정
response.setContentType("text/html; charset=UTF-8");
2) 응답하고자 하는 사용자 (요청했던 사용자)와의 스트림(클라이언트와의 통로) 생성
PrintWriter out = response.getWriter(); // PrintWriter 임포트
3) 생성된 스트림을 통해 응답 html 구문을 한 줄씩 출력
// print, println, printf
out.println("<html>");
out.println("<head>");
out.println("<style>");
out.println("h2 {color:red;}");
out.println("#name {color:orange;}");
out.println("#age {color:yellow;}");
out.println("#city {color:green;}");
out.println("#height {color:blue;}");
out.println("#gender {color:navy;}");
out.println("li {color:purple;}");
out.println("</style>");
out.println("</head>");
out.println("<body>");
out.println("<h2>개인정보 응답 화면</h2>");
// out.println("<span id='name'>" + name + "</span> 님은");
out.printf("<span id='name'>%s</span> 님은 ", name);
out.printf("<span id='age'>%d</span>살이며, ", age);
out.printf("<span id='city'>%s</span>에 사는 키가 ", city);
out.printf("<span id='height'>%.1f</span>cm이고 ", height);
out.print("성별은 ");
if(gender == null) {
out.print("선택을 안 했습니다. <br>");
} else {
if(gender.equals("M")) {
out.print("<span id='gender'>남자</span>입니다. <br>");
} else {
out.print("<span id='gender'>여자</span>입니다. <br>");
}
}
out.print("좋아하는 음식은 ");
if(foods == null) {
out.print("목록 중에 없습니다.");
} else {
out.print("<ul>");
for(int i = 0; i < foods.length; i++) {
out.printf("<li>%s</li>", foods[i]);
}
out.print("</ul>");
}
out.println("</body>");
out.println("</html>");