jakaruta.doc_024
R e i - D r e a m
for Laravel
TOP > Jakarta_EE10 > ビーンバリデーション詳細②
Guest
login

最終投稿日:2026年07月26日

ビーンバリデーション詳細②
都合の良いときだけ発火するバリデーション ①
ちょっと何を言ってるかわからないですね..汗
例えば『下書』『保存して送信』のボタンがあるとします。
これ見るからに『下書』の方のバリデーションは多少ユルくても良いですよね?
『面倒だがカスタムバリデーションかぁ』と思うかもしれませんが、Jakarutaにはちゃんと標準機能があります。
    それがビーンバリデーションの『groups』属性です。
あれ、前の章でも出てきましたね。
実はこの属性順番にも使えるし、発火《させる|させない》にも使えるんです。
ではサンプルをご紹介します。
SampleBean.java

@Getter
@Setter
@NotBlank(message = "{error.required.name}"
, groups = Group1.class)
@Size(min = 3, max = 10, message = "{error.Size.name}"
, groups = Group2.class)
private String name;
@Getter
@Setter
@NotBlank(message = "{error.required.pref}"
, groups = Group1.class)
@Max(message = "{error.max.pref}", value = 10
, groups = Group2.class)
private String pref;

ValidationMessages.properties

error.required.name=名前は必須入力です(入力された値は「${validatedValue}」です)。
error.Size.name=この項目は{min}以上、{max}以下で記入してね。入力された文字は「${validatedValue}」でした。

error.required.pref=都道府県は必須入力です。
error.max.pref=都道府県は{value}以下だよ。

sample.xhtml

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="jakarta.faces.core"
    xmlns:h="jakarta.faces.html">
<h:head>
    <title>Hello World</title>
    <h:outputStylesheet library="css" name="style.css" />
</h:head>
<h:body>
    <h1>おはよう世界!</h1>
    <h:form id="sample_form" prependId="false">
        <h:messages errorClass="alert-danger" warnClass="alert-warning" infoClass="alert-info" layout="list" />

        
        <f:validateBean validationGroups="view.validator.group.Group1">
            <h:inputText id="inpText" value="#{sampleBean.name}" />
            <BR />
            <h:inputText id="pref" value="#{sampleBean.pref}"/>
            
            <BR />
            <h:commandButton value="下書き" action="#{sampleBean.submit()}">
                <f:param name="actionType" value="DRAFT" />
            </h:commandButton>
            <BR />
            <h:commandButton value="送信して保存" action="#{sampleBean.submit()}">
                <f:param name="actionType" value="SAVE" />
            </h:commandButton>
            
            <BR />
            <h:commandButton value="POST繊維" action="#{sampleBean.goPost()}" />
            <BR />
            <h:commandButton value="GET繊維" action="#{sampleBean.goGet()}" />
            <BR />
            <h:commandButton value="外部繊維" action="#{sampleBean.goYahoo()}" />

        </f:validateBean>
    </h:form>
</h:body>
</html>

『下書き』を押下してみて下さい。
無事《Group1》のみのバリデーションが発火しましたね。
ポイント

[form]タグ内を[f:validateBean]タグで囲う事で全てのUIにルールを適用できます。
ただひとつ問題があり、バッキングビーン側に「groups」属性を指定してないビーンバリデーションはどうなると思います?
答えは発火しないですw

これはシステムが内部的に『jakarta.validation.groups.Default』と割り振っているためです。
ではどうする?全てのビーンバリデーションに「groups」属性を指定?
いえ、答えは簡単で、そのグループもルールに加えるだけです。
[xhtml]の[f:validateBean]タグを以下の様に修正すれば解決です!
    <f:validateBean validationGroups="jakarta.validation.groups.Default, view.validator.group.Group1" >

都合の良いときだけ発火するバリデーション ②
あれ、まだ何か問題がありますか?
  『ふざけるなぁ~![Group2]が一生発火しないじゃないかっ!!』
って聞こえますね。 そうです。動的にルールが変わらないと意味がありませんよね。
でもこれ結構難問でして、例えば『validateBean』タグを以下の様に動的に変化する様に修正します。
    <f:validateBean validationGroups="#{sampleBean.currentGroup}" >
これでJAVA側の『submit()』メソッドを以下の様に修正する。
SampleBean.java

@Getter
private String currentGroup = "jakarta.validation.groups.Default, view.validator.group.Group1";
~ 省略 ~
    public void submit() {

        String actionType = FacesContext.getCurrentInstance()
                .getExternalContext().getRequestParameterMap().get("actionType");
        if (actionType.equals("DRAFT")) {
            this.currentGroup = "jakarta.validation.groups.Default, view.validator.group.Group1";
        } else {
            this.currentGroup = "jakarta.validation.groups.Default, view.validator.group.GroupOrder";
        }
        // ~ バリデーションが通過した時の処理 ~
    }

