🍁내장 객체
내장 객체(Implicit Object)는 개발자가 직접 생성하지 않아도 JSP(톰캣)가 미리 만들어서 제공하는 객체이다.
JSP에는 미리 만들어진 예약어들이 있으며, 이 안에는 객체가 내장되어 있다. 이러한 내장 객체는 JSP에서만 볼 수 있는 특징이다.
사용 빈도
1. request, response, session, pageContext
2. out, application
3. config, page, exception
사용 빈도수에 따라서 위와 같이 구분할 수 있다.
Map 형태의 내장 객체
request, session, pageContext, application
- void setAttribute(String key, Object value)
- Object getAttribute(String key)
이 내장 객체에는 객체 내부에 사용자(개발자)가 데이터를 저장할 수 있는 컬렉션을 가지고 있다.
이 컬렉션은 Map 형태라는 특징이 있다.
컬렉션이 대한 의존도가 굉장히 높기 때문에 기억해 두는 게 좋다.
🍁request 객체
- HttpServletRequest
request 객체는 클라이언트가 웹 서버에 보낸 HTTP 요청에 관한 정보를 담고 있는 내장 객체이다.
이 객체를 통해 클라이언트로부터 받은 데이터를 처리하고, 서버에서 클라이언트로 응답을 보낼 수 있다.
즉, 클라이언트 쪽에서 서버 방향으로 어떤 행동이 이루어질 때 request가 해당 행동을 담당한다.
HttpServletRequest
HttpServletRequest 인터페이스는 Servlet API의 일부로, 클라이언트의 HTTP 요청 정보를 담고 있다.
웹 브라우저에서 서버로 HTTP 요청이 들어오면, 서버는 각 요청에 대해 HttpServletRequest 객체를 생성하고, 해당 요청의 정보를 이 객체에 담는다.
HttpServletRequest 객체는 서블릿에게 전달되어, 서블릿에서 요청 정보를 처리하고 응답을 생성할 때 사용된다.
request 객체의 업무
1. 클라이언트에서 서버로 전송한 데이터를 가져오기
2. 클라이언트에서 서버로 전송한 데이터의 인코딩 처리
3. 클라이언트에서 서버로 전송할 때의 여러 가지 관련 정보 가져오기
🍂클라이언트에서 서버로 전송한 데이터 가져오기 및 인코딩 처리
- ex07.jsp: 사용자로부터 데이터를 입력하여 서버에 전송하는 역할
- ex07_ok.jsp: 데이터를 수신하고 가공 및 처리하여 피드백하는 역할
위의 두 페이지를 만들어 JSP로 데이터를 송수신하는 과정을 구현해 보도록 하자.
그전에 POST 방식에 대한 이해가 필요하다.
POST 방식은 왜 한글이 깨지는 걸까?
POST 방식은 패킷 본문(body) 안에 넣어서 데이터를 전송하며, 자바를 통해서 데이터를 전송하기 때문에 인코딩이 자바를 통해서 진행된다.
- 브라우저(UTF-8) > 인터넷(ISO-8859-1) > 톰캣(UTF-8) > 자바 JSP(UTF-8)
위 과정에서 인터넷을 지나갈 때 한글을 깨지는 것이다. 따라서 POST 방식일 때에는 자바에서 UTF-8로 복구하는 작업이 필요하다.
request.setCharacterEncoding("UTF-8");
위 코드를 데이터를 받기 전(request 하기 전)에 작성하면 한글이 깨지지 않는다.
GET 방식일 때 한글이 깨지지 않는 이유는 GET 방식은 데이터를 URL 뒤에 붙여서 전송하는데, 넘겨지는 데이터의 인코딩의 URL 규칙에 따라 인코딩 되기 때문이다. 이를 톰캣(UTF-8)이 관리하므로 한글이 깨지지 않는다.
폼태그 + POST 방식으로 보내기
ex07.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="http://pinnpublic.dothome.co.kr/cdn/example-min.css">
</head>
<body>
<h1>데이터 전송하기</h1>
<h2>폼태그 + POST 방식으로 보내기</h2>
<form method="POST" action="ex07_ok.jsp">
<div>
문자: <input type="text" name="txt">
</div>
<div>
숫자: <input type="text" name="num">
</div>
<div>
<input type="submit" value="보내기">
</div>
</form>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="http://pinnpublic.dothome.co.kr/cdn/example-min.js"></script>
</body>
</html>
ex07_ok.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
//클라이언트 > (데이터) > 서버
//데이터 수신하기
//- String request.getParameter(String key)
//POST 방식으로 넘어온 데이터 인코딩
request.setCharacterEncoding("UTF-8");
String txt = request.getParameter("txt");
String num = request.getParameter("num");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="http://pinnpublic.dothome.co.kr/cdn/example-min.css">
</head>
<body>
<h1>결과</h1>
<div>문자: <%= txt %></div>
<div>숫자: <%= num %></div>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="http://pinnpublic.dothome.co.kr/cdn/example-min.js"></script>
</body>
</html>
컨트롤 입력 + 전송
- ex08.jsp: 모든 입력 컨트롤 테스트 (송신)
- ex08_ok.jsp: 모든 입력 컨트롤 테스트 (수신)
컨트롤을 송수신할 수 있는 페이지를 구현해 보도록 하자.
ex08.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="http://pinnpublic.dothome.co.kr/cdn/example-min.css">
</head>
<body>
<h1>컨트롤 입력 + 전송</h1>
<form method="POST" action="ex08_ok.jsp">
<table class="vertical">
<tr>
<th>텍스트 박스</th>
<td><input type="text" name="txt1"></td>
</tr>
<tr>
<th>암호 박스</th>
<td><input type="password" name="txt2"></td>
</tr>
<tr>
<th>다중 텍스트 박스</th>
<td><textarea name="txt3"></textarea></td>
</tr>
<tr>
<th>체크 박스</th>
<td><input type="checkbox" name="cb1" value="yes"></td>
</tr>
<tr>
<th>체크 박스들 1</th>
<td>
<h3>취미를 선택하세요.</h3>
<label>코딩<input type="checkbox" name="cb2" value="코딩"></label>
<label>독서<input type="checkbox" name="cb3" value="독서"></label>
<label>운동<input type="checkbox" name="cb4" value="운동"></label>
</td>
</tr>
<tr>
<th>체크 박스들 2</th>
<td>
<h3>취미를 선택하세요.</h3>
<label>코딩<input type="checkbox" name="cb5" value="코딩"></label>
<label>독서<input type="checkbox" name="cb5" value="독서"></label>
<label>운동<input type="checkbox" name="cb5" value="운동"></label>
</td>
</tr>
<tr>
<th>라디오 버튼</th>
<td>
<h3>성별을 선택하시오.</h3>
<label><input type="radio" name="rb" value="male" checked>남자</label>
<label><input type="radio" name="rb" value="female">여자</label>
</td>
</tr>
<tr>
<th>셀렉트 박스</th>
<td>
<select name="sel1">
<option value="1">사과</option>
<option value="2">귤</option>
<option value="3">포도</option>
</select>
</td>
</tr>
<tr>
<th>다중 셀렉트 박스</th>
<td>
<select name="sel2" multiple>
<option value="1">사과</option>
<option value="2">귤</option>
<option value="3">포도</option>
</select>
</td>
</tr>
<tr>
<th>히든 태그</th>
<td><input type="hidden" name="txt4" value="Isaac"></td>
</tr>
<tr>
<th>날짜</th>
<td><input type="date" name="regdate"></td>
</tr>
<tr>
<th>범위</th>
<td><input type="range" name="min" min="10" max="1000" step="10"></td>
</tr>
<tr>
<th>색상</th>
<td><input type="color" name="color"></td>
</tr>
</table>
<div>
<input type="submit" value="보내기">
<input type="button" value="클릭1" id="btn1">
<input type="button" value="클릭2" id="btn2">
</div>
<input type="hidden" name="count">
</form>
<h1>링크</h1>
<div>
<a href="ex08_ok.jsp?id=isaac&pw=1234">링크로 이동</a>
</div>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="http://pinnpublic.dothome.co.kr/cdn/example-min.js"></script>
<script>
let count = 0;
$('#btn1').click(function(){
count++;
$('input[name=count]').val(count);
});
$('#btn2').click(function(){
location.href = 'ex08_ok.jsp?id=test&pw=' + $('#txt1');
});
</script>
</body>
</html>
ex08_ok.jsp
<%@page import="java.util.Arrays"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
request.setCharacterEncoding("UTF-8");
//텍스트 박스
//1. 입력O: 입력값 반환
//2. 컨트롤O 입력X: null(X), ""(O)
//3. 컨트롤X (key 오류): null 반환
String txt1 = request.getParameter("txt1");
//암호 박스
//한글 입력(X)
String txt2 = request.getParameter("txt2");
//다중 텍스트 박스
String txt3 = request.getParameter("txt3");
if (txt3 == null) txt3 ="";
txt3 = txt3.replace("\r\n", "<br>");
//체크 박스
//1. value가 없을 때
// 체크O: on
// 체크X: null
//2. value가 있을 때
// 체크O: value
// 체크X: null
String cb1 = request.getParameter("cb1");
//체크 박스들 1
/*
String cb2 = request.getParameter("cb2");
String cb3 = request.getParameter("cb3");
String cb4 = request.getParameter("cb4");
String hobby = "";
hobby += cb2 + ",";
hobby += cb3 + ",";
hobby += cb4 + ",";
*/
//체크 박스들 1 일괄 처리
String hobby = "";
for (int i=2; i<=4; i++) {
hobby += request.getParameter("cb" + i) + ",";
}
//체크 박스들 2
//동일한 name의 컨트롤을 여러 개 전송
String[] cb5 = request.getParameterValues("cb5");
//라디오 버튼
String rb = request.getParameter("rb");
//셀렉트 박스
String sel1 = request.getParameter("sel1");
//다중 셀렉트 박스
String[] sel2 = request.getParameterValues("sel2");
//히든 태그
String txt4 = request.getParameter("txt4");
//히든 태그
String count = request.getParameter("count");
//날짜
String regdate = request.getParameter("regdate");
//범위
String min = request.getParameter("min");
//색상
String color = request.getParameter("color");
String id = request.getParameter("id");
String pw = request.getParameter("pw");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="http://pinnpublic.dothome.co.kr/cdn/example-min.css">
</head>
<body>
<h1>결과</h1>
<h2>텍스트 박스</h2>
<div><%= txt1 %></div>
<h2>암호 박스</h2>
<div><%= txt2 %></div>
<h2>다중 텍스트 박스</h2>
<div><%= txt3 %></div>
<h2>체크 박스</h2>
<div><%= cb1 %></div>
<h2>체크 박스들 1</h2>
<div><%= hobby %></div>
<h2>체크 박스들 2</h2>
<div><%= Arrays.toString(cb5) %></div>
<h2>라디오 버튼</h2>
<div><%= rb %></div>
<h2>셀렉트 박스</h2>
<div><%= sel1 %></div>
<h2>셀렉트 박스</h2>
<div><%= Arrays.toString(sel2) %></div>
<h2>히든 태그</h2>
<div><%= txt4 %></div>
<h2>히든 태그</h2>
<div><%= count %>번 클릭!</div>
<h2>날짜</h2>
<div><%= regdate %></div>
<h2>범위</h2>
<div><%= min %></div>
<h2>색상</h2>
<div style="background-color: <%= color %>;"><%= color %></div>
<h2>아이디,암호</h2>
<div><%= id %>,<%= pw %></div>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="http://pinnpublic.dothome.co.kr/cdn/example-min.js"></script>
</body>
</html>
폼 컨트롤에 대해서는 위 글을 참고한다.
체크 박스, 라디오 박스에 대해서는 위 글을 참고한다.
텍스트 박스
- 입력O: 입력값 반환
- 컨트롤O 입력X: null(X), ""(O)
- 컨트롤X (key 오류): null 반환
해당 컨트롤이 존재하는데 값을 입력하지 않았으면 빈문자열("")이다.
그리고 없는 컨트롤을 가져오려고 해서 key 오류가 발생하면 null을 출력한다.
암호 박스
- 한글 입력X
암호 박스는 한글을 입력할 수 없는 컨트롤이지만, 한글을 다른 곳에 적고 이를 복사해서 붙여 넣기 하면 입력할 수 있다. 하지만 암호를 붙여 넣기 해서 넣는 경우는 없으므로 통상적으로 한글이 입력되지 않는다고 본다.
다중 텍스트 박스
모든 텍스트 박스는 getParameter로 받으므로, 다중 텍스트 박스도 마찬가지로 getParameter로 데이터를 수신받는다.
데이터에 White Space(개행)이 있을 때 소스에는 White Space가 있지만, 문서에서는 White Space 처리가 되지 않는다. 그래서 replace 메서드로 "\r\n"을 "<br>"태그로 바꿔줘서 다시 저장하는 작업이 필요하다.
체크 박스
1. value가 없을 때
- 체크O: on
- 체크X: null
2. value가 있을 때
- 체크O: value
- 체크X: null
체크를 하면 on, 체크를 안 하면 null을 반환한다.
체크 박스에 value를 작성하면 체크를 했을 때 작성한 value가 넘어간다.
제대로 관리하기 위해서는 value를 넣는 게 정석이다.
체크 박스들
for문을 사용하여 여러 개의 컨트롤을 일괄 처리 할 수 있다.
getParameterValues는 동일한 name의 컨트롤이 여러 개 전송될 때 사용하는 메서드이다.
라디오 버튼
라디오 버튼은 절대로 두 값을 한꺼번에 전송할 수 있는 방법이 없다. 그래서 서버 쪽에서 라디오 버튼으로 데이터를 받을 때 getParameter를 사용한다.
request로 rb를 받으면 그 안에 "남자"가 있을 수도, "여자"가 있을 수도 있으며, 아무거나 checked 속성을 두면 사용자는 무조건 선택을 해야 하기 때문에 따로 유효성 검사를 하지 않는다.
셀렉트 박스
셀렉트 박스도 라디오 버튼과 마찬가지로 항목들 중에 하나만 선택할 수 있고, 선택한 항목의 value가 넘어가게 된다.
히든 태그
히든 태그는 눈에 보이진 않지만 input 태그이다. 그런데 눈에 보이지 않으므로 입력을 할 수 없다.
사용자가 입력을 할 수 없기 때문에 value를 미리 넣는다.
div>
<input type="submit" value="보내기">
<input type="button" value="클릭" id="btn1">
</div>
<input type="hidden" name="count">
let count = 0;
$('#btn1').click(function(){
count++;
$('input[name=count]').val(count);
});
사용자가 '클릭' 버튼을 누른 횟수를 기억했다가 '보내기' 버튼을 눌렀을 때 버튼을 누른 횟수를 출력하고 싶다고 하자.
그런데 자바스크립트에서 쓰이는 모든 자원은 페이지에 종속적이므로 벗어날 수 없다고 했다.
서버 쪽에서 count를 ok페이지로 전달하는 것은 기본적으로 불가능하다. 그래서 전송 버튼을 눌러서 전송하는 수밖에 없다.
주로 input 태그만 전송 대상이므로 count와 태그를 연결해야 하는데, 이를 화면에 보이기 싫다면 히든 태그를 사용하면 된다.
hidden 태그는 server와 함께 사용할 때 활용도가 높다. 주로 코드의 끝에 넣어서 작성한다.
날짜
눈에 보이는 날짜 그대로가 넘어가므로 2023-10-18이 출력된다.
범위
range(슬라이더)는 근사치를 입력하는 숫자 컨트롤이다.
색상
색상은 16진수(#000000 ~ #FFFFFF)가 넘어간다.
링크
if (txt3 == null) txt3 ="";
링크 버튼을 누르면 에러가 발생한다. 위에서 작성한 모든 request parameter가 존재하지 않기 때문에 모든 값이 null이 되기 때문이다. 이를 해결하기 위해서는 다중 텍스트에 받은 데이터를 가지고 조작하는 부분을 처리해 주어야 한다.
h1>링크</h1>
<div>
<a href="ex08_ok.jsp?id=isaac&pw=1234">링크로 이동</a>
</div>
클라이언트에서 서버로 데이터를 보내는 정석적인 방법은 폼태그를 사용하는 방법이다.
이는 일종의 편법이지만, 링크를 이용해서 데이터를 보내는 방법을 사용할 수 있다. 꼭 a태그가 아니더라도 URL이면 모두 가능하다. 이는 링크 태그가 아니더라도 페이지를 넘어가는 상황에서도 가능하다는 의미이다.
버튼 만들기
- ex09.jsp
- ex09_ok.jsp
ex09.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="http://pinnpublic.dothome.co.kr/cdn/example-min.css">
<style>
</style>
</head>
<body>
<h1>버튼 만들기</h1>
<form method="POST" action="ex09_ok.jsp">
<table class="vertical">
<tr>
<th>너비(px)</th>
<td><input type="number" name="width" min="50" max="300" step="10" value="100"></td>
</tr>
<tr>
<th>높이(px)</th>
<td><input type="number" name="height" min="50" max="300" step="10" value="50"></td>
</tr>
<tr>
<th>텍스트</th>
<td><input type="text" name="text" value="Button"></td>
</tr>
<tr>
<th>배경색</th>
<td><input type="color" name="backcolor" value="#FFFFFF" style="height: 40px;"></td>
</tr>
<tr>
<th>글자색</th>
<td><input type="color" name="textcolor" value="#000000" style="height: 40px;"></td>
</tr>
<tr>
<th>글자 크기(px)</th>
<td><input type="number" name="fontsize" min="10" max="50" value="16"></td>
</tr>
<tr>
<th>버튼 개수(ea)</th>
<td><input type="number" name="ea" min="1" max="20" value="1"></td>
</tr>
</table>
<div>
<input type="submit" value="만들기">
</div>
</form>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="http://pinnpublic.dothome.co.kr/cdn/example-min.js"></script>
<script>
</script>
</body>
</html>
ex09_ok.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
request.setCharacterEncoding("UTF-8");
String width = request.getParameter("width");
String height = request.getParameter("height");
String text = request.getParameter("text");
String backcolor = request.getParameter("backcolor");
String textcolor = request.getParameter("textcolor");
String fontsize = request.getParameter("fontsize");
String ea = request.getParameter("ea");
int count = Integer.parseInt(ea);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<!-- <link rel="stylesheet" href="http://pinnpublic.dothome.co.kr/cdn/example-min.css"> -->
<style>
.btn {
width: <%= width %>px;
height: <%= height %>px;
background-color: <%= backcolor %>;
color: <%= textcolor %>;
font-size: <%= fontsize %>px;
}
</style>
</head>
<body>
<h1>결과</h1>
<div>
<% for (int i=0; i<count; i++) { %>
<button class="btn"><%= text %></button>
<% } %>
</div>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="http://pinnpublic.dothome.co.kr/cdn/example-min.js"></script>
<script>
</script>
</body>
</html>
🍂클라이언트에서 서버로 전송할 때의 여러 가지 관련 정보 가져오기
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="http://pinnpublic.dothome.co.kr/cdn/example-min.css">
</head>
<body>
<h1>request</h1>
<p>요청 URL: <%= request.getRequestURI() %></p>
<p>요청 서버 도메인: <%= request.getServerName() %></p>
<p>요청 방식: <%= request.getMethod() %></p>
<p>클라이언트 주소: <%= request.getRemoteAddr() %></p>
<p>컨텍스트 경로: <%= request.getContextPath() %></p>
<a href="ex09.jsp">9번 예제</a> <!-- 상대 경로 -->
<a href="/request.getContextPath()/ex09.jsp">9번 예제</a> <!-- 절대 경로 -->
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="http://pinnpublic.dothome.co.kr/cdn/example-min.js"></script>
</body>
</html>
- getRequestURI
- getServerName
- getMethod
- getRemoteAddr
- getContextPath
getRequestURI는 사용자가 지금 어떤 페이지를 방문하고 있는지, 유입 경로를 알아내고 싶을 때 등의 상황에서 사용하는 메서드이다.
getRemoteAddr는 IP Address이다. 하지만 주소를 요청할 때 도메인이 없어서 localhost로 호출하는데, 이럴 때 0:0:0:0:0:0:0:1로 출력된다.
절대 경로로 주소를 찾아서 들어갈 때 컨텍스트 경로를 알아내는 방법으로 사용하면 된다. 실시간으로 정보를 얻어오기 때문에 컨텍스트 루트명을 바꾸더라도 에러가 발생하지 않는다.