국비교육(22-23)

27일차(1)/jsp(3) : servlet, jsp 비교 (table, form)

서리/Seori 2022. 11. 15. 22:09

<index>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>index.html</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
</head>
<body>
	<div class="container">
		<h1>인덱스 페이지입니다.</h1>
		<ul>
			<li><a href="fortune">오늘의 운세 보기</a></li>
			<li><a href="fortune.jsp">오늘의 운세 보기2</a></li>
			<li><a href="friends/list">친구 목록보기</a></li>
			<li><a href="friends/list.jsp">친구 목록보기2</a></li>
			<li><a href="member/list">회원 목록보기</a></li>
			<li><a href="member/list.jsp">회원 목록보기2</a></li>
		</ul>		
	</div>
</body>
</html>

 

- /Step01_Servlet/ 이 주소를 context 경로라고 부른다.
- 이 경로의 / 는 가상의 최상위 경로이거나 webapp 폴더를 가리킨다. 이 컨텐츠 안에서 요청을 할 수 있다.
- jsp 파일의 경우 webapp 폴더 안에서의 경로가 일치하면 접속할 수 있다.

 


- jsp 문서를 작성하는 것은 서버에 응답하는 입장이라는 것을 항상 생각하기!

- 현재 공부하는 환경은 client 와 server가 같은 pc에서 실행중이다. (localhost / 127.0.0.1)
- 하지만 이후에는 만든 웹서버앱은 Linux 환경에서 실행될 예정이고, client는 인터넷 상의 임의의 위치가 된다.
 → 두개가 분리된다는 것을 생각하며 코딩하기.

- 실제 응답된 내용은 '페이지 소스 보기'에서 확인가능!(보는 것을 습관화하기)
- 브라우저가 소스 보기에서 본 내용을 하나하나 해석해서 해석된 결과를 화면에 표현해 주는 것이다.

- 표시된 a href 링크는 외부 css파일을 로딩한 것이다.
- 웹브라우저가 요청하다 보면 추가요청을 할 필요가 있다.
 → 최초 요청: http://localhost:8888/Step01_Servlet/index.html
 → 추가 요청: 그 내부의 css 링크 등

- 이 위치에 css가 원래 <style> 안에 있었던 것처럼 해석해준다.
- 응답되는 문자열은 이 안에 있었던 것처럼 해석된다.
- 링크에 있었던 css를 아래에 적용해 정렬해준다. 추가요청을 받아와서 같이 로딩해준 것.

 

- 최상위 경로의 fortune 이라는 요청을 보내는 것

/  는 context 최상위 경로를 가리킨다. 여기서는 실제로 존재하는 폴더가 아니라 가상의 경로이다.
 (파일 탐색기의 c:\ 처럼! context 경로상의 최상위를 말한다.)

- 이 요청은 java 객체가 응답하게 할 수 있다.(FortuneServlet 객체가 지금 응답하고 있다.)

 

 

- 우리가 만든 클래스로 생성된 객체가 Tomcat 웹 서버에서 특별한 일을 한다.
 특별한 일이란? → 클라이언트가 /fortune요청을 해 오면 응답을 해준다.

- 특정 형식에 맞춰서 클래스를 만들어놓으면 웹서버가 알아서 필요한 시점에 저 클래스로 응답해준다.
  (특정 형식: 상속 / annotation / service 메소드 override 등)

- Tomcat webserver가 누군가 요청하면 new 해서 객체를 생성해준다.

 

- Tomcat Server는 클라이언트가 /fortune 요청을 해 오면 
 Http Servlet s=new FortuneServlet(); 객체를 생성해서 (최초 1번만)
 서비스 메소드를 호출하면서 자기가 가지고 있는 HttpServletRequest, HttpServletResponse 객체의 참조값을 전달해준다.

s.service(xxx, yyy);
- 적절한 시점에 xxx, yyy 객체(참조값)가 전달된다는 가정 하에 해당 객체를 활용하는 프로그래밍을 미리 해두면 된다.

 


 

** 응답하는 페이지를 jsp 로 만들 경우

 

최상위경로? 아님 webapp?
→ 여기서는 webapp이다. 폴더에 들어가보면 실제로 fortune.jsp가 있다.

 

 

