Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)十(商品的规格类型以及参数管理)

在这里插入图片描述

package com.leyou.item.service;

import org.springframework.stereotype.Service;

@Service

public class SpecificationService {

}

(4)实体类对应的Controller(根据分类id查询规格组)

在这里插入图片描述

在这里插入图片描述

package com.leyou.item.web;

import com.leyou.item.pojo.SpecGroup;

import com.leyou.item.service.SpecificationService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.http.ResponseEntity;

import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController

@RequestMapping(“spec”)

public class SpecificationController {

@Autowired

private SpecificationService specificationService;

@GetMapping(“groups/{cid}”)

public ResponseEntity<List> queryGroupByCid(@PathVariable(“cid”)Long cid){

return ResponseEntity.ok(specificationService.queryGroupByCid(cid));

}

}

(5)完善Service层
1)创建对应抛出异常的枚举

在这里插入图片描述

SPEC_GROUP_NOT_FOND(404,“商品规格组不存在”),

2)继续完善Service

在这里插入图片描述

在这里插入图片描述

package com.leyou.item.service;

import com.leyou.common.enums.ExceptionEnum;

import com.leyou.common.exception.LyException;

import com.leyou.item.mapper.SpecGroupMapper;

import com.leyou.item.pojo.SpecGroup;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import org.springframework.util.CollectionUtils;

import java.util.List;

@Service

public class SpecificationService {

@Autowired

private SpecGroupMapper specGroupMapper;

public List queryGroupByCid(Long cid) {

//设置查询条件

SpecGroup specGroup = new SpecGroup();

specGroup.setCid(cid);

List list = specGroupMapper.select(specGroup);

if(CollectionUtils.isEmpty(list)){

// 没有查询到

throw new LyException(ExceptionEnum.SPEC_GROUP_NOT_FOND);

}

return list;

}

}

(6)运行测试

在这里插入图片描述

在这里插入图片描述

3、后台代码实现规格组的添加

在这里插入图片描述

@PostMapping(“group”)

public ResponseEntity addGroup(@RequestBody SpecGroup group) {

System.out.println(group);

boolean flag = specificationService.addGroup(group);

if (!flag) {

return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();

}

return ResponseEntity.status(HttpStatus.CREATED).build();

}

在这里插入图片描述

public boolean addGroup(SpecGroup specGroup) {

int count = specGroupMapper.insert(specGroup);

if(count > 0){

return true;

}

return false;

}

运行测试

在这里插入图片描述

在这里插入图片描述

4、完善实现规格组的修改

在这里插入图片描述

@PutMapping(“group”)

public ResponseEntity updateGroup(@RequestBody SpecGroup group) {

System.out.println(group);

boolean flag = specificationService.updateGroup(group);

if (!flag) {

return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();

}

return ResponseEntity.status(HttpStatus.CREATED).build();

}

在这里插入图片描述

public boolean updateGroup(SpecGroup group) {

int count = specGroupMapper.updateByPrimaryKeySelective(group);

if(count > 0){

return true;

}

return false;

}

运行测试

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

5、完善实现规格组的删除

在这里插入图片描述

@DeleteMapping(“group/{id}”)

public ResponseEntity deleteGroup(@PathVariable(“id”)Long id) {

specificationService.deleteGroupById(id);

return ResponseEntity.status(HttpStatus.CREATED).build();

}

在这里插入图片描述

public void deleteGroupById(Long id) {

SpecGroup specGroup = new SpecGroup();

specGroup.setId(id);

int count = specGroupMapper.delete(specGroup);

if(count <= 0){

// 没有查询到

throw new LyException(ExceptionEnum.INVALID_FILE_TYPE);

}

}

运行测试

在这里插入图片描述

在这里插入图片描述

删除成功

在这里插入图片描述

三、商品规格参数管理


1、页面分析

点击上面的规格组我们会发现

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

我们可以看到当前请求参数是规格组id,返回值为当前组下面的所有规格参数

2、实现规格参数的查询(后台实现)

1)实体类

在这里插入图片描述

在这里插入图片描述

package com.leyou.item.pojo;

import lombok.Data;

import tk.mybatis.mapper.annotation.KeySql;

import javax.persistence.Column;

import javax.persistence.Id;

import javax.persistence.Table;

@Table(name = “tb_spec_param”)

@Data

public class SpecParam {

@Id

@KeySql(useGeneratedKeys = true)

private Long id;

private Long cid;

private Long groupId;

private String name;

@Column(name = “numeric”)

private Boolean numeric;

private String unit;

private Boolean generic;

private Boolean searching;

private String segments;

}

