From 68013ea55390ea8cabcf7eef4de0cc86ac01b7f1 Mon Sep 17 00:00:00 2001 From: jhchoi57 <46276276+jhchoi57@users.noreply.github.com> Date: Wed, 18 Jan 2023 11:40:44 +0900 Subject: [PATCH 1/6] =?UTF-8?q?[=EC=B5=9C=EC=A3=BC=ED=98=95]=2012=EC=9D=BC?= =?UTF-8?q?=EC=B0=A8=20-=20=EC=9B=B9=205=EB=8B=A8=EA=B3=84,=206=EB=8B=A8?= =?UTF-8?q?=EA=B3=84=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20(#135)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * FIX : 파일 확장자를 통한 파일 경로 설정으로 수정 기존에는 컨텐트 타입으로 파일 경로 설정 - */* 입력시 로직 꼬임 * FIX : 302 header 응답에서 목적지를 생성자로 넘겨줄 수 있게 수정 기존에는 index.html로 하드코딩 했는데 로그인 실패할 경우 생각해서 수정 * FEAT : Session database 클래스 추가 * FIX : builder 패턴 수정 * FIX : builder 패턴 수정 makeHeader() 메소드 추가 및 구현 * FEAT : 응답 객체에 addCookie 추가 * TEST : postman test 및 관련 코드 수정 cookie값 일단 하드코딩으로 삽입 * FEAT : 쿠키 응답 이후 클라이언트에서 쿠키 요청 확인 로그인이 성공하면 세션아이디를 생성하고 세션아이디와 유저아이디를 세션 데이터베이스에 추가 쿠키 헤더를 만들어서 클라이언트에게 응답 클라이언트가 홈페이지 들어왔을 때 쿠키 요청 보내는지 확인 * REFACTOR : UserController 리팩토링 * FEAT : Http request header에서 쿠키 얻는 함수 구현 * FEAT : 동적 html 구현 쿠키 얻어서 로그인 확인 하고 로그인 상태일 경우 index.html의 로그인 문자열을 user name으로 변경 /user/list todo * FIX : Controllerhandler 로직 수정 * FEAT : List 출력 기능 구현 동적 html인 것과 그렇지 않은 것으로 구분 index.html 로그인 X > 정적 컨트롤러로 그대로 출력 index.html 로그인 O > 동적 컨트롤러로 indexService 통해서 userName 설정 /user/list.html > ListService에서 로그인인 경우와 그렇지 않은 경우 처리 * DOCS : README.md 수정 --- README.md | 11 +++- src/main/java/controller/Controller.java | 2 +- .../controller/DynamicHtmlController.java | 37 ++++++++++++ .../java/controller/StaticFileController.java | 12 ++-- src/main/java/controller/UserController.java | 29 ++++------ src/main/java/db/Database.java | 5 ++ src/main/java/db/Session.java | 29 ++++++++++ src/main/java/http/HttpHeader.java | 6 ++ src/main/java/http/HttpUri.java | 4 ++ src/main/java/http/request/HttpRequest.java | 28 +++++++-- src/main/java/http/response/HttpResponse.java | 55 ++++++++++-------- src/main/java/service/IndexHtmlService.java | 25 ++++++++ src/main/java/service/ListService.java | 58 +++++++++++++++++++ src/main/java/service/LogInService.java | 39 ++++++++++++- src/main/java/service/SignUpService.java | 26 ++++++--- src/main/java/util/HttpResponseUtils.java | 21 ++++++- .../java/webserver/ControllerHandler.java | 17 ++++-- src/main/resources/templates/user/list.html | 1 + src/test/java/SignUpServiceTest.java | 9 ++- 19 files changed, 338 insertions(+), 76 deletions(-) create mode 100644 src/main/java/controller/DynamicHtmlController.java create mode 100644 src/main/java/db/Session.java create mode 100644 src/main/java/service/IndexHtmlService.java create mode 100644 src/main/java/service/ListService.java diff --git a/README.md b/README.md index 8a72f8ce..3e9b64c4 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,9 @@ Java Web Application Server 2022 이 프로젝트는 우아한 테크코스 박재성님의 허가를 받아 https://github.com/woowacourse/jwp-was 를 참고하여 작성되었습니다. +## 프로젝트 구조 + + ## 프로젝트 학습 내용 ### 2주차 @@ -144,4 +147,10 @@ Java Web Application Server 2022 + 생성자는 public, 파라미터는 필수 값들 + Optional한 값들은 속성마다 메소드로 제공, 리턴 값이 빌더 객체 자신이어야 함 + 마지막으로 빌더 클래스 내에 build()메소드를 정의하여 최종 생성된 결과물 리턴, - builder를 통해서만 객체 생성을 하므로 생성 대상이 되는 클래스의 생성자는 private \ No newline at end of file + builder를 통해서만 객체 생성을 하므로 생성 대상이 되는 클래스의 생성자는 private +----------- + + Day 12 + + 쿠키와 세션 + + 서버는 Set-Cookie header 값으로 상태를 유지하고 싶은 값을 클라이언트에 전송 + + 클라이언트는 받은 쿠키 값을 모든 요청의 쿠키 헤더로 서버에 전송 + + 서버는 쿠키 헤더에 따라 이전 접속자인지 확인! \ No newline at end of file diff --git a/src/main/java/controller/Controller.java b/src/main/java/controller/Controller.java index 51c32a57..330cd478 100644 --- a/src/main/java/controller/Controller.java +++ b/src/main/java/controller/Controller.java @@ -6,5 +6,5 @@ import java.io.IOException; public interface Controller { - HttpResponse makeResponse(HttpRequest httpRequest) throws IOException; + HttpResponse makeResponse(HttpRequest httpRequest); } diff --git a/src/main/java/controller/DynamicHtmlController.java b/src/main/java/controller/DynamicHtmlController.java new file mode 100644 index 00000000..14f9b3c9 --- /dev/null +++ b/src/main/java/controller/DynamicHtmlController.java @@ -0,0 +1,37 @@ +package controller; + +import db.Database; +import db.Session; +import http.HttpStatus; +import http.request.HttpRequest; +import http.response.HttpResponse; +import http.response.HttpStatusLine; +import model.User; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import service.IndexHtmlService; +import service.ListService; +import util.HttpResponseUtils; + +import java.util.Collection; + +public class DynamicHtmlController implements Controller{ + private static final Logger logger = LoggerFactory.getLogger(UserController.class); + + @Override + public HttpResponse makeResponse(HttpRequest httpRequest){ + //ContentType, 파일 확장자, uri를 받음 + User loginUser = Database.findUserById(Session.findUserIdBySessionId(httpRequest.getCookie())); + String contentType = httpRequest.getContentType(); + String fileNameExtension = httpRequest.getFileNameExtension(); + String uri = httpRequest.getUri(); + String httpVersion = httpRequest.getHttpVersion(); + + if(uri.equals("/user/list.html")){ + return ListService.service(httpRequest.isLogin(), fileNameExtension, uri, httpVersion, contentType); + } + + // /index.html 로그인 O + return IndexHtmlService.service(fileNameExtension, uri, loginUser, httpVersion, contentType); + } +} diff --git a/src/main/java/controller/StaticFileController.java b/src/main/java/controller/StaticFileController.java index b18ecb14..98dfb9d1 100644 --- a/src/main/java/controller/StaticFileController.java +++ b/src/main/java/controller/StaticFileController.java @@ -11,25 +11,25 @@ public class StaticFileController implements Controller { @Override - public HttpResponse makeResponse(HttpRequest httpRequest) throws IOException { - // ContentType를 받음 + public HttpResponse makeResponse(HttpRequest httpRequest) { + // ContentType, 파일 확장자를 받음 String contentType = httpRequest.getContentType(); + String fileNameExtension = httpRequest.getFileNameExtension(); - // ContentType를 통해 파일 경로 설정 + // 파일 확장자를 통해 파일 경로 설정 // TODO 여러 확장자에 대한 처리 필요 // 일단은 html 확장자일 경우 /templates 그 외는 /static - String filePath = HttpResponseUtils.makeFilePath(contentType); + String filePath = HttpResponseUtils.makeFilePath(fileNameExtension); // 파일 경로를 넘겨서 http response body 생성 byte[] responseBody = HttpResponseUtils.makeBody(httpRequest.getUri(), filePath); - // TODO 여러 HttpStatus에 대한 처리 필요 - // 일단은 200 OK 고정 박아놓음 // 만들어진 body로 응답 객체를 만들어서 리턴 return new HttpResponse.HttpResponseBuilder() .setHttpStatusLine(new HttpStatusLine(HttpStatus.OK, httpRequest.getHttpVersion())) .setBody(responseBody) .setContentType(contentType) + .makeHeader() .build(); } } diff --git a/src/main/java/controller/UserController.java b/src/main/java/controller/UserController.java index 4ebb7757..55b2a742 100644 --- a/src/main/java/controller/UserController.java +++ b/src/main/java/controller/UserController.java @@ -1,6 +1,7 @@ package controller; import db.Database; +import db.Session; import http.HttpStatus; import http.request.HttpRequest; import http.response.HttpResponse; @@ -10,41 +11,31 @@ import org.slf4j.LoggerFactory; import service.LogInService; import service.SignUpService; +import util.HttpRequestUtils; import util.HttpResponseUtils; import java.io.IOException; +import java.util.Map; public class UserController implements Controller { private static final Logger logger = LoggerFactory.getLogger(UserController.class); @Override - public HttpResponse makeResponse(HttpRequest httpRequest) throws IOException { - // Uri 받아옵시다 + public HttpResponse makeResponse(HttpRequest httpRequest) { + // Uri, httpVersion 받아옵시다 String uri = httpRequest.getUri(); + String httpVersion = httpRequest.getHttpVersion(); + // body 에서 params 분리 + Map params = HttpRequestUtils.parseQueryString(httpRequest.getBody()); // 회원가입일 때 if (isSignUpService(uri)) { - // user 정보 받아서 데이터베이스에 입력 - Database.addUser(SignUpService.makeUserByBody(httpRequest.getBody())); - // 302 응답이라 location만 필요하기 때문에 body랑 contentType는 없음! - return new HttpResponse.HttpResponseBuilder() - .setHttpStatusLine(new HttpStatusLine(HttpStatus.FOUND, httpRequest.getHttpVersion())) - .build(); + return SignUpService.service(params, httpVersion); } // 로그인일 때 if(isLoginService(uri)){ - // 성공 - if(LogInService.isLoginSuccess(httpRequest.getBody())){ - // index.html로 이동 - // HTTP 헤더의 쿠키 값을 SID = 세션 ID로 응답 - // 세션 ID는 적당한 크기의 무작위 숫자 또는 문자열 - // 서버는 세션 아이디에 해당하는 User 정보에 접근 가능해야 한다. - } - - // 실패 - // /user/login_failed.html로 이동 - + return LogInService.service(params, httpVersion); } //TODO 임시 코드 - return 예외처리 해야됨 diff --git a/src/main/java/db/Database.java b/src/main/java/db/Database.java index ebaaeef7..d810507b 100644 --- a/src/main/java/db/Database.java +++ b/src/main/java/db/Database.java @@ -1,15 +1,20 @@ package db; import com.google.common.collect.Maps; +import http.response.HttpResponse; import model.User; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.Map; public class Database { + private static final Logger logger = LoggerFactory.getLogger(Database.class); private static Map users = Maps.newHashMap(); public static void addUser(User user) { + logger.debug("Database User input : {}", user); users.put(user.getUserId(), user); } diff --git a/src/main/java/db/Session.java b/src/main/java/db/Session.java new file mode 100644 index 00000000..805f25d0 --- /dev/null +++ b/src/main/java/db/Session.java @@ -0,0 +1,29 @@ +package db; + +import com.google.common.collect.Maps; +import model.User; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; +import java.util.Map; +import java.util.UUID; + +public class Session { + private static final Logger logger = LoggerFactory.getLogger(Session.class); + private static Map sessions = Maps.newHashMap(); + + public static String makeSessionIdAndAddUserId(String userId) { + String sessionId = UUID.randomUUID().toString(); + logger.debug("Session User Input : userId = {}", userId + " sessionId = " + sessionId); + sessions.put(sessionId, userId); + return sessionId; + } + + public static String findUserIdBySessionId(String sessionId){ return sessions.get(sessionId); } + + public static Collection findAll() { + return sessions.values(); + } + +} diff --git a/src/main/java/http/HttpHeader.java b/src/main/java/http/HttpHeader.java index 2d191cdc..7bad295f 100644 --- a/src/main/java/http/HttpHeader.java +++ b/src/main/java/http/HttpHeader.java @@ -17,6 +17,10 @@ public HttpHeader(List headers) { } } + public void addHeader(String headerKey, String headerValue){ + headers.put(headerKey, headerValue); + } + public String toString() { String headerString = ""; for (Map.Entry header : headers.entrySet()) { @@ -34,4 +38,6 @@ public String getAccept() { public String getContentLength() { return headers.get("Content-Length"); } + + public String getCookie() { return headers.get("Cookie"); } } diff --git a/src/main/java/http/HttpUri.java b/src/main/java/http/HttpUri.java index 6d91226b..aead5213 100644 --- a/src/main/java/http/HttpUri.java +++ b/src/main/java/http/HttpUri.java @@ -20,4 +20,8 @@ public String getUri() { public boolean isStaticUri() { return uri.contains("."); } + + public String getFileNameExtension() { + return uri.substring(uri.lastIndexOf(".") + 1); + } } diff --git a/src/main/java/http/request/HttpRequest.java b/src/main/java/http/request/HttpRequest.java index 01c487de..e12f6185 100644 --- a/src/main/java/http/request/HttpRequest.java +++ b/src/main/java/http/request/HttpRequest.java @@ -1,5 +1,6 @@ package http.request; +import db.Session; import http.HttpHeader; import http.exception.NullHttpRequestException; import org.slf4j.Logger; @@ -27,10 +28,6 @@ public String getUri() { return this.httpRequestLine.getHttpUri().getUri(); } - public boolean wantStatic() { - return httpRequestLine.getHttpUri().isStaticUri(); - } - public String getContentType() { logger.debug("Accept : {}", httpHeader.getAccept()); return httpHeader.getAccept().split(",")[0]; @@ -41,11 +38,32 @@ public String getHttpVersion() { } public boolean isPost() { - logger.debug("HTTP method : {}", httpRequestLine.getHttpMethod()); + //logger.debug("HTTP method : {}", httpRequestLine.getHttpMethod()); return this.httpRequestLine.getHttpMethod().equals("POST"); } public String getBody(){ return this.body; } + + public String getFileNameExtension() { + return httpRequestLine.getHttpUri().getFileNameExtension(); + } + + public String getCookie(){ + logger.debug("Cookie : {}", httpHeader.getCookie()); + String cookie = httpHeader.getCookie(); + if(cookie == null) return null; + return HttpRequestUtils.parseQueryString(httpHeader.getCookie()).get("sid"); + } + + public boolean wantDynamicHtml() { + // TODO 동적으로 작동하는 html 리스트를 따로 빼야 할까 + return getUri().equals("/index.html") || getUri().equals("/user/list.html"); + } + + public boolean isLogin() { + // userId가 null 이 아닌 경우 login 상태임 ! + return Session.findUserIdBySessionId(getCookie()) != null; + } } diff --git a/src/main/java/http/response/HttpResponse.java b/src/main/java/http/response/HttpResponse.java index beb42a56..2eda5777 100644 --- a/src/main/java/http/response/HttpResponse.java +++ b/src/main/java/http/response/HttpResponse.java @@ -4,6 +4,8 @@ import http.HttpStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import util.HttpRequestUtils; +import util.HttpResponseUtils; import java.io.DataOutputStream; import java.io.IOException; @@ -17,27 +19,22 @@ public class HttpResponse { private byte[] body; private String contentType; + private String destination; private HttpResponse(HttpResponseBuilder httpResponseBuilder){ this.statusLine = httpResponseBuilder.httpStatusLine; this.body = httpResponseBuilder.body; this.contentType = httpResponseBuilder.contentType; - - this.header = makeHeader(); - } - - private HttpHeader makeHeader() { - if (statusLine.checkStatus(HttpStatus.OK)) return makeResponse200Header(); - if (statusLine.checkStatus(HttpStatus.FOUND)) return makeResponse302Header(); - - // 200 302 응답 둘다 아니면? - return null; + this.destination = httpResponseBuilder.destination; + this.header = httpResponseBuilder.header; } public static class HttpResponseBuilder{ private HttpStatusLine httpStatusLine; private byte[] body; private String contentType; + private String destination; + private HttpHeader header; public HttpResponseBuilder(){} @@ -46,6 +43,19 @@ public HttpResponseBuilder setHttpStatusLine(HttpStatusLine httpStatusLine){ return this; } + public HttpResponseBuilder makeHeader() { + if (this.httpStatusLine.checkStatus(HttpStatus.OK)) { + this.header = HttpResponseUtils.makeResponse200Header(contentType, body.length); + return this; + } + if (this.httpStatusLine.checkStatus(HttpStatus.FOUND)) { + this.header = HttpResponseUtils.makeResponse302Header(destination); + return this; + } + // 200 302 응답 둘다 아니면? + return null; + } + public HttpResponseBuilder setBody(byte[] body){ this.body = body; return this; @@ -56,25 +66,20 @@ public HttpResponseBuilder setContentType(String contentType){ return this; } - public HttpResponse build(){ - return new HttpResponse(this); + public HttpResponseBuilder setDestination(String destination){ + this.destination = destination; + return this; } - } + public HttpResponseBuilder addCookie(String cookieValue){ + this.header.addHeader("Set-Cookie", "sid=" + cookieValue + "; Path=/"); + return this; + } - private HttpHeader makeResponse200Header() { - List headerLines = new ArrayList<>(); - logger.debug("contentType: {}", contentType); - headerLines.add("Content-Type: " + contentType + ";charset=utf-8" + System.lineSeparator()); - headerLines.add("Content-Length: " + body.length + System.lineSeparator()); - return new HttpHeader(headerLines); - } + public HttpResponse build(){ + return new HttpResponse(this); + } - private HttpHeader makeResponse302Header() { - List headerLines = new ArrayList<>(); - // TODO 회원 가입에 대한 리다이렉트로 첫 페이지 띄워주게 하드 코딩 했는데 나중에 확장 해야 할듯 - headerLines.add("Location: " + "/index.html" + System.lineSeparator()); - return new HttpHeader(headerLines); } public void send(DataOutputStream dos) throws IOException { diff --git a/src/main/java/service/IndexHtmlService.java b/src/main/java/service/IndexHtmlService.java new file mode 100644 index 00000000..8a546ce2 --- /dev/null +++ b/src/main/java/service/IndexHtmlService.java @@ -0,0 +1,25 @@ +package service; + +import http.HttpStatus; +import http.response.HttpResponse; +import http.response.HttpStatusLine; +import model.User; +import util.HttpResponseUtils; + +public class IndexHtmlService { + public static HttpResponse service(String fileNameExtension, String uri, User loginUser, String httpVersion, String contentType) { + String filePath = HttpResponseUtils.makeFilePath(fileNameExtension); + + // 파일 경로를 넘겨서 http response string 생성 + String responseString = new String(HttpResponseUtils.makeBody(uri, filePath)); + byte[] responseBody = responseString.replace("로그인", loginUser.getName()).getBytes(); + + // 만들어진 body로 응답 객체를 만들어서 리턴 + return new HttpResponse.HttpResponseBuilder() + .setHttpStatusLine(new HttpStatusLine(HttpStatus.OK, httpVersion)) + .setBody(responseBody) + .setContentType(contentType) + .makeHeader() + .build(); + } +} diff --git a/src/main/java/service/ListService.java b/src/main/java/service/ListService.java new file mode 100644 index 00000000..971fea69 --- /dev/null +++ b/src/main/java/service/ListService.java @@ -0,0 +1,58 @@ +package service; + +import db.Database; +import http.HttpStatus; +import http.response.HttpResponse; +import http.response.HttpStatusLine; +import model.User; +import util.HttpResponseUtils; + +import java.util.Collection; + +public class ListService { + public static HttpResponse service(boolean isLogin, String fileNameExtension, String uri, String httpVersion, String contentType){ + // Login check + if(isLogin) return logInListService(fileNameExtension, uri, httpVersion, contentType); + + // not Login + return new HttpResponse.HttpResponseBuilder() + .setHttpStatusLine(new HttpStatusLine(HttpStatus.FOUND, httpVersion)) + .setDestination("/user/login.html") + .makeHeader() + .build(); + } + + private static HttpResponse logInListService(String fileNameExtension, String uri, String httpVersion, String contentType){ + StringBuilder stringBuilder = makeHtml(); + String filePath = HttpResponseUtils.makeFilePath(fileNameExtension); + + // 파일 경로를 넘겨서 http response string 생성 + String responseString = new String(HttpResponseUtils.makeBody(uri, filePath)); + byte[] responseBody = responseString.replace("%userList%", stringBuilder.toString()).getBytes(); + + // 만들어진 body로 응답 객체를 만들어서 리턴 + return new HttpResponse.HttpResponseBuilder() + .setHttpStatusLine(new HttpStatusLine(HttpStatus.OK, httpVersion)) + .setBody(responseBody) + .setContentType(contentType) + .makeHeader() + .build(); + } + + private static StringBuilder makeHtml() { + int index = 3; // 이미 두개 들어 있음 + Collection userList = Database.findAll(); + StringBuilder stringBuilder = new StringBuilder(); + + for (User user : userList) { + stringBuilder.append("").append(index).append("") + .append("").append(user.getUserId()).append("") + .append("").append(user.getName()).append("") + .append("").append(user.getEmail()).append("") + .append("수정"); + index++; + } + return stringBuilder; + } + +} diff --git a/src/main/java/service/LogInService.java b/src/main/java/service/LogInService.java index 88240e25..e9e48f4f 100644 --- a/src/main/java/service/LogInService.java +++ b/src/main/java/service/LogInService.java @@ -1,6 +1,10 @@ package service; import db.Database; +import db.Session; +import http.HttpStatus; +import http.response.HttpResponse; +import http.response.HttpStatusLine; import model.User; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -9,11 +13,34 @@ import java.util.Map; public class LogInService { - private static final Logger logger = LoggerFactory.getLogger(SignUpService.class); + private static final Logger logger = LoggerFactory.getLogger(LogInService.class); - public static boolean isLoginSuccess(String body) { - Map params = HttpRequestUtils.parseQueryString(body); + public static HttpResponse service(Map params, String httpVersion) { + // 성공 + if(isLoginSuccess(params)){ + // index.html로 이동 + // HTTP 헤더의 쿠키 값을 SID = 세션 ID로 응답 + // 세션 ID는 적당한 크기의 무작위 숫자 또는 문자열 + // 서버는 세션 아이디에 해당하는 User 정보에 접근 가능해야 한다. + String cookie = addSessionAndGetSessionID(params.get("userId")); + return new HttpResponse.HttpResponseBuilder() + .setHttpStatusLine(new HttpStatusLine(HttpStatus.FOUND, httpVersion)) + .setDestination("/index.html") + .makeHeader() + .addCookie(cookie) + .build(); + } + + // 실패 + // /user/login_failed.html로 이동 + return new HttpResponse.HttpResponseBuilder() + .setHttpStatusLine(new HttpStatusLine(HttpStatus.FOUND, httpVersion)) + .setDestination("/user/login_failed.html") + .makeHeader() + .build(); + } + private static boolean isLoginSuccess(Map params) { User tryLoginUser = Database.findUserById(params.get("userId")); logger.debug("User : {}", tryLoginUser); @@ -34,4 +61,10 @@ public static boolean isLoginSuccess(String body) { return false; } + + private static String addSessionAndGetSessionID(String userId) { + return Session.makeSessionIdAndAddUserId(userId); + } + + } diff --git a/src/main/java/service/SignUpService.java b/src/main/java/service/SignUpService.java index 8e12519c..04c5590c 100644 --- a/src/main/java/service/SignUpService.java +++ b/src/main/java/service/SignUpService.java @@ -1,6 +1,10 @@ package service; import controller.UserController; +import db.Database; +import http.HttpStatus; +import http.response.HttpResponse; +import http.response.HttpStatusLine; import model.User; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -11,17 +15,25 @@ public class SignUpService{ private static final Logger logger = LoggerFactory.getLogger(SignUpService.class); - public static User makeUserByBody(String body) { - Map params = HttpRequestUtils.parseQueryString(body); - - User user = new User( + public static User makeUserByParams(Map params) { + return new User( params.get("userId"), params.get("password"), params.get("name"), params.get("email")); + } + public static void addDatabase(User user){ + Database.addUser(user); + } - logger.debug("User : {}", user); - - return user; + public static HttpResponse service(Map params, String httpVersion) { + // user 정보 받아서 데이터베이스에 입력 + SignUpService.addDatabase(SignUpService.makeUserByParams(params)); + // 302 응답이라 location만 필요하기 때문에 body랑 contentType는 없음! + return new HttpResponse.HttpResponseBuilder() + .setHttpStatusLine(new HttpStatusLine(HttpStatus.FOUND, httpVersion)) + .setDestination("/index.html") + .makeHeader() + .build(); } } diff --git a/src/main/java/util/HttpResponseUtils.java b/src/main/java/util/HttpResponseUtils.java index 5893c9eb..94d39276 100644 --- a/src/main/java/util/HttpResponseUtils.java +++ b/src/main/java/util/HttpResponseUtils.java @@ -1,11 +1,14 @@ package util; +import http.HttpHeader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; public class HttpResponseUtils { private static final Logger logger = LoggerFactory.getLogger(HttpResponseUtils.class); @@ -14,8 +17,8 @@ public class HttpResponseUtils { private static final String htmlFilePath = "/templates"; private static final String staticFilePath = "/static"; - public static String makeFilePath(String contentType) { - if (contentType.equals("text/html")) { + public static String makeFilePath(String fileNameExtension) { + if (fileNameExtension.equals("html")) { return basePath + htmlFilePath; } return basePath + staticFilePath; @@ -30,4 +33,18 @@ public static byte[] makeBody(String httpUri, String filePath) { } } + public static HttpHeader makeResponse200Header(String contentType, int bodyLength) { + List headerLines = new ArrayList<>(); + logger.debug("contentType: {}", contentType); + headerLines.add("Content-Type: " + contentType + ";charset=utf-8" + System.lineSeparator()); + headerLines.add("Content-Length: " + bodyLength + System.lineSeparator()); + return new HttpHeader(headerLines); + } + + public static HttpHeader makeResponse302Header(String destination) { + List headerLines = new ArrayList<>(); + headerLines.add("Location: " + destination + System.lineSeparator()); + return new HttpHeader(headerLines); + } + } diff --git a/src/main/java/webserver/ControllerHandler.java b/src/main/java/webserver/ControllerHandler.java index becf7473..9b2896f3 100644 --- a/src/main/java/webserver/ControllerHandler.java +++ b/src/main/java/webserver/ControllerHandler.java @@ -1,6 +1,7 @@ package webserver; import controller.Controller; +import controller.DynamicHtmlController; import controller.StaticFileController; import controller.UserController; import http.request.HttpRequest; @@ -17,11 +18,19 @@ public static Controller handleController(HttpRequest httpRequest) { return whoWant(httpRequest.getUri()); } - // 정적 파일만 원한다면? ex) index.html, /user/form.html - if (httpRequest.wantStatic()) return new StaticFileController(); + // 파일을 원한다면? ex) index.html, /user/form.html, .css, .js + // /index.html, /user/list.html + // Login 정보가 필요한 파일들을 원한다면 - 동적 html 처리 + if(httpRequest.wantDynamicHtml()){ + // 로그인을 하지 않은 index.html인 경우 정적 html 처리 + if(httpRequest.getUri().equals("/index.html") && !httpRequest.isLogin()) + return new StaticFileController(); + return new DynamicHtmlController(); + } + + // 나머지 - 정적 처리 + return new StaticFileController(); - //TODO 아무것도 없으면 나중에 예외처리 - return null; } // ControllerHandler Util을 빼줘야 하나? diff --git a/src/main/resources/templates/user/list.html b/src/main/resources/templates/user/list.html index 77732d3a..a7706df9 100644 --- a/src/main/resources/templates/user/list.html +++ b/src/main/resources/templates/user/list.html @@ -105,6 +105,7 @@ slipp@sample.net 수정 + %userList% diff --git a/src/test/java/SignUpServiceTest.java b/src/test/java/SignUpServiceTest.java index eefc115d..9d6c98bb 100644 --- a/src/test/java/SignUpServiceTest.java +++ b/src/test/java/SignUpServiceTest.java @@ -2,6 +2,9 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import service.SignUpService; +import util.HttpRequestUtils; + +import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; @@ -10,13 +13,13 @@ public class SignUpServiceTest { @DisplayName("회원 가입 시 유저 정보들을 유저 클래스에 잘 담아 주는지 테스트") void makeUserInfoTest() { // given - final String uri = "/user/create?userId=jhchoi57&" + + final String body = "userId=jhchoi57&" + "password=12349865&" + "name=%EC%B5%9C%EC%A3%BC%ED%98%95&" + "email=jhchoi57%40gmail.com"; - + final Map params = HttpRequestUtils.parseQueryString(body); // when - final User user = SignUpService.makeUserInfo(uri); + final User user = SignUpService.makeUserByParams(params); // then assertThat(user).usingRecursiveComparison().isEqualTo(new User( From 4f0941d623c0bcf7a62a657042841ce6115d6ee9 Mon Sep 17 00:00:00 2001 From: jhchoi57 <46276276+jhchoi57@users.noreply.github.com> Date: Fri, 20 Jan 2023 11:27:53 +0900 Subject: [PATCH 2/6] =?UTF-8?q?[=EC=B5=9C=EC=A3=BC=ED=98=95]=2013=EC=9D=BC?= =?UTF-8?q?=EC=B0=A8=20-=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81=20(#141)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * REFACTOR : StaticFileService 클래스 생성 및 리팩토링 * REFACTOR : DynamicHtmlController > HtmlController 이름 변경 * REFACTOR : controller handle 로직 수정 일단 html이면 html컨트롤러로 보내고 정적/동적 판별하여 정적인 경우 StaticFileService 호출 * REFACTOR : ResponseBuilder makeHeader 함수 나누기 200 응답일 경우와 302 응답일 경우 두 경우를 처리하므로 set200Header와 set302Header로 나누고 리팩토링 * FIX : 오타 수정 * FIX : body length가 아닌 body를 인자로 받도록 수정 * REFACTOR : 바꾼 빌더 패턴 IndexHtmlService에 적용 * REFACTOR : 바꾼 빌더 패턴 ListService에 적용 * REFACTOR : 바꾼 빌더 패턴 LogInService에 적용 * REFACTOR : 바꾼 빌더 패턴 SignUpService에 적용 * REFACTOR : 바꾼 빌더 패턴 StaticFileService에 적용 * REFACTOR : static일 경우와 html일 경우 두 가지로 path 정해줌 * REFACTOR : path 인자로 전달해주는 부분 놓친 곳 리팩토링 * REFACTOR : 필요없는 변수 삭제 * REFACTOR : service 함수들 인자 통합 및 정리 * FIX : Test 하면서 생기는 오류 수정 * FEAT : login 이후 index.html에서 유저 이름 눌렀을 때 하이퍼링크 삭제, 회원가입 버튼 삭제 * REFACTOR : 로그인 상태일 경우 로그인버튼과 회원가입 버튼 없애는 로직 함수로 분리 * REFACTOR : IndexHtmlService > HtmlService 이름 변경 * FEAT : 다른 html 파일에서도 로그인 상태일 경우 버튼 없애게 구현 및 리팩토링 * FIX : profile.html 쓸데없는 문자 삭제 * DOCS README.md 학습내용 추가 --- README.md | 9 ++++- .../controller/DynamicHtmlController.java | 37 ----------------- src/main/java/controller/HtmlController.java | 40 +++++++++++++++++++ .../java/controller/StaticFileController.java | 25 ++++-------- src/main/java/http/request/HttpRequest.java | 5 +-- src/main/java/http/response/HttpResponse.java | 11 +++++ src/main/java/service/HtmlService.java | 33 +++++++++++++++ src/main/java/service/IndexHtmlService.java | 25 ------------ src/main/java/service/ListService.java | 24 ++++++----- src/main/java/service/LogInService.java | 6 +-- src/main/java/service/SignUpService.java | 3 +- src/main/java/service/StaticFileService.java | 19 +++++++++ src/main/java/util/HttpResponseUtils.java | 17 ++------ .../java/webserver/ControllerHandler.java | 25 ++++-------- .../resources/templates/user/profile.html | 1 - src/test/java/HttpResponseUtilsTest.java | 20 ---------- 16 files changed, 146 insertions(+), 154 deletions(-) delete mode 100644 src/main/java/controller/DynamicHtmlController.java create mode 100644 src/main/java/controller/HtmlController.java create mode 100644 src/main/java/service/HtmlService.java delete mode 100644 src/main/java/service/IndexHtmlService.java create mode 100644 src/main/java/service/StaticFileService.java diff --git a/README.md b/README.md index 3e9b64c4..5615d2b2 100644 --- a/README.md +++ b/README.md @@ -153,4 +153,11 @@ Java Web Application Server 2022 + 쿠키와 세션 + 서버는 Set-Cookie header 값으로 상태를 유지하고 싶은 값을 클라이언트에 전송 + 클라이언트는 받은 쿠키 값을 모든 요청의 쿠키 헤더로 서버에 전송 - + 서버는 쿠키 헤더에 따라 이전 접속자인지 확인! \ No newline at end of file + + 서버는 쿠키 헤더에 따라 이전 접속자인지 확인! + +----------- + + Day 13 + + Servlet + + Java 언어로 작성된 웹 애플리케이션의 컴포넌트 + + 서버 측에서 실행되며 http 요청을 처리 + + 클라이언트의 요청을 처리하고 응답을 생성 \ No newline at end of file diff --git a/src/main/java/controller/DynamicHtmlController.java b/src/main/java/controller/DynamicHtmlController.java deleted file mode 100644 index 14f9b3c9..00000000 --- a/src/main/java/controller/DynamicHtmlController.java +++ /dev/null @@ -1,37 +0,0 @@ -package controller; - -import db.Database; -import db.Session; -import http.HttpStatus; -import http.request.HttpRequest; -import http.response.HttpResponse; -import http.response.HttpStatusLine; -import model.User; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import service.IndexHtmlService; -import service.ListService; -import util.HttpResponseUtils; - -import java.util.Collection; - -public class DynamicHtmlController implements Controller{ - private static final Logger logger = LoggerFactory.getLogger(UserController.class); - - @Override - public HttpResponse makeResponse(HttpRequest httpRequest){ - //ContentType, 파일 확장자, uri를 받음 - User loginUser = Database.findUserById(Session.findUserIdBySessionId(httpRequest.getCookie())); - String contentType = httpRequest.getContentType(); - String fileNameExtension = httpRequest.getFileNameExtension(); - String uri = httpRequest.getUri(); - String httpVersion = httpRequest.getHttpVersion(); - - if(uri.equals("/user/list.html")){ - return ListService.service(httpRequest.isLogin(), fileNameExtension, uri, httpVersion, contentType); - } - - // /index.html 로그인 O - return IndexHtmlService.service(fileNameExtension, uri, loginUser, httpVersion, contentType); - } -} diff --git a/src/main/java/controller/HtmlController.java b/src/main/java/controller/HtmlController.java new file mode 100644 index 00000000..645e31eb --- /dev/null +++ b/src/main/java/controller/HtmlController.java @@ -0,0 +1,40 @@ +package controller; + +import db.Database; +import db.Session; +import http.request.HttpRequest; +import http.response.HttpResponse; +import model.User; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import service.HtmlService; +import service.ListService; +import service.StaticFileService; + +public class HtmlController implements Controller{ + private static final Logger logger = LoggerFactory.getLogger(HtmlController.class); + private static final String htmlFilePath = "./src/main/resources/templates"; + + @Override + public HttpResponse makeResponse(HttpRequest httpRequest){ + //ContentType, 파일 확장자, uri를 받음 + User logInUser = Database.findUserById(Session.findUserIdBySessionId(httpRequest.getCookie())); + String contentType = httpRequest.getContentType(); + String filePath = htmlFilePath + httpRequest.getUri(); + String httpVersion = httpRequest.getHttpVersion(); + + // list service + if(httpRequest.getUri().equals("/user/list.html")) + return ListService.service( + logInUser, filePath, httpVersion, contentType); + + // index.html service 로그인 O + if(httpRequest.isLogin()) + return HtmlService.service( + filePath, logInUser, httpVersion, contentType); + + // index.html service 로그인 X + return StaticFileService.service( + filePath, httpVersion, contentType); + } +} diff --git a/src/main/java/controller/StaticFileController.java b/src/main/java/controller/StaticFileController.java index 98dfb9d1..986b23a7 100644 --- a/src/main/java/controller/StaticFileController.java +++ b/src/main/java/controller/StaticFileController.java @@ -4,32 +4,21 @@ import http.response.HttpResponse; import http.HttpStatus; import http.response.HttpStatusLine; +import service.StaticFileService; import util.HttpResponseUtils; import java.io.IOException; public class StaticFileController implements Controller { + private static final String staticFilePath = "./src/main/resources/static"; @Override public HttpResponse makeResponse(HttpRequest httpRequest) { - // ContentType, 파일 확장자를 받음 - String contentType = httpRequest.getContentType(); - String fileNameExtension = httpRequest.getFileNameExtension(); + String filePath = staticFilePath + httpRequest.getUri(); + return StaticFileService.service( + filePath, + httpRequest.getHttpVersion(), + httpRequest.getContentType()); - // 파일 확장자를 통해 파일 경로 설정 - // TODO 여러 확장자에 대한 처리 필요 - // 일단은 html 확장자일 경우 /templates 그 외는 /static - String filePath = HttpResponseUtils.makeFilePath(fileNameExtension); - - // 파일 경로를 넘겨서 http response body 생성 - byte[] responseBody = HttpResponseUtils.makeBody(httpRequest.getUri(), filePath); - - // 만들어진 body로 응답 객체를 만들어서 리턴 - return new HttpResponse.HttpResponseBuilder() - .setHttpStatusLine(new HttpStatusLine(HttpStatus.OK, httpRequest.getHttpVersion())) - .setBody(responseBody) - .setContentType(contentType) - .makeHeader() - .build(); } } diff --git a/src/main/java/http/request/HttpRequest.java b/src/main/java/http/request/HttpRequest.java index e12f6185..59c30aa9 100644 --- a/src/main/java/http/request/HttpRequest.java +++ b/src/main/java/http/request/HttpRequest.java @@ -57,9 +57,8 @@ public String getCookie(){ return HttpRequestUtils.parseQueryString(httpHeader.getCookie()).get("sid"); } - public boolean wantDynamicHtml() { - // TODO 동적으로 작동하는 html 리스트를 따로 빼야 할까 - return getUri().equals("/index.html") || getUri().equals("/user/list.html"); + public boolean wantHtml() { + return getFileNameExtension().equals("html"); } public boolean isLogin() { diff --git a/src/main/java/http/response/HttpResponse.java b/src/main/java/http/response/HttpResponse.java index 2eda5777..e0e56691 100644 --- a/src/main/java/http/response/HttpResponse.java +++ b/src/main/java/http/response/HttpResponse.java @@ -56,6 +56,17 @@ public HttpResponseBuilder makeHeader() { return null; } + public HttpResponseBuilder set200Header(String contentType, byte[] body){ + this.header = HttpResponseUtils.makeResponse200Header(contentType, body.length); + this.body = body; + return this; + } + + public HttpResponseBuilder set302Header(String destination){ + this.header = HttpResponseUtils.makeResponse302Header(destination); + return this; + } + public HttpResponseBuilder setBody(byte[] body){ this.body = body; return this; diff --git a/src/main/java/service/HtmlService.java b/src/main/java/service/HtmlService.java new file mode 100644 index 00000000..7fa9f46a --- /dev/null +++ b/src/main/java/service/HtmlService.java @@ -0,0 +1,33 @@ +package service; + +import http.HttpStatus; +import http.response.HttpResponse; +import http.response.HttpStatusLine; +import model.User; +import util.HttpResponseUtils; + +public class HtmlService { + public static HttpResponse service(String filePath, User logInUser, String httpVersion, String contentType) { + + // 파일 경로를 넘겨서 http response string 생성 + String responseString = new String(HttpResponseUtils.makeBody(filePath)); + byte[] responseBody = banLogInAndSignUpWhenUserLogInState(responseString, logInUser); + + return new HttpResponse.HttpResponseBuilder() + .setHttpStatusLine(new HttpStatusLine(HttpStatus.OK, httpVersion)) + .set200Header(contentType, responseBody) + .build(); + } + + public static byte[] banLogInAndSignUpWhenUserLogInState(String responseString, User logInUser){ + return replaceHyperLinkLikeIndexHtml(responseString).replace( + "
  • 로그인
  • \n" + + "
  • 회원가입
  • ", + "
  • " + logInUser.getName() + "
  • ").getBytes(); + } + public static String replaceHyperLinkLikeIndexHtml(String responseString){ + return responseString.replace( + "../user/login.html", "user/login.html").replace( + "../user/form.html", "user/form.html"); + } +} diff --git a/src/main/java/service/IndexHtmlService.java b/src/main/java/service/IndexHtmlService.java deleted file mode 100644 index 8a546ce2..00000000 --- a/src/main/java/service/IndexHtmlService.java +++ /dev/null @@ -1,25 +0,0 @@ -package service; - -import http.HttpStatus; -import http.response.HttpResponse; -import http.response.HttpStatusLine; -import model.User; -import util.HttpResponseUtils; - -public class IndexHtmlService { - public static HttpResponse service(String fileNameExtension, String uri, User loginUser, String httpVersion, String contentType) { - String filePath = HttpResponseUtils.makeFilePath(fileNameExtension); - - // 파일 경로를 넘겨서 http response string 생성 - String responseString = new String(HttpResponseUtils.makeBody(uri, filePath)); - byte[] responseBody = responseString.replace("로그인", loginUser.getName()).getBytes(); - - // 만들어진 body로 응답 객체를 만들어서 리턴 - return new HttpResponse.HttpResponseBuilder() - .setHttpStatusLine(new HttpStatusLine(HttpStatus.OK, httpVersion)) - .setBody(responseBody) - .setContentType(contentType) - .makeHeader() - .build(); - } -} diff --git a/src/main/java/service/ListService.java b/src/main/java/service/ListService.java index 971fea69..ba64bc73 100644 --- a/src/main/java/service/ListService.java +++ b/src/main/java/service/ListService.java @@ -1,41 +1,43 @@ package service; +import controller.UserController; import db.Database; import http.HttpStatus; import http.response.HttpResponse; import http.response.HttpStatusLine; import model.User; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import util.HttpResponseUtils; import java.util.Collection; public class ListService { - public static HttpResponse service(boolean isLogin, String fileNameExtension, String uri, String httpVersion, String contentType){ + private static final Logger logger = LoggerFactory.getLogger(ListService.class); + public static HttpResponse service(User logInUser, String filePath, String httpVersion, String contentType){ + logger.debug("logInUser : {}", logInUser); // Login check - if(isLogin) return logInListService(fileNameExtension, uri, httpVersion, contentType); + if(logInUser != null) return logInListService(logInUser, filePath, httpVersion, contentType); // not Login return new HttpResponse.HttpResponseBuilder() .setHttpStatusLine(new HttpStatusLine(HttpStatus.FOUND, httpVersion)) - .setDestination("/user/login.html") - .makeHeader() + .set302Header("/user/login.html") .build(); } - private static HttpResponse logInListService(String fileNameExtension, String uri, String httpVersion, String contentType){ + private static HttpResponse logInListService(User logInUser, String filePath, String httpVersion, String contentType){ StringBuilder stringBuilder = makeHtml(); - String filePath = HttpResponseUtils.makeFilePath(fileNameExtension); // 파일 경로를 넘겨서 http response string 생성 - String responseString = new String(HttpResponseUtils.makeBody(uri, filePath)); - byte[] responseBody = responseString.replace("%userList%", stringBuilder.toString()).getBytes(); + String responseString = new String(HttpResponseUtils.makeBody(filePath)); + String addedUserListToresponseString = responseString.replace("%userList%", stringBuilder.toString()); + byte[] responseBody = HtmlService.banLogInAndSignUpWhenUserLogInState(addedUserListToresponseString, logInUser); // 만들어진 body로 응답 객체를 만들어서 리턴 return new HttpResponse.HttpResponseBuilder() .setHttpStatusLine(new HttpStatusLine(HttpStatus.OK, httpVersion)) - .setBody(responseBody) - .setContentType(contentType) - .makeHeader() + .set200Header(contentType, responseBody) .build(); } diff --git a/src/main/java/service/LogInService.java b/src/main/java/service/LogInService.java index e9e48f4f..6141b3c3 100644 --- a/src/main/java/service/LogInService.java +++ b/src/main/java/service/LogInService.java @@ -25,8 +25,7 @@ public static HttpResponse service(Map params, String httpVersio String cookie = addSessionAndGetSessionID(params.get("userId")); return new HttpResponse.HttpResponseBuilder() .setHttpStatusLine(new HttpStatusLine(HttpStatus.FOUND, httpVersion)) - .setDestination("/index.html") - .makeHeader() + .set302Header("/index.html") .addCookie(cookie) .build(); } @@ -35,8 +34,7 @@ public static HttpResponse service(Map params, String httpVersio // /user/login_failed.html로 이동 return new HttpResponse.HttpResponseBuilder() .setHttpStatusLine(new HttpStatusLine(HttpStatus.FOUND, httpVersion)) - .setDestination("/user/login_failed.html") - .makeHeader() + .set302Header("/user/login_failed.html") .build(); } diff --git a/src/main/java/service/SignUpService.java b/src/main/java/service/SignUpService.java index 04c5590c..23786c98 100644 --- a/src/main/java/service/SignUpService.java +++ b/src/main/java/service/SignUpService.java @@ -32,8 +32,7 @@ public static HttpResponse service(Map params, String httpVersio // 302 응답이라 location만 필요하기 때문에 body랑 contentType는 없음! return new HttpResponse.HttpResponseBuilder() .setHttpStatusLine(new HttpStatusLine(HttpStatus.FOUND, httpVersion)) - .setDestination("/index.html") - .makeHeader() + .set302Header("/index.html") .build(); } } diff --git a/src/main/java/service/StaticFileService.java b/src/main/java/service/StaticFileService.java new file mode 100644 index 00000000..16a68650 --- /dev/null +++ b/src/main/java/service/StaticFileService.java @@ -0,0 +1,19 @@ +package service; + +import http.HttpStatus; +import http.response.HttpResponse; +import http.response.HttpStatusLine; +import util.HttpResponseUtils; + +public class StaticFileService { + public static HttpResponse service(String filePath, String httpVersion, String contentType){ + // 파일 경로를 넘겨서 http response body 생성 + byte[] responseBody = HttpResponseUtils.makeBody(filePath); + + // 만들어진 body로 응답 객체를 만들어서 리턴 + return new HttpResponse.HttpResponseBuilder() + .setHttpStatusLine(new HttpStatusLine(HttpStatus.OK, httpVersion)) + .set200Header(contentType, responseBody) + .build(); + } +} diff --git a/src/main/java/util/HttpResponseUtils.java b/src/main/java/util/HttpResponseUtils.java index 94d39276..8805b2d3 100644 --- a/src/main/java/util/HttpResponseUtils.java +++ b/src/main/java/util/HttpResponseUtils.java @@ -13,21 +13,10 @@ public class HttpResponseUtils { private static final Logger logger = LoggerFactory.getLogger(HttpResponseUtils.class); - private static final String basePath = "./src/main/resources"; - private static final String htmlFilePath = "/templates"; - private static final String staticFilePath = "/static"; - - public static String makeFilePath(String fileNameExtension) { - if (fileNameExtension.equals("html")) { - return basePath + htmlFilePath; - } - return basePath + staticFilePath; - } - - public static byte[] makeBody(String httpUri, String filePath) { - logger.debug("filePath get : {}", filePath + httpUri); + public static byte[] makeBody(String filePath) { + logger.debug("filePath get : {}", filePath); try { - return Files.readAllBytes(new File(filePath + httpUri).toPath()); + return Files.readAllBytes(new File(filePath).toPath()); } catch (IOException e) { return " 파일을 찾지 못함 !".getBytes(); } diff --git a/src/main/java/webserver/ControllerHandler.java b/src/main/java/webserver/ControllerHandler.java index 9b2896f3..d72285a0 100644 --- a/src/main/java/webserver/ControllerHandler.java +++ b/src/main/java/webserver/ControllerHandler.java @@ -1,7 +1,7 @@ package webserver; import controller.Controller; -import controller.DynamicHtmlController; +import controller.HtmlController; import controller.StaticFileController; import controller.UserController; import http.request.HttpRequest; @@ -10,23 +10,12 @@ public class ControllerHandler { public static Controller handleController(HttpRequest httpRequest) { //TODO httpRequest 보고 어떤 컨트롤러 써야되는지 리턴 해줘야됨 - // 어떤 기능 (회원가입, 로그인 등) 을 원한다면? - // POST 요청일 때 - if (httpRequest.isPost()) { - // 누가 원하는지 > 누구의 컨트롤러가 필요한지 넘겨줌 - // User가 원하면 UserController - return whoWant(httpRequest.getUri()); - } - - // 파일을 원한다면? ex) index.html, /user/form.html, .css, .js - // /index.html, /user/list.html - // Login 정보가 필요한 파일들을 원한다면 - 동적 html 처리 - if(httpRequest.wantDynamicHtml()){ - // 로그인을 하지 않은 index.html인 경우 정적 html 처리 - if(httpRequest.getUri().equals("/index.html") && !httpRequest.isLogin()) - return new StaticFileController(); - return new DynamicHtmlController(); - } + // POST 요청일 때 : 회원가입, 로그인 + // User의 요청이면 UserController 리턴 + if (httpRequest.isPost()) return whoWant(httpRequest.getUri()); + + // html 파일을 원한다면? + if(httpRequest.wantHtml()) return new HtmlController(); // 나머지 - 정적 처리 return new StaticFileController(); diff --git a/src/main/resources/templates/user/profile.html b/src/main/resources/templates/user/profile.html index a3a4ee76..7f5835df 100644 --- a/src/main/resources/templates/user/profile.html +++ b/src/main/resources/templates/user/profile.html @@ -68,7 +68,6 @@ diff --git a/src/main/resources/templates/qna/form.html b/src/main/resources/templates/qna/form.html index 39c7328d..44557a1b 100644 --- a/src/main/resources/templates/qna/form.html +++ b/src/main/resources/templates/qna/form.html @@ -1,5 +1,6 @@ + @@ -68,10 +69,11 @@ diff --git a/src/main/resources/templates/qna/show.html b/src/main/resources/templates/qna/show.html index 261ac16e..a045d94d 100644 --- a/src/main/resources/templates/qna/show.html +++ b/src/main/resources/templates/qna/show.html @@ -1,5 +1,6 @@ + @@ -68,10 +69,11 @@ diff --git a/src/main/resources/templates/user/form.html b/src/main/resources/templates/user/form.html index e56a3dce..bf3b0c97 100644 --- a/src/main/resources/templates/user/form.html +++ b/src/main/resources/templates/user/form.html @@ -1,5 +1,6 @@ + @@ -67,10 +68,11 @@ diff --git a/src/main/resources/templates/user/list.html b/src/main/resources/templates/user/list.html index 170940f9..bfd689bb 100644 --- a/src/main/resources/templates/user/list.html +++ b/src/main/resources/templates/user/list.html @@ -1,5 +1,6 @@ + @@ -68,10 +69,11 @@ @@ -91,7 +93,13 @@ - %userList% + + + + + + 수정 + diff --git a/src/main/resources/templates/user/login.html b/src/main/resources/templates/user/login.html index f843a966..98b95047 100644 --- a/src/main/resources/templates/user/login.html +++ b/src/main/resources/templates/user/login.html @@ -1,5 +1,6 @@ + @@ -68,10 +69,11 @@ diff --git a/src/main/resources/templates/user/login_failed.html b/src/main/resources/templates/user/login_failed.html index cd57fc9e..488abb41 100644 --- a/src/main/resources/templates/user/login_failed.html +++ b/src/main/resources/templates/user/login_failed.html @@ -1,5 +1,6 @@ + @@ -68,10 +69,11 @@ diff --git a/src/main/resources/templates/user/profile.html b/src/main/resources/templates/user/profile.html index 7f5835df..ef024bd6 100644 --- a/src/main/resources/templates/user/profile.html +++ b/src/main/resources/templates/user/profile.html @@ -1,5 +1,6 @@ + @@ -68,10 +69,11 @@ diff --git a/src/test/java/HtmlServiceTest.java b/src/test/java/HtmlServiceTest.java deleted file mode 100644 index e0e4edbd..00000000 --- a/src/test/java/HtmlServiceTest.java +++ /dev/null @@ -1,30 +0,0 @@ -import model.User; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import service.HtmlService; - -import static org.assertj.core.api.Assertions.assertThat; - -public class HtmlServiceTest { - @Test - @DisplayName("동적 html 변환 테스트") - void 동적_HTMl_변환_테스트() { - // given - String indexHtmlResponseString = "
  • 로그인
  • \n" + - "
  • 회원가입
  • "; - String HtmlInUserFolderResponseString = "
  • 로그인
  • \n" + - "
  • 회원가입
  • "; - User logInUser = new User("testid", "testpassword", "홍길동", "asdf@naver.com"); - - // when - byte[] indexHtmlReplacedString = - HtmlService.banLogInAndSignUpWhenUserLogInState(indexHtmlResponseString, logInUser); - byte[] HtmlInUserFolderReplacedString = - HtmlService.banLogInAndSignUpWhenUserLogInState(HtmlInUserFolderResponseString, logInUser); - - // then - byte[] result = ("
  • " + logInUser.getName() + "
  • ").getBytes(); - assertThat(indexHtmlReplacedString).isEqualTo(result); - assertThat(HtmlInUserFolderReplacedString).isEqualTo(result); - } -} diff --git a/src/test/java/HttpRequestUtilsTest.java b/src/test/java/HttpRequestUtilsTest.java deleted file mode 100644 index 7acdb348..00000000 --- a/src/test/java/HttpRequestUtilsTest.java +++ /dev/null @@ -1,37 +0,0 @@ -import http.HttpUri; -import http.request.HttpRequestLine; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import util.HttpRequestUtils; - -import java.util.Map; - -import static org.assertj.core.api.Assertions.assertThat; - -public class HttpRequestUtilsTest { - String sampleRequestLine = "GET /index.html HTTP/1.1"; - String queryString = "userId=jhchoi57&" + - "password=12349865&" + - "name=%EC%B5%9C%EC%A3%BC%ED%98%95&" + - "email=jhchoi57%40gmail.com"; - - @Test - @DisplayName("RequestLine 입력받기 테스트") - public void readRequestLineTest() { - HttpRequestLine httpRequestLine = HttpRequestUtils.readRequestLine(sampleRequestLine); - - assertThat(httpRequestLine).usingRecursiveComparison(). - isEqualTo(new HttpRequestLine("GET", new HttpUri("/index.html"), "HTTP/1.1")); - } - - @Test - @DisplayName("queryString 파싱 테스트") - public void parseQueryStringTest() { - Map requestParamsMap = HttpRequestUtils.parseQueryString(queryString); - assertThat(requestParamsMap.get("userId")).isEqualTo("jhchoi57"); - assertThat(requestParamsMap.get("password")).isEqualTo("12349865"); - assertThat(requestParamsMap.get("name")).isEqualTo("최주형"); - assertThat(requestParamsMap.get("email")).isEqualTo("jhchoi57@gmail.com"); - } - -} diff --git a/src/test/java/HttpResponseUtilsTest.java b/src/test/java/HttpResponseUtilsTest.java deleted file mode 100644 index e017748f..00000000 --- a/src/test/java/HttpResponseUtilsTest.java +++ /dev/null @@ -1,48 +0,0 @@ -import http.HttpHeader; -import org.junit.jupiter.api.Test; -import util.HttpResponseUtils; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; - -import static org.assertj.core.api.Assertions.assertThat; - -public class HttpResponseUtilsTest { - - @Test - void 바디_생성_테스트() throws IOException { - // given - String filePath = "./src/main/resources/templates/index.html"; - // when - byte[] body = HttpResponseUtils.makeBody(filePath); - // then - assertThat(body.length).isEqualTo(Files.readAllBytes(new File(filePath).toPath()).length); - } - - @Test - void OK헤더_생성_테스트() { - // given - String contentType = "text/html"; - int bodyLength = 1024; - // when - HttpHeader header = HttpResponseUtils.makeResponse200Header(contentType, bodyLength); - // then - assertThat(header.toString()).isEqualTo( - "Content-Length: 1024" + System.lineSeparator() + - "Content-Type: text/html;charset=utf-8" + System.lineSeparator() + System.lineSeparator()); - } - - @Test - void FOUND헤더_생성_테스트() { - // given - String destination = "/index.html"; - // when - HttpHeader header = HttpResponseUtils.makeResponse302Header(destination); - // then - assertThat(header.toString()).isEqualTo( - "Location: /index.html" + System.lineSeparator() + System.lineSeparator()); - } - - -} diff --git a/src/test/java/ListServiceTest.java b/src/test/java/ListServiceTest.java deleted file mode 100644 index 709f8b7c..00000000 --- a/src/test/java/ListServiceTest.java +++ /dev/null @@ -1,32 +0,0 @@ -import http.response.HttpResponse; -import model.User; -import org.junit.jupiter.api.Test; -import service.ListService; - -import static org.assertj.core.api.Assertions.assertThat; - -public class ListServiceTest { - // Given - User logInUser = new User("user1", "password", "홍길동", "jasd@email.com"); - String filePath = "src/main/resources/templates/user/list.html"; - String httpVersion = "HTTP/1.1"; - String contentType = "text/html"; - - @Test - public void 로그인상태_ListService_테스트() { - // When - HttpResponse response = ListService.logInListService(logInUser, filePath, httpVersion, contentType); - - // Then - assertThat(response.getBody()).isNotEmpty(); - } - - @Test - public void 로그인상태가아닐때_ListService_테스트() { - // When - HttpResponse response = ListService.service(null, filePath, httpVersion, contentType); - - // Then - assertThat(response.getHeaders().getLocation()).isEqualTo("/user/login.html"); - } -} diff --git a/src/test/java/LogInServiceTest.java b/src/test/java/LogInServiceTest.java deleted file mode 100644 index d8239766..00000000 --- a/src/test/java/LogInServiceTest.java +++ /dev/null @@ -1,41 +0,0 @@ -import db.Database; -import http.response.HttpResponse; -import model.User; -import org.junit.jupiter.api.Test; -import service.LogInService; -import util.HttpRequestUtils; - -import java.util.Map; - -import static org.assertj.core.api.Assertions.assertThat; - -public class LogInServiceTest { - @Test - void 로그인서비스_성공_테스트() { - // given - Database.addUser(new User("testUserId", "testPassword", "testName", "testEmail@naver.com")); - String body = "userId=testUserId&password=testPassword"; - Map params = HttpRequestUtils.parseQueryString(body); - - // when - HttpResponse successResponse = LogInService.service(params, "HTTP/1.1"); - - // then - assertThat(successResponse.getHeaders().getLocation()).isEqualTo("/index.html"); - } - - @Test - void 로그인서비스_실패_테스트() { - // given - Database.addUser(new User("testUserId", "testPassword", "testName", "testEmail@naver.com")); - String body = "userId=testfdadUserId&password=testasdPassword"; - Map params = HttpRequestUtils.parseQueryString(body); - - // when - HttpResponse FailResponse = LogInService.service(params, "HTTP/1.1"); - - // then - assertThat(FailResponse.getHeaders().getLocation()).isEqualTo("/user/login_failed.html"); - - } -} diff --git a/src/test/java/SignUpServiceTest.java b/src/test/java/SignUpServiceTest.java deleted file mode 100644 index 0bda0fc0..00000000 --- a/src/test/java/SignUpServiceTest.java +++ /dev/null @@ -1,48 +0,0 @@ -import db.Database; -import http.response.HttpResponse; -import model.User; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import service.SignUpService; -import util.HttpRequestUtils; - -import java.util.Map; - -import static org.assertj.core.api.Assertions.assertThat; - -public class SignUpServiceTest { - @Test - @DisplayName("회원 가입 시 유저 정보들을 유저 클래스에 잘 담아 주는지 테스트") - void makeUserInfoTest() { - // given - final String body = "userId=jhchoi57&" + - "password=12349865&" + - "name=%EC%B5%9C%EC%A3%BC%ED%98%95&" + - "email=jhchoi57%40gmail.com"; - final Map params = HttpRequestUtils.parseQueryString(body); - // when - final User user = SignUpService.makeUserByParams(params); - - // then - assertThat(user).usingRecursiveComparison().isEqualTo(new User( - "jhchoi57", "12349865", "최주형", "jhchoi57@gmail.com")); - } - - @Test - void 회원가입_서비스_테스트() { - // given - String body = "userId=jhchoi57&" + - "password=12349865&" + - "name=%EC%B5%9C%EC%A3%BC%ED%98%95&" + - "email=jhchoi57%40gmail.com"; - Map params = HttpRequestUtils.parseQueryString(body); - - // when - HttpResponse response = SignUpService.service(params, "HTTP/1.1"); - - // then - assertThat(response.getHeaders().getLocation()).isEqualTo("/index.html"); - assertThat(Database.findUserById("jhchoi57").getUserId()).isNotEmpty(); - } - -} diff --git a/src/test/java/StaticFileServiceTest.java b/src/test/java/StaticFileServiceTest.java deleted file mode 100644 index d5bd7e7d..00000000 --- a/src/test/java/StaticFileServiceTest.java +++ /dev/null @@ -1,21 +0,0 @@ -import http.response.HttpResponse; -import org.junit.jupiter.api.Test; -import service.StaticFileService; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; - -public class StaticFileServiceTest { - @Test - void 정적_파일_서비스_테스트() { - // Given - String filePath = "src/main/resources/templates/index.html"; - String httpVersion = "HTTP/1.1"; - String contentType = "text/html"; - - // When - HttpResponse response = StaticFileService.service(filePath, httpVersion, contentType); - - // Then - assertThat(response.getBody()).isNotEmpty(); - } -} diff --git a/src/test/java/bejavawebserver/WebserverApplicationTests.java b/src/test/java/bejavawebserver/WebserverApplicationTests.java new file mode 100644 index 00000000..402ad991 --- /dev/null +++ b/src/test/java/bejavawebserver/WebserverApplicationTests.java @@ -0,0 +1,13 @@ +package bejavawebserver; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class WebserverApplicationTests { + + @Test + void contextLoads() { + } + +} From b6af4b90e4b0d7ecf8a93fa780afbabbabc418e9 Mon Sep 17 00:00:00 2001 From: jhchoi57 <46276276+jhchoi57@users.noreply.github.com> Date: Fri, 27 Jan 2023 08:33:39 +0900 Subject: [PATCH 5/6] =?UTF-8?q?[=EC=B5=9C=EC=A3=BC=ED=98=95]=2017=EC=9D=BC?= =?UTF-8?q?=EC=B0=A8=20PR=20(#195)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * FEAT : jdbc 구현 및 테스트 * FEAT : 회원가입 기능 db 연동 * FEAT : 로그인 기능 db 연동 * FEAT : list 기능 db 연동 * FEAT : Html controller, htmlservice Autowired 처리 * FEAT : qna 등록 기능 구현 * FEAT : qna 홈페이지 출력 기능 구현 * FEAT : qna에 글쓴 시간 추가 * FEAT : 한줄 게시판이므로 qna title 삭제 * FEAT : 로그인한 사람만 질문 가능 할 수 있게 구현 * FEAT : 로그아웃 구현 * REFORMAT CODE * FEAT : qna 날짜순 정렬 구현 * REFACTOR : 필요없는 것 삭제 * FIX : logback.xml 이름 수정 --- build.gradle | 3 + .../java/bejavawebserver/SpringConfig.java | 24 +++ .../bejavawebserver/WebserverApplication.java | 6 +- .../controller/HomeController.java | 5 +- .../controller/HtmlController.java | 31 ++- .../controller/QnaController.java | 25 +++ .../controller/UserController.java | 34 +++- src/main/java/bejavawebserver/model/Qna.java | 22 ++ .../java/bejavawebserver/model/QnaForm.java | 17 ++ .../repository/JdbcRepository.java | 191 ++++++++++++++++++ ...yRepository.java => MemoryRepository.java} | 4 +- .../bejavawebserver/service/HtmlService.java | 12 +- .../bejavawebserver/service/ListService.java | 14 +- .../bejavawebserver/service/LoginService.java | 22 +- .../service/LogoutService.java | 12 ++ .../bejavawebserver/service/QnaService.java | 24 +++ .../service/SignUpService.java | 12 +- .../{logback.xml => logback-spring.xml} | 0 src/main/resources/templates/index.html | 31 +-- src/main/resources/templates/qna/form.html | 8 +- src/main/resources/templates/qna/show.html | 2 +- src/main/resources/templates/user/form.html | 2 +- src/main/resources/templates/user/list.html | 4 +- src/main/resources/templates/user/login.html | 2 +- .../templates/user/login_failed.html | 2 +- .../resources/templates/user/profile.html | 2 +- .../repository/JdbcRepositoryTest.java | 28 +++ 27 files changed, 456 insertions(+), 83 deletions(-) create mode 100644 src/main/java/bejavawebserver/SpringConfig.java create mode 100644 src/main/java/bejavawebserver/controller/QnaController.java create mode 100644 src/main/java/bejavawebserver/model/Qna.java create mode 100644 src/main/java/bejavawebserver/model/QnaForm.java create mode 100644 src/main/java/bejavawebserver/repository/JdbcRepository.java rename src/main/java/bejavawebserver/repository/{memoryRepository.java => MemoryRepository.java} (93%) create mode 100644 src/main/java/bejavawebserver/service/LogoutService.java create mode 100644 src/main/java/bejavawebserver/service/QnaService.java rename src/main/resources/{logback.xml => logback-spring.xml} (100%) create mode 100644 src/test/java/bejavawebserver/repository/JdbcRepositoryTest.java diff --git a/build.gradle b/build.gradle index b3b525f0..a3dd9d8b 100644 --- a/build.gradle +++ b/build.gradle @@ -24,6 +24,9 @@ dependencies { // mysql implementation group: 'com.mysql', name: 'mysql-connector-j', version: '8.0.32' + + // jdbc + implementation 'org.springframework.boot:spring-boot-starter-jdbc' } tasks.named('test') { diff --git a/src/main/java/bejavawebserver/SpringConfig.java b/src/main/java/bejavawebserver/SpringConfig.java new file mode 100644 index 00000000..f397209d --- /dev/null +++ b/src/main/java/bejavawebserver/SpringConfig.java @@ -0,0 +1,24 @@ +//package bejavawebserver; +// +//import bejavawebserver.repository.JdbcRepository; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Configuration; +// +//import javax.sql.DataSource; +// +// +//@Configuration +//public class SpringConfig { +// private DataSource dataSource; +// +// @Autowired +// public SpringConfig(DataSource dataSource){ +// this.dataSource = dataSource; +// } +// +// @Bean +// public JdbcRepository jdbcRepository(){ +// return new JdbcRepository(dataSource); +// } +//} diff --git a/src/main/java/bejavawebserver/WebserverApplication.java b/src/main/java/bejavawebserver/WebserverApplication.java index e15e927b..794dacbd 100644 --- a/src/main/java/bejavawebserver/WebserverApplication.java +++ b/src/main/java/bejavawebserver/WebserverApplication.java @@ -6,8 +6,8 @@ @SpringBootApplication public class WebserverApplication { - public static void main(String[] args) { - SpringApplication.run(WebserverApplication.class, args); - } + public static void main(String[] args) { + SpringApplication.run(WebserverApplication.class, args); + } } diff --git a/src/main/java/bejavawebserver/controller/HomeController.java b/src/main/java/bejavawebserver/controller/HomeController.java index 285db67f..0b6d6ce3 100644 --- a/src/main/java/bejavawebserver/controller/HomeController.java +++ b/src/main/java/bejavawebserver/controller/HomeController.java @@ -2,12 +2,11 @@ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.SessionAttribute; @Controller public class HomeController { @GetMapping("/") - public String home(){ - return "index"; + public String home() { + return "redirect:/index.html"; } } diff --git a/src/main/java/bejavawebserver/controller/HtmlController.java b/src/main/java/bejavawebserver/controller/HtmlController.java index 471cc3d3..11a9a6ce 100644 --- a/src/main/java/bejavawebserver/controller/HtmlController.java +++ b/src/main/java/bejavawebserver/controller/HtmlController.java @@ -1,23 +1,26 @@ package bejavawebserver.controller; import bejavawebserver.model.User; -import bejavawebserver.repository.memoryRepository; import bejavawebserver.service.HtmlService; import bejavawebserver.service.ListService; import bejavawebserver.service.LoginService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import bejavawebserver.service.QnaService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; @Controller public class HtmlController { - //@GetMapping("/index.html") + @Autowired + HtmlService htmlService; + @Autowired + ListService listService; + @Autowired + QnaService qnaService; @GetMapping(value = { "/index.html", @@ -27,25 +30,31 @@ public class HtmlController { "/user/login.html", "/user/login_failed.html", "/user/profile.html"}) - public String indexHtml(HttpServletRequest httpServletRequest, Model model){ + public String indexHtml(HttpServletRequest httpServletRequest, Model model) { HttpSession session = httpServletRequest.getSession(false); String uri = httpServletRequest.getRequestURI(); + if (uri.equals("/index.html")) qnaService.makeQnaList(model); + // 로그인 상태인 경우 - if(LoginService.isLogin(session)) { - return HtmlService.makeLoginView(model, uri, (User)session.getAttribute("user")); + if (LoginService.isLogin(session)) { + return htmlService.makeLoginView(model, uri, (User) session.getAttribute(session.getId())); } // 로그인 상태가 아닌 경우 - return HtmlService.makeNotLoginView(model, uri); + if (uri.equals("/qna/form.html")) return "redirect:/user/login.html"; + return htmlService.makeNotLoginView(model, uri); } @GetMapping("/user/list.html") - public String listHtml(HttpServletRequest httpServletRequest, Model model){ + public String listHtml(HttpServletRequest httpServletRequest, Model model) { HttpSession session = httpServletRequest.getSession(false); String uri = httpServletRequest.getRequestURI(); // 로그인 상태인 경우 - if(LoginService.isLogin(session)) return ListService.makeUserList(model, uri, (User)session.getAttribute("user")); + if (LoginService.isLogin(session)) { + listService.makeUserList(model); + return htmlService.makeLoginView(model, uri, (User) session.getAttribute("user")); + } // 로그인 상태가 아닌 경우 return "redirect:/user/login.html"; diff --git a/src/main/java/bejavawebserver/controller/QnaController.java b/src/main/java/bejavawebserver/controller/QnaController.java new file mode 100644 index 00000000..7a7af659 --- /dev/null +++ b/src/main/java/bejavawebserver/controller/QnaController.java @@ -0,0 +1,25 @@ +package bejavawebserver.controller; + +import bejavawebserver.model.Qna; +import bejavawebserver.model.QnaForm; +import bejavawebserver.service.QnaService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PostMapping; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +@Controller +public class QnaController { + @Autowired + QnaService qnaService; + + @PostMapping("/qna/form") + public String writeQna(QnaForm qnaForm) { + String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")); + qnaService.addQna(new Qna(qnaForm, time)); + return "redirect:/index.html"; + } + +} diff --git a/src/main/java/bejavawebserver/controller/UserController.java b/src/main/java/bejavawebserver/controller/UserController.java index fc2cfb1c..a0beb714 100644 --- a/src/main/java/bejavawebserver/controller/UserController.java +++ b/src/main/java/bejavawebserver/controller/UserController.java @@ -3,30 +3,52 @@ import bejavawebserver.model.LoginForm; import bejavawebserver.model.User; import bejavawebserver.service.LoginService; +import bejavawebserver.service.LogoutService; import bejavawebserver.service.SignUpService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; +import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; @Controller public class UserController { + private static final Logger logger = LoggerFactory.getLogger(UserController.class); + @Autowired + SignUpService signUpService; + @Autowired + LoginService loginService; + @Autowired + LogoutService logoutService; + @PostMapping("/user/create") - public String signUp(User user){ - try{ - SignUpService.addDatabase(user); - }catch (RuntimeException r){ + public String signUp(User user) { + try { + signUpService.addDatabase(user); + } catch (RuntimeException r) { + logger.debug(r.getMessage()); return "redirect:/user/form.html"; } return "redirect:/"; } @PostMapping("/user/login") - public String login(LoginForm loginForm, HttpSession session){ - if(LoginService.isLoginSuccess(loginForm, session)){ + public String login(LoginForm loginForm, HttpSession session) { + if (loginService.isLoginSuccess(loginForm, session)) { return "redirect:/index.html"; } return "redirect:/user/login_failed.html"; } + @GetMapping("/user/logout") + public String logout(HttpServletRequest httpServletRequest) { + HttpSession session = httpServletRequest.getSession(); + logoutService.removeSession(session); + return "redirect:/"; + } + } diff --git a/src/main/java/bejavawebserver/model/Qna.java b/src/main/java/bejavawebserver/model/Qna.java new file mode 100644 index 00000000..2ee03f3f --- /dev/null +++ b/src/main/java/bejavawebserver/model/Qna.java @@ -0,0 +1,22 @@ +package bejavawebserver.model; + +import lombok.Data; + +@Data +public class Qna { + private String writer; + private String contents; + private String time; + + public Qna(QnaForm qnaForm, String time) { + this.writer = qnaForm.getWriter(); + this.contents = qnaForm.getContents(); + this.time = time; + } + + public Qna(String writer, String contents, String time) { + this.writer = writer; + this.contents = contents; + this.time = time; + } +} diff --git a/src/main/java/bejavawebserver/model/QnaForm.java b/src/main/java/bejavawebserver/model/QnaForm.java new file mode 100644 index 00000000..f3aac0a5 --- /dev/null +++ b/src/main/java/bejavawebserver/model/QnaForm.java @@ -0,0 +1,17 @@ +package bejavawebserver.model; + +import lombok.Data; +import lombok.NonNull; + +@Data +public class QnaForm { + @NonNull + private String writer; + @NonNull + private String contents; + + public QnaForm(@NonNull String writer, @NonNull String contents) { + this.writer = writer; + this.contents = contents; + } +} diff --git a/src/main/java/bejavawebserver/repository/JdbcRepository.java b/src/main/java/bejavawebserver/repository/JdbcRepository.java new file mode 100644 index 00000000..ea850e27 --- /dev/null +++ b/src/main/java/bejavawebserver/repository/JdbcRepository.java @@ -0,0 +1,191 @@ +package bejavawebserver.repository; + +import bejavawebserver.model.Qna; +import bejavawebserver.model.User; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.jdbc.datasource.DataSourceUtils; +import org.springframework.stereotype.Repository; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +@Repository +public class JdbcRepository { + private static final Logger logger = LoggerFactory.getLogger(JdbcRepository.class); + private final DataSource dataSource; + + public JdbcRepository(DataSource dataSource) { + this.dataSource = dataSource; + } + + public boolean checkDuplicate(User user) { + return findUserById(user.getUserId()) != null; + } + + public void addUser(User user) { + String sql = "insert into User values(?, ?, ?, ?)"; + Connection conn = null; + PreparedStatement pstmt = null; + ResultSet rs = null; + + try { + conn = getConnection(); + pstmt = conn.prepareStatement(sql); + pstmt.setString(1, user.getUserId()); + pstmt.setString(2, user.getPassword()); + pstmt.setString(3, user.getName()); + pstmt.setString(4, user.getEmail()); + pstmt.executeUpdate(); + + } catch (Exception e) { + throw new IllegalStateException(e); + } finally { + close(conn, pstmt, rs); + } + } + + public User findUserById(String userId) { + String sql = "select * from User where user_id = ?"; + Connection conn = null; + PreparedStatement pstmt = null; + ResultSet rs = null; + User findUser = null; + try { + conn = getConnection(); + pstmt = conn.prepareStatement(sql); + pstmt.setString(1, userId); + + rs = pstmt.executeQuery(); + while (rs.next()) { + findUser = new User( + rs.getString("user_id"), + rs.getString("password"), + rs.getString("name"), + rs.getString("email") + ); + } + return findUser; + + } catch (Exception e) { + logger.debug("error : {}", e.getMessage()); + return null; + } finally { + close(conn, pstmt, rs); + } + } + + public List findUserAll() { + String sql = "select * from User"; + Connection conn = null; + PreparedStatement pstmt = null; + ResultSet rs = null; + + try { + conn = getConnection(); + pstmt = conn.prepareStatement(sql); + + rs = pstmt.executeQuery(); + + List userList = new ArrayList<>(); + while (rs.next()) { + User user = new User( + rs.getString("user_id"), + rs.getString("password"), + rs.getString("name"), + rs.getString("email") + ); + userList.add(user); + } + return userList; + + } catch (Exception e) { + logger.debug("error : {}", e.getMessage()); + + return null; + } finally { + close(conn, pstmt, rs); + } + } + + public List findQnaAll() { + String sql = "select * from qna order by time desc"; + Connection conn = null; + PreparedStatement pstmt = null; + ResultSet rs = null; + + try { + conn = getConnection(); + pstmt = conn.prepareStatement(sql); + + rs = pstmt.executeQuery(); + + List qnaList = new ArrayList<>(); + while (rs.next()) { + Qna qna = new Qna( + rs.getString("writer"), + rs.getString("contents"), + rs.getString("time") + ); + qnaList.add(qna); + } + return qnaList; + + } catch (Exception e) { + logger.debug("error : {}", e.getMessage()); + + return null; + } finally { + close(conn, pstmt, rs); + } + } + + public void addQna(Qna qna) { + String sql = "insert into qna values(?, ?, ?)"; + Connection conn = null; + PreparedStatement pstmt = null; + ResultSet rs = null; + + try { + conn = getConnection(); + pstmt = conn.prepareStatement(sql); + pstmt.setString(1, qna.getWriter()); + pstmt.setString(2, qna.getContents()); + pstmt.setString(3, qna.getTime()); + pstmt.executeUpdate(); + + } catch (Exception e) { + throw new IllegalStateException(e); + } finally { + close(conn, pstmt, rs); + } + } + + private Connection getConnection() { + return DataSourceUtils.getConnection(dataSource); + } + + private void close(Connection conn, PreparedStatement pstmt, ResultSet rs) { + // 역순으로 닫아주어야 한다 + try { + if (pstmt != null) { + pstmt.close(); + } + if (conn != null) { + conn.close(); + } + if (rs != null) { + rs.close(); + } + } catch (SQLException e) { + e.printStackTrace(); + } + } + + +} diff --git a/src/main/java/bejavawebserver/repository/memoryRepository.java b/src/main/java/bejavawebserver/repository/MemoryRepository.java similarity index 93% rename from src/main/java/bejavawebserver/repository/memoryRepository.java rename to src/main/java/bejavawebserver/repository/MemoryRepository.java index 565cfa78..c3884b9d 100644 --- a/src/main/java/bejavawebserver/repository/memoryRepository.java +++ b/src/main/java/bejavawebserver/repository/MemoryRepository.java @@ -8,8 +8,8 @@ import java.util.HashMap; import java.util.Map; -public class memoryRepository { - private static final Logger logger = LoggerFactory.getLogger(memoryRepository.class); +public class MemoryRepository { + private static final Logger logger = LoggerFactory.getLogger(MemoryRepository.class); private static final Map users = new HashMap<>(); public static void addUser(User user) { diff --git a/src/main/java/bejavawebserver/service/HtmlService.java b/src/main/java/bejavawebserver/service/HtmlService.java index 69c94d3b..3577723b 100644 --- a/src/main/java/bejavawebserver/service/HtmlService.java +++ b/src/main/java/bejavawebserver/service/HtmlService.java @@ -2,24 +2,22 @@ import bejavawebserver.controller.HtmlController; import bejavawebserver.model.User; -import org.springframework.stereotype.Service; -import org.springframework.ui.Model; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -import javax.servlet.http.HttpSession; +import org.springframework.stereotype.Service; +import org.springframework.ui.Model; @Service public class HtmlService { private static final Logger logger = LoggerFactory.getLogger(HtmlController.class); - public static String makeNotLoginView(Model model, String uri){ + + public String makeNotLoginView(Model model, String uri) { logger.debug("현재 로그인 상태 아님"); model.addAttribute("isLogin", false); return uri; } - - public static String makeLoginView(Model model, String uri, User loginUser) { + public String makeLoginView(Model model, String uri, User loginUser) { logger.debug("현재 로그인 상태임"); model.addAttribute("userName", loginUser.getName()); model.addAttribute("isLogin", true); diff --git a/src/main/java/bejavawebserver/service/ListService.java b/src/main/java/bejavawebserver/service/ListService.java index eed17d5a..e9f4ce63 100644 --- a/src/main/java/bejavawebserver/service/ListService.java +++ b/src/main/java/bejavawebserver/service/ListService.java @@ -1,20 +1,20 @@ package bejavawebserver.service; import bejavawebserver.model.User; -import bejavawebserver.repository.memoryRepository; +import bejavawebserver.repository.JdbcRepository; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.ui.Model; -import javax.servlet.http.HttpSession; -import java.util.ArrayList; -import java.util.Collection; import java.util.List; @Service public class ListService { - public static String makeUserList(Model model, String uri, User loginUser){ - List userList = new ArrayList<>(memoryRepository.findAll()); + @Autowired + JdbcRepository jdbcRepository; + + public void makeUserList(Model model) { + List userList = jdbcRepository.findUserAll(); model.addAttribute("userList", userList); - return HtmlService.makeLoginView(model, uri, loginUser); } } diff --git a/src/main/java/bejavawebserver/service/LoginService.java b/src/main/java/bejavawebserver/service/LoginService.java index 2e7a9b69..6a584994 100644 --- a/src/main/java/bejavawebserver/service/LoginService.java +++ b/src/main/java/bejavawebserver/service/LoginService.java @@ -2,20 +2,28 @@ import bejavawebserver.model.LoginForm; import bejavawebserver.model.User; -import bejavawebserver.repository.memoryRepository; +import bejavawebserver.repository.JdbcRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; import javax.servlet.http.HttpSession; import java.util.Objects; +@Service public class LoginService { - public static boolean isLoginSuccess(LoginForm loginForm, HttpSession session) { - User user = memoryRepository.findUserById(loginForm.getUserId()); - session.setAttribute("user", user); - return Objects.equals(user.getPassword(), loginForm.getPassword()); - } + @Autowired + JdbcRepository jdbcRepository; public static boolean isLogin(HttpSession session) { - return session != null; + if (session == null) return false; + return session.getAttribute(session.getId()) != null; + } + + public boolean isLoginSuccess(LoginForm loginForm, HttpSession session) { + User user = jdbcRepository.findUserById(loginForm.getUserId()); + boolean isSuccess = Objects.equals(user.getPassword(), loginForm.getPassword()); + if (isSuccess) session.setAttribute(session.getId(), user); + return isSuccess; } diff --git a/src/main/java/bejavawebserver/service/LogoutService.java b/src/main/java/bejavawebserver/service/LogoutService.java new file mode 100644 index 00000000..eefb9508 --- /dev/null +++ b/src/main/java/bejavawebserver/service/LogoutService.java @@ -0,0 +1,12 @@ +package bejavawebserver.service; + +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpSession; + +@Service +public class LogoutService { + public void removeSession(HttpSession session) { + session.removeAttribute(session.getId()); + } +} diff --git a/src/main/java/bejavawebserver/service/QnaService.java b/src/main/java/bejavawebserver/service/QnaService.java new file mode 100644 index 00000000..c07f1d3c --- /dev/null +++ b/src/main/java/bejavawebserver/service/QnaService.java @@ -0,0 +1,24 @@ +package bejavawebserver.service; + +import bejavawebserver.model.Qna; +import bejavawebserver.repository.JdbcRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.ui.Model; + +import java.util.List; + +@Service +public class QnaService { + @Autowired + JdbcRepository jdbcRepository; + + public void addQna(Qna qna) { + jdbcRepository.addQna(qna); + } + + public void makeQnaList(Model model) { + List qnaList = jdbcRepository.findQnaAll(); + model.addAttribute("qnaList", qnaList); + } +} diff --git a/src/main/java/bejavawebserver/service/SignUpService.java b/src/main/java/bejavawebserver/service/SignUpService.java index fa60818c..ecee3511 100644 --- a/src/main/java/bejavawebserver/service/SignUpService.java +++ b/src/main/java/bejavawebserver/service/SignUpService.java @@ -1,13 +1,17 @@ package bejavawebserver.service; -import bejavawebserver.repository.memoryRepository; import bejavawebserver.model.User; +import bejavawebserver.repository.JdbcRepository; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class SignUpService { - public static void addDatabase(User user) { - if(memoryRepository.checkDuplicate(user)) throw new RuntimeException("중복된 사용자가 있습니다."); - memoryRepository.addUser(user); + @Autowired + JdbcRepository jdbcRepository; + + public void addDatabase(User user) { + if (jdbcRepository.checkDuplicate(user)) throw new RuntimeException("중복된 사용자가 있습니다."); + jdbcRepository.addUser(user); } } diff --git a/src/main/resources/logback.xml b/src/main/resources/logback-spring.xml similarity index 100% rename from src/main/resources/logback.xml rename to src/main/resources/logback-spring.xml diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index 1615d17c..69c149d4 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -77,7 +77,7 @@
  • 로그인
  • 회원가입
  • --> -
  • 로그아웃
  • +
  • 로그아웃
  • 개인정보수정
  • @@ -88,38 +88,21 @@
    @@ -82,19 +82,23 @@
    -
    +
    + +
    +
    diff --git a/src/main/resources/templates/qna/show.html b/src/main/resources/templates/qna/show.html index a045d94d..2c7a5329 100644 --- a/src/main/resources/templates/qna/show.html +++ b/src/main/resources/templates/qna/show.html @@ -72,7 +72,7 @@
  • 로그인
  • 회원가입
  • -
  • 로그아웃
  • +
  • 로그아웃
  • 개인정보수정
  • diff --git a/src/main/resources/templates/user/form.html b/src/main/resources/templates/user/form.html index bf3b0c97..0244618d 100644 --- a/src/main/resources/templates/user/form.html +++ b/src/main/resources/templates/user/form.html @@ -71,7 +71,7 @@
  • 로그인
  • 회원가입
  • -
  • 로그아웃
  • +
  • 로그아웃
  • 개인정보수정
  • diff --git a/src/main/resources/templates/user/list.html b/src/main/resources/templates/user/list.html index bfd689bb..e6a0536a 100644 --- a/src/main/resources/templates/user/list.html +++ b/src/main/resources/templates/user/list.html @@ -72,7 +72,7 @@
  • 로그인
  • 회원가입
  • -
  • 로그아웃
  • +
  • 로그아웃
  • 개인정보수정
  • @@ -98,7 +98,7 @@ - 수정 + 수정 diff --git a/src/main/resources/templates/user/login.html b/src/main/resources/templates/user/login.html index 98b95047..5cb8a852 100644 --- a/src/main/resources/templates/user/login.html +++ b/src/main/resources/templates/user/login.html @@ -72,7 +72,7 @@
  • 로그인
  • 회원가입
  • -
  • 로그아웃
  • +
  • 로그아웃
  • 개인정보수정
  • diff --git a/src/main/resources/templates/user/login_failed.html b/src/main/resources/templates/user/login_failed.html index 488abb41..ea79c6e2 100644 --- a/src/main/resources/templates/user/login_failed.html +++ b/src/main/resources/templates/user/login_failed.html @@ -72,7 +72,7 @@
  • 로그인
  • 회원가입
  • -
  • 로그아웃
  • +
  • 로그아웃
  • 개인정보수정
  • diff --git a/src/main/resources/templates/user/profile.html b/src/main/resources/templates/user/profile.html index ef024bd6..ffa84b2e 100644 --- a/src/main/resources/templates/user/profile.html +++ b/src/main/resources/templates/user/profile.html @@ -72,7 +72,7 @@
  • 로그인
  • 회원가입
  • -
  • 로그아웃
  • +
  • 로그아웃
  • 개인정보수정
  • diff --git a/src/test/java/bejavawebserver/repository/JdbcRepositoryTest.java b/src/test/java/bejavawebserver/repository/JdbcRepositoryTest.java new file mode 100644 index 00000000..ffed4a42 --- /dev/null +++ b/src/test/java/bejavawebserver/repository/JdbcRepositoryTest.java @@ -0,0 +1,28 @@ +package bejavawebserver.repository; + +import bejavawebserver.model.User; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import javax.sql.DataSource; +import java.sql.SQLException; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +class JdbcRepositoryTest { + @Autowired JdbcRepository jdbcRepository; + @Test + @DisplayName("데이터베이스에 유저 추가 테스트") + void addUser() throws SQLException { + // given + User user = new User("testid", "testpassword", "주형", "test@gmail.com"); + // when + jdbcRepository.addUser(user); + // then + assertThat(jdbcRepository.findUserById(user.getUserId())).usingRecursiveComparison().isEqualTo(user); + } +} \ No newline at end of file From b1c4bb67d8289256a1c4aa41e92322b526efd3e2 Mon Sep 17 00:00:00 2001 From: jhchoi57 Date: Fri, 27 Jan 2023 11:35:34 +0900 Subject: [PATCH 6/6] =?UTF-8?q?FIX=20:=20sessionid=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/bejavawebserver/service/LoginService.java | 4 ++-- src/main/java/bejavawebserver/service/LogoutService.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/bejavawebserver/service/LoginService.java b/src/main/java/bejavawebserver/service/LoginService.java index 6a584994..3029c51c 100644 --- a/src/main/java/bejavawebserver/service/LoginService.java +++ b/src/main/java/bejavawebserver/service/LoginService.java @@ -16,13 +16,13 @@ public class LoginService { public static boolean isLogin(HttpSession session) { if (session == null) return false; - return session.getAttribute(session.getId()) != null; + return session.getAttribute("user") != null; } public boolean isLoginSuccess(LoginForm loginForm, HttpSession session) { User user = jdbcRepository.findUserById(loginForm.getUserId()); boolean isSuccess = Objects.equals(user.getPassword(), loginForm.getPassword()); - if (isSuccess) session.setAttribute(session.getId(), user); + if (isSuccess) session.setAttribute("user", user); return isSuccess; } diff --git a/src/main/java/bejavawebserver/service/LogoutService.java b/src/main/java/bejavawebserver/service/LogoutService.java index eefb9508..313764c0 100644 --- a/src/main/java/bejavawebserver/service/LogoutService.java +++ b/src/main/java/bejavawebserver/service/LogoutService.java @@ -7,6 +7,6 @@ @Service public class LogoutService { public void removeSession(HttpSession session) { - session.removeAttribute(session.getId()); + session.removeAttribute("user"); } }