英文:
Unable to add header and footer to the file using Apache Camel Bindy
问题
@Component
public class EmployeePackageRoute extends RouteBuilder {
@Autowired
private Header header;
private Trailer footer;
@SuppressWarnings("deprecation")
@Override
public final void configure() {
System.out.println("fetching employee details from employee api");
try {
from("jetty://http://localhost:8084/employee-package/getEmployee")
.unmarshal().json(JsonLibrary.Jackson, RecurringPaymentResults.class)
.process(
ex -> {
System.out.println("+++++++++++++++++ " + ex.getIn().getBody());
RecurringPaymentResults result = ex.getIn().getBody(RecurringPaymentResults.class);
List<RecurringPaymentsDeduct> employee = result.getResults();
ex.getOut().setBody(employee);
System.out.println("**** Header ** " + header);
})
.to("seda:employeeFeed");
final DataFormat bindy = new BindyFixedLengthDataFormat(RecurringPaymentsDeduct.class);
footer = new Trailer("TRAILER", 3);
Map<String, Object> headerObjMap = new HashMap<String, Object>();
headerObjMap.put(Header.class.getName(), header);
Map<String, Object> footerObjMap = new HashMap<String, Object>();
footerObjMap.put(Trailer.class.getName(), footer);
from("seda:employeeFeed")
.log("process csv")
.marshal(bindy)
.log("csv processed")
.process(
ex -> {
System.out.println("******************** " + ex.getIn().getBody());
//ex.getOut().setHeader("header", header);
ex.getOut().setHeader(BindyFixedLengthDataFormat.CAMEL_BINDY_FIXED_LENGTH_HEADER, headerObjMap);
ex.getOut().setBody(ex.getIn().getBody());
ex.getOut().setHeader(BindyFixedLengthDataFormat.CAMEL_BINDY_FIXED_LENGTH_FOOTER, footerObjMap);
}).to("file://C:\\Users\\testfolder?fileName=test.txt")
.end();
} catch (Exception e) {
System.out.println("Error occurred while processing employee data: " + e.getMessage());
e.printStackTrace();
}
}
}
@Data
@Section(number = 2)
@FixedLengthRecord(header = Header.class, footer = Trailer.class)
public class RecurringPaymentsDeduct implements Serializable {
private static final long serialVersionUID = 1L;
@DataField(pos = 1, length = 10)
public String RECTY;
// Other fields...
}
@Configuration
@EnableConfigurationProperties
@ConfigurationProperties("test")
@Data
@Section(number = 1)
@FixedLengthRecord()
public class Header implements Serializable {
private static final long serialVersionUID = 1L;
@DataField(pos = 1, length = 5)
private String header1;
// Other fields...
}
@Section(number = 3)
@FixedLengthRecord
public class Trailer implements Serializable {
private static final long serialVersionUID = 1L;
@DataField(pos = 1, length = 7)
private String trailer;
// Other fields...
}
英文:
I am trying to create a file with header and footer record along with json payload as body.
Header and footer property values will be dynamic based on the timestamp and total number of records
(At the moment I am planning to achieve with static values from properties).
I am using FixedLengthDataFormat to achieve this.
However header and footer records are not being added to the file, the file only has json payload as body.
Can someone help me to achieve this?
I have copied all the class files below.
@Component
public class EmployeePackageRoute extends RouteBuilder {
@Autowired
private Header header;
private Trailer footer;
@SuppressWarnings("deprecation")
@Override
public final void configure() {
System.out.println("fetching employee details from employee api");
try {
from("jetty://http://localhost:8084/employee-package/getEmployee")
.unmarshal().json(JsonLibrary.Jackson, RecurringPaymentResults.class)
.process(
ex -> {
System.out.println("+++++++++++++++++ "+ex.getIn().getBody());
RecurringPaymentResults result = ex.getIn().getBody(RecurringPaymentResults.class);
List<RecurringPaymentsDeduct> employee = result.getResults();
ex.getOut().setBody(employee);
System.out.println("**** Header ** "+header);
})
.to("seda:employeeFeed");
final DataFormat bindy = new BindyFixedLengthDataFormat(RecurringPaymentsDeduct.class);
footer = new Trailer("TRAILER",3);
Map<String, Object> headerObjMap = new HashMap<String,Object>();
headerObjMap.put(Header.class.getName(), header);
Map<String, Object> footerObjMap = new HashMap<String,Object>();
footerObjMap.put(Trailer.class.getName(), footer);
from("seda:employeeFeed")
.log("process csv")
.marshal(bindy)
.log("csv processed")
.process(
ex -> {
System.out.println("******************** "+ex.getIn().getBody());
//ex.getOut().setHeader("header", header);
ex.getOut().setHeader(BindyFixedLengthDataFormat.CAMEL_BINDY_FIXED_LENGTH_HEADER, headerObjMap);
ex.getOut().setBody(ex.getIn().getBody());
ex.getOut().setHeader(BindyFixedLengthDataFormat.CAMEL_BINDY_FIXED_LENGTH_FOOTER, footerObjMap);
}).to("file://C:\Users\testfolder?fileName=test.txt")
.end();
} catch(Exception e) {
System.out.println("Error occurred while processing employee data: "+e.getMessage());
e.printStackTrace();
}
}
}
@Data
@Section(number = 2)
@FixedLengthRecord(header = Header.class, footer = Trailer.class)
public class RecurringPaymentsDeduct implements Serializable {
private static final long serialVersionUID = 1L;
@DataField(pos = 1, length = 10)
public String RECTY;
@DataField(pos = 2, length = 10)
public String CLIID;
@DataField(pos = 3, length = 10)
public String INTCA;
@DataField(pos = 4, length = 10)
public String ORDNO;
@DataField(pos = 5, length = 10)
public String IOPER;
@DataField(pos = 6, length = 10)
public String INFTY;
@DataField(pos = 7, length = 10)
public String SUBTY;
@DataField(pos = 8, length = 10)
public String BEGDA;
@DataField(pos = 9, length = 10)
public String ENDDA;
@DataField(pos = 10, length = 10)
public String OBJPS;
}
@Configuration
@EnableConfigurationProperties
@ConfigurationProperties("test")
@Data
@Section(number = 1)
@FixedLengthRecord()
public class Header implements Serializable {
private static final long serialVersionUID = 1L;
@DataField(pos = 1, length = 5)
private String header1;
@DataField(pos = 2, length = 5)
private String header2;
@DataField(pos = 3, length = 15)
private String header3;
@DataField(pos = 4, length = 60)
private String header4;
@DataField(pos = 5, length = 15)
private String header5;
@DataField(pos = 6, length = 30)
private String header6;
@DataField(pos = 7, length = 30)
private String header7;
@DataField(pos = 8, length = 8, pattern = "YYYYMMDD")
private String header8;
@DataField(pos = 9, length = 6)
private String header9;
@DataField(pos = 10, length = 1)
private String header10;
@DataField(pos = 11, length = 2)
private String header11;
@DataField(pos = 12, length = 10)
private String header12;
@DataField(pos = 13, length = 10)
private String header13;
@DataField(pos = 14, length = 10)
private String header14;
}
@Section(number = 3)
@FixedLengthRecord
public class Trailer implements Serializable {
private static final long serialVersionUID = 1L;
@DataField(pos = 1, length = 7)
private String trailer;
@DataField(pos = 2, length = 2)
private int count;
public String getTrailer() {
return trailer;
}
public void setTrailer(String trailer) {
this.trailer = trailer;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
答案1
得分: 1
I found the answer.
This solution had fixed many issues that I had in various stage.
Issue 1) 使用 BindyFixedLengthDataFormat 向平面文件添加动态头部和尾部。正如名称所示,它是固定长度的。我必须分配最大长度,并在生成正文后修剪空白字符。(我可能仍需要使用不同的类或方式来修剪空白字符)。
Issue 2) 我有将管道分隔符替换为 |" 的要求。
Issue 3) 不使用 jetty 暴露硬编码的端点 URL,而是使用 rest 配置,这样主机名将不再是硬编码的,并且您可以部署到任何环境。
@Component
public class EmployeePackageRoute extends RouteBuilder {
@Autowired
private Header header;
private Trailer footer;
private String file_name;
@SuppressWarnings("deprecation")
@Override
public final void configure() {
System.out.println("fetching employee details from employee api");
final SimpleDateFormat TARGET_DATE_FORMAT = new SimpleDateFormat("YYYYMMDDHHMMSS");
String date = TARGET_DATE_FORMAT.format(new Date());
String year = date.substring(0, 8);
String hr = date.substring(9, 13);
try {
restConfiguration().component("jetty").port(8000).bindingMode(RestBindingMode.json);
rest("/api/test/getTestResponse")
.get().consumes(MediaType.APPLICATION_JSON_VALUE).route().setBody().constant("return test response");
rest("/api/bcr/recurringPaymentsDeduct")
.post().consumes(MediaType.APPLICATION_JSON_VALUE).type(RecurringPaymentResults.class).outType(ResponseEntity.class).route()
.process(
ex -> {
RecurringPaymentResults result = ex.getIn().getBody(RecurringPaymentResults.class);
List<RecurringPaymentsDeduct> employee = result.getResults();
file_name = Constants.FILE_NUMBER_DEV+"_"+date+"_"+Constants.AUMBCR_HRMD+result.getSequenceNumber()+"_"+Constants.DUT8G2I+".SAP";
header.setHeader7(Constants.FILE_NUMBER_DEV+"_"+date+"_"+Constants.AUMBCR_HRMD+result.getSequenceNumber()+"_"+Constants.DUT8G2I+".SAP");
header.setHeader8(year);
header.setHeader9(hr);
header.setHeader10(Constants.ENVIRONMENT);
footer = new Footer("Footer",(employee.size()+2));
ex.getOut().setBody(employee);
})
.to("seda:recurringPaymentsFeed");
final DataFormat recurringPaymentsBindy = new BindyFixedLengthDataFormat(RecurringPaymentsDeduct.class);
from("seda:recurringPaymentsFeed")
.startupOrder(2)
.log("add footer to the file")
.process(
ex -> {
Map<String, Object> headerObjMap = new HashMap<String,Object>();
headerObjMap.put(Header.class.getName(), header);
System.out.println(" *** file_name 1 - "+file_name);
Map<String, Object> footerObjMap = new HashMap<String,Object>();
footerObjMap.put(Footer.class.getName(), footer);
ex.getOut().setHeader(BindyFixedLengthDataFormat.CAMEL_BINDY_FIXED_LENGTH_HEADER, headerObjMap);
ex.getOut().setBody(ex.getIn().getBody());
ex.getOut().setHeader(BindyFixedLengthDataFormat.CAMEL_BINDY_FIXED_LENGTH_FOOTER, footerObjMap);
})
.marshal(recurringPaymentsBindy)
.convertBodyTo(byte[].class, "iso-8859-1")
.setBody(body().regexReplaceAll("\\|", "\\|""))
.log("csv processed")
.to("file://app/bcr-files?fileName=recurringPaymentsDeduct.SAP")
.end();
} catch(Exception e) {
System.out.println("Error occurred while processing employee data: "+e.getMessage());
e.printStackTrace();
}
}
}
@Data
@Section(number = 2)
@FixedLengthRecord(header = Header.class, footer = Trailer.class)
public class RecurringPaymentsDeduct implements Serializable {
private static final long serialVersionUID = 1L;
@DataField(pos = 1, length = 10, delimiter = "|", trim = true)
public String RECTY;
@DataField(pos = 2, length = 10, delimiter = "|", trim = true)
public String CLIID;
// Other fields...
}
@Configuration
@EnableConfigurationProperties
@ConfigurationProperties("adp")
@Data
@Section(number = 1)
@FixedLengthRecord()
public class Header implements Serializable {
private static final long serialVersionUID = 1L;
@DataField(pos = 1, length = 5, delimiter = "|", trim = true)
private String header1;
// Other fields...
}
@Data
@Section(number = 3)
@FixedLengthRecord()
public class Footer implements Serializable {
private static final long serialVersionUID = 1L;
@DataField(pos = 1, length = 7, delimiter = "|", trim = true)
private String trailer;
// Other fields...
}
英文:
I found the answer.
This solution had fixed many issues that I had in various stage.
Issue 1) Added dynamic header and footer to the flat file using BindyFixedLengthDataFormat. As the name suggests it's fixed length. I had to assign maximum length and trim the whitespaces after generating the body. (I still may need to use different class or way to trim the whitespaces).
Issue 2) I had the requirement to replace the pipe delimiter with |".
Issue 3) Instead of using jetty to expose the end point url which will be hard coded I have used rest configuration so that hostname will no longer be hard coded and you can deploy to any environment.
@Component
public class EmployeePackageRoute extends RouteBuilder {
@Autowired
private Header header;
private Trailer footer;
private String file_name;
@SuppressWarnings("deprecation")
@Override
public final void configure() {
System.out.println("fetching employee details from employee api");
final SimpleDateFormat TARGET_DATE_FORMAT = new SimpleDateFormat("YYYYMMDDHHMMSS");
String date = TARGET_DATE_FORMAT.format(new Date());
String year = date.substring(0, 8);
String hr = date.substring(9, 13);
try {
restConfiguration().component("jetty").port(8000).bindingMode(RestBindingMode.json);
rest("/api/test/getTestResponse")
.get().consumes(MediaType.APPLICATION_JSON_VALUE).route().setBody().constant("return test response");
rest("/api/bcr/recurringPaymentsDeduct")
.post().consumes(MediaType.APPLICATION_JSON_VALUE).type(RecurringPaymentResults.class).outType(ResponseEntity.class).route()
.process(
ex -> {
RecurringPaymentResults result = ex.getIn().getBody(RecurringPaymentResults.class);
List<RecurringPaymentsDeduct> employee = result.getResults();
file_name = Constants.FILE_NUMBER_DEV+"_"+date+"_"+Constants.AUMBCR_HRMD+result.getSequenceNumber()+"_"+Constants.DUT8G2I+".SAP";
header.setHeader7(Constants.FILE_NUMBER_DEV+"_"+date+"_"+Constants.AUMBCR_HRMD+result.getSequenceNumber()+"_"+Constants.DUT8G2I+".SAP");
header.setHeader8(year);
header.setHeader9(hr);
header.setHeader10(Constants.ENVIRONMENT);
footer = new Footer("Footer",(employee.size()+2));
ex.getOut().setBody(employee);
})
.to("seda:recurringPaymentsFeed");
final DataFormat recurringPaymentsBindy = new BindyFixedLengthDataFormat(RecurringPaymentsDeduct.class);
from("seda:recurringPaymentsFeed")
.startupOrder(2)
.log("add footer to the file")
.process(
ex -> {
Map<String, Object> headerObjMap = new HashMap<String,Object>();
headerObjMap.put(Header.class.getName(), header);
System.out.println(" *** file_name 1 - "+file_name);
Map<String, Object> footerObjMap = new HashMap<String,Object>();
footerObjMap.put(Footer.class.getName(), footer);
ex.getOut().setHeader(BindyFixedLengthDataFormat.CAMEL_BINDY_FIXED_LENGTH_HEADER, headerObjMap);
ex.getOut().setBody(ex.getIn().getBody());
ex.getOut().setHeader(BindyFixedLengthDataFormat.CAMEL_BINDY_FIXED_LENGTH_FOOTER, footerObjMap);
})
.marshal(recurringPaymentsBindy)
.convertBodyTo(byte[].class, "iso-8859-1")
.setBody(body().regexReplaceAll("\\|", "\\|\""))
.log("csv processed")
.to("file://app/bcr-files?fileName=recurringPaymentsDeduct.SAP")
.end();
} catch(Exception e) {
System.out.println("Error occurred while processing employee data: "+e.getMessage());
e.printStackTrace();
}
}
}
@Data
@Section(number = 2)
@FixedLengthRecord(header = Header.class, footer = Trailer.class)
public class RecurringPaymentsDeduct implements Serializable {
private static final long serialVersionUID = 1L;
@DataField(pos = 1, length = 10, delimiter = "|", trim = true)
public String RECTY;
@DataField(pos = 2, length = 10, delimiter = "|", trim = true)
public String CLIID;
@DataField(pos = 3, length = 10, delimiter = "|", trim = true)
public String INTCA;
@DataField(pos = 4, length = 10, delimiter = "|", trim = true)
public String ORDNO;
@DataField(pos = 5, length = 10, delimiter = "|", trim = true)
public String IOPER;
@DataField(pos = 6, length = 10, delimiter = "|", trim = true)
public String INFTY;
@DataField(pos = 7, length = 10, delimiter = "|", trim = true)
public String SUBTY;
@DataField(pos = 8, length = 10, delimiter = "|", trim = true)
public String BEGDA;
@DataField(pos = 9, length = 10, delimiter = "|", trim = true)
public String ENDDA;
@DataField(pos = 10, length = 10, trim = true)
public String OBJPS;
}
@Configuration
@EnableConfigurationProperties
@ConfigurationProperties("adp")
@Data
@Section(number = 1)
@FixedLengthRecord()
public class Header implements Serializable {
private static final long serialVersionUID = 1L;
@DataField(pos = 1, length = 5, delimiter = "|", trim = true)
private String header1;
@DataField(pos = 2, length = 5, delimiter = "|", trim = true)
private String header2;
@DataField(pos = 3, length = 15, delimiter = "|", trim = true)
private String header3;
@DataField(pos = 4, length = 60, delimiter = "|", trim = true)
private String header4;
@DataField(pos = 5, length = 15, delimiter = "|", trim = true)
private String header5;
@DataField(pos = 6, length = 30, delimiter = "|", trim = true)
private String header6;
@DataField(pos = 7, length = 30, delimiter = "|", trim = true)
private String header7;
@DataField(pos = 8, length = 8, pattern = "YYYYMMDD", delimiter = "|", trim = true)
private String header8;
@DataField(pos = 9, length = 6, delimiter = "|", trim = true)
private String header9;
@DataField(pos = 10, length = 1, delimiter = "|", trim = true)
private String header10;
@DataField(pos = 11, length = 2, delimiter = "|", trim = true)
private String header11;
@DataField(pos = 12, length = 10, delimiter = "|", trim = true)
private String header12;
@DataField(pos = 13, length = 10, delimiter = "|", trim = true)
private String header13;
@DataField(pos = 14, length = 10, align = "L", trim = true)
private String header14;
}
@Data
@Section(number = 3)
@FixedLengthRecord()
public class Footer implements Serializable {
private static final long serialVersionUID = 1L;
@DataField(pos = 1, length = 7, delimiter = "|", trim = true)
private String trailer;
@DataField(pos = 2, length = 5, align = "L", trim = true)
private int count;
public Footer() {
}
public Footer(String trailer, int count) {
this.trailer = trailer;
this.count = count;
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论