Chiriri's blog Chiriri's blog
首页
  • Java

    • JavaSE
    • JavaEE
    • 设计模式
  • Python

    • Python
    • Python模块
    • 机器学习
  • Golang

    • Golang
    • gRPC
  • 服务器

    • Linux
    • MySQL
    • NoSQL
    • Kubernetes
  • 项目

    • 传智健康
    • 畅购商城
  • Hadoop生态

    • Hadoop
    • Zookeeper
    • Hive
    • Flume
    • Kafka
    • Azkaban
    • Hbase
    • Scala
    • Spark
    • Flink
  • 大数据项目

    • 离线数仓
  • 青训营

    • 第四届青训营
  • HTML

    • HTML
    • JavaScript
  • Vue

    • Vue2
    • TypeScript
    • Vue3
    • Uni-APP
  • 数据结构与算法
  • C语言
  • 考研数据结构
  • 计算机组成原理
  • 计算机操作系统
  • Java基础

    • Java基础
    • Java集合
    • JUC
    • JVM
  • 框架

    • Spring
    • Dubbo
    • Spring Cloud
  • 数据库

    • MySQL
    • Redis
    • Elasticesearch
  • 消息队列

    • RabbitMQ
    • RocketMQ
  • 408

    • 计算机网络
    • 操作系统
    • 算法
  • 分类
  • 标签
  • 归档
  • 导航站
GitHub (opens new window)

Iekr

苦逼后端开发
首页
  • Java

    • JavaSE
    • JavaEE
    • 设计模式
  • Python

    • Python
    • Python模块
    • 机器学习
  • Golang

    • Golang
    • gRPC
  • 服务器

    • Linux
    • MySQL
    • NoSQL
    • Kubernetes
  • 项目

    • 传智健康
    • 畅购商城
  • Hadoop生态

    • Hadoop
    • Zookeeper
    • Hive
    • Flume
    • Kafka
    • Azkaban
    • Hbase
    • Scala
    • Spark
    • Flink
  • 大数据项目

    • 离线数仓
  • 青训营

    • 第四届青训营
  • HTML

    • HTML
    • JavaScript
  • Vue

    • Vue2
    • TypeScript
    • Vue3
    • Uni-APP
  • 数据结构与算法
  • C语言
  • 考研数据结构
  • 计算机组成原理
  • 计算机操作系统
  • Java基础

    • Java基础
    • Java集合
    • JUC
    • JVM
  • 框架

    • Spring
    • Dubbo
    • Spring Cloud
  • 数据库

    • MySQL
    • Redis
    • Elasticesearch
  • 消息队列

    • RabbitMQ
    • RocketMQ
  • 408

    • 计算机网络
    • 操作系统
    • 算法
  • 分类
  • 标签
  • 归档
  • 导航站
GitHub (opens new window)
  • JavaSE

  • JavaEE

  • Linux

  • MySQL

  • NoSQL

  • Python

  • Python模块

  • 机器学习

  • 设计模式

  • 传智健康

  • 畅购商城

    • Day01 项目搭建
    • Day02 FastDFS
    • Day03 微服务鉴权
    • Day04 新增和修改商品
      • 分布式ID生成解决方案
        • UUID
        • Redis
        • snowflake
        • snowflake测试类
        • 微服务snowflake
      • 新增和修改商品
        • SPU与SKU概念
        • 代码实现
        • SPU与SKU列表的保存
        • 品牌与分类关联
        • 根据id查询商品
        • 保存修改
        • 商品审核和上下架
        • 商品审核
        • 下架商品
        • 上架商品
        • 删除与还原商品
        • 逻辑删除商品
        • 商品还原
        • 物理删除
    • Day05 广告缓存
    • Day06 监听数据库更新广告缓存
    • Day07 ES搜索
    • Day08 Thymeleaf
    • Day09 Oauth2
    • Day10 购物车渲染
    • Day11 订单结算
    • Day12 分布式事务解决方案
    • Day13 微信支付
    • Day14 订单处理
    • Day15 秒杀前端
    • Day16 秒杀后端
  • 博客项目

  • JVM

  • JUC

  • Golang

  • Kubernetes

  • 硅谷课堂

  • C

  • 源码

  • 神领物流

  • RocketMQ

  • 短链平台

  • 后端
  • 畅购商城
