导入项目依赖
创建springboot项目上导入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- es -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<!--Mybatis-plus的依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<!-- kafka -->
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.15</version>
</dependency>
</dependencies>
编写配置文件
在application.yml中编写配置项目的启动信息
# 应用服务 WEB 访问端口
server:
port: 8080
#数据库的驱动
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/shop?serverTimezone=GMT%2b8
username: root
password: 123456
# elasticsearch的对应ip
elasticsearch:
uris: 121.40.249.149:9200
kafka:
bootstrap-servers: 121.40.249.149:9092 #kafka地址
# mybatis的日志、可以看到mybatisPlus的执行语句,参数等详细信息
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
编写相关的代码
商品实体类
/**
* 商品信息
* @TableName t_product
*/
@Data
@TableName("t_product")
public class Product implements Serializable {
/**
*
*/
private Integer id;
/**
* 商品类型
*/
private Integer typeId;
/**
* 价格
*/
private BigDecimal price;
/**
* 商品名称
*/
private String productName;
/**
* 商品图片
*/
private String productImg;
/**
* 商品详情
*/
private String productDetails;
/**
* 库存数量
*/
private Integer productNum;
/**
* 创建时间
*/
private Date createTime;
/**
* 创建人
*/
private String createBy;
/**
* 修改时间
*/
private Date updateTime;
/**
* 修改人
*/
private String updateBy;
private static final long serialVersionUID = 1L;
}
创建商品Vo的实体类
该实体类用于es中对应的文档属性
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
@Data
// @Document 注解用于告诉Elasticsearch客户端这个类代表一个文档,并指定了文档应该索引
@Document(indexName = "product-index")
public class ProductTOElasticVo {
@Id
private String productId;
// 使用ik_max_word分词器进行文本分析
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String productName;
@Field(type = FieldType.Double)
private BigDecimal productPrice;
@Field(type = FieldType.Integer)
private String productNum;
}
创建es操作接口
ProductRepository接口,继承自CrudRepository,提供对ProductTOElastic类型数据的基本CRUD操作。
该接口为操作产品数据提供了一套方法,使得可以在Elasticsearch中进行产品数据的增删改查。
public interface ProductRepository extends CrudRepository<ProductTOElasticVo,String> {
}
相关业务层代码
该Java类是一个Kafka服务类,其中包含一个发送消息到Kafka的主题的公共方法
@Slf4j
@Service
public class KafkaService {
@Autowired
private KafkaTemplate<String, String> kafkaTemplate;
/**
* 创建发送消息公共方法
*/
public void sendMsgToKafka(Object object, String type) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("type", type);
jsonObject.put("data", object);
kafkaTemplate.send("test", jsonObject.toString());
}
}
该Java类是一个Kafka消费者服务,用于监听名为"test"的主题,并根据接收到的消息类型执行对应的操作。
- @KafkaListener注解表示该方法是一个Kafka消费者,topics = “test"指定监听的主题为"test”,groupId = “test"指定消费者组ID为"test”。
- receiveMessage方法将接收到的消息解析为JSON对象,并根据消息类型执行对应的操作,包括添加或更新数据到ES、删除数据以及同步所有数据到ES。
- synchronousValueToElastic方法用于将所有数据从数据库同步到ElasticSearch中,通过调用productService.list获取所有产品信息,并将这些信息转换为ProductTOElasticVo对象,然后通过调用productRepository.saveAll保存到ElasticSearch中。
- addOrEditData方法用于添加或更新数据到ElasticSearch中,根据接收到的消息内容解析出产品信息,并将其转换为ProductTOElasticVo对象,然后通过调用productRepository.save保存到ElasticSearch中。CrudRepository中的save()这个方法既可以用于新增数据,也可以用于更新已有的数据。具体来说,如果实体对象已经存在于数据库中,调用 save() 方法会执行更新操作;如果实体对象在数据库中不存在,调用 save() 方法会执行新增操作。
- delData方法用于从ElasticSearch中删除数据,根据接收到的消息内容删除指定ID的产品
@Slf4j
@Service
public class KafkaConsumerService {
@Resource
private ProductRepository productRepository;
@Resource
private ProductService productService;
@KafkaListener(topics = "test", groupId = "test")
public void receiveMessage(String message) {
JSONObject jsonObject = JSONUtil.parseObj(message);
// 根据对应的消息类型进行操作
if (ObjectUtil.equals(TypeEnum.ADDOREDIT.getValue(), jsonObject.get("type"))) {
addOrEditData(jsonObject.get("data"));
} else if (ObjectUtil.equals(TypeEnum.DELETE.getValue(), jsonObject.get("type"))) {
delData(jsonObject.get("data"));
} else {
synchronousValueToElastic();
}
}
/**
* 同步所有数据
*/
public boolean synchronousValueToElastic() {
List<Product> list = productService.list();
if (CollUtil.isNotEmpty(list)) {
List<ProductTOElasticVo> productTOElasticList = new ArrayList<>();
list.stream().map(product -> {
ProductTOElasticVo pe = new ProductTOElasticVo();
pe.setId(String.valueOf(product.getId()));
pe.setProductName(product.getProductName());
pe.setProductPrice(product.getProductPrice().doubleValue());
return pe;
}).forEach(productTOElasticList::add);
// 将数据存入ElasticSearch中
Iterable<ProductTOElasticVo> productTOElastics = productRepository.saveAll(productTOElasticList);
if (!IterUtil.isEmpty(productTOElastics)) {
return true;
}
}
return false;
}
/**
* 添加或更新数据到es
*
* @param object
*/
public void addOrEditData(Object object) {
if (StrUtil.isNotBlank(object.toString())) {
log.info("----------开始同步数据----------");
Product product = JSONUtil.toBean(object.toString(), Product.class);
ProductTOElasticVo productTOElasticVo = new ProductTOElasticVo();
// 复制对象
BeanUtil.copyProperties(product, productTOElasticVo);
boolean b = productRepository.existsById(productTOElasticVo.getId());
ProductTOElasticVo save = productRepository.save(productTOElasticVo);
if (ObjectUtil.isNull(save)) {
log.info("----------ES同步数据失败----------");
} else {
log.info("----------ES同步数据成功----------");
}
}
}
/**
* es删除
*
* @param object
*/
private void delData(Object object) {
if (StrUtil.isNotBlank(object.toString())) {
log.info("----------开始同步数据----------");
productRepository.deleteById(object.toString());
log.info("----------开始同步结束----------");
}
}
商品业务代码,并且集成了Kafka消息队列用户同步将数据库的数据更新到es中
public interface ProductService extends IService<Product> {
ResponseData getAll();
ResponseData insert(Product product);
ResponseData edit(Product product);
ResponseData del(Integer id);
}
@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product>
implements ProductService {
@Resource
private ProductRepository productRepository;
@Resource
private KafkaService kafkaService;
/**
* 查询所有数据
*/
@Override
public ResponseData getAll() {
int count = count();
//
if (!NumberUtil.equals(count, productRepository.count())) {
// 同步全部
kafkaService.sendMsgToKafka(null, TypeEnum.SYN.getValue());
return ResponseData.Ok(list());
}
Iterable<ProductTOElasticVo> all = productRepository.findAll();
Iterator<ProductTOElasticVo> iterator = all.iterator();
List<ProductTOElasticVo> productTOElasticList = new ArrayList<>();
while (iterator.hasNext()) {
productTOElasticList.add(iterator.next());
}
return ResponseData.Ok(productTOElasticList);
}
@Override
public ResponseData insert(Product product) {
product.setCreateTime(DateUtil.date());
product.setCreateBy("admin");
boolean save = save(product);
// 向kafka发送添加消息
kafkaService.sendMsgToKafka(product, TypeEnum.ADDOREDIT.getValue());
if (save) {
return ResponseData.Ok();
}
return ResponseData.error();
}
@Override
public ResponseData edit(Product product) {
product.setUpdateTime(DateUtil.date());
product.setUpdateBy("admin");
boolean update = updateById(product);
// 向kafka发送修改消息
kafkaService.sendMsgToKafka(product, TypeEnum.ADDOREDIT.getValue());
if (update) {
return ResponseData.Ok();
}
return ResponseData.error();
}
@Override
public ResponseData del(Integer id) {
boolean b = removeById(id);
if (b) {
// 发送删除消息
kafkaService.sendMsgToKafka(id, TypeEnum.DELETE.getValue());
return ResponseData.Ok();
}
return ResponseData.error();
}
}