【小项目】Spring boot基于Redis缓存商城分类,商品信息(含源码下载)

初始化分类以及商品信息

@Component
public class InitGoodsRedisData implements ApplicationListener<ContextRefreshedEvent> {

    @Autowired
    private JedisPool jedisPool;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent c)
    {
        Jedis jedis = jedisPool.getResource();
        if (jedis.scard(RCRedisKey.GOODS_CATEGORY) > 0)
        {
            System.out.println("已经缓存商品初始化数据***************");
            return;
        }
        Transaction transaction = jedis.multi();
        initCategoryData(transaction);
        initGoodsData(transaction);
        transaction.exec();
        jedis.close();
        System.out.println("写入商品初始化数据***************OK");
    }

    // 初始化商品分类
    private void initCategoryData(Transaction transaction)
    {
        transaction.sadd(RCRedisKey.GOODS_CATEGORY,
                JSONObject.toJSONString(new CategoryVO(1, "手机")),
                JSONObject.toJSONString(new CategoryVO(2, "平板")));
    }

    // 初始化商品信息
    private void initGoodsData(Transaction transaction)
    {

        // 手机
        Map<String, Double> phoneScoreMembers = new HashMap<String, Double>(5);

        String goods11 = JSONObject.toJSONString(new GoodsVO(11, 1, "Iphone X", 8388.00,
                "https://img11.360buyimg.com/n5/s75x75_jfs/t9907/361/46671134/65420/7d66b903/59c47a15N36a2fc0d.jpg"));
        phoneScoreMembers.put(goods11, 0d);
        transaction.hset(RCRedisKey.GOODS_INFO, 11 + "", goods11);

        String goods12 = JSONObject.toJSONString(new GoodsVO(12, 1, "Iphone8 P", 6688.00,
                "https://img10.360buyimg.com/n5/s54x54_jfs/t7339/80/2994230157/58546/a4b72d95/59b85837N990db7d3.jpg"));
        phoneScoreMembers.put(goods12, 0d);
        transaction.hset(RCRedisKey.GOODS_INFO, 12 + "", goods12);

        String goods13 = JSONObject.toJSONString(new GoodsVO(13, 1, "三星S8", 5688.00,
                "https://img14.360buyimg.com/n5/s54x54_jfs/t5095/313/1561100036/253747/b2dfce2f/59119ddcNc7305e8b.jpg"));
        phoneScoreMembers.put(goods13, 0d);
        transaction.hset(RCRedisKey.GOODS_INFO, 13 + "", goods13);

        String goods14 = JSONObject.toJSONString(new GoodsVO(14, 1, "小米MIX2", 3599.00,
                "https://img13.360buyimg.com/n5/s54x54_jfs/t9214/51/1590664916/300151/a59b7cd3/59bb8691Naca717e9.jpg"));
        phoneScoreMembers.put(goods14, 0d);
        transaction.hset(RCRedisKey.GOODS_INFO, 14 + "", goods14);

        String goods15 = JSONObject.toJSONString(new GoodsVO(15, 1, "华为P10", 3488.00,
                "https://img14.360buyimg.com/n5/s54x54_jfs/t4333/208/365266204/337840/e9e7bd9a/58b3f51aN10566aa1.jpg"));
        phoneScoreMembers.put(goods15, 0d);
        transaction.hset(RCRedisKey.GOODS_INFO, 15 + "", goods15);

        transaction.zadd(String.format(RCRedisKey.GOODS_LIST, 1), phoneScoreMembers);

        // 电脑
        Map<String, Double> computerScoreMembers = new HashMap<String, Double>(5);
        String goods21 = JSONObject.toJSONString(new GoodsVO(21, 2, "Apple iPad", 3258.00,
                "https://img12.360buyimg.com/n5/s54x54_jfs/t3214/177/9256496777/621169/2a1735b5/58d16208N55e7302b.jpg"));
        computerScoreMembers.put(goods21, 0d);
        transaction.hset(RCRedisKey.GOODS_INFO, 21 + "", goods21);

        String goods22 = JSONObject.toJSONString(new GoodsVO(22, 2, "华为M3", 2258.00,
                "https://img10.360buyimg.com/n5/s54x54_jfs/t3235/143/2924985643/316383/370982db/57e8d527Ncb5ce343.jpg"));
        computerScoreMembers.put(goods22, 0d);
        transaction.hset(RCRedisKey.GOODS_INFO, 22 + "", goods22);

        String goods23 = JSONObject.toJSONString(new GoodsVO(23, 2, "Apple iPad mini 4", 3098.00,
                "https://img14.360buyimg.com/n5/s54x54_jfs/t9751/18/332152129/67998/3cef982f/59cc62ccN582dbd8a.jpg"));
        computerScoreMembers.put(goods23, 0d);
        transaction.hset(RCRedisKey.GOODS_INFO, 23 + "", goods23);

        String goods24 = JSONObject.toJSONString(new GoodsVO(24, 2, "Apple iPad Pro", 5888.00,
                "https://img10.360buyimg.com/n5/s54x54_jfs/t6679/178/76604977/301064/4e10cb22/5938ffa2Nb4d435f2.jpg"));
        computerScoreMembers.put(goods24, 0d);
        transaction.hset(RCRedisKey.GOODS_INFO, 24 + "", goods24);

        String goods25 = JSONObject.toJSONString(new GoodsVO(25, 2, "Surface Pro", 9888.00,
                "https://img10.360buyimg.com/n5/s54x54_jfs/t5617/321/1137763311/121847/b9326254/5923eb44Ndae8df59.jpg"));
        computerScoreMembers.put(goods25, 0d);
        transaction.hset(RCRedisKey.GOODS_INFO, 25 + "", goods25);

        transaction.zadd(String.format(RCRedisKey.GOODS_LIST, 2), computerScoreMembers);

    }

}