Iekr
2021-11-15
目录

Day04 新增和修改商品

# Day04 新增和修改商品

# 分布式 ID 生成解决方案

# UUID

常见的方式。可以利用数据库也可以利用程序生成,一般来说全球唯一。

优点:

1)简单,代码方便。

2)生成 ID 性能非常好,基本不会有性能问题。

3)全球唯一,在遇见数据迁移,系统数据合并,或者数据库变更等情况下,可以从容应对。

缺点:

1)没有排序,无法保证趋势递增。

2)UUID 往往是使用字符串存储,查询的效率比较低。

3)存储空间比较大,如果是海量数据库,就需要考虑存储量的问题。

4)传输数据量大

5)不可读。

# Redis

当使用数据库来生成 ID 性能不够要求的时候,我们可以尝试使用 Redis 来生成 ID。这主要依赖于 Redis 是单线程的,所以也可以用生成全局唯一的 ID。可以用 Redis 的原子操作 INCR 和 INCRBY 来实现。

优点:

1)不依赖于数据库,灵活方便,且性能优于数据库。

2)数字 ID 天然排序,对分页或者需要排序的结果很有帮助。

缺点:

1)如果系统中没有 Redis,还需要引入新的组件,增加系统复杂度。

2)需要编码和配置的工作量比较大。

3)网络传输造成性能下降。

# snowflake

snowflake 是 Twitter 开源的分布式 ID 生成算法,结果是一个 long 型的 ID。其核心思想是:使用 41bit 作为毫秒数,10bit 作为机器的 ID(5 个 bit 是数据中心,5 个 bit 的机器 ID),12bit 作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是 0

img

# snowflake 测试类

雪花算法编码

package com.changgou.util;

import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;

/**
 * <p>名称:IdWorker.java</p>
 * <p>描述:分布式自增长ID</p>
 * <pre>
 *     Twitter的 Snowflake JAVA实现方案
 * </pre>
 * 核心代码为其IdWorker这个类实现,其原理结构如下,我分别用一个0表示一位,用—分割开部分的作用:
 * 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
 * 在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,
 * 然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识),
 * 然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。
 * 这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和机器ID作区分),
 * 并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。
 * <p>
 * 64位ID (42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))
 *
 * @author Polim
 */
public class IdWorker {
    // 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
    private final static long twepoch = 1288834974657L;
    // 机器标识位数
    private final static long workerIdBits = 5L;
    // 数据中心标识位数
    private final static long datacenterIdBits = 5L;
    // 机器ID最大值
    private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
    // 数据中心ID最大值
    private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
    // 毫秒内自增位
    private final static long sequenceBits = 12L;
    // 机器ID偏左移12位
    private final static long workerIdShift = sequenceBits;
    // 数据中心ID左移17位
    private final static long datacenterIdShift = sequenceBits + workerIdBits;
    // 时间毫秒左移22位
    private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;

    private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
    /* 上次生产id时间戳 */
    private static long lastTimestamp = -1L;
    // 0,并发控制
    private long sequence = 0L;

    private final long workerId;
    // 数据标识id部分
    private final long datacenterId;

