Complete pageByStatus api

pull/137/head
johnniang 2019-03-19 23:16:14 +08:00
parent 9c52e24a8d
commit 6a823ddcde
13 changed files with 521 additions and 17 deletions

View File

@ -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<CategoryOutputDTO, Category> {
private String name;
private String snakeName;
private String description;
private Integer parentId;
}

View File

@ -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<TagOutputDTO, Tag> {
private String name;
private String snakeName;
}

View File

@ -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<T> {
*
* @return enum value
*/
@JsonValue
T getValue();
}

View File

@ -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<TagOutputDTO> tags;
private List<CategoryOutputDTO> categories;
}

View File

@ -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<PostCategory, Integer> {
/**
* 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<Integer> 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<Integer> 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<PostCategory> findAllByPostIdIn(@NonNull Iterable<Integer> postIds);
}

View File

@ -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<Tag, Integer> {
public interface PostTagRepository extends BaseRepository<PostTag, Integer> {
/**
* Finds all post tags by post id.
*
* @param postId post id must not be null
* @return a list of post tags
*/
@NonNull
List<PostTag> 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<Integer> 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<PostTag> 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<Integer> findAllPostIdsByTagId(@NonNull Integer tagId);
/**
* Finds all tags by post id in.
*
* @param postIds post id collection
* @return a list of post tags
*/
@NonNull
List<PostTag> findAllByPostIdIn(@NonNull Iterable<Integer> postIds);
}

View File

@ -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<PostCategory, Integer> {
/**
* Lists category by post id.
*
* @param postId post id must not be null
* @return a list of category
*/
@NonNull
List<Category> 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<Integer, List<Category>> listCategoryListMap(Collection<Integer> postIds);
/**
* Lists post by category id.
*
* @param categoryId category id must not be null
* @return a list of post
*/
@NonNull
List<Post> listPostBy(@NonNull Integer categoryId);
}

View File

@ -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<Post, Integer> {
@NonNull
Page<Post> 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<PostSimpleOutputDTO>
*/
@NonNull
Page<PostSimpleOutputDTO> pageByStatus(PostStatus status, PostType type, Pageable pageable);
Page<Post> 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<PostSimpleOutputDTO>
*/
@NonNull
Page<PostSimpleOutputDTO> 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<PostListVO> pageListVoBy(@NonNull PostStatus status, @NonNull PostType type, @NonNull Pageable pageable);
/**
* Count posts by status and type

View File

@ -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<PostTag, Integer> {
/**
* Lists tags by post id.
*
* @param postId post id must not be null
* @return a list of tag
*/
@NonNull
List<Tag> 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<Integer, List<Tag>> listTagListMapBy(Collection<Integer> postIds);
/**
* Lists post by tag id.
*
* @param tagId tag id must not be null
* @return a list of post
*/
@NonNull
List<Post> listPostBy(@NonNull Integer tagId);
}

View File

@ -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<PostCategory, Integer> 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<Category> listCategoryBy(Integer postId) {
Assert.notNull(postId, "Post id must not be null");
// Find all category ids
Set<Integer> categoryIds = postCategoryRepository.findAllCategoryIdsByPostId(postId);
return categoryRepository.findAllById(categoryIds);
}
@Override
public Map<Integer, List<Category>> listCategoryListMap(Collection<Integer> postIds) {
if (CollectionUtils.isEmpty(postIds)) {
return Collections.emptyMap();
}
// Find all post categories
List<PostCategory> postCategories = postCategoryRepository.findAllByPostIdIn(postIds);
// Fetch category ids
Set<Integer> categoryIds = ServiceUtils.fetchProperty(postCategories, PostCategory::getCategoryId);
// Find all categories
List<Category> categories = categoryRepository.findAllById(categoryIds);
// Convert to category map
Map<Integer, Category> categoryMap = ServiceUtils.convertToMap(categories, Category::getId);
// Create category list map
Map<Integer, List<Category>> 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<Post> listPostBy(Integer categoryId) {
Assert.notNull(categoryId, "Category id must not be null");
// Find all post ids
Set<Integer> postIds = postCategoryRepository.findAllPostIdsByCategoryId(categoryId);
return postRepository.findAllById(postIds);
}
}

