【工作学习记录】更新至20221118

摘要:记录一下工作中学到的知识点


前言

提示:这里可以添加本文要记录的大概内容:

先简单写写


一、Kafka定时任务推送数据

code:performance-alarm-access

1.1 Kafka的使用

1.1.1 本地测试(Windows)

参考文献:在Windows系统上安装消息队列kafka

1)下载及配置

  1. kafka只需要解压下载的压缩包就行了;kafka当前版本已经内置了zookeeper,所以不需要再安装zookeeper。
  2. kafka服务端配置在server.properties中,kafka配置需要修改两处配置文件:listeners 和 log.dirs。
# listeners:服务器监听的地址
listeners=PLAINTEXT://localhost:9092
# log.dirs:日志文件修改为自定义的日志目录
log.dirs=D:/softFiles/kafka/kafka_2.13-3.2.1/logs
  1. zookeeper配置文件为zookeeper.properties,只需修改dataDir
# dataDir:zookeeper存储数据的路径修改自定义的目录
dataDir=D:/softFiles/kafka/kafka_2.13-3.2.1/data

2)本地测试

  1. 进入kafka安装根目录下,地址栏输入cmd,然后回车,通过命令行启动之后都不要关闭窗口(每步打开新窗口)
  2. 启动zookeeper
.\bin\windows\zookeeper-server-start.bat .\config\zookeeper.properties
  1. 启动kafka-server
.\bin\windows\kafka-server-start.bat .\config\server.properties
# 如果启动kafka失败,并出现以下异常,删除logs文件夹下的meta.properties文件即可。
# The Cluster ID xxxx doesn’t match stored clusterId Some(finN2zUTRWaXMomXCknRew) in meta.properties. The broker is trying to join the wrong cluster. Configured zookeeper.connect may be wrong.
  1. 启动kafka-topics(创建一个名为test的topic)
.\bin\windows\kafka-topics.bat --create --bootstrap-server  localhost:2181 --replication-factor 1 --partitions 1 --topic test
# 启动之后,kafka-topics处于等待创建topic状态,一段时间内如果不createTopic,kafka-topics将自动断开
  1. 启动生产者
.\bin\windows\kafka-console-producer.bat --broker-list localhost:9092 --topic test
  1. 启动消费者
.\bin\windows\kafka-console-consumer.bat --bootstrap-server localhost:9092 --topic test
  1. 在生产端发送消息,可以看到消费端就收到了

1.1.2 代码测试

依赖

 <dependency>
     <groupId>org.apache.kafka</groupId>
     <artifactId>kafka-clients</artifactId>
     <version>3.2.0</version>
 </dependency>

代码

// 定义主题
public static String topic = "test";
// 配置kafka(本地)
Properties p = new Properties();
p.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");//kafka地址,多个地址用逗号分割
p.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
p.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
KafkaProducer<String, String> kafkaProducer = new KafkaProducer<>(p);
// Kafka推送
ProducerRecord<String, String> recordTest = new ProducerRecord<String, String>(topic, jsonArray.toJSONString());
kafkaProducer.send(recordTest);
logger.info("消息发送成功:" + jsonArray.toJSONString());

1.2 定时任务SpringTask

注解

@Component
@Scheduled(cron = "0 */15 * * * ?") //每15分钟执行一次
public void execute() throws Exception {}
@EnableScheduling
@SpringBootApplication
public class PerformanceAlarmAccessApplication {}

1.3 其他

1.3.1 如何写log

代码

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SendKafkaMsgTimer {
    private static final Logger logger = LoggerFactory.getLogger(SendKafkaMsgTimer.class);
    logger.info("消息发送成功");
}

关于报错:可能是因为系统配置?改完就好了
Settings->Maven和Java Compiler
Project Structure

1.3.2 数据库连接及配置

application.properties中配置数据库

# PostgreSql连接信息
driver=org.postgresql.Driver
url=jdbc:postgresql://ip:port/数据库
user=
password=

依赖(我用的PostgreSql)

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
</dependency>

代码

