-
Notifications
You must be signed in to change notification settings - Fork 309
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
[톰캣 구현하기 - 3, 4단계] 디노(신종화) 미션 제출합니다. #441
Changes from all commits
fb1a684
c8b8685
6faa7a2
656a8e3
14cea64
e6454d2
e88da3c
46d938a
5f41b28
7566751
a0278bd
304fe4d
c5d20eb
51ca60f
f53d16f
d3994c8
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 |
---|---|---|
@@ -1,11 +1,17 @@ | ||
package nextstep; | ||
|
||
import nextstep.jwp.HomeController; | ||
import nextstep.jwp.LoginController; | ||
import nextstep.jwp.RegisterController; | ||
import org.apache.catalina.startup.Tomcat; | ||
|
||
public class Application { | ||
|
||
public static void main(String[] args) { | ||
final var tomcat = new Tomcat(); | ||
tomcat.addController("/", new HomeController()); | ||
tomcat.addController("/login", new LoginController()); | ||
tomcat.addController("register", new RegisterController()); | ||
tomcat.start(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package nextstep.jwp; | ||
|
||
import java.io.IOException; | ||
import org.apache.catalina.AbstractController; | ||
import org.apache.coyote.http11.ExtensionType; | ||
import org.apache.coyote.http11.HttpStatusCode; | ||
import org.apache.coyote.http11.request.HttpRequest; | ||
import org.apache.coyote.http11.response.HttpResponse; | ||
import org.apache.coyote.http11.response.ResponseBody; | ||
import org.apache.coyote.http11.response.ResponseHeader; | ||
import org.apache.coyote.http11.response.StatusLine; | ||
|
||
public class HomeController extends AbstractController { | ||
|
||
private static final String DEFAULT_CONTENT = "Hello world!"; | ||
|
||
@Override | ||
protected void doPost(final HttpRequest request, final HttpResponse response) throws IOException { | ||
setResponse(response, "/500", HttpStatusCode.INTERNAL_SERVER_ERROR); | ||
} | ||
|
||
@Override | ||
protected void doGet(final HttpRequest request, final HttpResponse response) throws IOException { | ||
final ResponseBody responseBody = ResponseBody.of(ExtensionType.HTML.getExtension(), DEFAULT_CONTENT); | ||
final ResponseHeader responseHeader = ResponseHeader.from(responseBody); | ||
|
||
response.setStatusLine(new StatusLine(HttpStatusCode.OK)); | ||
response.setResponseHeader(responseHeader); | ||
response.setResponseBody(responseBody); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package nextstep.jwp; | ||
|
||
import java.io.IOException; | ||
import java.util.UUID; | ||
import nextstep.jwp.db.InMemoryUserRepository; | ||
import nextstep.jwp.exception.LoginException; | ||
import nextstep.jwp.model.User; | ||
import org.apache.catalina.AbstractController; | ||
import org.apache.catalina.SessionManager; | ||
import org.apache.coyote.http11.HttpCookie; | ||
import org.apache.coyote.http11.HttpStatusCode; | ||
import org.apache.coyote.http11.Session; | ||
import org.apache.coyote.http11.request.HttpRequest; | ||
import org.apache.coyote.http11.response.HttpResponse; | ||
|
||
public class LoginController extends AbstractController { | ||
|
||
private static final SessionManager sessionManager = new SessionManager(); | ||
|
||
private static final String JSESSIONID = "JSESSIONID"; | ||
private static final String INDEX = "/index"; | ||
private static final String ACCOUNT = "account"; | ||
private static final String PASSWORD = "password"; | ||
private static final String COOKIE = "Cookie"; | ||
private static final String USER = "user"; | ||
private static final String UNAUTHORIZED = "/401"; | ||
private static final String BAD_REQUEST = "/400"; | ||
|
||
@Override | ||
protected void doPost(final HttpRequest request, final HttpResponse response) throws IOException { | ||
try { | ||
final String userName = request.getRequestBody().get(ACCOUNT); | ||
final String password = request.getRequestBody().get(PASSWORD); | ||
|
||
if (userName.isBlank() || password.isBlank()) { | ||
setResponse(response, BAD_REQUEST, HttpStatusCode.BAD_REQUEST); | ||
return; | ||
} | ||
|
||
final User user = InMemoryUserRepository.findByAccount(userName) | ||
.orElseThrow(LoginException::new); | ||
|
||
if (user.checkPassword(password)) { | ||
log.info("user : " + user); | ||
final HttpCookie cookie = HttpCookie.from(request.getRequestHeaders().geHeaderValue(COOKIE)); | ||
checkSession(user, cookie); | ||
setResponse(response, INDEX, HttpStatusCode.FOUND); | ||
response.setCookie(cookie); | ||
return; | ||
} | ||
throw new LoginException(); | ||
} catch (LoginException exception) { | ||
setResponse(response, UNAUTHORIZED, HttpStatusCode.UNAUTHORIZED); | ||
} | ||
} | ||
|
||
private void checkSession(final User user, final HttpCookie cookie) { | ||
if (!cookie.contains(JSESSIONID)) { | ||
final Session session = new Session(UUID.randomUUID().toString()); | ||
session.setAttribute(USER, user); | ||
sessionManager.add(session); | ||
cookie.setCookie(JSESSIONID, session.getId()); | ||
} | ||
} | ||
|
||
@Override | ||
protected void doGet(final HttpRequest request, final HttpResponse response) throws IOException { | ||
final HttpCookie cookie = HttpCookie.from(request.getRequestHeaders().geHeaderValue(COOKIE)); | ||
final String requestResource = request.getRequestPath().getResource(); | ||
|
||
if (cookie.contains(JSESSIONID)) { | ||
setResponse(response, INDEX, HttpStatusCode.FOUND); | ||
response.setCookie(cookie); | ||
return; | ||
} | ||
setResponse(response, requestResource, HttpStatusCode.OK); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package nextstep.jwp; | ||
|
||
import java.io.IOException; | ||
import java.util.Map; | ||
import nextstep.jwp.db.InMemoryUserRepository; | ||
import nextstep.jwp.model.User; | ||
import org.apache.catalina.AbstractController; | ||
import org.apache.coyote.http11.HttpStatusCode; | ||
import org.apache.coyote.http11.request.HttpRequest; | ||
import org.apache.coyote.http11.response.HttpResponse; | ||
|
||
public class RegisterController extends AbstractController { | ||
|
||
private static final String BAD_REQUEST = "/400"; | ||
private static final String CONFLICT = "/409"; | ||
private static final String INDEX = "/index"; | ||
private static final String REGISTER = "/register"; | ||
private static final String ACCOUNT = "account"; | ||
private static final String PASSWORD = "password"; | ||
private static final String EMAIL = "email"; | ||
|
||
@Override | ||
protected void doPost(final HttpRequest request, final HttpResponse response) throws IOException { | ||
final Map<String, String> requestBody = request.getRequestBody(); | ||
|
||
final String account = requestBody.get(ACCOUNT); | ||
final String password = requestBody.get(PASSWORD); | ||
final String email = requestBody.get(EMAIL); | ||
|
||
if (account.isBlank() || password.isBlank() || email.isBlank()) { | ||
setResponse(response, BAD_REQUEST, HttpStatusCode.BAD_REQUEST); | ||
return; | ||
} | ||
|
||
if (InMemoryUserRepository.checkExistingId(account)) { | ||
setResponse(response, CONFLICT, HttpStatusCode.CONFLICT); | ||
return; | ||
} | ||
final User user = new User(account, password, email); | ||
InMemoryUserRepository.save(user); | ||
setResponse(response, INDEX, HttpStatusCode.OK); | ||
} | ||
|
||
@Override | ||
protected void doGet(final HttpRequest request, final HttpResponse response) throws IOException { | ||
setResponse(response, REGISTER, HttpStatusCode.OK); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,19 +3,23 @@ | |
import java.util.Map; | ||
import java.util.Optional; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
import java.util.concurrent.atomic.AtomicLong; | ||
import nextstep.jwp.model.User; | ||
|
||
public class InMemoryUserRepository { | ||
|
||
private static final AtomicLong id = new AtomicLong(1L); | ||
|
||
private static final Map<String, User> database = new ConcurrentHashMap<>(); | ||
|
||
static { | ||
final User user = new User(1L, "gugu", "password", "[email protected]"); | ||
final User user = new User(id.getAndIncrement(), "gugu", "password", "[email protected]"); | ||
database.put(user.getAccount(), user); | ||
} | ||
|
||
public static void save(User user) { | ||
database.put(user.getAccount(), user); | ||
final User userWithId = new User(id.getAndIncrement(), user.getAccount(), user.getPassword(), user.getEmail()); | ||
database.put(user.getAccount(), userWithId); | ||
} | ||
|
||
public static Optional<User> findByAccount(String account) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package nextstep.jwp.exception; | ||
|
||
public class NotAllowedExtensionException extends RuntimeException { | ||
|
||
public NotAllowedExtensionException() { | ||
super("해당하는 Extension이 존재하지 않습니다."); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package org.apache.catalina; | ||
|
||
import java.io.IOException; | ||
import org.apache.coyote.http11.FileExtractor; | ||
import org.apache.coyote.http11.HttpStatusCode; | ||
import org.apache.coyote.http11.request.HttpMethod; | ||
import org.apache.coyote.http11.request.HttpRequest; | ||
import org.apache.coyote.http11.response.HttpResponse; | ||
import org.apache.coyote.http11.response.ResponseBody; | ||
import org.apache.coyote.http11.response.ResponseHeader; | ||
import org.apache.coyote.http11.response.StatusLine; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
public abstract class AbstractController implements Controller { | ||
|
||
protected static final Logger log = LoggerFactory.getLogger(AbstractController.class); | ||
|
||
@Override | ||
public void service(final HttpRequest request, final HttpResponse response) throws IOException { | ||
if (request.getHttpMethod().equals(HttpMethod.GET)) { | ||
doGet(request, response); | ||
return; | ||
} | ||
if (request.getHttpMethod().equals(HttpMethod.POST)) { | ||
doPost(request, response); | ||
return; | ||
} | ||
throw new UnsupportedOperationException(); | ||
} | ||
|
||
protected abstract void doPost(HttpRequest request, HttpResponse response) throws IOException; | ||
|
||
protected abstract void doGet(final HttpRequest request, final HttpResponse response) throws IOException; | ||
|
||
protected void setResponse( | ||
final HttpResponse response, | ||
final String resource, | ||
final HttpStatusCode statusCode | ||
) throws IOException { | ||
final ResponseBody responseBody = FileExtractor.extractFile(resource); | ||
final ResponseHeader responseHeader = ResponseHeader.from(responseBody); | ||
|
||
response.setStatusLine(new StatusLine(statusCode)); | ||
response.setResponseHeader(responseHeader); | ||
response.setResponseBody(responseBody); | ||
} | ||
Comment on lines
+36
to
+47
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. setResponse로 이렇게 Response를 설정해주고 Processor에서 Response를 사용하는 군요! |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package org.apache.catalina; | ||
|
||
import java.io.IOException; | ||
import org.apache.coyote.http11.request.HttpRequest; | ||
import org.apache.coyote.http11.response.HttpResponse; | ||
|
||
public interface Controller { | ||
|
||
void service(final HttpRequest request, final HttpResponse response) throws IOException; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package org.apache.catalina; | ||
|
||
import java.io.IOException; | ||
import org.apache.coyote.http11.HttpStatusCode; | ||
import org.apache.coyote.http11.request.HttpRequest; | ||
import org.apache.coyote.http11.response.HttpResponse; | ||
|
||
public class DefaultController extends AbstractController { | ||
|
||
private static final String INTERNAL_SERVER_ERROR = "/500"; | ||
|
||
@Override | ||
protected void doPost(final HttpRequest request, final HttpResponse response) throws IOException { | ||
setResponse(response, INTERNAL_SERVER_ERROR, HttpStatusCode.INTERNAL_SERVER_ERROR); | ||
} | ||
|
||
@Override | ||
protected void doGet(final HttpRequest request, final HttpResponse response) throws IOException { | ||
final String resource = request.getRequestPath().getResource(); | ||
|
||
setResponse(response, resource, HttpStatusCode.OK); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package org.apache.catalina; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
import org.apache.coyote.http11.request.HttpRequest; | ||
|
||
public class RequestMapping { | ||
|
||
private final Map<String, Controller> mapper = new HashMap<>(); | ||
|
||
public void put(final String path, final Controller controller) { | ||
this.mapper.put(path, controller); | ||
} | ||
|
||
public Controller getController(final HttpRequest request) { | ||
final String resource = request.getRequestPath().getResource(); | ||
return mapper.getOrDefault(resource, new DefaultController()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package org.apache.catalina; | ||
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.
이 부분에 대해서 Apache의 coyote, catalina 패키지 중에 어떤 패키지에 둘지 고민하신 것 같아요! 찾아보니 톰캣의 catalina에서 Session 관리를 한다고 하더라구요! 실제 코드에서 구구가 만든 Manager를 구현하고 있는데 catalina 패키지에 만들어 놓으셨네요! |
||
|
||
import java.util.Map; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
import org.apache.coyote.http11.Session; | ||
|
||
public class SessionManager implements Manager { | ||
|
||
private static final Map<String, Session> sessions = new ConcurrentHashMap<>(); | ||
|
||
@Override | ||
public void add(final Session session) { | ||
sessions.put(session.getId(), session); | ||
} | ||
|
||
@Override | ||
public Session findSession(final String id) { | ||
return sessions.get(id); | ||
} | ||
|
||
@Override | ||
public void remove(final Session session) { | ||
sessions.remove(session.getId()); | ||
} | ||
} |
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.
제가 제안드린 방향을 고려해서 해주신 것 같아요!! 👍🏻
다만 실제 동작은 Mapping된 컨트롤러에서 지원하지 않는 메소드면
405 method not allowed가 응답되기 때문에 405가 뜨도록 리팩토링해보는 것을 제안했던 것이었습니다!!
그래도 잘 고려해주셔서 감사합니다 ㅎㅎ
미션이니 이 부분은 언급만 하고 머지하도록 하겠습니다!! 👍🏻👍🏻👍🏻