- Servlet 파일은 작성한 대로 똑같이 이동했지만, jsp는 원본파일의 내용과 응답된 컨텐츠가 좀 다르다.

- <% %> 안에 있는 것들은 응답 페이지에 출력되지 않았다. 이 이외에는 전부 출력된다.

 

<%@ %>

<% %>

<%= %>

 

- jsp는 그대로 응답하는 컨텐츠가 있고 아닌 컨텐츠가 있다.

- 그래서 jsp는 꼭 페이지 소스 확인작업이 필요하다!

 

- 페이지 소스 보기를 꼭 해야 하는 이유는 웹브라우저가 해석을 잘 해줘서

 잘못된 부분이 있어도 화면상에서 잘 표가 나지 않기 때문에..

 

- 이 안에는 java 코딩이 가능한데, 여기에 작성하는 코드는

  jsp 서비스 메소드 안으로 들어간다.(만들어진 .java 클래스 파일에서 확인가능!)

- 어떤 영역에도 들어가지않는 나머지들은 our.write 안으로 들어간다.

 

- jsp의 <%%>안에서 쓸 수 있는 8개의 지역변수를 jsp기본객체라 부른다.

 

 

- 클래스파일에 들어가보면 이 기본객체들이 정의되어 있는 것이 보인다.

- java 객체나 변수에 참조되는 내용을 특정 위치에 그대로 출력하고 싶을 때,
 특정 방에 있는 내용을 참조하는 것 (fortunes[ranNum] 같은..)

 


- <%= %> 안에 넣으면 그대로 출력해준다. 참조만해주면 알아서 출력해주는 것.

 

- 최상위 경로란 실제 존재하는 폴더를 말하는것은 아니다.
- /webapp/fortune 은 존재하지 않는다. 폴더 안에 fortune이 없는데 요청하는 것은 가상의 경로요청이다.

- 논리적인 최상위 경로를 가리키는 것
이것은 webapp일 때도 있고, 가상의 root path 일 수도 있다.

 

- 마지막 경로가 확장자가 있는 특정 파일인 경우(.jsp/.html/.css 등...) 특정 폴더(webapp)를 가리키는 것이지만,

 그게 아닌 경우 어떤 가상의 경로를 가리키는 것이다.

 

 

- 이런 요청을 받을 Servlet을 만들어놓았기 때문에 응답하게 할 수 있는 것이지,

 이것이 실제 파일시스템 상 존재하는 경로는 아니다.

 

- 이 경우에는 가상의 경로가 아니다.

 list.jsp가 물리적으로 파일시스템의 friend 폴더 안에서 찾아볼 수 있는 파일이므로!

 

- 2개의 ul은 같은 내용이지만, 아래를 더 많이 사용한다. <%%>, <%=%> 안에 넣어서 출력하기!

 


 

** '회원목록보기' 추가하기

 

<MemberServlet>

package test.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

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 test.dto.MemberDto;

@WebServlet("/member/list")
public class MemberServlet extends HttpServlet {
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		//DB에서 불러온 회원 목록이라 가정(sample data)
		//회원 목록을 담을 ArrayList객체
		List<MemberDto> list = new ArrayList<>();
		list.add(new MemberDto(1,"바나나","서울"));
		list.add(new MemberDto(2,"딸기","부산"));
		list.add(new MemberDto(3,"복숭아","대전"));
		
		//응답 인코딩 설정
		resp.setCharacterEncoding("utf-8");
		//응답 컨텐트 설정
		resp.setContentType("text/html; charset=utf-8");
		//클라이언트의 웹브라우저에 문자열을 출력할수 있는 객체의 참조값 얻어내기
		PrintWriter pw = resp.getWriter();
		pw.println("<!doctype html>");
		pw.println("<html>");
		pw.println("<head>");
		pw.println("<meta charset=\"utf-8\">");
		pw.println("<title>회원 목록입니다.</title>");
		pw.println("</head>");
		pw.println("<body>");		
		pw.println("<table>");
			pw.println("<thead>");
				pw.println("<tr>");
					pw.println("<th>번호</th>");
					pw.println("<th>이름</th>");
					pw.println("<th>주소</th>");
				pw.println("</tr>");
			pw.println("</thead>");
			
