思路:需求分析–表设计–后台基本代码生成(根据数据库表进行生成基本的CRUD)–Swagger或postman测试–前台功能展示
所有的设计都是结合业务进行设计的
商品的属性
商品的属性包括:sku属性和显示属性
显示属性:页面以key和value的方式进行展示
需求分析:
DB中有一张表,存有显示属性和sku属性的值
productType商品类型
type类型:区分sku属性或显示属性
目的:对商品的显示属性进行CRUD(前台的值和后台的属性对应上,就会自动回显)
思路:前台添加多个显示属性,后台通过属性对象接受,然后使用afastJSON转为json字符串,然后保存到ext扩展表,注意此时是更新,不是插入。因为在保商品数据信息的时候,已经保存了显示属性的图文详情。
sku属性:影响商品价格和库存的属性,也叫销售属性
① 需求分析
用户在详情页面可以选择sku属性,切换不同的sku组合,价格和库存会进行动态的改变。
首选后台添加sku属性和属性值------》前台才能进行搜索-------》商品模块添加sku按钮------》弹出dialog:动态获取sku的属性-------》sku的属性值,应该为手动输入-------》保存更新到数据库(包括删除、查询)都是在删除商品的时候进行删除和查询)形成sku数据时保存在sku表内,一个商品有多个sku。查询商品的时候,对应的将sku进行查询、删除。
② sku表设计
与sku相关联的数据
商品表、扩展表(skuProperties)、sku表
添加数据,需要动态的获取sku属性,---》从t_pecification表中进行获取,数据都是保存到sku表内,sku值应该保存在扩展表内 ,有三条数据,就对应三个属性 -----》简言之,扩展表内的sku属性字段内保存的就是属性表(属性表多了一个skuValue的字段)----》选择对应的sku
③前台页面设计(后台需要一定的想象能力)
dialog
商品的上架和下架
- ES知识储备
ElastisSearch 基于Lucene的全文检索框架。(另外还有solr)\
1. 为什么有了Lucene还要使用ElasticSearch???
lucene:需要在本地的磁盘创建索引
IndexWriter : 写索引——
① 写入本地磁盘——不适合实现集群,和缓存思维一致,磁盘文件的资源是不共享的,无法实现索引的同步,官方未提供对应的API
② 索引会占用磁盘空间,占用服务器使用的资源
IndexSearch:搜索索引
ES:
①官方支持集群
②基于lucene
2. 特点
① 针对文本进行全文检索
② 支持集群
③ 实现相关度排序
④ 搜索精准,快速
⑤ 客户端支持(kibana,支持restful风格的传输)
3. 使用场景
① 替代数据库的模糊查询,比数据库快,更加精准
② 与文本搜索相关的
baidu/google使用全文检索的技术
4. 如何使用
① 创建索引
index 对应数据库
type 对应表格
id 对应主键
document 对应一条数据
field 对应具体字段
② 使用kibana
put /index/type/id
put /crm/emp/1
{
"id":3
"name":"zs"
}
------->将mysql的数据转换为es对应的document
④ 使用步骤
a . 安装es(零配置,开瓶即饮)
b . 选择合适的客户端,如:kibana
c . 查询数据库内的额数据,----》转换为es的document,并写入到es中
d . 使用客户端,实现数据的CRUD
⑤ 设置IK分词器
⑥ 实现全局映射(不影响功能实现,简化配置)
5. 实战演练
替代数据库的模糊查询
因为有很多的商品,用户的访问多,去数据库查询,性能较差,
- 商品的上架和下架
将mysql的数据库转换为es的文档
上架: 即把mysql的数据写入es中,只有这样,用户才能在前台搜索到商品。
下架:即将数据从es中进行删除,mysql中的数据不能进行删除,下架之后,用户在前台搜索不到商品
es的java客户端:在SpingBoot进行es的实战
- ES在SpringBoo环境中t使用(Hello ElasticSearch)
SpringBoot内置有SpringDataJpa之类的
1. 版本限制
2. 导入依赖 :web、tet、SpringDataElasticSearch
3. application.yml配置文件 :
4. 启动类
5.准备文档对象,并配置映射规则(分词器、分词字段、不分词字段)
应该和mysql 的数据库对应一致,因为使用的是mysql数据写入es中,字段必须对应,才能进行匹配。类似于domain
于es进行映射,打注解
@Document(indexName="数据库名",type="表名")
@Id
@Feild(type=FieldType.Keyword)不进行分词
String 有text和keyword
text:要分词(方便进行搜索)
keywor:不分词
专有名词不分词、品牌等等有特殊意义的不进行分词
如:name不进行分词,intro,需要进行分词
5. 测试
配置SpringBoot的测试类注解
注入ElasticsearchTemplate: 与数据库进行连接
创建索引
配置映射
实现CRUD
ES启动之后默认端口为9002
java客户端默认端口为9003
kibana客户端默认端口为5601
高级查询示例:
① 创建NativeSeaechBuilder对象 builder
②设置条件
③获取一个query对象,通过builder.build()获取
④执行查询
- 实战
1. 需求分析
上架:就是mysql数据写入到ES中,修改为上架状态
下架:删除ES中的数据,修改为下架状态
2. 流程设计
ES中不需要表设计,实现流程设计
在商品模块,上架按钮。
点击上架时,
① 判断是否是下架状态
不是,返回错误信息给用户
② 修改mysql的商品的状态,以及上架的时间,并将数据查出来并放入到ES中,
点击下架时:
① 判断是否为上架状态
不是,返回错误信息给yonnh
②修改mysql的状态和下架时间,把数据从ES中删除
-----修改状态:
方式1:前端判断。可以减少后台压力,但postman可以绕过前台
方式2:后端判断。安全,但是会增加后台的压力。因为需要进行数据库的查询。
方式3:前台和后台都要判断。
项目实战
ES可以作为一个公共的查询服务,作为其他服务进行调用,因此将es抽取到common模块。
- 1、common_interface模块内导入ES依赖
<!--es依赖-->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
</dependency>
- 2、common_service模块内配置name和节点
spring:
data:
elasticsearch:
cluster-nodes: 127.0.0.1:9300
cluster-name: elasticsearch #name必须为 elasticsearch
- 3、建立需要存入ES内的domain (此处单独建立,不适用和数据库内匹配的domain)
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import static org.springframework.data.elasticsearch.annotations.FieldType.*;
/**
* indexName:就是数据库名 type:就是数据库表
*/
@Document( indexName = "aigou_product",type = "product")
public class ProductEs {
@Id
private Long id;
///字段:来自需求:查询和展示的数据
// 关键字 :标题和副标题(品牌的名字分类的名字)
// 分类id(ProductTypeId) 品牌id(BrandId) 价格:最小值minPrice 最大值maxPrice
// 排序:销量saleCount 评价commentCount 新品onSaleTime 人气viewCount 价格minPrice
@Field(type = Text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
private String queryContent;// name + subName +品牌的名字+ 分类的名字
private Long productTypeId;
private Long brandId;
private Integer minPrice;
private Integer maxPrice;
private Integer saleCount;
private Integer commentCount;
private Long onSaleTime;
private Integer viewCount;
//分页返回数据:价格minPrice 已售多少saleCount 名字
//这些:以后都从mysql中查询,生成静态页面,就不放在es中
// 详情页面: 标题和副标题(Product), 累计评价数:commentCount
// sku相关的东西 显示属性(扩展表)
// 图文详情(直接从数据获取) 媒体属性:媒体属性不用于查询,所以直接从数据库获取
//---------------此处省略getter和setter、toString方法
}
- 4、配置其他服务调用的接口和回调的函数
import cn.lzj.aigou.client.doc.ProductEs;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@FeignClient(value="COMMON-PROVIDER",fallback = EsFallback.class)
public interface EsClient {
//上架
@PostMapping("/common/es/save")
// @RequestMapping(value = "/common/es/save",method = RequestMethod.POST)
void save(@RequestBody ProductEs productEs);
@PostMapping("/common/es/saveAll")
// @RequestMapping(value = "/common/es/saveAll",method = RequestMethod.POST)
void saveAll(@RequestBody List<ProductEs> list);
//下架
@PostMapping("/common/es/delete")
// @RequestMapping(value = "/common/es/delete",method = RequestMethod.POST)
void delete(@RequestBody Long id);
}
package cn.lzj.aigou.client;
import cn.lzj.aigou.client.doc.ProductEs;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class EsFallback implements EsClient{
@Override
public void save(ProductEs productEs) {
}
@Override
public void saveAll(List<ProductEs> list) {
}
@Override
public void delete(Long id) {
}
}
此时Es的服务就已经搭建好了
3. 实现
前台上架或下架---》调用controller ----》service:使用feign进行调用
后台:提供公共服务
定义ES客户端接口,实现CRUDfangf
controller实现接口
service:封装crud方法
封装映射?
domain内进行配置。只配置需要搜索的内容,放入ES中,以供前台查询展示。所以应该单独写一个domain来映射ducument的字段
前台需要哪些数据来进行一个数据的搜索?分析业务