ぺーぺーSEのブログ

備忘録・メモ用サイト。

JSF(JavaServer Faces)の基本

JSF2.2の基本をまとめる。(2.2感は無いかも)
JSF2.2はJavaEE7のコンポーネントベースのMVCフレームワーク
コンポーネントベースは、「リクエストの際URIを意識せずサーバサイドのロジックを直接呼ぶ」って感じかな。
対してStrutsのようなリクエスト駆動型ってやつは、「リクエストの際URIを意識してサーバサイドのリクエストURIに紐づいたロジックを呼ぶ」。
JSF2.2のMVCは以下の通り。

■ビューの例(Facelets+EL式)

<h:inputText id="textField" value="#{sampleManagedBean.input}" />
<h:commandButton value="送信" action="#{sampleManegedBean.pushButton()}" />

」「」の部分がFacelets。
タグ内のvalue属性、action属性の中身がEL式。
EL式は下記のJSFマネージドBeanに紐づいている。
EL式内の「sampleManagedBean」という記述と下記JSFマネージドBeanの@Namedアノテーション内value属性値「sampleManagedBean」が紐づいている。
EL式内の「sampleManagedBean.」後の記述が下記JSFマネージドBeanのフィールド変数inputやメソッドpushButton()に紐づいている。


■モデルの例(CDI管理のJSFマネージドBean)

@Named(value = "sampleManagedBean")
@RequestScoped
public class SampleManagedBean {

  private String input; // GetterとSetterは書いてね!
  
  public String pushButton() {
    System.out.println(this.input);
    return "";
  }
}

「@RequestScoped」アノテーションで文字通りこのクラスはリクエストスコープになる。

