提交 b83262af authored 作者: YunaiV's avatar YunaiV

完成的商品搜索和条件功能

上级 f3316d14
package cn.iocoder.common.framework.vo;
import java.io.Serializable;
/**
* 排序字段 DTO
*
* 类名加了 ing 的原因是,避免和 ES SortField 重名。
*/
public class SortingField {
public class SortingField implements Serializable {
/**
* 字段
*/
private String field;
/**
*
*
*/
private String order;
// 空构造方法,解决反序列化
public SortingField() {
}
public SortingField(String field, String order) {
this.field = field;
this.order = order;
......
......@@ -6,6 +6,7 @@ import cn.iocoder.mall.productservice.rpc.category.dto.ProductCategoryListQueryR
import cn.iocoder.mall.productservice.rpc.category.dto.ProductCategoryRespDTO;
import cn.iocoder.mall.productservice.rpc.category.dto.ProductCategoryUpdateReqDTO;
import java.util.Collection;
import java.util.List;
/**
......@@ -49,7 +50,7 @@ public interface ProductCategoryRpc {
* @param productCategoryIds 商品分类编号列表
* @return 商品分类列表
*/
CommonResult<List<ProductCategoryRespDTO>> listProductCategories(List<Integer> productCategoryIds);
CommonResult<List<ProductCategoryRespDTO>> listProductCategories(Collection<Integer> productCategoryIds);
/**
* 获得符合条件的商品分类列表
......
......@@ -10,6 +10,7 @@ import cn.iocoder.mall.productservice.service.category.bo.ProductCategoryBO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
/**
......@@ -67,7 +68,7 @@ public class ProductCategoryManager {
* @param productCategoryIds 商品分类编号列表
* @return 商品分类列表
*/
public List<ProductCategoryRespDTO> listProductCategories(List<Integer> productCategoryIds) {
public List<ProductCategoryRespDTO> listProductCategories(Collection<Integer> productCategoryIds) {
List<ProductCategoryBO> productCategoryBOs = productCategoryService.listProductCategories(productCategoryIds);
return ProductCategoryConvert.INSTANCE.convertList02(productCategoryBOs);
}
......
......@@ -9,6 +9,7 @@ import cn.iocoder.mall.productservice.rpc.category.dto.ProductCategoryUpdateReqD
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Collection;
import java.util.List;
import static cn.iocoder.common.framework.vo.CommonResult.success;
......@@ -45,7 +46,7 @@ public class ProductCategoryRpcImpl implements ProductCategoryRpc {
}
@Override
public CommonResult<List<ProductCategoryRespDTO>> listProductCategories(List<Integer> productCategoryIds) {
public CommonResult<List<ProductCategoryRespDTO>> listProductCategories(Collection<Integer> productCategoryIds) {
return success(productCategoryManager.listProductCategories(productCategoryIds));
}
......
......@@ -14,6 +14,7 @@ import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.validation.Valid;
import java.util.Collection;
import java.util.List;
import static cn.iocoder.mall.productservice.enums.ProductErrorCodeConstants.*;
......@@ -102,7 +103,7 @@ public class ProductCategoryService {
* @param productCategoryIds 商品分类编号列表
* @return 商品分类列表
*/
public List<ProductCategoryBO> listProductCategories(List<Integer> productCategoryIds) {
public List<ProductCategoryBO> listProductCategories(Collection<Integer> productCategoryIds) {
List<ProductCategoryDO> productCategoryDOs = productCategoryMapper.selectBatchIds(productCategoryIds);
return ProductCategoryConvert.INSTANCE.convertList(productCategoryDOs);
}
......
......@@ -16,4 +16,8 @@ public enum SearchProductConditionFieldEnum {
this.field = field;
}
public String getField() {
return field;
}
}
......@@ -2,6 +2,8 @@ package cn.iocoder.mall.searchservice.rpc.product;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.searchservice.rpc.product.dto.SearchProductConditionReqDTO;
import cn.iocoder.mall.searchservice.rpc.product.dto.SearchProductConditionRespDTO;
import cn.iocoder.mall.searchservice.rpc.product.dto.SearchProductPageReqDTO;
import cn.iocoder.mall.searchservice.rpc.product.dto.SearchProductRespDTO;
......@@ -10,6 +12,20 @@ import cn.iocoder.mall.searchservice.rpc.product.dto.SearchProductRespDTO;
*/
public interface SearchProductRpc {
CommonResult<PageResult<SearchProductRespDTO>> pageSearchProduct(SearchProductPageReqDTO pageQueryReqDTO);
/**
* 获得商品搜索分页
*
* @param pageReqDTO 分页请求 DTO
* @return 商品搜索分页结果
*/
CommonResult<PageResult<SearchProductRespDTO>> pageSearchProduct(SearchProductPageReqDTO pageReqDTO);
/**
* 获得商品搜索条件
*
* @param conditionReqDTO 搜索条件 DTO
* @return 搜索条件
*/
CommonResult<SearchProductConditionRespDTO> getSearchProductCondition(SearchProductConditionReqDTO conditionReqDTO);
}
package cn.iocoder.mall.search.rest.request.user;
package cn.iocoder.mall.searchservice.rpc.product.dto;
import cn.iocoder.mall.searchservice.enums.product.SearchProductConditionFieldEnum;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Collection;
/**
* 获得商品检索条件 DTO
* 商品搜索条件 Request DTO
*/
@Data
@Accessors(chain = true)
public class UsersProductConditionRequest{
/**
* Field - 商品分类
*/
public static final String FIELD_CATEGORY = "category";
public class SearchProductConditionReqDTO implements Serializable {
/**
* 关键字
*/
private String keyword;
/**
* 需要返回的搜索条件的 fields 名
* 需要返回的搜索条件
*
* 可选择的条件,见 {@link SearchProductConditionFieldEnum} 枚举类
*/
private Collection<String> fields;
......
package cn.iocoder.mall.search.rest.response.user;
package cn.iocoder.mall.searchservice.rpc.product.dto;
import lombok.Data;
import lombok.experimental.Accessors;
......@@ -6,17 +6,16 @@ import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
/**
* 商品搜索条件 Response DTO
*/
@Data
@Accessors(chain = true)
public class UsersProductPageResponse implements Serializable {
public class SearchProductConditionRespDTO implements Serializable {
/**
* 管理员数组
* 商品分类数组
*/
private List<ProductResponse> list;
/**
* 总量
*/
private Integer total;
private List<Integer> cids;
}
......@@ -3,6 +3,7 @@ package cn.iocoder.mall.searchservice.rpc.product.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
/**
......@@ -10,7 +11,7 @@ import java.util.List;
*/
@Data
@Accessors(chain = true)
public class SearchProductRespDTO {
public class SearchProductRespDTO implements Serializable {
private Integer id;
......
......@@ -4,9 +4,11 @@ import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.productservice.rpc.category.dto.ProductCategoryRespDTO;
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuRespDTO;
import cn.iocoder.mall.searchservice.dal.es.dataobject.ESProductDO;
import cn.iocoder.mall.searchservice.rpc.product.dto.SearchProductConditionRespDTO;
import cn.iocoder.mall.searchservice.rpc.product.dto.SearchProductPageReqDTO;
import cn.iocoder.mall.searchservice.rpc.product.dto.SearchProductRespDTO;
import cn.iocoder.mall.searchservice.service.product.bo.SearchProductBO;
import cn.iocoder.mall.searchservice.service.product.bo.SearchProductConditionBO;
import cn.iocoder.mall.searchservice.service.product.bo.SearchProductPageQueryBO;
import cn.iocoder.mall.searchservice.service.product.bo.SearchProductSaveBO;
import org.mapstruct.Mapper;
......@@ -37,13 +39,15 @@ public interface SearchProductConvert {
List<SearchProductBO> convertList(List<ESProductDO> list);
default PageResult<SearchProductBO> convertPage(Page<ESProductDO> searchPage) {
return new PageResult<SearchProductBO>().setList(convertList(searchPage.getContent()))
.setTotal(searchPage.getTotalElements());
default PageResult<SearchProductBO> convertPage(Page<ESProductDO> page) {
return new PageResult<SearchProductBO>().setList(convertList(page.getContent()))
.setTotal(page.getTotalElements());
}
SearchProductPageQueryBO convert(SearchProductPageReqDTO bean);
PageResult<SearchProductRespDTO> convertPage(PageResult<SearchProductBO> pageResult);
PageResult<SearchProductRespDTO> convertPage(PageResult<SearchProductBO> page);
SearchProductConditionRespDTO convert(SearchProductConditionBO bean);
}
......@@ -11,10 +11,13 @@ import cn.iocoder.mall.productservice.rpc.sku.dto.ProductSkuRespDTO;
import cn.iocoder.mall.productservice.rpc.spu.ProductSpuRpc;
import cn.iocoder.mall.productservice.rpc.spu.dto.ProductSpuRespDTO;
import cn.iocoder.mall.searchservice.convert.product.SearchProductConvert;
import cn.iocoder.mall.searchservice.rpc.product.dto.SearchProductConditionReqDTO;
import cn.iocoder.mall.searchservice.rpc.product.dto.SearchProductConditionRespDTO;
import cn.iocoder.mall.searchservice.rpc.product.dto.SearchProductPageReqDTO;
import cn.iocoder.mall.searchservice.rpc.product.dto.SearchProductRespDTO;
import cn.iocoder.mall.searchservice.service.product.SearchProductService;
import cn.iocoder.mall.searchservice.service.product.bo.SearchProductBO;
import cn.iocoder.mall.searchservice.service.product.bo.SearchProductConditionBO;
import cn.iocoder.mall.searchservice.service.product.bo.SearchProductSaveBO;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
......@@ -48,6 +51,12 @@ public class SearchProductManager {
return SearchProductConvert.INSTANCE.convertPage(pageResult);
}
public SearchProductConditionRespDTO getSearchProductCondition(SearchProductConditionReqDTO conditionReqDTO) {
SearchProductConditionBO conditionBO =
searchProductService.getSearchProductCondition(conditionReqDTO.getKeyword(), conditionReqDTO.getFields());
return SearchProductConvert.INSTANCE.convert(conditionBO);
}
/**
* 重建所有商品的 ES 索引
*
......
......@@ -3,6 +3,8 @@ package cn.iocoder.mall.searchservice.rpc.product;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.searchservice.manager.product.SearchProductManager;
import cn.iocoder.mall.searchservice.rpc.product.dto.SearchProductConditionReqDTO;
import cn.iocoder.mall.searchservice.rpc.product.dto.SearchProductConditionRespDTO;
import cn.iocoder.mall.searchservice.rpc.product.dto.SearchProductPageReqDTO;
import cn.iocoder.mall.searchservice.rpc.product.dto.SearchProductRespDTO;
import org.apache.dubbo.config.annotation.DubboService;
......@@ -17,8 +19,13 @@ public class SearchProductRpcImpl implements SearchProductRpc {
private SearchProductManager searchProductManager;
@Override
public CommonResult<PageResult<SearchProductRespDTO>> pageSearchProduct(SearchProductPageReqDTO pageQueryReqDTO) {
return success(searchProductManager.pageSearchProduct(pageQueryReqDTO));
public CommonResult<PageResult<SearchProductRespDTO>> pageSearchProduct(SearchProductPageReqDTO pageReqDTO) {
return success(searchProductManager.pageSearchProduct(pageReqDTO));
}
@Override
public CommonResult<SearchProductConditionRespDTO> getSearchProductCondition(SearchProductConditionReqDTO conditionReqDTO) {
return success(searchProductManager.getSearchProductCondition(conditionReqDTO));
}
}
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>onemall</artifactId>
<groupId>cn.iocoder.mall</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>search</artifactId>
<packaging>pom</packaging>
<modules>
<module>search-application</module>
<module>search-biz</module>
<module>search-biz-api</module>
<!-- <module>search-service-api</module>-->
<!-- <module>search-service-impl</module>-->
<module>search-rpc</module>
<module>search-rest</module>
<module>search-rpc-api</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>mall-dependencies</artifactId>
<version>1.0-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>search</artifactId>
<groupId>cn.iocoder.mall</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>search-rest</artifactId>
<description>提供 商品搜索服务的 Rest 接口的实现,提供对外调用</description>
<dependencies>
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>search-biz</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>mall-spring-boot-starter-web</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>mall-spring-boot-starter-security</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>mall-spring-boot-starter-swagger</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package cn.iocoder.mall.search.rest.controller.user;
import cn.iocoder.common.framework.enums.MallConstants;
import cn.iocoder.common.framework.util.StringUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.common.framework.vo.SortingField;
import cn.iocoder.mall.search.biz.service.ProductSearchService;
import cn.iocoder.mall.search.rest.response.user.ProductPageResponse;
import io.swagger.annotations.Api;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import cn.iocoder.mall.search.rest.request.user.ProductConditionRequest;
import cn.iocoder.mall.search.rest.request.user.ProductSearchPageRequest;
import cn.iocoder.mall.search.rest.response.user.ProductConditionResponse;
import java.util.Collections;
import static cn.iocoder.common.framework.vo.CommonResult.success;
/**
* Created with IDEA
*
* @author : lhl
* @version : 1.0
* @Time : 19:26
* @date : 2020/5/14
*/
@RestController
@RequestMapping(MallConstants.ROOT_PATH_ADMIN + "users/product")
@Api(tags = "商品查询 API")
@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class UsersProductSearchController {
private final ProductSearchService productSearchService;
@GetMapping("/page") // TODO 芋艿,后面把 BO 改成 VO
public CommonResult<ProductPageResponse> page(@RequestParam(value = "cid", required = false) Integer cid,
@RequestParam(value = "keyword", required = false) String keyword,
@RequestParam(value = "pageNo", required = false) Integer pageNo,
@RequestParam(value = "pageSize", required = false) Integer pageSize,
@RequestParam(value = "sortField", required = false) String sortField,
@RequestParam(value = "sortOrder", required = false) String sortOrder) {
// 创建 ProductSearchPageDTO 对象
ProductSearchPageRequest productSearchPageDTO = new ProductSearchPageRequest().setCid(cid).setKeyword(keyword)
.setPageNo(pageNo).setPageSize(pageSize);
if (StringUtil.hasText(sortField) && StringUtil.hasText(sortOrder)) {
productSearchPageDTO.setSorts(Collections.singletonList(new SortingField(sortField, sortOrder)));
}
// 执行搜索
// return success(productSearchService.getSearchPage(productSearchPageDTO));
return success(null);
}
@GetMapping("/condition") // TODO 芋艿,后面把 BO 改成 VO
public CommonResult<ProductConditionResponse> condition(@RequestParam(value = "keyword", required = false) String keyword) {
// 创建 ProductConditionDTO 对象
ProductConditionRequest productConditionDTO = new ProductConditionRequest().setKeyword(keyword)
.setFields(Collections.singleton(ProductConditionRequest.FIELD_CATEGORY));
// 执行搜索
// return success(productSearchService.getSearchCondition(productConditionDTO));
return success(null);
}
}
package cn.iocoder.mall.search.rest.convert.user;
import cn.iocoder.mall.search.biz.bo.ProductBO;
import cn.iocoder.mall.search.biz.dataobject.ESProductDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface UsersProductSearchConvert {
cn.iocoder.mall.search.biz.convert.ProductSearchConvert INSTANCE = Mappers.getMapper(cn.iocoder.mall.search.biz.convert.ProductSearchConvert.class);
// @Mappings({})
// ESProductDO convert(ProductSpuDetailBO spu);
// @Mappings({})
// default ESProductDO convert(ProductSpuDetailBO spu, CalcSkuPriceBO calcSkuPrice) {
// // Spu 的基础数据
// ESProductDO product = this.convert(spu);
// product.setOriginalPrice(calcSkuPrice.getOriginalPrice()).setBuyPrice(calcSkuPrice.getBuyPrice());
// // 设置促销活动相关字段
// if (calcSkuPrice.getTimeLimitedDiscount() != null) {
// PromotionActivityBO activity = calcSkuPrice.getTimeLimitedDiscount();
// product.setPromotionActivityId(activity.getId()).setPromotionActivityTitle(activity.getTitle())
// .setPromotionActivityType(activity.getActivityType());
// }
// // 返回
// return product;
// }
List<ProductBO> convert(List<ESProductDO> list);
}
package cn.iocoder.mall.search.rest.request.user;
import cn.iocoder.common.framework.util.CollectionUtil;
import cn.iocoder.common.framework.vo.SortingField;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
import java.util.Set;
/**
* Created with IDEA
*
* @author : lhl
* @version : 1.0
* @Time : 19:09
* @date : 2020/5/14
*/
@Data
@Accessors(chain = true)
public class UsersProductSearchPageRequest {
public static final Set<String> SORT_FIELDS = CollectionUtil.asSet("buyPrice");
/**
* 分类编号
*/
private Integer cid;
/**
* 关键字
*/
private String keyword;
/**
* 页码
*/
private Integer pageNo;
/**
* 分页大小
*/
private Integer pageSize;
/**
* 排序字段数组
*/
private List<SortingField> sorts;
}
package cn.iocoder.mall.search.rest.response.user;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
/**
* 商品 ES BO
*/
@Data
@Accessors(chain = true)
public class UsersProductResponse implements Serializable {
private Integer id;
// ========== 基本信息 =========
/**
* SPU 名字
*/
private String name;
/**
* 卖点
*/
private String sellPoint;
/**
* 描述
*/
private String description;
/**
* 分类编号
*/
private Integer cid;
/**
* 分类名
*/
private String categoryName;
/**
* 商品主图地数组
*/
private List<String> picUrls;
// ========== 其他信息 =========
/**
* 是否上架商品(是否可见)。
*
* true 为已上架
* false 为已下架
*/
private Boolean visible;
/**
* 排序字段
*/
private Integer sort;
// ========== Sku 相关字段 =========
/**
* 原价格,单位:分
*/
private Integer originalPrice;
/**
* 购买价格,单位:分。
*/
private Integer buyPrice;
/**
* 库存数量
*/
private Integer quantity;
// ========== 促销活动相关字段 =========
// 目前只促销单体商品促销,目前仅限制折扣。
/**
* 促销活动编号
*/
private Integer promotionActivityId;
/**
* 促销活动标题
*/
private String promotionActivityTitle;
/**
* 促销活动类型
*/
private Integer promotionActivityType;
}
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>search</artifactId>
<groupId>cn.iocoder.mall</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>search-rpc-api</artifactId>
<dependencies>
<!--mall-->
<dependency>
<artifactId>search-biz-api</artifactId>
<groupId>cn.iocoder.mall</groupId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- 工具类相关 -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package cn.iocoder.mall.search.biz.request.user;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Collection;
/**
* 获得商品检索条件 DTO
*/
@Data
@Accessors(chain = true)
public class ProductConditionRequest {
/**
* Field - 商品分类
*/
public static final String FIELD_CATEGORY = "category";
/**
* 关键字
*/
private String keyword;
/**
* 需要返回的搜索条件的 fields 名
*/
private Collection<String> fields;
}
package cn.iocoder.mall.search.biz.request.user;
import cn.iocoder.common.framework.util.CollectionUtil;
import cn.iocoder.common.framework.vo.SortingField;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
import java.util.Set;
/**
* Created with IDEA
*
* @author : lhl
* @version : 1.0
* @Time : 19:09
* @date : 2020/5/14
*/
@Data
@Accessors(chain = true)
public class ProductSearchPageRequest {
public static final Set<String> SORT_FIELDS = CollectionUtil.asSet("buyPrice");
/**
* 分类编号
*/
private Integer cid;
/**
* 关键字
*/
private String keyword;
/**
* 页码
*/
private Integer pageNo;
/**
* 分页大小
*/
private Integer pageSize;
/**
* 排序字段数组
*/
private List<SortingField> sorts;
}
package cn.iocoder.mall.search.biz.response.user;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 商品搜索条件返回 BO
*/
@Data
@Accessors(chain = true)
public class ProductConditionResponse {
/**
* 商品分类数组
*/
private List<Category> categories;
@Data
@Accessors(chain = true)
public static class Category {
/**
* 分类编号
*/
private Integer id;
/**
* 分类名称
*/
private String name;
}
}
package cn.iocoder.mall.search.biz.response.user;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
/**
* 商品 ES BO
*/
@Data
@Accessors(chain = true)
public class ProductResponse implements Serializable {
private Integer id;
// ========== 基本信息 =========
/**
* SPU 名字
*/
private String name;
/**
* 卖点
*/
private String sellPoint;
/**
* 描述
*/
private String description;
/**
* 分类编号
*/
private Integer cid;
/**
* 分类名
*/
private String categoryName;
/**
* 商品主图地数组
*/
private List<String> picUrls;
// ========== 其他信息 =========
/**
* 是否上架商品(是否可见)。
*
* true 为已上架
* false 为已下架
*/
private Boolean visible;
/**
* 排序字段
*/
private Integer sort;
// ========== Sku 相关字段 =========
/**
* 原价格,单位:分
*/
private Integer originalPrice;
/**
* 购买价格,单位:分。
*/
private Integer buyPrice;
/**
* 库存数量
*/
private Integer quantity;
// ========== 促销活动相关字段 =========
// 目前只促销单体商品促销,目前仅限制折扣。
/**
* 促销活动编号
*/
private Integer promotionActivityId;
/**
* 促销活动标题
*/
private String promotionActivityTitle;
/**
* 促销活动类型
*/
private Integer promotionActivityType;
}
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>search</artifactId>
<groupId>cn.iocoder.mall</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>search-service-api</artifactId>
<dependencies>
<!-- Mall 相关 -->
<dependency>
<groupId>cn.iocoder.mall</groupId>
<artifactId>common-framework</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- 工具类相关 -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId> <!-- use mapstruct-jdk8 for Java 8 or higher -->
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 提供给 mapstruct 使用 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
package cn.iocoder.mall.search.biz.bo;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 商品搜索条件返回 BO
*/
@Data
@Accessors(chain = true)
public class ProductConditionBO {
/**
* 商品分类数组
*/
private List<Category> categories;
@Data
@Accessors(chain = true)
public static class Category {
/**
* 分类编号
*/
private Integer id;
/**
* 分类名称
*/
private String name;
}
}
package cn.iocoder.mall.search.biz.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Collection;
/**
* 获得商品检索条件 DTO
*/
@Data
@Accessors(chain = true)
public class ProductConditionDTO {
/**
* Field - 商品分类
*/
public static final String FIELD_CATEGORY = "category";
/**
* 关键字
*/
private String keyword;
/**
* 需要返回的搜索条件的 fields 名
*/
private Collection<String> fields;
}
package cn.iocoder.mall.search.biz.dto;
import cn.iocoder.common.framework.util.CollectionUtil;
import cn.iocoder.common.framework.vo.SortingField;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
import java.util.Set;
/**
* 商品检索分页 DTO
*/
@Data
@Accessors(chain = true)
public class ProductSearchPageDTO {
public static final Set<String> SORT_FIELDS = CollectionUtil.asSet("buyPrice");
/**
* 分类编号
*/
private Integer cid;
/**
* 关键字
*/
private String keyword;
/**
* 页码
*/
private Integer pageNo;
/**
* 分页大小
*/
private Integer pageSize;
/**
* 排序字段数组
*/
private List<SortingField> sorts;
}
### /product-spu/page 成功(全部)
GET {{shop-api-base-url}}/product-spu/page?pageNo=1&pageSize=10&keyword=骚气
Content-Type: application/x-www-form-urlencoded
### /product-spu/search-condition 成功
GET {{shop-api-base-url}}/product-spu/search-condition?keyword=骚气
Content-Type: application/x-www-form-urlencoded
###
......@@ -4,13 +4,16 @@ import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.shopweb.controller.product.vo.product.ProductSpuPageReqVO;
import cn.iocoder.mall.shopweb.controller.product.vo.product.ProductSpuRespVO;
import cn.iocoder.mall.shopweb.controller.product.vo.product.ProductSpuSearchConditionRespVO;
import cn.iocoder.mall.shopweb.manager.product.ProductSpuManager;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import static cn.iocoder.common.framework.vo.CommonResult.success;
......@@ -30,4 +33,12 @@ public class ProductSpuController {
return success(productSpuManager.pageProductSpu(pageReqVO));
}
@GetMapping("/search-condition")
@ApiOperation("获得商品的搜索条件")
@ApiImplicitParam(name = "keyword", value = "关键字", example = "芋艿")
public CommonResult<ProductSpuSearchConditionRespVO> getProductSpuSearchCondition(
@RequestParam(value = "keyword", required = false) String keyword) {
return success(productSpuManager.getProductSpuSearchCondition(keyword));
}
}
package cn.iocoder.mall.shopweb.controller.product.vo.product;
import cn.iocoder.common.framework.vo.PageParam;
import cn.iocoder.common.framework.vo.SortingField;
import java.util.List;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
@ApiModel("商品 SPU 分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class ProductSpuPageReqVO extends PageParam {
/**
* 分类编号
*/
@ApiModelProperty(value = "分类编号", example = "1")
private Integer cid;
/**
* 关键字
*/
@ApiModelProperty(value = "关键字", example = "芋艿")
private String keyword;
/**
* 排序字段数组
*/
private List<SortingField> sorts;
@ApiModelProperty(value = "排序字段", example = "buyPrice", notes = "参见 SearchProductPageQuerySortFieldEnum 枚举")
private String sortField;
@ApiModelProperty(value = "排序顺序", example = "1")
private String sortOrder;
}
package cn.iocoder.mall.shopweb.controller.product.vo.product;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
......@@ -11,62 +12,38 @@ import java.util.List;
@Accessors(chain = true)
public class ProductSpuRespVO {
@ApiModelProperty(value = "SPU 编号", required = true)
private Integer id;
// ========== 基本信息 =========
/**
* SPU 名字
*/
@ApiModelProperty(value = "SPU 名字", required = true, example = "芋艿")
private String name;
/**
* 卖点
*/
@ApiModelProperty(value = "卖点", required = true, example = "好吃好玩")
private String sellPoint;
/**
* 描述
*/
@ApiModelProperty(value = "描述", required = true, example = "我是哈哈哈")
private String description;
/**
* 分类编号
*/
@ApiModelProperty(value = "分类编号", required = true, example = "1")
private Integer cid;
/**
* 分类名
*/
@ApiModelProperty(value = "分类名字", required = true, example = "蔬菜")
private String categoryName;
/**
* 商品主图地数组
*/
@ApiModelProperty(value = "商品主图地址", required = true, example = "http://www.iocoder.cn/xxx.jpg", notes = "多个之间,使用逗号分隔")
private List<String> picUrls;
// ========== 其他信息 =========
/**
* 是否上架商品(是否可见)。
*
* true 为已上架
* false 为已下架
*/
@ApiModelProperty(value = "是否上架商品", required = true, example = "true")
private Boolean visible;
/**
* 排序字段
*/
@ApiModelProperty(value = "排序字段", required = true, example = "1024")
private Integer sort;
// ========== Sku 相关字段 =========
/**
* 原价格,单位:分
*/
@ApiModelProperty(value = "原始价格,单位:分", required = true, example = "233", notes = "该价格为商品的原始价格")
private Integer originalPrice;
/**
* 购买价格,单位:分。
*/
@ApiModelProperty(value = "购买价格,单位:分", required = true, example = "233", notes = "该价格为商品经过优惠计算后的价格")
private Integer buyPrice;
/**
* 库存数量
*/
@ApiModelProperty(value = "库存数量", required = true, example = "1024")
private Integer quantity;
// ========== 促销活动相关字段 =========
// ========== 促销活动相关字段 ========= TODO 芋艿:等做到促销在处理
// 目前只促销单体商品促销,目前仅限制折扣。
/**
* 促销活动编号
......
package cn.iocoder.mall.search.rest.response.user;
package cn.iocoder.mall.shopweb.controller.product.vo.product;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 商品搜索条件返回 BO
*/
@ApiModel("商品 SPU 搜索条件 Response VO")
@Data
@Accessors(chain = true)
public class UsersProductConditionResponse {
/**
* 商品分类数组
*/
private List<Category> categories;
public class ProductSpuSearchConditionRespVO {
@ApiModel("商品分类信息")
@Data
@Accessors(chain = true)
public static class Category {
/**
* 分类编号
*/
@ApiModelProperty(value = "分类编号", required = true, example = "1")
private Integer id;
/**
* 分类名称
*/
@ApiModelProperty(value = "分类名称", required = true, example = "手机")
private String name;
}
/**
* 商品分类数组
*/
private List<Category> categories;
}
package cn.iocoder.mall.shopweb.convert.product;
import cn.iocoder.common.framework.util.StringUtils;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.common.framework.vo.SortingField;
import cn.iocoder.mall.productservice.rpc.category.dto.ProductCategoryRespDTO;
import cn.iocoder.mall.searchservice.rpc.product.dto.SearchProductPageReqDTO;
import cn.iocoder.mall.searchservice.rpc.product.dto.SearchProductRespDTO;
import cn.iocoder.mall.shopweb.controller.product.vo.product.ProductSpuPageReqVO;
import cn.iocoder.mall.shopweb.controller.product.vo.product.ProductSpuRespVO;
import cn.iocoder.mall.shopweb.controller.product.vo.product.ProductSpuSearchConditionRespVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.Collections;
import java.util.List;
@Mapper
public interface ProductSpuConvert {
ProductSpuConvert INSTANCE = Mappers.getMapper(ProductSpuConvert.class);
SearchProductPageReqDTO convert(ProductSpuPageReqVO bean);
default SearchProductPageReqDTO convert(ProductSpuPageReqVO bean) {
SearchProductPageReqDTO reqDTO = new SearchProductPageReqDTO()
.setCid(bean.getCid()).setKeyword(bean.getKeyword());
reqDTO.setPageNo(bean.getPageNo()).setPageSize(bean.getPageSize());
if (StringUtils.hasText(bean.getSortField()) && StringUtils.hasText(bean.getSortOrder())) {
reqDTO.setSorts(Collections.singletonList(new SortingField(bean.getSortField(), bean.getSortOrder())));
}
return reqDTO;
}
PageResult<ProductSpuRespVO> convertPage(PageResult<SearchProductRespDTO> page);
List<ProductSpuSearchConditionRespVO.Category> convertList(List<ProductCategoryRespDTO> list);
}
package cn.iocoder.mall.shopweb.manager.product;
import cn.iocoder.common.framework.util.CollectionUtils;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.productservice.rpc.category.ProductCategoryRpc;
import cn.iocoder.mall.productservice.rpc.category.dto.ProductCategoryRespDTO;
import cn.iocoder.mall.searchservice.enums.product.SearchProductConditionFieldEnum;
import cn.iocoder.mall.searchservice.rpc.product.SearchProductRpc;
import cn.iocoder.mall.searchservice.rpc.product.dto.SearchProductConditionReqDTO;
import cn.iocoder.mall.searchservice.rpc.product.dto.SearchProductConditionRespDTO;
import cn.iocoder.mall.searchservice.rpc.product.dto.SearchProductRespDTO;
import cn.iocoder.mall.shopweb.controller.product.vo.product.ProductSpuPageReqVO;
import cn.iocoder.mall.shopweb.controller.product.vo.product.ProductSpuRespVO;
import cn.iocoder.mall.shopweb.controller.product.vo.product.ProductSpuSearchConditionRespVO;
import cn.iocoder.mall.shopweb.convert.product.ProductSpuConvert;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.Collections;
import java.util.List;
/**
* Product SPU Manager
* 商品 SPU Manager
*/
@Service
@Validated
......@@ -21,6 +31,9 @@ public class ProductSpuManager {
@DubboReference(version = "${dubbo.consumer.SearchProductRpc.version}")
private SearchProductRpc searchProductRpc;
@DubboReference(version = "${dubbo.consumer.ProductCategoryRpc.version}")
private ProductCategoryRpc productCategoryRpc;
public PageResult<ProductSpuRespVO> pageProductSpu(ProductSpuPageReqVO pageReqVO) {
CommonResult<PageResult<SearchProductRespDTO>> pageResult =
searchProductRpc.pageSearchProduct(ProductSpuConvert.INSTANCE.convert(pageReqVO));
......@@ -28,4 +41,23 @@ public class ProductSpuManager {
return ProductSpuConvert.INSTANCE.convertPage(pageResult.getData());
}
public ProductSpuSearchConditionRespVO getProductSpuSearchCondition(String keyword) {
// 获得搜索条件
CommonResult<SearchProductConditionRespDTO> getSearchProductConditionResult =
searchProductRpc.getSearchProductCondition(new SearchProductConditionReqDTO().setKeyword(keyword)
.setFields(Collections.singletonList(SearchProductConditionFieldEnum.CATEGORY.getField())));
getSearchProductConditionResult.checkError();
// 拼接结果
ProductSpuSearchConditionRespVO conditionRespVO = new ProductSpuSearchConditionRespVO();
if (CollectionUtils.isEmpty(getSearchProductConditionResult.getData().getCids())) {
conditionRespVO.setCategories(Collections.emptyList());
} else {
CommonResult<List<ProductCategoryRespDTO>> listProductCategoriesResult =
productCategoryRpc.listProductCategories(getSearchProductConditionResult.getData().getCids());
listProductCategoriesResult.checkError();
conditionRespVO.setCategories(ProductSpuConvert.INSTANCE.convertList(listProductCategoriesResult.getData()));
}
return conditionRespVO;
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论