商品上架功能实现

develop
ddyd 2 weeks ago
parent 7ae2f66ea4
commit 77d56ad27c

@ -6,11 +6,7 @@ import java.util.Map;
import com.bookstore.bookmall.product.vo.SpuSaveVo; import com.bookstore.bookmall.product.vo.SpuSaveVo;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.*;
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 com.bookstore.bookmall.product.entity.SpuInfoEntity; import com.bookstore.bookmall.product.entity.SpuInfoEntity;
import com.bookstore.bookmall.product.service.SpuInfoService; import com.bookstore.bookmall.product.service.SpuInfoService;
@ -32,6 +28,17 @@ public class SpuInfoController {
@Autowired @Autowired
private SpuInfoService spuInfoService; private SpuInfoService spuInfoService;
//POST /product/spuinfo/{spuId}/up 商品上架保存在es
@PostMapping("/{spuId}/up")
//@RequiresPermissions("product:spuinfo:list")
public R list(@PathVariable("spuId") Long spuId){
spuInfoService.up(spuId);
return R.ok();
}
/** /**
* *
*/ */

@ -3,6 +3,9 @@ package com.bookstore.bookmall.product.dao;
import com.bookstore.bookmall.product.entity.AttrEntity; import com.bookstore.bookmall.product.entity.AttrEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/** /**
* *
@ -13,5 +16,6 @@ import org.apache.ibatis.annotations.Mapper;
*/ */
@Mapper @Mapper
public interface AttrDao extends BaseMapper<AttrEntity> { public interface AttrDao extends BaseMapper<AttrEntity> {
List<Long> selectSearchAttrIds(@Param("attrIds") List<Long> attrIds);
} }

@ -3,6 +3,7 @@ package com.bookstore.bookmall.product.dao;
import com.bookstore.bookmall.product.entity.SpuInfoEntity; import com.bookstore.bookmall.product.entity.SpuInfoEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/** /**
* spu * spu
@ -13,5 +14,6 @@ import org.apache.ibatis.annotations.Mapper;
*/ */
@Mapper @Mapper
public interface SpuInfoDao extends BaseMapper<SpuInfoEntity> { public interface SpuInfoDao extends BaseMapper<SpuInfoEntity> {
void updateSpuStatus(@Param("spuId") Long spuId, @Param("code") int code);
} }

@ -0,0 +1,16 @@
package com.bookstore.bookmall.product.feign;
import com.bookstore.common.to.es.SkuEsModel;
import com.bookstore.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("mall-search")
public interface SearchFeignService {
@PostMapping("/search/save/product")
R productStatusUp(@RequestBody List<SkuEsModel> skuEsModels);
}

@ -0,0 +1,19 @@
package com.bookstore.bookmall.product.feign;
import com.bookstore.bookmall.product.to.SkuHasStockTo;
import com.bookstore.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("mall-ware")
public interface WareFeignService {
//查询sku是否有库存
@PostMapping("ware/waresku/hasstock")
R getSkusHasStock(@RequestBody List<Long> skuIds);
}

@ -32,6 +32,13 @@ public interface AttrService extends IService<AttrEntity> {
PageUtils getNoRelationAttr(Map<String, Object> params, Long attrgroupId); PageUtils getNoRelationAttr(Map<String, Object> params, Long attrgroupId);
/**
*
* @param attrIds
* @return
*/
List<Long> selectSearchAttrIds(List<Long> attrIds);
} }

@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
import com.bookstore.common.utils.PageUtils; import com.bookstore.common.utils.PageUtils;
import com.bookstore.bookmall.product.entity.SkuInfoEntity; import com.bookstore.bookmall.product.entity.SkuInfoEntity;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
@ -20,5 +21,7 @@ public interface SkuInfoService extends IService<SkuInfoEntity> {
void saveSkuInfo(SkuInfoEntity skuInfoEntity); void saveSkuInfo(SkuInfoEntity skuInfoEntity);
PageUtils queryPageByCondition(Map<String, Object> params); PageUtils queryPageByCondition(Map<String, Object> params);
List<SkuInfoEntity> getSkusBySpuId(Long spuId);
} }

@ -23,5 +23,15 @@ public interface SpuInfoService extends IService<SpuInfoEntity> {
void saveBaseSpuInfo(SpuInfoEntity spuInfoEntity); void saveBaseSpuInfo(SpuInfoEntity spuInfoEntity);
PageUtils queryPageByCondition(Map<String, Object> params); PageUtils queryPageByCondition(Map<String, Object> params);
/*
* @Description:
* @param: spuId
* @return:
* @Author:
* @date:
*/
void up(Long spuId);
} }

