当前位置: 首页 > 知识库问答 >
问题:

JavaFX8 TableView未使用计划服务中RestTemplate调用的列表进行更新

西门飞翮
2023-03-14

我对Java和JavaFX相当陌生,我正在开发一个JavaFX应用程序,并在javafx.concurrent.的SchduledService任务中使用一个REST api来更新TableView。我能够从我的SpringBoot REST服务中获得响应,并且可以看到数据正在模型对象、观察列表以及TableView本身上设置,但是表仍然是空的。

SpringBoot Apiendpoint:

 @RequestMapping(value = "/getAllActive", method = RequestMethod.GET)
public List<IssuedTicket> getAllActive () {
    List<IssuedTicket> issuedTicketList = issuedTicketService.findAll();
    return issuedTicketList;
}

来自上述endpoint的JSON响应:

[{"id":2,"ticketId":1230717013545,"dateArrived":"23-07-17","timeArrived":"01:35:45","deviceId":1},{"id":3,"ticketId":1230717013552,"dateArrived":"23-07-17","timeArrived":"01:35:52","deviceId":1},{"id":4,"ticketId":1230717013556,"dateArrived":"23-07-17","timeArrived":"01:35:56","deviceId":1}]

在我的JavaFX应用程序中:

HomeSceneController。Java语言

package com.ronintech.bayTrans.ui.main;

import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXTextField;
import com.ronintech.bayTrans.model.ActiveTickets;
import com.ronintech.bayTrans.utils.RestErrorHandler;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.ScheduledService;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.AnchorPane;
import javafx.util.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;

import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;

public class HomeSceneController implements Initializable{

@FXML
private AnchorPane homeAnchorPane;

@FXML
private JFXTextField ticketTxt;

@FXML
private JFXButton scanTicketBtn;

@FXML
private TableView<ActiveTickets> activeTicketsTable;

@FXML
private TableColumn<ActiveTickets, Long > ticketIdCol;

@FXML
private TableColumn<ActiveTickets, String > dateArrivedCol;

@FXML
private TableColumn<ActiveTickets, String> timeArrivedCol;

private ObservableList<ActiveTickets> activeTicketsList;

private static final Logger LOGGER = LoggerFactory.getLogger(HomeSceneController.class);
private static final String ACTIVE_TICKETS_URL = "http://localhost:9090/api/ticket/getAllActive";

@Override
public void initialize(URL location, ResourceBundle resources) {
    getActiveTickets.reset();
    getActiveTickets.setPeriod(Duration.seconds(20));
    getActiveTickets.start();

    getActiveTickets.setOnSucceeded(event -> {
        LOGGER.info("onSuccess");
        List<ActiveTickets> activeList = getActiveTickets.getValue();
        activeTicketsList = FXCollections.observableArrayList(activeList);

        ticketIdCol.setCellValueFactory(new PropertyValueFactory<ActiveTickets, Long>("ticketId"));
        dateArrivedCol.setCellValueFactory(new PropertyValueFactory<ActiveTickets, String>("dateArrived"));
        timeArrivedCol.setCellValueFactory(new PropertyValueFactory<ActiveTickets, String>("timeArrived"));
        activeTicketsTable.setItems(activeTicketsList);

        LOGGER.info("Items in Table");
        LOGGER.info(activeTicketsTable.getItems().toString());
    });

    getActiveTickets.setOnFailed(event -> {
        LOGGER.error("service task FAILED");
    });
}

@FXML
void openTicketModal(ActionEvent event) {
}

private ScheduledService<List<ActiveTickets>> getActiveTickets = new ScheduledService<List<ActiveTickets>>() {
    @Override
    protected Task<List<ActiveTickets>> createTask() {
        return new Task<List<ActiveTickets>>() {
            @Override
            protected List<ActiveTickets> call() throws Exception {
                LOGGER.info("Scheduled Service getActiveTickets STARTED");
                RestTemplate restTemplate = new RestTemplate();
                restTemplate.setErrorHandler(new RestErrorHandler());

                List<ActiveTickets> response = restTemplate.getForObject(ACTIVE_TICKETS_URL, List.class);

                LOGGER.info(response.toString);
                return response;
            }
        };
    }
};

}

我的模型对象:ActiveTickets。Java语言

package com.ronintech.bayTrans.model;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.beans.property.SimpleStringProperty;

@JsonIgnoreProperties(ignoreUnknown = true)
public class ActiveTickets {

private SimpleLongProperty id;
private SimpleLongProperty ticketId;
private SimpleStringProperty dateArrived;
private SimpleStringProperty timeArrived;
private SimpleIntegerProperty deviceId;

public ActiveTickets(long id,
                     long ticketId,
                     String dateArrived,
                     String timeArrived,
                     int deviceId) {
    this.id = new SimpleLongProperty(id);
    this.ticketId = new SimpleLongProperty(ticketId);
    this.dateArrived = new SimpleStringProperty(dateArrived);
    this.timeArrived = new SimpleStringProperty(timeArrived);
    this.deviceId = new SimpleIntegerProperty(deviceId);
}

public long getId() {
    return id.get();
}

public SimpleLongProperty idProperty() {
    return id;
}

public long getTicketId() {
    return ticketId.get();
}

public SimpleLongProperty ticketIdProperty() {
    return ticketId;
}

public String getDateArrived() {
    return dateArrived.get();
}

public SimpleStringProperty dateArrivedProperty() {
    return dateArrived;
}

public String getTimeArrived() {
    return timeArrived.get();
}

public SimpleStringProperty timeArrivedProperty() {
    return timeArrived;
}

public int getDeviceId() {
    return deviceId.get();
}

public SimpleIntegerProperty deviceIdProperty() {
    return deviceId;
}

public void setId(long id) {
    this.id.set(id);
}

public void setTicketId(long ticketId) {
    this.ticketId.set(ticketId);
}

public void setDateArrived(String dateArrived) {
    this.dateArrived.set(dateArrived);
}

public void setTimeArrived(String timeArrived) {
    this.timeArrived.set(timeArrived);
}

public void setDeviceId(int deviceId) {
    this.deviceId.set(deviceId);
}

@Override
public String toString() {
    return "ActiveTickets{" +
            "ticketId=" + ticketId +
            ", dateArrived=" + dateArrived +
            ", timeArrived=" + timeArrived +
            '}';
}
}

RestTemplate调用的响应为:

00:43:06.901 [Thread-9] INFO com.ronintech.bayTrans.ui.main.HomeSceneController - [{id=2, ticketId=1230717013545, dateArrived=23-07-17, timeArrived=01:35:45, deviceId=1}, {id=3, ticketId=1230717013552, dateArrived=23-07-17, timeArrived=01:35:52, deviceId=1}, {id=4, ticketId=1230717013556, dateArrived=23-07-17, timeArrived=01:35:56, deviceId=1}]

将观察列表设置为TableView后的日志:

activeTicketsTable.setItems(activeTicketsList);

00:43:07.159 [JavaFX Application Thread] INFO com.ronintech.bayTrans.ui.main.HomeSceneController - [{id=2, ticketId=1230717013545, dateArrived=23-07-17, timeArrived=01:35:45, deviceId=1}, {id=3, ticketId=1230717013552, dateArrived=23-07-17, timeArrived=01:35:52, deviceId=1}, {id=4, ticketId=1230717013556, dateArrived=23-07-17, timeArrived=01:35:56, deviceId=1}]

日志显示TableView数据正在主UI线程上设置,但表仍然为空

我不确定我是否做错了什么。如果有人知道如何解决这个问题,请帮忙。

提前感谢。

编辑

我在FXML中的TableView结构:

