나를 기록하다
article thumbnail
반응형

전에 말했듯, 나는 스프링과 스프링부트, JPA를 먼저 만져보았다.(아주 기초 수준이다.)

그렇기에 스프링과 스프링부트, JPA가 얼마나 편한지 명확하게 인지하지 못하였다.

 

따라서 스프링 이전의 기술인 Servlet과 JSP를 깊게는 못하더라도,

최소한은 공부하고 관련 미니 프로젝트를 만들어보고자 다음주까지 쭉 공부할 계획이다.

 

이 기간동안은 웬만해서는 Servlet과 JSP에 몰입할 계획이다.

다른 공부들은 시간이 나면 하겠지만 조금 미뤄두려 한다.(네트워크와 테코톡)

 

이제 오늘 공부한 내용을 정리하겠다.

 

백엔드 개발 - Java

front / back
자바 로드맵

 

Servlet

GET 요청과 쿼리스트링

  • GET 요청
    • http://localhost/hello에서 hello라는 servlet 문서를 요청하는 것.
    • 무엇을 달라고 하는 요청에는 옵션이 있을 수 있음.
    • ex) http:/localhost/hello?cnt=3 ("cnt=3" 이것을 쿼리스트링이라 한다.)
  • 이와 같이 클라이언트의 옵션 요청에 서버에서 옵션값을 받으려면 request.getParameter("cnt")로 받아준다.
    • 이때 cnt의 값 타입은 String이므로 int형으로 변환해서 받는다.
    • ex) int cnt = Integer.parseInt(request.getParameter("cnt");   

기본값 사용

  • 클라이언트가 GET 요청시 추가적인 옵션 값을 입력하지 않았을 때 에러 발생
  • default를 위한 조건식 추가
http://localhost/hello?cnt=3  ==> "3" 전달(문자열3)
http://localhost/hello?cnt=   ==> "" 전달(빈 문자열)
http://localhost/hello?       ==> null값 전달
http://localhost/hello        ==> null값 전달
String temp = request.getParameter("cnt"); //임시변수로 담아두기

int cnt = 100;

if(temp != null && !temp.equals("")) {
    cnt = Integer.parseInt(temp);
}

for(int i = 0; i < cnt; i++) {
	out.println((i+1) + ": 안녕 Servlet~~~~ <br />");
}

사용자 입력을 통한 GET 요청

  • input 태그의 속성인 name은 사용자가 입력한 값을 전달하는 역할을 한다.
  • form 태그의 action 속성에는 Servlet 매핑 주소를 기입

입력할 내용 많은 경우 POST 요청

  • form 태그에서 값 전달 시 옵션 부여 가능(method="")
  • default로 옵션 부여하지 않을 시 GET 요청
  • GET 요청시 URL을 타고 감, 보안상 문제 및 데이터 전송 한계
  • POST 요청시 데이터는 문서 요청 body에 넣어서 전달(데이터 크기 상관없이 전부 전달)

POST 입력시 한글 입력 문제

  • 클라이언트가 UTF-8 인코딩 방식으로 한글(2 byte) 입력하여 데이터를 웹 서버(tomcat)에 보냄.
  • 웹 서버(tomcat)는 ISO-8859-1 인코딩 방식으로 1 byte씩 읽음.
  • 한글이 깨지는 에러 발생
  • 웹 서버에서 클라이언트의 값을 읽어들이는 과정을 ISO-885901이 아닌 UTF-8로 읽어들이게 해야함.
    • request.setCharacterEncoding("UTF-8"); 으로 설정

서블릿 필터

서블릿 필터

  • 클라이언트로부터 입력받은 한글 데이터를 처리하는 서블릿마다 request.setCharacterEncoding("UTF-8"); 써야하는 상황
    → 대안: 서블릿 실행 전과 후로 실행되는 서블릿 필터
  • 필터 실행은 tomcat이 처음 실행될 때 필터가 실행되고 요청이 올 때마다 전과 후로 실행된다.
  • 필터 클래스 생성 방법
    • java.com.web에 filter라는 directory 생성
    • Filter 인터페이스를 implements한 Filter를 생성
    • doFilter 오버라이딩
    • request.setCharacterEncoding("UTF-8"); 추가
    • chain.doFilter(request,response); 추가 - 흐름을 제어하는 역할
    • web.xml에 등록하여 필터를 설정하는 방법도 있으나, 어노테이션(@WebFilter("/*")의방식으로 하는 것을 추천
package com.web.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

@WebFilter("/*")
public class CharacterEncodingFilter implements Filter {
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws
		IOException,
		ServletException {
		request.setCharacterEncoding("UTF-8");
		chain.doFilter(request,response); //흐름을 제어하는 역할. 다음 단계가 진행됨.
	}
}

여러 개의 submit 버튼 사용

  • Submit 버튼의 name 속성 활용
    → input 태그의 name과 사용자로부터 입력되니 값이 서버로 전달(type이 submit일 때는 선택한 버튼의 value 값만 전달)
  • 예시 코드
<input type="text" name="x" /> 일때 서버에 name과 사용자로부터 입력된 값이 전달된다.("x"와 "입력된 값")

<input type="submit" name="operator" value="덧셈" /> 일때 서버에 name과 value가 전달된다.("operator"과 "덧셈")

입력 데이터를 배열로 전달

  • 입력 데이터가 여러개일 때 input 태그마다 name을 붙여주면 변수의 수에 맞는 많은 name 속성을 지정해야 함.
    → 배열로 해결

[변경 전]

<input type="text" name="x" />          String x_ = request.get request.getParameter("x");
<input type="text" name="y" />          String y_ = request.get request.getParameter("y");
<input type="text" name="z" />          String z_ = request.get request.getParameter("z");

[변경 후]

<div>
	<input type="text" name="num" />
	<input type="text" name="num" />   ===>   String[] num_ = request.getParameterValues("num");
	<input type="text" name="num" />
</div>

 

상태 유지의 필요성 - application | session | cookie

application
session
cookie

Application 객체

  • Application 저장소: 서블릿 컨텍스트(Context: 문맥, 책갈피와 같은 존재 → 책을 이어 읽을 수 있게 해주는 역할)
  • 서블릿 컨텍스트(Servlet Context)란, 서블릿 간에 서로 문맥을 이어갈 수 있는 저장소
[저장소 객체 생성]

ServletContext application = request.getServletContext();

[저장소에 값 저장]

application.setAttribute("value", v) //map 컬렉션(key, value)와 같이 저장한다.

application.setAttribute("op", op);

[저장소에 값 가져오기]

application.getAttribute("value"); ==> 괄호 안에 저장한 키워드 값 넣기

-> Object 객체로 반환 됨
-> int x = (Integer)application.getAttribute("value");

Wrapper 클래스를 활용해서 박싱
  • 예시
@WebServlet("/calc")

public class Calc2 extends HttpServlet {

@Override

protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

	ServletContext application = request.getServletContext(); //서블릿 컨텍스트 저장소 application 객체 생성

	response.setCharacterEncoding("UTF-8");
	response.setContentType("text/html; charset=UTF-8"); 

	String v_ = request.getParameter("v");
	String op = request.getParameter("operator");

	int v = 0;
    
	if(!v_.equals("")) {
		v = Integer.parseInt(v_);
	}
 
	if(op.equals("=")) { //연산이 "=" 일때는 Context 저장소에 있는 값들을 계산해야한다.
		int x = (Integer)application.getAttribute("value"); //앞에 Context에 저장한 값
		int y = v; //현재 사용자가 입력한 값
		String operator = (String)application.getAttribute("op"); //Context에 저장되어있던 operator

		int result = 0;

	if(operator.equals("+")) {
		result = x + y;
		} else {
			result = x - y;
	    }
	response.getWriter().printf("result is %d\n", result);

	} else { //연산이 "+" 또는 "-" 일때는 값을 저장한다.
		application.setAttribute("value", v); //map 컬렉션과 같이 저장한다.
		application.setAttribute("op", op);
		}
	}
}

Session 객체

  • Application 객체의 범위는 Application 전역에서 상태값 유지하는데 사용
  • Session 객체의 범위는 현재 접속한 사용자에 한해서 상태값을 유지하는데 사용
    → 접속한 사용자마다 각각 달느 공간을 가진다.
  • 사용 방법
    • 세션 생성: HttpSession session = request.getSession();
    • 사용: Application 객체 사용 방법과 같음
  • 서로 다른 브라우저 띄워 동일한 사이트 접속 → 2개의 Session(2개의 프로세스)
  • 하나의 브라우저를 2개 띄워 동일한 사이트 접속 → 1개의 Session(1개의 프로세스, 다른 스레드)

웹 서버가 현재 사용자(Session)을 구분하는 방식

  • 사용자가 처음으로 요청 시 Servlet의 SID(Session ID)가 없음.
    (헬스장을 예시로 들면, 첫 방문이기에 아직 회원번호가 발급되지 않은 상황)
  • SID가 없기 때문에 Session 저장소는 사용하지 못하고 Application 저장소만 사용 가능)
    (Session 저장소 - 개인 사물함 / Application - 공용 사물함)

