商品品牌的查询
上面就是我们需要根据分类id去找品牌
假设我们现在拿到的是 商品的分类id,我们需要根据分类id查询出对应的品牌即可
下面我们拿到上面的接口,直接撸代码
这个是和品牌相关联的操作,因为先去看一下BrandMapper,这个mapper是已经存在了,那我们现在去写Controller层
那我们要去完成service层,BrandService
下面我们去BrandMapper里面编写sql
再去编写这个sql之前,我们来思考一下,这个应该是一个什么样的sql语句,我们的目的是:查出当前类拥有的所有品牌
简单说一下上面查询什么意思,先是内连接找出分类与品牌关联的所有数据,然后在用一个where ba把我们需要的分类id对应的品牌拿出来,这些品牌肯定不能等于NULL,这也是为什么不能使用左连接与右连接的根本原因
那我们去把这条语句写到通用mapper的方法上面
商品描述
商品的规格参数
这里的想表达的是什么意思,其实就是当我们添加完了这个商品的最后,我们要添上我们新添加的商品的参数啊,但是这些参数是什么,我们需要通过关联分类id去找这个参数
,一个分类下面都多个,之前写的tb_category表与tb_spec_param表这两张表是一个1对多的关系
下面我们要去改造一下这个查询规格参数接口
这个都是在参数的相关控制器里面
现在我们把这个代码给重构一下
下面我们去重构SpecificationService里面的代码
好了,上面重新启动一下这个微服务模块,测试
我们去测试一下这个接口
原因在于cid被配置到gid里面了,我们这里cid等于空,自然查不到
修改测试
下面说一下sku页面信息的处理
它是spu下面每个商品的不同特征
当我们填写了一些数据之后,会在下面给我们生成一个表格,比如我们可以填写更多的颜色,更多的内存,以及更多的机身存储
当我们填写完上面的信息之后,下方就会生成一个sku的表格
我们去看一下保存商品信息的前端
里面直接给我们绑定了一个提交事件
当我们点击保存的时候,下面我们就能看到请求路径,请求方式,请求参数,与返回值
我们看一下请求参数,这里是向服务器发送请求,很明显这里也是一个表单请求
下面我们来对这个表单请求进行一个详细的说明
这里的操作,很明显就是向数据库里面插入各种表的信息,所以一般没有返回值,我们可以去前端看一下
上面也就分析的差不多了,下面我们去后台实现页面
首先我们需要的实体类,spu有了,sku没有需要添加,spuDetail也没有(这个对象会封装spu里面一些比较大的信息)需要添加,stock库存对象也没有,
我们去数据库里面看了一下,本身来说,sku里面是没有stock这个字段的,而这个字段是保存在tb_stock里面,又从某种情况来说,sku表与stock表是一张表
另外还需要注意的是,这个整体的大表单数据是向spu这张表里面做的插入,所以我们必须给spu进行属性的扩展,扩展一些spu本身没有的属性,但是客户端又会传给我们的数据
这个扩展可以放到SpuBo里面,这样可以在不改变原对象的基础之上,进行属性的扩展,下面我们先去扩展SpuBo
扩展的属性是:1.商品的详情对象 2.一个List集合用于封装多个sku商品过来
下面我们就要去实现SpuDetail与Sku这个类,这两个类在数据库都有实体表与之对应
先来扩展Sku
package com.leyou.item.pojo;
import lombok.Data;
import javax.persistence.*;
import java.util.Date;
@Data
@Table(name = "tb_sku")
public class Sku {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long spuId;
private String images;
private Long price;
private String ownSpec;//商品特殊规格键值对{"4":"白色","12":"3GB","13":"16GB"}
//这里应该是在展示主体商品的时候
//我们要展商品的特有属性值
private String indexes;//商品特殊规格下标0_0_0,这个是与spu表里面special_spec值对应
private Boolean enable;//是否有效,逻辑删除用
private Date createTime;//创建时间
private Date lastUpdateTime;//最后的修改时间
//注意在我们请求体里面还有一个库存字段
//但是这个字段不在我们的sku表里面
//所以这里做映射的时候,必须忽略这个字段
@Transient
private Integer stock;//库存
}
上面我们有个库存字段,那么我们要把库存信息存入库存表里面
Stock
下面还要扩展一个在数据库中tb_spu_detail对应的类
SpuDetail(这个是主表对应的类,我们放在pojo包里面),它不想SpuBo一样是中间扩展出来的类
下面开始写后台代码
这个是对商品的操作,所以,这里是在商品的控制器页面进行操作
GoodsController
下面我们去GoodsService里面实现上面的saveGoods方法
GoodsService
再去写这个GoodsService方法之前,先去写上我们需要的几个Mapper
下面贴上完成的service代码
GoodsService
package com.leyou.item.service;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.leyou.common.pojo.PageResult;
import com.leyou.item.bo.SpuBo;
import com.leyou.item.mapper.*;
import com.leyou.item.pojo.Brand;
import com.leyou.item.pojo.Spu;
import com.leyou.item.pojo.SpuDetail;
import com.leyou.item.pojo.Stock;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class GoodsService {
//先不考虑引入什么样的mapper
//要查spu,所以要引入spu的mapper对象
@Autowired
private SpuMapper spuMapper;
//我们在想找分类字段的时候,我们必须用到CategoryService里面相应的通过id找到分类的方法
@Autowired
private CategoryService categoryService;
//我们在考虑通过spu里面的商品id去找,直接引入mapper一键搞定
@Autowired
private BrandMapper brandMapper;
//插入SpuDetail的mapper
@Autowired
private SpuDetailMapper spuDetailMapper;
//插入sku的mapper
@Autowired
private SkuMapper skuMapper;
//插入stock的mapper
@Autowired
private StockMapper stockMapper;
public PageResult<SpuBo> querySpuByPageAndSort(Integer page, Integer rows, String key, Boolean saleable) {
//这里是查询spu
//返回一个带有分页的结果集
PageHelper.startPage(page,rows);//这个分页会拼到后面的所有sql语句里面
//我们利用通用Mapper来查,我们要设置通用条件
Example example = new Example(Spu.class);
Example.Criteria criteria = example.createCriteria();
//查询上下架
if (saleable != null) {
criteria.orEqualTo("saleable",saleable);
}
//模糊查询如果有key的话
if (StringUtils.isNotBlank(key)) {
criteria.andLike("title","%" + key + "%");
}
//下面通过spuMapper查Spu对象,这个需要一个集合类型的对象
//通过上面的
Page<Spu> pageInfo = (Page<Spu>) spuMapper.selectByExample(example);
//上面是得到了一个spu,我们的目的是得到一个List<SpuBo>
List<SpuBo> list = pageInfo.getResult().stream().map(spu -> {
//处理每一个查寻到的spu对象
//我们要把spu对象变成SpuBo对象
SpuBo spuBo = new SpuBo();//每个对象一进来都会实例一个这个对象
//我们把每一个spu的属性给拷贝一下
BeanUtils.copyProperties(spu,spuBo);
//下面考虑一下问题:1.我们的cname怎么取,也就是这个spu关联的分类
//怎么取?是不是要通过spu里面的cid来取,这是个List<Category>
//我们要把它变成字符串集合对象打印
//这个是category表里面的操作,调用categoryService里面的具体方法
//这里面针对这个品牌来讲是三级目录
List<String> names = categoryService.queryNameByIds(Arrays.asList(spu.getCid1(),spu.getCid2(),spu.getCid3()));
//上面我们就先去把这个queryNameByIds这个方法给写出来
//上面就查询到了商品的所属分类
//把分类赋值给Bo对象
spuBo.setCname(StringUtils.join(names,"/"));//格式化一下
//上面查了分类,下面就要去查找品牌
//品牌的查找我们就考虑要引入品牌的servcie还是mapper
//考虑到这里如果mapper能一下给我们找出来,就直接mapper
//如果不能一下找出来,还要经过业务处理,那么就走service
//这里我们通过Brand的Mapper中的主键查询就能找出来,并且没有业务转换,直接引入mapper
Brand brand = brandMapper.selectByPrimaryKey(spu.getBrandId());
spuBo.setBname(brand.getName());
return spuBo;
}).collect(Collectors.toList());//变成了List<spuBo>这样一个集合对象
//注意要给前端返回一个分页对象,并把结果给带过去
//现在就是上面的结果集数据全部都封装到了spuBo这个对象里面
return new PageResult<>(pageInfo.getTotal(),list);
}
//新增商品
//这里注意我们需要对三张表进行数据插入
//1.spu表与spu_detail表(这两张表本质上来说是一张表)
//2.拿到spuId在插入sku表
//3.拿到skuid之后,在插入stock表更新库存
@Transactional//注意对事务进行控制
public void saveGoods(SpuBo spuBo) {
//所有是信息全都给我们封装到了SpuBo这个对象里面
//1.先来新增spu表
//我说了有些字段没有设置
//必须我们自己来进行设置
spuBo.setId(null);
spuBo.setId(null);
spuBo.setSaleable(true);
spuBo.setValid(true);
spuBo.setCreateTime(new Date());
spuBo.setLastUpdateTime(spuBo.getCreateTime());
//利用spu的通用mapper进行数据库插入就行了
//对于我们不需要插入的字段我们已经做了忽略处理
spuMapper.insertSelective(spuBo);
//下面又要新增spuDetail这张表
//先来获取这样一个对象信息
//因为全都是封装到SpuBo里面嘛,所以我们
//从这个对象里面获取
SpuDetail spuDeatil = spuBo.getSpuDetail();
//在插入之前我们考虑一下有没有没有封装的字段
//spuid是需要我们去封装的
//这种张表本质上来说,就是spu表
spuDeatil.setSpuId(spuBo.getId());
//然后在把这个对象的信息插入到spu_detail这张表里面
spuDetailMapper.insertSelective(spuDeatil);
//下面我们要插入sku表与库存表
//这里直接做成一个函数
saveSkuAndStock(spuBo);
}
private void saveSkuAndStock(SpuBo spuBo) {
//这里利用了一个函数式接口,然后用了lambda表达式处理
spuBo.getSkus().forEach(sku -> {
//新增sku
//还是那句话,有些字段没有处理的要处理上
sku.setSpuId(spuBo.getId());
sku.setCreateTime(new Date());
sku.setLastUpdateTime(sku.getCreateTime());
skuMapper.insertSelective(sku);
//然后新增库存这张表
//本质来说,这两张表是同一张表
Stock stock = new Stock();//利用mapper插入需要一个对象
stock.setSkuId(sku.getId());
stock.setStock(sku.getStock());
stockMapper.insertSelective(stock);
});
}
}
下面重启商品微服务然后去测试一下
保存成功就不展示了
我们可以看到数据库里面是插进去了
下面我们去做商品修改部分
看一下对应的方法
下面我们要编写查询SpuDetail接口
这个spu也是针对于商品来说的,先来看GoodsController里面的代码
GoodsService
下面看一下这个接口能用不,记得重新启动商品微服务
测试了一下接口看到是有数据的
下面我们要去查询sku信息
下面我们要去实现service里面的方法
下面重启这个微服务,测试一下接口
下面我们去页面看一下页面有没有被回显
这里之前出现了一个问题,这个位置显示不出来
查看静态源代码
提示这个函数没有被加载进来
原因在于之前我们没有在http.js文件里面设置好下面的函数
这个函数的作用是
下面可以看到数据回显了
这样我们可以去修改这些数据,然后点击保存,就会数据插入到相应的表里面,这里上面分析过是一个大的SpuBo的提交表单
但是现在有一个问题是,这些数据是会向数据库里面插入,但是我们原来的数据应该被删除,然后在覆盖
另外需要注意的一点是,我们相同的请求路径,采用不同的请求方式走的路线也不一样
比如
这里发送的是put请求,主要是用于更新或者替换服务器上的资源
点击保存的时候,我们发现服务器拒绝了我们的请求
下面我们去把这些页面补上
下面去写GoodsService里面的方法
package com.leyou.item.service;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.leyou.common.pojo.PageResult;
import com.leyou.item.bo.SpuBo;
import com.leyou.item.mapper.*;
import com.leyou.item.pojo.*;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class GoodsService {
//先不考虑引入什么样的mapper
//要查spu,所以要引入spu的mapper对象
@Autowired
private SpuMapper spuMapper;
//我们在想找分类字段的时候,我们必须用到CategoryService里面相应的通过id找到分类的方法
@Autowired
private CategoryService categoryService;
//我们在考虑通过spu里面的商品id去找,直接引入mapper一键搞定
@Autowired
private BrandMapper brandMapper;
//插入SpuDetail的mapper
@Autowired
private SpuDetailMapper spuDetailMapper;
//插入sku的mapper
@Autowired
private SkuMapper skuMapper;
//插入stock的mapper
@Autowired
private StockMapper stockMapper;
public PageResult<SpuBo> querySpuByPageAndSort(Integer page, Integer rows, String key, Boolean saleable) {
//这里是查询spu
//返回一个带有分页的结果集
PageHelper.startPage(page,rows);//这个分页会拼到后面的所有sql语句里面
//我们利用通用Mapper来查,我们要设置通用条件
Example example = new Example(Spu.class);
Example.Criteria criteria = example.createCriteria();
//查询上下架
if (saleable != null) {
criteria.orEqualTo("saleable",saleable);
}
//模糊查询如果有key的话
if (StringUtils.isNotBlank(key)) {
criteria.andLike("title","%" + key + "%");
}
//下面通过spuMapper查Spu对象,这个需要一个集合类型的对象
//通过上面的
Page<Spu> pageInfo = (Page<Spu>) spuMapper.selectByExample(example);
//上面是得到了一个spu,我们的目的是得到一个List<SpuBo>
List<SpuBo> list = pageInfo.getResult().stream().map(spu -> {
//处理每一个查寻到的spu对象
//我们要把spu对象变成SpuBo对象
SpuBo spuBo = new SpuBo();//每个对象一进来都会实例一个这个对象
//我们把每一个spu的属性给拷贝一下
BeanUtils.copyProperties(spu,spuBo);
//下面考虑一下问题:1.我们的cname怎么取,也就是这个spu关联的分类
//怎么取?是不是要通过spu里面的cid来取,这是个List<Category>
//我们要把它变成字符串集合对象打印
//这个是category表里面的操作,调用categoryService里面的具体方法
//这里面针对这个品牌来讲是三级目录
List<String> names = categoryService.queryNameByIds(Arrays.asList(spu.getCid1(),spu.getCid2(),spu.getCid3()));
//上面我们就先去把这个queryNameByIds这个方法给写出来
//上面就查询到了商品的所属分类
//把分类赋值给Bo对象
spuBo.setCname(StringUtils.join(names,"/"));//格式化一下
//上面查了分类,下面就要去查找品牌
//品牌的查找我们就考虑要引入品牌的servcie还是mapper
//考虑到这里如果mapper能一下给我们找出来,就直接mapper
//如果不能一下找出来,还要经过业务处理,那么就走service
//这里我们通过Brand的Mapper中的主键查询就能找出来,并且没有业务转换,直接引入mapper
Brand brand = brandMapper.selectByPrimaryKey(spu.getBrandId());
spuBo.setBname(brand.getName());
return spuBo;
}).collect(Collectors.toList());//变成了List<spuBo>这样一个集合对象
//注意要给前端返回一个分页对象,并把结果给带过去
//现在就是上面的结果集数据全部都封装到了spuBo这个对象里面
return new PageResult<>(pageInfo.getTotal(),list);
}
//新增商品
//这里注意我们需要对三张表进行数据插入
//1.spu表与spu_detail表(这两张表本质上来说是一张表)
//2.拿到spuId在插入sku表
//3.拿到skuid之后,在插入stock表更新库存
@Transactional//注意对事务进行控制
public void saveGoods(SpuBo spuBo) {
//所有是信息全都给我们封装到了SpuBo这个对象里面
//1.先来新增spu表
//我说了有些字段没有设置
//必须我们自己来进行设置
spuBo.setId(null);
spuBo.setSaleable(true);
spuBo.setValid(true);
spuBo.setCreateTime(new Date());
spuBo.setLastUpdateTime(spuBo.getCreateTime());
//利用spu的通用mapper进行数据库插入就行了
//对于我们不需要插入的字段我们已经做了忽略处理
spuMapper.insertSelective(spuBo);
//下面又要新增spuDetail这张表
//先来获取这样一个对象信息
//因为全都是封装到SpuBo里面嘛,所以我们
//从这个对象里面获取
SpuDetail spuDeatil = spuBo.getSpuDetail();
//在插入之前我们考虑一下有没有没有封装的字段
//spuid是需要我们去封装的
//这种张表本质上来说,就是spu表
spuDeatil.setSpuId(spuBo.getId());
//然后在把这个对象的信息插入到spu_detail这张表里面
spuDetailMapper.insertSelective(spuDeatil);
//下面我们要插入sku表与库存表
//这里直接做成一个函数
saveSkuAndStock(spuBo);
}
private void saveSkuAndStock(SpuBo spuBo) {
//这里利用了一个函数式接口,然后用了lambda表达式处理
spuBo.getSkus().forEach(sku -> {
//新增sku
//还是那句话,有些字段没有处理的要处理上
sku.setSpuId(spuBo.getId());
sku.setCreateTime(new Date());
sku.setLastUpdateTime(sku.getCreateTime());
skuMapper.insertSelective(sku);
//然后新增库存这张表
//本质来说,这两张表是同一张表
Stock stock = new Stock();//利用mapper插入需要一个对象
stock.setSkuId(sku.getId());
stock.setStock(sku.getStock());
stockMapper.insertSelective(stock);
});
}
public SpuDetail querySpuDetailBySpuId(Long spuId) {
return spuDetailMapper.selectByPrimaryKey(spuId);
}
//我们需要注意的是
//为了方便回显,我们需要把stock里面的库存
//也设置给Sku这个对象
public List<Sku> querySkusBySpuId(Long spuId) {
Sku sku = new Sku();
sku.setSpuId(spuId);
List<Sku> skus = skuMapper.select(sku);
//把每一个sku的库存给设置进去
//这个库存信息存放在Stock表里面
//因此我们需要查出stock这个对象
skus.forEach(s -> {
Stock stock = stockMapper.selectByPrimaryKey(s.getId());
s.setStock(stock.getStock());
});
return skus;
}
@Transactional
public void updateGoods(SpuBo spuBo) {
//先查询以前的sku
List<Sku> skus = querySkusBySpuId(spuBo.getId());
//如果以前的sku存在,我们需要先删除
//这里的思想就是先删除在添加
if (!CollectionUtils.isEmpty(skus)) {
//需要删除sku先关的库存
//那么这里会有很多sku的id关联的库存,我们通过stream转变成一个List集合不就好了
//这里也就是List<sku>->stream(sku)->stream(sku.getId())->List<int> skuid的集合
List<Long> ids = skus.stream().map(s -> s.getId()).collect(Collectors.toList());
//上面有了id的集合,下面就可以去删除以前的库存
Example example = new Example(Stock.class);
example.createCriteria().andIn("skuId",ids);//类中与数据库关联的字段
stockMapper.deleteByExample(example);
//上面删除了库存,再删除以前的sku
Sku record = new Sku();
record.setSpuId(spuBo.getId());
skuMapper.delete(record);//根据sku里面关联的spuid进行删除,与当前spu关联的sku都会被删除
//这里上面的思想是这样的,点击一个spu,后面会设置出多个sku商品
//我们先全部删除,然后在插入
}
//下面我们新增修改后的sku和库存
saveSkuAndStock(spuBo);//这里是一个新的spuBo过来
//下面去更新一下spu信息这张表
// 更新spu
spuBo.setLastUpdateTime(new Date());
spuBo.setCreateTime(null);
spuBo.setValid(null);
spuBo.setSaleable(null);
spuMapper.updateByPrimaryKeySelective(spuBo);//上面使用了默认值的地方,不会更新
//还要更新一下spu详情
//这些数据都是要插入到数据库里面的,只是我们从后对象当中拿而已
spuDetailMapper.updateByPrimaryKeySelective(spuBo.getSpuDetail());
}
}
重启商品微服务测试,自行测试
下面我们要开始搭建前台系统
这个放到资料里面
好了,先说到这,祝大家早安午安晚安