뉴렉처님의 Servlet-JSP [21강~30강]

byeol·2022년 9월 27일
0

22강 연습문제 풀이


class가 아닌 servlet으로 만들어보자

/add와 매핑한다.

package com.newlecture.web;

import java.io.IOException;
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("/add")
public class Add_1 extends HttpServlet {
	

	
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	    response.setCharacterEncoding("UTF-8");
	    response.setContentType("text/html; charset=UTF-8");
		
		String x_ =request.getParameter("x");
		String y_ =request.getParameter("y");
    //빈문자거나 담겨져오거나
	    int x =0;
	    int y=0;
	    
	    if(!x_.equals("")) x=Integer.parseInt(x_);
	    if(!y_.equals("")) y=Integer.parseInt(y_);
	    
	    int result = x+y;
	    
	    response.getWriter().printf("result is %d",result);
	
	}


위와 같은 결과가 나온다.


23강 여러 개의 Submit 버튼 사용하기.

앞서 나타냈던 덧셈 버튼만이 아니라 뺄셈, 곱셈 등의 버튼을 추가할 때 어떻게 해야할까?

그렇다면 서블릿은 이 버튼들을 어떻게 식별하는 것일까?


위와 같이 /calc라는 url로 calc.html과 calc.java를 연결하자.

calc.html에 덧셈, 뺄셈 두개의 버튼을 만들었다.
이를 어떻게 java에서 식별할 수 있을까?


개발자 도구 환경을 통해 보면 서버 쪽에서는 어떤 버튼을 눌렀는지 전혀 알 수 없다.

앞서 우리는 <input>태그에 name이라는 속성을 부여하여 사용자로부터 값을 받았고 이를 식별할 수 있는 인자로써 name 속성의 값을 사용하였다.
마찬가지로 이번에도 버튼에 name이라는 속성을 부여해서 이 두개의 버튼의 동작을 java에서 조종하도록 하자. 두개의 버튼이 operator로 값이 같은 이유는 두개 중 하나의 버튼이 클리될 것이므로 같은 이름을 갖는다.


개발자 도구를 보자 이제 'operator:덧셈'이라는 데이터를 서버에 전달하게 된다.

package com.newlecture.web;

import java.io.IOException;
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("/calc")
public class Calc extends HttpServlet {
	

	
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	    response.setCharacterEncoding("UTF-8");
	    response.setContentType("text/html; charset=UTF-8");
		
		String x_ =request.getParameter("x");
		String y_ =request.getParameter("y");
        String op=request.getParameter("operator");
		
		//빈문자거나 담겨져오거나
	    int x =0;
	    int y=0;
	    
	    if(!x_.equals("")) x=Integer.parseInt(x_);
	    if(!y_.equals("")) y=Integer.parseInt(y_);
	    
	    int result = 0;
	    
	    if(op.equals("덧셈"))
	    	result=x+y;
	    else
	    	result=x-y;
	    
	    response.getWriter().printf("result is %d",result);
	
	}

}


24강 입력데이터 배열로 보내기

오늘은 사용자로부터 입력 받을 때 배열 형태로 입력 받는 방법에 대해서 알아보자

입력박스가 2개로 정적으로 고정되어 있으나 동적으로 추가할 수도 있다
예를 들어 자기소개서를 작성할 때 자격증 항목이나 취미, 기타 사항을 추가하는 경우가 이와 같다.
그렇다면 각 항목을 nome으로 식별할 수 있도록 다른 이름으로 할 것인가?
하지만 이렇게 하면 수많은 이름이 생기며 서버쪽에서도 이는 부담이 된다
따라서 이름은 같으나 전달할 때는 가변적인 길이가 변동될 수 있도록 배열을 이용하는 것이다.
같은 이름으로 다 보낼 수 있게 된다.
그런데 식별이 가능한가? 가능하다 배열의 위치로 이를 식별하도록 하는 것이다.
즉 배열로 꺼내서 반복문오르 써서 활용이 가능하다.



자 이렇게 <input>태그에 num이라는 name이 중복되지만 이를 배열로 받았으며 java에서 getParameter가 아닌 getParameterValues 함수를 이용한다.


