2 * Copyright 2014 Hanei Management Co.,Ltd.
\r
4 * This file is part of Jaxcel
\r
6 * Jaxcel is free software: you can redistribute it and/or modify
\r
7 * it under the terms of the GNU Lesser General Public License as published by
\r
8 * the Free Software Foundation, either version 3 of the License, or
\r
9 * (at your option) any later version.
\r
11 * Jaxcel is distributed in the hope that it will be useful,
\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 * GNU Lesser General Public License for more details.
\r
16 * You should have received a copy of the GNU Lesser General Public License
\r
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
\r
19 package org.hanei.jaxcel.report;
\r
21 import java.io.BufferedInputStream;
\r
22 import java.io.File;
\r
23 import java.io.FileInputStream;
\r
24 import java.io.FileOutputStream;
\r
25 import java.io.IOException;
\r
26 import java.io.InputStream;
\r
27 import java.io.OutputStream;
\r
28 import java.util.Map;
\r
31 import org.apache.commons.collections.ExtendedProperties;
\r
32 import org.apache.poi.hssf.usermodel.HSSFSheet;
\r
33 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
\r
34 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
\r
35 import org.apache.poi.openxml4j.opc.OPCPackage;
\r
36 import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
\r
37 import org.apache.poi.poifs.filesystem.OfficeXmlFileException;
\r
38 import org.apache.poi.ss.usermodel.Cell;
\r
39 import org.apache.poi.ss.usermodel.Row;
\r
40 import org.apache.poi.ss.usermodel.Sheet;
\r
41 import org.apache.poi.ss.usermodel.Workbook;
\r
42 import org.apache.poi.ss.usermodel.WorkbookFactory;
\r
43 import org.apache.poi.ss.util.CellReference;
\r
44 import org.apache.poi.xssf.usermodel.XSSFChartSheet;
\r
45 import org.apache.poi.xssf.usermodel.XSSFDialogsheet;
\r
46 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
\r
47 import org.hanei.jaxcel.exception.JaxcelInputException;
\r
48 import org.hanei.jaxcel.exception.JaxcelOutputException;
\r
49 import org.hanei.jaxcel.parser.CellParser;
\r
50 import org.slf4j.LoggerFactory;
\r
51 import org.slf4j.Logger;
\r
55 * テンプレートのExcelファイルにデータを挿入することでExcel帳票を生成する。
\r
57 * <p>テンプレートの書式については、AbstractTLParserのサブクラスのJavadocを参照</p>
\r
60 * @author Noboru Saito
\r
62 public class ReportMaker {
\r
64 private static final Logger log = LoggerFactory.getLogger(ReportMaker.class);
\r
68 * Excel 2003 形式(.xls)
\r
70 private NPOIFSFileSystem npoifs = null;
\r
74 * Excel 2007 形式(.xlsx, .xlsm)
\r
76 private OPCPackage pkg = null;
\r
81 private ELManager elMgr = null;
\r
86 private JaxcelContext context = null;
\r
91 private CellParser cellParser = null;
\r
96 private File tempFile = null;
\r
101 private ExtendedProperties customProperties = null;
\r
106 public ReportMaker() {}
\r
109 * カスタムパーサ用のプロパティファイルを指定
\r
111 * @param properties カスタムパーサ用プロパティファイル
\r
113 public ReportMaker(File properties) {
\r
114 setCustomProperties(properties);
\r
118 * カスタムパーサ用のプロパティファイルを指定
\r
120 * @param properties カスタムパーサ用プロパティファイル
\r
122 public ReportMaker(InputStream properties) {
\r
123 setCustomProperties(properties);
\r
127 * カスタムパーサ用のプロパティファイルセッター
\r
129 * @param properties カスタムパーサ用プロパティファイル
\r
131 public void setCustomProperties(File properties) {
\r
132 if(properties != null) {
\r
133 try(InputStream stream = new FileInputStream(properties)) {
\r
134 setCustomProperties(stream);
\r
136 catch(Exception e) {}
\r
141 * カスタムパーサ用のプロパティファイルセッター
\r
143 * @param properties カスタムパーサ用プロパティファイル
\r
145 public void setCustomProperties(InputStream properties) {
\r
147 if(properties != null) {
\r
148 customProperties = new ExtendedProperties();
\r
149 customProperties.load(properties);
\r
152 catch(Exception e) {}
\r
156 * 入力ストリームのExcelテンプレートファイルにデータを挿入することでExcel帳票を生成、Workbookオブジェクトを返却する。<br>
\r
157 * 返却されたWorkbookオブジェクトはPOIを使用し、加工・出力が可能。<br>
\r
158 * 入力ストリームは別途クローズが必要。<br>
\r
159 * Workbookオブジェクトの使用終了後はclose()メソッドでExcelテンプレートファイルのクローズが必要。
\r
161 * @param template Excelテンプレートファイル入力ストリーム
\r
162 * @param parameter テンプレートに挿入するデータ
\r
164 * @return Workbookオブジェクト
\r
166 * @throws JaxcelInputException 入力例外発生時
\r
168 public Workbook makeReport(InputStream template, Map<String, Object> parameter) {
\r
169 log.trace("makeReport start");
\r
172 if(template == null) {
\r
173 log.error("template is null");
\r
174 throw new JaxcelInputException("template is null");
\r
178 if (tempFile != null && tempFile.exists()) {
\r
180 log.debug("template file delete: {}", tempFile.getPath());
\r
183 tempFile = createTempFile(template);
\r
186 Workbook book = makeReport(tempFile, parameter);
\r
188 log.trace("makeReport end");
\r
193 * 入力ストリームのExcelテンプレートファイルにデータを挿入することでExcel帳票を生成、出力ストリームにExcel帳票を出力する。<br>
\r
194 * 入出力ストリームは別途クローズが必要。
\r
196 * @param template Excelテンプレートファイル入力ストリーム
\r
197 * @param parameter テンプレートに挿入するデータ
\r
198 * @param output Excel帳票出力ストリーム
\r
200 * @throws JaxcelInputException 入力例外発生時
\r
201 * @throws JaxcelOutputException 出力例外発生時
\r
203 public void makeReport(InputStream template, Map<String, Object> parameter, OutputStream output) {
\r
204 log.trace("makeReport start");
\r
207 Workbook book = makeReport(template, parameter);
\r
210 outputReport(book, output);
\r
215 log.trace("makeReport end");
\r
219 * 入力ストリームのExcelテンプレートファイルにデータを挿入することでExcel帳票を生成、Excel帳票ファイルを出力する。<br>
\r
220 * 入力ストリームは別途クローズが必要。
\r
222 * @param template Excelテンプレートファイル入力ストリーム
\r
223 * @param parameter テンプレートに挿入するデータ
\r
224 * @param output Excel帳票出力ファイル
\r
226 * @throws JaxcelInputException 入力例外発生時
\r
227 * @throws JaxcelOutputException 出力例外発生時
\r
229 public void makeReport(InputStream template, Map<String, Object> parameter, File output) {
\r
230 log.trace("makeReport start");
\r
233 Workbook book = makeReport(template, parameter);
\r
236 FileOutputStream _output;
\r
238 _output = new FileOutputStream(output);
\r
240 catch(Exception e) {
\r
241 log.error("output file open error: {}", e.getMessage(), e);
\r
242 throw new JaxcelOutputException("output file open error");
\r
246 outputReport(book, _output);
\r
249 } catch (IOException e) {
\r
250 log.error("output file close error: {}", e.getMessage(), e);
\r
251 throw new JaxcelOutputException("output file close error");
\r
257 log.trace("makeReport end");
\r
261 * Excelテンプレートファイルにデータを挿入することでExcel帳票を生成、Workbookオブジェクトを返却する。<br>
\r
262 * 返却されたWorkbookオブジェクトはPOIを使用し、加工・出力が可能。<br>
\r
263 * Workbookオブジェクトの使用終了後はclose()メソッドでExcelテンプレートファイルのクローズが必要。
\r
265 * @param template Excelテンプレートファイル
\r
266 * @param parameter テンプレートに挿入するデータ
\r
268 * @return Workbookオブジェクト
\r
270 * @throws JaxcelInputException 入力例外発生時
\r
272 public Workbook makeReport(File template, Map<String, Object> parameter) {
\r
273 log.trace("makeReport start");
\r
276 if(template == null) {
\r
277 log.error("template file is null");
\r
278 throw new JaxcelInputException("template file is null");
\r
280 else if(!template.exists()) {
\r
281 log.error("template file does not exist: {}", template.getAbsolutePath());
\r
282 throw new JaxcelInputException("template file does not exist");
\r
284 else if(!template.canRead()) {
\r
285 log.error("template file can not read: {}", template.getAbsolutePath());
\r
286 throw new JaxcelInputException("template file can not read");
\r
288 if(parameter == null) {
\r
289 log.debug("parameter is null");
\r
292 // Excelテンプレートファイルオープン
\r
293 Workbook book = openWorkbook(template);
\r
296 makeReport(book, parameter);
\r
298 log.trace("makeReport end");
\r
303 * Excelテンプレートファイルにデータを挿入することでExcel帳票を生成、出力ストリームにExcel帳票を出力する。<br>
\r
304 * 出力ストリームは別途クローズが必要。
\r
306 * @param template Excelテンプレートファイル
\r
307 * @param parameter テンプレートに挿入するデータ
\r
308 * @param output Excel帳票出力ストリーム
\r
310 * @throws JaxcelInputException 入力例外発生時
\r
311 * @throws JaxcelOutputException 出力例外発生時
\r
313 public void makeReport(File template, Map<String, Object> parameter, OutputStream output) {
\r
314 log.trace("makeReport start");
\r
317 Workbook book = makeReport(template, parameter);
\r
320 outputReport(book, output);
\r
325 log.trace("makeReport end");
\r
329 * Excelテンプレートファイルにデータを挿入することでExcel帳票を生成、Excel帳票ファイルを出力する。<br>
\r
331 * @param template Excelテンプレートファイル
\r
332 * @param parameter テンプレートに挿入するデータ
\r
333 * @param output Excel帳票出力ファイル
\r
335 * @throws JaxcelInputException 入力例外発生時
\r
336 * @throws JaxcelOutputException 出力例外発生時
\r
338 public void makeReport(File template, Map<String, Object> parameter, File output) {
\r
339 log.trace("makeReport start");
\r
342 Workbook book = makeReport(template, parameter);
\r
345 FileOutputStream _output;
\r
347 _output = new FileOutputStream(output);
\r
349 catch(Exception e) {
\r
350 log.error("output file open error: {}", e.getMessage(), e);
\r
351 throw new JaxcelOutputException("output file open error");
\r
355 outputReport(book, _output);
\r
358 } catch (IOException e) {
\r
359 log.error("output file close error: {}", e.getMessage(), e);
\r
360 throw new JaxcelOutputException("output file close error");
\r
366 log.trace("makeReport end");
\r
370 * ExcelテンプレートのWorkbookオブジェクトにデータを挿入することでExcel帳票を生成する。<br>
\r
371 * Workbookオブジェクトの使用終了後はclose()メソッドでExcelテンプレートファイルのクローズが必要。
\r
373 * @param book Workbookオブジェクト
\r
374 * @param parameter テンプレートに挿入するデータ
\r
376 * @throws JaxcelInputException 入力例外発生時
\r
378 public void makeReport(Workbook book, Map<String, Object> parameter) {
\r
379 log.trace("makeReport start");
\r
383 log.error("workbook is null");
\r
384 throw new JaxcelInputException("Workbook is null");
\r
386 else if(!(book instanceof HSSFWorkbook) && !(book instanceof XSSFWorkbook)) {
\r
387 log.error("Workbook is unsupport type: {}", book.getClass().getName());
\r
388 throw new JaxcelInputException("Workbook is unsupported type");
\r
390 if(parameter == null) {
\r
391 log.debug("parameter is null");
\r
395 context = new JaxcelContext();
\r
397 // EL式マネージャ生成。パラメータ設定
\r
398 elMgr = new ELManager();
\r
399 elMgr.setParameter(parameter);
\r
401 // コンテキストにEL式マネージャ設定
\r
402 context.setElManager(elMgr);
\r
404 // コンテキストにカスタムプロパティ設定
\r
405 context.setCustomProperties(customProperties);
\r
410 log.trace("makeReport end");
\r
416 * @param template Excelテンプレートファイル
\r
418 * @throws JaxcelInputException Excelテンプレートファイルオープン失敗時
\r
420 private Workbook openWorkbook(File template) {
\r
421 log.trace("openWorkbook start");
\r
424 Workbook book = null;
\r
428 npoifs = new NPOIFSFileSystem(template);
\r
429 book = WorkbookFactory.create(npoifs);
\r
430 } catch (OfficeXmlFileException | IOException e1) {
\r
433 pkg = OPCPackage.open(template);
\r
434 book = WorkbookFactory.create(pkg);
\r
435 } catch (InvalidFormatException | IOException e2) {
\r
436 log.error("template file open error: [{}]. [{}]", e1.getMessage(), e2.getMessage());
\r
442 throw new JaxcelInputException("template file open error");
\r
445 log.trace("openWorkbook end");
\r
451 * 出力ストリームにワークブックを出力する
\r
454 * @param book Workbookオブジェクト
\r
455 * @param output 出力ストリーム
\r
457 * @throws JaxcelOutputException 出力例外発生時
\r
459 private void outputReport(Workbook book, OutputStream output) {
\r
460 log.trace("outputReport start");
\r
463 book.write(output);
\r
464 } catch (Exception e) {
\r
465 log.error("workbook output error: {}", e.getMessage(), e);
\r
466 throw new JaxcelOutputException("workbook output error");
\r
469 log.trace("outputReport end");
\r
473 * Excelテンプレートファイルのクローズ<br>
\r
474 * テンプレートファイルの変更は保存しません。
\r
476 * @throws JaxcelOutputException 出力例外発生時
\r
478 public void close() {
\r
479 log.trace("close start");
\r
482 if (npoifs != null) {
\r
484 log.debug("template file close.");
\r
489 log.debug("template file close.");
\r
492 if (tempFile != null && tempFile.exists()) {
\r
494 log.debug("template file delete: {}", tempFile.getPath());
\r
497 } catch (IOException e) {
\r
498 log.error("template file close error: {}", e.getMessage(), e);
\r
499 throw new JaxcelOutputException("template file close error");
\r
502 log.trace("close end");
\r
506 * InputStreamから一時ファイルを作成
\r
508 * @return Fileオブジェクト
\r
510 * @throws JaxcelInputException 一時ファイル作成エラー発生時
\r
512 private File createTempFile(InputStream template) {
\r
513 log.trace("createTempFile start");
\r
515 final String PREFIX = "org.hanei.jaxcel_";
\r
516 final String SUFFIX = ".tmp";
\r
517 final int BUF_SIZE = 1024;
\r
519 BufferedInputStream inStream = null;
\r
520 File tmpFile = null;
\r
522 if(template instanceof BufferedInputStream) {
\r
523 inStream = (BufferedInputStream) template;
\r
526 inStream = new BufferedInputStream((InputStream) template);
\r
529 tmpFile = File.createTempFile(PREFIX, SUFFIX);
\r
530 FileOutputStream outStream = new FileOutputStream(tmpFile);
\r
532 byte buf[]=new byte[BUF_SIZE];
\r
534 while((len = inStream.read(buf)) != -1){
\r
535 outStream.write(buf, 0, len);
\r
539 log.debug("createTempFile: {}", tmpFile.getPath());
\r
540 } catch (SecurityException | IOException e) {
\r
541 log.error("template file create error: {}", e.getMessage());
\r
542 throw new JaxcelInputException("template file create error");
\r
545 log.trace("createTempFile end");
\r
551 * @param book Workbookオブジェクト
\r
553 private void makeBook(Workbook book) {
\r
554 log.trace("makeBook start");
\r
557 cellParser = new CellParser(context);
\r
560 log.debug("sheet count: {}", book.getNumberOfSheets());
\r
561 for(int i = 0; i < book.getNumberOfSheets(); i++) {
\r
563 Sheet sheet = book.getSheetAt(i);
\r
564 if(sheet == null) {
\r
565 log.warn("sheet[{}] is null. skip", i);
\r
568 else if((sheet instanceof HSSFSheet && ((HSSFSheet)sheet).getDialog()) || (sheet instanceof XSSFDialogsheet)) {
\r
569 log.debug("sheet[{}] is dialog sheet. skip", i);
\r
572 else if(sheet instanceof XSSFChartSheet) {
\r
573 log.debug("sheet[{}] is chart sheet. skip", i);
\r
577 log.debug("sheet[{}] name: {}", i, sheet.getSheetName());
\r
584 book.setForceFormulaRecalculation(true);
\r
586 log.trace("makeBook end");
\r
591 * @param sheet ワークシートオブジェクト
\r
593 private void makeSheet(Sheet sheet) {
\r
594 log.trace("makeSheet start");
\r
596 Row row; // 行オブジェクト
\r
597 Cell cell; // セルブジェクト
\r
600 context.setCurrentSheet(sheet);
\r
603 int lastRowNum = sheet.getLastRowNum();
\r
604 log.debug("lastRowNum: {}", lastRowNum);
\r
610 for(int rowIdx = 0; rowIdx <= lastRowNum; rowIdx++) {
\r
612 row = sheet.getRow(rowIdx);
\r
616 log.debug("row[{}] is null", (rowIdx + 1));
\r
621 maxColNum = row.getLastCellNum();
\r
622 log.debug("maxColNum: {}", maxColNum);
\r
625 for(int cellIdx = 0; cellIdx < maxColNum; cellIdx++) {
\r
627 cell = row.getCell(cellIdx);
\r
631 log.debug("cell[{}] is null", (new CellReference(rowIdx, cellIdx)).formatAsString());
\r
636 switch (cell.getCellType()) {
\r
638 case Cell.CELL_TYPE_STRING:
\r
639 case Cell.CELL_TYPE_FORMULA:
\r
640 if(log.isDebugEnabled()) {
\r
641 log.debug("cell[{}] type is {}", (new CellReference(cell)).formatAsString(), (cell.getCellType() == Cell.CELL_TYPE_STRING ? "string" : "formula"));
\r
644 cellParser.parse(cell);
\r
646 if(cellParser.isReParseCell()) {
\r
653 log.debug("cell[{}] type is not string or formula", (new CellReference(cell)).formatAsString());
\r
658 if(lastRowNum < sheet.getLastRowNum()) {
\r
659 lastRowNum = sheet.getLastRowNum();
\r
660 log.debug("lastRowNum update: {}", lastRowNum);
\r
663 log.trace("transformSheet end");
\r