kazpgmの日記

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

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

14:09
①昨日Flutter側のページングを作ったので、今日はバックエンドSpringBoot側を作っている。
16:32
①昨日作ったFlutter側のページングダメなところが出てきた。例えば”[最初]”のバリューが0で、当ページが0なら、1つのドロップダウンリストに同じバリューが複数できて、例外が発生する。
ので、'[最初]'は-20、'[前グループ]'は「((pageNumberGroup - 1) * maxPageSizes - 1)*-1 - 20」、'[前ページ]'は「(pageNumber0Org - 1)*-1 - 20」、'[次ページ]'は「(pageNumber0Org + 1)*-1 -20」、'[次グループ]'は「(((pageNumberGroup * maxPageSizes) - 1) + 1)*-1 - 20」、'[最後]'は「(totalPages - 1)*-1 -20」にして、ドロップダウンリストのバリューが-20よりマイナスの時は、+20して*-1して正の値にする。ってことにしよう。
もともと-1~-19までは処理しないために使用しているので、-20以下を使うって感じ。
22:44
①例外はこんなもんだった。ほんと、手こずった。自分的には、”よくやるよ”って感じのでき。ほめていない。こんぽん原因はpageを0起算にするか1起算にするかがうまくハンドリングできなかったことだった。javaのPageオブジェクトでは0起算、画面は1起算がどこかでうまくいかなかった。
 ”There should be exactly one item with value 0.
 Either zero or 2 or more Items were detected with the same value.”
 をgoogle翻訳で、
 ”値が0のアイテムが1つだけ存在する必要があります。
 ゼロまたは2つ以上のアイテムが同じ値で検出されました。”
■Flutter側スマホ画面
f:id:kazpgm:20220303224650p:plain
f:id:kazpgm:20220303224728p:plain
↓2ページを選択
f:id:kazpgm:20220303224822p:plain
■PC側WEB画面
f:id:kazpgm:20220303230921p:plain
■Flutter側プロフラム

class _UserListState extends State<UserList> {
・・・
  Widget build(BuildContext context) {
・・・
      body: Form(
        key: _formKey,
        child : ListView(
          controller: _scrollController,
          children: _makeWidgets(),
       ),
      ),
・・・
  }
  List<Widget> _makeWidgets() {
      if (_selectedIndex == 0) {
        return _makeCndsWidgets();
      } else {
        return _makeListWidgets();
      }
  }
・・・
  List<Widget> _makeListWidgets() {
・・・
      contentWidgets.add(Center(
        // ページ指定選択
        child:Wrap(
          //mainAxisAlignment: MainAxisAlignment.center,
          direction: Axis.horizontal,
          children: <Widget>[
            DropdownButton(
              items: getPageDropDown(5,
                  _userSrchForm.pageObjSize,
                  _userSrchForm.pageObjTotalPages,
                  _userSrchForm.page),
              value: _userSrchForm.page>0?_userSrchForm.page-1:0,
              icon: const Icon(Icons.arrow_downward),
              elevation: 16,
              style: const TextStyle(color: Colors.deepPurple),
              underline: Container(
                height: 2,
                color: Colors.deepPurpleAccent,
              ),
              onChanged: (value) {
                setState(() {
                  // ページ指定可能な物のみ処理する
                  int intWk = (value as int);
                  // -20以下または、0以上(-1から-19の時は何もしない)
                  if (intWk <= -20 || intWk >= 0) {
                    if (intWk <= -20) {
                      // -20よりマイナスの時は、+20して*-1して正の値にし、+1(画面用ページ番号は+1するので)する。
                      intWk = (intWk + 20) * -1 + 1;
                    } else {
                      // +1(画面用ページ番号は+1するので)する。
                      intWk += 1;
                    }
                    if (intWk != _userSrchForm.page) {
                      _userSrchForm.page = intWk;
                      // 情報一覧リストへ、list_backで、httpアクセス
                      httpForListBack();
                    }
                  }
                }
                );
              },
            ),
            // 並び順選択
       ・・・
       ]),
      ),
      );
      ・・・
    return contentWidgets;
  }