2)实体类对应的通用Mapper

在这里插入图片描述

package com.leyou.item.mapper;

import com.leyou.item.pojo.SpecParam;

import tk.mybatis.mapper.common.Mapper;

public interface SpecParamMapper extends Mapper {

}

3)实体类对应的Service,在SpecificationService当中注入SpecParamMapper 即可

在这里插入图片描述

@Autowired

private SpecParamMapper specParamMapper;

4)在SpecificationController当中

在这里插入图片描述

/*

根据组id查询参数

*/

@GetMapping(“params”)

public ResponseEntity<List> queryParamByGid(@RequestParam(“gid”) Long gid){

return ResponseEntity.ok(specificationService.queryParamByGid(gid));

}

5)完善SpecificationService

创建抛出异常的枚举

在这里插入图片描述

SPEC_PARAM_NOT_FOND(404,“商品规格参数不存在”),

完善SpecificationService

在这里插入图片描述

在这里插入图片描述

public List queryParamByGid(Long gid) {

SpecParam specParam = new SpecParam();

specParam.setGroupId(gid);

List list = specParamMapper.select(specParam);

if(CollectionUtils.isEmpty(list)){

// 没有查询到

throw new LyException(ExceptionEnum.SPEC_PARAM_NOT_FOND);

}

return list;

}

6)重新运行并测试

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3、SPU和SKU数据结构

(1)什么是SPU和SKU

SPU: Standard Product Unit(标准产品单位),一组具有共同属性的商品集

SKU: Stock Keeping Unit(库存量单位),SPU商品集因具体特性不同而细分的每个商品

以图为例来看:

在这里插入图片描述

  • 本页的华为就是一个商品集(SPU)

  • 因为颜色、内存等不同,而细分出不同的手机,如亮黑色128G版。(SKU)可以看出;

  • SPU是一个抽象的商品集概念,为了方便后台的管理。

  • SKU才是具体要销售的商品,每一个SKU的价格、库存可能会不一样,用户购买的是SKU而不是SPU

(2)数据库设计分析
1)思考分析

弄清楚了SPU和SKU的概念区分,接下来我们一起思考一下该如何设计数据库表。

首先来看SPU,大家一起思考下SPU应该有哪些字段来描述?

  • SPU共享数据

id:主键

title:标题

description:描述

specification:规格

packaging_list:包装

after _service:售后服务

comment:评价

category_id:商品分类

brand_id:品牌

似乎并不复杂

  • 再看下SKU(每个商品的特殊属性)

大家觉得应该有什么字段?

id:主健

spu_id:关联的

spuprice:价格

images:图片

stock:库存颜色?

内存?

硬盘?

上述做法是错误的:SKU的特有属性也是变化的。

不同分类特有属性也不一定相同。

2)SKU的特有属性

SPU中会有一些特殊属性,用来区分不同的SKU,我们称为sKU特有属性。如华为META10的颜色、内存属性.不同种类的商品,一个手机,一个衣服,其SKU属性不相同。

同一种类的商品,比如都是衣服,SKU属性基本是一样的,都是颜色、尺码等。

这样说起来,似乎SKU的特有属性也是与分类相关的?事实上,仔细观察你会发现,

SKU的特有属性是商品规格参数的一部分∶

也就是说,我们没必要单独对SKu的特有属性进行设计,它可以看做是规格参数中的一部分。这样规格参数中性可以标记成两部分:

  • 所有sku共享的规格属性〈称为通用属性),我们记录在SPU表中。

  • 每个sku不同的规格属性(称为特有属性),我们记录在SKU表中。

回一下之前我们设计的tb _spec_param表,是不是有一个字段,名为generic,标记通用和特有属性。就是为使用。

(3)SPU表
1)表结构

SPU表:

CREATE TABLE tb_spu (

id bigint(20) NOT NULL AUTO_INCREMENT COMMENT ‘spu id’,

title varchar(128) NOT NULL DEFAULT ‘’ COMMENT ‘标题’,

sub_title varchar(256) DEFAULT ‘’ COMMENT ‘子标题’,

cid1 bigint(20) NOT NULL COMMENT ‘1级类目id’,

cid2 bigint(20) NOT NULL COMMENT ‘2级类目id’,

cid3 bigint(20) NOT NULL COMMENT ‘3级类目id’,

brand_id bigint(20) NOT NULL COMMENT ‘商品所属品牌id’,

saleable tinyint(1) NOT NULL DEFAULT ‘1’ COMMENT ‘是否上架,0下架,1上架’,

valid tinyint(1) NOT NULL DEFAULT ‘1’ COMMENT ‘是否有效,0已删除,1有效’,

create_time datetime DEFAULT NULL COMMENT ‘添加时间’,

last_update_time datetime DEFAULT NULL COMMENT ‘最后修改时间’,

PRIMARY KEY (id) USING BTREE

) ENGINE=InnoDB AUTO_INCREMENT=195 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT=‘spu表,该表描述的是一个抽象性的商品,比如 iphone8’;

