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.fukurou.util.StringUtil; 021import org.opengion.fukurou.util.ToString; 022import org.opengion.fukurou.util.XHTMLTag; 023import org.opengion.fukurou.util.Attributes; 024 025import org.opengion.fukurou.util.QrcodeImage; 026import static org.opengion.fukurou.util.QrcodeImage.ErrCrct; 027import static org.opengion.fukurou.util.QrcodeImage.EncMode; 028import static org.opengion.fukurou.util.StringUtil.nval ; 029 030import java.util.Locale ; 031 032/** 033 * QRコードに対応したイメージファイルを作成するタグです。 034 * 035 * QRコードで表示できる文字数は、バージョン、エンコードモード、エラー訂正レベル に依存します。 036 * また、イメージの大きさは、文字数と1セル辺りのピクセルに依存します。 037 * fileURLは、通常、システムリソースのFILE_URL(=filetemp)なので、fileURL="{@USER.ID}" と 038 * するのが一般的です。 039 * ファイル名は、初期値:rqcode ですが、拡張子はimageType(初期値:PNG)を小文字化して追加します。 040 * 拡張子が付いている場合は、そのまま使用されます。 041 * また、同一ファイル名の場合、ブラウザキャッシュのため、画像が更新されないことがあるため 042 * imgタグのsrc属性に、キャッシュの無効化のための引数を追加しています。 043 * 044 * @og.formSample 045 * ●形式:<og:qrCode fileURL="{@USER.ID}" > 046 * エンコードする文字列 047 * </og:qrCode > 048 * ●body:あり(EVAL_BODY_BUFFERED:BODYを評価し、{@XXXX} を解析します) 049 * 050 * または、 051 * 052 * ●形式:<og:qrCode value="エンコードする文字列" /> 053 * 054 * ●Tag定義: 055 * <og:qrCode 056 * value 【TAG】エンコードする文字列(または、BODY部に記述) 057 * version 【TAG】バージョン (2から40の整数)(初期値:5) 058 * encodeMode 【TAG】エンコードモード('N':数字モード 'A':英数字モード 'B':8bit byteモード)(初期値:B) 059 * errCorrect 【TAG】エラー訂正レベル ('L','M','Q','H')(初期値:M) 060 * imageType 【TAG】イメージファイル形式(PNG/JPEG)(初期値:PNG) 061 * pixel 【TAG】1セル辺りの塗りつぶしピクセル(初期値:3) 062 * fileURL 【TAG】QRイメージファイルを出力するディレクトリ(初期値:初期値:FILE_URL) 063 * filename 【TAG】QRイメージファイル名 (初期値:rqcode) 064 * caseKey 【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null) 065 * caseVal 【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null) 066 * caseNN 【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない) 067 * caseNull 【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない) 068 * caseIf 【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない) 069 * debug 【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false) 070 * > ... Body ... 071 * </og:qrCode> 072 * 073 * @og.rev 7.2.1.0 (2020/03/13) 新規作成 074 * @og.group 画面表示 075 * 076 * @version 7.2 077 * @author Kazuhiko Hasegawa 078 * @since JDK11.0, 079 */ 080public class QRcodeTag extends CommonTagSupport { 081 /** このプログラムのVERSION文字列を設定します。 {@value} */ 082 private static final String VERSION = "7.2.1.0 (2020/03/13)" ; 083 private static final long serialVersionUID = 721020200313L ; 084 085 private static final int MAX_ALT_SIZE = 50 ; // イメージに表示させる alt属性の文字数制限 086 087 private String value ; // エンコードする文字列(または、BODY部に記述) 088 private int version = QrcodeImage.DEF_VERSION ; // バージョン (2から40の整数)(初期値:5) 089 private EncMode encMode = EncMode.DEF; // エンコードモード('N':数字モード 'A':英数字モード 'B':8bit byteモード)(初期値:B) 090 private ErrCrct errCrct = ErrCrct.DEF; // エラー訂正レベル ('L','M','Q','H')(初期値:M) 091 private String imgType = QrcodeImage.IMAGE_TYPE; // イメージファイル形式(PNG/JPEG)(初期値:PNG) 092 private int pixel = QrcodeImage.PIXEL ; // 1セル辺りの塗りつぶしピクセル(初期値:3) 093 private String fileURL = HybsSystem.sys( "FILE_URL" ); // QRイメージファイルを出力するディレクトリ(初期値:FILE_URL/{@USER.ID}) 094 private String filename = "rqcode"; // QRイメージファイル名 (初期値:rqcode) 095 096 /** 097 * デフォルトコンストラクター 098 * 099 * @og.rev 7.2.1.0 (2020/03/13) 新規作成 100 */ 101 public QRcodeTag() { super(); } // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。 102 103 /** 104 * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。 105 * 106 * @return 後続処理の指示( EVAL_BODY_BUFFERED ) 107 */ 108 @Override 109 public int doStartTag() { 110 // caseKey 、caseVal 属性対応 111 if( useTag() ) { 112 if( value == null || value.length() <= 0 ) { 113 return EVAL_BODY_BUFFERED ; // Body を評価する 114 } 115 } 116 return SKIP_BODY ; // Body を評価しない 117 } 118 119 /** 120 * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。 121 * 122 * @return 後続処理の指示(SKIP_BODY) 123 */ 124 @Override 125 public int doAfterBody() { 126 value = getBodyString(); 127 128 return SKIP_BODY ; 129 } 130 131 /** 132 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。 133 * 134 * @return 後続処理の指示 135 */ 136 @Override 137 public int doEndTag() { 138 debugPrint(); 139 // caseKey 、caseVal 属性対応 140 if( useTag() ) { 141 if( filename.indexOf( '.' ) < 0 ) { // 拡張子が存在しない 142 filename = filename + "." + imgType.toLowerCase(Locale.JAPAN); 143 } 144 145 try { 146 final String saveFile = HybsSystem.url2dir( fileURL,filename ); 147 148 final QrcodeImage qrcode = new QrcodeImage(); 149 qrcode.init( value,saveFile,version,encMode,errCrct,imgType,pixel ); 150 qrcode.saveImage(); 151 } 152 catch( final Throwable th ) { 153 final String errMsg = "QRコードが作成できませんでした。" + CR 154 + "指定のパラメータが正しいかどうかご確認ください。" + CR 155 + " version = [" + version + "] バージョン (2から40の整数)" + CR 156 + " encodeMode = [" + encMode + "] エンコードモード('N':数字 'A':英数字'B':byte)" + CR 157 + " errCorrect = [" + errCrct + "] エラー訂正レベル ('L','M','Q','H')" + CR 158 + " imageType = [" + imgType + "] イメージファイル形式(PNG/JPEG)" + CR 159 + " pixel = [" + pixel + "] 1セル辺りの塗りつぶしピクセル" ; 160 throw new HybsSystemException( errMsg,th ); 161 } 162 163 filename = filename + "?val=" + System.currentTimeMillis() ; // 同じファイル名の場合のキャッシュの無効化 164 final String src = StringUtil.urlAppend( getContextPath() , fileURL , filename ); 165 final String alt = value.substring( 0,Math.min( value.length() , MAX_ALT_SIZE ) ); 166 167 // 作成された QRコードのイメージを表示します。 168 final String img = XHTMLTag.img( 169 new Attributes() 170 .set( "src" , src ) 171 .set( "alt" , alt ) 172 .set( "title" , alt ) 173 ); 174 175 jspPrint( img ); 176 } 177 return EVAL_PAGE ; 178 } 179 180 /** 181 * タグリブオブジェクトをリリースします。 182 * キャッシュされて再利用されるので、フィールドの初期設定を行います。 183 * 184 */ 185 @Override 186 protected void release2() { 187 super.release2(); 188 value = null; // エンコードする文字列(または、BODY部に記述) 189 version = QrcodeImage.DEF_VERSION; // バージョン (2から40の整数)(初期値:5) 190 encMode = EncMode.DEF; // エンコードモード('N':数字モード 'A':英数字モード 'B':8bit byteモード)(初期値:B) 191 errCrct = ErrCrct.DEF ; // エラー訂正レベル ('L','M','Q','H')(初期値:M) 192 imgType = QrcodeImage.IMAGE_TYPE; // イメージファイル形式(PNG/JPEG)(初期値:PNG) 193 pixel = QrcodeImage.PIXEL ; // 1セル辺りの塗りつぶしピクセル(初期値:3) 194 fileURL = HybsSystem.sys( "FILE_URL" ); // QRイメージファイルを出力するディレクトリ(初期値:FILE_URL/{@USER.ID}) 195 filename = "rqcode"; // QRイメージファイル名 (初期値:rqcode) 196 } 197 198 /** 199 * 【TAG】エンコードする文字列(または、BODY部に記述)を指定します。 200 * 201 * @og.tag 202 * エンコードする文字列のバイト数は、バージョン、エンコードモード、エラー訂正レベルに依存します。 203 * また、イメージの大きさは、それらプラス1セル辺りのピクセルも影響します。 204 * 205 * @param val エンコードする文字列(または、BODY部に記述) 206 */ 207 public void setValue( final String val ) { 208 value = nval( getRequestParameter( val ),value ); 209 } 210 211 /** 212 * 【TAG】バージョン (2から40の整数)を指定します(初期値:5)。 213 * 214 * @og.tag 215 * エンコードする文字列のバイト数は、エラー訂正レベル、バージョン に依存します。 216 * 文字列のバイト数を増やす場合は、バージョンを適切に設定します。 217 * 218 * @param ver バージョン 219 */ 220 public void setVersion( final String ver ) { 221 version = nval( getRequestParameter( ver ),version ); 222 } 223 224 /** 225 * 【TAG】エンコードモード('N':数字モード 'A':英数字モード 'B':8bit byteモード)を指定します(初期値:B)。 226 * 227 * @og.tag 228 * エンコードする文字列の種類に応じて設定します。 229 * 日本語等を含む場合は、'B':8bit byteモード にしてください。 230 * 231 * @param mode エンコードモード 232 */ 233 public void setEncodeMode( final String mode ) { 234 final String em = nval( getRequestParameter( mode ),null ); 235 if( em != null ) { 236 encMode = EncMode.get( em.charAt(0) ); 237 } 238 } 239 240 /** 241 * 【TAG】エラー訂正レベル ('L','M','Q','H')を指定します(初期値:M)。 242 * 243 * @og.tag 244 * エンコードする文字列のバイト数は、エラー訂正レベル、バージョン に依存します。 245 * 通常、初期値のままで問題ありません。 246 * 247 * @param crct エラー訂正レベル 248 */ 249 public void setErrCorrect( final String crct ) { 250 final String ec = nval( getRequestParameter( crct ),null ); 251 if( ec != null ) { 252 errCrct = ErrCrct.get( ec.charAt(0) ); 253 } 254 } 255 256 /** 257 * 【TAG】イメージファイル形式(PNG/JPEG)を指定します(初期値:PNG)。 258 * 259 * @og.tag 260 * QRコードのイメージファイルの形式を指定します。 261 * 拡張子は自動的にイメージファイル形式(の小文字)がセットされます。 262 * 263 * @param type イメージファイル形式 264 */ 265 public void setImageType( final String type ) { 266 imgType = nval( getRequestParameter( type ),imgType ); 267 } 268 269 /** 270 * 【TAG】1セル辺りの塗りつぶしピクセルを指定します(初期値:3)。 271 * 272 * @og.tag 273 * QRコードのイメージファイルの形式を指定します。 274 * 拡張子は自動的にイメージファイル形式(の小文字)がセットされます。 275 * 276 * @param px ピクセル数 277 */ 278 public void setPixel( final String px ) { 279 pixel = nval( getRequestParameter( px ),pixel ); 280 } 281 282 /** 283 * 【TAG】 QRイメージファイルを出力するディレクトリを指定します(初期値:FILE_URL)。 284 * 285 * @og.tag 286 * この属性で指定されるディレクトリに、QRイメージファイルをセーブします。 287 * 指定方法は、通常の fileURL 属性と同様に、先頭が、'/' (UNIX) または、2文字目が、 288 * ":" (Windows)の場合は、指定のURLそのままのディレクトリに、そうでない場合は、 289 * FILE_URL 属性で指定のフォルダの下に、フォルダを作成します。 290 * 初期値は、FILE_URL になるため、通常は{@USER.ID}を指定する必要があります。 291 * 292 * @param url 保存先ディレクトリ名 293 * @see org.opengion.hayabusa.common.SystemData#FILE_URL 294 */ 295 public void setFileURL( final String url ) { 296 final String furl = nval( getRequestParameter( url ),null ); 297 if( furl != null ) { 298 fileURL = StringUtil.urlAppend( fileURL,furl ); 299 } 300 } 301 302 /** 303 * 【TAG】QRイメージファイル名をセットします(初期値:rqcode)。 304 * 305 * @og.tag 306 * ファイルを作成するときのファイル名をセットします。 307 * ファイル名の拡張子は、imageType属性の小文字を追加します。 308 * 拡張子付きで指定した場合(ファイル名に、ピリオドを含む場合)は、 309 * そのままの値を使用します。 310 * 311 * @param fname ファイル名 312 */ 313 public void setFilename( final String fname ) { 314 filename = nval( getRequestParameter( fname ),filename ); 315 } 316 317 /** 318 * このオブジェクトの文字列表現を返します。 319 * 基本的にデバッグ目的に使用します。 320 * 321 * @return このクラスの文字列表現 322 * @og.rtnNotNull 323 */ 324 @Override 325 public String toString() { 326 return ToString.title( this.getClass().getName() ) 327 .println( "VERSION" , VERSION ) 328 .println( "value" , value ) 329 .println( "version" , version ) 330 .println( "encMode" , encMode ) 331 .println( "errCrct" , errCrct ) 332 .println( "imgType" , imgType ) 333 .println( "pixel" , pixel ) 334 .println( "fileURL" , fileURL ) 335 .println( "filename" , filename ) 336 .fixForm().toString() ; 337 } 338} 339