			pw.println("<tbody>");
				//회원의 숫자만큼 반복문 돌면서 tr을 출력하면 된다.
				for(MemberDto tmp:list) {	
					pw.println("<tr>");
						pw.println("<td>"+tmp.getNum()+"</td>");
						pw.println("<td>"+tmp.getName()+"</td>");
						pw.println("<td>"+tmp.getAddr()+"</td>");	
					pw.println("</tr>");
				}
			pw.println("</tbody>");			
		pw.println("</table>");		
		pw.println("</body>");
		pw.println("</html>");
		pw.close();//닫아주기
	}
}

 

- 3개의 형식 맞춰주기 (상속, @webservlet , 서비스 override)
- 데이터는 DB에서 불러온 데이터라고 가정한다! 가져온 데이터를 table 에 넣어주기

- servlet 페이지를 직접 작성해보면서 jsp페이지에 대한 이해도를 높일 수 있다.

 

- 꼭 페이지 소스 보기를 보고 확인하기!!!
- \t 들여쓰기 기호를 사용해서 탭을 인식하도록 처리해줄 수도 있다.

- DB에서 불러온 데이터를 합쳐서 html 마크업을 만들어낸 것!

 


 

같은 내용 jsp로 작성하기

<list.jsp>

<%@page import="java.util.ArrayList"%>
<%@page import="test.dto.MemberDto"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	//DB에서 불러온 회원 목록이라 가정(sample data)
	List<MemberDto> list = new ArrayList<>();
	list.add(new MemberDto(1,"바나나","서울"));
	list.add(new MemberDto(2,"딸기","부산"));
	list.add(new MemberDto(3,"복숭아","대전"));
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>member/list.jsp</title>
</head>
<body>
	<table>
		<thead>
			<tr>
				<th>번호</th>
				<th>이름</th>
				<th>주소</th>
			</tr>
		</thead>
		<tbody>		
			<% for(MemberDto tmp:list){ %>
				<tr>
					<td><%=tmp.getNum() %></td>
					<td><%=tmp.getName() %></td>
					<td><%=tmp.getAddr() %></td>	
				</tr>
			<%} %>	
		</tbody>
	</table>
</body>
</html>

 

- webapp 안에 member 폴더를 만들어서 jsp파일을 그 안에 생성해주기!(물리적으로 위치시키기)

 

- jsp에서는 기본으로 탭, 개행기호도 인식한다.

 

 


 

- bootstrap css를 적용하고 싶다면?

- CDN을 통해 삽입하기에서 우측 링크를 복사해준다!

 

- CSS는 <head>의 <title> 아래에 위치시키는 것이 보편적이다.

- body 안에 <div class="container"> 를 생성해서 전체 테이블을 이 안에 넣어주기.

 

- 위 css 적용 상태

 

- 테이블 서식 적용하기: Docs-Content-table 에서 지정되어 있는 클래스를 본다

*링크 : https://getbootstrap.com/docs/5.2/content/tables/

- 클래스가 기본 "table"로 지정되어 있음

 

- table 클래스를 추가한 상태

 

 

- 각각의 요소에 class="table-primary"(파란색) 라는 클래스만 지정하면

 테이블 전체 / row / column 등 원하는 곳에 색상을 지정할 수 있다.

 

 

<tr class="table-success">

<tbody class="table-group-divider"> 

- 위 2개 css를 적용한 상태. tr에만 색상을 지정하고, tbdoy 에 구분선을 넣어주었다.

 

- bootstrap css 링크를 연결한 다음, 요소에 원하는 디자인을 지정하기만 하면 된다.

 


 

** 클라이언트에게 정보를 받아 반응하는 form, button 만들기

 