与我们前面分析的基本类似,但是似乎少了一些字段,比如商品描述。

我们做了表的垂直拆分,将SPu的详情放到了另一张表: tb_spu_detail

CREATE TABLE tb_spu_detail (

spu_id bigint(20) NOT NULL,

description text COMMENT ‘商品描述信息’,

generic_spec varchar(2048) NOT NULL DEFAULT ‘’ COMMENT ‘通用规格参数数据’,

special_spec varchar(1024) NOT NULL COMMENT ‘特有规格参数及可选值信息,json格式’,

packing_list varchar(1024) DEFAULT ‘’ COMMENT ‘包装清单’,

after_service varchar(1024) DEFAULT ‘’ COMMENT ‘售后服务’,

PRIMARY KEY (spu_id) USING BTREE

) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

在这里插入图片描述

下面的参数字段是JSON格式的字符串,与规格参数表当中的数据是一致的

在这里插入图片描述

在这里插入图片描述

(4)SKU表
1)表结构

CREATE TABLE tb_sku (

id bigint(20) NOT NULL AUTO_INCREMENT COMMENT ‘sku id’,

spu_id bigint(20) NOT NULL COMMENT ‘spu id’,

title varchar(256) NOT NULL COMMENT ‘商品标题’,

images varchar(1024) DEFAULT ‘’ COMMENT ‘商品的图片,多个图片以‘,’分割’,

price bigint(15) NOT NULL DEFAULT ‘0’ COMMENT ‘销售价格,单位为分’,

indexes varchar(32) DEFAULT ‘’ COMMENT ‘特有规格属性在spu属性模板中的对应下标组合’,

own_spec varchar(1024) DEFAULT ‘’ COMMENT ‘sku的特有规格参数键值对,json格式,反序列化时请使用linkedHashMap,保证有序’,

enable tinyint(1) NOT NULL DEFAULT ‘1’ COMMENT ‘是否有效,0无效,1有效’,

create_time datetime NOT NULL COMMENT ‘添加时间’,

last_update_time datetime NOT NULL COMMENT ‘最后修改时间’,

PRIMARY KEY (id) USING BTREE,

KEY key_spu_id (spu_id) USING BTREE

) ENGINE=InnoDB AUTO_INCREMENT=27359021729 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT=‘sku表,该表表示具体的商品实体,如黑色的 64g的iphone 8’;

还有一张表代表库存

CREATE TABLE tb_stock (

sku_id bigint(20) NOT NULL COMMENT ‘库存对应的商品sku id’,

seckill_stock int(9) DEFAULT ‘0’ COMMENT ‘可秒杀库存’,

seckill_total int(9) DEFAULT ‘0’ COMMENT ‘秒杀总数量’,

stock int(9) NOT NULL COMMENT ‘库存数量’,

PRIMARY KEY (sku_id) USING BTREE

) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT=‘库存表,代表库存,秒杀库存等信息’;

问题:为什么要将库存独立—张表?

因为库存字段写频率较高,而SKu的其它字段以读为主,因此我们将两张表分离,读写不会干扰。

特别需要注意的是sku表中的 indexes 字段和 own_spec字段。

sku中应该保存特有规格参数的值,就在这两个字段中。

在这里插入图片描述

4、功能实现

(1)页面分析

请求方式为GET

请求参数:

上架saleable是true

下降saleable是false

全部是没有saleable

key搜索的关键字

初始也page

以及显示的行数rows

在这里插入图片描述

在这里插入图片描述

发起的请求

在这里插入图片描述

(2)后台代码实现
1)实体类
a)SPU

在这里插入图片描述

在这里插入图片描述

package com.leyou.item.pojo;

import lombok.Data;

import tk.mybatis.mapper.annotation.KeySql;

import javax.persistence.Id;

import javax.persistence.Table;

import java.util.Date;

@Table(name = “tb_spu”)

@Data