개발자 환경을 보면 저렇게 서버에 전달된다.


25강 상태 유지에 대한 필요성과 방법

웹이라고 하는 녀석은 어플리케이션이 조각나 있음
서블릿이라는 의미도 그렇다.
이렇게 조각나 있기 때문에 전역변수가 없다.
하지만 전역변수가 필요한 경우가 있다. 다음 페이지에서 현재 페이지의 데이터를 필요로 하는 경우이다.
따라서 전역변수처럼 서블릿간의 값을 유지해야 하는 일들이 꼭 필요하다
그렇다면 우리는 어떻게 처리할 것인가?

위 예시처럼 A: (2+) -> B : (3=) ==> B에서는 2+3=5라는 결과를 내야하기 때문에 이전 서블릿 A의 데이터가 필요한 것이다.

따라서 상태를 유지하기 위한 5가지 방법이 있으며 우리는 어플리케여션, 세션, 쿠키 이 3가지 방법을 배움으로써 이번 생에서 어딘가에 담아 놓았던 것을 다음 생에도 이용할 수 있도록 한다.

일단 먼저


이렇게 하나의 입력값을 저장해서 전달하도록 하나의 칸의 html을 만들고 이름을 calc2.html이라고 하자.

또한 Calc2.java를 만들어서 '/calc2'의 이름으로 java와 html를 연결하자


26강 Application 객체

상태를 저장하기 위해서 또는 앞에서 다루었던 결과를 저장하기 위해서 사용할 수 있는 객체 중에서 application 객체 또는 저장소가 있는데 그것에 대해서 배워보자

요청이 오면 웹 서버는 그 요청에 맞는 서블릿을 메모리 공간에 올렸다가 자기 일을 다하면 사라진다.
이러면 다음 결과를 받아서 사용할 수 없기 때문에
서블릿 간 또는 그 자신 간의 데이터를 이어갈 수 있는 저장소가 필요하다. 우리는 그 저장소를 Servlet Context라고 부른다.
Context는 문맥을 의미하며 책갈피와 비슷한 역할을 한다. 책갈피는 책을 이어갈 수 있도록 상태값을 표시해준다. 마찬가지고 Servlet 간의 문맥을 이어갈 수 있도록 하는 상태저장 공간이라고 볼 수 있다.

이것을 우리는 application 객체 또는 저장소라고 한다.

package com.newlecture.web;

import java.io.IOException;

import javax.servlet.ServletContext;
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("/calc2")
public class Calc2 extends HttpServlet {



protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext 
// 클라이언트로부터 얻기application=request.getServletContext();
//웹서버가 보낼 때 웹서버 입장
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("=")) {
        //하나는 앞에서 저장한 내용, 지금 가져온 내용 2가지 가져와야한다.
        
        int x = (Integer)application.getAttribute("value");
        int y=v;
        String operator =(String)application.getAttribute("op");
        
        int result=0;
        
        if(operator.equals("+"))
            result=x+y;
        else
            result=x-y;
        
        response.getWriter().printf("result is %d",result);
        
        }
        //값을 저장
        else {
    //이 값을 저장하는데 어디다 저장?
    
    // 이 application에 v와 op를 저장할 것이다.
        application.setAttribute("value",v);
        application.setAttribute("op",op);
        }
    }

}


27강 Session 객체로 상태 값 저장하기(그리고 Application 객체와의 차이점)

앞서 했던 Calc2.java에서 application을 Attribute로 바꿔보자.
하지만 결과가 같다는 것에 의문이 들겄이다.

무엇이 다른 것인가?
Appliction 객체는 범주 내 즉 전역이다
Session도 범주 내이지만 현재 접속한 사용자마다 다른 저장공간을 가진다. 즉 사용자 별로 그 공간이 달라질 수 있다는 것이다.


자 마이크로소프트 엣지에서
v="1"과 operator="+"에 대한 값을 session에 저장
하지만 이 것이 크롬에 전달되지 못함을 보여준다.

이 것은 크롬 창 2개를 띄우고 한 것이다.
하나의 크롬에 v="1", operator="+" Session을 생성해서 저장하면 이는 다른 창의 크롬에 전달되는 것을 볼 수 있다.

이는 왜 그럴까?

작업 관리자 창을 띄우자
크롬을 보자
여러 프로세스 동작이 아닌
하나의 프로세스에 여러개의 쓰레드가 존재한다.
이는 프로세스가 가지고 있는 자원을 여러개의 쓰레드가 공유하고 있으며 그렇기 때문에 같은 사용자로 인식한다는 것을 알 수 있다.

그렇다면 브라우저가 달라지면 사용자를 다르게 인식한다는 것을 알 수 있다. 서버 쪽에 어떻게 이걸 인식하는 것일까?


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

브라우저를 이용해서 서버에 뭔가를 요청한다.
서버는 그 요청을 수반한 그 프로그램을 처리하다가 그 프로그램에서 다른 Servlet에게 전달하고 싶은 내용을 저장하는 공간이 있으며 이를 application 공간이라고 한다.
사용자마다 그 session 공간이 따로 존재하며 이는 학교나 휘트니스 센터처럼 개인별로 공간이 따로 있는 것이다. (사물함)

사용자의 요청이 오고 만약 그것이 서버 상에 프로그램을 실행하기 위한 첫 요청이라면 사용자는 새로운 사용자가 된다. 그래서 서버 쪽에서 사용자에 대한 session공간이 존재하지 않는다.

하지만 application 객체는 새로운 사용자든 기존 사용자든 상관 없이 모든 정보에 대한 정보를 저장할 수 있다.

session은 사용자 ID를 가지고 있어야한다. 그래야 그 ID에 맞는 공간에 값을 넣어 저장할 수 있다.
처음에는 사용자 식별 ID가 없지만 서버 쪽에서 클라이언트에게 응답이 갈 때 ID를 부여한 응답을 준다.

만약에 A브라우저에 107번을 부여해줬다면
A브라우저의 창이 N개가 띄어져 있어도 같은 ID를 가지고 있기 때문엥 같은 사용자로 인식한다.

Microsoft EdgeChrome

개발자 환경을 통해서 Request Header의 Cookie를 보면 같은 브라우저의 경우 SESSIONID가 같지만 다른 경우에는 SESSIONID가 다르다.

이 경우를 상상해볼 수 있다.
각기 다른 많은 사용자로부터 요청이 오면 SESSION의 공간을 다 유지해야 할까?
그것은 아니다 정리한다.

이 저장소를 비울 때 invalidata()메소드를 사용한다.
Session은 타임아웃이라는 것을 사용하는데
사용자가 요청하고 이 요청에 다른 session 공간을 만들었으나 이후에 이 사용자로부터 요청이 오지 않은 경우 30분동안 이 공간은 유지된다. 기본 타임아웃값이 30분이기 때문이다.
만약 29분 59초에 이 사용자로부터 요청이 오면 다시 30분 동안 이 공간은 유지된다.

만약 30분이 경과되어 같은 ID를 갖은 사용자로부터 요청이 온 경우에는 앞서 들어왔던 사용자와 다르게 인식하며 그에 맞는 공간을 다시 만든다.


29강 Cookie를 이용해 상태 값 유지하기


이 그림은 내가 cookie에 대해 이해할 때 도움이 되었기 때문에
https://lasbe.tistory.com/88 에서 가지고 왔다.
쿠키를 웹 서버에서 만들고 이를 다시 브라우저에 저장하고
다시 요청할 때 이 쿠키를 함께 보낸다는 의미이다.

누구나 쓸 수 있는 application 객체
자기만 쓸 수 있는 Sesscion 객체
꼭 서버에 두지 않고 가지고 다니는 값 Cookie~

클라이언트가 서버에 무언가를 요청할 때 값을 가져갈 수 있다. 크게 3가지 값이 있다.
1. 내가 설정한 것이 아닌 브라우저가 알아서 담아주는 헤더정보 getHeader()
2. 내가 보내는 데이터 getParameter()
3. 브라우저가 쿠키가 있으며 가져가는 getCookies

addCookie()는 서버에 저장하지 않고 브라우저게 저장하겠다는 의미이며 클라이언트에 저장하다가 다음 요청 때 이 쿠키를 가져간다.