@ -266,5 +266,14 @@ public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements
return pageUtils; return pageUtils;
} }
@Override
public List<Long> selectSearchAttrIds(List<Long> attrIds) {
// SELECT attr_id FROM `pms_attr` WHERE attr_id IN (?) AND search_type = 1
return baseMapper.selectSearchAttrIds(attrIds);
}
} }

@ -4,6 +4,7 @@ import com.mysql.cj.util.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List;
import java.util.Map; import java.util.Map;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
@ -88,4 +89,10 @@ public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoDao, SkuInfoEntity> i
return new PageUtils(page); return new PageUtils(page);
} }
@Override
public List<SkuInfoEntity> getSkusBySpuId(Long spuId){
List<SkuInfoEntity> skus = this.list(new QueryWrapper<SkuInfoEntity>().eq("spu_id", spuId));
return skus;
}
} }

@ -1,11 +1,17 @@
package com.bookstore.bookmall.product.service.impl; package com.bookstore.bookmall.product.service.impl;
import com.alibaba.fastjson.TypeReference;
import com.bookstore.bookmall.product.entity.*; import com.bookstore.bookmall.product.entity.*;
import com.bookstore.bookmall.product.feign.CouponFeignService; import com.bookstore.bookmall.product.feign.CouponFeignService;
import com.bookstore.bookmall.product.feign.SearchFeignService;
import com.bookstore.bookmall.product.feign.WareFeignService;
import com.bookstore.bookmall.product.service.*; import com.bookstore.bookmall.product.service.*;
import com.bookstore.bookmall.product.to.SkuHasStockTo;
import com.bookstore.bookmall.product.vo.*; import com.bookstore.bookmall.product.vo.*;
import com.bookstore.common.constant.ProductConstant;
import com.bookstore.common.to.SkuReductionTo; import com.bookstore.common.to.SkuReductionTo;
import com.bookstore.common.to.SpuBoundsTo; import com.bookstore.common.to.SpuBoundsTo;
import com.bookstore.common.to.es.SkuEsModel;
import com.bookstore.common.utils.R; import com.bookstore.common.utils.R;
import com.fasterxml.jackson.databind.annotation.JsonAppend; import com.fasterxml.jackson.databind.annotation.JsonAppend;
import com.mysql.cj.util.StringUtils; import com.mysql.cj.util.StringUtils;
@ -16,9 +22,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@ -50,6 +54,14 @@ public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> i
SkuSaleAttrValueService skuSaleAttrValueService; SkuSaleAttrValueService skuSaleAttrValueService;
@Autowired @Autowired
CouponFeignService couponFeignService; CouponFeignService couponFeignService;
@Autowired
BrandService brandService;
@Autowired
CategoryService categoryService;
@Autowired
WareFeignService wareFeignService;
@Autowired
SearchFeignService searchFeignService;
@Override @Override
public PageUtils queryPage(Map<String, Object> params) { public PageUtils queryPage(Map<String, Object> params) {
@ -232,5 +244,113 @@ public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> i
return new PageUtils(page); return new PageUtils(page);
} }
//商品上架
@Override
public void up(Long spuId) {
//查出所有skuinfo
List<SkuInfoEntity> skus = skuInfoService.getSkusBySpuId(spuId);
//TODO 查出当前sku可以被检索的规格属性
List<ProductAttrValueEntity> valueEntities = valueService.baseAttrlistforspu(spuId);
List<Long> attrIds = valueEntities.stream().map(entity -> {
return entity.getAttrId();
}).collect(Collectors.toList());
List<Long> selectSearchAttrs = attrService.selectSearchAttrIds(attrIds);
Set<Long> idSet = new HashSet<>(selectSearchAttrs);
List<SkuEsModel.Attrs> attrsList = valueEntities.stream().filter(item -> {
return idSet.contains(item.getAttrId());
}).map(item->{
SkuEsModel.Attrs attrs1= new SkuEsModel.Attrs();
BeanUtils.copyProperties(item, attrs1);
return attrs1;
}).collect(Collectors.toList());
List<Long> skuIds = skus.stream().map(item -> {
return item.getSkuId();
}).collect(Collectors.toList());
Map<Long, Boolean> stockMap = null;
try {
//TODO 远程调用库存服务,查询是否有库存
R skusHasStock = wareFeignService.getSkusHasStock(skuIds);
TypeReference<List<SkuHasStockTo>> typeReference = new TypeReference<List<SkuHasStockTo>>() {
};
stockMap = skusHasStock.getData(typeReference).stream()
.collect(Collectors.toMap(SkuHasStockTo::getSkuId, item -> item.getHasStock()));
}catch (Exception e) {
log.error("库存服务查询异常:原因{}", e);
}
Map<Long, Boolean> finalStockMap = stockMap;
List<SkuEsModel> esModels = skus.stream().map((sku) -> {
//组装需要的数据
SkuEsModel skuEsModel = new SkuEsModel();
BeanUtils.copyProperties(sku, skuEsModel);
//skuPrice, skuImg, hotStock, hotScore
skuEsModel.setSkuPrice(sku.getPrice());
skuEsModel.setSkuImg(sku.getSkuDefaultImg());
//hotStock
if (finalStockMap == null) {
skuEsModel.setHasStock(true);
}else {
skuEsModel.setHasStock(finalStockMap.get(sku.getSkuId()));
}
//TODO 热度评分 默认0
skuEsModel.setHotScore(0L);
// /*
// * private String brandName;
//
// private String brandImg;
//
// private String catalogName;
//
// * */
BrandEntity brand = brandService.getById(sku.getBrandId());
skuEsModel.setBrandName(brand.getName());
skuEsModel.setBrandImg(brand.getLogo());
CategoryEntity categoryEntity = categoryService.getById(sku.getCatalogId());
skuEsModel.setCatalogName(categoryEntity.getName());
// @Data
// public static class Attrs {
//
// private Long attrId;
//
// private String attrName;
//
// private String attrValue;
//
// }
skuEsModel.setAttrs(attrsList);
return skuEsModel;
}).collect(Collectors.toList());
//TODO 将数据发送给es保存
R r = searchFeignService.productStatusUp(esModels);
if (r.getCode() == 0) {
//远程调用成功
//TODO 修改商品上架状态
baseMapper.updateSpuStatus(spuId, ProductConstant.StatusEnum.SPU_UP.getCode());
}else {
//远程调用失败
//重复调用,接口幂等性
}
}
} }

