我为jExcelApi类创建了一个包装器,可以轻松地将对象列表导出到Excel。为了最小化对象创建,单元格格式创建为静态字段,并在连续的导出调用中重用。但是我的日期格式有问题 - 第一次调用效果很好,但在所有连续导出日期中,单元格都有数字格式而不是日期格式。如果我为日期格式创建一个新对象而不是使用静态字段,一切都很好。是否有任何理由为不同的工作表或工作簿使用相同的格式对象失败? 这是代码,简化了异常处理,省略了其他数据类型,可能还缺少一些导入:
ExcelCellGenerator.java:
import jxl.write.WritableCell;
public interface ExcelCellGenerator<T> {
WritableCell getCell(int col, int row, T arg);
}
ExcelCellGeneratorFactory.java:
import jxl.write.DateFormat;
import jxl.write.DateTime;
import jxl.write.Label;
import jxl.write.NumberFormat;
import jxl.write.NumberFormats;
import jxl.write.WritableCell;
import jxl.write.WritableCellFormat;
import ExcelExporter.DateTimeExtractor;
final class ExcelCellGeneratorFactory {
private ExcelCellGeneratorFactory() {}
private static final WritableCellFormat DATE_FORMAT = new WritableCellFormat ( new DateFormat ("dd MMM yyyy hh:mm:ss")); // reusing this field fails
static public <T> ExcelCellGenerator<T> createDateCellGenerator(final DateTimeExtractor<T> extractor) {
return new ExcelCellGenerator<T>() {
public WritableCell getCell(int col, int row, T arg) {
return new DateTime(col, row, extractor.extract(arg), DATE_FORMAT);
// if there is new WritableCellFormat(new DateFormat(...)) instead of DATE_FORMAT, works fine
}
};
}
}
ExcelExporter.java:
import jxl.Workbook;
import jxl.write.DateFormat;
import jxl.write.DateTime;
import jxl.write.Label;
import jxl.write.NumberFormat;
import jxl.write.WritableCellFormat;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
public class ExcelExporter<T> {
// describe a column in Excel sheet
private static class ColumnDescription<T> {
public ColumnDescription() {}
// column title
private String title;
// a way to generate a value given an object to export
private ExcelCellGenerator<T> generator;
}
// all columns for current sheet
private List<ColumnDescription<T>> columnDescList = new ArrayList<ColumnDescription<T>>();
// export given list to Excel (after configuring exporter using addColumn function
// in row number rowStart starting with column colStart there will be column titles
// and below, in each row, extracted values from each rowList element
public byte[] exportList(int rowStart, int colStart, List<? extends T> rowList) {
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
WritableWorkbook workbook;
try {
workbook = Workbook.createWorkbook(outputStream);
} catch (IOException e) {
e.printStackTrace();
}
final WritableSheet sheet = workbook.createSheet("Arkusz1", 0);
int currRow = rowStart;
try {
int currCol = colStart;
for (ColumnDescription<T> columnDesc : columnDescList) {
final Label label = new Label(currCol, currRow, columnDesc.title);
sheet.addCell(label);
currCol++;
}
currRow++;
for (T object : rowList) {
currCol = colStart;
for (ColumnDescription<T> columnDesc : columnDescList) {
sheet.addCell(columnDesc.generator.getCell(currCol, currRow, object));
currCol++;
}
currRow++;
}
workbook.write();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
workbook.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return outputStream.toByteArray();
}
// configure a Date column
public ExcelExporter<T> addColumn(String title, DateTimeExtractor<T> extractor) {
final ColumnDescription<T> desc = new ColumnDescription<T>();
desc.title = title;
desc.generator = ExcelCellGeneratorFactory.createDateCellGenerator(extractor);
columnDescList.add(desc);
return this;
}
// and test that shows the problem
public static void main(String []args) {
final ExcelExporter<Date> exporter = new ExcelExporter<Date>();
exporter.addColumn("Data", new DateTimeExtractor<Date>() {
public Date extract(Date date) {
return date;
}});
// this file looks OK
FileOutputStream ostream = new FileOutputStream("C:\\tmp\\test1.xls");
try {
ostream.write(exporter.exportList(0, 0, Collections.singletonList(new Date())));
} finally {
ostream.close();
}
// but in this file date is shown in cell with numeric format
final ExcelExporter<Date> exporter2 = new ExcelExporter<Date>();
exporter2.addColumn("Data", new DateTimeExtractor<Date>() {
public Date extract(Date date) {
return date;
}});
ostream = new FileOutputStream("C:\\tmp\\test2.xls");
try {
ostream.write(exporter2.exportList(0, 0, Collections.singletonList(new Date())));
} finally {
ostream.close();
}
}
}
答案 0 :(得分:5)
Telcontar的回答很有帮助,因为它说明了这是一个功能,而不是一个错误,但还不足以提供任何常见问题解答或文档链接。所以我做了一些研究,发现FAQ说:
另外,不要将您的单元格格式声明为静态非常重要。将单元格格式添加到工作表时,会为其分配内部索引编号。
所以答案是 - 格式不能在不同的工作表中重复使用,因为它们不能以这种方式重复使用。
答案 1 :(得分:2)
在jxl格式中,对象无法在多个工作簿中重用。我不知道为什么。
答案 2 :(得分:2)
实际上比这更糟糕。字体和格式隐含地依赖于“工作簿”。哪个工作簿可以解决问题的问题。 在创建后续工作簿后,似乎需要重新分配它们。
final WritableWorkbook workbook = Workbook.createWorkbook(response
.getOutputStream());
// We have to assign this every time we create a new workbook.
bodyText = new WritableCellFormat(WritableWorkbook.ARIAL_10_PT);
...
应该更改API,以便构造函数需要与它们相关的工作簿作为参数,或者构造函数应该是私有的,并且应该从工作簿中获取字体和格式。
WritableCellFormat bodyText = new WritableCellFormat(workbook,
WritableWorkbook.ARIAL_10_PT);
或
WritableCellFormat bodyText = workbook.getCellFormat(
WritableWorkbook.ARIAL_10_PT);
答案 3 :(得分:1)
您可以尝试SmartXLS,可以在任何地方重复使用单元格格式。