我有一个JSF页面,它接受一个viewparam并设置一个变量,该变量从数据库中查找相应的实体,并使用找到的详细信息加载bean,如下所示:
<f:metadata>
<f:viewParam name="attractionId" value="#{attractionsBean.attractionId}" />
</f:metadata>
我有一个使用primefaces API的谷歌地图,当拖动标记时,会发出ajax调用来更新标记位置。
<h:outputText value="Location" />
<f:view contentType="text/html">
<p:gmap id="gmap" center="41.381542, 2.122893" zoom="10" type="HYBRID" style="width:380px;height:350px"
model="#{attractionsBean.attractionModel.mapModel}"
markerDragListener="#{attractionsBean.onMarkerDrag}"
onMarkerDragUpdate="growl" />
</f:view>
问题在于,在每个标记拖动事件和 ajax 调用之后,每次都会调用元数据中的方法 setAttractionId。
如何解决此问题以防止每次调用 setAttractionId 方法?
大量小时尝试找到解决方法后,此问题的解决方案如下:
将托管Bean设置为
@ViewScoped
,以便在仍在同一页面上时成为相同的Bean我没有从 attractionId 的 setter 中的数据库中检索实体,而是在视图作用域 bean 中引入了一个
@PostConstruct
方法,以使用如下代码通过 view 参数检索对象:@PostConstruct public void setupAttractionModel() { this.attractionId = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get(ATTRACTION_ID_VIEW_PARAM); // Lookup by attractionId ... }
postconstruct方法在每个需要Bean的页面之前调用。
删除导致问题的
<f:metadata>
标签
实际上,更好的方法是将 setter 保留为简单的 setter 并使用延迟实例化模式:
- 在 setAttractionId 中设置一个 id 的实例变量(如果脏),并清除当前检索到的实例。如果变量不脏,则吸引力实例将保持未修改状态。
- 在 getter (getAttractionModel) 中,如果为 null,则使用吸引力 ID 检索吸引力实例。 对 getter 的后续调用将返回实例,而无需从 db 检索。
- 删除后构造
这将适用于 ViewScoped bean。
受管 Bean 中的资源库可能是请求作用域的。 尝试将受管 Bean 设置为 ViewScoped,看看这是否有区别。