첫 번째 요청(SID 없음)


  • 처음 요청에 응답 시 SID가 부여되고 응답(저장할 수 있는 회원번호가 생기고 앞으로 그 번호에 해당되는 session에 저장)
    (첫 방문 후 회원번호가 발급되면 다음 방문부터는 개인 사물함 사용)

첫 번째 요청 응답


  • 두 번째로 사용자가 요청시 SID를 동반해서 요청이 들어옴.
  • SID가 있기에 Session 저장소에 저장 가능
    (개인 사물함 이용)

두 번째 요청

  • 브라우저를 닫으면 SID는 소멸되고 Session 저장소도 소멸
    (브라우저 닫기 - 회원 탈퇴 - 회원번호 소멸과 같음)
  • 세션 메서드
void setAttribute(String name, Object value); //지정된 이름으로 객체를 설정
Object getAttribute(String name); //지정한 이름의 객체를 반환
void invalidate(); //세션에서 사용되는 객체들을 바로 해제
void setMaxInactiveInterval(int interval); //세션 타임아웃을 정수(초)로 설정
-> 설정한 시간이전에 요청시 타임아웃을 초기화, 설정한 시간이 넘으면 새로운 Session ID로 인식
-> 세션을 무한정으로 유지시키면 저장소가 무한히 증가하게 됨으로 타임아웃을 세팅해줘서 세션 저장소를 관리

