CDI ViewScope & PrettyFaces: Multiple calls to @PostConstruct (JSF 2.2)

冷暖自知 提交于 2019-12-22 10:18:29

问题


I'v already check similar questions which declare that JSF 2.1 had this bug, but I'm using JSF 2.2 Let's detail:

My environment:

  • CDI: 1.1
  • Dynamic Web Module: 3.0
  • Java: 1.7
  • JSF: 2.2
  • PrettyFaces: 2.0.12.Final

My Bean:

@Named(value = "home")
@javax.faces.view.ViewScoped
public class HomeBean implements Serializable {

  @Inject
  private HomeController controller;

  private List<Store> myPopularStores;

   @PostConstruct
   public void postConstruct() {
    myPopularStores = controller.getStores();
    LOG.log(Level.FINE, "HomeBean: initialized");
  }

  public String buttonClicked() {
     // whatever
  }
}

That controller, right now is just a mock which returns a one-element list.

@Named
public class HomeController implements Serializable {
  public List<Store> getStores() {
    // mocked
  }
}

I'm using pretty faces, the pretty-config.xml is the following:

<?xml version="1.0" encoding="UTF-8"?>
<pretty-config xmlns="http://ocpsoft.org/schema/rewrite-config-prettyfaces" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://ocpsoft.org/schema/rewrite-config-prettyfaces
                      http://ocpsoft.org/xml/ns/prettyfaces/rewrite-config-prettyfaces.xsd">

 <url-mapping id="Home">
    <pattern value="/" />
    <view-id value="/home.xhtml" />
  </url-mapping>

 <url-mapping id="cityIndex">
    <pattern value="/#{provinceName}" />
    <view-id value="/home.xhtml" />
 </url-mapping>

</pretty-config>

In the home.xhtml I'm going to omit irrelevant code but say that I call N times the homeBean; for example #{home.buttonClicked()}


OK; Now the problem.


Each one of those references to the HomeBean, creates a new HomeBean instance; If I debug it with a breakpoint at the @PostConstruct it's called N times; so the controller is called N times and the log line "HomeBean: initialized" is printed N times.

It's a @ViewScopped, so I assume it will be alive for the entire view isn't it?

Let's say, finally it renders the home page correctly... but the controller is going to be a DB access... I don't want a new DB access per image! O_O

[EDITED] It's definitely related with pretty-faces because if I remove it, it works perfectly fine. I've configured Pretty faces as the following in the web.xml

<filter>
    <filter-name>OCPsoft Rewrite Filter</filter-name>
    <filter-class>org.ocpsoft.rewrite.servlet.RewriteFilter</filter-class>
    <async-supported>true</async-supported>
</filter>
<filter-mapping>
    <filter-name>OCPsoft Rewrite Filter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ASYNC</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

And the Pom dependencies are (prettyfaces.version is 2.0.12.Final):

<dependency>
   <groupId>org.ocpsoft.rewrite</groupId>
   <artifactId>rewrite-servlet</artifactId>
   <version>${prettyfaces.version}</version>
</dependency>
<dependency>
   <groupId>org.ocpsoft.rewrite</groupId>
   <artifactId>rewrite-integration-faces</artifactId>
   <version>${prettyfaces.version}</version>
</dependency>
<dependency>
   <groupId>org.ocpsoft.rewrite</groupId>
   <artifactId>rewrite-config-prettyfaces</artifactId>
   <version>${prettyfaces.version}</version>
</dependency>

What's going on there? Thx very much.


回答1:


The problem is caused by this mapping:

<url-mapping id="cityIndex">
   <pattern value="/#{provinceName}" />
   <view-id value="/home.xhtml" />
</url-mapping>

This mapping is basically matching every URL beginning with a /. So it doesn't just match /foobar but also /style.css and /scripts.js and /jquery.min.js and so on.

There are basically two ways to fix this. First you could try to use a custom regular expression to restrict what the path parameter is allowed to contain. You could for example use something like this:

<url-mapping id="cityIndex">
   <pattern value="/#{ /[a-z]+/ provinceName }" />
   <view-id value="/home.xhtml" />
</url-mapping>

This tells PrettyFaces that the province name must only contain letters, but no number, periods, etc. This was something like style.css won't be matched any more.

The second option is to use some kind of URL prefix like this:

<url-mapping id="cityIndex">
   <pattern value="/province/#{provinceName}" />
   <view-id value="/home.xhtml" />
</url-mapping>

That's what I usually recommend as it is the most simply and straight forward way. :)



来源:https://stackoverflow.com/questions/30378962/cdi-viewscope-prettyfaces-multiple-calls-to-postconstruct-jsf-2-2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!