pull/1121/head
liujiang 2025-05-21 19:58:30 +08:00
commit e2f1b1ec7a
22 changed files with 354 additions and 360 deletions

View File

@ -22,70 +22,9 @@ import java.util.List;
* @date 2025-03-26
*/
@RestController
@RequestMapping("/rest/v1/pic-searches")
@RequestMapping("/rest/v1/pic-search")
public class PictureSearchController extends XktBaseController {
@Autowired
private IPictureSearchService pictureSearchService;
/**
*
*/
// @PreAuthorize("@ss.hasPermi('system:search:list')")
@GetMapping("/list")
public TableDataInfo list(PictureSearch pictureSearch) {
startPage();
List<PictureSearch> list = pictureSearchService.selectPictureSearchList(pictureSearch);
return getDataTable(list);
}
/**
*
*/
// @PreAuthorize("@ss.hasPermi('system:search:export')")
@Log(title = "以图搜款", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, PictureSearch pictureSearch) {
List<PictureSearch> list = pictureSearchService.selectPictureSearchList(pictureSearch);
ExcelUtil<PictureSearch> util = new ExcelUtil<PictureSearch>(PictureSearch.class);
util.exportExcel(response, list, "以图搜款数据");
}
/**
*
*/
// @PreAuthorize("@ss.hasPermi('system:search:query')")
@GetMapping(value = "/{picSearchId}")
public R getInfo(@PathVariable("picSearchId") Long picSearchId) {
return success(pictureSearchService.selectPictureSearchByPicSearchId(picSearchId));
}
/**
*
*/
// @PreAuthorize("@ss.hasPermi('system:search:add')")
@Log(title = "以图搜款", businessType = BusinessType.INSERT)
@PostMapping
public R add(@RequestBody PictureSearch pictureSearch) {
return success(pictureSearchService.insertPictureSearch(pictureSearch));
}
/**
*
*/
// @PreAuthorize("@ss.hasPermi('system:search:edit')")
@Log(title = "以图搜款", businessType = BusinessType.UPDATE)
@PutMapping
public R edit(@RequestBody PictureSearch pictureSearch) {
return success(pictureSearchService.updatePictureSearch(pictureSearch));
}
/**
*
*/
// @PreAuthorize("@ss.hasPermi('system:search:remove')")
@Log(title = "以图搜款", businessType = BusinessType.DELETE)
@DeleteMapping("/{picSearchIds}")
public R remove(@PathVariable Long[] picSearchIds) {
return success(pictureSearchService.deletePictureSearchByPicSearchIds(picSearchIds));
}
}

View File

@ -143,4 +143,9 @@ public class CacheConstants
*/
public static final String APP_ADVERT = "app_advert:";
/**
*
*/
public static final String IMG_SEARCH_STATISTICS = "img_search_statistics:";
}

View File

@ -229,5 +229,13 @@ public class Constants
*
*/
public static final Integer PAY_EXPIRE_MAX_HOURS = 24 * 7;
/**
*
*/
public static final int IMG_SEARCH_CATEGORY_ID = 4;
/**
*
*/
public static final float IMG_SEARCH_MATCH_SCORE_THRESHOLD = (float) 0.5;
}

View File

@ -271,4 +271,8 @@ public class RedisCache
public boolean exists(final String key) {
return redisTemplate.hasKey(key);
}
public Long valueIncr(final String key) {
return redisTemplate.opsForValue().increment(key);
}
}

View File

