开发背景
需求背景
由于公司在外面有很多产品,而公司的产品是部署在远程服务端的,在客户使用的过程中,为了解决随机出现的问题,我们总不能一出现问题就大老远跑过去解决,这样无论是时间还是人力成本都是非常高昂的。在此处,我们的解决办法就是通过抓取远程开放路径下的系统日志文件,然后在本地查看解决。
源文件格式
源日志格式如下:
日志内容如下:
档号;全宗号;全宗名称;目录号;案卷号;档案类别;导出种类;开始时间;结束时间;用时;完成百分比;预计剩余时间(小时);文件名;文件路径;md5;是否可用
9-0-555-53;9;南京市XX公司;1;0053;0;案卷;Mon Mar 18 19:14:01 -0400 2019;Mon Mar 18 19:14:04 -0400 2019;2.900846;6.71828160256499e-05;725.074067644962;;;;
9-0-555-54;9;南京市XX公司;1;0054;0;案卷;Mon Mar 18 19:14:04 -0400 2019;Mon Mar 18 19:14:07 -0400 2019;2.943011;6.83411404398853e-05;724.745752051916;;;;
9-0-555-55;9;南京市XX公司;1;0055;0;案卷;Mon Mar 18 19:14:07 -0400 2019;Mon Mar 18 19:14:10 -0400 2019;2.972452;6.94994648541206e-05;724.545356220889;;;;
9-0-555-56;9;南京市XX公司;1;0056;0;案卷;Mon Mar 18 19:14:10 -0400 2019;Mon Mar 18 19:14:13 -0400 2019;2.942553;7.0657789268356e-05;724.23223611118;;;;
分析解决
通过观察日志,我们不难发现,由于有众多的公司,而公司又分布在众多的城市中,而城市对应的是省-市-区/县三级中的地级市,为了很方便的查看众多的项目日志信息,我们需要做一个web页面,该页面左侧是全国的行政区划树,分为三级,分别是省-市-公司,而点击公司之后,就会展示该公司下的日志信息。
由于我这里实现的是后台日志文件录入数据库功能,因而前台功能以及数据展示相关功能在此不做过多讨论。
在分析了上述情况后,我们需要三张表,分别是:
- 行政区划表
- 公司表
- 日志表
行政区划表的数据很简单,直接从网上下载一份,稍加改动,去掉第三级区/县即可搞定。
公司表需要录入公司名称以及公司所在的地级市,而源日志文件中并没有给出。不过由于源日志文件中都包含所在城市的关键字,因而我们通过关键字提取,就是通过循环遍历行政区划表,找出该区划包含在日志全宗名称中的城市,以全宗名称为公司名,然后将公司挂载到该城市下。
日志表比较简单,就是循环遍历日志文件,然后再循环遍历日内的每一行信息,将其字段对应,挂在到对应的公司下,批量录入数据库即可。
由于我这里使用的是JPA,因而实体类结构就是数据表结构。也就是说,如果行政区划表亦或是日志表不存在,则系统在启动时会自动创建而无需手动处理。
源码
核心依赖
<dependencies>
<!-- jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- postgresql -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
</dependencies>
Java源码
SystemLogApplication
package com.lyc.systemLog;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author: zhangzhenyi
* @date: 2019/4/11 15:04
* @description: 系统日志 Application
**/
@SpringBootApplication
public class SystemLogApplication {
public static void main(String[] args) {
SpringApplication.run(SystemLogApplication.class,args);
}
}
FileNameUtil
package com.lyc.systemLog.util;
import com.google.common.base.Splitter;
import com.lyc.systemLog.common.CommonConstant;
import lombok.var;
/**
* @author: zhangzhenyi
* @date: 2019/4/12 10:30
* @description: 获取文件名工具类
**/
public class FileNameUtil {
/**
* 返回创建的FileNameUtil实例
* @return
*/
public static FileNameUtil newFileNameUtil(){
return new FileNameUtil();
}
/**
* 从文件路径中获取文件名
* @param filePath
* @return
*/
public String getFileName(String filePath){
// 将文件路径转换成文件夹名与文件名的list集合
var nameList = Splitter.on(CommonConstant.Separators.BACK_SLASH).splitToList(filePath);
// 从最后一项中获取文件名
String fileNameFull = nameList.get(nameList.size() - 1);
var fileNameList = Splitter.on(CommonConstant.Separators.DOT).splitToList(fileNameFull);
return fileNameList.get(0);
}
/**
* 获取公司名称
* @param fileName 文件名称
* @return
*/
public String getCompanyName(String fileName){
// 公司后面的最后一个词是公司,因而匹配该词所在位置
int lastIndex = fileName.lastIndexOf(CommonConstant.LogKeys.COMPANY);
// 返回截取获得的公司名称
return fileName.substring(0,lastIndex + 2);
}
}
ReadLogUtil
package com.lyc.systemLog.util;
import java.io.*;
/**
* @author: zhangzhenyi
* @date: 2019/4/11 16:04
* @description: 读取日志文件工具类
**/
public class ReadLogUtil {
private FileInputStream in = null;
private InputStreamReader read = null;
private BufferedReader bufferedReader = null;
/**
* 创建"读取日志文件工具类"工具类
* @return
*/
public static ReadLogUtil newReadLogUtil(){
return new ReadLogUtil();
}
/**
* 根据文件路径获取缓存文件流
* @param filePath
* @return
* @throws FileNotFoundException
* @throws UnsupportedEncodingException
*/
public BufferedReader getBufferedReader(String filePath) throws FileNotFoundException, UnsupportedEncodingException {
File file = new File(filePath);
in = new FileInputStream(file);
read = new InputStreamReader(in,"UTF-8");
bufferedReader = new BufferedReader(read);
return bufferedReader;
}
/**
* 关闭文件流
* @throws IOException
*/
public void close() throws IOException {
bufferedReader.close();
read.close();
in.close();
}
}
TimeFormatUtil
package com.lyc.systemLog.util;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/**
* @author: zhangzhenyi
* @date: 2019/4/11 16:52
* @description: 格式化时间字符串
**/
public class TimeFormatUtil {
// 开始时间
private long startTime = 0;
// 截止时间
private long endTime = 0;
/**
* 返回创建的TimeFormatUtil实例
* @return
*/
public static TimeFormatUtil newTimeFormatUtil(){
return new TimeFormatUtil();
}
/**
* 设置开始时间
* @return
*/
public void setStartTime(){
this.startTime = new Date().getTime();
}
/**
* 设置截止时间
* @return
*/
public void setEndTime(){
this.endTime = new