master:新增商品时传输数据到ES;

pull/1121/head
liujiang 2025-04-23 11:06:02 +08:00
parent a2cc166908
commit 2c69535ed5
16 changed files with 344 additions and 89 deletions

View File

@ -22,6 +22,7 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/**
@ -84,33 +85,33 @@ public class StoreProductController extends XktBaseController {
/**
*
*/
@PreAuthorize("@ss.hasPermi('system:product:add')")
// @PreAuthorize("@ss.hasPermi('system:product:add')")
@Log(title = "档口商品", businessType = BusinessType.INSERT)
@ApiOperation(value = "新增档口商品", httpMethod = "POST", response = R.class)
@PostMapping
public R<Integer> add(@Validated @RequestBody StoreProdVO storeProdVO) {
public R<Integer> add(@Validated @RequestBody StoreProdVO storeProdVO) throws IOException {
return R.ok(storeProdService.insertStoreProduct(BeanUtil.toBean(storeProdVO, StoreProdDTO.class)));
}
/**
*
*/
@PreAuthorize("@ss.hasPermi('system:product:edit')")
// @PreAuthorize("@ss.hasPermi('system:product:edit')")
@ApiOperation(value = "修改档口商品", httpMethod = "PUT", response = R.class)
@Log(title = "档口商品", businessType = BusinessType.UPDATE)
@PutMapping("/{storeProdId}")
public R<Integer> edit(@PathVariable Long storeProdId, @Validated @RequestBody StoreProdVO storeProdVO) {
public R<Integer> edit(@PathVariable Long storeProdId, @Validated @RequestBody StoreProdVO storeProdVO) throws IOException {
return R.ok(storeProdService.updateStoreProduct(storeProdId, BeanUtil.toBean(storeProdVO, StoreProdDTO.class)));
}
/**
*
*/
@PreAuthorize("@ss.hasPermi('system:product:edit')")
// @PreAuthorize("@ss.hasPermi('system:product:edit')")
@Log(title = "修改档口商品状态", businessType = BusinessType.UPDATE)
@ApiOperation(value = "修改档口商品状态", httpMethod = "PUT", response = R.class)
@PutMapping("/prod-status")
public R editProdStatus(@Validated @RequestBody StoreProdStatusVO prodStatusVO) {
public R editProdStatus(@Validated @RequestBody StoreProdStatusVO prodStatusVO) throws IOException {
storeProdService.updateStoreProductStatus(BeanUtil.toBean(prodStatusVO, StoreProdStatusDTO.class));
return R.ok();
}
@ -118,7 +119,7 @@ public class StoreProductController extends XktBaseController {
/**
*
*/
@PreAuthorize("@ss.hasPermi('system:product:query')")
// @PreAuthorize("@ss.hasPermi('system:product:query')")
@ApiOperation(value = "获取档口图片空间", httpMethod = "GET", response = R.class)
@GetMapping(value = "/pic-space/{storeId}")
public R<StoreProdPicSpaceResVO> getStoreProductPicSpace(@PathVariable("storeId") Long storeId) {
@ -129,7 +130,7 @@ public class StoreProductController extends XktBaseController {
/**
*
*/
@PreAuthorize("@ss.hasPermi('system:product:export')")
// @PreAuthorize("@ss.hasPermi('system:product:export')")
@Log(title = "档口商品", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, StoreProduct storeProduct) {

View File

@ -20,7 +20,7 @@ public class StoreProdStatusVO {
@NotNull(message = "档口商品ID不能为空!")
@ApiModelProperty(value = "档口商品ID", required = true)
private List<Long> storeProdIdList;
@NotBlank(message = "档口商品状态不能为空!")
@NotNull(message = "档口商品状态不能为空!")
@ApiModelProperty(value = "档口商品状态", required = true)
private Integer prodStatus;

View File

@ -30,9 +30,15 @@ public class StoreProdVO {
@ApiModelProperty(value = "档口ID", required = true)
@NotNull(message = "档口ID不能为空!")
private Long storeId;
@ApiModelProperty(value = "档口名称")
@NotBlank(message = "档口名称不能为空!")
private String storeName;
@ApiModelProperty(value = "商品分类ID", required = true)
@NotNull(message = "商品分类ID不能为空!")
private Long prodCateId;
@ApiModelProperty(value = "商品分类名称")
@NotBlank(message = "商品分类名称不能为空!")
private String prodCateName;
@ApiModelProperty(value = "工厂货号")
@Size(min = 0, max = 15, message = "工厂货号不能超过60个字!")
private String factoryArtNum;

View File

@ -211,6 +211,8 @@ public class Constants
public static final String EXPRESS_REGION_LIST_CACHE_KEY = "EXPRESS_REGION_LIST";
public static final String EXPRESS_REGION_TREE_CACHE_KEY = "EXPRESS_REGION_TREE";
// ES 索引 product_info
public static final String ES_IDX_PRODUCT_INFO = "product_info";

View File

@ -9,6 +9,8 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
/**
*
*
@ -52,7 +54,7 @@ public class DailySaleController extends BaseController {
}
@PostMapping("/prod-tag")
public R dailyProdTag(SysJob sysJob) {
public R dailyProdTag(SysJob sysJob) throws IOException {
task.dailyProdTag();
return R.ok();
}

View File

@ -1,11 +1,14 @@
package com.ruoyi.quartz.task;
import cn.hutool.core.bean.BeanUtil;
import co.elastic.clients.elasticsearch.core.BulkResponse;
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.entity.SysProductCategory;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.framework.es.EsClientWrapper;
import com.ruoyi.quartz.domain.*;
import com.ruoyi.quartz.dto.DailySaleCusDTO;
import com.ruoyi.quartz.dto.DailySaleDTO;
@ -19,11 +22,11 @@ import com.ruoyi.xkt.enums.*;
import com.ruoyi.xkt.mapper.*;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
@ -56,6 +59,7 @@ public class XktTask {
final DailyProdTagMapper dailyProdTagMapper;
final StoreProductCategoryAttributeMapper cateAttrMapper;
final StoreProductStatisticsMapper prodStatMapper;
final EsClientWrapper esClientWrapper;
/**
* 1
@ -211,7 +215,7 @@ public class XktTask {
*
*/
@Transactional
public void dailyProdTag() {
public void dailyProdTag() throws IOException {
// 先删除所有的商品标签,保证数据唯一性
List<DailyProdTag> existList = this.dailyProdTagMapper.selectList(new LambdaQueryWrapper<DailyProdTag>()
.eq(DailyProdTag::getDelFlag, Constants.UNDELETED));
@ -241,12 +245,15 @@ public class XktTask {
return;
}
this.dailyProdTagMapper.insert(tagList);
// 更新商品的标签到ES
this.updateESTags(tagList);
}
/**
*
*/
@Transactional
public void dailyProdWeight() {
List<StoreProduct> storeProdList = this.storeProdMapper.selectList(new LambdaQueryWrapper<StoreProduct>()
.eq(StoreProduct::getDelFlag, Constants.UNDELETED));
@ -309,10 +316,10 @@ public class XktTask {
/**
*
*
* @param yesterday
* @param fourDaysAgo 4
* @param oneWeekAgo
* @param tagList
* @param yesterday
* @param fourDaysAgo 4
* @param oneWeekAgo
* @param tagList
*/
private void tagSevenDayNew(Date yesterday, Date fourDaysAgo, Date oneWeekAgo, List<DailyProdTag> tagList) {
List<StoreProduct> storeProdList = this.storeProdMapper.selectList(new LambdaQueryWrapper<StoreProduct>()
@ -545,6 +552,31 @@ public class XktTask {
}
}
/**
* ES
*
* @param tagList
* @throws IOException
*/
private void updateESTags(List<DailyProdTag> tagList) throws IOException {
// 构建一个批量数据集合
List<BulkOperation> list = new ArrayList<>();
tagList.stream().collect(Collectors.groupingBy(DailyProdTag::getStoreProdId))
.forEach((storeProdId, tags) -> {
// 构建部分文档更新请求
list.add(new BulkOperation.Builder().update(u -> u
.action(a -> a.doc(new HashMap<String, Object>() {{
put("tags", tags.stream().map(DailyProdTag::getTag).collect(Collectors.toList()));
}}))
.id(String.valueOf(storeProdId))
.index(Constants.ES_IDX_PRODUCT_INFO))
.build());
});
// 调用bulk方法执行批量更新操作
BulkResponse bulkResponse = esClientWrapper.getEsClient().bulk(e -> e.index(Constants.ES_IDX_PRODUCT_INFO).operations(list));
System.out.println("bulkResponse.items() = " + bulkResponse.items());
}
}

View File

@ -2,6 +2,7 @@ package com.ruoyi.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.common.core.domain.entity.SysProductCategory;
import com.ruoyi.system.domain.dto.productCategory.ProdCateDTO;
/**
*
@ -10,4 +11,12 @@ import com.ruoyi.common.core.domain.entity.SysProductCategory;
*/
public interface SysProductCategoryMapper extends BaseMapper<SysProductCategory> {
/**
*
*
* @param prodCateId
* @return ProdCateDTO
*/
ProdCateDTO getParentCate(Long prodCateId);
}

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.system.mapper.SysProductCategoryMapper">
<select id="getParentCate" parameterType="Long" resultType="com.ruoyi.system.domain.dto.productCategory.ProdCateDTO">
SELECT
spc2.id AS prodCateId,
spc2.`name` AS `name`
FROM
sys_product_category spc1
LEFT JOIN sys_product_category spc2 ON spc1.parent_id = spc2.id
WHERE
spc1.del_flag = 0
AND spc1.id = #{prodCateId}
</select>
</mapper>

View File

@ -3,6 +3,7 @@ package com.ruoyi.xkt.dto.es;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
@ -13,6 +14,7 @@ import java.util.List;
*/
@ApiModel("ES返回商品数据")
@Data
@Accessors(chain = true)
public class ESProductDTO {
@ApiModelProperty(value = "货号")
@ -40,7 +42,7 @@ public class ESProductDTO {
@ApiModelProperty(value = "适合季节")
private String season;
@ApiModelProperty(value = "商品状态")
private String status;
private String prodStatus;
@ApiModelProperty(value = "档口ID")
private String storeId;
@ApiModelProperty(value = "档口名称")

View File

@ -0,0 +1,59 @@
package com.ruoyi.xkt.dto.storeProduct;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel("ES返回商品数据")
@Data
@Accessors(chain = true)
public class ProductESDTO {
@ApiModelProperty(value = "档口商品ID")
private Long id;
@ApiModelProperty(value = "货号")
private String prodArtNum;
@ApiModelProperty(value = "档口商品分类ID")
private String prodCateId;
@ApiModelProperty(value = "档口商品分类名称")
private String prodCateName;
@ApiModelProperty(value = "销量权重")
private String saleWeight;
@ApiModelProperty(value = "推荐权重")
private String recommendWeight;
@ApiModelProperty(value = "人气权重")
private String popularityWeight;
@ApiModelProperty(value = "创建时间")
private String createTime;
@ApiModelProperty(value = "主图")
private String mainPic;
@ApiModelProperty(value = "上级分类名称")
private String parCateName;
@ApiModelProperty(value = "上级分类ID")
private String parCateId;
@ApiModelProperty(value = "单价")
private String prodPrice;
@ApiModelProperty(value = "适合季节")
private String season;
@ApiModelProperty(value = "商品状态")
private String prodStatus;
@ApiModelProperty(value = "档口ID")
private String storeId;
@ApiModelProperty(value = "档口名称")
private String storeName;
@ApiModelProperty(value = "风格")
private String style;
@ApiModelProperty(value = "标签")
private List<String> tags;
@ApiModelProperty(value = "标题")
private String prodTitle;
}

View File

@ -15,6 +15,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.Date;
@ -34,8 +35,12 @@ public class StoreProdDTO {
private String prodName;
@ApiModelProperty(value = "档口ID")
private Long storeId;
@ApiModelProperty(value = "档口名称")
private String storeName;
@ApiModelProperty(value = "商品分类ID")
private Long prodCateId;
@ApiModelProperty(value = "商品分类名称")
private String prodCateName;
@ApiModelProperty(value = "工厂货号")
private String factoryArtNum;
@ApiModelProperty(value = "商品货号")

View File

@ -3,6 +3,7 @@ package com.ruoyi.xkt.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.xkt.domain.StoreProduct;
import com.ruoyi.xkt.dto.storeHomepage.StoreHomeResDTO;
import com.ruoyi.xkt.dto.storeProduct.ProductESDTO;
import com.ruoyi.xkt.dto.storeProduct.StoreProdFuzzyResPicDTO;
import com.ruoyi.xkt.dto.storeProduct.StoreProdStatusCountDTO;
import org.apache.ibatis.annotations.Param;
@ -81,4 +82,12 @@ public interface StoreProductMapper extends BaseMapper<StoreProduct> {
* @return StoreProdCountDTO
*/
StoreProdStatusCountDTO selectStatusCount(Long storeId);
/**
* ID
* @param idList id
* @return List<ProductESDTO>
*/
List<ProductESDTO> selectESDTOList(@Param("idList") List<Long> idList);
}

View File

@ -4,6 +4,7 @@ import com.ruoyi.common.core.page.Page;
import com.ruoyi.xkt.domain.StoreProduct;
import com.ruoyi.xkt.dto.storeProduct.*;
import java.io.IOException;
import java.util.List;
/**
@ -46,7 +47,7 @@ public interface IStoreProductService {
* @param storeProdDTO
* @return
*/
int insertStoreProduct(StoreProdDTO storeProdDTO);
int insertStoreProduct(StoreProdDTO storeProdDTO) throws IOException;
/**
*
@ -54,14 +55,14 @@ public interface IStoreProductService {
* @param storeProdDTO
* @return
*/
public int updateStoreProduct(Long storeProdId, StoreProdDTO storeProdDTO);
public int updateStoreProduct(Long storeProdId, StoreProdDTO storeProdDTO) throws IOException;
/**
*
*
* @param prodStatusDTO
*/
public void updateStoreProductStatus(StoreProdStatusDTO prodStatusDTO);
public void updateStoreProductStatus(StoreProdStatusDTO prodStatusDTO) throws IOException;
/**
*

View File

@ -6,6 +6,7 @@ import co.elastic.clients.elasticsearch._types.query_dsl.*;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.page.Page;
import com.ruoyi.framework.es.EsClientWrapper;
import com.ruoyi.xkt.dto.es.ESProductDTO;
@ -42,7 +43,6 @@ public class IndexSearchServiceImpl implements IIndexSearchService {
@Transactional(readOnly = true)
public Page<ESProductDTO> search(IndexSearchDTO searchDTO) throws IOException {
String indexName = "product_info";
/*// 查询索引
GetIndexResponse res = esClientWrapper.getEsClient().indices().get(request -> request.index(indexName));
System.err.println(res);
@ -55,70 +55,8 @@ public class IndexSearchServiceImpl implements IIndexSearchService {
System.err.println(response);*/
// 分页查询
// 如果有搜索词,则要分词
if (StringUtils.isNotBlank(searchDTO.getSearch())) {
}
// 多个query 根据入参是否为空 分别赋值有multi_match , terms , range
/*SearchResponse<ESProductInfo> list = esClientWrapper.getEsClient().search(s -> s
.index(indexName)
.query(q -> q
.bool(b -> b
.must(m -> m
.multiMatch(mm -> mm
.query(searchDTO.getSearch())
.fields("prodTitle", "prodArtNum", "storeName"))
)
.filter(f -> f
.terms(t -> t
.field("prodCateId")
.terms(new TermsQueryField.Builder()
.value(searchDTO.getProdCateIdList().stream()
.map(IndexSearchServiceImpl::newFieldValue)
.collect(Collectors.toList()))
.build()
))
)
.filter(f -> f
.terms(t -> t
.field("parCateId")
.terms(new TermsQueryField.Builder()
.value(searchDTO.getParCateIdList().stream()
.map(IndexSearchServiceImpl::newFieldValue)
.collect(Collectors.toList()))
.build())))
.filter(f -> f
.terms(t -> t
.field("style.keyword")
.terms(new TermsQueryField.Builder()
.value(searchDTO.getStyleList().stream()
.map(IndexSearchServiceImpl::newFieldValue)
.collect(Collectors.toList()))
.build())))
.filter(f -> f
.terms(t -> t
.field("season.keyword")
.terms(new TermsQueryField.Builder()
.value(searchDTO.getSeasonList().stream()
.map(IndexSearchServiceImpl::newFieldValue)
.collect(Collectors.toList()))
.build())))
)
)
.from(0)
.size(10)
.sort(sort -> sort.field(f -> f.field("recommendWeight").order(SortOrder.Desc)))
,
ESProductInfo.class
);*/
// 构建 bool 查询
BoolQuery.Builder boolQuery = new BoolQuery.Builder();
// 添加 price 范围查询
if (searchDTO.getMinPrice() != null && searchDTO.getMaxPrice() != null) {
RangeQuery.Builder builder = new RangeQuery.Builder();
@ -173,7 +111,7 @@ public class IndexSearchServiceImpl implements IIndexSearchService {
// 构建最终的查询
Query query = new Query.Builder().bool(boolQuery.build()).build();
// 执行搜索
SearchResponse<ESProductDTO> resList = esClientWrapper.getEsClient().search(s -> s.index(indexName)
SearchResponse<ESProductDTO> resList = esClientWrapper.getEsClient().search(s -> s.index(Constants.ES_IDX_PRODUCT_INFO)
.query(query).from(searchDTO.getPageNum() - 1).size(searchDTO.getPageSize())
.sort(sort -> sort.field(f -> f.field(searchDTO.getSort()).order(SortOrder.Desc))),
ESProductDTO.class);

View File

@ -1,6 +1,10 @@
package com.ruoyi.xkt.service.impl;
import cn.hutool.core.bean.BeanUtil;
import co.elastic.clients.elasticsearch.core.BulkResponse;
import co.elastic.clients.elasticsearch.core.CreateResponse;
import co.elastic.clients.elasticsearch.core.UpdateResponse;
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
@ -9,7 +13,11 @@ import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.page.Page;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.framework.es.EsClientWrapper;
import com.ruoyi.system.domain.dto.productCategory.ProdCateDTO;
import com.ruoyi.system.mapper.SysProductCategoryMapper;
import com.ruoyi.xkt.domain.*;
import com.ruoyi.xkt.dto.es.ESProductDTO;
import com.ruoyi.xkt.dto.storeColor.StoreColorDTO;
import com.ruoyi.xkt.dto.storeProdCateAttr.StoreProdCateAttrDTO;
import com.ruoyi.xkt.dto.storeProdColor.StoreProdColorDTO;
@ -22,6 +30,7 @@ import com.ruoyi.xkt.dto.storeProduct.*;
import com.ruoyi.xkt.dto.storeProductFile.StoreProdFileDTO;
import com.ruoyi.xkt.dto.storeProductFile.StoreProdFileResDTO;
import com.ruoyi.xkt.dto.storeProductFile.StoreProdMainPicDTO;
import com.ruoyi.xkt.enums.EProductStatus;
import com.ruoyi.xkt.enums.FileType;
import com.ruoyi.xkt.enums.ProductSizeStatus;
import com.ruoyi.xkt.mapper.*;
@ -33,6 +42,8 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -59,6 +70,9 @@ public class StoreProductServiceImpl implements IStoreProductService {
final StoreProductColorSizeMapper storeProdColorSizeMapper;
final StoreProductProcessMapper storeProdProcMapper;
final StoreMapper storeMapper;
final EsClientWrapper esClientWrapper;
final SysProductCategoryMapper prodCateMapper;
/**
*
@ -157,9 +171,10 @@ public class StoreProductServiceImpl implements IStoreProductService {
@Override
@Transactional
public int insertStoreProduct(StoreProdDTO storeProdDTO) {
public int insertStoreProduct(StoreProdDTO storeProdDTO) throws IOException {
// 组装StoreProduct数据
StoreProduct storeProd = BeanUtil.toBean(storeProdDTO, StoreProduct.class).setVoucherDate(DateUtils.getNowDate());
StoreProduct storeProd = BeanUtil.toBean(storeProdDTO, StoreProduct.class).setVoucherDate(DateUtils.getNowDate())
.setRecommendWeight(0L).setSaleWeight(0L).setPopularityWeight(0L);
int count = this.storeProdMapper.insert(storeProd);
// 处理编辑档口商品颜色
this.handleStoreProdColorList(storeProdDTO.getColorList(), storeProd.getId(), storeProd.getStoreId(), Boolean.TRUE);
@ -167,6 +182,8 @@ public class StoreProductServiceImpl implements IStoreProductService {
this.handleStoreProdColorSizeList(storeProdDTO.getSizeList(), storeProd.getId(), Boolean.TRUE);
// 处理StoreProduct其它属性
this.handleStoreProdProperties(storeProd, storeProdDTO);
// 向ES索引: product_info 创建文档
this.createESDoc(storeProd, storeProdDTO);
return count;
}
@ -179,7 +196,7 @@ public class StoreProductServiceImpl implements IStoreProductService {
*/
@Override
@Transactional
public int updateStoreProduct(final Long storeProdId, StoreProdDTO storeProdDTO) {
public int updateStoreProduct(final Long storeProdId, StoreProdDTO storeProdDTO) throws IOException {
StoreProduct storeProd = Optional.ofNullable(this.storeProdMapper.selectOne(new LambdaQueryWrapper<StoreProduct>()
.eq(StoreProduct::getId, storeProdId).eq(StoreProduct::getDelFlag, Constants.UNDELETED)))
.orElseThrow(() -> new ServiceException("档口商品不存在!", HttpStatus.ERROR));
@ -204,9 +221,12 @@ public class StoreProductServiceImpl implements IStoreProductService {
this.handleStoreProdColorList(storeProdDTO.getColorList(), storeProdId, storeProd.getStoreId(), Boolean.FALSE);
// 处理编辑档口商品颜色尺码
this.handleStoreProdColorSizeList(storeProdDTO.getSizeList(), storeProdId, Boolean.FALSE);
// 更新索引: product_info 的文档
this.updateESDoc(storeProd, storeProdDTO);
return count;
}
/**
*
*
@ -325,19 +345,36 @@ public class StoreProductServiceImpl implements IStoreProductService {
*/
@Override
@Transactional
public void updateStoreProductStatus(StoreProdStatusDTO prodStatusDTO) {
public void updateStoreProductStatus(StoreProdStatusDTO prodStatusDTO) throws IOException {
// 根据商品ID列表查询数据库中的商品信息
List<StoreProduct> storeProdList = this.storeProdMapper.selectByIds(prodStatusDTO.getStoreProdIdList());
// 检查查询结果是否为空,如果为空,则抛出异常
if (CollectionUtils.isEmpty(storeProdList)) {
throw new ServiceException("档口商品不存在!", HttpStatus.ERROR);
}
List<StoreProduct> reSaleList = new ArrayList<>();
// 遍历查询到的商品列表,设置新的商品状态
storeProdList.forEach(x -> x.setProdStatus(prodStatusDTO.getProdStatus()));
storeProdList.forEach(x -> {
// 已下架上的商品重新上架
if (Objects.equals(x.getProdStatus(), EProductStatus.OFF_SALE.getValue())
&& Objects.equals(prodStatusDTO.getProdStatus(), EProductStatus.ON_SALE.getValue())) {
reSaleList.add(x);
}
x.setProdStatus(prodStatusDTO.getProdStatus());
});
// 保存更新后的商品列表到数据库
this.storeProdMapper.updateById(storeProdList);
// 筛选商品状态为已下架则删除ES文档
if (Objects.equals(prodStatusDTO.getProdStatus(), EProductStatus.OFF_SALE.getValue())) {
this.deleteESDoc(prodStatusDTO.getStoreProdIdList());
}
// 已下架的商品重新上架
if (CollectionUtils.isNotEmpty(reSaleList)) {
this.reSaleCreateESDoc(reSaleList);
}
}
/**
*
*
@ -478,4 +515,105 @@ public class StoreProductServiceImpl implements IStoreProductService {
}
}
/**
* ES
*
* @param storeProd
* @param storeProdDTO
* @throws IOException
*/
private void createESDoc(StoreProduct storeProd, StoreProdDTO storeProdDTO) throws IOException {
ESProductDTO esProductDTO = this.getESDTO(storeProd, storeProdDTO);
// 向索引中添加数据
CreateResponse createResponse = esClientWrapper.getEsClient().create(e -> e.index(Constants.ES_IDX_PRODUCT_INFO)
.id(storeProd.getId().toString()).document(esProductDTO));
System.out.println("createResponse.result() = " + createResponse.result());
}
/**
* ES
*
* @param storeProd
* @param storeProdDTO
* @throws IOException
*/
private void updateESDoc(StoreProduct storeProd, StoreProdDTO storeProdDTO) throws IOException {
ESProductDTO esProductDTO = this.getESDTO(storeProd, storeProdDTO);
UpdateResponse<ESProductDTO> updateResponse = esClientWrapper.getEsClient().update(u -> u
.index(Constants.ES_IDX_PRODUCT_INFO).doc(esProductDTO).id(storeProd.getId().toString()), ESProductDTO.class);
System.out.println("deleteResponse.result() = " + updateResponse.result());
}
/**
* ES DTO
*
* @param storeProd
* @param storeProdDTO
* @return
*/
private ESProductDTO getESDTO(StoreProduct storeProd, StoreProdDTO storeProdDTO) {
// 获取第一张主图
String firstMainPic = storeProdDTO.getFileList().stream().filter(x -> Objects.equals(x.getFileType(), FileType.MAIN_PIC.getValue()))
.min(Comparator.comparing(StoreProdFileDTO::getOrderNum)).map(StoreProdFileDTO::getFileUrl)
.orElseThrow(() -> new ServiceException("商品主图不存在!", HttpStatus.ERROR));
// 获取上一级分类的分类ID 及 分类名称
ProdCateDTO parCate = this.prodCateMapper.getParentCate(storeProdDTO.getProdCateId());
// 获取当前商品的最低价格
BigDecimal minPrice = storeProdDTO.getPriceList().stream().min(Comparator.comparing(StoreProdColorPriceDTO::getPrice))
.map(StoreProdColorPriceDTO::getPrice).orElseThrow(() -> new ServiceException("商品价格不存在!", HttpStatus.ERROR));
// 获取使用季节
String season = storeProdDTO.getCateAttrList().stream().filter(x -> Objects.equals(x.getDictType(), "suitable_season"))
.map(StoreProdCateAttrDTO::getDictValue).findAny().orElse("");
// 获取风格
String style = storeProdDTO.getCateAttrList().stream().filter(x -> Objects.equals(x.getDictType(), "style"))
.map(StoreProdCateAttrDTO::getDictValue).findAny().orElse("");
return BeanUtil.toBean(storeProd, ESProductDTO.class)
.setProdCateName(storeProdDTO.getProdCateName()).setSaleWeight("0").setRecommendWeight("0").setPopularityWeight("0")
.setCreateTime(DateUtils.getTime()).setStoreName(storeProdDTO.getStoreName()).setMainPic(firstMainPic)
.setParCateId(parCate.getProdCateId().toString()).setParCateName(parCate.getName()).setProdPrice(minPrice.toString())
.setSeason(season).setStyle(style).setTags(Collections.singletonList(style));
}
/**
* ES
*
* @param storeProdIdList ID
* @throws IOException
*/
private void deleteESDoc(List<Long> storeProdIdList) throws IOException {
List<BulkOperation> list = storeProdIdList.stream().map(x -> new BulkOperation.Builder().delete(
d -> d.id(String.valueOf(x)).index(Constants.ES_IDX_PRODUCT_INFO)).build()).collect(Collectors.toList());
// 调用bulk方法执行批量插入操作
BulkResponse bulkResponse = esClientWrapper.getEsClient().bulk(e -> e.index(Constants.ES_IDX_PRODUCT_INFO).operations(list));
System.out.println("bulkResponse.items() = " + bulkResponse.items());
}
/**
* ES
*
* @param reSaleList
* @throws IOException
*/
private void reSaleCreateESDoc(List<StoreProduct> reSaleList) throws IOException {
if (CollectionUtils.isEmpty(reSaleList)) {
return;
}
List<ProductESDTO> esDTOList = this.storeProdMapper.selectESDTOList(reSaleList.stream()
.map(StoreProduct::getId).distinct().collect(Collectors.toList()));
Map<Long, ProductESDTO> esDTOMap = esDTOList.stream().collect(Collectors.toMap(ProductESDTO::getId, Function.identity()));
// 构建一个批量数据集合
List<BulkOperation> list = reSaleList.stream().map(x -> {
final String createTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, x.getCreateTime());
final ProductESDTO esDTO = Optional.ofNullable(esDTOMap.get(x.getId())).orElseThrow(() -> new ServiceException("档口商品不存在!", HttpStatus.ERROR));
ESProductDTO esProductDTO = BeanUtil.toBean(x, ESProductDTO.class).setProdCateName(esDTO.getProdCateName()).setMainPic(esDTO.getMainPic())
.setParCateId(esDTO.getParCateId()).setParCateName(esDTO.getParCateName()).setProdPrice(esDTO.getProdPrice()).setStoreName(esDTO.getStoreName())
.setSeason(esDTO.getSeason()).setStyle(esDTO.getStyle()).setCreateTime(createTime);
return new BulkOperation.Builder().create(d -> d.document(esProductDTO).id(String.valueOf(x.getId()))
.index(Constants.ES_IDX_PRODUCT_INFO)).build();
}).collect(Collectors.toList());
// 调用bulk方法执行批量插入操作
BulkResponse bulkResponse = esClientWrapper.getEsClient().bulk(e -> e.index(Constants.ES_IDX_PRODUCT_INFO).operations(list));
System.out.println("bulkResponse.items() = " + bulkResponse.items());
}
}

View File

@ -176,5 +176,37 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
del_flag = 0 AND store_id = #{storeId}
</select>
<select id="selectESDTOList" resultType="com.ruoyi.xkt.dto.storeProduct.ProductESDTO">
SELECT DISTINCT
sp.id,
s.store_name AS storeName,
sf.file_url AS mainPic,
spca1.dict_value AS season,
spca2.dict_value AS style,
spcp.min_price AS prodPrice,
spc1.`name` AS prodCateName,
spc2.id AS parCateId,
spc2.`name` AS parCateName
FROM
store_product sp
LEFT JOIN store s ON sp.store_id = s.id
LEFT JOIN store_product_file spf ON sp.id = spf.store_prod_id
AND spf.file_type = 1
AND spf.order_num = 1
LEFT JOIN sys_file sf ON spf.file_id = sf.id
LEFT JOIN store_product_category_attribute spca1 ON sp.id = spca1.store_prod_id
AND spca1.dict_type = 'suitable_season'
LEFT JOIN sys_product_category spc1 ON sp.prod_cate_id = spc1.id
LEFT JOIN sys_product_category spc2 ON spc1.parent_id = spc2.id
LEFT JOIN store_product_category_attribute spca2 ON sp.id = spca2.store_prod_id
AND spca2.dict_type = 'style'
LEFT JOIN ( SELECT store_prod_id, MIN( price ) AS min_price FROM store_product_color_price GROUP BY store_prod_id ) spcp ON sp.id = spcp.store_prod_id
WHERE
sp.del_flag = 0 AND sp.id IN
<foreach item="id" collection="idList" open="(" separator="," close=")">
#{id}
</foreach>
</select>
</mapper>