需求:
网站首页 - 商品分类展示( 使用缓存 - 提高效率 - 提高用户满意度 )
1.实现效果如下: (京东-首页分类)
一、需求分析
1.表关系如下: ( 自关联表 - tb_item_cat )
parent_id:
一级分类: 默认是 0
二级分类: 一级分类的id
三级分类: 二级分类的id
2.如何接收返回的JSON数据(三级分类数据)? ★
分析:
一级分类 -> 包含二级分类 -> 包含三级分类! ( 一对多对多 )
①自关联表 -> 自关联POJO对象! ( 本文使用 )
②Map集合接收 -> Map<String , Map<String , List>>
二、后端实现( 分布式框架 )
1.数据层 - Mybatis
注: 只添加了特殊的sql语句 , 其余都是逆向工程!
1.1 ItemCatDao.java
public interface ItemCatDao {
// 根据父类id - 0 , 查询分类信息
List<ItemCat> selectByParentId(@Param("id") Long id);
}
1.2 ItemCatDao.xml ( 原因: 固定一级分类的长度 )
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="cn.xxx.dao.item.ItemCatDao" >
<!-- 查询三级分类信息 -->
<select id="selectByParentId" resultType="cn.xxx.pojo.item.ItemCat">
SELECT * FROM tb_item_cat WHERE parent_id = #{id} LIMIT 15
</select>
</mapper>
2.业务层 - Spring
2.1 ItemCatService.java
public interface ItemCatService {
List<ItemCat> findByItemCat3(Long parentId);
}
2.2 ItemCatServiceImpl.java ( 重点 )
@Service
public class ItemCatServiceImpl implements ItemCatService {
@Resource
private ItemCatDao itemCatDao;
@Resource
private RedisTemplate<String,Object> redisTemplate;
@Override
public List<ItemCat> findByItemCat3(Long parentId01) {
// 1.先从redis缓存中 , 获取三级分类信息!
List<ItemCat> itemCat01List = (List<ItemCat>) redisTemplate.boundValueOps("itemCat03").get();
// 2.若缓存中没有数据 , 从数据库中查询( 并放到缓存中 )
if (itemCat01List==null){
// 缓存穿透 -> 请求排队等候.
synchronized (this){
// 进行二次校验?
itemCat01List = (List<ItemCat>) redisTemplate.boundValueOps("itemCat03").get();
if (itemCat01List==null){
// 创建一个集合 , 存放一级分类
itemCat01List = new ArrayList<>();
// 根据parent_id = 0 , 获取一级分类信息!
List<ItemCat> itemCatList = itemCatDao.selectByParentId(parentId01);
for (ItemCat itemCat : itemCatList) {
// 设置一级分类信息!
ItemCat itemCat01 = new ItemCat();
itemCat01.setId(itemCat.getId());
itemCat01.setName(itemCat.getName());
itemCat01.setParentId(itemCat.getParentId());
// 根据一级分类的id -> 找到对应的二级分类!
List<ItemCat> itemCatList02 = new ArrayList<>();
ItemCatQuery itemCatQuery02 = new ItemCatQuery();
itemCatQuery02.createCriteria().andParentIdEqualTo(itemCat.getId());
List<ItemCat> itemCat02List = itemCatDao.selectByExample(itemCatQuery02);
for (ItemCat itemCat2 : itemCat02List) {
// 设置二级分类信息!
ItemCat itemCat02 = new ItemCat();
itemCat02.setId(itemCat2.getId());
itemCat02.setName(itemCat2.getName());
itemCat02.setParentId(itemCat2.getParentId());
// 根据二级分类的id -> 找到对应的三级分类!
List<ItemCat> itemCatList03 = new ArrayList<>();
ItemCatQuery itemCatQuery03 = new ItemCatQuery();
itemCatQuery03.createCriteria().andParentIdEqualTo(itemCat02.getId());
List<ItemCat> itemCat03List = itemCatDao.selectByExample(itemCatQuery03);
for (ItemCat itemCat3 : itemCat03List) {
itemCatList03.add(itemCat3);
}
itemCat02.setItemCatList(itemCatList03); // 二级分类中 添加 三级分类.
itemCatList02.add(itemCat02); // 添加二级分类.
}
itemCat01.setItemCatList(itemCatList02); // 一级分类中 添加 二级分类!
itemCat01List.add(itemCat01); // 添加一级分类
}
// 将查询到的数据放入缓存中!
redisTemplate.boundValueOps("itemCat03").set(itemCat01List);
return itemCat01List;
}
}
}
// 3.若缓存中有数据 , 直接返回即可!
return itemCat01List;
}
}
3.视图层 - SpringMVC
@RestController
@RequestMapping("/itemCat")
public class ItemCatController {
@Reference
private ItemCatService itemCatService;
@RequestMapping("/findByParentId.do")
public List<ItemCat> findByParentId(Long parentId) {
return itemCatService.findByItemCat3(parentId);
}
}
三、前端实现( angularjs )
1.初始化加载方法( 传递parent_id = 0 )
ng-init="findByParentId(0);"
2.前端遍历展示( 鼠标移入移除 )
注: 遍历名称可能不一致 , 需要改变!
<div class="yui3-u Left all-sort-list">
<div class="all-sort-list2">
<div class="item {{flag?'hover':''}}" ng-repeat="itemCat1 in list" ng-mouseenter="flag=true"
ng-mouseleave="flag=false">
<h3><a href="">{{itemCat1.name}}</a></h3>
<!--通过三元表达式确定是显示还是隐藏-->
<div class="item-list clearfix" style="display: {{flag?'block':'none'}}">
<div class="subitem">
<!--遍历2级分类-->
<dl class="fore1" ng-repeat="itemCat2 in itemCat1.itemCat02List">
<dt><a href="">{{itemCat2.name}}</a></dt>
<dd>
<!--遍历3级分类-->
<em ng-repeat="itemCat3 in itemCat2.itemCat03List">
<a href="">{{itemCat3.name}}</a>
</em>
</dd>
</dl>
</div>
</div>
</div>
</div>
</div>