package com.sfa.hcc.logread;
import com.alibaba.fastjson.JSON;
import com.sfa.hcc.utils.DateUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;
@Component
public class SecurityReadLogManagerImpl implements SecurityReadLogManager {
private final Logger logger = LoggerFactory.getLogger(SecurityReadLogManagerImpl.class);
private static Properties properties = new Properties();
private static Properties properties1 = new Properties();
//@Autowired
//private SysConfUtil sysConfUtil;
static {
File file = new File(System.getProperty("user.dir") + File.separator + "config.properties");
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
properties.load(fileInputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
@PostConstruct
public void contextInitialized() {
while (1 == 1) {
try {
readAndSendSecurityLog();
//获取配置的读取频率
String readFrequency = properties.getProperty("read_frequency");
//如果没有配置默认为1秒
if (StringUtils.isBlank(readFrequency)) {
Thread.sleep(1000);
} else {
//配置的是秒,这里是毫秒,转换一下
Thread.sleep(Long.valueOf(readFrequency) * 1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void readAndSendSecurityLog() {
String fileUrl = properties.getProperty("file.url");//读取的日志文件路径
try {
File localFile = new File(System.getProperty("user.dir") + File.separator + "lastTimeFileSize.properties");
try (FileInputStream fileInputStream = new FileInputStream(localFile)) {
properties1.load(fileInputStream);
}
RandomAccessFile accessFile1 = new RandomAccessFile(localFile, "rw");
String s1 = "";
//定义当前要读取的文件名
String path = "";
//如果记录下标的文件没有内容就从当天的.0文件开始读取,有内容就取上次读取的文件以及记录的下标开始读取
if ((s1 = accessFile1.readLine()) != null) {
String s2 = new String(s1.getBytes("ISO-8859-1"));
String[] strings = s2.split("=");
path = strings[0];
} else {
path = DateUtil.parse(new Date(), DateUtil.DEFAULT_FORMAT) + ".0" + ".txt";
}
//拼接读取的文件完整路径
String readPath = fileUrl + File.separator + path;
RandomAccessFile accessFile = new RandomAccessFile(readPath, "r");
List<String> readMsg = null;
//读取日志文件
readMsg = readTxt(path, accessFile, accessFile1);
if (CollectionUtils.isEmpty(readMsg)) {
//如果读取的文件里没有新内容,就去看看有没有新文件
searchNewTxt(fileUrl, accessFile1, path);
}
//关流
accessFile.close();
accessFile1.close();
} catch (Exception e) {
logger.error(e.getMessage());
}
}
private void searchNewTxt(String fileUrl, RandomAccessFile accessFile1, String path) throws IOException {
String[] split = path.split("\\.");
//將2022-05-23.0.txt中的.0改成.1看看有没有
String integer = String.valueOf(Integer.valueOf(split[1]) + 1);
String newPath = split[0] + "." + integer + "." + split[2];
//获取读取日志日期记录的下一天
String lastDate = split[0];
try {
int countDay = DateUtil.getDay(lastDate, DateUtil.parse(new Date(), DateUtil.DEFAULT_FORMAT));
File file = new File(fileUrl + File.separator);
for (File listFile : file.listFiles()) {
//统计当前文件下,当前日期的日志文件个数
String trim = listFile.getName().trim();
String[] split1 = trim.split("\\\\");
String filePath = split1[split1.length - 1];
if (filePath.equals(newPath)) {
//将文件内容清除,防止写入文本内容小于原内容,导致无法完全覆盖
accessFile1.setLength(0);
//每次都从文件开头开始写入
accessFile1.seek(0);
//将光标位置写进lastTimeFileSize.properties文件
accessFile1.write((newPath + "=0").getBytes());
break;
} else {
//将记录下标读取的最后文件的日期提取出来
Date date = DateUtil.parse(lastDate, DateUtil.DEFAULT_FORMAT);
for (int i = 1; i <= countDay; i++) {
//从记录的日期下一天开始寻找
String nextDate = DateUtil.parse(DateUtil.getBeforOrNextDay(date, i), DateUtil.DEFAULT_FORMAT);
String newPath1 = nextDate + ".0.txt";
if (filePath.equals(newPath1)) {
// 将文件内容清除,防止写入文本内容小于原内容,导致无法完全覆盖
accessFile1.setLength(0);
//每次都从文件开头开始写入
accessFile1.seek(0);
//将光标位置写进lastTimeFileSize.properties文件
accessFile1.write((newPath1 + "=0").getBytes());
break;
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private List<String> readTxt(String newPath, RandomAccessFile accessFile, RandomAccessFile accessFile1) throws IOException {
List<String> messages = new ArrayList<>();
int count = 0;
long lastTime = System.currentTimeMillis();
//通过配置的文件名作key查询有没有记录下标,如果记录的下标位置后面有新内容就继续读取
String property = properties1.getProperty(newPath);
//以日志文件名为key获取当前读取的光标位置
//如果为空,从0开始读取
if (StringUtils.isBlank(property)) {
property = "0";
}
//查询上次读取的点标位置
Long lastTimeFileSize = Long.valueOf(property);
//从记录的指标最后读取位置开始读取文件
accessFile.seek(lastTimeFileSize);
String s = "";
long nowTime = 0L;
do {
s = accessFile.readLine();
nowTime = System.currentTimeMillis();
if (s == null) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
String s1 = new String(s.getBytes("ISO-8859-1"), "UTF-8");
messages.add(s1);
count++;
//每次读取后记录当前读取的位置
lastTimeFileSize = s1.length() + lastTimeFileSize + 2; //加2 是\r\n的字节数
//每读取了500条数据,就推送信息给安检服务
if (count % 500 == 0) {
sendMsg(newPath, accessFile1, messages, lastTimeFileSize);
return messages;
}
}
//如果1分钟后没有500条记录,就跳出循环
} while ((nowTime - lastTime) / 1000 / 60 <= 1);
//如果跳出了循环,则推送一次
if (CollectionUtils.isNotEmpty(messages)){
sendMsg(newPath, accessFile1, messages, lastTimeFileSize);
}
return messages;
}
private boolean sendMsg(String newPath, RandomAccessFile accessFile1, List<String> messages, Long lastTimeFileSize) throws IOException {
String airport3Code = properties.getProperty("airport3_code");//航站
String channelNum = properties.getProperty("channel_num");//通道编号
//将要推送的信息封装
SecurityReadLog securityReadLog = new SecurityReadLog();
securityReadLog.setAirport3Code(airport3Code);
securityReadLog.setChannelNum(channelNum);
securityReadLog.setSecurityLogList(messages);
//转换为json格式
String body = JSON.toJSONString(securityReadLog);
//请求接口
String pushReadLog_url = properties.getProperty("pushReadLog_url", "http://10.88.5.141:8000/check/securityReadLog/saveReceiveLog");
HttpResponse responResult = doPost(pushReadLog_url, body);
if (responResult != null && responResult.getStatusLine().getStatusCode() == 200) {
//将文件内容清除,防止写入文本内容小于原内容,导致无法完全覆盖
accessFile1.setLength(0);
//每次都从文件开头开始写入
accessFile1.seek(0);
//将光标位置写进lastTimeFileSize.properties文件
accessFile1.write((newPath + "=" + lastTimeFileSize).getBytes());
return true;
} else {
logger.error("推送信息失败");
}
return false;
}
/**
* Post请求一个地址
*
* @param url 请求地址
* @param requestBody 请求的body
* @return
*/
public HttpResponse doPost(String url, String requestBody) {
//获得Http客户端(相当于一个浏览器)
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
//创建post请求
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("Content-type", "application/json;charset=utf-8");
//设置参数(post请求是将参数放在请求体里面传过去的)
httpPost.setEntity(new StringEntity(requestBody, "utf-8"));
//设置超时
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(5000).setConnectionRequestTimeout(1000)
.setSocketTimeout(5000).build();
httpPost.setConfig(requestConfig);
//推送并获取响应
HttpResponse httpResponse = null;
try {
httpResponse = httpClient.execute(httpPost);
return httpResponse;
} catch (IOException e) {
e.printStackTrace();
}
return httpResponse;
}
}