jee6 学习笔记 5 - Struggling with JSF2 binding GET params

这题目可能有点儿吓人,但却是实事求是。

我们看看JSF2有哪些方法来获取HTTP GET parameters:

1. use of new JSF tag "f:viewParam". is it ugly?


    //in the page:
    <f:metadata>  
        <f:viewParam name="s1" value="#{pt.s1}" />  
    </f:metadata>  

    //in the bean:
    private String s1;
    // s1 getter/setter


2. use @ManagedProperty(value="#{param.s2}"). an EL in backing bean? what's the point? The backing bean must be @RequestScoped, which is the default scope. For a post-redirect, test showed that you must append the "faces-redirect=true" to the GET url, as part of the query string. otherwise it's just not working.


@ManagedProperty(value="#{param.s2}")
private String s2;
// s2 getter/setter

public String urActionMethod() {
  return "/tst/testGetParam.xhtml?faces-redirect=true&s2=hello&s1=hi"
}


3. use of tag <f:setPropertyActionListener value="val" target="#{bean.propertySetter}">.

4. get the "native" HttpServletRequest" object and get parameters by the servlet API: your final resort if all other means does not work.
(HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
request.getParameter("paramName");


the page: "tst/testGetParam.xhtml"
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:p="http://primefaces.org/ui">
    
<h:head>
	<title>Test JSF Parameter Binding</title>
</h:head>

<h:body>

	<!-- GET: by a new JSF tag "f:viewParam" -->
	<f:metadata>
	    <f:viewParam name="s1" value="#{pt.s1}" />
	</f:metadata>
	
	<p:panel header="Test1: by new tag 'f:viewParam'" style="width:50%">
		s1=<h:outputText value="#{pt.s1}"/>
	</p:panel>
	
	<p:spacer height="7"/>

	<!-- POST followed by a redirect with GET. Not working without redirect -->
	<h:form id="frm2">
		<p:panel header="Test2: POST followed by a redirect GET" style="width:50%">
			<p:commandButton update="out2" value="Go GET 2" action="#{pt.print2}"/> 
			s2=<h:outputText id="out2" value="#{pt.s2}"/> 
		</p:panel>
    </h:form>
    
    <p:spacer height="7"/>
	
	<!-- POST with tag 'f:setPropertyActionListener' -->
	<h:form id="frm3">
		<p:panel header="Test3: with tag 'f:setPropertyActionListener'" style="width:50%">
			<p:commandButton update="out3" value="Go POST" actionListener="#{pt.print3}">
				<f:setPropertyActionListener value="hello world III!" target="#{pt.s3}"/> 
			</p:commandButton>
			s3=<h:outputText id="out3" value="#{pt.s3}"/> 
		</p:panel>
    </h:form>
</h:body>
</html>


the backing bean: "ParameterTester.java"
package com.jxee.action.getparam;

import java.io.Serializable;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;

/**
 * backing bean to test JSF2 parameter binding
 */
@ManagedBean(name="pt")
@RequestScoped
public class ParamTester implements Serializable {

  private static final Logger log = Logger.getLogger(ParamTester.class);
  
  private String s1;
  
  @ManagedProperty(value="#{param.s2}")
  private String s2;
  
  private String s3;
  
  private HttpServletRequest request;


  @PostConstruct
  public void init() {
    log.debug(String.format(">>> PostConstruct: s1=%s, s2=%s, s3=%s", s1, s2, s3));
    request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
    this.printRequestParams();
  }

  private void printRequestParams() {
    log.debug("--- printing 3 params in http request:");
    String ps1 = request.getParameter("s1");
    String ps2 = request.getParameter("s2");
    String ps3 = request.getParameter("s3");
    log.debug(String.format("--- Http Request params: ps1=%s,ps2=%s,ps3=%s ---", ps1,ps2,ps3));
  }
  
  public String print2() {
    log.debug(">>> print2 called, do redirect with url query string");
    this.printRequestParams();
    return "/tst/testGetParam.xhtml?faces-redirect=true&s2=hello john!&s1=hi s1 again!";
  }
  
  public String print3() {
    log.debug(">>> print3 called, setPropertyActionListener");
    this.printRequestParams();
    return null;
  }
  
  public String getS1() {
    return s1;
  }

  public void setS1(String s1) {
    this.s1 = s1;
  }
  
  public String getS2() {
    return s2;
  }

  public void setS2(String s2) {
    this.s2 = s2;
  }
  
  public String getS3() {
    return s3;
  }

  public void setS3(String s3) {
    this.s3 = s3;
  }
}


test screens:

1. set get request with url: http://localhost:8180/ProJee6/tst/testGetParam.jsf?s1=hi01&s2=hi02&s3=hi03

jee6 学习笔记 5 - Struggling with JSF2 binding GET params_第1张图片

server log:
2012-07-18 12:13:52,003 DEBUG  [ParamTester] >>> PostConstruct: s1=null, s2=hi02, s3=null
2012-07-18 12:13:52,018 DEBUG  [ParamTester] --- printing 3 params in http request:
2012-07-18 12:13:52,018 DEBUG  [ParamTester] --- Http Request params: ps1=hi01,ps2=hi02,ps3=hi03 ---


2. clicked button "GET 2"

jee6 学习笔记 5 - Struggling with JSF2 binding GET params_第2张图片

server log:
2012-07-18 12:16:59,141 DEBUG  [ParamTester] >>> PostConstruct: s1=null, s2=null, s3=null
2012-07-18 12:16:59,141 DEBUG  [ParamTester] --- printing 3 params in http request:
2012-07-18 12:16:59,141 DEBUG  [ParamTester] --- Http Request params: ps1=null,ps2=null,ps3=null ---
2012-07-18 12:16:59,141 DEBUG  [ParamTester] >>> print2 called, do redirect with url query string
2012-07-18 12:16:59,141 DEBUG  [ParamTester] --- printing 3 params in http request:
2012-07-18 12:16:59,141 DEBUG  [ParamTester] --- Http Request params: ps1=null,ps2=null,ps3=null ---
2012-07-18 12:16:59,141 DEBUG  [ParamTester] >>> PostConstruct: s1=null, s2=hello john!, s3=null
2012-07-18 12:16:59,141 DEBUG  [ParamTester] --- printing 3 params in http request:
2012-07-18 12:16:59,157 DEBUG  [ParamTester] --- Http Request params: ps1=hi s1 again!,ps2=hello john!,ps3=null ---

3. clicked button "GO POST"
one thing to mention: after the form submitted, "s2" still has the same value. this is because that it used Primefaces <p:commandButton> instead of JSF <h:commandButton/>. Primefaces <p:commandButton/> uses ajax as default method to submit the form. This can be disabled by adding attribute ajax="false": <p:commandButton value="Go POST" action="#{pt.print3}" ajax="false">. Now after "Go POST" clicked, the page re-rendered and "s2" should be empty.

jee6 学习笔记 5 - Struggling with JSF2 binding GET params_第3张图片

server log:
2012-07-18 12:20:15,217 DEBUG  [ParamTester] >>> PostConstruct: s1=null, s2=null, s3=null
2012-07-18 12:20:15,217 DEBUG  [ParamTester] --- printing 3 params in http request:
2012-07-18 12:20:15,217 DEBUG  [ParamTester] --- Http Request params: ps1=null,ps2=null,ps3=null ---
2012-07-18 12:20:15,217 DEBUG  [ParamTester] >>> print3 called, setPropertyActionListener
2012-07-18 12:20:15,217 DEBUG  [ParamTester] --- printing 3 params in http request:
2012-07-18 12:20:15,217 DEBUG  [ParamTester] --- Http Request params: ps1=null,ps2=null,ps3=null ---


结论:

也许是本人,maybe it's JSF2.0, that is struggling with GET parameters. it seems to me that @ManagedPropery requires @RequesetScoped might be reasonable but this limitation makes the @ManagedProperty virtually useless in this case.

the only use full stuff JSF provides in this use case is the tag <f:setPropertyActionListener value="val" target="#{bean.property}">.

JSF should provide something like SEAM2 tag @RequestParameter("pname"), so that the GET parameter can be injected to the backing bean directly. forget the @ManagedProperty here: the value is in the HttpServletRequest and the framework should be able to bind the request parameter by a simple annotation, without anything else required. no more drama!

It's such a common simple task to bind GET parameters to backing beans. but JSF2 tried lots of stuff and just failed the test.

Next i'd explore some features of EJB3.1 and then come back to Primefaces, such as adding menu, using template and etc.

The zipped project so far: ProJee6-phase1.zip

你可能感兴趣的:(get,Parameters,jsf2)