## 55. 웹 애플리케이션 서버 구조로 전환하기 - 웹 기술 도입
- 웹브라우저를 이용하여 클라이언트를 구축하는 방법
- 쿠키와 세션을 다루는 방법
=>
Favicon 생성
https://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 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
'네이버클라우드 > JAVA 웹 프로그래밍' 카테고리의 다른 글
JAVA 53일차 (2023-08-04) 자바 프로그래밍_56. 웹 애플리케이션 자바 표준 기술 JavaEE 도입_개인프로젝트 - 마트 관리 시스템 (0) | 2023.08.05 |
---|---|
JAVA 53일차 (2023-08-04) 자바 프로그래밍_Tomcat (0) | 2023.08.05 |
JAVA 51일차 (2023-08-02) 자바 프로그래밍_55. 웹 애플리케이션 서버 구조로 전환하기 - 웹 기술 도입_개인프로젝트 - 마트 관리 시스템 (0) | 2023.08.02 |
JAVA 50일차 (2023-08-01) 자바 프로그래밍_54. IoC 컨테이너 적용하기_개인프로젝트 - 마트 관리 시스템 (0) | 2023.08.01 |
JAVA 49일차 (2023-07-31) 자바 프로그래밍_주석 (0) | 2023.08.01 |