Mastering JavaServer Faces 2.2
上QQ阅读APP看书,第一时间看更新

The request scope

The request scope is bound to the HTTP request-response life cycle.

The request scope is very useful in any web application, and an object defined in the request scope usually has a short lifespan; beans live as long as the HTTP request-response lives. When the container accepts an HTTP request from the client, the specified object is attached to the request scope and it is released when the container has finished transmitting the response to that request. A new HTTP request always comes in a new request scope object. In short, a request scope represents a user's interaction with a web application in a single HTTP request. Commonly, a request scope is useful for simple GET requests that expose some data to the user without requiring to store the data.

Note

The request scope is present in JSF and CDI and functions in the same way. It can be used for nonrich AJAX and non-AJAX requests. For JSF managed beans (@ManagedBean), this is the default scope, when none is specified.

For example, let's suppose that we have a predefined list of tennis players, and we randomly extract them one-by-one from this list and store them in another list. The current generated player and the list of extracted players are managed bean's properties and their values are rendered in a JSF page.

Note

The request scope annotation is @RequestScoped and is defined in the javax.enterprise.context package for CDI, and in the javax.faces.bean package for JSF.

The code for the CDI bean can be written as follows:

@Named
@RequestScoped
public class PlayersBean {

  final String[] players_list = {"Nadal, Rafael (ESP)","Djokovic, Novak (SRB)", "Ferrer, David (ESP)", "Murray, Andy (GBR)", "Del Potro, Juan Martin (ARG)"};

  private ArrayList players = new ArrayList();
  private String player;

  //getters and setters
      
  public void newPlayer() {
    int nr = new Random().nextInt(4);
    player = players_list[nr];
    players.add(player);
  }
}

The relevant part of the JSF page is as follows:

<h:body>
  Just generated:
  <h:outputText value="#{playersBean.player}"/><br/>

  List of generated players:
  <h:dataTable var="t" value="#{playersBean.players}">
    <h:column>
      <h:outputText value="#{t}"/>
    </h:column>
  </h:dataTable>       
  <h:form>
    <h:commandButton value="Get Players In Same View" actionListener="#{playersBean.newPlayer()}"/>
    <h:commandButton value="Get Players With Page Forward" actionListener="#{playersBean.newPlayer()}" action="index.xhtml"/>
    <h:commandButton value="Get Players With Page Redirect" actionListener="#{playersBean.newPlayer()}" action="index.xhtml?faces-redirect=true;"/>
  </h:form>
</h:body>

When you click on the button labeled Get Players With Page Forward or Get Players In Same View, you will see something as shown in the following screenshot:

Since a request scope lives as long as the HTTP request-response lives and page forward implies a single HTTP request-response, you will see the player extracted at the current request and the list of extracted players, which will always only contain this player. The list is created for each request and filled with the current player, which makes the list useless.

Note

The request scope doesn't lose the object's state while forwarding, because the source page and the destination page (the forwarded page) are part of the same request-response cycle. This is not true in the case of redirect actions.

When you click on the button labeled Get Players With Page Redirect, you will see something as shown in the following screenshot:

The current extracted player and the list content is not available in this case, because a JSF redirect implies two requests, instead of one as in the forward case.

Programmatically, you can access the request map using the following code:

FacesContext context = FacesContext.getCurrentInstance();
Map<String, Object> requestMap = context.getExternalContext().getRequestMap();

Submitting a form defined in page 1 to page 2 via a bean, and then you have the following cases:

  • If the same view or forward is used, then the data is available for display on page 2
  • If redirect is used, then data will be lost and not available for display on page 2

The JSF version of the CDI beans is as follows:

import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;

@ManagedBean
@RequestScoped
public class PlayersBean {
  ...
}

And it works the same as the CDI bean!

Note

A method annotated with @PostConstruct will be called for each request, since each request requires a separate instance of the request scoped bean.

The case of the CDI bean is wrapped into the application named ch3_1_1, while the case of the JSF bean is wrapped into application named ch3_1_2.