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