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.
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