转换--连接字符串和计算器
目录
一、流程
concat fields和计算器是转换里面的,本次以这两个为列讲述转换里面的东西,还是从ktr分析开始。
观察concat fields节点,其实就是将firstName和lastName连接起来,并赋值给name这个字段,
计算器就是定义新字段,选择计算方式,指定需要计算的列,
明白界面怎么配置后,就知道该设置哪些属性,该怎么看ktr文件,该怎么写代码,关于spoon工具的讲解,B站有很多。
我看的就是下面这个,还是很透彻的。2019kettle8.2最新教程_哔哩哔哩_bilibili2019kettle8.2最新教程https://www.bilibili.com/video/BV1jE411B7J8
二、代码说明
这篇就不分析ktr文件了,之前两篇对ktr里面哪些元素应该知道怎么看了。
在代码后面标注了是从ktr哪个节点知道设置的代码。
定义下面四个获取Meta获取,重点说明ConcatFieldMeta和CalculatorMeta,
/*
1. Excel输入
*/
ExcelInputMeta inputMeta = getInputMeta();
/*
2. concat fields节点
*/
ConcatFieldsMeta concatFieldsMeta = getConcatFieldsMeta();
/*
3. 计算器节点
*/
CalculatorMeta calculatorMeta = getCalculatorMeta();
/*
4. excel输出
*/
ExcelOutputMeta outputMeta = getOutputMeta();
ConcatFieldsMeta
最好的解释就是代码注释,
/**
* 获取字符串连接
* @return
*/
private ConcatFieldsMeta getConcatFieldsMeta(){
ConcatFieldsMeta concatFieldsMeta = new ConcatFieldsMeta(); //<type>ConcatFields</type>
//设置连接分割符
concatFieldsMeta.setSeparator("-"); // <separator>-</separator>
//设置封闭符
concatFieldsMeta.setEnclosure("\""); // <enclosure>"</enclosure>
concatFieldsMeta.setEnclosureForced(false); // <enclosure_forced>N</enclosure_forced>
concatFieldsMeta.setEnclosureFixDisabled(false); // <enclosure_fix_disabled>N</enclosure_fix_disabled>
concatFieldsMeta.setHeaderEnabled(false); // <header>N</header>
concatFieldsMeta.setFooterEnabled(false); // <footer>N</footer>
//此处有默认值,可不设置
concatFieldsMeta.setFileFormat("DOS"); // <format>DOS</format>
concatFieldsMeta.setFileCompression("None"); // <compression>None</compression>
concatFieldsMeta.setFileNameInField(false); // <fileNameInField>N</fileNameInField>
concatFieldsMeta.setCreateParentFolder(true);// <create_parent_folder>Y</create_parent_folder>
//设置源字段列
TextFileField[] textFileFields = new TextFileField[2];
/*
<field>
<name>firstName</name>
<type>None</type>
<format/>
<currency/>
<decimal/>
<group/>
<nullif/>
<trim_type>none</trim_type>
<length>-1</length>
<precision>-1</precision>
</field>
*/
textFileFields[0] = new TextFileField();
textFileFields[0].setName("firstName");
textFileFields[0].setType(ValueMetaInterface.TYPE_NONE);
textFileFields[0].setLength(-1); // <fields> --> <field> --> <length>-1</length>
/*
<field>
<name>lastName</name>
<type>None</type>
<format/>
<currency/>
<decimal/>
<group/>
<nullif/>
<trim_type>none</trim_type>
<length>-1</length>
<precision>-1</precision>
</field>
*/
textFileFields[1] = new TextFileField();
textFileFields[1].setName("lastName"); // <name>lastName</name>
textFileFields[1].setType(ValueMetaInterface.TYPE_NONE); // <type>None</type>
textFileFields[1].setLength(-1); // <fields> --> <field> --> <length>-1</length>
concatFieldsMeta.setOutputFields(textFileFields);
//设置目标字段
/*
<ConcatFields>
<targetFieldName>name</targetFieldName>
<targetFieldLength>0</targetFieldLength>
<removeSelectedFields>N</removeSelectedFields>
</ConcatFields>
*/
concatFieldsMeta.setTargetFieldName("name"); // <targetFieldName>name</targetFieldName>
concatFieldsMeta.setTargetFieldLength(0); // <targetFieldLength>0</targetFieldLength>
concatFieldsMeta.setRemoveSelectedFields(false);// <removeSelectedFields>N</removeSelectedFields>
return concatFieldsMeta;
}
class ConcatFieldsMeta extends TextFileOutputMeta
ConcatFieldsMeta继承了TextFileOutputMeta,所以其实是一个文本输出Meta。
CalculatorMeta
这是计算器节点的Meta,仿照计算器的节点配置图片产生的代码如下,下面是选择的三种计算方式,
其中 Quarter of Date A 是用于计算birthday这个时间格式,是属于哪个季度;
Day of week of date A 是此日期A是星期几,周日算第一天;
A * B 就比较明显了 字段A 乘以 字段B 得到一个新值,那么A,B就必须是数字类型才行,否则报错。
/**
* 获取计算器
* @return
*/
private CalculatorMeta getCalculatorMeta(){
CalculatorMeta calculatorMeta = new CalculatorMeta(); // <type>Calculator</type>
CalculatorMetaFunction[] metaFunctions = new CalculatorMetaFunction[3];
metaFunctions[0] = new CalculatorMetaFunction();
metaFunctions[0].setFieldName("quarter"); // <field_name>quarter</field_name>
metaFunctions[0].setCalcType(CalculatorMetaFunction.CALC_QUARTER_OF_DATE);// <calc_type>QUARTER_OF_DATE</calc_type>
metaFunctions[0].setFieldA("birthday"); // <field_a>birthday</field_a>
metaFunctions[0].setValueType(ValueMetaInterface.TYPE_NONE); // <value_type>None</value_type>
metaFunctions[0].setRemovedFromResult(false); // <remove>N</remove>
metaFunctions[1] = new CalculatorMetaFunction();
metaFunctions[1].setFieldName("week_of_day");
metaFunctions[1].setCalcType(CalculatorMetaFunction.CALC_DAY_OF_WEEK);
metaFunctions[1].setFieldA("birthday");
metaFunctions[1].setValueType(ValueMetaInterface.TYPE_NONE);
metaFunctions[1].setRemovedFromResult(false);
metaFunctions[2] = new CalculatorMetaFunction();
metaFunctions[2].setFieldName("account");
metaFunctions[2].setCalcType(CalculatorMetaFunction.CALC_MULTIPLY);
metaFunctions[2].setFieldA("working_life");
metaFunctions[2].setFieldB("yearly_salary");
metaFunctions[2].setValueType(ValueMetaInterface.TYPE_NONE);
metaFunctions[2].setRemovedFromResult(false);
calculatorMeta.setCalculation(metaFunctions);
return calculatorMeta;
}
当上述concat fields和计算器节点代码好了以后,那么剩下的就是把节点串联在一起。
/*
5. 添加步骤
*/
TransMeta transMeta = new TransMeta();
transMeta.setName("计算器"); // <info> --> <name>计算器</name>
PluginRegistry registry = PluginRegistry.getInstance();
String inputPluginId = registry.getPluginId(StepPluginType.class, inputMeta);
StepMeta inputStep = new StepMeta(inputPluginId, "Excel输入", (StepMetaInterface) inputMeta); //<step> --> <name>Excel输入</name>
transMeta.addStep(inputStep);
String concatFieldPluginId = registry.getPluginId(StepPluginType.class, concatFieldsMeta);
StepMeta concatFieldStep = new StepMeta(concatFieldPluginId, "Concat fields", (StepMetaInterface) concatFieldsMeta); //<step> --> <name>Excel输入</name>
transMeta.addStep(concatFieldStep);
String calculatorPluginId = registry.getPluginId(StepPluginType.class, calculatorMeta);
StepMeta calculatorStep = new StepMeta(calculatorPluginId, "计算器", (StepMetaInterface) calculatorMeta); //<step> --> <name>Excel输入</name>
transMeta.addStep(calculatorStep);
String outPluginId = registry.getPluginId(StepPluginType.class, outputMeta);
StepMeta outputStep = new StepMeta(outPluginId, "Excel输出", (StepMetaInterface) outputMeta);// <step> --> <name>Excel输出</name>
transMeta.addStep(outputStep);
/*
4. 关联步骤
*/
transMeta.addTransHop(new TransHopMeta(inputStep, concatFieldStep));
transMeta.addTransHop(new TransHopMeta(concatFieldStep, calculatorStep));
transMeta.addTransHop(new TransHopMeta(calculatorStep, outputStep));
/*
5.执行
*/
Trans trans = new Trans(transMeta);
//执行转换
trans.execute(null);
//等待完成
trans.waitUntilFinished();
if (trans.getErrors() > 0) {
System.out.println("交换出错.");
return;
}
三、问题项
写这个交换案例时,只碰到一个问题,但这个问题真是让人头大,看了好久直到不得已跟踪源码才发现是少设置了一个length属性。
如下图所示,name只有一个连接符,和想象中压根不一样,firstName和lastName压根没有连接在一起。
而ktr文件在spoon中运行后,name的值是firstName和lastName的连接,比如 liu-wei,刘-大壮。
明白下面三个类的作用后,那么看代码自然是看ConcatFields这个类了。
此ConcatFields类的简略如下,包含ConcatFieldsMeta和ConcatFieldsData,其中processRow()方法是主要用来处理交换过程的,每一个交换节点都是如此。
public class ConcatFields extends TextFileOutput implements StepInterface {
private static Class<?> PKG = ConcatFields.class; // for i18n purposes, needed by Translator2!!
public ConcatFieldsMeta meta;
public ConcatFieldsData data;
public ConcatFields( StepMeta stepMeta, StepDataInterface stepDataInterface, int copyNr, TransMeta transMeta,
Trans trans ) {
super( stepMeta, stepDataInterface, copyNr, transMeta, trans ); // allocate TextFileOutput
}
@Override
public synchronized boolean processRow( StepMetaInterface smi, StepDataInterface sdi ) throws KettleException {
meta = (ConcatFieldsMeta) smi;
data = (ConcatFieldsData) sdi;
Object[] r = getRow(); // This also waits for a row to be finished.
return result;
}
}
跟踪processRow这个方法,终于在TextFileOutput中找到了真相,在这个类中有一个方法,把String转变为binary,然后这里面有length的判断,在下面代码注释已经说明了原因,
private byte[] convertStringToBinaryString( ValueMetaInterface v, String string ) throws KettleValueException {
int length = v.getLength(); // 由于没有设置length,所以int默认为0
//string.length()为大于0的值,所以进入此分支
if ( length > -1 && length < string.length() ) {
//所以此处 string.substring(0,0)
String tmp = string.substring( 0, length );
}
}
所以tmp是一个空字符串,自然也没有后面连接什么事了,“”-“” 这种在Excel中就是一个 - 。
解决方式:
textFileFields[1].setLength(-1); // <fields> --> <field> --> <length>-1</length>
四、运行
完整代码
@Before
public void before() {
try {
//初始化环境
EnvUtil.environmentInit();
KettleEnvironment.init();
} catch (KettleException e) {
log.error("", e);
}
}
/**
* 转换->计算器
*/
@Test
public void exchangeWithComputer() throws KettleException {
/*
1. Excel输入
*/
ExcelInputMeta inputMeta = getInputMeta();
/*
2. concat fields节点
*/
ConcatFieldsMeta concatFieldsMeta = getConcatFieldsMeta();
/*
3. 计算器节点
*/
CalculatorMeta calculatorMeta = getCalculatorMeta();
/*
4. excel输出
*/
ExcelOutputMeta outputMeta = getOutputMeta();
/*
5. 添加步骤
*/
TransMeta transMeta = new TransMeta();
transMeta.setName("计算器"); // <info> --> <name>计算器</name>
PluginRegistry registry = PluginRegistry.getInstance();
String inputPluginId = registry.getPluginId(StepPluginType.class, inputMeta);
StepMeta inputStep = new StepMeta(inputPluginId, "Excel输入", (StepMetaInterface) inputMeta); //<step> --> <name>Excel输入</name>
transMeta.addStep(inputStep);
String concatFieldPluginId = registry.getPluginId(StepPluginType.class, concatFieldsMeta);
StepMeta concatFieldStep = new StepMeta(concatFieldPluginId, "Concat fields", (StepMetaInterface) concatFieldsMeta); //<step> --> <name>Excel输入</name>
transMeta.addStep(concatFieldStep);
String calculatorPluginId = registry.getPluginId(StepPluginType.class, calculatorMeta);
StepMeta calculatorStep = new StepMeta(calculatorPluginId, "计算器", (StepMetaInterface) calculatorMeta); //<step> --> <name>Excel输入</name>
transMeta.addStep(calculatorStep);
String outPluginId = registry.getPluginId(StepPluginType.class, outputMeta);
StepMeta outputStep = new StepMeta(outPluginId, "Excel输出", (StepMetaInterface) outputMeta);// <step> --> <name>Excel输出</name>
transMeta.addStep(outputStep);
/*
4. 关联步骤
*/
transMeta.addTransHop(new TransHopMeta(inputStep, concatFieldStep));
transMeta.addTransHop(new TransHopMeta(concatFieldStep, calculatorStep));
transMeta.addTransHop(new TransHopMeta(calculatorStep, outputStep));
/*
5.执行
*/
Trans trans = new Trans(transMeta);
//执行转换
trans.execute(null);
//等待完成
trans.waitUntilFinished();
if (trans.getErrors() > 0) {
System.out.println("交换出错.");
return;
}
}
/**
* 获取字符串连接
* @return
*/
private ConcatFieldsMeta getConcatFieldsMeta(){
ConcatFieldsMeta concatFieldsMeta = new ConcatFieldsMeta(); //<type>ConcatFields</type>
// concatFieldsMeta.setDefault();
//设置连接分割符
concatFieldsMeta.setSeparator("-"); // <separator>-</separator>
//设置封闭符
concatFieldsMeta.setEnclosure("\""); // <enclosure>"</enclosure>
concatFieldsMeta.setEnclosureForced(false); // <enclosure_forced>N</enclosure_forced>
concatFieldsMeta.setEnclosureFixDisabled(false); // <enclosure_fix_disabled>N</enclosure_fix_disabled>
concatFieldsMeta.setHeaderEnabled(false); // <header>N</header>
concatFieldsMeta.setFooterEnabled(false); // <footer>N</footer>
//此处有默认值,可不设置
concatFieldsMeta.setFileFormat("DOS"); // <format>DOS</format>
concatFieldsMeta.setFileCompression("None"); // <compression>None</compression>
concatFieldsMeta.setFileNameInField(false); // <fileNameInField>N</fileNameInField>
concatFieldsMeta.setCreateParentFolder(true);// <create_parent_folder>Y</create_parent_folder>
//设置源字段列
TextFileField[] textFileFields = new TextFileField[2];
/*
<field>
<name>firstName</name>
<type>None</type>
<format/>
<currency/>
<decimal/>
<group/>
<nullif/>
<trim_type>none</trim_type>
<length>-1</length>
<precision>-1</precision>
</field>
*/
textFileFields[0] = new TextFileField();
textFileFields[0].setName("firstName");
textFileFields[0].setType(ValueMetaInterface.TYPE_NONE);
textFileFields[0].setTrimType(ValueMetaInterface.TRIM_TYPE_NONE);
textFileFields[0].setLength(-1);
/*
<field>
<name>lastName</name>
<type>None</type>
<format/>
<currency/>
<decimal/>
<group/>
<nullif/>
<trim_type>none</trim_type>
<length>-1</length>
<precision>-1</precision>
</field>
*/
textFileFields[1] = new TextFileField();
textFileFields[1].setName("lastName"); // <name>lastName</name>
textFileFields[1].setType(ValueMetaInterface.TYPE_NONE); // <type>None</type>
textFileFields[1].setTrimType(ValueMetaInterface.TRIM_TYPE_NONE);
textFileFields[1].setLength(-1); // <fields> --> <field> --> <length>-1</length>
concatFieldsMeta.setOutputFields(textFileFields);
//设置目标字段
/*
<ConcatFields>
<targetFieldName>name</targetFieldName>
<targetFieldLength>0</targetFieldLength>
<removeSelectedFields>N</removeSelectedFields>
</ConcatFields>
*/
concatFieldsMeta.setTargetFieldName("name"); // <targetFieldName>name</targetFieldName>
concatFieldsMeta.setTargetFieldLength(0); // <targetFieldLength>0</targetFieldLength>
concatFieldsMeta.setRemoveSelectedFields(false);// <removeSelectedFields>N</removeSelectedFields>
return concatFieldsMeta;
}
/**
* 获取计算器
* @return
*/
private CalculatorMeta getCalculatorMeta(){
CalculatorMeta calculatorMeta = new CalculatorMeta(); // <type>Calculator</type>
CalculatorMetaFunction[] metaFunctions = new CalculatorMetaFunction[3];
metaFunctions[0] = new CalculatorMetaFunction();
metaFunctions[0].setFieldName("quarter"); // <field_name>quarter</field_name>
metaFunctions[0].setCalcType(CalculatorMetaFunction.CALC_QUARTER_OF_DATE);// <calc_type>QUARTER_OF_DATE</calc_type>
metaFunctions[0].setFieldA("birthday"); // <field_a>birthday</field_a>
metaFunctions[0].setValueType(ValueMetaInterface.TYPE_NONE); // <value_type>None</value_type>
metaFunctions[0].setRemovedFromResult(false); // <remove>N</remove>
metaFunctions[1] = new CalculatorMetaFunction();
metaFunctions[1].setFieldName("week_of_day");
metaFunctions[1].setCalcType(CalculatorMetaFunction.CALC_DAY_OF_WEEK);
metaFunctions[1].setFieldA("birthday");
metaFunctions[1].setValueType(ValueMetaInterface.TYPE_NONE);
metaFunctions[1].setRemovedFromResult(false);
metaFunctions[2] = new CalculatorMetaFunction();
metaFunctions[2].setFieldName("account");
metaFunctions[2].setCalcType(CalculatorMetaFunction.CALC_MULTIPLY);
metaFunctions[2].setFieldA("working_life");
metaFunctions[2].setFieldB("yearly_salary");
metaFunctions[2].setValueType(ValueMetaInterface.TYPE_NONE);
metaFunctions[2].setRemovedFromResult(false);
calculatorMeta.setCalculation(metaFunctions);
return calculatorMeta;
}
/**
* 获取输入
*
* @return
*/
private ExcelInputMeta getInputMeta() {
ExcelInputMeta inputMeta = new ExcelInputMeta(); // <type>ExcelInput</type>
//文件路径
String filePath = "F:\\kette_test\\input\\计算器.xlsx";
String[] fileName = new String[]{filePath};
inputMeta.setFileName(fileName); // <name>F:\kette_test\input\计算器.xlsx</name>
String[] fileMasks = new String[1];
inputMeta.setFileMask(fileMasks); // <filemask/>
String[] fileExcludeMasks = new String[1];
inputMeta.setExcludeFileMask(fileExcludeMasks); // <exclude_filemask/>
String[] filerequireds = new String[]{"N"};
inputMeta.setFileRequired(filerequireds); // <file_required>N</file_required>
String[] subFolders = new String[]{"N"};
inputMeta.setIncludeSubFolders(subFolders); // <include_subfolders>N</include_subfolders>
inputMeta.setSpreadSheetType(SpreadSheetType.POI); // <spreadsheet_type>POI</spreadsheet_type>
//第二行开始
int[] startRow = new int[]{1};
inputMeta.setStartRow(startRow);
//第一列开始
int[] startColumn = new int[]{0};
inputMeta.setStartColumn(startColumn);
//字段列
String[] fieldsName = new String[]{"id", "firstName", "lastName", "birthday", "working_life", "yearly_salary"};
int[] fieldsType = new int[]{ValueMetaInterface.TYPE_NUMBER, ValueMetaInterface.TYPE_STRING, ValueMetaInterface.TYPE_STRING, ValueMetaInterface.TYPE_DATE, ValueMetaInterface.TYPE_NUMBER, ValueMetaInterface.TYPE_NUMBER};
//Excel输入 step下的 <fields> .... </fields>
ExcelInputField[] excelInputFields = new ExcelInputField[fieldsName.length];
for (int i = 0; i < excelInputFields.length; i++) {
excelInputFields[i] = new ExcelInputField();
excelInputFields[i].setName(fieldsName[i]);
excelInputFields[i].setType(fieldsType[i]);
excelInputFields[i].setTrimType(ExcelInputMeta.TYPE_TRIM_NONE);
excelInputFields[i].setRepeated(false);
}
inputMeta.setField(excelInputFields);
return inputMeta;
}
/**
* 获取输出
*
* @return
*/
private ExcelOutputMeta getOutputMeta() {
ExcelOutputMeta outputMeta = new ExcelOutputMeta(); // <type>ExcelOutput</type>
outputMeta.setAppend(false); // <append>N</append>
outputMeta.setHeaderEnabled(true); // <header>Y</header>
outputMeta.setFooterEnabled(false);// <footer>N</footer>
outputMeta.setFileName("F:\\kette_test\\output\\excel输出-计算器"); // <name>F:\kette_test\output\计算器</name>
outputMeta.setExtension("xls");// <extention>xls</extention>
outputMeta.setDoNotOpenNewFileInit(false); // <do_not_open_newfile_init>N</do_not_open_newfile_init>
outputMeta.setCreateParentFolder(false); // <create_parent_folder>N</create_parent_folder>
String[] fieldsName = new String[]{"id", "firstName", "lastName", "birthday", "working_life", "yearly_salary","name","quarter","week_of_day","account"};
int[] fieldsType = new int[]{ValueMetaInterface.TYPE_NUMBER, ValueMetaInterface.TYPE_STRING, ValueMetaInterface.TYPE_STRING, ValueMetaInterface.TYPE_DATE, ValueMetaInterface.TYPE_NUMBER, ValueMetaInterface.TYPE_NUMBER,ValueMetaInterface.TYPE_NUMBER,ValueMetaInterface.TYPE_INTEGER,ValueMetaInterface.TYPE_INTEGER,ValueMetaInterface.TYPE_NUMBER};
// <fields> ..... </fields>
ExcelField[] excelFields = new ExcelField[fieldsName.length];
for (int i = 0; i < excelFields.length; i++) {
excelFields[i] = new ExcelField();
excelFields[i].setName(fieldsName[i]);
excelFields[i].setType(fieldsType[i]);
/*
<field>
<name>id</name>
<type>Number</type>
<format>0</format>
</field>
*/
if(fieldsName[i].equals("id")){
excelFields[i].setFormat("0"); // <format>0</format>
}
}
outputMeta.setOutputFields(excelFields);
return outputMeta;
}
ktr文件
<?xml version="1.0" encoding="UTF-8"?>
<transformation>
<info>
<name>计算器</name>
<description/>
<extended_description/>
<trans_version/>
<trans_type>Normal</trans_type>
<directory>/</directory>
<parameters>
</parameters>
<log>
<trans-log-table>
<connection/>
<schema/>
<table/>
<size_limit_lines/>
<interval/>
<timeout_days/>
<field>
<id>ID_BATCH</id>
<enabled>Y</enabled>
<name>ID_BATCH</name>
</field>
<field>
<id>CHANNEL_ID</id>
<enabled>Y</enabled>
<name>CHANNEL_ID</name>
</field>
<field>
<id>TRANSNAME</id>
<enabled>Y</enabled>
<name>TRANSNAME</name>
</field>
<field>
<id>STATUS</id>
<enabled>Y</enabled>
<name>STATUS</name>
</field>
<field>
<id>LINES_READ</id>
<enabled>Y</enabled>
<name>LINES_READ</name>
<subject/>
</field>
<field>
<id>LINES_WRITTEN</id>
<enabled>Y</enabled>
<name>LINES_WRITTEN</name>
<subject/>
</field>
<field>
<id>LINES_UPDATED</id>
<enabled>Y</enabled>
<name>LINES_UPDATED</name>
<subject/>
</field>
<field>
<id>LINES_INPUT</id>
<enabled>Y</enabled>
<name>LINES_INPUT</name>
<subject/>
</field>
<field>
<id>LINES_OUTPUT</id>
<enabled>Y</enabled>
<name>LINES_OUTPUT</name>
<subject/>
</field>
<field>
<id>LINES_REJECTED</id>
<enabled>Y</enabled>
<name>LINES_REJECTED</name>
<subject/>
</field>
<field>
<id>ERRORS</id>
<enabled>Y</enabled>
<name>ERRORS</name>
</field>
<field>
<id>STARTDATE</id>
<enabled>Y</enabled>
<name>STARTDATE</name>
</field>
<field>
<id>ENDDATE</id>
<enabled>Y</enabled>
<name>ENDDATE</name>
</field>
<field>
<id>LOGDATE</id>
<enabled>Y</enabled>
<name>LOGDATE</name>
</field>
<field>
<id>DEPDATE</id>
<enabled>Y</enabled>
<name>DEPDATE</name>
</field>
<field>
<id>REPLAYDATE</id>
<enabled>Y</enabled>
<name>REPLAYDATE</name>
</field>
<field>
<id>LOG_FIELD</id>
<enabled>Y</enabled>
<name>LOG_FIELD</name>
</field>
<field>
<id>EXECUTING_SERVER</id>
<enabled>N</enabled>
<name>EXECUTING_SERVER</name>
</field>
<field>
<id>EXECUTING_USER</id>
<enabled>N</enabled>
<name>EXECUTING_USER</name>
</field>
<field>
<id>CLIENT</id>
<enabled>N</enabled>
<name>CLIENT</name>
</field>
</trans-log-table>
<perf-log-table>
<connection/>
<schema/>
<table/>
<interval/>
<timeout_days/>
<field>
<id>ID_BATCH</id>
<enabled>Y</enabled>
<name>ID_BATCH</name>
</field>
<field>
<id>SEQ_NR</id>
<enabled>Y</enabled>
<name>SEQ_NR</name>
</field>
<field>
<id>LOGDATE</id>
<enabled>Y</enabled>
<name>LOGDATE</name>
</field>
<field>
<id>TRANSNAME</id>
<enabled>Y</enabled>
<name>TRANSNAME</name>
</field>
<field>
<id>STEPNAME</id>
<enabled>Y</enabled>
<name>STEPNAME</name>
</field>
<field>
<id>STEP_COPY</id>
<enabled>Y</enabled>
<name>STEP_COPY</name>
</field>
<field>
<id>LINES_READ</id>
<enabled>Y</enabled>
<name>LINES_READ</name>
</field>
<field>
<id>LINES_WRITTEN</id>
<enabled>Y</enabled>
<name>LINES_WRITTEN</name>
</field>
<field>
<id>LINES_UPDATED</id>
<enabled>Y</enabled>
<name>LINES_UPDATED</name>
</field>
<field>
<id>LINES_INPUT</id>
<enabled>Y</enabled>
<name>LINES_INPUT</name>
</field>
<field>
<id>LINES_OUTPUT</id>
<enabled>Y</enabled>
<name>LINES_OUTPUT</name>
</field>
<field>
<id>LINES_REJECTED</id>
<enabled>Y</enabled>
<name>LINES_REJECTED</name>
</field>
<field>
<id>ERRORS</id>
<enabled>Y</enabled>
<name>ERRORS</name>
</field>
<field>
<id>INPUT_BUFFER_ROWS</id>
<enabled>Y</enabled>
<name>INPUT_BUFFER_ROWS</name>
</field>
<field>
<id>OUTPUT_BUFFER_ROWS</id>
<enabled>Y</enabled>
<name>OUTPUT_BUFFER_ROWS</name>
</field>
</perf-log-table>
<channel-log-table>
<connection/>
<schema/>
<table/>
<timeout_days/>
<field>
<id>ID_BATCH</id>
<enabled>Y</enabled>
<name>ID_BATCH</name>
</field>
<field>
<id>CHANNEL_ID</id>
<enabled>Y</enabled>
<name>CHANNEL_ID</name>
</field>
<field>
<id>LOG_DATE</id>
<enabled>Y</enabled>
<name>LOG_DATE</name>
</field>
<field>
<id>LOGGING_OBJECT_TYPE</id>
<enabled>Y</enabled>
<name>LOGGING_OBJECT_TYPE</name>
</field>
<field>
<id>OBJECT_NAME</id>
<enabled>Y</enabled>
<name>OBJECT_NAME</name>
</field>
<field>
<id>OBJECT_COPY</id>
<enabled>Y</enabled>
<name>OBJECT_COPY</name>
</field>
<field>
<id>REPOSITORY_DIRECTORY</id>
<enabled>Y</enabled>
<name>REPOSITORY_DIRECTORY</name>
</field>
<field>
<id>FILENAME</id>
<enabled>Y</enabled>
<name>FILENAME</name>
</field>
<field>
<id>OBJECT_ID</id>
<enabled>Y</enabled>
<name>OBJECT_ID</name>
</field>
<field>
<id>OBJECT_REVISION</id>
<enabled>Y</enabled>
<name>OBJECT_REVISION</name>
</field>
<field>
<id>PARENT_CHANNEL_ID</id>
<enabled>Y</enabled>
<name>PARENT_CHANNEL_ID</name>
</field>
<field>
<id>ROOT_CHANNEL_ID</id>
<enabled>Y</enabled>
<name>ROOT_CHANNEL_ID</name>
</field>
</channel-log-table>
<step-log-table>
<connection/>
<schema/>
<table/>
<timeout_days/>
<field>
<id>ID_BATCH</id>
<enabled>Y</enabled>
<name>ID_BATCH</name>
</field>
<field>
<id>CHANNEL_ID</id>
<enabled>Y</enabled>
<name>CHANNEL_ID</name>
</field>
<field>
<id>LOG_DATE</id>
<enabled>Y</enabled>
<name>LOG_DATE</name>
</field>
<field>
<id>TRANSNAME</id>
<enabled>Y</enabled>
<name>TRANSNAME</name>
</field>
<field>
<id>STEPNAME</id>
<enabled>Y</enabled>
<name>STEPNAME</name>
</field>
<field>
<id>STEP_COPY</id>
<enabled>Y</enabled>
<name>STEP_COPY</name>
</field>
<field>
<id>LINES_READ</id>
<enabled>Y</enabled>
<name>LINES_READ</name>
</field>
<field>
<id>LINES_WRITTEN</id>
<enabled>Y</enabled>
<name>LINES_WRITTEN</name>
</field>
<field>
<id>LINES_UPDATED</id>
<enabled>Y</enabled>
<name>LINES_UPDATED</name>
</field>
<field>
<id>LINES_INPUT</id>
<enabled>Y</enabled>
<name>LINES_INPUT</name>
</field>
<field>
<id>LINES_OUTPUT</id>
<enabled>Y</enabled>
<name>LINES_OUTPUT</name>
</field>
<field>
<id>LINES_REJECTED</id>
<enabled>Y</enabled>
<name>LINES_REJECTED</name>
</field>
<field>
<id>ERRORS</id>
<enabled>Y</enabled>
<name>ERRORS</name>
</field>
<field>
<id>LOG_FIELD</id>
<enabled>N</enabled>
<name>LOG_FIELD</name>
</field>
</step-log-table>
<metrics-log-table>
<connection/>
<schema/>
<table/>
<timeout_days/>
<field>
<id>ID_BATCH</id>
<enabled>Y</enabled>
<name>ID_BATCH</name>
</field>
<field>
<id>CHANNEL_ID</id>
<enabled>Y</enabled>
<name>CHANNEL_ID</name>
</field>
<field>
<id>LOG_DATE</id>
<enabled>Y</enabled>
<name>LOG_DATE</name>
</field>
<field>
<id>METRICS_DATE</id>
<enabled>Y</enabled>
<name>METRICS_DATE</name>
</field>
<field>
<id>METRICS_CODE</id>
<enabled>Y</enabled>
<name>METRICS_CODE</name>
</field>
<field>
<id>METRICS_DESCRIPTION</id>
<enabled>Y</enabled>
<name>METRICS_DESCRIPTION</name>
</field>
<field>
<id>METRICS_SUBJECT</id>
<enabled>Y</enabled>
<name>METRICS_SUBJECT</name>
</field>
<field>
<id>METRICS_TYPE</id>
<enabled>Y</enabled>
<name>METRICS_TYPE</name>
</field>
<field>
<id>METRICS_VALUE</id>
<enabled>Y</enabled>
<name>METRICS_VALUE</name>
</field>
</metrics-log-table>
</log>
<maxdate>
<connection/>
<table/>
<field/>
<offset>0.0</offset>
<maxdiff>0.0</maxdiff>
</maxdate>
<size_rowset>10000</size_rowset>
<sleep_time_empty>50</sleep_time_empty>
<sleep_time_full>50</sleep_time_full>
<unique_connections>N</unique_connections>
<feedback_shown>Y</feedback_shown>
<feedback_size>50000</feedback_size>
<using_thread_priorities>Y</using_thread_priorities>
<shared_objects_file/>
<capture_step_performance>N</capture_step_performance>
<step_performance_capturing_delay>1000</step_performance_capturing_delay>
<step_performance_capturing_size_limit>100</step_performance_capturing_size_limit>
<dependencies>
</dependencies>
<partitionschemas>
</partitionschemas>
<slaveservers>
</slaveservers>
<clusterschemas>
</clusterschemas>
<created_user>-</created_user>
<created_date>2021/11/16 10:21:02.172</created_date>
<modified_user>-</modified_user>
<modified_date>2021/11/16 10:21:02.172</modified_date>
<key_for_session_key/>
<is_key_private>N</is_key_private>
</info>
<notepads>
</notepads>
<order>
<hop>
<from>计算器</from>
<to>Excel输出</to>
<enabled>Y</enabled>
</hop>
<hop>
<from>Excel输入</from>
<to>Concat fields</to>
<enabled>Y</enabled>
</hop>
<hop>
<from>Concat fields</from>
<to>计算器</to>
<enabled>Y</enabled>
</hop>
</order>
<step>
<name>Excel输入</name>
<type>ExcelInput</type>
<description/>
<distribute>Y</distribute>
<custom_distribution/>
<copies>1</copies>
<partitioning>
<method>none</method>
<schema_name/>
</partitioning>
<header>Y</header>
<noempty>Y</noempty>
<stoponempty>N</stoponempty>
<filefield/>
<sheetfield/>
<sheetrownumfield/>
<rownumfield/>
<sheetfield/>
<filefield/>
<limit>0</limit>
<encoding/>
<add_to_result_filenames>Y</add_to_result_filenames>
<accept_filenames>N</accept_filenames>
<accept_field/>
<accept_stepname/>
<file>
<name>F:\kette_test\input\计算器.xlsx</name>
<filemask/>
<exclude_filemask/>
<file_required>N</file_required>
<include_subfolders>N</include_subfolders>
</file>
<fields>
<field>
<name>id</name>
<type>Number</type>
<length>-1</length>
<precision>-1</precision>
<trim_type>none</trim_type>
<repeat>N</repeat>
<format/>
<currency/>
<decimal/>
<group/>
</field>
<field>
<name>firstName</name>
<type>String</type>
<length>-1</length>
<precision>-1</precision>
<trim_type>none</trim_type>
<repeat>N</repeat>
<format/>
<currency/>
<decimal/>
<group/>
</field>
<field>
<name>lastName</name>
<type>String</type>
<length>-1</length>
<precision>-1</precision>
<trim_type>none</trim_type>
<repeat>N</repeat>
<format/>
<currency/>
<decimal/>
<group/>
</field>
<field>
<name>birthday</name>
<type>Date</type>
<length>-1</length>
<precision>-1</precision>
<trim_type>none</trim_type>
<repeat>N</repeat>
<format/>
<currency/>
<decimal/>
<group/>
</field>
<field>
<name>working_life</name>
<type>Number</type>
<length>-1</length>
<precision>-1</precision>
<trim_type>none</trim_type>
<repeat>N</repeat>
<format/>
<currency/>
<decimal/>
<group/>
</field>
<field>
<name>yearly_salary</name>
<type>Number</type>
<length>-1</length>
<precision>-1</precision>
<trim_type>none</trim_type>
<repeat>N</repeat>
<format/>
<currency/>
<decimal/>
<group/>
</field>
</fields>
<sheets>
</sheets>
<strict_types>N</strict_types>
<error_ignored>N</error_ignored>
<error_line_skipped>N</error_line_skipped>
<bad_line_files_destination_directory/>
<bad_line_files_extension>warning</bad_line_files_extension>
<error_line_files_destination_directory/>
<error_line_files_extension>error</error_line_files_extension>
<line_number_files_destination_directory/>
<line_number_files_extension>line</line_number_files_extension>
<shortFileFieldName/>
<pathFieldName/>
<hiddenFieldName/>
<lastModificationTimeFieldName/>
<uriNameFieldName/>
<rootUriNameFieldName/>
<extensionFieldName/>
<sizeFieldName/>
<spreadsheet_type>POI</spreadsheet_type>
<attributes/>
<cluster_schema/>
<remotesteps>
<input>
</input>
<output>
</output>
</remotesteps>
<GUI>
<xloc>320</xloc>
<yloc>272</yloc>
<draw>Y</draw>
</GUI>
</step>
<step>
<name>Excel输出</name>
<type>ExcelOutput</type>
<description/>
<distribute>Y</distribute>
<custom_distribution/>
<copies>1</copies>
<partitioning>
<method>none</method>
<schema_name/>
</partitioning>
<header>Y</header>
<footer>N</footer>
<encoding/>
<append>N</append>
<add_to_result_filenames>Y</add_to_result_filenames>
<file>
<name>F:\kette_test\output\计算器</name>
<extention>xls</extention>
<do_not_open_newfile_init>N</do_not_open_newfile_init>
<create_parent_folder>N</create_parent_folder>
<split>N</split>
<add_date>N</add_date>
<add_time>N</add_time>
<SpecifyFormat>N</SpecifyFormat>
<date_time_format/>
<sheetname>Sheet1</sheetname>
<autosizecolums>N</autosizecolums>
<nullisblank>N</nullisblank>
<protect_sheet>N</protect_sheet>
<password>Encrypted </password>
<splitevery>0</splitevery>
<usetempfiles>N</usetempfiles>
<tempdirectory/>
</file>
<template>
<enabled>N</enabled>
<append>N</append>
<filename>template.xls</filename>
</template>
<fields>
<field>
<name>id</name>
<type>Number</type>
<format>0</format>
</field>
<field>
<name>firstName</name>
<type>String</type>
<format/>
</field>
<field>
<name>lastName</name>
<type>String</type>
<format/>
</field>
<field>
<name>birthday</name>
<type>Date</type>
<format/>
</field>
<field>
<name>working_life</name>
<type>Number</type>
<format/>
</field>
<field>
<name>yearly_salary</name>
<type>Number</type>
<format/>
</field>
<field>
<name>name</name>
<type>Number</type>
<format/>
</field>
<field>
<name>quarter</name>
<type>Integer</type>
<format/>
</field>
<field>
<name>week_of_day</name>
<type>Integer</type>
<format/>
</field>
<field>
<name>account</name>
<type>Number</type>
<format/>
</field>
</fields>
<custom>
<header_font_name>arial</header_font_name>
<header_font_size>10</header_font_size>
<header_font_bold>N</header_font_bold>
<header_font_italic>N</header_font_italic>
<header_font_underline>no</header_font_underline>
<header_font_orientation>horizontal</header_font_orientation>
<header_font_color>black</header_font_color>
<header_background_color>none</header_background_color>
<header_row_height>255</header_row_height>
<header_alignment>left</header_alignment>
<header_image/>
<row_font_name>arial</row_font_name>
<row_font_size>10</row_font_size>
<row_font_color>black</row_font_color>
<row_background_color>none</row_background_color>
</custom>
<attributes/>
<cluster_schema/>
<remotesteps>
<input>
</input>
<output>
</output>
</remotesteps>
<GUI>
<xloc>688</xloc>
<yloc>288</yloc>
<draw>Y</draw>
</GUI>
</step>
<step>
<name>计算器</name>
<type>Calculator</type>
<description/>
<distribute>Y</distribute>
<custom_distribution/>
<copies>1</copies>
<partitioning>
<method>none</method>
<schema_name/>
</partitioning>
<failIfNoFile>Y</failIfNoFile>
<calculation>
<field_name>quarter</field_name>
<calc_type>QUARTER_OF_DATE</calc_type>
<field_a>birthday</field_a>
<field_b/>
<field_c/>
<value_type>None</value_type>
<value_length>-1</value_length>
<value_precision>-1</value_precision>
<remove>N</remove>
<conversion_mask/>
<decimal_symbol/>
<grouping_symbol/>
<currency_symbol/>
</calculation>
<calculation>
<field_name>week_of_day</field_name>
<calc_type>DAY_OF_WEEK</calc_type>
<field_a>birthday</field_a>
<field_b/>
<field_c/>
<value_type>None</value_type>
<value_length>-1</value_length>
<value_precision>-1</value_precision>
<remove>N</remove>
<conversion_mask/>
<decimal_symbol/>
<grouping_symbol/>
<currency_symbol/>
</calculation>
<calculation>
<field_name>account</field_name>
<calc_type>MULTIPLY</calc_type>
<field_a>working_life</field_a>
<field_b>yearly_salary</field_b>
<field_c/>
<value_type>None</value_type>
<value_length>-1</value_length>
<value_precision>-1</value_precision>
<remove>N</remove>
<conversion_mask/>
<decimal_symbol/>
<grouping_symbol/>
<currency_symbol/>
</calculation>
<attributes/>
<cluster_schema/>
<remotesteps>
<input>
</input>
<output>
</output>
</remotesteps>
<GUI>
<xloc>560</xloc>
<yloc>288</yloc>
<draw>Y</draw>
</GUI>
</step>
<step>
<name>Concat fields</name>
<type>ConcatFields</type>
<description/>
<distribute>Y</distribute>
<custom_distribution/>
<copies>1</copies>
<partitioning>
<method>none</method>
<schema_name/>
</partitioning>
<separator>-</separator>
<enclosure>"</enclosure>
<enclosure_forced>N</enclosure_forced>
<enclosure_fix_disabled>N</enclosure_fix_disabled>
<header>N</header>
<footer>N</footer>
<format>DOS</format>
<compression>None</compression>
<encoding/>
<endedLine/>
<fileNameInField>N</fileNameInField>
<fileNameField/>
<create_parent_folder>Y</create_parent_folder>
<file>
<name>file</name>
<servlet_output>N</servlet_output>
<do_not_open_new_file_init>N</do_not_open_new_file_init>
<extention>txt</extention>
<append>N</append>
<split>N</split>
<haspartno>N</haspartno>
<add_date>N</add_date>
<add_time>N</add_time>
<SpecifyFormat>N</SpecifyFormat>
<date_time_format/>
<add_to_result_filenames>Y</add_to_result_filenames>
<pad>N</pad>
<fast_dump>N</fast_dump>
<splitevery>0</splitevery>
</file>
<fields>
<field>
<name>firstName</name>
<type>None</type>
<format/>
<currency/>
<decimal/>
<group/>
<nullif/>
<trim_type>none</trim_type>
<length>-1</length>
<precision>-1</precision>
</field>
<field>
<name>lastName</name>
<type>None</type>
<format/>
<currency/>
<decimal/>
<group/>
<nullif/>
<trim_type>none</trim_type>
<length>-1</length>
<precision>-1</precision>
</field>
</fields>
<ConcatFields>
<targetFieldName>name</targetFieldName>
<targetFieldLength>0</targetFieldLength>
<removeSelectedFields>N</removeSelectedFields>
</ConcatFields>
<attributes/>
<cluster_schema/>
<remotesteps>
<input>
</input>
<output>
</output>
</remotesteps>
<GUI>
<xloc>448</xloc>
<yloc>288</yloc>
<draw>Y</draw>
</GUI>
</step>
<step_error_handling>
</step_error_handling>
<slave-step-copy-partition-distribution>
</slave-step-copy-partition-distribution>
<slave_transformation>N</slave_transformation>
<attributes/>
</transformation>
吐槽: 要是能有把这些java文件和ktr文件上传保存为附件就好了。完整代码和ktr文件就可以附件查看了。