Статьи

Графики RESTful с JAX-RS и PrimeFaces

Часто полезно использовать диаграмму для визуального представления ваших данных. PrimeFaces поставляет графические решения, которые позволяют легко добавлять визуальные представления ваших данных в веб-приложения и мобильные приложения. Если мы объединяем использование компонентов диаграмм PrimeFaces с данными веб-службы RESTful, мы можем создавать собственные диаграммы, которые хорошо масштабируются как для настольных, так и для мобильных устройств.

В этой статье я обновлю приложение MoviePlex Java EE 7 Hands On Lab, чтобы предоставить панель управления, в которую мы можем интегрировать компоненты диаграмм PrimeFaces. В этом примере мы создадим один график, но вы можете использовать этот пост, чтобы помочь вам построить еще больше графиков аналогичным образом. В частности, мы будем использовать веб-сервис RESTful для сбора информации о вместимости кинотеатра, и будем отображать каждую вместимость кинотеатра, используя гистограмму PrimeFaces.

Для начала загрузите архив решения приложения Java EE 7 Hands On Lab, если вы этого еще не сделали. Оттуда откройте его в IDE NetBeans. Для создания этого поста я использую NetBeans 8.0.2. После того, как проект был импортирован в NetBeans, разверните его на своем сервере приложений (в моем случае GlassFish 4.1), щелкнув правой кнопкой мыши по проекту и выбрав «Выполнить». После завершения развертывания откройте веб-службу Theatre в браузере, открыв следующий URL-адрес: http: // localhost: 8080 / ExploringJavaEE7 / webresources / theatre /. Веб-сервис должен создать листинг, который выглядит примерно так, как показано на рисунке 1.

Рисунок 1: Театральная веб-служба XML

Рисунок 1: Театральная веб-служба XML

Мы будем использовать данные этого веб-сервиса для подачи нашего виджета на панель инструментов. Давайте сначала создадим бэкэнд-код, а затем займемся пользовательским интерфейсом. Сначала создайте новый пакет с именем org.glassfish.movieplex7.jsf , щелкнув правой кнопкой мыши Пакеты с исходным кодом и выбрав «Новый…» -> «Пакеты Java». Затем создайте контроллер JSF Managed Bean, щелкнув правой кнопкой мыши по этому пакету и выбрав «New…» -> «JSF Managed Bean», и назовите его « DashboardController . Давайте аннотируем контроллер как @SessionScoped , а затем реализуем java.io.Serializable . В этом контроллере мы получим данные и создадим модель для панели мониторинга. Сначала мы запросим веб-службу, используя клиент JAX-RS, и будем использовать данные для заполнения списка объектов Theater . Поэтому для начала нам нужно определить следующие четыре поля:

1
2
3
4
5
6
Client jaxRsClient;
// Typically not hard coded...store in a properties file or database
     
private List<Theater> theaterList;
private BarChartModel theaterCapacityModel;

Клиент имеет тип javax.ws.rs.client.Client , и мы инициализируем поле в конструкторе класса, вызывая javax.ws.rs.client.ClientBuilder следующим образом:

1
2
3
public DashboardController() {
    jaxRsClient = ClientBuilder.newClient();
}

Далее нам нужно создать метод для загрузки данных, создать и настроить модель. В нашем контроллере метод init() основном содержит реализацию делегирования задач другим методам. Реализация метода init() вызывает два метода: loadData() и createTheaterCapacityModel() .

1
2
3
4
5
public void init() {
    loadData();
   
    createTheaterCapacityModel();
}

Код написан так, что при желании будет легче добавить больше виджетов на нашу панель инструментов позже. Метод loadData() обеспечивает реализацию для загрузки данных из нашего веб-сервиса в наш локальный список.

1
2
3
4
5
6
7
8
9
private void loadData() {
        
    theaterList = jaxRsClient.target(baseUri)
            .request("application/xml")
            .get(new GenericType>() {
            }
            );
       
}