public class JdbcUtils {
    /**
     * @Description: 连接数据库
     * @return: Connection
     */
    public static Connection getConnection() throws ClassNotFoundException, SQLException {
        ResourceBundle jdbc = ResourceBundle.getBundle("application");

        String driver = jdbc.getString("driver");
        String url = jdbc.getString("url");
        String username = jdbc.getString("user");
        String password = jdbc.getString("password");

        Class.forName(driver);
        Connection connection = DriverManager.getConnection(url, username, password);

        if (connection != null) {
            System.out.println("数据库连接成功! ");
        } else {
            System.out.println("数据库连接失败! ");
        }
        return connection;
    }
}

1.3.3 JSONArray的使用

依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.41</version>
</dependency>

代码

JSONArray jsonArray = new JSONArray();
JSONObject json = new JSONObject();
json.put("value", value);
jsonArray.add(json);

1.3.4 sql语句

  1. 占位符?的使用 或 用+按字符串进行拼接
  2. rs.next() 和 rs.getString()
  3. 代码
Connection con = JdbcUtils.getConnection();
PreparedStatement pstmt = con.prepareStatement("SQL"+"语句");
ResultSet rs = pstmt.executeQuery();
while (rs.next()) { rs.getString("列名"); //得到值 }

1.3.5 字符串的分割

代码

// 添加原数据
dataMap.put("tt", "a,aa,aaa");
// 分割字段        
String[] columns = dataMap.get(key).split(",");

1.3.6 kafka启动报错

参考:ERROR Fatal error during KafkaServer startup. Prepare to shutdown (kafka.server.KafkaServer) kafka.c


二、FTP读取excel数据并解析入库

code:emergency-data-upload

2.1 FTP的使用

2.1.1 FTP服务器本地搭建(用于测试)

参考文献:Windows10 下搭建 FTP 服务器

2.1.2 FTP配置及使用

1.本地配置+配置类+服务(此次demo)

因为只有读取功能,所以这次直接写在服务中实现了;其实也可以写一个工具类,再在服务中调用

本地配置application-dev.yml

#ftp服务器配置
ftp :
  ftpHost: 110.110.110.110
#ftp服务器端口号
  ftpPort: 21
#ftp用户名
  ftpUserName: user
#ftp密码
  ftpPassword: 123
#ftp文件在服务器上存放物理路径
  ftpPath: /path
#ftp下载下来的文件存放本地的地址
  localPath: D://test
#文件名称
  excelFileName: 模版.xlsx

配置类代码

@Component
@ConfigurationProperties(prefix = "ftp")
@Data
public class FtpConfig {
    /**
     * ip
     */
    private String ftpHost;

    /**
     * 端口
     */
    private int ftpPort;

    /**
     * 用户名
     */
    private String ftpUserName;

    /**
     * 密码
     */
    private String ftpPassword;

    /**
     * ftp文件位置
     */
    private String ftpPath;

    /**
     * 本地文件位置
     */
    private String localPath;

    private List<String> excelFileName;

}

服务实现类代码
注意:避免中文名乱码问题

@Service
public class ReadFtpFileServiceImpl implements ReadFtpFileService {
    // 本地字符编码 UTF-8/GBK
    private static String localCharset = "GBK";

    @Autowired
    private BaseStationService baseStationService;

    @Autowired
    private EmergencyDataService emergencyDataService;

    /**
     * @param filePath 文件路径
     * @param user     用户名
     * @param password 密码
     * @param ip       主机名
     * @param port     端口号
     * @param fileName 文件名
     * @Description: 通过ftp连接解析并上传文件数据
     */
    @Override
    public Map<String, Object> read(String filePath, String user, String password, String ip, int port, String fileName) {
        Map<String, Object> map = new HashMap<>();
        FTPClient ftp = new FTPClient();
        try {
            // 连接ftp服务器
            ftp.connect(ip, port);
            // 登陆
            ftp.login(user, password);
            // 检验登陆操作的返回码是否正确
            if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
                ftp.disconnect();
            }
            // 设置被动模式
            ftp.enterLocalActiveMode();
            // 设置文件类型为二进制,与ASCII有区别
            ftp.setFileType(FTP.BINARY_FILE_TYPE);
            // 设置编码格式
            ftp.setControlEncoding(localCharset);
            // 获得ftp文件路径
            String dir = filePath.substring(0, filePath.lastIndexOf(File.separatorChar));
            // 进入文件所在目录,注意编码格式,以能够正确识别中文目录
            ftp.changeWorkingDirectory(new String(dir.getBytes(localCharset), FTP.DEFAULT_CONTROL_ENCODING));
            // 拆分文件名和后缀
            String ext = "";
            String ftpFileName = "";
            if (fileName.contains(".")) {
                ftpFileName = fileName.split("\\.")[0];
                ext = fileName.split("\\.")[1];
            }
            // 遍历寻找文件
            FTPFile[] files = ftp.listFiles();
            // 记录入口文件数量
            int num = 0;
            String uploadFileName = "";
            for (FTPFile file1 : files) {
                if (file1.getName().contains(ftpFileName)) {
                    // 两个sheet,两个文件流
                    int i = 2;
                    while (i > 0) {
                        // 检验文件是否存在
                        filePath = filePath + file1.getName();
                        String file = filePath.substring(filePath.lastIndexOf(File.separatorChar) + 1);
                        InputStream is = ftp.retrieveFileStream(new String(file.getBytes(localCharset), FTP.DEFAULT_CONTROL_ENCODING));
                        filePath = "";
                        // 若存在,解析文件
                        if (is != null) {
                            // 处理excel数据
                            if (ext.equals("xls") || ext.equals("xlsx") || ext.equals("csv")) {
                                if (i == 2) {
                                    EasyExcel.read(is, BaseStationTemplate.class, new BaseStationListener(baseStationService)).sheet("模板1").doRead();
                                } else {
                                    EasyExcel.read(is, EmergencyDataTemplate.class, new EmergencyDataListener(emergencyDataService)).headRowNumber(0).sheet("模板2").doRead();
                                }
                                num++;
                                uploadFileName += file1.getName() + ",";
                            }
                            if (is != null) {
                                is.close();
                                ftp.completePendingCommand();
                            }
                        }
                        i--;
                    }
                }
            }
            map.put("num", num);
            map.put("uploadFileName", uploadFileName);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (ftp != null) {
                try {
                    ftp.disconnect();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return map;
    }
}
2.动态配置+工具类+服务(SFTP)

Linux默认是不提供ftp的;使用nacos配置中心进行配置;在服务中通过@Value注解将外部配置文件的值注入到Bean中

FTPUtil可包含的功能
1.连接服务器
2.断开连接
3.上传文件
4.下载文件
5.其他……

添加SFTP依赖

<!-- SFTP -->
<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.54</version>
    <scope>compile</scope>
</dependency>

FTP工具类代码

import com.jcraft.jsch.*;
import org.apache.commons.net.ftp.FTP;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.*;

/**
 * @Description: FTP工具类
 * @Date: 2022/9/15 15:15
 */
public class FtpUtil {
    private static final Logger log = LoggerFactory.getLogger(FtpUtil.class);

    private String username;
    private String password;
    private String privateKey;
    private String host;
    private int port;
    public ChannelSftp sftp;
    private Session session;

    public FtpUtil(String username, String password, String host, int port) {
        this.username = username;
        this.password = password;
        this.host = host;
        this.port = port;
    }

    // 使用私钥而不是密码
    public FtpUtil(String username, String host, int port, String privateKey) {
        this.username = username;
        this.host = host;
        this.port = port;
        this.privateKey = privateKey;
    }

    public FtpUtil() {
    }


    /**
     * 连接服务器
     *
     * @param
     */
    public void connect() {
        try {
            JSch e = new JSch();
            if (this.privateKey != null) {
                e.addIdentity(this.privateKey);
            }

            this.session = e.getSession(this.username, this.host, this.port);
            if (this.password != null) {
                this.session.setPassword(this.password);
            }

            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            this.session.setConfig(config);
            this.session.connect();
            Channel channel = this.session.openChannel("sftp");
            channel.connect();
            this.sftp = (ChannelSftp) channel;
        } catch (JSchException var4) {
            log.error("连接sftp服务器异常", var4);
        }
    }


    /**
     * 断开连接
     *
     * @param
     */
    public void disconnect() {
        if (this.sftp != null && this.sftp.isConnected()) {
            this.sftp.disconnect();
        }

        if (this.session != null && this.session.isConnected()) {
            this.session.disconnect();
        }
    }


    /**
     * 上传文件
     *
     * @param basePath     上传路径
     * @param sftpFileName 文件名
     * @param input        输入流
     */
    public void upload(String basePath, String sftpFileName, InputStream input) throws SftpException {
        if (!isDirExist(basePath)) {
            this.createDir(basePath, this.sftp);
        }
        this.sftp.cd(basePath);
        this.sftp.put(input, sftpFileName);
    }

    /**
     * 下载文件
     *
     * @param downloadFilePath 下载路径
     * @param saveFile         文件名
     */
    public File download(String downloadFilePath, String saveFile) {
        FileOutputStream fileOutputStream = null;
        try {
            int i = downloadFilePath.lastIndexOf('/');
            if (i == -1) {
                return null;
            }
            sftp.cd(downloadFilePath.substring(0, i));
            File file = new File(saveFile);
            fileOutputStream = new FileOutputStream(file);
            sftp.get(downloadFilePath.substring(i + 1), fileOutputStream);
            fileOutputStream.close();
            return file;
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        } finally {
            if (null != fileOutputStream) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    log.info("关闭资源失败");
                }
            }
        }
    }

    /**
     * 删除文件
     *
     * @param directory  文件路径
     * @param deleteFile 文件名
     */
    public void delete(String directory, String deleteFile) throws SftpException {
        this.sftp.cd(directory);
        this.sftp.rm(deleteFile);
    }

    /**
     * 读取文件(不完善)
     *
     * @param directory 文件路径
     * @param readFile 文件名
     */
    public void read(String directory, String readFile) {
        InputStream in = null;
        try {
            this.sftp.cd(directory);
            in = sftp.get(readFile);
            if (in != null) {
                BufferedReader br = new BufferedReader(new InputStreamReader(in, FTP.DEFAULT_CONTROL_ENCODING));
                String str = null;
                //这里写逻辑,在控制台进行按行输出
                while ((str = br.readLine()) != null) {
                    System.out.println(str);
                }
            } else {
                log.error("in为空,不能读取");
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    log.info("关闭资源失败");
                }
            }
        }
    }

    /**
     * 读取所有文件名
     *
     * @param directory 文件路径
     * @param sign
     */
    public List<String> listFiles(String directory, boolean sign) throws SftpException {
        Vector vector = sftp.ls(directory);
        Iterator iterator = vector.iterator();
        List<String> fileList = new ArrayList<>();
        while (iterator.hasNext()) {
            ChannelSftp.LsEntry file = (ChannelSftp.LsEntry) iterator.next();
            //文件名称
            String fileName = file.getFilename();
            if (file.getAttrs().isDir()) {
                if (!fileName.equals(".") && !fileName.equals("..")) {
                    if (sign) {
                        String path = directory + "/" + fileName;
                        List<String> files = listFiles(path, sign);
                        fileList.addAll(files);
                    }
                }
            } else {
                fileList.add(fileName);
            }
        }
        return fileList;
    }

    /**
     * 创建一个文件目录
     */
    public void createDir(String createPath, ChannelSftp sftp) {
        try {
            String pathArray[] = createPath.split("/");
            StringBuffer filePath = new StringBuffer("/");
            for (String path : pathArray) {
                if (path.equals("")) {
                    continue;
                }
                filePath.append(path + "/");
                if (isDirExist(filePath.toString())) {
                    sftp.cd(filePath.toString());
                } else {
                    // 建立目录
                    sftp.mkdir(filePath.toString());
                    // 进入并设置为当前目录
                    sftp.cd(filePath.toString());
                }
            }
            this.sftp.cd(createPath);
        } catch (SftpException e) {
            e.printStackTrace();
        }
    }

    /**
     * 判断目录是否存在
     */
    public boolean isDirExist(String directory) {
        boolean isDirExistFlag = false;
        try {
            SftpATTRS sftpATTRS = sftp.lstat(directory);
            isDirExistFlag = true;
            return sftpATTRS.isDir();
        } catch (Exception e) {
            if (e.getMessage().toLowerCase().equals("no such file")) {
                isDirExistFlag = false;
            }
        }
        return isDirExistFlag;
    }

    /**
     * 获取文件数量
     */
    public long getFileSize(String srcSftpFilePath) {
        long fileSize;//文件大于等于0则存在
        try {
            SftpATTRS sftpATTRS = sftp.lstat(srcSftpFilePath);
            fileSize = sftpATTRS.getSize();
        } catch (Exception e) {
            fileSize = -1;//获取文件大小异常
            if (e.getMessage().toLowerCase().equals("no such file")) {
                fileSize = -2;//文件不存在
            }
        }
        return fileSize;
    }
}

