2009年1月21日星期三

JSF_021:JSF 问与答

问题1:哪里可以下载到JSF开发环境?
(1)下载地址:http://java.sun.com/javaee/javaserverfaces/download.html
(2)把JSF和commons jars放到WEB-INF/lib中。
(3)配置Faces controller servlet(javax.faces.webapp.FacesServlet)在web.xml中。
(4)配置faces-config.xml,其功能类似于struts-config.xml,包含两种组件的配置信息:Managed Beans 和 Navigation Rule。

问题2:哪些人员可以使用JSF?
无论是网页设计人员,应用程序开发人员,还是UI 组件开发人员都可以使用,而且互不干扰。
(1)网页设计人员
JSF 提供了一套像是新版本的HTML 标签,但它不是静态的,而是动态的,可以与后端的程序结合,但网页设计人员无需理会。
(2)应用程序开发人员JSF 提供了一个与传统应用程序开发相类似的模型(当然因某些本质上的差异,模型还是稍有不同),可以基于事件驱动来开发,不必关心HTTP 的处理细节。
(3)UI 组件开发人员
如同设计Swing 组件一样,UI 组件开发人员可以设计自定义的UI 组件,供网页设计人员和应用程序开发人员使用。

问题3:JSF基于JSP定制标签库有哪些?
JSF标签库core是有关于UI组件的,用于事件处理和数据转换:<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
JSF标签库html是有关于HTML的,用于展现用户界面:<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
更多有关JSF标签库的信息请访问:http://horstmann.com/corejsf/jsf-tags.html。
<f:view> 与<html> 有类似的作用,使用JSF组件时,这些组件一定要在<f: view> 与</f:view> 之间,就如同使用HTML时,所有的标签一定要在<html> 与</html> 之间。

问题4:UI组件的binding属性是干吗用的?
例如:<h:inputText value="Hello" binding="#{Backing.txtComponentInput}"></h:inputText>
binding属性就是把该组件的实例以属性的形式存储到bean中,便于其它方法(如Listener方法)中操作这个组件及其各个属性。
详细说明请参考:http://ztc.javaeye.com/blog/82305。

问题5:JSF 隐含对象由哪些,如何使用?
param 是JSF EL 预设的隐含对象变量,它代表request 所有参数的集合,实际是一个java.util.Map 型态对象,JSF 所提供的隐含对象。
JSF 隐含对象移除了pageScope 与pageContext,而增加了facesContext 与view,它们分别对应于 javax.faces.context.FacesContext 与javax.faces.component.UIViewRoot。

问题6:Command类型的组件的actionListener属性是干吗用的?例如:<h:commandButton value="送出"actionListener="#{user.verify}"action="#{user.outcome}"/>
在简单的导航中,我们根据Command类型的组件的action属性(设置成为Managed Beans的一个属性或一个方法)来决定要导向的页面。
这其实就是JSF 所提供的事件处理程序,JSF会为其自动产生一个预设的ActionListener来处理事件,并根据其返回值来决定导向的页面。
在运行时,JSF 会首先检查是否有指定的actionListener,然后再检查是否指定了action方法,并产生相应的或预设的ActionListener,并根据其返回值导航页面。
当你需要使用同一个方法来应付多种事件来源,并想要取得事件来源的相关讯息,您可以让处理事件的方法接收一个javax.faces.event.ActionEvent 事件参数,例如:
public void verify(ActionEvent e) {
if(!name.equals("justin") !password.equals("123456")) {
errMessage = "名称或密码错误" + e.getSource();
outcome = "failure";}
else {
outcome = "success";
}
}

可以使用<f:actionListener>为一个组件注册多个ActionListener,例如:
<h:commandButton value="送出" action="#{user.outcome}">
<f:actionListener type="onlyfun.caterpillar.LogHandler"/>
<f:actionListener type="onlyfun.caterpillar.VerifyHandler"/>
</h:commandButton>

<f:actionListener>会自动产生type 所指定的对象,并呼叫组件的addActionListener()方法注册Listener。

2009年1月20日星期二