Cookie를 이용해 상태값 유지

  • Session은 헬스장에 등록하고 사물함에 신발과 세면도구를 두고 다니는 경우
  • Cookie는 헬스장에 갈 때마다 신발과 세면도구를 들고 다니는 경우
    → 클라이언트가 상태값을 가지고 있다가 웹 서버에 보내고 다시 가지고 오는 것(상태값은 유지)

쿠키

  • Application과 Session은 서버에 저장하는 저장소
  • Cookie는 클라이언트에 저장하는 저장소
  • 클라이언트가 서버에 데이터를 요청할 때 1)Header 설정 2)데이터 설정 3)Cookie의 데이터를 보낼 수 있음
  • 웹 서버에서 데이터를 받는 과정
    1. getHeader("remote-host") - Header 설정 데이터를 가져옴
    2. getParameter("x"); - 데이터를 가져옴
    3. getCookies(); - Cookie를 가져옴

웹 서버에서 데이터를 받는 과정

  • 웹 서버에서 다시 클라이언트로 응답 시 addCookie()를 이용해서 쿠키에 데이터를 담아 클라이언트에 전송
  • 예시
(클라이언트 -> 웹 서버): 웹 서버에 전달 된 쿠키 가져오기
Cookie[] cookies = request.getCookies(); //클라이언트로부터 전달 받은 쿠키를 저장하는 객체 생성
(쿠키는 여러개라고 가정해서 배열값이다.)
Cookie c = cookies[0] //0번째에 있는 cookies값을 쿠키객체 c에 저장