Если бы у нас было больше виджетов, мы бы также добавили в этот метод код загрузки данных для этих моделей данных. Далее нам нужно инициализировать определенный нами org.primefaces.model.chart.BarChartModel и загрузить его с данными из веб-службы. Метод initTheaterCapacityModel() содержит реализацию для создания BarChartModel и заполнения его одним или несколькими объектами ChartSeries для построения данных.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
public BarChartModel initTheaterCapacityModel() {
 
    BarChartModel model = new BarChartModel();
 
    ChartSeries theaterCapacity = new ChartSeries();
    theaterCapacity.setLabel("Capacities");
 
 
    for (Theater theater : theaterList) {
 
        theaterCapacity.set(theater.getId(), theater.getCapacity());
 
    }
    model.addSeries(theaterCapacity);
 
    return model;
}

Как видите, эта модель состоит из одного объекта org.primefaces.model.chart.ChartSeries . На самом деле модель может содержать более одного объекта ChartSeries , и для отображения этих данных на диаграмме будут использоваться разные цветные полосы. В этом случае мы просто добавляем ID театра и емкость для каждого объекта Theater объект ChartSeries , а затем добавляем его в BarChartModel . Метод createTheaterCapacityModel() вызывается внутри нашего метода init() , и в нем мы вызываем метод initTheaterCapacityModel() для создания org.primefaces.model.chart.BarChartModel , а затем настраиваем его соответствующим образом.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
private void createTheaterCapacityModel() {
    theaterCapacityModel = initTheaterCapacityModel();
 
    theaterCapacityModel.setTitle("Theater Capacity");
    theaterCapacityModel.setLegendPosition("ne");
    theaterCapacityModel.setBarPadding(3);
    theaterCapacityModel.setShadow(false);
 
    Axis xAxis = theaterCapacityModel.getAxis(AxisType.X);
    xAxis.setLabel("Theater");
 
    Axis yAxis = theaterCapacityModel.getAxis(AxisType.Y);
    yAxis.setLabel("Capacity");
    yAxis.setMin(0);
    yAxis.setMax(200);
 
}

Как вы можете видеть, внутри метода мы инициализируем модель, вызывая initTheaterCapacityModel() , а затем настраиваем ее с помощью ряда методов «set». В частности, мы устанавливаем заголовок, положение и предоставляем некоторые визуальные конфигурации. Затем установите ось, вызвав метод getAxis() модели и передав константы оси X и Y. Затем мы настраиваем каждую ось по своему вкусу, устанавливая метку и минимальные / максимальные значения для оси Y. Смотрите полные источники для класса в конце этого поста.

Это делается для кода на стороне сервера, теперь давайте посмотрим на код пользовательского интерфейса, который используется для отображения компонента диаграммы. Начните с создания нового файла XHTML в корне папки «Веб-страницы» в своем проекте, щелкнув правой кнопкой мыши и выбрав "New..."-> "XHTML..." , и назовите файл dashboard.xhtml . Исходники для dashboard.xhtml должны содержать следующее:

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
    <h:head>
      
      
        <title>Theater Dashboard</title>
 
    </h:head>
    <h:body>
        <f:event listener="#{dashboardController.initView}" type="preRenderView"/>
        <h:form id="theaterDash" prependid="false">
            <p:growl id="growl" showdetail="true"/>
            <p:layout fullpage="true">
                <p:layoutUnit position="center">
                    
                            <p:panel header="Capacity for Theaters" id="theater_capacity" style="border: 0px;">
                                <p:chart model="#{dashboardController.theaterCapacityModel}" style="border: 0px; height: 200px; width: 500px;" type="bar">
                            </p:chart></p:panel>
                          
                  
                </p:layoutUnit>
            </p:layout>
 
            <p:poll interval="60" listener="#{dashboardController.pollData}"/>
 
        </h:form>
 
    </h:body>
</html>

