html+angularjs+redis获取后台数据模拟京东/天猫的商品分类导航

版权声明:作者: 阿顾, 转载请写明出处, 谢谢 https://blog.csdn.net/u010452388/article/details/82120664

文章中一些详细的说明,会在代码中用注释的方式解释,如果有疑问或者写的不好的地方可以留言交流

先上效果图(文末会附上源码): 


目录

一 数据库表结构

二 实体类设计 

三 后端代码

3.1 数据访问层

3.2 redis属性文件

3.3 redis配置文件

3.4 接口层

3.5 服务层

3.6 控制层

四 前端代码

4.1 indexService.js文件

4.2 indexController.js文件

4.3 index.html

五 源码分享


一 数据库表结构

数据库表的parentId为0的话,那么是1级分类;2级分类的parentId为1级分类的id;3级分类的parentId为2级分类的id,文末源码中会给出sql的结构和数据


二 实体类设计 

从上图可以看出1级分类和2级分类是一对多的关系,2级分类和3级分类也是一对多的关系,所以整体的结构关系如下图

从上面分析的结构图可以看出,1级分类的对应着一个2级分类的集合,所以可以在设计实体类的时候,添加一个商品分类集合的属性,设计如下:


public class TbItemCat implements Serializable {
    private Long id;

    private Long parentId;

    private String name;

    private Long typeId;
    //添加下级分类的集合作为属性
    private List<TbItemCat> itemCatList;

    public List<TbItemCat> getItemCatList() {
        return itemCatList;
    }

    public void setItemCatList(List<TbItemCat> itemCatList) {
        this.itemCatList = itemCatList;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getParentId() {
        return parentId;
    }

    public void setParentId(Long parentId) {
        this.parentId = parentId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name == null ? null : name.trim();
    }

    public Long getTypeId() {
        return typeId;
    }

    public void setTypeId(Long typeId) {
        this.typeId = typeId;
    }
}

三 后端代码

由于后端用的分布式开发的,对分布式框架搭建不清楚的可以访问下面的地址:

https://blog.csdn.net/u010452388/article/details/82014152

3.1 数据访问层

3.1.1 商品分类的mapper接口


public interface TbItemCatMapper {

    List<TbItemCat> findItemCatListByParentId(@Param("parentId") Long parentId);

}

3.1.2  商品分类的mapper.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接口的全限定类名-->
<mapper namespace="com.demo.mapper.TbItemCatMapper">
    <!--结果映射,id为了给执行语句调用指定的映射Map,type为返回实体类的全限定类名-->
    <resultMap id="BaseResultMap" type="com.demo.pojo.TbItemCat">
        <!--column为查出来的列名,property为对应的实体属性名-->
        <id column="id" property="id"/>
        <result column="parent_id" property="parentId"/>
        <result column="name" property="name"/>
        <result column="type_id" property="typeId"/>
    </resultMap>

    <sql id="Base_Column_List">
    id, parent_id, name, type_id
    </sql>
    <!--id为TbItemCatMapper接口的方法名-->
    <select id="findItemCatListByParentId" resultMap="BaseResultMap">
        select
        /*这里查询直接用字段名,查询的性能会比用*高一点*/
        <include refid="Base_Column_List"/>
        from
          tb_item_cat
        where
        /*parentId为findItemCatListByParentId方法传递的参数*/
          parent_id=#{parentId}
    </select>

</mapper>

3.2 redis属性文件

# Redis settings 
# server IP 
redis.host=127.0.0.1
# server port 
redis.port=6379
# server pass 
redis.pass=
# use dbIndex 
redis.database=0
# 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例 
redis.maxIdle=300
# 表示当borrow(引入)一个jedis实例时,最大的等待时间,如果超过等待时间(毫秒),则直接抛出JedisConnectionException;  
redis.maxWait=3000
# 在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的  
redis.testOnBorrow=true

3.3 redis配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans   
            http://www.springframework.org/schema/beans/spring-beans.xsd   
            http://www.springframework.org/schema/context   
            http://www.springframework.org/schema/context/spring-context.xsd   
            ">
    <!--引入redis属性文件-->
    <context:property-placeholder location="classpath*:properties/*.properties"/>

    <!-- redis 相关配置 -->
    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxIdle" value="${redis.maxIdle}"/>
        <property name="maxWaitMillis" value="${redis.maxWait}"/>
        <property name="testOnBorrow" value="${redis.testOnBorrow}"/>
    </bean>
    <!--配置jedis连接工厂-->
    <bean id="JedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
          p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}" p:pool-config-ref="poolConfig"/>
    <!--配置redisTemplate-->
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="JedisConnectionFactory"/>
    </bean>

</beans>  

3.4 接口层

public interface IndexService {

    public List<TbItemCat> findItemCatList();

}

