Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
eb9459f
학습 테스트 진행
zangsu Sep 3, 2024
caae46a
이슈 템플릿 생성
zangsu Sep 4, 2024
c00ca94
refactor : 컨벤션 적용
zangsu Sep 4, 2024
e9002f8
test: Request 객체 정의 및 테스트 작성
zangsu Sep 4, 2024
9d5dc56
feat: Method 클래스 생성
zangsu Sep 4, 2024
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
d719ae3
refactor: findByName 을 static 으로 지정
zangsu Sep 5, 2024
ef54ac6
feat: 요청으로 Request 객체를 파싱
zangsu Sep 5, 2024
cd76254
refactor: 요청에 대한 응답 생성을 메서드 분리
zangsu Sep 5, 2024
bc3c241
refactor: 디버깅을 위해 toString 생성
zangsu Sep 5, 2024
f830fd7
refactor: 입력을 읽는데 BufferedReader.lines() 제거
zangsu Sep 5, 2024
d19e5ff
feat: 응답할 내용을 Content 객체로 생성
zangsu Sep 5, 2024
fd7e409
feat: css 파일도 응답할 수 있도록 변경
zangsu Sep 5, 2024
62539e6
refactor: http 버전을 응답과 요청이 동일하도록 변경
zangsu Sep 5, 2024
04921cb
Merge branch 'woowacourse:main' into main
zangsu Sep 6, 2024
8b26c89
Merge branch 'main' into step1
zangsu Sep 6, 2024
49c4761
feat: templates 에서 정적파일을 읽어오기 위한 의존성 추가
zangsu Sep 6, 2024
3e389a4
feat: 휴리스틱 캐시 제거 인터셉터 추가
zangsu Sep 6, 2024
2932a9f
feat: Http 압축 설정 추가
zangsu Sep 6, 2024
1346792
feat: etag 경로에 ETag 캐싱 적용
zangsu Sep 6, 2024
17595c7
feat: 정적 파일에 버저닝, eTag 캐싱 추가
zangsu Sep 6, 2024
8895b00
feat: 파일 클래스 학습 테스트 수정
zangsu Sep 6, 2024
d7c55ed
Merge branch 'studyTest' into step1
zangsu Sep 6, 2024
2bdba9a
refactor: RequestHandler 인터페이스 생성
zangsu Sep 6, 2024
84882ed
refactor: 응답 생성 책임을 Response 객체로 분리
zangsu Sep 6, 2024
f4e8d60
refactor: Json 직렬화를 위한 의존성 추가
zangsu Sep 6, 2024
30bf463
refactor: api 요청을 처리할 수 있는 Handler 구현
zangsu Sep 6, 2024
f9e544e
refactor: api 요청을 객체로 구현
zangsu Sep 6, 2024
64559fa
refactor: 책임에 따라 클래스 분리
zangsu Sep 6, 2024
f1eb2bf
refactor: 사용처에 따라 네이밍 변경
zangsu 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
23 changes: 23 additions & 0 deletions .github/ISSUE_TEMPLATE/Feature Template
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
name: Feature Template
about: 기능 추가 이슈 템플릿
title: "[FEAT] "
labels: feature
assignees: ''

---

## 📌 어떤 기능인가요?
> 추가하려는 기능에 대해 간결하게 설명해주세요


## 📜 작업 상세 내용
- [ ] TODO
- [ ] TODO
- [ ] TODO

## ⏳ 예상 소요 시간
> 이슈를 완료하기까지 예상되는 소요 시간을 분 or 시간 or 일 단위로 작성해주세요.


## 🔍 참고할만한 자료(선택)
3 changes: 2 additions & 1 deletion study/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ 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'

implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'

testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.assertj:assertj-core:3.26.0'
testImplementation 'org.mockito:mockito-core:5.12.0'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package cache.com.example.cachecontrol;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class CacheControllerInterceptor implements HandlerInterceptor {
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView
) throws Exception {
if(!response.containsHeader("Cache-Control")) {
response.addHeader("Cache-Control", "no-cache, private");
}
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ public class CacheWebConfig implements WebMvcConfigurer {

@Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(new CacheControllerInterceptor());
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
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> filterFilterRegistrationBean =
new FilterRegistrationBean<>(new ShallowEtagHeaderFilter());
filterFilterRegistrationBean.addUrlPatterns("/etag", "/resources/*");
return filterFilterRegistrationBean;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
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 +23,7 @@ public CacheBustingWebConfig(ResourceVersion version) {
@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler(PREFIX_STATIC_RESOURCES + "/" + version.getVersion() + "/**")
.addResourceLocations("classpath:/static/");
.addResourceLocations("classpath:/static/")
.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
32 changes: 21 additions & 11 deletions study/src/test/java/study/FileTest.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
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.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

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

/**
* 웹서버는 사용자가 요청한 html 파일을 제공 할 수 있어야 한다.
Expand All @@ -18,36 +26,38 @@ class FileTest {

/**
* resource 디렉터리 경로 찾기
*
* <p>
* File 객체를 생성하려면 파일의 경로를 알아야 한다.
* 자바 애플리케이션은 resource 디렉터리에 HTML, CSS 같은 정적 파일을 저장한다.
* resource 디렉터리의 경로는 어떻게 알아낼 수 있을까?
*/
@Test
void resource_디렉터리에_있는_파일의_경로를_찾는다() {
//현재 프로젝트의 경로를 알아내는 방법은...? -> 해결
// 현재 위치하고 있는 곳 (test / main ) 을 알아내는 방법은?

final String fileName = "nextstep.txt";

// todo
final String actual = "";
final URL resoucrcesUrl = getClass().getClassLoader().getResource(fileName);
String actual = resoucrcesUrl.getFile();

assertThat(actual).endsWith(fileName);
}

/**
* 파일 내용 읽기
*
* <p>
* 읽어온 파일의 내용을 I/O Stream을 사용해서 사용자에게 전달 해야 한다.
* File, Files 클래스를 사용하여 파일의 내용을 읽어보자.
*/
@Test
void 파일의_내용을_읽는다() {
void 파일의_내용을_읽는다() throws IOException {
final String fileName = "nextstep.txt";

// todo
final Path path = null;

// todo
final List<String> actual = Collections.emptyList();
final URL resoucrcesUrl = getClass().getClassLoader().getResource(fileName);
final List<String> actual = Files.readAllLines(Paths.get(resoucrcesUrl.getPath()));

assertThat(actual).containsOnly("nextstep");
}
Expand Down
66 changes: 46 additions & 20 deletions study/src/test/java/study/IOStreamTest.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
package study;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.in;
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)은 하나의 시스템에서 다른 시스템으로 데이터를 이동 시킬 때 사용한다.
*
* <br>
* InputStream은 데이터를 읽고, OutputStream은 데이터를 쓴다.
* FilterStream은 InputStream이나 OutputStream에 연결될 수 있다.
* FilterStream은 읽거나 쓰는 데이터를 수정할 때 사용한다. (e.g. 암호화, 압축, 포맷 변환)
*
* <br>
* Stream은 데이터를 바이트로 읽고 쓴다.
* 바이트가 아닌 텍스트(문자)를 읽고 쓰려면 Reader와 Writer 클래스를 연결한다.
* Reader, Writer는 다양한 문자 인코딩(e.g. UTF-8)을 처리할 수 있다.
Expand All @@ -26,7 +38,7 @@ class IOStreamTest {

/**
* OutputStream 학습하기
*
* <p>
* 자바의 기본 출력 클래스는 java.io.OutputStream이다.
* OutputStream의 write(int b) 메서드는 기반 메서드이다.
* <code>public abstract void write(int b) throws IOException;</code>
Expand All @@ -39,7 +51,7 @@ class OutputStream_학습_테스트 {
* OutputStream의 서브 클래스(subclass)는 특정 매체에 데이터를 쓰기 위해 write(int b) 메서드를 사용한다.
* 예를 들어, FilterOutputStream은 파일로 데이터를 쓸 때,
* 또는 DataOutputStream은 자바의 primitive type data를 다른 매체로 데이터를 쓸 때 사용한다.
*
* <p>
* write 메서드는 데이터를 바이트로 출력하기 때문에 비효율적이다.
* <code>write(byte[] data)</code>와 <code>write(byte b[], int off, int len)</code> 메서드는
* 1바이트 이상을 한 번에 전송 할 수 있어 훨씬 효율적이다.
Expand All @@ -48,12 +60,11 @@ class OutputStream_학습_테스트 {
void OutputStream은_데이터를_바이트로_처리한다() throws IOException {
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");
Expand All @@ -62,8 +73,9 @@ class OutputStream_학습_테스트 {

/**
* 효율적인 전송을 위해 스트림에서 버퍼링을 사용 할 수 있다.
* BufferedOutputStream 필터를 연결하면 버퍼링이 가능하다.
*
* BufferedOutputStream 필터를 연결하면 버퍼링이 가능하다. \\n
* <p>
* <p>
* 버퍼링을 사용하면 OutputStream을 사용할 때 flush를 사용하자.
* flush() 메서드는 버퍼가 아직 가득 차지 않은 상황에서 강제로 버퍼의 내용을 전송한다.
* Stream은 동기(synchronous)로 동작하기 때문에 버퍼가 찰 때까지 기다리면
Expand All @@ -78,6 +90,7 @@ class OutputStream_학습_테스트 {
* flush를 사용해서 테스트를 통과시킨다.
* ByteArrayOutputStream과 어떤 차이가 있을까?
*/
outputStream.flush();

verify(outputStream, atLeastOnce()).flush();
outputStream.close();
Expand All @@ -96,19 +109,22 @@ class OutputStream_학습_테스트 {
* try-with-resources를 사용한다.
* java 9 이상에서는 변수를 try-with-resources로 처리할 수 있다.
*/
try (outputStream) {
}

verify(outputStream, atLeastOnce()).close();
}
}

/**
* InputStream 학습하기
*
* <br>
* 자바의 기본 입력 클래스는 java.io.InputStream이다.
* InputStream은 다른 매체로부터 바이트로 데이터를 읽을 때 사용한다.
* InputStream의 read() 메서드는 기반 메서드이다.
* <code>public abstract int read() throws IOException;</code>
*
*
* <br>
* InputStream의 서브 클래스(subclass)는 특정 매체에 데이터를 읽기 위해 read() 메서드를 사용한다.
*/
@Nested
Expand All @@ -128,7 +144,9 @@ class InputStream_학습_테스트 {
* todo
* inputStream에서 바이트로 반환한 값을 문자열로 어떻게 바꿀까?
*/
final String actual = "";
final OutputStream outputStream = new ByteArrayOutputStream(bytes.length);
inputStream.transferTo(outputStream);
final String actual = outputStream.toString();

assertThat(actual).isEqualTo("🤩");
assertThat(inputStream.read()).isEqualTo(-1);
Expand All @@ -148,14 +166,17 @@ class InputStream_학습_테스트 {
* try-with-resources를 사용한다.
* java 9 이상에서는 변수를 try-with-resources로 처리할 수 있다.
*/
try (inputStream) {

}

verify(inputStream, atLeastOnce()).close();
}
}

/**
* FilterStream 학습하기
*
* <p>
* 필터는 필터 스트림, reader, writer로 나뉜다.
* 필터는 바이트를 다른 데이터 형식으로 변환 할 때 사용한다.
* reader, writer는 UTF-8, ISO 8859-1 같은 형식으로 인코딩된 텍스트를 처리하는 데 사용된다.
Expand All @@ -169,12 +190,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 Down Expand Up @@ -204,9 +225,14 @@ class InputStreamReader_학습_테스트 {
"😋😛😝😜🤪🤨🧐🤓😎🥸🤩",
"");
final InputStream inputStream = new ByteArrayInputStream(emoji.getBytes());
final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

final StringBuilder actual = new StringBuilder();

bufferedReader.lines()
.forEach(line -> actual.append(line).append("\r\n"));

assertThat(actual).hasToString(emoji);
}
}
Expand Down
3 changes: 3 additions & 0 deletions tomcat/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ dependencies {
implementation 'ch.qos.logback:logback-classic:1.5.7'
implementation 'org.apache.commons:commons-lang3:3.14.0'

//objectMapper
implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.3'

testImplementation 'org.assertj:assertj-core:3.26.0'
testImplementation 'org.mockito:mockito-core:5.12.0'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2'
Expand Down
2 changes: 1 addition & 1 deletion tomcat/src/main/java/com/techcourse/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
public class Application {

public static void main(String[] args) {
final var tomcat = new Tomcat();
var tomcat = new Tomcat();
tomcat.start();
}
}
Loading