<TableView fx:id="activeTicketsTable" prefHeight="800.0" prefWidth="800.0" tableMenuButtonVisible="true">
    <columns>
        <TableColumn fx:id="ticketIdCol" prefWidth="75.0" text="Ticket ID"/>
        <TableColumn fx:id="dateArrivedCol" prefWidth="75.0" text="Date Arrived"/>
        <TableColumn fx:id="timeArrivedCol" prefWidth="75.0" text="Time Arrived"/>
    </columns>
    <columnResizePolicy>
        <TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
    </columnResizePolicy>
</TableView>

更新

似乎编组没有正确进行。

这是观察列表activeTicketsList的调试跟踪:

列表已设置为LinkedHashMap的ArrayList

然而,当我手动创建ObservableList时:

private final ObservableList<ActiveTickets> data = FXCollections.observableArrayList(
        new ActiveTickets(1,1234,"date1","time1",1),
        new ActiveTickets(2,5678,"date2","time2",2)
);

“data”被正确设置为ActiveTickets类对象的ArrayList

如何确保JSON-

共有1个答案

苏高远
2023-03-14

我不确定这是否真的是问题所在,但通常我的REST客户端项目不会直接列表到列表中(这可能是Jackson的问题)。这就是我要做的:

ActiveTickets[] response = restTemplate.getForObject(ACTIVE_TICKETS_URL, ActiveTickets[].class);

return Arrays.asList(response);

请注意,您仍然会在endpoint返回一个列表;您不需要更改它。

阅读本文,了解另一种方法

 类似资料:
  • 如果需要从应用程序调用远程REST服务,可以使用Spring Framework的RestTemplate类。 由于RestTemplate实例在使用之前通常需要进行自定义,因此Spring Boot不提供任何单个自动配置的RestTemplate bean。 但是,它会自动配置RestTemplateBuilder,可用于在需要时创建RestTemplate实例。 自动配置的RestTempla

  • 我正在尝试设置Azure功能,以将我们的应用程序服务计划扩展到在工作时间更大,在工作时间以外更小。我从这个问题的答案中得出结论。 当我在本地运行它时,它可以工作,并且实际上在我们的Azure应用服务计划上执行了扩展(我相信是通过Azure CLI)。但是,当此Azure Function部署到Azure时,它找不到任何应用服务计划。它点击块并返回。我已为已部署的Azure Function打开托管

  • 我正在尝试更改其中一个Azure应用服务的Azure应用服务计划,以下是我得到的。它无法搜索我刚刚创建的应用服务计划。 Azure应用服务的当前应用服务计划和我想要更改为存在于同一位置和同一资源组中的计划。这两个计划的唯一区别是定价层。现有计划恰好在“标准:2小”中,我刚刚创建的计划在“标准:1小”中。对于这两个计划,我都选择定价层为“标准1”,因此不确定这是如何在定价层名称中添加数字1和2的。

  • 我使用此命令使用powershell创建了一个新的Web应用程序。 现在,我希望将web应用的应用服务计划从免费更改为共享/标准等。 读过文章 https://azure.microsoft.com/en-us/documentation/articles/azure-web-sites-web-hosting-plans-in-depth-overview/ 无法创建空的应用程序服务计划。那么,

  • 问题内容: 我有以下代码,在部署到测试服务器之前,它工作正常: 问题是我已部署到虚拟目录,并且下面的调用试图从服务器根目录访问GetUserList。这是有道理的,而且我知道许多解决方法。 我想知道的是一种 正确的 方式,该方式以可移植且可在Angular中维护的方式引用服务URL。 问题答案: 我建议在头部使用HTML基本标记,并对与此相关的所有路径进行编码。例如,在ASP.NET中,您可以获取

  • 如果我直接通过控制器使用play web服务客户端,这些调用可以是异步的,这比我们现在所做的(阻塞)要好得多。然而,我不清楚这到底是如何在重载下的行为。并发/线程管理将主要留给底层的Netty服务器吗?我有什么办法调它吗? 另一种方法是使用控制器中的Akka执行器系统,在这里我可以控制路由策略、池大小、容错等。如果我采用这种方法,那么使用Play的异步WS客户端是否仍然有意义?如果是的话,这种方法