kazpgmの日記

『プログラム自動作成@自動生成』作成の日記

フロント側を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