@ -0,0 +1,10 @@
package com.bookstore.bookmall.product.to;
import lombok.Data;
@Data
public class SkuHasStockTo {
private Long skuId;
private Boolean hasStock;
}

@ -16,6 +16,12 @@
<result property="catelogId" column="catelog_id"/> <result property="catelogId" column="catelog_id"/>
<result property="showDesc" column="show_desc"/> <result property="showDesc" column="show_desc"/>
</resultMap> </resultMap>
<select id="selectSearchAttrIds" resultType="java.lang.Long">
SELECT attr_id FROM `pms_attr` WHERE attr_id IN
<foreach collection="attrIds" item="id" separator="," open="(" close=")">
#{id}
</foreach>
AND search_type = 1
</select>
</mapper> </mapper>

@ -15,6 +15,8 @@
<result property="createTime" column="create_time"/> <result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/> <result property="updateTime" column="update_time"/>
</resultMap> </resultMap>
<update id="updateSpuStatus">
UPDATE `pms_spu_info` SET publish_status=#{code}, update_time=NOW() WHERE id=#{spuId}
</update>
</mapper> </mapper>

@ -1,15 +1,13 @@
package com.bookstore.bookmall.ware.controller; package com.bookstore.bookmall.ware.controller;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.Map; import java.util.Map;
import com.bookstore.bookmall.ware.to.SkuHasStockTo;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.*;
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 com.bookstore.bookmall.ware.entity.WareSkuEntity; import com.bookstore.bookmall.ware.entity.WareSkuEntity;
import com.bookstore.bookmall.ware.service.WareSkuService; import com.bookstore.bookmall.ware.service.WareSkuService;
@ -31,6 +29,15 @@ public class WareSkuController {
@Autowired @Autowired
private WareSkuService wareSkuService; private WareSkuService wareSkuService;
//查询sku是否有库存
@PostMapping("/hasstock")
public R getSkusHasStock(@RequestBody List<Long> skuIds) {
List<SkuHasStockTo> vos = wareSkuService.getSkusHasStock(skuIds);
return R.ok().setData(vos);
}
/** /**
* *
*/ */

@ -3,6 +3,7 @@ package com.bookstore.bookmall.ware.dao;
import com.bookstore.bookmall.ware.entity.WareSkuEntity; import com.bookstore.bookmall.ware.entity.WareSkuEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/** /**
* *
@ -13,5 +14,6 @@ import org.apache.ibatis.annotations.Mapper;
*/ */
@Mapper @Mapper
public interface WareSkuDao extends BaseMapper<WareSkuEntity> { public interface WareSkuDao extends BaseMapper<WareSkuEntity> {
Long getSkuStock(Long skuId);
} }

@ -4,5 +4,5 @@ package com.bookstore.bookmall.ware.feign;
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.cloud.openfeign.FeignClient;
@FeignClient("book-product") @FeignClient("book-product")
public class ProductFeignService { public interface ProductFeignService {
} }

@ -1,9 +1,11 @@
package com.bookstore.bookmall.ware.service; package com.bookstore.bookmall.ware.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.bookstore.bookmall.ware.to.SkuHasStockTo;
import com.bookstore.common.utils.PageUtils; import com.bookstore.common.utils.PageUtils;
import com.bookstore.bookmall.ware.entity.WareSkuEntity; import com.bookstore.bookmall.ware.entity.WareSkuEntity;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
@ -16,5 +18,7 @@ import java.util.Map;
public interface WareSkuService extends IService<WareSkuEntity> { public interface WareSkuService extends IService<WareSkuEntity> {
PageUtils queryPage(Map<String, Object> params); PageUtils queryPage(Map<String, Object> params);
List<SkuHasStockTo> getSkusHasStock(List<Long> skuIds);
} }

@ -1,8 +1,13 @@
package com.bookstore.bookmall.ware.service.impl; package com.bookstore.bookmall.ware.service.impl;
import com.bookstore.bookmall.ware.to.SkuHasStockTo;
import com.mysql.cj.util.StringUtils; import com.mysql.cj.util.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@ -43,4 +48,21 @@ public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> i
return new PageUtils(page); return new PageUtils(page);
} }
@Override
public List<SkuHasStockTo> getSkusHasStock(List<Long> skuIds) {
List<SkuHasStockTo> collect = skuIds.stream().map(skuId -> {
SkuHasStockTo vo = new SkuHasStockTo();
//查询当前库存
//SELECT SUM(stock-stock_locked) FROM `wms_ware_sku` WHERE sku_id=1
Long count = baseMapper.getSkuStock(skuId);
vo.setHasStock(count == null ? false : count>0);
vo.setSkuId(skuId);
return vo;
}).collect(Collectors.toList());
return collect;
}
} }