JSF_020:MIME TYPE 汇总


  1. application/acad *.dwg AutoCAD-Dateien (nach NCSA)

  2. application/applefile AppleFile-Dateien

  3. application/astound *.asd *.asn Astound-Dateien

  4. application/dsptype *.tsp TSP-Dateien

  5. application/dxf *.dxf AutoCAD-Dateien (nach CERN)

  6. application/futuresplash *.spl Flash Futuresplash-Dateien

  7. application/gzip *.gz GNU Zip-Dateien

  8. application/listenup *.ptlk Listenup-Dateien

  9. application/mac-binhex40 *.hqx Macintosh Bin?r-Dateien

  10. application/mbedlet *.mbd Mbedlet-Dateien

  11. application/mif *.mif FrameMaker Interchange Format Dateien

  12. application/msexcel *.xls *.xla Microsoft Excel Dateien

  13. application/mshelp *.hlp *.chm Microsoft Windows Hilfe Dateien

  14. application/mspowerpoint *.ppt *.ppz *.pps *.pot Microsoft Powerpoint Dateien

  15. application/msword *.doc *.dot Microsoft Word Dateien

  16. application/octet-stream *.bin *.exe *.com *.dll *.class Ausführbare Dateien

  17. application/oda *.oda Oda-Dateien

  18. application/pdf *.pdf Adobe PDF-Dateien

  19. application/postscript *.ai *.eps *.ps Adobe Postscript-Dateien

  20. application/rtc *.rtc RTC-Dateien

  21. application/rtf *.rtf Microsoft RTF-Dateien

  22. application/studiom *.smp Studiom-Dateien

  23. application/toolbook *.tbk Toolbook-Dateien

  24. application/vocaltec-media-desc *.vmd Vocaltec Mediadesc-Dateien

  25. application/vocaltec-media-file *.vmf Vocaltec Media-Dateien

  26. application/x-bcpio *.bcpio BCPIO-Dateien

  27. application/x-compress *.z -Dateien

  28. application/x-cpio *.cpio CPIO-Dateien

  29. application/x-csh *.csh C-Shellscript-Dateien

  30. application/x-director *.dcr *.dir *.dxr -Dateien

  31. application/x-dvi *.dvi DVI-Dateien

  32. application/x-envoy *.evy Envoy-Dateien

  33. application/x-gtar *.gtar GNU tar-Archiv-Dateien

  34. application/x-hdf *.hdf HDF-Dateien

  35. application/x-httpd-php *.php *.phtml PHP-Dateien

  36. application/x-javascript *.js serverseitige JavaScript-Dateien

  37. application/x-latex *.latex Latex-Quelldateien

  38. application/x-macbinary *.bin Macintosh Bin?rdateien

  39. application/x-mif *.mif FrameMaker Interchange Format Dateien

  40. application/x-netcdf *.nc *.cdf Unidata CDF-Dateien

  41. application/x-nschat *.nsc NS Chat-Dateien

  42. application/x-sh *.sh Bourne Shellscript-Dateien

  43. application/x-shar *.shar Shell-Archiv-Dateien

  44. application/x-shockwave-flash *.swf *.cab Flash Shockwave-Dateien

  45. application/x-sprite *.spr *.sprite Sprite-Dateien

  46. application/x-stuffit *.sit Stuffit-Dateien

  47. application/x-supercard *.sca Supercard-Dateien

  48. application/x-sv4cpio *.sv4cpio CPIO-Dateien

  49. application/x-sv4crc *.sv4crc CPIO-Dateien mit CRC

  50. application/x-tar *.tar tar-Archivdateien application/x-tcl *.tcl TCL Scriptdateien

  51. application/x-tex *.tex TEX-Dateien

  52. application/x-texinfo *.texinfo *.texi TEXinfo-Dateien

  53. application/x-troff *.t *.tr *.roff TROFF-Dateien (Unix)

  54. application/x-troff-man *.man *.troff TROFF-Dateien mit MAN-Makros (Unix)

  55. application/x-troff-me *.me *.troff TROFF-Dateien mit ME-Makros (Unix)

  56. application/x-troff-ms *.me *.troff TROFF-Dateien mit MS-Makros (Unix)

  57. application/x-ustar *.ustar tar-Archivdateien (Posix)

  58. application/x-wais-source *.src WAIS Quelldateien

  59. application/x-www-form-urlencoded HTML-Formulardaten an CGI

  60. application/zip *.zip ZIP-Archivdateien

  61. application/vnd.wap.wmlc *.wmlc WMLC-Dateien (WAP)

  62. application/vnd.wap.wmlscriptc *.wmlsc WML-Script-C-dateien (WAP)

  63. audio/basic *.au *.snd Sound-Dateien audio/echospeech *.es Echospeed-Dateien

  64. audio/tsplayer *.tsi TS-Player-Dateien

  65. audio/voxware *.vox Vox-Dateien audio/x-aiff *.aif *.aiff *.aifc AIFF-Sound-Dateien

  66. audio/x-dspeeh *.dus *.cht Sprachdateien

  67. audio/x-midi *.mid *.midi MIDI-Dateien

  68. audio/x-mpeg *.mp2 MPEG-Dateien

  69. audio/x-pn-realaudio *.ram *.ra RealAudio-Dateien

  70. audio/x-pn-realaudio-plugin *.rpm RealAudio-Plugin-Dateien

  71. audio/x-qt-stream *.stream -Dateien

  72. audio/x-wav *.wav Wav-Dateien drawing/x-dwf *.dwf Drawing-Dateien

  73. image/cis-cod *.cod CIS-Cod-Dateien

  74. image/cmu-raster *.ras CMU-Raster-Dateien image/fif *.fif FIF-Dateien

  75. image/gif *.gif GIF-Dateien image/ief *.ief IEF-Dateien

  76. image/jpeg *.jpeg *.jpg *.jpe JPEG-Dateien

  77. image/tiff *.tiff *.tif TIFF-Dateien

  78. image/vasa *.mcf Vasa-Dateien

  79. image/vnd.wap.wbmp *.wbmp Bitmap-Dateien (WAP)

  80. image/x-freehand *.fh4 *.fh5 *.fhc Freehand-Dateien

  81. image/x-portable-anymap *.pnm PBM Anymap Dateien

  82. image/x-portable-bitmap *.pbm PBM Bitmap Dateien

  83. image/x-portable-graymap *.pgm PBM Graymap Dateien

  84. image/x-portable-pixmap *.ppm PBM Pixmap Dateien image/x-rgb *.rgb RGB-Dateien

  85. image/x-windowdump *.xwd X-Windows Dump

  86. image/x-xbitmap *.xbm XBM-Dateien image/x-xpixmap *.xpm XPM-Dateien

  87. message/external-body Nachricht mit externem Inhalt

  88. message/http HTTP-Headernachricht

  89. message/news Newsgroup-Nachricht message/partial Nachricht mit Teilinhalt

  90. message/rfc822 Nachricht nach RFC 1822 model/vrml *.wrl Visualisierung virtueller Welten

  91. multipart/alternative mehrteilige Daten gemischt

  92. multipart/byteranges mehrteilige Daten mit Byte-Angaben

  93. multipart/digest mehrteilige Daten / Auswahl

  94. multipart/encrypted mehrteilige Daten verschlüsselt

  95. multipart/form-data mehrteilige Daten aus HTML-Formular (z.B. File-Upload)

  96. multipart/mixed

  97. mehrteilige Daten gemischt

  98. multipart/parallel mehrteilige Daten parallel

  99. multipart/related mehrteilige Daten / verbunden

  100. multipart/report mehrteilige Daten / Bericht

  101. multipart/signed mehrteilige Daten / bezeichnet

  102. multipart/voice-message mehrteilige Daten / Sprachnachricht

  103. text/comma-separated-values *.csv komma-separierte Datendateien

  104. text/css *.css CSS Stylesheet-Dateien

  105. text/html *.htm *.html *.shtml -Dateien

  106. text/javascript *.js JavaScript-Dateien

  107. text/plain *.txt reine Textdateien

  108. text/richtext *.rtx Richtext-Dateien

  109. text/rtf *.rtf Microsoft RTF-Dateien

  110. text/tab-separated-values *.tsv tabulator-separierte Datendateien

  111. text/vnd.wap.wml *.wml WML-Dateien (WAP)

  112. text/vnd.wap.wmlscript *.wmls WML-Scriptdateien (WAP)

  113. text/xml-external-parsed-entity extern geparste XML-Dateien

  114. text/x-setext *.etx SeText-Dateien text/x-sgml *.sgm *.sgml SGML-Dateien

  115. text/x-speech *.talk *.spc Speech-Dateien

  116. video/mpeg *.mpeg *.mpg *.mpe MPEG-Dateien

  117. video/quicktime *.qt *.mov Quicktime-Dateien

  118. video/vnd.vivo *viv *.vivo Vivo-Dateien

  119. video/x-msvideo *.avi Microsoft AVI-Dateien

  120. video/x-sgi-movie *.movie Movie-Dateien

  121. workbook/formulaone *.vts *.vtts FormulaOne-Dateien

  122. x-world/x-3dmf *.3dmf *.3dm *.qd3d *.qd3 3DMF-Dateien

  123. x-world/x-vrml *.wrl VRML-Dateien

