1.Nginx前端界面配置
server {
listen 9001;
server_name localhost;
location / {
root html/hm-mall-admin;
index index.html index.htm;
}
}
server {
listen 9002;
server_name localhost;
location / {
root html/hm-mall-portal;
index index.html index.htm;
}
}
listen部分配置端口号,分别走localhost:9001和localhost:9002;将前端的资源包放到Nginx下的html文件夹中,再在root部分配置具体的路径。
2.Nacos启动问题
Nacos安装目录下进入bin文件夹,启动cmd命令,输入指令:
startup.cmd -m standalone
不可以直接双击startup启动文件,直接单击会以默认的Cluster集群方式启动,需要使用standalone模式启动,如果想配置非8848默认端口参数,可以输入以下指令修改端口号启动:
startup.cmd -m standalone -Dserver.port=8848
3.MySQL数据库数据导入ES问题
当数据量过大时,应该分批进行数据导入,不可以一次性导入大量数据。具体实现中,借助商品模块中的分页功能,将全部数据分割成一页一页的等份存入ES,将商品模块的分页接口暴露出来,使用Feign远程调用商品模块。
@Autowired
private ItemFeignClient itemFeignClient;
@Autowired
private RestHighLevelClient client;
@Test
void testBulkRequest() throws IOException {
// 设置每次导入的数据量大小
Integer page = 1;
Integer size = 1000;
while (true) {
PageDTO<Item> pageDTO = itemFeignClient.list(page, size);
if (pageDTO.getList() == null || pageDTO.getList().size() == 0) {
break;
}
// 创建BulkRequest
BulkRequest request = new BulkRequest();
// 准备参数,添加多个新增的Request
for (Item item : pageDTO.getList()) {
// 转换为文档类型ItemDoc
ItemDoc itemDoc = new ItemDoc(item);
// 创建新增文档的Request对象
request.add(new IndexRequest("hmall")
.id(itemDoc.getId().toString())
.source(JSON.toJSONString(itemDoc), XContentType.JSON));
}
// 发送请求
client.bulk(request, RequestOptions.DEFAULT);
page++;
}
}
使用while(true)而不用具体的for循环来改变page参数,在实际的业务中,不会去因为数据库内有多少条数据而去计算循环次数,所以使用for来控制次数是不符合实际业务的。
4.在从MySQL将数据导入ES的过程中,如果出现类似下面的报错:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'com.hmall.search.ItemDocumentTest': Unsatisfied dependency expressed through field 'itemFeignClient'; nested exception is
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.hmall.common.clients.ItemFeignClient': Unexpected exception during bean creation;
nested exception is java.lang.IllegalStateException:
No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?
需要在ES模块中,添加Nacos服务发现依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
对于出现的其他问题:
检查Feign模块对应的客户端接口,保证注解声明的服务名和yml中声明的一致
@FeignClient("itemservice")
5.Feign远程调用依赖引入问题
关于Feign远程调用,只有Feign自身所在的模块需要引入起步依赖
<!-- Feign起步依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
其他用到了远程调用的模块,只需要对应的Feign模块依赖
<!-- Feign模块依赖 -->
<dependency>
<groupId>com.hmall</groupId>
<artifactId>feign-api</artifactId>
<version>1.0</version>
</dependency>
6.RabbitMQ实现MySQL和ES数据同步问题
商品模块的业务包括:分页、根据id查询回显、新增、修改、删除、商品上下架
这里我们先来分析业务逻辑:所有的商品在上架之后,不可以进行修改删除操作,想要进行任何操作必须先进行下架;而当商品下架之后,我们应该将ES部分用户端的商品也同时下架,而对于ES的下架问题,实际实现就是删除索引库中的数据,所以我们得出结论,只要进行下架(即使进行新增,修改,删除等操作),我们直接删除ES中的数据;对于数据新增后不上架,依旧不需要更新ES中的数据,直到上架完成,我们才在ES中进行新增的操作。
通过分析我们可以操作代码,只需要在上下架方法处进行if判断,导向正确的消费者。
// 进行上架操作(1),则新增ES数据 ;进行下架操作(2),则删除ES数据
if (status == 1){
rabbitTemplate.convertAndSend(RabbitMQConfig.ITEM_EXCHANGE, RabbitMQConfig.UPDATE, JSON.toJSONString(item1));
}else if (status == 2){
rabbitTemplate.convertAndSend(RabbitMQConfig.ITEM_EXCHANGE, RabbitMQConfig.REMOVE, JSON.toJSONString(id));
}
// ES数据新增方法
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = UPDATE_QUEUE),
exchange = @Exchange(name = ITEM_EXCHANGE, type = ExchangeTypes.TOPIC),
key = UPDATE
))
public void updateES(String msg) throws IOException {
Item item = JSON.parseObject(msg, Item.class);
// 准备Request对象
IndexRequest indexRequest = new IndexRequest("hmall")
.id(item.getId().toString())
.source(msg, XContentType.JSON);
// 发送请求
client.index(indexRequest, RequestOptions.DEFAULT);
}
// ES数据删除方法
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = REMOVE_QUEUE),
exchange = @Exchange(name = ITEM_EXCHANGE, type = ExchangeTypes.TOPIC),
key = REMOVE
))
public void removeES(String id) throws IOException {
// 准备Request对象
DeleteRequest deleteRequest = new DeleteRequest("hmall", id);
// 发送请求
client.delete(deleteRequest, RequestOptions.DEFAULT);
}