@ -0,0 +1,10 @@
package com.bookstore.bookmall.ware.to;
import lombok.Data;
@Data
public class SkuHasStockTo {
private Long skuId;
private Boolean hasStock;
}

@ -12,6 +12,8 @@
<result property="skuName" column="sku_name"/> <result property="skuName" column="sku_name"/>
<result property="stockLocked" column="stock_locked"/> <result property="stockLocked" column="stock_locked"/>
</resultMap> </resultMap>
<select id="getSkuStock" resultType="java.lang.Long">
SELECT SUM(stock-stock_locked) FROM `wms_ware_sku` WHERE sku_id=#{skuId}
</select>
</mapper> </mapper>

@ -39,6 +39,7 @@
<orderEntry type="library" name="Maven: commons-lang:commons-lang:2.6" level="project" /> <orderEntry type="library" name="Maven: commons-lang:commons-lang:2.6" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: javax.servlet:javax.servlet-api:3.1.0" level="project" /> <orderEntry type="library" scope="PROVIDED" name="Maven: javax.servlet:javax.servlet-api:3.1.0" level="project" />
<orderEntry type="library" name="Maven: javax.validation:validation-api:2.0.1.Final" level="project" /> <orderEntry type="library" name="Maven: javax.validation:validation-api:2.0.1.Final" level="project" />
<orderEntry type="library" name="Maven: com.alibaba:fastjson:1.2.79" level="project" />
<orderEntry type="library" name="Maven: mysql:mysql-connector-java:8.0.17" level="project" /> <orderEntry type="library" name="Maven: mysql:mysql-connector-java:8.0.17" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery:2021.0.4.0" level="project" /> <orderEntry type="library" name="Maven: com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery:2021.0.4.0" level="project" />
<orderEntry type="library" name="Maven: com.alibaba.cloud:spring-cloud-alibaba-commons:2021.0.4.0" level="project" /> <orderEntry type="library" name="Maven: com.alibaba.cloud:spring-cloud-alibaba-commons:2021.0.4.0" level="project" />

@ -51,6 +51,12 @@
<artifactId>validation-api</artifactId> <artifactId>validation-api</artifactId>
<version>2.0.1.Final</version> <version>2.0.1.Final</version>
</dependency> </dependency>
<!-- json-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.79</version>
</dependency>
<!-- <dependency>--> <!-- <dependency>-->
<!-- <groupId>org.apache.shiro</groupId>--> <!-- <groupId>org.apache.shiro</groupId>-->