2009年1月19日星期一

JSF_019:一个读取BLOB中图片的Servlet代码

说明:本代码来源于Oracle FOD Demo,仅供参考学习。
package uiresources;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.OutputStream;

import java.sql.Blob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

import java.sql.SQLException;

import javax.naming.Context;
import javax.naming.InitialContext;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import javax.sql.DataSource;


public class ImageServlet extends HttpServlet {
    private static final String CONTENT_TYPE =
        "image/jpg; charset=utf-8";

    public void init(ServletConfig config) throws ServletException {
        super.init(config);
    }

    public void doGet(HttpServletRequest request,
                      HttpServletResponse response) throws ServletException,
                                                           IOException {
        response.setContentType(CONTENT_TYPE);
        response.setContentType(CONTENT_TYPE);
        String detailProductId = request.getParameter("detail");
        String thumbnailProductId = request.getParameter("thumbnail");
        boolean thumbnail = true;
        String productId = null;
        OutputStream os = response.getOutputStream();
        Connection conn = null;
     
        try {
            Context ctx = new InitialContext();
            DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/FODDS");
            conn = ds.getConnection();
            PreparedStatement statement = conn.prepareStatement(
              "SELECT ProductImageEO.PRODUCT_IMAGE_ID, " +
              "       ProductImageEO.PRODUCT_ID, " +
              "       ProductImageEO.DEFAULT_VIEW_FLAG, " +
              "       ProductImageEO.DETAIL_IMAGE_ID, " +
              "       ProductImageEO.IMAGE " +
              "FROM  PRODUCT_IMAGES ProductImageEO " +
              "WHERE ProductImageEO.DEFAULT_VIEW_FLAG = ?" +
              "      AND ProductImageEO.PRODUCT_ID = ?");

            if (detailProductId != null) {
                productId = detailProductId;
                thumbnail = false;
            } else {
                productId = thumbnailProductId;
 
            }
 
            statement.setString(1,(thumbnail ? "Y" : "N"));         
            statement.setInt(2, new Integer(productId));
            ResultSet rs = statement.executeQuery();
         
            if (rs.next()) {
                Blob blob = rs.getBlob("IMAGE");
                BufferedInputStream in = new BufferedInputStream(blob.getBinaryStream());
                int b; byte[] buffer = new byte[10240];
                while ((b = in.read(buffer, 0, 10240)) != -1) { os.write(buffer, 0, b); }
                os.close();
            }
        } catch (Exception e){
            System.out.println(e);
        } finally {
            try{
                if (conn != null){
                     conn.close();
                }
             } catch (SQLException sqle){
                 System.out.println("SQLException error");
             }
        }
    }
}

2009年1月18日星期日

JSF_018:HTTP forward 与 redirect 的区别

1. 转发 forward
(1)由容器控制页面的转向,在浏览器地址栏中不会显示出转向后的地址。
(2)Request参数值不会丢失。
(3)相对路径与绝对路径问题。

2. 重定向 redirect
(1)由浏览器重定向到下一个页面,在浏览器地址栏中会显示出跳转后的地址。
(2)Request参数值会丢失。
(3)相对路径与绝对路径问题。

参考文献:
1. 请求的跳转与转发
2. forward redirect 区别

2009年1月17日星期六

JSF_017:深刻理解immediate=true的含义

在实际使用中,我发现自己对immediate=true的了解仅仅局限在可以“跳过验证”环节,其实immediate=true还有很多别的意义,对应的使用场景也不同,下面就以实验的方式总结一下。

1. immediate=true的适用场景
(1)点击某个命令组件后直接导航到下一页面,不再验证当前页面的输入数据,不再处理值变事件等等环节。最典型的就是“取消”按钮。
(2)点击某个命令组件后直接调用组件上的action事件,不再验证当前页面的输入数据,不再处理值变事件等等环节。
(3)当某个输入组件验证出错了,不再验证其它输入组件,防止一次弹出所有的出错信息。

2. immediate=true是如何影响生命周期的?
我们知道JSF页面生命周期分为6个阶段,详细说明请参考《JSF 的生命周期》。
很多开发者常常以为:只要把组件的immediate=true,那么就会跳过"Process Validations" 阶段。
这其实是个误解,真相是:immediate=true时,只是该组件的所有事件处理将提前到"Apply Request Values "阶段。

3. 对输入组件来说,immediate=true意味着
组件将在"Apply Request Values "阶段进行验证,其它immediate=false的组件依然会在"Process Validations" 阶段验证。
如果immediate=true的组件验证不通过,那么将会直接进入"Render Response"阶段,不会再验证其它immediate=false的组件。
如果immediate=true的组件上还有值变事件,那么该事件也在"Apply Request Values "阶段触发执行,而不是原先默认的"Process Validations" 阶段。

4. 对命令组件来说,immediate=true意味着
组件上的ActionListener或action事件将在"Apply Request Values "阶段触发执行。
如果action事件返回一个非Null的String,那么将会根据导航规则直接导航到下一页面,即直接跳到"Render Response"阶段,不再经过中间的阶段,用户输入的数据将被丢弃。
取消按钮,就是我们最常见的例子。
如果action事件返回的String为Null,那么剩下的阶段继续按照原来的顺序执行。

5. 常见问题与解答
(1)immediate=true的输入组件,当用户输入数据后,在后台却得不到这个数据。
(2)immediate=true的命令组件,如何获得那些immediate=false的输入组件的值?
在Managed Bean中绑定到该输入组件,然后调用该组件的getSubmittedValue()方法,注意这个方法返回的是raw String,没有经过验证和转换。

说明:所有实验验证可以参考《使用PhaseListener观察JSF生命周期的各个阶段》。

参考文献:
1. http://wiki.apache.org/myfaces/How_The_Immediate_Attribute_Works。

2009年1月16日星期五

JSF_016:使用PhaseListener观察JSF生命周期的各个阶段

