Authored by 胡古飞

重构ProductSizesLogicService逻辑【添加实时计算断码率的逻辑】

... ... @@ -4,11 +4,9 @@ package com.yoho.search.dal.model;
* Created by wangnan on 2016/6/30.
*/
public class ProductSizes {
private Integer productId;
private String sizeIds;
private String sizeNames;
private Integer storageNum;
private double breakSizePercent = 100;
protected Integer productId;
protected Integer storageNum;
protected String sizeIds;
public Integer getProductId() {
return productId;
... ... @@ -33,21 +31,4 @@ public class ProductSizes {
public void setStorageNum(Integer storageNum) {
this.storageNum = storageNum;
}
public String getSizeNames() {
return sizeNames;
}
public void setSizeNames(String sizeNames) {
this.sizeNames = sizeNames;
}
public double getBreakSizePercent() {
return breakSizePercent;
}
public void setBreakSizePercent(double breakSizePercent) {
this.breakSizePercent = breakSizePercent;
}
}
... ...
... ... @@ -4,7 +4,6 @@
<resultMap id="ProductSizes" type="com.yoho.search.dal.model.ProductSizes">
<result column="product_id" property="productId" jdbcType="INTEGER"/>
<result column="size_ids" property="sizeIds" jdbcType="VARCHAR"/>
<result column="sales_num" property="salesNum" jdbcType="INTEGER"/>
<result column="storage_num" property="storageNum" jdbcType="INTEGER"/>
</resultMap>
<select id="getProductSizes" resultMap="ProductSizes"
... ...
package com.yoho.search.consumer.index.increment;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSONArray;
import com.yoho.search.consumer.service.base.GoodsService;
import com.yoho.search.consumer.service.base.SizeService;
import com.yoho.search.consumer.service.base.StorageService;
import com.yoho.search.consumer.service.bo.ProductGoodsBO;
import com.yoho.search.consumer.service.bo.ProductSizesBO;
import com.yoho.search.consumer.service.logic.productIndex.ProductGoodsLogicService;
import com.yoho.search.consumer.service.logic.productIndex.ProductSizesLogicService;
import com.yoho.search.dal.model.Storage;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Created by ginozhang on 2017/2/8.
... ... @@ -39,54 +38,26 @@ public abstract class AbstractStorageRelatedMqListener extends AbstractMqListene
private ProductSizesLogicService productSizesLogicService;
protected void fillStorageNumAndSizeInfo(Integer productId, Map<String, Object> indexData) {
List<Storage> storageList = storageService.getStoragesByProductId(productId);
// 过滤掉下架的storage
if (CollectionUtils.isNotEmpty(storageList)) {
storageList = storageList.stream().filter(storage -> Integer.valueOf(1).equals(storage.getStatus())).collect(Collectors.toList());
}
int totalSizeCount = storageList.size();
// 过滤掉无库存的storage
if (CollectionUtils.isNotEmpty(storageList)) {
storageList = storageList.stream().filter(storage -> storage.getStorageNum() != null && storage.getStorageNum().intValue() > 0).collect(Collectors.toList());
}
int effectiveSizeCount = storageList.size();
double breakSizePercent = productSizesLogicService.getBreakSizePercent(totalSizeCount,effectiveSizeCount);
if (CollectionUtils.isEmpty(storageList)) {
List<ProductSizesBO> productSizesBOList = productSizesLogicService.getData(Arrays.asList(productId));
if (productSizesBOList == null || productSizesBOList.isEmpty()) {
indexData.put("storageNum", 0);
indexData.put("isSoonSoldOut", "Y");
indexData.put("isSoldOut", "Y");
indexData.put("soldOut", 0);
indexData.put("sizeIds", null);
indexData.put("sizeNames", null);
indexData.put("sizeIds", "");
indexData.put("sizeNames", "");
indexData.put("breakSizePercent", 100);
} else {
int storageNum = 0;
Set<String> sizeSet = new HashSet<String>();
for (Storage stor : storageList) {
storageNum += stor.getStorageNum();
if (stor.getGoodsDimensionId() != null) {
sizeSet.add(stor.getGoodsDimensionId() + "");
}
}
indexData.put("storageNum", storageNum);
indexData.put("isSoonSoldOut", storageNum <= 2 ? "Y" : "N");
indexData.put("isSoldOut", storageNum == 0 ? "Y" : "N");
indexData.put("soldOut", storageNum == 0 ? 0 : 1);
if (!sizeSet.isEmpty()) {
// 设置尺码信息
indexData.put("sizeIds", StringUtils.join(sizeSet, ","));
indexData.put("sizeNames", sizeService.getSizeNamesBySizeIds(sizeSet.stream().map(Integer::valueOf).collect(Collectors.toList())));
} else {
indexData.put("sizeIds", null);
indexData.put("sizeNames", null);
}
indexData.put("breakSizePercent", breakSizePercent);
}
ProductSizesBO productSizesBO = productSizesBOList.get(0);
indexData.put("storageNum", productSizesBO.getStorageNum());
indexData.put("isSoonSoldOut", productSizesBO.getIsSoonSoldOut());
indexData.put("isSoldOut", productSizesBO.getIsSoldOut());
indexData.put("soldOut", productSizesBO.getSoldOut());
indexData.put("sizeIds", productSizesBO.getSizeIds());
indexData.put("sizeNames", productSizesBO.getSizeNames());
indexData.put("breakSizePercent", productSizesBO.getBreakSizePercent());
}
protected void fillColor(Map<String, Object> indexData, Integer productId) {
Set<String> colorIdSet = new HashSet<String>();
Set<String> colorNameSet = new HashSet<String>();
... ...
package com.yoho.search.consumer.service.bo;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import com.yoho.search.dal.model.ProductSizes;
public class ProductSizesBO extends ProductSizes {
private String sizeNames;
private double breakSizePercent;
public ProductSizesBO(ProductSizes productSizes) {
this.productId = productSizes.getProductId();
this.storageNum = productSizes.getStorageNum();
this.sizeIds = productSizes.getSizeIds();
}
public Set<Integer> getSizeIdSet() {
Set<Integer> results = new HashSet<Integer>();
if (StringUtils.isBlank(this.sizeIds)) {
return results;
}
String[] sizeIdArray = this.sizeIds.split(",");
for (String sizeId : sizeIdArray) {
try {
results.add(Integer.valueOf(sizeId));
} catch (Exception e) {
}
}
return results;
}
public void setSizeNames(String sizeNames) {
this.sizeNames = sizeNames;
}
public String getSizeNames() {
return sizeNames;
}
public double getBreakSizePercent() {
return breakSizePercent;
}
public void setBreakSizePercent(double breakSizePercent) {
this.breakSizePercent = breakSizePercent;
}
public Integer getSoldOut() {
return storageNum == null || storageNum == 0 ? 0 : 1;
}
public String getIsSoldOut() {
return storageNum == null || storageNum == 0 ? "Y" : "N";
}
public String getIsSoonSoldOut() {
return storageNum == null || storageNum <= 2 ? "Y" : "N";
}
}
... ...
package com.yoho.search.consumer.service.logic.productIndex;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.yoho.search.consumer.service.bo.ProductSizesBO;
import com.yoho.search.dal.GoodsMapper;
import com.yoho.search.dal.ProductSizesMapper;
import com.yoho.search.dal.SizeMapper;
... ... @@ -9,13 +22,6 @@ import com.yoho.search.dal.model.ProductSizes;
import com.yoho.search.dal.model.Size;
import com.yoho.search.dal.model.Storage;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
/**
* Created by wangnan on 2016/6/30.
*/
... ... @@ -26,13 +32,10 @@ public class ProductSizesLogicService {
@Autowired
private GoodsMapper goodsMapper;
@Autowired
private StorageMapper storageMapper;
@Autowired
private SizeMapper sizeMapper;
@Autowired
private ProductSizesMapper productSizesMapper;
... ... @@ -41,42 +44,48 @@ public class ProductSizesLogicService {
*
* @return
*/
public List<ProductSizes> getData(List<Integer> ids) {
public List<ProductSizesBO> getData(List<Integer> productIds) {
// 获取ProductId对应的上架的goodsId列表
List<Goods> goodsList = goodsMapper.getByIdsAndStatus(ids);
List<Goods> goodsList = goodsMapper.getByIdsAndStatus(productIds);
if (CollectionUtils.isEmpty(goodsList)) {
return new ArrayList<>();
}
// 获取goodsId对应得Storage列表
List<Integer> goodsIdList = goodsList.parallelStream().map(Goods::getId).collect(Collectors.toList());
List<Storage> storageList = storageMapper.getByGoodsIds(goodsIdList);
if (CollectionUtils.isEmpty(storageList)) {
List<Storage> oldStorageList = storageMapper.getByGoodsIds(goodsIdList);
if (CollectionUtils.isEmpty(oldStorageList)) {
return new ArrayList<>();
}
// 过滤掉下架的sku
storageList = storageList.parallelStream().filter(storageItem -> VALID_STATUS.equals(storageItem.getStatus())).collect(Collectors.toList());
// 计算每个skn则总尺码数
Map<Integer, Integer> sknSizeCountMap = new HashMap<Integer, Integer>();
for (Storage storage : storageList) {
// 过滤状态是上架的且有库存的Goods和Storage
Map<Integer,Set<Integer>> productValidStatusSizeIds = new HashMap<Integer, Set<Integer>>();
Map<Integer,Set<Integer>> productHasStorageSizeIds = new HashMap<Integer, Set<Integer>>();
List<Storage> realEffectiveStorageList = new ArrayList<Storage>();
for (Storage storage : oldStorageList) {
Integer productId = storage.getProductId();
int count = sknSizeCountMap.getOrDefault(productId, 0);
sknSizeCountMap.put(productId, count + 1);
Integer sizeId = storage.getGoodsDimensionId();
//处理未下架的sku
if(!VALID_STATUS.equals(storage.getStatus())){
continue;
}
this.addToMap(productId, sizeId, productValidStatusSizeIds);
//处理有库存的sku
if(storage.getStorageNum() == null || storage.getStorageNum().intValue() <= 0){
continue;
}
this.addToMap(productId, sizeId, productHasStorageSizeIds);
realEffectiveStorageList.add(storage);
}
// 过滤状态是上架的且有库存的Goods和Storage
storageList = storageList.parallelStream().filter(storageItem -> storageItem.getStorageNum() != null && storageItem.getStorageNum().intValue() > 0)
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(storageList)) {
if (CollectionUtils.isEmpty(realEffectiveStorageList)) {
return new ArrayList<>();
}
// 根据上架的GoodsId筛选Storage数据
Set<Integer> validGoodsIdSet = goodsIdList.stream().collect(Collectors.toSet());
List<Integer> validErpSkuIdList = new ArrayList<>();
for (Storage s : storageList) {
for (Storage s : realEffectiveStorageList) {
if (validGoodsIdSet.contains(s.getGoodsId())) {
validErpSkuIdList.add(s.getErpSkuId());
}
... ... @@ -85,55 +94,69 @@ public class ProductSizesLogicService {
if (validErpSkuIdList == null || validErpSkuIdList.isEmpty()) {
return new ArrayList<>();
}
List<ProductSizes> productSizesList = productSizesMapper.getProductSizes(validErpSkuIdList);
if (CollectionUtils.isEmpty(productSizesList)) {
// 从数据库中获取真实库存
List<ProductSizes> productSizesFromDb = productSizesMapper.getProductSizes(validErpSkuIdList);
if (CollectionUtils.isEmpty(productSizesFromDb)) {
return new ArrayList<>();
}
// 设置尺码名称,多个名称之间使用逗号分隔
Set<Integer> sizeIdSet = new HashSet<>();
for (ProductSizes ps : productSizesList) {
String sizeArray[] = ps.getSizeIds().split(",");
if (sizeArray != null) {
for (int i = 0; i < sizeArray.length; i++) {
sizeIdSet.add(Integer.valueOf(sizeArray[i]));
}
}
// 构造返回结果对象
List<ProductSizesBO> results = new ArrayList<ProductSizesBO>();
for (ProductSizes productSizes : productSizesFromDb) {
results.add(new ProductSizesBO(productSizes));
}
// 获取尺码信息
Set<Integer> sizeIdSet = new HashSet<>();
for (ProductSizesBO productSizesBO : results) {
sizeIdSet.addAll(productSizesBO.getSizeIdSet());
}
List<Size> sizeList = sizeMapper.getByIds(sizeIdSet.stream().collect(Collectors.toList()));
// 填充尺码信息和断码率
if (CollectionUtils.isNotEmpty(sizeList)) {
Map<Integer, String> sizeMap = sizeList.stream().collect(Collectors.toMap(Size::getId, Size::getSizeName));
for (ProductSizes ps : productSizesList) {
String sizeArray[] = ps.getSizeIds().split(",");
// 计算断码率
double breakSizePercent = this.getBreakSizePercent(sknSizeCountMap.getOrDefault(ps.getProductId(), 0), sizeArray == null ? 0 : sizeArray.length);
ps.setBreakSizePercent(breakSizePercent);
// 填充尺码名称
if (sizeArray != null) {
for (int i = 0; i < sizeArray.length; i++) {
if (i == 0) {
ps.setSizeNames(sizeMap.get(Integer.valueOf(sizeArray[i])) + ",");
} else {
ps.setSizeNames(ps.getSizeNames() + sizeMap.get(Integer.valueOf(sizeArray[i])) + ",");
}
}
}
Map<Integer, String> sizeNameMap = sizeList.stream().collect(Collectors.toMap(Size::getId, Size::getSizeName));
//填充其他信息
for (ProductSizesBO productSizesBO : results) {
// 填充尺码名称
productSizesBO.setSizeNames(this.getSizeNames(productSizesBO.getSizeIdSet(), sizeNameMap));
// 填充断码率
Set<Integer> validStatusSizeIds = productValidStatusSizeIds.getOrDefault(productSizesBO.getProductId(), new HashSet<Integer>());
Set<Integer> hasStorageSizeIds = productHasStorageSizeIds.getOrDefault(productSizesBO.getProductId(), new HashSet<Integer>());
productSizesBO.setBreakSizePercent(this.getBreakSizePercent(validStatusSizeIds, hasStorageSizeIds));
}
return results;
}
private<K,V> void addToMap(K key,V value,Map<K,Set<V>> map){
Set<V> values = map.get(key);
if(values==null){
values = new HashSet<V>();
map.put(key, values);
}
values.add(value);
}
private String getSizeNames(Set<Integer> sizeIds,Map<Integer, String> sizeNameMap){
StringBuilder results = new StringBuilder();
for (Integer sizeId : sizeIds) {
String sizeName = sizeNameMap.get(sizeId);
if(sizeName==null){
continue;
}
results.append(",").append(sizeName);
}
return productSizesList;
return results.toString().replaceFirst(",", "");
}
public double getBreakSizePercent(int totalSizeCount, int effectiveSizeCount) {
if (totalSizeCount == 0 || effectiveSizeCount == 0) {
private double getBreakSizePercent(Set<Integer> validStatusSizeIds,Set<Integer> hasStorageSizeIds) {
if (validStatusSizeIds == null || validStatusSizeIds.isEmpty()) {
return 100d;
}
if (hasStorageSizeIds == null || hasStorageSizeIds.isEmpty()) {
return 100d;
}
return 100d * (totalSizeCount - effectiveSizeCount) / totalSizeCount;
int totalSizeCount = validStatusSizeIds.size();
int hasStorageSizeCount = hasStorageSizeIds.size();
return 100d * (totalSizeCount - hasStorageSizeCount) / totalSizeCount;
}
}
... ...
package com.yoho.search.consumer.service.logic.productIndex.viewBuilder;
import com.yoho.search.consumer.service.bo.ProductIndexBO;
import com.yoho.search.consumer.service.logic.productIndex.ProductSizesLogicService;
import com.yoho.search.dal.model.ProductSizes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.yoho.search.consumer.service.bo.ProductIndexBO;
import com.yoho.search.consumer.service.bo.ProductSizesBO;
import com.yoho.search.consumer.service.logic.productIndex.ProductSizesLogicService;
import com.yoho.search.dal.model.ProductSizes;
/**
* Created by wangnan on 2017/1/6.
*/
... ... @@ -25,32 +27,28 @@ public class ProductSizesBuilder implements ViewBuilder {
*/
@Override
public void build(List<ProductIndexBO> productIndexBOs, List<Integer> ids, List<Integer> skns) {
List<ProductSizes> productSizess = productSizesLogicService.getData(ids);
Map<Integer, ProductSizes> productSizesMap = productSizess.stream().parallel().collect(Collectors.toMap(ProductSizes::getProductId, (p) -> p));
List<ProductSizesBO> productSizess = productSizesLogicService.getData(ids);
Map<Integer, ProductSizesBO> productSizesMap = productSizess.stream().parallel().collect(Collectors.toMap(ProductSizes::getProductId, (p) -> p));
for (ProductIndexBO productIndexBO : productIndexBOs) {
ProductSizes productSizes = productSizesMap.get(productIndexBO.getProductId());
productIndexBO.setIsSoonSoldOut("N");
productIndexBO.setIsSoldOut("N");
// 设置默认值
productIndexBO.setStorageNum(BigDecimal.valueOf(0));
productIndexBO.setIsSoonSoldOut("Y");
productIndexBO.setIsSoldOut("Y");
productIndexBO.setSoldOut(1);
productIndexBO.setBreakSizePercent(100);
if (productSizes != null) {
productIndexBO.setStorageNum(BigDecimal.valueOf(productSizes.getStorageNum()));
if (productSizes.getStorageNum() <= 2) {
productIndexBO.setIsSoonSoldOut("Y");
}
if (productSizes.getStorageNum() == 0) {
productIndexBO.setIsSoldOut("Y");
productIndexBO.setSoldOut(0);
}
productIndexBO.setSizeIds(productSizes.getSizeIds());
productIndexBO.setSizeNames(productSizes.getSizeNames());
productIndexBO.setBreakSizePercent(productSizes.getBreakSizePercent());
} else {
productIndexBO.setStorageNum(BigDecimal.valueOf(0));
productIndexBO.setIsSoldOut("Y");
productIndexBO.setSoldOut(0);
productIndexBO.setBreakSizePercent(100);
// fill property from ProductSizesBO
ProductSizesBO productSizesBO = productSizesMap.get(productIndexBO.getProductId());
if (productSizesBO != null) {
productIndexBO.setStorageNum(BigDecimal.valueOf(productSizesBO.getStorageNum()));
productIndexBO.setIsSoonSoldOut(productSizesBO.getIsSoonSoldOut());
productIndexBO.setIsSoldOut(productSizesBO.getIsSoldOut());
productIndexBO.setSoldOut(productSizesBO.getSoldOut());
productIndexBO.setSizeIds(productSizesBO.getSizeIds());
productIndexBO.setSizeNames(productSizesBO.getSizeNames());
productIndexBO.setBreakSizePercent(productSizesBO.getBreakSizePercent());
}
}
}
}
... ...