商品上架-功能实现(3)

1.在ProductConstant中添加ProductStatusEnum

package com.atguigu.common.constant;

/**
 * 商品属性类型枚举
 * @author zfh
 */
public class ProductConstant {
    public enum  AttrEnum{
        ATTR_TYPE_BASE(1,"基本属性"),ATTR_TYPE_SALE(0,"销售属性");
        private int code;
        private String msg;

        AttrEnum(int code,String msg){
            this.code = code;
            this.msg = msg;
        }

        public int getCode() {
            return code;
        }

        public String getMsg() {
            return msg;
        }
    }

    public enum ProductStatusEnum {
        NEW_SPU(0,"新建"),
        SPU_UP(1,"商品上架"),
        SPU_DOWN(2,"商品下架"),
        ;

        private int code;

        private String msg;

        public int getCode() {
            return code;
        }

        public String getMsg() {
            return msg;
        }

        ProductStatusEnum(int code, String msg) {
            this.code = code;
            this.msg = msg;
        }

    }
}

2.修改BizCodeEnume

package com.atguigu.common.exception;

/***
 * 错误码和错误信息定义类
 * 1. 错误码定义规则为5为数字
 * 2. 前两位表示业务场景,最后三位表示错误码。例如:100001。10:通用 001:系统未知异常
 * 3. 维护错误码后需要维护错误描述,将他们定义为枚举形式
 * 错误码列表:
 *  10: 通用
 *      001:参数格式校验
 *  11: 商品
 *  12: 订单
 *  13: 购物车
 *  14: 物流
 */
public enum BizCodeEnume {
    UNKNOW_EXCEPTION(10000,"系统未知异常"),
    VAILD_EXCEPTION(10001,"参数格式校验失败"),
    TO_MANY_REQUEST(10002,"请求流量过大,请稍后再试"),
    SMS_CODE_EXCEPTION(10002,"验证码获取频率太高,请稍后再试"),
    PRODUCT_UP_EXCEPTION(11000,"商品上架异常"),
    USER_EXIST_EXCEPTION(15001,"存在相同的用户"),
    PHONE_EXIST_EXCEPTION(15002,"存在相同的手机号"),
    NO_STOCK_EXCEPTION(21000,"商品库存不足"),
    LOGINACCT_PASSWORD_EXCEPTION(15003,"账号或密码错误")
    ;


