获取Spring Boot项目中文件的相对路径(附Kafka生产者配置类)

在配置Kafka生产者的时候遇到SSL证书无法识别的问题,看到网上说这是因为 Kafka 客户端在运行时通常期望从文件系统中加载 SSL 证书文件,而不是从类路径加载。

但是我们可以通过.getAbsolutePath()去获取文件在Spring Boot项目中的绝对路径在赋值给Kafka配置

    public String getJKS() {
        // 获取文件在类路径中的 URL
        URL truststoreUrl = KafkaProducerConfig.class.getClassLoader().getResource("client.truststore.jks");
        File file = null;
        if (truststoreUrl != null) {
            // 转换 URL 到路径
            try {
                InputStream inputStream = truststoreUrl.openStream();
                // 生成目标文件
                file = File.createTempFile("client.truststore", ".jks");
                FileUtils.copyInputStreamToFile(inputStream, file);

            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            String jksFile = file.getAbsolutePath();
            // log.info("Truststore file path: " + truststoreFile.getAbsolutePath());
            return jksFile;
        } else {
            // log.error("Truststore file not found in classpath.");
            return null;
        }
    }

首先通过类加载器获取文件在项目中的URL,然后将这个路径赋给File类,最后就可以通过getAbsolutePath()方法获取文件的绝对路径。绝对路径是文件在文件系统中的完整路径,包括该文件所在的文件夹路径和文件名。这个方法返回一个字符串,表示调用该方法的文件的绝对路径。

最后附上通过spring-kafka配置SSL认证并实现发送消息的代码

1.坐标依赖:

        <!-- spring-kafka -->
        <dependency>
            <groupId>org.springframework.kafka</groupId>
            <artifactId>spring-kafka</artifactId>
            <version>2.9.13</version>
        </dependency>

2.配置文件(yml)

spring:
  application:
    name: KafkaDemo
  kafka:
    #bootstrap-servers: 127.0.0.1
    security:
      protocol: SASL_SSL
    properties:
      sasl:
        #SASL鉴权方式
        mechanism: PLAIN
        jaas:
          config: org.apache.kafka.common.security.plain.PlainLoginModule required username="用户名" password="密码";
      ssl:
        truststore:
          #这里如果不需要再项目中配置证书,可以直接引用本地证书
          location: D:\KafkaDemo\src\main\resources\client.truststore.jks
          #ssl truststore文件的密码,固定,请勿修改。配置此密码是为了访问Java生成的jks文件。
          password: 密码
        endpoint:
          identification:
            algorithm:
    producer:
      # 发生错误后,消息重发的次数。
      retries: 0
      # 键的序列化方式
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      # 值的序列化方式
      value-serializer: org.apache.kafka.common.serialization.StringSerializer
      # 发送确认参数
      acks: all
      buffer-memory: 33554432

3.编写生产者配置类

import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.CommonClientConfigs;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.common.config.SaslConfigs;
import org.apache.kafka.common.config.SslConfigs;
import org.apache.kafka.common.serialization.StringSerializer;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.core.DefaultKafkaProducerFactory;
import org.springframework.kafka.core.KafkaTemplate;

import java.io.*;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;


@Slf4j
@Configuration
public class KafkaProducerConfig {

    @Value("${spring.kafka.bootstrap-servers}")
    private String addressStr;

    @Value("${spring.kafka.properties.ssl.truststore.password}")
    private String password;

    @Value("${spring.kafka.properties.sasl.mechanism}")
    private String mechanism;

    @Value("${spring.kafka.properties.sasl.jaas.config}")
    private String config;


    //注入kafkaTemplate  如果项目中没有其他的kafkaTemplate
    //这样就可以覆盖掉默认的kafkaTemplate了
    @Bean
    KafkaTemplate<String,String> myKafkaTemplate(){
        DefaultKafkaProducerFactory<String, String> producerFactory =
                new DefaultKafkaProducerFactory<>(producerProperties(addressStr));
        return new KafkaTemplate<>(producerFactory);
    }


    //kafka的配置
    private Map<String,Object> producerProperties(String addressStr){
        // kafka的相关参数 比如ip地址和分组这些参数
        Map<String,Object> properties = new HashMap<>();
        //生产者
        properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, addressStr);
        properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);

        //ssl加密和认证配置
        properties.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, "SASL_SSL");
        properties.put(SslConfigs.SSL_TRUSTSTORE_TYPE_CONFIG,"JKS");
        //设置为空字符串来禁用服务器主机名验证
        properties.put(SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG ,"");
        properties.put(SslConfigs.SSL_KEY_PASSWORD_CONFIG, password);
        //获取Resources配置文件中client.truststore.jks
        properties.put(SslConfigs.SSL_TRUSTSTORE_LOCATION_CONFIG, getJKS());
        properties.put(SslConfigs.SSL_TRUSTSTORE_PASSWORD_CONFIG, password);
        //SASL鉴权方式
        properties.put(SaslConfigs.SASL_MECHANISM,mechanism);
        properties.put(SaslConfigs.SASL_JAAS_CONFIG,config);
        return properties;

    }

    public String getJKS(){
        // 获取文件在类路径中的 URL
        URL truststoreUrl = KafkaProducerConfig.class.getClassLoader().getResource("client.truststore.jks");
        File truststoreFile ;
        if (truststoreUrl != null) {
            // 转换 URL 到路径
            try {
                truststoreFile = new File(truststoreUrl.toURI());
            } catch (URISyntaxException e) {
                throw new RuntimeException(e);
            }
            String jksFile = truststoreFile.getAbsolutePath();
            log.info("Truststore file path:"+ truststoreFile.getAbsolutePath());
            return  jksFile;
        } else {
            log.info("Truststore file not found in classpath.");
            return  null;
        }
    }

}