本文最后一次修改时间:2012-05-02。
开发环境 :JDeveloper 11.1.2.1.0。
我们知道JSF把一个页面分为了六个阶段,组件上的不同的事件发生在不同的阶段。
组件上的有些属性可能会改变事件发生的阶段。
为了能够清楚地了解这些事件发生的阶段,我们需要使用PhaseListener来观察JSF生命周期。

1. PhaseListener 代码如下:
package com.javaneverdie.adf.lifecycle.view.phaselistener;

import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;

public class MyPhaseListener implements PhaseListener {
public MyPhaseListener() {
super();
}

public void beforePhase(PhaseEvent pe) {
if (pe.getPhaseId() == PhaseId.RESTORE_VIEW)
System.out.println("###### Processing new Request!");

System.out.println("before - " + pe.getPhaseId().toString());
}

public void afterPhase(PhaseEvent pe) {
System.out.println("after - " + pe.getPhaseId().toString());

if (pe.getPhaseId() == PhaseId.RENDER_RESPONSE)
System.out.println("###### Done with Request!\n");
}

public PhaseId getPhaseId() {
return PhaseId.ANY_PHASE;
}
}

2. BackingBean 代码如下:
package com.javaneverdie.adf.lifecycle.view.backing;

public class MyBackingBean {
public MyBackingBean() {
super();
}

public String clickMe_action() {
System.out.println("$$$$$ Action event processed...");
return "success";
}
}

3. Validator 代码如下:
package com.javaneverdie.adf.lifecycle.view.validator;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;

public class MyValidator implements Validator {
public MyValidator() {
super();
}

public void validate(FacesContext context, UIComponent component,
Object obj) throws ValidatorException {

System.out.println("$$$$$ Validate processed...");

}
}

4. ValueChangeListener 代码如下:

package com.javaneverdie.adf.lifecycle.view.valuechangelistener;

import javax.faces.event.ValueChangeListener;
import javax.faces.event.ValueChangeEvent;
import javax.faces.event.AbortProcessingException;

public class MyValueChangeListener implements ValueChangeListener {

public MyValueChangeListener() {
}

public void processValueChange(ValueChangeEvent vce) throws AbortProcessingException {
System.out.println("$$$$$ Value Change event processed...");
}
}

5. faces-config.xml 内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee">
<application>
<default-render-kit-id>oracle.adf.rich</default-render-kit-id>
</application>
<lifecycle>
<phase-listener>com.javaneverdie.adf.lifecycle.view.phaselistener.MyPhaseListener</phase-listener>
</lifecycle>
<managed-bean>
<managed-bean-name>myBackingBean</managed-bean-name>
<managed-bean-class>com.javaneverdie.adf.lifecycle.view.backing.MyBackingBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<validator>
<validator-id>myValidator</validator-id>
<validator-class>com.javaneverdie.adf.lifecycle.view.validator.MyValidator</validator-class>
</validator>
</faces-config>

好,下面我们就可以做一些有意思的实验了。

实验1:页面中只有一个Button,代码如下:
<h:commandButton value="Click Me" id="cb1" action="#{myBackingBean.clickMe_action}"/>
第一次Run的结果:
###### Processing new Request!
before - RESTORE_VIEW 1
after - RESTORE_VIEW 1
###### Processing new Request!
before - RESTORE_VIEW 1
after - RESTORE_VIEW 1
before - RENDER_RESPONSE 6
after - RENDER_RESPONSE 6
###### Done with Request!

我们注意到,页面初始化时,只进入了两个生命周期阶段:RESTORE_VIEW 1 和 RENDER_RESPONSE 6。
这符合JSF生命周期的规范,详细说明请参考《JSF 的生命周期》。

点击按钮后的结果:
###### Processing new Request!
before - RESTORE_VIEW 1
after - RESTORE_VIEW 1
before - APPLY_REQUEST_VALUES 2
after - APPLY_REQUEST_VALUES 2
before - PROCESS_VALIDATIONS 3
after - PROCESS_VALIDATIONS 3
before - UPDATE_MODEL_VALUES 4
after - UPDATE_MODEL_VALUES 4
before - INVOKE_APPLICATION 5
$$$$$ Action event processed...
after - INVOKE_APPLICATION 5

before - RENDER_RESPONSE 6
after - RENDER_RESPONSE 6
###### Done with Request!

我们注意到,因为点击了按钮,相当于发出了POST请求,页面经历了完整的六个阶段。其中按钮上的action事件是在INVOKE_APPLICATION 5阶段被调用。

实验2:页面代码同上,只是增加immediate="true":
点击按钮后的结果:
###### Processing new Request!
before - RESTORE_VIEW 1
after - RESTORE_VIEW 1
before - APPLY_REQUEST_VALUES 2
$$$$$ Action event processed...
after - APPLY_REQUEST_VALUES 2

before - RENDER_RESPONSE 6
after - RENDER_RESPONSE 6
###### Done with Request!

点击了按钮,相当于发出了POST请求,本来页面应该经历完整的六个阶段。
但是,因为按钮上的immediate="true",我们发现只经历了三个阶段,并且按钮上的action事件是在APPLY_REQUEST_VALUES 2阶段被调用。

实验3:一个InputText,一个validator,一个valueChangeListener,一个Button,页面代码如下:
<h:inputText value="hello">
<f:valueChangeListener type="com.javaneverdie.adf.lifecycle.view.valuechangelistener.MyValueChangeListener"/>
<f:validator validatorId="myValidator"/>
</h:inputText>
<h:commandButton value="Submit" id="cb1" action="#{myBackingBean.clickMe_action}"/>

点击按钮后的结果:
###### Processing new Request!
before - RESTORE_VIEW 1
after - RESTORE_VIEW 1
before - APPLY_REQUEST_VALUES 2
after - APPLY_REQUEST_VALUES 2
before - PROCESS_VALIDATIONS 3
$$$$$ Validate processed...
$$$$$ Value Change event processed...
after - PROCESS_VALIDATIONS 3

before - UPDATE_MODEL_VALUES 4
after - UPDATE_MODEL_VALUES 4
before - INVOKE_APPLICATION 5
$$$$$ Action event processed...
after - INVOKE_APPLICATION 5

before - RENDER_RESPONSE 6
after - RENDER_RESPONSE 6
###### Done with Request!

