diff --git a/src/main/java/com/example/solidconnection/application/controller/ApplicationController.java b/src/main/java/com/example/solidconnection/application/controller/ApplicationController.java index 8baf7255f..6242180aa 100644 --- a/src/main/java/com/example/solidconnection/application/controller/ApplicationController.java +++ b/src/main/java/com/example/solidconnection/application/controller/ApplicationController.java @@ -1,6 +1,8 @@ package com.example.solidconnection.application.controller; -import com.example.solidconnection.application.dto.*; +import com.example.solidconnection.application.dto.ApplicationSubmissionResponse; +import com.example.solidconnection.application.dto.ApplicationsResponse; +import com.example.solidconnection.application.dto.ApplyRequest; import com.example.solidconnection.application.service.ApplicationQueryService; import com.example.solidconnection.application.service.ApplicationSubmissionService; import jakarta.validation.Valid; diff --git a/src/main/java/com/example/solidconnection/application/domain/Application.java b/src/main/java/com/example/solidconnection/application/domain/Application.java index 0c56fd7f5..7faf77e6e 100644 --- a/src/main/java/com/example/solidconnection/application/domain/Application.java +++ b/src/main/java/com/example/solidconnection/application/domain/Application.java @@ -3,7 +3,16 @@ import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.type.VerifyStatus; import com.example.solidconnection.university.domain.UniversityInfoForApply; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; diff --git a/src/main/java/com/example/solidconnection/application/dto/ApplicantResponse.java b/src/main/java/com/example/solidconnection/application/dto/ApplicantResponse.java index d03f1c9a3..b6b5ee477 100644 --- a/src/main/java/com/example/solidconnection/application/dto/ApplicantResponse.java +++ b/src/main/java/com/example/solidconnection/application/dto/ApplicantResponse.java @@ -2,12 +2,10 @@ import com.example.solidconnection.application.domain.Application; import com.example.solidconnection.type.LanguageTestType; - import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "지원자") public record ApplicantResponse( - @Schema(description = "닉네임", example = "행복한 개발자") String nicknameForApply, diff --git a/src/main/java/com/example/solidconnection/application/dto/ApplicationSubmissionResponse.java b/src/main/java/com/example/solidconnection/application/dto/ApplicationSubmissionResponse.java index 279f2b150..fe112a8d0 100644 --- a/src/main/java/com/example/solidconnection/application/dto/ApplicationSubmissionResponse.java +++ b/src/main/java/com/example/solidconnection/application/dto/ApplicationSubmissionResponse.java @@ -4,7 +4,6 @@ @Schema(description = "지원 정보 제출 성공 여부") public record ApplicationSubmissionResponse( - @Schema(description = "제출 성공 여부", example = "true") boolean isSuccess) { } diff --git a/src/main/java/com/example/solidconnection/application/dto/ApplicationsResponse.java b/src/main/java/com/example/solidconnection/application/dto/ApplicationsResponse.java index 2e3025137..3d5e2ca88 100644 --- a/src/main/java/com/example/solidconnection/application/dto/ApplicationsResponse.java +++ b/src/main/java/com/example/solidconnection/application/dto/ApplicationsResponse.java @@ -5,9 +5,8 @@ import java.util.List; -@Schema(description = "1지망과 2지망 대학과 그 대학에 지원한 지원자 정보") +@Schema(description = "지망별 지원자 목록") public record ApplicationsResponse( - @ArraySchema(arraySchema = @Schema(description = "1지망 대학에 지원한 지원자 목록")) List firstChoice, diff --git a/src/main/java/com/example/solidconnection/application/dto/ScoreRequest.java b/src/main/java/com/example/solidconnection/application/dto/ScoreRequest.java deleted file mode 100644 index 1f17be430..000000000 --- a/src/main/java/com/example/solidconnection/application/dto/ScoreRequest.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.example.solidconnection.application.dto; - - -import com.example.solidconnection.application.domain.Gpa; -import com.example.solidconnection.application.domain.LanguageTest; -import com.example.solidconnection.type.LanguageTestType; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; - -@Schema(description = "대학 성적과 어학 시험 성적") -public record ScoreRequest( - @NotNull(message = "어학 종류를 입력해주세요.") - @Schema(description = "어학 시험 종류", example = "TOEFL", required = true) - LanguageTestType languageTestType, - - @NotBlank(message = "어학 점수를 입력해주세요.") - @Schema(description = "어학 시험 점수", example = "115", required = true) - String languageTestScore, - - @NotBlank(message = "어학 증명서를 첨부해주세요.") - @Schema(description = "어학 증명서 URL", example = "http://example.com/test-report.pdf", required = true) - String languageTestReportUrl, - - @NotNull(message = "학점을 입력해주세요.") - @Schema(description = "GPA", example = "3.5", required = true) - Double gpa, - - @NotNull(message = "학점 기준을 입력해주세요.") - @Schema(description = "GPA 계산 기준", example = "4.0", required = true) - Double gpaCriteria, - - @NotBlank(message = "대학 성적 증명서를 첨부해주세요.") - @Schema(description = "대학 성적 증명서 URL", example = "http://example.com/gpa-report.pdf", required = true) - String gpaReportUrl) { - - public Gpa toGpa() { - return new Gpa( - this.gpa, - this.gpaCriteria, - this.gpaReportUrl); - } - - public LanguageTest toLanguageTest() { - return new LanguageTest( - this.languageTestType, - this.languageTestScore, - this.languageTestReportUrl - ); - } -} diff --git a/src/main/java/com/example/solidconnection/application/dto/UniversityChoiceRequest.java b/src/main/java/com/example/solidconnection/application/dto/UniversityChoiceRequest.java index a76799571..033de880a 100644 --- a/src/main/java/com/example/solidconnection/application/dto/UniversityChoiceRequest.java +++ b/src/main/java/com/example/solidconnection/application/dto/UniversityChoiceRequest.java @@ -5,7 +5,6 @@ @Schema(description = "지망 대학") public record UniversityChoiceRequest( - @NotNull(message = "1지망 대학교를 입력해주세요.") @Schema(description = "1지망 대학교의 지원 정보 ID", example = "1") Long firstChoiceUniversityId, @@ -14,4 +13,5 @@ public record UniversityChoiceRequest( Long secondChoiceUniversityId, @Schema(description = "3지망 대학교의 지원 정보 ID (선택사항)", example = "3", nullable = true) - Long thirdChoiceUniversityId) {} + Long thirdChoiceUniversityId) { +} diff --git a/src/main/java/com/example/solidconnection/application/dto/VerifyStatusResponse.java b/src/main/java/com/example/solidconnection/application/dto/VerifyStatusResponse.java deleted file mode 100644 index 8019e9f8e..000000000 --- a/src/main/java/com/example/solidconnection/application/dto/VerifyStatusResponse.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.example.solidconnection.application.dto; - -import io.swagger.v3.oas.annotations.media.Schema; - -@Schema(description = "지원 상태와 지망 대학 변경 횟수") -public record VerifyStatusResponse( - - @Schema(description = "지원 상태", example = "SUBMITTED_PENDING") - String status, - - @Schema(description = "지망 대학 변경 횟수", example = "1") - int updateCount) { -} diff --git a/src/main/java/com/example/solidconnection/application/repository/ApplicationRepository.java b/src/main/java/com/example/solidconnection/application/repository/ApplicationRepository.java index a3bca9dc2..1a06ec321 100644 --- a/src/main/java/com/example/solidconnection/application/repository/ApplicationRepository.java +++ b/src/main/java/com/example/solidconnection/application/repository/ApplicationRepository.java @@ -20,14 +20,22 @@ public interface ApplicationRepository extends JpaRepository boolean existsByNicknameForApply(String nicknameForApply); - @Query("SELECT a FROM Application a WHERE a.siteUser = :siteUser AND a.term = :term AND a.isDelete = false") - Optional findBySiteUserAndTerm(@Param("siteUser") SiteUser siteUser, @Param("term") String term); + List findAllByFirstChoiceUniversityAndVerifyStatusAndTerm( + UniversityInfoForApply firstChoiceUniversity, VerifyStatus verifyStatus, String term); - List findAllByFirstChoiceUniversityAndVerifyStatusAndTerm(UniversityInfoForApply firstChoiceUniversity, VerifyStatus verifyStatus, String term); + List findAllBySecondChoiceUniversityAndVerifyStatusAndTerm( + UniversityInfoForApply secondChoiceUniversity, VerifyStatus verifyStatus, String term); - List findAllBySecondChoiceUniversityAndVerifyStatusAndTerm(UniversityInfoForApply secondChoiceUniversity, VerifyStatus verifyStatus, String term); + List findAllByThirdChoiceUniversityAndVerifyStatusAndTerm( + UniversityInfoForApply thirdChoiceUniversity, VerifyStatus verifyStatus, String term); - List findAllByThirdChoiceUniversityAndVerifyStatusAndTerm(UniversityInfoForApply thirdChoiceUniversity, VerifyStatus verifyStatus, String term); + @Query(""" + SELECT a FROM Application a + WHERE a.siteUser = :siteUser + AND a.term = :term + AND a.isDelete = false + """) + Optional findBySiteUserAndTerm(@Param("siteUser") SiteUser siteUser, @Param("term") String term); default Application getApplicationBySiteUserAndTerm(SiteUser siteUser, String term) { return findBySiteUserAndTerm(siteUser, term) diff --git a/src/main/java/com/example/solidconnection/application/service/ApplicationQueryService.java b/src/main/java/com/example/solidconnection/application/service/ApplicationQueryService.java index 66ae84918..68cf9c0aa 100644 --- a/src/main/java/com/example/solidconnection/application/service/ApplicationQueryService.java +++ b/src/main/java/com/example/solidconnection/application/service/ApplicationQueryService.java @@ -36,6 +36,7 @@ public class ApplicationQueryService { private final UniversityInfoForApplyRepository universityInfoForApplyRepository; private final SiteUserRepository siteUserRepository; private final UniversityFilterRepositoryImpl universityFilterRepository; + @Value("${university.term}") public String term; diff --git a/src/main/java/com/example/solidconnection/application/service/ApplicationSubmissionService.java b/src/main/java/com/example/solidconnection/application/service/ApplicationSubmissionService.java index 6b263996e..f82e9ad76 100644 --- a/src/main/java/com/example/solidconnection/application/service/ApplicationSubmissionService.java +++ b/src/main/java/com/example/solidconnection/application/service/ApplicationSubmissionService.java @@ -1,14 +1,14 @@ package com.example.solidconnection.application.service; -import com.example.solidconnection.application.domain.*; +import com.example.solidconnection.application.domain.Application; import com.example.solidconnection.application.dto.ApplyRequest; import com.example.solidconnection.application.dto.UniversityChoiceRequest; import com.example.solidconnection.application.repository.ApplicationRepository; -import com.example.solidconnection.score.repository.GpaScoreRepository; -import com.example.solidconnection.score.repository.LanguageTestScoreRepository; import com.example.solidconnection.custom.exception.CustomException; import com.example.solidconnection.score.domain.GpaScore; import com.example.solidconnection.score.domain.LanguageTestScore; +import com.example.solidconnection.score.repository.GpaScoreRepository; +import com.example.solidconnection.score.repository.LanguageTestScoreRepository; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.repository.SiteUserRepository; import com.example.solidconnection.type.VerifyStatus; @@ -19,9 +19,16 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.*; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; -import static com.example.solidconnection.custom.exception.ErrorCode.*; +import static com.example.solidconnection.custom.exception.ErrorCode.APPLY_UPDATE_LIMIT_EXCEED; +import static com.example.solidconnection.custom.exception.ErrorCode.CANT_APPLY_FOR_SAME_UNIVERSITY; +import static com.example.solidconnection.custom.exception.ErrorCode.INVALID_GPA_SCORE; +import static com.example.solidconnection.custom.exception.ErrorCode.INVALID_GPA_SCORE_STATUS; +import static com.example.solidconnection.custom.exception.ErrorCode.INVALID_LANGUAGE_TEST_SCORE; +import static com.example.solidconnection.custom.exception.ErrorCode.INVALID_LANGUAGE_TEST_SCORE_STATUS; @RequiredArgsConstructor @Service diff --git a/src/main/java/com/example/solidconnection/application/service/NicknameCreator.java b/src/main/java/com/example/solidconnection/application/service/NicknameCreator.java index 21a36dfab..d9243ce39 100644 --- a/src/main/java/com/example/solidconnection/application/service/NicknameCreator.java +++ b/src/main/java/com/example/solidconnection/application/service/NicknameCreator.java @@ -9,18 +9,20 @@ @NoArgsConstructor(access = lombok.AccessLevel.PRIVATE) class NicknameCreator { - public static final List ADJECTIVES = List.copyOf( - Set.of("기쁜", "행복한", "즐거운", "밝은", "따뜻한", "시원한", "고고한", "예쁜", "신선한", "풍부한", "깨끗한", - "귀한", "눈부신", "멋진", "고귀한", "화려한", "상큼한", "활기찬", "유쾌한", "똘똘한", "친절한", "좋은", - "영리한", "용감한", "정직한", "성실한", "강인한", "귀여운", "순수한", "희망찬", "발랄한", "나른한", "후한", "빛나는", - "따스한", "안락한", "편안한", "성공한", "재미난", "청량한", "찬란한", "소중한", "특별한", "단순한", "반가운", "그리운") + public static final List ADJECTIVES = List.copyOf(Set.of( + "기쁜", "행복한", "즐거운", "밝은", "따뜻한", "시원한", "고고한", "예쁜", "신선한", "풍부한", "깨끗한", + "귀한", "눈부신", "멋진", "고귀한", "화려한", "상큼한", "활기찬", "유쾌한", "똘똘한", "친절한", "좋은", + "영리한", "용감한", "정직한", "성실한", "강인한", "귀여운", "순수한", "희망찬", "발랄한", "나른한", "후한", "빛나는", + "따스한", "안락한", "편안한", "성공한", "재미난", "청량한", "찬란한", "소중한", "특별한", "단순한", "반가운", "그리운") ); - public static final List NOUNS = List.copyOf( - Set.of("청춘", "토끼", "기사", "곰", "사슴", "여우", "팬더", "이슬", "새싹", "햇빛", "나비", "별", "달", "구름", - "사탕", "젤리", "마법", "풍선", "캔디", "초코", "인형", "쿠키", "요정", "장미", "마녀", "보물", "꽃", "보석", - "달빛", "오리", "날개", "여행", "편지", "불꽃", "파도", "별빛", "구슬", "노래", "음표", "선율", "미소", "가방", "거울", - "씨앗", "열매", "바다", "약속", "구두", "공기", "등불", "촛불", "진주", "꿀벌", "예감", "바람", "오전", "오후", "아침", "점심", "저녁") + public static final List NOUNS = List.copyOf(Set.of( + "청춘", "토끼", "기사", "곰", "사슴", "여우", "팬더", "이슬", "새싹", "햇빛", "나비", "별", "달", "구름", + "사탕", "젤리", "마법", "풍선", "캔디", "초코", "인형", "쿠키", "요정", "장미", "마녀", "보물", "꽃", "보석", + "달빛", "오리", "날개", "여행", "편지", "불꽃", "파도", "별빛", "구슬", "노래", "음표", "선율", "미소", "가방", + "거울", "씨앗", "열매", "바다", "약속", "구두", "공기", "등불", "촛불", "진주", "꿀벌", "예감", "바람", + "오전", "오후", "아침", "점심", "저녁") ); + private static final Random RANDOM = new Random(); public static String createRandomNickname() { diff --git a/src/main/java/com/example/solidconnection/auth/client/KakaoOAuthClient.java b/src/main/java/com/example/solidconnection/auth/client/KakaoOAuthClient.java index fa9d1f265..9862d0074 100644 --- a/src/main/java/com/example/solidconnection/auth/client/KakaoOAuthClient.java +++ b/src/main/java/com/example/solidconnection/auth/client/KakaoOAuthClient.java @@ -25,12 +25,16 @@ public class KakaoOAuthClient { private final RestTemplate restTemplate; + @Value("${kakao.redirect_uri}") public String redirectUri; + @Value("${kakao.client_id}") private String clientId; + @Value("${kakao.token_url}") private String tokenUrl; + @Value("${kakao.user_info_url}") private String userInfoUrl; diff --git a/src/main/java/com/example/solidconnection/auth/dto/SignInResponse.java b/src/main/java/com/example/solidconnection/auth/dto/SignInResponse.java index ec89bbf16..41d9425cb 100644 --- a/src/main/java/com/example/solidconnection/auth/dto/SignInResponse.java +++ b/src/main/java/com/example/solidconnection/auth/dto/SignInResponse.java @@ -1,7 +1,6 @@ package com.example.solidconnection.auth.dto; import com.example.solidconnection.auth.dto.kakao.KakaoOauthResponse; - import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "로그인 응답 데이터") diff --git a/src/main/java/com/example/solidconnection/auth/dto/kakao/FirstAccessResponse.java b/src/main/java/com/example/solidconnection/auth/dto/kakao/FirstAccessResponse.java index 2f777c3b7..d766099ed 100644 --- a/src/main/java/com/example/solidconnection/auth/dto/kakao/FirstAccessResponse.java +++ b/src/main/java/com/example/solidconnection/auth/dto/kakao/FirstAccessResponse.java @@ -4,7 +4,6 @@ @Schema(description = "등록되지 않은 사용자의 최초 접속 시 응답 데이터") public record FirstAccessResponse( - @Schema(description = "사용자 등록 여부", example = "false") boolean isRegistered, diff --git a/src/main/java/com/example/solidconnection/board/controller/BoardController.java b/src/main/java/com/example/solidconnection/board/controller/BoardController.java index 29cfc249a..1777603cd 100644 --- a/src/main/java/com/example/solidconnection/board/controller/BoardController.java +++ b/src/main/java/com/example/solidconnection/board/controller/BoardController.java @@ -7,7 +7,11 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirements; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/com/example/solidconnection/board/domain/Board.java b/src/main/java/com/example/solidconnection/board/domain/Board.java index 007553367..77d0aada8 100644 --- a/src/main/java/com/example/solidconnection/board/domain/Board.java +++ b/src/main/java/com/example/solidconnection/board/domain/Board.java @@ -1,8 +1,13 @@ package com.example.solidconnection.board.domain; import com.example.solidconnection.post.domain.Post; -import jakarta.persistence.*; -import lombok.*; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import lombok.Getter; +import lombok.NoArgsConstructor; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/com/example/solidconnection/board/service/BoardService.java b/src/main/java/com/example/solidconnection/board/service/BoardService.java index 1ec5ac8b0..2513e0903 100644 --- a/src/main/java/com/example/solidconnection/board/service/BoardService.java +++ b/src/main/java/com/example/solidconnection/board/service/BoardService.java @@ -23,6 +23,18 @@ public class BoardService { private final BoardRepository boardRepository; + @Transactional(readOnly = true) + public List findPostsByCodeAndPostCategory(String code, String category) { + + String boardCode = validateCode(code); + PostCategory postCategory = validatePostCategory(category); + + Board board = boardRepository.getByCodeUsingEntityGraph(boardCode); + List postList = getPostListByPostCategory(board.getPostList(), postCategory); + + return BoardFindPostResponse.from(postList); + } + private String validateCode(String code) { try { return String.valueOf(BoardCode.valueOf(code)); @@ -31,25 +43,13 @@ private String validateCode(String code) { } } - private PostCategory validatePostCategory(String category){ - if(!EnumUtils.isValidEnum(PostCategory.class, category)){ + private PostCategory validatePostCategory(String category) { + if (!EnumUtils.isValidEnum(PostCategory.class, category)) { throw new CustomException(INVALID_POST_CATEGORY); } return PostCategory.valueOf(category); } - @Transactional(readOnly = true) - public List findPostsByCodeAndPostCategory(String code, String category) { - - String boardCode = validateCode(code); - PostCategory postCategory = validatePostCategory(category); - - Board board = boardRepository.getByCodeUsingEntityGraph(boardCode); - List postList = getPostListByPostCategory(board.getPostList(), postCategory); - - return BoardFindPostResponse.from(postList); - } - private List getPostListByPostCategory(List postList, PostCategory postCategory) { if (postCategory.equals(PostCategory.전체)) { return postList; diff --git a/src/main/java/com/example/solidconnection/cache/CacheUpdateListener.java b/src/main/java/com/example/solidconnection/cache/CacheUpdateListener.java index 34e2752b3..c785168b3 100644 --- a/src/main/java/com/example/solidconnection/cache/CacheUpdateListener.java +++ b/src/main/java/com/example/solidconnection/cache/CacheUpdateListener.java @@ -14,6 +14,7 @@ public class CacheUpdateListener implements MessageListener { private final CompletableFutureManager futureManager; + @Override public void onMessage(Message message, byte[] pattern) { String messageBody = new String(message.getBody(), StandardCharsets.UTF_8).replaceAll("^\"|\"$", ""); diff --git a/src/main/java/com/example/solidconnection/cache/CachingAspect.java b/src/main/java/com/example/solidconnection/cache/CachingAspect.java index 29c355372..816532022 100644 --- a/src/main/java/com/example/solidconnection/cache/CachingAspect.java +++ b/src/main/java/com/example/solidconnection/cache/CachingAspect.java @@ -15,6 +15,7 @@ @Component @RequiredArgsConstructor public class CachingAspect { + private final ApplicationContext applicationContext; private final RedisUtils redisUtils; @@ -47,7 +48,7 @@ public Object cacheEvict(ProceedingJoinPoint joinPoint, DefaultCacheOut defaultC if (usingPrefix) { cacheManager.evictUsingPrefix(cacheKey); - }else{ + } else { cacheManager.evict(cacheKey); } } diff --git a/src/main/java/com/example/solidconnection/cache/CompletableFutureManager.java b/src/main/java/com/example/solidconnection/cache/CompletableFutureManager.java index 6bcf01e03..48c36b28c 100644 --- a/src/main/java/com/example/solidconnection/cache/CompletableFutureManager.java +++ b/src/main/java/com/example/solidconnection/cache/CompletableFutureManager.java @@ -2,12 +2,13 @@ import org.springframework.stereotype.Component; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; -import java.util.Map; @Component public class CompletableFutureManager { + private final Map> waitingRequests = new ConcurrentHashMap<>(); public CompletableFuture getOrCreateFuture(String key) { diff --git a/src/main/java/com/example/solidconnection/cache/ThunderingHerdCachingAspect.java b/src/main/java/com/example/solidconnection/cache/ThunderingHerdCachingAspect.java index 8dc1694db..a37e80f51 100644 --- a/src/main/java/com/example/solidconnection/cache/ThunderingHerdCachingAspect.java +++ b/src/main/java/com/example/solidconnection/cache/ThunderingHerdCachingAspect.java @@ -16,14 +16,22 @@ import java.time.Duration; import java.util.UUID; -import java.util.concurrent.*; +import java.util.concurrent.Callable; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; -import static com.example.solidconnection.type.RedisConstants.*; +import static com.example.solidconnection.type.RedisConstants.CREATE_CHANNEL; +import static com.example.solidconnection.type.RedisConstants.LOCK_TIMEOUT_MS; +import static com.example.solidconnection.type.RedisConstants.MAX_WAIT_TIME_MS; +import static com.example.solidconnection.type.RedisConstants.REFRESH_LIMIT_PERCENT; @Aspect @Component @Slf4j public class ThunderingHerdCachingAspect { + private final ApplicationContext applicationContext; private final RedisTemplate redisTemplate; private final CompletableFutureManager futureManager; diff --git a/src/main/java/com/example/solidconnection/cache/annotation/DefaultCacheOut.java b/src/main/java/com/example/solidconnection/cache/annotation/DefaultCacheOut.java index bb1d5b518..2b5c8aada 100644 --- a/src/main/java/com/example/solidconnection/cache/annotation/DefaultCacheOut.java +++ b/src/main/java/com/example/solidconnection/cache/annotation/DefaultCacheOut.java @@ -8,7 +8,10 @@ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface DefaultCacheOut { + String[] key(); + String cacheManager(); + boolean prefix() default false; } diff --git a/src/main/java/com/example/solidconnection/cache/annotation/DefaultCaching.java b/src/main/java/com/example/solidconnection/cache/annotation/DefaultCaching.java index 36c45a616..316daab0f 100644 --- a/src/main/java/com/example/solidconnection/cache/annotation/DefaultCaching.java +++ b/src/main/java/com/example/solidconnection/cache/annotation/DefaultCaching.java @@ -8,7 +8,10 @@ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface DefaultCaching { + String key(); + String cacheManager(); + long ttlSec(); } diff --git a/src/main/java/com/example/solidconnection/cache/annotation/ThunderingHerdCaching.java b/src/main/java/com/example/solidconnection/cache/annotation/ThunderingHerdCaching.java index 6772a52e7..c5a9e0e9b 100644 --- a/src/main/java/com/example/solidconnection/cache/annotation/ThunderingHerdCaching.java +++ b/src/main/java/com/example/solidconnection/cache/annotation/ThunderingHerdCaching.java @@ -9,6 +9,8 @@ @Retention(RetentionPolicy.RUNTIME) public @interface ThunderingHerdCaching { String key(); + String cacheManager(); + long ttlSec(); } diff --git a/src/main/java/com/example/solidconnection/cache/manager/CacheManager.java b/src/main/java/com/example/solidconnection/cache/manager/CacheManager.java index 8c46324e1..3373d1563 100644 --- a/src/main/java/com/example/solidconnection/cache/manager/CacheManager.java +++ b/src/main/java/com/example/solidconnection/cache/manager/CacheManager.java @@ -1,8 +1,12 @@ package com.example.solidconnection.cache.manager; public interface CacheManager { + void put(String key, Object value, Long ttl); + Object get(String key); + void evict(String key); + void evictUsingPrefix(String key); } diff --git a/src/main/java/com/example/solidconnection/cache/manager/CustomCacheManager.java b/src/main/java/com/example/solidconnection/cache/manager/CustomCacheManager.java index 833ed00f7..2e489567c 100644 --- a/src/main/java/com/example/solidconnection/cache/manager/CustomCacheManager.java +++ b/src/main/java/com/example/solidconnection/cache/manager/CustomCacheManager.java @@ -11,6 +11,7 @@ @Component("customCacheManager") public class CustomCacheManager implements CacheManager { + private final RedisTemplate redisTemplate; @Autowired @@ -33,7 +34,7 @@ public void evict(String key) { } public void evictUsingPrefix(String key) { - Set keys = redisTemplate.keys(key+"*"); + Set keys = redisTemplate.keys(key + "*"); if (keys != null && !keys.isEmpty()) { redisTemplate.delete(keys); } diff --git a/src/main/java/com/example/solidconnection/comment/controller/CommentController.java b/src/main/java/com/example/solidconnection/comment/controller/CommentController.java index 61bae1036..bcb50715c 100644 --- a/src/main/java/com/example/solidconnection/comment/controller/CommentController.java +++ b/src/main/java/com/example/solidconnection/comment/controller/CommentController.java @@ -1,13 +1,23 @@ package com.example.solidconnection.comment.controller; -import com.example.solidconnection.comment.dto.*; +import com.example.solidconnection.comment.dto.CommentCreateRequest; +import com.example.solidconnection.comment.dto.CommentCreateResponse; +import com.example.solidconnection.comment.dto.CommentDeleteResponse; +import com.example.solidconnection.comment.dto.CommentUpdateRequest; +import com.example.solidconnection.comment.dto.CommentUpdateResponse; import com.example.solidconnection.comment.service.CommentService; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirements; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import java.security.Principal; @@ -28,7 +38,6 @@ public ResponseEntity createComment( @PathVariable("post_id") Long postId, @Valid @RequestBody CommentCreateRequest commentCreateRequest ) { - CommentCreateResponse commentCreateResponse = commentService.createComment( principal.getName(), postId, commentCreateRequest); return ResponseEntity.ok().body(commentCreateResponse); @@ -41,7 +50,6 @@ public ResponseEntity updateComment( @PathVariable("comment_id") Long commentId, @Valid @RequestBody CommentUpdateRequest commentUpdateRequest ) { - CommentUpdateResponse commentUpdateResponse = commentService.updateComment( principal.getName(), postId, commentId, commentUpdateRequest ); @@ -54,9 +62,7 @@ public ResponseEntity deleteCommentById( @PathVariable("post_id") Long postId, @PathVariable("comment_id") Long commentId ) { - CommentDeleteResponse commentDeleteResponse = commentService.deleteCommentById(principal.getName(), postId, commentId); return ResponseEntity.ok().body(commentDeleteResponse); } - } diff --git a/src/main/java/com/example/solidconnection/comment/domain/Comment.java b/src/main/java/com/example/solidconnection/comment/domain/Comment.java index 774c01123..a4d147a61 100644 --- a/src/main/java/com/example/solidconnection/comment/domain/Comment.java +++ b/src/main/java/com/example/solidconnection/comment/domain/Comment.java @@ -3,7 +3,17 @@ import com.example.solidconnection.entity.common.BaseEntity; import com.example.solidconnection.post.domain.Post; import com.example.solidconnection.siteuser.domain.SiteUser; -import jakarta.persistence.*; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Transient; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; diff --git a/src/main/java/com/example/solidconnection/comment/dto/CommentCreateRequest.java b/src/main/java/com/example/solidconnection/comment/dto/CommentCreateRequest.java index 8cf57e360..c2065685b 100644 --- a/src/main/java/com/example/solidconnection/comment/dto/CommentCreateRequest.java +++ b/src/main/java/com/example/solidconnection/comment/dto/CommentCreateRequest.java @@ -10,6 +10,7 @@ public record CommentCreateRequest( @NotBlank(message = "댓글 내용은 빈 값일 수 없습니다.") @Size(min = 1, max = 255, message = "댓글 내용은 최소 1자 이상, 최대 255자 이하여야 합니다.") String content, + Long parentId ) { public Comment toEntity(SiteUser siteUser, Post post, Comment parentComment) { diff --git a/src/main/java/com/example/solidconnection/comment/dto/CommentUpdateRequest.java b/src/main/java/com/example/solidconnection/comment/dto/CommentUpdateRequest.java index 23ae16118..d99429931 100644 --- a/src/main/java/com/example/solidconnection/comment/dto/CommentUpdateRequest.java +++ b/src/main/java/com/example/solidconnection/comment/dto/CommentUpdateRequest.java @@ -8,5 +8,4 @@ public record CommentUpdateRequest( @Size(min = 1, max = 255, message = "댓글 내용은 최소 1자 이상, 최대 255자 이하여야 합니다.") String content ) { - } diff --git a/src/main/java/com/example/solidconnection/comment/dto/PostFindCommentResponse.java b/src/main/java/com/example/solidconnection/comment/dto/PostFindCommentResponse.java index 2335b68ad..a0d68066a 100644 --- a/src/main/java/com/example/solidconnection/comment/dto/PostFindCommentResponse.java +++ b/src/main/java/com/example/solidconnection/comment/dto/PostFindCommentResponse.java @@ -13,8 +13,8 @@ public record PostFindCommentResponse( ZonedDateTime createdAt, ZonedDateTime updatedAt, PostFindSiteUserResponse postFindSiteUserResponse - ) { + public static PostFindCommentResponse from(Boolean isOwner, Comment comment) { return new PostFindCommentResponse( comment.getId(), diff --git a/src/main/java/com/example/solidconnection/comment/repository/CommentRepository.java b/src/main/java/com/example/solidconnection/comment/repository/CommentRepository.java index b78011903..ce37c42a1 100644 --- a/src/main/java/com/example/solidconnection/comment/repository/CommentRepository.java +++ b/src/main/java/com/example/solidconnection/comment/repository/CommentRepository.java @@ -9,6 +9,7 @@ import java.util.List; import static com.example.solidconnection.custom.exception.ErrorCode.INVALID_COMMENT_ID; + public interface CommentRepository extends JpaRepository { @Query(value = """ diff --git a/src/main/java/com/example/solidconnection/comment/service/CommentService.java b/src/main/java/com/example/solidconnection/comment/service/CommentService.java index 8c0b0458f..7d25ee5f6 100644 --- a/src/main/java/com/example/solidconnection/comment/service/CommentService.java +++ b/src/main/java/com/example/solidconnection/comment/service/CommentService.java @@ -1,8 +1,13 @@ package com.example.solidconnection.comment.service; -import com.example.solidconnection.comment.dto.*; -import com.example.solidconnection.comment.repository.CommentRepository; import com.example.solidconnection.comment.domain.Comment; +import com.example.solidconnection.comment.dto.CommentCreateRequest; +import com.example.solidconnection.comment.dto.CommentCreateResponse; +import com.example.solidconnection.comment.dto.CommentDeleteResponse; +import com.example.solidconnection.comment.dto.CommentUpdateRequest; +import com.example.solidconnection.comment.dto.CommentUpdateResponse; +import com.example.solidconnection.comment.dto.PostFindCommentResponse; +import com.example.solidconnection.comment.repository.CommentRepository; import com.example.solidconnection.custom.exception.CustomException; import com.example.solidconnection.post.domain.Post; import com.example.solidconnection.post.repository.PostRepository; @@ -15,7 +20,9 @@ import java.util.List; import java.util.stream.Collectors; -import static com.example.solidconnection.custom.exception.ErrorCode.*; +import static com.example.solidconnection.custom.exception.ErrorCode.CAN_NOT_UPDATE_DEPRECATED_COMMENT; +import static com.example.solidconnection.custom.exception.ErrorCode.INVALID_COMMENT_LEVEL; +import static com.example.solidconnection.custom.exception.ErrorCode.INVALID_POST_ACCESS; @Service @RequiredArgsConstructor @@ -25,29 +32,6 @@ public class CommentService { private final SiteUserRepository siteUserRepository; private final PostRepository postRepository; - private Boolean isOwner(Comment comment, String email) { - return comment.getSiteUser().getEmail().equals(email); - } - - private void validateOwnership(Comment comment, String email) { - if (!comment.getSiteUser().getEmail().equals(email)) { - throw new CustomException(INVALID_POST_ACCESS); - } - } - - private void validateDeprecated(Comment comment) { - if (comment.getContent() == null) { - throw new CustomException(CAN_NOT_UPDATE_DEPRECATED_COMMENT); - } - } - - // 대대댓글부터 허용하지 않음 - private void validateCommentDepth(Comment parentComment) { - if (parentComment.getParentComment() != null) { - throw new CustomException(INVALID_COMMENT_LEVEL); - } - } - @Transactional(readOnly = true) public List findCommentsByPostId(String email, Long postId) { return commentRepository.findCommentTreeByPostId(postId) @@ -56,6 +40,10 @@ public List findCommentsByPostId(String email, Long pos .collect(Collectors.toList()); } + private Boolean isOwner(Comment comment, String email) { + return comment.getSiteUser().getEmail().equals(email); + } + @Transactional public CommentCreateResponse createComment(String email, Long postId, CommentCreateRequest commentCreateRequest) { @@ -72,6 +60,13 @@ public CommentCreateResponse createComment(String email, Long postId, CommentCre return CommentCreateResponse.from(createdComment); } + // 대대댓글부터 허용하지 않음 + private void validateCommentDepth(Comment parentComment) { + if (parentComment.getParentComment() != null) { + throw new CustomException(INVALID_COMMENT_LEVEL); + } + } + @Transactional public CommentUpdateResponse updateComment(String email, Long postId, Long commentId, CommentUpdateRequest commentUpdateRequest) { @@ -86,6 +81,12 @@ public CommentUpdateResponse updateComment(String email, Long postId, Long comme return CommentUpdateResponse.from(comment); } + private void validateDeprecated(Comment comment) { + if (comment.getContent() == null) { + throw new CustomException(CAN_NOT_UPDATE_DEPRECATED_COMMENT); + } + } + @Transactional public CommentDeleteResponse deleteCommentById(String email, Long postId, Long commentId) { SiteUser siteUser = siteUserRepository.getByEmail(email); @@ -117,4 +118,10 @@ public CommentDeleteResponse deleteCommentById(String email, Long postId, Long c } return new CommentDeleteResponse(commentId); } + + private void validateOwnership(Comment comment, String email) { + if (!comment.getSiteUser().getEmail().equals(email)) { + throw new CustomException(INVALID_POST_ACCESS); + } + } } diff --git a/src/main/java/com/example/solidconnection/config/redis/RedisConfig.java b/src/main/java/com/example/solidconnection/config/redis/RedisConfig.java index 282c36e8c..22847dc6d 100644 --- a/src/main/java/com/example/solidconnection/config/redis/RedisConfig.java +++ b/src/main/java/com/example/solidconnection/config/redis/RedisConfig.java @@ -23,7 +23,6 @@ public class RedisConfig { private final String redisHost; - private final int redisPort; public RedisConfig(@Value("${spring.data.redis.host}") final String redisHost, diff --git a/src/main/java/com/example/solidconnection/config/scheduler/SchedulerConfig.java b/src/main/java/com/example/solidconnection/config/scheduler/SchedulerConfig.java index a52bf281a..2a2cfa6a5 100644 --- a/src/main/java/com/example/solidconnection/config/scheduler/SchedulerConfig.java +++ b/src/main/java/com/example/solidconnection/config/scheduler/SchedulerConfig.java @@ -7,6 +7,7 @@ @Configuration public class SchedulerConfig implements SchedulingConfigurer { + private final int POOL_SIZE = 5; @Override diff --git a/src/main/java/com/example/solidconnection/config/security/JwtAuthenticationFilter.java b/src/main/java/com/example/solidconnection/config/security/JwtAuthenticationFilter.java index 7e103f911..6062c640e 100644 --- a/src/main/java/com/example/solidconnection/config/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/example/solidconnection/config/security/JwtAuthenticationFilter.java @@ -29,6 +29,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { public static final String TOKEN_HEADER = "Authorization"; public static final String TOKEN_PREFIX = "Bearer "; + private final TokenService tokenService; private final TokenValidator tokenValidator; private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; diff --git a/src/main/java/com/example/solidconnection/config/swagger/SwaggerConfig.java b/src/main/java/com/example/solidconnection/config/swagger/SwaggerConfig.java index f74a57fb9..82902d32b 100644 --- a/src/main/java/com/example/solidconnection/config/swagger/SwaggerConfig.java +++ b/src/main/java/com/example/solidconnection/config/swagger/SwaggerConfig.java @@ -22,7 +22,7 @@ ) public class SwaggerConfig { - public static final String ACCESS_TOKEN = "access_token"; + public static final String ACCESS_TOKEN = "access_token"; @Bean public OpenAPI customOpenAPI() { diff --git a/src/main/java/com/example/solidconnection/config/sync/AsyncConfig.java b/src/main/java/com/example/solidconnection/config/sync/AsyncConfig.java index 738d26e04..417b040b3 100644 --- a/src/main/java/com/example/solidconnection/config/sync/AsyncConfig.java +++ b/src/main/java/com/example/solidconnection/config/sync/AsyncConfig.java @@ -9,7 +9,6 @@ public class AsyncConfig { @Bean(name = "asyncExecutor") public ThreadPoolTaskExecutor asyncExecutor() { - ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(10); diff --git a/src/main/java/com/example/solidconnection/config/token/TokenValidator.java b/src/main/java/com/example/solidconnection/config/token/TokenValidator.java index a95a504ed..9a63a21f5 100644 --- a/src/main/java/com/example/solidconnection/config/token/TokenValidator.java +++ b/src/main/java/com/example/solidconnection/config/token/TokenValidator.java @@ -36,30 +36,15 @@ public void validateAccessToken(String token) { validateRefreshToken(token); } - private void validateRefreshToken(String token) { - String email = getClaim(token).getSubject(); - if (redisTemplate.opsForValue().get(TokenType.REFRESH.addTokenPrefixToSubject(email)) == null) { - throw new CustomException(REFRESH_TOKEN_EXPIRED); - } - } - - private void validateNotSignOut(String token) { - String email = getClaim(token).getSubject(); - if (SIGN_OUT_VALUE.equals(redisTemplate.opsForValue().get(TokenType.REFRESH.addTokenPrefixToSubject(email)))) { - throw new CustomException(USER_ALREADY_SIGN_OUT); - } - } - public void validateKakaoToken(String token) { validateTokenNotEmpty(token); validateTokenNotExpired(token, TokenType.KAKAO_OAUTH); validateKakaoTokenNotUsed(token); } - private void validateKakaoTokenNotUsed(String token) { - String email = getClaim(token).getSubject(); - if (!Objects.equals(redisTemplate.opsForValue().get(TokenType.KAKAO_OAUTH.addTokenPrefixToSubject(email)), token)) { - throw new CustomException(INVALID_SERVICE_PUBLISHED_KAKAO_TOKEN); + private void validateTokenNotEmpty(String token) { + if (!StringUtils.hasText(token)) { + throw new CustomException(INVALID_TOKEN); } } @@ -76,9 +61,24 @@ private void validateTokenNotExpired(String token, TokenType tokenType) { } } - private void validateTokenNotEmpty(String token) { - if (!StringUtils.hasText(token)) { - throw new CustomException(INVALID_TOKEN); + private void validateNotSignOut(String token) { + String email = getClaim(token).getSubject(); + if (SIGN_OUT_VALUE.equals(redisTemplate.opsForValue().get(TokenType.REFRESH.addTokenPrefixToSubject(email)))) { + throw new CustomException(USER_ALREADY_SIGN_OUT); + } + } + + private void validateRefreshToken(String token) { + String email = getClaim(token).getSubject(); + if (redisTemplate.opsForValue().get(TokenType.REFRESH.addTokenPrefixToSubject(email)) == null) { + throw new CustomException(REFRESH_TOKEN_EXPIRED); + } + } + + private void validateKakaoTokenNotUsed(String token) { + String email = getClaim(token).getSubject(); + if (!Objects.equals(redisTemplate.opsForValue().get(TokenType.KAKAO_OAUTH.addTokenPrefixToSubject(email)), token)) { + throw new CustomException(INVALID_SERVICE_PUBLISHED_KAKAO_TOKEN); } } diff --git a/src/main/java/com/example/solidconnection/custom/exception/CustomException.java b/src/main/java/com/example/solidconnection/custom/exception/CustomException.java index 367d704eb..2f1962fbf 100644 --- a/src/main/java/com/example/solidconnection/custom/exception/CustomException.java +++ b/src/main/java/com/example/solidconnection/custom/exception/CustomException.java @@ -4,6 +4,7 @@ @Getter public class CustomException extends RuntimeException { + private final int code; private final String message; diff --git a/src/main/java/com/example/solidconnection/custom/exception/ErrorCode.java b/src/main/java/com/example/solidconnection/custom/exception/ErrorCode.java index 1a3aa8df7..765013303 100644 --- a/src/main/java/com/example/solidconnection/custom/exception/ErrorCode.java +++ b/src/main/java/com/example/solidconnection/custom/exception/ErrorCode.java @@ -53,7 +53,7 @@ public enum ErrorCode { PROFILE_IMAGE_NEEDED(HttpStatus.BAD_REQUEST.value(), "프로필 이미지가 필요합니다."), // community - INVALID_POST_CATEGORY(HttpStatus.BAD_REQUEST.value(),"잘못된 카테고리명입니다."), + INVALID_POST_CATEGORY(HttpStatus.BAD_REQUEST.value(), "잘못된 카테고리명입니다."), INVALID_BOARD_CODE(HttpStatus.BAD_REQUEST.value(), "잘못된 게시판 코드입니다."), INVALID_POST_ID(HttpStatus.BAD_REQUEST.value(), "존재하지 않는 게시글입니다."), INVALID_POST_ACCESS(HttpStatus.BAD_REQUEST.value(), "자신의 게시글만 제어할 수 있습니다."), @@ -62,7 +62,7 @@ public enum ErrorCode { INVALID_COMMENT_ID(HttpStatus.BAD_REQUEST.value(), "존재하지 않는 댓글입니다."), INVALID_COMMENT_LEVEL(HttpStatus.BAD_REQUEST.value(), "최대 대댓글까지만 작성할 수 있습니다."), INVALID_COMMENT_ACCESS(HttpStatus.BAD_REQUEST.value(), "자신의 댓글만 제어할 수 있습니다."), - CAN_NOT_UPDATE_DEPRECATED_COMMENT(HttpStatus.BAD_REQUEST.value(),"이미 삭제된 댓글을 수정할 수 없습니다."), + CAN_NOT_UPDATE_DEPRECATED_COMMENT(HttpStatus.BAD_REQUEST.value(), "이미 삭제된 댓글을 수정할 수 없습니다."), INVALID_POST_LIKE(HttpStatus.BAD_REQUEST.value(), "존재하지 않는 게시글 좋아요입니다."), DUPLICATE_POST_LIKE(HttpStatus.BAD_REQUEST.value(), "이미 좋아요한 게시글입니다."), diff --git a/src/main/java/com/example/solidconnection/entity/PostImage.java b/src/main/java/com/example/solidconnection/entity/PostImage.java index 9ab87853c..653beecc4 100644 --- a/src/main/java/com/example/solidconnection/entity/PostImage.java +++ b/src/main/java/com/example/solidconnection/entity/PostImage.java @@ -1,7 +1,14 @@ package com.example.solidconnection.entity; import com.example.solidconnection.post.domain.Post; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import lombok.Getter; import lombok.NoArgsConstructor; @@ -9,6 +16,7 @@ @Getter @NoArgsConstructor public class PostImage { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; diff --git a/src/main/java/com/example/solidconnection/post/controller/PostController.java b/src/main/java/com/example/solidconnection/post/controller/PostController.java index c5b974082..cd287809b 100644 --- a/src/main/java/com/example/solidconnection/post/controller/PostController.java +++ b/src/main/java/com/example/solidconnection/post/controller/PostController.java @@ -1,13 +1,28 @@ package com.example.solidconnection.post.controller; -import com.example.solidconnection.post.dto.*; +import com.example.solidconnection.post.dto.PostCreateRequest; +import com.example.solidconnection.post.dto.PostCreateResponse; +import com.example.solidconnection.post.dto.PostDeleteResponse; +import com.example.solidconnection.post.dto.PostDislikeResponse; +import com.example.solidconnection.post.dto.PostFindResponse; +import com.example.solidconnection.post.dto.PostLikeResponse; +import com.example.solidconnection.post.dto.PostUpdateRequest; +import com.example.solidconnection.post.dto.PostUpdateResponse; import com.example.solidconnection.post.service.PostService; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirements; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.security.Principal; diff --git a/src/main/java/com/example/solidconnection/post/domain/Post.java b/src/main/java/com/example/solidconnection/post/domain/Post.java index 203feb5a9..31125f8bd 100644 --- a/src/main/java/com/example/solidconnection/post/domain/Post.java +++ b/src/main/java/com/example/solidconnection/post/domain/Post.java @@ -7,8 +7,21 @@ import com.example.solidconnection.post.dto.PostUpdateRequest; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.type.PostCategory; -import jakarta.persistence.*; -import lombok.*; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; import org.hibernate.annotations.BatchSize; import java.util.ArrayList; diff --git a/src/main/java/com/example/solidconnection/post/domain/PostLike.java b/src/main/java/com/example/solidconnection/post/domain/PostLike.java index 0af621370..9edf4052e 100644 --- a/src/main/java/com/example/solidconnection/post/domain/PostLike.java +++ b/src/main/java/com/example/solidconnection/post/domain/PostLike.java @@ -1,7 +1,13 @@ package com.example.solidconnection.post.domain; import com.example.solidconnection.siteuser.domain.SiteUser; -import jakarta.persistence.*; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; @@ -11,6 +17,7 @@ @NoArgsConstructor @EqualsAndHashCode(of = "id") public class PostLike { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @@ -24,7 +31,6 @@ public class PostLike { private SiteUser siteUser; public void setPostAndSiteUser(Post post, SiteUser siteUser) { - if (this.post != null) { this.post.getPostLikeList().remove(this); } @@ -39,7 +45,6 @@ public void setPostAndSiteUser(Post post, SiteUser siteUser) { } public void resetPostAndSiteUser() { - if (this.post != null) { this.post.getPostLikeList().remove(this); } diff --git a/src/main/java/com/example/solidconnection/post/dto/BoardFindPostResponse.java b/src/main/java/com/example/solidconnection/post/dto/BoardFindPostResponse.java index 8e6d3202a..4f475824c 100644 --- a/src/main/java/com/example/solidconnection/post/dto/BoardFindPostResponse.java +++ b/src/main/java/com/example/solidconnection/post/dto/BoardFindPostResponse.java @@ -33,6 +33,12 @@ public static BoardFindPostResponse from(Post post) { ); } + public static List from(List postList) { + return postList.stream() + .map(BoardFindPostResponse::from) + .collect(Collectors.toList()); + } + private static int getCommentCount(Post post) { return post.getCommentList().size(); } @@ -43,10 +49,4 @@ private static String getFirstImageUrl(Post post) { .map(PostImage::getUrl) .orElse(null); } - - public static List from(List postList) { - return postList.stream() - .map(BoardFindPostResponse::from) - .collect(Collectors.toList()); - } } diff --git a/src/main/java/com/example/solidconnection/post/dto/PostCreateRequest.java b/src/main/java/com/example/solidconnection/post/dto/PostCreateRequest.java index 03ab79686..a1ba1c696 100644 --- a/src/main/java/com/example/solidconnection/post/dto/PostCreateRequest.java +++ b/src/main/java/com/example/solidconnection/post/dto/PostCreateRequest.java @@ -11,12 +11,15 @@ public record PostCreateRequest( @NotNull(message = "게시글 카테고리를 설정해주세요.") String postCategory, + @NotBlank(message = "게시글 제목은 빈 값일 수 없습니다.") @Size(min = 1, max = 255, message = "댓글 내용은 최소 1자 이상, 최대 255자 이하여야 합니다.") String title, + @NotBlank(message = "게시글 내용은 빈 값일 수 없습니다.") @Size(min = 1, max = 1000, message = "댓글 내용은 최소 1자 이상, 최대 255자 이하여야 합니다.") String content, + @NotNull(message = "게시글 질문여부를 설정해주세요.") Boolean isQuestion ) { diff --git a/src/main/java/com/example/solidconnection/dto/PostFindPostImageResponse.java b/src/main/java/com/example/solidconnection/post/dto/PostFindPostImageResponse.java similarity index 93% rename from src/main/java/com/example/solidconnection/dto/PostFindPostImageResponse.java rename to src/main/java/com/example/solidconnection/post/dto/PostFindPostImageResponse.java index 22a6a4af0..63adf0020 100644 --- a/src/main/java/com/example/solidconnection/dto/PostFindPostImageResponse.java +++ b/src/main/java/com/example/solidconnection/post/dto/PostFindPostImageResponse.java @@ -1,4 +1,4 @@ -package com.example.solidconnection.dto; +package com.example.solidconnection.post.dto; import com.example.solidconnection.entity.PostImage; diff --git a/src/main/java/com/example/solidconnection/post/dto/PostFindResponse.java b/src/main/java/com/example/solidconnection/post/dto/PostFindResponse.java index 45e4e5dc7..1562dd5bc 100644 --- a/src/main/java/com/example/solidconnection/post/dto/PostFindResponse.java +++ b/src/main/java/com/example/solidconnection/post/dto/PostFindResponse.java @@ -2,7 +2,6 @@ import com.example.solidconnection.board.dto.PostFindBoardResponse; import com.example.solidconnection.comment.dto.PostFindCommentResponse; -import com.example.solidconnection.dto.*; import com.example.solidconnection.post.domain.Post; import com.example.solidconnection.siteuser.dto.PostFindSiteUserResponse; diff --git a/src/main/java/com/example/solidconnection/post/dto/PostLikeResponse.java b/src/main/java/com/example/solidconnection/post/dto/PostLikeResponse.java index 0ce14b175..35d7d58c9 100644 --- a/src/main/java/com/example/solidconnection/post/dto/PostLikeResponse.java +++ b/src/main/java/com/example/solidconnection/post/dto/PostLikeResponse.java @@ -5,8 +5,6 @@ public record PostLikeResponse( Long likeCount, Boolean isLiked - - ) { public static PostLikeResponse from(Post post) { return new PostLikeResponse( diff --git a/src/main/java/com/example/solidconnection/post/dto/PostUpdateRequest.java b/src/main/java/com/example/solidconnection/post/dto/PostUpdateRequest.java index b82b73685..b9bdc6f54 100644 --- a/src/main/java/com/example/solidconnection/post/dto/PostUpdateRequest.java +++ b/src/main/java/com/example/solidconnection/post/dto/PostUpdateRequest.java @@ -7,9 +7,11 @@ public record PostUpdateRequest( @NotNull(message = "게시글 카테고리를 설정해주세요.") String postCategory, + @NotBlank(message = "게시글 제목은 빈 값일 수 없습니다.") @Size(min = 1, max = 255, message = "댓글 내용은 최소 1자 이상, 최대 255자 이하여야 합니다.") String title, + @NotBlank(message = "게시글 내용은 빈 값일 수 없습니다.") @Size(min = 1, max = 1000, message = "댓글 내용은 최소 1자 이상, 최대 255자 이하여야 합니다.") String content diff --git a/src/main/java/com/example/solidconnection/post/repository/PostLikeRepository.java b/src/main/java/com/example/solidconnection/post/repository/PostLikeRepository.java index 398157c73..bebde7a92 100644 --- a/src/main/java/com/example/solidconnection/post/repository/PostLikeRepository.java +++ b/src/main/java/com/example/solidconnection/post/repository/PostLikeRepository.java @@ -1,8 +1,8 @@ package com.example.solidconnection.post.repository; import com.example.solidconnection.custom.exception.CustomException; -import com.example.solidconnection.post.domain.PostLike; import com.example.solidconnection.post.domain.Post; +import com.example.solidconnection.post.domain.PostLike; import com.example.solidconnection.siteuser.domain.SiteUser; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; diff --git a/src/main/java/com/example/solidconnection/post/repository/PostRepository.java b/src/main/java/com/example/solidconnection/post/repository/PostRepository.java index b819cc45a..e96881147 100644 --- a/src/main/java/com/example/solidconnection/post/repository/PostRepository.java +++ b/src/main/java/com/example/solidconnection/post/repository/PostRepository.java @@ -19,6 +19,27 @@ public interface PostRepository extends JpaRepository { @EntityGraph(attributePaths = {"postImageList", "board", "siteUser"}) Optional findPostById(Long id); + @Modifying(clearAutomatically = true, flushAutomatically = true) + @Query(""" + UPDATE Post p SET p.likeCount = p.likeCount - 1 + WHERE p.id = :postId AND p.likeCount > 0 + """) + void decreaseLikeCount(@Param("postId") Long postId); + + @Modifying(clearAutomatically = true, flushAutomatically = true) + @Query(""" + UPDATE Post p SET p.likeCount = p.likeCount + 1 + WHERE p.id = :postId + """) + void increaseLikeCount(@Param("postId") Long postId); + + @Modifying(clearAutomatically = true, flushAutomatically = true) + @Query(""" + UPDATE Post p SET p.viewCount = p.viewCount + :count + WHERE p.id = :postId + """) + void increaseViewCount(@Param("postId") Long postId, @Param("count") Long count); + default Post getByIdUsingEntityGraph(Long id) { return findPostById(id) .orElseThrow(() -> new CustomException(INVALID_POST_ID)); @@ -28,19 +49,4 @@ default Post getById(Long id) { return findById(id) .orElseThrow(() -> new CustomException(INVALID_POST_ID)); } - - @Modifying(clearAutomatically = true, flushAutomatically = true) - @Query("UPDATE Post p SET p.likeCount = p.likeCount - 1 " + - "WHERE p.id = :postId AND p.likeCount > 0") - void decreaseLikeCount(@Param("postId") Long postId); - - @Modifying(clearAutomatically = true, flushAutomatically = true) - @Query("UPDATE Post p SET p.likeCount = p.likeCount + 1 " + - "WHERE p.id = :postId") - void increaseLikeCount(@Param("postId") Long postId); - - @Modifying(clearAutomatically = true, flushAutomatically = true) - @Query("UPDATE Post p SET p.viewCount = p.viewCount + :count " + - "WHERE p.id = :postId") - void increaseViewCount(@Param("postId") Long postId, @Param("count") Long count); } diff --git a/src/main/java/com/example/solidconnection/post/service/PostService.java b/src/main/java/com/example/solidconnection/post/service/PostService.java index 4f9f77a73..d31cfb97a 100644 --- a/src/main/java/com/example/solidconnection/post/service/PostService.java +++ b/src/main/java/com/example/solidconnection/post/service/PostService.java @@ -1,17 +1,24 @@ package com.example.solidconnection.post.service; +import com.example.solidconnection.board.domain.Board; import com.example.solidconnection.board.dto.PostFindBoardResponse; import com.example.solidconnection.board.repository.BoardRepository; import com.example.solidconnection.comment.dto.PostFindCommentResponse; import com.example.solidconnection.comment.service.CommentService; import com.example.solidconnection.custom.exception.CustomException; -import com.example.solidconnection.dto.*; -import com.example.solidconnection.board.domain.Board; import com.example.solidconnection.entity.PostImage; +import com.example.solidconnection.post.domain.Post; import com.example.solidconnection.post.domain.PostLike; +import com.example.solidconnection.post.dto.PostCreateRequest; +import com.example.solidconnection.post.dto.PostCreateResponse; +import com.example.solidconnection.post.dto.PostDeleteResponse; +import com.example.solidconnection.post.dto.PostDislikeResponse; +import com.example.solidconnection.post.dto.PostFindPostImageResponse; +import com.example.solidconnection.post.dto.PostFindResponse; +import com.example.solidconnection.post.dto.PostLikeResponse; +import com.example.solidconnection.post.dto.PostUpdateRequest; +import com.example.solidconnection.post.dto.PostUpdateResponse; import com.example.solidconnection.post.repository.PostLikeRepository; -import com.example.solidconnection.post.domain.Post; -import com.example.solidconnection.post.dto.*; import com.example.solidconnection.post.repository.PostRepository; import com.example.solidconnection.s3.S3Service; import com.example.solidconnection.s3.UploadedFileUrlResponse; @@ -32,11 +39,17 @@ import java.util.List; -import static com.example.solidconnection.custom.exception.ErrorCode.*; +import static com.example.solidconnection.custom.exception.ErrorCode.CAN_NOT_DELETE_OR_UPDATE_QUESTION; +import static com.example.solidconnection.custom.exception.ErrorCode.CAN_NOT_UPLOAD_MORE_THAN_FIVE_IMAGES; +import static com.example.solidconnection.custom.exception.ErrorCode.DUPLICATE_POST_LIKE; +import static com.example.solidconnection.custom.exception.ErrorCode.INVALID_BOARD_CODE; +import static com.example.solidconnection.custom.exception.ErrorCode.INVALID_POST_ACCESS; +import static com.example.solidconnection.custom.exception.ErrorCode.INVALID_POST_CATEGORY; @Service @RequiredArgsConstructor public class PostService { + private final PostRepository postRepository; private final SiteUserRepository siteUserRepository; private final BoardRepository boardRepository; diff --git a/src/main/java/com/example/solidconnection/repositories/CountryRepository.java b/src/main/java/com/example/solidconnection/repositories/CountryRepository.java index aff9470b4..d9ba75555 100644 --- a/src/main/java/com/example/solidconnection/repositories/CountryRepository.java +++ b/src/main/java/com/example/solidconnection/repositories/CountryRepository.java @@ -7,21 +7,10 @@ import org.springframework.stereotype.Repository; import java.util.List; -import java.util.Optional; @Repository public interface CountryRepository extends JpaRepository { - Optional findByKoreanName(String koreanName); - -/* default Country getByKoreanName(String koreanName) { - return findByKoreanName(koreanName) - .orElseThrow(() -> new CustomException(COUNTRY_NOT_FOUND_BY_KOREAN_NAME)); - }*/ - @Query("SELECT c FROM Country c WHERE c.koreanName IN :names") List findByKoreanNames(@Param(value = "names") List names); - - @Query("SELECT c FROM Country c WHERE c.koreanName LIKE %:keyword%") - List findByKoreanNameContaining(@Param("keyword") String keyword); } diff --git a/src/main/java/com/example/solidconnection/repositories/RegionRepository.java b/src/main/java/com/example/solidconnection/repositories/RegionRepository.java index 9a26233bc..0dc99fb08 100644 --- a/src/main/java/com/example/solidconnection/repositories/RegionRepository.java +++ b/src/main/java/com/example/solidconnection/repositories/RegionRepository.java @@ -7,18 +7,10 @@ import org.springframework.stereotype.Repository; import java.util.List; -import java.util.Optional; @Repository public interface RegionRepository extends JpaRepository { - Optional findByKoreanName(String koreanName); - -/* default Region getByKoreanName(String koreanName) { - return findByKoreanName(koreanName) - .orElseThrow(() -> new CustomException(REGION_NOT_FOUND_BY_KOREAN_NAME)); - }*/ - @Query("SELECT r FROM Region r WHERE r.koreanName IN :names") List findByKoreanNames(@Param(value = "names") List names); } diff --git a/src/main/java/com/example/solidconnection/s3/FileUploadService.java b/src/main/java/com/example/solidconnection/s3/FileUploadService.java index 5e31c5475..71d9f9c7a 100644 --- a/src/main/java/com/example/solidconnection/s3/FileUploadService.java +++ b/src/main/java/com/example/solidconnection/s3/FileUploadService.java @@ -22,6 +22,7 @@ @EnableAsync @Slf4j public class FileUploadService { + private final AmazonS3Client amazonS3; public FileUploadService(AmazonS3Client amazonS3) { diff --git a/src/main/java/com/example/solidconnection/s3/S3Controller.java b/src/main/java/com/example/solidconnection/s3/S3Controller.java index 7a1c1fc7c..2c513cb8c 100644 --- a/src/main/java/com/example/solidconnection/s3/S3Controller.java +++ b/src/main/java/com/example/solidconnection/s3/S3Controller.java @@ -4,7 +4,11 @@ import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.security.Principal; @@ -15,12 +19,16 @@ public class S3Controller implements S3ControllerSwagger { private final S3Service s3Service; + @Value("${cloud.aws.s3.url.default}") private String s3Default; + @Value("${cloud.aws.s3.url.uploaded}") private String s3Uploaded; + @Value("${cloud.aws.cloudFront.url.default}") private String cloudFrontDefault; + @Value("${cloud.aws.cloudFront.url.uploaded}") private String cloudFrontUploaded; diff --git a/src/main/java/com/example/solidconnection/s3/S3Service.java b/src/main/java/com/example/solidconnection/s3/S3Service.java index 534c4a935..049be9fa3 100644 --- a/src/main/java/com/example/solidconnection/s3/S3Service.java +++ b/src/main/java/com/example/solidconnection/s3/S3Service.java @@ -16,7 +16,11 @@ import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.UUID; import static com.example.solidconnection.custom.exception.ErrorCode.FILE_NOT_EXIST; import static com.example.solidconnection.custom.exception.ErrorCode.INVALID_FILE_EXTENSIONS; @@ -29,13 +33,15 @@ public class S3Service { private static final Logger log = LoggerFactory.getLogger(S3Service.class); + private static final long MAX_FILE_SIZE_MB = 1024 * 1024 * 3; + private final AmazonS3Client amazonS3; private final SiteUserRepository siteUserRepository; private final FileUploadService fileUploadService; private final ThreadPoolTaskExecutor asyncExecutor; + @Value("${cloud.aws.s3.bucket}") private String bucket; - private final long MAX_FILE_SIZE_MB = 1024 * 1024 * 3; /* * 파일을 S3에 업로드한다. diff --git a/src/main/java/com/example/solidconnection/scheduler/UpdateViewCountScheduler.java b/src/main/java/com/example/solidconnection/scheduler/UpdateViewCountScheduler.java index 41ba66398..8da1fe1ca 100644 --- a/src/main/java/com/example/solidconnection/scheduler/UpdateViewCountScheduler.java +++ b/src/main/java/com/example/solidconnection/scheduler/UpdateViewCountScheduler.java @@ -13,7 +13,7 @@ import java.util.List; -import static com.example.solidconnection.type.RedisConstants.*; +import static com.example.solidconnection.type.RedisConstants.VIEW_COUNT_KEY_PATTERN; @RequiredArgsConstructor @Component diff --git a/src/main/java/com/example/solidconnection/score/controller/ScoreController.java b/src/main/java/com/example/solidconnection/score/controller/ScoreController.java index 7bd0edaf2..7550102aa 100644 --- a/src/main/java/com/example/solidconnection/score/controller/ScoreController.java +++ b/src/main/java/com/example/solidconnection/score/controller/ScoreController.java @@ -1,13 +1,20 @@ package com.example.solidconnection.score.controller; -import com.example.solidconnection.score.dto.*; +import com.example.solidconnection.score.dto.GpaScoreRequest; +import com.example.solidconnection.score.dto.GpaScoreStatusResponse; +import com.example.solidconnection.score.dto.LanguageTestScoreRequest; +import com.example.solidconnection.score.dto.LanguageTestScoreStatusResponse; import com.example.solidconnection.score.service.ScoreService; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirements; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import java.security.Principal; diff --git a/src/main/java/com/example/solidconnection/score/domain/GpaScore.java b/src/main/java/com/example/solidconnection/score/domain/GpaScore.java index 2747f8c88..17b5cca48 100644 --- a/src/main/java/com/example/solidconnection/score/domain/GpaScore.java +++ b/src/main/java/com/example/solidconnection/score/domain/GpaScore.java @@ -4,7 +4,15 @@ import com.example.solidconnection.entity.common.BaseEntity; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.type.VerifyStatus; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; @@ -17,9 +25,11 @@ @NoArgsConstructor @EqualsAndHashCode public class GpaScore extends BaseEntity { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Embedded private Gpa gpa; diff --git a/src/main/java/com/example/solidconnection/score/domain/LanguageTestScore.java b/src/main/java/com/example/solidconnection/score/domain/LanguageTestScore.java index bc16bc4e4..88501f686 100644 --- a/src/main/java/com/example/solidconnection/score/domain/LanguageTestScore.java +++ b/src/main/java/com/example/solidconnection/score/domain/LanguageTestScore.java @@ -4,7 +4,15 @@ import com.example.solidconnection.entity.common.BaseEntity; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.type.VerifyStatus; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -17,9 +25,11 @@ @NoArgsConstructor @AllArgsConstructor public class LanguageTestScore extends BaseEntity { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Embedded private LanguageTest languageTest; diff --git a/src/main/java/com/example/solidconnection/score/repository/GpaScoreRepository.java b/src/main/java/com/example/solidconnection/score/repository/GpaScoreRepository.java index c5fbb2847..e3c26665b 100644 --- a/src/main/java/com/example/solidconnection/score/repository/GpaScoreRepository.java +++ b/src/main/java/com/example/solidconnection/score/repository/GpaScoreRepository.java @@ -9,6 +9,7 @@ @Repository public interface GpaScoreRepository extends JpaRepository { + Optional findGpaScoreBySiteUser(SiteUser siteUser); Optional findGpaScoreBySiteUserAndId(SiteUser siteUser, Long id); diff --git a/src/main/java/com/example/solidconnection/score/service/ScoreService.java b/src/main/java/com/example/solidconnection/score/service/ScoreService.java index b2d9ad29e..d09038fa5 100644 --- a/src/main/java/com/example/solidconnection/score/service/ScoreService.java +++ b/src/main/java/com/example/solidconnection/score/service/ScoreService.java @@ -3,7 +3,12 @@ import com.example.solidconnection.application.domain.LanguageTest; import com.example.solidconnection.score.domain.GpaScore; import com.example.solidconnection.score.domain.LanguageTestScore; -import com.example.solidconnection.score.dto.*; +import com.example.solidconnection.score.dto.GpaScoreRequest; +import com.example.solidconnection.score.dto.GpaScoreStatus; +import com.example.solidconnection.score.dto.GpaScoreStatusResponse; +import com.example.solidconnection.score.dto.LanguageTestScoreRequest; +import com.example.solidconnection.score.dto.LanguageTestScoreStatus; +import com.example.solidconnection.score.dto.LanguageTestScoreStatusResponse; import com.example.solidconnection.score.repository.GpaScoreRepository; import com.example.solidconnection.score.repository.LanguageTestScoreRepository; import com.example.solidconnection.siteuser.domain.SiteUser; diff --git a/src/main/java/com/example/solidconnection/service/RedisService.java b/src/main/java/com/example/solidconnection/service/RedisService.java index 9816a264e..93a9de74f 100644 --- a/src/main/java/com/example/solidconnection/service/RedisService.java +++ b/src/main/java/com/example/solidconnection/service/RedisService.java @@ -9,10 +9,12 @@ import java.util.Collections; import java.util.concurrent.TimeUnit; -import static com.example.solidconnection.type.RedisConstants.*; +import static com.example.solidconnection.type.RedisConstants.VALIDATE_VIEW_COUNT_TTL; +import static com.example.solidconnection.type.RedisConstants.VIEW_COUNT_TTL; @Service public class RedisService { + private final RedisTemplate redisTemplate; private final RedisScript incrViewCountLuaScript; @@ -28,7 +30,7 @@ public void increaseViewCount(String key) { redisTemplate.execute(incrViewCountLuaScript, Collections.singletonList(key), VIEW_COUNT_TTL.getValue()); } - public void deleteKey(String key){ + public void deleteKey(String key) { redisTemplate.opsForValue().getAndDelete(key); } diff --git a/src/main/java/com/example/solidconnection/siteuser/controller/SiteUserController.java b/src/main/java/com/example/solidconnection/siteuser/controller/SiteUserController.java index 443404def..d03c69fa8 100644 --- a/src/main/java/com/example/solidconnection/siteuser/controller/SiteUserController.java +++ b/src/main/java/com/example/solidconnection/siteuser/controller/SiteUserController.java @@ -1,11 +1,20 @@ package com.example.solidconnection.siteuser.controller; -import com.example.solidconnection.siteuser.dto.*; +import com.example.solidconnection.siteuser.dto.MyPageResponse; +import com.example.solidconnection.siteuser.dto.MyPageUpdateResponse; +import com.example.solidconnection.siteuser.dto.NicknameUpdateRequest; +import com.example.solidconnection.siteuser.dto.NicknameUpdateResponse; +import com.example.solidconnection.siteuser.dto.ProfileImageUpdateResponse; import com.example.solidconnection.siteuser.service.SiteUserService; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.security.Principal; diff --git a/src/main/java/com/example/solidconnection/siteuser/controller/SiteUserControllerSwagger.java b/src/main/java/com/example/solidconnection/siteuser/controller/SiteUserControllerSwagger.java index 6f479f67e..260610436 100644 --- a/src/main/java/com/example/solidconnection/siteuser/controller/SiteUserControllerSwagger.java +++ b/src/main/java/com/example/solidconnection/siteuser/controller/SiteUserControllerSwagger.java @@ -1,17 +1,14 @@ package com.example.solidconnection.siteuser.controller; import com.example.solidconnection.siteuser.dto.MyPageResponse; -import com.example.solidconnection.siteuser.dto.MyPageUpdateRequest; import com.example.solidconnection.siteuser.dto.MyPageUpdateResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.parameters.RequestBody; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.security.SecurityRequirements; import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.validation.Valid; import org.springframework.http.ResponseEntity; import java.security.Principal; diff --git a/src/main/java/com/example/solidconnection/siteuser/domain/SiteUser.java b/src/main/java/com/example/solidconnection/siteuser/domain/SiteUser.java index 47a071b04..d548ff852 100644 --- a/src/main/java/com/example/solidconnection/siteuser/domain/SiteUser.java +++ b/src/main/java/com/example/solidconnection/siteuser/domain/SiteUser.java @@ -8,8 +8,20 @@ import com.example.solidconnection.type.Gender; import com.example.solidconnection.type.PreparationStatus; import com.example.solidconnection.type.Role; -import jakarta.persistence.*; -import lombok.*; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; import java.time.LocalDate; import java.time.LocalDateTime; diff --git a/src/main/java/com/example/solidconnection/siteuser/dto/MyPageResponse.java b/src/main/java/com/example/solidconnection/siteuser/dto/MyPageResponse.java index 892094394..88396f5b9 100644 --- a/src/main/java/com/example/solidconnection/siteuser/dto/MyPageResponse.java +++ b/src/main/java/com/example/solidconnection/siteuser/dto/MyPageResponse.java @@ -2,7 +2,6 @@ import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.type.Role; - import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "마이페이지 페이지 정보 응답") diff --git a/src/main/java/com/example/solidconnection/siteuser/dto/MyPageUpdateResponse.java b/src/main/java/com/example/solidconnection/siteuser/dto/MyPageUpdateResponse.java index d186b08af..5572d5a2d 100644 --- a/src/main/java/com/example/solidconnection/siteuser/dto/MyPageUpdateResponse.java +++ b/src/main/java/com/example/solidconnection/siteuser/dto/MyPageUpdateResponse.java @@ -11,10 +11,10 @@ public record MyPageUpdateResponse( @Schema(description = "업데이트된 프로필 이미지 URL", example = "http://example.com/updated-profile.jpg") String profileImageUrl) { - public static MyPageUpdateResponse from(SiteUser siteUser) { - return new MyPageUpdateResponse( - siteUser.getNickname(), - siteUser.getProfileImageUrl() - ); - } + public static MyPageUpdateResponse from(SiteUser siteUser) { + return new MyPageUpdateResponse( + siteUser.getNickname(), + siteUser.getProfileImageUrl() + ); + } } diff --git a/src/main/java/com/example/solidconnection/siteuser/service/SiteUserService.java b/src/main/java/com/example/solidconnection/siteuser/service/SiteUserService.java index 793627adf..a7a2e5d71 100644 --- a/src/main/java/com/example/solidconnection/siteuser/service/SiteUserService.java +++ b/src/main/java/com/example/solidconnection/siteuser/service/SiteUserService.java @@ -4,7 +4,11 @@ import com.example.solidconnection.s3.S3Service; import com.example.solidconnection.s3.UploadedFileUrlResponse; import com.example.solidconnection.siteuser.domain.SiteUser; -import com.example.solidconnection.siteuser.dto.*; +import com.example.solidconnection.siteuser.dto.MyPageResponse; +import com.example.solidconnection.siteuser.dto.MyPageUpdateResponse; +import com.example.solidconnection.siteuser.dto.NicknameUpdateRequest; +import com.example.solidconnection.siteuser.dto.NicknameUpdateResponse; +import com.example.solidconnection.siteuser.dto.ProfileImageUpdateResponse; import com.example.solidconnection.siteuser.repository.LikedUniversityRepository; import com.example.solidconnection.siteuser.repository.SiteUserRepository; import com.example.solidconnection.type.ImgType; @@ -19,7 +23,9 @@ import java.time.format.DateTimeFormatter; import java.util.List; -import static com.example.solidconnection.custom.exception.ErrorCode.*; +import static com.example.solidconnection.custom.exception.ErrorCode.CAN_NOT_CHANGE_NICKNAME_YET; +import static com.example.solidconnection.custom.exception.ErrorCode.NICKNAME_ALREADY_EXISTED; +import static com.example.solidconnection.custom.exception.ErrorCode.PROFILE_IMAGE_NEEDED; @RequiredArgsConstructor @Service @@ -51,22 +57,6 @@ public MyPageUpdateResponse getMyPageInfoToUpdate(String email) { return MyPageUpdateResponse.from(siteUser); } - private void validateNicknameDuplicated(String nickname) { - if (siteUserRepository.existsByNickname(nickname)) { - throw new CustomException(NICKNAME_ALREADY_EXISTED); - } - } - private void validateNicknameNotChangedRecently(LocalDateTime lastModifiedAt) { - if (lastModifiedAt == null) { - return; - } - if (LocalDateTime.now().isBefore(lastModifiedAt.plusDays(MIN_DAYS_BETWEEN_NICKNAME_CHANGES))) { - String formatLastModifiedAt - = String.format("(마지막 수정 시간 : %s)", NICKNAME_LAST_CHANGE_DATE_FORMAT.format(lastModifiedAt)); - throw new CustomException(CAN_NOT_CHANGE_NICKNAME_YET, formatLastModifiedAt); - } - } - /* * 관심 대학교 목록을 조회한다. * */ @@ -79,7 +69,6 @@ public List getWishUniversity(String emai .toList(); } - /* * 프로필 이미지를 수정한다. * */ @@ -89,7 +78,7 @@ public ProfileImageUpdateResponse updateProfileImage(String email, MultipartFile validateProfileImage(imageFile); // 프로필 이미지를 처음 수정하는 경우에는 deleteExProfile 수행하지 않음 - if(!isDefaultProfileImage(siteUser.getProfileImageUrl())){ + if (!isDefaultProfileImage(siteUser.getProfileImageUrl())) { s3Service.deleteExProfile(email); } UploadedFileUrlResponse uploadedFileUrlResponse = s3Service.uploadFile(imageFile, ImgType.PROFILE); @@ -104,7 +93,6 @@ private void validateProfileImage(MultipartFile imageFile) { throw new CustomException(PROFILE_IMAGE_NEEDED); } } - private boolean isDefaultProfileImage(String profileImageUrl) { String prefix = "profile/"; return profileImageUrl == null || !profileImageUrl.startsWith(prefix); @@ -126,4 +114,21 @@ public NicknameUpdateResponse updateNickname(String email, NicknameUpdateRequest return NicknameUpdateResponse.from(siteUser); } + + private void validateNicknameDuplicated(String nickname) { + if (siteUserRepository.existsByNickname(nickname)) { + throw new CustomException(NICKNAME_ALREADY_EXISTED); + } + } + + private void validateNicknameNotChangedRecently(LocalDateTime lastModifiedAt) { + if (lastModifiedAt == null) { + return; + } + if (LocalDateTime.now().isBefore(lastModifiedAt.plusDays(MIN_DAYS_BETWEEN_NICKNAME_CHANGES))) { + String formatLastModifiedAt + = String.format("(마지막 수정 시간 : %s)", NICKNAME_LAST_CHANGE_DATE_FORMAT.format(lastModifiedAt)); + throw new CustomException(CAN_NOT_CHANGE_NICKNAME_YET, formatLastModifiedAt); + } + } } diff --git a/src/main/java/com/example/solidconnection/university/domain/University.java b/src/main/java/com/example/solidconnection/university/domain/University.java index 8e31dfa4a..c3021385e 100644 --- a/src/main/java/com/example/solidconnection/university/domain/University.java +++ b/src/main/java/com/example/solidconnection/university/domain/University.java @@ -2,7 +2,12 @@ import com.example.solidconnection.entity.Country; import com.example.solidconnection.entity.Region; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/src/main/java/com/example/solidconnection/university/dto/UniversityDetailResponse.java b/src/main/java/com/example/solidconnection/university/dto/UniversityDetailResponse.java index 118bfdaa6..ed4c6109b 100644 --- a/src/main/java/com/example/solidconnection/university/dto/UniversityDetailResponse.java +++ b/src/main/java/com/example/solidconnection/university/dto/UniversityDetailResponse.java @@ -9,7 +9,6 @@ @Schema(description = "대학 세부 사항 응답 데이터") public record UniversityDetailResponse( - @Schema(description = "대학 지원을 위한 정보 id", example = "1") long id, diff --git a/src/main/java/com/example/solidconnection/university/dto/UniversityInfoForApplyPreviewResponse.java b/src/main/java/com/example/solidconnection/university/dto/UniversityInfoForApplyPreviewResponse.java index fe5713c67..de0987eaf 100644 --- a/src/main/java/com/example/solidconnection/university/dto/UniversityInfoForApplyPreviewResponse.java +++ b/src/main/java/com/example/solidconnection/university/dto/UniversityInfoForApplyPreviewResponse.java @@ -36,8 +36,8 @@ public record UniversityInfoForApplyPreviewResponse( public static UniversityInfoForApplyPreviewResponse from(UniversityInfoForApply universityInfoForApply) { List languageRequirementResponses = new java.util.ArrayList<>( universityInfoForApply.getLanguageRequirements().stream() - .map(LanguageRequirementResponse::from) - .toList()); + .map(LanguageRequirementResponse::from) + .toList()); Collections.sort(languageRequirementResponses); return new UniversityInfoForApplyPreviewResponse( diff --git a/src/main/java/com/example/solidconnection/university/repository/custom/UniversityFilterRepositoryImpl.java b/src/main/java/com/example/solidconnection/university/repository/custom/UniversityFilterRepositoryImpl.java index 0beac6763..dd84cfbf5 100644 --- a/src/main/java/com/example/solidconnection/university/repository/custom/UniversityFilterRepositoryImpl.java +++ b/src/main/java/com/example/solidconnection/university/repository/custom/UniversityFilterRepositoryImpl.java @@ -85,8 +85,8 @@ public List findByRegionCodeAndKeywordsAndLanguageTestTy .and(universityInfoForApply.term.eq(term))) .fetch(); - if(testScore == null || testScore.isEmpty()) { - if(testType != null) { + if (testScore == null || testScore.isEmpty()) { + if (testType != null) { return filteredUniversityInfoForApply.stream() .filter(uifa -> uifa.getLanguageRequirements().stream() .anyMatch(lr -> lr.getLanguageTestType().equals(testType))) diff --git a/src/main/java/com/example/solidconnection/university/service/UniversityService.java b/src/main/java/com/example/solidconnection/university/service/UniversityService.java index c0cbe2c05..708374e96 100644 --- a/src/main/java/com/example/solidconnection/university/service/UniversityService.java +++ b/src/main/java/com/example/solidconnection/university/service/UniversityService.java @@ -8,7 +8,11 @@ import com.example.solidconnection.university.domain.LikedUniversity; import com.example.solidconnection.university.domain.University; import com.example.solidconnection.university.domain.UniversityInfoForApply; -import com.example.solidconnection.university.dto.*; +import com.example.solidconnection.university.dto.IsLikeResponse; +import com.example.solidconnection.university.dto.LikeResultResponse; +import com.example.solidconnection.university.dto.UniversityDetailResponse; +import com.example.solidconnection.university.dto.UniversityInfoForApplyPreviewResponse; +import com.example.solidconnection.university.dto.UniversityInfoForApplyPreviewResponses; import com.example.solidconnection.university.repository.UniversityInfoForApplyRepository; import com.example.solidconnection.university.repository.custom.UniversityFilterRepositoryImpl; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/example/solidconnection/util/RedisUtils.java b/src/main/java/com/example/solidconnection/util/RedisUtils.java index ef91dfc3d..6c56fa73f 100644 --- a/src/main/java/com/example/solidconnection/util/RedisUtils.java +++ b/src/main/java/com/example/solidconnection/util/RedisUtils.java @@ -11,7 +11,10 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import static com.example.solidconnection.type.RedisConstants.*; +import static com.example.solidconnection.type.RedisConstants.CREATE_LOCK_PREFIX; +import static com.example.solidconnection.type.RedisConstants.REFRESH_LOCK_PREFIX; +import static com.example.solidconnection.type.RedisConstants.VALIDATE_VIEW_COUNT_KEY_PREFIX; +import static com.example.solidconnection.type.RedisConstants.VIEW_COUNT_KEY_PREFIX; @Component public class RedisUtils { @@ -70,6 +73,6 @@ public String getRefreshLockKey(String key) { public boolean isCacheExpiringSoon(String key, Long defaultTtl, Double percent) { Long leftTtl = redisTemplate.getExpire(key); - return defaultTtl != null && ((double) leftTtl /defaultTtl)*100 < percent; + return defaultTtl != null && ((double) leftTtl / defaultTtl) * 100 < percent; } } diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html deleted file mode 100644 index c3dca01d5..000000000 --- a/src/main/resources/static/index.html +++ /dev/null @@ -1,3 +0,0 @@ - -

Solid Connection Backend Page

-이 페이지가 보이면 백엔드 배포 서버가 잘 작동하고 있다는 것입니다. \ No newline at end of file diff --git a/src/test/java/com/example/solidconnection/unit/service/PostServiceTest.java b/src/test/java/com/example/solidconnection/unit/service/PostServiceTest.java index 917d073f5..57c5916a9 100644 --- a/src/test/java/com/example/solidconnection/unit/service/PostServiceTest.java +++ b/src/test/java/com/example/solidconnection/unit/service/PostServiceTest.java @@ -7,7 +7,7 @@ import com.example.solidconnection.comment.service.CommentService; import com.example.solidconnection.custom.exception.CustomException; import com.example.solidconnection.custom.exception.ErrorCode; -import com.example.solidconnection.dto.PostFindPostImageResponse; +import com.example.solidconnection.post.dto.PostFindPostImageResponse; import com.example.solidconnection.entity.PostImage; import com.example.solidconnection.post.domain.PostLike; import com.example.solidconnection.post.repository.PostLikeRepository;