最近做数据清洗及传输,要求用ETL做调度,所以研究了下Kettle的Json组件,FTP组件以及Java代码组件,这次主要记录下Java代码处理文件的方法,方便以后的使用
先说下处理大概流程:
1、客户端从各系统抽取数据并生成数据文件(.json),然后生成对应的MD5编码(.txt);
2、将Json文件及存储MD5编码的txt文件一起通过FTP上传到服务器;
3、服务端校验json文件完整性,通过后将数据写入到数据库中;
服务端的Java代码主要用于判断Json文件完整性,如果不完整,删除文件并记录日志,以下为代码:
import java.io.File;
import java.io.FileFilter;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException {
//获取变量中设置的文件路径
String filePath = getVariable("FILE_PATH", "").replace("\\","\\\\");
File file = new File(filePath);
//开始处理文件
dealFile(file, filePath);
setOutputDone();
return false;
}
/*
文件处理方法
*/
public void dealFile(File file, String filePath) throws KettleException {
try{
//定义变量信息
String fileName,fileNameSuffix,fileNameJson,fileNameMd5;
//取目录下所有文件,并循环
File[] fs = file.listFiles();
for(int i=0;i<fs.length;i++) {
File f = fs[i];
if(f.isFile()){
fileName = f.toString();
fileNameSuffix = fileName.substring(fileName.lastIndexOf(".") + 1); //取文件后缀名
fileNameJson = fileName.substring(0, fileName.lastIndexOf(".")) + ".json"; //Json文件完整文件名
fileNameMd5 = fileName.substring(0, fileName.lastIndexOf(".")) + ".txt"; //txt文件完整文件名
//如果是json文件
if(fileNameSuffix.equals("json")){
String md5 = getMD5One(fileNameJson); //取json文件的md5码
String md5Txt = getMd5Code(fileNameMd5); //取上传文件的md5码
//如果不一样,说明文件损坏,删除并写入日志
if(!md5.equals(md5Txt)){
File f_txt = new File(fileNameMd5);
f_txt.delete();
f.delete();
//写入日志信息
writeLog(fileName.substring(0, fileName.lastIndexOf(".")), "文件完整性校验失败!json_md5:" + md5 + ";txt_md5:" + md5Txt);
}
}
}
}
} catch(Exception e){
}
}
/*
获取json文件MD5值
*/
public String getMD5One(String path) throws KettleException {
try{
FileInputStream fis= new FileInputStream(path);
String md5 = DigestUtils.md5Hex(IOUtils.toByteArray(fis));
IOUtils.closeQuietly(fis);
return md5;
} catch(Exception e){
return e.toString();
}
}
/*
获取上传的txt文件md5值
*/
public String getMd5Code(String fileName) throws KettleException{
try{
File filename = new File(fileName);
InputStreamReader reader = new InputStreamReader(new FileInputStream(filename));
BufferedReader br = new BufferedReader(reader);
String line = "";
line = br.readLine();
br.close();
return line;
}catch(Exception e){
return "err";
}
}
/*
写入错误日志
*/
public void writeLog(String str_fileName, String err_msg) throws KettleException{
try{
Connection conn = getConnection();
Statement statement=(Statement) conn.createStatement();
String sql="insert into data_file_err_log(err_time,file_name,err_msg) values(now(),'" + str_fileName + "','" + err_msg + "')";
statement.executeUpdate(sql);
logBasic("sql:" + sql);
conn.close();
} catch(Exception e){
logBasic("connErr:" + e.toString());
}
}
/*
获取mysql数据库连接
*/
public Connection getConnection() throws KettleException{
Connection conn;
String driver = getParameter("mysql_driver");
String url = getParameter("mysql_url");
String user = getParameter("mysql_user");
String password = getParameter("mysql_password");
try {
Class.forName(driver);
conn = DriverManager.getConnection(url,user,password);
return conn;
} catch(Exception e) {
logBasic("connErr:" + e.toString());
}
return null;
}
Kettle中使用Java代码有几个地方需要注意:
1、Kettle只提供了基础Jar包,其余jar需要复制到【lib】文件夹中;
2、Kettle中的主方法为【processRow】,类似于【main】方法,可通过左侧的提示框双击生成(Code Snippits - Common use -- Main);
3、看代码是否通过编译,点击下面的“测试类”即可,如果想输出日志,要使用【logBasic】方法;
代码很简单,说下关键位置:
1、String filePath = getVariable("FILE_PATH", "").replace("\\","\\\\");
这行代码主要是取环境变量“FILE_PATH”,该环境变量我单独写了转换,用于存储整个作业中要用到的常量,如下图
2、获取数据库连接的【getConnection】,里面用到【getParameter】方法:
这里的参数是存储在文件【kettle.properties】中,Win10系统中,文件一般在【C:\Users\Administrator\.kettle\】这个路径下,配置信息如下图:
注意“mysql_url”后面有utf8编码设置,防止写到数据库的中文为乱码
最后将数据解析写入数据库: