Skip to content

Commit 364e4e0

Browse files
author
cheon-eunjeong
authored
[톰캣 구현하기 3, 4단계] 토리(천은정) 미션 제출합니다. (#491)
* feat: GreetingControllerTest 변경 * refactor: HttpRequest 클래스 구현 - HttpRequest 클래스 구조 분리 및 역할 세분화 - HttpRequestLine - HttpMethod - HttpPath - HttpProtocol - HttpRequestHeaders - HttpRequestBody - HttpProtocol enum 클래스 추가 * refactor: Controller 인터페이스 추가 - HttpResponse 구조 변경 - HttpRequest 객체의 요청을 처리할 FrontController 추가 - Http11Processor 내부 HttpRequest path로 인한 분기 로직 책임 분리 * feat: 동시성 확장 * refactor: 의존 관계 분리 * fix: 로그인 문제 해결
1 parent 2353692 commit 364e4e0

40 files changed

+745
-295
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
package cache.com.example.cachecontrol;
22

33
import org.springframework.context.annotation.Configuration;
4+
import org.springframework.http.CacheControl;
45
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
56
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
7+
import org.springframework.web.servlet.mvc.WebContentInterceptor;
68

79
@Configuration
810
public class CacheWebConfig implements WebMvcConfigurer {
911

1012
@Override
1113
public void addInterceptors(final InterceptorRegistry registry) {
14+
final WebContentInterceptor webContentInterceptor = new WebContentInterceptor();
15+
final CacheControl cacheControl = CacheControl
16+
.noCache()
17+
.cachePrivate();
18+
webContentInterceptor.addCacheMapping(cacheControl, "/**");
19+
registry.addInterceptor(webContentInterceptor);
1220
}
1321
}
Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
package cache.com.example.etag;
22

3+
import org.springframework.boot.web.servlet.FilterRegistrationBean;
4+
import org.springframework.context.annotation.Bean;
35
import org.springframework.context.annotation.Configuration;
6+
import org.springframework.web.filter.ShallowEtagHeaderFilter;
7+
8+
import static cache.com.example.version.CacheBustingWebConfig.PREFIX_STATIC_RESOURCES;
49

510
@Configuration
611
public class EtagFilterConfiguration {
7-
8-
// @Bean
9-
// public FilterRegistrationBean<ShallowEtagHeaderFilter> shallowEtagHeaderFilter() {
10-
// return null;
11-
// }
12+
@Bean
13+
public FilterRegistrationBean<ShallowEtagHeaderFilter> shallowEtagHeaderFilter() {
14+
FilterRegistrationBean<ShallowEtagHeaderFilter> filterFilterRegistrationBean
15+
= new FilterRegistrationBean<>(new ShallowEtagHeaderFilter());
16+
filterFilterRegistrationBean.addUrlPatterns("/etag", PREFIX_STATIC_RESOURCES + "/*");
17+
return filterFilterRegistrationBean;
18+
}
1219
}

study/src/main/java/cache/com/example/version/CacheBustingWebConfig.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22

33
import org.springframework.beans.factory.annotation.Autowired;
44
import org.springframework.context.annotation.Configuration;
5+
import org.springframework.http.CacheControl;
56
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
67
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
78

9+
import java.time.Duration;
10+
811
@Configuration
912
public class CacheBustingWebConfig implements WebMvcConfigurer {
1013

@@ -20,6 +23,7 @@ public CacheBustingWebConfig(ResourceVersion version) {
2023
@Override
2124
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
2225
registry.addResourceHandler(PREFIX_STATIC_RESOURCES + "/" + version.getVersion() + "/**")
23-
.addResourceLocations("classpath:/static/");
26+
.addResourceLocations("classpath:/static/")
27+
.setCacheControl(CacheControl.maxAge(Duration.ofDays(365)).cachePublic());
2428
}
2529
}

study/src/main/resources/application.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ handlebars:
22
suffix: .html
33

44
server:
5+
compression:
6+
enabled: true
7+
min-response-size: 10
58
tomcat:
69
accept-count: 1
710
max-connections: 1

study/src/test/java/thread/stage0/SynchronizationTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* 다중 스레드 환경에서 두 개 이상의 스레드가 변경 가능한(mutable) 공유 데이터를 동시에 업데이트하면 경쟁 조건(race condition)이 발생한다.
1313
* 자바는 공유 데이터에 대한 스레드 접근을 동기화(synchronization)하여 경쟁 조건을 방지한다.
1414
* 동기화된 블록은 하나의 스레드만 접근하여 실행할 수 있다.
15-
*
15+
* <p>
1616
* Synchronization
1717
* https://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html
1818
*/
@@ -21,7 +21,7 @@ class SynchronizationTest {
2121
/**
2222
* 테스트가 성공하도록 SynchronizedMethods 클래스에 동기화를 적용해보자.
2323
* synchronized 키워드에 대하여 찾아보고 적용하면 된다.
24-
*
24+
* <p>
2525
* Guide to the Synchronized Keyword in Java
2626
* https://www.baeldung.com/java-synchronized
2727
*/
@@ -41,7 +41,7 @@ private static final class SynchronizedMethods {
4141

4242
private int sum = 0;
4343

44-
public void calculate() {
44+
public synchronized void calculate() {
4545
setSum(getSum() + 1);
4646
}
4747

study/src/test/java/thread/stage0/ThreadPoolsTest.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
1212
/**
1313
* 스레드 풀은 무엇이고 어떻게 동작할까?
1414
* 테스트를 통과시키고 왜 해당 결과가 나왔는지 생각해보자.
15-
*
15+
* <p>
1616
* Thread Pools
1717
* https://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html
18-
*
18+
* <p>
1919
* Introduction to Thread Pools in Java
2020
* https://www.baeldung.com/thread-pool-java-and-guava
2121
*/
@@ -31,8 +31,8 @@ void testNewFixedThreadPool() {
3131
executor.submit(logWithSleep("hello fixed thread pools"));
3232

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

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

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

5252
assertThat(expectedPoolSize).isEqualTo(executor.getPoolSize());
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
package nextstep;
22

3+
import nextstep.jwp.controller.HomeController;
4+
import nextstep.jwp.controller.LoginController;
5+
import nextstep.jwp.controller.RegisterController;
36
import org.apache.catalina.startup.Tomcat;
47

58
public class Application {
69

710
public static void main(String[] args) {
811
final var tomcat = new Tomcat();
12+
tomcat.addController("/", new HomeController());
13+
tomcat.addController("/login", new LoginController());
14+
tomcat.addController("/register", new RegisterController());
915
tomcat.start();
1016
}
1117
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package nextstep.jwp.controller;
2+
3+
import org.apache.coyote.http11.controller.AbstractController;
4+
import org.apache.coyote.http11.request.HttpRequest;
5+
import org.apache.coyote.http11.response.HttpResponse;
6+
7+
public class HomeController extends AbstractController {
8+
@Override
9+
protected void doPost(final HttpRequest request, final HttpResponse response) throws Exception {
10+
throw new UnsupportedOperationException();
11+
}
12+
13+
@Override
14+
protected void doGet(final HttpRequest request, final HttpResponse response) throws Exception {
15+
response.home("Hello world!");
16+
}
17+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package nextstep.jwp.controller;
2+
3+
import nextstep.jwp.db.InMemoryUserRepository;
4+
import nextstep.jwp.model.User;
5+
import org.apache.coyote.http11.common.HttpUri;
6+
import org.apache.coyote.http11.controller.AbstractController;
7+
import org.apache.coyote.http11.cookie.HttpCookie;
8+
import org.apache.coyote.http11.request.HttpRequest;
9+
import org.apache.coyote.http11.response.HttpResponse;
10+
import org.apache.coyote.http11.session.HttpSession;
11+
import org.apache.coyote.http11.session.SessionManager;
12+
13+
import java.util.Map;
14+
import java.util.Objects;
15+
16+
public class LoginController extends AbstractController {
17+
private static final SessionManager sessionManager = SessionManager.create();
18+
private static final String USER = "user";
19+
private static final String PASSWORD = "password";
20+
21+
@Override
22+
protected void doPost(final HttpRequest request, final HttpResponse response) throws Exception {
23+
final Map<String, String> loginData = request.getBody();
24+
final User user = InMemoryUserRepository.findByAccount(loginData.get("account"))
25+
.orElse(null);
26+
if (!Objects.isNull(user) && user.checkPassword(loginData.get(PASSWORD))) {
27+
final HttpCookie newCookie = HttpCookie.create();
28+
saveSession(newCookie, user);
29+
response.found(HttpUri.INDEX_HTML.getUri());
30+
response.setCookie(newCookie.getJSESSIONID());
31+
return;
32+
}
33+
response.ok(HttpUri.UNAUTHORIZED_HTML.getUri());
34+
}
35+
36+
@Override
37+
protected void doGet(final HttpRequest request, final HttpResponse response) {
38+
final HttpCookie cookie = makeHttpCookie(request);
39+
if (cookie.hasJSESSIONID()) {
40+
final String jsessionid = cookie.getJSESSIONID();
41+
final HttpSession httpSession = sessionManager.findSession(jsessionid);
42+
if (Objects.isNull(httpSession)) {
43+
response.ok(HttpUri.LOGIN_HTML.getUri());
44+
return;
45+
}
46+
response.found(HttpUri.INDEX_HTML.getUri());
47+
return;
48+
}
49+
response.ok(HttpUri.LOGIN_HTML.getUri());
50+
}
51+
52+
private void saveSession(final HttpCookie newCookie, final User user) {
53+
final HttpSession httpSession = new HttpSession(newCookie.getJSESSIONID());
54+
httpSession.setAttribute(USER, user);
55+
sessionManager.add(httpSession);
56+
}
57+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package nextstep.jwp.controller;
2+
3+
import nextstep.jwp.db.InMemoryUserRepository;
4+
import nextstep.jwp.model.User;
5+
import org.apache.coyote.http11.common.HttpUri;
6+
import org.apache.coyote.http11.controller.AbstractController;
7+
import org.apache.coyote.http11.request.HttpRequest;
8+
import org.apache.coyote.http11.response.HttpResponse;
9+
10+
import java.util.Map;
11+
12+
public class RegisterController extends AbstractController {
13+
@Override
14+
protected void doPost(final HttpRequest request, final HttpResponse response) throws Exception {
15+
final Map<String, String> registerData = request.getBody();
16+
InMemoryUserRepository.save(new User(registerData.get("account"), registerData.get("password"), registerData.get("email")));
17+
response.ok(HttpUri.INDEX_HTML.getUri());
18+
}
19+
20+
@Override
21+
protected void doGet(final HttpRequest request, final HttpResponse response) throws Exception {
22+
response.ok(HttpUri.REGISTER.getUri());
23+
}
24+
}

0 commit comments

Comments
 (0)