if(c.getName().equals("value")){ //꺼낸 쿠키에 이름(key)값이 value이면 c.getValue();로 값을 가져온다.(반환형 String)
   x = Integer.parseInt(c.getValue());
}

*쿠키가 여러개라면 반복문을 활용해서 이름을 찾아 value를 추출한다.
for(Cookie c : cookies){
   if(c.getName().equals("value")){
      x = Integer.parseInt(c.getValue());
      break;
   }
}

(웹 서버 -> 클라이언트)
1. 저장하고 클라이언트에게 보낼 쿠키 생성
형식: Cookie cookie = new Cookie("문자열", "문자열")

ex)
Cookie valueCookie = new Cookie("value", String.valueOf(v)); //쿠키 저장시 key와 value로 저장
Cookie opCookie = new Cookie("op", op);

2. 쿠키를 클라이언트에게 전달
response.addCookie(valueCookie);
response.addCookie(opCookie);

Cookie의 path 옵션

  • 서블릿마다 쿠기가 다름(A 서블릿을 요청하는데 B 쿠키를 가져가면 안됨)
    → A 서블릿 호출 시 A 쿠키를 들고가도록 설정 또는 특정 범위의 서블릿을 실행할 때 특정 쿠키를 가져가게 설정)
  • path 설정: cookie.setPath("/URI명");
  • 예시
valueCookie.setPath("/"); //valueCookie는 모든 페이지를 요청할때마다 쿠키를 가져와라.
opCookie.setPath("/notice/"); //opCookie는 notice가 포함된 uri일때 쿠키를 가져와라.

Cookie의 maxAge 옵션

  • maxAge를 설정하지 않으면 브라우저가 닫혔을 때 Cookie는 없어짐(브라우저랑 생존주기가 같음)
  • maxAge를 설정하면 브라우저가 닫혀도 그 기간 내에는 Cookie가 유지
  • 예시
valueCookie.setMaxAge(1000); //1000초 설정
opCookie.setMaxAge(24*60*60); //60초 * 60초 = 1시간 * 24 = 24시간(하루동안 쿠키 유지)

Application | Session | Cookie의 차이점

  • Application 저장소
    • 사용범위: 전역범위
    • 생명주기: WAS가 시작해서 종료할 때까지
    • 저장위치: WAS 서버의 메모리
  • Session 저장소
    • 사용범위: 전역범위
    • 생명주기: 세션이 시작해서 종료할 때까지
    • 저장위치: WAS 서버의 메모리
  • Cookie
    • 사용범위: 웹 브라우저별 지정한 path 범주 공간
    • 생명주기: 브라우저에 전달한 시간부터 만료시간까지
    • 저장위치: 웹 브라우저의 메모리 또는 파일
기간을 오래 가지고 사용해야 한다면 Cookie에 저장하는 것이 합리적
세션에 두고 사용하게 된다면 브라우저를 끄고 새로 열 때마다 새로운 SID를 부여받고 세션 저장소에 저장하게 된다.
매번 새로운 SID의 저장소를 만들게 되면 웹 서버 자원을 낭비하게 되므로 Cookie를 사용

참고자료

https://www.youtube.com/@newlec1

 

뉴렉처

"유료" 온라인 강의 사이트 뉴렉처에서 제공하는 프로그래밍 강의 채널입니다. 교육서비스 : (10월 새롭게 오픈될 예정입니다.) https://www.newlecture.com 교재: https://javaweb.tistory.com https://answeris.tistory.

www.youtube.com

 

반응형

'TIL > NewLecture' 카테고리의 다른 글

[TIL-25/230916][뉴렉처] GET/POST, JSP, MVC Model  (0) 2023.09.16
[TIL-24/230915][뉴렉처] JDBC, MySQL  (0) 2023.09.16
profile

나를 기록하다

@prao

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

profile on loading

Loading...