サンプルアプリ(Tomcat

テキストフィールドにメッセージを入力するとAPサーバの標準出力に出るだけのアプリ。
Maven Tomcat Pluginで動かしてみる。


■POM

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.sample</groupId>
  <artifactId>jsf-sample</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <name>jsf-sample</name>

  <properties>
    <!-- Generic properties -->
    <jdk.version>1.7</jdk.version>
    <encoding>UTF-8</encoding>
    
    <!-- lib versions -->
    <jsf.version>2.2.4</jsf.version>
    <el.version>2.2</el.version>
  </properties>

  <build>
    <finalName>jsf-sample</finalName>
    <plugins>
      <!-- compiler -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>${jdk.version}</source>
          <target>${jdk.version}</target>
          <encoding>${encoding}</encoding>
        </configuration>
      </plugin>
      <!-- Tomcat Maven Plugin -->
      <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.2</version>
        <configuration>
          <charset>${encoding}</charset>
          <uriEncoding>${encoding}</uriEncoding>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <dependencies>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <scope>provided</scope>
      <version>2.5</version>
    </dependency>
    
    <dependency>
      <groupId>com.sun.faces</groupId>
      <artifactId>jsf-api</artifactId>
      <version>${jsf.version}</version>
    </dependency>
    <dependency>
      <groupId>com.sun.faces</groupId>
      <artifactId>jsf-impl</artifactId>
      <version>${jsf.version}</version>
    </dependency>
    
     <dependency>
      <groupId>javax.enterprise</groupId>
      <artifactId>cdi-api</artifactId>
      <version>1.1</version>
    </dependency>
    <dependency>
      <groupId>org.jboss.weld.servlet</groupId>
      <artifactId>weld-servlet</artifactId>
      <version>2.1.0.Final</version>
    </dependency>
    
    <dependency>
      <groupId>javax.el</groupId>
      <artifactId>el-api</artifactId>
      <version>${el.version}</version>
    </dependency>
    <dependency>
      <groupId>org.glassfish.web</groupId>
      <artifactId>el-impl</artifactId>
      <version>${el.version}</version>
    </dependency>
  </dependencies>
</project>



■web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
  
  <!-- CDI用リスナー(GlassFishだと不要) -->
  <listener>
    <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
  </listener>
  
  <!-- EL式用(GlassFishだと不要) -->
  <context-param>
    <param-name>com.sun.faces.expressionFactory</param-name>
    <param-value>com.sun.el.ExpressionFactoryImpl</param-value>
  </context-param>
  
  <!-- JSF用 -->
  <context-param>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <param-value>Development</param-value>
  </context-param>
  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>/faces/*</url-pattern>
  </servlet-mapping>
  
  <session-config>
    <session-timeout>30</session-timeout>
  </session-config>
  
  <welcome-file-list>
    <welcome-file>faces/index.xhtml</welcome-file>
  </welcome-file-list>
</web-app>



■faces-config.xml(web.xmlと同じ階層におく、なくてもいい)

<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
  version="2.2">
</faces-config>

特に設定不要。


■beans.xml(web.xmlと同じ階層におく)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
  bean-discovery-mode="all">
</beans>

「bean-discovery-mode」の設定バリエーションは下記の通り。

  • all
    • 全てのクラスにインジェクション
  • annotated
  • none
    • インジェクションしない?



■index.xml(webapp直下)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="ja" xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
  <meta charset="UTF-8" />
  <title>JSF Sample</title>
</h:head>
<h:body>
  はろー Facelets
  <h:form>
    <h:inputText id="textField" value="#{sampleManagedBean.input}"/>
    <h:commandButton value="Send Message" action="#{sampleManagedBean.pushButton()}"/><br/>
  </h:form>
</h:body>
</html>

一応HTML5仕様。JSFHTML5フレンドリらしいので。


JSFマネージドBean(org.sample.managedbean.SampleManagedBean)

package org.sample.managedbean;

import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named(value = "sampleManagedBean")
@RequestScoped
public class SampleManagedBean {
  
  private String input;
  
  public SampleManagedBean() {
  }
  
  public String pushButton() throws Exception {
    System.out.println(getInput());
    return "";
  }

  public String getInput() {
    return input;
  }

  public void setInput(String input) {
    this.input = input;
  }
}



下記を実行するとTomcatが起動する。

mvn tomcat:run-war



なんだがよくわからんが、EL式(テキストフィールド入力)経由で渡した日本語が文字化けする。。。
setCharacterEncodingとかTomcatのcharsetとか一般的なやつは試したのだが、、、
JSF特有の設定とかあるのかね?
GlassFish4だとGlassFishディスクリプタglassfish-web.xml」で下記のように設定しておくと化けないんだけどなぁ。


GlassFishディスクリプタglassfish-web.xml」(web.xmlと同じ階層におく)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC
  "-//GlassFish.org//DTD GlassFish Application Server 3.1Servlet 3.0//EN"
  "http://glassfish.org/dtds/glassfishweb-app_3_0-1.dtd">
<glassfish-web-app error-url="">
  <class-loader delegate="true"/>
  <jsp-config>
    <property name="keepgenerated" value="true">
      <description>
        Keep a copy of the generated servlet class' java code.
      </description>
    </property>
  </jsp-config>
  <parameter-encoding default-charset="UTF-8" />
</glassfish-web-app>

サンプル(GlassFish

GlassFishをローカル(Windows)にインストールして、Maven GlassFish Pluginでデプロイして動かす例。
アプリの内容はさっきと一緒。ただし、glassfish-web.xmlは配置しておく。

GlassFishのダウンロード
  • ダウンロード
  • 今回はGlassFish4を選択
  • glassfish4\binにPATHを通す
  • glassfish4\bin\asadminをリネーム(asadmin_bkなど)
    • Windows環境の場合はMaven GlassFish Pluginが「asadmin.bat」を選択できるようにするため


GlassFishドメイン作成
  • 下記コマンドでドメインを作成し、ユーザ名とパスワードを入力する。
asadmin.bat create-domain my_domain
  • 下記コマンドを実行し、ドメインを起動する。
asadmin.bat start-domain my_domain


Maven GlassFish Pluginの設定
  • POMに下記を追記
<plugin>
  <groupId>org.glassfish.maven.plugin</groupId>
  <artifactId>maven-glassfish-plugin</artifactId>
  <version>2.1</version>
  <configuration>
    <!-- ドメイン作成時に指定したユーザ -->
    <user>user</user>
    <!-- GlassFishのインストール先 -->
    <glassfishDirectory>C:/〜/glassfish-4.0</glassfishDirectory>
    <!-- ドメイン作成時に指定したパスワード -->
    <adminPassword>PassWord</adminPassword>
    <debug>true</debug>
    <echo>true</echo>
    <components>
    <component>
    <name>${project.artifactId}</name>
    <artifact>${project.build.directory}/${project.build.finalName}.war</artifact>
    </component>
    </components>
    <domain>
      <name>my_domain</name>
      <adminPort>4848</adminPort>
    </domain>
  </configuration>
</plugin>
  • デプロイ実行
mvn clean package glassfish:deploy
  • 下記へアクセスする
http://localhost:8080/jsf-sample/

GlassFishで動かすとTomcatのときと違ってELのところが文字化けしない。

MavenからGlassFishをコントロールするゴール



参考
http://himalab.hatenablog.com/entry/2012/04/16/213051
https://maven-glassfish-plugin.java.net/

JSF系参考

JSF勉強メモ
http://d.hatena.ne.jp/maji-KY/20100426/1272248157

FacesContextでリクエスト情報

JSF + WebSocket で実装した IMAP Web メール・クライアント
http://yoshio3.com/2013/12/11/imap-client-created-by-jsf-websocket/

What's New JSF 2.2 & CDI & EL
http://www.oracle.com/technetwork/jp/ondemand/java/whatsnewjsf22-cdi-el-2014283-ja.pdf