Skip to content
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단계] 키아라(김도희) 미션 제출합니다 #487

Merged
merged 14 commits into from
Sep 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package cache.com.example.cachecontrol;

import org.springframework.http.CacheControl;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import static org.springframework.http.HttpHeaders.CACHE_CONTROL;

public class CacheControlInterceptor implements HandlerInterceptor {

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
CacheControl cacheControl = CacheControl.noCache().cachePrivate();
String cacheControlValue = cacheControl.getHeaderValue();
response.addHeader(CACHE_CONTROL, cacheControlValue);
return true;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package cache.com.example.cachecontrol;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
Expand All @@ -9,5 +10,11 @@ public class CacheWebConfig implements WebMvcConfigurer {

@Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(cacheControlInterceptor()).addPathPatterns("/**");
}

@Bean
public CacheControlInterceptor cacheControlInterceptor() {
return new CacheControlInterceptor();
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package cache.com.example.etag;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.ShallowEtagHeaderFilter;

@Configuration
public class EtagFilterConfiguration {

// @Bean
// public FilterRegistrationBean<ShallowEtagHeaderFilter> shallowEtagHeaderFilter() {
// return null;
// }
@Bean
public FilterRegistrationBean<ShallowEtagHeaderFilter> shallowEtagHeaderFilter() {
final var registration = new FilterRegistrationBean<>(new ShallowEtagHeaderFilter());
registration.addUrlPatterns("/etag");
registration.addUrlPatterns("/resources/*");
return registration;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.CacheControl;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.time.Duration;

@Configuration
public class CacheBustingWebConfig implements WebMvcConfigurer {

Expand All @@ -20,6 +23,7 @@ public CacheBustingWebConfig(ResourceVersion version) {
@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler(PREFIX_STATIC_RESOURCES + "/" + version.getVersion() + "/**")
.setCacheControl(CacheControl.maxAge(Duration.ofDays(365)).cachePublic())
.addResourceLocations("classpath:/static/");
}
}
3 changes: 3 additions & 0 deletions study/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ server:
max-connections: 1
threads:
max: 2
compression:
enabled: true
min-response-size: 10
6 changes: 3 additions & 3 deletions study/src/test/java/thread/stage0/ThreadPoolsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ void testNewFixedThreadPool() {
executor.submit(logWithSleep("hello fixed thread pools"));

// 올바른 값으로 바꿔서 테스트를 통과시키자.
final int expectedPoolSize = 0;
final int expectedQueueSize = 0;
final int expectedPoolSize = 2;
final int expectedQueueSize = 1;

assertThat(expectedPoolSize).isEqualTo(executor.getPoolSize());
assertThat(expectedQueueSize).isEqualTo(executor.getQueue().size());
Expand All @@ -46,7 +46,7 @@ void testNewCachedThreadPool() {
executor.submit(logWithSleep("hello cached thread pools"));

// 올바른 값으로 바꿔서 테스트를 통과시키자.
final int expectedPoolSize = 0;
final int expectedPoolSize = 3;
final int expectedQueueSize = 0;

assertThat(expectedPoolSize).isEqualTo(executor.getPoolSize());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package nextstep.jwp.exception;

public class ResourceNotFoundException extends RuntimeException {

public ResourceNotFoundException(Exception e) {
super(e);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package nextstep.jwp.presentation;

import org.apache.coyote.http11.request.HttpRequest;
import org.apache.coyote.http11.response.HttpResponse;

import static org.apache.coyote.http11.Method.*;

public abstract class AbstractController implements Controller {

@Override
public HttpResponse service(HttpRequest httpRequest, HttpResponse httpResponse) {

if (GET.matches(httpRequest.getMethod())) {
return doGet(httpRequest, httpResponse);
}
if (POST.matches(httpRequest.getMethod())) {
return doPost(httpRequest, httpResponse);
}
throw new IllegalArgumentException("지원하지 않는 HTTP Method 입니다.");
}

protected abstract HttpResponse doGet(HttpRequest httpRequest, HttpResponse httpResponse);

protected abstract HttpResponse doPost(HttpRequest httpRequest, HttpResponse httpResponse);
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package nextstep.jwp.presentation;

import org.apache.coyote.http11.request.RequestReader;
import org.apache.coyote.http11.response.Response;

import java.io.IOException;
import org.apache.coyote.http11.request.HttpRequest;
import org.apache.coyote.http11.response.HttpResponse;

public interface Controller {

Response service(RequestReader requestReader) throws IOException;
HttpResponse service(HttpRequest httpRequest, HttpResponse httpResponse);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3차 요구사항에 맞춰 반환 타입을 void로 변경하면 좋을 것 같습니다
Http11Processor.process()에서 HttpResponse 객체를 생성하고, 생성한 response에 setter로 response 필드를 추가해주는 형식으로 변경할 수 있을 것 같아요

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

public enum ControllerType {

MAIN("/", new MainController()),
LOGIN("/login.html", new LoginController()),
REGISTER("/register.html", new RegisterController()),
INDEX("/index.html", new IndexController()),
MAIN("/", MainController.getInstance()),
LOGIN("/login.html", LoginController.getInstance()),
REGISTER("/register.html", RegisterController.getInstance()),
INDEX("/index.html", IndexController.getInstance()),
;

private final String requestUri;
Expand All @@ -24,6 +24,6 @@ public static Controller findController(String requestUri) {
.filter(findController -> findController.requestUri.equals(requestUri))
.findFirst()
.map(findController -> findController.controller)
.orElse(new OtherController());
.orElse(OtherController.getInstance());
}
}
31 changes: 21 additions & 10 deletions tomcat/src/main/java/nextstep/jwp/presentation/IndexController.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
package nextstep.jwp.presentation;

import org.apache.coyote.http11.request.RequestReader;
import org.apache.coyote.http11.response.Response;
import org.apache.coyote.http11.response.FileReader;
import org.apache.coyote.http11.request.HttpRequest;
import org.apache.coyote.http11.response.HttpResponse;

import java.io.IOException;
public class IndexController extends AbstractController {

import static org.apache.coyote.http11.response.StatusCode.OK;
private static final IndexController INSTANCE = new IndexController();

public class IndexController implements Controller {
private IndexController() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private으로 잘 막아주셨네요!!

}

public static IndexController getInstance() {
return INSTANCE;
}

@Override
public HttpResponse doGet(HttpRequest httpRequest, HttpResponse httpResponse) {
String body = FileReader.read(httpRequest.getUri());
return httpResponse
.addBaseHeader(httpRequest.getContentType())
.addBody(body);
}

@Override
public Response service(RequestReader requestReader) throws IOException {
return new Response()
.addResponseLine(requestReader.getProtocol(), OK)
.addBaseHeader(requestReader.getContentType())
.createBodyByFile(requestReader.getUri());
public HttpResponse doPost(HttpRequest httpRequest, HttpResponse httpResponse) {
return null;
}
}
86 changes: 38 additions & 48 deletions tomcat/src/main/java/nextstep/jwp/presentation/LoginController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,75 +2,65 @@

import nextstep.jwp.db.InMemoryUserRepository;
import nextstep.jwp.model.User;
import org.apache.coyote.http11.request.RequestReader;
import org.apache.coyote.http11.response.Response;
import org.apache.coyote.http11.response.FileReader;
import org.apache.coyote.http11.request.HttpRequest;
import org.apache.coyote.http11.response.HttpResponse;
import org.apache.coyote.http11.response.SessionManager;

import java.io.IOException;

import static org.apache.coyote.http11.response.Header.LOCATION;
import static org.apache.coyote.http11.Method.GET;
import static org.apache.coyote.http11.Method.POST;
import static org.apache.coyote.http11.response.StatusCode.FOUND;
import static org.apache.coyote.http11.response.StatusCode.OK;
import static org.apache.coyote.http11.response.StatusCode.UNAUTHORIZED;
import static org.reflections.Reflections.log;

public class LoginController implements Controller {

private static final String INDEX = "/index.html";
private static final String UNAUTHORIZED_HTML = "/401.html";
public class LoginController extends AbstractController {

@Override
public Response service(RequestReader requestReader) throws IOException {
String method = requestReader.getMethod();
private static final LoginController INSTANCE = new LoginController();

if (GET.matches(method)) {
return loginPage(requestReader);
}
if (POST.matches(method)) {
return tryLogin(requestReader);
}
private LoginController() {
}

return null;
public static LoginController getInstance() {
return INSTANCE;
}

private Response loginPage(RequestReader requestReader) throws IOException {
if (requestReader.hasSessionId()) {
return new Response()
.addResponseLine(requestReader.getProtocol(), FOUND)
.addHeader(LOCATION, INDEX)
.addBaseHeader(requestReader.getContentType());
@Override
public HttpResponse doGet(HttpRequest httpRequest, HttpResponse httpResponse) {
if (httpRequest.hasSessionId()) {
return httpResponse
.addBaseHeader(httpRequest.getContentType())
.redirect("/index.html");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 다 setXX() 해줬는데 ㅎ.. 객체를 반환해서 메서드 체이닝으로 하는거 좋네요👏🏻

}
return new Response()
.addResponseLine(requestReader.getProtocol(), OK)
.addBaseHeader(requestReader.getContentType())
.createBodyByFile(requestReader.getUri());
String body = FileReader.read(httpRequest.getUri());
return httpResponse
.addBaseHeader(httpRequest.getContentType())
.addBody(body);
}

private Response tryLogin(RequestReader requestReader) throws IOException {
@Override
public HttpResponse doPost(HttpRequest httpRequest, HttpResponse httpResponse) {
try {
String sessionId = login(requestReader);
return new Response()
.addResponseLine(requestReader.getProtocol(), FOUND)
.addBaseHeader(requestReader.getContentType())
.addHeader(LOCATION, INDEX)
.setCookie(sessionId);
login(httpRequest, httpResponse);
return httpResponse
.addBaseHeader(httpRequest.getContentType())
.redirect("/index.html");

} catch (IllegalArgumentException e) {
return new Response()
.addResponseLine(requestReader.getProtocol(), UNAUTHORIZED)
.addBaseHeader(requestReader.getContentType())
.createBodyByFile(UNAUTHORIZED_HTML);
String body = FileReader.read("/401.html");
return httpResponse
.setStatusCode(UNAUTHORIZED)
.addBaseHeader(httpRequest.getContentType())
.addBody(body);
}
}

private String login(RequestReader requestReader) {
User user = InMemoryUserRepository.findByAccount(requestReader.getBodyValue("account"))
private void login(HttpRequest httpRequest, HttpResponse httpResponse) {
User user = InMemoryUserRepository.findByAccount(httpRequest.getBodyValue("account"))
.orElseThrow(() -> new IllegalArgumentException("해당 아이디의 사용자가 존재하지 않습니다"));

if (!user.checkPassword(requestReader.getBodyValue("password"))) {
if (!user.checkPassword(httpRequest.getBodyValue("password"))) {
throw new IllegalArgumentException("비밀번호가 일치하지 않습니다");
}

return SessionManager.getSessionId(user);
String sessionId = SessionManager.getSessionId(user);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getSessionId()에서 session을 저장한다는 것은 메서드 내부를 확인해야 알 수 있을 것 같아요!
단순히 저장되어 있는 session을 가져오는 getter처럼 느껴집니다
저는 이럴 때 정팩메를 사용해 컬렉션에 저장 + 생성 로직을 추가해줬었는데 키아라 의견도 궁금합니다!

httpResponse.setCookie(sessionId);
log.info("로그인 성공: {}", SessionManager.getSession(sessionId).getAttribute("user"));
}
}
29 changes: 20 additions & 9 deletions tomcat/src/main/java/nextstep/jwp/presentation/MainController.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
package nextstep.jwp.presentation;

import org.apache.coyote.http11.request.RequestReader;
import org.apache.coyote.http11.response.Response;
import org.apache.coyote.http11.request.HttpRequest;
import org.apache.coyote.http11.response.HttpResponse;

import static org.apache.coyote.http11.response.StatusCode.OK;
public class MainController extends AbstractController{

public class MainController implements Controller{
private static final MainController INSTANCE = new MainController();

private MainController() {
}

public static MainController getInstance() {
return INSTANCE;
}

@Override
public HttpResponse doGet(HttpRequest httpRequest, HttpResponse httpResponse) {
return httpResponse
.addBaseHeader(httpRequest.getContentType())
.addBody("Hello world!");
}

@Override
public Response service(RequestReader requestReader) {
return new Response()
.addResponseLine(requestReader.getProtocol(), OK)
.addBaseHeader(requestReader.getContentType())
.createBodyByText("Hello world!");
public HttpResponse doPost(HttpRequest httpRequest, HttpResponse httpResponse) {
return null;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 null을 반환하기보다 예외를 던지는 방식은 어떤가요?

}
}
Loading