서버 쪽에서는 그 값을 application, session이 아닌 클라이언트에게 보내겠다
-> 쿠키를 만든다 new Cookie(키, 값)
-> 쿠키는 키와 값으로 나눠지며 "c"라는 키에 값을 심어서 보낸다.
-> 이 쿠키를 클라이언트로 보내어 그 브라우저에 저장한다. response.addCookie(cookie);

서버가 클라이언트로부터 받은 쿠키를 읽을 때 getCookie()는
클라이언트에 저장된 많은 쿠키들이 배열로 저장되어져 있기 때문에 for문을 통해서 배열의 값들을 읽게 된다.

브라우저 설정을 가면 쿠키에 대한 정보를 볼 수 있는데 쿠키를 허용하지 않으며 데이터를 유지 관리할 수 없다.

'모든 쿠키 및 사이트 데이터 보기'를 클릭하며
사이트 주소가 있고 이 사이트 주소가 나에게 보냈던 쿠키를 볼 수 있다.

package com.newlecture.web;

import java.io.IOException;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;


@WebServlet("/calc2")
public class Calc2 extends HttpServlet {
	

	
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		ServletContext application=request.getServletContext();//얻기
		HttpSession session=request.getSession();
		//쿠키 읽기
		Cookie[] cookies = request.getCookies();
		
		
		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("=")) {
        	//하나는 앞에서 저장한 내용, 지금 가져온 내용 2가지 가져와야한다.
        	
        	//int x = (Integer)application.getAttribute("value");
        	//int x = (Integer)session.getAttribute("value");
        	int x=0;
        	for(Cookie c : cookies) 
        	  if(c.getName().equals("value")) {
        	          x=Integer.parseInt(c.getValue());
        	          break;
        	  }
        	
        	int y=v;
        	//String operator =(String)application.getAttribute("op");
        	//String operator =(String)session.getAttribute("op");
            String operator ="";
            		
        	for(Cookie c : cookies) 
          	  if(c.getName().equals("op")) {
          	          operator=c.getValue();
          	          break;
          	  }
        	
        	int result=0;
    	    
    	    if(operator.equals("+"))
    	    	result=x+y;
    	    else
    	    	result=x-y;
    	    
    	    response.getWriter().printf("result is %d",result);
        	
        }	
        //값을 저장
        else {	
	    //이 값을 저장하는데 어디다 저장?
	    
	    // 이 application에 v와 op를 저장할 것이다.
	    //application.setAttribute("value",v);
	    //application.setAttribute("op",op);
	    
        //session.setAttribute("value",v);
	    //session.setAttribute("op",op);
       
        //문자열의 값으로 저장
        Cookie valueCookie = new Cookie("value",String.valueOf(v));
        Cookie opCookie = new Cookie("op",op);
        response.addCookie(valueCookie);
        response.addCookie(opCookie);
        // 자 이제 클라이언트에게 전달
        }
	    
	    
	    
	   
	
	}

}

30강 Cookie의 path옵션

쿠키란 녀석을 사용할 때 생각할 것이 2가지
첫번째 서블릿은 여러개 인데 모든 서블릿이 아닌 어떤 범주에 있는 서블릿에게만 쿠키를 전달하게 할 것인지
두번째 이 쿠키란 녀석을 얼마나 유지시킬 것인지?
이번 30강에서는 첫번째에 대해서 배우고 31강에서 두번째를 배우도록 하자

나한테만 올 때만 혹은 이 범주의 서블릿에서만 이 쿠키를 사용할 수 있도록 url를 매핑한다.
valueCookie.setPath("/");
opCookie.setPath("/");

위의 방식으로 설정하며 예를 들어
valueCookie.setPath("/add");
opCookie.setPath("/add");

이렇게 설정되어져 있다면 쿠키는 /add라는 url과 매핑된 것이다.
따라서 개발자 환경을 통해서 응답 헤더의 쿠키를 보면

쿠키를 보냈고 주소창 /add를 포함되도록 감색하면 아까 브라우저에 보냈던 쿠키를 다시 가져올 수도 있다.

profile
꾸준하게 Ready, Set, Go!

0개의 댓글