Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
fed02f6
fix: remove implementation logback-classic on gradle (#501)
geoje Sep 5, 2024
7e91356
fix: add threads min-spare configuration on properties (#502)
geoje Sep 5, 2024
f96f2f6
test: FileTest 작성
nayonsoso Sep 3, 2024
300e6b5
test: IOStreamTest 작성
nayonsoso Sep 3, 2024
060bd98
feat: index.html 응답하기
nayonsoso Sep 4, 2024
31a6516
refactor: import 문 정렬
nayonsoso Sep 4, 2024
fc55c4e
refactor: inputStreamReader 를 사용하도록 변경
nayonsoso Sep 4, 2024
8f43312
feat: 정상 응답, 예외 응답 생성 함수 추가
nayonsoso Sep 4, 2024
c08da98
test: / 경로에 대한 테스트, 잘못된 경로에 대한 테스트 추가
nayonsoso Sep 4, 2024
679a5e3
style: 코드 재정렬
nayonsoso Sep 4, 2024
111a035
feat: 파일확장자->contentType 변환 클래스 생성
nayonsoso Sep 4, 2024
f516d89
refactor: 응답 생성 객체 분리
nayonsoso Sep 4, 2024
4a3a161
refactor: 분리한 객체의 함수 호출하도록 수정
nayonsoso Sep 4, 2024
cbc1b38
refactor: 경로와 쿼리스트링 분리
nayonsoso Sep 5, 2024
9bac826
refactor: 정적 파일 반환 로직을 클래스로 분리
nayonsoso Sep 5, 2024
6b399e6
refactor: NotFound 응답 반환로직을 함수로 생성
nayonsoso Sep 5, 2024
8aa1d61
feat: HTTP Request 클래스 생성
nayonsoso Sep 5, 2024
3350344
feat: 정적 파일 요청인지 구분하는 클래스 생성
nayonsoso Sep 5, 2024
eed525f
refactor: 함수 분리 및 가독성 개선
nayonsoso Sep 5, 2024
6ae13d5
refactor: 함수 분리
nayonsoso Sep 5, 2024
29674ba
refactor: 패키지 변경
nayonsoso Sep 5, 2024
02f203b
refactor: 함수 이름 변경
nayonsoso Sep 5, 2024
77a5bc0
feat: 컨트롤러 추상 클래스 생성
nayonsoso Sep 5, 2024
7de1c27
feat: 요청에 매칭되는 컨트롤러 반환 로직 구현
nayonsoso Sep 5, 2024
bd62ae0
feat: ModelAndView 객체 생성
nayonsoso Sep 5, 2024
567a5f5
feat: LogInController 생성
nayonsoso Sep 5, 2024
9636183
refactor: 컨틀롤러 매핑을 사용하도록 수정
nayonsoso Sep 5, 2024
e92226c
style: 개행
nayonsoso Sep 5, 2024
1c9c044
fix: 오류 수정
nayonsoso Sep 5, 2024
50c7e60
refactor: 클래스 이름 변경
nayonsoso Sep 5, 2024
2389c2b
refactor: Http Request, Body 분리
nayonsoso Sep 5, 2024
312eef2
refactor: 패키지 이동
nayonsoso Sep 5, 2024
5de8074
refactor: RequestHeader 가 사용되던 곳을 Request 로 대체
nayonsoso Sep 5, 2024
f99e3b6
refactor: 가독성 개선
nayonsoso Sep 5, 2024
8114b44
refactor: 가독성 개선 및 레코드로 변경
nayonsoso Sep 5, 2024
f2d713a
feat: 객체에 toMap 함수 추가
nayonsoso Sep 5, 2024
9155b05
feat: 로그인 실패시 401 응답 반환 기능 구현
nayonsoso Sep 5, 2024
f4aeabd
feat: 로그인 method 를 post 로 변경
nayonsoso Sep 5, 2024
01109c8
refactor: 오타 수정
nayonsoso Sep 5, 2024
1fddd40
feat: HTTP Response 객체 생성
nayonsoso Sep 6, 2024
b77771d
style: 개행 및 안쓰는 함수 제거
nayonsoso Sep 6, 2024
4f1a5fc
feat: RequestBody 내용을 String 이 아니라 Map 으로 변경
nayonsoso Sep 6, 2024
472a6e6
feat: HttpResponse 변경 내용 적용
nayonsoso Sep 6, 2024
504e111
feat: 비밀번호 틀린 경우 리다이렉트
nayonsoso Sep 6, 2024
bdeb85b
refactor: 구구 대체
nayonsoso Sep 6, 2024
e41c3d3
refactor: 학습 테스트 정적 파일 위치 변경
nayonsoso Sep 6, 2024
49e5de3
feat: 모든 응답에 no-cache 붙이는 인터셉터 추가
nayonsoso Sep 6, 2024
aff1c83
feat: 회원가입 컨트롤러 생성
nayonsoso Sep 6, 2024
9a28430
fix: 인코딩 문제 해결
nayonsoso Sep 6, 2024
cec39fe
feat: 세션, 세션 메니저 객체 생성
nayonsoso Sep 6, 2024
d269899
feat: 로그인, 회원가입 시 세션 저장
nayonsoso Sep 6, 2024
4f552bc
feat: 로그인, 회원가입 시 SetCookie 헤더 설정
nayonsoso Sep 6, 2024
0fad218
feat: 로그인한 유저는 리다이렉트하는 기능 추가
nayonsoso Sep 6, 2024
6319148
feat: 응답 압축 설정
nayonsoso Sep 6, 2024
191c2a7
feat: 특정 경로에 대해 etag를 응답하도록 설정
nayonsoso Sep 6, 2024
161dd57
feat: 정적 파일 요청시 etag 응답
nayonsoso Sep 6, 2024
c9b83eb
refactor: 루트 경로에 대해 no cache 하도록 수정
nayonsoso Sep 6, 2024
5142706
feat: 정적 파일에 대해 캐시 만료 시간 설정
nayonsoso Sep 6, 2024
6479232
refactor: 오타 수정
nayonsoso Sep 6, 2024
b48b382
refactor: 시간을 etag 버전으로 설정
nayonsoso Sep 6, 2024
41b7cb5
refactor: 파일 확장자 추가
nayonsoso Sep 6, 2024
eb6b28c
chore: 사용하지 않는 클래스 삭제
nayonsoso Sep 6, 2024
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
1 change: 0 additions & 1 deletion study/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ repositories {
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'ch.qos.logback:logback-classic:1.5.7'
implementation 'org.apache.commons:commons-lang3:3.14.0'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.1'
implementation 'pl.allegro.tech.boot:handlebars-spring-boot-starter:0.4.1'
Expand Down
8 changes: 4 additions & 4 deletions study/src/main/java/cache/com/example/GreetingController.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class GreetingController {

@GetMapping("/")
public String index() {
return "index";
return "index.html";
}

/**
Expand All @@ -25,16 +25,16 @@ public String cacheControl(final HttpServletResponse response) {
.cachePrivate()
.getHeaderValue();
response.addHeader(HttpHeaders.CACHE_CONTROL, cacheControl);
return "index";
return "index.html";
}

@GetMapping("/etag")
public String etag() {
return "index";
return "index.html";
}

@GetMapping("/resource-versioning")
public String resourceVersioning() {
return "resource-versioning";
return "resource-versioning.html";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ public class CacheWebConfig implements WebMvcConfigurer {

@Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(new NoCacheInterceptor())
.addPathPatterns("/");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package cache.com.example.cachecontrol;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class NoCacheInterceptor implements HandlerInterceptor {

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
response.setHeader("Cache-Control", "no-cache, private");
}
}
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() {
FilterRegistrationBean<ShallowEtagHeaderFilter> filterRegistrationBean
= new FilterRegistrationBean<>(new ShallowEtagHeaderFilter());
filterRegistrationBean.addUrlPatterns("/etag/*");
return filterRegistrationBean;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package cache.com.example.version;

import java.time.Duration;
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;

Expand All @@ -20,6 +22,8 @@ public CacheBustingWebConfig(ResourceVersion version) {
@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler(PREFIX_STATIC_RESOURCES + "/" + version.getVersion() + "/**")
.addResourceLocations("classpath:/static/");
.addResourceLocations("classpath:/static/")
.setEtagGenerator(resource -> version.getVersion())
.setCacheControl(CacheControl.maxAge(Duration.ofDays(365)).cachePublic());
}
}
4 changes: 4 additions & 0 deletions study/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@ server:
accept-count: 1
max-connections: 1
threads:
min-spare: 2
max: 2
compression:
enabled: true
min-response-size: 10
29 changes: 15 additions & 14 deletions study/src/test/java/study/FileTest.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package study;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;

import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

/**
* 웹서버는 사용자가 요청한 html 파일을 제공 할 수 있어야 한다.
Expand All @@ -24,11 +26,12 @@ class FileTest {
* resource 디렉터리의 경로는 어떻게 알아낼 수 있을까?
*/
@Test
void resource_디렉터리에_있는_파일의_경로를_찾는다() {
void resource_디렉터리에_있는_파일의_경로를_찾는다() throws URISyntaxException {
final String fileName = "nextstep.txt";

// todo
final String actual = "";
URL resource = getClass().getResource("/" + fileName);
Path path = Path.of(resource.toURI());
final String actual = path.toString();

assertThat(actual).endsWith(fileName);
}
Expand All @@ -40,14 +43,12 @@ class FileTest {
* File, Files 클래스를 사용하여 파일의 내용을 읽어보자.
*/
@Test
void 파일의_내용을_읽는다() {
void 파일의_내용을_읽는다() throws IOException, URISyntaxException {
final String fileName = "nextstep.txt";
URL resource = getClass().getResource("/" + fileName);
Path path = Path.of(resource.toURI());

// todo
final Path path = null;

// todo
final List<String> actual = Collections.emptyList();
List<String> actual = Files.readAllLines(path);

assertThat(actual).containsOnly("nextstep");
}
Expand Down
73 changes: 38 additions & 35 deletions study/src/test/java/study/IOStreamTest.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
package study;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import java.io.*;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.*;

/**
* 자바는 스트림(Stream)으로부터 I/O를 사용한다.
* 입출력(I/O)은 하나의 시스템에서 다른 시스템으로 데이터를 이동 시킬 때 사용한다.
Expand Down Expand Up @@ -49,13 +59,9 @@ class OutputStream_학습_테스트 {
final byte[] bytes = {110, 101, 120, 116, 115, 116, 101, 112};
final OutputStream outputStream = new ByteArrayOutputStream(bytes.length);

/**
* todo
* OutputStream 객체의 write 메서드를 사용해서 테스트를 통과시킨다
*/
outputStream.write(bytes);

final String actual = outputStream.toString();

assertThat(actual).isEqualTo("nextstep");
outputStream.close();
}
Expand All @@ -73,11 +79,7 @@ class OutputStream_학습_테스트 {
void BufferedOutputStream을_사용하면_버퍼링이_가능하다() throws IOException {
final OutputStream outputStream = mock(BufferedOutputStream.class);

/**
* todo
* flush를 사용해서 테스트를 통과시킨다.
* ByteArrayOutputStream과 어떤 차이가 있을까?
*/
outputStream.flush();

verify(outputStream, atLeastOnce()).flush();
outputStream.close();
Expand All @@ -90,12 +92,10 @@ class OutputStream_학습_테스트 {
@Test
void OutputStream은_사용하고_나서_close_처리를_해준다() throws IOException {
final OutputStream outputStream = mock(OutputStream.class);

/**
* todo
* try-with-resources를 사용한다.
* java 9 이상에서는 변수를 try-with-resources로 처리할 수 있다.
*/
try(outputStream) {
outputStream.write(1);
outputStream.flush();
}

verify(outputStream, atLeastOnce()).close();
}
Expand Down Expand Up @@ -124,12 +124,9 @@ class InputStream_학습_테스트 {
byte[] bytes = {-16, -97, -92, -87};
final InputStream inputStream = new ByteArrayInputStream(bytes);

/**
* todo
* inputStream에서 바이트로 반환한 값을 문자열로 어떻게 바꿀까?
*/
final String actual = "";
byte[] read = inputStream.readAllBytes();

final String actual = new String(read);
assertThat(actual).isEqualTo("🤩");
assertThat(inputStream.read()).isEqualTo(-1);
inputStream.close();
Expand All @@ -143,11 +140,8 @@ class InputStream_학습_테스트 {
void InputStream은_사용하고_나서_close_처리를_해준다() throws IOException {
final InputStream inputStream = mock(InputStream.class);

/**
* todo
* try-with-resources를 사용한다.
* java 9 이상에서는 변수를 try-with-resources로 처리할 수 있다.
*/
try(inputStream) {
}

verify(inputStream, atLeastOnce()).close();
}
Expand All @@ -169,12 +163,12 @@ class FilterStream_학습_테스트 {
* 버퍼 크기를 지정하지 않으면 버퍼의 기본 사이즈는 얼마일까?
*/
@Test
void 필터인_BufferedInputStream를_사용해보자() {
void 필터인_BufferedInputStream를_사용해보자() throws IOException {
final String text = "필터에 연결해보자.";
final InputStream inputStream = new ByteArrayInputStream(text.getBytes());
final InputStream bufferedInputStream = null;
final InputStream bufferedInputStream = new BufferedInputStream(inputStream);

final byte[] actual = new byte[0];
final byte[] actual = bufferedInputStream.readAllBytes();

assertThat(bufferedInputStream).isInstanceOf(FilterInputStream.class);
assertThat(actual).isEqualTo("필터에 연결해보자.".getBytes());
Expand All @@ -197,15 +191,24 @@ class InputStreamReader_학습_테스트 {
* 필터인 BufferedReader를 사용하면 readLine 메서드를 사용해서 문자열(String)을 한 줄 씩 읽어올 수 있다.
*/
@Test
void BufferedReader를_사용하여_문자열을_읽어온다() {
void BufferedReader를_사용하여_문자열을_읽어온다() throws IOException {
final String emoji = String.join("\r\n",
"😀😃😄😁😆😅😂🤣🥲☺️😊",
"😇🙂🙃😉😌😍🥰😘😗😙😚",
"😋😛😝😜🤪🤨🧐🤓😎🥸🤩",
"");
final InputStream inputStream = new ByteArrayInputStream(emoji.getBytes());
final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

final StringBuilder actual = new StringBuilder();
while (true) {
String txt = bufferedReader.readLine();
if (txt == null) {
break;
}
actual.append(txt).append("\r\n");
}

assertThat(actual).hasToString(emoji);
}
Expand Down
18 changes: 13 additions & 5 deletions tomcat/src/main/java/com/techcourse/db/InMemoryUserRepository.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.techcourse.db;

import com.techcourse.model.User;

import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
Expand All @@ -11,17 +10,26 @@ public class InMemoryUserRepository {
private static final Map<String, User> database = new ConcurrentHashMap<>();

static {
final User user = new User(1L, "gugu", "password", "hkkang@woowahan.com");
final User user = new User(1L, "sancho", "1234", "sancho@woowa.com");
database.put(user.getAccount(), user);
}

public static void save(User user) {
database.put(user.getAccount(), user);
public static User save(User user) {
return database.put(user.getAccount(), user);
}

public static Optional<User> findByAccount(String account) {
return Optional.ofNullable(database.get(account));
}

private InMemoryUserRepository() {}
public static Optional<User> findByAccountAndPassword(String account, String password) {
User user = database.get(account);
if (user != null && user.checkPassword(password)) {
return Optional.of(user);
}
return Optional.empty();
}

private InMemoryUserRepository() {
}
}
9 changes: 9 additions & 0 deletions tomcat/src/main/java/com/techcourse/model/User.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.techcourse.model;

import java.util.Map;

public class User {

private final Long id;
Expand All @@ -26,6 +28,13 @@ public String getAccount() {
return account;
}

public Map<String, Object> toMap() {
return Map.of(
"id", id,
"account", account,
"email", email);
}

@Override
public String toString() {
return "User{" +
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.apache.coyote.controller;

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

public abstract class Controller {

public abstract HttpResponse process(HttpRequest request);
}
Loading