diff --git a/README.md b/README.md
index 3f7ef2e..4d234ad 100644
--- a/README.md
+++ b/README.md
@@ -52,7 +52,9 @@
### 요구사항 7
- 지금까지 구현한 소스 코드는 stylesheet 파일을 지원하지 못하고 있다. Stylesheet 파일을 지원하도록 구현하도록 한다.
+## 2단계 - 리팩토링
-
-
-
+- 리팩토링 접근 방법 - 메소드 분리 및 클래스 분리
+- 클라이언트 요청 데이터를 처리하는 로직을 별도의 클래스로 분리한다.(HttpRequest)
+- 클라이언트 응답 데이터를 처리하는 로직을 별도의 클래스로 분리한다.(HttpResponse)
+- 다형성을 활용해 클라이언트 요청 URL에 대한 분기 처리를 제거한다.
diff --git a/build.gradle b/build.gradle
index 039b2bc..3c7e5e8 100644
--- a/build.gradle
+++ b/build.gradle
@@ -16,11 +16,11 @@ dependencies {
implementation 'org.apache.commons:commons-dbcp2:2.5.0'
implementation 'org.reflections:reflections:0.9.11'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'
- testImplementation 'org.assertj:assertj-core:3.11.1'
+ testImplementation 'org.assertj:assertj-core:3.18.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
runtimeOnly 'com.h2database:h2:1.4.200'
}
test {
useJUnitPlatform()
-}
\ No newline at end of file
+}
diff --git a/src/main/java/controller/BaseController.java b/src/main/java/controller/BaseController.java
new file mode 100644
index 0000000..5a6a160
--- /dev/null
+++ b/src/main/java/controller/BaseController.java
@@ -0,0 +1,27 @@
+package controller;
+
+import http.HttpMethod;
+import http.HttpRequest;
+import http.HttpResponse;
+
+public class BaseController implements Controller {
+
+ @Override
+ public void service(HttpRequest request, HttpResponse response) {
+ HttpMethod method = request.getMethod();
+
+ if (method.isPost()) {
+ doPost(request, response);
+ } else {
+ doGet(request, response);
+ }
+ }
+
+ public void doPost(HttpRequest request, HttpResponse response) {
+
+ }
+
+ public void doGet(HttpRequest request, HttpResponse response) {
+
+ }
+}
diff --git a/src/main/java/controller/Controller.java b/src/main/java/controller/Controller.java
new file mode 100644
index 0000000..3d23ddc
--- /dev/null
+++ b/src/main/java/controller/Controller.java
@@ -0,0 +1,8 @@
+package controller;
+
+import http.HttpRequest;
+import http.HttpResponse;
+
+public interface Controller {
+ void service(HttpRequest request, HttpResponse response);
+}
diff --git a/src/main/java/controller/CreateUserController.java b/src/main/java/controller/CreateUserController.java
new file mode 100644
index 0000000..906d282
--- /dev/null
+++ b/src/main/java/controller/CreateUserController.java
@@ -0,0 +1,28 @@
+package controller;
+
+import db.DataBase;
+import model.User;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import http.HttpRequest;
+import http.HttpResponse;
+
+public class CreateUserController extends BaseController {
+ private static final Logger log = LoggerFactory.getLogger(CreateUserController.class);
+
+ @Override
+ public void doPost(HttpRequest request, HttpResponse response) {
+ User user = getUserFrom(request);
+ DataBase.addUser(user);
+ response.sendRedirect("/index.html");
+ log.debug("{}님이 회원가입에 성공하셨습니다.", user.getUserId());
+ }
+
+ private User getUserFrom(HttpRequest request) {
+ String userId = request.getParameter("userId");
+ String password = request.getParameter("password");
+ String name = request.getParameter("name");
+ String email = request.getParameter("email");
+ return new User(userId, password, name, email);
+ }
+}
diff --git a/src/main/java/controller/ListUserController.java b/src/main/java/controller/ListUserController.java
new file mode 100644
index 0000000..2b2fad3
--- /dev/null
+++ b/src/main/java/controller/ListUserController.java
@@ -0,0 +1,74 @@
+package controller;
+
+import db.DataBase;
+import db.SessionDataBase;
+import model.User;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import util.HttpRequestUtils;
+import http.HttpRequest;
+import http.HttpResponse;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.Collection;
+import java.util.Map;
+
+public class ListUserController extends BaseController {
+ private static final Logger log = LoggerFactory.getLogger(ListUserController.class);
+
+ @Override
+ public void doGet(HttpRequest request, HttpResponse response) {
+ String sessionId = request.getHeader("Cookie");
+ if (!isLogin(sessionId)) {
+ response.sendRedirect("/user/login.html");
+ } else {
+ String body = getBody("/user/list.html");
+ int tbodyIndex = body.indexOf("
");
+ String result = addUserList(body, tbodyIndex).toString();
+ response.forwardBody(result);
+ }
+ }
+
+ private boolean isLogin(String id) {
+ Map cookieStringMap = HttpRequestUtils.parseCookies(id);
+ log.info("Cookie: {}", cookieStringMap.toString());
+ return SessionDataBase.isLoginUser(cookieStringMap.get("JSESSIONID"));
+ }
+
+ private String getBody(String url) {
+ byte[] body = new byte[0];
+ try {
+ body = Files.readAllBytes(new File("./webapp" + url).toPath());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return new String(body);
+ }
+
+ private StringBuilder processUserList(String body, int tbodyIndex) {
+ StringBuilder result = new StringBuilder(body.substring(0, tbodyIndex + 7));
+ Collection users = DataBase.findAll();
+ int id = 0;
+ for (User user : users) {
+ id++;
+ result.append("| ")
+ .append(id)
+ .append(" | ")
+ .append(user.getUserId())
+ .append(" | ")
+ .append(user.getName())
+ .append(" | ")
+ .append(user.getEmail())
+ .append(" | ")
+ .append("수정 | ");
+ }
+ return result;
+ }
+
+ private StringBuilder addUserList(String body, int tbodyIndex) {
+ StringBuilder result = processUserList(body, tbodyIndex);
+ return result.append(body.substring(tbodyIndex + 7));
+ }
+}
diff --git a/src/main/java/controller/LoginController.java b/src/main/java/controller/LoginController.java
new file mode 100644
index 0000000..5f865d6
--- /dev/null
+++ b/src/main/java/controller/LoginController.java
@@ -0,0 +1,32 @@
+package controller;
+
+import db.DataBase;
+import db.SessionDataBase;
+import model.User;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import http.HttpRequest;
+import http.HttpResponse;
+
+import java.util.UUID;
+
+public class LoginController extends BaseController {
+ private static final Logger log = LoggerFactory.getLogger(LoginController.class);
+
+ @Override
+ public void doPost(HttpRequest request, HttpResponse response) {
+ String userId = request.getParameter("userId");
+ String password = request.getParameter("password");
+ User targetUser = DataBase.findUserById(userId);
+ if (targetUser == null || !targetUser.isValidPassword(password)) {
+ response.addHeader("Set-Cookie", "loggedIn=false");
+ response.sendRedirect("/user/login_failed.html");
+ return;
+ }
+ UUID uuid = UUID.randomUUID();
+ SessionDataBase.sessions.put(uuid.toString(), targetUser);
+ response.addHeader("Set-Cookie", SessionDataBase.JSESSIONID + "=" + uuid);
+ response.sendRedirect("/index.html");
+ log.info("{}님이 로그인하셨습니다.", userId);
+ }
+}
diff --git a/src/main/java/db/SessionDataBase.java b/src/main/java/db/SessionDataBase.java
new file mode 100644
index 0000000..3311983
--- /dev/null
+++ b/src/main/java/db/SessionDataBase.java
@@ -0,0 +1,20 @@
+package db;
+
+import com.google.common.collect.Maps;
+import model.User;
+
+import java.util.Map;
+
+public class SessionDataBase {
+ public static Map sessions = Maps.newHashMap();
+
+ public static final String JSESSIONID = "JSESSIONID";
+
+ public static boolean isLoginUser(String sessionId) {
+ return getSessionUser(sessionId) != null;
+ }
+
+ public static User getSessionUser(String sessionId) {
+ return sessions.get(sessionId);
+ }
+}
diff --git a/src/main/java/http/HttpMethod.java b/src/main/java/http/HttpMethod.java
new file mode 100644
index 0000000..d344cc1
--- /dev/null
+++ b/src/main/java/http/HttpMethod.java
@@ -0,0 +1,9 @@
+package http;
+
+public enum HttpMethod {
+ GET, POST;
+
+ public boolean isPost() {
+ return this == POST;
+ }
+}
diff --git a/src/main/java/http/HttpRequest.java b/src/main/java/http/HttpRequest.java
new file mode 100644
index 0000000..0ecb9f5
--- /dev/null
+++ b/src/main/java/http/HttpRequest.java
@@ -0,0 +1,85 @@
+package http;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import util.HttpRequestUtils;
+import util.IOUtils;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+public class HttpRequest {
+ private static final Logger log = LoggerFactory.getLogger(HttpRequest.class);
+
+ private String requestLine;
+ private final Map headers = new HashMap<>();
+ private Map parameters;
+
+ public HttpRequest(InputStream in) {
+ try {
+ BufferedReader br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
+ requestLine = br.readLine();
+ processHeaders(br);
+ processParameters(br);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void processHeaders(BufferedReader br) throws IOException {
+ String line = br.readLine();
+ while (!line.isEmpty()) {
+ log.debug("headers : {}", line);
+ line = br.readLine();
+ if (line == null) {
+ return;
+ }
+ parseHeader(line);
+ }
+ }
+
+ private void parseHeader(String line) {
+ String[] headerTokens = line.split(": ");
+ if (headerTokens.length == 2) {
+ headers.put(headerTokens[0], headerTokens[1]);
+ }
+ }
+
+ private void processParameters(BufferedReader br) throws IOException {
+ String[] tokens = requestLine.split(" ");
+ String queryString = "";
+ String requestBody = "";
+ if (tokens[1].contains("?")) {
+ queryString = tokens[1].substring(tokens[1].indexOf("?") + 1);
+ }
+ if (headers.get("Content-Length") != null) {
+ requestBody = IOUtils.readData(br, Integer.parseInt(headers.get("Content-Length")));
+ }
+ queryString = queryString + "&" + requestBody;
+ parameters = HttpRequestUtils.parseQueryString(queryString);
+ }
+
+ public HttpMethod getMethod() {
+ String[] tokens = requestLine.split(" ");
+ String method = tokens[0];
+ return HttpMethod.valueOf(method);
+ }
+
+ public String getPath() {
+ String[] tokens = requestLine.split(" ");
+ if (tokens[1].contains("?")) {
+ return tokens[1].substring(0, tokens[1].indexOf("?"));
+ }
+ return tokens[1];
+ }
+
+ public String getHeader(String fieldName) {
+ return headers.get(fieldName);
+ }
+
+ public String getParameter(String fieldName) {
+ return parameters.get(fieldName);
+ }
+}
diff --git a/src/main/java/webserver/HttpResponse.java b/src/main/java/http/HttpResponse.java
similarity index 65%
rename from src/main/java/webserver/HttpResponse.java
rename to src/main/java/http/HttpResponse.java
index fa2c929..b1b9e3a 100644
--- a/src/main/java/webserver/HttpResponse.java
+++ b/src/main/java/http/HttpResponse.java
@@ -1,18 +1,27 @@
-package webserver;
+package http;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.DataOutputStream;
import java.io.*;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
public class HttpResponse {
private static final Logger log = LoggerFactory.getLogger(HttpResponse.class);
- private Map headers = new HashMap<>();
- private DataOutputStream dos;
+
+ private static final Map EXTENSIONS = new HashMap<>();
+ private final Map headers = new HashMap<>();
+ private final DataOutputStream dos;
+
+ static {
+ EXTENSIONS.put(".css", "text/css");
+ EXTENSIONS.put(".js", "application/javascript");
+ EXTENSIONS.put(".html", "text/html");
+ }
public HttpResponse(OutputStream out) {
this.dos = new DataOutputStream(out);
@@ -24,33 +33,21 @@ public void addHeader(String fieldName, String fieldValue) {
public void forward(String url) throws IOException {
byte[] body = Files.readAllBytes(new File("./webapp" + url).toPath());
- if (url.endsWith(".css")) {
- response200HeaderWithCss(body.length);
- } else {
- response200Header(body.length);
- }
+ String extension = url.substring(url.lastIndexOf("."));
+ response200Header(body.length, EXTENSIONS.get(extension));
responseBody(body);
}
- public void forwardBody(String string) {
-
- }
-
- public void response200HeaderWithCss(int lengthOfBodyContent) {
- try {
- dos.writeBytes("HTTP/1.1 200 OK \r\n");
- dos.writeBytes("Content-Type: text/css;charset=utf-8\r\n");
- dos.writeBytes("Content-Length: " + lengthOfBodyContent + "\r\n");
- dos.writeBytes("\r\n");
- } catch (IOException e) {
- log.error(e.getMessage());
- }
+ public void forwardBody(String result) {
+ byte[] body = result.getBytes(StandardCharsets.UTF_8);
+ response200Header(body.length, "text/html");
+ responseBody(body);
}
- public void response200Header(int lengthOfBodyContent) {
+ public void response200Header(int lengthOfBodyContent, String contentType) {
try {
dos.writeBytes("HTTP/1.1 200 OK \r\n");
- dos.writeBytes("Content-Type: text/html;charset=utf-8\r\n");
+ dos.writeBytes("Content-Type:" + contentType + ";charset=utf-8\r\n");
dos.writeBytes("Content-Length: " + lengthOfBodyContent + "\r\n");
dos.writeBytes("\r\n");
} catch (IOException e) {
@@ -73,7 +70,7 @@ public void sendRedirect(String url) {
processHeaders();
dos.writeBytes("Location: " + url + "\r\n");
} catch (IOException e) {
-
+ e.printStackTrace();
}
}
diff --git a/src/main/java/model/User.java b/src/main/java/model/User.java
index b7abb73..b3a3127 100644
--- a/src/main/java/model/User.java
+++ b/src/main/java/model/User.java
@@ -13,6 +13,10 @@ public User(String userId, String password, String name, String email) {
this.email = email;
}
+ public boolean isValidPassword(String password) {
+ return this.password.equals(password);
+ }
+
public String getUserId() {
return userId;
}
diff --git a/src/main/java/util/HttpRequestUtils.java b/src/main/java/util/HttpRequestUtils.java
index 6386da6..a679d7e 100644
--- a/src/main/java/util/HttpRequestUtils.java
+++ b/src/main/java/util/HttpRequestUtils.java
@@ -3,6 +3,7 @@
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.Map;
+import java.util.Objects;
import java.util.stream.Collectors;
import com.google.common.base.Strings;
@@ -10,8 +11,8 @@
public class HttpRequestUtils {
/**
- * @param queryString은
- * URL에서 ? 이후에 전달되는 field1=value1&field2=value2 형식임
+ * @param queryString
+ * 은 URL에서 ? 이후에 전달되는 field1=value1&field2=value2 형식임
* @return
*/
public static Map parseQueryString(String queryString) {
@@ -19,7 +20,7 @@ public static Map parseQueryString(String queryString) {
}
/**
- * @param 쿠키
+ * @param cookies
* 값은 name1=value1; name2=value2 형식임
* @return
*/
@@ -32,14 +33,14 @@ private static Map parseValues(String values, String separator)
return Maps.newHashMap();
}
String[] tokens = values.split(separator);
- return Arrays.stream(tokens).map(t -> getKeyValue(t, "=")).filter(p -> p != null)
- .collect(Collectors.toMap(p -> p.getKey(), p -> {
+ return Arrays.stream(tokens).map(t -> getKeyValue(t, "=")).filter(Objects::nonNull)
+ .collect(Collectors.toMap(Pair::getKey, p -> {
try {
return URLDecoder.decode(p.getValue(), "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
- return null;
+ return p.getValue();
}));
}
diff --git a/src/main/java/util/IOUtils.java b/src/main/java/util/IOUtils.java
index d88efe7..56186c6 100644
--- a/src/main/java/util/IOUtils.java
+++ b/src/main/java/util/IOUtils.java
@@ -3,18 +3,18 @@
import java.io.BufferedReader;
import java.io.IOException;
-public class IOUtils {
+public class IOUtils {
/**
- * @param BufferedReader는
+ * @param bufferedReader
* Request Body를 시작하는 시점이어야
- * @param contentLength는
+ * @param contentLength
* Request Header의 Content-Length 값이다.
* @return
* @throws IOException
*/
- public static String readData(BufferedReader br, int contentLength) throws IOException {
+ public static String readData(BufferedReader bufferedReader, int contentLength) throws IOException {
char[] body = new char[contentLength];
- br.read(body, 0, contentLength);
+ bufferedReader.read(body, 0, contentLength);
return String.copyValueOf(body);
}
}
diff --git a/src/main/java/webserver/HttpMethod.java b/src/main/java/webserver/HttpMethod.java
deleted file mode 100644
index 3db4524..0000000
--- a/src/main/java/webserver/HttpMethod.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package webserver;
-
-public enum HttpMethod {
- GET, POST;
-}
diff --git a/src/main/java/webserver/HttpRequest.java b/src/main/java/webserver/HttpRequest.java
deleted file mode 100644
index 9be415f..0000000
--- a/src/main/java/webserver/HttpRequest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package webserver;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import util.HttpRequestUtils;
-import util.IOUtils;
-
-import java.io.BufferedReader;
-import java.util.Map;
-
-public class HttpRequest {
- private static final Logger log = LoggerFactory.getLogger(HttpRequest.class);
-
- private String startLine;
- private Map headers;
-
- public HttpRequest(String startLine, Map headers) {
- this.startLine = startLine;
- this.headers = headers;
- }
-
- public HttpMethod getMethod() {
- String[] tokens = startLine.split(" ");
- String method = tokens[0];
- return HttpMethod.valueOf(method);
- }
-
- public String getPath() {
- String[] tokens = startLine.split(" ");
- return tokens[1];
- }
-
- public String getHeader(String fieldName) {
- return headers.get(fieldName);
- }
-
- public String getParameter(String fieldName, BufferedReader br) throws Exception {
- String RequestBody = IOUtils.readData(br, Integer.parseInt(headers.get("Content-Length")));
- Map parameters = HttpRequestUtils.parseQueryString(RequestBody);
- log.info("parameters : {}", parameters.toString());
- return parameters.get(fieldName);
- }
-}
diff --git a/src/main/java/webserver/RequestHandler.java b/src/main/java/webserver/RequestHandler.java
index 75f3e21..ec69f02 100644
--- a/src/main/java/webserver/RequestHandler.java
+++ b/src/main/java/webserver/RequestHandler.java
@@ -2,20 +2,29 @@
import java.io.*;
import java.net.Socket;
-import java.nio.file.Files;
-import java.util.*;
-
-import db.DataBase;
-import model.User;
+import java.util.HashMap;
+import java.util.Map;
+
+import controller.Controller;
+import controller.CreateUserController;
+import controller.ListUserController;
+import controller.LoginController;
+import http.HttpRequest;
+import http.HttpResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import util.HttpRequestUtils;
-import util.IOUtils;
public class RequestHandler extends Thread {
private static final Logger log = LoggerFactory.getLogger(RequestHandler.class);
- private Socket connection;
+ private static final Map CONTROLLER_MAP = new HashMap<>();
+ private final Socket connection;
+
+ static {
+ CONTROLLER_MAP.put("/create", new CreateUserController());
+ CONTROLLER_MAP.put("/login", new LoginController());
+ CONTROLLER_MAP.put("/list", new ListUserController());
+ }
public RequestHandler(Socket connectionSocket) {
this.connection = connectionSocket;
@@ -26,91 +35,19 @@ public void run() {
connection.getPort());
try (InputStream in = connection.getInputStream(); OutputStream out = connection.getOutputStream()) {
- // TODO 사용자 요청에 대한 처리는 이 곳에 구현하면 된다.
- BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8"));
-
- String requestLine = br.readLine();
- String line = requestLine;
- Map headers = new HashMap<>();
- while (!"".equals(line)) {
- System.out.println(line);
- line = br.readLine();
- String[] headerTokens = line.split(": ");
- if (headerTokens.length == 2) {
- headers.put(headerTokens[0], headerTokens[1]);
- }
- }
-
- HttpRequest httpRequest = new HttpRequest(requestLine, headers);
+ HttpRequest httpRequest = new HttpRequest(in);
HttpResponse httpResponse = new HttpResponse(out);
- HttpMethod method = httpRequest.getMethod();
- log.info("Http Method: {}", method.name());
String url = httpRequest.getPath();
- log.info("path : {}", url);
- DataOutputStream dos = new DataOutputStream(out);
-
- if (url.startsWith("/create")) {
- String RequestBody = IOUtils.readData(br, Integer.parseInt(headers.get("Content-Length")));
- Map parameters = HttpRequestUtils.parseQueryString(RequestBody);
- log.info("user : {}", parameters.toString());
- DataBase.addUser(new User(parameters.get("userId"), parameters.get("password"), parameters.get("name"), parameters.get("email")));
- httpResponse.sendRedirect("/index.html");
- } else if (url.startsWith("/login")) {
- String contentLength = headers.get("Content-Length");
- log.info("contentLength : {}", contentLength);
- String RequestBody = IOUtils.readData(br, Integer.parseInt(headers.get("Content-Length")));
-
- Map info = HttpRequestUtils.parseQueryString(RequestBody);
- String userId = info.get("userId");
- String password = info.get("password");
- User targetUser = DataBase.findUserById(userId);
- log.info("userId : {}", userId);
- log.info("password : {}", password);
- if (targetUser == null || !password.equals(targetUser.getPassword())) {
- httpResponse.addHeader("Set-Cookie", "logined=false");
- httpResponse.sendRedirect("/user/login_failed.html");
- } else if (password.equals(targetUser.getPassword())) {
- log.info("로그인 성공");
- httpResponse.addHeader("Set-Cookie", "logined=true");
- httpResponse.sendRedirect("/index.html");
- }
- } else if (url.startsWith("/list")) {
- String cookies = headers.get("Cookie");
- Map cookieStringMap = HttpRequestUtils.parseCookies(cookies);
- log.info("Cookie: {}", cookieStringMap.toString());
- if (cookieStringMap.get("logined").equals("false")) {
- httpResponse.sendRedirect("/user/login.html");
- } else {
- url = "/user/list.html";
- byte[] body = Files.readAllBytes(new File("./webapp" + url).toPath());
- String bodyStr = new String(body);
- int tbodyIndex = bodyStr.indexOf("");
- log.info("bodyStr : {}", bodyStr.substring(0, tbodyIndex + 7));
-
- StringBuilder result = new StringBuilder(bodyStr.substring(0, tbodyIndex + 7));
- Collection users = DataBase.findAll();
- int id = 0;
- for (User user : users) {
- id++;
- result.append("| ")
- .append(id).append(" | ")
- .append(user.getUserId()).append(" | ")
- .append(user.getName()).append(" | ")
- .append(user.getEmail()).append(" | ")
- .append("수정 | ");
- }
- result.append(bodyStr.substring(tbodyIndex + 7));
- log.info("result: {}", result.toString());
- httpResponse.response200Header(result.toString().getBytes().length);
- httpResponse.responseBody(result.toString().getBytes());
- }
- } else {
+ if (!CONTROLLER_MAP.containsKey(url)) {
httpResponse.forward(url);
+ return;
}
+
+ Controller controller = CONTROLLER_MAP.get(url);
+ controller.service(httpRequest, httpResponse);
} catch (IOException e) {
log.error(e.getMessage());
}
-
}
}
diff --git a/src/main/java/webserver/WebServer.java b/src/main/java/webserver/WebServer.java
index 91f4a0f..bac543e 100644
--- a/src/main/java/webserver/WebServer.java
+++ b/src/main/java/webserver/WebServer.java
@@ -2,6 +2,8 @@
import java.net.ServerSocket;
import java.net.Socket;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -25,9 +27,9 @@ public static void main(String args[]) throws Exception {
// 클라이언트가 연결될때까지 대기한다.
Socket connection;
+ ExecutorService executorService = Executors.newFixedThreadPool(10);
while ((connection = listenSocket.accept()) != null) {
- RequestHandler requestHandler = new RequestHandler(connection);
- requestHandler.start();
+ executorService.execute(new RequestHandler(connection));
}
}
}
diff --git a/src/test/java/util/HttpRequestUtilsTest.java b/src/test/java/util/HttpRequestUtilsTest.java
index a4265f5..d2918c6 100644
--- a/src/test/java/util/HttpRequestUtilsTest.java
+++ b/src/test/java/util/HttpRequestUtilsTest.java
@@ -1,73 +1,78 @@
package util;
-import static org.hamcrest.CoreMatchers.*;
-import static org.junit.Assert.*;
-
import java.util.Map;
-import org.junit.Test;
-
+import org.assertj.core.api.SoftAssertions;
+import org.assertj.core.api.junit.jupiter.InjectSoftAssertions;
+import org.assertj.core.api.junit.jupiter.SoftAssertionsExtension;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
import util.HttpRequestUtils.Pair;
-public class HttpRequestUtilsTest {
+@ExtendWith(SoftAssertionsExtension.class)
+class HttpRequestUtilsTest {
+
+ @InjectSoftAssertions
+ SoftAssertions softly;
+
@Test
- public void parseQueryString() {
+ void parseQueryString() {
String queryString = "userId=javajigi";
Map parameters = HttpRequestUtils.parseQueryString(queryString);
- assertThat(parameters.get("userId"), is("javajigi"));
- assertThat(parameters.get("password"), is(nullValue()));
+ softly.assertThat(parameters.get("userId")).isEqualTo("javajigi");
+ softly.assertThat(parameters.get("password")).isNull();
queryString = "userId=javajigi&password=password2";
parameters = HttpRequestUtils.parseQueryString(queryString);
- assertThat(parameters.get("userId"), is("javajigi"));
- assertThat(parameters.get("password"), is("password2"));
+ softly.assertThat(parameters.get("userId")).isEqualTo("javajigi");
+ softly.assertThat(parameters.get("password")).isEqualTo("password2");
}
@Test
- public void parseQueryString_null() {
+ void parseQueryString_null() {
Map parameters = HttpRequestUtils.parseQueryString(null);
- assertThat(parameters.isEmpty(), is(true));
+ softly.assertThat(parameters.isEmpty()).isTrue();
parameters = HttpRequestUtils.parseQueryString("");
- assertThat(parameters.isEmpty(), is(true));
+ softly.assertThat(parameters.isEmpty()).isTrue();
parameters = HttpRequestUtils.parseQueryString(" ");
- assertThat(parameters.isEmpty(), is(true));
+ softly.assertThat(parameters.isEmpty()).isTrue();
}
@Test
- public void parseQueryString_invalid() {
+ void parseQueryString_invalid() {
String queryString = "userId=javajigi&password";
Map parameters = HttpRequestUtils.parseQueryString(queryString);
- assertThat(parameters.get("userId"), is("javajigi"));
- assertThat(parameters.get("password"), is(nullValue()));
+ softly.assertThat(parameters.get("userId")).isEqualTo("javajigi");
+ softly.assertThat(parameters.get("password")).isNull();
}
@Test
- public void parseCookies() {
+ void parseCookies() {
String cookies = "logined=true; JSessionId=1234";
Map parameters = HttpRequestUtils.parseCookies(cookies);
- assertThat(parameters.get("logined"), is("true"));
- assertThat(parameters.get("JSessionId"), is("1234"));
- assertThat(parameters.get("session"), is(nullValue()));
+ softly.assertThat(parameters.get("logined")).isEqualTo("true");
+ softly.assertThat(parameters.get("JSessionId")).isEqualTo("1234");
+ softly.assertThat(parameters.get("session")).isNull();
}
@Test
- public void getKeyValue() throws Exception {
+ void getKeyValue() {
Pair pair = HttpRequestUtils.getKeyValue("userId=javajigi", "=");
- assertThat(pair, is(new Pair("userId", "javajigi")));
+ softly.assertThat(pair).isEqualTo(new Pair("userId", "javajigi"));
}
@Test
- public void getKeyValue_invalid() throws Exception {
+ void getKeyValue_invalid() {
Pair pair = HttpRequestUtils.getKeyValue("userId", "=");
- assertThat(pair, is(nullValue()));
+ softly.assertThat(pair).isNull();
}
@Test
- public void parseHeader() throws Exception {
+ void parseHeader() {
String header = "Content-Length: 59";
Pair pair = HttpRequestUtils.parseHeader(header);
- assertThat(pair, is(new Pair("Content-Length", "59")));
+ softly.assertThat(pair).isEqualTo(new Pair("Content-Length", "59"));
}
}
diff --git a/src/test/java/util/IOUtilsTest.java b/src/test/java/util/IOUtilsTest.java
index 3c00cc4..eb8812b 100644
--- a/src/test/java/util/IOUtilsTest.java
+++ b/src/test/java/util/IOUtilsTest.java
@@ -3,7 +3,7 @@
import java.io.BufferedReader;
import java.io.StringReader;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/test/java/webserver/HttpRequestTest.java b/src/test/java/webserver/HttpRequestTest.java
new file mode 100644
index 0000000..d1d4104
--- /dev/null
+++ b/src/test/java/webserver/HttpRequestTest.java
@@ -0,0 +1,53 @@
+package webserver;
+
+import http.HttpRequest;
+import org.assertj.core.api.SoftAssertions;
+import org.assertj.core.api.junit.jupiter.InjectSoftAssertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.assertj.core.api.junit.jupiter.SoftAssertionsExtension;
+
+import java.io.FileInputStream;
+import java.io.InputStream;
+
+@ExtendWith(SoftAssertionsExtension.class)
+class HttpRequestTest {
+ private final String testDirectory = "./src/test/resources/";
+
+ @InjectSoftAssertions
+ SoftAssertions softly;
+
+ @Test
+ public void request_GET() throws Exception {
+ InputStream in = new FileInputStream(testDirectory + "Http_GET.txt");
+ HttpRequest request = new HttpRequest(in);
+
+ softly.assertThat(request.getMethod().name()).isEqualTo("GET");
+ softly.assertThat(request.getPath()).isEqualTo("/user/create");
+ softly.assertThat(request.getHeader("Connection")).isEqualTo("keep-alive");
+ softly.assertThat(request.getParameter("userId")).isEqualTo("javajigi");
+ }
+
+ @Test
+ public void request_POST() throws Exception {
+ InputStream in = new FileInputStream(testDirectory + "Http_POST.txt");
+ HttpRequest request = new HttpRequest(in);
+
+ softly.assertThat(request.getMethod().name()).isEqualTo("POST");
+ softly.assertThat(request.getPath()).isEqualTo("/user/create");
+ softly.assertThat(request.getHeader("Connection")).isEqualTo("keep-alive");
+ softly.assertThat(request.getParameter("userId")).isEqualTo("javajigi");
+ }
+
+ @Test
+ public void request_POST2() throws Exception {
+ InputStream in = new FileInputStream(testDirectory + "Http_POST2.txt");
+ HttpRequest request = new HttpRequest(in);
+
+ softly.assertThat(request.getMethod().name()).isEqualTo("POST");
+ softly.assertThat(request.getPath()).isEqualTo("/user/create");
+ softly.assertThat(request.getHeader("Connection")).isEqualTo("keep-alive");
+ softly.assertThat(request.getParameter("id")).isEqualTo("1");
+ softly.assertThat(request.getParameter("userId")).isEqualTo("javajigi");
+ }
+}
diff --git a/src/test/java/webserver/HttpResponseTest.java b/src/test/java/webserver/HttpResponseTest.java
new file mode 100644
index 0000000..13bbc1a
--- /dev/null
+++ b/src/test/java/webserver/HttpResponseTest.java
@@ -0,0 +1,38 @@
+package webserver;
+
+import http.HttpResponse;
+import org.junit.jupiter.api.Test;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+
+public class HttpResponseTest {
+ private String testDirectory = "./src/test/resources/";
+
+ @Test
+ public void responseForward() throws Exception {
+ // Http_Forward.txt 결과는 응답 body에 index.html이 포함되어 있어야 한다.
+ HttpResponse response = new HttpResponse(createOutputStream("Http_Forward.txt"));
+ response.forward("/index.html");
+ }
+
+ @Test
+ public void responseRedirect() throws Exception {
+ // Http_Redirect.txt 결과는 응답 header에 Location 정보가 /index.html로 포함되어 있어야 한다.
+ HttpResponse response = new HttpResponse(createOutputStream("Http_Redirect.txt"));
+ response.sendRedirect("/index.html");
+ }
+
+ @Test
+ public void responseCookies() throws Exception {
+ // Http_Cookie.txt 결과는 응답 header에 Set-Cookie 값으로 logined=true 값이 포함되어 있어야 한다.
+ HttpResponse response = new HttpResponse(createOutputStream("Http_Cookie.txt"));
+ response.addHeader("Set-Cookie", "logined=true");
+ response.sendRedirect("/index.html");
+ }
+
+ private OutputStream createOutputStream(String filename) throws FileNotFoundException {
+ return new FileOutputStream(testDirectory + filename);
+ }
+}
diff --git a/src/test/resources/Http_Cookie.txt b/src/test/resources/Http_Cookie.txt
new file mode 100644
index 0000000..c0a4480
--- /dev/null
+++ b/src/test/resources/Http_Cookie.txt
@@ -0,0 +1,3 @@
+HTTP/1.1 302 Found
+Set-Cookie: logined=true
+Location: /index.html
diff --git a/src/test/resources/Http_Forward.txt b/src/test/resources/Http_Forward.txt
new file mode 100644
index 0000000..abfead4
--- /dev/null
+++ b/src/test/resources/Http_Forward.txt
@@ -0,0 +1,152 @@
+HTTP/1.1 200 OK
+Content-Type:text/html;charset=utf-8
+Content-Length: 6892
+
+
+
+
+
+
+ SLiPP Java Web Programming
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/resources/Http_GET.txt b/src/test/resources/Http_GET.txt
new file mode 100644
index 0000000..bd2324b
--- /dev/null
+++ b/src/test/resources/Http_GET.txt
@@ -0,0 +1,4 @@
+GET /user/create?userId=javajigi&password=password&name=JaeSung HTTP/1.1
+Host: localhost:8080
+Connection: keep-alive
+Accept: */*
diff --git a/src/test/resources/Http_POST.txt b/src/test/resources/Http_POST.txt
new file mode 100644
index 0000000..2b62495
--- /dev/null
+++ b/src/test/resources/Http_POST.txt
@@ -0,0 +1,8 @@
+POST /user/create HTTP/1.1
+Host: localhost:8080
+Connection: keep-alive
+Content-Length: 46
+Content-Type: application/x-www-form-urlencoded
+Accept: */*
+
+userId=javajigi&password=password&name=JaeSung
diff --git a/src/test/resources/Http_POST2.txt b/src/test/resources/Http_POST2.txt
new file mode 100644
index 0000000..d8151a6
--- /dev/null
+++ b/src/test/resources/Http_POST2.txt
@@ -0,0 +1,8 @@
+POST /user/create?id=1 HTTP/1.1
+Host: localhost:8080
+Connection: keep-alive
+Content-Length: 46
+Content-Type: application/x-www-form-urlencoded
+Accept: */*
+
+userId=javajigi&password=password&name=JaeSung
\ No newline at end of file
diff --git a/src/test/resources/Http_Redirect.txt b/src/test/resources/Http_Redirect.txt
new file mode 100644
index 0000000..7f8efa9
--- /dev/null
+++ b/src/test/resources/Http_Redirect.txt
@@ -0,0 +1,2 @@
+HTTP/1.1 302 Found
+Location: /index.html
diff --git a/webapp/index.html b/webapp/index.html
index 1675898..92f6b0b 100644
--- a/webapp/index.html
+++ b/webapp/index.html
@@ -40,7 +40,7 @@
Facebook
-
+
@@ -145,4 +145,4 @@
|---|
|---|