-
Notifications
You must be signed in to change notification settings - Fork 7
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
날짜 / 시간 및 기타 코드 컨벤션 통일 #78
Changes from all commits
d499e8f
ee33702
6f9192e
31b0447
2a5587a
7007393
9102746
a50b08f
898a780
23ff318
c52c39b
10b4f6e
1d99f69
237f9d6
aa54ad6
3d6a9d6
db12372
31a432c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,5 +6,6 @@ | |
@Getter | ||
@AllArgsConstructor | ||
public class RestResponse<T> { | ||
|
||
private T data; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package mouda.backend.config; | ||
|
||
import java.time.LocalDate; | ||
import java.time.LocalTime; | ||
import java.time.format.DateTimeFormatter; | ||
|
||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; | ||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; | ||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; | ||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; | ||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; | ||
|
||
@Configuration | ||
public class JacksonConfig { | ||
|
||
@Bean | ||
public JavaTimeModule javaTimeModule() { | ||
JavaTimeModule javaTimeModule = new JavaTimeModule(); | ||
DateTimeFormatter dateFormat = DateTimeFormatter.ISO_LOCAL_DATE; | ||
DateTimeFormatter timeFormat = DateTimeFormatter.ofPattern("HH:mm"); | ||
|
||
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(dateFormat)) | ||
.addSerializer(LocalTime.class, new LocalTimeSerializer(timeFormat)) | ||
.addDeserializer(LocalDate.class, new LocalDateDeserializer(dateFormat)) | ||
.addDeserializer(LocalTime.class, new LocalTimeDeserializer(timeFormat)); | ||
|
||
return javaTimeModule; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,7 +8,7 @@ | |
|
||
@Builder | ||
public record MoimFindAllResponse( | ||
long moimId, | ||
Long moimId, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 요청 DTO에는 null 처리를 위해서 래퍼 타입을 사용하는 것은 맞지만 응답 DTO에서는 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
(지극히 개인적인 관점) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 음음 좋은 의견이에요! 성능 이슈는 아마 발생하지 않을 것 같고, 래퍼 타입 사용에 대한 일관성이
|
||
String title, | ||
LocalDate date, | ||
LocalTime time, | ||
|
@@ -18,6 +18,7 @@ public record MoimFindAllResponse( | |
String authorNickname, | ||
String description | ||
) { | ||
|
||
public static MoimFindAllResponse toResponse(Moim moim) { | ||
return MoimFindAllResponse.builder() | ||
.moimId(moim.getId()) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
package mouda.backend.config; | ||
|
||
import static org.hamcrest.Matchers.*; | ||
|
||
import java.time.LocalDate; | ||
import java.time.LocalTime; | ||
import java.util.Map; | ||
|
||
import org.junit.jupiter.api.AfterEach; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Nested; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.boot.test.web.server.LocalServerPort; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.MediaType; | ||
|
||
import io.restassured.RestAssured; | ||
import mouda.backend.moim.domain.Moim; | ||
import mouda.backend.moim.repository.MoimRepository; | ||
|
||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) | ||
class JacksonConfigTest { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 테스트가 꼼꼼해서 행복하네요 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 상돌 폼 미쳤다 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 상돌 미쳤다 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 도레미~ |
||
|
||
@Autowired | ||
private MoimRepository moimRepository; | ||
|
||
@Autowired | ||
private DatabaseCleaner databaseCleaner; | ||
|
||
@LocalServerPort | ||
private int port; | ||
|
||
@BeforeEach | ||
void setUp() { | ||
RestAssured.port = port; | ||
} | ||
|
||
@AfterEach | ||
void tearDown() { | ||
databaseCleaner.cleanUp(); | ||
} | ||
|
||
@DisplayName("날짜 형식에 따른 직렬화 및 역직렬화 테스트") | ||
@Nested | ||
class DateFormatTest { | ||
|
||
@DisplayName("yyyy-MM-dd 형식의 날짜를 역직렬화한다.") | ||
@Test | ||
void deserialize() { | ||
Map<String, Object> params = Map.of( | ||
"title", "title", | ||
"date", "2024-07-19", | ||
"time", "12:30", | ||
"place", "place", | ||
"maxPeople", 10, | ||
"authorNickname", "안나", | ||
"description", "설명" | ||
); | ||
|
||
RestAssured.given() | ||
.contentType(MediaType.APPLICATION_JSON_VALUE) | ||
.body(params) | ||
.when().post("/v1/moim") | ||
.then().statusCode(is(HttpStatus.OK.value())); | ||
} | ||
|
||
@DisplayName("yyyy-MM-dd 형식이 아닌 날짜가 입력되면 예외가 발생한다.") | ||
@Test | ||
void deserialize_when_invalidDateFormat() { | ||
Map<String, Object> params = Map.of( | ||
"title", "title", | ||
"date", "2024/07/19", | ||
"time", "12:30", | ||
"place", "place", | ||
"maxPeople", 10, | ||
"authorNickname", "안나", | ||
"description", "설명" | ||
); | ||
|
||
RestAssured.given() | ||
.contentType(MediaType.APPLICATION_JSON_VALUE) | ||
.body(params) | ||
.when().post("/v1/moim") | ||
.then().statusCode(is(HttpStatus.BAD_REQUEST.value())); | ||
} | ||
|
||
@DisplayName("날짜는 yyyy-MM-dd 형식으로 직렬화된다.") | ||
@Test | ||
void serialize() { | ||
Moim moim = Moim.builder() | ||
.title("title") | ||
.date(LocalDate.parse("2024-07-19")) | ||
.time(LocalTime.parse("12:30")) | ||
.place("place") | ||
.maxPeople(10) | ||
.authorNickname("안나") | ||
.description("설명") | ||
.build(); | ||
|
||
Moim saved = moimRepository.save(moim); | ||
|
||
RestAssured.given() | ||
.when().get("/v1/moim/" + saved.getId()) | ||
.then().statusCode(is(HttpStatus.OK.value())) | ||
.body("data.date", is("2024-07-19")); | ||
} | ||
} | ||
|
||
@DisplayName("시간 형식에 따른 직렬화 및 역직렬화 테스트") | ||
@Nested | ||
class TimeFormatTest { | ||
|
||
@DisplayName("HH:mm 형식의 시간을 역직렬화한다.") | ||
@Test | ||
void deserialize() { | ||
Map<String, Object> params = Map.of( | ||
"title", "title", | ||
"date", "2024-07-19", | ||
"time", "12:30", | ||
"place", "place", | ||
"maxPeople", 10, | ||
"authorNickname", "안나", | ||
"description", "설명" | ||
); | ||
|
||
RestAssured.given() | ||
.contentType(MediaType.APPLICATION_JSON_VALUE) | ||
.body(params) | ||
.when().post("/v1/moim") | ||
.then().statusCode(is(HttpStatus.OK.value())); | ||
} | ||
|
||
@DisplayName("HH:mm 형식이 아닌 시간이 입력되면 예외가 발생한다.") | ||
@Test | ||
void deserialize_when_invalidTimeFormat() { | ||
Map<String, Object> params = Map.of( | ||
"title", "title", | ||
"date", "2024-07-19", | ||
"time", "12-30", | ||
"place", "place", | ||
"maxPeople", 10, | ||
"authorNickname", "안나", | ||
"description", "설명" | ||
); | ||
|
||
RestAssured.given() | ||
.contentType(MediaType.APPLICATION_JSON_VALUE) | ||
.body(params) | ||
.when().post("/v1/moim") | ||
.then().statusCode(is(HttpStatus.BAD_REQUEST.value())); | ||
} | ||
|
||
@DisplayName("시간은 HH:mm 형식으로 직렬화된다.") | ||
@Test | ||
void serialize() { | ||
Moim moim = Moim.builder() | ||
.title("title") | ||
.date(LocalDate.now().plusDays(1)) | ||
.time(LocalTime.parse("12:30")) | ||
.place("place") | ||
.maxPeople(10) | ||
.authorNickname("안나") | ||
.description("설명") | ||
.build(); | ||
Moim saved = moimRepository.save(moim); | ||
|
||
RestAssured.given() | ||
.when().get("/v1/moim/" + saved.getId()) | ||
.then().statusCode(is(HttpStatus.OK.value())) | ||
.body("data.time", is("12:30")); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[질문] 프론트엔드 측에서
maxPeople
값을 입력해주지 않으면 이 부분이 NULL로 들어오게 되는건가요?[의견] 추후에 Bean Validation 과 LocalTime, LocalDate 포맷팅 에러를 핸들링하는 것도 필요하겠네요 !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 부분은 어떻게 처리하는지에 따라 달라져요. 기본적으로는 Json에 maxPeople 필드가 없거나 빈 문자열이 들어오면 NULL이 입력되고, 숫자 이외의 값이 입력되면
HttpMessageNotReadableException
이 발생합니다😀조아요!👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오호 그렇군요 굿굿 👍
나중에 숫자 이외의 입력에 대해서도 에러 핸들링을 할 필요가 있겠네요.