文章目录
增量同步
1.功能分析
- 前端页面,点击"上架"链接,执行上架的动作
- 请求的url
/product/spuinfo/{spuid}/up
参数:
spuid
请求方法:
post
返回值:
R(转换成json数据) - product工程中
controller:
接收页面请求的参数
调用service处理请求
service:
1接收controller传递过来的参数,spuId
2根据spuId找到对应的商品修改商品状态
修改tb_spuinfo表中的publish_status字段为1
3需要把商品添加到索引库中,调用search工程的服务,实现ES索引库的添加
4返回结果 - 服务之间调用使用OpenFeign技术
- Search工程中
controller:
接收请求的参数:spuId
调用service商品添加到索引库
Service:
1.根据spuId查询对象的商品数据
2.商品数据包含的字段 Entity中包含的字段
3.使用ElasticSearchRepository对象将数据添加到索引库中
4.返回结果
2.索引库中文档的结构
(1) 字段分析
tb_spu_info
- id
- spu_name
- spu_description
- category_id
- brand_id
- update_time
tb_category
- name
tb_brand
- name
- image
tb_spu_images
- img_url
tb_sku_info
- price 取最低价格
(2) SQL语句
全量同步
1.实现思路
- 把所有的商品数据查询出来
- 把商品数据导入到ES中
2.dao层
查询出所有上架状态的商品数据
SELECT
a.id,
a.spu_name spuName,
a.spu_description spuDescription,
a.category_id categoryId,
c.`name` categoryName,
a.brand_id brandId,
d.`name` brandName,
d.image brandImage,
a.update_time updateTime,
b.img_url imgUrl,
e.price
FROM tb_spu_info a
left join (select * from tb_spu_images where default_img = 1) b on a.id=b.spu_id
left join tb_category c on a.category_id = c.id
left join tb_brand d on a.brand_id = d.id
left join (
select spu_id, min(price) price from tb_sku_info GROUP BY spu_id
) e on a.id = e.spu_id
WHERE a.publish_status=1
3.service层
- 把所有的商品数据查询出来
- 把商品数据导入到ES中
SpuInfoDao.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xd.cubemall.search.dao.SpuInfoDao">
<!-- 可根据自己的需求,是否要使用 -->
<resultMap type="com.xd.cubemall.search.entity.SpuInfoEntity" id="spuInfoMap">
<result property="id" column="id"/>
<result property="spuName" column="spu_name"/>
<result property="spuDescription" column="spu_description"/>
<result property="categoryId" column="category_id"/>
<result property="brandId" column="brand_id"/>
<result property="weight" column="weight"/>
<result property="publishStatus" column="publish_status"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
</resultMap>
<select id="getSpuInfoById" parameterType="long" resultType="com.xd.cubemall.search.model.SpuInfo">
SELECT
a.id,
a.spu_name spuName,
a.spu_description spuDescription,
a.category_id categoryId,
c.`name` categoryName,
a.brand_id brandId,
d.`name` brandName,
d.image brandImage,
a.update_time updateTime,
b.img_url imgUrl,
e.price
FROM tb_spu_info a
left join (select * from tb_spu_images where default_img = 1) b on a.id=b.spu_id
left join tb_category c on a.category_id = c.id
left join tb_brand d on a.brand_id = d.id
left join (
select spu_id, min(price) price from tb_sku_info GROUP BY spu_id
) e on a.id = e.spu_id
WHERE a.id=#{spuId}
</select>
<select id="getSpuInfoList" resultType="com.xd.cubemall.search.model.SpuInfo">
SELECT
a.id,
a.spu_name spuName,
a.spu_description spuDescription,
a.category_id categoryId,
c.`name` categoryName,
a.brand_id brandId,
d.`name` brandName,
d.image brandImage,
a.update_time updateTime,
b.img_url imgUrl,
e.price
FROM tb_spu_info a
left join (select * from tb_spu_images where default_img = 1) b on a.id=b.spu_id
left join tb_category c on a.category_id = c.id
left join tb_brand d on a.brand_id = d.id
left join (
select spu_id, min(price) price from tb_sku_info GROUP BY spu_id
) e on a.id = e.spu_id
WHERE a.publish_status=1
</select>
</mapper>
SpuInfo实体类
package com.xd.cubemall.search.model;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import java.util.Date;
@Data
@Document(indexName = "goods_1", shards = 5, replicas = 1)
public class SpuInfo {
@Id
@Field(type = FieldType.Long)
private Long id;
@Field(type = FieldType.Text, store = true, analyzer = "ik_max_word")
private String spuName;
@Field(type = FieldType.Text, store = true, analyzer = "ik_max_word")
private String spuDescription;
@Field(type = FieldType.Long)
private Long categoryId;
@Field(type = FieldType.Keyword, store = true)
private String categoryName;
@Field(type = FieldType.Long)
private Long brandId;
@Field(type = FieldType.Keyword, store = true)
private String brandName;
@Field(type = FieldType.Keyword, store = true, index = false)
private String brandImage;
@Field(type = FieldType.Date, store = true, format = DateFormat.basic_date_time)
private Date updateTime;
@Field(type = FieldType.Keyword, store = true, index = false)
private String imgUrl;
@Field(type = FieldType.Double, store = true)
private Double price;
}
application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/cube_goods?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: root
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
ip: 127.0.0.1
application:
name: cubemall-search
elasticsearch:
rest:
uris:
- 1.1.1.1:9200
- 2.2.2.2:9200
- 3.3.3.3:9200
server:
port: 8082
mybatis-plus:
mapper-locations: classpath:/mappers/*.xml
global-config:
db-config:
id-type: auto
logic-delete-value: 1 #逻辑删除值(默认为1)
logic-not-delete-value: 0 #逻辑未删除值(默认为0)
logging:
level:
com.xd.cubemall: debug
pom.xml
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<artifactId>chubemall-search</artifactId>
<packaging>jar</packaging>
<name>chubemall-search</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR3</spring-cloud.version>
<elasticsearch.version>7.10.2</elasticsearch.version>
</properties>
<dependencies>
<!-- <dependency>-->
<!-- <groupId>junit</groupId>-->
<!-- <artifactId>junit</artifactId>-->
<!-- <version>3.8.1</version>-->
<!-- <scope>test</scope>-->
<!-- </dependency>-->
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
<scope>provided</scope>
</dependency>
<!--引入common公共模块-->
<dependency>
<groupId>com.xd.cubemall</groupId>
<artifactId>cubemall-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.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.elasticsearch.client</groupId>-->
<!-- <artifactId>elasticsearch-rest-high-level-client</artifactId>-->
<!-- <version>7.10.2</version>-->
<!-- </dependency>-->
<!--阿里云OSS-->
<!-- <dependency>-->
<!-- <groupId>com.aliyun.oss</groupId>-->
<!-- <artifactId>aliyun-sdk-oss</artifactId>-->
<!-- <version>3.17.4</version>-->
<!-- </dependency>-->
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
SpuInfoController.java
package com.xd.cubemall.search.controller;
import com.xd.cubemall.common.utils.R;
import com.xd.cubemall.search.service.SpuInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(("/spuinfo"))
public class SpuInfoController {
@Autowired
private SpuInfoService spuInfoService;
private volatile boolean executeFlag = false;
@GetMapping("putonsale/{spuId}")
public R putOnSale(@PathVariable("spuId") Long spuId){
R r = spuInfoService.putOnSale(spuId);
return r;
}
/**
* 商品数据全量同步
* @return
*/
@GetMapping("/syncSpuInfo")
public R syncSpuInfo() {
if (!executeFlag) {
synchronized (this) {
if (!executeFlag) {
executeFlag = true;
R r = spuInfoService.syncSpuInfo();
return r;
}
}
}
return R.ok("数据正导入中,请勿重复执行");
}
}
SpuInfoDao.java
package com.xd.cubemall.search.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xd.cubemall.search.entity.SpuInfoEntity;
import com.xd.cubemall.search.model.SpuInfo;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* spu信息
*
* @author xuedong
* @email email@gmail.com
* @date 2024-08-13 01:36:04
*/
@Mapper
public interface SpuInfoDao extends BaseMapper<SpuInfoEntity> {
SpuInfo getSpuInfoById(Long spuId);
List<SpuInfo> getSpuInfoList();
}
SpuInfoEntity.java
package com.xd.cubemall.search.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* spu信息
*
* @author xuedong
* @email email@gmail.com
* @date 2024-08-13 01:36:04
*/
@Data
@TableName("tb_spu_info")
public class SpuInfoEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 自增ID
*/
@TableId
private Long id;
/**
* spu名称
*/
private String spuName;
/**
* spu描述
*/
private String spuDescription;
/**
* 分类ID
*/
private Long categoryId;
/**
* 品牌ID
*/
private Long brandId;
/**
* 权重
*/
private BigDecimal weight;
/**
* 发布状态
*/
private Integer publishStatus;
/**
*
*/
private Date createTime;
/**
*
*/
private Date updateTime;
}
SpuInfoRepository.java
package com.xd.cubemall.search.repository;
import com.xd.cubemall.search.model.SpuInfo;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
public interface SpuInfoRepository extends ElasticsearchRepository<SpuInfo,Long> {
}
SpuInfoServiceImpl.java
package com.xd.cubemall.search.service.impl;
import com.xd.cubemall.common.utils.R;
import com.xd.cubemall.search.dao.SpuInfoDao;
import com.xd.cubemall.search.model.SpuInfo;
import com.xd.cubemall.search.repository.SpuInfoRepository;
import com.xd.cubemall.search.service.SpuInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class SpuInfoServiceImpl implements SpuInfoService {
@Autowired
private SpuInfoDao spuInfoDao;
@Autowired
private SpuInfoRepository spuInfoRepository;
@Override
public R putOnSale(long spuId) {
// 1.根据spuId查询对象的商品数据
SpuInfo spuInfo = spuInfoDao.getSpuInfoById(spuId);
// 2.商品数据包含的字段 Entity中包含的字段
// 3.使用ElasticSearchRepository对象将数据添加到索引库中
spuInfoRepository.save(spuInfo);
// 4.返回结果
return R.ok();
}
@Override
public R syncSpuInfo() {
// 1) 把所有的商品数据查询出来
List<SpuInfo> infoList = spuInfoDao.getSpuInfoList();
// 2) 把商品数据导入到ES中
spuInfoRepository.saveAll(infoList);
//返回结果
return R.ok();
}
}
CubemallSearchApplication.java
package com.xd.cubemall.search;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.xd.cubemall.search.dao")
public class CubemallSearchApplication{
public static void main(String[] args) {
SpringApplication.run(CubemallSearchApplication.class);
}
}