实现Spring接口ApplicationListener(项目启动后执行初始化方法)。使用Redis事务控制分类,商品列表,商品详情信息的数据一致性。结合数据的访问情景,使用不同的Redis缓存方式。

  1. 商品分类:数据唯一,且一次性全部拿取,使用Set(集合)进行缓存
  2. 商品列表:数据具备排序支持,使用SortedSet(有序集合)进行缓存
  3. 商品详情:准确定位获取数据信息,使用Hash(哈希表)进行缓存

控制器以及业务处理类

@Controller
@RequestMapping("goods")
public class GoodsController {

    @Autowired
    private GoodsBiz goodsBiz;

    @Autowired
    private HttpServletRequest request;

    // 获取分类列表
    @RequestMapping(value = "category")
    public String category() {
        request.setAttribute("pageData", goodsBiz.category());
        return "goods/category";
    }

    // 获取商品列表
    @RequestMapping(value = "goods_list")
    public String goodsList(@RequestParam Integer cid) {
        request.setAttribute("pageData", goodsBiz.goodsList(cid));
        return "goods/goods_list";
    }

    // 获取商品详情
    @RequestMapping(value = "goods_detail")
    public String goodsDetail(@RequestParam Integer gid) {
        request.setAttribute("info", goodsBiz.goodsDetail(gid));
        return "goods/goods_detail";
    }

}
@Service
public class GoodsBiz {

    @Autowired
    private JedisPool jedisPool;

    // 获取分类列表
    public List<CategoryVO> category() {
        Jedis jedis = jedisPool.getResource();
        try {
            Set<String> cacheCategory = jedis.sunion(RCRedisKey.GOODS_CATEGORY);
            if (cacheCategory.isEmpty())
                return null;
            List<CategoryVO> result = new ArrayList<CategoryVO>(cacheCategory.size());
            for (String item : cacheCategory)
                result.add(JSONObject.parseObject(item, CategoryVO.class));
            return result;
        } finally {
            jedis.close();
        }
    }

    // 获取商品列表
    public List<GoodsListVO> goodsList(int categoryId) {
        Jedis jedis = jedisPool.getResource();
        try {
            Set<String> categoryGoods = jedis.zrevrange(String.format(RCRedisKey.GOODS_LIST, categoryId), 0, -1);
            if (categoryGoods.isEmpty())
                return null;
            List<GoodsListVO> result = new ArrayList<GoodsListVO>(categoryGoods.size());
            for (String item : categoryGoods) {
                GoodsListVO pCache = JSONObject.parseObject(item, GoodsListVO.class);
                pCache.setScore(jedis.zscore(String.format(RCRedisKey.GOODS_LIST, categoryId), item).intValue());
                result.add(pCache);
            }
            return result;
        } finally {
            jedis.close();
        }
    }