点击了按钮,相当于发出了POST请求,页面经历了完整的六个阶段。
其中值得注意的是,validator先调,valueChangeListener后调,两个事件都在PROCESS_VALIDATIONS 3阶段中被调用。
这其实符合我们一般的认识:只有验证通过了,才应该产生值变事件。

实验4:页面代码同上,只是在按钮上增加immediate="true":
点击按钮后的结果:
###### Processing new Request!
before - RESTORE_VIEW 1
after - RESTORE_VIEW 1
before - APPLY_REQUEST_VALUES 2
$$$$$ Action event processed...
after - APPLY_REQUEST_VALUES 2
before - RENDER_RESPONSE 6
after - RENDER_RESPONSE 6
###### Done with Request!

点击了按钮,相当于发出了POST请求,本来页面应该经历完整的六个阶段。
但是,因为按钮上的immediate="true",我们发现只经历了三个阶段。
其中值得注意的是,InputText上的validator和valueChangeListener并没有被调用!
这其实是我们在命令组件上使用immediate="true"的最常用的一个原因:跳过验证,直接处理action事件。
另外我们注意到,按钮上的action事件是在APPLY_REQUEST_VALUES 2阶段被调用得。

实验5:如果在输入组件上设置immediate="true",会有怎样的效果呢?代码如下:
<af:form id="f1">
<h:inputText value="hello" immediate="true">
<f:valueChangeListener type="com.javaneverdie.adf.lifecycle.view.valuechangelistener.MyValueChangeListener"/>
<f:validator validatorId="myValidator"/>
</h:inputText>
<h:inputText value="hello2">
<f:valueChangeListener type="com.javaneverdie.adf.lifecycle.view.valuechangelistener.MyValueChangeListener2"/>
<f:validator validatorId="myValidator2"/>
</h:inputText>
<h:commandButton value="Submit" id="cb1" action="#{myBackingBean.clickMe_action}"/>
</af:form>

点击按钮后的结果:
###### Processing new Request!
before - RESTORE_VIEW 1
after - RESTORE_VIEW 1
before - APPLY_REQUEST_VALUES 2
$$$$$ Validate processed...
$$$$$ Value Change event processed...
after - APPLY_REQUEST_VALUES 2

before - PROCESS_VALIDATIONS 3
$$$$$ Validate 2 processed...
$$$$$ Value Change 2 event processed...
after - PROCESS_VALIDATIONS 3

before - UPDATE_MODEL_VALUES 4
after - UPDATE_MODEL_VALUES 4
before - INVOKE_APPLICATION 5
$$$$$ Action event processed...
after - INVOKE_APPLICATION 5
before - RENDER_RESPONSE 6
after - RENDER_RESPONSE 6
###### Done with Request!

我们注意到第1个InputText的validator和valueChanger发生在APPLY_REQUEST_VALUES 2阶段,这是因为在这个InputText上的immediate="true"。
而第2个InputText的validator和valueChanger发生在PROCESS_VALIDATIONS 3阶段。

实验6:如果在第1个InputText上验证错误了以后,是否还会验证第2个InputText呢?
我们让第1个InputText上的validator抛出异常 throw new ValidatorException(message);
点击按钮后的结果:
###### Processing new Request!
before - RESTORE_VIEW 1
after - RESTORE_VIEW 1
before - APPLY_REQUEST_VALUES 2
$$$$$ Validate processed...
after - APPLY_REQUEST_VALUES 2
before - RENDER_RESPONSE 6
after - RENDER_RESPONSE 6
###### Done with Request!

从结果可以看出,由于第1个InputText验证没有通过,因此第2个InputText的validator也不再被调用了。
也就是说,在没有改正第1个InputText的错误之前,其它的验证器都不会起作用。

Project 下载:JSF_Lifecycle.7z

2009年1月15日星期四

JSF_015:JSF 高级开发之一:开发自己的 JSF 组件

如果只是使用JSF,你只需要知道「执行验证」、「更新模型值」与「唤起应用程序」这三个阶段及中间的事件触发,JSF 将这三个阶段之外的其它阶段之复杂性隐藏起来了,您不需要知道这几个阶段的处理细节。然而如果您要自订组件,则您还必须知道「恢复画面」、「套用请求值」与「绘制响应」这些阶段是如何处理的,这几个阶段相当复杂,所幸的是您可以使用JSF 所提供的框架来进行组件自订,JSF 提供的框架已经很大程度上降低了组件制作的复杂性。当然,即使JSF框架降低了复杂性,但实际上要处理JSF自订组件还是很复杂的一件事,在尝试开发自订组件之前,您可以先搜寻一些网站,像是 Apache MyFaceshttp://myfaces.apache.org/ ,看看是不是已经有相关类似的组件已经开发完成。
一个JSF 组件包括了三个部份:Tag、Component 与Renderer。
Tag 即之前一直在使用的JSF 卷标,类似于HTML 卷标,JSF 卷标主要是方便网页设计人员进行版面配置与数据呈现的一种方式,实际的处理中,JSF 标签的目的在于设定Component 属性、设定验证器、设定数据绑定、设定方法绑定等等。
Component 的目的在于处理请求,当请求来到伺服端应用程序时,每一个Component都有机会根据自己的client id,从请求中取得属于自己的值,接着Component 可以将这个值作处理,然后设定给绑定的bean。
当请求来到Web 应用程序时,HTTP 中的字符串内容可以转换为JSF 组件所需的值,这个动作称之为译码(decode),相对的,将JSF 组件的值转换为HTTP 字符串数据并送至客户端,这个动作称之为编码(encode),Component 可自己处理编码、译码的任务,也可以将之委托给 Renderer 来处理。
Renderer 是一个可替换的组件,您的Component 可以搭配不同的Renderer,而不用自行担任绘制响应或译码的动作,这会让您的Component 可以重用,当您需要将响应从HTML 转换为其它的媒介时(例如行动电话网络),则只要替换Renderer 就可以了,这是一个好处,或者您可以简单的替换掉一个Renderer,就可以将原先简单的HTML 响应,替换为有JavaScript 功能的Renderer。

2009年1月14日星期三

JSF_014:什么情况下该调用 request.getSession(false)方法?

查看Java EE API,解释如下:
(1)getSession(boolean create):返回当前request对象中的HttpSession对象,如果当前request中的HttpSession 为null,当create为true,就创建一个新的Session,否则返回null。
(2)HttpServletRequest.getSession() 等同于 HttpServletRequest.getSession(ture)。

