Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
32f26c2
fix: remove implementation logback-classic on gradle (#501)
geoje Sep 5, 2024
4fe78cc
fix: add threads min-spare configuration on properties (#502)
geoje Sep 5, 2024
aa8696a
전체 코드 롤백
pricelees Sep 11, 2024
a726a3c
test: http 캐시 테스트
pricelees Sep 11, 2024
2537d06
feat: index.html 응답 및 css 지원 기능 구현
pricelees Sep 11, 2024
a714e5a
feat: favicon 파일 추가
pricelees Sep 11, 2024
27c9983
feat: HTTP 요청 메시지를 담는 객체 구현
pricelees Sep 12, 2024
6afa63f
feat: HTTP 요청 메시지를 읽는 객체 구현
pricelees Sep 12, 2024
7a29f8a
feat: HTTP 응답 메시지를 만들 때 사용하는 객체 구현
pricelees Sep 12, 2024
d86ba66
remove: 미사용 클래스 삭제
pricelees Sep 12, 2024
2e2f23a
fix: 쿼리에서 값을 조회하지 못하는 문제 해결
pricelees Sep 12, 2024
d3af719
feat: 정적 리소스 파일을 불러오는 기능 및 테스트 구현
pricelees Sep 12, 2024
cc45a5e
feat: / 경로에 대한 요청을 처리하는 기능 및 테스트 구현
pricelees Sep 12, 2024
8b01768
feat: 정적 리소스 요청을 처리하는 기능 및 테스트 구현
pricelees Sep 12, 2024
6618122
feat: /login 경로에 대한 요청을 처리하는 기능 및 테스트 구현
pricelees Sep 12, 2024
a66d132
feat: 요청에 대해 적절한 핸들러를 찾는 기능 구현
pricelees Sep 12, 2024
048c263
refactor: 구현된 기능을 Http11Processor 에 반영
pricelees Sep 12, 2024
a429369
refactor: 응답 메시지를 만들 때 body가 없는 경우에 대한 처리 추가
pricelees Sep 12, 2024
433d41d
feat: 로그인 302 응답 기능 구현
pricelees Sep 12, 2024
7781280
refactor: http 요청 body를 읽을 때 content-length 헤더를 사용하도록 수정
pricelees Sep 12, 2024
f034f40
feat: 로그인 기능 구현
pricelees Sep 12, 2024
5925543
feat: Form 요청 body를 처리하는 기능 및 테스트 구현
pricelees Sep 12, 2024
15adb68
feat: 회원을 저장할 때 중복 account에 대한 검증 및 테스트 구현
pricelees Sep 12, 2024
9fdcccd
feat: 회원가입 기능 및 테스트 구현
pricelees Sep 12, 2024
b712e75
feat: 로그인 성공시 쿠키 설정 기능 및 테스트 구현
pricelees Sep 12, 2024
d8c737d
feat: 세션을 이용한 로그인 기능 구현
pricelees Sep 12, 2024
a44e28e
style: reformat code
pricelees Sep 12, 2024
ff51208
style: 테스트 메서드명 수정
pricelees Sep 12, 2024
202f711
refactor: 로그인 시 POST 요청을 보내도록 수정
pricelees Sep 12, 2024
38833b5
fix: 세션이 없을 때 페이지 로딩이 안되는 문제 해결
pricelees Sep 12, 2024
3c59f40
refactor: 공통 헤더 상수화
pricelees Sep 12, 2024
a1f6854
refactor: Handler가 존재하지 않으면 404 페이지를 반환하도록 수정
pricelees Sep 12, 2024
068883a
refactor: 로그인 페이지에서 User를 중복으로 조회하는 로직 수정
pricelees Sep 12, 2024
de48f3f
refactor: 헤더 상수를 public으로 수정 및 RequestMessageReader에 반영
pricelees Sep 12, 2024
8372959
refactor: JSessionId 존재 유무 확인 로직 수정
pricelees Sep 12, 2024
f056c5f
refactor: 요청 헤더에서의 타입 수정
pricelees Sep 12, 2024
6f3f4b7
refactor: HttpResponse 생성자 접근 제어자 수정(public -> private)
pricelees Sep 12, 2024
09e13b4
refactor: 테스트에서의 제네릭 타입 제거
pricelees Sep 12, 2024
b8c5de7
refactor: 테스트에서의 타입 체크 방법 수정(isInstanceof -> isExactlyInstanceOf)
pricelees Sep 12, 2024
a27514d
refactor: 미사용 html 파일 제거
pricelees Sep 12, 2024
329bb3c
refactor: sessionId를 로그인시 항상 갱신하도록 수정
pricelees Sep 12, 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
3 changes: 2 additions & 1 deletion study/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ 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'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,38 @@
package cache.com.example.cachecontrol;

import java.time.Duration;

import org.springframework.context.annotation.Configuration;
import org.springframework.http.CacheControl;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.mvc.WebContentInterceptor;

@Configuration
public class CacheWebConfig implements WebMvcConfigurer {

@Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(getNoCacheInterceptor());
registry.addInterceptor(getResourceCacheInterceptor());
}

// add no-cache, private cache
private WebContentInterceptor getNoCacheInterceptor() {
CacheControl cacheControl = CacheControl.noCache().cachePrivate();

return createWebContentInterceptorByCache(cacheControl, "/");
Copy link
Member

Choose a reason for hiding this comment

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

루트 경로에만 적용되지 않을까요?

Copy link
Author

Choose a reason for hiding this comment

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

루트 경로에만 적용되지 않을까요?

학습 테스트의 testNoCachePrivate()가 휴리스틱 캐싱을 적용해보는 것이 의도라고 생각해서 정해진 경로만 지정하였습니다 😄

}

private WebContentInterceptor getResourceCacheInterceptor() {
CacheControl cacheControl = CacheControl.maxAge(Duration.ofDays(365)).cachePublic();

return createWebContentInterceptorByCache(cacheControl, "/resources/**");
}

private WebContentInterceptor createWebContentInterceptorByCache(CacheControl cacheControl, String path) {
WebContentInterceptor webContentInterceptor = new WebContentInterceptor();
webContentInterceptor.addCacheMapping(cacheControl, path);
return webContentInterceptor;
}
}
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> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new ShallowEtagHeaderFilter());
registrationBean.addUrlPatterns("/etag", "/resources/*");
return registrationBean;
}
}
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
8 changes: 4 additions & 4 deletions tomcat/src/main/java/com/techcourse/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