    public IdWorker(){
        this.datacenterId = getDatacenterId(maxDatacenterId);
        this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
    }
    /**
     * @param workerId
     *            工作机器ID
     * @param datacenterId
     *            序列号
     */
    public IdWorker(long workerId, long datacenterId) {
        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
        }
        if (datacenterId > maxDatacenterId || datacenterId < 0) {
            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
        }
        this.workerId = workerId;
        this.datacenterId = datacenterId;
    }
    /**
     * 获取下一个ID
     *
     * @return
     */
    public synchronized long nextId() {
        long timestamp = timeGen();
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }

        if (lastTimestamp == timestamp) {
            // 当前毫秒内,则+1
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                // 当前毫秒内计数满了,则等待下一秒
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }
        lastTimestamp = timestamp;
        // ID偏移组合生成最终的ID,并返回ID
        long nextId = ((timestamp - twepoch) << timestampLeftShift)
                | (datacenterId << datacenterIdShift)
                | (workerId << workerIdShift) | sequence;

        return nextId;
    }

    private long tilNextMillis(final long lastTimestamp) {
        long timestamp = this.timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = this.timeGen();
        }
        return timestamp;
    }

    private long timeGen() {
        return System.currentTimeMillis();
    }

    /**
     * <p>
     * 获取 maxWorkerId
     * </p>
     */
    protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) {
        StringBuffer mpid = new StringBuffer();
        mpid.append(datacenterId);
        String name = ManagementFactory.getRuntimeMXBean().getName();
        if (!name.isEmpty()) {
            /*
             * GET jvmPid
             */
            mpid.append(name.split("@")[0]);
        }
        /*
         * MAC + PID 的 hashcode 获取16个低位
         */
        return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
    }

    /**
     * <p>
     * 数据标识id部分
     * </p>
     */
    protected static long getDatacenterId(long maxDatacenterId) {
        long id = 0L;
        try {
            InetAddress ip = InetAddress.getLocalHost();
            NetworkInterface network = NetworkInterface.getByInetAddress(ip);
            if (network == null) {
                id = 1L;
            } else {
                byte[] mac = network.getHardwareAddress();
                id = ((0x000000FF & (long) mac[mac.length - 1])
                        | (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
                id = id % (maxDatacenterId + 1);
            }
        } catch (Exception e) {
            System.out.println(" getDatacenterId: " + e.getMessage());
        }
        return id;
    }


    public static void main(String[] args) {

        IdWorker idWorker=new IdWorker(0,0);

        for(int i=0;i<10000;i++){
            long nextId = idWorker.nextId();
            System.out.println(nextId);
        }
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173

创建对象 传递机器 id (唯一的) 和 序列化

        IdWorker idWorker=new IdWorker(1,1);
        for(int i=0;i<10000;i++){
            long id = idWorker.nextId();
            System.out.println(id);
        }
1
2
3
4
5

输出结果为递增 不重复的 long 值

# 微服务 snowflake

IdWorker.java 拷贝到 changgou_common 工程 (公共工程) com.changgou.util 包中

在 changgou_service_goods 的 application.yml 添加配置

workerId: 0
datacenterId: 0
1
2

修改 GoodsApplication (启动类),增加自动注入雪花算法类

package com.changgou;

import com.changgou.util.IdWorker;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import tk.mybatis.spring.annotation.MapperScan;

@SpringBootApplication
@EnableEurekaClient
@MapperScan(basePackages = {"com.changgou.goods.dao"})
public class GoodsApplication {

    //从配置文件读取值
    @Value("${workerId}")
    private Integer workerId;

    @Value("${datacenterId}")
    private Integer datacenterId;

    public static void main(String[] args) {
        SpringApplication.run(GoodsApplication.class);
    }

    @Bean
    public IdWorker idWorker() {
        return new IdWorker(workerId, datacenterId);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 新增和修改商品

# SPU 与 SKU 概念

SPU = Standard Product Unit (标准产品单位)

  • 概念 : SPU 是商品信息聚合的最小单位,是一组可复用、易检索的标准化信息的集合,该集合描述了一个产品的特性。

  • 通俗点讲,属性值、特性相同的货品就可以称为一个 SPU

    例如:华为 P30 就是一个 SPU

SKU=stock keeping unit (库存量单位)

  • SKU 即库存进出计量的单位, 可以是以件、盒、托盘等为单位。

  • SKU 是物理上不可分割的最小存货单元。在使用时要根据不同业态,不同管理模式来处理。

  • 在服装、鞋类商品中使用最多最普遍。

    例如:华为 P30 红色 64G 就是一个 SKU

# 代码实现

前端传递给后端的数据格式 是一个 spu 对象和 sku 列表组成的对象

{
    "spu": {
        "name": "这个是商品名称",
        "caption": "这个是副标题",
        "brandId": 12,
        "category1Id": 558,
        "category2Id": 559,
        "category3Id": 560,
        "freightId": 10,
        "image": "http://www.changgou.com/image/1.jpg",
         "images": "http://www.changgou.com/image/1.jpg,http://www.changgou.com/image/2.jpg",
        "introduction": "这个是商品详情,html代码",
         "paraItems": "{'出厂年份':'2019','赠品':'充电器'}",
        "saleService": "七天包退,闪电退货",
        "sn": "020102331",
        "specItems":  "{'颜色':['红','绿'],'机身内存':['64G','8G']}",
        "templateId": 42
    },
    "skuList": [{
        "sn": "10192010292",
         "num": 100,
         "alertNum": 20,
         "price": 900000,
         "spec": "{'颜色':'红','机身内存':'64G'}",
         "image": "http://www.changgou.com/image/1.jpg",
         "images": "http://www.changgou.com/image/1.jpg,http://www.changgou.com/image/2.jpg",
        "status": "1",
        "weight": 130
    },
    {
        "sn": "10192010293",
         "num": 100,
         "alertNum": 20,
         "price": 600000,
         "spec": "{'颜色':'蓝','机身内存':'128G'}",
         "image": "http://www.changgou.com/image/1.jpg",
         "images": "http://www.changgou.com/image/1.jpg,http://www.changgou.com/image/2.jpg",
        "status": "1",
        "weight": 130
    }
  ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

# SPU 与 SKU 列表的保存

changgou_service_goods_api 工程创建组合实体类 Goods

package com.changgou.goods.pojo;

import java.io.Serializable;
import java.util.List;

public class Goods implements Serializable {

    //spu
    private Spu spu;

    //sku集合
    private List<Sku> skuList;

    public Spu getSpu() {
        return spu;
    }

    public void setSpu(Spu spu) {
        this.spu = spu;
    }

    public List<Sku> getSkuList() {
        return skuList;
    }

    public void setSkuList(List<Sku> skuList) {
        this.skuList = skuList;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

changgou_service_goods 工程 SpuService 新增方法 add 修改为 Goods pojo

/***
 * 新增
 * @param goods
 */
void add(Goods goods);
1
2
3
4
5

SpuServiceImpl 修改 add 方法

@Autowired
private IdWorker idWorker;

@Autowired
private CategoryMapper categoryMapper;

@Autowired
private BrandMapper brandMapper;

@Autowired
private SkuMapper skuMapper;

@Transactional
@Override
public void add(Goods goods) {
    //添加spu
    Spu spu = goods.getSpu();
    //设置分布式id
    spu.setId(String.valueOf(idWorker.nextId()));
    //设置删除状态
    spu.setIsDelete("0"); //未被删除
    //设置上架状态
    spu.setIsMarketable("0"); //未上架
    //审核状态
    spu.setStatus("0"); //未审核
    spuMapper.insertSelective(spu);
    //添加sku集合
    this.saveSkuList(goods);
}

    //添加sku数据
    private void saveSkuList(Goods goods) {
        Spu spu = goods.getSpu();
        //查询分类对象
        Category category = categoryMapper.selectByPrimaryKey(spu.getCategory3Id());
        //查询品牌对象
        Brand brand = brandMapper.selectByPrimaryKey(spu.getBrandId());
        //获取sku集合
        List<Sku> skuList = goods.getSkuList();
        if (skuList != null) {
            //遍历集合 循环填充数据 并添加到数据库中
            for (Sku sku : skuList) {
                //设置skuId
                sku.setId(String.valueOf(idWorker.nextId()));
                //设置sku规格数据
                if (StringUtils.isEmpty(sku.getSpec())) {
                    sku.setSpec("{}");
                }
                //设置sku名称 spu名称+规格
                String name = spu.getName();
                //将规格json转为map 将map中的value进行拼接
                Map<String, String> specMap = JSON.parseObject(sku.getSpec(), Map.class);
                if (specMap != null && specMap.size() > 0) {
                    for (String value : specMap.values()) {
                        name += " " + value;
                    }
                }
                sku.setName(name);
                //设置spu id
                sku.setSpuId(spu.getId());
                //设置创建和修改时间
                sku.setCreateTime(new Date());
                sku.setUpdateTime(new Date());
                //商品分类id
                sku.setCategoryId(category.getId());
                //设置商品分类名称
                sku.setCategoryName(category.getName());
                //设置品牌名称
                sku.setBrandName(brand.getName());
                //将sku添加到数据
                skuMapper.insertSelective(sku);

            }
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

修改 controller 层 spu 的 add 方法

/***
 * 新增数据
 * @param goods
 * @return
 */
@PostMapping
public Result add(@RequestBody Goods goods){
    spuService.add(goods);
    return new Result(true,StatusCode.OK,"添加成功");
}
1
2
3
4
5
6
7
8
9
10

# 品牌与分类关联

将分类 ID 与 SPU 的品牌 ID 一起插入到 tb_category_brand 表中

创建实体类

package com.changgou.goods.pojo;

import javax.persistence.Id;
import javax.persistence.Table;

@Table(name = "tb_category_brand")
public class CategoryBrand {
    //分类id
    @Id
    private Integer category_id;

    //品牌id
    @Id
    private Integer brandId;

    public Integer getCategory_id() {
        return category_id;
    }

    public void setCategory_id(Integer category_id) {
        this.category_id = category_id;
    }

    public Integer getBrandId() {
        return brandId;
    }

    public void setBrandId(Integer brandId) {
        this.brandId = brandId;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

mapper 层

package com.changgou.goods.dao;

import com.changgou.goods.pojo.CategoryBrand;
import tk.mybatis.mapper.common.Mapper;

public interface CategoryBrandMapper extends Mapper<CategoryBrand> {
}
1
2
3
4
5
6
7

SpuServiceImpl 注入 并封装 CategoryBrand 判断表中是否有值 如无则插入

@Autowired
private CategoryBrandMapper categoryBrandMapper;

    //添加sku数据
    private void saveSkuList(Goods goods) {
        Spu spu = goods.getSpu();
        //查询分类对象
        Category category = categoryMapper.selectByPrimaryKey(spu.getCategory3Id());
        //查询品牌对象
        Brand brand = brandMapper.selectByPrimaryKey(spu.getBrandId());
        //获取品牌与分类的关联关系
        //查询关联表
        CategoryBrand categoryBrand = new CategoryBrand();
        categoryBrand.setBrandId(spu.getBrandId());
        categoryBrand.setCategory_id(spu.getCategory3Id());
        int count = categoryBrandMapper.selectCount(categoryBrand);
        if (count == 0) {
            //品牌和分类没有关联关系
            categoryBrandMapper.insert(categoryBrand);
        }
        //获取sku集合
        List<Sku> skuList = goods.getSkuList();
        if (skuList != null) {
            //遍历集合 循环填充数据 并添加到数据库中
            for (Sku sku : skuList) {
                //设置skuId
                sku.setId(String.valueOf(idWorker.nextId()));
                //设置sku规格数据
                if (StringUtils.isEmpty(sku.getSpec())) {
                    sku.setSpec("{}");
                }
                //设置sku名称 spu名称+规格
                String name = spu.getName();
                //将规格json转为map 将map中的value进行拼接
                Map<String, String> specMap = JSON.parseObject(sku.getSpec(), Map.class);
                if (specMap != null && specMap.size() > 0) {
                    for (String value : specMap.values()) {
                        name += " " + value;
                    }
                }
                sku.setName(name);
                //设置spu id
                sku.setSpuId(spu.getId());
                //设置创建和修改时间
                sku.setCreateTime(new Date());
                sku.setUpdateTime(new Date());
                //商品分类id
                sku.setCategoryId(category.getId());
                //设置商品分类名称
                sku.setCategoryName(category.getName());
                //设置品牌名称
                sku.setBrandName(brand.getName());
                //将sku添加到数据
                skuMapper.insertSelective(sku);

            }
        }
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

# 根据 id 查询商品

changgou_service_goods 工程 SpuService 新增方法定义

Goods findGoodsById(String id);
1

serviceimpl 实现此方法

/**
 * 根据id查询spu和sku列表信息
 * @param id
 * @return
 */
@Override
public Goods findGoodsById(String id) {
    Goods goods =new Goods();
    //查询spu信息 封装到goods中
    Spu spu = spuMapper.selectByPrimaryKey(id);
    goods.setSpu(spu);
    //查询sku 封装
    Example example = new Example(Sku.class);
    Example.Criteria criteria = example.createCriteria();
    //根据spu进行sku列表查询
    criteria.andEqualTo("spuId",id);
    List<Sku> skus = skuMapper.selectByExample(example);
    goods.setSkuList(skus);
    return goods;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

修改 SpuController 的 findById 方法

    /***
     * 根据ID查询数据
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public Result findById(@PathVariable String id){
//        Spu spu = spuService.findById(id);
        Goods goods = spuService.findGoodsById(id);

        return new Result(true,StatusCode.OK,"查询成功",goods);
    }
1
2
3
4
5
6
7
8
9
10
11
12

# 保存修改

changgou_service_goods 工程 SpuService 修改方法定义

/***
 * 修改
 * @param goods
 */
void update(Goods goods);
1
2
3
4
5

changgou_service_goods 工程 SpuServiceImpl 实现此方法

/**
 * 修改
 *
 * @param goods
 */
@Transactional
@Override
public void update(Goods goods) {

    //修改spu
    Spu spu = goods.getSpu();
    spuMapper.updateByPrimaryKey(spu);
    //修改sku 删除原有的sku列表 重新添加sku列表
    Example example=new Example(Sku.class);
    Example.Criteria criteria = example.createCriteria();
    criteria.andEqualTo("spuId",spu.getId());
    skuMapper.deleteByExample(example);
    //重新添加sku列表
    this.saveSkuList(goods);


}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

controller

/***
 * 修改数据
 * @param goods
 * @param id
 * @return
 */
@PutMapping(value="/{id}")
public Result update(@RequestBody Goods goods,@PathVariable String id){
    spuService.update(goods);
    return new Result(true,StatusCode.OK,"修改成功");
}
1
2
3
4
5
6
7
8
9
10
11

# 商品审核和上下架

商品新增后,审核状态为 0(未审核),默认为下架状态。

审核商品,需要校验是否是被删除的商品,如果未删除则修改审核状态为 1,并自动上架

下架商品,需要校验是否是被删除的商品,如果未删除则修改上架状态为 0

上架商品,需要审核状态为 1, 如果为 1, 则更改上下架状态为 1

# 商品审核

需要校验是否是被删除的商品,如果未删除则修改审核状态为 1,并自动上架

SpuService 新增方法

//商品审核并自动上架
void audit(String id);
1
2

SpuServiceImpl 实现方法

@Override
@Transactional
public void audit(String id) {
    //查询spu对象
    Spu spu = spuMapper.selectByPrimaryKey(id);
    if (spu == null){
        throw new RuntimeException("当前商品不存在");
    }
    //判断当前spu是否处于删除状态
    if ("1".equals(spu.getIsDelete())){
        throw new RuntimeException("当前商品处于删除状态");
    }
    //不是删除状态 修改审核状态为1 上下架状态为1
    spu.setStatus("1");
    spu.setIsMarketable("1");
    //修改表数据
    spuMapper.updateByPrimaryKey(spu);


}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

SpuController 实现方法

@PutMapping("/audit/{id}")
public Result audit(@PathVariable("id") String id){
    spuService.audit(id);
    return new Result(true,StatusCode.OK,"商品审核成功");
}
1
2
3
4
5

# 下架商品

校验是否是被删除的商品,如果未删除则修改上架状态为 0

SpuService 新增方法

//商品下架
void pull(String id);
1
2

SpuServiceImpl 实现方法

@Override
@Transactional
public void pull(String id) {
    //查询spu
    Spu spu = spuMapper.selectByPrimaryKey(id);
    if (spu == null){
        throw new RuntimeException("当前商品不存在");
    }
    //判断当前商品是否处于删除状态
    if ("1".equals(spu.getIsDelete())){
        throw new RuntimeException("当前商品处于删除状态");
    }
    //商品处于未删除状态 则修改上下架状态为已下架
    spu.setIsMarketable("0");
    spuMapper.updateByPrimaryKeySelective(spu);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

controller

@PutMapping("/pull/{id}")
public Result pull(@PathVariable("id") String id){
    spuService.pull(id);
    return new Result(true,StatusCode.OK,"商品下架成功");
}
1
2
3
4
5

# 上架商品

必须是通过审核的商品才能上架

SpuService 新增方法

//商品上架
void put(String id);
1
2

SpuServiceImpl 实现此方法

@Override
@Transactional
public void put(String id) {
    //查询spu
    Spu spu = spuMapper.selectByPrimaryKey(id);
    if (spu == null){
        throw new RuntimeException("当前商品不存在");
    }
    //商品审核状态是否为已审核
    if ("0".equals(spu.getStatus())){
        throw new RuntimeException("当前商品未审核");
    }
    //上架状态改为1 已上架
    spu.setIsMarketable("1");
    spuMapper.updateByPrimaryKeySelective(spu);

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

SpuController 新增方法

@PutMapping("/put/{id}")
public Result put(@PathVariable("id") String id){
    spuService.put(id);
    return new Result(true,StatusCode.OK,"商品上架成功");
}
1
2
3
4
5

# 删除与还原商品

商品列表中的删除商品功能,并非真正的删除 (物理删除),而是采用逻辑删除将删除标记的字段设置为 1.

在回收站中有还原商品的功能,将删除标记的字段设置为 0

在回收站中有删除商品的功能,是真正的物理删除,将数据从数据库中删除掉。

商品列表中的删除商品,执行逻辑删除,修改 spu 表 is_delete 字段为 1

商品回收站中的还原商品,修改 spu 表 is_delete 字段为 0

商品回收站中的删除商品,执行 delete 操作,进行物理删除

# 逻辑删除商品

修改 SpuServiceImpl 的 delete 方法

/**
 * 删除
 *
 * @param id
 */
@Override
@Transactional
public void delete(String id) {
    //逻辑删除
    //查询spu
    Spu spu = spuMapper.selectByPrimaryKey(id);
    if (spu == null){
        throw new RuntimeException("当前商品不存在");
    }
    //当前商品是否处于下架状态
    if ("1".equals(spu.getIsMarketable())){
        throw new RuntimeException("当前商品必须处于下架状态才能删除");
    }
    //已下架商品 则修改逻辑删除状态
    spu.setIsDelete("1");
    spu.setStatus("0"); //未审核
    spuMapper.selectByPrimaryKey(spu);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 商品还原

SpuService 新增方法

//还原商品
void restore(String id);
1
2

impl 实现方法

@Override
@Transactional
public void restore(String id) {
    //查询spu
    Spu spu = spuMapper.selectByPrimaryKey(id);
    if (spu == null) {
        throw new RuntimeException("当前商品不存在");
    }
    //当前商品已经删除
    if ("0".equals(spu.getIsDelete())) {
        throw new RuntimeException("当前商品未被删除");
    }
    //修改删除状态 和审核状态
    spu.setIsDelete("0");
    spu.setStatus("0"); //未审核
    spuMapper.selectByPrimaryKey(spu);

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

SpuController 新增方法

@PutMapping("/restore/{id}")
public Result restore(@PathVariable("id") String id){
    spuService.restore(id);
    return new Result(true,StatusCode.OK,"商品还原成功");
}
1
2
3
4
5

# 物理删除

判断必须逻辑删除商品才能物理删除

service 层

//物理删除商品
void realDel(String id);
1
2

impl

@Override
@Transactional
public void realDel(String id) {
    //查询spu
    Spu spu = spuMapper.selectByPrimaryKey(id);
    if (spu == null) {
        throw new RuntimeException("当前商品不存在");
    }
    //当前商品未删除
    if ("0".equals(spu.getIsDelete())) {
        throw new RuntimeException("当前商品未被删除");
    }
    //执行删除
    spuMapper.deleteByPrimaryKey(id);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

controller

@DeleteMapping("/realDel/{id}")
public Result realDel(@PathVariable("id") String id) {
    spuService.realDel(id);
    return new Result(true, StatusCode.OK, "商品删除成功");
}
1
2
3
4
5
编辑 (opens new window)
上次更新: 2023/12/06, 01:31:48
Day03 微服务鉴权
Day05 广告缓存

← Day03 微服务鉴权 Day05 广告缓存→

最近更新
01
k8s
06-06
02
进程与线程
03-04
03
计算机操作系统概述
02-26
更多文章>
Theme by Vdoing | Copyright © 2022-2025 Iekr | Blog
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式