@ -2,7 +2,6 @@ package com.ruoyi.framework.img;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.BooleanUtil;
import com.aliyun.imagesearch20201214.Client;
import com.aliyun.imagesearch20201214.models.*;
@ -12,9 +11,7 @@ import com.ruoyi.framework.img.entity.ImgSearchReq;
import com.ruoyi.framework.img.entity.ImgSearchResult;
import lombok.extern.slf4j.Slf4j;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.List;
/**
@ -40,25 +37,22 @@ public class ImgSearchClientWrapper {
* @return
*/
public boolean addImg(ImgAdd imgAdd) {
AddImageAdvanceRequest request = new AddImageAdvanceRequest();
request.instanceName = instanceName;
request.productId = imgAdd.getProductId();
request.picName = imgAdd.getPicName();
request.categoryId = imgAdd.getCategoryId();
request.customContent = imgAdd.getCustomContent();
request.crop = true;
Assert.notEmpty(imgAdd.getPicPath());
try (InputStream inputStream = BooleanUtil.isTrue(imgAdd.getPicLocalFlag()) ?
new FileInputStream(imgAdd.getPicPath()) : new URL(imgAdd.getPicPath()).openStream()) {
try (InputStream inputStream = imgAdd.getPicInputStream()) {
AddImageAdvanceRequest request = new AddImageAdvanceRequest();
request.instanceName = instanceName;
request.productId = imgAdd.getProductId();
request.picName = imgAdd.getPicName();
request.categoryId = imgAdd.getCategoryId();
request.customContent = imgAdd.getCustomContent();
request.crop = true;
request.picContentObject = inputStream;
RuntimeOptions runtimeOptions = new RuntimeOptions();
AddImageResponse response = client.addImageAdvance(request, runtimeOptions);
AddImageResponse response = client.addImageAdvance(request, new RuntimeOptions());
if (response.getBody().success) {
return true;
}
log.warn("图片搜索-添加图片失败: {} - {}", imgAdd, response.getBody().toMap());
} catch (Exception e) {
log.error("图片搜索服务异常", e);
log.error("图片搜索服务添加图片异常", e);
}
return false;
}
@ -80,7 +74,7 @@ public class ImgSearchClientWrapper {
}
log.warn("图片搜索-删除图片失败: {} - {}", productId, response.getBody().toMap());
} catch (Exception e) {
log.error("图片搜索服务异常", e);
log.error("图片搜索服务删除图片异常", e);
}
return false;
}
@ -92,23 +86,21 @@ public class ImgSearchClientWrapper {
* @return
*/
public List<ImgSearchResult> searchByPic(ImgSearchReq imgSearchReq) {
SearchImageByPicAdvanceRequest request = new SearchImageByPicAdvanceRequest();
request.instanceName = instanceName;
request.categoryId = imgSearchReq.getCategoryId();
request.num = imgSearchReq.getNum();
request.start = imgSearchReq.getStart();
request.crop = true;
request.distinctProductId = BooleanUtil.isTrue(imgSearchReq.getDistinctProductId());
RuntimeOptions runtimeObject = new RuntimeOptions();
try (InputStream inputStream = BooleanUtil.isTrue(imgSearchReq.getPicLocalFlag()) ?
new FileInputStream(imgSearchReq.getPicPath()) : new URL(imgSearchReq.getPicPath()).openStream()) {
try (InputStream inputStream = imgSearchReq.getPicInputStream()) {
SearchImageByPicAdvanceRequest request = new SearchImageByPicAdvanceRequest();
request.instanceName = instanceName;
request.categoryId = imgSearchReq.getCategoryId();
request.num = imgSearchReq.getNum();
request.start = imgSearchReq.getStart();
request.crop = true;
request.distinctProductId = BooleanUtil.isTrue(imgSearchReq.getDistinctProductId());
request.picContentObject = inputStream;
SearchImageByPicResponse response = client.searchImageByPicAdvance(request, runtimeObject);
SearchImageByPicResponse response = client.searchImageByPicAdvance(request, new RuntimeOptions());
List<SearchImageByPicResponseBody.SearchImageByPicResponseBodyAuctions> auctions = response.getBody()
.getAuctions();
return BeanUtil.copyToList(auctions, ImgSearchResult.class);
} catch (Exception e) {
log.error("图片搜索服务异常", e);
log.error("图片搜索服务搜索异常", e);
}
return ListUtil.empty();
}

View File

@ -2,6 +2,8 @@ package com.ruoyi.framework.img.entity;
import lombok.Data;
import java.io.InputStream;
/**
* @author liangyq
* @date 2025-04-25 20:08
@ -32,15 +34,8 @@ public class ImgAdd {
*/
private String customContent;
/**
*
* <p>
* E:/test/123.jpg
* URLhttps://www.example.com/123.jpg
*
*/
private String picPath;
/**
*
*/
private Boolean picLocalFlag;
private InputStream picInputStream;
}

View File

@ -2,6 +2,8 @@ package com.ruoyi.framework.img.entity;
import lombok.Data;
import java.io.InputStream;
/**
* @author liangyq
* @date 2025-04-25 20:50
@ -9,16 +11,9 @@ import lombok.Data;
@Data
public class ImgSearchReq {
/**
*
* <p>
* E:/test/123.jpg
* URLhttps://www.example.com/123.jpg
*
*/
private String picPath;
/**
*
*/
private Boolean picLocalFlag;
private InputStream picInputStream;
/**
*
* <p>

View File

@ -242,7 +242,7 @@ public class OSSClientWrapper {
return "image/jpeg";
}
public InputStream getObject(String key) throws Exception {
public InputStream getObject(String key) {
OSSObject ossObject = client.getObject(configuration.getBucketName(), key);
return ossObject.getObjectContent();
}

View File

@ -0,0 +1,22 @@
package com.ruoyi.xkt.dto.picture;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author liangyq
* @date 2025-05-20
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PicSyncResultDTO {
private String productPicKey;
private Boolean success;
}

View File

@ -0,0 +1,19 @@
package com.ruoyi.xkt.dto.picture;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author liangyq
* @date 2025-05-21
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProductMatchDTO {
private Long storeProductId;
private Float score;
}

View File

@ -0,0 +1,22 @@
package com.ruoyi.xkt.dto.picture;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author liangyq
* @date 2025-05-20
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProductPicSyncDTO {
private Long storeProductId;
private List<String> productPicKeys;
}

View File

@ -0,0 +1,22 @@
package com.ruoyi.xkt.dto.picture;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author liangyq
* @date 2025-05-20
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProductPicSyncResultDTO {
private Boolean success;
private List<PicSyncResultDTO> picSyncResults;
}

View File

@ -0,0 +1,21 @@
package com.ruoyi.xkt.dto.picture;
import lombok.Data;
import java.math.BigDecimal;
/**
* @author liangyq
* @date 2025-05-21
*/
@Data
public class SearchRequestDTO {
private String picKey;
private BigDecimal picSize;
private Long userId;
private Integer num;
}

View File

@ -2,6 +2,7 @@ package com.ruoyi.xkt.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.xkt.domain.PictureSearch;
import org.springframework.stereotype.Repository;
import java.util.List;
@ -11,52 +12,6 @@ import java.util.List;
* @author ruoyi
* @date 2025-03-26
*/
@Repository
public interface PictureSearchMapper extends BaseMapper<PictureSearch> {
/**
*
*
* @param id
* @return
*/
public PictureSearch selectPictureSearchByPicSearchId(Long id);
/**
*
*
* @param pictureSearch
* @return
*/
public List<PictureSearch> selectPictureSearchList(PictureSearch pictureSearch);
/**
*
*
* @param pictureSearch
* @return
*/
public int insertPictureSearch(PictureSearch pictureSearch);
/**
*
*
* @param pictureSearch
* @return
*/
public int updatePictureSearch(PictureSearch pictureSearch);
/**
*
*
* @param id
* @return
*/
public int deletePictureSearchByPicSearchId(Long id);
/**
*
*
* @param picSearchIds
* @return
*/
public int deletePictureSearchByPicSearchIds(Long[] picSearchIds);
}

View File

@ -2,6 +2,7 @@ package com.ruoyi.xkt.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.xkt.domain.SysFile;
import org.springframework.stereotype.Repository;
import java.util.List;
@ -11,6 +12,7 @@ import java.util.List;
* @author ruoyi
* @date 2025-03-26
*/
@Repository
public interface SysFileMapper extends BaseMapper<SysFile> {
/**
* file

View File

@ -1,6 +1,7 @@
package com.ruoyi.xkt.service;
import com.ruoyi.xkt.domain.PictureSearch;
import com.ruoyi.xkt.dto.picture.ProductMatchDTO;
import com.ruoyi.xkt.dto.picture.SearchRequestDTO;
import java.util.List;
@ -12,50 +13,11 @@ import java.util.List;
*/
public interface IPictureSearchService {
/**
*
*
*
* @param picSearchId
* @return
* @param requestDTO
* @return
*/
public PictureSearch selectPictureSearchByPicSearchId(Long picSearchId);
List<ProductMatchDTO> searchProductByPic(SearchRequestDTO requestDTO);
/**
*
*
* @param pictureSearch
* @return
*/
public List<PictureSearch> selectPictureSearchList(PictureSearch pictureSearch);
/**
*
*
* @param pictureSearch
* @return
*/
public int insertPictureSearch(PictureSearch pictureSearch);
/**
*
*
* @param pictureSearch
* @return
*/
public int updatePictureSearch(PictureSearch pictureSearch);
/**
*
*
* @param picSearchIds
* @return
*/
public int deletePictureSearchByPicSearchIds(Long[] picSearchIds);
/**
*
*
* @param picSearchId
* @return
*/
public int deletePictureSearchByPicSearchId(Long picSearchId);
}

View File

@ -1,6 +1,11 @@
package com.ruoyi.xkt.service;
import com.ruoyi.xkt.dto.picture.PicZipDTO;
import com.ruoyi.xkt.dto.picture.ProductMatchDTO;
import com.ruoyi.xkt.dto.picture.ProductPicSyncDTO;
import com.ruoyi.xkt.dto.picture.ProductPicSyncResultDTO;
import java.util.List;
/**
* @author liangyq
@ -16,4 +21,21 @@ public interface IPictureService {
*/
PicZipDTO processPicZip(String key);
/**
*
*
* @param productPicSyncDTO
* @return
*/
ProductPicSyncResultDTO sync2ImgSearchServer(ProductPicSyncDTO productPicSyncDTO);
/**
*
*
* @param picKey
* @param num
* @return
*/
List<ProductMatchDTO> searchProductByPicKey(String picKey, Integer num);
}

View File

@ -1,14 +1,25 @@
package com.ruoyi.xkt.service.impl;
import com.ruoyi.common.utils.DateUtils;
import cn.hutool.core.lang.Assert;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.xkt.domain.PictureSearch;
import com.ruoyi.xkt.domain.SysFile;
import com.ruoyi.xkt.dto.picture.ProductMatchDTO;
import com.ruoyi.xkt.dto.picture.SearchRequestDTO;
import com.ruoyi.xkt.mapper.PictureSearchMapper;
import com.ruoyi.xkt.mapper.SysFileMapper;
import com.ruoyi.xkt.service.IPictureSearchService;
import com.ruoyi.xkt.service.IPictureService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
import java.util.Optional;
/**
* Service
@ -16,82 +27,44 @@ import java.util.List;
* @author ruoyi
* @date 2025-03-26
*/
@Slf4j
@Service
public class PictureSearchServiceImpl implements IPictureSearchService {
@Autowired
private PictureSearchMapper pictureSearchMapper;
@Autowired
private SysFileMapper sysFileMapper;
@Autowired
private IPictureService pictureService;
@Autowired
private RedisCache redisCache;
/**
*
*
* @param picSearchId
* @return
*/
@Override
@Transactional(readOnly = true)
public PictureSearch selectPictureSearchByPicSearchId(Long picSearchId) {
return pictureSearchMapper.selectPictureSearchByPicSearchId(picSearchId);
}
/**
*
*
* @param pictureSearch
* @return
*/
@Transactional(rollbackFor = Exception.class)
@Override
@Transactional(readOnly = true)
public List<PictureSearch> selectPictureSearchList(PictureSearch pictureSearch) {
return pictureSearchMapper.selectPictureSearchList(pictureSearch);
}
/**
*
*
* @param pictureSearch
* @return
*/
@Override
@Transactional
public int insertPictureSearch(PictureSearch pictureSearch) {
pictureSearch.setCreateTime(DateUtils.getNowDate());
return pictureSearchMapper.insertPictureSearch(pictureSearch);
}
/**
*
*
* @param pictureSearch
* @return
*/
@Override
@Transactional
public int updatePictureSearch(PictureSearch pictureSearch) {
pictureSearch.setUpdateTime(DateUtils.getNowDate());
return pictureSearchMapper.updatePictureSearch(pictureSearch);
}
/**
*
*
* @param picSearchIds
* @return
*/
@Override
@Transactional
public int deletePictureSearchByPicSearchIds(Long[] picSearchIds) {
return pictureSearchMapper.deletePictureSearchByPicSearchIds(picSearchIds);
}
/**
*
*
* @param picSearchId
* @return
*/
@Override
@Transactional
public int deletePictureSearchByPicSearchId(Long picSearchId) {
return pictureSearchMapper.deletePictureSearchByPicSearchId(picSearchId);
public List<ProductMatchDTO> searchProductByPic(SearchRequestDTO requestDTO) {
Assert.notEmpty(requestDTO.getPicKey());
SysFile sysFile = new SysFile();
sysFile.setFileUrl(requestDTO.getPicKey());
sysFile.setFileSize(requestDTO.getPicSize());
sysFile.setVersion(0);
sysFile.setDelFlag(Constants.UNDELETED);
sysFileMapper.insert(sysFile);
PictureSearch pictureSearch = new PictureSearch();
pictureSearch.setSearchFileId(sysFile.getId());
pictureSearch.setUserId(requestDTO.getUserId());
pictureSearch.setVoucherDate(new Date());
pictureSearch.setVersion(0);
pictureSearch.setDelFlag(Constants.UNDELETED);
pictureSearchMapper.insert(pictureSearch);
//搜索
List<ProductMatchDTO> results = pictureService.searchProductByPicKey(requestDTO.getPicKey(),
//默认30条
Optional.ofNullable(requestDTO.getNum()).orElse(30));
for (ProductMatchDTO result : results) {
//匹配次数+1
redisCache.valueIncr(CacheConstants.IMG_SEARCH_STATISTICS + result.getStoreProductId());
}
return results;
}
}

View File

@ -1,5 +1,7 @@
package com.ruoyi.xkt.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.lang.Assert;
@ -7,13 +9,16 @@ import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.text.CharsetKit;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.ImgExtUtil;
import com.ruoyi.framework.config.properties.OSSProperties;
import com.ruoyi.framework.img.ImgSearchClientWrapper;
import com.ruoyi.framework.img.entity.ImgAdd;
import com.ruoyi.framework.img.entity.ImgSearchReq;
import com.ruoyi.framework.oss.OSSClientWrapper;
import com.ruoyi.xkt.dto.picture.DownloadResultDTO;
import com.ruoyi.xkt.dto.picture.PicZipDTO;
import com.ruoyi.xkt.dto.picture.*;
import com.ruoyi.xkt.service.IPictureService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@ -25,7 +30,9 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author liangyq
@ -39,6 +46,8 @@ public class PictureServiceImpl implements IPictureService {
private OSSClientWrapper ossClient;
@Autowired
private OSSProperties ossProperties;
@Autowired
private ImgSearchClientWrapper imgSearchClient;
@Override
public PicZipDTO processPicZip(String key) {
@ -113,6 +122,59 @@ public class PictureServiceImpl implements IPictureService {
}
}
@Override
public ProductPicSyncResultDTO sync2ImgSearchServer(ProductPicSyncDTO productPicSyncDTO) {
Assert.notNull(productPicSyncDTO);
String productId = productPicSyncDTO.getStoreProductId().toString();
//删除商品图片
boolean allSuccess = imgSearchClient.deleteImg(productId);
List<String> picKeys = CollUtil.emptyIfNull(productPicSyncDTO.getProductPicKeys());
List<PicSyncResultDTO> picSyncResultList = new ArrayList<>(picKeys.size());
for (String picKey : picKeys) {
ImgAdd imgAdd = new ImgAdd();
imgAdd.setProductId(productId);
imgAdd.setPicName(FileUtil.getName(picKey));
imgAdd.setCategoryId(Constants.IMG_SEARCH_CATEGORY_ID);
try {
imgAdd.setPicInputStream(ossClient.getObject(picKey));
} catch (Exception e) {
log.error("获取图片流异常: " + picKey, e);
allSuccess = false;
picSyncResultList.add(new PicSyncResultDTO(picKey, false));
continue;
}
//添加商品图片
boolean success = imgSearchClient.addImg(imgAdd);
if (!success) {
allSuccess = false;
}
picSyncResultList.add(new PicSyncResultDTO(picKey, success));
}
return new ProductPicSyncResultDTO(allSuccess, picSyncResultList);
}
@Override
public List<ProductMatchDTO> searchProductByPicKey(String picKey, Integer num) {
Assert.notEmpty(picKey);
ImgSearchReq imgSearchReq = new ImgSearchReq();
imgSearchReq.setCategoryId(Constants.IMG_SEARCH_CATEGORY_ID);
imgSearchReq.setNum(num);
imgSearchReq.setStart(0);
imgSearchReq.setDistinctProductId(true);
try {
imgSearchReq.setPicInputStream(ossClient.getObject(picKey));
} catch (Exception e) {
log.error("获取图片流异常: " + picKey, e);
return ListUtil.empty();
}
return imgSearchClient.searchByPic(imgSearchReq)
.stream()
//过滤搜索评分0.5以下的商品
.filter(o -> o.getScore() >= Constants.IMG_SEARCH_MATCH_SCORE_THRESHOLD)
.map(o -> new ProductMatchDTO(Long.parseLong(o.getProductId()), o.getScore()))
.collect(Collectors.toList());
}
/**
*
* TODO zip

View File

@ -1,6 +1,10 @@
package com.ruoyi.xkt.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.json.JSONUtil;
import co.elastic.clients.elasticsearch.core.BulkResponse;
import co.elastic.clients.elasticsearch.core.CreateResponse;
import co.elastic.clients.elasticsearch.core.UpdateResponse;
@ -19,6 +23,8 @@ 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.picture.ProductPicSyncDTO;
import com.ruoyi.xkt.dto.picture.ProductPicSyncResultDTO;
import com.ruoyi.xkt.dto.storeColor.StoreColorDTO;
import com.ruoyi.xkt.dto.storeProdCateAttr.StoreProdCateAttrDTO;
import com.ruoyi.xkt.dto.storeProdColor.StoreProdColorDTO;
@ -34,8 +40,10 @@ import com.ruoyi.xkt.enums.EProductStatus;
import com.ruoyi.xkt.enums.FileType;
import com.ruoyi.xkt.enums.ProductSizeStatus;
import com.ruoyi.xkt.mapper.*;
import com.ruoyi.xkt.service.IPictureService;
import com.ruoyi.xkt.service.IStoreProductService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
@ -57,6 +65,7 @@ import static com.ruoyi.common.constant.Constants.*;
* @author ruoyi
* @date 2025-03-26
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class StoreProductServiceImpl implements IStoreProductService {
@ -80,6 +89,7 @@ public class StoreProductServiceImpl implements IStoreProductService {
final StoreProductStockMapper prodStockMapper;
final StoreCustomerMapper storeCusMapper;
final StoreCustomerProductDiscountMapper storeCusProdDiscMapper;
final IPictureService pictureService;
/**
@ -210,6 +220,8 @@ public class StoreProductServiceImpl implements IStoreProductService {
this.handleStoreProdProperties(storeProd, storeProdDTO);
// 向ES索引: product_info 创建文档
this.createESDoc(storeProd, storeProdDTO);
// 搜图服务同步
sync2ImgSearchServer(storeProd.getId(), storeProdDTO.getFileList());
return count;
}
@ -260,6 +272,8 @@ public class StoreProductServiceImpl implements IStoreProductService {
this.handleStoreProdColorSizeList(storeProdDTO.getSizeList(), storeProdId, Boolean.FALSE);
// 更新索引: product_info 的文档
this.updateESDoc(storeProd, storeProdDTO);
// 搜图服务同步
sync2ImgSearchServer(storeProd.getId(), storeProdDTO.getFileList());
return count;
}
@ -421,10 +435,20 @@ public class StoreProductServiceImpl implements IStoreProductService {
// 筛选商品状态为已下架则删除ES文档
if (Objects.equals(prodStatusDTO.getProdStatus(), EProductStatus.OFF_SALE.getValue())) {
this.deleteESDoc(prodStatusDTO.getStoreProdIdList());
// 搜图服务同步
prodStatusDTO.getStoreProdIdList().forEach(spId -> sync2ImgSearchServer(spId, ListUtil.empty()));
}
// 已下架的商品重新上架
if (CollectionUtils.isNotEmpty(reSaleList)) {
this.reSaleCreateESDoc(reSaleList);
// 搜图服务同步
Map<Long, List<String>> picKeyGroupMap = storeProdFileMapper.selectMainPicByStoreProdIdList(
reSaleList.stream().map(StoreProduct::getId).collect(Collectors.toList()),
FileType.MAIN_PIC.getValue(), null
).stream().collect(Collectors.groupingBy(StoreProdMainPicDTO::getStoreProdId,
Collectors.mapping(StoreProdMainPicDTO::getFileUrl, Collectors.toList())));
prodStatusDTO.getStoreProdIdList()
.forEach(spId -> sync2ImgSearchServer(spId, picKeyGroupMap.get(spId), true));
}
}
@ -778,4 +802,34 @@ public class StoreProductServiceImpl implements IStoreProductService {
}
}
/**
*
*
* @param storeProductId
* @param storeProdFiles
*/
private void sync2ImgSearchServer(Long storeProductId, List<StoreProdFileDTO> storeProdFiles) {
List<String> picKeys = CollUtil.emptyIfNull(storeProdFiles)
.stream()
.filter(o -> FileType.MAIN_PIC.getValue().equals(o.getFileType()))
.map(StoreProdFileDTO::getFileUrl)
.collect(Collectors.toList());
sync2ImgSearchServer(storeProductId, picKeys, true);
}
private void sync2ImgSearchServer(Long storeProductId, List<String> picKeys, boolean async) {
if (async) {
ThreadUtil.execAsync(() -> {
ProductPicSyncResultDTO r =
pictureService.sync2ImgSearchServer(new ProductPicSyncDTO(storeProductId, picKeys));
log.info("商品图片同步至搜图服务器: id: {}, result: {}", storeProductId, JSONUtil.toJsonStr(r));
}
);
} else {
ProductPicSyncResultDTO r =
pictureService.sync2ImgSearchServer(new ProductPicSyncDTO(storeProductId, picKeys));
log.info("商品图片同步至搜图服务器: id: {}, result: {}", storeProductId, JSONUtil.toJsonStr(r));
}
}
}

View File

@ -4,88 +4,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.xkt.mapper.PictureSearchMapper">
<resultMap type="PictureSearch" id="PictureSearchResult">
<result property="id" column="id" />
<result property="searchFileId" column="search_file_id" />
<result property="userId" column="user_id" />
<result property="voucherDate" column="voucher_date" />
<result property="version" column="version" />
<result property="delFlag" column="del_flag" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
</resultMap>
<sql id="selectPictureSearchVo">
select id, search_file_id, user_id, voucher_date, version, del_flag, create_by, create_time, update_by, update_time from picture_search
</sql>
<select id="selectPictureSearchList" parameterType="PictureSearch" resultMap="PictureSearchResult">
<include refid="selectPictureSearchVo"/>
<where>
<if test="searchFileId != null "> and search_file_id = #{searchFileId}</if>
<if test="userId != null "> and user_id = #{userId}</if>
<if test="voucherDate != null "> and voucher_date = #{voucherDate}</if>
<if test="version != null "> and version = #{version}</if>
</where>
</select>
<select id="selectPictureSearchByPicSearchId" parameterType="Long" resultMap="PictureSearchResult">
<include refid="selectPictureSearchVo"/>
where id = #{id}
</select>
<insert id="insertPictureSearch" parameterType="PictureSearch" useGeneratedKeys="true" keyProperty="picSearchId">
insert into picture_search
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="searchFileId != null">search_file_id,</if>
<if test="userId != null">user_id,</if>
<if test="voucherDate != null">voucher_date,</if>
<if test="version != null">version,</if>
<if test="delFlag != null">del_flag,</if>
<if test="createBy != null">create_by,</if>
<if test="createTime != null">create_time,</if>
<if test="updateBy != null">update_by,</if>
<if test="updateTime != null">update_time,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="searchFileId != null">#{searchFileId},</if>
<if test="userId != null">#{userId},</if>
<if test="voucherDate != null">#{voucherDate},</if>
<if test="version != null">#{version},</if>
<if test="delFlag != null">#{delFlag},</if>
<if test="createBy != null">#{createBy},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateBy != null">#{updateBy},</if>
<if test="updateTime != null">#{updateTime},</if>
</trim>
</insert>
<update id="updatePictureSearch" parameterType="PictureSearch">
update picture_search
<trim prefix="SET" suffixOverrides=",">
<if test="searchFileId != null">search_file_id = #{searchFileId},</if>
<if test="userId != null">user_id = #{userId},</if>
<if test="voucherDate != null">voucher_date = #{voucherDate},</if>
<if test="version != null">version = #{version},</if>
<if test="delFlag != null">del_flag = #{delFlag},</if>
<if test="createBy != null">create_by = #{createBy},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="updateBy != null">update_by = #{updateBy},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
</trim>
where id = #{id}
</update>
<delete id="deletePictureSearchByPicSearchId" parameterType="Long">
delete from picture_search where id = #{id}
</delete>
<delete id="deletePictureSearchByPicSearchIds" parameterType="String">
delete from picture_search where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>

View File

@ -135,8 +135,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#{storeProdId}
</foreach>
</if>
AND spf.file_type = #{fileType}
AND spf.order_num = #{orderNum}
<if test="fileType != null">
AND spf.file_type = #{fileType}
</if>
<if test="orderNum != null">
AND spf.order_num = #{orderNum}
</if>
</select>
<select id="selectPicSpaceList" >