-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
38 changed files
with
1,986 additions
and
361 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 17 additions & 11 deletions
28
backend/bang-ggood/src/main/java/com/bang_ggood/article/controller/ArticleController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,58 @@ | ||
package com.bang_ggood.article.controller; | ||
|
||
import com.bang_ggood.article.dto.request.ArticleCreateRequest; | ||
import com.bang_ggood.article.dto.request.ArticleUpdateRequest; | ||
import com.bang_ggood.article.dto.response.ArticleResponse; | ||
import com.bang_ggood.article.dto.response.ArticlesResponses; | ||
import com.bang_ggood.article.service.ArticleService; | ||
import com.bang_ggood.article.service.ArticleManageService; | ||
import com.bang_ggood.auth.config.AdminPrincipal; | ||
import com.bang_ggood.auth.config.AuthRequiredPrincipal; | ||
import com.bang_ggood.user.domain.User; | ||
import jakarta.validation.Valid; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.DeleteMapping; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.PutMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import java.net.URI; | ||
|
||
@RequiredArgsConstructor | ||
@RestController | ||
public class ArticleController { | ||
|
||
private final ArticleService articleService; | ||
|
||
public ArticleController(ArticleService articleService) { | ||
this.articleService = articleService; | ||
} | ||
private final ArticleManageService articleManageService; | ||
|
||
@PostMapping("/articles") | ||
public ResponseEntity<Void> createArticle(@AdminPrincipal User user, | ||
@Valid @RequestBody ArticleCreateRequest request) { | ||
Long id = articleService.createArticle(request); | ||
Long id = articleManageService.createArticle(request); | ||
return ResponseEntity.created(URI.create("/article/" + id)).build(); | ||
} | ||
|
||
@GetMapping("/articles/{id}") | ||
public ResponseEntity<ArticleResponse> readArticle(@PathVariable("id") Long id) { | ||
return ResponseEntity.ok(articleService.readArticle(id)); | ||
return ResponseEntity.ok(articleManageService.readArticle(id)); | ||
} | ||
|
||
@GetMapping("/articles") | ||
public ResponseEntity<ArticlesResponses> readArticles() { | ||
return ResponseEntity.ok(articleService.readArticles()); | ||
return ResponseEntity.ok(articleManageService.readArticles()); | ||
} | ||
|
||
@PutMapping("/articles/{id}") | ||
public ResponseEntity<Void> updateArticle(@AdminPrincipal User user, | ||
@PathVariable("id") Long id, @Valid @RequestBody ArticleUpdateRequest request) { | ||
articleManageService.updateArticle(id, request); | ||
return ResponseEntity.noContent().build(); | ||
} | ||
|
||
@DeleteMapping("/articles/{id}") | ||
public ResponseEntity<ArticleResponse> deleteArticle(@AdminPrincipal User user, | ||
@PathVariable("id") Long id) { | ||
articleService.deleteArticle(id); | ||
articleManageService.deleteArticle(id); | ||
return ResponseEntity.noContent().build(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 12 additions & 0 deletions
12
...end/bang-ggood/src/main/java/com/bang_ggood/article/dto/request/ArticleUpdateRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.bang_ggood.article.dto.request; | ||
|
||
import com.bang_ggood.article.domain.Article; | ||
import jakarta.validation.constraints.NotBlank; | ||
|
||
public record ArticleUpdateRequest(@NotBlank(message = "제목을 입력해야 합니다.") String title, String content, String keyword, | ||
String summary, String thumbnail) { | ||
|
||
public Article toEntity() { | ||
return new Article(title, content, keyword, summary, thumbnail); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
backend/bang-ggood/src/main/java/com/bang_ggood/article/service/ArticleManageService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package com.bang_ggood.article.service; | ||
|
||
import com.bang_ggood.article.domain.Article; | ||
import com.bang_ggood.article.dto.request.ArticleCreateRequest; | ||
import com.bang_ggood.article.dto.request.ArticleUpdateRequest; | ||
import com.bang_ggood.article.dto.response.ArticleResponse; | ||
import com.bang_ggood.article.dto.response.ArticlesResponse; | ||
import com.bang_ggood.article.dto.response.ArticlesResponses; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
import java.util.List; | ||
|
||
@RequiredArgsConstructor | ||
@Service | ||
public class ArticleManageService { | ||
|
||
private final ArticleService articleService; | ||
private final ArticleViewService articleViewService; | ||
|
||
@Transactional | ||
public Long createArticle(ArticleCreateRequest request) { | ||
Article article = request.toEntity(); | ||
return articleService.createArticle(article); | ||
} | ||
|
||
@Transactional(readOnly = true) | ||
public ArticleResponse readArticle(Long id) { | ||
Article article = articleService.readArticle(id); | ||
articleViewService.increaseViewCount(id); | ||
return ArticleResponse.from(article); | ||
} | ||
|
||
@Transactional(readOnly = true) | ||
public ArticlesResponses readArticles() { | ||
List<ArticlesResponse> articles = articleService.readArticles().stream() | ||
.map(ArticlesResponse::from) | ||
.toList(); | ||
return new ArticlesResponses(articles); | ||
} | ||
|
||
@Transactional | ||
public void updateArticle(Long id, ArticleUpdateRequest request) { | ||
articleViewService.syncViewCounts(); | ||
articleService.updateArticle(id, request.toEntity()); | ||
} | ||
|
||
@Transactional | ||
public void deleteArticle(Long id) { | ||
articleViewService.syncViewCounts(); | ||
articleService.deleteArticle(id); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
56 changes: 56 additions & 0 deletions
56
backend/bang-ggood/src/main/java/com/bang_ggood/article/service/ArticleViewService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package com.bang_ggood.article.service; | ||
|
||
import com.bang_ggood.article.domain.Article; | ||
import com.bang_ggood.article.repository.ArticleRepository; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.cache.Cache; | ||
import org.springframework.cache.CacheManager; | ||
import org.springframework.scheduling.annotation.Scheduled; | ||
import org.springframework.stereotype.Service; | ||
import java.util.HashSet; | ||
import java.util.Objects; | ||
import java.util.Set; | ||
|
||
import static com.bang_ggood.global.config.cache.CacheName.ARTICLE; | ||
|
||
@RequiredArgsConstructor | ||
@Service | ||
public class ArticleViewService { | ||
|
||
private final CacheManager cacheManager; | ||
private final ArticleRepository articleRepository; | ||
private final Set<Long> cacheArticleIds = new HashSet<>(); | ||
|
||
public void increaseViewCount(long id) { | ||
Cache cache = cacheManager.getCache(ARTICLE); | ||
if (cache != null) { | ||
handleViewCount(id, cache); | ||
} | ||
} | ||
|
||
private void handleViewCount(long id, Cache cache) { | ||
Article article = cache.get(id, Article.class); | ||
if (article != null) { | ||
article.increaseViewCount(); | ||
cache.put(id, article); | ||
cacheArticleIds.add(id); | ||
} | ||
} | ||
|
||
@Scheduled(cron = "0 0 0 * * ?") | ||
public void syncViewCounts() { | ||
Cache cache = cacheManager.getCache(ARTICLE); | ||
if (cache != null) { | ||
syncAllArticleViewCounts(cache); | ||
cache.clear(); | ||
cacheArticleIds.clear(); | ||
} | ||
} | ||
|
||
private void syncAllArticleViewCounts(Cache cache) { | ||
cacheArticleIds.stream() | ||
.map(id -> cache.get(id, Article.class)) | ||
.filter(Objects::nonNull) | ||
.forEach(article -> articleRepository.updateViewCount(article.getId(), article.getViewCount())); | ||
} | ||
} |
Oops, something went wrong.