SPU = Standard Product Unit (标准产品单位,某款产品的公共属性)
概念 : SPU 是商品信息聚合的最小单位,是一组可复用、易检索的标准化信息的集合,该集合描述了一个产品的特性。
通俗点讲,属性值、特性相同的货品就可以称为一个 SPU
例如:华为P50 就是一个 SPU
SKU=stock keeping unit( 库存量单位,某款商品不同参数对应的商品信息)
SKU 即库存进出计量的单位, 可以是以件、盒、托盘等为单位。
SKU 是物理上不可分割的最小存货单元。在使用时要根据不同业态,不同管理模式来处理。
在服装、鞋类商品中使用最多最普遍。
例如:华为P50 红色 64G 就是一个 SKU
tb_spu 表 (SPU表)
字段名称 | 字段含义 | 字段类型 | 字段长度 | 备注 |
---|---|---|---|---|
id | 主键 | VARCHAR | ||
sn | 货号 | VARCHAR | ||
name | SPU名 | VARCHAR | ||
caption | 副标题 | VARCHAR | ||
brand_id | 品牌ID | INT | ||
category1_id | 一级分类 | INT | ||
category2_id | 二级分类 | INT | ||
category3_id | 三级分类 | INT | ||
template_id | 模板ID | INT | ||
freight_id | 运费模板id | INT | ||
image | 图片 | VARCHAR | ||
images | 图片列表 | VARCHAR | ||
sale_service | 售后服务 | VARCHAR | ||
introduction | 介绍 | TEXT | ||
spec_items | 规格列表 | VARCHAR | ||
para_items | 参数列表 | VARCHAR | ||
sale_num | 销量 | INT | ||
comment_num | 评论数 | INT | ||
is_marketable | 是否上架 | CHAR | ||
is_enable_spec | 是否启用规格 | CHAR | ||
is_delete | 是否删除 | CHAR | ||
status | 审核状态 | CHAR |
tb_sku 表(SKU商品表)
字段名称 | 字段含义 | 字段类型 | 字段长度 | 备注 |
---|---|---|---|---|
id | 商品id | VARCHAR | ||
sn | 商品条码 | VARCHAR | ||
name | SKU名称 | VARCHAR | ||
price | 价格(分) | INT | ||
num | 库存数量 | INT | ||
alert_num | 库存预警数量 | INT | ||
image | 商品图片 | VARCHAR | ||
images | 商品图片列表 | VARCHAR | ||
weight | 重量(克) | INT | ||
create_time | 创建时间 | DATETIME | ||
update_time | 更新时间 | DATETIME | ||
spu_id | SPUID | BIGINT | ||
category_id | 类目ID | INT | ||
category_name | 类目名称 | VARCHAR | ||
brand_name | 品牌名称 | VARCHAR | ||
spec | 规格 | VARCHAR | ||
sale_num | 销量 | INT | ||
comment_num | 评论数 | INT | ||
status | 商品状态 1-正常,2-下架,3-删除 | CHAR |
前端传递给后端的数据格式 是一个spu对象和sku列表组成的对象
{
"spu": {
"name": "这个是商品名称",
"caption": "这个是副标题",
"brandId": 12,
"category1Id": 558,
"category2Id": 559,
"category3Id": 560,
"freightId": 10,
"image": "http://www.qingcheng.com/image/1.jpg",
"images": "http://www.qingcheng.com/image/1.jpg,http://www.qingcheng.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.qingcheng.com/image/1.jpg",
"images": "http://www.qingcheng.com/image/1.jpg,http://www.qingcheng.com/image/2.jpg",
"status": "1",
"weight": 130
},
{
"sn": "10192010293",
"num": 100,
"alertNum": 20,
"price": 600000,
"spec": {
"颜色":"绿","机身内存":"8G"},
"image": "http://www.qingcheng.com/image/1.jpg",
"images": "http://www.qingcheng.com/image/1.jpg,http://www.qingcheng.com/image/2.jpg",
"status": "1",
"weight": 130
}
]
}
(1)changgou_service_goods_api工程创建组合实体类Goods
/**
* 商品组合实体类
*/
public class Goods implements Serializable {
private Spu spu;
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;
}
}
(2)changgou_service_goods工程SpuService新增方法add(Goods goods)
/***
* 新增
* @param goods
*/
void add(Goods goods);
(3)changgou_service_goods工程SpuServiceImpl实现此方法
@Autowired
private CategoryMapper categoryMapper;
@Autowired
private SkuMapper skuMapper;
@Autowired
private BrandMapper brandMapper;
@Autowired
private IdWorker idWorker;
/**
* 保存商品 SPU+SKU列表
* @param goods 商品组合实体类
*/
@Transactional
@Override
public void add(Goods goods) {
//生成spuId
long spuId = idWorker.nextId();
//spuId放入SPU对象中
goods.getSpu().setId(String.valueOf(spuId));
//添加保存SPU数据
spuMapper.insertSelective(goods.getSpu());
//保存sku集合数据到数据库
saveSkuList(goods);
}
/**
* 保存sku列表
* @param goods
*/
private void saveSkuList(Goods goods){
//获取spu对象
Spu spu = goods.getSpu();
//当前日期
Date date = new Date();
//获取品牌对象
Brand brand = brandMapper.selectByPrimaryKey(spu.getBrandId());
//获取分类对象
Category category = categoryMapper.selectByPrimaryKey(spu.getCategory3Id());
//获取sku集合对象
List<Sku> skuList = goods.getSkuList();
if (skuList != null) {
for (Sku sku : skuList) {
//设置sku主键ID
sku.setId(String.valueOf(idWorker.nextId()));
//设置sku规格
if (sku.getSpec() == null || "".equals(sku.getSpec())) {
sku.setSpec("{}");
}
//设置sku名称(商品名称 + 规格)
String name = spu.getName();
//将规格json字符串转换成Map
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);//名称
sku.setSpuId(spu.getId());//设置spu的ID
sku.setCreateTime(date);//创建日期
sku.setUpdateTime(date);//修改日期
sku.setCategoryId(category.getId());//商品分类ID
sku.setCategoryName(category.getName());//商品分类名称
sku.setBrandName(brand.getName());//品牌名称
skuMapper.insertSelective(sku);//插入sku表数据
}
}
}
(3)修改SpuController的add方法
/***
* 新增数据
* @param goods
* @return
*/
@PostMapping
public Result add(@RequestBody Goods goods){
spuService.add(goods);
return new Result(true,StatusCode.OK,"添加成功");
}
不管什么业务场景,涉及到多级分类的话,在分类表里,aprentID=0则表示是一级分类;
Lua 是一个小巧的脚本语言。它是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个由Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo三人所组成的研究小组于1993年开发的。 其设计目的是为了通过灵活嵌入应用程序中从而为应用程序提供灵活的扩展和定制功能。Lua由标准C编写而成,几乎在所有操作系统和平台上都可以编译,运行。Lua并没有提供强大的库,这是由它的定位决定的。所以Lua不适合作为开发独立应用程序的语言。Lua 有一个同时进行的JIT项目,提供在特定平台上的即时编译功能。
简单来说:
Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
lua 语言具有以下特性
应用场景
这里我们采用linux版本的安装
yum install -y gcc
yum install libtermcap-devel ncurses-devel libevent-devel readline-devel
curl -R -O http://www.lua.org/ftp/lua-5.3.5.tar.gz
tar -zxf lua-5.3.5.tar.gz
cd lua-5.3.5
make linux test
# 下边这个命令可以不执行
#make install
查看是否安装成功
lua
# 或者
lua -i
出现lua版本信息即成功
如果出现如下错误
则需要安装下边的依赖库
yum install libtermcap-devel ncurses-devel libevent-devel readline-devel
创建hello.lua文件
vi hello.lua
内容为
print("hello");
保存。执行命令
lua hello.lua
输出为:
Hello
lua有交互式编程和脚本式编程。
交互式编程就是直接输入语法,就能执行。
脚本式编程需要编写脚本,然后再执行命令,执行脚本才可以。
一般采用脚本式编程。(例如:编写一个hello.lua的文件,输入文件内容,并执行lua hell.lua即可)
一行注释:两个减号是单行注释:
--
多行注释:
--[[
多行注释
多行注释
--]]
关键字就好比java中的 break if else等等一样的效果。lua的关键字如下:
and | break | do | else |
elseif | end | false | for |
function | if | in | local |
nil | not | or | repeat |
return | then | true | until |
while |
全局变量,默认的情况下,定义一个变量都是全局变量,如果要用局部变量,需要声明为local.例如:
-- 全局变量赋值
a=1
-- 局部变量赋值
local b=2
Lua 是动态类型语言,变量不要类型定义,只需要为变量赋值。 值可以存储在变量中,作为参数传递或结果返回。
Lua 中有 8 个基本类型分别为:nil、boolean、number、string、userdata、function、thread 和 table。
数据类型 | 描述 |
---|---|
nil | 这个最简单,只有值nil属于该类,表示一个无效值(在条件表达式中相当于false)。 |
boolean | 包含两个值:false和true。 |
number | 表示双精度类型的实浮点数 |
string | 字符串由一对双引号或单引号来表示 |
function | 由 C 或 Lua 编写的函数 |
userdata | 表示任意存储在变量中的C数据结构 |
thread | 表示执行的独立线路,用于执行协同程序 |
table | Lua 中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字、字符串或表类型。在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。 |
如下:类似于if else
--[ 0 为 true ]
if(0) then
print("0 为 true")
else
print("0 不为true")
end
lua中也可以定义函数,类似于java中的方法。例如:
--[[ 函数返回两个值的最大值 --]]
function max(num1, num2)
if (num1 > num2) then
result = num1;
else
result = num2;
end
return result;
end
-- 调用函数
print("两值比较最大值为 ",max(10,4))
print("两值比较最大值为 ",max(5,6))
执行之后的结果:
两值比较最大值为 10
两值比较最大值为 6
两个点或者一个逗号,表示拼接,相当于java里的+
.. : 拼接
require 用于 引入其他的模块(后边讲模块的概念),类似于java中的类要引用别的类的效果。
用法:
require("<模块名>")
require "<模块名>"
两种都可以。
OpenResty(又称:ngx_openresty) 是一个基于 NGINX 的可伸缩的 Web 平台,由中国人章亦春发起,提供了很多高质量的第三方模块。
OpenResty 是一个强大的 Web 应用服务器,Web 开发人员可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,更主要的是在性能方面,OpenResty可以 快速构造出足以胜任 10K 以上并发连接响应的超高性能 Web 应用系统。
360,UPYUN,阿里云,新浪,腾讯网,去哪儿网,酷狗音乐等都是 OpenResty 的深度用户。
OpenResty 简单理解,就相当于封装了nginx,并且集成了LUA脚本,开发人员只需要简单的其提供了模块就可以实现相关的逻辑,而不再像之前,还需要在nginx中自己编写lua的脚本,再进行调用了。
linux安装openresty:
1.添加仓库执行命令
yum install yum-utils
yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo
2.执行安装
yum install openresty
3.安装成功后 会在默认的目录如下:
/usr/local/openresty
安装nginx
安装完OpenResty后默认已经安装好了nginx,在目录:/usr/local/openresty/nginx 下。
修改/usr/local/openresty/nginx/conf/nginx.conf ,将配置文件使用的根设置为root,目的就是将来要使用lua脚本的时候 ,直接可以加载在root下的lua脚本。
#user nobody; 配置文件第一行原来为这样, 现改为下面的配置
user root root;