-
Notifications
You must be signed in to change notification settings - Fork 2
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
feat: 공지 CRUD API 구현 #323
feat: 공지 CRUD API 구현 #323
Changes from 1 commit
4e3af74
8d5ece2
4c39059
58e606e
d59695a
3de2eed
2063ce6
1c6b03e
8989a84
6a7d204
dffe121
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 |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.listywave.notice.application.converter; | ||
|
||
|
||
import com.listywave.notice.application.domain.ContentType; | ||
import jakarta.persistence.AttributeConverter; | ||
import jakarta.persistence.Converter; | ||
|
||
@Converter(autoApply = true) | ||
public class ContentTypeConverter implements AttributeConverter<ContentType, String> { | ||
|
||
@Override | ||
public String convertToDatabaseColumn(ContentType contentType) { | ||
return contentType.name().toLowerCase(); | ||
} | ||
|
||
@Override | ||
public ContentType convertToEntityAttribute(String s) { | ||
return ContentType.valueOf(s.toUpperCase()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package com.listywave.notice.application.domain; | ||
|
||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@Getter | ||
@RequiredArgsConstructor | ||
public enum ContentType { | ||
|
||
SUBTITLE, | ||
BODY, | ||
IMAGE, | ||
BUTTON, | ||
LINE, | ||
NOTE, | ||
; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package com.listywave.notice.application.domain; | ||
|
||
import static jakarta.persistence.CascadeType.ALL; | ||
import static jakarta.persistence.FetchType.LAZY; | ||
import static lombok.AccessLevel.PROTECTED; | ||
|
||
import com.listywave.common.BaseEntity; | ||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Embedded; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.OneToMany; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Entity | ||
@Getter | ||
@NoArgsConstructor(access = PROTECTED) | ||
public class Notice extends BaseEntity { | ||
|
||
@Column(name = "code", nullable = false) | ||
private NoticeType type; | ||
|
||
@Embedded | ||
private NoticeTitle title; | ||
|
||
@Embedded | ||
private NoticeDescription description; | ||
|
||
@OneToMany(mappedBy = "notice", fetch = LAZY, cascade = ALL, orphanRemoval = true) | ||
private final List<NoticeContent> contents = new ArrayList<>(); | ||
|
||
public Notice(NoticeType type, NoticeTitle title, NoticeDescription description) { | ||
this.type = type; | ||
this.title = title; | ||
this.description = description; | ||
} | ||
|
||
public void addContents(List<NoticeContent> contents) { | ||
this.contents.addAll(contents); | ||
} | ||
Comment on lines
+46
to
+48
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. 아직도 햇갈리는거 contents에 데잍터 바인딩 시켰으면 NoticeContent에서도 Notice 양방향으로 채워줘야하는 거 아니였어요? 이게 아직도 햇갈리네 ㅠ 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. 연관관계의 주인이 NoticeContent이니까 NoticeContent에도 Notice를 참조하도록 하는 게 맞습니다!
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에서 해주는군요 ㅎㅎ 확인했슴다! |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package com.listywave.notice.application.domain; | ||
|
||
import static jakarta.persistence.GenerationType.IDENTITY; | ||
import static lombok.AccessLevel.PRIVATE; | ||
import static lombok.AccessLevel.PROTECTED; | ||
|
||
import jakarta.annotation.Nullable; | ||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.Id; | ||
import jakarta.persistence.JoinColumn; | ||
import jakarta.persistence.ManyToOne; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Entity | ||
@Getter | ||
@AllArgsConstructor(access = PRIVATE) | ||
@NoArgsConstructor(access = PROTECTED) | ||
public class NoticeContent { | ||
|
||
@Id | ||
@GeneratedValue(strategy = IDENTITY) | ||
private Long id; | ||
|
||
@ManyToOne | ||
@JoinColumn(name = "notice_id", nullable = false) | ||
private Notice notice; | ||
|
||
@Column(name = "orders", nullable = false) | ||
private int order; | ||
|
||
@Column(nullable = false, length = 30) | ||
private ContentType type; | ||
|
||
@Column(nullable = true, length = 1000) | ||
private String description; | ||
|
||
@Column(nullable = true, length = 2048) | ||
private String imageUrl; | ||
|
||
@Column(nullable = true, length = 50) | ||
private String buttonName; | ||
|
||
@Column(nullable = true, length = 2048) | ||
private String buttonLink; | ||
|
||
public static NoticeContent create( | ||
Notice notice, | ||
int order, | ||
ContentType type, | ||
@Nullable String description, | ||
@Nullable String imageUrl, | ||
@Nullable String buttonName, | ||
@Nullable String buttonLink | ||
) { | ||
return new NoticeContent(null, notice, order, type, description, imageUrl, buttonName, buttonLink); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package com.listywave.notice.application.domain; | ||
|
||
import static com.listywave.common.exception.ErrorCode.LENGTH_EXCEEDED_EXCEPTION; | ||
import static com.listywave.common.exception.ErrorCode.NULL_OR_BLANK_EXCEPTION; | ||
import static lombok.AccessLevel.PROTECTED; | ||
|
||
import com.listywave.common.exception.CustomException; | ||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Embeddable; | ||
import lombok.EqualsAndHashCode; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@Embeddable | ||
@EqualsAndHashCode | ||
@NoArgsConstructor(access = PROTECTED, force = true) | ||
public class NoticeDescription { | ||
|
||
private static final int MAX_LENGTH = 30; | ||
|
||
@Column(name = "description", nullable = false, length = MAX_LENGTH) | ||
private final String value; | ||
|
||
public NoticeDescription(String value) { | ||
validate(value); | ||
this.value = value; | ||
} | ||
|
||
private void validate(String value) { | ||
if (value == null || value.isBlank()) { | ||
throw new CustomException(NULL_OR_BLANK_EXCEPTION, NULL_OR_BLANK_EXCEPTION.getDetail() + " 입력값: " + value); | ||
} | ||
if (value.length() > MAX_LENGTH) { | ||
throw new CustomException(LENGTH_EXCEEDED_EXCEPTION, LENGTH_EXCEEDED_EXCEPTION.getDetail() + " 입력값의 길이: " + value.length()); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package com.listywave.notice.application.domain; | ||
|
||
import static com.listywave.common.exception.ErrorCode.LENGTH_EXCEEDED_EXCEPTION; | ||
import static com.listywave.common.exception.ErrorCode.NULL_OR_BLANK_EXCEPTION; | ||
import static lombok.AccessLevel.PROTECTED; | ||
|
||
import com.listywave.common.exception.CustomException; | ||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Embeddable; | ||
import lombok.EqualsAndHashCode; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@Embeddable | ||
@EqualsAndHashCode | ||
@NoArgsConstructor(access = PROTECTED, force = true) | ||
public class NoticeTitle { | ||
|
||
private static final int MAX_LENGTH = 30; | ||
|
||
@Column(name = "title", nullable = false, length = MAX_LENGTH) | ||
private final String value; | ||
|
||
public NoticeTitle(String value) { | ||
validate(value); | ||
this.value = value; | ||
} | ||
|
||
private void validate(String value) { | ||
if (value == null || value.isBlank()) { | ||
throw new CustomException(NULL_OR_BLANK_EXCEPTION, NULL_OR_BLANK_EXCEPTION.getDetail() + " 입력값: " + value); | ||
} | ||
if (value.length() > MAX_LENGTH) { | ||
throw new CustomException(LENGTH_EXCEEDED_EXCEPTION, LENGTH_EXCEEDED_EXCEPTION.getDetail() + " 입력값의 길이: " + value.length()); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package com.listywave.notice.application.domain; | ||
|
||
import static com.listywave.common.exception.ErrorCode.LENGTH_EXCEEDED_EXCEPTION; | ||
import static com.listywave.common.exception.ErrorCode.NULL_OR_BLANK_EXCEPTION; | ||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.assertj.core.api.Assertions.assertThatNoException; | ||
import static org.junit.jupiter.api.Assertions.assertThrows; | ||
|
||
import com.listywave.common.exception.CustomException; | ||
import com.listywave.common.exception.ErrorCode; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.IntStream; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.params.ParameterizedTest; | ||
import org.junit.jupiter.params.provider.NullAndEmptySource; | ||
|
||
class NoticeDescriptionTest { | ||
|
||
@Test | ||
void 공지_제목의_최대_길이를_넘으면_예외를_발생한다() { | ||
// given | ||
String value = IntStream.range(0, 30) | ||
.mapToObj(String::valueOf) | ||
.collect(Collectors.joining("")); | ||
|
||
// when | ||
ErrorCode result = assertThrows(CustomException.class, () -> new NoticeDescription(value)) | ||
.getErrorCode(); | ||
|
||
// then | ||
assertThat(result).isEqualTo(LENGTH_EXCEEDED_EXCEPTION); | ||
} | ||
|
||
@ParameterizedTest | ||
@NullAndEmptySource | ||
void 값이_null이거나_빈_값이면_예외를_발생한다(String value) { | ||
// when | ||
ErrorCode result = assertThrows(CustomException.class, () -> new NoticeDescription(value)) | ||
.getErrorCode(); | ||
|
||
// then | ||
assertThat(result).isEqualTo(NULL_OR_BLANK_EXCEPTION); | ||
} | ||
|
||
@Test | ||
void 공지_제목을_정상적으로_생성한다() { | ||
// given | ||
String value = "12345678911234567891123456789"; | ||
|
||
// expect | ||
assertThatNoException().isThrownBy(() -> new NoticeDescription(value)); | ||
} | ||
|
||
@Test | ||
void 값이_같으면_같은_객체다() { | ||
// given | ||
NoticeDescription title1 = new NoticeDescription("123456789"); | ||
NoticeDescription title2 = new NoticeDescription("123456789"); | ||
|
||
// expect | ||
assertThat(title1).isEqualTo(title2); | ||
assertThat(title1).hasSameHashCodeAs(title2); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package com.listywave.notice.application.domain; | ||
|
||
import static com.listywave.common.exception.ErrorCode.LENGTH_EXCEEDED_EXCEPTION; | ||
import static com.listywave.common.exception.ErrorCode.NULL_OR_BLANK_EXCEPTION; | ||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.assertj.core.api.Assertions.assertThatNoException; | ||
import static org.junit.jupiter.api.Assertions.assertThrows; | ||
|
||
import com.listywave.common.exception.CustomException; | ||
import com.listywave.common.exception.ErrorCode; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.IntStream; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.params.ParameterizedTest; | ||
import org.junit.jupiter.params.provider.NullAndEmptySource; | ||
|
||
class NoticeTitleTest { | ||
|
||
@Test | ||
void 공지_제목의_최대_길이를_넘으면_예외를_발생한다() { | ||
// given | ||
String value = IntStream.range(0, 30) | ||
.mapToObj(String::valueOf) | ||
.collect(Collectors.joining("")); | ||
|
||
// when | ||
ErrorCode result = assertThrows(CustomException.class, () -> new NoticeTitle(value)) | ||
.getErrorCode(); | ||
|
||
// then | ||
assertThat(result).isEqualTo(LENGTH_EXCEEDED_EXCEPTION); | ||
} | ||
|
||
@ParameterizedTest | ||
@NullAndEmptySource | ||
void 값이_null이거나_빈_값이면_예외를_발생한다(String value) { | ||
// when | ||
ErrorCode result = assertThrows(CustomException.class, () -> new NoticeTitle(value)) | ||
.getErrorCode(); | ||
|
||
// then | ||
assertThat(result).isEqualTo(NULL_OR_BLANK_EXCEPTION); | ||
} | ||
|
||
@Test | ||
void 공지_제목을_정상적으로_생성한다() { | ||
// given | ||
String value = "12345678911234567891123456789"; | ||
|
||
// expect | ||
assertThatNoException().isThrownBy(() -> new NoticeTitle(value)); | ||
} | ||
|
||
@Test | ||
void 값이_같으면_같은_객체다() { | ||
// given | ||
NoticeTitle title1 = new NoticeTitle("123456789"); | ||
NoticeTitle title2 = new NoticeTitle("123456789"); | ||
|
||
// expect | ||
assertThat(title1).isEqualTo(title2); | ||
assertThat(title1).hasSameHashCodeAs(title2); | ||
} | ||
} |
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.
개행 제거!
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.
원래 package 아래는 개행 한 줄이 들어갑니다 😃 (출처)