JSFでSwingのように開発をする

Swingはコードのみでコンポーネントの生成がされる。一方Webシステムはほとんどの場合HTMLをベースとしたテンプレート系(JSPも含む)+コードだ。このときコードとHTMLとの同期が取れなくなるのが問題になる。1箇所を直すのに2箇所直すというのも具合が悪い。

2年ほど前、Wicketを見たときSwingのようなヘビーなと宣伝されたので心が躍った。でも、実際はぜんぜん違った。結局コードとテンプレートの2つの修正が必要だった。これだったら同期作業が必要ないCreator2のほうが優れてるじゃないかと。

Swingのように手軽に開発は出来ないものか。

そういやJSFコンポーネント化が一番進んでいて、htmlを一切書かなくても使えた記憶がした。VisualWebPackの場合、コンポーネントの配置も面倒を見てくれるため、あまり意味はないのだが、コンポーネントの配置を手軽に行えるプラグインでも作ればお手軽なWeb環境が用意できるのではないか?とかまたアホなことをおもっちまった。

まず、初期化部分に初期化メソッドをコールするように追加

    @Override
    public void init() {
        // Perform initializations inherited from our superclass
        super.init();
        // Perform application initialization that must complete
        // *before* managed components are initialized
        // TODO - add your own initialiation code here

        // <editor-fold defaultstate="collapsed" desc="Managed Component Initialization">
        // Initialize automatically managed components
        // *Note* - this logic should NOT be modified
        try {
            _init();
        } catch (Exception e) {
            log("Page1 Initialization Failure", e);
            throw e instanceof FacesException ? (FacesException) e : new FacesException(e);
        }

        // </editor-fold>
        // Perform application initialization that must complete
        // *after* managed components are initialized
        // TODO - add your own initialization code here

        customInit();//←ここ
    }

あとは下のほうにスクロールでもさせて空いたスペースに以下のコードを追加

    //初期化
    private void customInit() {
        if(getFacesContext().getRenderResponse() == false){
            return;
        }
        
        System.out.println("初期化は1回だけよ");
        
        ExpressionFactory ef = getFacesContext().getApplication().getExpressionFactory();

        //出力テキストの設定
        HtmlOutputText output = new HtmlOutputText();
        output.setId("outputText1");
        output.setStyle("position: absolute; left: 120px; top: 0px");
        output.setValue("ひょうじされるかな?");
        getForm1().getChildren().add(output);
        output.setParent(getForm1());

        //テキストフィールドの設定
        HtmlInputText input = new HtmlInputText();
        input.setId("InputText1");
        ValueExpression ve = ef.createValueExpression(
                getFacesContext().getELContext(), "#{Page1.text}", String.class);
        input.setStyle("position: absolute; left: 120px; top: 36px");
        input.setValueExpression("value", ve);
        input.setRequired(true);
        getForm1().getChildren().add(input);
        input.setParent(getForm1());

        //ボタンの設定
        HtmlCommandButton button = new HtmlCommandButton();
        button.setId("button1");
        button.setStyle("position: absolute; left: 120px; top: 72px");
        button.setValue("押してください");
        MethodExpression me = ef.createMethodExpression(
                getFacesContext().getELContext(), "#{Page1.button_click}",
                String.class, new Class[]{});
        button.setActionExpression(me);
        getForm1().getChildren().add(button);
        button.setParent(getForm1());
    }
    
    //入力項目がここに入ってくる
    private String text;
    public String getText() {
        return text;
    }
    public void setText(String text) {
        this.text = text;
    }
    
    //クリックしたら呼ばれるはず
    public String button_click() {
        String t = String.format("はろー%sさん" ,text );
        HtmlOutputText outtext = (HtmlOutputText) getForm1().findComponentById("outputText1");
        outtext.setValue(t);
        return null;
    }

コードを見ればわかると思うが、3つのコンポーネントを生成配置している。1回だけ初期化がされるようにしているのがポイントか。あとはメソッドとバリューのバインド方法はJSF1.2になって代わっているので注意。formまでは自動生成されているのでそこに追加していくというスタイルだ。

以下が実行結果。

「ひょうじされるかな?」というメッセージが最初は表示されているがそこが入力した文字によって置き換わる。

実際すべて用意してあげるのは骨が折れる作業ではあるが、素のSwingよりやれることが少ない分ある意味楽かもしれない。それに「HtmlOutputText」は単純にテキストを出力する。こいつのエスケープを切ればいくらでも自由にHTMLは生成できるし割合どうにでもなりやすい。


まぁ、Visual Web JSFだとコンポーネントの配置と各種プロパティの初期化を全てまかせられるので意味はないんだけどね。VisualWebを使えない場合恩恵があるかなーと思ったけど、どうだろ。