mirror of
https://github.com/kirklin/kkmall.git
synced 2024-09-20 06:46:15 +08:00
增加ES搜索服务
商城业务-->商品上架功能
This commit is contained in:
parent
119ab6fa81
commit
b25c34edb8
|
@ -0,0 +1,124 @@
|
|||
package name.lkk.common.to.es;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Title: SkuEsModel</p>
|
||||
* Description:
|
||||
* "mappings": {
|
||||
* "properties": {
|
||||
* "skuId":{
|
||||
* "type": "long"
|
||||
* },
|
||||
* "spuId":{
|
||||
* "type": "keyword"
|
||||
* },
|
||||
* "skuTitle":{
|
||||
* "type": "text",
|
||||
* "analyzer": "ik_smart"
|
||||
* },
|
||||
* "skuPrice":{
|
||||
* "type": "keyword"
|
||||
* },
|
||||
* "skuImg":{
|
||||
* "type": "keyword",
|
||||
* "index": false,
|
||||
* "doc_values": false
|
||||
* },
|
||||
* "saleCount":{
|
||||
* "type": "long"
|
||||
* },
|
||||
* "hasStock":{
|
||||
* "type": "boolean"
|
||||
* },
|
||||
* "hotScore":{
|
||||
* "type": "long"
|
||||
* },
|
||||
* "brandId":{
|
||||
* "type": "long"
|
||||
* },
|
||||
* "catalogId":{
|
||||
* "type": "long"
|
||||
* },
|
||||
* "brandName":{
|
||||
* "type":"keyword",
|
||||
* "index": false,
|
||||
* "doc_values": false
|
||||
* },
|
||||
* "brandImg":{
|
||||
* "type": "keyword",
|
||||
* "index": false,
|
||||
* "doc_values": false
|
||||
* },
|
||||
* "catalogName":{
|
||||
* "type": "keyword",
|
||||
* "index": false,
|
||||
* "doc_values": false
|
||||
* },
|
||||
* "attrs":{
|
||||
* "type": "nested",
|
||||
* "properties": {
|
||||
* "attrId":{
|
||||
* "type":"long"
|
||||
* },
|
||||
* "attrName":{
|
||||
* "type":"keyword",
|
||||
* "index":false,
|
||||
* "doc_values": false
|
||||
* },
|
||||
* "attrValue":{
|
||||
* "type":"keyword"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* date:2020/6/8 18:52
|
||||
*/
|
||||
@Data
|
||||
public class SkuEsModel implements Serializable {
|
||||
|
||||
private Long skuId;
|
||||
|
||||
private Long spuId;
|
||||
|
||||
private String skuTitle;
|
||||
|
||||
private BigDecimal skuPrice;
|
||||
|
||||
private String skuImg;
|
||||
|
||||
private Long saleCount;
|
||||
|
||||
private Boolean hasStock;
|
||||
|
||||
private Long hotScore;
|
||||
|
||||
private Long brandId;
|
||||
|
||||
private Long catalogId;
|
||||
|
||||
private String brandName;
|
||||
|
||||
private String brandImg;
|
||||
|
||||
private String catalogName;
|
||||
|
||||
private List<Attrs> attrs;
|
||||
|
||||
/**
|
||||
* 检索属性
|
||||
*/
|
||||
@Data
|
||||
public static class Attrs implements Serializable{
|
||||
private Long attrId;
|
||||
|
||||
private String attrName;
|
||||
|
||||
private String attrValue;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package name.lkk.common.to.es;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* <p>Title: SkuHasStockVo</p>
|
||||
* Description:存储这个sku是否有库存
|
||||
* date:2020/6/8 20:10
|
||||
*/
|
||||
@Data
|
||||
public class SkuHasStockVo {
|
||||
|
||||
private Long skuId;
|
||||
|
||||
private Boolean hasStock;
|
||||
}
|
|
@ -34,6 +34,14 @@ public class SpuInfoController {
|
|||
return R.ok().setData(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品上架
|
||||
*/
|
||||
@PostMapping("/{spuId}/up")
|
||||
public R up(@PathVariable("spuId") Long spuId){
|
||||
spuInfoService.up(spuId);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* spu管理的查询
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
package name.lkk.kkmall.product.dao;
|
||||
|
||||
import name.lkk.kkmall.product.entity.SpuInfoEntity;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import name.lkk.kkmall.product.entity.SpuInfoEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* spu信息
|
||||
|
@ -13,5 +14,8 @@ import org.apache.ibatis.annotations.Mapper;
|
|||
*/
|
||||
@Mapper
|
||||
public interface SpuInfoDao extends BaseMapper<SpuInfoEntity> {
|
||||
|
||||
/**
|
||||
* 修改上架成功的商品的状态
|
||||
*/
|
||||
void updateSpuStatus(@Param("spuId") Long spuId, @Param("code") int code);
|
||||
}
|
||||
|
|
|
@ -9,9 +9,7 @@ import org.springframework.web.bind.annotation.PostMapping;
|
|||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
/**
|
||||
* <p>Title: CouponFeignService</p>
|
||||
* Description:远程调用优惠券服务
|
||||
* date:2020/6/5 17:06
|
||||
* 远程调用优惠券服务
|
||||
*/
|
||||
@FeignClient("kkmall-coupon")
|
||||
public interface CouponFeignService {
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package name.lkk.kkmall.product.feign;
|
||||
|
||||
|
||||
import name.lkk.common.to.es.SkuEsModel;
|
||||
import name.lkk.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;
|
||||
|
||||
/**
|
||||
* 远程上架商品
|
||||
*/
|
||||
@FeignClient("kkmall-search")
|
||||
public interface SearchFeignService {
|
||||
|
||||
@PostMapping("/search/save/product")
|
||||
R productStatusUp(@RequestBody List<SkuEsModel> skuEsModels);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package name.lkk.kkmall.product.feign;
|
||||
|
||||
import name.lkk.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;
|
||||
|
||||
/**
|
||||
* 远程调用库存服务
|
||||
*/
|
||||
@FeignClient("kkmall-ware")
|
||||
public interface WareFeignService {
|
||||
|
||||
/**
|
||||
* 修改整个系统的 R 带上泛型
|
||||
*/
|
||||
@PostMapping("/ware/waresku/hasStock")
|
||||
R getSkuHasStock(@RequestBody List<Long> SkuIds);
|
||||
}
|
|
@ -32,5 +32,11 @@ public interface SpuInfoService extends IService<SpuInfoEntity> {
|
|||
SpuInfoEntity getSpuInfoBySkuId(Long skuId);
|
||||
|
||||
void saveSpuInfo(SpuSaveVo vo);
|
||||
|
||||
/**
|
||||
* 商品上架
|
||||
* @param spuId
|
||||
*/
|
||||
void up(Long spuId);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,22 @@
|
|||
package name.lkk.kkmall.product.service.impl;
|
||||
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import name.lkk.common.constant.ProductConstant;
|
||||
import name.lkk.common.to.SkuReductionTO;
|
||||
import name.lkk.common.to.SpuBoundTO;
|
||||
import name.lkk.common.to.es.SkuEsModel;
|
||||
import name.lkk.common.to.es.SkuHasStockVo;
|
||||
import name.lkk.common.utils.PageUtils;
|
||||
import name.lkk.common.utils.Query;
|
||||
import name.lkk.common.utils.R;
|
||||
import name.lkk.kkmall.product.dao.SpuInfoDao;
|
||||
import name.lkk.kkmall.product.entity.*;
|
||||
import name.lkk.kkmall.product.feign.CouponFeignService;
|
||||
import name.lkk.kkmall.product.feign.SearchFeignService;
|
||||
import name.lkk.kkmall.product.feign.WareFeignService;
|
||||
import name.lkk.kkmall.product.service.*;
|
||||
import name.lkk.kkmall.product.vo.*;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
@ -20,9 +26,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
|
@ -52,12 +56,27 @@ public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> i
|
|||
@Autowired
|
||||
private SkuSaleAttrValueService skuSaleAttrValueService;
|
||||
|
||||
@Autowired
|
||||
private BrandService brandService;
|
||||
|
||||
@Autowired
|
||||
private CategoryService categoryService;
|
||||
|
||||
/**
|
||||
* feign 远程调用优惠券服务
|
||||
*/
|
||||
@Autowired
|
||||
private CouponFeignService couponFeignService;
|
||||
|
||||
/**
|
||||
* feign 远程调用库存服务
|
||||
*/
|
||||
@Autowired
|
||||
private WareFeignService wareFeignService;
|
||||
/**
|
||||
* feign 远程调用ES服务
|
||||
*/
|
||||
@Autowired
|
||||
private SearchFeignService searchFeignService;
|
||||
|
||||
@Override
|
||||
public PageUtils queryPage(Map<String, Object> params) {
|
||||
|
@ -228,4 +247,82 @@ public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> i
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void up(Long spuId) {
|
||||
// 1 组装数据 查出当前spuId对应的所有sku信息
|
||||
List<SkuInfoEntity> skus = skuInfoService.getSkusBySpuId(spuId);
|
||||
// 查询这些sku是否有库存
|
||||
List<Long> skuids = skus.stream().map(SkuInfoEntity::getSkuId).collect(Collectors.toList());
|
||||
// 2 封装每个sku的信息
|
||||
|
||||
// 3.查询当前sku所有可以被用来检索的规格属性
|
||||
// 获取所有的spu商品的id 然后查询这些id中那些是可以被检索的 [数据库中目前 4、5、6、11不可检索]
|
||||
List<ProductAttrValueEntity> baseAttrs = attrValueService.baseAttrListForSpu(spuId);
|
||||
|
||||
List<Long> attrIds = baseAttrs.stream().map(ProductAttrValueEntity::getAttrId).collect(Collectors.toList());
|
||||
// 可检索的id集合
|
||||
Set<Long> isSet = new HashSet<>(attrService.selectSearchAttrIds(attrIds));
|
||||
|
||||
// 根据商品id 过滤不可检索的商品 最后映射号检索属性
|
||||
List<SkuEsModel.Attrs> attrs = baseAttrs.stream().filter(item -> isSet.contains(item.getAttrId())).map(item -> {
|
||||
SkuEsModel.Attrs attr = new SkuEsModel.Attrs();
|
||||
BeanUtils.copyProperties(item, attr);
|
||||
return attr;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
// skuId 对应 是否有库存
|
||||
Map<Long, Boolean> stockMap = null;
|
||||
try {
|
||||
// 3.1 发送远程调用 库存系统查询是否有库存
|
||||
R hasStock = wareFeignService.getSkuHasStock(skuids);
|
||||
// 构造器受保护 所以写成内部类对象
|
||||
stockMap = hasStock.getData(new TypeReference<List<SkuHasStockVo>>(){}).stream().collect(Collectors.toMap(SkuHasStockVo::getSkuId, item -> item.getHasStock()));
|
||||
log.warn("服务调用成功" + hasStock);
|
||||
} catch (Exception e) {
|
||||
log.error("库存服务调用失败: 原因{}",e);
|
||||
}
|
||||
|
||||
Map<Long, Boolean> finalStockMap = stockMap;
|
||||
List<SkuEsModel> collect = skus.stream().map(sku -> {
|
||||
SkuEsModel esModel = new SkuEsModel();
|
||||
BeanUtils.copyProperties(sku, esModel);
|
||||
esModel.setSkuPrice(sku.getPrice());
|
||||
esModel.setSkuImg(sku.getSkuDefaultImg());
|
||||
// 4 设置库存
|
||||
if(finalStockMap == null){
|
||||
esModel.setHasStock(true);
|
||||
}else {
|
||||
esModel.setHasStock(finalStockMap.get(sku.getSkuId()));
|
||||
}
|
||||
// TODO 1.热度评分 0
|
||||
esModel.setHotScore(0L);
|
||||
|
||||
BrandEntity brandEntity = brandService.getById(esModel.getBrandId());
|
||||
|
||||
// brandName、brandImg
|
||||
esModel.setBrandName(brandEntity.getName());
|
||||
esModel.setBrandImg(brandEntity.getLogo());
|
||||
|
||||
// 查询分类信息
|
||||
CategoryEntity categoryEntity = categoryService.getById(esModel.getCatalogId());
|
||||
esModel.setCatalogName(categoryEntity.getName());
|
||||
|
||||
// 保存商品的属性
|
||||
esModel.setAttrs(attrs);
|
||||
return esModel;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
// 5.发给ES进行保存 mall-search
|
||||
R r = searchFeignService.productStatusUp(collect);
|
||||
if(r.getCode() == 0){
|
||||
// 远程调用成功
|
||||
baseMapper.updateSpuStatus(spuId, ProductConstant.StatusEnum.SPU_UP.getCode());
|
||||
}else{
|
||||
// 远程调用失败 TODO 接口幂等性 重试机制
|
||||
/**
|
||||
* Feign 的调用流程 Feign有自动重试机制
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -15,6 +15,9 @@
|
|||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
</resultMap>
|
||||
<update id="updateSpuStatus">
|
||||
UPDATE `pms_spu_info` SET publish_status = #{code}, update_time = NOW() WHERE id = #{spuId}
|
||||
</update>
|
||||
|
||||
|
||||
</mapper>
|
83
kkmall-search/pom.xml
Normal file
83
kkmall-search/pom.xml
Normal file
|
@ -0,0 +1,83 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.5.0</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>cn.kirklin.kkmall</groupId>
|
||||
<artifactId>kkmall-search</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>kkmall-search</name>
|
||||
<description>Demo project for Spring Boot</description>
|
||||
<properties>
|
||||
<spring-cloud.version>2020.0.3</spring-cloud.version>
|
||||
<elasticsearch.version>7.13.2</elasticsearch.version>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>name.lkk.kkmall</groupId>
|
||||
<artifactId>kkmall-common</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<exclusions>
|
||||
<!-- 排除 Mybatis-Plus -->
|
||||
<exclusion>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.elasticsearch.client</groupId>
|
||||
<artifactId>elasticsearch-rest-high-level-client</artifactId>
|
||||
<version>${elasticsearch.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-dependencies</artifactId>
|
||||
<version>${spring-cloud.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,15 @@
|
|||
package cn.kirklin.kkmall.search;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
|
||||
@EnableDiscoveryClient
|
||||
@SpringBootApplication
|
||||
public class KkmallSearchApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(KkmallSearchApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package cn.kirklin.kkmall.search.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class Account {
|
||||
|
||||
private int accountNumber;
|
||||
|
||||
private int balance;
|
||||
|
||||
private String firstname;
|
||||
|
||||
private String lastname;
|
||||
|
||||
private int age;
|
||||
|
||||
private String gender;
|
||||
|
||||
private String address;
|
||||
|
||||
private String employer;
|
||||
|
||||
private String email;
|
||||
|
||||
private String city;
|
||||
|
||||
private String state;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package cn.kirklin.kkmall.search.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class User {
|
||||
private String userName;
|
||||
|
||||
private String gender;
|
||||
|
||||
private String age;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package cn.kirklin.kkmall.search.config;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.elasticsearch.client.RequestOptions;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.elasticsearch.client.RestHighLevelClient;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author: kirklin
|
||||
* @date: 2021/6/21 9:59 下午
|
||||
* @description:
|
||||
*/
|
||||
@Configuration
|
||||
public class MallElasticSearchConfig {
|
||||
|
||||
public static final RequestOptions COMMON_OPTIONS;
|
||||
|
||||
static {
|
||||
RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
|
||||
// builder.addHeader("Authorization", "Bearer " + TOKEN);
|
||||
// builder.setHttpAsyncResponseConsumerFactory(
|
||||
// new HttpAsyncResponseConsumerFactory
|
||||
// .HeapBufferedResponseConsumerFactory(30 * 1024 * 1024 * 1024));
|
||||
COMMON_OPTIONS = builder.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RestHighLevelClient esRestClient(){
|
||||
RestHighLevelClient client = new RestHighLevelClient(
|
||||
RestClient.builder(
|
||||
new HttpHost("localhost", 9200, "http")));
|
||||
return client;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package cn.kirklin.kkmall.search.constant;
|
||||
|
||||
/**
|
||||
* ES常量
|
||||
* @author kirklin
|
||||
*/
|
||||
public class EsConstant {
|
||||
|
||||
/**
|
||||
* sku数据在ES中的索引
|
||||
*/
|
||||
public static final String PRODUCT_INDEX = "product";
|
||||
|
||||
/**
|
||||
* 分页的大小
|
||||
*/
|
||||
public static final int PRODUCT_PAGE_SIZE = 2;
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package cn.kirklin.kkmall.search.controller;
|
||||
|
||||
/**
|
||||
* @author: kirklin
|
||||
* @date: 2021/6/22 3:42 下午
|
||||
* @description:
|
||||
*/
|
||||
|
||||
import cn.kirklin.kkmall.search.service.ProductSaveService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import name.lkk.common.exception.BizCodeEnum;
|
||||
import name.lkk.common.to.es.SkuEsModel;
|
||||
import name.lkk.common.utils.R;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 商品上架
|
||||
*/
|
||||
@Slf4j
|
||||
@RequestMapping("/search/save")
|
||||
@RestController
|
||||
public class ElasticSaveController {
|
||||
|
||||
@Autowired
|
||||
private ProductSaveService productSaveService;
|
||||
|
||||
/**
|
||||
* 上架商品
|
||||
*/
|
||||
@PostMapping("/product")
|
||||
public R productStatusUp(@RequestBody List<SkuEsModel> skuEsModels){
|
||||
|
||||
boolean status;
|
||||
try {
|
||||
status = productSaveService.productStatusUp(skuEsModels);
|
||||
} catch (IOException e) {
|
||||
log.error("ElasticSaveController商品上架错误: {}", e);
|
||||
return R.error(BizCodeEnum.PRODUCT_UP_EXCEPTION.getCode(), BizCodeEnum.PRODUCT_UP_EXCEPTION.getMsg());
|
||||
}
|
||||
if(!status){
|
||||
return R.ok();
|
||||
}
|
||||
return R.error(BizCodeEnum.PRODUCT_UP_EXCEPTION.getCode(), BizCodeEnum.PRODUCT_UP_EXCEPTION.getMsg());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package cn.kirklin.kkmall.search.service;
|
||||
|
||||
import name.lkk.common.to.es.SkuEsModel;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author: kirklin
|
||||
* @date: 2021/6/22 3:43 下午
|
||||
* @description:
|
||||
*/
|
||||
public interface ProductSaveService {
|
||||
|
||||
boolean productStatusUp(List<SkuEsModel> skuEsModels) throws IOException;
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package cn.kirklin.kkmall.search.service.impl;
|
||||
|
||||
import cn.kirklin.kkmall.search.config.MallElasticSearchConfig;
|
||||
import cn.kirklin.kkmall.search.constant.EsConstant;
|
||||
import cn.kirklin.kkmall.search.service.ProductSaveService;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import name.lkk.common.to.es.SkuEsModel;
|
||||
import org.elasticsearch.action.bulk.BulkItemResponse;
|
||||
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.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class ProductSaveServiceImpl implements ProductSaveService {
|
||||
|
||||
@Resource
|
||||
private RestHighLevelClient client;
|
||||
|
||||
/**
|
||||
* 将数据保存到ES
|
||||
* BulkRequest bulkRequest, RequestOptions options
|
||||
*/
|
||||
@Override
|
||||
public boolean productStatusUp(List<SkuEsModel> skuEsModels) throws IOException {
|
||||
// 1.给ES建立一个索引 product
|
||||
BulkRequest bulkRequest = new BulkRequest();
|
||||
// 2.构造保存请求
|
||||
for (SkuEsModel esModel : skuEsModels) {
|
||||
IndexRequest indexRequest = new IndexRequest(EsConstant.PRODUCT_INDEX);
|
||||
// 设置索引id
|
||||
indexRequest.id(esModel.getSkuId().toString());
|
||||
String jsonString = JSON.toJSONString(esModel);
|
||||
indexRequest.source(jsonString, XContentType.JSON);
|
||||
bulkRequest.add(indexRequest);
|
||||
}
|
||||
BulkResponse bulk = client.bulk(bulkRequest, MallElasticSearchConfig.COMMON_OPTIONS);
|
||||
// TODO 是否拥有错误
|
||||
boolean hasFailures = bulk.hasFailures();
|
||||
if(hasFailures){
|
||||
List<String> collect = Arrays.stream(bulk.getItems()).map(BulkItemResponse::getId).collect(Collectors.toList());
|
||||
log.error("商品上架错误:{}",collect);
|
||||
}
|
||||
return hasFailures;
|
||||
}
|
||||
}
|
71
kkmall-search/src/main/resources/ES中product的索引.txt
Normal file
71
kkmall-search/src/main/resources/ES中product的索引.txt
Normal file
|
@ -0,0 +1,71 @@
|
|||
PUT product
|
||||
{
|
||||
"mappings": {
|
||||
"properties": {
|
||||
"skuId":{
|
||||
"type": "long"
|
||||
},
|
||||
"spuId":{
|
||||
"type": "keyword"
|
||||
},
|
||||
"skuTitle":{
|
||||
"type": "text",
|
||||
"analyzer": "ik_smart"
|
||||
},
|
||||
"skuPrice":{
|
||||
"type": "keyword"
|
||||
},
|
||||
"skuImg":{
|
||||
"type": "keyword",
|
||||
"index": false,
|
||||
"doc_values": false
|
||||
},
|
||||
"saleCount":{
|
||||
"type": "long"
|
||||
},
|
||||
"hasStock":{
|
||||
"type": "boolean"
|
||||
},
|
||||
"hotScore":{
|
||||
"type": "long"
|
||||
},
|
||||
"brandId":{
|
||||
"type": "long"
|
||||
},
|
||||
"catalogId":{
|
||||
"type": "long"
|
||||
},
|
||||
"brandName":{
|
||||
"type":"keyword",
|
||||
"index": false,
|
||||
"doc_values": false
|
||||
},
|
||||
"brandImg":{
|
||||
"type": "keyword",
|
||||
"index": false,
|
||||
"doc_values": false
|
||||
},
|
||||
"catalogName":{
|
||||
"type": "keyword",
|
||||
"index": false,
|
||||
"doc_values": false
|
||||
},
|
||||
"attrs":{
|
||||
"type": "nested",
|
||||
"properties": {
|
||||
"attrId":{
|
||||
"type":"long"
|
||||
},
|
||||
"attrName":{
|
||||
"type":"keyword",
|
||||
"index":false,
|
||||
"doc_values": false
|
||||
},
|
||||
"attrValue":{
|
||||
"type":"keyword"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
9
kkmall-search/src/main/resources/application.yml
Normal file
9
kkmall-search/src/main/resources/application.yml
Normal file
|
@ -0,0 +1,9 @@
|
|||
server:
|
||||
port: 12000
|
||||
spring:
|
||||
application:
|
||||
name: kkmall-search
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: localhost:8848
|
|
@ -0,0 +1,128 @@
|
|||
package cn.kirklin.kkmall.search;
|
||||
|
||||
import cn.kirklin.kkmall.search.bean.Account;
|
||||
import cn.kirklin.kkmall.search.bean.User;
|
||||
import cn.kirklin.kkmall.search.config.MallElasticSearchConfig;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.elasticsearch.action.index.IndexRequest;
|
||||
import org.elasticsearch.action.index.IndexResponse;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.client.RestHighLevelClient;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
import org.elasticsearch.search.SearchHits;
|
||||
import org.elasticsearch.search.aggregations.AggregationBuilders;
|
||||
import org.elasticsearch.search.aggregations.Aggregations;
|
||||
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
|
||||
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
|
||||
import org.elasticsearch.search.aggregations.metrics.Avg;
|
||||
import org.elasticsearch.search.aggregations.metrics.AvgAggregationBuilder;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@SpringBootTest
|
||||
class KkmallSearchApplicationTests {
|
||||
|
||||
@Autowired
|
||||
RestHighLevelClient client;
|
||||
|
||||
@Test
|
||||
@DisplayName("测试RestHighLevelClient是否存在")
|
||||
void contextLoads() {
|
||||
System.out.println(client);
|
||||
}
|
||||
/**
|
||||
* 检索数据
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("测试ES检索数据")
|
||||
public void searchDataTest() throws IOException {
|
||||
SearchRequest searchRequest = new SearchRequest();
|
||||
|
||||
// 指定索引
|
||||
searchRequest.indices("bank");
|
||||
|
||||
// 1.指定检索条件 DSL
|
||||
SearchSourceBuilder builder = new SearchSourceBuilder();
|
||||
// 1.1 构造检索条件
|
||||
builder.query(QueryBuilders.matchQuery("address","mill"));
|
||||
|
||||
// 1.2 按照年龄值聚合
|
||||
TermsAggregationBuilder ageAgg = AggregationBuilders.terms("ageAgg").field("age").size(10);
|
||||
builder.aggregation(ageAgg);
|
||||
// 1.3 计算平均薪资
|
||||
AvgAggregationBuilder balanceAvg = AggregationBuilders.avg("balanceAvg").field("balance");
|
||||
builder.aggregation(balanceAvg);
|
||||
|
||||
System.out.println("检索条件:" + builder);
|
||||
searchRequest.source(builder);
|
||||
|
||||
// 2.执行检索
|
||||
SearchResponse search = client.search(searchRequest, MallElasticSearchConfig.COMMON_OPTIONS);
|
||||
|
||||
// 3.分析结果
|
||||
// Map map = JSON.parseObject(search.toString(), Map.class);
|
||||
// System.out.println(map);
|
||||
// 3.1 索取所有记录
|
||||
SearchHits hits = search.getHits();
|
||||
// 详细记录
|
||||
SearchHit[] searchHits = hits.getHits();
|
||||
for (SearchHit hit : searchHits) {
|
||||
// String index = hit.getIndex();
|
||||
// String id = hit.getId();
|
||||
String source = hit.getSourceAsString();
|
||||
Account account = JSON.parseObject(source, Account.class);
|
||||
System.out.println(account);
|
||||
}
|
||||
// 获取分析数据
|
||||
Aggregations aggregations = search.getAggregations();
|
||||
// List<Aggregation> list = aggregations.asList();
|
||||
// for (Aggregation aggregation : list) {
|
||||
// Terms agg = aggregations.get(aggregation.getName());
|
||||
// System.out.println(agg.getBuckets());
|
||||
// }
|
||||
Terms agg = aggregations.get("ageAgg");
|
||||
for (Terms.Bucket bucket : agg.getBuckets()) {
|
||||
System.out.println("年龄: " + bucket.getKeyAsString() + "-->" + bucket.getDocCount() + "人");
|
||||
}
|
||||
|
||||
Avg avg = aggregations.get("balanceAvg");
|
||||
System.out.println("平均薪资: " + avg.getValue());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入数据
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("测试ES插入数据")
|
||||
public void indexTest() throws IOException {
|
||||
IndexRequest request = new IndexRequest("users");
|
||||
// 设置索引id
|
||||
request.id("2");
|
||||
// 第1种方式
|
||||
// request.source("userName","firenay","age","20","gender","男");
|
||||
|
||||
// 第2种方式
|
||||
User user = new User();
|
||||
user.setUserName("kk");
|
||||
user.setAge("20");
|
||||
user.setGender("男");
|
||||
String jsonString = JSON.toJSONString(user);
|
||||
// 传入json时 指定类型
|
||||
request.source(jsonString, XContentType.JSON);
|
||||
|
||||
// 执行保存操作
|
||||
IndexResponse response = client.index(request, MallElasticSearchConfig.COMMON_OPTIONS);
|
||||
|
||||
System.out.println(response);
|
||||
System.out.println(response.status());
|
||||
}
|
||||
}
|
|
@ -1,19 +1,16 @@
|
|||
package name.lkk.kkmall.ware.controller;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import name.lkk.kkmall.ware.entity.WareSkuEntity;
|
||||
import name.lkk.kkmall.ware.service.WareSkuService;
|
||||
import name.lkk.common.to.es.SkuHasStockVo;
|
||||
import name.lkk.common.utils.PageUtils;
|
||||
import name.lkk.common.utils.R;
|
||||
import name.lkk.kkmall.ware.entity.WareSkuEntity;
|
||||
import name.lkk.kkmall.ware.service.WareSkuService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
|
||||
|
@ -29,7 +26,15 @@ import name.lkk.common.utils.R;
|
|||
public class WareSkuController {
|
||||
@Autowired
|
||||
private WareSkuService wareSkuService;
|
||||
|
||||
/**
|
||||
* 查询sku是否有库存
|
||||
* 返回当前id stock量
|
||||
*/
|
||||
@PostMapping("/hasStock")
|
||||
public R getSkuHasStock(@RequestBody List<Long> skuIds){
|
||||
List<SkuHasStockVo> vos = wareSkuService.getSkuHasStock(skuIds);
|
||||
return R.ok().setData(vos);
|
||||
}
|
||||
/**
|
||||
* 列表
|
||||
*/
|
||||
|
|
|
@ -17,4 +17,10 @@ public interface WareSkuDao extends BaseMapper<WareSkuEntity> {
|
|||
|
||||
void addStock(@Param("skuId") Long skuId, @Param("wareId") Long wareId, @Param("skuNum") Integer skuNum);
|
||||
|
||||
/**
|
||||
* 查询是否有库存
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
Long getSkuStock(Long id);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package name.lkk.kkmall.ware.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import name.lkk.common.to.es.SkuHasStockVo;
|
||||
import name.lkk.common.utils.PageUtils;
|
||||
import name.lkk.kkmall.ware.entity.WareSkuEntity;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@ -22,5 +24,11 @@ public interface WareSkuService extends IService<WareSkuEntity> {
|
|||
*/
|
||||
double addStock(Long skuId, Long wareId, Integer skuNum);
|
||||
|
||||
/**
|
||||
* 查询sku是否有库存
|
||||
* @param skuIds
|
||||
* @return
|
||||
*/
|
||||
List<SkuHasStockVo> getSkuHasStock(List<Long> skuIds);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package name.lkk.kkmall.ware.service.impl;
|
|||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import name.lkk.common.to.es.SkuHasStockVo;
|
||||
import name.lkk.common.utils.PageUtils;
|
||||
import name.lkk.common.utils.Query;
|
||||
import name.lkk.common.utils.R;
|
||||
|
@ -17,6 +18,7 @@ import org.springframework.util.ObjectUtils;
|
|||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
@Service("wareSkuService")
|
||||
|
@ -87,5 +89,21 @@ public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> i
|
|||
return price;
|
||||
}
|
||||
|
||||
/**
|
||||
* 这里存过库存数量
|
||||
* SELECT SUM(stock - stock_locked) FROM `wms_ware_sku` WHERE sku_id = 1
|
||||
*/
|
||||
@Override
|
||||
public List<SkuHasStockVo> getSkuHasStock(List<Long> skuIds) {
|
||||
return skuIds.stream().map(id -> {
|
||||
SkuHasStockVo stockVo = new SkuHasStockVo();
|
||||
|
||||
// 查询当前sku的总库存量
|
||||
stockVo.setSkuId(id);
|
||||
// 这里库存可能为null 要避免空指针异常
|
||||
stockVo.setHasStock(baseMapper.getSkuStock(id)==null?false:true);
|
||||
return stockVo;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
|
@ -16,5 +16,8 @@
|
|||
<insert id="addStock">
|
||||
UPDATE `wms_ware_sku` SET stock = stock + #{skuNum} WHERE sku_id = #{skuId} AND ware_id = #{wareId}
|
||||
</insert>
|
||||
<select id="getSkuStock" resultType="java.lang.Long">
|
||||
SELECT SUM(stock - stock_locked) FROM `wms_ware_sku` WHERE sku_id = #{id}
|
||||
</select>
|
||||
|
||||
</mapper>
|
Loading…
Reference in a new issue