@ -21,4 +21,24 @@ public class ProductConstant {
} }
public enum StatusEnum{
SPU_NEW(0, "新建"), SPU_UP(1,"商品上架"), SPU_DOWN(2,"商品下架");
private int code;
private String msg;
StatusEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
} }

@ -17,7 +17,8 @@ import java.sql.Struct;
public enum BizCodeEnume { public enum BizCodeEnume {
UNKNOW_EXCEPTION(10000, "系统未知错误"), UNKNOW_EXCEPTION(10000, "系统未知错误"),
VAILD_EXCEPTION(10001, "参数格式校验失败"); VAILD_EXCEPTION(10001, "参数格式校验失败"),
PRODUCT_EXPRESSION(11000, "商品上架异常");
private int code; private int code;
private String message; private String message;

@ -0,0 +1,51 @@
package com.bookstore.common.to.es;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
@Data
public class SkuEsModel {
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 {
private Long attrId;
private String attrName;
private String attrValue;
}
}

@ -8,6 +8,8 @@
package com.bookstore.common.utils; package com.bookstore.common.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import java.util.HashMap; import java.util.HashMap;
@ -18,9 +20,22 @@ import java.util.Map;
* *
* @author Mark sunlightcs@gmail.com * @author Mark sunlightcs@gmail.com
*/ */
//!!!!以后设计R时加上泛型
public class R extends HashMap<String, Object> { public class R extends HashMap<String, Object> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public <T> T getData(TypeReference<T> typeReference) {
Object data = get("data");
String s = JSON.toJSONString(data);
T t = JSON.parseObject(s, typeReference);
return t;
}
public R setData(Object data){
put("data", data);
return this;
}
public R() { public R() {
put("code", 0); put("code", 0);
put("msg", "success"); put("msg", "success");

@ -0,0 +1,2 @@
/mvnw text eol=lf
*.cmd text eol=crlf

@ -0,0 +1,75 @@
<?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.7.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.bookstore.bookmall</groupId>
<artifactId>mall-search</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mall-search</name>
<description>Demo project for Spring Boot</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>1.8</java.version>
<elasticsearch.version>7.11.1</elasticsearch.version>
</properties>
<dependencies>
<dependency>
<groupId>com.bookstore.bookmall</groupId>
<artifactId>mall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId> org.elasticsearch.client </groupId>
<artifactId> elasticsearch-rest-high-level-client </artifactId>
<version>7.11.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,16 @@
package com.bookstore.bookmall.search;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class MallSearchApplication {
public static void main(String[] args) {
SpringApplication.run(MallSearchApplication.class, args);
}
}

@ -0,0 +1,35 @@
package com.bookstore.bookmall.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;
@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("192.168.88.131", 9200, "http")));
return client;
}
}

@ -0,0 +1,6 @@
package com.bookstore.bookmall.search.constant;
public class EsConstant {
public static final String PRODUCT_INDEX = "product"; //sku数据在es中的索引
}

@ -0,0 +1,40 @@
package com.bookstore.bookmall.search.controller;
import com.bookstore.bookmall.search.service.ProductSaveService;
import com.bookstore.common.exception.BizCodeEnume;
import com.bookstore.common.to.es.SkuEsModel;
import com.bookstore.common.utils.R;
import lombok.extern.slf4j.Slf4j;
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.util.List;
@Slf4j
@RequestMapping("/search/save")
@RestController
public class ElasticSaveController {
@Autowired
ProductSaveService productSaveService;
//上架商品
@PostMapping("/product")
public R productStatusUp(@RequestBody List<SkuEsModel> skuEsModels) {
boolean b = false;
try {
b = productSaveService.productStatusUp(skuEsModels);
}catch (Exception e){
log.error("商品上架异常:{}",e);
return R.error(BizCodeEnume.PRODUCT_EXPRESSION.getCode(), BizCodeEnume.PRODUCT_EXPRESSION.getMessage());
}
if (b) {
return R.ok();
} else {
return R.error(BizCodeEnume.PRODUCT_EXPRESSION.getCode(), BizCodeEnume.PRODUCT_EXPRESSION.getMessage());
}
}
}

@ -0,0 +1,12 @@
package com.bookstore.bookmall.search.service;
import com.bookstore.common.to.es.SkuEsModel;
import java.io.IOException;
import java.util.List;
public interface ProductSaveService {
boolean productStatusUp(List<SkuEsModel> skuEsModels) throws IOException;
}

@ -0,0 +1,57 @@
package com.bookstore.bookmall.search.service.impl;
import com.bookstore.bookmall.search.config.mallElasticSearchConfig;
import com.bookstore.bookmall.search.constant.EsConstant;
import com.bookstore.bookmall.search.service.ProductSaveService;
import com.bookstore.common.to.es.SkuEsModel;
import lombok.extern.slf4j.Slf4j;
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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import com.alibaba.fastjson.JSON;
@Slf4j
@Service
public class ProductSaveServiceImpl implements ProductSaveService {
@Autowired
RestHighLevelClient restHighLevelClient;
@Override
public boolean productStatusUp(List<SkuEsModel> skuEsModels) throws IOException {
//保存到es
//1、给es中建立索引product建立好映射关系
//2、在es中保存这些数据
BulkRequest bulkRequest = new BulkRequest();
for (SkuEsModel skuEsModel : skuEsModels) {
IndexRequest indexRequest = new IndexRequest(EsConstant.PRODUCT_INDEX);
indexRequest.id(skuEsModel.getSkuId().toString());
String s = JSON.toJSONString(skuEsModel);
indexRequest.source(s, XContentType.JSON);
bulkRequest.add(indexRequest);
}
BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, mallElasticSearchConfig.COMMON_OPTIONS);
boolean b = bulk.hasFailures();
List<String> collect = Arrays.stream(bulk.getItems()).map(item -> {
return item.getId();
}).collect(Collectors.toList());
log.error("商品上架错误:{}", collect);
return !b;
}
}