<index.html>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>index.html</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
</head>
<body>
	<div class="container">
		<h1>인덱스 페이지입니다.</h1>
		<ul>
			<li><a href="fortune">오늘의 운세 보기</a></li>
			<li><a href="fortune.jsp">오늘의 운세 보기2</a></li>
			<li><a href="friends/list">친구 목록보기</a></li>
			<li><a href="friends/list.jsp">친구 목록보기2</a></li>
			<li><a href="member/list">회원 목록보기</a></li>
			<li><a href="member/list.jsp">회원 목록보기2</a></li>
		</ul>
		
		<!-- 
			폼을 제출(submit)하면 (type="submit"인 전송 버튼을 누르면)
			action="요청경로"
			method="전송방식"
			
			서버에 "요청경로"대로 요청이 되고,
			폼에 입력한 내용은 "전송방식"으로 전송이 된다.(get or post)
			
			- form 사용법
			1. action 속성의 값은 폼을 제출했을때 요청되는 경로가 된다.
			2. method 속성의 값은 전송 방식을 지정한다. 생략하면 default 값은 get이다.
			3. form의 자손요소 중에 type="submit" 버튼을 누르면 폼이 제출된다.
			4. 전송 방식은 get 방식과 post 방식이 있는데
			   get 방식 전송은 입력한 정보를 주소창에 달고 가는 방식이고
			   post 방식 전송은 요청의 몸통에 달고가는 방식이기 때문에 주소창에 보이지 않는다. 
		 -->		 
		 <form action="/Step01_Servlet/send" method="get">
		 	<input type="text" name="msg" placeholder="서버에 할말 입력..."/>
		 	<button type="submit">전송</button>		 
		 </form>
		 <br>
		 <form action="/Step01_Servlet/send2" method="post">
		 	<input type="text" name="msg" placeholder="서버에 할말 입력..."/>
		 	<button type="submit">전송</button>
		 </form>
		 <br>
		 <form action="/Step01_Servlet/send.jsp" method="post">
		 	<input type="text" name="msg" placeholder="서버에 할말 입력..."/>
		 	<button type="submit">전송</button>
		 </form>
	</div>
</body>
</html>

 

[ form 사용법 ]
1. action 속성의 값은 폼을 제출했을때 요청되는 경로가 된다.
2. method 속성의 값은 전송 방식을 지정한다. 생략하면 default 값은 get이다.
3. form의 자손요소 중에 type="submit" 버튼을 누르면 폼이 제출된다.
4. 전송 방식은 get 방식과 post 방식이 있는데
   get 방식 전송은 입력한 정보를 주소창에 달고 가는 방식이고,
   post 방식 전송은 요청의 몸통에 달고 가는 방식이기 때문에 주소창에 보이지 않는다. 

 

- form 안에 자손 or 자식으로 포함되어있는 type="submit" 버튼이 전송 버튼이다.

 

http://localhost:8888/Step01_Servlet/send?msg=hello
- 버튼을 누르면 이동한다(요청한다).

 

- /send 요청을 보내는 것!
- 여기서 / 는 가상의 경로. 최상위 경로에서 send라는 요청을 한 것

 

 

- 전송 버튼을 클릭하면 /send?msg=hello 라는 주소로 이동한다.(get 방식)

 

- /send : 요청 경로
- ?msg=helloget 방식 파라미터가 요청과 함께 전달되는 것
→ 파라미터명 : msg
→ 전달되는 문자열 : hello

 

- 요청과 함께 파라미터를 전달할 수도 있다.

- input요청의 name을 msg로 지정했기 때문에 주소창에 이렇게 표시되는 것! 잘 연관지어 생각하기.

 

http://localhost:8888/Step01_Servlet/send
- post 방식으로 보내면 send까지만 보이고, 보낸 정보는 보이지 않는다.
- 같이 전송되기는 하지만 주소창에는 나타나지 않는다.

 

- 404를 발생시키지 않으려면 Servlet을 만들어야 한다.

 


 

<SendServlet> 생성

- get 방식으로 전송

package test.servlet;

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;

@WebServlet("/send")
public class SendServlet extends HttpServlet{
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		/*
		 * 요청에 대한 정보를 얻어낼 때는 HttpServletRequest 객체를 활용하면 된다.
		 */
		// "msg"라는 파라미터명으로 전달되는 문자열을 읽어와서 msg라는 지역변수에 담기
		// 해당 파라미터 명으로 전달되는 정보가 없으면 null이 리턴된다.		
		String msg=req.getParameter("msg");
		
		//콘솔창에 출력해 보기
		System.out.println("msg:"+msg);
		