public class Spu {

@Id

@KeySql(useGeneratedKeys = true)

private Long id;

private Long brandId;

private Long cid1; //1级类目

private Long cid2; //2级类目

private Long cid3; //2级类目

private String title;//标题

private String subTitle;//子标题

private Boolean saleable;//是否上架

private Boolean valid;//是否有效。逻辑删除用

private Date createTime;//创建时间

private Date lastUpdateTime;//最后修改时间

}

b)SPU详情SpuDetail

在这里插入图片描述

package com.leyou.item.pojo;

import lombok.Data;

import javax.persistence.Id;

import javax.persistence.Table;

@Table(name = “tb_spu_detail”)

public class SpuDetail {

@Id

private Long spuId;//对应SPU的id

private String description ; //商品描述

private String specialSpec ; //商品特殊规格的名称及可选值模板

private String genericSpec; //商品的全局规格属性

private String packingList; //包装清单

private String afterService ; //售后服务

}

2)实体类对应的mapper
a)SpuMapper

在这里插入图片描述

在这里插入图片描述

package com.leyou.item.mapper;

import com.leyou.item.pojo.Spu;

import tk.mybatis.mapper.common.Mapper;

public interface SpuMapper extends Mapper {

}

b)SpuDetailMapper

在这里插入图片描述

在这里插入图片描述

package com.leyou.item.mapper;

import com.leyou.item.pojo.SpuDetail;

import tk.mybatis.mapper.common.Mapper;

public interface SpuDetailMapper extends Mapper {

}

3)实体类对应的service

在这里插入图片描述

在这里插入图片描述

package com.leyou.item.service;

import com.leyou.item.mapper.SpuDetailMapper;

import com.leyou.item.mapper.SpuMapper;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

@Service

public class GoodsService {

@Autowired

private SpuMapper spuMapper;

@Autowired

private SpuDetailMapper spuDetailMapper;

}

4)实体类对应的Controller

在这里插入图片描述

在这里插入图片描述

package com.leyou.item.web;

import com.leyou.item.pojo.Spu;

import com.leyou.item.service.GoodsService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.http.ResponseEntity;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

@RestController

@RequestMapping(“spu”)

public class GoodsController {

@Autowired

private GoodsService goodsService;

}

5)完善实体类对应返回的字段
a、添加依赖

在这里插入图片描述

com.fasterxml.jackson.core

jackson-databind

b、完善Spu实体类

在这里插入图片描述

package com.leyou.item.pojo;

import com.fasterxml.jackson.annotation.JsonIgnore;

import lombok.Data;

import tk.mybatis.mapper.annotation.KeySql;

import javax.persistence.Id;

import javax.persistence.Table;

import javax.persistence.Transient;

import java.util.Date;

@Table(name = “tb_spu”)

@Data

public class Spu {

@Id

@KeySql(useGeneratedKeys = true)

private Long id;

private Long brandId;

private Long cid1; //1级类目

private Long cid2; //2级类目

private Long cid3; //2级类目

private String title;//标题

private String subTitle;//子标题

private Boolean saleable;//是否上架

@JsonIgnore //设置返回页面数据的时候,忽略当前字段

private Boolean valid;//是否有效。逻辑删除用

private Date createTime;//创建时间

@JsonIgnore //设置返回页面数据的时候,忽略当前字段

private Date lastUpdateTime;//最后修改时间

@Transient //Transient声明当前字段不是数据对应的字段

private String cname;

@Transient //Transient声明当前字段不是数据对应的字段

private String bname;

}

c、完善GoodsController

在这里插入图片描述

package com.leyou.item.web;

import com.leyou.common.vo.PageResult;

import com.leyou.item.pojo.Spu;

import com.leyou.item.service.GoodsService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.http.ResponseEntity;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.RestController;

@RestController

@RequestMapping

public class GoodsController {

@Autowired

private GoodsService goodsService;

/*

分页查询SPU

*/

@GetMapping(“/spu/page”)

public ResponseEntity<PageResult> querySpuByPage(

@RequestParam(value = “page”,defaultValue = “1”) Integer page,

@RequestParam(value = “rows”,defaultValue = “5”) Integer rows,

@RequestParam(value = “saleable”,required = false) Boolean saleable,

@RequestParam(value = “key”,required = false) String key

){

return ResponseEntity.ok(goodsService.querySpuByPage(page,rows,saleable,key));

}

}

d、完善GoodsService
  • 设置对应商品查询不存在的枚举

在这里插入图片描述

GOODS_NOT_FOND(404,“商品不存在”),

  • 完善GoodsService

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值