헥사고날 아키텍쳐로 리아키텍쳐링 마무리, DDD를 적용하여 두꺼운 도메인, 얇은 서비스로 리팩토링
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
package myblog.blog.article.adapter.incomming.web;
|
||||
package myblog.blog.article.adapter.incomming;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@@ -6,17 +6,16 @@ import myblog.blog.article.application.port.incomming.ArticleUseCase;
|
||||
import myblog.blog.article.application.port.incomming.TempArticleUseCase;
|
||||
import myblog.blog.article.application.port.incomming.ArticleQueriesUseCase;
|
||||
import myblog.blog.article.application.port.incomming.TagsQueriesUseCase;
|
||||
import myblog.blog.article.application.port.request.ArticleCreateRequest;
|
||||
import myblog.blog.article.application.port.request.ArticleEditRequest;
|
||||
import myblog.blog.article.application.port.response.ArticleResponseByCategory;
|
||||
import myblog.blog.article.application.port.response.ArticleResponseForCardBox;
|
||||
import myblog.blog.article.application.port.response.ArticleResponseForDetail;
|
||||
import myblog.blog.article.application.port.response.ArticleResponseForEdit;
|
||||
|
||||
import myblog.blog.category.appliacation.port.incomming.CategoryUseCase;
|
||||
import myblog.blog.category.appliacation.port.response.CategoryViewForLayout;
|
||||
import myblog.blog.member.auth.PrincipalDetails;
|
||||
import myblog.blog.member.dto.MemberVo;
|
||||
import myblog.blog.article.application.port.incomming.request.ArticleCreateRequest;
|
||||
import myblog.blog.article.application.port.incomming.request.ArticleEditRequest;
|
||||
import myblog.blog.category.appliacation.port.incomming.response.CategoryViewForLayout;
|
||||
import myblog.blog.article.application.port.incomming.response.ArticleResponseByCategory;
|
||||
import myblog.blog.article.application.port.incomming.response.ArticleResponseForCardBox;
|
||||
import myblog.blog.article.application.port.incomming.response.ArticleResponseForDetail;
|
||||
import myblog.blog.article.application.port.incomming.response.ArticleResponseForEdit;
|
||||
import myblog.blog.member.application.port.incomming.response.PrincipalDetails;
|
||||
|
||||
import myblog.blog.shared.queries.LayoutRenderingQueries;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
@@ -209,7 +208,7 @@ public class ArticleController {
|
||||
Model model) {
|
||||
// 1. 로그인 여부에 따라 뷰단에 회원정보 출력 여부 결정
|
||||
if (principal != null) {
|
||||
model.addAttribute("member", MemberVo.from(principal.getMember()));
|
||||
model.addAttribute("member", principal.getMember());
|
||||
} else {
|
||||
model.addAttribute("member", null);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package myblog.blog.article.adapter.incomming.web;
|
||||
package myblog.blog.article.adapter.incomming;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -1,8 +1,8 @@
|
||||
package myblog.blog.article.adapter.incomming.web;
|
||||
package myblog.blog.article.adapter.incomming;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import myblog.blog.article.application.port.response.ArticleResponseForCardBox;
|
||||
import myblog.blog.article.application.port.incomming.response.ArticleResponseForCardBox;
|
||||
import myblog.blog.article.application.port.incomming.ArticleQueriesUseCase;
|
||||
import myblog.blog.shared.queries.LayoutRenderingQueries;
|
||||
import org.jsoup.Jsoup;
|
||||
@@ -1,4 +1,4 @@
|
||||
package myblog.blog.article.adapter.incomming.web;
|
||||
package myblog.blog.article.adapter.incomming;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -1,9 +1,9 @@
|
||||
package myblog.blog.article.adapter.incomming.web;
|
||||
package myblog.blog.article.adapter.incomming;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import myblog.blog.article.domain.TempArticle;
|
||||
import myblog.blog.article.application.TempArticleService;
|
||||
import myblog.blog.article.application.port.response.TempArticleResponse;
|
||||
import myblog.blog.article.application.port.incomming.response.TempArticleResponse;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Optional;
|
||||
@@ -2,17 +2,17 @@ package myblog.blog.article.application;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import myblog.blog.article.application.port.response.ArticleResponseForCardBox;
|
||||
import myblog.blog.article.application.port.incomming.response.ArticleResponseForCardBox;
|
||||
import myblog.blog.article.application.port.incomming.ArticleQueriesUseCase;
|
||||
import myblog.blog.article.application.port.outgoing.ArticleRepositoryPort;
|
||||
|
||||
import myblog.blog.article.domain.Article;
|
||||
import myblog.blog.category.appliacation.port.incomming.CategoryUseCase;
|
||||
import myblog.blog.category.domain.Category;
|
||||
import myblog.blog.article.application.port.response.ArticleResponseByCategory;
|
||||
import myblog.blog.article.application.port.response.ArticleResponseForDetail;
|
||||
import myblog.blog.article.application.port.response.ArticleResponseForEdit;
|
||||
import myblog.blog.article.application.port.incomming.response.ArticleResponseByCategory;
|
||||
import myblog.blog.article.application.port.incomming.response.ArticleResponseForDetail;
|
||||
import myblog.blog.article.application.port.incomming.response.ArticleResponseForEdit;
|
||||
|
||||
import myblog.blog.category.appliacation.CategoryService;
|
||||
import org.modelmapper.ModelMapper;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -27,7 +27,7 @@ import java.util.stream.Collectors;
|
||||
public class ArticleQueries implements ArticleQueriesUseCase {
|
||||
|
||||
private final ArticleRepositoryPort articleRepositoryPort;
|
||||
private final CategoryService categoryService;
|
||||
private final CategoryUseCase categoryUseCase;
|
||||
private final ModelMapper modelMapper;
|
||||
|
||||
/*
|
||||
@@ -130,7 +130,7 @@ public class ArticleQueries implements ArticleQueriesUseCase {
|
||||
*/
|
||||
@Override
|
||||
public List<ArticleResponseByCategory> getArticlesByCategoryForDetailView(String categoryName){
|
||||
Category category = categoryService.findCategory(categoryName);
|
||||
Category category = categoryUseCase.findCategory(categoryName);
|
||||
return articleRepositoryPort.findTop6ByCategoryOrderByIdDesc(category)
|
||||
.stream()
|
||||
.map(article -> modelMapper.map(article, ArticleResponseByCategory.class))
|
||||
|
||||
@@ -2,10 +2,12 @@ package myblog.blog.article.application;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import myblog.blog.article.application.port.request.ArticleCreateRequest;
|
||||
import myblog.blog.article.application.port.request.ArticleEditRequest;
|
||||
import myblog.blog.article.application.port.incomming.request.ArticleCreateRequest;
|
||||
import myblog.blog.article.application.port.incomming.request.ArticleEditRequest;
|
||||
import myblog.blog.article.application.port.incomming.ArticleUseCase;
|
||||
import myblog.blog.article.application.port.incomming.TagUseCase;
|
||||
import myblog.blog.category.appliacation.port.incomming.CategoryUseCase;
|
||||
import myblog.blog.member.application.port.incomming.MemberUseCase;
|
||||
import myblog.blog.article.application.port.outgoing.ArticleBackupRepositoryPort;
|
||||
import myblog.blog.article.application.port.outgoing.ArticleRepositoryPort;
|
||||
|
||||
@@ -13,8 +15,6 @@ import myblog.blog.article.domain.Article;
|
||||
import myblog.blog.category.domain.Category;
|
||||
import myblog.blog.member.doamin.Member;
|
||||
|
||||
import myblog.blog.category.appliacation.CategoryService;
|
||||
import myblog.blog.member.service.Oauth2MemberService;
|
||||
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -28,16 +28,16 @@ import java.util.List;
|
||||
public class ArticleService implements ArticleUseCase {
|
||||
|
||||
private final TagUseCase tagUseCase;
|
||||
private final CategoryService categoryService;
|
||||
private final Oauth2MemberService memberService;
|
||||
private final CategoryUseCase categoryUseCase;
|
||||
private final MemberUseCase memberUseCase;
|
||||
private final ArticleRepositoryPort articleRepositoryPort;
|
||||
private final ArticleBackupRepositoryPort articleBackupRepositoryPort;
|
||||
|
||||
@Override
|
||||
@CacheEvict(value = {"layoutCaching", "layoutRecentArticleCaching","seoCaching"}, allEntries = true)
|
||||
public Long writeArticle(ArticleCreateRequest articleCreateRequest) {
|
||||
Member writer = memberService.findById(articleCreateRequest.getMemberId());
|
||||
Category category = categoryService.findCategory(articleCreateRequest.getCategory());
|
||||
Member writer = memberUseCase.findById(articleCreateRequest.getMemberId());
|
||||
Category category = categoryUseCase.findCategory(articleCreateRequest.getCategory());
|
||||
Article newArticle = new Article(articleCreateRequest.getTitle(),
|
||||
articleCreateRequest.getContent(),
|
||||
articleCreateRequest.getToc(),
|
||||
@@ -54,7 +54,7 @@ public class ArticleService implements ArticleUseCase {
|
||||
public void editArticle(ArticleEditRequest articleEditRequest) {
|
||||
Article article = articleRepositoryPort.findById(articleEditRequest.getArticleId())
|
||||
.orElseThrow(() -> new IllegalArgumentException("NotFoundArticleException"));
|
||||
Category category = categoryService.findCategory(articleEditRequest.getCategoryName());
|
||||
Category category = categoryUseCase.findCategory(articleEditRequest.getCategoryName());
|
||||
tagUseCase.deleteAllTagsWith(article);
|
||||
tagUseCase.createNewTagsAndArticleTagList(articleEditRequest.getTags(), article);
|
||||
article.edit(articleEditRequest.getContent(),
|
||||
|
||||
@@ -5,7 +5,7 @@ import myblog.blog.article.application.port.outgoing.TagRepositoryPort;
|
||||
import myblog.blog.article.domain.Tags;
|
||||
import myblog.blog.article.application.port.incomming.TagsQueriesUseCase;
|
||||
import myblog.blog.shared.utils.MapperUtils;
|
||||
import myblog.blog.article.application.port.response.TagsResponse;
|
||||
import myblog.blog.article.application.port.incomming.response.TagsResponse;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package myblog.blog.article.application.port.incomming;
|
||||
|
||||
import myblog.blog.article.application.port.response.ArticleResponseForCardBox;
|
||||
import myblog.blog.article.application.port.response.ArticleResponseByCategory;
|
||||
import myblog.blog.article.application.port.response.ArticleResponseForDetail;
|
||||
import myblog.blog.article.application.port.response.ArticleResponseForEdit;
|
||||
import myblog.blog.article.application.port.incomming.response.ArticleResponseForCardBox;
|
||||
import myblog.blog.article.application.port.incomming.response.ArticleResponseByCategory;
|
||||
import myblog.blog.article.application.port.incomming.response.ArticleResponseForDetail;
|
||||
import myblog.blog.article.application.port.incomming.response.ArticleResponseForEdit;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Slice;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package myblog.blog.article.application.port.incomming;
|
||||
|
||||
import myblog.blog.article.application.port.request.ArticleCreateRequest;
|
||||
import myblog.blog.article.application.port.request.ArticleEditRequest;
|
||||
import myblog.blog.article.application.port.incomming.request.ArticleCreateRequest;
|
||||
import myblog.blog.article.application.port.incomming.request.ArticleEditRequest;
|
||||
import myblog.blog.article.domain.Article;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package myblog.blog.article.application.port.incomming;
|
||||
|
||||
import myblog.blog.article.application.port.response.TagsResponse;
|
||||
import myblog.blog.article.application.port.incomming.response.TagsResponse;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package myblog.blog.article.application.port.request;
|
||||
package myblog.blog.article.application.port.incomming.request;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import myblog.blog.article.adapter.incomming.web.ArticleForm;
|
||||
import myblog.blog.article.adapter.incomming.ArticleForm;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@@ -1,8 +1,8 @@
|
||||
package myblog.blog.article.application.port.request;
|
||||
package myblog.blog.article.application.port.incomming.request;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import myblog.blog.article.adapter.incomming.web.ArticleForm;
|
||||
import myblog.blog.article.adapter.incomming.ArticleForm;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@@ -1,4 +1,4 @@
|
||||
package myblog.blog.article.application.port.response;
|
||||
package myblog.blog.article.application.port.incomming.response;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -1,4 +1,4 @@
|
||||
package myblog.blog.article.application.port.response;
|
||||
package myblog.blog.article.application.port.incomming.response;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -1,4 +1,4 @@
|
||||
package myblog.blog.article.application.port.response;
|
||||
package myblog.blog.article.application.port.incomming.response;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -1,4 +1,4 @@
|
||||
package myblog.blog.article.application.port.response;
|
||||
package myblog.blog.article.application.port.incomming.response;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -1,4 +1,4 @@
|
||||
package myblog.blog.article.application.port.response;
|
||||
package myblog.blog.article.application.port.incomming.response;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package myblog.blog.article.application.port.response;
|
||||
package myblog.blog.article.application.port.incomming.response;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -3,7 +3,7 @@ package myblog.blog.base.config;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import myblog.blog.shared.exception.LoginFailHandler;
|
||||
import myblog.blog.member.doamin.Role;
|
||||
import myblog.blog.member.service.Oauth2MemberService;
|
||||
import myblog.blog.member.application.Oauth2MemberService;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
|
||||
@@ -3,9 +3,9 @@ package myblog.blog.category.adapter.imcomming;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import myblog.blog.category.appliacation.port.incomming.CategoryUseCase;
|
||||
import myblog.blog.category.appliacation.port.response.CategoryViewForLayout;
|
||||
import myblog.blog.category.appliacation.port.response.CategorySimpleDto;
|
||||
import myblog.blog.comment.application.port.incomming.CommentDtoForLayout;
|
||||
import myblog.blog.category.appliacation.port.incomming.response.CategoryViewForLayout;
|
||||
import myblog.blog.category.appliacation.port.incomming.response.CategorySimpleDto;
|
||||
import myblog.blog.comment.application.port.incomming.response.CommentDtoForLayout;
|
||||
import myblog.blog.comment.application.CommentService;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
@@ -27,13 +27,13 @@ public class CategoryController {
|
||||
- 카테고리 수정폼 조회
|
||||
*/
|
||||
@GetMapping("/category/edit")
|
||||
public String editCategoryForm(Model model) {
|
||||
String editCategoryForm(Model model) {
|
||||
|
||||
List<CategorySimpleDto> categoryList = categoryUseCase.getCategorytCountList();
|
||||
List<CategorySimpleDto> copyList = new ArrayList<>(List.copyOf(categoryList));
|
||||
copyList.remove(0);
|
||||
CategoryViewForLayout categoryViewForLayout = CategoryViewForLayout.from(categoryList);
|
||||
List<CommentDtoForLayout> comments = commentService.recentCommentList();
|
||||
List<CommentDtoForLayout> comments = commentService.recentCommentListForLayout();
|
||||
|
||||
model.addAttribute("categoryForEdit", copyList);
|
||||
model.addAttribute("category", categoryViewForLayout);
|
||||
@@ -45,8 +45,7 @@ public class CategoryController {
|
||||
- 카테고리 수정 요청
|
||||
*/
|
||||
@PostMapping("/category/edit")
|
||||
public @ResponseBody
|
||||
String editCategory(@RequestBody List<CategorySimpleDto> categoryList, Errors errors) {
|
||||
@ResponseBody String editCategory(@RequestBody List<CategorySimpleDto> categoryList, Errors errors) {
|
||||
// List DTO 검증을 위한 커스텀 validator
|
||||
categorylistValidator.validate(categoryList, errors);
|
||||
categoryUseCase.changeCategory(categoryList);
|
||||
|
||||
@@ -2,7 +2,7 @@ package myblog.blog.category.adapter.outgoing.persistence;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import myblog.blog.category.appliacation.port.outgoing.CategoryRepositoryPort;
|
||||
import myblog.blog.category.appliacation.port.response.CategorySimpleDto;
|
||||
import myblog.blog.category.appliacation.port.incomming.response.CategorySimpleDto;
|
||||
import myblog.blog.category.domain.Category;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package myblog.blog.category.adapter.outgoing.persistence;
|
||||
|
||||
import myblog.blog.category.appliacation.port.response.CategorySimpleDto;
|
||||
import myblog.blog.category.appliacation.port.incomming.response.CategorySimpleDto;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@@ -5,8 +5,8 @@ import lombok.RequiredArgsConstructor;
|
||||
import myblog.blog.category.domain.Category;
|
||||
import myblog.blog.category.appliacation.port.incomming.CategoryUseCase;
|
||||
import myblog.blog.category.appliacation.port.outgoing.CategoryRepositoryPort;
|
||||
import myblog.blog.category.appliacation.port.response.CategorySimpleDto;
|
||||
import myblog.blog.category.appliacation.port.response.CategoryViewForLayout;
|
||||
import myblog.blog.category.appliacation.port.incomming.response.CategorySimpleDto;
|
||||
import myblog.blog.category.appliacation.port.incomming.response.CategoryViewForLayout;
|
||||
|
||||
import org.modelmapper.ModelMapper;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package myblog.blog.category.appliacation.port.incomming;
|
||||
|
||||
import myblog.blog.category.appliacation.port.response.CategorySimpleDto;
|
||||
import myblog.blog.category.appliacation.port.response.CategoryViewForLayout;
|
||||
import myblog.blog.category.appliacation.port.incomming.response.CategorySimpleDto;
|
||||
import myblog.blog.category.appliacation.port.incomming.response.CategoryViewForLayout;
|
||||
import myblog.blog.category.domain.Category;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package myblog.blog.category.appliacation.port.response;
|
||||
package myblog.blog.category.appliacation.port.incomming.response;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -1,4 +1,4 @@
|
||||
package myblog.blog.category.appliacation.port.response;
|
||||
package myblog.blog.category.appliacation.port.incomming.response;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -1,6 +1,6 @@
|
||||
package myblog.blog.category.appliacation.port.outgoing;
|
||||
|
||||
import myblog.blog.category.appliacation.port.response.CategorySimpleDto;
|
||||
import myblog.blog.category.appliacation.port.incomming.response.CategorySimpleDto;
|
||||
import myblog.blog.category.domain.Category;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package myblog.blog.comment.adapter.incomming;
|
||||
|
||||
import myblog.blog.comment.application.port.incomming.CommentUseCase;
|
||||
import myblog.blog.comment.application.port.incomming.CommentDto;
|
||||
import myblog.blog.comment.application.port.incomming.response.CommentDto;
|
||||
|
||||
import myblog.blog.member.auth.PrincipalDetails;
|
||||
|
||||
import myblog.blog.member.doamin.Member;
|
||||
import myblog.blog.member.application.port.incomming.response.PrincipalDetails;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import myblog.blog.member.application.port.incomming.response.MemberVo;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@@ -24,7 +23,7 @@ public class CommentController {
|
||||
- 아티클 조회시 아티클에 달린 댓글들 전체 조회
|
||||
*/
|
||||
@GetMapping("/comment/list/{articleId}")
|
||||
public List<CommentDto> getCommentList(@PathVariable Long articleId){
|
||||
List<CommentDto> getCommentList(@PathVariable Long articleId){
|
||||
return commentUseCase.getCommentList(articleId);
|
||||
}
|
||||
|
||||
@@ -32,7 +31,7 @@ public class CommentController {
|
||||
- 댓글 작성 요청
|
||||
*/
|
||||
@PostMapping("/comment/write")
|
||||
public List<CommentDto> getCommentList(@RequestParam Long articleId,
|
||||
List<CommentDto> getCommentList(@RequestParam Long articleId,
|
||||
@RequestParam(required = false) Long parentId,
|
||||
@Validated @RequestBody CommentForm commentForm, Errors errors,
|
||||
@AuthenticationPrincipal PrincipalDetails principal){
|
||||
@@ -40,13 +39,13 @@ public class CommentController {
|
||||
throw new InvalidCommentRequestException(Objects.requireNonNull(errors.getFieldError()).getDefaultMessage());
|
||||
}
|
||||
|
||||
Member member = principal.getMember();
|
||||
MemberVo member = principal.getMember();
|
||||
// 부모 댓글인지 자식댓글인지 분기로 저장
|
||||
if(parentId != null){
|
||||
commentUseCase.saveCComment(commentForm.getContent(), commentForm.isSecret(), member, articleId, parentId);
|
||||
commentUseCase.saveCComment(commentForm.getContent(), commentForm.isSecret(), member.getId(), articleId, parentId);
|
||||
}
|
||||
else {
|
||||
commentUseCase.savePComment(commentForm.getContent(), commentForm.isSecret(), member, articleId);
|
||||
commentUseCase.savePComment(commentForm.getContent(), commentForm.isSecret(), member.getId(), articleId);
|
||||
}
|
||||
|
||||
return commentUseCase.getCommentList(articleId);
|
||||
@@ -56,7 +55,7 @@ public class CommentController {
|
||||
- 댓글 삭제 요청
|
||||
*/
|
||||
@PostMapping("/comment/delete")
|
||||
public List<CommentDto> deleteComment(@RequestParam Long articleId,
|
||||
List<CommentDto> deleteComment(@RequestParam Long articleId,
|
||||
@RequestParam Long commentId) {
|
||||
commentUseCase.deleteComment(commentId);
|
||||
return commentUseCase.getCommentList(articleId);
|
||||
|
||||
@@ -2,8 +2,8 @@ package myblog.blog.comment.application;
|
||||
|
||||
import myblog.blog.article.application.port.incomming.ArticleUseCase;
|
||||
import myblog.blog.comment.application.port.incomming.CommentUseCase;
|
||||
import myblog.blog.comment.application.port.incomming.CommentDto;
|
||||
import myblog.blog.comment.application.port.incomming.CommentDtoForLayout;
|
||||
import myblog.blog.comment.application.port.incomming.response.CommentDto;
|
||||
import myblog.blog.comment.application.port.incomming.response.CommentDtoForLayout;
|
||||
import myblog.blog.comment.application.port.outgoing.CommentRepositoryPort;
|
||||
|
||||
import myblog.blog.comment.domain.Comment;
|
||||
@@ -11,6 +11,7 @@ import myblog.blog.article.domain.Article;
|
||||
import myblog.blog.member.doamin.Member;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import myblog.blog.member.application.port.incomming.MemberUseCase;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -23,6 +24,7 @@ import java.util.stream.Collectors;
|
||||
@RequiredArgsConstructor
|
||||
public class CommentService implements CommentUseCase {
|
||||
private final ArticleUseCase articleUseCase;
|
||||
private final MemberUseCase memberUseCase;
|
||||
private final CommentRepositoryPort commentRepositoryPort;
|
||||
|
||||
/*
|
||||
@@ -38,8 +40,8 @@ public class CommentService implements CommentUseCase {
|
||||
*/
|
||||
@CacheEvict(value = "layoutRecentCommentCaching", allEntries = true)
|
||||
@Override
|
||||
public void savePComment(String content, boolean secret, Member member, Long articleId){
|
||||
|
||||
public void savePComment(String content, boolean secret, Long memberId, Long articleId){
|
||||
Member member = memberUseCase.findById(memberId);
|
||||
Article article = articleUseCase.getArticle(articleId);
|
||||
|
||||
Comment comment = Comment.builder()
|
||||
@@ -60,8 +62,8 @@ public class CommentService implements CommentUseCase {
|
||||
*/
|
||||
@CacheEvict(value = "layoutRecentCommentCaching", allEntries = true)
|
||||
@Override
|
||||
public void saveCComment(String content, boolean secret, Member member, Long articleId, Long parentId) {
|
||||
|
||||
public void saveCComment(String content, boolean secret, Long memberId, Long articleId, Long parentId) {
|
||||
Member member = memberUseCase.findById(memberId);
|
||||
Article article = articleUseCase.getArticle(articleId);
|
||||
Comment pComment = commentRepositoryPort.findById(parentId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("NotfoundParentCommentException"));
|
||||
@@ -97,7 +99,7 @@ public class CommentService implements CommentUseCase {
|
||||
*/
|
||||
@Cacheable(value = "layoutRecentCommentCaching", key = "0")
|
||||
@Override
|
||||
public List<CommentDtoForLayout> recentCommentList(){
|
||||
public List<CommentDtoForLayout> recentCommentListForLayout(){
|
||||
return commentRepositoryPort.findTop5ByOrderByIdDesc()
|
||||
.stream()
|
||||
.map(comment ->
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
package myblog.blog.comment.application.port.incomming;
|
||||
|
||||
import myblog.blog.member.doamin.Member;
|
||||
import myblog.blog.comment.application.port.incomming.response.CommentDto;
|
||||
import myblog.blog.comment.application.port.incomming.response.CommentDtoForLayout;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface CommentUseCase {
|
||||
List<CommentDto> getCommentList(Long articleId);
|
||||
void savePComment(String content, boolean secret, Member member, Long articleId);
|
||||
void saveCComment(String content, boolean secret, Member member, Long articleId, Long parentId);
|
||||
void savePComment(String content, boolean secret, Long memberId, Long articleId);
|
||||
void saveCComment(String content, boolean secret, Long memberId, Long articleId, Long parentId);
|
||||
void deleteComment(Long commentId);
|
||||
List<CommentDtoForLayout> recentCommentList();
|
||||
List<CommentDtoForLayout> recentCommentListForLayout();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package myblog.blog.comment.application.port.incomming;
|
||||
package myblog.blog.comment.application.port.incomming.response;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -1,4 +1,4 @@
|
||||
package myblog.blog.comment.application.port.incomming;
|
||||
package myblog.blog.comment.application.port.incomming.response;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -1,10 +1,9 @@
|
||||
package myblog.blog.imgupload.adapter.incomming;
|
||||
|
||||
import myblog.blog.imgupload.service.port.incomming.ImgUploadUseCase;
|
||||
import myblog.blog.imgupload.application.port.incomming.ImgUploadUseCase;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.io.IOException;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@@ -13,8 +12,7 @@ public class UploadImgController {
|
||||
private final ImgUploadUseCase imgUploadUseCase;
|
||||
|
||||
@PostMapping("/article/uploadImg")
|
||||
public @ResponseBody
|
||||
String imgUpload(@ModelAttribute UploadImgForm uploadImgForm) throws IOException {
|
||||
String imgUpload(@ModelAttribute UploadImgForm uploadImgForm){
|
||||
return imgUploadUseCase.storeImg(uploadImgForm.getImg());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import com.amazonaws.services.s3.AmazonS3;
|
||||
import com.amazonaws.services.s3.model.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import myblog.blog.imgupload.domain.ImageFile;
|
||||
import myblog.blog.imgupload.service.port.outgoing.ImgUploadStrategyPort;
|
||||
import myblog.blog.imgupload.application.port.outgoing.ImgUploadStrategyPort;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
package myblog.blog.imgupload.service;
|
||||
package myblog.blog.imgupload.application;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import myblog.blog.imgupload.domain.ImageFile;
|
||||
import myblog.blog.imgupload.service.port.incomming.ImgUploadUseCase;
|
||||
import myblog.blog.imgupload.service.port.outgoing.ImgUploadStrategyPort;
|
||||
import myblog.blog.imgupload.application.port.incomming.ImgUploadUseCase;
|
||||
import myblog.blog.imgupload.application.port.outgoing.ImgUploadStrategyPort;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
@RequiredArgsConstructor
|
||||
@@ -1,9 +1,7 @@
|
||||
package myblog.blog.imgupload.service.port.incomming;
|
||||
package myblog.blog.imgupload.application.port.incomming;
|
||||
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface ImgUploadUseCase {
|
||||
String storeImg(MultipartFile img);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package myblog.blog.imgupload.service.port.outgoing;
|
||||
package myblog.blog.imgupload.application.port.outgoing;
|
||||
|
||||
import myblog.blog.imgupload.domain.ImageFile;
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package myblog.blog.member.adapter.incomming;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import myblog.blog.shared.queries.LayoutRenderingQueries;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
@Controller
|
||||
@RequiredArgsConstructor
|
||||
public class MemberController {
|
||||
private final LayoutRenderingQueries layoutRenderingQueries;
|
||||
|
||||
/*
|
||||
- 회원 로그인 폼 조회
|
||||
*/
|
||||
@GetMapping("/login")
|
||||
String loginFrom(@RequestParam(value = "error",required = false) String error, Model model){
|
||||
if(error!=null&&error.equals("duplicatedEmail")){
|
||||
model.addAttribute("errMsg","이미 가입된 이메일입니다.");
|
||||
}
|
||||
layoutRenderingQueries.AddLayoutTo(model);
|
||||
return "login";
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
package myblog.blog.member.repository;
|
||||
package myblog.blog.member.adapter.outgoing.repository;
|
||||
|
||||
import myblog.blog.member.doamin.Member;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
public interface MemberRepository extends JpaRepository<Member, Long> {
|
||||
public interface JpaMemberRepository extends JpaRepository<Member, Long> {
|
||||
/*
|
||||
- Id로 유저 찾기
|
||||
*/
|
||||
@@ -0,0 +1,32 @@
|
||||
package myblog.blog.member.adapter.outgoing.repository;
|
||||
|
||||
import myblog.blog.member.application.port.outgoing.MemberRepositoryPort;
|
||||
import myblog.blog.member.doamin.Member;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class MemberRepositoryAdapter implements MemberRepositoryPort {
|
||||
private final JpaMemberRepository jpaMemberRepository;
|
||||
|
||||
@Override
|
||||
public Member findByEmail(String email) {
|
||||
return jpaMemberRepository.findByEmail(email);
|
||||
}
|
||||
@Override
|
||||
public void save(Member member) {
|
||||
jpaMemberRepository.save(member);
|
||||
}
|
||||
@Override
|
||||
public Optional<Member> findById(Long memberId) {
|
||||
return jpaMemberRepository.findById(memberId);
|
||||
}
|
||||
@Override
|
||||
public Member findByUserId(String providerId) {
|
||||
return jpaMemberRepository.findByUserId(providerId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package myblog.blog.member.application;
|
||||
|
||||
@Deprecated
|
||||
public class BuildAdminAccountHelper {
|
||||
|
||||
// 앱 구동시 ADMIN 계정 Insert
|
||||
// @Value("${admin.username}")
|
||||
// private String adminUsername;
|
||||
// @Value("${admin.picUrl}")
|
||||
// private String adminPicUrl;
|
||||
// @Value("${admin.email}")
|
||||
// private String adminEmail;
|
||||
// @Value("${admin.providerId}")
|
||||
// private String adminProviderId;
|
||||
// @Value("${admin.provider}")
|
||||
// private String adminProvider;
|
||||
/*
|
||||
- 앱 구동시 ADMIN 계정 INSERT
|
||||
*/
|
||||
// @PostConstruct
|
||||
// public void insertAdmin(){
|
||||
//
|
||||
// Member admin = memberRepository.findByEmail(adminEmail);
|
||||
// if(admin == null){
|
||||
// admin = Member.builder()
|
||||
// .username(adminUsername+"#"+adminProviderId.substring(0,5))
|
||||
// .email(adminEmail)
|
||||
// .picUrl(adminPicUrl)
|
||||
// .userId(adminProviderId)
|
||||
// .providerId(adminProviderId)
|
||||
// .provider(adminProvider)
|
||||
// .role(Role.ADMIN)
|
||||
// .build();
|
||||
//
|
||||
// memberRepository.save(admin);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
package myblog.blog.member.service;
|
||||
package myblog.blog.member.application;
|
||||
|
||||
import myblog.blog.member.application.port.incomming.MemberUseCase;
|
||||
import myblog.blog.member.application.port.incomming.response.PrincipalDetails;
|
||||
import myblog.blog.member.application.port.incomming.response.userinfo.Oauth2UserInfo;
|
||||
import myblog.blog.member.application.port.outgoing.MemberRepositoryPort;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import myblog.blog.member.auth.userinfo.Oauth2UserInfo;
|
||||
import myblog.blog.member.auth.UserInfoFactory;
|
||||
import myblog.blog.member.repository.MemberRepository;
|
||||
import myblog.blog.member.auth.PrincipalDetails;
|
||||
import myblog.blog.member.doamin.Member;
|
||||
import myblog.blog.member.doamin.Role;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
|
||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
@@ -15,42 +16,24 @@ import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
@RequiredArgsConstructor
|
||||
public class Oauth2MemberService extends DefaultOAuth2UserService {
|
||||
public class Oauth2MemberService extends DefaultOAuth2UserService implements MemberUseCase {
|
||||
|
||||
private final MemberRepository memberRepository;
|
||||
private final MemberRepositoryPort memberRepositoryPort;
|
||||
private final UserInfoFactory userInfoFactory;
|
||||
|
||||
// 앱 구동시 ADMIN 계정 Insert
|
||||
@Value("${admin.username}")
|
||||
private String adminUsername;
|
||||
@Value("${admin.picUrl}")
|
||||
private String adminPicUrl;
|
||||
@Value("${admin.email}")
|
||||
private String adminEmail;
|
||||
@Value("${admin.providerId}")
|
||||
private String adminProviderId;
|
||||
@Value("${admin.provider}")
|
||||
private String adminProvider;
|
||||
|
||||
|
||||
/*
|
||||
- OAuth2 인증 로그인
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
|
||||
|
||||
OAuth2User oAuth2User = super.loadUser(userRequest);
|
||||
Oauth2UserInfo userInfo =
|
||||
userInfoFactory.makeOauth2UserInfoOf(userRequest, oAuth2User);
|
||||
|
||||
Member member = getOrJoinMember(userInfo);
|
||||
|
||||
return new PrincipalDetails(member, userInfo.getAttributes());
|
||||
}
|
||||
|
||||
@@ -58,16 +41,12 @@ public class Oauth2MemberService extends DefaultOAuth2UserService {
|
||||
- 회원가입 or 로그인 로직
|
||||
*/
|
||||
private Member getOrJoinMember(Oauth2UserInfo userInfo) {
|
||||
|
||||
//DB에서 조회해서 존재시 로그인처리, 미존재시 가입처리
|
||||
Member member = memberRepository.findByUserId(userInfo.getProviderId());
|
||||
|
||||
Member member = memberRepositoryPort.findByUserId(userInfo.getProviderId());
|
||||
if(member == null) {
|
||||
|
||||
//Email 중복검증
|
||||
if(memberRepository.findByEmail(userInfo.getEmail()) != null)
|
||||
if(memberRepositoryPort.findByEmail(userInfo.getEmail()) != null)
|
||||
throw new OAuth2AuthenticationException("duplicateEmail");
|
||||
|
||||
member = Member.builder()
|
||||
.username(userInfo.getUserName())
|
||||
.picUrl(userInfo.getPicture())
|
||||
@@ -77,43 +56,18 @@ public class Oauth2MemberService extends DefaultOAuth2UserService {
|
||||
.provider(userInfo.getProvider())
|
||||
.role(Role.USER)
|
||||
.build();
|
||||
|
||||
memberRepository.save(member);
|
||||
memberRepositoryPort.save(member);
|
||||
}
|
||||
|
||||
// 유저 네임 변경시 더티체킹으로 유저네임 변경
|
||||
if(!member.getUsername().equals(userInfo.getUserName())){
|
||||
member.changeUsername(userInfo.getUserName());
|
||||
}
|
||||
|
||||
return member;
|
||||
}
|
||||
|
||||
/*
|
||||
- 앱 구동시 ADMIN 계정 INSERT
|
||||
*/
|
||||
// @PostConstruct
|
||||
public void insertAdmin(){
|
||||
|
||||
Member admin = memberRepository.findByEmail(adminEmail);
|
||||
if(admin == null){
|
||||
admin = Member.builder()
|
||||
.username(adminUsername+"#"+adminProviderId.substring(0,5))
|
||||
.email(adminEmail)
|
||||
.picUrl(adminPicUrl)
|
||||
.userId(adminProviderId)
|
||||
.providerId(adminProviderId)
|
||||
.provider(adminProvider)
|
||||
.role(Role.ADMIN)
|
||||
.build();
|
||||
|
||||
memberRepository.save(admin);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Member findById(Long memberId) {
|
||||
return memberRepository.findById(memberId)
|
||||
return memberRepositoryPort.findById(memberId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("NotFoundMemberException"));
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
package myblog.blog.member.auth;
|
||||
package myblog.blog.member.application;
|
||||
|
||||
import myblog.blog.member.auth.userinfo.*;
|
||||
import myblog.blog.member.application.port.incomming.response.userinfo.GoogleUserInfo;
|
||||
import myblog.blog.member.application.port.incomming.response.userinfo.NaverUserInfo;
|
||||
import myblog.blog.member.application.port.incomming.response.userinfo.Oauth2UserInfo;
|
||||
import myblog.blog.member.application.port.incomming.response.userinfo.ProviderType;
|
||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
|
||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -0,0 +1,7 @@
|
||||
package myblog.blog.member.application.port.incomming;
|
||||
|
||||
import myblog.blog.member.doamin.Member;
|
||||
|
||||
public interface MemberUseCase {
|
||||
Member findById(Long memberId);
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
package myblog.blog.member.dto;
|
||||
package myblog.blog.member.application.port.incomming.response;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import myblog.blog.member.doamin.Member;
|
||||
|
||||
/*
|
||||
@@ -1,6 +1,7 @@
|
||||
package myblog.blog.member.auth;
|
||||
package myblog.blog.member.application.port.incomming.response;
|
||||
|
||||
import myblog.blog.member.doamin.Member;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
@@ -16,12 +17,14 @@ public class PrincipalDetails implements OAuth2User {
|
||||
|
||||
private final Map<String, Object> attributes;
|
||||
private final Member member;
|
||||
private final MemberVo memberVo;
|
||||
|
||||
public PrincipalDetails(Member member, Map<String, Object> attributes) {
|
||||
this.member = member;
|
||||
this.attributes = attributes;
|
||||
this.memberVo = MemberVo.from(member);
|
||||
}
|
||||
public Member getMember(){return member;}
|
||||
public MemberVo getMember(){return memberVo;}
|
||||
|
||||
// 타임리프 뷰단처리를 위한 편의 메소드
|
||||
public Long getMemberId(){
|
||||
@@ -1,4 +1,4 @@
|
||||
package myblog.blog.member.auth.userinfo;
|
||||
package myblog.blog.member.application.port.incomming.response.userinfo;
|
||||
|
||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import java.util.Map;
|
||||
@@ -1,7 +1,6 @@
|
||||
package myblog.blog.member.auth.userinfo;
|
||||
package myblog.blog.member.application.port.incomming.response.userinfo;
|
||||
|
||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package myblog.blog.member.auth.userinfo;
|
||||
package myblog.blog.member.application.port.incomming.response.userinfo;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package myblog.blog.member.auth.userinfo;
|
||||
package myblog.blog.member.application.port.incomming.response.userinfo;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -0,0 +1,12 @@
|
||||
package myblog.blog.member.application.port.outgoing;
|
||||
|
||||
import myblog.blog.member.doamin.Member;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface MemberRepositoryPort {
|
||||
Member findByEmail(String email);
|
||||
void save(Member member);
|
||||
Optional<Member> findById(Long memberId);
|
||||
Member findByUserId(String providerId);
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package myblog.blog.member.controller;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import myblog.blog.category.appliacation.port.response.CategoryViewForLayout;
|
||||
import myblog.blog.category.appliacation.CategoryService;
|
||||
import myblog.blog.comment.application.port.incomming.CommentDtoForLayout;
|
||||
import myblog.blog.comment.application.CommentService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Controller
|
||||
@RequiredArgsConstructor
|
||||
public class MemberController {
|
||||
|
||||
private final CategoryService categoryService;
|
||||
private final CommentService commentService;
|
||||
|
||||
|
||||
/*
|
||||
- 회원 로그인 폼 조회
|
||||
*/
|
||||
@GetMapping("/login")
|
||||
public String loginFrom(@RequestParam(value = "error",required = false) String error, Model model){
|
||||
|
||||
// 가입 실패시 에러 메시지 처리
|
||||
if(error!=null&&error.equals("duplicatedEmail")){
|
||||
model.addAttribute("errMsg","이미 가입된 이메일입니다.");
|
||||
}
|
||||
|
||||
// 레이아웃 DTO 전처리
|
||||
CategoryViewForLayout categoryViewForLayout = categoryService.getCategoryViewForLayout();
|
||||
List<CommentDtoForLayout> comments = commentService.recentCommentList();
|
||||
//
|
||||
|
||||
model.addAttribute("category", categoryViewForLayout);
|
||||
model.addAttribute("commentsList", comments);
|
||||
|
||||
return "login";
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,21 @@
|
||||
package myblog.blog.seo.adapter.incomming;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import myblog.blog.article.application.port.incomming.RssUseCase;
|
||||
import myblog.blog.seo.application.port.incomming.RssUseCase;
|
||||
|
||||
/*
|
||||
- rss 피드 발행 요청
|
||||
- rss 발행 비용을 감안해 캐시처리
|
||||
- 발행빈도가 아직 예측되지않으므로 캐시 만료를 12시간으로 설정
|
||||
*/
|
||||
@Controller
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
public class RssController {
|
||||
private final RssUseCase rssUseCase;
|
||||
|
||||
@GetMapping(value = "/rss",produces = "application/xml;charset=utf-8")
|
||||
public @ResponseBody String rssFeed() {
|
||||
String rssFeed() {
|
||||
return rssUseCase.getRssFeed();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
package myblog.blog.seo.adapter.incomming;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import myblog.blog.article.application.port.incomming.SiteMapUseCase;
|
||||
import myblog.blog.seo.application.port.incomming.SiteMapUseCase;
|
||||
|
||||
/*
|
||||
- siteMap.xml 요청
|
||||
- 작성 비용을 감안해 캐시처리
|
||||
- 조회 빈도가 아직 예측되지않으므로 캐시 만료를 12시간으로 설정
|
||||
*/
|
||||
@Controller
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
public class SiteMapController {
|
||||
private final SiteMapUseCase siteMapUseCase;
|
||||
|
||||
@GetMapping(value = "/sitemap",produces = "application/xml;charset=utf-8")
|
||||
public @ResponseBody String getSiteMap() {
|
||||
String getSiteMap() {
|
||||
return siteMapUseCase.getSiteMap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,18 @@
|
||||
package myblog.blog.seo.application;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import myblog.blog.article.application.port.incomming.ArticleUseCase;
|
||||
import myblog.blog.article.application.port.incomming.RssUseCase;
|
||||
import myblog.blog.seo.application.port.incomming.RssUseCase;
|
||||
import myblog.blog.article.domain.Article;
|
||||
|
||||
import myblog.blog.seo.domain.RssFeed;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import myblog.blog.article.domain.Article;
|
||||
import org.jdom2.*;
|
||||
import org.jdom2.output.*;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
import static myblog.blog.shared.utils.MarkdownUtils.*;
|
||||
|
||||
/*
|
||||
- rss 서비스 로직
|
||||
1. jdom2 사용하여 xml파일 작성
|
||||
@@ -27,65 +24,14 @@ import static myblog.blog.shared.utils.MarkdownUtils.*;
|
||||
@RequiredArgsConstructor
|
||||
public class RssService implements RssUseCase {
|
||||
|
||||
static final String ITEM_ROOT = "https://www.jiniaslog.co.kr/article/view?articleId=";
|
||||
|
||||
private final ArticleUseCase articleUseCase;
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "seoCaching", key = "0")
|
||||
public String getRssFeed() {
|
||||
List<Article> articles = articleUseCase.getTotalArticle();
|
||||
Document doc = makeRssFeedDocumentFrom(articles);
|
||||
XMLOutputter xmlOutputter = getXmlOutputter();
|
||||
return xmlOutputter.outputString(doc);
|
||||
}
|
||||
|
||||
private Document makeRssFeedDocumentFrom(List<Article> articles) {
|
||||
Document doc = new Document();
|
||||
Element rss = buildRssRoot();
|
||||
doc.setRootElement(rss);
|
||||
Element channel = buildChannel();
|
||||
rss.addContent(channel);
|
||||
addArticleItemsToChannel(articles, channel, new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.ENGLISH));
|
||||
return doc;
|
||||
}
|
||||
|
||||
private Element buildRssRoot() {
|
||||
Element rss = new Element("rss");
|
||||
rss.setAttribute(new Attribute("version", "2.0"));
|
||||
return rss;
|
||||
}
|
||||
|
||||
private Element buildChannel() {
|
||||
Element channel = new Element("channel");
|
||||
channel.addContent(new Element("title").addContent(new CDATA("Jinia's LOG")));
|
||||
channel.addContent(new Element("link").setText("https://www.jiniaslog.co.kr"));
|
||||
channel.addContent(new Element("description").addContent(new CDATA("비전공 출신, 개발자 지망생의 공부 내용을 기록하는 블로그입니다.")));
|
||||
return channel;
|
||||
}
|
||||
|
||||
private void addArticleItemsToChannel(List<Article> articles, Element channel, SimpleDateFormat dateFormat) {
|
||||
for (Article article : articles) {
|
||||
Element item = createItemTo(article, dateFormat);
|
||||
channel.addContent(item);
|
||||
}
|
||||
}
|
||||
|
||||
private Element createItemTo(Article article, SimpleDateFormat dateFormat) {
|
||||
Element item = new Element("item");
|
||||
item
|
||||
.addContent(new Element("title").addContent(new CDATA(article.getTitle())))
|
||||
.addContent(new Element("link").setText(ITEM_ROOT + article.getId()))
|
||||
.addContent(new Element("description").addContent(new CDATA(getHtmlRenderer().render(getParser().parse(article.getContent())))))
|
||||
.addContent(new Element("pubDate").setText(dateFormat.format(Timestamp.valueOf(article.getCreatedDate()))))
|
||||
.addContent(new Element("guid").setText(ITEM_ROOT + article.getId()));
|
||||
return item;
|
||||
}
|
||||
|
||||
private XMLOutputter getXmlOutputter() {
|
||||
Format format = Format.getPrettyFormat();
|
||||
format.setEncoding("UTF-8");
|
||||
format.setLineSeparator("\r\n");
|
||||
return new XMLOutputter(format);
|
||||
RssFeed rssFeed = RssFeed.from(articles);
|
||||
XMLOutputter xmlOutputter = XMLOutPutterBuildHelper.getXmlOutputter();
|
||||
return xmlOutputter.outputString(rssFeed.getRssDoc());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
package myblog.blog.seo.application;
|
||||
|
||||
import myblog.blog.article.application.port.incomming.ArticleUseCase;
|
||||
import myblog.blog.article.application.port.incomming.SiteMapUseCase;
|
||||
import myblog.blog.category.appliacation.port.incomming.CategoryUseCase;
|
||||
import myblog.blog.seo.application.port.incomming.SiteMapUseCase;
|
||||
|
||||
import myblog.blog.article.domain.Article;
|
||||
import myblog.blog.category.domain.Category;
|
||||
import myblog.blog.seo.domain.SiteMap;
|
||||
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.stereotype.Service;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import myblog.blog.article.domain.Article;
|
||||
import myblog.blog.category.domain.Category;
|
||||
import myblog.blog.category.appliacation.CategoryService;
|
||||
import org.jdom2.*;
|
||||
import org.jdom2.output.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
@@ -22,68 +20,16 @@ import java.util.*;
|
||||
@RequiredArgsConstructor
|
||||
public class SiteMapService implements SiteMapUseCase {
|
||||
|
||||
static final String NAMESPACE = "http://www.sitemaps.org/schemas/sitemap/0.9";
|
||||
static final String ROOT = "https://www.jiniaslog.co.kr";
|
||||
static final String CATEGORYPRE = "/article/list?";
|
||||
static final String CATEGORYPRO = "&page=1";
|
||||
static final String ARTICLEPREV = "/article/view?articleId=";
|
||||
|
||||
private final ArticleUseCase articleUseCase;
|
||||
private final CategoryService categoryService;
|
||||
private final CategoryUseCase categoryUseCase;
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "seoCaching", key = "1")
|
||||
public String getSiteMap(){
|
||||
List<Article> articles = articleUseCase.getTotalArticle();
|
||||
List<Category> allCategories = categoryService.getAllCategories();
|
||||
Document doc = makeSiteMapDocument(articles, allCategories);
|
||||
XMLOutputter xmlOutputter = getXmlOutputter();
|
||||
return xmlOutputter.outputString(doc);
|
||||
}
|
||||
|
||||
private Document makeSiteMapDocument(List<Article> articles, List<Category> allCategories) {
|
||||
Document doc = new Document();
|
||||
Element siteMap = new Element("urlset", NAMESPACE);
|
||||
doc.setRootElement(siteMap);
|
||||
Element main = createMainElement();
|
||||
siteMap.addContent(main);
|
||||
addCategoryUrlsToSiteMap(allCategories, siteMap);
|
||||
addArticleUrlToSiteMap(articles, siteMap);
|
||||
return doc;
|
||||
}
|
||||
|
||||
private Element createMainElement() {
|
||||
Element main = new Element("url",NAMESPACE);
|
||||
main.addContent(new Element("loc",NAMESPACE).setText(ROOT));
|
||||
main.addContent(new Element("lastmod",NAMESPACE).setText(
|
||||
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd",Locale.ENGLISH))));
|
||||
main.addContent(new Element("priority",NAMESPACE).setText("1.0"));
|
||||
return main;
|
||||
}
|
||||
|
||||
private void addArticleUrlToSiteMap(List<Article> articles, Element siteMap) {
|
||||
for (Article article : articles) {
|
||||
Element articleUrl = new Element("url",NAMESPACE);
|
||||
articleUrl.addContent(new Element("loc",NAMESPACE)
|
||||
.setText(ROOT + ARTICLEPREV + article.getId()));
|
||||
siteMap.addContent(articleUrl);
|
||||
}
|
||||
}
|
||||
|
||||
private void addCategoryUrlsToSiteMap(List<Category> allCategories, Element siteMap) {
|
||||
for (Category category : allCategories) {
|
||||
Element categoryUrl = new Element("url",NAMESPACE);
|
||||
categoryUrl.addContent(new Element("loc",NAMESPACE)
|
||||
.setText(ROOT + CATEGORYPRE + "category="+category.getTitle()+"&tier="+category.getTier()+CATEGORYPRO));
|
||||
siteMap.addContent(categoryUrl);
|
||||
}
|
||||
}
|
||||
|
||||
// 쓰레드 세잎한지 확신이 안듬 방어적으로 생각해서 객체 생성하고 캐싱으로 처리하자
|
||||
private XMLOutputter getXmlOutputter() {
|
||||
Format format = Format.getPrettyFormat();
|
||||
format.setEncoding("UTF-8");
|
||||
format.setLineSeparator("\r\n");
|
||||
return new XMLOutputter(format);
|
||||
List<Category> allCategories = categoryUseCase.getAllCategories();
|
||||
SiteMap siteMap = SiteMap.from(articles, allCategories);
|
||||
XMLOutputter xmlOutputter = XMLOutPutterBuildHelper.getXmlOutputter();
|
||||
return xmlOutputter.outputString(siteMap.getSiteMapDoc());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package myblog.blog.seo.application;
|
||||
|
||||
import org.jdom2.output.Format;
|
||||
import org.jdom2.output.XMLOutputter;
|
||||
|
||||
public class XMLOutPutterBuildHelper {
|
||||
static public XMLOutputter getXmlOutputter() {
|
||||
Format format = Format.getPrettyFormat();
|
||||
format.setEncoding("UTF-8");
|
||||
format.setLineSeparator("\r\n");
|
||||
return new XMLOutputter(format);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package myblog.blog.article.application.port.incomming;
|
||||
package myblog.blog.seo.application.port.incomming;
|
||||
|
||||
public interface RssUseCase {
|
||||
String getRssFeed();
|
||||
@@ -1,4 +1,4 @@
|
||||
package myblog.blog.article.application.port.incomming;
|
||||
package myblog.blog.seo.application.port.incomming;
|
||||
|
||||
public interface SiteMapUseCase {
|
||||
String getSiteMap();
|
||||
67
src/main/java/myblog/blog/seo/domain/RssFeed.java
Normal file
67
src/main/java/myblog/blog/seo/domain/RssFeed.java
Normal file
@@ -0,0 +1,67 @@
|
||||
package myblog.blog.seo.domain;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import myblog.blog.article.domain.Article;
|
||||
|
||||
import org.jdom2.*;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static myblog.blog.shared.utils.MarkdownUtils.getHtmlRenderer;
|
||||
import static myblog.blog.shared.utils.MarkdownUtils.getParser;
|
||||
|
||||
@Getter
|
||||
public class RssFeed {
|
||||
static private final String ITEM_ROOT = "https://www.jiniaslog.co.kr/article/view?articleId=";
|
||||
private final Document rssDoc;
|
||||
|
||||
private RssFeed(Document rssDoc) {
|
||||
this.rssDoc = rssDoc;
|
||||
}
|
||||
|
||||
static public RssFeed from(List<Article> articles){
|
||||
Document doc = new Document();
|
||||
Element rss = buildRssRoot();
|
||||
doc.setRootElement(rss);
|
||||
Element channel = buildChannel();
|
||||
rss.addContent(channel);
|
||||
addArticleItemsToChannel(articles, channel, new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.ENGLISH));
|
||||
return new RssFeed(doc);
|
||||
}
|
||||
|
||||
static private Element buildRssRoot() {
|
||||
Element rss = new Element("rss");
|
||||
rss.setAttribute(new Attribute("version", "2.0"));
|
||||
return rss;
|
||||
}
|
||||
|
||||
static private Element buildChannel() {
|
||||
Element channel = new Element("channel");
|
||||
channel.addContent(new Element("title").addContent(new CDATA("Jinia's LOG")));
|
||||
channel.addContent(new Element("link").setText("https://www.jiniaslog.co.kr"));
|
||||
channel.addContent(new Element("description").addContent(new CDATA("비전공 출신, 개발자 지망생의 공부 내용을 기록하는 블로그입니다.")));
|
||||
return channel;
|
||||
}
|
||||
|
||||
static private void addArticleItemsToChannel(List<Article> articles, Element channel, SimpleDateFormat dateFormat) {
|
||||
for (Article article : articles) {
|
||||
Element item = createItemTo(article, dateFormat);
|
||||
channel.addContent(item);
|
||||
}
|
||||
}
|
||||
|
||||
static private Element createItemTo(Article article, SimpleDateFormat dateFormat) {
|
||||
Element item = new Element("item");
|
||||
item
|
||||
.addContent(new Element("title").addContent(new CDATA(article.getTitle())))
|
||||
.addContent(new Element("link").setText(ITEM_ROOT + article.getId()))
|
||||
.addContent(new Element("description").addContent(new CDATA(getHtmlRenderer().render(getParser().parse(article.getContent())))))
|
||||
.addContent(new Element("pubDate").setText(dateFormat.format(Timestamp.valueOf(article.getCreatedDate()))))
|
||||
.addContent(new Element("guid").setText(ITEM_ROOT + article.getId()));
|
||||
return item;
|
||||
}
|
||||
|
||||
}
|
||||
64
src/main/java/myblog/blog/seo/domain/SiteMap.java
Normal file
64
src/main/java/myblog/blog/seo/domain/SiteMap.java
Normal file
@@ -0,0 +1,64 @@
|
||||
package myblog.blog.seo.domain;
|
||||
|
||||
import lombok.Getter;
|
||||
import myblog.blog.article.domain.Article;
|
||||
import myblog.blog.category.domain.Category;
|
||||
import org.jdom2.Document;
|
||||
import org.jdom2.Element;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
@Getter
|
||||
public class SiteMap {
|
||||
static private final String NAMESPACE = "http://www.sitemaps.org/schemas/sitemap/0.9";
|
||||
static private final String ROOT = "https://www.jiniaslog.co.kr";
|
||||
static private final String CATEGORYPRE = "/article/list?";
|
||||
static private final String CATEGORYPRO = "&page=1";
|
||||
static private final String ARTICLEPREV = "/article/view?articleId=";
|
||||
private final Document siteMapDoc;
|
||||
|
||||
private SiteMap(Document siteMapDoc) {
|
||||
this.siteMapDoc = siteMapDoc;
|
||||
}
|
||||
|
||||
static public SiteMap from(List<Article> articles, List<Category> allCategories) {
|
||||
Document doc = new Document();
|
||||
Element siteMap = new Element("urlset", NAMESPACE);
|
||||
doc.setRootElement(siteMap);
|
||||
Element main = createMainElement();
|
||||
siteMap.addContent(main);
|
||||
addCategoryUrlsToSiteMap(allCategories, siteMap);
|
||||
addArticleUrlToSiteMap(articles, siteMap);
|
||||
return new SiteMap(doc);
|
||||
}
|
||||
|
||||
static private Element createMainElement() {
|
||||
Element main = new Element("url",NAMESPACE);
|
||||
main.addContent(new Element("loc",NAMESPACE).setText(ROOT));
|
||||
main.addContent(new Element("lastmod",NAMESPACE).setText(
|
||||
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.ENGLISH))));
|
||||
main.addContent(new Element("priority",NAMESPACE).setText("1.0"));
|
||||
return main;
|
||||
}
|
||||
|
||||
static private void addArticleUrlToSiteMap(List<Article> articles, Element siteMap) {
|
||||
for (Article article : articles) {
|
||||
Element articleUrl = new Element("url",NAMESPACE);
|
||||
articleUrl.addContent(new Element("loc",NAMESPACE)
|
||||
.setText(ROOT + ARTICLEPREV + article.getId()));
|
||||
siteMap.addContent(articleUrl);
|
||||
}
|
||||
}
|
||||
|
||||
static private void addCategoryUrlsToSiteMap(List<Category> allCategories, Element siteMap) {
|
||||
for (Category category : allCategories) {
|
||||
Element categoryUrl = new Element("url",NAMESPACE);
|
||||
categoryUrl.addContent(new Element("loc",NAMESPACE)
|
||||
.setText(ROOT + CATEGORYPRE + "category="+category.getTitle()+"&tier="+category.getTier()+CATEGORYPRO));
|
||||
siteMap.addContent(categoryUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@ package myblog.blog.shared.queries;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import myblog.blog.category.appliacation.port.incomming.CategoryUseCase;
|
||||
import myblog.blog.category.appliacation.port.response.CategoryViewForLayout;
|
||||
import myblog.blog.comment.application.port.incomming.CommentDtoForLayout;
|
||||
import myblog.blog.comment.application.CommentService;
|
||||
import myblog.blog.category.appliacation.port.incomming.response.CategoryViewForLayout;
|
||||
import myblog.blog.comment.application.port.incomming.CommentUseCase;
|
||||
import myblog.blog.comment.application.port.incomming.response.CommentDtoForLayout;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
@@ -15,14 +15,14 @@ import java.util.List;
|
||||
public class LayoutRenderingQueries {
|
||||
|
||||
private final CategoryUseCase categoryUseCase;
|
||||
private final CommentService commentService;
|
||||
private final CommentUseCase commentUseCase;
|
||||
|
||||
/*
|
||||
- 레이아웃에 필요한 모델 담기
|
||||
*/
|
||||
public void AddLayoutTo(Model model) {
|
||||
CategoryViewForLayout categoryViewForLayout = categoryUseCase.getCategoryViewForLayout();
|
||||
List<CommentDtoForLayout> comments = commentService.recentCommentList();
|
||||
List<CommentDtoForLayout> comments = commentUseCase.recentCommentListForLayout();
|
||||
model.addAttribute("category", categoryViewForLayout);
|
||||
model.addAttribute("commentsList", comments);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user