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.hayabusa.taglib; 017 018import org.opengion.hayabusa.common.HybsSystem; 019import org.opengion.hayabusa.common.HybsSystemException; 020import org.opengion.hayabusa.db.DBConstValue; 021 022import org.opengion.fukurou.util.StringUtil ; 023import static org.opengion.fukurou.util.StringUtil.nval ; 024 025import java.util.Map; 026import java.util.LinkedHashMap; 027 028/** 029 * TableUpdateTag にパラメーターを渡す為のタグクラスです。 030 * 031 * 汎用的なデータベース登録処理を行えるタグ tableUpdate タグを新規作成します。 032 * これは、具体的なSLQを作成する tableUpdateParam タグと組み合わせて使用できます。 033 * tableUpdate タグは、queryType に JDBCTableUpdate を指定します。基本的にこれだけ 034 * です。tableUpdateParam では、sqlType に、INSERT,COPY,UPDATE,MODIFY,DELETE の 035 * どれかを指定する事で、SQL文のタイプを指定します。COPY,MODIFY は command と 036 * 関連を持たす為に追加しているタイプで、INSERTやUPDATE と同じ処理を行います。 037 * tableUpdateParam の table には、作成したい SQL のテーブルを指定します。 038 * where 属性は、検索結果の DBTableModel の更新時に使用する条件を指定します。 039 * 040 * @og.formSample 041 * ●形式:<og:tableUpdate command="{@command}" queryType="JDBCTableUpdate" > 042 * <og:tableUpdateParam 043 * sqlType = "{@sqlType}" // INSERT,COPY,UPDATE,MODIFY,DELETE 044 * table = "{@TABLE_NAME}" // 処理対象のテーブル名 045 * names = "{@names}" // 処理対象のカラム名 046 * omitNames = "{@omitNames}" // 処理対象外のカラム名 047 * where = "{@where}" // 処理対象を特定するキー 048 * whereNames = "{@whereNames}" // 処理対象を特定するキー条件(where句)をCSV形式 049 * constKeys = "{@constKeys}" // 処理カラム名の中の固定情報カラム名 050 * constVals = "{@constVals}" // 処理カラム名の中の固定情報設定値 051 * asNames = "{@asNames}" // 別名を付けたカラム名(select A as B from TBL の B を指定) 052 * orgNames = "{@orgNames}" // tableの実際のカラム名(select A as B from TBL の A を指定) 053 * funcKeys = "{@funcKeys}" // 関数等を設定するカラム名 054 * funcVals = "{@funcVals}" // 関数等の設定値 055 * logicalDelete = "{@logicalDelete}" // sqlTypeがDELETEの場合にもUPDATE文を発行 056 * /> 057 * </og:tableUpdate> 058 * 059 * ●body:なし 060 * 061 * ●Tag定義: 062 * <og:tableUpdateParam 063 * sqlType ○【TAG】BODY部に書かれている SQLタイプを指定します(必須) 064 * table ○【TAG】処理対象のテーブル名を指定します(必須) 065 * names 【TAG】処理対象のカラム名をCSV形式で複数指定します 066 * omitNames 【TAG】処理対象外のカラム名をCSV形式で複数指定します 067 * where 【TAG】処理対象を特定するキー条件(where句)を指定します 068 * whereNames 【TAG】処理対象を特定するキー条件(where句)をCSV形式で複数指定します 069 * constKeys 【TAG】設定値を固定値と置き換える対象となるカラム名をCSV形式で複数指定します 070 * constVals 【TAG】設定値を固定値と置き換える対象となる設定値をCSV形式で複数指定します 071 * funcKeys 【TAG】関数等を設定するカラム名をCSV形式で複数指定します 072 * funcVals 【TAG】関数等の設定値をCSV形式で複数指定します 073 * asNames 【TAG】別名を付けたカラム名(select A as B from TBL の B を指定)をCSV形式で複数指定します 074 * orgNames 【TAG】tableの実際のカラム名(select A as B from TBL の A を指定)をCSV形式で複数指定します 075 * quotCheck 【TAG】リクエスト情報の クォーティション(') 存在チェックを実施するかどうか[true/false]を設定します (初期値:USE_SQL_INJECTION_CHECK[=true]) 076 * constObjKey 【TAG】固定情報カラムの処理オブジェクトを特定するキーを設定します(初期値:SYSTEM_ID) 077 * logicalDelete 【TAG】sqlType="DELETE"の場合に論理削除(UPDATE)を行うかどうかを指定します(初期値:false) 078 * debug 【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false) 079 * /> 080 * 081 * ●使用例 082 * ・【entry.jsp】 083 * <og:tableUpdate command="{@command}" queryType="JDBCTableUpdate" > 084 * <og:tableUpdateParam 085 * sqlType = "{@sqlType}" 086 * table = "{@MEM.TABLE_NAME}" 087 * where = "ROWID = [ROWID]" 088 * /> 089 * </og:tableUpdate> 090 * 091 * @og.rev 3.8.8.0 (2007/12/22) 新規作成 092 * @og.rev 4.1.2.0 (2008/03/12) 実装の大幅な修正 093 * @og.group DB登録 094 * 095 * @version 4.0 096 * @author Kazuhiko Hasegawa 097 * @since JDK5.0, 098 */ 099public class TableUpdateParamTag extends CommonTagSupport { 100 //* このプログラムのVERSION文字列を設定します。 {@value} */ 101 private static final String VERSION = "5.5.8.5 (2012/11/27)" ; 102 103 private static final long serialVersionUID = 558520121127L ; 104 105 /** sqlType属性に設定できる値 {@value} */ 106 public static final String SQL_TYPE = "|INSERT|COPY|UPDATE|MODIFY|DELETE|" ; 107 108 // 3.8.0.4 (2005/08/08) 印刷時に使用するシステムID 109 private static final String SYSTEM_ID =HybsSystem.sys( "SYSTEM_ID" ); 110 111 // 4.3.6.0 (2009/05/01) デフォルトで利用するconstObjのシステムリソース名 112 private static final String DEFAULT_CONST_OBJ = HybsSystem.sys( "DEFAULT_CONST_CLASS" ); 113 114 private String sqlType = null; // INSERT,COPY,UPDATE,MODIFY,DELETE 115 private String table = null; // 処理対象のテーブル名 116 private String[] names = null; // 処理対象のカラム名 117 private String omitNames = ",ROWID,ROWNUM,WRITABLE,"; // 処理対象外のカラム名 118 private String where = null; // 処理対象を特定するキー 119 private String whereNames = null; // 5.5.8.5 (2012/11/27) 処理対象を特定するCSV形式のカラム名 120 private String[] constKeys = null; // 処理カラム名の中の固定情報カラム名 121 private String[] constVals = null; // 処理カラム名の中の固定情報設定値 122 private String[] funcKeys = null; // 5.5.1.9 (2012/04/19) 関数等を設定するカラム名 123 private String[] funcVals = null; // 5.5.1.9 (2012/04/19) 関数等の設定値 124 private String[] asNames = null; // 5.5.1.9 (2012/04/19) 別名を付けたカラム名(select A as B from TBL の B を指定) 125 private String[] orgNames = null; // 5.5.1.9 (2012/04/19) tableの実際のカラム名(select A as B from TBL の A を指定) 126 private String constObjKey = SYSTEM_ID; // 固定情報カラムの処理オブジェクトを特定するキー 127 private boolean quotCheck = HybsSystem.sysBool( "USE_SQL_INJECTION_CHECK" ); 128 private boolean logicalDelete = false; // 4.3.7.0 (2009/06/01) sqlTypeがDELETEの場合にもUPDATE文を発行 129 130 /** 131 * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。 132 * 133 * @og.rev 5.5.1.9 (2012/04/19) エラーチェックを先に行います。 134 * 135 * @return 後続処理の指示( SKIP_BODY ) 136 */ 137 @Override 138 public int doStartTag() { 139 140 // constKeys,constVals の個数チェック 141 if( constKeys != null ) { 142 if( constVals == null || constKeys.length != constVals.length ) { 143 String errMsg = "<b>constKeys と、constVals の個数が異なります。</b><br />" 144 + " constKeys=[" + StringUtil.array2csv( constKeys ) + "]" 145 + " constVals=[" + StringUtil.array2csv( constVals ) + "]" ; 146 throw new HybsSystemException( errMsg ); 147 } 148 } 149 150 // funcKeys,funcVals の個数チェック 151 if( funcKeys != null ) { 152 if( funcVals == null || funcKeys.length != funcVals.length ) { 153 String errMsg = "<b>funcKeys と、funcVals の個数が異なります。</b><br />" 154 + " funcKeys=[" + StringUtil.array2csv( funcKeys ) + "]" 155 + " funcVals=[" + StringUtil.array2csv( funcVals ) + "]" ; 156 throw new HybsSystemException( errMsg ); 157 } 158 } 159 160 // asNames,orgNames の個数チェック 161 if( orgNames != null ) { 162 if( asNames == null || orgNames.length != asNames.length ) { 163 String errMsg = "<b>orgNames と、asNames の個数が異なります。</b><br />" 164 + " orgNames=[" + StringUtil.array2csv( orgNames ) + "]" 165 + " asNames=[" + StringUtil.array2csv( asNames ) + "]" ; 166 throw new HybsSystemException( errMsg ); 167 } 168 } 169 170 return SKIP_BODY ; // Body を評価しない 171 } 172 173 /** 174 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。 175 * 176 * @og.rev 4.3.7.0 (2009/06/01) 論理削除対応 177 * 178 * @return 後続処理の指示 179 */ 180 @Override 181 public int doEndTag() { 182 debugPrint(); 183 184 TableUpdateTag updateTag = (TableUpdateTag)findAncestorWithClass( this,TableUpdateTag.class ); 185 if( updateTag == null ) { 186 String errMsg = "<b>" + getTagName() + "タグは、TableUpdateTagの内側(要素)に記述してください。</b>"; 187 throw new HybsSystemException( errMsg ); 188 } 189 190 String upSqlType = updateTag.getSqlType() ; 191 if( upSqlType == null || upSqlType.equals( sqlType ) ) { 192 // 通常の names カラム配列を設定します。 193 if( names == null ) { names = updateTag.getNames(); } 194 NamesData namesData = makeNamesData( names ); 195 196 String query = null; 197 if( "INSERT".equalsIgnoreCase( sqlType ) || "COPY".equalsIgnoreCase( sqlType ) ) { 198 query = getInsertSQL( namesData ); 199 } 200 else if( "UPDATE".equalsIgnoreCase( sqlType ) || "MODIFY".equalsIgnoreCase( sqlType ) 201 || ( "DELETE".equalsIgnoreCase( sqlType ) && logicalDelete ) ) { // 4.3.7.0 (2009/06/01) 202 query = getUpdateSQL( namesData ); 203 } 204 else if( "DELETE".equalsIgnoreCase( sqlType ) ) { 205 query = getDeleteSQL(); 206 } 207 208 jspPrint( query ); 209 } 210 211 return EVAL_PAGE ; 212 } 213 214 /** 215 * タグリブオブジェクトをリリースします。 216 * キャッシュされて再利用されるので、フィールドの初期設定を行います。 217 * 218 * @og.rev 4.3.7.0 (2009/06/01) logicalDelete属性追加 219 * @og.rev 5.5.1.9 (2012/04/19) asNames、orgNames、funcKeys、funcVals属性追加 220 * @og.rev 5.5.8.5 (2012/11/27) 処理対象を特定するCSV形式のカラム名 221 */ 222 @Override 223 protected void release2() { 224 super.release2(); // 3.5.6.0 (2004/06/18) 追加(抜けていた) 225 sqlType = null; // INSERT,COPY,UPDATE,MODIFY,DELETE 226 table = null; // 処理対象のテーブル名 227 names = null; // 処理対象のカラム名 228 omitNames = ",ROWID,ROWNUM,WRITABLE,"; // 処理対象外のカラム名 229 where = null; // 処理対象を特定するキー 230 whereNames = null; // 5.5.8.5 (2012/11/27) 処理対象を特定するCSV形式のカラム名 231 constKeys = null; // 処理カラム名の中の固定情報カラム名 232 constVals = null; // 処理カラム名の中の固定情報設定値 233 quotCheck = HybsSystem.sysBool( "USE_SQL_INJECTION_CHECK" ); 234 constObjKey = SYSTEM_ID; // 固定情報カラムの処理オブジェクトを特定するキー 235 logicalDelete = false; // 4.3.7.0 (2009/06/01) 236 funcKeys = null; // 5.5.1.9 (2012/04/19) 関数等を設定するカラム名 237 funcVals = null; // 5.5.1.9 (2012/04/19) 関数等の設定値 238 asNames = null; // 5.5.1.9 (2012/04/19) 別名を付けたカラム名(select A as B from TBL の B を指定) 239 orgNames = null; // 5.5.1.9 (2012/04/19) tableの実際のカラム名(select A as B from TBL の A を指定) 240 } 241 242 /** 243 * 【TAG】BODY部に書かれている SQLタイプを指定します。 244 * 245 * @og.tag 246 * SQLタイプは、INSERT,COPY,UPDATE,MODIFY,DELETE の中から指定する 247 * 必要があります。これらは、内部に書かれるSQLの形式を指定するのに使用します。 248 * 内部処理は、DBTableModelの改廃コード(A,C,D)に対して使用される 249 * SQL を選択する場合の情報に使用されます。 250 * なお、COPY と MODIFY は、command で指定できる簡易機能として用意しています。 251 * 上位の TableUpdateTag の sqlType 属性 と同じsqlType 属性の場合のみ、SQL文を 252 * 合成・出力します。(上位のsqlTypeがnullの場合は、無条件実行します。) 253 * 指定のタイプが、異なる場合は、なにも処理を行いません。 254 * 255 * @param type BODY部に書かれている SQL タイプ 256 */ 257 public void setSqlType( final String type ) { 258 sqlType = nval( getRequestParameter( type ),sqlType ); 259 if( sqlType != null && SQL_TYPE.indexOf( "|" + sqlType + "|" ) < 0 ) { 260 sqlType = null; 261 // String errMsg = "sqlType属性には、" + SQL_TYPE + "以外設定できません。" 262 // + " typeIn=[" + type + "]" 263 // + " sqlType=[" + sqlType + "]" ; 264 // throw new HybsSystemException( errMsg ); 265 } 266 } 267 268 /** 269 * 【TAG】処理対象のテーブル名を指定します。 270 * 271 * @og.tag 272 * テーブル名を指定することで、sqlTypeに応じた QUERYを生成することが出来ます。 273 * 生成する場合のカラムを特定する場合は、names 属性で指定できます。 274 * また、WHERE条件は、where属性で指定します。 275 * 276 * @param tbl テーブル名 277 * @see #setNames( String ) 278 * @see #setWhere( String ) 279 * @see #setSqlType( String ) 280 */ 281 public void setTable( final String tbl ) { 282 table = nval( getRequestParameter( tbl ),table ); 283 } 284 285 /** 286 * 【TAG】処理対象のカラム名をCSV形式で複数指定します。 287 * 288 * @og.tag 289 * 生成するQUERYのカラム名をカンマ区切り文字(CSV)で複数指定します。 290 * 指定がない場合は、DBTableModel の全カラム(※)を使用して、QUERYを構築します。 291 * 一般に、テーブル結合してDBTableModelを構築した場合は、登録すべきカラムを 292 * 指定する必要があります。 293 * (※)正確には、DBTableModel の全カラムのうち、ROWID,ROWNUM,WRITABLE カラムは 294 * 無視します。 295 * 分解方法は、通常のパラメータ取得後に、CSV分解します。 296 * 297 * @og.rev 3.8.8.5 (2007/03/09) 通常のパラメータ取得後に、CSV分解に戻します。 298 * 299 * @param nms カラム名(CSV形式) 300 * @see #setTable( String ) 301 * @see #setOmitNames( String ) 302 */ 303 public void setNames( final String nms ) { 304 names = StringUtil.csv2Array( getRequestParameter( nms ) ); 305 if( names.length == 0 ) { names = null; } 306 } 307 308 /** 309 * 【TAG】処理対象外のカラム名をCSV形式で複数指定します。 310 * 311 * @og.tag 312 * 生成するQUERYのカラム名に指定しないカラム名をカンマ区切り文字(CSV)で複数指定します。 313 * 指定がない場合は、DBTableModel の全カラム(※)を使用して、QUERYを構築します。 314 * テーブル結合などで、処理したくないカラム数の方が少ない場合に、names ですべてを 315 * 指定するより少ない記述ですみます。 316 * (※)正確には、DBTableModel の全カラムのうち、ROWID,ROWNUM,WRITABLE カラムは 317 * 無視します。 318 * 319 * @param nms カラム名(CSV形式) 320 * @see #setTable( String ) 321 * @see #setNames( String ) 322 */ 323 public void setOmitNames( final String nms ) { 324 omitNames = omitNames + nval( getRequestParameter( nms ),"" ) + ","; 325 } 326 327 /** 328 * 【TAG】処理対象を特定するキー条件(where句)を指定します。 329 * 330 * @og.tag 331 * 生成するQUERYのwhere 句を指定します。通常の WHERE 句の書き方と同じで、 332 * DBTableModelの値を割り当てたい箇所に[カラム名] を記述します。 333 * 文字列の場合、設定値をセットするときに、シングルコーテーションを 334 * 使用しますが、[カラム名]で指定する場合は、その前後に、(')シングル 335 * コーテーションは、不要です。 336 * {@XXXX}変数を使用する場合は、パース時に固定文字に置き換えられる為、 337 * 文字列指定時の(')シングルコーテーションが必要になります。 338 * ※ 5.5.8.5 (2012/11/27) whereNames 属性と併用した場合は、where が、and を付けて、文字列結合されます。 339 * 例:FGJ='1' and CLM=[CLM] and SYSTEM_ID in ([SYSID],'**') and KBSAKU='{@KBSAKU}' 340 * 341 * @param wr 検索条件(where句) 342 */ 343 public void setWhere( final String wr ) { 344 where = nval( getRequestParameter( wr ),where ); 345 } 346 347 /** 348 * 【TAG】処理対象を特定するキー条件(where句)をCSV形式で複数指定します。 349 * 350 * @og.tag 351 * 生成するQUERYのwhere 句を指定する方法として、複数のカラム名をCSV指定し、内部で 352 * KEY=[KEY] 文字列を作成します。 353 * ここでは、カラム名は、データベースのカラム名と同じで、かつ、DBTableModel にも 354 * 同じカラムのデータが存在していること、という条件付きとします。 355 * また、where 条件との併用を行いますが、こちらの条件が先に使用され、where 条件は、 356 * and を付けて、文字列結合されます。 357 * 例: CLM,SYSTEM_ID,KBSAKU ⇒ CLM=[CLM] and SYSTEM_ID=[SYSTEM_ID] and KBSAKU=[KBSAKU] 358 * 359 * @og.rev 5.5.8.5 (2012/11/27) 新規追加 360 * 361 * @param wrnm 検索条件(where句)作成のためのカラム名(CSV形式) 362 */ 363 public void setWhereNames( final String wrnm ) { 364 whereNames = nval( getRequestParameter( wrnm ),whereNames ); 365 } 366 367 /** 368 * 【TAG】設定値を固定値と置き換える対象となるカラム名をCSV形式で複数指定します。 369 * 370 * @og.tag 371 * names 属性のカラムや table 属性より、QUERYを作成して、DBTableModelの値を 372 * 割り当てる場合、DBTableModelの値ではなく、外部から指定した固定値を 373 * 割り当てたい場合に、そのカラム名をカンマ区切り文字(CSV)で複数指定します。 374 * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。 375 * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。 376 * 377 * @param keys カラム名(CSV形式) 378 * @see #setConstVals( String ) 379 */ 380 public void setConstKeys( final String keys ) { 381 constKeys = getCSVParameter( keys ); 382 } 383 384 /** 385 * 【TAG】設定値を固定値と置き換える対象となる設定値をCSV形式で複数指定します。 386 * 387 * @og.tag 388 * names 属性のカラムや table 属性より、QUERYを作成して、DBTableModelの 389 * 値を割り当てる場合、DBTableModelの値ではなく、外部から指定した固定値を 390 * 割り当てたい場合に、そのカラム名に対応する設定値をカンマ区切り文字(CSV)で 391 * 複数指定します。ここで指定する設定値は、constKeys 属性と対応させます。 392 * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。 393 * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。 394 * 395 * @param vals 設定値(CSV形式) 396 * @see #setConstKeys( String ) 397 */ 398 public void setConstVals( final String vals ) { 399 constVals = getCSVParameter( vals ); 400 } 401 402 /** 403 * 【TAG】関数等を設定するカラム名をCSV形式で複数指定します。 404 * 405 * @og.tag 406 * constVals 属性で設定する値は、必ずシングルクオートが付与されます。 407 * その場合、関数などを設定したい場合でも、文字列として設定しようとします。 408 * ここで指定するカラム名(funcKeys)自身は、constKeys と同じ書式です。 409 * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。 410 * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。 411 * 412 * @og.rev 5.5.1.9 (2012/04/19) 新規追加 413 * 414 * @param keys カラム名(CSV形式) 415 * @see #setFuncVals( String ) 416 */ 417 public void setFuncKeys( final String keys ) { 418 funcKeys = getCSVParameter( keys ); 419 } 420 421 /** 422 * 【TAG】関数等の設定値をCSV形式で複数指定します。 423 * 424 * @og.tag 425 * funcKeys 属性に対応する 関数などの設定値を割り当てます。 426 * constVals 属性との違いは、funcVals の設定値は、そのままの形で、SQL文の 427 * 構築に使われます。 428 * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。 429 * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。 430 * 431 * @og.rev 5.5.1.9 (2012/04/19) 新規追加 432 * 433 * @param vals 設定値(CSV形式) 434 * @see #setFuncKeys( String ) 435 */ 436 public void setFuncVals( final String vals ) { 437 funcVals = getCSVParameter( vals ); 438 } 439 440 /** 441 * 【TAG】別名を付けたカラム名(select A as B from TBL の B を指定)をCSV形式で複数指定します。 442 * 443 * @og.tag 444 * SELECT 文を記述したとき、別名を付けていたり、SELECTしたテーブルと別のテーブルに 445 * DBTableModelの値を書き込む場合、DBTableModel の持っているカラム名と、実際に 446 * 書き込むカラム名が異なります。そのようなケースに、元の別名カラムを指定します。 447 * orgNames属性の並び順と、asNames属性の並び順を合わせておく必要があります。 448 * このカラム名は、DBTableModel には持っているが、テーブル側には持っていない値 449 * なので、内部的に omitNames 属性に値を設定します。利用者は、omitNames に 450 * 書き込む必要はありません。 451 * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。 452 * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。 453 * 454 * @og.rev 5.5.1.9 (2012/04/19) 新規追加 455 * 456 * @param keys カラム名(CSV形式) 457 * @see #setOrgNames( String ) 458 */ 459 public void setAsNames( final String keys ) { 460 asNames = getCSVParameter( keys ); 461 } 462 463 /** 464 * 【TAG】tableの実際のカラム名(select A as B from TBL の A を指定)をCSV形式で複数指定します。 465 * 466 * @og.tag 467 * SELECT 文を記述したとき、別名を付けていたり、SELECTしたテーブルと別のテーブルに 468 * DBTableModelの値を書き込む場合、DBTableModel の持っているカラム名と、実際に 469 * 書き込むカラム名が異なります。そのようなケースに、テーブルの実カラムを指定します。 470 * orgNames属性の並び順と、asNames属性の並び順を合わせておく必要があります。 471 * このカラム名は、DBTableModel には持っていませんが、テーブル側には持っている値 472 * なので、このカラム名で、SQL文を構築します。 UPDATE TBL SET A=[B] WHERE … となります。 473 * 分解方法は、CSV変数を先に分解してから、getRequestParameter で値を取得します。 474 * こうしないとデータ自身にカンマを持っている場合に分解をミスる為です。 475 * 476 * @og.rev 5.5.1.9 (2012/04/19) 新規追加 477 * 478 * @param keys カラム名(CSV形式) 479 * @see #setAsNames( String ) 480 */ 481 public void setOrgNames( final String keys ) { 482 orgNames = getCSVParameter( keys ); 483 } 484 485 /** 486 * 【TAG】リクエスト情報の クォーティション(') 存在チェックを実施するかどうか[true/false]を設定します 487 * (初期値:USE_SQL_INJECTION_CHECK[={@og.value org.opengion.hayabusa.common.SystemData#USE_SQL_INJECTION_CHECK}])。 488 * 489 * @og.tag 490 * SQLインジェクション対策の一つとして、暫定的ではありますが、SQLのパラメータに 491 * 渡す文字列にクォーティション(') を許さない設定にすれば、ある程度は防止できます。 492 * 数字タイプの引数には、 or 5=5 などのクォーティションを使用しないコードを埋めても、 493 * 数字チェックで検出可能です。文字タイプの場合は、必ず (')をはずして、 494 * ' or 'A' like 'A のような形式になる為、(')チェックだけでも有効です。 495 * (') が含まれていたエラーにする(true)/かノーチェックか(false)を指定します。 496 * (初期値:システム定数のUSE_SQL_INJECTION_CHECK[={@og.value org.opengion.hayabusa.common.SystemData#USE_SQL_INJECTION_CHECK}])。 497 * 498 * @param flag クォーティションチェック [true:する/それ以外:しない] 499 * @see org.opengion.hayabusa.common.SystemData#USE_SQL_INJECTION_CHECK 500 */ 501 public void setQuotCheck( final String flag ) { 502 quotCheck = nval( getRequestParameter( flag ),quotCheck ); 503 } 504 505 /** 506 * 【TAG】固定情報カラムの処理オブジェクトを特定するキーを設定します(初期値:SYSTEM_ID)。 507 * 508 * @og.tag 509 * 固定情報カラム をシステム単位にJavaクラスで管理できます。 510 * そのクラスオブジェクトは、org.opengion.hayabusa.db.DBConstValue インターフェースを 511 * 継承した、plugin クラスになります。 512 * そのクラスを特定するキーワードを指定します。 513 * 初期値は、SYSTEM_ID でシステム単位にクラスを作成します。 514 * もし、他のシステムと共通の場合は、継承だけさせることも可能です。 515 * 対応したDBConstValueクラスがプラグインとして存在しない場合は、 516 * システムリソースのDEFAULT_CONST_CLASSで指定されたクラスが利用されます。 517 * 518 * 初期値は、SYSTEM_ID です。 519 * 520 * @param key 固定情報カラムの処理オブジェクトを特定するキー 521 */ 522 public void setConstObjKey( final String key ) { 523 constObjKey = nval( getRequestParameter( key ),constObjKey ); 524 } 525 526 /** 527 * 【TAG】sqlType="DELETE"の場合に論理削除(UPDATE)を行うかどうかを指定します(初期値:false)。 528 * 529 * @og.tag 530 * sqlType="DELETE"の場合に論理削除(UPDATE)を行うかどうかを指定します。 531 * trueが指定された場合は、DELETE文ではなく、UPDATE文が発行されます。 532 * falseが指定された場合は、DELETE文が発行されます。 533 * さらに論理削除を行う場合、org.opengion.hayabusa.db.DBConstValue インターフェースに 534 * 定義されている、getLogicalDeleteKeys()及びgetLogicalDeleteValsを実装することで、 535 * 論理削除する際のフラグの更新方法を統一的に管理することが可能になります。 536 * 初期値は、false(物理削除する)です 537 * 538 * @param flg 論理削除(UPDATE)を行うかどうか 539 */ 540 public void setLogicalDelete( final String flg ) { 541 logicalDelete = nval( getRequestParameter( flg ),logicalDelete ); 542 } 543 544 /** 545 * データをインサートする場合に使用するSQL文を作成します。 546 * 547 * @og.rev 4.1.2.1 (2008/03/17) DBConstValue による固定値セットを採用 548 * @og.rev 4.3.6.4 (2009/05/01) デフォルト設定をシステムリソースで設定可能にする 549 * @og.rev 5.3.4.0 (2011/04/01) DEFAULT_CONST_OBJの初期値変更(null→ゼロ文字列) 550 * 551 * @param namesData NamesDataオブジェクト 552 * 553 * @return インサートSQL 554 */ 555 private String getInsertSQL( final NamesData namesData ) { 556 String cls = HybsSystem.sys( "DBConstValue_" + constObjKey ) ; 557 558 // 4.3.6.4 (2009/05/01) 標準の追加 559 if( cls == null){ 560 cls = DEFAULT_CONST_OBJ; 561 } 562 563 if( cls != null && !cls.isEmpty() ) { 564 DBConstValue constVal = (DBConstValue)HybsSystem.newInstance( cls ); 565 // 4.2.1.0 (2008/04/16) 初期化追加 566 constVal.init( table,getUser().getUserID(),getGUIInfoAttri( "KEY" ) ); 567 String[] keys = constVal.getInsertKeys(); 568 String[] vals = constVal.getInsertVals(); 569 namesData.add( keys,vals ); 570 } 571 572 String[] nms = namesData.getNames(); 573 String[] vls = namesData.getVals(); 574 575 StringBuilder sql = new StringBuilder(); 576 sql.append( "INSERT INTO " ).append( table ); 577 sql.append( " ( " ); 578 sql.append( nms[0] ); 579 for( int i=1; i<nms.length; i++ ) { 580 sql.append( "," ).append( nms[i] ); 581 } 582 sql.append( " ) VALUES ( " ); 583 sql.append( vls[0] ); 584 for( int i=1; i<vls.length; i++ ) { 585 sql.append( "," ).append( vls[i] ); 586 } 587 sql.append( " )" ); 588 589 return sql.toString(); 590 } 591 592 /** 593 * データをアップデートする場合に使用するSQL文を作成します。 594 * 595 * where と whereNames が同時に指定された場合は、whereNames が先に処理され 596 * where 条件は、and 結合されます。 597 * 598 * @og.rev 4.1.2.1 (2008/03/17) DBConstValue による固定値セットを採用 599 * @og.rev 4.3.6.4 (2009/05/01) デフォルト設定をシステムリソースで設定可能にする 600 * @og.rev 4.3.7.0 (2009/06/01) 論理削除対応 601 * @og.rev 5.3.7.0 (2011/07/01) DEFAULT_CONST_OBJの初期値変更(null→ゼロ文字列) 対応忘れ 602 * @og.rev 5.5.8.5 (2012/11/27) whereNames 対応 603 * 604 * @param namesData NamesDataオブジェクト 605 * 606 * @return アップデートSQL 607 */ 608 private String getUpdateSQL( final NamesData namesData ) { 609 String cls = HybsSystem.sys( "DBConstValue_" + constObjKey ) ; 610 611 // 4.3.6.4 (2009/05/01) 標準の追加 612 if( cls == null){ 613 cls = DEFAULT_CONST_OBJ; 614 } 615 616 if( cls != null && !cls.isEmpty() ) { // 5.3.7.0 (2011/07/01) 617 DBConstValue constVal = (DBConstValue)HybsSystem.newInstance( cls ); 618 // 4.2.1.0 (2008/04/16) 初期化追加 619 constVal.init( table,getUser().getUserID(),getGUIInfoAttri( "KEY" ) ); 620 // 4.3.7.0 (2009/06/01) 論理削除対応 621 String[] keys = null; 622 String[] vals = null; 623 if( "DELETE".equalsIgnoreCase( sqlType ) ) { 624 keys = constVal.getLogicalDeleteKeys(); 625 vals = constVal.getLogicalDeleteVals(); 626 } 627 else { 628 keys = constVal.getUpdateKeys(); 629 vals = constVal.getUpdateVals(); 630 } 631 namesData.add( keys,vals ); 632 } 633 634 String[] nms = namesData.getNames(); 635 String[] vls = namesData.getVals(); 636 637 StringBuilder sql = new StringBuilder(); 638 sql.append( "UPDATE " ).append( table ).append( " SET " ); 639 sql.append( nms[0] ).append( "=" ).append( vls[0] ); 640 641 for( int i=1; i<nms.length; i++ ) { 642 sql.append( "," ); 643 sql.append( nms[i] ).append( "=" ).append( vls[i] ); 644 } 645 646 // 5.5.8.5 (2012/11/27) whereNames 対応 647 String whereAnd = " WHERE " ; 648 if( whereNames != null && whereNames.length() > 0 ) { 649 String[] wnms = whereNames.split(","); 650 sql.append( whereAnd ).append( wnms[0] ).append( "=[" ).append( wnms[0] ).append( "]" ); 651 652 for( int i=1; i<wnms.length; i++ ) { 653 sql.append( " AND " ).append( wnms[i] ).append( "=[" ).append( wnms[i] ).append( "]" ); 654 } 655 whereAnd = " AND " ; // whereNames 優先。ここを通らなければ、初期値のまま、" WHERE " が使われる 656 } 657 658 // 5.5.8.5 (2012/11/27) whereNames 対応。whereNames が登録されていれば、AND で繋げる。 659 if( where != null && where.length() > 0 ) { 660 sql.append( whereAnd ).append( where ); 661 } 662 663 return sql.toString(); 664 } 665 666 /** 667 * データをデリートする場合に使用するSQL文を作成します。 668 * 669 * where と whereNames が同時に指定された場合は、whereNames が先に処理され 670 * where 条件は、and 結合されます。 671 * 672 * @og.rev 5.5.8.5 (2012/11/27) whereNames 対応 673 * 674 * @return デリートSQL 675 */ 676 private String getDeleteSQL() { 677 StringBuilder sql = new StringBuilder(); 678 sql.append( "DELETE FROM " ).append( table ); 679 680 // 5.5.8.5 (2012/11/27) whereNames 対応 681 String whereAnd = " WHERE " ; 682 if( whereNames != null && whereNames.length() > 0 ) { 683 String[] wnms = whereNames.split(","); 684 sql.append( whereAnd ).append( wnms[0] ).append( "=[" ).append( wnms[0] ).append( "]" ); 685 686 for( int i=1; i<wnms.length; i++ ) { 687 sql.append( " AND " ).append( wnms[i] ).append( "=[" ).append( wnms[i] ).append( "]" ); 688 } 689 whereAnd = " AND " ; // whereNames 優先。ここを通らなければ、初期値のまま、" WHERE " が使われる 690 } 691 692 // 5.5.8.5 (2012/11/27) whereNames 対応。whereNames が登録されていれば、AND で繋げる。 693 if( where != null && where.length() > 0 ) { 694 sql.append( whereAnd ).append( where ); 695 } 696 return sql.toString(); 697 } 698 699 /** 700 * names,constKeys,omitNames から、必要なキー情報と、属性情報を持った NamesData を作成します。 701 * 702 * @og.rev 4.1.2.1 (2008/03/17) 固定値の constVals の前後に、"'" を入れる。 703 * @og.rev 5.5.1.9 (2012/04/19) asNames、orgNames、funcKeys、funcVals属性追加 704 * 705 * @param nms カラム名配列 706 * 707 * @return 属性情報を持ったNamesData 708 */ 709 private NamesData makeNamesData( final String[] nms ) { 710 711 NamesData namesData = new NamesData(); 712 713 // 5.5.1.9 (2012/04/19) omitNames に、asNames配列の値を設定しておきます。 714 if( asNames != null ) { 715 for( int i=0; i<asNames.length; i++ ) { 716 if( asNames[i] != null && asNames[i].length() > 0 ) { 717 omitNames = omitNames + asNames[i] + ","; 718 } 719 } 720 } 721 722 // names で指定されたカラム名 723 for( int i=0; i<nms.length; i++ ) { 724 String nm = nms[i]; 725 if( nm != null && nm.length() > 0 && omitNames.indexOf( "," + nm + "," ) < 0 ) { 726 namesData.add( nm,"[" + nm + "]" ) ; 727 } 728 } 729 730 // 固定値の constKeys カラム配列を設定します。 731 if( constKeys != null && constKeys.length > 0 ) { 732 for( int j=0; j<constKeys.length; j++ ) { 733 String nm = constKeys[j]; 734 if( nm != null && nm.length() > 0 ) { 735 namesData.add( nm,"'" + constVals[j] + "'" ) ; // constVals は、シングルクオートで囲います。 736 } 737 } 738 } 739 740 // 関数値の funcKeys カラム配列を設定します。 741 if( funcKeys != null && funcKeys.length > 0 ) { 742 for( int j=0; j<funcKeys.length; j++ ) { 743 String nm = funcKeys[j]; 744 if( nm != null && nm.length() > 0 ) { 745 namesData.add( nm, funcVals[j] ) ; // funcVals は、シングルクオートで囲いません。 746 } 747 } 748 } 749 750 // 別名の asNames,orgNames カラム配列を設定します。 751 if( orgNames != null && orgNames.length > 0 ) { 752 for( int j=0; j<orgNames.length; j++ ) { 753 String onm = orgNames[j]; 754 if( onm != null && onm.length() > 0 ) { 755 namesData.add( onm,"[" + asNames[j] + "]" ) ; 756 } 757 } 758 } 759 760 return namesData ; 761 } 762 763 /** 764 * 内部データを受け渡す為の、簡易クラスです。 765 * 更新するカラム名と値のセット配列を管理しています。 766 * 767 */ 768 private static class NamesData { 769 final Map<String,String> data = new LinkedHashMap<String,String>() ; 770 771 /** 772 * キーと値のセットを追加します。 773 * 774 * @param nm String 775 * @param val String 776 */ 777 public void add( final String nm,final String val ) { 778 data.put( nm,val ); 779 } 780 781 /** 782 * キー配列と対応する、値配列のセットを追加します。 783 * 784 * @param nms String[] 785 * @param vals String[] 786 */ 787 public void add( final String[] nms,final String[] vals ) { 788 if( nms != null ) { 789 for( int i=0; i<nms.length; i++ ) { 790 data.put( nms[i],vals[i] ); 791 } 792 } 793 } 794 795 /** 796 * キー配列を返します。 797 * 798 * @return String[] 799 */ 800 public String[] getNames() { 801 return data.keySet().toArray( new String[data.size()] ); 802 } 803 804 /** 805 * 値配列を返します。 806 * 807 * @return String[] 808 */ 809 public String[] getVals() { 810 return data.values().toArray( new String[data.size()] ); 811 } 812 } 813 814 /** 815 * このオブジェクトの文字列表現を返します。 816 * 基本的にデバッグ目的に使用します。 817 * 818 * @return このクラスの文字列表現 819 */ 820 @Override 821 public String toString() { 822 return org.opengion.fukurou.util.ToString.title( this.getClass().getName() ) 823 .println( "VERSION" ,VERSION ) 824 .println( "sqlType" ,sqlType ) 825 .println( "table" ,table ) 826 .println( "names" ,names ) 827 .println( "omitNames" ,omitNames ) 828 .println( "where" ,where ) 829 .println( "whereNames" ,whereNames ) 830 .println( "constKeys" ,constKeys ) 831 .println( "constVals" ,constVals ) 832 .println( "logicalDelete" ,logicalDelete ) 833 .fixForm().toString() ; 834 } 835}