  /// ページング用DropdownMenuItemを戻す
  ///
  /// maxPageSizes 1画面あたりのページ数
  /// contentSize 1ページのレコード数
  /// totalPages 総ページ数
  /// pageNumber 現在のページ番号
  /// return ページング用DropdownMenuItem
  static List<DropdownMenuItem<int>> getPageDropDown(int maxPageSizes, int contentSize, int totalPages, int pageNumberBase) {
    List<DropdownMenuItem<int>> _items = <DropdownMenuItem<int>>[];
    int totalGroups = (totalPages / (maxPageSizes + 0.0)).ceil();
    int pageNumber = contentSize == 0 ? 0 : pageNumberBase;
    int pageNumberGroup = (pageNumber / (maxPageSizes + 0.0)).ceil();
    int startPage = (pageNumberGroup - 1) * maxPageSizes + 1;
    int endPage = startPage + maxPageSizes - 1;
    if (endPage >= totalPages) {
      endPage = totalPages;
    }

    int pageNumber0Org = pageNumber - 1;
    Map<int,int> _minusMap = {};
    if (pageNumberGroup > 1) {
      _items.add(getPageMinusItem('[最初]', _minusMap, 0 - 20, -3));
      _items.add(getPageMinusItem('[前グループ]', _minusMap, ((pageNumberGroup - 1) * maxPageSizes - 1)*-1 - 20, -4));
    } else {
      _items.add(const DropdownMenuItem(
        value: -5,
        child: Text('[最初]', style: TextStyle(fontWeight: FontWeight.normal, color: Colors.grey)),
      ));
    }
    if (pageNumber == 1) {
      _items.add(const DropdownMenuItem(
        value: -6,
        child: Text('[前ページ]', style: TextStyle(fontWeight: FontWeight.normal, color: Colors.grey)),
      ));
    } else {
      _items.add(getPageMinusItem('[前ページ]', _minusMap, (pageNumber0Org - 1)*-1 - 20, -7));
    }
    for (int i = startPage; i <= endPage; i++) {
      if (pageNumber == i) {
        _items.add(DropdownMenuItem(
          value: i - 1,
          child: Text('[' + CommUtils.chgToString(i) + ']', style: const TextStyle(fontWeight:FontWeight.w900, color: Colors.black, backgroundColor: Colors.yellow)),
        ));
      } else {
        _items.add(DropdownMenuItem(
          value: i - 1,
          child: Text('[' + CommUtils.chgToString(i) + ']', style: const TextStyle(fontWeight: FontWeight.normal, color: Colors.black)),
        ));
      }
    }
    if (pageNumber == totalPages || totalPages == 1 || totalPages == 0) {
      if (totalPages == 0) {
        _items.add(const DropdownMenuItem(
          value: -8,
          child: Text('[1]', style: TextStyle(
              fontWeight: FontWeight.normal, color: Colors.grey)),
        ));
        _items.add(const DropdownMenuItem(
          value: -9,
          child: Text('[次ページ]"', style: TextStyle(
              fontWeight: FontWeight.normal, color: Colors.grey)),
        ));
      } else {
        _items.add(const DropdownMenuItem(
          value: -10,
          child: Text('[次ページ]', style: TextStyle(
              fontWeight: FontWeight.normal, color: Colors.grey)),
        ));
      }
    } else {
      _items.add(getPageMinusItem('[次ページ]', _minusMap, (pageNumber0Org + 1)*-1 - 20, -11));
    }
    if (pageNumberGroup < totalGroups) {
      _items.add(getPageMinusItem('[次グループ]', _minusMap, (((pageNumberGroup * maxPageSizes) - 1) + 1)*-1 - 20, -12));
      _items.add(getPageMinusItem('[最後]', _minusMap, (totalPages - 1)*-1 - 20, -13));
    } else {
      _items.add(const DropdownMenuItem(
        value: -14,
        child: Text('[最後]', style: TextStyle(fontWeight: FontWeight.normal, color: Colors.grey)),
      ));
    }
    return _items.toList();
  }

