递归查询子菜单
实体类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);
}
}