-
Notifications
You must be signed in to change notification settings - Fork 15
[Shion, Jane] HTTP 웹 서버 2단계 - 리팩토링 #12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: ShionJane
Are you sure you want to change the base?
Changes from all commits
e6e490d
c1bcc8d
074a52e
c5a9085
732de5b
65f8d64
47bcfce
2ef2e76
b7eb9c3
2dfd22b
7f1068b
5a8b133
950d599
21d952a
c75f752
82b8cda
56be465
cec3f61
9084520
10b36ff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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) { | ||
|
|
||
| } | ||
|
Comment on lines
+20
to
+26
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아직 리팩토링 중이어서 구현체가 없는걸까요?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 만약에 오버라이딩 하기 위함이라면 |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package controller; | ||
|
|
||
| import http.HttpRequest; | ||
| import http.HttpResponse; | ||
|
|
||
| public interface Controller { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 인터페이스를 사용해주셨네요 👍 |
||
| void service(HttpRequest request, HttpResponse response); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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"); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 상수로 적절히 추출해봅시다! |
||
| 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); | ||
| } | ||
|
Comment on lines
+21
to
+27
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 스프링은 어떻게 이걸 처리해줄까요? 한 번 공부해봅시다. |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 우리가 만들었던 스프링 Application은 한 Controller에서 해당 역할과 연관된 일을 전부 수행해줄 수 있었습니다.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 만약 HTTP Method들이 하나씩 늘어나면, 분기문은 계속해서 추가될텐데, 그 때 마다 기본 동작을 일일이 재정의 해줘야하는 걸까요? |
||
| 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("<tbody>"); | ||
| String result = addUserList(body, tbodyIndex).toString(); | ||
| response.forwardBody(result); | ||
|
Comment on lines
+27
to
+30
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이건 View가 해줘야 할 책임이 아닐까요? |
||
| } | ||
|
Comment on lines
+23
to
+31
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기서도 if else 문이 사용되었네요. 최대한 지양해봅시다. |
||
| } | ||
|
|
||
| private boolean isLogin(String id) { | ||
| Map<String, String> cookieStringMap = HttpRequestUtils.parseCookies(id); | ||
| log.info("Cookie: {}", cookieStringMap.toString()); | ||
| return SessionDataBase.isLoginUser(cookieStringMap.get("JSESSIONID")); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 하드 코딩된 부분은 상수로 추출해서 사용해봅시다. |
||
| } | ||
|
|
||
| private String getBody(String url) { | ||
| byte[] body = new byte[0]; | ||
| try { | ||
| body = Files.readAllBytes(new File("./webapp" + url).toPath()); | ||
| } catch (IOException e) { | ||
| e.printStackTrace(); | ||
| } | ||
|
Comment on lines
+44
to
+46
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분의 예외처리를 이렇게 해주신 이유가 있나요? 대략적으로 생각해보면, 요청한 파일이 없는 경우가 되지 않을까요? |
||
| return new String(body); | ||
| } | ||
|
|
||
| private StringBuilder processUserList(String body, int tbodyIndex) { | ||
| StringBuilder result = new StringBuilder(body.substring(0, tbodyIndex + 7)); | ||
| Collection<User> users = DataBase.findAll(); | ||
| int id = 0; | ||
| for (User user : users) { | ||
| id++; | ||
| result.append("<tr><th scope=\"row\">") | ||
| .append(id) | ||
| .append("</th> <td>") | ||
| .append(user.getUserId()) | ||
| .append("</td> <td>") | ||
| .append(user.getName()) | ||
| .append("</td> <td>") | ||
| .append(user.getEmail()) | ||
| .append("</td> <td>") | ||
| .append("<a href=\"#\" class=\"btn btn - success\" role=\"button\">수정</a></td>"); | ||
| } | ||
| return result; | ||
|
Comment on lines
+51
to
+67
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 요것도 역시 Controller가 가질 부분은 아니죠~ |
||
| } | ||
|
|
||
| private StringBuilder addUserList(String body, int tbodyIndex) { | ||
| StringBuilder result = processUserList(body, tbodyIndex); | ||
| return result.append(body.substring(tbodyIndex + 7)); | ||
| } | ||
|
Comment on lines
+34
to
+73
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 우리가 Spring을 사용하면서 써왔던 패턴 대로 개발해봅시다. |
||
| if (targetUser == null || !targetUser.isValidPassword(password)) { | ||
| response.addHeader("Set-Cookie", "loggedIn=false"); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 로그인 상태를 유저가 관리하는 형태인데 이게 안전할까요? |
||
| response.sendRedirect("/user/login_failed.html"); | ||
| return; | ||
| } | ||
| UUID uuid = UUID.randomUUID(); | ||
| SessionDataBase.sessions.put(uuid.toString(), targetUser); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SessionDataBase에 직접 접근하기보다는 별도의 클래스를 만들어서 거치도록 해줍시다. |
||
| response.addHeader("Set-Cookie", SessionDataBase.JSESSIONID + "=" + uuid); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Set-Cookie도 상수로 빼고, =도 상수로 빼줄 수 있을 것 같네요~ |
||
| response.sendRedirect("/index.html"); | ||
| log.info("{}님이 로그인하셨습니다.", userId); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<String, User> sessions = Maps.newHashMap(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 외부에서 접근해도 되는 걸까요?
|
||
|
|
||
| public static final String JSESSIONID = "JSESSIONID"; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
|
|
||
| public static boolean isLoginUser(String sessionId) { | ||
| return getSessionUser(sessionId) != null; | ||
| } | ||
|
Comment on lines
+13
to
+15
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이곳에는 DB와 관련된 로직만 넣어줍시다. |
||
|
|
||
| public static User getSessionUser(String sessionId) { | ||
| return sessions.get(sessionId); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,9 @@ | ||||||||
| package http; | ||||||||
|
|
||||||||
| public enum HttpMethod { | ||||||||
| GET, POST; | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
|
||||||||
| public boolean isPost() { | ||||||||
| return this == POST; | ||||||||
| } | ||||||||
|
Comment on lines
+6
to
+8
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 다른 메서드는 정의될 필요가 없나요? |
||||||||
| } | ||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<String, String> headers = new HashMap<>(); | ||
| private Map<String, String> parameters; | ||
|
Comment on lines
+17
to
+18
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 일급콜렉션에 대해서 학습해보시고 적용해보시는것도 좋을 것 같네요. |
||
|
|
||
| public HttpRequest(InputStream in) { | ||
| try { | ||
| BufferedReader br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); | ||
| requestLine = br.readLine(); | ||
| processHeaders(br); | ||
| processParameters(br); | ||
|
Comment on lines
+24
to
+25
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 값을 리턴받아 할당하는 형태로 되는건 어떤가요?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 그리고 생성자가 하는 일이 너무 많은 것 같아요! |
||
| } catch (IOException e) { | ||
| e.printStackTrace(); | ||
|
Comment on lines
+26
to
+27
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 예외처리를 좀 더 신경써서 해주세요! |
||
| } | ||
| } | ||
|
|
||
| private void processHeaders(BufferedReader br) throws IOException { | ||
| String line = br.readLine(); | ||
| while (!line.isEmpty()) { | ||
| log.debug("headers : {}", line); | ||
| line = br.readLine(); | ||
| if (line == null) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 조건문이 여기 나와야할까요? |
||
| return; | ||
| } | ||
| parseHeader(line); | ||
| } | ||
| } | ||
|
|
||
| private void parseHeader(String line) { | ||
| String[] headerTokens = line.split(": "); | ||
| if (headerTokens.length == 2) { | ||
| headers.put(headerTokens[0], headerTokens[1]); | ||
| } | ||
|
Comment on lines
+44
to
+47
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 리터럴들을 상수로 추출해주면 더 읽기 좋은 코드가 될 것 같네요~ |
||
| } | ||
|
|
||
| private void processParameters(BufferedReader br) throws IOException { | ||
| String[] tokens = requestLine.split(" "); | ||
| String queryString = ""; | ||
| String requestBody = ""; | ||
| if (tokens[1].contains("?")) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 적절하게 tokens[1]을 변수로 추출해보세요~. |
||
| 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]; | ||
| } | ||
|
Comment on lines
+70
to
+76
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. tokens[1]이 무엇인지~ 역시 변수로 추출해봅시다. |
||
|
|
||
| public String getHeader(String fieldName) { | ||
| return headers.get(fieldName); | ||
| } | ||
|
|
||
| public String getParameter(String fieldName) { | ||
| return parameters.get(fieldName); | ||
| } | ||
|
Comment on lines
+78
to
+84
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 좋네요~ |
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if else를 제거할 수 있는 방법은 없을까요?