菜单支持多级

pull/146/head
ruibaby 2019-04-07 21:49:08 +08:00
parent c42203ac20
commit 8860a3270e
7 changed files with 135 additions and 16 deletions

View File

@ -26,4 +26,6 @@ public class MenuOutputDTO implements OutputConverter<MenuOutputDTO, Menu> {
private String target; private String target;
private String icon; private String icon;
private Integer parentId;
} }

View File

@ -58,6 +58,11 @@ public class Menu extends BaseEntity {
@Column(name = "icon", columnDefinition = "varchar(50) default ''") @Column(name = "icon", columnDefinition = "varchar(50) default ''")
private String icon; private String icon;
/**
* Parent menu.
*/
@Column(name = "parent_id", columnDefinition = "int default 0")
private Integer parentId;
@Override @Override
public void prePersist() { public void prePersist() {

View File

@ -1,7 +1,5 @@
package run.halo.app.model.params; package run.halo.app.model.params;
import run.halo.app.model.dto.base.InputConverter;
import run.halo.app.model.entity.Menu;
import lombok.Data; import lombok.Data;
import lombok.ToString; import lombok.ToString;
import run.halo.app.model.dto.base.InputConverter; import run.halo.app.model.dto.base.InputConverter;
@ -37,4 +35,6 @@ public class MenuParam implements InputConverter<Menu> {
@Size(max = 50, message = "Length of menu icon must not be more than {max}") @Size(max = 50, message = "Length of menu icon must not be more than {max}")
private String icon; private String icon;
private Integer parentId;
} }

View File

@ -0,0 +1,16 @@
package run.halo.app.model.vo;
import lombok.Data;
import run.halo.app.model.dto.MenuOutputDTO;
import java.util.List;
/**
* @author : RYAN0UP
* @date : 2019-04-07
*/
@Data
public class MenuVO extends MenuOutputDTO {
private List<MenuVO> children;
}

View File

@ -1,11 +1,11 @@
package run.halo.app.service; package run.halo.app.service;
import org.springframework.data.domain.Sort;
import org.springframework.lang.NonNull;
import run.halo.app.model.dto.MenuOutputDTO; import run.halo.app.model.dto.MenuOutputDTO;
import run.halo.app.model.entity.Menu; import run.halo.app.model.entity.Menu;
import run.halo.app.model.params.MenuParam; import run.halo.app.model.params.MenuParam;
import run.halo.app.service.base.CrudService; import run.halo.app.model.vo.MenuVO;
import org.springframework.data.domain.Sort;
import org.springframework.lang.NonNull;
import run.halo.app.service.base.CrudService; import run.halo.app.service.base.CrudService;
import java.util.List; import java.util.List;
@ -14,6 +14,7 @@ import java.util.List;
* Menu service. * Menu service.
* *
* @author johnniang * @author johnniang
* @author RYAN0UP
*/ */
public interface MenuService extends CrudService<Menu, Integer> { public interface MenuService extends CrudService<Menu, Integer> {
@ -34,4 +35,12 @@ public interface MenuService extends CrudService<Menu, Integer> {
*/ */
@NonNull @NonNull
Menu createBy(@NonNull MenuParam menuParam); Menu createBy(@NonNull MenuParam menuParam);
/**
* Lists as menu tree.
*
* @param sort sort info must not be null
* @return a menu tree
*/
List<MenuVO> listAsTree(Sort sort);
} }

View File

@ -1,21 +1,21 @@
package run.halo.app.service.impl; package run.halo.app.service.impl;
import run.halo.app.exception.AlreadyExistsException;
import run.halo.app.model.dto.MenuOutputDTO;
import run.halo.app.model.entity.Menu;
import run.halo.app.model.params.MenuParam;
import run.halo.app.repository.MenuRepository;
import run.halo.app.service.MenuService;
import run.halo.app.service.base.AbstractCrudService;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import run.halo.app.exception.AlreadyExistsException; import run.halo.app.exception.AlreadyExistsException;
import run.halo.app.model.dto.MenuOutputDTO;
import run.halo.app.model.entity.Menu;
import run.halo.app.model.params.MenuParam;
import run.halo.app.model.vo.MenuVO;
import run.halo.app.repository.MenuRepository; import run.halo.app.repository.MenuRepository;
import run.halo.app.service.MenuService;
import run.halo.app.service.base.AbstractCrudService; import run.halo.app.service.base.AbstractCrudService;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -57,6 +57,87 @@ public class MenuServiceImpl extends AbstractCrudService<Menu, Integer> implemen
return create(menuParam.convertTo()); return create(menuParam.convertTo());
} }
/**
* Lists as menu tree.
*
* @param sort sort info must not be null
* @return a menu tree
*/
@Override
public List<MenuVO> listAsTree(Sort sort) {
Assert.notNull(sort, "Sort info must not be null");
// List all menu
List<Menu> menus = listAll(sort);
if (CollectionUtils.isEmpty(menus)) {
return Collections.emptyList();
}
// Create top menu
MenuVO topLevelMenu = createTopLevelMenu();
// Concrete the tree
concreteTree(topLevelMenu, menus);
return topLevelMenu.getChildren();
}
/**
* Concrete menu tree.
*
* @param parentMenu parent menu vo must not be null
* @param menus a list of menu
*/
private void concreteTree(MenuVO parentMenu, List<Menu> menus) {
Assert.notNull(parentMenu, "Parent menu must not be null");
if (CollectionUtils.isEmpty(menus)) {
return;
}
// Create children container for removing after
List<Menu> children = new LinkedList<>();
menus.forEach(menu -> {
if (parentMenu.getId().equals(menu.getParentId())) {
// Save child menu
children.add(menu);
// Convert to child menu vo
MenuVO child = new MenuVO().convertFrom(menu);
// Init children if absent
if (parentMenu.getChildren() == null) {
parentMenu.setChildren(new LinkedList<>());
}
parentMenu.getChildren().add(child);
}
});
// Remove all child menus
menus.removeAll(children);
// Foreach children vos
if (!CollectionUtils.isEmpty(parentMenu.getChildren())) {
parentMenu.getChildren().forEach(childMenu -> concreteTree(childMenu, menus));
}
}
/**
* Creates a top level menu.
*
* @return top level menu with id 0
*/
@NonNull
private MenuVO createTopLevelMenu() {
MenuVO topMenu = new MenuVO();
// Set default value
topMenu.setId(0);
topMenu.setChildren(new LinkedList<>());
topMenu.setParentId(-1);
return topMenu;
}
private List<MenuOutputDTO> convertTo(List<Menu> menus) { private List<MenuOutputDTO> convertTo(List<Menu> menus) {
if (CollectionUtils.isEmpty(menus)) { if (CollectionUtils.isEmpty(menus)) {

View File

@ -1,19 +1,19 @@
package run.halo.app.web.controller.admin.api; package run.halo.app.web.controller.admin.api;
import run.halo.app.model.dto.MenuOutputDTO;
import run.halo.app.model.entity.Menu;
import run.halo.app.model.params.MenuParam;
import run.halo.app.service.MenuService;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.data.web.SortDefault; import org.springframework.data.web.SortDefault;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import run.halo.app.model.dto.MenuOutputDTO;
import run.halo.app.model.entity.Menu; import run.halo.app.model.entity.Menu;
import run.halo.app.model.params.MenuParam;
import run.halo.app.model.vo.MenuVO;
import run.halo.app.service.MenuService; import run.halo.app.service.MenuService;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.List; import java.util.List;
import static org.springframework.data.domain.Sort.Direction.ASC;
import static org.springframework.data.domain.Sort.Direction.DESC; import static org.springframework.data.domain.Sort.Direction.DESC;
/** /**
@ -38,6 +38,12 @@ public class MenuController {
return menuService.listDtos(sort); return menuService.listDtos(sort);
} }
@GetMapping("tree_view")
@ApiOperation("List as category tree")
public List<MenuVO> listAsTree(@SortDefault(sort = "name", direction = ASC) Sort sort) {
return menuService.listAsTree(sort);
}
@PostMapping @PostMapping
@ApiOperation("Creates a menu") @ApiOperation("Creates a menu")
public MenuOutputDTO createBy(@RequestBody @Valid MenuParam menuParam) { public MenuOutputDTO createBy(@RequestBody @Valid MenuParam menuParam) {