4.这样就将所有配置完成了,接下来编写一个发送消息方法

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class KafkaProducer {

    private final KafkaTemplate<String,String> kafkaTemplate;

    @Autowired
    public KafkaProducer(KafkaTemplate<String, String> kafkaTemplate) {
        this.kafkaTemplate = kafkaTemplate;
    }

    /**
     * kafka消息发送
     * @param topic   目标主题
     * @param message 消息
     */
    public void sendMessage(String topic, String message) {
        kafkaTemplate.send(topic, message);
        log.info("生产者发送完成!");
    }
}

在项目中调用sendMessage()方法,传入要发送的topic和消息体就可以发送了!

Spring Boot使用Kafka需要在配置文件指定Kafka的相关配置。下面是一个简单的Kafka配置文件示例: ``` spring.kafka.bootstrap-servers=localhost:9092 spring.kafka.consumer.group-id=my-group spring.kafka.consumer.auto-offset-reset=earliest spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer spring.kafka.consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer ``` 解释一下上述配置项的含义: - `spring.kafka.bootstrap-servers`:Kafka集群的地址,如果有多个地址,可以用逗号分隔。 - `spring.kafka.consumer.group-id`:消费者所属的组ID。 - `spring.kafka.consumer.auto-offset-reset`:指定消费者在没有初始偏移量的情况下该如何开始消费消息。这里配置为最早的偏移量。 - `spring.kafka.consumer.key-deserializer`:消费者使用的键反序列化器。 - `spring.kafka.consumer.value-deserializer`:消费者使用的值反序列化器。 - `spring.kafka.producer.key-serializer`:生产者使用的键序列化器。 - `spring.kafka.producer.value-serializer`:生产者使用的值序列化器。 注意:这里的序列化器和反序列化器需要根据实际情况进行替换。如果使用的是JSON格式的消息,可以使用`org.springframework.kafka.support.serializer.JsonSerializer`和`org.springframework.kafka.support.serializer.JsonDeserializer`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值