diff --git a/build.gradle b/build.gradle index db2674e..a773856 100644 --- a/build.gradle +++ b/build.gradle @@ -36,7 +36,6 @@ dependencies { implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5' implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.9' - implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.7.1' implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.0' // implementation 'com.querydsl:querydsl-jpa' implementation 'com.github.node-gradle:gradle-node-plugin:3.1.0' diff --git a/src/main/java/myblog/blog/article/controller/ArticleController.java b/src/main/java/myblog/blog/article/controller/ArticleController.java index edceff4..b62a24b 100644 --- a/src/main/java/myblog/blog/article/controller/ArticleController.java +++ b/src/main/java/myblog/blog/article/controller/ArticleController.java @@ -1,24 +1,25 @@ package myblog.blog.article.controller; import lombok.RequiredArgsConstructor; + import myblog.blog.article.domain.Article; +import myblog.blog.article.service.*; import myblog.blog.article.dto.*; -import myblog.blog.article.service.ArticleService; -import myblog.blog.article.service.TempArticleService; -import myblog.blog.category.dto.CategoryForView; -import myblog.blog.category.dto.CategoryNormalDto; import myblog.blog.category.service.CategoryService; +import myblog.blog.category.dto.*; import myblog.blog.member.auth.PrincipalDetails; import myblog.blog.member.dto.MemberDto; -import myblog.blog.tags.dto.TagsDto; import myblog.blog.tags.service.TagsService; -import myblog.blog.utils.LayoutDtoFactory; +import myblog.blog.tags.dto.TagsDto; +import myblog.blog.layout.LayoutDtoFactory; + import org.commonmark.parser.Parser; import org.commonmark.renderer.html.HtmlRenderer; import org.jsoup.Jsoup; + import org.modelmapper.ModelMapper; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Slice; + +import org.springframework.data.domain.*; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.stereotype.Controller; import org.springframework.transaction.annotation.Transactional; @@ -29,6 +30,7 @@ import org.springframework.web.bind.annotation.*; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; + import java.util.List; import java.util.stream.Collectors; @@ -65,10 +67,8 @@ public class ArticleController { @PostMapping("article/write") @Transactional public String writeArticle(@Validated ArticleForm articleForm, - Errors errors, @AuthenticationPrincipal PrincipalDetails principal, - Model model) { - + Errors errors, Model model) { if (errors.hasErrors()) { getWriteArticleForm(model); } @@ -85,19 +85,15 @@ public class ArticleController { @GetMapping("/article/edit") public String updateArticle(@RequestParam Long articleId, Model model) { - // 기존 아티클 DTO 전처리 Article article = articleService.readArticle(articleId); - ArticleDtoForEdit articleDto = - modelMapper.map(article, ArticleDtoForEdit.class); - - articleDto.setArticleTagList( - article.getArticleTagLists() - .stream() - .map(articleTag -> articleTag.getTags().getName()) - .collect(Collectors.toList())); + ArticleDtoForEdit articleDto = modelMapper.map(article, ArticleDtoForEdit.class); + List articleTagStrings = article.getArticleTagLists() + .stream() + .map(articleTag -> articleTag.getTags().getName()) + .collect(Collectors.toList()); + articleDto.setArticleTagList(articleTagStrings); // - layoutDtoFactory.AddLayoutTo(model); model.addAttribute("categoryInput", getCategoryDtosForForm()); model.addAttribute("tagsInput", getTagsDtosForForm());; @@ -112,7 +108,6 @@ public class ArticleController { @Transactional public String editArticle(@RequestParam Long articleId, @ModelAttribute ArticleForm articleForm) { - articleService.editArticle(articleId, articleForm); return "redirect:/article/view?articleId=" + articleId; } @@ -123,7 +118,6 @@ public class ArticleController { @PostMapping("/article/delete") @Transactional public String deleteArticle(@RequestParam Long articleId) { - articleService.deleteArticle(articleId); return "redirect:/"; } @@ -137,17 +131,16 @@ public class ArticleController { @RequestParam Integer tier, @RequestParam Integer page, Model model) { - // DTO 매핑 전처리 PagingBoxDto pagingBoxDto = PagingBoxDto.createOf(page, getTotalArticleCntByCategory(category, categoryService.getCategoryForView())); - Slice articleDtoList = + Slice articleDtoList = articleService.getArticlesByCategory(category, tier, pagingBoxDto.getCurPageNum()) - .map(article -> modelMapper.map(article, ArticleDtoForMain.class)); + .map(article -> modelMapper.map(article, ArticleDtoForCardBox.class)); // - for(ArticleDtoForMain articleDto : articleDtoList){ + for(ArticleDtoForCardBox articleDto : articleDtoList){ articleDto.setContent(Jsoup.parse(htmlRenderer.render(parser.parse(articleDto.getContent()))).text()); } @@ -167,12 +160,12 @@ public class ArticleController { @RequestParam String tagName, Model model) { // DTO 매핑 전처리 - Page articleList = + Page articleList = articleService.getArticlesByTag(tagName, page) .map(article -> - modelMapper.map(article, ArticleDtoForMain.class)); + modelMapper.map(article, ArticleDtoForCardBox.class)); - for(ArticleDtoForMain article : articleList){ + for(ArticleDtoForCardBox article : articleList){ article.setContent(Jsoup.parse(htmlRenderer.render(parser.parse(article.getContent()))).text()); } @@ -195,12 +188,12 @@ public class ArticleController { @RequestParam String keyword, Model model) { // DTO 매핑 전처리 - Page articleList = + Page articleList = articleService.getArticlesByKeyword(keyword, page) .map(article -> - modelMapper.map(article, ArticleDtoForMain.class)); + modelMapper.map(article, ArticleDtoForCardBox.class)); - for(ArticleDtoForMain article : articleList){ + for(ArticleDtoForCardBox article : articleList){ article.setContent(Jsoup.parse(htmlRenderer.render(parser.parse(article.getContent()))).text()); } @@ -257,7 +250,7 @@ public class ArticleController { List articleTitlesSortByCategory = articleService - .getArticlesByCategoryForDetailView(article.getCategory(), article) + .getArticlesByCategoryForDetailView(article.getCategory()) .stream() .map(article1 -> modelMapper.map(article1, ArticleDtoByCategory.class)) .collect(Collectors.toList()); @@ -291,14 +284,13 @@ public class ArticleController { /* - 쿠키 추가 / 조회수 증가 검토 */ - @Transactional - public void addHitWithCookie(Article article, String cookie, HttpServletResponse response) { + private void addHitWithCookie(Article article, String cookie, HttpServletResponse response) { Long articleId = article.getId(); if (cookie == null) { Cookie viewCookie = new Cookie("view", articleId + "/"); viewCookie.setComment("게시물 조회 확인용"); viewCookie.setMaxAge(60 * 60); - article.addHit(); + articleService.addHit(article); response.addCookie(viewCookie); } else { boolean isRead = false; @@ -340,7 +332,7 @@ public class ArticleController { /* - 아티클 폼에 필요한 태그 dtos -*/ + */ private List getTagsDtosForForm() { return tagsService .findAllTags() @@ -359,6 +351,4 @@ public class ArticleController { .map(category -> modelMapper.map(category, CategoryNormalDto.class)) .collect(Collectors.toList()); } - - } diff --git a/src/main/java/myblog/blog/article/controller/TempArticleController.java b/src/main/java/myblog/blog/article/controller/TempArticleController.java index 2c8f248..e594539 100644 --- a/src/main/java/myblog/blog/article/controller/TempArticleController.java +++ b/src/main/java/myblog/blog/article/controller/TempArticleController.java @@ -2,8 +2,8 @@ package myblog.blog.article.controller; import lombok.RequiredArgsConstructor; import myblog.blog.article.domain.TempArticle; -import myblog.blog.article.dto.TempArticleDto; import myblog.blog.article.service.TempArticleService; +import myblog.blog.article.dto.TempArticleDto; import org.springframework.web.bind.annotation.*; import java.util.Optional; diff --git a/src/main/java/myblog/blog/article/domain/Article.java b/src/main/java/myblog/blog/article/domain/Article.java index 91a5574..d9f7b69 100644 --- a/src/main/java/myblog/blog/article/domain/Article.java +++ b/src/main/java/myblog/blog/article/domain/Article.java @@ -3,7 +3,7 @@ package myblog.blog.article.domain; import lombok.Builder; import lombok.Getter; import myblog.blog.article.dto.ArticleForm; -import myblog.blog.base.domain.BasicEntity; +import myblog.blog.base.BasicEntity; import myblog.blog.category.domain.Category; import myblog.blog.comment.domain.Comment; import myblog.blog.member.doamin.Member; @@ -12,8 +12,7 @@ import org.hibernate.annotations.OnDelete; import org.hibernate.annotations.OnDeleteAction; import javax.persistence.*; -import java.util.ArrayList; -import java.util.List; +import java.util.*; /* @@ -51,7 +50,7 @@ public class Article extends BasicEntity { @Column(columnDefinition = "bigint default 0",nullable = false) private Long hit; - // 추후 개발 예정 + // TODO: 추후 개발 예정 private String toc; @Column(nullable = false) @@ -87,8 +86,6 @@ public class Article extends BasicEntity { this.hit = 0L; } - // 비지니스 로직 // - /* - 아티클 수정을 위한 로직 */ diff --git a/src/main/java/myblog/blog/article/domain/TempArticle.java b/src/main/java/myblog/blog/article/domain/TempArticle.java index d435f7d..df3bd77 100644 --- a/src/main/java/myblog/blog/article/domain/TempArticle.java +++ b/src/main/java/myblog/blog/article/domain/TempArticle.java @@ -1,7 +1,7 @@ package myblog.blog.article.domain; import lombok.Getter; -import myblog.blog.base.domain.BasicEntity; +import myblog.blog.base.BasicEntity; import javax.persistence.*; diff --git a/src/main/java/myblog/blog/article/dto/ArticleDtoByCategory.java b/src/main/java/myblog/blog/article/dto/ArticleDtoByCategory.java index 8094a03..0d89a44 100644 --- a/src/main/java/myblog/blog/article/dto/ArticleDtoByCategory.java +++ b/src/main/java/myblog/blog/article/dto/ArticleDtoByCategory.java @@ -8,7 +8,6 @@ import lombok.Setter; */ @Getter @Setter public class ArticleDtoByCategory { - private String title; private Long id; } diff --git a/src/main/java/myblog/blog/article/dto/ArticleDtoForMain.java b/src/main/java/myblog/blog/article/dto/ArticleDtoForCardBox.java similarity index 80% rename from src/main/java/myblog/blog/article/dto/ArticleDtoForMain.java rename to src/main/java/myblog/blog/article/dto/ArticleDtoForCardBox.java index 9af282f..9914ad1 100644 --- a/src/main/java/myblog/blog/article/dto/ArticleDtoForMain.java +++ b/src/main/java/myblog/blog/article/dto/ArticleDtoForCardBox.java @@ -3,7 +3,6 @@ package myblog.blog.article.dto; import lombok.Getter; import lombok.Setter; -import javax.validation.constraints.NotBlank; import java.time.LocalDateTime; /* @@ -11,8 +10,7 @@ import java.time.LocalDateTime; */ @Getter @Setter -public class ArticleDtoForMain { - +public class ArticleDtoForCardBox { private Long id; private String title; private String content; diff --git a/src/main/java/myblog/blog/article/service/ArticleService.java b/src/main/java/myblog/blog/article/service/ArticleService.java index 5beb900..b084553 100644 --- a/src/main/java/myblog/blog/article/service/ArticleService.java +++ b/src/main/java/myblog/blog/article/service/ArticleService.java @@ -44,11 +44,9 @@ public class ArticleService { */ @CacheEvict(value = {"layoutCaching", "layoutRecentArticleCaching","seoCaching"}, allEntries = true) public Long writeArticle(ArticleForm articleDto, Member writer) { - Article newArticle = articleFrom(articleDto, writer); articleRepository.save(newArticle); tagsService.createNewTagsAndArticleTagList(articleDto.getTags(), newArticle); - return newArticle.getId(); } @@ -58,13 +56,10 @@ public class ArticleService { */ @CacheEvict(value = {"layoutCaching", "layoutRecentArticleCaching","seoCaching"}, allEntries = true) public void editArticle(Long articleId, ArticleForm articleForm) { - Article article = articleRepository.findById(articleId).get(); Category category = categoryService.findCategory(articleForm.getCategory()); tagsService.deleteArticleTags(article); tagsService.createNewTagsAndArticleTagList(articleForm.getTags(), article); - - // 더티 체킹으로 업데이트 article.isEditedFrom(articleForm,category); } @@ -74,7 +69,6 @@ public class ArticleService { */ @CacheEvict(value = {"layoutCaching", "layoutRecentArticleCaching","seoCaching"}, allEntries = true) public void deleteArticle(Long articleId) { - naArticleRepository.deleteArticle(articleId); } @@ -96,7 +90,6 @@ public class ArticleService { */ @Cacheable(value = "layoutRecentArticleCaching", key = "#lastArticleId") public List
getRecentArticles(Long lastArticleId) { - return lastArticleId.equals(0L)? articleRepository .findByOrderByIdDescWithList(PageRequest.of(0, 5)) @@ -110,19 +103,22 @@ public class ArticleService { - 카테고리별 게시물 페이징 처리해서 가져오기 */ public Slice
getArticlesByCategory(String category, Integer tier, Integer page) { - Slice
articles = null; if (tier.equals(0)) { articles = articleRepository .findByOrderByIdDesc( PageRequest.of(pageResolve(page), 5)); - } else if (tier.equals(1)) { + } + + if (tier.equals(1)) { articles = articleRepository .findBySupCategoryOrderByIdDesc( PageRequest.of(pageResolve(page), 5), category); - } else { + } + + if (tier.equals(2)) { articles = articleRepository .findBySubCategoryOrderByIdDesc( PageRequest.of(pageResolve(page), 5), category); @@ -148,52 +144,53 @@ public class ArticleService { /* - 카테고리별 최신게시물 6개만 아티클 상세뷰 위해 가져오는로직 */ - public List
getArticlesByCategoryForDetailView(Category category, Article article){ - + public List
getArticlesByCategoryForDetailView(Category category){ return articleRepository.findTop6ByCategoryOrderByIdDesc(category); - } /* - 태그별 게시물 페이징 처리해서 가져오기 */ public Page
getArticlesByTag(String tag, Integer page) { - return articleRepository .findAllByArticleTagsOrderById(PageRequest.of(pageResolve(page), 5), tag); - } /* - 검색어별 게시물 페이징 처리해서 가져오기 */ public Page
getArticlesByKeyword(String keyword, Integer page) { - return articleRepository .findAllByKeywordOrderById(PageRequest.of(pageResolve(page),5), keyword); } + /* + - 아티클 조회수 추가 + */ + public void addHit(Article article) { + article.addHit(); + } + /* - 깃헙에 아티클 푸시하기 */ public void pushArticleToGithub(Long articleId) { - Article article = articleRepository.findById(articleId).get(); + articleRepository.findById(articleId).ifPresent(this::pushArticleToGithub); + } + private void pushArticleToGithub(Article article) { try { - GitHub gitHub = new GitHubBuilder().withOAuthToken(gitToken).build(); GHRepository repository = gitHub.getRepository(gitRepo); repository.createContent() - .path(article.getCategory().getParents().getTitle()+"/"+article.getCategory().getTitle()+"/"+article.getTitle()+".md") + .path(article.getCategory().getParents().getTitle()+"/"+ article.getCategory().getTitle()+"/"+ article.getTitle()+".md") .content(article.getContent()) .message("test") .branch("main") .commit(); - } catch (IOException e) { e.printStackTrace(); } - } /* @@ -209,7 +206,6 @@ public class ArticleService { - 새로운 아티클 도메인 생성 메서드 */ private Article articleFrom(ArticleForm articleDto, Member writer) { - return Article.builder() .title(articleDto.getTitle()) .content(articleDto.getContent()) diff --git a/src/main/java/myblog/blog/base/domain/BasicEntity.java b/src/main/java/myblog/blog/base/BasicEntity.java similarity index 95% rename from src/main/java/myblog/blog/base/domain/BasicEntity.java rename to src/main/java/myblog/blog/base/BasicEntity.java index f0b5d59..78f6c91 100644 --- a/src/main/java/myblog/blog/base/domain/BasicEntity.java +++ b/src/main/java/myblog/blog/base/BasicEntity.java @@ -1,4 +1,4 @@ -package myblog.blog.base.domain; +package myblog.blog.base; import lombok.Getter; import org.springframework.data.annotation.CreatedDate; diff --git a/src/main/java/myblog/blog/base/config/AppConfig.java b/src/main/java/myblog/blog/base/config/AppConfig.java index 40e5a42..07994f0 100644 --- a/src/main/java/myblog/blog/base/config/AppConfig.java +++ b/src/main/java/myblog/blog/base/config/AppConfig.java @@ -40,5 +40,4 @@ public class AppConfig { .extensions(List.of(TablesExtension.create())) .build(); } - } diff --git a/src/main/java/myblog/blog/category/controller/CategoryController.java b/src/main/java/myblog/blog/category/controller/CategoryController.java index 918b3db..d8a3aab 100644 --- a/src/main/java/myblog/blog/category/controller/CategoryController.java +++ b/src/main/java/myblog/blog/category/controller/CategoryController.java @@ -38,12 +38,9 @@ public class CategoryController { // DTO 매핑 전처리 List categoryList = categoryService.getCategorytCountList(); - List copyList = cloneList(categoryList); copyList.remove(0); - CategoryForView categoryForView = CategoryForView.createCategory(categoryList); - List comments = commentService.recentCommentList(); // diff --git a/src/main/java/myblog/blog/category/domain/Category.java b/src/main/java/myblog/blog/category/domain/Category.java index fb432b1..dab8cb3 100644 --- a/src/main/java/myblog/blog/category/domain/Category.java +++ b/src/main/java/myblog/blog/category/domain/Category.java @@ -4,7 +4,7 @@ package myblog.blog.category.domain; import lombok.Builder; import lombok.Getter; import myblog.blog.article.domain.Article; -import myblog.blog.base.domain.BasicEntity; +import myblog.blog.base.BasicEntity; import javax.persistence.*; import java.util.ArrayList; diff --git a/src/main/java/myblog/blog/category/dto/CategoryForView.java b/src/main/java/myblog/blog/category/dto/CategoryForView.java index e0f46f4..c0eb41e 100644 --- a/src/main/java/myblog/blog/category/dto/CategoryForView.java +++ b/src/main/java/myblog/blog/category/dto/CategoryForView.java @@ -65,5 +65,4 @@ public class CategoryForView { private CategoryForView() { } - } diff --git a/src/main/java/myblog/blog/category/service/CategoryService.java b/src/main/java/myblog/blog/category/service/CategoryService.java index b9466ce..bf87cc5 100644 --- a/src/main/java/myblog/blog/category/service/CategoryService.java +++ b/src/main/java/myblog/blog/category/service/CategoryService.java @@ -24,30 +24,6 @@ public class CategoryService { private final CategoryRepository categoryRepository; private final NaCategoryRepository naCategoryRepository; - /* - - 새로운 카테고리 생성하기 - - 상위 카테고리 존재 유무 분기 - */ - public Category createNewCategory(String title, String parent, int pOrder, int cOrder, int tier) { - - Category parentCategory = null; - if (parent != null) { - parentCategory = categoryRepository.findByTitle(parent); - } - - Category category = Category.builder() - .title(title) - .pSortNum(pOrder) - .cSortNum(cOrder) - .tier(tier) - .parents(parentCategory) - .build(); - - categoryRepository.save(category); - - return category; - } - /* - 카테고리 이름으로 카테고리 찾기 */ @@ -55,7 +31,6 @@ public class CategoryService { return categoryRepository.findByTitle(title); } - /* - 카테고리 이름으로 카테고리 찾기 */ @@ -103,13 +78,11 @@ public class CategoryService { // 1.카테고리 리스트 순서 작성 sortingOrder(categoryList); - // 2. 기존 DB 저장된 카테고리 리스트 불러오기 List allWithoutDummy = categoryRepository.findAllWithoutDummy(); // 3. 카테고리 변경 루프 while (!categoryList.isEmpty()) { - CategoryNormalDto categoryNormalDto = categoryList.get(0); categoryList.remove(0); @@ -120,13 +93,7 @@ public class CategoryService { // 부모카테고리가 기존에 존재 x if (categoryNormalDto.getId() == null) { - pCategory - = createNewCategory(categoryNormalDto.getTitle(), - null, - categoryNormalDto.getPOrder(), - categoryNormalDto.getCOrder(), - categoryNormalDto.getTier()); - + pCategory = createNewCategory(categoryNormalDto, null); } // 부모카테고리가 기존에 존재 o else { @@ -137,43 +104,41 @@ public class CategoryService { break; } } - pCategory.updateCategory(categoryNormalDto.getTitle(), + pCategory.updateCategory( + categoryNormalDto.getTitle(), categoryNormalDto.getTier(), categoryNormalDto.getPOrder(), categoryNormalDto.getCOrder(), - null); + null + ); } while (!categoryList.isEmpty()) { - CategoryNormalDto subCategoryDto = categoryList.get(0); - if (subCategoryDto.getTier() == 1) break; + CategoryNormalDto subCategoryNormalDto = categoryList.get(0); + if (subCategoryNormalDto.getTier() == 1) break; categoryList.remove(0); // 자식 카테고리인경우 Category cCategory = null; // 카테고리가 기존에 존재 x - if (subCategoryDto.getId() == null) { - cCategory = createNewCategory(subCategoryDto.getTitle(), - pCategory.getTitle(), - subCategoryDto.getPOrder(), - subCategoryDto.getCOrder(), - subCategoryDto.getTier()); - + if (subCategoryNormalDto.getId() == null) { + cCategory = createNewCategory(subCategoryNormalDto, pCategory.getTitle()); } // 카테고리가 기존에 존재 o else { for (int i = 0; i < allWithoutDummy.size(); i++) { - if (allWithoutDummy.get(i).getId().equals(subCategoryDto.getId())) { + if (allWithoutDummy.get(i).getId().equals(subCategoryNormalDto.getId())) { cCategory = allWithoutDummy.get(i); allWithoutDummy.remove(i); break; } } - cCategory.updateCategory(subCategoryDto.getTitle(), - subCategoryDto.getTier(), - subCategoryDto.getPOrder(), - subCategoryDto.getCOrder(), + cCategory.updateCategory( + subCategoryNormalDto.getTitle(), + subCategoryNormalDto.getTier(), + subCategoryNormalDto.getPOrder(), + subCategoryNormalDto.getCOrder(), pCategory); } } @@ -183,6 +148,27 @@ public class CategoryService { categoryRepository.deleteAll(allWithoutDummy); } + /* + - 새로운 카테고리 생성하기 + - 상위 카테고리 존재 유무 분기 + */ + private Category createNewCategory(CategoryNormalDto categoryNormalDto, String parent) { + Category parentCategory = null; + if (parent != null) { + parentCategory = categoryRepository.findByTitle(parent); + } + + Category category = Category.builder() + .title(categoryNormalDto.getTitle()) + .pSortNum(categoryNormalDto.getPOrder()) + .cSortNum(categoryNormalDto.getCOrder()) + .tier(categoryNormalDto.getTier()) + .parents(parentCategory) + .build(); + categoryRepository.save(category); + return category; + } + /* - 카테고리 변경을 위해 카테고리의 순번을 작성하는 로직 */ @@ -208,7 +194,7 @@ public class CategoryService { - 최초 필수 더미 카테고리 추가 코드 */ @PostConstruct - public void insertDummyCategory() { + private void insertDummyCategory() { if(categoryRepository.findByTitle("total")==null) { Category category0 = Category.builder() .tier(0) @@ -219,5 +205,4 @@ public class CategoryService { categoryRepository.save(category0); } } - } diff --git a/src/main/java/myblog/blog/comment/controller/CommentController.java b/src/main/java/myblog/blog/comment/controller/CommentController.java index b753b2b..99ebeae 100644 --- a/src/main/java/myblog/blog/comment/controller/CommentController.java +++ b/src/main/java/myblog/blog/comment/controller/CommentController.java @@ -41,7 +41,6 @@ public class CommentController { @RequestParam(required = false) Long parentId, @Validated @RequestBody CommentForm commentForm, Errors errors, @AuthenticationPrincipal PrincipalDetails principal){ - if (errors.hasErrors()) { throw new CustomFormException(Objects.requireNonNull(errors.getFieldError()).getDefaultMessage()); } diff --git a/src/main/java/myblog/blog/comment/domain/Comment.java b/src/main/java/myblog/blog/comment/domain/Comment.java index 804526d..5c70d2d 100644 --- a/src/main/java/myblog/blog/comment/domain/Comment.java +++ b/src/main/java/myblog/blog/comment/domain/Comment.java @@ -3,7 +3,7 @@ package myblog.blog.comment.domain; import lombok.Builder; import lombok.Getter; import myblog.blog.article.domain.Article; -import myblog.blog.base.domain.BasicEntity; +import myblog.blog.base.BasicEntity; import myblog.blog.member.doamin.Member; import org.hibernate.annotations.OnDelete; import org.hibernate.annotations.OnDeleteAction; diff --git a/src/main/java/myblog/blog/exception/ExceptionController.java b/src/main/java/myblog/blog/exception/ExceptionController.java index c53d4a1..cab4cee 100644 --- a/src/main/java/myblog/blog/exception/ExceptionController.java +++ b/src/main/java/myblog/blog/exception/ExceptionController.java @@ -1,39 +1,28 @@ package myblog.blog.exception; import lombok.RequiredArgsConstructor; -import myblog.blog.article.dto.ArticleDtoForMain; -import myblog.blog.category.dto.CategoryForView; -import myblog.blog.category.service.CategoryService; -import myblog.blog.comment.dto.CommentDtoForLayout; -import myblog.blog.comment.service.CommentService; +import lombok.extern.slf4j.Slf4j; +import myblog.blog.layout.LayoutDtoFactory; import org.springframework.boot.web.servlet.error.ErrorController; -import org.springframework.data.domain.Slice; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.context.request.WebRequest; +import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; -import java.util.List; +import java.security.Principal; @Controller @RequiredArgsConstructor +@Slf4j public class ExceptionController implements ErrorController { - private static final String ERROR_PATH = "/error"; - - private final CategoryService categoryService; - private final CommentService commentService; + private final LayoutDtoFactory layoutDtoFactory; @GetMapping("/error") - public String errorView(Model model){ - - CategoryForView categoryForView = categoryService.getCategoryForView(); - List comments = commentService.recentCommentList(); - // - - model.addAttribute("category",categoryForView); - model.addAttribute("commentsList", comments); - + public String errorView(Model model) { + layoutDtoFactory.AddLayoutTo(model); return "error"; } diff --git a/src/main/java/myblog/blog/exception/ExceptionControllerAdvice.java b/src/main/java/myblog/blog/exception/ExceptionControllerAdvice.java index 7cb41ab..e63792d 100644 --- a/src/main/java/myblog/blog/exception/ExceptionControllerAdvice.java +++ b/src/main/java/myblog/blog/exception/ExceptionControllerAdvice.java @@ -1,12 +1,12 @@ package myblog.blog.exception; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import javax.servlet.http.HttpServletRequest; import java.security.Principal; +import java.time.LocalDateTime; /* - 일반 에러 컨트롤러 @@ -17,11 +17,11 @@ public class ExceptionControllerAdvice { @ExceptionHandler public String handleRuntimeException(Principal principal, HttpServletRequest req, RuntimeException e) { if (principal != null) { - log.info("'{}' requested '{}'", principal.getName(), req.getRequestURI()); + log.info("[{}]'{}' requested '{}'", LocalDateTime.now(),principal.getName(), req.getRequestURI()); } else { - log.info("requested '{}'", req.getRequestURI()); + log.info("[{}]requested '{}'",LocalDateTime.now(), req.getRequestURI()); } - log.error("bad request", e); + log.error("[{}] but throw Exception, {}",LocalDateTime.now() ,e.getMessage()); return "redirect:/error"; } } diff --git a/src/main/java/myblog/blog/utils/LayoutDtoFactory.java b/src/main/java/myblog/blog/layout/LayoutDtoFactory.java similarity index 96% rename from src/main/java/myblog/blog/utils/LayoutDtoFactory.java rename to src/main/java/myblog/blog/layout/LayoutDtoFactory.java index b820662..92ad52e 100644 --- a/src/main/java/myblog/blog/utils/LayoutDtoFactory.java +++ b/src/main/java/myblog/blog/layout/LayoutDtoFactory.java @@ -1,4 +1,4 @@ -package myblog.blog.utils; +package myblog.blog.layout; import lombok.RequiredArgsConstructor; import myblog.blog.category.dto.CategoryForView; @@ -22,11 +22,9 @@ public class LayoutDtoFactory { */ public void AddLayoutTo(Model model) { CategoryForView categoryForView = categoryService.getCategoryForView(); - model.addAttribute("category", categoryForView); - List comments = commentService.recentCommentList(); + model.addAttribute("category", categoryForView); model.addAttribute("commentsList", comments); - } diff --git a/src/main/java/myblog/blog/log/LogAspect.java b/src/main/java/myblog/blog/log/LogAspect.java new file mode 100644 index 0000000..7f52ea4 --- /dev/null +++ b/src/main/java/myblog/blog/log/LogAspect.java @@ -0,0 +1,33 @@ +package myblog.blog.log; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.stereotype.Component; + +@Aspect +@Slf4j +@RequiredArgsConstructor +@Component +public class LogAspect { + + private final LogTracer logTracer; + + @Around("execution(* myblog.blog..*Controller.*(..))||execution(* myblog.blog..*Service.*(..))||execution(* myblog.blog..*Repository.*(..))") + public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable { + TraceStatus status = null; + boolean hasException = false; + try { + status = logTracer.begin(joinPoint.getSignature().toString()); + return joinPoint.proceed(); + } catch (Exception ex) { + logTracer.exception(status, ex); + hasException = true; + throw ex; + } finally { + if(!hasException) logTracer.end(status); + } + } +} diff --git a/src/main/java/myblog/blog/log/LogTracer.java b/src/main/java/myblog/blog/log/LogTracer.java new file mode 100644 index 0000000..e885787 --- /dev/null +++ b/src/main/java/myblog/blog/log/LogTracer.java @@ -0,0 +1,72 @@ +package myblog.blog.log; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class LogTracer { + + private static final String START_PREFIX = "-->"; + private static final String COMPLETE_PREFIX = "<--"; + private static final String EX_PREFIX = " traceIdHolder = new ThreadLocal<>(); + + public TraceStatus begin(String message){ + syncTraceId(); + TraceId traceId = traceIdHolder.get(); + Long startTimeMs = System.currentTimeMillis(); + log.info("[{}] {}{}",traceId.getId(), addSpace(START_PREFIX, + traceId.getLevel()), message); + return new TraceStatus(traceId, startTimeMs, message); + } + + private void syncTraceId() { + TraceId traceId = traceIdHolder.get(); + if (traceId == null) { + traceIdHolder.set(new TraceId()); + } else { + traceIdHolder.set(traceId.createNextId()); + } + } + + public void end(TraceStatus traceStatus){ + complete(traceStatus, null); + } + + public void exception(TraceStatus traceStatus, Exception ex){ + complete(traceStatus, ex); + } + + private void complete(TraceStatus traceStatus, Exception ex) { + Long stopTimeMs = System.currentTimeMillis(); + Long resultTimeMs = stopTimeMs - traceStatus.getStartTimesMs(); + TraceId traceId = traceStatus.getTraceId(); + if(ex == null){ + log.info("[{}] {} {} time = {}ms", traceId.getId(), addSpace(COMPLETE_PREFIX, traceId.getLevel()), + traceStatus.getMessage(), resultTimeMs); + } else { + log.info("[{}] {} {} time = {}ms ex={}", traceId.getId(), addSpace(EX_PREFIX, traceId.getLevel()), + traceStatus.getMessage(), resultTimeMs, ex.toString()); + } + releaseTraceId(); + } + + private void releaseTraceId() { + TraceId traceId = traceIdHolder.get(); + if (traceId.isFirstLevel()) { + traceIdHolder.remove(); //destroy + } else { + traceIdHolder.set(traceId.createPrevId()); + } + } + + private String addSpace(String prefix, int level) { + StringBuilder sb = new StringBuilder(); + for(int i = 0; i< level; i++){ + sb.append((i==level-1) ? "|" + prefix : "| "); + } + return sb.toString(); + } +} diff --git a/src/main/java/myblog/blog/log/TraceId.java b/src/main/java/myblog/blog/log/TraceId.java new file mode 100644 index 0000000..5870db8 --- /dev/null +++ b/src/main/java/myblog/blog/log/TraceId.java @@ -0,0 +1,37 @@ +package myblog.blog.log; + +import lombok.Getter; + +import java.util.UUID; + +@Getter +public class TraceId { + private final String id; + private final int level; + + public TraceId() { + this.id = createdId(); + this.level = 0; + } + + private TraceId(String id, int level) { + this.id = id; + this.level = level; + } + + private String createdId() { + return UUID.randomUUID().toString().substring(0,8); + } + + public TraceId createNextId(){ + return new TraceId(id, level+1); + } + + public TraceId createPrevId(){ + return new TraceId(id, level-1); + } + + public boolean isFirstLevel(){ + return level == 0; + } +} diff --git a/src/main/java/myblog/blog/log/TraceStatus.java b/src/main/java/myblog/blog/log/TraceStatus.java new file mode 100644 index 0000000..2d79ade --- /dev/null +++ b/src/main/java/myblog/blog/log/TraceStatus.java @@ -0,0 +1,12 @@ +package myblog.blog.log; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class TraceStatus { + private TraceId traceId; + private Long startTimesMs; + private String message; +} diff --git a/src/main/java/myblog/blog/main/MainController.java b/src/main/java/myblog/blog/main/MainController.java index 40a57c7..0f06c17 100644 --- a/src/main/java/myblog/blog/main/MainController.java +++ b/src/main/java/myblog/blog/main/MainController.java @@ -1,18 +1,19 @@ package myblog.blog.main; +import ch.qos.logback.core.Layout; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import myblog.blog.article.dto.ArticleDtoForMain; +import myblog.blog.article.dto.ArticleDtoForCardBox; import myblog.blog.article.service.ArticleService; import myblog.blog.category.dto.CategoryForView; import myblog.blog.category.service.CategoryService; import myblog.blog.comment.dto.CommentDtoForLayout; import myblog.blog.comment.service.CommentService; +import myblog.blog.layout.LayoutDtoFactory; import org.commonmark.parser.Parser; import org.commonmark.renderer.html.HtmlRenderer; import org.jsoup.Jsoup; import org.modelmapper.ModelMapper; -import org.springframework.data.domain.Slice; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @@ -28,33 +29,23 @@ import java.util.stream.Collectors; public class MainController { private final ArticleService articleService; - private final CategoryService categoryService; - private final CommentService commentService; private final HtmlRenderer htmlRenderer; private final Parser parser; private final ModelMapper modelMapper; - + private final LayoutDtoFactory layoutDtoFactory; /* - 메인 화면 제어용 컨트롤러 */ @GetMapping("/") public String main(Model model) { - // Dto 전처리 - CategoryForView categoryForView = categoryService.getCategoryForView(); - - List comments = commentService.recentCommentList(); - - List popularArticles = articleService.getPopularArticles() + List popularArticles = articleService.getPopularArticles() .stream() - .map(article -> modelMapper.map(article, ArticleDtoForMain.class)) + .map(article -> modelMapper.map(article, ArticleDtoForCardBox.class)) .collect(Collectors.toList()); // - - model.addAttribute("category",categoryForView); - model.addAttribute("commentsList", comments); + layoutDtoFactory.AddLayoutTo(model); model.addAttribute("popularArticles", popularArticles); - return "index"; } @@ -63,17 +54,17 @@ public class MainController { */ @GetMapping("/main/article/{lastArticleId}") public @ResponseBody - List mainNextPage(@PathVariable(required = false) Long lastArticleId) { + List mainNextPage(@PathVariable(required = false) Long lastArticleId) { // Entity to Dto - List articles = articleService.getRecentArticles(lastArticleId) + List articles = articleService.getRecentArticles(lastArticleId) .stream() - .map(article -> modelMapper.map(article, ArticleDtoForMain.class)) + .map(article -> modelMapper.map(article, ArticleDtoForCardBox.class)) .collect(Collectors.toList()); ; // 화면렌더링을 위한 파싱 - for(ArticleDtoForMain article : articles){ + for(ArticleDtoForCardBox article : articles){ String content = Jsoup.parse(htmlRenderer.render(parser.parse(article.getContent()))).text(); if(content.length()>300) { content = content.substring(0, 300); diff --git a/src/main/java/myblog/blog/member/auth/UserInfoFactory.java b/src/main/java/myblog/blog/member/auth/UserInfoFactory.java index 4f1dd7c..2021415 100644 --- a/src/main/java/myblog/blog/member/auth/UserInfoFactory.java +++ b/src/main/java/myblog/blog/member/auth/UserInfoFactory.java @@ -36,7 +36,7 @@ public class UserInfoFactory { /* - 팩토리 메소드 */ - public Oauth2UserInfo makeOauth2UserinfoOf(OAuth2UserRequest oAuth2UserRequest, OAuth2User oAuth2User) { + public Oauth2UserInfo makeOauth2UserInfoOf(OAuth2UserRequest oAuth2UserRequest, OAuth2User oAuth2User) { Optional providerTypeOptional = fromString(oAuth2UserRequest.getClientRegistration().getRegistrationId()); diff --git a/src/main/java/myblog/blog/member/controller/MemberController.java b/src/main/java/myblog/blog/member/controller/MemberController.java index 0d98919..f353736 100644 --- a/src/main/java/myblog/blog/member/controller/MemberController.java +++ b/src/main/java/myblog/blog/member/controller/MemberController.java @@ -16,7 +16,6 @@ import java.util.stream.Collectors; @Controller @RequiredArgsConstructor -@Slf4j public class MemberController { private final CategoryService categoryService; diff --git a/src/main/java/myblog/blog/member/doamin/Member.java b/src/main/java/myblog/blog/member/doamin/Member.java index 3eb8161..ee7e915 100644 --- a/src/main/java/myblog/blog/member/doamin/Member.java +++ b/src/main/java/myblog/blog/member/doamin/Member.java @@ -3,7 +3,7 @@ package myblog.blog.member.doamin; import lombok.Builder; import lombok.Getter; import myblog.blog.article.domain.Article; -import myblog.blog.base.domain.BasicEntity; +import myblog.blog.base.BasicEntity; import myblog.blog.comment.domain.Comment; import javax.persistence.*; diff --git a/src/main/java/myblog/blog/member/service/Oauth2MemberService.java b/src/main/java/myblog/blog/member/service/Oauth2MemberService.java index 95a6a6f..52044f7 100644 --- a/src/main/java/myblog/blog/member/service/Oauth2MemberService.java +++ b/src/main/java/myblog/blog/member/service/Oauth2MemberService.java @@ -47,7 +47,7 @@ public class Oauth2MemberService extends DefaultOAuth2UserService { OAuth2User oAuth2User = super.loadUser(userRequest); Oauth2UserInfo userInfo = - userInfoFactory.makeOauth2UserinfoOf(userRequest, oAuth2User); + userInfoFactory.makeOauth2UserInfoOf(userRequest, oAuth2User); Member member = getOrJoinMember(userInfo); diff --git a/src/main/java/myblog/blog/tags/domain/ArticleTagList.java b/src/main/java/myblog/blog/tags/domain/ArticleTagList.java index 31f7f71..2804bd1 100644 --- a/src/main/java/myblog/blog/tags/domain/ArticleTagList.java +++ b/src/main/java/myblog/blog/tags/domain/ArticleTagList.java @@ -3,7 +3,7 @@ package myblog.blog.tags.domain; import lombok.Builder; import lombok.Getter; import myblog.blog.article.domain.Article; -import myblog.blog.base.domain.BasicEntity; +import myblog.blog.base.BasicEntity; import javax.persistence.*; diff --git a/src/main/java/myblog/blog/tags/domain/Tags.java b/src/main/java/myblog/blog/tags/domain/Tags.java index 064d621..fecc4ee 100644 --- a/src/main/java/myblog/blog/tags/domain/Tags.java +++ b/src/main/java/myblog/blog/tags/domain/Tags.java @@ -2,7 +2,7 @@ package myblog.blog.tags.domain; import lombok.Builder; import lombok.Getter; -import myblog.blog.base.domain.BasicEntity; +import myblog.blog.base.BasicEntity; import javax.persistence.*; import java.util.ArrayList; diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..b857fe1 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + ${LOGS_ABSOLUTE_PATH}/logback.log + + [%d{yyyy-MM-dd HH:mm:ss}:%-3relative][%thread] %-5level %logger{35} - %msg%n + + + ${LOGS_ABSOLUTE_PATH}/logback.%d{yyyy-MM-dd}.%i.log.gz + + 50MB + + 30 + + + + + + + error + ACCEPT + DENY + + + ${LOGS_ABSOLUTE_PATH}/ERR_LOG.log + + [%d{yyyy-MM-dd HH:mm:ss}:%-3relative][%thread] %-5level %logger{35} - %msg%n + + + + ${LOGS_ABSOLUTE_PATH}/logback.%d{yyyy-MM-dd}.%i.Error_log.gz + + + 50MB + + + 60 + + + + + + + + + +