View File

@ -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<Post, Integer> 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<Post, Integer> implemen
return listAll(latestPageable);
}
@Override
public Page<Post> 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<Post, Integer> implemen
* @return Page<PostSimpleOutputDTO>
*/
@Override
public Page<PostSimpleOutputDTO> pageByStatus(PostStatus status, PostType type, Pageable pageable) {
Page<Post> posts = postRepository.findAllByStatusAndType(status, type, pageable);
return posts.map(post -> new PostSimpleOutputDTO().convertFrom(post));
public Page<PostSimpleOutputDTO> pageSimpleDtoByStatus(PostStatus status, PostType type, Pageable pageable) {
return pageBy(status, type, pageable).map(post -> new PostSimpleOutputDTO().convertFrom(post));
}
@Override
public Page<PostListVO> pageListVoBy(PostStatus status, PostType type, Pageable pageable) {
Page<Post> postPage = pageBy(status, type, pageable);
List<Post> posts = postPage.getContent();
Set<Integer> postIds = ServiceUtils.fetchProperty(posts, Post::getId);
Map<Integer, List<Tag>> tagListMap = postTagService.listTagListMapBy(postIds);
Map<Integer, List<Category>> categoryListMap = postCategoryService.listCategoryListMap(postIds);
return postPage.map(post -> {
PostListVO postListVO = new PostListVO().convertFrom(post);
// Set tags
List<TagOutputDTO> tagOutputDTOS = tagListMap.get(post.getId()).stream().map(tag -> (TagOutputDTO) new TagOutputDTO().convertFrom(tag)).collect(Collectors.toList());
postListVO.setTags(tagOutputDTOS);
// Set categories
List<CategoryOutputDTO> categoryOutputDTOS = categoryListMap.get(post.getId()).stream().map(category -> (CategoryOutputDTO) new CategoryOutputDTO().convertFrom(category)).collect(Collectors.toList());
postListVO.setCategories(categoryOutputDTOS);
return postListVO;
});
}
/**

View File

@ -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<PostTag, Integer> 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<Tag> listTagBy(Integer postId) {
Assert.notNull(postId, "Post id must not be null");
// Find all tag ids
Set<Integer> tagIds = postTagRepository.findAllTagIdsByPostId(postId);
return tagRepository.findAllById(tagIds);
}
@Override
public Map<Integer, List<Tag>> listTagListMapBy(Collection<Integer> postIds) {
if (CollectionUtils.isEmpty(postIds)) {
return Collections.emptyMap();
}
// Find all post tags
List<PostTag> postTags = postTagRepository.findAllByPostIdIn(postIds);
// Fetch tag ids
Set<Integer> tagIds = ServiceUtils.fetchProperty(postTags, PostTag::getTagId);
// Find all tags
List<Tag> tags = tagRepository.findAllById(tagIds);
// Convert to tag map
Map<Integer, Tag> tagMap = ServiceUtils.convertToMap(tags, Tag::getId);
// Create tag list map
Map<Integer, List<Tag>> 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<Post> listPostBy(Integer tagId) {
Assert.notNull(tagId, "Tag id must not be null");
// Find all post ids
Set<Integer> postIds = postTagRepository.findAllPostIdsByTagId(tagId);
return postRepository.findAllById(postIds);
}
}

View File

@ -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<PostSimpleOutputDTO> pageByStatus(@PathVariable(name = "status") PostStatus status,
@PageableDefault(sort = "updateTime", direction = DESC) Pageable pageable) {
return postService.pageSimpleDtoByStatus(status, PostType.POST, pageable);
}
}