服务示例

public CommonModel uploader(MultipartFile file) {
        CommonModel result = ModelTool.createModel();
        if (file.isEmpty()) {
            throw new CustomException("上传文件不能为空");
        }
        if (file.getSize() > MAX_SIZE) {
            throw new CustomException("上传文件过大, 请选择大小在2MB以内的文件");
        }
        String fileName = file.getOriginalFilename();
        String suffixName = fileName.substring(fileName.lastIndexOf("."));
        String newFileName = System.currentTimeMillis() + suffixName;
        FTPUtil sftpUtils = new FTPUtil(
                sftpUsername,
                sftpPassword,
                sftpIp,
                (sftpPort != null ? Integer.parseInt(sftpPort) : 22)
        );
        sftpUtils.login();
        if (!sftpUtils.isDirExist(diskFilePath)) {
            sftpUtils.createDir(diskFilePath, sftpUtils.sftp);
        }
        try {
            sftpUtils.upload(diskFilePath, newFileName, file.getInputStream());
            File sysFile = new File();
            sysFile.setFileName(fileName);
            sysFile.setPath(diskFilePath + "/" + newFileName);
            sysFile.setFileType(suffixName);
            sysFile.setDel(0);
            FieldUtil.setCreatedField(sysFile);
            try {
                fileMapper.insert(sysFile);
                result.success(sysFile);
            } catch (Exception e) {
                sftpUtils.delete(diskFilePath, newFileName);
                result.fail("上传失败");
                log.error("文件保存失败");
            }
        } catch (SftpException e) {
            log.error("SFTP异常");
        } catch (IOException e) {
            log.error("IO异常");
        }

        return result;
    }