3.5 服务层

这里主要实现思路:

先判断缓存中有没有数据,如果有,直接返回给前端,如果没有,则从数据库查询,并放入缓存,再返回给前端

因为首页访问的压力比较多,所以放到缓存中,主要目的:减少数据库访问压力


@Service
public class IndexServiceImpl implements IndexService {

    @Autowired
    private TbItemCatMapper itemCatMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public List<TbItemCat> findItemCatList() {
        //从缓存中查询首页商品分类
        List<TbItemCat> itemCatList = (List<TbItemCat>) redisTemplate.boundHashOps("itemCat").get("indexItemCat");

        //如果缓存中没有数据,则从数据库查询再存入缓存
        if(itemCatList==null){
            //查询出1级商品分类的集合
            List<TbItemCat> itemCatList1 = itemCatMapper.findItemCatListByParentId(0L);
            //遍历1级商品分类的集合
            for(TbItemCat itemCat1:itemCatList1){
                //查询2级商品分类的集合(将1级商品分类的id作为条件)
                List<TbItemCat> itemCatList2 = itemCatMapper.findItemCatListByParentId(itemCat1.getId());
                //遍历2级商品分类的集合
                for(TbItemCat itemCat2:itemCatList2){
                    //查询3级商品分类的集合(将2级商品分类的父id作为条件)
                    List<TbItemCat> itemCatList3 = itemCatMapper.findItemCatListByParentId(itemCat2.getId());
                    //将2级商品分类的集合封装到2级商品分类实体中
                    itemCat2.setItemCatList(itemCatList3);
                }
                /*到这一步的时候,3级商品分类已经封装到2级分类中*/
                //将2级商品分类的集合封装到1级商品分类实体中
                itemCat1.setItemCatList(itemCatList2);
            }
            //存入缓存
            redisTemplate.boundHashOps("itemCat").put("indexItemCat",itemCatList1);
            return itemCatList1;
        }
        //到这一步,说明缓存中有数据,直接返回
        return itemCatList;
    }
}

3.6 控制层

@RestController
@RequestMapping("/index")
public class IndexController {

    @Reference
    private IndexService indexService;

    /**
     * 查询商品分类信息
     *
     * @return
     */
    @RequestMapping("/findItemCatList")
    public List<TbItemCat> findItemCatList() {
        return indexService.findItemCatList();
    }
}

四 前端代码

这里把前端分成service、controller主要是为了便于后期维护

4.1 indexService.js文件

//服务层
app.service('indexService', function ($http) {

    //查询商品分类信息
    this.findItemCatList = function () {
        return $http.get("index/findItemCatList.do");
    }
});

4.2 indexController.js文件

app.controller('indexController',function ($scope,indexService) {

    //查询商品分类信息
    $scope.findItemCatList=function () {
        indexService.findItemCatList().success(function (response) {
            $scope.itemCatList=response;
        })
    }
})

4.3 index.html

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7"/>
    <title>demo</title>
    <!--引入样式-->
    <link rel="stylesheet" type="text/css" href="css/webbase.css"/>
    <link rel="stylesheet" type="text/css" href="css/pages-JD-index.css"/>
    <!--引入js文件-->
    <script src="angularjs/angular.min.js"></script>
    <script src="js/base.js"></script>
    <script src="js/service/indexService.js"></script>
    <script src="js/controller/indexController.js"></script>
</head>

<body ng-app="demo" ng-controller="indexController" ng-init="findItemCatList()">

<!--列表-->
<div class="sort">
    <div class="py-container">
        <div class="yui3-g SortList ">
            <div class="yui3-u Left all-sort-list">
                <div class="all-sort-list2">
                    <!--商品分类 开始-->
                    <!--这里鼠标移入某个分类,就会给flag变量赋值为true,然后通过三元表达式确定样式-->
                    <div class="item {{flag?'hover':''}}" ng-repeat="itemCat1 in itemCatList" 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.itemCatList">
                                    <dt>
                                        <a href="">{{itemCat2.name}}</a>
                                    </dt>
                                    <dd>
                                        <!--遍历3级分类-->
                                        <em ng-repeat="itemCat3 in itemCat2.itemCatList">
                                            <a href="">{{itemCat3.name}}</a>
                                        </em>
                                    </dd>
                                </dl>
                            </div>
                        </div>
                    </div>
                    <!--商品分类 结束-->
                </div>
            </div>
        </div>
    </div>
</div>

</body>

</html>

启动顺序:

1.先启动redis和zookeeper

2.启动service服务

3.启动web

4.浏览器输入指定地址即可 


五 源码分享

链接:https://pan.baidu.com/s/1SwRSF7oGVNMWiMO2DQFzyw 密码:ntq9

猜你喜欢

转载自blog.csdn.net/u010452388/article/details/82120664