001/* 002 * Copyright (c) 2009 The openGion Project. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the specific language 014 * governing permissions and limitations under the License. 015 */ 016package org.opengion.plugin.io; 017 018import java.io.PrintWriter; 019import java.io.File; // 6.2.0.0 (2015/02/27) 020 021import org.opengion.fukurou.model.NativeType; 022import org.opengion.fukurou.util.StringUtil; 023import org.opengion.hayabusa.common.HybsSystemException; 024import org.opengion.hayabusa.db.DBTableModel; 025import org.opengion.hayabusa.db.DBColumn; 026 027import org.opengion.fukurou.model.ExcelModel; 028 029/** 030 * ネイティブEXCELファイルの書き出しクラスです。 031 * 032 * DefaultTableWriter を継承していますので、ラベル、名前、データの出力部のみ 033 * オーバーライドして、MIcrosoft Excelファイルの出力機能を実現しています。 034 * 035 * 出力形式は、openXML形式にも対応しています。 036 * 出力ファイルの拡張子が、.xlsならExcel2003のバイナリ形式、.xlsxならExcel2007の 037 * openXML形式で出力されます。 038 * 039 * useCellStyle = [false/true]; データを書き込んだ範囲に罫線を入れる(true)かどうか(初期値:false) 040 * useAutoCellSize = [false/true]; セルの幅をデータの幅に自動的に合わせる(true)かどうか(初期値:false) 041 * useActiveWorkbook = [false/true]; セルの有効範囲を設定する(true)かどうか(初期値:false) 042 * pageBreakColumn = PBCLM; シートブレイクするキーとなるカラム名を指定します(このカラムの値がシート名になります) 043 * fileBreakColumn = FBCLM; ファイルブレイクするキーとなるカラム名を指定します(このカラムの値がファイル名になります) 044 * 045 * appendモードの場合は、オリジナルが雛形ファイルになります。雛形ファイルを指定した場合は、 046 * 同じファイル名で無ければエラーになります。 047 * 048 * @og.group ファイル出力 049 * 050 * @og.rev 4.3.4.3 (2008/12/22) 一部protected化 051 * @og.rev 4.3.6.7 (2009/05/22) ooxml形式対応 052 * @og.rev 6.0.1.2 (2014/08/08) ロジックの完全書き換え(保証もできない位・・・) 053 * 054 * @version 4.0 055 * @author Kazuhiko Hasegawa 056 * @since JDK5.0, 057 */ 058public class TableWriter_Excel extends TableWriter_Default { 059 /** このプログラムのVERSION文字列を設定します。 {@value} */ 060 private static final String VERSION = "8.5.5.1 (2024/02/29)"; 061 062 private int nRowIndex ; // 6.0.1.2 (2014/08/08) private化 063 private String filename ; // 3.5.4.3 (2004/01/05) 064 /** 6.0.2.0 (2014/09/19) ディレクトリとファイルを分けて管理 */ 065 private String directory ; 066 /** 6.0.2.0 (2014/09/19) ディレクトリとファイルを分けて管理 */ 067 private String fileKey ; 068 /** 3.5.4.3 (2004/01/05) 書き込むSheet名 */ 069 private String sheetName = "Sheet"; 070 private String fontName ; // 3.8.5.3 (2006/08/07) 071 private short fontPoint = -1; // 3.8.5.3 (2006/08/07) 072 private String refFilename ; // 3.5.4.3 (2004/01/05) 073 private String refSheetName ; // 3.5.4.3 (2004/01/05) 074 // 5.1.4.0 (2010/03/01) 行番号情報を、出力する(true)/しない(false)を指定 075 private boolean useNumber = true; 076 /** 6.0.1.2 (2014/08/08) データの書き込み開始位置設定 */ 077 private int skipRowCount ; 078 079 private ExcelModel excel ; // 6.0.2.0 (2014/09/19) 新規作成 080 081 // 6.0.2.0 (2014/09/19) EXCEL関係機能追加 082 /** データを書き込んだ範囲に罫線を入れるかどうかを指定します */ 083 private boolean useCellStyle ; 084 /** セルの幅をデータの幅に自動的に合わせるかどうかを指定します */ 085 private boolean useAutoCellSize ; 086 /** セルの有効範囲を設定するかどうかを指定します */ 087 private boolean useActiveWorkbook ; 088 /** ファイルブレイクするキーとなるカラム名を指定します(このカラムの値がファイル名になります) */ 089 private String fileBreakColumn ; 090 /** シートブレイクするキーとなるカラム名を指定します(このカラムの値がシート名になります) */ 091 private String pageBreakColumn ; 092 /** 6.1.0.0 (2014/12/26) pageBreak,fileBreak 修正 */ 093 private boolean noPageBreak ; // NOPMD 094 095 096 /** Hyperlinkを作成するキーとなるカラム名を指定 */ 097 private String hLinkKeyColumn ; 098 /** Hyperlinkを作成する値となるカラム名を指定 */ 099 private String hLinkValColumn ; 100 101 /** Sheet一覧を先頭Sheetに作成する場合のSheet名を指定します */ 102 private String addTitleSheet ; 103 104 /** シートブレイクするキーとなるカラムNo */ 105 private int pageBreakClmNo = -1; 106 /** ファイルブレイクするキーとなるカラムNo */ 107 private int fileBreakClmNo = -1; 108 /** Hyperlinkを作成するキーとなるカラムNo */ 109 private int hLinkKeyClmNo = -1; 110 /** Hyperlinkを作成する値となるカラムNo */ 111 private int hLinkValClmNo = -1; 112 /** シートブレイクしても、データは続きから出力します。 */ 113 private int tblRow ; 114 115// private boolean[] nvar ; // 6.0.2.0 (2014/09/19) writeData( DBTableModel ,PrintWriter ) で使うカラム情報 8.5.2.0 (2023/07/14) Delete 116 // 8.5.4.2 (2024/01/12) PMD 7.0.0 LinguisticNaming 117// private boolean[] isNums ; // 6.0.2.0 (2014/09/19) writeData( DBTableModel ,PrintWriter ) で使うカラム情報 118 /** 6.0.2.0 (2014/09/19) writeData( DBTableModel ,PrintWriter ) で使うカラム情報 */ 119 private boolean[] numClms ; 120 121 // 5.9.12.1 (2016/09/09) シート上書き設定 122 private boolean sheetOverwrite ; // 5.9.12.1 (2016/09/09) 123 private String[] recalcSheetNames ; // 5.9.12.1 (2016/09/09) 124 125 /** 126 * デフォルトコンストラクター 127 * 128 * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor. 129 */ 130 public TableWriter_Excel() { super(); } // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。 131 132 /** 133 * DBTableModel から 各形式のデータを作成して、PrintWriter に書き出します。 134 * このメソッドは、EXCEL 書き出し時に使用します。 135 * 136 * 雛形シートを使う場合は、雛形シートの後ろに追加していきます。 137 * 最後には、雛形シートとして存在しな部分は、すべて削除します。 138 * 雛形シートを使わない場合は、新規シートに追加していくことになります。 139 * appendモードの場合は、オリジナルが雛形ファイルになります。 140 * 雛形ファイルの指定は、無効になります。 141 * 142 * @og.rev 4.0.0.0 (2006/09/31) 新規追加 143 * @og.rev 5.1.4.0 (2010/03/01) columns 対応、useNumber属性対応 144 * @og.rev 6.0.1.2 (2014/08/08) ロジックの完全書き換え(保証もできない位・・・) 145 * @og.rev 6.0.2.0 (2014/09/19) EXCEL新機能追加 146 * @og.rev 6.1.0.0 (2014/12/26) Excel関係改善 147 * @og.rev 6.2.0.0 (2015/02/27) ファイル引数を、String → File に変更 148 * @og.rev 6.2.2.3 (2015/04/10) 雛形シートにそのままデータを書き込んでいく。シートは削除不要 149 * @og.rev 5.9.12.1 (2016/09/09) sheetOverwrite,recalcSheetNames 150 * @og.rev 6.5.0.0 (2016/09/30) セルの計算式の再計算をさせる recalcSheetNames 属性の追加。(5.9.12.1 (2016/09/09)) 151 * @og.rev 8.5.4.2 (2024/01/12) PMD 7.0.0 LocalVariableNamingConventions 対応 152 * 153 * @see #isExcel() 154 */ 155 @Override 156 public void writeDBTable() { 157 if( ! createDBColumn() ) { return ; } // 親クラスを改造。2回実行されない。 158 159 useNumber = isUseNumber(); 160 161 // 3.5.6.0 (2004/06/18) 移動 162 if( filename == null ) { 163 final String errMsg = "ファイルが指定されていません。"; 164 throw new HybsSystemException( errMsg ); 165 } 166 167 // appendモードの場合は、オリジナルが雛形ファイルになります。 168 // 雛形ファイルの指定は、無効になります。 169 if( isAppend() ) { 170 // 互換性のため、雛形ファイルが出力ファイルと同じでない場合はエラーとします。 171 if( refFilename != null && !filename.equalsIgnoreCase( refFilename ) ) { 172 final String errMsg = "追加(appendモード)の時、雛形ファイルの指定は無効です。" + CR 173 + " filename=[" + filename + "] , refFilename=[" + refFilename + "]" + CR ; 174 throw new HybsSystemException( errMsg ); 175 } 176 177 refFilename = filename ; 178 } 179 180 // 雛形があれば、雛形ファイルを読み込みます。なければ、オリジナルのファイルを読み込みます。 181 // 6.3.9.1 (2015/11/27) Found 'DD'-anomaly for variable(PMD) 182 final boolean isRefFile = refFilename != null && refFilename.length() > 0; 183 final String nameUse = isRefFile ? refFilename : filename ; // 6.3.9.1 (2015/11/27) 184 185 initWriteData(); // 6.0.2.0 (2014/09/19) カラム関連の初期化 186 187 final boolean isDebug = isDebug(); // 6.1.0.0 (2014/12/26) デバッグ情報 188 189 // 6.1.0.0 (2014/12/26) useRenderer 時に使用。できるだけループ内処理を避ける。 190 final DBColumn fileBreakClm = fileBreakClmNo >= 0 && isUseRenderer() ? dbColumn[fileBreakClmNo] : null ; 191 final DBColumn pageBreakClm = pageBreakClmNo >= 0 && isUseRenderer() ? dbColumn[pageBreakClmNo] : null ; 192 193 // ファイルブレイクの初期値を求めます。(fileKey は、setFilename(String,String) で、初期値セット済み) 194 if( fileBreakClmNo >= 0 ) { fileKey = table.getValue( tblRow,fileBreakClmNo ); } 195 // 処理のループを抜ける条件は、すべてのデータを書出し終わった場合。fileKey = null をセットします。 196 while( fileKey != null ) { 197 // fileKey は、super.writeDBTable( null ) で、writeData( DBTableModel ,PrintWriter )で、再セットされる。 198 // 8.5.4.2 (2024/01/12) PMD 7.0.0 LocalVariableNamingConventions 対応 199// final String fileKey_ren = fileBreakClm == null ? fileKey : fileBreakClm.getWriteValue( fileKey ); 200 final String renFileKey = fileBreakClm == null ? fileKey : fileBreakClm.getWriteValue( fileKey ); 201 202 // ExcelModelで作成。新規の場合は、nameUseの拡張子(.xlsx/.xls)に応じて、タイプが変わります。 203 excel = new ExcelModel( new File( nameUse ) , isRefFile ); // 6.2.0.0 (2015/02/27) 204 205 // 雛形シートを使わない場合のみ、フォント設定を行う。 206 if( !isRefFile ) { excel.setFont( fontName,fontPoint ); } 207 // 6.0.2.0 (2014/09/19) 新機能追加 208 if( useCellStyle ) { excel.setCellStyle(); } 209 excel.useAutoCellSize( useAutoCellSize ); 210 excel.setRecalcSheetName( recalcSheetNames ); // 6.5.0.0 (2016/09/30) セルの計算式の再計算をさせる recalcSheetNames 属性の追加。 211 excel.setAddTitleSheet( addTitleSheet ); 212 213 if( isRefFile ) { excel.setRefSheetName( refSheetName ); } 214 215 // シートブレイクする場合は、sheetName名をあらかじめ取得する。 216 if( pageBreakClmNo >= 0 ) { sheetName = table.getValue( tblRow,pageBreakClmNo ); } 217 noPageBreak = true ; // ファイルブレイク、シートブレイクの場合は、false をセット 218 while( noPageBreak ) { 219 // 6.1.0.0 (2014/12/26) デバッグ情報 220 if( isDebug ) { System.out.println( " file=" + fileKey + " , sheet=" + sheetName + " , row=" + tblRow ) ; } 221 222 // シート名のセット。重複チェックと新しいシート名の作成処理を行う。 223 // 8.5.4.2 (2024/01/12) PMD 7.0.0 LocalVariableNamingConventions 対応 224// final String sheetName_ren = pageBreakClm == null ? sheetName : pageBreakClm.getWriteValue( sheetName ); 225 final String renSheetName = pageBreakClm == null ? sheetName : pageBreakClm.getWriteValue( sheetName ); 226 // excel.createSheet( sheetName_ren ); 227// excel.createSheet( sheetName_ren , sheetOverwrite ); 228 excel.createSheet( renSheetName , sheetOverwrite ); 229 230 nRowIndex = skipRowCount; // 6.0.1.2 (2014/08/08) 開始行の指定 231 232 // この super.writeDBTable(null) 内から、各種実態のメソッドが呼ばれる。 233 // シートブレイク,ファイルブレイク は、writeData( DBTableModel ,PrintWriter ) で処理される。 234 // シートブレイクすると、新しい sheetName がセットされ、noPageBreak=false がセットされる。 235 // ファイルブレイクすると、新しい fileKey がセットされ、noPageBreak=false がセットされる。 236 super.writeDBTable( null ); 237 238 // 指定以降の余計な行を削除 239 excel.removeRow( nRowIndex ); 240 } 241 242 // 6.0.2.0 (2014/09/19) activeWorkbook は、全シートに対して、最後に適用する。 243 if( useActiveWorkbook ) { excel.activeWorkbook( false ); } // false は Cellの末尾削除は行わない。 244 245 // メモリ中のデータをファイルに書き込む 246// excel.saveFile( new File( directory,fileKey_ren ) ); // 6.2.0.0 (2015/02/27) 247 excel.saveFile( new File( directory,renFileKey ) ); // 6.2.0.0 (2015/02/27) 248 } 249 } 250 251 /** 252 * PrintWriter に DBTableModelのヘッダー情報を書き込みます。 253 * ここでは、ラベル情報を同じデータを出力します。 254 * 255 * @og.rev 7.2.6.1 (2020/07/17) H:Header(ヘッダー)属性追加。 256 * 257 * @param table DBTableModelオブジェクト 258 * @param writer PrintWriterオブジェクト 259 */ 260 @Override 261 protected void writeLabel2( final DBTableModel table,final PrintWriter writer ) { 262 writeLabel( table,writer ); 263 } 264 265 /** 266 * PrintWriter に DBTableModelのラベル情報を書き込みます。 267 * 第一カラム目は、ラベル情報を示す "#Label" を書き込みます。 268 * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。 269 * 270 * @og.rev 5.1.4.0 (2010/03/01) useNumber属性対応 271 * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加 272 * @og.rev 6.2.3.0 (2015/05/01) writeKeyLabel 属性を追加 273 * @og.rev 6.2.4.2 (2015/05/29) StringUtil#tagCut(String) をラベルに適用します。 274 * 275 * @param table DBTableModelオブジェクト 276 * @param writer PrintWriterオブジェクト 277 */ 278 @Override 279 protected void writeLabel( final DBTableModel table,final PrintWriter writer ) { 280 short nColIndex = 0; 281 excel.createRow( nRowIndex++ ); 282 if( useNumber ) { headerCellValue( "Label",nColIndex++ ); } 283 284 for( int i=0; i<numberOfColumns; i++ ) { 285 final int clm = clmNo[i]; 286 if( clm < 0 ) { // 6.0.1.2 (2014/08/08) カラム飛ばし 287 nColIndex++; 288 continue; 289 } 290 291 final String val = StringUtil.tagCut( dbColumn[clm].getLabel() ); // 6.2.4.2 (2015/05/29) 292 headerCellValue( val,nColIndex++ ); 293 294 // 6.2.3.0 (2015/05/01) keyLabelは、後ろのカラムのラベルを付けません。 295 if( isKeyLbl[i] ) { 296 headerCellValue( "",nColIndex++ ); 297 } 298 } 299 300 // 余計なセルを削除 301 excel.removeCell( nColIndex ); 302 } 303 304 /** 305 * PrintWriter に DBTableModelの項目名情報を書き込みます。 306 * 第一カラム目は、項目名情報を示す "#Name" を書き込みます。 307 * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。 308 * 309 * @og.rev 3.1.1.0 (2003/03/28) 同期メソッド(synchronized付き)を非同期に変更する。 310 * @og.rev 5.1.4.0 (2010/03/01) useNumber属性対応 311 * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加 312 * @og.rev 6.2.3.0 (2015/05/01) writeKeyLabel 属性を追加 313 * 314 * @param table DBTableModelオブジェクト 315 * @param writer PrintWriterオブジェクト 316 */ 317 @Override 318 protected void writeName( final DBTableModel table,final PrintWriter writer ) { 319 short nColIndex = 0; 320 excel.createRow( nRowIndex++ ); 321 if( useNumber ) { headerCellValue( "Name",nColIndex++ ); } 322 323 for( int i=0; i<numberOfColumns; i++ ) { 324 final int clm = clmNo[i]; 325 if( clm < 0 ) { // 6.0.1.2 (2014/08/08) カラム飛ばし 326 nColIndex++; 327 continue; 328 } 329 330 final String name = table.getColumnName( clm ); 331 headerCellValue( name,nColIndex++ ); 332 333 // 6.2.3.0 (2015/05/01) keyLabelは、後ろのカラムの項目名を付けません。 334 if( isKeyLbl[i] ) { 335 headerCellValue( "",nColIndex++ ); 336 } 337 } 338 339 // 余計なセルを削除 340 excel.removeCell( nColIndex ); 341 } 342 343 /** 344 * PrintWriter に DBTableModelのサイズ情報を書き込みます。 345 * 第一カラム目は、サイズ情報を示す "#Size" を書き込みます。 346 * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。 347 * 348 * @og.rev 3.5.5.5 (2004/04/23) DBColumn の size と maxlength の 意味を変更 349 * @og.rev 5.1.4.0 (2010/03/01) useNumber属性対応 350 * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加 351 * @og.rev 6.2.3.0 (2015/05/01) writeKeyLabel 属性を追加 352 * 353 * @param table DBTableModelオブジェクト 354 * @param writer PrintWriterオブジェクト 355 */ 356 @Override 357 protected void writeSize( final DBTableModel table,final PrintWriter writer ) { 358 short nColIndex = 0; 359 excel.createRow( nRowIndex++ ); 360 if( useNumber ) { headerCellValue( "Size",nColIndex++ ); } 361 362 for( int i=0; i<numberOfColumns; i++ ) { 363 final int clm = clmNo[i]; 364 if( clm < 0 ) { // 6.0.1.2 (2014/08/08) カラム飛ばし 365 nColIndex++; 366 continue; 367 } 368 369 // 4.0.0 (2005/01/31) メソッド名変更 370 final String val = String.valueOf( dbColumn[clm].getTotalSize() ); 371 headerCellValue( val,nColIndex++ ); 372 373 // 6.2.3.0 (2015/05/01) keyLabelは、後ろのカラムのサイズを付けません。 374 if( isKeyLbl[i] ) { 375 headerCellValue( "",nColIndex++ ); 376 } 377 } 378 379 // 余計なセルを削除 380 excel.removeCell( nColIndex ); 381 } 382 383 /** 384 * PrintWriter に DBTableModelのクラス名情報を書き込みます。 385 * 第一カラム目は、サイズ情報を示す "#Class" を書き込みます。 386 * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。 387 * 388 * @og.rev 5.1.4.0 (2010/03/01) useNumber属性対応 389 * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加 390 * @og.rev 6.2.3.0 (2015/05/01) writeKeyLabel 属性を追加 391 * 392 * @param table DBTableModelオブジェクト 393 * @param writer PrintWriterオブジェクト 394 */ 395 @Override 396 protected void writeClass( final DBTableModel table,final PrintWriter writer ) { 397 short nColIndex = 0; 398 excel.createRow( nRowIndex++ ); 399 if( useNumber ) { headerCellValue( "Class",nColIndex++ ); } 400 401 for( int i=0; i<numberOfColumns; i++ ) { 402 final int clm = clmNo[i]; 403 if( clm < 0 ) { // 6.0.1.2 (2014/08/08) カラム飛ばし 404 nColIndex++; 405 continue; 406 } 407 408 final String val = dbColumn[clm].getClassName(); 409 headerCellValue( val,nColIndex++ ); 410 411 // 6.2.3.0 (2015/05/01) keyLabelは、後ろのカラムのクラス名を付けません。 412 if( isKeyLbl[i] ) { 413 headerCellValue( "",nColIndex++ ); 414 } 415 } 416 417 // 余計なセルを削除 418 excel.removeCell( nColIndex ); 419 } 420 421 /** 422 * PrintWriter に セパレーターを書き込みます。 423 * 第一カラム目は、サイズ情報を示す "#----" を書き込みます。 424 * この行は、出力形式に無関係に、TableWriter.TAB_SEPARATOR で区切られます。 425 * 426 * @og.rev 5.1.4.0 (2010/03/01) useNumber属性対応 427 * @og.rev 6.2.3.0 (2015/05/01) writeKeyLabel 属性を追加 428 * 429 * @param table DBTableModelオブジェクト 430 * @param writer PrintWriterオブジェクト 431 */ 432 @Override 433 protected void writeSeparator( final DBTableModel table,final PrintWriter writer ) { 434 final String SEP = "----" ; 435 436 short nColIndex = 0; 437 excel.createRow( nRowIndex++ ); 438 if( useNumber ) { headerCellValue( SEP,nColIndex++ ); } 439 440 for( int i=0; i<numberOfColumns; i++ ) { 441 final int clm = clmNo[i]; 442 if( clm < 0 ) { // 6.0.1.2 (2014/08/08) カラム飛ばし 443 nColIndex++; 444 continue; 445 } 446 headerCellValue( SEP,nColIndex++ ); 447 448 // 6.2.3.0 (2015/05/01) keyLabelは、後ろのカラムのセパレーターを書き込みます。 449 if( isKeyLbl[i] ) { 450 headerCellValue( SEP,nColIndex++ ); 451 } 452 } 453 454 // 余計なセルを削除 455 excel.removeCell( nColIndex ); 456 } 457 458 /** 459 * ExcelModel#setCellValue(String.int) の第一カラムの場合に、コメントの # を追加する簡易メソッドです。 460 * 461 * colNo == 0 の場合だけ、引数の val に、"#" を追加します。 462 * これは、openGion特有のコメント行を意味するため、ヘッダーレコードにのみ適用します。 463 * 464 * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加 465 * 466 * @param val 設定文字列 467 * @param colNo 行番号 468 */ 469 private void headerCellValue( final String val,final int colNo ) { 470 if( colNo == 0 ) { 471 excel.setCellValue( "#" + val,colNo ); 472 } 473 else { 474 excel.setCellValue( val,colNo ); 475 } 476 } 477 478 /** 479 * writeData( DBTableModel ,PrintWriter ) の呼び出し前に、一度だけ実行すればよい処理をまとめました。 480 * 481 * 通常のTableWriterは、1回の DBTableModel の読み込みで、1ファイルだけ出力します。 482 * そのため、writeData( DBTableModel ,PrintWriter ) の呼び出し処理の初めに、初期化している処理があります。 483 * EXCELでは、Sheet 処理と、File 処理のループがあり、本来1回だけ初期化すればよいのですが、 484 * writeData( DBTableModel ,PrintWriter ) が複数回呼ばれるため、無駄な処理になってしまいます。 485 * ただし、今までは、ローカル変数でしたが、インスタンス変数に変更しています。 486 * 487 * @og.rev 6.0.2.0 (2014/09/19) 新規追加 488 * @og.rev 8.5.2.0 (2023/07/14) 一部の機能廃止による修正(問合・トラブル 0200010980) 489 * @og.rev 8.5.5.1 (2024/02/29) switch式の使用 490 */ 491 private void initWriteData() { 492 final DBTableModel table = getDBTableModel(); 493 pageBreakClmNo = table.getColumnNo( pageBreakColumn,false ); // シートブレイクするキーとなるカラムNo 494 fileBreakClmNo = table.getColumnNo( fileBreakColumn,false ); // ファイルブレイクするキーとなるカラムNo 495 496 hLinkKeyClmNo = table.getColumnNo( hLinkKeyColumn,false ); // Hyperlinkを作成するキーとなるカラムNo 497 hLinkValClmNo = table.getColumnNo( hLinkValColumn,false ); // Hyperlinkを作成する値となるカラムNo 498 499// nvar = new boolean[numberOfColumns]; // 8.5.2.0 (2023/07/14) Delete 500 // 8.5.4.2 (2024/01/12) PMD 7.0.0 LinguisticNaming 501// isNums = new boolean[numberOfColumns]; // 6.0.2.0 (2014/09/19) NUMBER型かどうか 502 numClms = new boolean[numberOfColumns]; // 6.0.2.0 (2014/09/19) NUMBER型かどうか 503 final boolean useRenderer = isUseRenderer(); // 5.2.1.0 (2010/10/01) 504 505 for( int i=0; i<numberOfColumns; i++ ) { 506 final int clm = clmNo[i]; 507 if( clm < 0 ) { continue; } // 6.0.1.2 (2014/08/08) カラム飛ばし 508 509 // 5.7.6.3 (2014/05/23) ここでレンデラ時の文字タイプ判定を行う 510 if( useRenderer && dbColumn[clm].isStringOutput() ){ 511// isNums[i] = false; 512 numClms[i] = false; // 8.5.4.2 (2024/01/12) PMD 7.0.0 LinguisticNaming 513 } 514 else { 515 final NativeType nativeType = dbColumn[clm].getNativeType(); 516 // 8.5.5.1 (2024/02/29) switch式の使用 517// switch( nativeType ) { 518// case INT : 519// case LONG : 520// case DOUBLE : 521//// isNums[i] = true; 522// numClms[i] = true; // 8.5.4.2 (2024/01/12) PMD 7.0.0 LinguisticNaming 523// break; 524// case STRING : 525// case CALENDAR : 526// default : 527//// isNums[i] = false; 528// numClms[i] = false; // 8.5.4.2 (2024/01/12) PMD 7.0.0 LinguisticNaming 529// break; 530// } 531 numClms[i] = switch( nativeType ) { 532 case INT, LONG, DOUBLE -> true; 533 // case STRING, CALENDAR -> false; 534 default -> false; 535 }; 536 } 537// nvar[i] = "NVAR".equals( dbColumn[clm].getDbType()) ; // 8.5.2.0 (2023/07/14) Delete 538 } 539 } 540 541 /** 542 * PrintWriter に DBTableModelのテーブル情報を書き込みます。 543 * このクラスでは、データを ダブルコーテーション(")で囲みます。 544 * PrintWriter に DBTableModelのテーブル情報を書き込みます。 545 * 546 * @og.rev 3.8.0.1 (2005/06/17) DBTypeが NVAR の場合は、元のUnicodeに戻します。 547 * @og.rev 3.8.5.3 (2006/08/07) DBType の nativeType に対応した、CELL_TYPE をセットします。 548 * @og.rev 4.1.1.2 (2008/02/28) NativeタイプをEnum型(fukurou.model.NativeType)に変更 549 * @og.rev 5.1.4.0 (2010/03/01) columns 対応 550 * @og.rev 5.1.4.0 (2010/03/01) useNumber属性対応 551 * @og.rev 5.2.1.0 (2010/10/01) useRenderer 対応 552 * @og.rev 5.7.6.3 (2014/05/23) stringOutput対応 553 * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加 554 * @og.rev 6.0.4.0 (2014/11/28) データ出力用のレンデラー 555 * @og.rev 6.2.3.0 (2015/05/01) writeKeyLabel 属性を追加 556 * @og.rev 8.5.2.0 (2023/07/14) 一部の機能廃止による修正(問合・トラブル 0200010980) 557 * 558 * @param table DBTableModelオブジェクト 559 * @param writer PrintWriterオブジェクト(未使用) 560 */ 561 @Override 562 protected void writeData( final DBTableModel table,final PrintWriter writer ) { 563 final int numberOfRows = table.getRowCount(); 564 final boolean useRenderer = isUseRenderer(); // 5.2.1.0 (2010/10/01) 565 566 if( useAutoCellSize ) { 567 excel.setDataStartRow( nRowIndex ); // データ行の書き込み開始位置の行番号を設定 568 } 569 570 int rowNo = 1; 571 for( ; tblRow<numberOfRows; tblRow++ ) { // tblRow は、シートブレイクしても連続してカウントアップ 572 // まずはファイルブレイク判定 573 if( fileBreakClmNo >= 0 ) { 574 // ファイルブレイクすると、noPageBreak=false と、noFileBreak=false がセットされる。 575 final String nowFBC = table.getValue( tblRow,fileBreakClmNo ); 576 if( !fileKey.equals( nowFBC ) ) { 577 fileKey = nowFBC; 578 noPageBreak = false; 579 return; 580 } 581 } 582 if( pageBreakClmNo >= 0 ) { 583 // シートブレイクすると、新しい sheetName がセットされ、noPageBreak=false がセットされる。 584 final String nowPBC = table.getValue( tblRow,pageBreakClmNo ); 585 if( !sheetName.equals( nowPBC ) ) { 586 sheetName = nowPBC; 587 return; 588 } 589 } 590 591 short nColIndex = 0; 592 excel.createRow( nRowIndex++ ); 593 if( useNumber ) { excel.setCellValue( String.valueOf( rowNo++ ),nColIndex++,true ); } 594 595 for( int i=0; i<numberOfColumns; i++ ) { 596 final int clm = clmNo[i]; 597 if( clm < 0 ) { // 6.0.1.2 (2014/08/08) カラム飛ばし 598 nColIndex++; 599 continue; 600 } 601 602 String val = table.getValue( tblRow,clm ); 603 604 // 6.2.3.0 (2015/05/01) keyLabelは、後ろのカラムのラベルを付けません。 605 if( isKeyLbl[i] ) { 606// excel.setCellValue( val,nColIndex++,isNums[i] ); 607 excel.setCellValue( val,nColIndex++,numClms[i] ); // 8.5.4.2 (2024/01/12) PMD 7.0.0 LinguisticNaming 608 } 609 610// if( nvar[i] ) { // 8.5.2.0 (2023/07/14) Delete 611// val = StringUtil.getReplaceEscape( val ); // 8.5.2.0 (2023/07/14) Delete 612// } // 8.5.2.0 (2023/07/14) Delete 613 // 5.2.1.0 (2010/10/01) useRenderer 対応 614// else if( useRenderer ) { // 8.5.2.0 (2023/07/14) Modify 615 if( useRenderer ) { 616 // 6.0.4.0 (2014/11/28) データ出力用のレンデラー 617 val = dbColumn[clm].getWriteValue( val ); 618 } 619 620// excel.setCellValue( val,nColIndex,isNums[i] ); 621 excel.setCellValue( val,nColIndex,numClms[i] ); // 8.5.4.2 (2024/01/12) PMD 7.0.0 LinguisticNaming 622 623 // ハイパーリンク設定は、文字の設定の後で行います。 624 if( clm == hLinkKeyClmNo && hLinkValClmNo >= 0 ) { 625 final String shtNm = table.getValue( tblRow,hLinkValClmNo ); 626 excel.setCellLink( shtNm,nColIndex ); 627 } 628 629 nColIndex++; 630 } 631 632 // 余計なセルを削除 633 excel.removeCell( nColIndex ); 634 } 635 noPageBreak = false; // 最後まで終了した 636 fileKey = null; // 最後まで終了した 637 } 638 639 /** 640 * 出力先ディレクトリとファイル名をセットします。 641 * これは、EXCEL追加機能として実装されています。 642 * 643 * 雛形ファイルとの関係から、内部的に filename は合成しておきます。 644 * 645 * @og.rev 3.5.4.3 (2004/01/05) 新規作成 646 * @og.rev 6.0.2.0 (2014/09/19) ディレクトリとファイルを分けて管理します。 647 * 648 * @param dir 出力先ディレクトリ 649 * @param fname 出力ファイル名 650 */ 651 @Override 652 public void setFilename( final String dir , final String fname ) { 653 filename = StringUtil.urlAppend( dir,fname ) ; 654 655 directory = dir; 656 fileKey = fname; 657 } 658 659 /** 660 * DBTableModelのデータとして読み込むときのシート名を設定します。 661 * 初期値は、"Sheet1" です。 662 * これは、EXCEL追加機能として実装されています。 663 * 664 * @og.rev 3.5.4.2 (2003/12/15) 新規追加 665 * 666 * @param shtName シート名 667 */ 668 @Override 669 public void setSheetName( final String shtName ) { 670 if( shtName != null ) { this.sheetName = shtName; } 671 } 672 673 /** 674 * このクラスが、EXCEL対応機能を持っているかどうかを返します。 675 * 676 * EXCEL対応機能とは、シート名のセット、雛型参照ファイル名のセット、 677 * 書き込み元ファイルのFileオブジェクト取得などの、特殊機能です。 678 * 本来は、インターフェースを分けるべきと考えますが、taglib クラス等の 679 * 関係があり、問い合わせによる条件分岐で対応します。 680 * 681 * @og.rev 3.5.4.3 (2004/01/05) 新規追加 682 * 683 * @return EXCEL対応機能を持っているかどうか(常に true) 684 */ 685 @Override 686 public boolean isExcel() { 687 return true; 688 } 689 690 /** 691 * EXCEL雛型参考ファイル名をセットします。(DIR + Filename) 692 * これは、EXCEL追加機能として実装されています。 693 * 694 * @og.rev 3.5.4.3 (2004/01/05) 新規作成 695 * 696 * @param rfname EXCEL雛型参考ファイル名 697 */ 698 @Override 699 public void setRefFilename( final String rfname ) { 700 refFilename = rfname; 701 } 702 703 /** 704 * 雛形のシート名を、そのまま使用する(true)か、新規、または、外部指定のシート名を使用する(false)を指定します。(初期値:false[外部指定のシート名を使用])。 705 * 706 * ※ Ver5では、追記モード時に、指定シートが存在した場合は上書きします(初期値:false[上書きしない])。5.9.12.1 (2016/09/09) 707 * Ver6では、追記モード時に、雛形を指定できないため、雛形のシート名を、そのまま使用する(true)か、 708 * 新規、または、外部指定のシート名を使用する(false)を指定する属性になります。 709 * 710 * @og.rev 6.5.0.0 (2016/09/30) sheetOverwrite で、雛形シートの使用時に、元のシート名を使用します。 711 * 712 * @param flag 元のシート名を使用するかどうか[true:使用する/false:新規、または、外部指定のシート名を使用] 713 */ 714 @Override 715 public void setSheetOverwrite( final boolean flag ) { 716 sheetOverwrite = flag; 717 } 718 719 /** 720 * EXCELで、出力処理の最後にセルの計算式の再計算をさせるシート名をCSV形式で指定します。 721 * 722 * @og.rev 6.5.0.0 (2016/09/30) recalcSheetName で、セル内の計算式を再計算させるシート名を指定。5.9.12.1 (2016/09/09) 723 * 724 * @param sheet 対象シート名をCSV形式で指定 725 */ 726 @Override 727 public void setRecalcSheetName( final String sheet ){ 728 recalcSheetNames = StringUtil.csv2Array( sheet); 729 } 730 731 /** 732 * EXCEL雛型参考ファイルのシート名を設定します。 733 * これは、EXCEL追加機能として実装されています。 734 * 735 * EXCELファイルを書き出す時に、雛型として参照するシート名を指定します。 736 * これにより、複数の形式の異なるデータを順次書き出したり(appendモードを併用)する 737 * ことや、シートを指定して新規にEXCELを作成する場合にフォームを設定する事が可能になります。 738 * 初期値は、null(第一シート) です。 739 * 740 * @og.rev 3.5.4.3 (2004/01/05) 新規追加 741 * 742 * @param rshtName シート名 743 */ 744 @Override 745 public void setRefSheetName( final String rshtName ) { 746 if( rshtName != null ) { refSheetName = rshtName; } 747 } 748 749 /** 750 * データの書き込み開始位置を設定します(初期値:0)。 751 * 752 * TAB区切りテキストやEXCEL等のデータの書き込みの開始位置を指定します。 753 * 属性名は、行を飛ばす処理ということで、readTable タグと同じ名称です。 754 * ファイルの先頭行が、0行としてカウントしますので、設定値は、読み飛ばす 755 * 件数になります。(1と指定すると、1件読み飛ばし、2行目から読み込みます。) 756 * 行の読み飛ばしと、カラムの読み飛ばし(columns)、refFileURL、refFilename、 757 * refSheetName とともに使用すれば、ある程度のレイアウト設定が可能です。 758 * なお、この機能は、TableWriter_Excel のみに実装します。 759 * 760 * @og.rev 6.0.1.2 (2014/08/08) 新規作成 761 * 762 * @param skipCount 書き込み開始位置 763 */ 764 @Override 765 public void setSkipRowCount( final int skipCount ) { 766 skipRowCount = skipCount ; 767 } 768 769 /** 770 * EXCEL出力時のデフォルトフォント名を設定します。 771 * これは、EXCEL追加機能として実装されています。 772 * 773 * EXCELファイルを書き出す時に、デフォルトフォント名を指定します。 774 * フォント名は、EXCELのフォント名をそのまま使用してください。 775 * 内部的に、POI の org.apache.poi.hssf.usermodel.HSSFFont#setFontName( String ) 776 * に設定されます。 777 * 雛形ファイルを使用しない場合のみ、有効です。 778 * 779 * @og.rev 3.8.5.3 (2006/08/07) 新規追加 780 * 781 * @param font デフォルトフォント名 782 */ 783 @Override 784 public void setFontName( final String font ) { 785 fontName = font ; 786 } 787 788 /** 789 * EXCEL出力時のデフォルトフォントポイント数を設定します。 790 * これは、EXCEL追加機能として実装されています。 791 * 792 * EXCELファイルを書き出す時に、デフォルトポイント数を指定します。 793 * 内部的に、POI の org.apache.poi.hssf.usermodel.HSSFFont#setFontHeightInPoints( short ) 794 * に設定されます。 795 * 雛形ファイルを使用しない場合のみ、有効です。 796 * 797 * @og.rev 3.8.5.3 (2006/08/07) 新規追加 798 * 799 * @param point デフォルトフォントポイント数 800 */ 801 @Override 802 public void setFontPoint( final short point ) { 803 fontPoint = point; 804 } 805 806 /** 807 * EXCEL出力時に、データを書き込んだ範囲に罫線を入れるかどうかを指定します。 808 * 809 * データを書き込んでEXCELを作成しても、ノーマルのセルに値がセットされている 810 * だけなので、ある程度加工が必要です。 811 * そこで、データのセットされたセルに罫線を入れることで、それなりのデータが 812 * 出力された感じになります。 813 * この設定と、useAutoCellSize="true" で、セルの幅を自動調整すれば、見栄えが良くなります。 814 * なお、この機能は、TableWriter_Excel のみに実装します。 815 * 816 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 817 * 818 * @param useCellStyle 罫線を入れるかどうか(true:入れる/false:入れない) 819 * @see #setUseAutoCellSize( boolean ) 820 */ 821 @Override 822 public void setUseCellStyle( final boolean useCellStyle ) { 823 this.useCellStyle = useCellStyle; 824 } 825 826 /** 827 * EXCEL出力時に、セルの幅をデータの幅に自動的に合わせるかどうかを指定します。 828 * 829 * データを書き込んでEXCELを作成しても、ノーマルのセルに値がセットされている 830 * だけなので、ある程度加工が必要です。 831 * そこで、データのセットされたセルの幅を自動調整することで、それなりのデータが 832 * 出力された感じになります。 833 * この設定と、useCellStyle="true" で、セルの罫線を自動設定すれば、見栄えが良くなります。 834 * なお、この機能は、TableWriter_Excel のみに実装します。 835 * 836 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 837 * 838 * @param useAutoCellSize データの幅に自動的に合わせるかどうか(true:自動調整/false:何もしない) 839 * @see #setUseCellStyle( boolean ) 840 */ 841 @Override 842 public void setUseAutoCellSize( final boolean useAutoCellSize ) { 843 this.useAutoCellSize = useAutoCellSize; 844 } 845 846 /** 847 * EXCEL出力時に、セルの有効範囲を設定するかどうかを指定します。 848 * 849 * セルの有効範囲というのは、EXCELでの 空行、空列の存在しない範囲を指します。 850 * 通常、空行でも、データとして残っている場合は、EXCELのセルオブジェクトは存在します。 851 * ここで、useActiveWorkbook="true" とすると、空行、空列を削除します。 852 * 853 * 雛形を使用した場合は、データより多めに設定した計算などは、この処理で 854 * 削除されますので、データサイズにフィットさせることができます。 855 * なお、この機能は、TableWriter_Excel のみに実装します。 856 * 857 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 858 * 859 * @param useActiveWorkbook セルの有効範囲を設定するかどうか(true:設定する/false:そのまま) 860 */ 861 @Override 862 public void setUseActiveWorkbook( final boolean useActiveWorkbook ) { 863 this.useActiveWorkbook = useActiveWorkbook; 864 } 865 866 /** 867 * EXCEL出力時に、シートブレイクするキーとなるカラム名を指定します(このカラムの値がシート名になります)。 868 * 869 * EXCEL帳票では、帳票雛形に、PAGE_BRAKE キーを設定しましたが、TableWriterでは、 870 * メモリ上のカラムの値が変更したときに、シートブレイクさせることができます。 871 * このカラムの値がキーブレイクすると、新しいシートに書き出し始めます。 872 * シート名は、このカラムの値(キーブレイクする値)です。 873 * 874 * 雛形ファイルを使用する場合、雛形シートもキーブレイクに伴って、+1されます。 875 * つまり、雛形シートとデータシートは同時に変更されます。 876 * ただし、雛形シートは、最後の雛形シートで止まります。 877 * これは、雛形シートにヘッダー雛形とボディ雛形を用意しておき、最初のキーブレイクで 878 * ヘッダーからボディの書き込みにチェンジするイメージで使用できます。 879 * なお、この機能は、TableWriter_Excel のみに実装します。 880 * 881 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 882 * 883 * @param pageBreakColumn シートブレイクするキーとなるカラム名を指定 884 * @see #setFileBreakColumn( String ) 885 */ 886 @Override 887 public void setPageBreakColumn( final String pageBreakColumn ) { 888 this.pageBreakColumn = pageBreakColumn; 889 } 890 891 /** 892 * EXCEL出力時に、ファイルブレイクするキーとなるカラム名を指定します(このカラムの値がファイル名になります)。 893 * 894 * EXCEL帳票では、メモリ上のカラムの値が変更したときに、ファイルブレイクすることができます。 895 * このカラムの値がキーブレイクすると、新しいファイルに書き出し始めます。 896 * ファイル名は、このカラムの値(キーブレイクする値)+ 元の出力ファイル名の拡張子(.xlsなど)です。 897 * この設定を使用する場合は、出力ファイル名は無視されますが、拡張子だけは使用されます。 898 * 899 * 雛形ファイルを使用する場合、雛形ファイルもキーブレイクに伴って、再利用されます。 900 * 例えば、pageBreakColumn と併用する場合、キーブレイクで雛形シートも最初から適用になります。 901 * なお、この機能は、TableWriter_Excel のみに実装します。 902 * 903 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 904 * 905 * @param fileBreakColumn ファイルブレイクするキーとなるカラム名を指定 906 * @see #setPageBreakColumn( String ) 907 */ 908 @Override 909 public void setFileBreakColumn( final String fileBreakColumn ) { 910 this.fileBreakColumn = fileBreakColumn; 911 } 912 913 /** 914 * EXCEL出力時に、Hyperlinkを作成するキーとなるカラム名と値となるカラム名を指定します。 915 * 916 * ここで、作成するハイパーリンクは、EXCELのシートに対するハイパーリンクです。 917 * それ以外のリンク(本当のURLやファイル等)のリンクは(今は)作成できません。 918 * ハイパーリンクを作成するには、①作成するカラム と ②作成する値 が必要です。 919 * このメソッドで設定するのは、「①:②」という形式でカラム名を指定します。 920 * ②がなければ、①と同じとします。 921 * ②の値のシートの存在有無は、無視します。ハイパーリンクを作成するシートを作成する前に 922 * ハイパーリンクを作成するケースが存在します。 923 * (例えば、各シートへのリンクを持った一覧を作成してから、明細の各シートを作成する様なケース) 924 * なお、この機能は、TableWriter_Excel のみに実装します。 925 * 926 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 927 * 928 * @param hyperLinkColumn Hyperlinkを作成するキーとなるカラム名と値となるカラム名を指定 929 */ 930 @Override 931 public void setHyperLinkColumn( final String hyperLinkColumn ) { 932 if( hyperLinkColumn != null && hyperLinkColumn.length() > 0 ) { 933 final int sep = hyperLinkColumn.indexOf( ':' ); // ①:② の形式かどうかの確認 934 if( sep >= 0 ) { 935 hLinkKeyColumn = hyperLinkColumn.substring( 0,sep ); // ①キーカラム 936 hLinkValColumn = hyperLinkColumn.substring( sep+1 ); // ②値カラム 937 } 938 else { 939 hLinkKeyColumn = hyperLinkColumn; // ①キーカラム = ②値カラム 940 hLinkValColumn = hyperLinkColumn; 941 } 942 } 943 } 944 945 /** 946 * EXCEL出力時に、Sheet一覧を先頭Sheetに作成する場合のSheet名を指定します。 947 * 948 * これは、Workbook に含まれる Sheet 一覧を作成する場合に、利用可能です。 949 * なお、この機能は、TableWriter_Excel のみに実装します。 950 * 951 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 952 * 953 * @param sheetName EXCELファイルのシート名 954 */ 955 @Override 956 public void setAddTitleSheet( final String sheetName ) { 957 addTitleSheet = sheetName ; 958 } 959}