    private int code;
    private String msg;
    BizCodeEnume(int code,String msg){
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

3.EsConstant

package com.atguigu.gulimall.search.constant;

/**
 * ES常量
 * @author zfh
 * @email hst1406959716@163.com
 * @date 2021-12-15 09:40:46
 */
public class EsConstant {

    //在es中的索引
    public static final String PRODUCT_INDEX = "gulimall_product";

    public static final Integer PRODUCT_PAGESIZE = 16;
}

4.在gulimall-search项目中新增ESSaveController

package com.atguigu.gulimall.search.controller;

import com.atguigu.common.exception.BizCodeEnume;
import com.atguigu.common.to.es.SkuEsModel;
import com.atguigu.common.utils.R;
import com.atguigu.gulimall.search.service.ProductSaveService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.List;

/**
 * ES保存
 * @author zfh
 * @email hst1406959716@163.com
 * @date 2021-12-15 09:40:46
 */
@RestController
@RequestMapping("/search/save")
public class ESSaveController {
    @Autowired
    private ProductSaveService productSaveService;

    /**
     * 上架商品
     * @param skuEsModels
     * @return
     */
    @PostMapping(value = "/product")
    public R productStatusUp(@RequestBody List<SkuEsModel> skuEsModels) {
        boolean status = false;
        try {
            status = productSaveService.productStatusUp(skuEsModels);
        } catch (IOException e) {
            //log.error("商品上架错误{}",e);
            return R.error(BizCodeEnume.PRODUCT_UP_EXCEPTION.getCode(),BizCodeEnume.PRODUCT_UP_EXCEPTION.getMsg());
        }

        if(status){
            return R.error(BizCodeEnume.PRODUCT_UP_EXCEPTION.getCode(),BizCodeEnume.PRODUCT_UP_EXCEPTION.getMsg());
        }else {
            return R.ok();
        }
    }
}

5.ProductSaveService

package com.atguigu.gulimall.search.service;

import com.atguigu.common.to.es.SkuEsModel;

import java.io.IOException;
import java.util.List;


public interface ProductSaveService {
    boolean productStatusUp(List<SkuEsModel> skuEsModels) throws IOException;
}

6.ProductSaveServiceImpl

package com.atguigu.gulimall.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.common.to.es.SkuEsModel;
import com.atguigu.gulimall.search.config.GulimallESConfiguration;
import com.atguigu.gulimall.search.constant.EsConstant;
import com.atguigu.gulimall.search.service.ProductSaveService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;


@Slf4j
@Service("productSaveService")
public class ProductSaveServiceImpl implements ProductSaveService {

    @Autowired
    private RestHighLevelClient esRestClient;

    @Override
    public boolean productStatusUp(List<SkuEsModel> skuEsModels) throws IOException {

        //1.在es中建立索引,建立号映射关系(doc/json/product-mapping.json)

        //2. 在ES中保存这些数据
        BulkRequest bulkRequest = new BulkRequest();
        for (SkuEsModel skuEsModel : skuEsModels) {
            //构造保存请求
            IndexRequest indexRequest = new IndexRequest(EsConstant.PRODUCT_INDEX);
            indexRequest.id(skuEsModel.getSkuId().toString());
            String jsonString = JSON.toJSONString(skuEsModel);
            indexRequest.source(jsonString, XContentType.JSON);

            bulkRequest.add(indexRequest);
        }


        BulkResponse bulk = esRestClient.bulk(bulkRequest, GulimallESConfiguration.COMMON_OPTIONS);


        //TODO 如果批量错误
        boolean hasFailures = bulk.hasFailures();
        List<String> collect = Arrays.asList(bulk.getItems()).stream().map(item -> {
            return item.getId();
        }).collect(Collectors.toList());
        log.info("商品上架完成:{}",collect);

        return hasFailures;
    }
}

7.ES远程调用

在gulimall-product项目feign包下新建SearchFeignService

package com.atguigu.gulimall.product.feign;

import com.atguigu.common.to.es.SkuEsModel;
import com.atguigu.common.utils.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.List;

/**
 * ES远程调用
 * @author zfh
 * @email hst1406959716@163.com
 * @date 2021-12-15 09:50:46
 */
@FeignClient("gulimall-search")
public interface SearchFeignService {
    @PostMapping(value = "/search/save/product")
    R productStatusUp(@RequestBody List<SkuEsModel> skuEsModels);
}

8.SpuInfoDao中新增updaSpuStatus

package com.atguigu.gulimall.product.dao;

import com.atguigu.gulimall.product.entity.SpuInfoEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

/**
 * spu信息
 * 
 * @author zfh
 * @email hst1406959716@163.com
 * @date 2021-10-14 09:40:46
 */
@Mapper
public interface SpuInfoDao extends BaseMapper<SpuInfoEntity> {
    void updaSpuStatus(@Param("spuId") Long spuId, @Param("code") int code);
}

9.SpuInfoDao.xml

 <update id="updaSpuStatus">
        UPDATE pms_spu_info SET publish_status = #{code} ,update_time = NOW() WHERE id = #{spuId}
 </update>

10.SpuInfoServiceImpl中up方法实现

 /**
  * 商品上架
  * @param spuId
  */
  @Override
  public void up(Long spuId) {
      //1.查询当前spuId对应的sku
      List<SkuInfoEntity> skuInfoEntityList = skuInfoService.getSkusBySpuId(spuId);
      List<Long> spuIdList = skuInfoEntityList.stream().map(SkuInfoEntity::getSkuId).collect(Collectors.toList());

      //4.查询当前sku所有可被检索的规格属性
      List<ProductAttrValueEntity> productAttrValueEntityList = productAttrValueService.baseAttrListForSPU(spuId);
      List<Long> attrIds = productAttrValueEntityList.stream().map(productAttrValue -> {
          return productAttrValue.getAttrId();
      }).collect(Collectors.toList());
      //查找可被检索的attrId
      List<Long> searchAttrIds = attrService.selectSearchAttrIds(attrIds);
      HashSet<Long> attrIdSet = new HashSet<>(searchAttrIds);
//        Set<Long> attrIdSet = searchAttrIds.stream().collect(Collectors.toSet());

      List<SkuEsModel.Attrs> attrsList = productAttrValueEntityList.stream().filter(item ->
              attrIdSet.contains(item.getAttrId())
      ).map(item -> {
          SkuEsModel.Attrs attrs = new SkuEsModel.Attrs();
          BeanUtils.copyProperties(item, attrs);
          return attrs;
      }).collect(Collectors.toList());

      Map<Long, Boolean> stockMap = null;
      try{
          //1.发送远程调用,库存系统查询是否有库存
          R skuHasStock = wareFeignService.getSkuHasStock(spuIdList);
          TypeReference<List<SkuHasStockVo>> typeReference = new TypeReference<List<SkuHasStockVo>>() {
          };
          stockMap = skuHasStock.getData(typeReference).stream().collect(Collectors.toMap(SkuHasStockVo::getSkuId, item -> item.getHasStock()));
      }catch (Exception e){
          log.error("库存服务查询出现异常: " + e.getMessage());
      }

      //封装每个sku的信息
      Map<Long, Boolean> finalStockMap = stockMap;
      List<SkuEsModel> skuEsModelList = skuInfoEntityList.stream().map(skuInfoEntity -> {
          SkuEsModel skuEsModel = new SkuEsModel();
          BeanUtils.copyProperties(skuInfoEntity,skuEsModel);
          //设置skuPrice,skuImg
          skuEsModel.setSkuPrice(skuInfoEntity.getPrice());
          skuEsModel.setSkuImg(skuInfoEntity.getSkuDefaultImg());

          //设置库存
          if(finalStockMap == null){
              skuEsModel.setHasStock(true);
          }else{
              skuEsModel.setHasStock(finalStockMap.get(skuInfoEntity.getSkuId()));
          }

          //2.热度评分
          skuEsModel.setHotScore(0L); //暂时设为0  TODO

          //3.查询品牌和分类的名字
          BrandEntity brandEntity = brandService.getById(skuEsModel.getBrandId());
          skuEsModel.setBrandName(brandEntity.getName());
          skuEsModel.setBrandImg(brandEntity.getLogo());

          CategoryEntity categoryEntity = categoryService.getById(skuEsModel.getCatalogId());
          skuEsModel.setCatalogName(categoryEntity.getName());

          //设置检索属性
          skuEsModel.setAttrs(attrsList);
          return skuEsModel;
      }).collect(Collectors.toList());


      //5.将数据发送给es进行保存
      R r = searchFeignService.productStatusUp(skuEsModelList);
      if (r.getCode() == 0) {
          //远程调用成功
          //6、修改当前spu的状态
          this.baseMapper.updaSpuStatus(spuId, ProductConstant.ProductStatusEnum.SPU_UP.getCode());
      } else {
          //远程调用失败
          //7、重复调用?接口幂等性:重试机制
          /**
           * feign调用流程
           *
           * 1.构造请求数据,将对象转json
           * RequestTemplate template = this.buildTemplateFromArgs.create(argv);
           * 2.发送请求进行执行(执行成功会解码响应数据)
           * this.executeAndDecode(template, options);
           * 3.
           * retryer.continueOrPropagate(e);
           */
      }
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值