@ -0,0 +1,5 @@
spring.application.name=mall-search
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
server.port=12000

@ -0,0 +1,71 @@
PUT product
{
"mappings": {
"properties": {
"skuId": {
"type": "long"
},
"spuId": {
"type": "long"
},
"skuTitle": {
"type": "text",
"analyzer": "ik_smart"
},
"skuPrice": {
"type": "keyword"
},
"skuImg": {
"type": "keyword",
"index": false,
"doc_values": false
},
"saleCount": {
"type": "long"
},
"hosStock": {
"type": "boolean"
},
"hotScore": {
"type": "long"
},
"brandId": {
"type": "long"
},
"catelogId": {
"type": "long"
},
"brandName": {
"type": "keyword",
"index": false,
"doc_values": false
},
"brandImg": {
"type": "keyword",
"index": false,
"doc_values": false
},
"catelogName": {
"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"
}
}
}
}
}
}

@ -0,0 +1,22 @@
package com.bookstore.bookmall.search;
import org.elasticsearch.client.RestHighLevelClient;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
class MallSearchApplicationTests {
@Autowired
private RestHighLevelClient client;
@Test
public void contextLoads() {
System.out.println(client);
}
}

@ -76,5 +76,3 @@ export default {
activated() {} //keep-alive activated() {} //keep-alive
}; };
</script> </script>
<style scoped>
</style>

@ -74,5 +74,3 @@ export default {
} }
}; };
</script> </script>
<style scoped>
</style>

