[톰캣 구현하기 3, 4단계] 주디(오은비) 미션 제출합니다.#497
Conversation
hyena0608
left a comment
There was a problem hiding this comment.
주디 Conflict 해결 고생하셨어요~
리뷰 요청해주셔서 바로 확인해봤어요.
PR 받아서 애플리케이션 실행해봤는데 요구사항에 맞지 않는 오류가 있어요..! 🥲
확인 후 다시 리뷰 요청 부탁드리겠습니다.
01. 로그인 후 쿠키에 세션이 저장이 안돼요.
기존에 있는 gugu로 로그인 시도해봤습니다.
쿠키에 세션 정보가 없네요 ㅠㅠ
02. 회원가입 세션이 없어요.
hyena 회원가입을 진행해봤습니다.
여기도 안되네요.. 🙁
저장되나 직접 로깅해봤는데 일단 InMemory에 잘 들어가고 있네요!

03. locahost:8080/index를 찾을 수 없습니다!
04. 학습 테스트가 모두 사라졌어요! 😮
요청해주신대로 커멘트 후 머지하려고 했지만 미션 요구사항에 맞게 수정해주셔야 할 거 같아요 👍
요구사항에 맞을 때 다시 리뷰 하겠습니다!! 화이팅입니다 주디~~🚀
|
Kudos, SonarCloud Quality Gate passed!
|
hyena0608
left a comment
There was a problem hiding this comment.
안녕하세요 주디~
반영 고생하셨어요!
1, 2단계에서 많이 리팩터링 해주셨네요 👍
주디가 요청해주신대로 머지 먼저 하겠습니다 🚀
그래도 시간이 되신다면 제가 남긴 커맨트를 읽고 의견도 남겨주시면 재밌을거 같네요~
학습 테스트 관해서도 이야기 나눴으면 좋을텐데 ㅜㅜ
이것도 시간되신다면 학습 테스트 진행하시고 같이 더 많이 얻어갈 수 있으면 좋겠네요!
화이팅입니다 주디~
| import java.io.IOException; | ||
|
|
||
| public interface Controller { | ||
| String process(HttpRequestParser httpRequestParser, HttpResponseBuilder httpResponseBuilder) throws IOException; |
There was a problem hiding this comment.
요구사항에 맞지 않아서 조금 아쉽네요 ㅜㅜ
LMS에 있는 방식으로도 구현해보시면 좋을거 같아요!
| @Override | ||
| public String process(HttpRequestParser httpRequestParser, HttpResponseBuilder httpResponseBuilder) throws IOException { | ||
| return httpResponseBuilder.buildStaticFileOkResponse(httpRequestParser, | ||
| httpRequestParser.findPathWithoutQueryString() + ".html"); | ||
| } |
There was a problem hiding this comment.
쿼리 파라미터가 없다고해도 만약 index/1 이었다면 생각과 다른 결과가 나올거 같아요!
이후에 이러한 상황이 발생할 수도 있다는 것을 기억하고 있지 않다면 예외가 발생할 위험성이 있다고 생각합니다
| String account = splitRequestBody[0].split(KEY_VALUE_SEPARATOR)[1]; | ||
| String password = splitRequestBody[1].split(KEY_VALUE_SEPARATOR)[1]; |
There was a problem hiding this comment.
배열에 대한 생각을 두 번해야할거 같아요 ㅜㅜ
파싱에 대한 역할을 더 쪼개면 이후에 사용하기도 읽기도 편해질 수 있겠네요!
| try { | ||
| User user = InMemoryUserRepository.findByAccount(account).orElseThrow(UserNotFoundException::new); | ||
| addSession(user, httpRequestParser); | ||
| return redirect(password, user, httpRequestParser, httpResponseBuilder); | ||
| } catch (UserNotFoundException e) { | ||
| return httpResponseBuilder.buildStaticFileRedirectResponse(httpRequestParser, "/401.html"); | ||
| } |
There was a problem hiding this comment.
로그인 실패를 try catch로 잡아주셨네요
저는 큰 오류가 있는 줄 알았어요 😂
로그인 실패 처리를 이런 방식으로 구현하신 이유가 궁금합니다
| private void addCookie(HttpRequestParser httpRequestParser, Map<String, String> cookies, String uuid) { | ||
| if (cookies.isEmpty()) { | ||
| httpRequestParser.addHeader("Cookie", SESSION_ID + "=" + uuid); | ||
| return; | ||
| } | ||
| //cookies에 잇는 cookie들로 Cookie header 만들어줘 | ||
| String existedCookie = joinExistedCookie(cookies); | ||
| httpRequestParser.addHeader("Cookie", existedCookie + "; " + SESSION_ID + "=" + uuid); | ||
| } |
There was a problem hiding this comment.
HttpRequest 객체를 컨트롤러에서 제가 내부 값을 컨트롤할 수 있네요.
클라이언트가 보낸 정보를 조작할 수 있는게 위험할 수 있지 않을까요?
| private final Map<String, Controller> getMappingControllers = new HashMap<>(); | ||
| private final Map<String, Controller> postMappingControllers = new HashMap<>(); | ||
|
|
||
| public FrontController() { | ||
| getMappingControllers.put("/", new RootController()); | ||
| getMappingControllers.put("/login", new GetLoginController()); | ||
| getMappingControllers.put("/register", new GetRegisterController()); | ||
| postMappingControllers.put("/login", new PostLoginController()); | ||
| postMappingControllers.put("/register", new PostRegisterController()); | ||
| } | ||
|
|
||
| public String process(HttpRequestParser httpRequestParser, HttpResponseBuilder httpResponseBuilder) throws IOException { | ||
| String method = httpRequestParser.findMethod(); | ||
| String path = httpRequestParser.findPathWithoutQueryString(); | ||
| Controller controller = findController(method, path); | ||
|
|
||
| return controller.process(httpRequestParser, httpResponseBuilder); | ||
| } | ||
|
|
||
| public Controller findController(String method, String path) { | ||
| if (isStaticPath(path)) { | ||
| return new StaticController(); | ||
| } | ||
| if (method.equals("GET") && getMappingControllers.containsKey(path)) { | ||
| return getMappingControllers.get(path); | ||
| } | ||
| if (method.equals("POST") && postMappingControllers.containsKey(path)) { | ||
| return postMappingControllers.get(path); | ||
| } | ||
| return new NotFoundController(); | ||
| } |
There was a problem hiding this comment.
Http 메서드에 따라 사용하는 map이 다르네요!
그래서 분기문도 나오게 된거야 같아요.
현재는 분기문이 적지만 이후에 어떻게 해결하실지 궁금하네요.
| public Connector(final int port, final int acceptCount, final int maxThreads) { | ||
| this.serverSocket = createServerSocket(port, acceptCount); | ||
| this.threadPoolExecutor = new ThreadPoolExecutor( | ||
| CORE_POOL_SIZE, | ||
| maxThreads, | ||
| KEEP_ALIVE_TIME, | ||
| TimeUnit.SECONDS, | ||
| new LinkedBlockingQueue<>(DEFAULT_ACCEPT_COUNT)); | ||
| this.stopped = false; | ||
| } |
There was a problem hiding this comment.
흠.. Executors를 이용해보라고 LMS에 있었던거 같은데 ㅜㅜ
ThreadPoolExecutor를 바로 이용하신 이유가 있나요?
| public Map<String, String> findCookies() { | ||
| Map<String, String> cookie = header.entrySet().stream() | ||
| .filter(entry -> entry.getKey().equals("Cookie")) | ||
| .map(entry -> entry.getValue().split("; ")) | ||
| .flatMap(Arrays::stream) | ||
| .map(line -> line.split(KEY_VALUE_DELIMITER)) | ||
| .collect(Collectors.toMap(line -> line[0], line -> line[1])); | ||
| return cookie; | ||
| } |
There was a problem hiding this comment.
중간에 반환된 값을 변수로 받은 후 진행하면 더 읽기 편할거 같아요.
| return protocol + SPACE + status + SPACE + LINE_FEED + | ||
| findCookie(httpRequestParser) + | ||
| contentType + SPACE + LINE_FEED + | ||
| contentLength + SPACE + LINE_FEED + | ||
| LINE_FEED + | ||
| content; |
|
|
||
| public enum HttpStatus { | ||
| OK("200", "OK"), | ||
| REDIRECT("302", "Moved Temporarily"), |
There was a problem hiding this comment.
302가 Moved Temporarily가 맞나요??
저는 다른거로 알고 있는데 혹시 보신 문서가 있으시다면 공유해주시면 감사하겠습니다!!

















안녕하세요 헤나 ㅎㅎ 주디입니다!
3,4단계 구현하여 PR 보냅니다~ 이번에도 잘 부탁드려요!