public class Application {

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

Choose a reason for hiding this comment

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

탭사이즈 몇으로 사용하고 계신가요??

Copy link
Author

Choose a reason for hiding this comment

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

탭사이즈 몇으로 사용하고 계신가요??

4로 사용하고 있습니다 ㅎㅎ 탭사이즈에 제약이 있었나용?

Copy link
Member

Choose a reason for hiding this comment

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

제약은 없는걸로 아는데 원래 있던 코드의 탭 사이즈가 달라져서 여쭤봤어요!

Copy link
Author

Choose a reason for hiding this comment

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

제약은 없는걸로 아는데 원래 있던 코드의 탭 사이즈가 달라져서 여쭤봤어요!

인텔리제이 포맷 파일을 https://naver.github.io/hackday-conventions-java/ 를 쓰고있어요😄

final var tomcat = new Tomcat();
tomcat.start();
}
}
46 changes: 29 additions & 17 deletions tomcat/src/main/java/com/techcourse/db/InMemoryUserRepository.java
Original file line number Diff line number Diff line change
@@ -1,27 +1,39 @@
package com.techcourse.db;

import com.techcourse.model.User;

import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

public class InMemoryUserRepository {

private static final Map<String, User> database = new ConcurrentHashMap<>();
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

public static void save(User user) {
database.put(user.getAccount(), user);
}
import com.techcourse.model.User;

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

private InMemoryUserRepository() {}
private static final Logger log = LoggerFactory.getLogger(InMemoryUserRepository.class);
private static final Map<String, User> database = new ConcurrentHashMap<>();

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

public static void save(User user) {
if (database.containsKey(user.getAccount())) {
throw new IllegalArgumentException("account is already exist");
}
database.put(user.getAccount(), user);
}

public static Optional<User> findByAccount(String account) {
if (account == null) {
log.info("account not exist");
return Optional.empty();
}
return Optional.ofNullable(database.get(account));
}

private InMemoryUserRepository() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

public class UncheckedServletException extends RuntimeException {

public UncheckedServletException(Exception e) {
super(e);
}
public UncheckedServletException(Exception e) {
super(e);
}
}
87 changes: 54 additions & 33 deletions tomcat/src/main/java/com/techcourse/model/User.java
Original file line number Diff line number Diff line change
@@ -1,38 +1,59 @@
package com.techcourse.model;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class User {

private final Long id;
private final String account;
private final String password;
private final String email;

public User(Long id, String account, String password, String email) {
this.id = id;
this.account = account;
this.password = password;
this.email = email;
}

public User(String account, String password, String email) {
this(null, account, password, email);
}

public boolean checkPassword(String password) {
return this.password.equals(password);
}

public String getAccount() {
return account;
}

@Override
public String toString() {
return "User{" +
"id=" + id +
", account='" + account + '\'' +
", email='" + email + '\'' +
", password='" + password + '\'' +
'}';
}
private static final Logger log = LoggerFactory.getLogger(User.class);
private final Long id;
private final String account;
private final String password;
private final String email;

public User(Long id, String account, String password, String email) {
validateIsNotEmptyValue(account, password, email);
this.id = id;
this.account = account;
this.password = password;
this.email = email;
}

private void validateIsNotEmptyValue(String account, String password, String email) {
if (account == null || account.isBlank()) {
Copy link
Member

Choose a reason for hiding this comment

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

user 검증 추가 좋네요 👍🏻

Copy link
Author

Choose a reason for hiding this comment

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

user 검증 추가 좋네요 👍🏻

감사링 ㅎㅎ

throw new IllegalArgumentException("Account is empty");
}
if (password == null || password.isBlank()) {
throw new IllegalArgumentException("Password is empty");
}
if (email == null || email.isBlank()) {
throw new IllegalArgumentException("Email is empty");
}
}

public User(String account, String password, String email) {
this(null, account, password, email);
}

public boolean checkPassword(String password) {
if (password == null) {
log.info("password not exist");
return false;
}
return this.password.equals(password);
}

public String getAccount() {
return account;
}

@Override
public String toString() {
return "User{" +
"id=" + id +
", account='" + account + '\'' +
", email='" + email + '\'' +
", password='" + password + '\'' +
'}';
}
}
Loading