    // 获取商品详情
    public GoodsVO goodsDetail(Integer gid) {
        Jedis jedis = jedisPool.getResource();
        try {
            String cacheGoods = jedis.hget(RCRedisKey.GOODS_INFO, gid + "");
            if (cacheGoods == null)
                return null;
            GoodsVO result = JSONObject.parseObject(cacheGoods, GoodsVO.class);
            jedis.zincrby(String.format(RCRedisKey.GOODS_LIST, result.getCategoryId()), 1, cacheGoods);
            return result;
        } finally {
            jedis.close();
        }
    }

}

注:使用jedis注意close

获取商品列表使用ZREVRANGE根据缓存的序号倒序拿取

ZREVRANGE
命令使用:ZREVRANGE key start stop [WITHSCORES]
返回有序集 key 中,指定区间内的成员。
其中成员的位置按 score 值递减 (从大到小) 来排列
具有相同 score 值的成员按字典序的逆序 排列

获取商品详情时使用ZINCRBY对商品缓存列表序号追加1

ZINCRBY
命令使用:ZINCRBY key increment member
为有序集 key 的成员 member 的 score 值加上增量 increment
可以通过传递一个负数值 increment ,让 score 减去相应的值,比如 ZINCRBY key -5 member ,就是
让member 的 score 值减去 5 。
当 key 不存在,或 member 不是 key 的成员时,ZINCRBY key increment member 等同于 ZADD key
increment member 。
当 key 不是有序集类型时,返回一个错误。
score 值可以是整数值或双精度浮点数

页面展示

界面使用thymeleaf模版进行编辑

thymeleaf介绍
简单说, Thymeleaf 是一个跟 Velocity、FreeMarker 类似的模板引擎,它可以完全替代 JSP 。相较与其他的模板引擎,它有如下三个极吸引人的特点:
1.Thymeleaf 在有网络和无网络的环境下皆可运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。这是由于它支持 html 原型,然后在 html 标签里增加额外的属性来达到模板+数据的展示方式。浏览器解释 html 时会忽略未定义的标签属性,所以 thymeleaf 的模板可以静态地运行;当有数据返回到页面时,Thymeleaf 标签会动态地替换掉静态内容,使页面动态显示
2.Thymeleaf 开箱即用的特性。它提供标准和spring标准两种方言,可以直接套用模板实现JSTL、 OGNL表达式效果,避免每天套模板、该jstl、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言
3.Thymeleaf 提供spring标准方言和一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能

信息参考:http://www.importnew.com/25826.html

列表页面

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<meta charset="UTF-8" />
<title>商品列表</title>
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" />
<link href="https://cdn.bootcss.com/Buttons/2.0.0/css/buttons.min.css" rel="stylesheet" />
<style type="text/css"> .content_container { width: 1366px; } th { text-align: center; } </style>
</head>
<body class="container-fluid">
    <div class="content_container center-block" style="text-align: center; margin-top: 30px;">
        <table class="table table-hover">
            <thead>
                <tr>
                    <th>编号</th>
                    <th>名称</th>
                    <th>图片</th>
                    <th>价格</th>
                    <th>浏览量</th>
                    <th>操作</th>
                </tr>
            </thead>
            <tbody>
                <tr th:each="item:${pageData}">
                    <td th:text="${item.id}"></td>
                    <td th:text="${item.name}"></td>
                    <td><img th:src="${item.img}" class="img-rounded" /></td>
                    <td th:text="${item.price}"></td>
                    <td th:text="${item.score}"></td>
                    <td><a class="button button-primary" th:href="@{goods_detail(gid=${item.id})}">查看</a></td>
                </tr>
            </tbody>
        </table>
        <a class="button" th:href="@{category}">返回分类</a>
    </div>
</body>
</html>

HTML页面需引用thymeleaf标签声明,Eclipse对thymeleaf标签插件支持地址:http://www.thymeleaf.org/eclipse-plugin-update-site/(Eclipse->Help->Install New Software)

页面展示
《【小项目】Spring boot基于Redis缓存商城分类,商品信息(含源码下载)》

此项目缓存思路不仅限于商城,适用于所有类似的业务缓存

项目源码下载(2分):http://download.csdn.net/download/qq_19260029/10022078

更多文章:
Java基于Redis实现“附近的人”
Eclipse新建Spring-boot项目,打包部署并输出HelloWord

    原文作者:Spring Boot
    原文地址: https://blog.csdn.net/qq_19260029/article/details/78230599
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