diff --git a/src/main/java/cc/ryanc/halo/model/dto/CategoryOutputDTO.java b/src/main/java/cc/ryanc/halo/model/dto/CategoryOutputDTO.java index 9391095c1..f83a32161 100644 --- a/src/main/java/cc/ryanc/halo/model/dto/CategoryOutputDTO.java +++ b/src/main/java/cc/ryanc/halo/model/dto/CategoryOutputDTO.java @@ -13,6 +13,8 @@ import lombok.Data; @Data public class CategoryOutputDTO implements OutputConverter { + private Integer id; + private String name; private String slugName; diff --git a/src/main/java/cc/ryanc/halo/model/vo/CategoryVO.java b/src/main/java/cc/ryanc/halo/model/vo/CategoryVO.java new file mode 100644 index 000000000..32182a6dc --- /dev/null +++ b/src/main/java/cc/ryanc/halo/model/vo/CategoryVO.java @@ -0,0 +1,18 @@ +package cc.ryanc.halo.model.vo; + +import cc.ryanc.halo.model.dto.CategoryOutputDTO; +import lombok.Data; + +import java.util.List; + +/** + * Category vo. + * + * @author johnniang + * @date 3/21/19 + */ +@Data +public class CategoryVO extends CategoryOutputDTO { + + private List children; +} diff --git a/src/main/java/cc/ryanc/halo/service/CategoryService.java b/src/main/java/cc/ryanc/halo/service/CategoryService.java index 5830f3c45..15b9b22bb 100755 --- a/src/main/java/cc/ryanc/halo/service/CategoryService.java +++ b/src/main/java/cc/ryanc/halo/service/CategoryService.java @@ -1,7 +1,12 @@ package cc.ryanc.halo.service; import cc.ryanc.halo.model.entity.Category; +import cc.ryanc.halo.model.vo.CategoryVO; import cc.ryanc.halo.service.base.CrudService; +import org.springframework.data.domain.Sort; +import org.springframework.lang.NonNull; + +import java.util.List; /** * Category service. @@ -15,5 +20,15 @@ public interface CategoryService extends CrudService { * * @param id id */ - void remove(Integer id); + @Deprecated + void remove(@NonNull Integer id); + + /** + * List as category tree. + * + * @param sort sort info must not be null + * @return a category tree + */ + @NonNull + List listAsTree(@NonNull Sort sort); } diff --git a/src/main/java/cc/ryanc/halo/service/impl/CategoryServiceImpl.java b/src/main/java/cc/ryanc/halo/service/impl/CategoryServiceImpl.java index 1983a431e..827bb0ef0 100644 --- a/src/main/java/cc/ryanc/halo/service/impl/CategoryServiceImpl.java +++ b/src/main/java/cc/ryanc/halo/service/impl/CategoryServiceImpl.java @@ -1,10 +1,20 @@ package cc.ryanc.halo.service.impl; import cc.ryanc.halo.model.entity.Category; +import cc.ryanc.halo.model.vo.CategoryVO; import cc.ryanc.halo.repository.CategoryRepository; import cc.ryanc.halo.service.CategoryService; import cc.ryanc.halo.service.base.AbstractCrudService; +import org.springframework.data.domain.Sort; +import org.springframework.lang.NonNull; import org.springframework.stereotype.Service; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; /** * CategoryService implementation class @@ -31,4 +41,78 @@ public class CategoryServiceImpl extends AbstractCrudService public void remove(Integer id) { // TODO 删除分类,以及和文章的对应关系 } + + @Override + public List listAsTree(Sort sort) { + Assert.notNull(sort, "Sort info must not be null"); + + // List all category + List categories = listAll(sort); + + if (CollectionUtils.isEmpty(categories)) { + return Collections.emptyList(); + } + + // Create top category + CategoryVO topLevelCategory = createTopLevelCategory(); + + // Concrete the tree + concreteTree(topLevelCategory, categories); + + return topLevelCategory.getChildren(); + } + + /** + * Concrete category tree. + * + * @param parentCategory parent category vo must not be null + * @param categories a list of category + */ + private void concreteTree(CategoryVO parentCategory, List categories) { + Assert.notNull(parentCategory, "Parent category must not be null"); + + if (CollectionUtils.isEmpty(categories)) { + return; + } + + // Create children container for removing after + List children = new LinkedList<>(); + + categories.forEach(category -> { + if (parentCategory.getId().equals(category.getParentId())) { + // Save child category + children.add(category); + + // Convert to child category vo + CategoryVO child = new CategoryVO().convertFrom(category); + + // Init children if absent + Optional.ofNullable(parentCategory.getChildren()).orElseGet(LinkedList::new).add(child); + } + }); + + // Remove all child categories + categories.removeAll(children); + + // Foreach children vos + if (!CollectionUtils.isEmpty(parentCategory.getChildren())) { + parentCategory.getChildren().forEach(childCategory -> concreteTree(childCategory, categories)); + } + } + + /** + * Creates a top level category. + * + * @return top level category with id 0 + */ + @NonNull + private CategoryVO createTopLevelCategory() { + CategoryVO topCategory = new CategoryVO(); + // Set default value + topCategory.setId(0); + topCategory.setChildren(new LinkedList<>()); + topCategory.setParentId(-1); + + return topCategory; + } } diff --git a/src/main/java/cc/ryanc/halo/web/controller/admin/api/CategoryController.java b/src/main/java/cc/ryanc/halo/web/controller/admin/api/CategoryController.java new file mode 100644 index 000000000..c08224111 --- /dev/null +++ b/src/main/java/cc/ryanc/halo/web/controller/admin/api/CategoryController.java @@ -0,0 +1,37 @@ +package cc.ryanc.halo.web.controller.admin.api; + +import cc.ryanc.halo.model.vo.CategoryVO; +import cc.ryanc.halo.service.CategoryService; +import io.swagger.annotations.ApiOperation; +import org.springframework.data.domain.Sort; +import org.springframework.data.web.SortDefault; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +import static org.springframework.data.domain.Sort.Direction.DESC; + +/** + * Category controller. + * + * @author johnniang + * @date 3/21/19 + */ +@RestController +@RequestMapping("/admin/api/categories") +public class CategoryController { + + private final CategoryService categoryService; + + public CategoryController(CategoryService categoryService) { + this.categoryService = categoryService; + } + + @GetMapping("tree") + @ApiOperation("List as category tree") + public List listAsTree(@SortDefault(sort = "name", direction = DESC) Sort sort) { + return categoryService.listAsTree(sort); + } +} 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 5e9021196..e04c40645 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 @@ -38,7 +38,7 @@ public class PostController { } @GetMapping("status/{status}") - @ApiOperation("") + @ApiOperation("Gets a page of post by post status") public Page pageByStatus(@PathVariable(name = "status") PostStatus status, @PageableDefault(sort = "updateTime", direction = DESC) Pageable pageable) { return postService.pageSimpleDtoByStatus(status, PostType.POST, pageable);