Authored by mali

闲鱼详情

... ... @@ -21,6 +21,8 @@ public enum UfoProductCacheKeyEnum {
PRODUCT_STORAGE_INFO_KEY("ufo:product:storageInfo:", "商品SKU信息", 15, TimeUnit.MINUTES),
SIZE_LIST_CACHE_KEY("ufo:product:sizeList:", "尺码列表", 15, TimeUnit.MINUTES),
STORAGE_PRICE_IN_STOCK_INFO_KEY("ufo:product:storagePrice:inStock", "商品现货价格信息", 5, TimeUnit.MINUTES),
;
private String cacheKey;
... ...
... ... @@ -21,6 +21,7 @@ import com.yohobuy.ufo.model.response.StorageInfoResp;
import com.yohobuy.ufo.model.response.StorageCheckResp;
import com.yohoufo.common.ApiResponse;
import com.yohoufo.common.alarm.EventBusPublisher;
import com.yohoufo.common.annotation.IgnoreSession;
import com.yohoufo.common.annotation.IgnoreSignature;
import com.yohoufo.common.cache.Cachable;
... ... @@ -29,12 +30,14 @@ import com.yohoufo.common.caller.UfoServiceCaller;
import com.yohoufo.common.utils.StringUtil;
import com.yohoufo.dal.product.model.Goods;
import com.yohoufo.dal.product.model.StoragePrice;
import com.yohoufo.product.event.StoragePriceUpdateEvent;
import com.yohoufo.product.model.SkupInfo;
import com.yohoufo.product.response.*;
import com.yohoufo.product.service.ProductService;
import com.yohoufo.product.service.impl.ProductBatchService;
import com.yohoufo.product.service.impl.ProductPoolService;
import com.yohoufo.product.service.impl.SeekToBuyStorageService;
import com.yohoufo.product.service.impl.StoragePriceService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
... ... @@ -74,6 +77,9 @@ public class ProductController {
@Autowired
private ConfigReader configReader;
@Autowired
private StoragePriceService storagePriceService;
private static final String LIMIT_PRODUCT_TIP = "很抱歉通知您,您现在还不具备销售此商品的资质。我们需要您提供完整的商品来源凭证,诸如购买单据、发票等,确保您的货源稳定可靠,请将以上资料、联系手机等相关信息通过邮箱发送至luyan.qian@yoho.cn,我们的工作人员审核通过后会联系您并为您添加出售资质权限,谢谢!";
... ... @@ -507,6 +513,9 @@ public class ProductController {
// 商品详情:数量
Integer productId = sp.getProductId();
LOG.info("clearCache queryProductDetailById skup = {}, ", skup);
storagePriceService.publishPriceUpdateEvent(productId);
cacheAop.clearCache(
ProductController.class.getMethod("queryProductDetailById", new Class[]{Integer.class}),
new Object[]{productId});
... ... @@ -565,6 +574,9 @@ public class ProductController {
LOG.info("in clearProductDetailCache productId = {}", productId);
// 商品详情:数量
LOG.info("clearCache queryProductDetailById productId = {}, ", productId);
storagePriceService.publishPriceUpdateEvent(productId);
cacheAop.clearCache(
ProductController.class.getMethod("queryProductDetailById", new Class[]{Integer.class}),
new Object[]{productId});
... ... @@ -592,6 +604,9 @@ public class ProductController {
if (CollectionUtils.isNotEmpty(productIdList)) {
for (Integer productId : productIdList) {
LOG.info("Batch clearCache queryProductDetailById productId = {}, ", productId);
storagePriceService.publishPriceUpdateEvent(productId);
//商品详情
cacheAop.clearCache(
ProductController.class.getMethod("queryProductDetailById", new Class[]{Integer.class}),
... ...
package com.yohoufo.product.event;
import com.yohoufo.common.alarm.Event;
import java.util.function.Function;
/**
* Created by li.ma on 2019/9/25.
*/
public abstract class ProductAsyncEvent<T extends Event, R> extends Event{
private Function<ProductAsyncEvent, R> function;
public ProductAsyncEvent(Function<ProductAsyncEvent, R> function){
this.function = function;
}
public R accept(){
return function.apply(getAsyncEvent());
}
abstract ProductAsyncEvent getAsyncEvent();
}
\ No newline at end of file
... ...
package com.yohoufo.product.event;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.util.function.Function;
/**
* Created by li.ma on 2019/9/25.
*/
@Builder
public class StoragePriceUpdateEvent extends ProductAsyncEvent {
@Getter
@Setter
private Integer productId;
@Getter@Setter
private Integer storageId;
@Getter@Setter
private Integer skup;
public StoragePriceUpdateEvent(Function<StoragePriceUpdateEvent, Boolean> function) {
super(function);
}
@Override
ProductAsyncEvent getAsyncEvent() {
return this;
}
}
\ No newline at end of file
... ...
package com.yohoufo.product.service.handler;
import com.google.common.eventbus.Subscribe;
import com.yohoufo.common.alarm.IEventHandler;
import com.yohoufo.product.event.ProductAsyncEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* 异步处理
*/
@Component
public class ProductAsyncHandler implements IEventHandler<ProductAsyncEvent> {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Override
@Subscribe
public void handle(ProductAsyncEvent event) {
logger.info("in ProductAsyncHandler handle ProductAsyncEvent {}", event);
event.accept();
}
}
\ No newline at end of file
... ...
... ... @@ -10,6 +10,8 @@ import com.yohoufo.dal.product.model.*;
import com.yohoufo.product.cache.UfoProductCacheKeyEnum;
import com.yohoufo.product.cache.UfoProductCacheService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
... ... @@ -25,6 +27,8 @@ import java.util.stream.Collectors;
*/
@Service
public class GoodsService {
private final static Logger LOGGER = LoggerFactory.getLogger(GoodsService.class);
@Autowired
private GoodsMapper goodsMapper;
... ... @@ -37,6 +41,7 @@ public class GoodsService {
public List<GoodsBO> getGoodsList(Integer productId) {
List<GoodsBO> goodsCacheList = productCacheService.getListCacheByString(UfoProductCacheKeyEnum.PRODUCT_GOODS_INFO_KEY, GoodsBO.class, productId);
if (null != goodsCacheList) {
LOGGER.info("goodsCacheList is cache hit, productId is {}", productId);
return goodsCacheList;
}
... ...
package com.yohoufo.product.service.impl;
import com.yohoufo.common.exception.UfoServiceException;
import java.util.Objects;
/**
* Created by li.ma on 2019/9/25.
*/
public class ProductCheckService {
public static void checkNull(Object value, int code, String errDesc) {
if (Objects.isNull(value)) {
throw new UfoServiceException(code, errDesc);
}
}
}
... ...
... ... @@ -13,6 +13,8 @@ import com.yohoufo.product.cache.UfoProductCacheService;
import com.yohoufo.product.service.cache.BrandCacheService;
import com.yohoufo.product.service.cache.BrandSeriesCacheService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
... ... @@ -27,6 +29,8 @@ import java.util.stream.Collectors;
*/
@Service
public class ProductHelpService {
private final static Logger LOGGER = LoggerFactory.getLogger(ProductHelpService.class);
@Autowired
private ProductMapper productMapper;
... ... @@ -51,6 +55,7 @@ public class ProductHelpService {
productInfo.setGender(getGenderName(product.getGender()));
productInfo.setSaleTime((product.getSaleTime() == null || product.getSaleTime().equals(0)) ? "0" : DateUtil.getDateString(product.getSaleTime(), DateUtil.YYYY_MM_DD_DOT));
productInfo.setOfferPrice(product.getOfferPrice());
productInfo.setLeastPrice(null);
return productInfo;
}
... ... @@ -79,21 +84,25 @@ public class ProductHelpService {
public Product selectByIdCache(Integer productId) {
Product productCacheInfo = productCacheService.getCacheByString(UfoProductCacheKeyEnum.PRODUCT_INFO_KEY, Product.class, productId);
if (null == productCacheInfo) {
productCacheInfo = productMapper.selectByPrimaryKey(productId);
productCacheService.setCacheByString(UfoProductCacheKeyEnum.PRODUCT_INFO_KEY, productCacheInfo, productId);
if (!Objects.isNull(productCacheInfo)) {
LOGGER.info("product is cache hit, productId is {}", productId);
return productCacheInfo;
}
productCacheInfo = productMapper.selectByPrimaryKey(productId);
productCacheService.setCacheByString(UfoProductCacheKeyEnum.PRODUCT_INFO_KEY, productCacheInfo, productId);
return productCacheInfo;
}
public void setBrand(ProductInfo productInfo, Integer brandId) {
public ProductHelpService setBrand(ProductInfo productInfo, Integer brandId) {
String brandName = Optional.ofNullable(brandId).map(brandCacheService::queryByBrandId).map(Brand::getBrandName).orElse("");
productInfo.setBrandName(brandName);
return this;
}
public void setSeries(ProductInfo productInfo, Integer seriesId) {
public ProductHelpService setSeries(ProductInfo productInfo, Integer seriesId) {
String brandSeriesName = Optional.ofNullable(seriesId).map(brandSeriesCacheService::queryByBrandSeriesId).map(BrandSeries::getSeriesName).orElse("");
productInfo.setSeriesName(brandSeriesName);
return this;
}
/**
... ...
... ... @@ -13,6 +13,7 @@ import com.yohobuy.ufo.model.request.product.ProductRequestBo;
import com.yohobuy.ufo.model.response.StorageCheckResp;
import com.yohobuy.ufo.model.response.store.StoreInfoBo;
import com.yohoufo.common.ApiResponse;
import com.yohoufo.common.exception.UfoServiceException;
import com.yohoufo.common.utils.OrikaUtils;
import com.yohoufo.dal.product.*;
import com.yohoufo.dal.product.model.*;
... ... @@ -2245,31 +2246,30 @@ public class ProductServiceImpl implements ProductService {
*/
public ProductDetailResp queryProductDetail3ById(Integer productId) {
Product product = productHelpService.selectByIdCache(productId);
ProductDetailResp productDetailResp = new ProductDetailResp();
if (product != null) {
ProductInfo productInfo = productHelpService.convertProductInfo(product);
productHelpService.setBrand(productInfo, product.getBrandId());
productHelpService.setSeries(productInfo, product.getSeriesId());
productInfo.setLeastPrice(null);
List<GoodsBO> goodsBOList = goodsService.getGoodsList(product.getId());
if (!CollectionUtils.isEmpty(goodsBOList)) {
List<GoodsSize> goodsSizes = storageService.getSizeList(productId, goodsBOList.get(0));
ProductCheckService.checkNull(product, 400, "商品不存在");
storagePriceService.setStoragePrice(goodsSizes, productId); // 设置库存,最低价 skup等信息
ProductInfo productInfo = productHelpService.convertProductInfo(product);
productHelpService.setBrand(productInfo, product.getBrandId())
.setSeries(productInfo, product.getSeriesId());
goodsBOList.get(0).setSizeList(goodsSizes);
List<GoodsBO> goodsBOList = goodsService.getGoodsList(product.getId()); // 查询商品的颜色、封面信息
if (!CollectionUtils.isEmpty(goodsBOList)) {
List<GoodsSize> goodsSizes = storageService.getSizeList(productId, goodsBOList.get(0)); // 查询尺码信息
storageService.setMaxMinPrice(goodsSizes, product.getMinPrice(), product.getMaxPrice()); //设置商品最高价和最低价
storagePriceService.setStoragePrice(goodsSizes, productId); // 设置库存,最低价 skup等信息
productHelpService.setProductLeastPrice(productInfo, goodsSizes); // 设置商品SKn的最低价
goodsBOList.get(0).setSizeList(goodsSizes);
storageService.sort(goodsSizes);
storageService.setMaxMinPrice(goodsSizes, product.getMinPrice(), product.getMaxPrice()); //设置商品最高价和最低价
productHelpService.setProductLeastPrice(productInfo, goodsSizes); // 设置商品SKn的最低价
storageService.sort(goodsSizes); // 根据尺码库的排序值排序
}
productInfo.setGoodsList(goodsBOList);
productDetailResp.setProduct_info(productInfo);
}
return productDetailResp;
productInfo.setGoodsList(goodsBOList);
return new ProductDetailResp(productInfo);
}
}
... ...
package com.yohoufo.product.service.impl;
import com.yohobuy.ufo.model.GoodsSize;
import com.yohoufo.common.alarm.EventBusPublisher;
import com.yohoufo.dal.product.StoragePriceMapper;
import com.yohoufo.dal.product.model.StoragePrice;
import com.yohoufo.product.cache.UfoProductCacheKeyEnum;
import com.yohoufo.product.cache.UfoProductCacheService;
import com.yohoufo.product.event.StoragePriceUpdateEvent;
import org.apache.commons.collections.CollectionUtils;
import org.apache.ibatis.annotations.Param;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;
... ... @@ -20,6 +25,8 @@ import java.util.stream.Collectors;
*/
@Service
public class StoragePriceService {
private final static Logger LOGGER = LoggerFactory.getLogger(StoragePriceService.class);
@Autowired
private StoragePriceMapper storagePriceMapper;
... ... @@ -31,13 +38,36 @@ public class StoragePriceService {
}
private List<StoragePrice> selectInStockLeastPCache(Integer productId) {
List<StoragePrice> sizePriceCacheList = productCacheService.getListCacheByString(UfoProductCacheKeyEnum.STORAGE_PRICE_IN_STOCK_INFO_KEY, StoragePrice.class, productId);
if (CollectionUtils.isNotEmpty(sizePriceCacheList)) {
LOGGER.info("sizePriceCacheList is cache hit, productId is {}", productId);
return sizePriceCacheList;
}
sizePriceCacheList = setStoragePriceCache(productId);
return sizePriceCacheList;
}
/**
* 重新设置缓存
* @param productId
* @return
*/
public List<StoragePrice> setStoragePriceCache(Integer productId) {
List<StoragePrice> sizePriceCacheList = storagePriceMapper.selectInStockLeastPByProductId(productId);
productCacheService.setCacheByString(UfoProductCacheKeyEnum.STORAGE_PRICE_IN_STOCK_INFO_KEY, sizePriceCacheList, productId);
return sizePriceCacheList;
}
/**
* 查询现货各尺码的最低价
* @param productId
* @return
*/
private Map<Integer, StoragePrice> selectInStockLeastPByProductId(@Param("productId") Integer productId) {
return storagePriceMapper.selectInStockLeastPByProductId(productId).stream().collect(Collectors.toMap(StoragePrice::getStorageId, Function.identity()));
private Map<Integer, StoragePrice> selectInStockLeastP(@Param("productId") Integer productId) {
return selectInStockLeastPCache(productId).stream().collect(Collectors.toMap(StoragePrice::getStorageId, Function.identity()));
}
public void setStoragePrice(List<GoodsSize> goodsSizes, Integer productId) {
... ... @@ -45,8 +75,7 @@ public class StoragePriceService {
return;
}
Map<Integer, StoragePrice> storagePriceMap = selectInStockLeastPByProductId(productId);
Map<Integer, StoragePrice> storagePriceMap = selectInStockLeastP(productId);
goodsSizes.stream().forEach(item -> {
StoragePrice storagePrice = storagePriceMap.get(item.getId());//大陆现货
if (null != storagePrice && null != item.getSuggestHighPrice()
... ... @@ -61,4 +90,18 @@ public class StoragePriceService {
}
});
}
public boolean reSetStoragePriceCache(StoragePriceUpdateEvent storagePriceUpdateEvent) {
Integer productId = storagePriceUpdateEvent.getProductId();
setStoragePriceCache(productId);
return false;
}
public void publishPriceUpdateEvent(Integer productId) {
LOGGER.info("method com.yohoufo.product.service.impl.StoragePriceService.publishPriceUpdateEvent in productId is 【{}】", productId);
StoragePriceUpdateEvent storagePriceUpdateEvent = new StoragePriceUpdateEvent(this::reSetStoragePriceCache);
storagePriceUpdateEvent.setProductId(productId);
EventBusPublisher.publishEvent(storagePriceUpdateEvent);
}
}
... ...
... ... @@ -8,6 +8,8 @@ import com.yohoufo.dal.product.model.Storage;
import com.yohoufo.product.cache.UfoProductCacheKeyEnum;
import com.yohoufo.product.cache.UfoProductCacheService;
import com.yohoufo.product.service.cache.SizeCacheService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
... ... @@ -22,7 +24,7 @@ import java.util.Map;
*/
@Service
public class StorageService {
private final static Logger LOGGER = LoggerFactory.getLogger(StorageService.class);
@Autowired
private UfoProductCacheService productCacheService;
... ... @@ -57,6 +59,7 @@ public class StorageService {
List<GoodsSize> sizeCacheList = productCacheService.getListCacheByString(UfoProductCacheKeyEnum.PRODUCT_STORAGE_INFO_KEY, GoodsSize.class, goodsBO.getId());
if (!CollectionUtils.isEmpty(sizeCacheList)) {
LOGGER.info("sizeCacheList is cache hit, productId is {}", productId);
return sizeCacheList;
}
... ...