		//응답 인코딩 설정
		resp.setCharacterEncoding("utf-8");
		//응답 컨텐트 설정
		resp.setContentType("text/html; charset=utf-8");
		//클라이언트의 웹브라우저에 문자열을 출력할수 있는 객체의 참조값 얻어내기
		PrintWriter pw = resp.getWriter();
		pw.println("<!doctype html>");
		pw.println("<html>");
		pw.println("<head>");
		pw.println("<meta charset=\"utf-8\">");
		pw.println("<title>메세지 전송 결과 페이지</title>");
		pw.println("</head>");
		pw.println("<body>");
		pw.println("<p>메세지 잘 받았어 클라이언트야!</p>");
		pw.println("</body>");
		pw.println("</html>");
		pw.close();//닫아주기
	}
}

 

getParameter(); : req 변수의 getParameter 객체로 입력된 값을 얻어올 수 있다.

- 요청에 대한 정보를 얻어낼 때는 HttpServletRequest 객체를 활용하면 된다.

 


http://localhost:8888/Step01_Servlet/send?msg=hello

- 주소창에 입력한 메시지(값)이 그대로 드러나는 형태!

- 입력된 값을 전송도 받고 응답도 해줄 수 있다.

 

- 정상적으로 전달되어 콘솔창에 입력된것도 확인해볼 수 있음!

 


<SendServlet2>

- post 방식으로 전송

package test.servlet;

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;

@WebServlet("/send2")
public class SendServlet2 extends HttpServlet {
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		//post방식 전송 파라미터를 추출하기 전에 한글이 깨지지 않도록 인코딩 설정을 해준다.
		req.setCharacterEncoding("utf-8");
		
		String msg=req.getParameter("msg");

		//콘솔창에 출력해 보기
		System.out.println("msg:"+msg);		
		
		//응답 인코딩 설정
		resp.setCharacterEncoding("utf-8");
		//응답 컨텐트 설정
		resp.setContentType("text/html; charset=utf-8");
		//클라이언트의 웹브라우저에 문자열을 출력할수 있는 객체의 참조값 얻어내기
		PrintWriter pw = resp.getWriter();
		pw.println("<!doctype html>");
		pw.println("<html>");
		pw.println("<head>");
		pw.println("<meta charset=\"utf-8\">");
		pw.println("<title>메시지 전송 결과 페이지2</title>");
		pw.println("</head>");
		pw.println("<body>");
		pw.println("메시지 전송 완료!");
		pw.println("</body>");
		pw.println("</html>");
		pw.close();//닫아주기
	}
}

 

- post 방식으로 전송되는 send2 에 연결되는 페이지 만들기

 

<form action="/Step01_Servlet/send2"> : index.html에 만들어진 주소
- 위와 같이 context 경로로 시작하는 것은 절대경로! /send 이렇게만 작성하면 상대경로이다.

참고) Servlet 을 새로 만들면 새로고침으로는 적용되지 않고, 서버를 껐다 켜야 한다.

 

- post방식은 주소창에 전송된 내용이 보이지 않는다.
- 구분하기! 웹페이지 경로 끝에 ?msg=x 가 나오는 것은 get방식 전송 / 보이지 않는 것은 post방식 전송

 

- 단, post 방식은 한글이 깨지기 때문에, 한 가지를 더 설정해야 한다.

 

req.setCharacterEncoding("utf-8");

- post방식은 전송 파라미터를 추출하기 전에 한글이 깨지지 않도록 인코딩 설정을 해준다.

 


 

<send.jsp> 파일 생성 (webapp폴더에)

- jsp 파일로 form과 연결되는 페이지 만들기

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/send.jsp</title>
</head>
<body>
	<%
		request.setCharacterEncoding("utf-8");
		String msg=request.getParameter("msg");
		System.out.println("msg:"+msg);
	%>	
	<p>메시지가 전송되었어요.</p>
</body>
</html>

 

 

request.getParameter();

- req변수 대신 jsp에 기본으로 만들어져 있는 request 지역변수 사용

- <% %> 안에서는 java 문법으로 코딩하기!

 

 

- Servlet에서는 서비스 메소드 안에 했던 코딩을, jsp에서는 <% %> 안에다가 하면 된다.

 

 

- jsp도 결국 Servlet이므로 함께 비교해보면서 공부하기!