フロント側をFlutter(スマホ)Thymeleaf(PC)、バックエンド側SpringBootの自動作成勉強中
19:22
①今日は、バックエンドSpringBootを使ってのファイル保存を調べる。
汎用的に使用できるgetFileFromFilePickerメソッドを作った。かつ、ファイルサイズチェックやっている。拡張子指定して選択している。
②スマホ画像はこんな感じ
フォルダをクリックすると、フォルダが表示される。
ファイルを選択すると、ファイル名が表示される。
登録ボタンを押下すると、登録完了が表示される。
バックエンド側UPLOADフォルダに登録されたことを確認した。
③PGMはこんな感じ
■gazo_register_amend.dart
class _GazoRegisterAmendState extends State<GazoRegisterAmend> { ・・・ Widget build(BuildContext context) { ・・・ List<Widget> _makeWidgets() { ・・・ //--テストファイル選択 start---------------------------- contentWidgets.add( Container( margin: const EdgeInsets.fromLTRB(10.0, 0, 10.0, 5), padding: const EdgeInsets.fromLTRB(10.0, 0, 10.0, 0), decoration: CommUtils.commBoxDecoration(), child:Column ( children: <Widget>[ Padding( padding: const EdgeInsets.all(8.0), child: Container( margin: const EdgeInsets.fromLTRB(10.0, 0, 10.0, 5), padding: const EdgeInsets.fromLTRB(10.0, 0, 10.0, 0), child: _gazoForm.fileFile == null ? const Text('ファイルを選んでください。') : Text("ファイル:" + _gazoForm.fileFile!.path, textAlign: TextAlign.left, overflow: TextOverflow.clip,), ), ), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ FloatingActionButton( onPressed: () async { File? _file = await CommUtils.getFileFromFilePicker(context, Consts.maxFileSize, Consts.fileExt); if (_file != null) { setState(() { _gazoForm.fileFile = _file; // displayText = _file.path; }); } }, tooltip: 'Pick File', child: const Icon(Icons.folder), ), ], ), const SizedBox( height : 10.0, ), ], ), ), ); //--テストファイル選択 end---------------------------- ・・・ /// 情報登録、情報変更、情報一覧へのhttpアクセス void httpForInfo(String _modeBase) async { ・・・ _mode = (_gazoForm.messageForm.mode == 'ins' || _gazoForm.messageForm.mode == 'ins_do')?'ins_do':'upd_do'; widget.headers["content-type"]= "multipart/form-data"; widget.headers["X-XSRF-TOKEN"]= "${widget.cookies['XSRF-TOKEN']}"; final url = Uri.parse("${Consts.myHttpUrl}/members/admin/gazo/gazo/" + _mode); var request = http.MultipartRequest("POST", url); request.fields['formComm.page'] = _gazoForm.messageForm.page.toString(); if (_gazoForm.gazoFlFile != null) { final mimeTypeData = lookupMimeType( _gazoForm.gazoFlFile!.path, headerBytes: [0xFF, 0xD8])!.split('/'); final file = await http.MultipartFile.fromPath( 'gazoForm.gazoFlFile', _gazoForm.gazoFlFile!.path, contentType: MediaType(mimeTypeData[0], mimeTypeData[1])); request.files.add(file); } if (_gazoForm.fileFile != null) { final mimeTypeData = lookupMimeType( _gazoForm.fileFile!.path, headerBytes: [0xFF, 0xD8])!.split('/'); final file = await http.MultipartFile.fromPath( 'gazoForm.fileFile', _gazoForm.fileFile!.path, contentType: MediaType(mimeTypeData[0], mimeTypeData[1])); request.files.add(file); } request.headers.addAll(widget.headers); final streamedResponse = await request.send(); response = await http.Response.fromStream(streamedResponse); } if (response.statusCode != 200) { setState(() { int statusCode = response.statusCode; if (response.statusCode == 401 || response.statusCode == 403) { _errorSuccessMsg = "ログインしてください"; } else { _errorSuccessMsg = "エラーが発生しました $statusCode"; } }); // 画面を先頭に戻す _scrollController.animateTo(0, duration: const Duration(milliseconds:600), curve: Curves.easeInQuint); return; } CommUtils.updateCookie(response, widget.cookies, widget.headers); // response.bodyをutf8でdecodeする。 String _resData = utf8.decode(response.body.runes.toList()); if (kDebugMode) { print(_resData); } // バックエンドで例外発生の場合MessageFormの値しか戻らないため、ここで確認する MessageForm _messageForm = MessageForm.initData(); _messageForm.fromJson(_resData); // SpringBootで例外発生の場合 if (_messageForm.mode =="SystemError") { // エラー画面 Navigator.of(context).push( MaterialPageRoute( builder: (context) => Error(title: widget.title, username: widget.username, headers: widget.headers, cookies: widget.cookies, resData: _resData), ), ); // 正常処理 } else { if (_messageForm.mode == 'list_back') { } else { setState(() { _gazoForm.fromJson(_resData); _errorSuccessMsg = _gazoForm.messageForm.errorMessage + _gazoForm.messageForm.successMessage; if (_errorSuccessMsg == '' && _gazoForm.messageForm.itemErrorMessages != '') { _errorSuccessMsg = '項目エラーを確認してください'; } }); } } } catch (e) { setState(() { _errorSuccessMsg = "エラーが発生しました" + e.toString(); }); } // 画面を先頭に戻す _scrollController.animateTo(0, duration: const Duration(milliseconds:600), curve: Curves.easeInQuint); }
■comm_utils.dart
class CommUtils { ・・・ /// ファイル読み込み static Future<File?> getFileFromFilePicker(BuildContext _context, int _maxFileSize, List<String> _fileExt) async { FilePickerResult? filePickerResult = await FilePicker.platform.pickFiles( // 拡張子を指定してマッチするファイルを取り出す type: FileType.custom, allowedExtensions: _fileExt, ); if (filePickerResult != null && filePickerResult.files.single.path != null) { File _file = File(filePickerResult.files.single.path!); int _iLength = _file.lengthSync(); // ファイルサイズが指定バイト以上のとき if (_iLength > (_maxFileSize * 1000000)) { await CommUtils.openDialogOkComm( _context, "ファイルサイズは${_maxFileSize}Mバイト以下を選んでください。"); } else { return _file; } } return null; }
■consts.dart
class Consts { ・・・ /// ファイルMAXサイズ。M指定 static const int maxFileSize = 10; /// FilePicker.platform.pickFilesに使用するファイル拡張子 static const List<String> fileExt = ["txt","pdf",];
■2022/06/15に、勉強した成果:『Flutter_JavaSpringプログラム自動作成◎自動生成ツール』をVectorに載せました。Zenn本も書きました。使ってみての感想や間違いの指定や、こうやったほうがいいとかの情報があればメールください。
・Vector
www.vector.co.jp
・Zenn本(Flutter_JavaSpringプログラム自動作成)
zenn.dev