フロント側をFlutter(スマホ)Thymeleaf(PC)、バックエンド側SpringBootの自動作成勉強中
9:00
①今日は、削除ボタンを作ろう。
11:40
①andoriidstudioで表示された「更新」を押したら立ち上がり時に以下エラーが出た。
Internal error. Please refer to https://code.google.com/p/android/issues java.lang.VerifyError: Expecting a stack map frame Exception Details: Location: com/intellij/openapi/util/text/StringUtil.pluralize(Ljava/lang/String;I)Ljava/lang/String; @7: nop Reason: Expected stackmap frame at this location. Bytecode:
ネットで調べたら
C:\Users\ユーザー名\AppData\Roaming\Google の下にある「AndroidStudio2099.9」を削除すればOKとのことなので、やってみた。
ということで、とりあえず動くようになった。
20:53
①削除ボタン処理ができた。
■Flutter側スマホ画面
↓ID=16を選んで削除ボタン押下。削除メッセージを付加して、ユーザー情報一覧画面が表示される。
・・・PC側WEB画面にはある「削除確認画面」を作るのを忘れていた。ので、あした作ろう。
■PC側WEB画面
↓ID=15を選んで削除ボタン押下。削除メッセージを付加して、ユーザー情報一覧画面が表示される。
■Flutter側プロフラム
・UserList.dartから抜粋
class UserList extends StatefulWidget { ・・・ class _UserListState extends State<UserList> { ・・・ Widget build(BuildContext context) { ・・・ // 画面に収まり入れないので、ListViewを使う body: Form( key: _formKey, child : ListView( controller: _scrollController, children: _makeWidgets(), ), ), ・・・ } List<Widget> _makeWidgets() { if (_selectedIndex == 0) { return _makeCndsWidgets(); } else { return _makeListWidgets(); } } ・・・ // 一覧表を表示するWidgets List<Widget> _makeListWidgets() { ・・・ Row ( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ ・・・ Container( margin: const EdgeInsets.fromLTRB(5, 0, 5, 5), padding: const EdgeInsets.fromLTRB(5, 0, 5, 0), child: ElevatedButton( // 情報一覧リストへ、del_do、httpアクセス onPressed: (){httpForDelDo(element["id"]);}, style: ElevatedButton.styleFrom( primary: Colors.blue, ), child: const Text("削除"), ), ), ], ) ), ); } } return contentWidgets; ・・・ /// 情報一覧リストへ、del_doで、httpアクセス void httpForDelDo(int _id) { httpForInfo("del_do", "http://192.168.1.13:8080/members/admin/user/userA/del_do", _id); } ・・・ /// 情報詳細、情報変更、情報削除へのhttpアクセス void httpForInfo(String _mode, String _url, int _id) async { try { UserForm _userForm = UserForm.initData(); _userForm.id = _id; String _userFormJson = _userForm.toJson(_mode, "${widget.cookies['XSRF-TOKEN']}", _userSrchForm.page); widget.headers["content-type"]= "application/json; charset=UTF-8"; widget.headers["X-XSRF-TOKEN"]= "${widget.cookies['XSRF-TOKEN']}"; final url = Uri.parse(_url); http.Response response = await http.post(url,headers: widget.headers, body: _userFormJson); if (response.statusCode != 200) { setState(() { int statusCode = response.statusCode; if (response.statusCode == 401) { _errorSuccessMsg = "ログインしてください"; } else { _errorSuccessMsg = "エラーが発生しました $statusCode"; } }); 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.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 == 'detail') { //情報登録 Navigator.of(context).push( MaterialPageRoute( builder: (context) => UserDetail(title: widget.title, username: widget.username, headers: widget.headers, cookies: widget.cookies, resData: _resData), ), ); } else if (_messageForm.mode == 'upd') { //情報登録 Navigator.of(context).push( MaterialPageRoute( builder: (context) => UserRegisterAmend(title: widget.title, username: widget.username, headers: widget.headers, cookies: widget.cookies, resData: _resData), ), ); // _mode=='list_back'(エラーになった場合または、削除OK)を想定 } else { setState(() { // 検索結果リスト表示 _selectedIndex = 1; _userSrchForm.fromJson(_resData); // From値を、TextFormFieldに設定する。補足:TextFormField以外は直接Formを見ている。 _userSrchForm.forUserSrchFormController(_nameController, _emailController ); _errorSuccessMsg = _userSrchForm.errorMessage + _userSrchForm.successMessage; if (_errorSuccessMsg == '' && _userSrchForm.itemErrorMessages != '') { _errorSuccessMsg = '項目エラーを確認してください'; // 検索画面表示 _selectedIndex = 0; } // 並び順指定があればドロップダウンリストはそれにする。 if (_userSrchForm.sortItemName == "") { _selectItem = 0; } else { for (int i = 0; i < _selectItems.length; i++) { if (_selectItems[i] == _userSrchForm.sortItemName) { _selectItem = i; break; } } } }); // 画面を先頭に戻す _scrollController.animateTo(0, duration: const Duration(milliseconds:600), curve: Curves.easeInQuint); } } } on Exception catch (ex) { setState(() { _errorSuccessMsg = "エラーが発生しました" + ex.toString(); }); } }
■SpringBootバックエンドがわのController抜粋
・PC・スマホ向け共通Controller
public class UserCommController { ・・・ /** * ユーザー情報リスト一覧表示処理 * ページリンク押下により、ユーザー情報リスト一覧を表示する処理 * * @param userFForm Flutter向けユーザー情報+ページ番号 * @param id ID * @param model モデル * @param pageable ページ * @param flutterFlg true:Flutter用 false:PC・WEB用 * @return Flutter用:jsonデータ PC・WEB用:遷移先 */ protected Object userDelDoComm(UserFForm userFForm, Long id, Model model, Pageable pageable, boolean flutterFlg) { log.info("delete form user:{}", id); try { userService.delete(id); } catch(Exception e){ if (e.getMessage() != null && e.getMessage().equals("invalid pk")) { model.addAttribute("successMessage", "『id』=" + id +"は既に削除されています"); } else { e.printStackTrace(); log.error("エラーが発生しました", e); model.addAttribute("errorMessage", "エラーが発生しました"); } userListBackSub(model, pageable); if (flutterFlg) { userListBackSubForFlutter(userFForm.get_csrf(), model); } return returnComm("/members/admin/user/userList", model, null, flutterFlg, "userSrchFForm"); } userListBackSub(model, pageable); model.addAttribute("successMessage", "ユーザー情報削除(" + "『id』=" + id + ")が完了しました"); if (flutterFlg) { userListBackSubForFlutter(userFForm.get_csrf(), model); } return returnComm("/members/admin/user/userList", model, null, flutterFlg, "userSrchFForm"); } private void userListBackSubForFlutter(String csrf, Model model) { UserSrchFForm userSrchFForm = new UserSrchFForm(); userSrchFForm.set_csrf(csrf); //同一プロパティ(型名まで同じもの)コピー BeanUtils.copyProperties(this.sessionUserSrchForm.getUserSrchForm(), userSrchFForm); BeanUtils.copyProperties(this.sessionUserSrchOrderForm.getSrchOrderForm(), userSrchFForm); Map<String, Object> modelMap = model.asMap(); userSrchFForm.setPage(((Page)modelMap.get("page")).getNumber() + 1); // Flutter向け検索条件+ソート条件+ページ番号 model.addAttribute("userSrchFForm", userSrchFForm); model.addAttribute("mode", "list_back"); }
・スマホ向けController
public class UserFlutterController extends UserCommController { ・・・ /** * ユーザー情報削除処理 * * @param userFForm Flutter向けユーザー情報+ページ番号 * @param mode モード * @return */ @SuppressWarnings("unchecked") @PostMapping("/members/admin/user/userA/del_do") @ResponseBody public Map<String, Object> userDelDo(@RequestBody UserFForm userFForm, Model model) { int page = ObjectUtils.isEmpty(userFForm.getPage())||userFForm.getPage()==0?0:userFForm.getPage()-1; Pageable pageable = PageRequest.of(page, pageableDefaultSize, Sort.unsorted()); return ( Map<String, Object>)userDelDoComm(userFForm, userFForm.getId(), model, pageable, true); }
・PC向けController
public class UserPcController extends UserCommController { ・・・ /** * ユーザー情報削除処理 * * @param mode モード * @param id ID * @param model モデル * @param pageable ページ * @return */ @PostMapping(params="mode=del_do") public String userDelDo(@RequestParam("mode") String mode, @RequestParam("id") Long id, Model model, @PageableDefault( size=pageableDefaultSize ) Pageable pageable) { return (String)userDelDoComm(null, id, model, pageable, false); }
■2022/06/15に、勉強した成果:『Flutter_JavaSpringプログラム自動作成◎自動生成ツール』をVectorに載せました。Zenn本も書きました。使ってみての感想や間違いの指定や、こうやったほうがいいとかの情報があればメールください。
・Vector
www.vector.co.jp
・Zenn本(Flutter_JavaSpringプログラム自動作成)
zenn.dev