SpringBoot整合Elasticsearch的CRUD--kafka同步更新数据库到es

导入项目依赖

创建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();
    }

}

验证

1.png2.png3.png4.png

  • 23
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值