본문 바로가기
네이버클라우드/JAVA 웹 프로그래밍

JAVA 52일차 (2023-08-03) 자바 프로그래밍_55. 웹 애플리케이션 서버 구조로 전환하기 - 웹 기술 도입_개인프로젝트 - 마트 관리 시스템

by prometedor 2023. 8. 3.
## 55. 웹 애플리케이션 서버 구조로 전환하기 - 웹 기술 도입

- 웹브라우저를 이용하여 클라이언트를 구축하는 방법
- 쿠키와 세션을 다루는 방법

 

=>

 

Favicon 생성

https://www.favicon-generator.org/

 

Favicon & App Icon Generator

Upload an image (PNG to ICO, JPG to ICO, GIF to ICO) and convert it to a Windows favicon (.ico) and App Icons. Learn more about favicons.

www.favicon-generator.org

=>

ㄴ 파일 선택 후 [Create Favicon] 선택

=>

ㄴ Download the generated favicon 선택

=>

ㄴ favicon 파일 다운 완료

 

=>

ㄴ favicon.ico 파일 Users/사용자명/git/bitcamp-study/report/app-server/src/main/resources/static 경로에 favicon.ico 파일 넣어주기

 

ServerApp.java

=>

=>

 

ServerApp.java

ㄴ 들어오는 요청이 favicon.ico 파일에 대한 것인지 확인하고, 그렇다면 /static 디렉토리의 해당 파일 내용으로 응답하도록 함

=>

ServerApp 실행

=>

ㄴ favicon 이 적용됨을 확인

 

 

ㄴ microsoft.icon 확인

 

 

ServerApp.java

ㄴ Content-Type 을 "image/vnd.microsoft.icon" 으로 설정

=>

ServerApp 실행

=>

ㄴ 설정한 Content-Type 을 개발자 도구로 확인 가능

=>

ServerApp.java

=>

ServerApp.java

ㄴ  '/'로 끝나는 디렉토리의 경우 해당 디렉토리의 index 파일을 반환하며, 그 외에는 요청된 파일 자체를 반환하도록 함

 

DispatcherServlet.java

ㄴ 해당 코드 모두 제거

=>

ServerApp 실행

=>

=>

=>

 

 

로그인

 

암호가 일치할 때

=>

ㄴ get 방식으로 할 경우 정보가 모두 노출됨

 

암호가 일치하지 않을 때

=>

ㄴ get 방식으로 할 경우 정보가 모두 노출됨

 

ServerApp.java

=>

ServerApp.java

ㄴ allCookies() 메서드를 이용하여 쿠키에서 세션 ID 추출하기

=>

ServerApp.java

ㄴ REPORT_SESSION_ID 를 이용하기 위해 상수 설정

     => 오타 방지를 위함

=>

ServerApp.java

=>

ServerApp.java

ㄴ request2.allCookies() 를 이용하여 가져온 REPORT_SESSION_ID 쿠키 목록에서 첫 번째 쿠키를 선택하여 가져오도록 함

(쿠키는 이름-값 쌍으로 구성)

=>

ServerApp.java

=>

ServerApp.java

=>

ServerApp.java

=>

ServerApp.java

=>

ServerApp.java

=>

ServerApp.java

=>

ServerApp.java

=>

ServerApp.java

=>

ServerApp.java

=>

ServerApp 실행 

=>

=>

=>

ServerApp.java

=>

ServerApp 실행 

=>

=>

ㄴ 세션 새로 생성됨을 확인

=>

=>

=>

ㄴ 생성된 세션이 계속 사용됨을 알 수 있음

 

 

크롬에서 쿠키 차단해보기

=>

ㄴ 쿠키 차단 시 로그인 불가함을 알 수 있음

    => 이를 통해 로그인 시 쿠키, 세션이 필요함을 알 수 있음

=>

ㄴ 해결방법보기 링크 선택 시 위와 같이 노출됨

=>

쿠키 차단 풀면 다시 로그인 잘 됨을 확인

 

ServerApp.java

=>

ㄴ HttpSession 이라는 이름의 클래스 생성

 

HttpSession.java

ㄴ String sessionId => 세션을 식별하는 문자열로서, 해당 세션의 고유한 식별자임
ㄴ Map<String, Object> attrMap => 세션에 저장된 속성(attribute)을 관리하기 위한 맵

    ㄴ 각 속성은 이름과 값으로 이루어져 있음
ㄴ public HttpSession(String sessionId) => 생성자 메서드로, 세션 ID를 받아와 초기화 하도록 함
ㄴ public void setAttribute(String name, Object value) => 세션에 속성을 설정하는 메서드

    ㄴ 이름과 값을 받아서 내부의 attrMap에 저장하도록 함
ㄴ public Object getAttribute(String name) => 세션에서 이름에 해당하는 속성 값을 가져오는 메서드

    ㄴ 이름을 인자로 받아 해당 속성 값을 attrMap에서 찾아 반환하도록 함

 

 

