九、黑马程序员酒店admin之数据同步代码

文末附上项目的下载地址

1、数据同步方案选型

es和数据库之间的数据同步和数据库数据的数据迁移、主从同步、数据实时同步是相似的在各个方案之间,选择和定制适合特定业务场景的数据同步策略,为构建高效、稳定、可扩展的系统奠定基础。

1.1 方案1、程序处理(直接调用、服务接口调用)

1、先写入数据库

2、调用es接口写入es(es处理数据异常时,要重新放回es,一直异常,要排查程序)

实现简单。耦合,影响性能,一个位置发生异常,程序终止

方案二、异步通知

1、写入数据库

2、发布消息(发布消息异常的处理机制)

3、监听消息,更新es(同样要处理异常消息)

可靠性依赖mq的稳定性

方案三、监听数据库的binlog

1、写入数据库

2、利用一些中间件入canal等工具,监听日志

3、通知es的服务更新es

耦合度最低,要开启binlog,影响数据库性能,依赖数据管理员

2、黑马酒店admin代码(增删改/生产消息)

2.1 目录结构

在这里插入图片描述

2.2 MqContents代码
package com.toto.es.hotel.constants;

public class MqContents {
    /**
     * 交换机
     */
    public final static String HOTEL_EXCHANGE = "hotel.topic";
    /**
     * 监听新增和修改的队列
     */
    public final static String HOTEL_INSERT_QUEUE = "hotel.insert.queue";
    /**
     * 监听删除的队列
     */
    public final static String HOTEL_DELETE_QUEUE = "hotel.delete.queue";
    /**
     * 监听新增和修改的队列的路由键
     */
    public final static String HOTEL_INSERT_KEY = "hotel.insert";
    /**
     * 监听删除的队列的路由键
     */
    public final static String HOTEL_DELETE_KEY = "hotel.delete";
}

2.3 HotelMapper代码
package com.toto.es.hotel.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.toto.es.hotel.pojo.Hotel;

public interface HotelMapper extends BaseMapper<Hotel> {
}

2.4 Hotel代码
package com.toto.es.hotel.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("tb_hotel")
public class Hotel {
    @TableId(type = IdType.INPUT)
    private Long id;
    private String name;
    private String address;
    private Integer price;
    private Integer score;
    private String brand;
    private String city;
    private String starName;
    private String business;
    private String longitude;
    private String latitude;
    private String pic;
}

2.5 PageResult代码
package com.toto.es.hotel.pojo;

import lombok.Data;

import java.util.List;

@Data
public class PageResult {
    private Long total;
    private List<Hotel> hotels;

    public PageResult() {
    }

    public PageResult(Long total, List<Hotel> hotels) {
        this.total = total;
        this.hotels = hotels;
    }
}

2.6 IHotelService代码
package com.toto.es.hotel.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.toto.es.hotel.pojo.Hotel;

public interface IHotelService extends IService<Hotel> {

}

2.7 HotelService代码
package com.toto.es.hotel.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.toto.es.hotel.mapper.HotelMapper;
import com.toto.es.hotel.pojo.Hotel;
import com.toto.es.hotel.service.IHotelService;
import org.springframework.stereotype.Service;

@Service
public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {
}

2.8 HotelController代码
package com.toto.es.hotel.web;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.toto.es.hotel.constants.MqContents;
import com.toto.es.hotel.pojo.Hotel;
import com.toto.es.hotel.pojo.PageResult;
import com.toto.es.hotel.service.IHotelService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.security.InvalidParameterException;

@RestController
@RequestMapping("hotel")
public class HotelController {

    @Autowired
    private IHotelService hotelService;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GetMapping("/{id}")
    public Hotel queryById(@PathVariable("id") Long id){
        return hotelService.getById(id);
    }

    @GetMapping("/list")
    public PageResult hotelList(@RequestParam(value = "page", defaultValue = "1") Integer page, @RequestParam(value = "size", defaultValue = "1") Integer size){
        QueryWrapper wrapper = new QueryWrapper<>();
        wrapper.orderByAsc("id");
        Page<Hotel> result = hotelService.page(new Page<>(page, size), wrapper);
        return new PageResult(result.getTotal(), result.getRecords());
    }

    @PostMapping
    public void saveHotel(@RequestBody Hotel hotel){
        hotelService.save(hotel);
        rabbitTemplate.convertAndSend(MqContents.HOTEL_EXCHANGE, MqContents.HOTEL_INSERT_KEY, hotel.getId());
    }

    @PutMapping()
    public void updateById(@RequestBody Hotel hotel){
        if (hotel.getId() == null) {
            throw new InvalidParameterException("id不能为空");
        }
        hotelService.updateById(hotel);
        rabbitTemplate.convertAndSend(MqContents.HOTEL_EXCHANGE, MqContents.HOTEL_INSERT_KEY, hotel.getId());
    }

    @DeleteMapping("/{id}")
    public void deleteById(@PathVariable("id") Long id) {
        hotelService.removeById(id);
        rabbitTemplate.convertAndSend(MqContents.HOTEL_EXCHANGE, MqContents.HOTEL_DELETE_KEY, id);
    }
}

