Spring-batch使用PatternMatchingCompositeLineTokenizer解析不规则数据文件



     大家都知道,传统Spring-batch能够很好的处理批量任务,其中,提供的trunk组件(batch:trunk)能够处理行文本或者数据库的普通读写操作。下面这个例子可以读写基本的规范数据文件:

     

<batch:step id="analyseInfo">
       <batch:tasklet transaction-manager="transactionManager">
       <batch:chunk reader="wxReader" writer="wxWriter" commit-interval="10"></batch:chunk>
       </batch:tasklet>
</batch:step>
<!-- wx Detail -->
    <bean id="wxReader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
    	<property name="resource" value="file:#{jobParameters['filename']}"></property>
        <property name="encoding" value="UTF-8"></property>
    	<property name="comments" value="#{'#'}"></property>
    	<property name="lineMapper" ref="wxMapper"></property>    
    	<property name="linesToSkip" value="1"></property>	    
    </bean>
    <bean id="wxWriter" class="com.secondgame.demo_service.demo.batch.task.WxWriter" scope="step">

上述代码中,wxReader负责解析源文件:

resource配置源文件的地址,

encoding配置文件的编码方式,

comments配置注释行的开头,可以跳过注释行,本文例子跳过以#开头的注释行,不进行处理

lineMapper负责具体的处理文件的类,后文会介绍

lineToSkip用来指定跳过处理文本的头N行,本例跳过1行

 

 

lineMapper的配置

 

  <bean id="wxMapper" class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
    	<property name="lineTokenizer" ref="wxMultiTokenizer"></property>
    	<property name="fieldSetMapper">
    		<bean class="com.secondgame.demo_service.demo.batch.task.WxFileSetMapper">
    		</bean>
    	</property>
    </bean>
<bean id="wxTokenizer" class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer" scope="step">
     	<property name="delimiter" value=","></property>
    	<property name="names">
	   		<list>
	   			<value>tradeTime</value>
	   			<value>pubAccountId</value>
	   			<value>merchantId</value>
	   			<value>subMerchantId</value>
	   			<value>deviceId</value>
	   			<value>wxOrderId</value>
	   			<value>merchantOrderId</value>
	   			<value>userTag</value>
	   			<value>tradeType</value>
	   			<value>tradeStatus</value>
	   			<value>payerBank</value>
	   			<value>capitalType</value>
	   			<value>totalAmount</value>
	   			<value>enterpriseRedAmount</value>
	   			<value>wxRefundId</value>
	   			<value>merchantRefundId</value>
	   			<value>refundAmount</value>
	   			<value>enterpriseRedRefundAmount</value>
	   			<value>refundType</value>
	   			<value>refundStatus</value>
	   			<value>goodsName</value>
	   			<value>merchantData</value>
	   			<value>fee</value>
	   			<value>feeRate</value>
	   		</list>
    	</property>
    </bean>

 

该配置中,使用org.springframework.batch.item.file.transform.DelimitedLineTokenizer进行文件解析,能够将解析出来的每一行利用类com.secondgame.demo_service.demo.batch.task.WxFileSetMapper进行处理。

实际应用中,数据源没有想象的那么“整齐”,可以通过离线数据清洗(各种脚本)的方式将数据进行预处理。但对于基本整齐的文件,可以采用spring-batch提供的行解析器org.springframework.batch.item.file.transform.PatternMatchingCompositeLineTokenizer进行处理。该解析器不受限于一种解析器,可以根据通配符配置,对不同的行进行不同的解析,假设文本文件有如下结构:

 

1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24
1,2,3,4,5
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24

该文件每行数据由逗号分隔,但是存在不规则的行(或者有特殊意义,作者遇到的情况是,对账明细单最后有汇总项,而且无法通过前缀区分)。该文本在上述代码配置中,会直接在解析第三行的地方报错:需要24个参数,实际只有5个。

笔者想到的解决方案有如下几种:

1. 与处理文件,把不规则的第三行处理掉

2. 补齐第三行的数据,凑足24个内容。

两者都需要额外的处理数据过程,而使用前文介绍的PatternMatchingCompositeLineTokenizer则可以直接处理该种情况。

 

部分实现的代码如下(仅体现核心思想,直接拷贝代码无法使用,实际工程需要额外配置文件):

<bean id="wxMapper" class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
    	<property name="lineTokenizer" ref="wxMultiTokenizer"></property>
    	<property name="fieldSetMapper">
    		<bean class="com.secondgame.demo_service.demo.batch.task.WxFileSetMapper">
    		</bean>
    	</property>
    </bean>
    <bean id="wxMultiTokenizer" class="org.springframework.batch.item.file.transform.PatternMatchingCompositeLineTokenizer" scope="step">
    	<!-- <property name="delimiter" value=","></property> -->
   		<property name="tokenizers">
   			<map>
   				<entry key="*,*,*,*,*" value-ref="wxTokenizerTail"></entry>
   				<entry key="*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*" value-ref="wxTokenizer"></entry>
   			</map>
   		</property>
   	</bean>
    <bean id="wxTokenizer" class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer" scope="step">
     	<property name="delimiter" value=","></property>
    	<property name="names">
	   		<list>
	   			<value>tradeTime</value>
	   			<value>pubAccountId</value>
	   			<value>merchantId</value>
	   			<value>subMerchantId</value>
	   			<value>deviceId</value>
	   			<value>wxOrderId</value>
	   			<value>merchantOrderId</value>
	   			<value>userTag</value>
	   			<value>tradeType</value>
	   			<value>tradeStatus</value>
	   			<value>payerBank</value>
	   			<value>capitalType</value>
	   			<value>totalAmount</value>
	   			<value>enterpriseRedAmount</value>
	   			<value>wxRefundId</value>
	   			<value>merchantRefundId</value>
	   			<value>refundAmount</value>
	   			<value>enterpriseRedRefundAmount</value>
	   			<value>refundType</value>
	   			<value>refundStatus</value>
	   			<value>goodsName</value>
	   			<value>merchantData</value>
	   			<value>fee</value>
	   			<value>feeRate</value>
	   		</list>
    	</property>
    </bean>
    <bean id="wxTokenizerTail" class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer" scope="step">
     	<property name="delimiter" value=","></property>
     	<property name="names">
	   		<list>
	   			<value>totalCount</value>
	   			<value>totalAmount</value>
	   			<value>refundAmount</value>
	   			<value>enterpriseRedRefundAmount</value>
	   			<value>fee</value>
	   		</list>
    	</property>
    </bean>

上述代码实现了两个行解析器,分别解析24个数据和5个数据的情况,其他情况可以继续增加行解析器即可。

 

如果数据文件情况更加复杂,可以考虑自定义行解析器,实现自定义功能,这个笔者并没有进一步的研究,以后可以再尝试,本文思路来自于stackoverflow:

http://stackoverflow.com/questions/27504722/how-to-custom-spring-batch-delimitedlinetokenizer

不过这个作者的代码通配符部分我实现*全量替代过不去,还需要进一步看源码。

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值