商品新增后台代码
商品規格參數
規格參數的查詢我們之前也已經編寫過接口,因為商品規格參數也是與商品分類綁定,所以需要在商品分類變化后去查詢,我們也是通過watch監控來實現:
可以看到這里是根據商品分類id查詢規格參數:SpecParam。我們之前寫過一個根據gid(分組id)來查詢規格參數的接口,我們接下來完成根據分類id查詢規格參數。
改造查詢規格參數接口
我們在原來的根據 gid(規格組id)查詢規格參數的接口上,添加一個參數:cid,即商品分類id。
等一下, 考慮到以后可能還會根據是否搜索、是否為通用屬性等條件過濾,我們多添加幾個過濾條件:
@GetMapping("params")public ResponseEntity<List<SpecParam>> queryParams(@RequestParam(value = "gid", required = false)Long gid,@RequestParam(value = "cid", required = false)Long cid,@RequestParam(value = "generic", required = false)Boolean generic,@RequestParam(value = "searching", required = false)Boolean searching){List<SpecParam> params = this.specificationService.queryParams(gid, cid, generic, searching);if (CollectionUtils.isEmpty(params)){return ResponseEntity.notFound().build();}return ResponseEntity.ok(params);}改造SpecificationService:
/*** 根據gid查詢規格參數* @param gid* @return*/public List<SpecParam> queryParams(Long gid, Long cid, Boolean generic, Boolean searching) {SpecParam record = new SpecParam();record.setGroupId(gid);record.setCid(cid);record.setGeneric(generic);record.setSearching(searching);return this.specParamMapper.select(record);}如果param中有屬性為null,則不會把屬性作為查詢條件,因此該方法具備通用性,即可根據gid查詢,也可根據cid查詢。
測試:
刷新頁面測試:
SKU信息
Sku屬性是SPU下的每個商品的不同特征,如圖:
當我們填寫一些屬性后,會在頁面下方生成一個sku表格,大家可以計算下會生成多少個不同屬性的Sku呢?
當你選擇了上圖中的這些選項時:
-
顏色共2種:迷夜黑,勃艮第紅,絢麗藍
-
內存共2種:4GB,6GB
-
機身存儲1種:64GB,128GB
此時會產生多少種SKU呢? 應該是 3 * 2 * 2 = 12種,這其實就是在求笛卡爾積。
我們會在頁面下方生成一個sku的表格:
頁面表單提交
在sku列表的下方,有一個提交按鈕:
并且綁定了點擊事件:
點擊后會組織數據并向后臺提交:
submit() {// 表單校驗。if(!this.$refs.basic.validate){this.$message.error("請先完成表單內容!");}// 先處理goods,用結構表達式接收,除了categories外,都接收到goodsParams中const {categories: [{ id: cid1 }, { id: cid2 }, { id: cid3 }],...goodsParams} = this.goods;// 處理規格參數const specs = {};this.specs.forEach(({ id,v }) => {specs[id] = v;});// 處理特有規格參數模板const specTemplate = {};this.specialSpecs.forEach(({ id, options }) => {specTemplate[id] = options;});// 處理skuconst skus = this.skus.filter(s => s.enable).map(({ price, stock, enable, images, indexes, ...rest }) => {// 標題,在spu的title基礎上,拼接特有規格屬性值const title = goodsParams.title + " " + Object.values(rest).map(v => v.v).join(" ");const obj = {};Object.values(rest).forEach(v => {obj[v.id] = v.v;});return {price: this.$format(price), // 價格需要格式化stock,indexes,enable,title, // 基本屬性images: images ? images.join(",") : '', // 圖片ownSpec: JSON.stringify(obj) // 特有規格參數};});Object.assign(goodsParams, {cid1,cid2,cid3, // 商品分類skus // sku列表});goodsParams.spuDetail.genericSpec = JSON.stringify(specs);goodsParams.spuDetail.specialSpec = JSON.stringify(specTemplate);// 提交到后臺this.$http({method: this.isEdit ? "put" : "post",url: "/item/goods",data: goodsParams}).then(() => {// 成功,關閉窗口this.$emit("close");// 提示成功this.$message.success("保存成功了");}).catch(() => {this.$message.error("保存失敗!");});}點擊提交,查看控制臺提交的數據格式:
整體是一個json格式數據,包含Spu表所有數據:
-
brandId:品牌id
-
cid1、cid2、cid3:商品分類id
-
subTitle:副標題
-
title:標題
-
spuDetail:是一個json對象,代表商品詳情表數據
-
afterService:售后服務
-
description:商品描述
-
packingList:包裝列表
-
specialSpec:sku規格屬性模板
-
genericSpec:通用規格參數
-
-
skus:spu下的所有sku數組,元素是每個sku對象:
-
title:標題
-
images:圖片
-
price:價格
-
stock:庫存
-
ownSpec:特有規格參數
-
indexes:特有規格參數的下標
-
后臺實現
1.7.1.實體類
SPU和SpuDetail實體類已經添加過,添加Sku和Stock對象:
Sku
@Table(name = "tb_sku") public class Sku {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private Long spuId;private String title;private String images;private Long price;private String ownSpec;// 商品特殊規格的鍵值對private String indexes;// 商品特殊規格的下標private Boolean enable;// 是否有效,邏輯刪除用private Date createTime;// 創建時間private Date lastUpdateTime;// 最后修改時間@Transientprivate Integer stock;// 庫存 }注意:這里保存了一個庫存字段,在數據庫中是另外一張表保存的,方便查詢。
Stock
@Table(name = "tb_stock") public class Stock {@Idprivate Long skuId;private Integer seckillStock;// 秒殺可用庫存private Integer seckillTotal;// 已秒殺數量private Integer stock;// 正常庫存 }GoodsController
結合瀏覽器頁面控制臺,可以發現:
請求方式:POST
請求路徑:/goods
請求參數:Spu的json格式的對象,spu中包含spuDetail和Sku集合。這里我們該怎么接收?我們之前定義了一個SpuBo對象,作為業務對象。這里也可以用它,不過需要再擴展spuDetail和skus字段:
public class SpuBo extends Spu {String cname;// 商品分類名稱String bname;// 品牌名稱SpuDetail spuDetail;// 商品詳情List<Sku> skus;// sku列表 }-
返回類型:無
在GoodsController中添加新增商品的代碼:
@PostMapping("goods") public ResponseEntity<Void> saveGoods(@RequestBody SpuBo spuBo){this.goodsService.saveGoods(spuBo);return ResponseEntity.status(HttpStatus.CREATED).build(); }注意:通過@RequestBody注解來接收Json請求
GoodsService
這里的邏輯比較復雜,我們除了要對SPU新增以外,還要對SpuDetail、Sku、Stock進行保存
/*** 新增商品* @param spuBo*/ @Transactional public void saveGoods(SpuBo spuBo) {// 新增spu// 設置默認字段spuBo.setId(null);spuBo.setSaleable(true);spuBo.setValid(true);spuBo.setCreateTime(new Date());spuBo.setLastUpdateTime(spuBo.getCreateTime());this.spuMapper.insertSelective(spuBo);// 新增spuDetailSpuDetail spuDetail = spuBo.getSpuDetail();spuDetail.setSpuId(spuBo.getId());this.spuDetailMapper.insertSelective(spuDetail);saveSkuAndStock(spuBo); }private void saveSkuAndStock(SpuBo spuBo) {spuBo.getSkus().forEach(sku -> {// 新增skusku.setSpuId(spuBo.getId());sku.setCreateTime(new Date());sku.setLastUpdateTime(sku.getCreateTime());this.skuMapper.insertSelective(sku);// 新增庫存Stock stock = new Stock();stock.setSkuId(sku.getId());stock.setStock(sku.getStock());this.stockMapper.insertSelective(stock);}); }?
總結