CDI ViewScope 和 PrettyFaces:多次调用 @PostConstruct (JSF 2.2)

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

我已经检查了声明 JSF 2.1 有此错误的类似问题,但我使用的是 JSF 2.2 让我们详细说明:

我的环境:

我的豆子:

@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
  }
}

那个控制器,现在只是一个模拟,returns 一个单元素列表。

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

我用的是漂亮的脸蛋,pretty-config.xml如下:

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

home.xhtml 中,我将省略不相关的代码,但我会调用 NhomeBean;例如 #{home.buttonClicked()}


好的;现在的问题。


每个对 HomeBean 的引用都会创建一个新的 HomeBean 实例;如果我在 @PostConstruct 处用断点调试它,它会被调用 N 次;所以控制器被调用 N 次并且日志行 "HomeBean: initialized" 被打印 N 次。

它是 @ViewScopped,所以我认为它会在整个视图中都处于活动状态,不是吗?

比方说,它最终正确地呈现了主页...但是控制器将成为数据库访问...我不希望每个图像都有新的数据库访问! O_O

[编辑] 它肯定与 pretty-faces 相关,因为如果我删除它,它就可以正常工作。我在 web.xml

中将 Pretty faces 配置如下
<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>

Pom 依赖项是(prettyfaces.version 是 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>

那里发生了什么事?非常感谢。

问题是由这个映射引起的:

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

此映射基本上匹配以 / 开头的每个 URL。所以它不仅匹配 /foobar,还匹配 /style.css/scripts.js/jquery.min.js 等等。

基本上有两种方法可以解决这个问题。首先,您可以尝试使用 custom regular expression 来限制允许包含的路径参数。例如,您可以使用这样的东西:

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

这告诉 PrettyFaces 省名只能包含字母,不能包含数字、句点等。这类似于 style.css 将不再匹配。

第二种选择是使用某种 URL 前缀,如下所示:

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

这是我通常推荐的方法,因为它是最简单直接的方法。 :)