Java集成kettle開發-解決kettle無法插入空字符串的問題

問題背景

今天使用kettle做數據歸檔時,發現kettle無法插入空字符串,它默認會把空字符串變爲null。這就導致問題出現。

查詢資料

通過查資料發現了網上的一個解決辦法,首先感謝 關於kettle的空字符串和NULL的問題 這篇文章。但是他那個是直接使用的kettle客戶端,並沒有和java集成。
然後我就去研究源碼,看kettle是否支持設置這樣的環境變量,我以KettleEnvironment.init();EnvUtil.environmentInit(); 這兩個初始化方法爲入口,經過仔細研究並沒有找到對應的辦法;
無奈之下,我就想:是否可以利用提前生成kettle.properties文件的辦法來解決。遂有本文。

解決方案

直接上代碼(本文是在quartz + kettle8二次開發-實現集羣高可用)基礎上繼續做的,修改了裏面的kettleUtil:

- 注意看裏面的dealWriteNull()方法

package cc.xxxx.utils;

import cc.xxxx.configs.EnvConfig;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.KettleClientEnvironment;
import org.pentaho.di.core.KettleEnvironment;
import org.pentaho.di.core.util.EnvUtil;
import org.pentaho.di.job.Job;
import org.pentaho.di.job.JobMeta;
import org.pentaho.di.trans.Trans;
import org.pentaho.di.trans.TransMeta;
import org.springframework.stereotype.Component;

import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileWriter;
import java.util.Map;

/**
 * kettle工具類
 * 使用靜態塊的原因:
 *    1.執行ktr和kjb都要執行初始化,爲了代碼的複用;
 *    2.由於quartz的定時任務是異步的,在springBoot剛剛啓動完成就可能會執行ktr和kjb,所以kettle的初始化工作
 *      必須在springBoot啓動完成前執行,故使用靜態塊;
 * @author wangll
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class KettleUtil {

    @NonNull
    private EnvConfig envConfig;

    static {
        log.info("正在初始化kettle ...");
        try {
            dealWriteNull();
            KettleEnvironment.init();
            EnvUtil.environmentInit();
        }catch (Exception e){
            log.error("初始化kettle失敗",e);
            System.exit(0);
        }
        log.info("初始化kettle成功!");
    }

    /**
     * 執行ktr文件內容
     * @param file
     * @param beginTime
     * @param endTime
     */
    public void runTrans(@NonNull String file, String beginTime, String endTime){
        log.info("正在執行ktr ...");
        try {
            TransMeta transMeta = new TransMeta(new ByteArrayInputStream(file.getBytes("UTF-8")), null, true, null, null);
            Trans trans = new Trans(transMeta);
            Map<String,String> params = this.dealParams(beginTime,endTime);
            params.forEach((k,v)->trans.setVariable(k,v));
            trans.prepareExecution(null);
            trans.startThreads();
            trans.waitUntilFinished();
            if (trans.getErrors() != 0) {
                log.error("執行ktr過程中存在錯誤");
            }
        }catch (Exception e){
            log.error("runTrans失敗",e);
        }
        log.info("ktr執行完畢!");
    }

    /**
     * 執行kjb文件內容
     * @param file
     * @param beginTime
     * @param endTime
     */
    public void runJob(@NonNull String file, String beginTime, String endTime){
        log.info("正在執行kjb ...");
        try {
            JobMeta jobMeta = new JobMeta(new ByteArrayInputStream(file.getBytes("UTF-8")), null, null);
            Job job = new Job(null, jobMeta);
            Map<String,String> params = this.dealParams(beginTime,endTime);
            params.forEach((k,v)->job.setVariable(k,v));
            job.start();
            job.waitUntilFinished();
            if (job.getErrors() != 0) {
                log.error("執行kjb過程中存在錯誤");
            }
        }catch (Exception e){
            log.error("runJob失敗",e);
        }
        log.info("kjb執行完畢...");
    }

    /**
     * 處理公共參數
     */
    private Map<String,String> dealParams(String beginTime, String endTime){
        Map<String, String> params = envConfig.getDamEnv();
        params.put("beginTime",beginTime);
        params.put("endTime",endTime);
        if (params.containsKey("beginTime")){
            params.put("beginTimeId",TimeUtil.date2timeId(params.get("beginTime")));
        }
        if (params.containsKey("endTime")){
            params.put("endTimeId",TimeUtil.date2timeId(params.get("endTime")));
        }
        log.debug("kettle參數:{}",params);
        return params;
    }

    /**
     * 解決kettle無法寫入空字符串的問題
     * window環境中,需要在C:\Users\wangll\.kettle\kettle.properties中寫入如下配置;
     * linux環境中,需要在/root/.kettle/kettle.properties中寫入如下配置。
     * 故爲了方便直接使用它自帶的方法去生成上述文件
     */
    public static void dealWriteNull()throws Exception{
        String directory = Const.getKettleDirectory();
        File dir = new File(directory);
        dir.mkdirs();
        KettleClientEnvironment.createKettleHome();
        String kpFile = directory + Const.FILE_SEPARATOR + "kettle.properties";
        File file = new File(kpFile);
        FileWriter fw = new FileWriter(file);
        BufferedWriter bw=new BufferedWriter(fw);
        bw.write("KETTLE_EMPTY_STRING_DIFFERS_FROM_NULL=Y");
        bw.close();
        fw.close();
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章