https://docs.oracle.com/javaee/7/api/toc.htm

 

Java(TM) EE 7 Specification APIs

 

docs.oracle.com

ㄴ Java api 에 존재하는 HttpSession 모방하여 만들기

=>

HttpSession.java

ㄴ sessionId 를 리턴하는 getId 메서드 생성

=>

HttpSession.java

 

 

ServerApp.java

ㄴ 현재 클라이언트가 사용할 HttpSession 객체가 배정되지 않았다면, 새로 만들도록 함

 

HttpServletRequest.java

ㄴ생성한 HttpSession 사용하기 위해 선언 및 메서드 추가

ㄴ setSession(HttpSession session) => 현재 요청과 연결된 세션 객체를 설정하는 메서드

    ㄴ 이 메서드를 통해 세션을 설정하여 요청과 세션을 연결하도록 함
ㄴ public HttpSession getSession() => 현재 요청과 연결된 세션 객체를 반환하는 메서드

    ㄴ 이를 통해 현재 세션을 얻도록 함

 

ServerApp.java

ㄴ 서블릿에서 HttpSession 보관소를 사용할 수 있도록 HttpServletRequest 에 담아 두도록 함

 

LoginServlet.java

ㄴ 로그인 정보를 다른 요청에도 사용할 수 있도록 세션 보관소에 담아 두도록 함

=>

LoginServlet.java

ㄴ html 태그 수정

 

DispatcherServlet.java

ㄴ 해당 코드 제거 (임의로 member 를 정해주지 말기)

 

BoardAddServlet.java

ㄴ request.getSession() => 현재 요청과 연결된 세션을 가져오는 메서드를 호출하여 세션 객체에 접근할 수 있도록 함

ㄴ .getAttribute("loginUser") => 세션 객체에서 이름이 "loginUser"인 속성(attribute)의 값을 가져오는 메서드를 호출하도록 함

    ㄴ 이 값은 로그인한 사용자 정보를 담고 있음

 

BoardAddServlet.java

ㄴ 로그인한 사용자를 확인하고 로그인하지 않은 경우에 로그인 페이지로 이동시키도록 함

ㄴ Member loginUser = (Member) request.getSession().getAttribute("loginUser"); => 세션에서 이름이 "loginUser"인 속성을 가져와서 Member 클래스로 형변환하여 loginUser 변수에 저장하도록 함

=> 세션에 저장된 로그인한 사용자 정보를 loginUser 변수에 담도록 함
ㄴ if (loginUser == null) { ... }: loginUser 변수가 null인지 확인하도록 함

    ㄴ 이는 세션에 로그인 정보가 없는 경우를 의미
ㄴ response.sendRedirect("/auth/form.html"); => 로그인 정보가 없는 경우, 클라이언트를 /auth/form.html로 리다이렉트시키도록 함 => 이렇게 함으로써 로그인 페이지로 이동
ㄴ return;: 리다이렉트 후에는 함수 실행을 중단하고 종료함

    ㄴ 즉, 로그인되지 않은 상태에서는 이후의 코드가 실행되지 않음

 

BoardAddServlet.java

ㄴ 작성자를 위쪽에서 선언한 loginUser 로 설정해줌

=>

ServerApp 실행

=>

=>

=>

=>

 

ServerApp.java

ㄴ 새로 만든 세션 객체를 sessionMap 에 세션 ID를 키로하여 저장하도록 함

 

LoginServlet.java

ㄴ loginUser 객체를 html 태그보다 위쪽을 이동시킴

=>

loginServlet.java

ㄴ 사용자 정보가 조회되었을 경우 로그인이 성공한 것으로 판단하고, 로그인 성공 후 메인 페이지로 리다이렉트하도록 함

ㄴ 위의 조건문에서 로그인이 실패한 경우, 간단한 로그인 폼을 출력하는 HTML 코드를 작성하여 응답으로 보내도록 함

=>

ServerApp 실행

=>

=>

=>

=>

=>

=>

ㄴ get 방식의 문제점 => 정보가 노출됨

 

HttpServletRequest.java

ㄴ qsDecoder 제거

ㄴ paramMap, servletPath 추가

=>

HttpServletRequest.java

=>

HttpServletRequest.java

ㄴ QueryStringDecoder 의 original.uri()를 사용하여 qsDecoder를 생성하도록 함

    => URI의 쿼리 파라미터와 경로를 추출하고 파싱하도록 함
ㄴ qsDecoder에서 추출한 경로를 클래스 멤버 변수인 servletPath에 저장하여 현재 HTTP 요청의 경로를 클래스 내에서 사용할 수 있도록 함
ㄴ qsDecoder.parameters().entrySet()을 사용하여 모든 쿼리 파라미터를 순회하면서, 각 쿼리 파라미터의 이름과 값을 paramMap에 저장하여 쿼리 파라미터들을 클래스 내에서 사용할 수 있도록 함

 