解释的比较清楚,但是到底什么情况下使用 request.getSession(false)方法,什么情况下使用 request.getSession(true)方法呢?

为了节省Web 服务器内存资源,不要创建没有用处的HttpSession对象。
因此,好的系统设计应该限定一个HttpSession只能从单一入口程序(Servlet/Filter)创建。
比如只有用户登录成功后才可以调用 request.getSession(true)创建HttpSession对象;其它程序只能调用request.getSession(false)获取HttpSession对象。
这样做的好处是,防止用户访问了其它程序,导致创建了一些不必要的HttpSession对象,造成内存浪费。

参考文献:
1. 《深入体验Java Web 开发内幕——核心基础》

2009年1月13日星期二

JSF_013:JSF 入门级开发之三:使用 Managed Bean

本文最后一次修改时间:2012-01-19。
开发环境:JDeveloper 11.1.2.1.0。

完成《Bind a JSF Page to a Managed Bean》。

以下对常用操作界面中的选项作一下说明:

1. Resource Bundle
默认情况下,JDeveloper不会为页面自动产生资源文件。要想自动产生,在 Project Properties 面板中,选上Automatically Synchronize Bundle。


2. 选择Managed Bean
在faces-config.xml中注册Managed Bean后,就可以为组件,比如InputText的Value值绑定到Managed Bean的某个属性上。


Project 下载: JSFBeanApp.7z

2009年1月12日星期一

JSF_012:JSF 入门级开发之二:创建页面导航规则

本文最后一次修改时间: 2012-01-18。
开发环境:JDeveloper 11.1.2.1.0。

完成 《Create JSF Page Navigation》。

以下对常用操作界面中的选项作一下说明:

1. 创建 Application
因为是创建标准的JSF应用,所以选择Java EE Web Application。

注意,这一点跟教程有出入,因为教程是针对JDeveloper 11.1.1的。

2. 创建 JSF1.0 页面
注意,这里我为了跟教程一致,没有选择JSF2.0页面,而是选择了JSP页面。
因为是创建标准的JSF1.0页面,所以右上角的组件面板要选择JSF。

3. 编辑 faces-config.xml 文件
创建好页面后,再把页面拖放到faces-config.xml界面上来。
如果从JSF面板中,拖放页面到faces-config.xml界面上,会生成后缀为.jsf的页面,这个是JSF2.0的页面,不是我们想要的。

Project 下载: JSFNavigateApp.7z

2009年1月11日星期日

JSF_011:JSF 入门级开发之一:一个简单的JSF应用

本文最后一次修改时间: 2012-01-18。
开发环境:JDeveloper 11.1.2.1.0。

完成《Build a Simple JSF Application》。

以下对常用操作界面中的选项作一下说明:

1. 创建 Application
因为是创建标准的JSF应用,所以选择Java EE Web Application。
注意,这一点跟教程有出入,因为教程是针对JDeveloper 11.1.1的。

2. 创建 JSF1.0 页面
注意,这里我为了跟教程一致,没有选择JSF2.0页面,而是选择了JSP页面。
因为是创建标准的JSF1.0页面,所以右上角的组件面板要选择JSF。


选项说明:
(1)Create as XML Docuemnt(*.jspx)
选中这个选项,源码是一个XML文件:
<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
<jsp:directive.page contentType="text/html;charset=UTF-8"/>
<f:view>
<af:document id="d1">
<af:form id="f1"></af:form>
</af:document>
</f:view>
</jsp:root>

不选中这个选项,源码是符合JSP规范的jsp文件:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%@ page contentType="text/html;charset=UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://xmlns.oracle.com/adf/faces/rich" prefix="af"%>
<f:view>
<af:document id="d1">
<af:form id="f1"></af:form>
</af:document>
</f:view>

注意,两种方式中都包括了 html和core 库。
The JavaServer Faces HTML tag library, which contains tags representing common HTML user interface components.
The JavaServer Faces core tag library, which contains tags that perform core actions such as event handling and data conversion.

组件面板中还有HTML、CSS和JSP组件的Tags,建议不要在一个页面中混用JSP和JSF组件。

(2)Automatically Expose UI components in a New Managed Bean
是否自动把UI组件binding到一个新的Managed Bean。
如果选择是,以后向界面中拖放一个组件,都会在相应的Managed Bean中增加一定的代码,并且在JSF的代码中,会将该组件binding到该Managed Bean中的对应对象。
如果选择否,就不会产生一个新的Managed Bean。
以后可以手工把UI组件binding到指定的Managed Bean。
方法是选择该UI组件,然后在属性窗口里选择binding。
或者为整个页面手工指定Managed Bean:Design--> Page Properties --> Auto Bind。

注:这是个很重要的小技巧,请记住。

(3)双击按钮,可以为按钮增加action事件。

3. 编辑 faces-config.xml 文件


4. Standard JSF Component Tag Attributes
(1)Common:
Commonly used attributes, which varies from component to component.
Also includes the attributes id and binding.
The id is the unique identifier of a component, which must be a valid XML name; you cannot use leading numeric values or spaces in the id name.
The binding is the EL expression that binds a component instance to a property in a bean.
(2)Appearance:
Basic attributes that control the visible parts, including title and accessKey.
Style: HTML style and presentation attributes such as background, border, cellpadding, cellspacing, font, margin, style, outline. Most of the attributes that the HTML 4.01 specification declares for corresponding HTML elements are supported.
(3)Behavior:
Basic attributes that control the component's behavior, including HTML pass-through attributes such as disabled and readOnly.
Also includes an Internationalization section for HTML language translation attributes such as lang and dir.
(4)JavaScript:
HTML event attributes (for associating client-side scripts with events) such as onclick, onkeypress, and onmouseover.

Project 下载: JSFApplication.7z

2009年1月10日星期六

JSF_010:JSF FacesContext

在JSF中,所有请求都由FacesServlet处理,它会为每一个请求创建一个javax.faces. context. FacesContext类的实例。
那么,如何获取当前的FacesContext实例呢?很简单,FacesContext facesContext = FacesContext.getCurrentInstance(); 。
至于我们熟悉的其它对象信息,如ServletContext、ServletRequest和ServletResponse,则是通过获取ExternalContext后,调用相应方法再获取。

1. 获取ServletContext对象
Object contextAttribute = null;
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
Map contextMap = externalContext.getApplicationMap();
if (contextMap!=null)
contextAttribute = contextMap.get("user");

String initParam = externalContext.getInitParameter("userName");

