lyshop學(xué)習(xí)筆記七-商品管理(添加商品)


title: 樂優(yōu)商城學(xué)習(xí)筆記七-商品管理(添加商品)
date: 2019-04-17 16:18:10
tags:
- 樂優(yōu)商城
- java
- springboot
categories:
- 樂優(yōu)商城


0.學(xué)習(xí)目標(biāo)

  • 獨(dú)立實(shí)現(xiàn)商品新增后臺(tái)
  • 獨(dú)立實(shí)現(xiàn)商品編輯后臺(tái)
  • 獨(dú)立搭建前臺(tái)系統(tǒng)頁面

1.商品新增

1.1.頁面預(yù)覽

當(dāng)我們點(diǎn)擊新增商品按鈕:

1528083727447

就會(huì)出現(xiàn)一個(gè)彈窗:

[圖片上傳失敗...(image-55dc49-1555491859890)]

里面把商品的數(shù)據(jù)分為了4部分來填寫:

  • 基本信息:主要是一些簡(jiǎn)單的文本數(shù)據(jù),包含了SPU和SpuDetail的部分?jǐn)?shù)據(jù)导而,如
    • 商品分類:是SPU中的cid1润绵,cid2cid3屬性
    • 品牌:是spu中的brandId屬性
    • 標(biāo)題:是spu中的title屬性
    • 子標(biāo)題:是spu中的subTitle屬性
    • 售后服務(wù):是SpuDetail中的afterService屬性
    • 包裝列表:是SpuDetail中的packingList屬性
  • 商品描述:是SpuDetail中的description屬性,數(shù)據(jù)較多,所以單獨(dú)放一個(gè)頁面
  • 規(guī)格參數(shù):商品規(guī)格信息,對(duì)應(yīng)SpuDetail中的genericSpec屬性
  • SKU屬性:spu下的所有Sku信息

對(duì)應(yīng)到頁面中的四個(gè)stepper-content

[圖片上傳失敗...(image-4fa092-1555491859890)]

1.2.彈窗事件

彈窗是一個(gè)獨(dú)立組件:

[圖片上傳失敗...(image-591a50-1555491859890)]

并且在Goods組件中已經(jīng)引用它:

[圖片上傳失敗...(image-465e8e-1555491859890)]

并且在頁面中渲染:

[圖片上傳失敗...(image-44bb64-1555491859890)]

新增商品按鈕的點(diǎn)擊事件中颜屠,改變這個(gè)dialogshow屬性:

[圖片上傳失敗...(image-4e78e8-1555491859890)]

[圖片上傳失敗...(image-d90975-1555491859890)]

1.3.基本數(shù)據(jù)

我們先來看下基本數(shù)據(jù):

[圖片上傳失敗...(image-1e3aeb-1555491859890)]

1.3.1.商品分類

商品分類信息查詢我們之前已經(jīng)做過辰妙,所以這里的級(jí)聯(lián)選框已經(jīng)實(shí)現(xiàn)完成:

[圖片上傳失敗...(image-211bab-1555491859890)]

刷新頁面,可以看到請(qǐng)求已經(jīng)發(fā)出:

[圖片上傳失敗...(image-47d990-1555491859890)]

[圖片上傳失敗...(image-4d6430-1555491859890)]

[圖片上傳失敗...(image-4a702e-1555491859890)]

1.3.2.品牌選擇

頁面

品牌也是一個(gè)下拉選框汽纤,不過其選項(xiàng)是不確定的,只有當(dāng)用戶選擇了商品分類福荸,才會(huì)把這個(gè)分類下的所有品牌展示出來蕴坪。

