kazpgmの日記

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

フロント側をFlutter(スマホ)Thymeleaf(PC)、バックエンド側SpringBootの自動作成勉強中

9:04
①情報一覧画面に遷移したとき、検索タブになるが、先頭TextFieldにフォーカスが当たって、キーボードが出ているけど、BottomNavigationBarの「検索タブアイコン」「リストタブアイコン」が見えない。ので、フォーカスあてるのやめる。
■user_list.dart
 ・以下の「_myFocusNode」に関する箇所をコメントにしたので、PGMソースからは削除する。
  余談:ユーザー情報登録更新画面(user_register_amend.dart)からは修正しない。現在のまま、先頭TextFieldにフォーカスを当てる。

//  late FocusNode _myFocusNode;
・・・
  List<Widget> _makeCndsWidgets() {
・・・
            children:<Widget>[TextFormField(
//              // フォームを含むウィジェットが作成された時点でフォーカスする。
//              autofocus: true,
              controller: _nameController,
//              focusNode: _myFocusNode,
              decoration: const InputDecoration(
                labelText: "名前",
                hintText: '全角カナ 前方一致',
              ),
・・・
  }

  /// 情報一覧リストへのhttpアクセス
  void httpForList(String _mode, String _url) async {
・・・
    // 画面を先頭に戻す
    _scrollController.animateTo(0,
        duration: const Duration(milliseconds:600),
        curve: Curves.easeInQuint);
//    _myFocusNode.requestFocus();
  }
・・・
  @override
  void initState() {
・・・
//    _myFocusNode = FocusNode();
・・・
  }
・・・
  @override
  void dispose() {
    _scrollController.dispose();
//    _myFocusNode.dispose();
    // Clean up the focus node when the Form is disposed.
    super.dispose();
  }

■情報一覧画面に遷移したときの、修正前画面(先頭TextFieldにフォーカスが当たって、キーボードが出ているので、検索タブアイコン」「リストタブアイコン」が見えない。)

■情報一覧画面に遷移したときの、修正後画面(キーボードは出ていないので、検索タブアイコン」「リストタブアイコン」が見える。)

11:03
①昨日、”③いろいろ考えたが、こんな制約が必要なことになった。”としたが、この制約がなくてもOKなようにするための調査をしている。
11:44
 結果、バックエンドSpring側UserFForm,.javaを以下のように変更することで、うまくいくことが分かった。もちろんFlutter側のjsonMapの変更も必要だけど。
 これに沿って手直ししていく。
■今までのバックエンドSpring側UserFForm,.java(UserForm.javaを拡張していた)

@Data
@EqualsAndHashCode(callSuper=false)
@NoArgsConstructor
@AllArgsConstructor
@Component
public class UserFForm extends UserForm implements Serializable {	
	private static final long serialVersionUID = 1L;
	private String roles; //ロール(詳細表示用)
	private String mode;
	private String _csrf;
	private Integer page;
}

■これからのバックエンドSpring側UserFForm,.java(UserForm.javaを包含する)→18:25にさらに修正した。

@Data
@EqualsAndHashCode(callSuper=false)
@NoArgsConstructor
@AllArgsConstructor
@Component
public class UserFForm implements Serializable {
	private static final long serialVersionUID = 1L;
	@Valid
	private UserForm userForm;
	private String roles; //ロール(詳細表示用)
	private String mode;
	private String _csrf;
	private Integer page;
}

18:25 上記11:44を修正した。
■これからのバックエンドSpring側UserFForm,.java(UserForm.javaを包含する)
 さらに、mode、_csrf、pageをFormComm.javaにして包含した。

package com.kaz02u.demo.fForm;
・・・
@Data
@EqualsAndHashCode(callSuper=false)
@NoArgsConstructor
@AllArgsConstructor
@Component
public class UserFForm2 implements Serializable {
	private static final long serialVersionUID = 1L;
	@Valid
	private UserForm userForm;
	private String roles; //ロール(詳細表示用)
	private FormComm formComm;
}

package com.kaz02u.demo.fForm;
・・・
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FormComm implements Serializable {
	private static final long serialVersionUID = 1L;
	private String mode;
	private String _csrf;
	private Integer page;
}

19:02 フロントFlutter側のuser_form.dartを、バックエンドSpringの修正内容に合わせた。
■今までのフロントFlutter側のuser_form.dart(MessageFormを継承している)

import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter_app/form/message_form.dart';

/// ユーザー情報画面Form
class UserForm extends MessageForm{
  //プロパティ 入出力データ用
  late int id; // ID
  late String name; // 名前
  late String email; // メールアドレス
  late String password; // パスワード
  late String passwordConfirm; // パスワード確認
  late List<String> rolesArray; // ロール
  late String roles; // ロール (詳細表示用)
  // バックエンド(SpringBoot)のFormでBooleanだけどStringで処理する
  late String enableFlag; // 可否フラグ
  //プロパティ エラーメッセージ用
  late List<String> idErr; // ID
  late List<String> nameErr; // 名前
  late List<String> emailErr; // メールアドレス
  late List<String> passwordErr; // パスワード
  late List<String> passwordConfirmErr; // パスワード確認
  late List<String> checkPasswordPasswordConfirmErr; // パスワード、パスワード確認の相関チェック
  late List<String> rolesArrayErr; // ロール
  late List<String> enableFlagErr; // 可否フラグ

  /// コンストラクタ
  // Dartでは「コンストラクタ名.任意名称」で複数のコンストラクタを定義する
  // 「UserForm(this.name,・・・);」コンストラクタはいらないので,
  // これだけにする。
  // 初期値のクラスを作成している
  UserForm.initData() : super.initData() {
    //入出力データ用
    id = 0;
    name = "";
    email = "";
    password = "";
    passwordConfirm = "";
    rolesArray = <String>[];
    roles = "";
    enableFlag = "";
    //エラーメッセージ用
    idErr = <String>[];
    nameErr = <String>[];
    emailErr = <String>[];
    passwordErr = <String>[];
    passwordConfirmErr = <String>[];
    checkPasswordPasswordConfirmErr = <String>[];
    rolesArrayErr = <String>[];
    enableFlagErr = <String>[];
  }

  /// HTTPレスポンスデータを反映する
  @override
  fromJson(String resData) {
    Map<String,dynamic> _resDataMap =
              jsonDecode(resData);
    //入出力データ用
    if (_resDataMap["resForm"]==null) {
      id = 0;
      name = "";
      email = "";
      password = "";
      passwordConfirm = "";
      rolesArray = <String>[];
      roles = "";
      enableFlag = "";
    } else {
      id = _resDataMap["resForm"]["id"] ?? 0;
      name = _resDataMap["resForm"]["name"] ?? "";
      email = _resDataMap["resForm"]["email"] ?? "";
      password = _resDataMap["resForm"]["password"] ?? "";
      passwordConfirm = _resDataMap["resForm"]["passwordConfirm"] ?? "";
      //jsonから読み込んだときのエラー(”type 'List<dynamic>' is not a subtype of type 'List<String>'”)に
      // 対応し、".cast<String>()"でキャストした
      rolesArray = _resDataMap["resForm"]["rolesArray"]!=null?_resDataMap["resForm"]["rolesArray"].cast<String>():<String>[];
      roles = _resDataMap["resForm"]["roles"] ?? "";
      enableFlag = "";
      if (_resDataMap["resForm"]["enableFlag"] != null) {
        if (_resDataMap["resForm"]["enableFlag"]) {
          enableFlag = "true";
        } else {
          enableFlag = "false";
        }
      }
    }
    //エラーメッセージ用
    if (_resDataMap["resErrorData"]==null) {
      idErr = <String>[];
      nameErr = <String>[];
      emailErr = <String>[];
      passwordErr = <String>[];
      passwordConfirmErr = <String>[];
      checkPasswordPasswordConfirmErr = <String>[];
      rolesArrayErr = <String>[];
      enableFlagErr = <String>[];
    } else {
      idErr = _resDataMap["resErrorData"]["id"]!=null?_resDataMap["resErrorData"]["id"].cast<String>():<String>[];
      nameErr = _resDataMap["resErrorData"]["name"]!=null?_resDataMap["resErrorData"]["name"].cast<String>():<String>[];
      emailErr = _resDataMap["resErrorData"]["email"]!=null?_resDataMap["resErrorData"]["email"].cast<String>():<String>[];
      passwordErr = _resDataMap["resErrorData"]["password"]!=null?_resDataMap["resErrorData"]["password"].cast<String>():<String>[];
      passwordConfirmErr = _resDataMap["resErrorData"]["passwordConfirm"]!=null?_resDataMap["resErrorData"]["passwordConfirm"].cast<String>():<String>[];
      checkPasswordPasswordConfirmErr = _resDataMap["resErrorData"]["checkPasswordPasswordConfirm"]!=null?_resDataMap["resErrorData"]["checkPasswordPasswordConfirm"].cast<String>():<String>[];
      rolesArrayErr = _resDataMap["resErrorData"]["rolesArray"]!=null?_resDataMap["resErrorData"]["rolesArray"].cast<String>():<String>[];
      enableFlagErr = _resDataMap["resErrorData"]["enableFlag"]!=null?_resDataMap["resErrorData"]["enableFlag"].cast<String>():<String>[];
    }
    super.fromJson(resData);
  }

  /// HTTPレスポンスデータを作成する
  @override
  Map<String,dynamic> toJsonMap (String _mode, String _csrf, int page) {
    Map<String,dynamic> rtnMap = {
      'id': id,
      'name': name,
      'email': email,
      'password': password,
      'passwordConfirm': passwordConfirm,
      'rolesArray': rolesArray,
      'enableFlag': enableFlag,
    };
    rtnMap.addAll(super.toJsonMap(_mode, _csrf, page));
    return rtnMap;
  }

  /// 入出力データを、TextFormFieldに設定する
  forUserFormController(
      TextEditingController nameController,
      TextEditingController emailController,
      TextEditingController passwordController,
      TextEditingController passwordConfirmController
      ) {
    nameController.text = name;
    emailController.text = email;
    passwordController.text = password;
    passwordConfirmController.text = passwordConfirm;
  }

  /// TextFormField値を、入出力データに設定する
  fromUserFormController(
      TextEditingController nameController,
      TextEditingController emailController,
      TextEditingController passwordController,
      TextEditingController passwordConfirmController
      ) {
    name = nameController.text;
    email = emailController.text;
    password = passwordController.text;
    passwordConfirm = passwordConfirmController.text;
  }
}

■これからのフロントFlutter側のuser_form.dart(MessageFormを包含している)→明日の日記でさらに修正している。

import 'dart:convert';
import 'package:flutter/cupertino.dart';

import 'message_form.dart';

/// ユーザー情報画面Form
class UserForm {
  //プロパティ 入出力データ用
  late int id; // ID
  late String name; // 名前
  late String email; // メールアドレス
  late String password; // パスワード
  late String passwordConfirm; // パスワード確認
  late List<String> rolesArray; // ロール
  late String roles; // ロール (詳細表示用)
  // バックエンド(SpringBoot)のFormでBooleanだけどStringで処理する
  late String enableFlag; // 可否フラグ
  //プロパティ エラーメッセージ用
  late List<String> idErr; // ID
  late List<String> nameErr; // 名前
  late List<String> emailErr; // メールアドレス
  late List<String> passwordErr; // パスワード
  late List<String> passwordConfirmErr; // パスワード確認
  late List<String> checkPasswordPasswordConfirmErr; // パスワード、パスワード確認の相関チェック
  late List<String> rolesArrayErr; // ロール
  late List<String> enableFlagErr; // 可否フラグ
  // 共通・メッセージ
  late MessageForm messageForm; // 共通・メッセージ

  /// コンストラクタ
  // Dartでは「コンストラクタ名.任意名称」で複数のコンストラクタを定義する
  // 「UserForm(this.name,・・・);」コンストラクタはいらないので,
  // これだけにする。
  // 初期値のクラスを作成している
  UserForm.initData()  {
    //入出力データ用
    id = 0;
    name = "";
    email = "";
    password = "";
    passwordConfirm = "";
    rolesArray = <String>[];
    roles = "";
    enableFlag = "";
    //エラーメッセージ用
    idErr = <String>[];
    nameErr = <String>[];
    emailErr = <String>[];
    passwordErr = <String>[];
    passwordConfirmErr = <String>[];
    checkPasswordPasswordConfirmErr = <String>[];
    rolesArrayErr = <String>[];
    enableFlagErr = <String>[];
    // 共通・メッセージ
    messageForm = MessageForm.initData();
  }

  /// HTTPレスポンスデータを反映する
  fromJson(String resData) {
    Map<String,dynamic> _resDataMap =
              jsonDecode(resData);
    //入出力データ用
    if (_resDataMap["resForm"]==null) {
      id = 0;
      name = "";
      email = "";
      password = "";
      passwordConfirm = "";
      rolesArray = <String>[];
      roles = "";
      enableFlag = "";
    } else {
      id = _resDataMap["resForm"]["id"] ?? 0;
      name = _resDataMap["resForm"]["name"] ?? "";
      email = _resDataMap["resForm"]["email"] ?? "";
      password = _resDataMap["resForm"]["password"] ?? "";
      passwordConfirm = _resDataMap["resForm"]["passwordConfirm"] ?? "";
      //jsonから読み込んだときのエラー(”type 'List<dynamic>' is not a subtype of type 'List<String>'”)に
      // 対応し、".cast<String>()"でキャストした
      rolesArray = _resDataMap["resForm"]["rolesArray"]!=null?_resDataMap["resForm"]["rolesArray"].cast<String>():<String>[];
      roles = _resDataMap["resForm"]["roles"] ?? "";
      enableFlag = "";
      if (_resDataMap["resForm"]["enableFlag"] != null) {
        if (_resDataMap["resForm"]["enableFlag"]) {
          enableFlag = "true";
        } else {
          enableFlag = "false";
        }
      }
    }
    //エラーメッセージ用
    if (_resDataMap["resErrorData"]==null) {
      idErr = <String>[];
      nameErr = <String>[];
      emailErr = <String>[];
      passwordErr = <String>[];
      passwordConfirmErr = <String>[];
      checkPasswordPasswordConfirmErr = <String>[];
      rolesArrayErr = <String>[];
      enableFlagErr = <String>[];
    } else {
      idErr = _resDataMap["resErrorData"]["userForm.id"]!=null?_resDataMap["resErrorData"]["userForm.id"].cast<String>():<String>[];
      nameErr = _resDataMap["resErrorData"]["userForm.name"]!=null?_resDataMap["resErrorData"]["userForm.name"].cast<String>():<String>[];
      emailErr = _resDataMap["resErrorData"]["userForm.email"]!=null?_resDataMap["resErrorData"]["userForm.email"].cast<String>():<String>[];
      passwordErr = _resDataMap["resErrorData"]["userForm.password"]!=null?_resDataMap["resErrorData"]["userForm.password"].cast<String>():<String>[];
      passwordConfirmErr = _resDataMap["resErrorData"]["userForm.passwordConfirm"]!=null?_resDataMap["resErrorData"]["userForm.passwordConfirm"].cast<String>():<String>[];
      checkPasswordPasswordConfirmErr = _resDataMap["resErrorData"]["userForm.checkPasswordPasswordConfirm"]!=null?_resDataMap["resErrorData"]["userForm.checkPasswordPasswordConfirm"].cast<String>():<String>[];
      rolesArrayErr = _resDataMap["resErrorData"]["userForm.rolesArray"]!=null?_resDataMap["resErrorData"]["userForm.rolesArray"].cast<String>():<String>[];
      enableFlagErr = _resDataMap["resErrorData"]["userForm.enableFlag"]!=null?_resDataMap["resErrorData"]["userForm.enableFlag"].cast<String>():<String>[];
    }
    messageForm.fromJson(resData);
  }

  /// HTTPレスポンスデータを作成する
  Map<String,dynamic> toJsonMap (String _mode, String _csrf, int page) {
    Map<String,dynamic> userFormMap = {
      'id': id,
      'name': name,
      'email': email,
      'password': password,
      'passwordConfirm': passwordConfirm,
      'rolesArray': rolesArray,
      'enableFlag': enableFlag,
    };
    Map<String,dynamic> rtnMap = {
      'userForm': userFormMap,
      'formComm': messageForm.toJsonMap(_mode, _csrf, page),
    };
    return rtnMap;
  }

  /// http.postのbodyで使用するJsonデータを返却する
  String toJson(String _mode, String _csrf, [int page=1]) {
    return json.encode(toJsonMap(_mode, _csrf, page));
  }

  /// 入出力データを、TextFormFieldに設定する
  forUserFormController(
      TextEditingController nameController,
      TextEditingController emailController,
      TextEditingController passwordController,
      TextEditingController passwordConfirmController
      ) {
    nameController.text = name;
    emailController.text = email;
    passwordController.text = password;
    passwordConfirmController.text = passwordConfirm;
  }

  /// TextFormField値を、入出力データに設定する
  fromUserFormController(
      TextEditingController nameController,
      TextEditingController emailController,
      TextEditingController passwordController,
      TextEditingController passwordConfirmController
      ) {
    name = nameController.text;
    email = emailController.text;
    password = passwordController.text;
    passwordConfirm = passwordConfirmController.text;
  }
}

■2022/06/15に、勉強した成果:『Flutter_JavaSpringプログラム自動作成◎自動生成ツール』をVectorに載せました。Zenn本も書きました。使ってみての感想や間違いの指定や、こうやったほうがいいとかの情報があればメールください。
Vector
www.vector.co.jp
・Zenn本(Flutter_JavaSpringプログラム自動作成)
zenn.dev