Map paramMap = externalContext.getInitParameterMap();
if (paramMap!=null)
System.out.println(paramMap.get("userName"));

2. 获取Session中的参数值
Object sessionAttribute = null;
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
Map sessionMap = externalContext.getSessionMap();
if (sessionMap!=null)
sessionAttribute = sessionMap.get(key);

3. 获取Resquest 对象
Object requestAttribute = null;
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
Map requestMap = externalContext.getRequestMap();
if (requestMap!=null)
requestAttribute = requestMap.get(key);

Map requestParameterMap = externalContext.getRequestParameterMap();
if (requestParameterMap!=null)
id = (String) requestParameterMap.get("id"); Map requestParameterMap = externalContext.getRequestParameterMap();
Iterator parameterNames = externalContext.getRequestParameterNames();
while (parameterNames.hasNext()) {
String parameterName = (String) parameterNames.next();
String parameterValue =(String) requestParameterMap.get(parameterName);
System.out.println(parameterName + " : " + parameterValue);
}

Map requestParameterValuesMap = externalContext.getRequestParameterValuesMap();
if (requestParameterValuesMap!=null) {
id = (String[]) requestParameterValuesMap.get("id");
for (int i=0; i<id.length; i++) {
System.out.println(id[i]);
}
}


Map headerMap = externalContext.getRequestHeaderMap();
if (headerMap!=null) {
host = (String) headerMap.get("host");
System.out.println(host);
}

Map headerValuesMap = externalContext.getRequestHeaderValuesMap();
if (headerValuesMap!=null) {
Enumeration headers =(Enumeration) headerValuesMap.get("Accept-Encoding");
while (headers.hasMoreElements()) {
String value = (String) headers.nextElement();
System.out.println(value);
}
}

4. 获取Managed Bean
FacesContext context = FacesContext.getCurrentInstance();
ValueBinding binding =context.getApplication().createValueBinding("#{user}");
UserBean user = (UserBean) binding.getValue(context);

2009年1月9日星期五

JSF_009:JSF 的生命周期

JSF页面的生命周期与JSP页面的生命周期有几分类似:客户端发起一个HTTP请求,请求该页面,服务端响应该请求,把该页面(转换成HTML)返回给客户端。
但是,JSF页面的生命周期要更复杂,它增加了一些服务。
根据不同的请求(initial requests 和 postbacks),生命周期所包括的阶段有所不同。
如果是initial requests,表明客户端是第一次请求该页面,因为没有任何用户输入,生命周期只有restore view 和 render response这两个阶段;
如果是postbacks,表明客户端是提交了一个表单(含有该表单的页面之前已经被initial requests 请求显示了),此时生命周期将包括完整的六个阶段。

除了事件处理,JSF的生命周期包括六个阶段:
  1. 恢复视图(Restore View)
    在此阶段,会接到一个来自FacesServlet控制器的请求。控制器会对请求进行考查,并提取出视图ID,就是该JSP页面的名称。
    控制器根据视图ID来查找该视图的所有组件。如果这个视图尚未存在,控制器会创建它;如果这个视图已经存在,控制器会使用它。
    如果是initial requests,为该页面新的组件树,然后直接到阶段6:绘制响应阶段;如果是postbacks,进入阶段2。

  2. 套用申请值(Apply Request Values)
    每个组件尝试从请求中找寻自己的参数并更新组件值,接着触发ActionEvent,该事件会被排入队列中,直到阶段5(唤起应用程序)由事件处理者进行处理。

  3. 执行验证(Process Validations)
    进行转换与验证。如果验证出错,则会跳过之后的阶段,直接到阶段6:绘制响应阶段,重新呼叫同一页面并绘制结果。

  4. 更新模型值(Update Model Values)
    更新每一个与组件绑定的backing bean 或 模型对象。

  5. 唤起应用程序(Invoke Application)
    处理动作事件,执行后端应用程序逻辑。

  6. 绘制回应(Render Response)
    使用绘制器绘制页面。

2009年1月8日星期四

JSF_008:错误信息的显示与保存

使用标准转换器或验证器出错时,会有一些预设的错误讯息显示,这些信息可以使 用<h:messages>或<h:message>标签来显示出来。
错误信息预先写在 一个properties文件中。

2009年1月7日星期三

JSF_007:JSF Validator

当用户输入数据时,必然要对输入进行检验,检验包括语法检验和语义检验。

  • 语法检验(Synatic Validation)
    检查使用者输入的数据是否合乎我们所要求的格式,最基本的就是检查使用者是否填入了字段值,或是字段值的长度、大小值等等是否符合要求。

  • 语义检验(Semantic Validation)
    在通过语法检验之后,进一步验证输入的数据语意上是否正确,例如检查使用者的名称与密码是否匹配。
JSF提供了三种标准验证器:
(1)<f:validateDoubleRange>
(2)<f:validateLongRange>
(3)<f:validateLength>

当然,除了JSF提供的标准的验证器,你也可以自己定制验证器。

2009年1月6日星期二

JSF_006:JSF Converter

Web 应用与浏览器之间使用HTTP 进行沟通,浏览器所传送的数据都是字符串,而Java 应用程序使用的都是对象,对象必须转换成字符串传送给浏览器,而浏览器传送来的字符串必须转换为对象供程序使用。
为此,JSF 定义了一系列标准的转换器:
(1)对于基本数据类型(primitive type)或其Wrapper 类型,JSF使用javax.faces.Boolean、javax.faces.Byte、javax.faces.Character、 javax.faces.Double、javax.faces.Float、javax.faces.Integer、 javax.faces.Long、javax.faces.Short 自动进行转换。
(2)对于BigDecimal、BigInteger,使用javax.faces.BigDecimal、 javax.faces.BigInteger自动进行转换。
(3)对于DateTime、Number,使用
<f:convertdatetime> 和 <f:convertnumber>标签进行转换,它们各自提供一些属性,供转换时指定格式。

当然,除了JSF提供的标准的转换器,你也可以自己订制转换器。

2009年1月5日星期一

JSF_005:JSF Expression Language

JSF EL是存取数据对象的一个简易语言,搭配JSF 标签来使用。
使用方法很简单:以#开始,将变量或表达式放置{与}之间,例如:#{someBeanName}。
注意,JSF EL格式为#{expression},而JSP EL格式为${expression}。在JSF的标签中设定属性时,只能接受JSF EL。

