在这篇文章中,您将看到如何结合PrimeFaces和OmniFaces获得可缓存的图表。 为了使事情变得简单,我们将使用PrimeFaces 折线图。 对于这种图表,我们可以在页面中使用<p:chart />标记和一个简单的托管bean。 因此,在页面中我们可以有:
<p:chart id="someChartId" type="line"
model="#{chartView.lineModel}"
style="height:300px;width:600px;"/>
ChartView可以编写如下:
@Named
@ViewScoped
public class ChartView implements Serializable {
private LineChartModel lineModel;
@PostConstruct
public void init() {
createLineModels();
}
private void createLineModels() {
lineModel = initLinearModel();
lineModel.setTitle("Linear Chart");
lineModel.setLegendPosition("e");
lineModel.setZoom(true);
Axis yAxis = lineModel.getAxis(AxisType.Y);
yAxis.setMin(0);
yAxis.setMax(10);
}
private LineChartModel initLinearModel() {
LineChartModel model = new LineChartModel();
LineChartSeries series1 = new LineChartSeries();
series1.setLabel("Series 1");
Random rnd = new Random();
series1.set(rnd.nextInt(10), rnd.nextInt(10));
series1.set(rnd.nextInt(10), rnd.nextInt(10));
series1.set(rnd.nextInt(10), rnd.nextInt(10));
series1.set(rnd.nextInt(10), rnd.nextInt(10));
series1.set(rnd.nextInt(10), rnd.nextInt(10));
LineChartSeries series2 = new LineChartSeries();
series2.setLabel("Series 2");
series2.set(rnd.nextInt(10), rnd.nextInt(10));
series2.set(rnd.nextInt(10), rnd.nextInt(10));
series2.set(rnd.nextInt(10), rnd.nextInt(10));
series2.set(rnd.nextInt(10), rnd.nextInt(10));
model.addSeries(series1);
model.addSeries(series2);
return model;
}
public LineChartModel getLineModel() {
return lineModel;
}
}
此代码将产生一个简单的折线图,如下图:
现在,让我们假设在应用程序运行期间,该图表会定期更新或重新创建(我们将通过随机序列值和“ Refresh
按钮对此进行模拟)。 每次发生这种情况时,我们都会丢失当前图表。 但是,缓存(如保存)某些图表可能很有用,并且有可能稍后在当前会话(对于属于某些用户的图表)/应用程序(对于所有用户通用的图表)中加载它们。
为了完成此任务,我们可以使用OmniFaces 缓存组件。 基本上,此组件在OmniFaces Showcase和Mastering OmniFaces书中都有很好的描述,但主要思想是:
-
Cache
组件通过以下方式向JSF页面作者公开
<o:cache>
标记。 -
Cache
为“渲染响应”阶段生成的标记实现了服务器端缓存机制。 -
Cache
在“渲染响应”阶段执行操作。 - 缓存的标记存储在OmniFaces生成的密钥下,或者通过可选的
<o:cache>
密钥属性指示。 - 可以通过可选的
<o:cache>
禁用的flag属性禁用每个请求的<o:cache>
。 - 可以通过
<o:cache>
reset flag属性来重新缓存已缓存的条目。 - 默认情况下,缓存的数据存储在会话范围内(也支持应用程序范围)。
例如,从JSF页面作者的角度来看,我们可以表明我们想在键foo
下重新缓存一块标记,如下所示:
<o:cache id="cacheId" key="foo" disabled="false" reset="true">
... // the markup produced for this snippet of code will be cached
</o:cache>
显然,在此示例中, disabled
属性可以跳过,因为那是其隐式值。 如果还跳过了key
,则OmniFaces将生成一个。 如果跳过了reset
,则不会重新缓存标记。
既然我们要必须决定哪些图表缓存和负载的可能性/删除某个图表从缓存中,我们不能简单地做只有这个:
<o:cache id="cacheId">
<p:chart id="someChartId" type="line"
model="#{chartView.lineModel}"
style="height:300px;width:600px;"/>
</o:cache>
基本上,这将缓存第一个图表,并且在每次回发时,将从缓存中为该图表提供服务。
因此,一种快速的方法将包括以编程方式处理<o:cache>
属性。 就像我在上面说的, Cache
在“渲染响应”阶段采取行动。 这意味着我们可以从我们的控制
ChartView
bean在实际发生Cache
之前是Cache
组件。 此实现的核心将包含以下private
方法,该方法允许我们以编程方式配置Cache
组件:
private void configureCache(String key, boolean disabled, boolean reset) {
Cache cache = Components.findComponent("cacheId");
cache.setDisabled(disabled);
cache.setReset(reset);
cache.setKey(key);
}
现在,我们将添加一对一的控制缓存所需的UI。 首先,我们添加一个标记为“
刷新。 实际上,每次我们按下此按钮时,都会生成一个新图表(新数据)。 这是用于模拟图表更新。
<h:commandButton action="#{chartView.redrawAction()}" value="Refresh"/>
redrawAction()
确保新图表不被缓存,因此缓存被禁用并且密钥不相关:
public void redrawAction() {
configureCache("none", true, false);
createLineModels();
}
此外,我们添加了一个名为Save
的按钮。 按下此按钮时,当前图表将缓存在key_ random-number类型的键下(在实际情况下,您可能希望允许用户提供该键作为图表标题)。 该key
将在代表已保存图表的列表中向用户公开:
<h:commandButton action="#{chartView.saveChart()}" value="Save"/>
saveChart()
方法启用缓存并生成一个新密钥。 密钥存储在列表中:
private List<String> keys;
...
public void saveChart() {
String key = "key_" + new Random().nextInt(1000);
configureCache(key, false, true);
keys.add(key);
}
接下来,我们列出缓存的键和一个标记为Load
的按钮。 用户可以选择一个键,然后单击
加载按钮以加载缓存的图表:
<h:selectOneMenu value="#{chartView.selected}">
<f:selectItem itemLabel="Select a chart ..." noSelectionOption="true"/>
<f:selectItems value="#{chartView.keys}" var="t" itemLabel="#{t}" itemValue="#{t}"/>
</h:selectOneMenu>
<h:commandButton value="Load Chart" action="#{chartView.loadChart()}"
disabled="#{chartView.keys.size() eq 0}"/>
loadChart()
是:
public void loadChart() {
if (selected != null) {
configureCache(selected, false, false);
}
}
最后,我们添加一个标记为Delete
的按钮,该按钮将从缓存中删除所选图表:
<h:commandButton value="Delete Chart" action="#{chartView.deleteChart()}"
disabled="#{chartView.keys.size() eq 0}"/> |
并且, deleteChart()
是:
public void deleteChart() {
if (selected != null) {
CacheFactory.getCache(Faces.getContext(), "session").remove(selected);
keys.remove(selected);
configureCache("none", true, false);
resetLineModels();
}
}
private void resetLineModels(){
lineModel.getSeries().clear();
}
注意这里,我们如何使用CacheFactory
通过密钥从缓存中删除条目。
这是一个提示性屏幕截图:
- 完整的应用程序可在此处获得 。