こんにちは。船井総研デジタルのいっちーです。
前回の記事では、画面遷移を作成しました。
今回は、ロジックを組み込んで、画面(フロントサイド)とサーバ(バックサイド)でデータの授受ができるようにしていきます。長くなると思いますので、何回かに分けて投稿したいと思います。
データのやり取りを考える
画面遷移の際に、どのようなデータがやり取りされるかを考えます。
メイン画面
メイン画面とサーバの間でやり取りされるデータを洗い出していきます。
サーバーから画面に送られるデータ
No | データ | 繰り返し | 備考 |
---|---|---|---|
1 | つぶやき | あり | - |
2 | エラーメッセージ | あり | 処理時にエラーが発生した場合のみ。エラーメッセージがなければ表示エリアそのものを出力しない。 |
3 | ページ情報 | なし | - |
画面からサーバーに送られるデータ
No | データ | 繰り返し | 備考 |
---|---|---|---|
4 | つぶやき | なし | 処理時にエラーが発生した場合、表示中のページに戻すため、自ページ番号を一緒に送る。 |
ねぎ登録画面
ねぎ登録画面とサーバの間でやり取りされるデータを洗い出していきます。
ねぎマスタの主キーであるIDを非表示項目として画面に渡すことで、対応する「修正」「削除」のボタンを押したときに、対応するねぎ情報のIDをサーバーに返せるようにします。
サーバーから画面に送られるデータ
No | データ | 繰り返し | 備考 |
---|---|---|---|
1 | ねぎ情報 | あり | - |
2 | エラーメッセージ | あり | 処理時にエラーが発生した場合のみ。エラーメッセージがなければ表示エリアそのものを出力しない。 |
画面からサーバーに送られるデータ
No | データ | 繰り返し | 備考 |
---|---|---|---|
3 | 登録情報 | なし | - |
4 | 更新情報 | なし | ボタンの種類で修正/削除を区別し、ねぎマスタのIDを送ることで修正/削除対象のレコードを特定する。 |
データ受け渡しのためのクラスを作成する。
画面とサーバーの間でデータを受け渡すためのクラスを実装していきます。
画面からサーバーに送られるデータ
画面からサーバーに送られるデータは、画面のform
に対応したFormクラスで表現します。前準備として、データのバリデーションを自動的に組み込めるように、pom.xmlのdependenciesに下記の2つを追加します。
(略)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>3.0.3</version>
</dependency>
(略)
つぶやきForm
@Data
@AllArgsConstructor
public class NegiitForm {
@NotBlank(message="お名前は必須項目です。")
@Size(max=128, message="お名前は128文字以下で入力してください。")
private String name;
@NotBlank(message="つぶやきは必須項目です。")
@Size(max=128, message="つぶやきは128文字以下で入力してください。")
private String negiit;
private Integer pageNum;
}
ねぎ登録Form
@Data
@AllArgsConstructor
public class RegisterNegiForm {
@NotBlank(message="ねぎ名称は必須項目です。")
@Size(max=128, message="ねぎ名称は128文字以下で入力してください。")
private String negiName;
}
ねぎ更新Form
@Data
@AllArgsConstructor
public class UpdateNegiForm {
@NotBlank(message="処理区分が設定されていません。")
private String process;
@NotNull(message="処理対象が設定されていません。")
private Integer id;
@NotBlank(message="ねぎ名称が入力されていません。")
@Size(max=128, message="ねぎ名称は128文字以下で入力してください。")
private String negiName;
}
各フィールドに@NotNull
等のアノテーションをつけることによって、項目チェックを組み込むことができます。バリデーション結果は、ControllerクラスのメソッドにBindingResult
型の引数を定義することで受け取ることができます。
サーバーから画面に送られるデータ
サーバーから画面に送られるデータのうち、つぶやきとねぎ情報の2つは、DBテーブルレコードのListとなります。今回MyBatisを使ってO/Rマッピングを行いますので、MyBatis Generatorで必要なソースを自動作成します。
pom.xmlの修正
pom.xmlのpluginsに下記の設定を追加します。
(略)
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.4.1</version>
<configuration>
<configurationFile>
${project.basedir}/src/resources/dev/generatorConfig.xml</configurationFile>
<overwrite>
true</overwrite>
<includeAllDependencies>true</includeAllDependencies>
</configuration>
<dependencies>
<dependency>
<groupId>com.softwareloop</groupId>
<artifactId>mybatis-generator-lombok-plugin</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</plugin>
(略)
configurationFileは、MyBatis Generatorの設定ファイルを格納するパスを指定します。続いて、MyBatis Generatorの設定ファイルを作ります。
MyBatis Generatorの設定
generatorConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="tables" targetRuntime="MyBatis3">
<!-- <plugin type="org.mybatis.generator.plugins.EqualsHashCodePlugin"/> -->
<plugin type="org.mybatis.generator.plugins.MapperAnnotationPlugin" />
<plugin type="com.softwareloop.mybatis.generator.plugins.LombokPlugin" />
<jdbcConnection
driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost/negitter"
userId="user"
password="pass" />
<javaModelGenerator
targetPackage="com.example.negitter.entity"
targetProject="MAVEN" />
<sqlMapGenerator
targetPackage="com.example.negitter.mapper"
targetProject="MAVEN" />
<javaClientGenerator
type="XMLMAPPER"
targetPackage="com.example.negitter.mapper"
targetProject="MAVEN" />
<table tableName="negi_mst" enableInsert="true" enableSelectByPrimaryKey="true"
enableSelectByExample="false" enableUpdateByPrimaryKey="true"
enableDeleteByPrimaryKey="true" enableDeleteByExample="false"
enableCountByExample="false" enableUpdateByExample="false"
selectByPrimaryKeyQueryId="false" selectByExampleQueryId="false">
<generatedKey column="id" sqlStatement="JDBC" />
</table>
<table tableName="message_tbl" enableInsert="true"
enableSelectByPrimaryKey="true"
enableSelectByExample="false" enableUpdateByPrimaryKey="true"
enableDeleteByPrimaryKey="true" enableDeleteByExample="false"
enableCountByExample="false" enableUpdateByExample="false"
selectByPrimaryKeyQueryId="false" selectByExampleQueryId="false">
<generatedKey column="id" sqlStatement="JDBC" />
</table>
</context>
</generatorConfiguration>
ソース生成
VSCodeのMAVENタブを開いていくとmybatis-generatorという項目が追加されていると思いますので、「generate」を実行します。
実行が終わると、targetフォルダ配下に自動生成されたentitiyクラス、mapperクラス、mapper.xmlが格納されますので、これをsrcフォルダ内のしかるべきパスに配置します。
後の工程でこれらのソースを手書きで修正していきますが、手書き修正したソースと自動生成したソースが混在すると、デグレしたりして管理が面倒なことになるので、十分お気をつけください。
受け渡しデータの定義をControllerクラスに追加する
設計したデータ定義に基づいて、Controllerクラスを修正します。
画面からサーバーに送られるデータ
ControllerクラスのPost/GetMappingしているメソッドに引数を追加します。それぞれ以下のような意味合いがあります。
型 | アノテーション | 役割 | 備考 |
---|---|---|---|
Model | - | サーバーから画面へ引き渡すデータを格納する | - |
T | @RequestParam |
リクエストパラメータを格納する | - |
T | @ModelAttribute |
画面のFormデータを格納する | - |
T | @Valid |
自動的にバリデーションされるデータであることを示す | BindingResultでバリデーション結果を受け取る前提 |
BindingResult | - | バリデーション結果を格納する | 対象のFormクラスが@Valid で修飾されている前提 |
Controllerクラス
(略)
@GetMapping("/")
-public String index() {
+public String index(@RequestParam(name = "page", required = false, defaultValue = "1") int pageNum, Model model) {
return "negitter";
}
(略)
@GetMapping("/register")
-public String register() {
+public String register(Model model) {
return "register";
}
(略)
@GetMapping("/negitter")
-public String negitter() {
+public String negitter(@RequestParam(name = "page", required = false, defaultValue = "1") int pageNum, Model model) {
return "negitter";
}
(略)
@PostMapping("/negiit")
-public String negiit() {
+public String negiit(@ModelAttribute @Valid NegiitForm negiitForm, BindingResult bindingResult, Model model) {
return "negitter";
}
(略)
@PostMapping("/registerNegi")
-public String registerNegi() {
+public String registerNegi(@ModelAttribute @Valid RegisterNegiForm negiForm, BindingResult bindingResult, Model model) {
return "register";
}
(略)
@PostMapping("/updateNegi")
-public String updateNegi() {
+public String updateNegi(@ModelAttribute @Valid UpdateNegiForm updateNegiForm, BindingResult bindingResult, Model model) {
return "register";
}
(略)
サーバーから画面に送られるデータ
Post/GetMappingメソッドに追加したModel型の引数に画面に引き渡すデータを格納します。
データの中身は次回以降作成していきますので、バリデーション結果以外は仮の値をとりあえず詰めておくことにします。
Controllerクラス
(略)
@GetMapping("/")
public String index(@RequestParam(name = "page", required = false, defaultValue = "1") int pageNum, Model model) {
+ // TODO つぶやきとページ情報を取得
+ model.addAttribute("negiits", new ArrayList<MessageTbl>());
+ model.addAttribute("pageNum", pageNum);
+ model.addAttribute("totalPages", 1);
+ model.addAttribute("prevPage", 1);
+ model.addAttribute("nextPage", 1);
+ model.addAttribute("errorMessages", new ArrayList<String>());
return "negitter";
}
(略)
@GetMapping("/register")
public String register(Model model) {
+ // TODO ねぎマスタのデータを取得
+ model.addAttribute("negiList", new ArrayList<NegiMst>());
+ model.addAttribute("errorMessages", new ArrayList<String>());
return "register";
}
(略)
@GetMapping("/negitter")
public String negitter(@RequestParam(name = "page", required = false, defaultValue = "1") int pageNum, Model model) {
+ // TODO つぶやきとページ情報を取得
+ model.addAttribute("negiits", new ArrayList<MessageTbl>());
+ model.addAttribute("pageNum", pageNum);
+ model.addAttribute("totalPages", 1);
+ model.addAttribute("prevPage", 1);
+ model.addAttribute("nextPage", 1);
+ model.addAttribute("errorMessages", new ArrayList<String>());
return "negitter";
}
(略)
@PostMapping("/negiit")
public String negiit(@ModelAttribute @Valid NegiitForm negiitForm, BindingResult bindingResult, Model model) {
+ List<String> errorMessages = bindingResult.getAllErrors().stream().map(e -> e.getDefaultMessage()).toList();
+ // TODO つぶやき登録処理結果によってページ情報を設定
+ model.addAttribute("negiits", new ArrayList<MessageTbl>());
+ model.addAttribute("pageNum", pageNum);
+ model.addAttribute("totalPages", 1);
+ model.addAttribute("prevPage", 1);
+ model.addAttribute("nextPage", 1);
+ model.addAttribute("errorMessages", errorMessages);
+ return "negitter";
}
(略)
@PostMapping("/registerNegi")
public String registerNegi(@ModelAttribute @Valid RegisterNegiForm negiForm, BindingResult bindingResult, Model model) {
+ List<String> errorMessages = bindingResult.getAllErrors().stream().map(e -> e.getDefaultMessage()).toList();
+ // TODO ねぎ情報登録結果を設定
+ // TODO ねぎ情報を検索し直す
+ model.addAttribute("negiList", negiList);
+ model.addAttribute("errorMessages", errorMessages);
return "register";
}
(略)
@PostMapping("/updateNegi")
public String updateNegi(@ModelAttribute @Valid UpdateNegiForm updateNegiForm, BindingResult bindingResult, Model model) {
+ List<String> errorMessages = bindingResult.getAllErrors().stream().map(e -> e.getDefaultMessage()).toList();
+ // TODO ねぎ情報更新結果を設定
+ // TODO ねぎ情報を検索し直す
+ model.addAttribute("negiList", negiList);
+ model.addAttribute("errorMessages", errorMessages);
return "register";
}
+ // TODO ページ情報を管理するprivate methodを作る
(略)
まとめ
今回は、サーバーと画面の間でやり取りされるデータの設計と、必要なクラス等の実装を行いました。
次回は、受け取ったデータを画面側で表示できるように、テンプレートを修正していきます。
それではまた。