Статьи

Программно кешировать диаграммы PrimeFaces с помощью компонента OmniFaces Cache

В этом посте вы увидите, как объединить PrimeFaces и OmniFaces для получения кэшируемых диаграмм. Для простоты мы будем использовать линейную диаграмму PrimeFaces. Для диаграмм такого типа мы можем использовать тег <p: chart /> на странице и простой управляемый компонент. Итак, на странице мы можем иметь:

1
2
3
<p:chart id="someChartId" type="line"
        model="#{chartView.lineModel}"
        style="height:300px;width:600px;"/>

ChartView можно записать так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
@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 Cache . По сути, этот компонент очень хорошо описан в книге «OmniFaces Showcase» и « Mastering OmniFaces» , но основные идеи:

  • Компонент Cache предоставляется авторам страниц JSF через
    Тег <o:cache> .
  • Cache инкапсулирует механизм кэширования на стороне сервера для разметки, созданной на этапе ответа при визуализации.
  • Cache принимает меры на этапе ответа при визуализации.
  • Кэшированная разметка хранится под ключом, сгенерированным OmniFaces или указывающим через необязательный атрибут ключа <o:cache> .
  • Кэширование может быть отключено для каждого запроса с помощью необязательного атрибута флага отключения <o:cache> .
  • Кэшированная запись может быть повторно кэширована с помощью атрибута флага сброса <o:cache> .
  • По умолчанию кэшированные данные хранятся в области сеанса (область приложения также поддерживается).

Например, с точки зрения автора страницы JSF, мы можем указать, что мы хотим повторно кэшировать фрагмент разметки под ключом foo , как показано ниже:

1
2
3
<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 пропущен, разметка не будет повторно кэширована.

Поскольку мы хотим иметь возможность решить, какие диаграммы кэшируются, и загрузить / удалить определенную диаграмму из кэша, мы не можем просто сделать только это:

1
2
3
4
5
<o:cache id="cacheId">     
 <p:chart id="someChartId" type="line"
          model="#{chartView.lineModel}"
          style="height:300px;width:600px;"/>                  
</o:cache>

По сути, это кэширует первый график и при каждой обратной передаче обслуживает этот график из кэша.

Итак, быстрый подход заключается в программном жонглировании атрибутами <o:cache> . Как я уже говорил выше, Cache выполняет действия на этапе ответа при визуализации. Это означает, что мы можем контролировать
ChartView компонент Cache до того, как кеширование действительно происходит. Центральная часть этой реализации будет заключаться в следующем private методе, который позволяет нам программно настраивать компонент Cache :

1
2
3
4
5
6
private void configureCache(String key, boolean disabled, boolean reset) {
 Cache cache = Components.findComponent("cacheId");
 cache.setDisabled(disabled);
 cache.setReset(reset);
 cache.setKey(key);
}

Теперь мы добавим один к одному пользовательский интерфейс, необходимый для управления кэшированием. Сначала мы добавляем кнопку с надписью,
Обновить. Практически, каждый раз, когда мы нажимаем эту кнопку, генерируется новый график (новые данные). Это для имитации обновления графика.

1
<h:commandButton action="#{chartView.redrawAction()}" value="Refresh"/>

redrawAction() гарантирует, что новая диаграмма не будет кэширована, поэтому кэширование отключено, а ключ не имеет значения:

1
2
3
4
public void redrawAction() {
 configureCache("none", true, false);
 createLineModels();
}

Далее добавляем кнопку с надписью Save . Когда эта кнопка нажата, текущий график кэшируется под ключом типа key_ random-number (в реальных случаях вы можете разрешить пользователю указывать ключ в качестве заголовка графика). key будет выставлен пользователю в списке, представляющем сохраненные диаграммы:

1
<h:commandButton action="#{chartView.saveChart()}" value="Save"/>

Метод saveChart() включает кэширование и генерирует новый ключ. Ключ хранится в списке:

1
2
3
4
5
6
7
private List<String> keys;
...
public void saveChart() {
 String key = "key_" + new Random().nextInt(1000);
 configureCache(key, false, true);
 keys.add(key);
}

Далее мы перечисляем кэшированные ключи и кнопку с надписью Load . Пользователь может выбрать ключ и нажать
Кнопка Загрузить, чтобы загрузить кешированный график:

1
2
3
4
5
6
7
<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() :

1
2
3
4
5
public void loadChart() {
 if (selected != null) {
     configureCache(selected, false, false);
 }
}

Наконец, мы добавляем кнопку « Delete , которая удаляет из кэша выбранный график:

1
2
<h:commandButton value="Delete Chart" action="#{chartView.deleteChart()}"
                disabled="#{chartView.keys.size() eq 0}"/> |

И deleteChart() это:

01
02
03
04
05
06
07
08
09
10
11
12
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 .

Вот скриншот:

диаграмма простых лиц и омнифасов

  • Полное приложение доступно здесь .