2009年1月4日星期日

JSF_004:JSF Navigation Rule

JSF 导航规则的配置信息包含在 faces-config.xml 文件中:<faces-config>
<navigation-rule>
<from-view-id>/pages/index.jsp</from-view-id>
<navigation-case>
<from-outcome>login</from-outcome>
<to-view-id>/pages/welcome.jsp</to-view-id>
</navigation-case>
</navigation-rule>

</faces-config>

说明(1)<from-view-id>:来自页面。
(2)<navigation-case>:定义各种导航条件。
(3)<from- outcome>:当来自页面的form的action值等于该条件时,导向哪一个目的页面。该action值来自于Command类型的 组件的action属性,该属性值可以为Managed Beans的一个属性或一个方法(返回值)。
(4)<to-view-id>:目的页面。
(5)你还可以在<navigation-case>中加入<from-action>,进一步规定 form的action值必须来自哪一个动作方法(action method),使用 EL来设定。像这样,
<navigation-rule>
<from-view-id>/pages/index.jsp</from-view-id>
<navigation-case>
<from-action>#{user.verify}</from-action>
<from-outcome>success</from-outcome>
<to-view-id>/pages/welcome.jsp</to-view-id>
</navigation-case>
....
</navigation-rule>
(6)如果来自网页是某个特定模块,可以使用wildcards,即 * 字符。像这样,
<navigation-rule>
<from-view-id>/admin/*</from-view-id>
<navigation-case>
<from-action>#{user.verify}</from-action>
<from-outcome>success</from-outcome>
<to-view-id>/pages/welcome.jsp</to-view-id>
</navigation-case>
....
</navigation-rule>
(7)使用 forward 或 redirect 方式导航到下一页面(默认是forward 方式)。像这样,
<navigation-rule>
<from-view-id>/pages/index.jsp</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/pages/welcome.jsp</to-view-id>
<redirect/>
</navigation-case>
....
</navigation-rule>

关于
forward 和 redirect 的区别请参考《HTTP forward 与 redirect 的区别

2009年1月3日星期六

JSF_003:JSF Managed Bean

JSF Managed Bean的配置信息包含在 faces-config.xml 文件中:
<faces-config>
<managed-bean>
<managed-bean-name>user</managed-bean-name>
<managed-bean-class>onlyfun.caterpillar.UserBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
</faces-config>

你可以使用普通Java Bean与UI组件进行binding(即在配置文件faces-config.xml中注册的Managed beans),但最好的选择是使用JSF managed bean,即Backing Bean。
Backing Bean是Managed Bean的一种,由于它只为页面服务,是页面的幕后工作者,因此叫Backing Bean。
它的主要功能是:
(1)访问页面上UI组件的值。
(2)页面上的事件处理。
A backing bean is a convention to describe a managed bean that stores accessors for UI components and event handling code on a JSF page.
It exists forthe duration of a request and should not be used to maintain state
其作用是在真正的业务逻辑Bean和UI组件之间搭起桥梁,在Backing Bean中会呼叫业务逻辑Bean处理请求,或者将业务处理结果放置其中,由UI 组件获取并显示出来。
Backing bean的具体工作包括:

  • 存储 UI组件的属性。

  • 定义 UI组件上的action方法。

  • 作为 UI组件树的实例,根据需要,动态掌控用户界面,比如显示/隐藏某些组件。

当JSF应用启动时,它将解析配置文件faces-config.xml,装载Managed beans类。
当某个组件引用到某个Managed bean时(如使用EL表达式),该Managed bean将被实例化(用默认的构造器),属性也随之被赋上默认值(可在配置文件中指定)。
Managed bean的引用名唯一标识该Managed bean,你可以修改Managed bean类的内容,但在JSF中仍然使用Managed bean的引用名,因此视图不受模型影响。
<managed- bean-scope>的值可以设定为如下值,表示不同的生命周期:

  • application:在Web应用中可见,直到应用程序关闭为止。适用于全局性的bean,如 LDAP 目录。

  • session:在当前会话中(从打开浏览器到关闭浏览器或显式注销之间)可见。

  • request:在当前请求周期内(从页面发送请求到收到响应之间,注意,可能forward多个页面)可见。

  • none:在每次引用时可见,用完后不可见。适用于一个bean被其它beans引用。

2009年1月2日星期五

JSF_002:JSF 架构

1. JSF MVC架构图
2. JSF组件架构图

2009年1月1日星期四

JSF_001:JSF 是啥东东?

【JSF】:JavaServer Faces。JSF是一种构建Java Web应用的标准框架。说它标准,是因为JSF1.1符合JSR 127 ;JSF1.2符合JSR 252
下面这个英文定义准确地表达了JSF的特征:
JavaServer Faces technology is a server-side user interface component framework for Java technology-based web applications. It includes

  • A set of APIs for representing UI components and managing their state, handling events and input validation, defining page navigation, and supporting internationalization and accessibility.
  • A JavaServer Pages (JSP) custom tag library for expressing a JavaServer Faces interface within a JSP page.
那么,JSF比其它Web开发框架有何优势?要回答这个问题,我们就要从Web开发谈起。我们知道,Web 开发比桌面应用开发相对要复杂的多,因为开发者必须要关注
(1)必须深入HTTP 的细节,比如要处理数据验证与转换。
(2)HTTP 本身是无状态的,每个请求/响应与其它的请求/响应无关。如何维持多个请求之间状态信息?如何保证事务的完整性和一致性?
(3)Web安全。
(4)本质上是静态的HTML与本质上是动态的应用程序造成网页设计人员与应用程序开发人员之间的矛盾,双方将互相干扰。

与其它Web开发框架不同,JSF是 Web 开发的新的标准,很多厂商已经支持JSF Container了。
而且,与传统的request-driven Web框架不同,JSF基于组件开发Web应用,一个JSF页面是由一个树状的UI组件组成的,目的就是让你感觉不到是在开发Web应用——和开发桌面应用一样。


JSF的核心组件包括:
(1)UI组件:即JSF标签库,JSF是基于组件的。
(2)导航模型:定义了导航规则。
(3)Managed Beans:封装业务逻辑和数据。
(4)Expression Language:把数据或方法绑定到组件上。
(5)生命周期管理
(6)其它助手类:转换器与验证器。


参考文献:
1. 《JSF 教程》 作者:Tellixu。
2. 《使用JSF 架构进行设计》
3. 《JSF 应用程序的生命周期》