2.9 HotelAdminApplication代码

package com.toto.es.hotel;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;

import java.net.InetAddress;
import java.net.UnknownHostException;

@Slf4j
@MapperScan(basePackages = "com.toto.es.hotel.mapper")
@SpringBootApplication
public class HotelAdminApplication {

    public static void main(String[] args) throws UnknownHostException {
        ConfigurableApplicationContext application = SpringApplication.run(HotelAdminApplication.class,args);
        Environment env = application.getEnvironment();
        String ip = InetAddress.getLocalHost().getHostAddress();
        String port = env.getProperty("server.port");
        log.info("\n----------------------------------------------------------\n\t" +
                //"ElasticSearch Demo: \thttp://localhost" + ip + ":" + port + "\n" +
                "ElasticSearch Demo: \thttp://localhost:" + port + "\n" +
                "----------------------------------------------------------");
        openE("http://localhost:" + port + "");
    }

    private static void openE(String url) {
        String runCmd = "cmd   /c   start " + url;
        Runtime run = Runtime.getRuntime();
        try {
            run.exec(runCmd);
        } catch (Exception e) {
            System.out.println("启动项目自动打开浏览器失败");
        }
    }

    // 最新版
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

    @Bean
    public ElasticsearchClient slasticsearchClient() {
        BasicCredentialsProvider credsProv = new BasicCredentialsProvider();
        credsProv.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("elastic", "elastic"));

        RestClient restClient = RestClient.builder(HttpHost.create("http://127.0.0.1:9200"))
                .setHttpClientConfigCallback(hc -> hc.setDefaultCredentialsProvider(credsProv))
                .build();
        ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
        return new ElasticsearchClient(transport);
    }
}

2.10 application.yaml代码
server:
  port: 8099
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:23306/totograin?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: guest
    password: guest
    virtual-host: /
logging:
  level:
    com.toto: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true
  type-aliases-package: com.toto.es.hotel.pojo

3、黑马酒店demo代码(消费消息)、补全上一章代码

3.1 目录结构

在这里插入图片描述

3.2 MqConfig代码
package com.toto.es.hotel.config;

import com.toto.es.hotel.constants.MqContents;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MqConfig {

    @Bean
    public TopicExchange topicExchange() {
        return new TopicExchange(MqContents.HOTEL_EXCHANGE, true, false);
    }

    @Bean
    public Queue insertQueue() {
        return new Queue(MqContents.HOTEL_INSERT_QUEUE, true);
    }

    @Bean
    public Queue deleteQueue() {
        return new Queue(MqContents.HOTEL_DELETE_QUEUE, true);
    }

    @Bean
    public Binding insertBinding() {
        return BindingBuilder.bind(insertQueue()).to(topicExchange()).with(MqContents.HOTEL_INSERT_KEY);
    }

    @Bean
    public Binding deleteBinding() {
        return BindingBuilder.bind(deleteQueue()).to(topicExchange()).with(MqContents.HOTEL_DELETE_KEY);
    }
}

3.3 MqContents代码
package com.toto.es.hotel.constants;

public class MqContents {
    /**
     * 交换机
     */
    public final static String HOTEL_EXCHANGE = "hotel.topic";
    /**
     * 监听新增和修改的队列
     */
    public final static String HOTEL_INSERT_QUEUE = "hotel.insert.queue";
    /**
     * 监听删除的队列
     */
    public final static String HOTEL_DELETE_QUEUE = "hotel.delete.queue";
    /**
     * 监听新增和修改的队列的路由键
     */
    public final static String HOTEL_INSERT_KEY = "hotel.insert";
    /**
     * 监听删除的队列的路由键
     */
    public final static String HOTEL_DELETE_KEY = "hotel.delete";
}

3.4 HotelListener代码
package com.toto.es.hotel.mq;

import com.toto.es.hotel.constants.MqContents;
import com.toto.es.hotel.service.impl.HotelService;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class HotelListener {

    @Autowired
    private HotelService hotelService;

    /**
     * 监听酒店新增和修改的消息
     * @param id
     */
    @RabbitListener(queues = MqContents.HOTEL_INSERT_QUEUE)
    public void listenHotelInsertOrUpdate(Long id) {
        System.out.println("接收到新增消息:" + id);
        hotelService.insertById(id);
    }

    /**
     * 监听酒店删除的消息
     * @param id
     */
    @RabbitListener(queues = MqContents.HOTEL_DELETE_QUEUE)
    public void listenHotelDelete(Long id) {
        hotelService.deleteById(id);
        System.out.println("接收到删除消息:" + id);
    }
}

4、写在最后

跟着黑马程序员的培训,对ElasticSearch7的RestAPI进行了ElasticSearch8版本的替换,翻阅了ElasticSearch8的一些文档,对ElasticSearch的开发有了初步的入门,后续会根据业务场景进行完善自己ElasticSearch的知识体系。

项目下载地址

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Grain322

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值