2.2 spring boot + mybatis

参考:
项目源码参考
MyBatis代码生成器源码

2.3 easyexcel使用

参考:
项目源码参考
官方文档

2.4 其他

2.4.1 生成sql文件方法

生成sql文件方法——转储sql文件

2.4.2 EasyExcel从指定位置开始读数据

EasyExcel从指定位置开始读数据——headRowNumber()

2.4.3 FTP中文文件名乱码问题

FTP中文文件名乱码问题以及本地编码
另外,在.properties文件配置会存在中午乱码问题,改成.yml文件会解决

三、配置相关问题

真正工作起来全靠百度,用的多忘得快,根本没时间记捏,就记点百度不容易查到的吧

  1. 因为项目用到了微服务,调用其他服务时一开始居然直接加了依赖,耦合性太高,其他服务一崩自己的服务也就崩了,应该用@FeignClient(name = "xxx") 注解调用其他服务,用到的实体类和函数再写一份就行
  2. es用到了ik分词器,忘记跟运维说了,又报错。。。
  3. 配置文件,其实是最重点,但因为同事帮忙搞了,一知半解的;简单来说,bootstrap相关配置复制其他服务的(nacos和jasypt解密,服务名之类的之前已经写好了,一定注意看看服务在nacos注册成功了没,jasypt还有个依赖要加也容易忘捏),application相关配置之前也写好了,但是es配置要改一下,其他一些报错完全靠同事(有个ip字段多余了可能?反正去掉就不报错了,application.yml还有个profiles: active: ${APPLICATION_URL:dev} 要加,反正我自己是发现不了的),其他的靠运维,告诉他端口(原话:A:你要起XXX肯定得给他一个端口吧,然后这个服务与其他服务之间是怎么关联的,B:都注册到nacos上的,正常启动就可以,你配置一下nacos就行,端口按照配置文件或者让他随便映射一个),运维自己指定环境(原话:升级的时候测试环境让他指定test环境,生产prod环境)

ok了,愚蠢的我


总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值