やりたい事は分かります。
でもこれはもう遅いですよ。
JAVAの処理をざっくり説明すると以下です。
① [xhtml]からJAVAへ送信される
② 各UIの内容とビーンバリデーションの内容を確認する
③ ②で1つでも問題があれば[xhtml]へ戻される
④ ②で問題がなければ、関数「submit」が処理される
④でルール変更しても無意味なのが分かりますね。
では、どうする?
そう!JAVAフレームワークと言ったら『AJAX』ですよね。
サンプルの前に仕組みをご説明します。
① ルールはクラスが初期化された際に決めたルールとする
②「下書」「保存して送信」を押下する
①' 実はこれ保存系のボタンでは無く「currentGroup」の値を変更するためのボタンです
②' ①'のボタンをAJAXで発火させる
③' ①'のAJAXは「execute="@this"」で送信するためバリデーションの影響を受けない
④' ①'のどのボタンが押下されたか、メソッドで振り分け「currentGroup」の内容を以下の様に変更する
・jakarta.validation.groups.Default, view.validator.group.Group1
・jakarta.validation.groups.Default, view.validator.group.GroupOrder
③ ②のAJAX通信が終了した時点で「f:validateBean」の内容が更新される
④ ②のAJAX通信が終了したら、JavaScriptを発火させ、隠しボタンを押下させる
⑤ ④で押下したボタンは同期通信なので、全てのUI情報がJAVA側に送信される
⑥ ③のルールでビーンバリデーションが発火します
⑦ ④のボタンの「action」属性を「submit()」に設定していればエラーが無い場合に限り発火します
ちょっと複雑ですが、他にもっとシンプルな方法があればご教授願います。
それではサンプルです。
SampleBean.java

package view;

import java.io.IOException;
import java.io.Serializable;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import jakarta.faces.context.ExternalContext;
import jakarta.faces.context.FacesContext;
import jakarta.faces.context.Flash;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Named;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;
import view.validator.group.Group1;
import view.validator.group.Group2;

@Named(value = "sampleBean")
@ViewScoped
public class SampleBean implements Serializable {
    private static final long serialVersionUID = 1L;
    
    
@Getter
    private String currentGroup = "jakarta.validation.groups.Default, view.validator.group.Group1";
    @Getter
    @Setter
    @NotBlank(message = "{error.required.name}", groups = Group1.class)
    @Size(min = 3, max = 10, message = "{error.Size.name}", groups = Group2.class)
    private String name;
    @Getter
    @Setter
    @NotBlank(message = "{error.required.pref}", groups = Group1.class)
    @Max(message = "{error.max.pref}", value = 10, groups = Group2.class)
    private String pref;
    
    
public void changeGroup1() {
        this.currentGroup = "jakarta.validation.groups.Default, view.validator.group.Group1";
    }
    public void changeGroupOrder() {
        this.currentGroup = "jakarta.validation.groups.Default, view.validator.group.GroupOrder";
    }
    public void submit() {
        // ~ バリデーションが通過した時の処理 ~
        System.out.println("処理実行!");
    }
    public String goPost() {
        Flash flash = FacesContext.getCurrentInstance().getExternalContext().getFlash();
        flash.put("pram_name", "フラッシュスコープです");
        return "next";
    }
    public String goGet() {
        return String.format("next?faces-redirect=true&inpText=%s&munber=%d", this.name, 123);
    }
    public void goYahoo() {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        ExternalContext externalContext = facesContext.getExternalContext();
        try {
            String paramName = URLEncoder.encode("テスト", StandardCharsets.UTF_8.toString());
            String targetUrl = "https://www.yahoo.co.jp/?q=" + paramName;
            externalContext.redirect(targetUrl);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

sample.xhtml

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="jakarta.faces.core"
    xmlns:h="jakarta.faces.html">
<h:head>
    <title>Hello World</title>
    <h:outputStylesheet library="css" name="style.css" />
    
<script>
    function change_rule(data){
        if (data.status === 'success') {
            let btn = document.getElementById("kakushi");
            btn.click();
        }
    }
    </script>
</h:head>
<h:body>
    <h1>おはよう世界!</h1>
    <h:form id="sample_form" prependId="false">
        <h:messages errorClass="alert-danger" warnClass="alert-warning" infoClass="alert-info" layout="list" />

        
        <f:validateBean validationGroups="#{sampleBean.currentGroup}">
            <h:inputText id="inpText" value="#{sampleBean.name}" />
            <BR />
            <h:inputText id="pref" value="#{sampleBean.pref}"/>
            
            <BR />
            
<h:commandButton value="下書き" actionListener="#{sampleBean.changeGroup1()}">
                <f:ajax execute="@this" onevent="change_rule" />
            </h:commandButton>
            <BR />
            <h:commandButton value="送信して保存" actionListener="#{sampleBean.changeGroupOrder()}">
                <f:ajax execute="@this" onevent="change_rule" />
            </h:commandButton>
            <BR />
            <h:commandButton id="kakushi" value="隠し" action="#{sampleBean.submit()}" tabindex="-1" style="display: none;" />
            
            <BR />
            <h:commandButton value="POST繊維" action="#{sampleBean.goPost()}" />
            <BR />
            <h:commandButton value="GET繊維" action="#{sampleBean.goGet()}" />
            <BR />
            <h:commandButton value="外部繊維" action="#{sampleBean.goYahoo()}" />
        </f:validateBean>
    </h:form>
</h:body>
</html>

どうですか?
きっちりバリデーションルール通りですよね!
ポイント

ルールが切り替わる仕組みは前述の通りです。
『AJAX』の部分に注目して下さい。『render』属性がありませんよね。

実は『f:validateBean』タグって、そもそもソース内にも描画されないタグなんです。
なので本当は『f:validateBean』タグに《id="valid"》とか付与して『render="valid"』とかしたかったんですが、問題ないみたいです。

レンズモード 【新規購入限定用】
ログインしてコメントを残そう!!


きっぷる