  static DropdownMenuItem<int> getPageMinusItem(String str, Map<int,int> minusMap, int minusVal, int constVal) {
    // すでに設定したバリューの場合
    if (minusMap.containsKey(minusVal)) {
      return  DropdownMenuItem(
        // 指定の値にする
        value: constVal,
        child: Text(str, style: const TextStyle(fontWeight: FontWeight.normal, color: Colors.grey)),
      );
    } else {
      minusMap[minusVal] = minusVal;
      return  DropdownMenuItem(
        value: minusVal,
        child: Text(str, style: const TextStyle(fontWeight: FontWeight.normal, color: Colors.black)),
      );
    }
  }

④これがSpringBootバックエンドがわのController抜粋
・PC・スマホ向け共通Controller

public class UserCommController {
・・・
	/**
	 * リターン共通処理(Flutter、PC・WEB共用)
	 * リターン共通処理
	 *
	 * @param url 遷移先
	 * @param model モデル
	 * @param result チェック結果
	 * @param flutterFlg true:Flutter用 false:PC・WEB用
	 * @param resFormName Flutter用レスポンスForm名
	 * @return Flutter用String:jsonデータ PC・WEB用 Map<String, Object>:遷移先
	 */
	protected Object returnComm(String url ,Model model,BindingResult result, boolean flutterFlg, String resFormName) {
		if (flutterFlg) {
			ResData resData = new ResData(model, result);
	        return resData.getResDataMap(messageSource, resFormName);
		} else {
			return url;
		}
	}
・・・
	protected Object  userListBackComm(SrchOrderFForm srchOrderFForm, Model model, Pageable pageable, boolean flutterFlg) {
		//補足:フロント側がFlutter時のsrchOrderFormはsrchOrderFFormを指しています。
		userListBackSub(model, pageable);
		if (flutterFlg) {
			UserSrchFForm userSrchFForm = new UserSrchFForm();
			//同一プロパティ(型名まで同じもの)コピー
			BeanUtils.copyProperties(this.sessionUserSrchForm.getUserSrchForm(), userSrchFForm);
			BeanUtils.copyProperties(srchOrderFForm, userSrchFForm);
			Map<String, Object> modelMap = model.asMap();
			userSrchFForm.setPage(((Page)modelMap.get("page")).getNumber() + 1);
			// Flutter向け検索条件+ソート条件+ページ番号
			model.addAttribute("userSrchFForm", userSrchFForm);
		}
		return returnComm("/members/admin/user/userList", model, null, flutterFlg, "userSrchFForm");
	}

	/**
	 * userListBackSubメソッド
	 * ユーザー情報リスト一覧表示サブ処理
	 * 
	 * @param model モデル
	 * @param pageable ページ
	 */
	protected void userListBackSub(Model model, Pageable pageable) {
		userListSub(this.sessionUserSrchForm.getUserSrchForm(), this.sessionUserSrchOrderForm.getSrchOrderForm(), model, pageable);
		model.addAttribute("userSrchForm", this.sessionUserSrchForm.getUserSrchForm());
		model.addAttribute("srchOrderForm", this.sessionUserSrchOrderForm.getSrchOrderForm());
	}

スマホ向けController

public class UserFlutterController extends UserCommController {
・・・
	/**
	 * ユーザー情報リスト一覧表示処理
	 * ページリンク押下により、ユーザー情報リスト一覧を表示する処理
	 * 
	 * @param mode モード
	 * @param model モデル
	 * @param pageable ページ
	 * @return 遷移先 
	 */
	@SuppressWarnings("unchecked")
	@PostMapping("/members/admin/user/userA/list_back")
	@ResponseBody
	public Map<String, Object> userListBack(@RequestBody SrchOrderFForm srchOrderFForm,
			Model model) {
		int page = ObjectUtils.isEmpty(srchOrderFForm.getPage())||srchOrderFForm.getPage()==0?0:srchOrderFForm.getPage()-1;
	    Pageable pageable = PageRequest.of(page, pageableDefaultSize, Sort.unsorted());
		return (Map<String, Object>)userListBackComm(srchOrderFForm, model, pageable, true);
	}

・PC向けController

public class UserPcController extends UserCommController {
	/**
	 * ユーザー情報リスト一覧表示処理
	 * ページリンク押下により、ユーザー情報リスト一覧を表示する処理
	 * 
	 * @param mode モード
	 * @param model モデル
	 * @param pageable ページ
	 * @return 遷移先 
	 */
	@PostMapping(params="mode=list_back")
	public String userListBack(
			@RequestParam("mode") String mode,
			Model model, 
			@PageableDefault(
				  			size=pageableDefaultSize
                          ) 
			Pageable pageable) {
		return (String)userListBackComm(null, model, pageable, false);
	}