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.servlet; 017 018import org.opengion.fukurou.util.StringUtil; 019import org.opengion.hayabusa.common.HybsSystem; 020import org.opengion.hayabusa.common.HybsSystemException; 021 022import java.io.ByteArrayInputStream; 023import java.io.File; 024import java.util.Base64; 025import java.awt.image.BufferedImage; 026import javax.imageio.ImageIO; 027 028import java.time.LocalDateTime; 029import java.time.format.DateTimeFormatter; 030 031import java.io.IOException; 032import jakarta.servlet.ServletException; 033import jakarta.servlet.ServletConfig; 034import jakarta.servlet.http.HttpServlet; 035import jakarta.servlet.http.HttpServletRequest; 036import jakarta.servlet.http.HttpServletResponse; 037// import jakarta.servlet.ServletOutputStream; // 8.0.0.0 (2021/07/31) Delete 038import jakarta.servlet.annotation.WebServlet; 039import jakarta.servlet.annotation.WebInitParam; 040 041/** 042 * クライアントからBase64でエンコードして送信された画像ファイルを、 043 * ファイルに変換してセーブするサーブレットです。 044 * 045 * 想定される使い方は、クライアント側で、カメラ等で撮影された映像を 046 * canvasに書き込み、それを、Base64でPOSTする感じです。 047 * 048 * 一般的なサーブレットと同様に、デプロイメント・ディスクリプタ WEB-INF/web.xml に、 049 * servlet 要素と そのマッピング(servlet-mapping)を定義する必要があります。 050 * 051 * <servlet> 052 * <servlet-name>imageSave</servlet-name> 053 * <servlet-class>org.opengion.hayabusa.servlet.ImageSave</servlet-class> 054 * <init-param> 055 * <param-name>saveDir</param-name> 056 * <param-value>jsp/snapshot/</param-value> 057 * </init-param> 058 * <init-param> 059 * <param-name>debug</param-name> 060 * <param-value>false</param-value> 061 * </init-param> 062 * </servlet> 063 * 064 * <servlet-mapping> 065 * <servlet-name>imageSave</servlet-name> 066 * <url-pattern>/jsp/imageSave</url-pattern> 067 * </servlet-mapping> 068 * 069 * 一般には、http://サーバー:ポート/システムID/jsp/imageSave 070 * 引数;img=イメージファイル 071 * dir=ディレクトリ (初期値は、saveDir="jsp/snapshot/") 072 * file=ファイル名 (初期値は、filePtn="yyyyMMddHHmmssSSS" + ".png"(固定)) 073 * 形式のURL でPOSTします。 074 * 075 * @og.rev 7.4.2.1 (2021/05/21) 新規追加 076 * @og.group その他機能 077 * 078 * @version 7.4 079 * @author Kazuhiko Hasegawa 080 * @since JDK11, 081 */ 082@WebServlet( 083 urlPatterns = "/jsp/imageSave" , 084 initParams = { 085 @WebInitParam( name="saveDir" , value="jsp/snapshot/" ) 086 } 087) 088public class ImageSave extends HttpServlet { 089 private static final long serialVersionUID = 742120210521L ; 090 091 private final static DateTimeFormatter YMDH = DateTimeFormatter.ofPattern( "yyyyMMddHHmmssSSS" ); 092 093 private String saveDir = "jsp/snapshot/"; 094// private boolean isDebug = false; 095 private boolean isDebug ; // 8.0.0.0 (2021/07/31) Avoid using redundant field initializer for *** 096 097 /** 098 * Servlet の 初期値設定を行います。 099 * 100 * WEB-INF/web.xml ファイルで、<servlet> タグ内で初期値設定を行います。 101 * <init-param> 102 * <param-name>saveDir</param-name> 103 * <param-value>jsp/snapshot/</param-value> 104 * </init-param> 105 * 106 * @param config ServletConfigオブジェクト 107 */ 108 @Override 109 public void init( final ServletConfig config ) throws ServletException { 110 super.init( config ); 111 112 saveDir = StringUtil.nval( config.getInitParameter("saveDir") , saveDir ); 113 114 // boolean の StringUtil.nval は厳密チェックするので使わない。 115 isDebug = Boolean.parseBoolean( config.getInitParameter( "debug" ) ); 116 } 117 118 /** 119 * GET メソッドが呼ばれたときに実行します。 120 * 121 * 処理は、doPost へ振りなおしています。 122 * 123 * @param request HttpServletRequestオブジェクト 124 * @param response HttpServletResponseオブジェクト 125 * 126 * @og.rev 7.4.2.1 (2021/05/21) 新規追加 127 * 128 * @throws ServletException サーブレット関係のエラーが発生した場合、throw されます。 129 * @throws IOException 入出力エラーが発生したとき 130 */ 131 @Override 132 public void doGet( final HttpServletRequest request, final HttpServletResponse response ) 133 throws ServletException, IOException { 134 doPost( request,response ); 135 } 136 137 /** 138 * POST メソッドが呼ばれたときに実行します。 139 * 140 * @param request HttpServletRequestオブジェクト 141 * @param response HttpServletResponseオブジェクト 142 * 143 * @og.rev 7.4.2.1 (2021/05/21) 新規追加 144 * 145 * @throws ServletException サーブレット関係のエラーが発生した場合、throw されます。 146 * @throws IOException 入出力エラーが発生したとき 147 */ 148 @Override 149 public void doPost( final HttpServletRequest request, final HttpServletResponse response ) 150 throws ServletException, IOException { 151 152 // boolean の StringUtil.nval は厳密チェックするので使わない。 153 final String debugPrm = request.getParameter( "debug" ) ; 154 final boolean debug = StringUtil.isNull( debugPrm ) 155 ? isDebug // 未指定なら、初期値を使う 156 : Boolean.parseBoolean( debugPrm ); // "true"以外はfalse になる。 157 158 String data = request.getParameter( "img" ); 159 if( StringUtil.isNotNull( data ) ) { 160 // Javascriptのcanvas.toDataURL()関数から派生したデータを保存したい場合は、 161 // 空白をプラスに変換する必要があります。そうしないと、デコードされたデータが破損します。 162 data = data.replace(' ','+'); 163 164 // 相対パスを絶対パスに変換。ファイルセパレータも正規化されています。 165 final String dir = HybsSystem.url2dir( StringUtil.nval( request.getParameter( "dir" ),saveDir ) ); 166 if( debug ) { System.out.println( "dir=" + dir ); } 167 168 // ファイル名が無ければ、現在時刻.png 169 String file = request.getParameter( "file" ); 170 if( StringUtil.isNull( file ) ) { 171 final LocalDateTime nowDateTime = LocalDateTime.now(); 172 file = nowDateTime.format( YMDH ) + ".png"; 173 } 174 175 if( debug ) { System.out.println( "file=" + file ); } 176 177 // Base64をデコードしてファイルに戻す。 178 final byte[] bytes = Base64.getDecoder().decode(data); 179 try( ByteArrayInputStream input = new ByteArrayInputStream(bytes) ) { 180 final BufferedImage image = ImageIO.read(input); 181 final File output = new File( dir, file ); 182 final File parent = output.getParentFile(); 183 if( parent != null && !parent.exists() ) { // parent は null があり得る。存在しない場合のみ。 184 if( !parent.mkdirs() ) { // 8.0.0.0 (2021/07/31) spotbugs:例外的戻り値を無視 185 final String errMsg = "出力先フォルダが生成できませんでした。" + parent ; 186 throw new HybsSystemException( errMsg ); 187 } 188 } 189 ImageIO.write(image, "png", output); 190 if( debug ) { System.out.println( "output=" + output.getAbsolutePath() ); } 191 } 192 catch( final Throwable th ) { 193 final String errMsg = "Base64 デコード処理が失敗しました。" ; 194 throw new HybsSystemException( errMsg,th ); 195 } 196 } 197 } 198}