所以頁面編寫了watch函數(shù),監(jiān)控商品分類的變化敬锐,每當(dāng)商品分類值有變化背传,就會(huì)發(fā)起請(qǐng)求,查詢品牌列表:

    "goods.categories": {
      deep: true,
      handler(val) {
        // 判斷商品分類是否存在台夺,存在才查詢
        if (val && val.length > 0) {
          // 根據(jù)分類查詢品牌
          this.$http
            .get("/item/brand/cid/" + this.goods.categories[2].id)
            .then(({ data }) => {
              this.brandOptions = data;
            });

刷新頁面径玖,可以看到請(qǐng)求發(fā)起:

[圖片上傳失敗...(image-478a3f-1555491859890)]

接下來,我們只要編寫后臺(tái)接口颤介,根據(jù)商品分類id梳星,查詢對(duì)應(yīng)品牌即可。

后臺(tái)接口

頁面需要去后臺(tái)查詢品牌信息滚朵,我們自然需要提供:

controller

/**
  * 根據(jù)分類查詢品牌
  * @param cid
  * @return
  */
@GetMapping("cid/{cid}")
public ResponseEntity<List<Brand>> queryBrandByCategory(@PathVariable("cid") Long cid) {
    List<Brand> list = this.brandService.queryBrandByCategory(cid);
    if(list == null){
        new ResponseEntity<>(HttpStatus.NOT_FOUND);
    }
    return ResponseEntity.ok(list);
}

service

public List<Brand> queryBrandByCategory(Long cid) {
    return this.brandMapper.queryByCategoryId(cid);
}

mapper

根據(jù)分類查詢品牌有中間表冤灾,需要自己編寫Sql:

@Select("SELECT b.* FROM tb_category_brand cb LEFT JOIN tb_brand b ON cb.brand_id = b.id WHERE cb.category_id = #{cid}")
List<Brand> queryByCategoryId(Long cid);

1.4.商品規(guī)格參數(shù)

規(guī)格參數(shù)的查詢我們之前也已經(jīng)編寫過接口,因?yàn)樯唐芬?guī)格參數(shù)也是與商品分類綁定辕近,所以需要在商品分類變化后去查詢韵吨,我們也是通過watch監(jiān)控來實(shí)現(xiàn):

1529631056153

可以看到這里是根據(jù)商品分類id查詢規(guī)格參數(shù):SpecParam。我們之前寫過一個(gè)根據(jù)gid(分組id)來查詢規(guī)格參數(shù)的接口移宅,我們可以對(duì)其進(jìn)行擴(kuò)展:

改造查詢規(guī)格參數(shù)接口

我們?cè)谠瓉淼母鶕?jù) gid(規(guī)格組id)查詢規(guī)格參數(shù)的接口上归粉,添加一個(gè)參數(shù):cid,即商品分類id漏峰。

等一下糠悼, 考慮到以后可能還會(huì)根據(jù)是否搜索、是否為通用屬性等條件過濾浅乔,我們多添加幾個(gè)過濾條件:

