谷粒商城——递归查询子菜单方法分析

递归查询子菜单

实体类CategoryEntity

    /**
     * 形成树型结构
     * @TableField 该注解的false表示表中不存在该字段,只是自定义的字段,方便编码
     */
    @TableField(exist = false)
    private List<CategoryEntity> children;

CategoryController层

    /**
     * 查出所有分类和子分类列表,以树型结构组成
     */
    @GetMapping("/list/tree")
    public R list() {
        List<CategoryEntity> categoryEntities = categoryService.listWithTree();
        return R.ok().put("data", categoryEntities);
    }

1、listWithTree()

查出所有数据并组装成树形结构

生成listWithTree()方法到CategoryService接口中,并在该接口的实现类中添加listWithTree()的实现

返回的是一个 CategoryEntity 对象的List集合,方法名称叫做 listWithTree

/**
 * 商品三级分类
 *
 */
public interface CategoryService extends IService<CategoryEntity> {

    PageUtils queryPage(Map<String, Object> params);

    List<CategoryEntity> listWithTree();

CategoryServiceImpl

@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {
    
    /**
     * 树型显示
     *
     **/
    @Override
    public List<CategoryEntity> listWithTree() {

        /**
         * 1.查出所有分类
         */
        List<CategoryEntity> categoryEntities = baseMapper.selectList(null);

        /**
         * 2.查找到所有的一级分类
         */
        List<CategoryEntity> treeMenus = categoryEntities.stream().filter((categoryEntity) -> {
            return categoryEntity.getParentCid() == 0;
        }).map((menu) -> {
            menu.setChildren(getChildren(menu, categoryEntities));
            return menu;
        }).sorted((menu1, menu2) -> {
            return (menu1.getSort() == null ? 0 : menu1.getSort()) - (menu2.getSort() == null ? 0 : menu2.getSort());

        }).collect(Collectors.toList());

        return treeMenus;
    }

    // 递归查找所有菜单的子菜单
    private List<CategoryEntity> getChildren(CategoryEntity rootMenu, List<CategoryEntity> allMenus) {

        List<CategoryEntity> childrenList = allMenus.stream().filter(categoryEntity -> {
            return categoryEntity.getParentCid().equals(rootMenu.getCatId());
        }).map(menu -> {

            // 找到子菜单
            menu.setChildren(getChildren(menu, allMenus));
            return menu;
        }).sorted((menu1, menu2) -> {

            /**
             * 菜单排序
             * 如果sort()==null,则赋给他默认值0,否则就用它就自己的值menu1.getSort()
             */
            return (menu1.getSort() == null ? 0 : menu1.getSort()) - (menu2.getSort() == null ? 0 : menu2.getSort());
        }).collect(Collectors.toList());
        return childrenList;
}

2、baseMapper

baseMapper也就是泛型指定的Mapper

CategoryServiceImpl:

ServiceImpl:

ServiceImpl中BaseMapper<T>继承自顶级Mapper<T>

BaseMapper所有接口:

public interface BaseMapper<T> {
    Integer insert(T entity);
    Integer insertAllColumn(T entity);
    Integer deleteById(Serializable id);
    Integer deleteByMap(@Param("cm") Map<String, Object> columnMap);
    Integer delete(@Param("ew") Wrapper<T> wrapper);
    Integer deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);
    Integer updateById(@Param("et") T entity);
    Integer updateAllColumnById(@Param("et") T entity);
    Integer update(@Param("et") T entity, @Param("ew") Wrapper<T> wrapper);
    T selectById(Serializable id);
    List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
    List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
    T selectOne(@Param("ew") T entity);
    Integer selectCount(@Param("ew") Wrapper<T> wrapper);
    List<T> selectList(@Param("ew") Wrapper<T> wrapper);
    List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> wrapper);
    List<Object> selectObjs(@Param("ew") Wrapper<T> wrapper);
    List<T> selectPage(RowBounds rowBounds, @Param("ew") Wrapper<T> wrapper);
    List<Map<String, Object>> selectMapsPage(RowBounds rowBounds, @Param("ew") Wrapper<T> wrapper);

顶级Mapper<T>

而CategoryDao接口同样继承自BaseMapper接口

baseMapper调用selectList方法查询所有,传入null即为查询所有,并返回所有查询数据categoryEntities

3、Stream流处理

使用stream流的filter()方法处理,过滤集合categoryEntities中每个一个元素,如果父分类的id==0,则说明是一个一级分类,并通过stream的collect(toList())方法把这些一级分类收集成一个列表

List<CategoryEntity> treeMenus = categoryEntities.stream().filter(categoryEntity ->
	categoryEntity.getParentCid() == 0
).collect(Collectors.toList());

return treeMenus;

4、sorted()

递归方法getChildren(),传入当前菜单rootMenu和所有菜单allMenu

// 递归查找所有菜单的子菜单
private List<CategoryEntity> getChildren(CategoryEntity rootMenu, List<CategoryEntity> allMenus) {

    List<CategoryEntity> childrenList = allMenus.stream().filter(categoryEntity -> {
        return categoryEntity.getParentCid().equals(rootMenu.getCatId());
    }).map(menu -> {

        // 找到子菜单
        menu.setChildren(getChildren(menu, allMenus));
        return menu;
    }).sorted((menu1, menu2) -> {

        /**
         * 菜单排序
         * 如果sort()==null,则赋给他默认值0,否则就用它就自己的值menu1.getSort()
         */
        return (menu1.getSort() == null ? 0 : menu1.getSort()) - (menu2.getSort() == null ? 0 : menu2.getSort());
    }).collect(Collectors.toList());
    return childrenList;
}

最后通过sorted()方法进行排序,menu1.getSort()-menu2.getSort(),拿对象的sort字段进行升序排序,反之则是降序排序

// 由于sort是Integer类型的,如果sort()==null,则赋给他默认值0,否则就用它就自己的值menu1.getSort()
.sorted((menu1, mxenu2) -> {    
	return (menu1.getSort() == null ? 0 : menu1.getSort()) - (menu2.getSort() == null ? 0 : menu2.getSort());
}

5、跨域

同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。所以a.com下的js脚本采用ajax读取b.com里面的文件数据是会报错的。

http://www.domain.com/a.js

http://www.doamin.com/b.js

同一域名

允许

http://www.domain.com/a/a.js

http://www.doamin.com/b/b.js

同一域名下不同文件夹

允许

http://www.domain.com:8080/a.js

http://www.doamin.com:8090/b.js

同一域名,不同端口

不允许

http://www.domain.com/a.js

https://www.doamin.com/b.js

同一域名,不同协议

不允许

http://www.domain.com/a.js

http://127.0.0.1/b.js

域名与域名对应ip

不允许

浏览器跨域流程

使用过滤器filter解决跨域问题

@Configuration
public class GulimallCorsConfiguration {

    @Bean
    public CorsWebFilter corsWebFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

        CorsConfiguration corsConfiguration = new CorsConfiguration();

		/**
 		* 配置跨域
 		* addAllowedHeader 允许跨域的头
 		* addAllowedMethod 请求方式
 		* addAllowedOrigin 请求来源
 		* setAllowCredentials(true) 是否携带cookie进行跨域
 		* */      
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.setAllowCredentials(true);

		//任意路径都需要跨域配置
        source.registerCorsConfiguration("/**",corsConfiguration);
        return new CorsWebFilter(source);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_41819893/article/details/121443722