: 클라이언트 식별기술. name과 value의 쌍으로 구성된 작은 정보
✔️ 이름, 값, 유효기간, 도메인, 경로
✔️ 아스키 문자만 가능, 한글의 경우 URL인코딩
✔️ 서버에서 생성 후 전송, 브라우저에 저장, 유효기간 이후 자동삭제
✔️ 서버에서 요청시 domain, path가 일치하는 경우(하위경로 포함)에만 자동전송
✅ 상대시간: Max-Age=86400
✅ 절대시간: Expires=Thu, 1-Jun-2023 11:12:15 GMT
Domain: fastcampus.co.kr
path: /ch2/login
id=hello
Max-Age: 606024
❶ 클라이언트가 페이지 요청
❷ 서버에서 쿠키 생성, HTTP 응답 헤더에 쿠키를 포함시켜 응답(Set-Cookie)
❸ 브라우저에 쿠키 저장, 같은 요청을 보내는 경우 자동적으로 HTTP 요청 헤더에 Cookie와 함께 보냄
❹ 서버에서 쿠키를 읽어 클라이언트 식별하여 응답
Cookie cookie = new Cookie("id", "hello"); //쿠키생성
cookie.setMaxAge(60*60*24); //유효기간 설정(sec)
response.addCookie(cookie); //응답에 쿠키 추가
Cookie cookie = new Cookie("id", ""); //변경할 쿠키와 같은 이름의 쿠키 생성
cookie.setMaxAge(0); //유효기간 0으로 설정(삭제)
response.addCookie(cookie); //응답에 쿠키 추가
Cookie cookie = new Cookie("id", ""); //변경할 쿠키와 같은 이름의 쿠키 생성
cookie.setValue(URLEncoder.encode("김아무개")); //값 변경
cookie.setDomain("www.fastcampus.co.kr"); //도메인 변경
cookie.setPath("/ch2"); //경로 변경
cookie.setMaxAge(60*60*24*7); //유효기간 변경
response.addCookie(cookie); //응답에 쿠키 추가
Cookie[] cookies = request.getCookies(); //쿠키읽기, cookie 없으면 null
for(Cookie cookie:cookies){
String name=cookie.getName();
String value=cookie.getValue();
System.out.printf("[cookie]name=%s, value=%s%n", name, value);
}
// loginController
// 1. id와 pwd를 확인
if(!loginCheck(id, pwd)) {
// 2-1. 일치하지 않으면, loginForm으로 이동
String msg = URLEncoder.encode("id 또는 pwd가 일치하지 않습니다.", "utf-8");
// redirect 시 Get으로 이동
return "redirect:/login/login?msg="+msg;
}
// 2-2. id와 pwd가 일치할 때
if(rememberId) {
Cookie cookie = new Cookie("id", id); //쿠키 생성
response.addCookie(cookie); //응답에 저장
} else {
Cookie cookie = new Cookie("id", id);
cookie.setMaxAge(0); //쿠키 삭제
response.addCookie(cookie); //응답에 저장
}
쿠키를 이용하여 서로 관련된 독립적인 요청/응답들을 하나로 묶은 것. login-logout
✔️ 브라우저마다 개별저장소(session객체)를 서버에 제공
✔️ 쿠키는 브라우저마다 저장되기 때문에 서로 다른 PC또는 같은 PC라도 서로 다른 브라우저를 사용한다면 다른 세션 ID를 가짐
✔️ 쿠키를 허용하지 않는 브라우저의 경우 url태그를 사용하면 자동으로 get방식을 이용하여 세션id를 주소에 붙여줌 <c:url value='/login/login'/>
HttpSession session = request.Session; //Http요청헤더로 부터 받아오는 것이므로 Request
session.setAttribute("id", "hello");
❶ 클라이언트가 서버에 처음으로 요청을 보내면 무조건 세션 객체 생성
❷ 세션ID가 담긴 쿠키를 만들어 응답으로 보냄(Set-Cookie)
❸ 브라우저에 쿠키저장, 그 다음부터 요청을 보낼때 쿠키가 자동으로 따라감
❹ 서버는 같은 세션ID를 통해 같은 브라우저에서 온 요청인지 식별
메서드 | 설명 |
---|---|
String getId() | 세션id 반환 |
long getLastAccessedTime() | 세션 내 최근(마지막) 요청을 받은 시간 반환 |
boolean isNew() | 새로 생성된 세션인지 반환, request.getSeesion() 호출 후 사용 |
void invalidate() | 세션 객체 제거, 즉시종료 ex.logout |
void setMaxInactiveInterval(int interval) | 예약종료 |
int getMaxInactiveInterval() | 예약된 세션종료 시간 반환 |
속성 관련 메서드 | 설명 |
---|---|
void setAttribute(String name, Object value) | value를 name에 저장 |
Object getAttribute(String name) | name에 저장된 value 반환 |
void removeAttribute(String name) | 지정된 name의 속성 삭제 |
Enumeration getAttributeNames() | 기본객체에 저장된 모든 속성의 이름 반환 |
✅ 수동종료: sec 단위 ex. 로그아웃
HttpSession session = request.getSession();
session.invalidate(); //즉시종료
session.setMaxInactiveInterval(30*60) //예약종료(30분후)
✅ 자동종료: web.xml에 추가, min 단위
<session-config>
<session-timeout>30</session-timeout>
</session-config>
ex. 로그인 전까지 false, 로그인 후 board 세션 true/home 세션 false
<%@ page session="false" %>
✅ ="true": 세션 없을 때 생성
✅ ="false": 세션 없을 때 새로 생성 X
✔️ 세션에 필요없는 jsp화면
session="false"가 기존 세션에 영향X이미 세✔️ 션이 있는 경우 삭제하지는 않지만 없는 경우 새로 만들지 않음
✔️ sessionScope와 pageContext.session은 사용 불가, sessinScope.id를 pageContext.request.getSession(false).getAttribute("id")로 변경해야함(sts에서 에러라고 표시해도 무시)_
cf. getSession(true)는 session이 없는 경우 session을 새로 생성하기 때문에 session이 없어도 새로 생성하지 않도록 getSession(false) 사용
public String login(
@CookieValue("id") String cookieId,
@CookieValue("JSESSIONID") String sessionId){}
//loginController
@GetMapping("/logout")
public String logout(HttpSession session) {
session.invalidate(); //세션종료
return "redirect:/main"; //홈으로 이동
}
//loginController-login
HttpSession session = request.getSession(); //세션객체 얻어오기
session.setAttribute("id", id); //새션객체에 id저장
//index.jsp
<c:set var="loginOutLink" value="${sessionScope.id==null ? '/login/login' : '/login/logout'}"/>
<c:set var="loginOut" value="${empty sessionScope.id ? 'Login' : 'Logout'}"/>
<li><a href="<c:url value='${loginOutLink}'/>">${loginOut}</a></li>
[http://localhost:8080/ch2/main] -> GET[/ch2/login/logout] 소요시간=95ms
[http://localhost:8080/ch2/main] -> GET[/ch2/main] 소요시간=34ms
[http://localhost:8080/ch2/main] -> GET[/ch2/main] 소요시간=11ms
[http://localhost:8080/ch2/main] -> GET[/ch2/login/login] 소요시간=18ms
[http://localhost:8080/ch2/login/login] -> POST[/ch2/login/login] 소요시간=89ms
//from->to, PerformanceFilter.java
HttpServletRequest req = (HttpServletRequest)request;
String referer = req.getHeader("referer"); //from
String method = req.getMethod();
System.out.print("["+referer+"] -> "+method+"["+req.getRequestURI()+"]");
//boardController:
return "redirect:/login/login?toURL="+request.getRequestURL();
loginForm에서 id와 pw를 입력받아 넘겨줄 때 toURL과 같이 넘겨줌
//loginForm
<input type="hidden" name="toURL" value=${param.toURL}>
//loginController-login
toURL = toURL==null || toURL.equals("") ? "/main" : toURL;
return "redirect:/"+toURL;
@RequestMapping("/ex")
public String main(Model m) throws Exception {
try{
throw new Exception("예외가 발생했습니다.");
} catch(Exception e) {
return "error";
}
}
✅ @ExceptionHandler: 예외처리를 위한 메서드를 작성하고 @ExceptionHandler를 앞에 붙임
//클래스 내 예외처리, 다른 컨트롤러에서 작동X
@Controller
public class ExceptionController {
@ExceptionHandler(NullPointerException.class)
public String catcher2(Exception ex) {
return "error";
}
@ExceptionHandler(Exception.class)
public String catcher(Exception ex) {
return "error";
}
@RequestMapping("/ex")
public String main(Model m) throws Exception {
throw new Exception("예외가 발생했습니다.");
}
@RequestMapping("/ex2")
public String main2() throws Exception {
throw new NullPointerException("예외가 발생했습니다.");
}
}
✅ @ControllerAdvice: 전역 예외처리 클래스 작성 가능(패키지 지정 가능)
✔️ 예외처리 메서드가 중복된 경우, 컨트롤러 내(가까운 곳)의 예외 처리 메서드가 우선
//@ControllerAdvice("com.fastcampus.ch3") // 지정된 패키지에서 발생한 예외만 처리
@ControllerAdvice // 모든 패키지에 적용
public class GlobalCatcher {
@ExceptionHandler({NullPointerException.class, FileNotFoundException.class})
public String catcher2(Exception ex) {
return "error";
}
@ExceptionHandler(Exception.class)
public String catcher(Exception ex) {
return "error";
}
}
✴️ 처리할 예외가 여러 개일 시 {} 배열 이용
✴️ 예외처리 메서드의 Model객체와 컨트롤러 메서드의 Model객체는 다른 객체임
✴️ < %@ page isErrorPage=“true”> 을 작성하면
ExceptionController에 m.addAttribute(“ex”, ex) 문장없이 기본 exception 객체 사용 가능
error.jsp에 ex 변경 -> pageContext.exception
error.jsp: ex -> pageContext.exception
<%@ page isErrorPage="true"%>
<body>
<h1>예외가 발생했습니다.</h1>
발생한 예외 : ${pageContext.exception}<br>
예외 메시지 : ${pageContext.exception.message}<br>
<ol>
<c:forEach items="${pageContext.exception.stackTrace}" var="i">
<li>${i.toString()}</li>
</c:forEach>
</ol>
</body>
: 응답메세지의 상태코드를 변경할 때 사용
❶ 예외처리 메서드 앞에 사용
✔️ 에러가 발생하면 error.jsp로 이동하기 때문에 상태코드 200(요청처리성공), 하지만 에러가 발생했으므로 에러코드를 400(client) or 500(서버)에러로 바꿔줘야함
✔️ ex) 500(default, HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) // 405: Method not allowed(200 -> 405)
@ExceptionHandler({NullPointerException.class, ClassCastException.class})
public String catcher(Exception ex, Model m) {
m.addAttribute("ex", ex);
return "error";
}
❷ 사용자 정의 예외클래스 앞에 사용
✔️ @ResponseStatus을 쓰지 않으면 디폴트 500, 다른 결과값을 얻고싶을 때 사용
@ResponseStatus(HttpStatus.BAD_REQUEST) // 400: Bad Request(500 -> 400)
public MyException extends RuntimeException{
MyException(String msg){
super(msg);
}
MyException(){
this("");
}
}
:상태코드 별 뷰 맵핑, web.xml에 추가
// ExceptionController2
@ResponseStatus(HttpStatus.BAD_REQUEST) // 500 -> 400
class MyException extends RuntimeException {
MyException(String msg) {
super(msg);
}
MyException() { this(""); }
}
<!-- web.xml -->
<error-page>
<error-code>400</error-code>
<location>/error400.jsp</location>
</error-page>
: 예외 종류 별 뷰 맵핑에 사용, servlet-context.xml에 등록
✔️ view-controller와 비슷
✔️ statusCodes로 뷰에대한 상태코드 설정(성공코드 200이 아닌 에러코드)
<beans:bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<beans:property name="defaultErrorView" value="error"/>
<beans:property name="exceptionMappings">
<beans:props>
<beans:prop key="com.fastcampus.ch2.MyException">error400</beans:prop>
</beans:props>
</beans:property>
<beans:property name="statusCodes">
<beans:props>
<beans:prop key="error400">400</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
참고) 자바의 정석 | 남궁성과 끝까지 간다