@GetMapping("/params")
public ResponseEntity<List<SpecParam>> querySpecParam(
    @RequestParam(value="gid", required = false) Long gid,
    @RequestParam(value="cid", required = false) Long cid,
    @RequestParam(value="searching", required = false) Boolean searching,
    @RequestParam(value="generic", required = false) Boolean generic
    ){
        List<SpecParam> list =
                this.specificationService.querySpecParams(gid,cid,searching,generic);
        if(list == null || list.size() == 0){
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        return ResponseEntity.ok(list);
    }

改造service:

public List<SpecParam> querySpecParams(Long gid, Long cid, Boolean searching, Boolean generic) {
    SpecParam param = new SpecParam();
    param.setGroupId(gid);
    param.setCid(cid);
    param.setSearching(searching);
    param.setGeneric(generic);
    return this.specParamMapper.select(param);
}

如果param中有屬性為null绢掰,則不會(huì)吧屬性作為查詢條件,因此該方法具備通用性童擎,即可根據(jù)gid查詢滴劲,也可根據(jù)cid查詢。

測(cè)試


image

刷新頁面測(cè)試:

[圖片上傳失敗...(image-abff9f-1555491859890)]

1.5.SKU信息

Sku屬性是SPU下的每個(gè)商品的不同特征顾复,如圖:

1529656674978

當(dāng)我們填寫一些屬性后班挖,會(huì)在頁面下方生成一個(gè)sku表格,大家可以計(jì)算下會(huì)生成多少個(gè)不同屬性的Sku呢芯砸?

當(dāng)你選擇了上圖中的這些選項(xiàng)時(shí):

  • 顏色共2種:夜空黑萧芙,絢麗紅
  • 內(nèi)存共2種:4GB给梅,6GB
  • 機(jī)身存儲(chǔ)1種:64GB

此時(shí)會(huì)產(chǎn)生多少種SKU呢? 應(yīng)該是 2 * 2 * 1 = 4種双揪,這其實(shí)就是在求笛卡爾積动羽。

我們會(huì)在頁面下方生成一個(gè)sku的表格:

1528856353718

1.7.頁面表單提交

在sku列表的下方,有一個(gè)提交按鈕:

[圖片上傳失敗...(image-3f3a7a-1555491859890)]

并且綁定了點(diǎn)擊事件:

[圖片上傳失敗...(image-8f8986-1555491859890)]

點(diǎn)擊后會(huì)組織數(shù)據(jù)并向后臺(tái)提交:

[圖片上傳失敗...(image-4f782d-1555491859890)]

提交:

[圖片上傳失敗...(image-b00b0a-1555491859890)]

點(diǎn)擊提交渔期,查看控制臺(tái)提交的數(shù)據(jù)格式:

[圖片上傳失敗...(image-619613-1555491859890)]

  • 整體是一個(gè)json格式數(shù)據(jù)运吓,包含Spu表所有數(shù)據(jù):
    • brandId:品牌id
    • cid1、cid2疯趟、cid3:商品分類id
    • subTitle:副標(biāo)題
    • title:標(biāo)題
    • spuDetail:是一個(gè)json對(duì)象拘哨,代表商品詳情表數(shù)據(jù)
      • afterService:售后服務(wù)
      • description:商品描述
      • packingList:包裝列表
      • specialSpec:sku規(guī)格屬性模板
      • genericSpec:通用規(guī)格參數(shù)
    • skus:spu下的所有sku數(shù)組,元素是每個(gè)sku對(duì)象:
      • title:標(biāo)題
      • images:圖片
      • price:價(jià)格
      • stock:庫(kù)存
      • ownSpec:特有規(guī)格參數(shù)
      • indexes:特有規(guī)格參數(shù)的下標(biāo)

1.7.后臺(tái)實(shí)現(xiàn)

實(shí)體類

Spu

@Table(name = "tb_spu")
public class Spu {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long brandId;
    private Long cid1;// 1級(jí)類目
    private Long cid2;// 2級(jí)類目
    private Long cid3;// 3級(jí)類目
    private String title;// 標(biāo)題
    private String subTitle;// 子標(biāo)題
    private Boolean saleable;// 是否上架
    private Boolean valid;// 是否有效信峻,邏輯刪除用
    private Date createTime;// 創(chuàng)建時(shí)間
    private Date lastUpdateTime;// 最后修改時(shí)間
}

SpuDetail

@Table(name="tb_spu_detail")
public class SpuDetail {
    @Id
    private Long spuId;// 對(duì)應(yīng)的SPU的id
    private String description;// 商品描述
    private String specTemplate;// 商品特殊規(guī)格的名稱及可選值模板
    private String specifications;// 商品的全局規(guī)格屬性
    private String packingList;// 包裝清單
    private String afterService;// 售后服務(wù)
}

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;// 商品特殊規(guī)格的鍵值對(duì)
    private String indexes;// 商品特殊規(guī)格的下標(biāo)
    private Boolean enable;// 是否有效倦青,邏輯刪除用
    private Date createTime;// 創(chuàng)建時(shí)間
    private Date lastUpdateTime;// 最后修改時(shí)間
    @Transient
    private Integer stock;// 庫(kù)存
}

注意:這里保存了一個(gè)庫(kù)存字段,在數(shù)據(jù)庫(kù)中是另外一張表保存的盹舞,方便查詢产镐。

Stock

@Table(name = "tb_stock")
public class Stock {
    @Id
    private Long skuId;
    private Integer seckillStock;// 秒殺可用庫(kù)存
    private Integer seckillTotal;// 已秒殺數(shù)量
    private Integer stock;// 正常庫(kù)存
}

Controller