Довольно простое представление JSF содержит макет PrimeFaces, включая панель и диаграмму. В верхней части представления тег f: event используется для вызова метода слушателя, который реализован в классе DashboardController, identified by initView() . Для целей этого примера, тег p:chart – это место, где происходит волшебство. Тип диаграммы в этом случае установлен на «бар», хотя доступны и другие варианты (посетите http://www.primefaces.org/showcase). Для модели задано значение #{dashboardController.theaterCapacityModel} , которое мы определили, заполнили и настроили в классе контроллера. Затем мы предоставляем ширину и высоту, чтобы диаграмма хорошо отображалась. В случае изменения данных (я знаю, что кинотеатры не часто увеличиваются или уменьшаются в размере, но идут со мной здесь), мы добавили компонент опроса PrimeFaces, вызывающий метод pollData( ), который периодически обновляет данные. В этом случае данные будут обновляться каждые 60 секунд. После завершения диаграмма должна выглядеть так, как показано на рисунке 2.

Рисунок 2: Гистограмма PrimeFaces

Рисунок 2: Гистограмма PrimeFaces

Диаграмма является интерактивной, и если вы нажмете на ярлык, столбцы станут скрытыми. Это удобно, если у вас более одной категории (через ChartSeries ). Вы даже можете включить тег p:ajax в компонент диаграммы и вызывать действие при щелчке по диаграмме… возможно, появится диалоговое окно для отображения дополнительных данных по элементу, по которому щелкают. Это делает это … теперь вы можете создавать еще больше диаграмм, используя PrimeFaces и веб-сервисы RESTful. Я предлагаю опираться на приложение MoviePlex, чтобы увидеть, какие еще возможности могут быть. Полные источники для класса DashboardController:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package org.glassfish.movieplex7.jsf;
 
import java.util.List;
import javax.inject.Named;
import javax.enterprise.context.SessionScoped;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.GenericType;
import org.glassfish.movieplex7.entities.Theater;
 
import org.primefaces.model.chart.Axis;
import org.primefaces.model.chart.AxisType;
import org.primefaces.model.chart.BarChartModel;
import org.primefaces.model.chart.ChartSeries;
 
/**
 *
 * @author Juneau
 */
@Named(value = "dashboardController")
@SessionScoped
public class DashboardController implements java.io.Serializable {
     
    Client jaxRsClient;
    // Typically not hard coded...store in a properties file or database
     
    private List theaterList;
   
    private BarChartModel theaterCapacityModel;
 
 
    /**
     * Creates a new instance of FamisEquipPmChartController
     */
    public DashboardController() {
        jaxRsClient = ClientBuilder.newClient();
    }
     
    public void init() {
        loadData();
 
        createTheaterCapacityModel();
    }
     
    /**
     * Initializes the view on page render...if we wish to grab a reference
     * to a panel, etc.
     */
    public void initView(){
        UIViewRoot viewRoot =  FacesContext.getCurrentInstance().getViewRoot();
        // Do something
    }
 
    public void pollData() {
        System.out.println("polling data...");
        loadData();
    }
 
    /**
     * JAX-RS client to poll the data
     */
    private void loadData() {
        
        theaterList = jaxRsClient.target(baseUri)
                .request("application/xml")
                .get(new GenericType>() {
                }
                );
       
    }
 
     
 
    /**
     * Initialize the Bar Chart Model for Displaying PM Estimated Hours by Month
     *
     * @return
     */
    public BarChartModel initTheaterCapacityModel() {
 
        BarChartModel model = new BarChartModel();
 
        ChartSeries theaterCapacity = new ChartSeries();
        theaterCapacity.setLabel("Capacities");
 
 
        for (Theater theater : theaterList) {
 
            theaterCapacity.set(theater.getId(), theater.getCapacity());
 
        }
        model.addSeries(theaterCapacity);
 
        return model;
    }
 
    
 
  
     
    private void createTheaterCapacityModel() {
        theaterCapacityModel = initTheaterCapacityModel();
 
        theaterCapacityModel.setTitle("Theater Capacity");
        theaterCapacityModel.setLegendPosition("ne");
        theaterCapacityModel.setBarPadding(3);
        theaterCapacityModel.setShadow(false);
 
        Axis xAxis = theaterCapacityModel.getAxis(AxisType.X);
        xAxis.setLabel("Theater");
 
        Axis yAxis = theaterCapacityModel.getAxis(AxisType.Y);
        yAxis.setLabel("Capacity");
        yAxis.setMin(0);
        yAxis.setMax(200);
 
    }
 
    /**
     * @return the theaterCapacityModel
     */
    public BarChartModel getTheaterCapacityModel() {
        return theaterCapacityModel;
    }
 
    /**
     * @param theaterCapacityModel the theaterCapacityModel to set
     */
   public void setTheaterCapacityModel(BarChartModel theaterCapacityModel) {
        this.theaterCapacityModel = theaterCapacityModel;
    }
     
    
}