HttpServletRequest.java

ㄴ 전달받은 body 문자열을 사용하여 새로운 QueryStringDecoder 객체를 생성한 후 /dumy?를 붙여서 임시로 URI를 만들어주고, 이렇게 만든 URI에 포함된 쿼리 파라미터를 추출할 수 있게 함

ㄴ Charset.forName("UTF-8")는 문자 인코딩을 지정함
ㄴ 생성된 decoder 객체에서 추출한 쿼리 파라미터 값을 bodyParams 맵에 저장하여 바디의 파라미터 값을 추출함
ㄴ bodyParams 맵에 저장된 파라미터들을 순회

    ㄴ paramMap 맵에서 현재 순회 중인 파라미터의 이름에 해당하는 값을 가져옴
    ㄴ 기존에 해당 파라미터가 paramMap에 없는 경우와 있는 경우를 구분하여 처리하도록 함
        ㄴ 파라미터가 기존에 없는 경우: 새로운 ArrayList를 생성하고, 현재 파라미터의 값을 추가한 후 paramMap에 저장함
        ㄴ 파라미터가 기존에 있는 경우: 기존 값에 현재 파라미터의 값을 추가함

HttpServletRequest.java

ㄴ qsDecoder.path -> this.servletPath 로 변경

ㄴ getParameter, getParameterValues 메서드 수정

ㄴ getParameter => 주어진 이름에 해당하는 파라미터 값을 가져오는 역할을 함

                                   => 파라미터 값이 없는 경우 null을 반환하며, 파라미터 값이 있는 경우에는 첫 번째 값을 반환함

                                         ㄴ 사용자는 특정 이름의 파라미터 값을 간단하게 추출하여 사용할 수 있음

ㄴ getParameterValues => 주어진 이름에 해당하는 모든 파라미터 값을 배열로 추출하는 역할을 함

                                                => 파라미터 값이 없는 경우 null을 반환하며, 파라미터 값이 있는 경우에는 값들을 배열로 변환하여 반환함

                                                      ㄴ 사용자는 특정 이름의 파라미터 값들을 배열 형태로 추출하여 사용할 수 있음

 

ServerApp.java

ㄴ resourcePath 변수 설정
     => servletPath에 따라 리소스 경로를 설정하는데, welcome 파일인 경우 index.html 파일을 가리키도록 함
     => servletPath.endsWith("/") ? "index.html" : ""은 servletPath가 /로 끝나면 "index.html"을, 그렇지 않으면 빈 문자열을 반환하여 리소스 경로를 설정함

=>

ServerApp.java

ㄴ 폼 데이터를 전송한 경우 처리
    ㄴ 요청의 바디를 문자열로 읽어온 후, 해당 문자열을 가지고 처리하는 부분을 작성
    ㄴ request2.parseFormBody(body); => 요청의 바디에서 파라미터 값을 추출하여 기존의 파라미터 맵(paramMap)에 추가하는 메서드를 호출
    ㄴ dispatcherServlet.service(request2, response2); => 추출한 파라미터 값을 사용하여 dispatcherServlet을 호출

        ㄴ 이는 요청을 처리하고 응답을 생성하는 로직을 수행
    ㄴ response.addHeader("Content-Type", response2.getContentType()); => 응답의 Content-Type 헤더를 설정
    ㄴ return response2.getContent(); => 처리된 응답의 내용을 반환
ㄴ 폼 데이터를 전송하지 않은 경우 처리
    ㄴ dispatcherServlet.service(request2, response2); => dispatcherServlet을 호출하여 요청을 처리하고 응답을 생성
ㄴ response.addHeader("Content-Type", response2.getContentType()); => 응답의 Content-Type 헤더를 설정함
ㄴ return response.sendString(Mono.just(response2.getContent())); => 처리된 응답의 내용을 반환함

 

static/auth/form.html

ㄴ get -> post 로 변경

 

BoardFormServlet.java

ㄴ method='post' 를 추가하여 POST 방식으로 변경해줌

 

BoardUpdateServlet.java

ㄴ 로그인을 체크하도록 함

 

BoardDeleteServlet.java

ㄴ 로그인을 체크하도록 함

 

BoardDetailServlet.java

ㄴ method='post' 를 추가하여 POST 방식으로 변경해줌

 

static/member/form.html

ㄴ method='post' 를 추가하여 POST 방식으로 변경해줌

 

MemberDetailServlet.java

ㄴ method='post' 를 추가하여 POST 방식으로 변경해줌

=>

ServerApp 실행

=>

=>

 

BoardDeleteServlet.java

ㄴ 게시글 삭제되지 않는 문제 해결

    => 삭제 부분에 list 로 되어었음

          ㄴ list -> delete