四個(gè)問題:

  • 請(qǐng)求方式:POST

  • 請(qǐng)求路徑:/goods

  • 請(qǐng)求參數(shù):Spu的json格式的對(duì)象,spu中包含spuDetail和Sku集合踢步。這里我們?cè)撛趺唇邮樟渍耍课覀冎岸x了一個(gè)SpuBo對(duì)象,作為業(yè)務(wù)對(duì)象贾虽。這里也可以用它逃糟,不過需要再擴(kuò)展spuDetail和skus字段:

    public class SpuBo extends Spu {
    
        @Transient
        String cname;// 商品分類名稱
        @Transient
        String bname;// 品牌名稱
        @Transient
        SpuDetail spuDetail;// 商品詳情
        @Transient
        List<Sku> skus;// sku列表
    }
    
  • 返回類型:無

代碼:

/**
 * 新增商品
 * @param spu
 * @return
 */
@PostMapping
public ResponseEntity<Void> saveGoods(@RequestBody Spu spu) {
    try {
        this.goodsService.save(spu);
        return new ResponseEntity<>(HttpStatus.CREATED);
    } catch (Exception e) {
        e.printStackTrace();
        return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

注意:通過@RequestBody注解來接收J(rèn)son請(qǐng)求

Service

這里的邏輯比較復(fù)雜,我們除了要對(duì)SPU新增以外蓬豁,還要對(duì)SpuDetail绰咽、Sku、Stock進(jìn)行保存

@Transactional
public void save(SpuBo spu) {
    // 保存spu
    spu.setSaleable(true);
    spu.setValid(true);
    spu.setCreateTime(new Date());
    spu.setLastUpdateTime(spu.getCreateTime());
    this.spuMapper.insert(spu);
    // 保存spu詳情
    spu.getSpuDetail().setSpuId(spu.getId());
    this.spuDetailMapper.insert(spu.getSpuDetail());

    // 保存sku和庫(kù)存信息
    saveSkuAndStock(spu.getSkus(), spu.getId());
}

private void saveSkuAndStock(List<Sku> skus, Long spuId) {
    for (Sku sku : skus) {
        if (!sku.getEnable()) {
            continue;
        }
        // 保存sku
        sku.setSpuId(spuId);
        // 初始化時(shí)間
        sku.setCreateTime(new Date());
        sku.setLastUpdateTime(sku.getCreateTime());
        this.skuMapper.insert(sku);

        // 保存庫(kù)存信息
        Stock stock = new Stock();
        stock.setSkuId(sku.getId());
        stock.setStock(sku.getStock());
        this.stockMapper.insert(stock);
    }
}

Mapper

都是通用Mapper地粪,略

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末取募,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蟆技,更是在濱河造成了極大的恐慌玩敏,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件质礼,死亡現(xiàn)場(chǎng)離奇詭異旺聚,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)眶蕉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門砰粹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人造挽,你說我怎么就攤上這事碱璃∨裕” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵嵌器,是天一觀的道長(zhǎng)肛真。 經(jīng)常有香客問我,道長(zhǎng)爽航,這世上最難降的妖魔是什么蚓让? 我笑而不...
    開封第一講書人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮岳掐,結(jié)果婚禮上凭疮,老公的妹妹穿的比我還像新娘饭耳。我一直安慰自己串述,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開白布寞肖。 她就那樣靜靜地躺著纲酗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪新蟆。 梳的紋絲不亂的頭發(fā)上觅赊,一...
    開封第一講書人閱讀 51,679評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音琼稻,去河邊找鬼吮螺。 笑死,一個(gè)胖子當(dāng)著我的面吹牛帕翻,可吹牛的內(nèi)容都是我干的鸠补。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼嘀掸,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼紫岩!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起睬塌,我...
    開封第一講書人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤泉蝌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后揩晴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體勋陪,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年硫兰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了粥鞋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瞄崇,死狀恐怖呻粹,靈堂內(nèi)的尸體忽然破棺而出壕曼,到底是詐尸還是另有隱情,我是刑警寧澤等浊,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布腮郊,位于F島的核電站,受9級(jí)特大地震影響筹燕,放射性物質(zhì)發(fā)生泄漏轧飞。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一撒踪、第九天 我趴在偏房一處隱蔽的房頂上張望过咬。 院中可真熱鬧,春花似錦制妄、人聲如沸掸绞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽衔掸。三九已至,卻和暖如春俺抽,著一層夾襖步出監(jiān)牢的瞬間敞映,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工磷斧, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留振愿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓弛饭,卻偏偏與公主長(zhǎng)得像冕末,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子孩哑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容