1) Login / Signup JSP + Servlet 로직 개발 완료
2) <form> 태그는 한 HTML 안에 여러 개가 올 수 있음.
하지만, <form> 태그 안에 <form> 태그가 하나 더 있는건 동작하지 않음.
(화면 상에 문제가 없음)
3) 서블릿 내에서 여러 개의 요청 매핑을 가지기 위해
input type="hidden" 인 pageCode와 같은 값으로 요청을 받아 페이지를 구분했지만,
Spring에서는 이를 개선하여 메소드마다 주소와 요청을 받을 수 있도록 개선함.
4) JDBC의 PreparedStatement 의 executeQuery()는 ResultSet을 반환하고, executeUpdate()는 int값으로 메소드로 인해 영향받은 Row의 개수를 반환함.
5) Front-End의 <form> 태그나 API Request로 받은 Request Parameter의 이름을 내가 원하는 이름의 파라미터로 바인딩할 수 있다. ( String myParam = request.getParameter("요청 스펙에서의 param 이름");
HTTP Protocol이 무상태성(Stateless)의 특징을 가지기 때문요청-응답의 단순성을 가지고, 확장이 용이하지만, 클라이언트의 요청 정보를 기억해야하는 경우가 있다.Java Servlet 단에서 제공하는 Session
javax.servlet.http.HttpSession

String getId()
String[] getValueNames()
Object getAttribute(String name)
Object 타입으로 리턴받기에, 이를 캐스팅해주어야한다.void setAttribute(String name, Object value)
`void removeAttribute(String name)
void invalidate()
void setMaxInactiveInterval(int interval)
0으로 설정함으로써 invalidate()와 동일한 효과를 낼 수 있습니다.int getMaxInactiveInterval()
long getCreationTime()
long getLastAccessedTime()
session을 가지고 있습니다. 이는 추후 Tomcat에 의해 Servlet으로 변환될 때 HttpSession 타입의 인스턴스로 변환됩니다.void removeAttribute(String name)invalidate()setMaxInactiveInterval(0)1) Session 객체 생성
HttpSession session = request.getSession();2) Session에 Client 정보 저장
session.setAttribute(String key, Object value);3) Session 정보 얻어오기
Object obj = session.getAttribute(String key);4) Session 종료하기
session.invalidate();session.removeAttribute(String key); // 해당 session 종료5) Session 시간 설정
Tomcat의 web.xml or 특정 어플리케이션의 web.xml<session-config>
<session-timeout> 초 </session-timeout>
</session-config>
applciation.properties 등의 설정과도 연관이 있다.
<servlet> : 서블릿 등록<servlet-class> : 서블릿이 존재하는 패키지포함 클래스 이름<init-param> : 서블릿이 초기화(init())될 때 전달할 파라미터debug 모드는 켜지말라는 뜻(0)<load-on-startup> : 톰캣 구동 시, 등록된 서블릿 중 구동되는 순서
JspServlet 이다.

<servlet-name> 을 보면 이름이 default 인 서블릿이 등록된다는 것을 알 수 있다.
<servlet-mapping>을 보면, / , 즉 모든 url에 대해 매핑된다는 것을 알 수 있다.
톰캣은 전달받은 요청에 대해 URL을 기준으로 실행시킨다.
톰캣에서 URL-Pattern을 이렇게 등록해놓으면, /로 오는 서블릿을 실행시킨다.
톰캣은, <servlet-mapping>으로 url pattern에 매핑된 Servlet을 확인하고, <servlet-name>을 통해 서블릿을 init() 한 이후 service()를 호출해준다.
<!-- Tomcat server.xml 설정 중 일부 -->
<Connector connectionTimeout="20000"
maxParameterCount="1000" port="8081"
URIEncoding="UTF-8" protocol="HTTP/1.1" redirectPort="8443"/>

webapps

web_prj ( 톰켓 위에서 동작하는 어플리케이션의 이름의 예시로, 현재 web_prj라는 패키지 명으로 되어있기에 이렇게 적었습니다. )프로젝트 4개를 등록했다면?
- <Context docBase =”web_prj” …> <Context docBase = “my_prj” … > <Context docBase = “user_prj” … >
이와 같이 추가해서 적어주면 됩니다.
즉, 하나의 톰캣 위에서 여러 개의 어플리케이션을 띄울 수 있습니다.
( 스프링 부트에서는 내장 Tomcat으로 하나의 어플리케이션에 하나의 WAS가 붙습니다. )
톰캣은 실행 시작 시, web.xml / server.xml 을 비롯한 모든 xml 설정 파일을 읽어서
이렇게 설정된 내용을 기반으로 동작합니다.
webapp - WEB/INF 는 우리 프로젝트 자체의 설정!
**Tomcat**의 **web.xml** & 우리 프로젝트를 위한 **web.xml****Tomcat**의 **web.xml** 에서 세션 최대 시간을 50초로 해놓으면**web_prj**) 에서 세션 지속 시간을 5분으로 하면**Tomcat**의 **web.xml**은 왜 하는건가?Tomcat의 **web.xml** 을 참조하고**web.xml**을 참조해야한다.\**web.xml**을 통해 세션 지속 시간 / 한글 처리 등의 설정을 지정해줄 수 있다.
web_prj )의 web.xml 구경<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
<display-name>web_prj</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.jsp</welcome-file>
<welcome-file>default.htm</welcome-file>
</welcome-file-list>
</web-app>
한글 설정
응답 헤더의 contentType 설정
<%@page contentType=”text/html;charset=euc-kr” pageEncoding=”euc-kr” %>매 서블릿마다 아래의 코드를 추가해준다.
request.setCharacterEncoding("euc-kr");
response.setContentType("text/html;charset=euc-kr");
이걸 모든 서블릿에 해주는 것이 불편하니
설정 파일을 건든다. ( **web.xml** )
URL : 주소 ( 프로토콜 포함 )
URI : 모든 접근가능한 자원의 식별자
!!! 세션은 파일이다 !!!

HttpSession session = request.getSession();
session.setAttribute("KEY_SESS_USERID", uuvo.getUserId());
session.setAttribute("KEY_SESS_UNAME", uuvo.getUname());
session.setAttribute("KEY_SESS_GRADE", uuvo.getGrade());
// 서블릿에서 session 꺼내서 표시할 때.
// JSP에서 하는게 낫다! 왜냐하면 JSP는 내장객체로 session이 있기 때문이다.
<%
String uid = (String) session.getAttribute("KEY_SESS_USERID");
String unam = (String) session.getAttribute("KEY_SESS_UNAME");
String grade = (String) session.getAttribute("KEY_SESS_GRADE");
%>
<%= uid %>
<%= out.println(unam + "님 환영합니다 "); %>
// 근데 만약 로직이 들어가야한다면, <%= %> 를 쓰는 것이 아니다.
// <%= %> 은 out.println의 약자로 동작하기 때문이다!
<div class="container-fluid px-4">
<h1 class="mt-4">Dashboard</h1>
<%= session.getAttribute("KEY_SESS_USERID")%>님 환영합니다.
<!-- 세션 보이기 -->
<%
String userId = (String) session.getAttribute("KEY_SESS_USERID");
String uname = (String) session.getAttribute("KEY_SESS_UNAME");
String grade = (String) session.getAttribute("KEY_SESS_GRADE");
if(grade.equals("u")){
out.println("사용자접속");
} else if(grade.equals("a")){
out.println("관리자 접속");
} else {
response.sendRedirect("500.html");
}
%>
클라이언트가 서버에게 세션을 지워달라 요청해도,
서버가 지우는 것이기에 즉각적으로(Right Now) 지우지 못한다.
(서버가 처리해야할 시간이 필요하다.)
가장 확실한 방법은 브라우저를 껐다가 키는 것.
브라우저가 종료되니 브라우저 세션 키가 바뀜!!
그래서 서버는 기존의 브라우저의 키에 해당하는 세션로그파일을 설정된 시간만큼 관리하다 폐기함.

근데 만약 이런 JSP가 30개면??
공통적으로 다 불러들이는 문법인 include 를 통해 이 문제를 해결할 수 있다.
<%
String grade = (String) session.getAttribute("KEY_SESS_GRADE");
%>
<%
if(grade != null) {
%>
<a class="nav-link" href="<%=request.getContextPath()%>/user_servlet">Logout</a>
<% } else { %>
<a class="nav-link" href="<%=request.getContextPath()%>login.jsp">Login</a>
<% } %>
/**
* response.sendRedirect("xx.jsp"); : 글자 전송에 사용
* response.sendRedirect("tables.jsp?UID=kim"); : Query String 전달 가능
*/
// 객체 전송에 사용
request.setAttribute("bvos", bvos);
RequestDispatcher rd = request.getRequestDispatcher("xx.jsp");
rd.forward(request, response);
// 세션에 담으면 어떤 일이 일어날까?
// session.setAttribute("bvos", bvos);
// 사용자 로그인 이후 세션 삭제될 때까지 board같은 경우
// 기존의 값이 유지됨. ( 새로운 Board가 추가되어도 반영되지 않음 )
request.setAttribute는 해당 요청에 대해서만 유효, 끝
session.setAttribute는, 로그아웃 할 때까지 해당 데이터가 고정됨
**유저 등급** 같은 경우는 session으로 담는다.**request.setAttribute**에 담는다.session이 request 보다 데이터가 유지되는 범위가 크다.
**application.setAttribute()** 라는 것도 있다.
page.setAttribute는?
page scopepage ( JSP 안에서 ) → requet (JSP + Servlet) → session (로그인, 로그아웃 하기 전 모든 페이지?) → application (서버에 연결된 모든 페이지)
**setAttribute**를 통해 담음.<table id="datatablesSimple">
<thead>
<tr>
<th>글번호</th>
<th>제목</th>
<th>글쓴이</th>
<th>작성일</th>
</tr>
</thead>
<tfoot>
<tr>
<th>글번호</th>
<th>제목</th>
<th>글쓴이</th>
<th>작성일</th>
</tr>
</tfoot>
<tbody>
<%
if(request.getAttribute("bvos") != null){
ArrayList<BoardVO> list = (ArrayList<BoardVO>) request.getAttribute("bvos");
out.println("총 : " + list.size());
for(BoardVO bvo : list){
%>
<tr>
<td><%=bvo.getSeq()%></td>
<td><%=bvo.getTitle()%></td>
<td><%=bvo.getRegId()%></td>
<td><%=bvo.getRegDate()%></td>
</tr>
<% }} %>
</tbody>
</table>
<% if(session.getAttribute("KEY_SESS_USERID") != null) {
out.println(session.getAttribute("KEY_SESS_USERID") + "님 환영합니다.");
}
%>
<!-- tables.jsp -->
<!-- 세션 보이기 -->
<%
if(grade != null){
if(grade.equals("u")){
out.println("사용자접속");
} else if(grade.equals("a")){
out.println("관리자 접속");
} else {
response.sendRedirect("500.html");
}
}
%>
<!-- tables_detail.jsp 내용 -->
<%
BoardVO bvo = null;
if(request.getAttribute("bvo") != null){
bvo = (BoardVO) request.getAttribute("bvo");
}
%>
<a href> 태그에서 직접 ? 를 통해 Query String을 넣어줄 수 있다.<%
if(request.getAttribute("bvos") != null){
ArrayList<BoardVO> list = (ArrayList<BoardVO>) request.getAttribute("bvos");
out.println("총 : " + list.size());
for(BoardVO bvo : list){
%>
<tr>
<td><%=bvo.getSeq()%></td>
<td><a href="<%=request.getContextPath()%>/board_servlet?seq=<%=bvo.getSeq()%>&pagecode=B002"><%=bvo.getTitle()%></a></td>
<td><%=bvo.getRegId()%></td>0
<td><%=bvo.getRegDate()%></td>
</tr>
<% }} %>
<td>
<a href="<%=request.getContextPath()%>/board_servlet?seq=<%=bvo.getSeq()%>&pagecode=B002"><%=bvo.getTitle()%></a>
</td>