You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

384 lines
12 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 一、商品上架功能
在线笔记https://dpb-bobokaoya-sm.blog.csdn.net/
ElasticSearch实现商城系统中全文检索的流程。
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1645443661000/ff739a228f5b44e0a790f81d59c4c8c6.png)
## 1.商品ES模型
商品的映射关系
```json
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"
}
}
}
}
}
}
```
## 2.netsted数据类型
参考官网地址https://www.elastic.co/guide/en/elasticsearch/reference/7.4/nested.html
在线笔记https://dpb-bobokaoya-sm.blog.csdn.net/
## 3.实现上架功能
### 3.1 创建ESModel
点击上架功能传递spuId到后台我们需要根据SpuID查询对应的信息然后封装到自定义的Model对象中然后将该对象传递给mall-search服务所以我们需要先定义这样一个Model对象
```java
@Data
public class SkuESModel {
private Long skuId;
private Long spuId;
private String subTitle;
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;
}
}
```
### 3.2 上架逻辑实现
```java
/**
* 实现商品上架--》商品相关数据存储到ElasticSearch中
* 1.根据SpuID查询出相关的信息
* 封装到对应的对象中
* 2.将封装的数据存储到ElasticSearch中--》调用mall-search的远程接口
* 3.更新SpuID对应的状态--》上架
*
* @param spuId
*/
@Override
public void up(Long spuId) {
// 1.根据spuId查询相关的信息 封装到SkuESModel对象中
List<SkuESModel> skuEs = new ArrayList<>();
// 根据spuID找到对应的SKU信息
List<SkuInfoEntity> skus = skuInfoService.getSkusBySpuId(spuId);
// 对应的规格参数 根据spuId来查询规格参数信息
List<SkuESModel.Attrs> attrsModel = getAttrsModel(spuId);
// 需要根据所有的skuId获取对应的库存信息---》远程调用
List<Long> skuIds = skus.stream().map(sku -> {
return sku.getSkuId();
}).collect(Collectors.toList());
Map<Long, Boolean> skusHasStockMap = getSkusHasStock(skuIds);
// 2.远程调用mall-search的服务将SukESModel中的数据存储到ES中
List<SkuESModel> skuESModels = skus.stream().map(item -> {
SkuESModel model = new SkuESModel();
// 先实现属性的复制
BeanUtils.copyProperties(item,model);
model.setSubTitle(item.getSkuTitle());
model.setSkuPrice(item.getPrice());
// hasStock 是否有库存 --》 库存系统查询 一次远程调用获取所有的skuId对应的库存信息
if(skusHasStockMap == null){
model.setHasStock(true);
}else{
model.setHasStock(skusHasStockMap.get(item.getSkuId()));
}
// hotScore 热度分 --> 默认给0即可
model.setHotScore(0l);
// 品牌和类型的名称
BrandEntity brand = brandService.getById(item.getBrandId());
CategoryEntity category = categoryService.getById(item.getCatalogId());
model.setBrandName(brand.getName());
model.setBrandImg(brand.getLogo());
model.setCatalogName(category.getName());
// 需要存储的规格数据
model.setAttrs(attrsModel);
return model;
}).collect(Collectors.toList());
// 将SkuESModel中的数据存储到ES中
R r = searchFeginService.productStatusUp(skuESModels);
// 3.更新SPUID对应的状态
// 根据对应的状态更新商品的状态
log.info("----->ES操作完成{}" ,r.getCode());
System.out.println("-------------->"+r.getCode());
if(r.getCode() == 0){
// 远程调用成功 更新商品的状态为 上架
baseMapper.updateSpuStatusUp(spuId, ProductConstant.StatusEnum.SPU_UP.getCode());
}else{
// 远程调用失败
}
}
```
# 二、三级分类数据
## 1.一级分类的数据
加载商城首页的时候就需要获取一级分类的数据
```java
@GetMapping({"/","/index.html","/home","/home.html"})
public String index(Model model){
// 查询出所有的一级分类的信息
List<CategoryEntity> list = categoryService.getLeve1Category();
model.addAttribute("categorys",list);
// classPath:/templates/
// .html
return "index";
}
```
在Service中的实现
```java
/**
* 查询出所有的商品大类(一级分类)
* @return
*/
@Override
public List<CategoryEntity> getLeve1Category() {
List<CategoryEntity> list = baseMapper.queryLeve1Category();
return list;
}
```
然后在index.html中处理
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1645443661000/060401ab8d3b4a94a93592ddcec25353.png)
然后访问页面的效果
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1645443661000/4fb19df2873648309fcc0a4f7e86ab02.png)
## 2.二三级分类数据
在默认的情况下其实加载的是写死的JSON文件
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1645443661000/6c1b243955e74222be7cfe51e12a2463.png)
结合这个文件我们创建了对应的VO对象来封装对应的数据
```java
package com.msb.mall.product.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 二级分类需要展示的数据VO
*/
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Catalog2VO {
private String catalog1Id; // 二级分类对应的一级父类的编号
private List<Catalog3VO> catalog3List; // 二级分类对应的三级分类的数据
private String id; // 二级分类的编号
private String name ; // 二级分类对应的类别名称
/**
* 三级分类
*/
@NoArgsConstructor
@AllArgsConstructor
@Data
public static class Catalog3VO{
private String catalog2Id ; // 三级分类对应的二级分类的编号
private String id; // 三级分类编号
private String name; // 三级分类名称
}
}
```
然后我们在服务端查询对应的数据
```java
@ResponseBody
@RequestMapping("/index/catalog.json")
public Map<String, List<Catalog2VO>> getCatalog2JSON(){
Map<String, List<Catalog2VO>> map = categoryService.getCatelog2JSON();
return map;
}
```
然后在service中完成对应的逻辑
```java
/**
* 查询出所有的二级和三级分类的数据
* 并封装为Map<String, Catalog2VO>对象
* @return
*/
@Override
public Map<String, List<Catalog2VO>> getCatelog2JSON() {
// 获取所有的一级分类的数据
List<CategoryEntity> leve1Category = this.getLeve1Category();
// 把一级分类的数据转换为Map容器 key就是一级分类的编号 value就是一级分类对应的二级分类的数据
Map<String, List<Catalog2VO>> map = leve1Category.stream().collect(Collectors.toMap(
key -> key.getCatId().toString()
, value -> {
// 根据一级分类的编号,查询出对应的二级分类的数据
List<CategoryEntity> l2Catalogs = baseMapper
.selectList(new QueryWrapper<CategoryEntity>().eq("parent_cid", value.getCatId()));
List<Catalog2VO> Catalog2VOs =null;
if(l2Catalogs != null){
Catalog2VOs = l2Catalogs.stream().map(l2 -> {
// 需要把查询出来的二级分类的数据填充到对应的Catelog2VO中
Catalog2VO catalog2VO = new Catalog2VO(l2.getParentCid().toString(), null, l2.getCatId().toString(), l2.getName());
// 根据二级分类的数据找到对应的三级分类的信息
List<CategoryEntity> l3Catelogs = baseMapper.selectList(new QueryWrapper<CategoryEntity>().eq("parent_cid", catalog2VO.getId()));
if(l3Catelogs != null){
// 获取到的二级分类对应的三级分类的数据
List<Catalog2VO.Catalog3VO> catalog3VOS = l3Catelogs.stream().map(l3 -> {
Catalog2VO.Catalog3VO catalog3VO = new Catalog2VO.Catalog3VO(l3.getParentCid().toString(), l3.getCatId().toString(), l3.getName());
return catalog3VO;
}).collect(Collectors.toList());
// 三级分类关联二级分类
catalog2VO.setCatalog3List(catalog3VOS);
}
return catalog2VO;
}).collect(Collectors.toList());
}
return Catalog2VOs;
}
));
return map;
}
```
修改js中的访问路径
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1645443661000/08c5115601a54c84aa8a314972a77665.png)
然后访问即可
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1645443661000/f859f724ef224297a6dcfc01ad33dacc.png)
# 三、Nginx域名
## 1.hosts文件
在c:/window/system32/drivers/etc/hosts文件我们在这个文件中添加
```hosts
192.168.56.100 msb.mall.com
```
注意如果是没有操作权限,那么点击该文件右击属性,去掉只读属性即可
通过这个域名访问到Nginx服务
## 2.Nginx的方向代理
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1645443661000/af848cb6a4094d86a740ccdc04b2f136.png)
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1645443661000/ea79b90d44834bac9d268b6f8ee18dd3.png)
## 3.Nginx的负载均衡
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1645443661000/d7e1e31d4c24466f8a15f64e6b3fffae.png)
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1645443661000/485a6db3c3f045a7981fcacf8391907c.png)
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1645443661000/d3d7b8f9d7514f70a67ed965f8ea9bf4.png)
对应的需要修改网关的配置
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1645443661000/16d180a1b164475fb4baa4311b6fffc2.png)
然后即可通过域名来访问商城的首页
![image.png](https://fynotefile.oss-cn-zhangjiakou.aliyuncs.com/fynote/1462/1645443661000/ff1dfbf57a734a049c57f569ce732111.png)