diff --git a/src/main/java/cc/ryanc/halo/model/dto/CategoryOutputDTO.java b/src/main/java/cc/ryanc/halo/model/dto/CategoryOutputDTO.java new file mode 100644 index 000000000..694760da6 --- /dev/null +++ b/src/main/java/cc/ryanc/halo/model/dto/CategoryOutputDTO.java @@ -0,0 +1,23 @@ +package cc.ryanc.halo.model.dto; + +import cc.ryanc.halo.model.dto.base.OutputConverter; +import cc.ryanc.halo.model.entity.Category; +import lombok.Data; + +/** + * Category output dto. + * + * @author johnniang + * @date 3/19/19 + */ +@Data +public class CategoryOutputDTO implements OutputConverter { + + private String name; + + private String snakeName; + + private String description; + + private Integer parentId; +} diff --git a/src/main/java/cc/ryanc/halo/model/dto/TagOutputDTO.java b/src/main/java/cc/ryanc/halo/model/dto/TagOutputDTO.java new file mode 100644 index 000000000..89e2cbdba --- /dev/null +++ b/src/main/java/cc/ryanc/halo/model/dto/TagOutputDTO.java @@ -0,0 +1,19 @@ +package cc.ryanc.halo.model.dto; + +import cc.ryanc.halo.model.dto.base.OutputConverter; +import cc.ryanc.halo.model.entity.Tag; +import lombok.Data; + +/** + * Tag output dto. + * + * @author johnniang + * @date 3/19/19 + */ +@Data +public class TagOutputDTO implements OutputConverter { + + private String name; + + private String snakeName; +} diff --git a/src/main/java/cc/ryanc/halo/model/enums/ValueEnum.java b/src/main/java/cc/ryanc/halo/model/enums/ValueEnum.java index a54966315..edbc7dae9 100644 --- a/src/main/java/cc/ryanc/halo/model/enums/ValueEnum.java +++ b/src/main/java/cc/ryanc/halo/model/enums/ValueEnum.java @@ -1,6 +1,5 @@ package cc.ryanc.halo.model.enums; -import com.fasterxml.jackson.annotation.JsonValue; import org.springframework.util.Assert; import java.util.stream.Stream; @@ -38,6 +37,5 @@ public interface ValueEnum { * * @return enum value */ - @JsonValue T getValue(); } diff --git a/src/main/java/cc/ryanc/halo/model/vo/PostListVO.java b/src/main/java/cc/ryanc/halo/model/vo/PostListVO.java new file mode 100644 index 000000000..47335c361 --- /dev/null +++ b/src/main/java/cc/ryanc/halo/model/vo/PostListVO.java @@ -0,0 +1,22 @@ +package cc.ryanc.halo.model.vo; + +import cc.ryanc.halo.model.dto.CategoryOutputDTO; +import cc.ryanc.halo.model.dto.TagOutputDTO; +import cc.ryanc.halo.model.dto.post.PostSimpleOutputDTO; +import lombok.Data; + +import java.util.List; + +/** + * Post list vo. + * + * @author johnniang + * @date 3/19/19 + */ +@Data +public class PostListVO extends PostSimpleOutputDTO { + + private List tags; + + private List categories; +} diff --git a/src/main/java/cc/ryanc/halo/repository/PostCategoryRepository.java b/src/main/java/cc/ryanc/halo/repository/PostCategoryRepository.java index 91e98c8f7..3c8ef925a 100644 --- a/src/main/java/cc/ryanc/halo/repository/PostCategoryRepository.java +++ b/src/main/java/cc/ryanc/halo/repository/PostCategoryRepository.java @@ -2,6 +2,11 @@ package cc.ryanc.halo.repository; import cc.ryanc.halo.model.entity.PostCategory; import cc.ryanc.halo.repository.base.BaseRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.lang.NonNull; + +import java.util.List; +import java.util.Set; /** @@ -11,4 +16,32 @@ import cc.ryanc.halo.repository.base.BaseRepository; */ public interface PostCategoryRepository extends BaseRepository { + /** + * Finds all category ids by post id + * + * @param postId post id must not be null + * @return a list of category id + */ + @NonNull + @Query("select postCategory.categoryId from PostCategory postCategory where postCategory.postId = ?1") + Set findAllCategoryIdsByPostId(@NonNull Integer postId); + + /** + * Finds all post ids by category id. + * + * @param categoryId category id must not be null + * @return a set of post id + */ + @NonNull + @Query("select postCategory.postId from PostCategory postCategory where postCategory.categoryId = ?1") + Set findAllPostIdsByCategoryId(@NonNull Integer categoryId); + + /** + * Finds all post categories by post id in. + * + * @param postIds post id collection must not be null + * @return a list of post category + */ + @NonNull + List findAllByPostIdIn(@NonNull Iterable postIds); } diff --git a/src/main/java/cc/ryanc/halo/repository/PostTagRepository.java b/src/main/java/cc/ryanc/halo/repository/PostTagRepository.java index 4bfafcca7..4423bded4 100644 --- a/src/main/java/cc/ryanc/halo/repository/PostTagRepository.java +++ b/src/main/java/cc/ryanc/halo/repository/PostTagRepository.java @@ -1,7 +1,12 @@ package cc.ryanc.halo.repository; -import cc.ryanc.halo.model.entity.Tag; +import cc.ryanc.halo.model.entity.PostTag; import cc.ryanc.halo.repository.base.BaseRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.lang.NonNull; + +import java.util.List; +import java.util.Set; /** @@ -9,6 +14,52 @@ import cc.ryanc.halo.repository.base.BaseRepository; * * @author johnniang */ -public interface PostTagRepository extends BaseRepository { +public interface PostTagRepository extends BaseRepository { + /** + * Finds all post tags by post id. + * + * @param postId post id must not be null + * @return a list of post tags + */ + @NonNull + List findAllByPostId(@NonNull Integer postId); + + /** + * Finds all tag ids by post id. + * + * @param postId post id must not be null + * @return a set of tag id + */ + @Query("select postTag.tagId from PostTag postTag where postTag.postId = ?1") + @NonNull + Set findAllTagIdsByPostId(@NonNull Integer postId); + + /** + * Finds all post tags by tag id. + * + * @param tagId tag id must not be null + * @return a list of post tags + */ + @NonNull + List findAllByTagId(@NonNull Integer tagId); + + /** + * Finds all post id by tag id. + * + * @param tagId tag id must not be null + * @return a set of post id + */ + @Query("select postTag.postId from PostTag postTag where postTag.tagId = ?1") + @NonNull + Set findAllPostIdsByTagId(@NonNull Integer tagId); + + /** + * Finds all tags by post id in. + * + * @param postIds post id collection + * @return a list of post tags + */ + @NonNull + List findAllByPostIdIn(@NonNull Iterable postIds); } diff --git a/src/main/java/cc/ryanc/halo/service/PostCategoryService.java b/src/main/java/cc/ryanc/halo/service/PostCategoryService.java new file mode 100644 index 000000000..6d74cc133 --- /dev/null +++ b/src/main/java/cc/ryanc/halo/service/PostCategoryService.java @@ -0,0 +1,47 @@ +package cc.ryanc.halo.service; + +import cc.ryanc.halo.model.entity.Category; +import cc.ryanc.halo.model.entity.Post; +import cc.ryanc.halo.model.entity.PostCategory; +import cc.ryanc.halo.service.base.CrudService; +import org.springframework.lang.NonNull; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * Post category service interface. + * + * @author johnniang + * @date 3/19/19 + */ +public interface PostCategoryService extends CrudService { + + /** + * Lists category by post id. + * + * @param postId post id must not be null + * @return a list of category + */ + @NonNull + List listCategoryBy(@NonNull Integer postId); + + /** + * List category list map by post id collection. + * + * @param postIds post id collection + * @return a category list map (key: postId, value: a list of category) + */ + @NonNull + Map> listCategoryListMap(Collection postIds); + + /** + * Lists post by category id. + * + * @param categoryId category id must not be null + * @return a list of post + */ + @NonNull + List listPostBy(@NonNull Integer categoryId); +} diff --git a/src/main/java/cc/ryanc/halo/service/PostService.java b/src/main/java/cc/ryanc/halo/service/PostService.java index 20719599a..a5cde3f49 100755 --- a/src/main/java/cc/ryanc/halo/service/PostService.java +++ b/src/main/java/cc/ryanc/halo/service/PostService.java @@ -7,6 +7,7 @@ import cc.ryanc.halo.model.entity.Post; import cc.ryanc.halo.model.entity.Tag; import cc.ryanc.halo.model.enums.PostStatus; import cc.ryanc.halo.model.enums.PostType; +import cc.ryanc.halo.model.vo.PostListVO; import cc.ryanc.halo.service.base.CrudService; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -68,17 +69,39 @@ public interface PostService extends CrudService { @NonNull Page pageLatest(int top); - /** * List by status and type * - * @param status status - * @param type type - * @param pageable pageable + * @param status post status must not be null + * @param type post type must not be null + * @param pageable page info must not be null * @return Page */ @NonNull - Page pageByStatus(PostStatus status, PostType type, Pageable pageable); + Page pageBy(@NonNull PostStatus status, @NonNull PostType type, @NonNull Pageable pageable); + + + /** + * List simple output dto by status and type + * + * @param status post status must not be null + * @param type post type must not be null + * @param pageable page info must not be null + * @return Page + */ + @NonNull + Page pageSimpleDtoByStatus(@NonNull PostStatus status, @NonNull PostType type, @NonNull Pageable pageable); + + /** + * Lists page list vo by status, type and pageable. + * + * @param status post status must not be null + * @param type post type must not be null + * @param pageable page info must not be null + * @return a page of page list vo + */ + @NonNull + Page pageListVoBy(@NonNull PostStatus status, @NonNull PostType type, @NonNull Pageable pageable); /** * Count posts by status and type diff --git a/src/main/java/cc/ryanc/halo/service/PostTagService.java b/src/main/java/cc/ryanc/halo/service/PostTagService.java new file mode 100644 index 000000000..e55708be8 --- /dev/null +++ b/src/main/java/cc/ryanc/halo/service/PostTagService.java @@ -0,0 +1,48 @@ +package cc.ryanc.halo.service; + +import cc.ryanc.halo.model.entity.Post; +import cc.ryanc.halo.model.entity.PostTag; +import cc.ryanc.halo.model.entity.Tag; +import cc.ryanc.halo.service.base.CrudService; +import org.springframework.lang.NonNull; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * Post tag service interface. + * + * @author johnniang + * @date 3/19/19 + */ +public interface PostTagService extends CrudService { + + /** + * Lists tags by post id. + * + * @param postId post id must not be null + * @return a list of tag + */ + @NonNull + List listTagBy(@NonNull Integer postId); + + /** + * Lists tag list map by post id. + * + * @param postIds post id collection + * @return tag map (key: postId, value: a list of tags) + */ + @NonNull + Map> listTagListMapBy(Collection postIds); + + /** + * Lists post by tag id. + * + * @param tagId tag id must not be null + * @return a list of post + */ + @NonNull + List listPostBy(@NonNull Integer tagId); + +} diff --git a/src/main/java/cc/ryanc/halo/service/impl/PostCategoryServiceImpl.java b/src/main/java/cc/ryanc/halo/service/impl/PostCategoryServiceImpl.java new file mode 100644 index 000000000..d7094da74 --- /dev/null +++ b/src/main/java/cc/ryanc/halo/service/impl/PostCategoryServiceImpl.java @@ -0,0 +1,88 @@ +package cc.ryanc.halo.service.impl; + +import cc.ryanc.halo.model.entity.Category; +import cc.ryanc.halo.model.entity.Post; +import cc.ryanc.halo.model.entity.PostCategory; +import cc.ryanc.halo.repository.CategoryRepository; +import cc.ryanc.halo.repository.PostCategoryRepository; +import cc.ryanc.halo.repository.PostRepository; +import cc.ryanc.halo.service.PostCategoryService; +import cc.ryanc.halo.service.base.AbstractCrudService; +import cc.ryanc.halo.utils.ServiceUtils; +import org.springframework.stereotype.Service; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +import java.util.*; + +/** + * Post category service implementation. + * + * @author johnniang + * @date 3/19/19 + */ +@Service +public class PostCategoryServiceImpl extends AbstractCrudService implements PostCategoryService { + + private final PostCategoryRepository postCategoryRepository; + + private final PostRepository postRepository; + + private final CategoryRepository categoryRepository; + + public PostCategoryServiceImpl(PostCategoryRepository postCategoryRepository, + PostRepository postRepository, + CategoryRepository categoryRepository) { + super(postCategoryRepository); + this.postCategoryRepository = postCategoryRepository; + this.postRepository = postRepository; + this.categoryRepository = categoryRepository; + } + + @Override + public List listCategoryBy(Integer postId) { + Assert.notNull(postId, "Post id must not be null"); + + // Find all category ids + Set categoryIds = postCategoryRepository.findAllCategoryIdsByPostId(postId); + + return categoryRepository.findAllById(categoryIds); + } + + @Override + public Map> listCategoryListMap(Collection postIds) { + if (CollectionUtils.isEmpty(postIds)) { + return Collections.emptyMap(); + } + + // Find all post categories + List postCategories = postCategoryRepository.findAllByPostIdIn(postIds); + + // Fetch category ids + Set categoryIds = ServiceUtils.fetchProperty(postCategories, PostCategory::getCategoryId); + + // Find all categories + List categories = categoryRepository.findAllById(categoryIds); + + // Convert to category map + Map categoryMap = ServiceUtils.convertToMap(categories, Category::getId); + + // Create category list map + Map> categoryListMap = new HashMap<>(); + + // Foreach and collect + postCategories.forEach(postCategory -> categoryListMap.putIfAbsent(postCategory.getPostId(), new LinkedList<>()).add(categoryMap.get(postCategory.getCategoryId()))); + + return categoryListMap; + } + + @Override + public List listPostBy(Integer categoryId) { + Assert.notNull(categoryId, "Category id must not be null"); + + // Find all post ids + Set postIds = postCategoryRepository.findAllPostIdsByCategoryId(categoryId); + + return postRepository.findAllById(postIds); + } +} diff --git a/src/main/java/cc/ryanc/halo/service/impl/PostServiceImpl.java b/src/main/java/cc/ryanc/halo/service/impl/PostServiceImpl.java index 77ad00931..29626b7a3 100644 --- a/src/main/java/cc/ryanc/halo/service/impl/PostServiceImpl.java +++ b/src/main/java/cc/ryanc/halo/service/impl/PostServiceImpl.java @@ -1,5 +1,7 @@ package cc.ryanc.halo.service.impl; +import cc.ryanc.halo.model.dto.CategoryOutputDTO; +import cc.ryanc.halo.model.dto.TagOutputDTO; import cc.ryanc.halo.model.dto.post.PostMinimalOutputDTO; import cc.ryanc.halo.model.dto.post.PostSimpleOutputDTO; import cc.ryanc.halo.model.entity.Category; @@ -7,9 +9,13 @@ import cc.ryanc.halo.model.entity.Post; import cc.ryanc.halo.model.entity.Tag; import cc.ryanc.halo.model.enums.PostStatus; import cc.ryanc.halo.model.enums.PostType; +import cc.ryanc.halo.model.vo.PostListVO; import cc.ryanc.halo.repository.PostRepository; +import cc.ryanc.halo.service.PostCategoryService; import cc.ryanc.halo.service.PostService; +import cc.ryanc.halo.service.PostTagService; import cc.ryanc.halo.service.base.AbstractCrudService; +import cc.ryanc.halo.utils.ServiceUtils; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -18,6 +24,9 @@ import org.springframework.stereotype.Service; import org.springframework.util.Assert; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; /** * Post service implementation. @@ -30,9 +39,17 @@ public class PostServiceImpl extends AbstractCrudService implemen private final PostRepository postRepository; - public PostServiceImpl(PostRepository postRepository) { + private final PostTagService postTagService; + + private final PostCategoryService postCategoryService; + + public PostServiceImpl(PostRepository postRepository, + PostTagService postTagService, + PostCategoryService postCategoryService) { super(postRepository); this.postRepository = postRepository; + this.postTagService = postTagService; + this.postCategoryService = postCategoryService; } /** @@ -78,6 +95,15 @@ public class PostServiceImpl extends AbstractCrudService implemen return listAll(latestPageable); } + @Override + public Page pageBy(PostStatus status, PostType type, Pageable pageable) { + Assert.notNull(status, "Post status must not be null"); + Assert.notNull(type, "Post type must not be null"); + Assert.notNull(pageable, "Page info must not be null"); + + return postRepository.findAllByStatusAndType(status, type, pageable); + } + /** * List by status and type * @@ -87,9 +113,35 @@ public class PostServiceImpl extends AbstractCrudService implemen * @return Page */ @Override - public Page pageByStatus(PostStatus status, PostType type, Pageable pageable) { - Page posts = postRepository.findAllByStatusAndType(status, type, pageable); - return posts.map(post -> new PostSimpleOutputDTO().convertFrom(post)); + public Page pageSimpleDtoByStatus(PostStatus status, PostType type, Pageable pageable) { + return pageBy(status, type, pageable).map(post -> new PostSimpleOutputDTO().convertFrom(post)); + } + + @Override + public Page pageListVoBy(PostStatus status, PostType type, Pageable pageable) { + Page postPage = pageBy(status, type, pageable); + + List posts = postPage.getContent(); + + Set postIds = ServiceUtils.fetchProperty(posts, Post::getId); + + Map> tagListMap = postTagService.listTagListMapBy(postIds); + + Map> categoryListMap = postCategoryService.listCategoryListMap(postIds); + + return postPage.map(post -> { + PostListVO postListVO = new PostListVO().convertFrom(post); + + // Set tags + List tagOutputDTOS = tagListMap.get(post.getId()).stream().map(tag -> (TagOutputDTO) new TagOutputDTO().convertFrom(tag)).collect(Collectors.toList()); + postListVO.setTags(tagOutputDTOS); + + // Set categories + List categoryOutputDTOS = categoryListMap.get(post.getId()).stream().map(category -> (CategoryOutputDTO) new CategoryOutputDTO().convertFrom(category)).collect(Collectors.toList()); + postListVO.setCategories(categoryOutputDTOS); + + return postListVO; + }); } /** diff --git a/src/main/java/cc/ryanc/halo/service/impl/PostTagServiceImpl.java b/src/main/java/cc/ryanc/halo/service/impl/PostTagServiceImpl.java new file mode 100644 index 000000000..45607cc57 --- /dev/null +++ b/src/main/java/cc/ryanc/halo/service/impl/PostTagServiceImpl.java @@ -0,0 +1,89 @@ +package cc.ryanc.halo.service.impl; + +import cc.ryanc.halo.model.entity.Post; +import cc.ryanc.halo.model.entity.PostTag; +import cc.ryanc.halo.model.entity.Tag; +import cc.ryanc.halo.repository.PostRepository; +import cc.ryanc.halo.repository.PostTagRepository; +import cc.ryanc.halo.repository.TagRepository; +import cc.ryanc.halo.service.PostTagService; +import cc.ryanc.halo.service.base.AbstractCrudService; +import cc.ryanc.halo.utils.ServiceUtils; +import org.springframework.stereotype.Service; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +import java.util.*; + +/** + * Post tag service implementation. + * + * @author johnniang + * @date 3/19/19 + */ +@Service +public class PostTagServiceImpl extends AbstractCrudService implements PostTagService { + + private final PostTagRepository postTagRepository; + + private final PostRepository postRepository; + + private final TagRepository tagRepository; + + public PostTagServiceImpl(PostTagRepository postTagRepository, + PostRepository postRepository, + TagRepository tagRepository) { + super(postTagRepository); + this.postTagRepository = postTagRepository; + this.postRepository = postRepository; + this.tagRepository = tagRepository; + } + + @Override + public List listTagBy(Integer postId) { + Assert.notNull(postId, "Post id must not be null"); + + // Find all tag ids + Set tagIds = postTagRepository.findAllTagIdsByPostId(postId); + + return tagRepository.findAllById(tagIds); + } + + @Override + public Map> listTagListMapBy(Collection postIds) { + if (CollectionUtils.isEmpty(postIds)) { + return Collections.emptyMap(); + } + + // Find all post tags + List postTags = postTagRepository.findAllByPostIdIn(postIds); + + // Fetch tag ids + Set tagIds = ServiceUtils.fetchProperty(postTags, PostTag::getTagId); + + // Find all tags + List tags = tagRepository.findAllById(tagIds); + + // Convert to tag map + Map tagMap = ServiceUtils.convertToMap(tags, Tag::getId); + + // Create tag list map + Map> tagListMap = new HashMap<>(); + + // Foreach and collect + postTags.forEach(postTag -> tagListMap.putIfAbsent(postTag.getPostId(), new LinkedList<>()).add(tagMap.get(postTag.getTagId()))); + + return tagListMap; + } + + + @Override + public List listPostBy(Integer tagId) { + Assert.notNull(tagId, "Tag id must not be null"); + + // Find all post ids + Set postIds = postTagRepository.findAllPostIdsByTagId(tagId); + + return postRepository.findAllById(postIds); + } +} diff --git a/src/main/java/cc/ryanc/halo/web/controller/admin/api/PostController.java b/src/main/java/cc/ryanc/halo/web/controller/admin/api/PostController.java index d34a3c3d2..5e9021196 100644 --- a/src/main/java/cc/ryanc/halo/web/controller/admin/api/PostController.java +++ b/src/main/java/cc/ryanc/halo/web/controller/admin/api/PostController.java @@ -1,15 +1,20 @@ package cc.ryanc.halo.web.controller.admin.api; import cc.ryanc.halo.model.dto.post.PostMinimalOutputDTO; +import cc.ryanc.halo.model.dto.post.PostSimpleOutputDTO; +import cc.ryanc.halo.model.enums.PostStatus; +import cc.ryanc.halo.model.enums.PostType; import cc.ryanc.halo.service.PostService; import io.swagger.annotations.ApiOperation; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PageableDefault; +import org.springframework.web.bind.annotation.*; import java.util.List; +import static org.springframework.data.domain.Sort.Direction.DESC; + /** * Post controller. * @@ -32,4 +37,10 @@ public class PostController { return postService.pageLatestOfMinimal(top).getContent(); } + @GetMapping("status/{status}") + @ApiOperation("") + public Page pageByStatus(@PathVariable(name = "status") PostStatus status, + @PageableDefault(sort = "updateTime", direction = DESC) Pageable pageable) { + return postService.pageSimpleDtoByStatus(status, PostType.POST, pageable); + } }