@ -1,217 +1,186 @@
<template> <!-- -->
<el-row :gutter="20"> <template>
<el-col :span="6"> <el-row :gutter="20">
<category @tree-node-click="treenodeclick"></category> <el-col :span="6">
</el-col> <category @tree-node-click="treeNodeClick"></category>
<el-col :span="18"> </el-col>
<div class="mod-config"> <el-col :span="18">
<el-form :inline="true" :model="dataForm" @keyup.enter.native="getDataList()"> <div class="mod-config">
<el-form-item> <el-form :inline="true" :model="dataForm" @keyup.enter.native="getDataList()">
<el-input v-model="dataForm.key" placeholder="参数名" clearable></el-input> <el-form-item>
</el-form-item> <el-input v-model="dataForm.key" placeholder="参数名" clearable></el-input>
<el-form-item> </el-form-item>
<el-button @click="getDataList()"></el-button> <el-form-item>
<el-button type="success" @click="getAllDataList()"></el-button> <el-button @click="getDataList()"></el-button>
<el-button <el-button v-if="isAuth('product:attrgroup:save')" type="primary"
v-if="isAuth('product:attrgroup:save')" @click="addOrUpdateHandle()">新增</el-button>
type="primary" <el-button v-if="isAuth('product:attrgroup:delete')" type="danger" @click="deleteHandle()"
@click="addOrUpdateHandle()" :disabled="dataListSelections.length <= 0">批量删除</el-button>
>新增</el-button> </el-form-item>
<el-button </el-form>
v-if="isAuth('product:attrgroup:delete')" <el-table :data="dataList" border v-loading="dataListLoading" @selection-change="selectionChangeHandle"
type="danger" style="width: 100%;">
@click="deleteHandle()" <el-table-column type="selection" header-align="center" align="center" width="50">
:disabled="dataListSelections.length <= 0" </el-table-column>
>批量删除</el-button> <el-table-column prop="attrGroupId" header-align="center" align="center" label="分组id">
</el-form-item> </el-table-column>
</el-form> <el-table-column prop="attrGroupName" header-align="center" align="center" label="组名">
<el-table </el-table-column>
:data="dataList" <el-table-column prop="sort" header-align="center" align="center" label="排序">
border </el-table-column>
v-loading="dataListLoading" <el-table-column prop="descript" header-align="center" align="center" label="描述">
@selection-change="selectionChangeHandle" </el-table-column>
style="width: 100%;" <el-table-column prop="icon" header-align="center" align="center" label="组图标">
> </el-table-column>
<el-table-column type="selection" header-align="center" align="center" width="50"></el-table-column> <el-table-column prop="catelogId" header-align="center" align="center" label="所属分类id">
<el-table-column prop="attrGroupId" header-align="center" align="center" label="分组id"></el-table-column> </el-table-column>
<el-table-column prop="attrGroupName" header-align="center" align="center" label="组名"></el-table-column> <el-table-column fixed="right" header-align="center" align="center" width="150" label="操作">
<el-table-column prop="sort" header-align="center" align="center" label="排序"></el-table-column> <template slot-scope="scope">
<el-table-column prop="descript" header-align="center" align="center" label="描述"></el-table-column> <el-button type="text" size="small"
<el-table-column prop="icon" header-align="center" align="center" label="组图标"></el-table-column> @click="addOrUpdateHandle(scope.row.attrGroupId)">修改</el-button>
<el-table-column prop="catelogId" header-align="center" align="center" label="所属分类id"></el-table-column> <el-button type="text" size="small"
<el-table-column @click="deleteHandle(scope.row.attrGroupId)">删除</el-button>
fixed="right" </template>
header-align="center" </el-table-column>
align="center" </el-table>
width="150" <el-pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle"
label="操作" :current-page="pageIndex" :page-sizes="[10, 20, 50, 100]" :page-size="pageSize" :total="totalPage"
> layout="total, sizes, prev, pager, next, jumper">
<template slot-scope="scope"> </el-pagination>
<el-button type="text" size="small" @click="relationHandle(scope.row.attrGroupId)"></el-button> <!-- 弹窗, 新增 / 修改 -->
<el-button <add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate"
type="text" @refreshDataList="getDataList"></add-or-update>
size="small" </div>
@click="addOrUpdateHandle(scope.row.attrGroupId)" </el-col>
>修改</el-button>
<el-button type="text" size="small" @click="deleteHandle(scope.row.attrGroupId)"></el-button> </el-row>
</template> </template>
</el-table-column>
</el-table>
<el-pagination <script>
@size-change="sizeChangeHandle" /*
@current-change="currentChangeHandle" 父子组件传递数据
:current-page="pageIndex" 1子组件给父组件传递数据事件机制
:page-sizes="[10, 20, 50, 100]" 子组件给父子件发送一个事件携带上数据
:page-size="pageSize"
:total="totalPage" */
layout="total, sizes, prev, pager, next, jumper"
></el-pagination> //jsjsjson
<!-- 弹窗, 新增 / 修改 --> //import from '';
<add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="getDataList"></add-or-update> import Category from "../common/category.vue";
import AddOrUpdate from "./attrgroup-add-or-update.vue";
<!-- 修改关联关系 -->
<relation-update v-if="relationVisible" ref="relationUpdate" @refreshData="getDataList"></relation-update> export default {
</div> //import使
</el-col> components: { Category, AddOrUpdate },
</el-row> data() {
</template> return {
catId: 0,
<script> dataForm: {
/** key: ''
* 父子组件传递数据 },
* 1)子组件给父组件传递数据事件机制 dataList: [],
* 子组件给父组件发送一个事件携带上数据 pageIndex: 1,
* // this.$emit("",...) pageSize: 10,
*/ totalPage: 0,
//jsjsjson dataListLoading: false,
//import  from ''; dataListSelections: [],
import Category from "../common/category"; addOrUpdateVisible: false
import AddOrUpdate from "./attrgroup-add-or-update"; }
import RelationUpdate from "./attr-group-relation"; },
export default { // data
//import使 //data
components: { Category, AddOrUpdate, RelationUpdate }, watch: {},
props: {}, //
data() { methods: {
return { //
catId: 0, treeNodeClick(data, node, component) {
dataForm: { console.log("attrgroup感知到节点被点击", data, node, component);
key: "" console.log("菜单id:", data.catId);
}, if(node.childNodes.length == 0) {
dataList: [], this.catId=data.catId;
pageIndex: 1, this.getDataList();
pageSize: 10, }
totalPage: 0, },
dataListLoading: false,
dataListSelections: [], //
addOrUpdateVisible: false, getDataList() {
relationVisible: false this.dataListLoading = true
}; this.$http({
}, url: this.$http.adornUrl(`/product/attrgroup/list/${this.catId}`),
activated() { method: 'get',
this.getDataList(); params: this.$http.adornParams({
}, 'page': this.pageIndex,
methods: { 'limit': this.pageSize,
// 'key': this.dataForm.key
relationHandle(groupId) { })
this.relationVisible = true; }).then(({ data }) => {
this.$nextTick(() => { if (data && data.code === 0) {
this.$refs.relationUpdate.init(groupId); this.dataList = data.page.list
}); this.totalPage = data.page.totalCount
}, } else {
// this.dataList = []
treenodeclick(data, node, component) { this.totalPage = 0
if (node.level == 3) { }
this.catId = data.catId; this.dataListLoading = false
this.getDataList(); // })
} },
}, //
getAllDataList(){ sizeChangeHandle(val) {
this.catId = 0; this.pageSize = val
this.getDataList(); this.pageIndex = 1
}, this.getDataList()
// },
getDataList() { //
this.dataListLoading = true; currentChangeHandle(val) {
this.$http({ this.pageIndex = val
url: this.$http.adornUrl(`/product/attrgroup/list/${this.catId}`), this.getDataList()
method: "get", },
params: this.$http.adornParams({ //
page: this.pageIndex, selectionChangeHandle(val) {
limit: this.pageSize, this.dataListSelections = val
key: this.dataForm.key },
}) // /
}).then(({ data }) => { addOrUpdateHandle(id) {
if (data && data.code === 0) { this.addOrUpdateVisible = true
this.dataList = data.page.list; this.$nextTick(() => {
this.totalPage = data.page.totalCount; this.$refs.addOrUpdate.init(id)
} else { })
this.dataList = []; },
this.totalPage = 0; //
} deleteHandle(id) {
this.dataListLoading = false; var ids = id ? [id] : this.dataListSelections.map(item => {
}); return item.attrGroupId
}, })
// this.$confirm(`确定对[id=${ids.join(',')}]进行[${id ? '删除' : '批量删除'}]操作?`, '提示', {
sizeChangeHandle(val) { confirmButtonText: '确定',
this.pageSize = val; cancelButtonText: '取消',
this.pageIndex = 1; type: 'warning'
this.getDataList(); }).then(() => {
}, this.$http({
// url: this.$http.adornUrl('/product/attrgroup/delete'),
currentChangeHandle(val) { method: 'post',
this.pageIndex = val; data: this.$http.adornData(ids, false)
this.getDataList(); }).then(({ data }) => {
}, if (data && data.code === 0) {
// this.$message({
selectionChangeHandle(val) { message: '操作成功',
this.dataListSelections = val; type: 'success',
}, duration: 1500,
// / onClose: () => {
addOrUpdateHandle(id) { this.getDataList()
this.addOrUpdateVisible = true; }
this.$nextTick(() => { })
this.$refs.addOrUpdate.init(id); } else {
}); this.$message.error(data.msg)
}, }
// })
deleteHandle(id) { })
var ids = id }
? [id] },
: this.dataListSelections.map(item => { created(){
return item.attrGroupId; this.getDataList();
}); }
this.$confirm(
`确定对[id=${ids.join(",")}]进行[${id ? "删除" : "批量删除"}]操作?`, }
"提示", </script>
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}
).then(() => {
this.$http({
url: this.$http.adornUrl("/product/attrgroup/delete"),
method: "post",
data: this.$http.adornData(ids, false)
}).then(({ data }) => {
if (data && data.code === 0) {
this.$message({
message: "操作成功",
type: "success",
duration: 1500,
onClose: () => {
this.getDataList();
}
});
} else {
this.$message.error(data.msg);
}
});
});
}
}
};
</script>
<style scoped>
</style>

@ -247,5 +247,3 @@ export default {
} }
}; };
</script> </script>
<style scoped>
</style>

@ -379,5 +379,3 @@ export default {
activated() {} //keep-alive activated() {} //keep-alive
}; };
</script> </script>
<style scoped>
</style>

@ -91,5 +91,3 @@ export default {
activated() {} //keep-alive activated() {} //keep-alive
}; };
</script> </script>
<style scoped>
</style>
Loading…
Cancel
Save