我是JavaFX的新手,我想知道用这种语言开发MVC数据库应用程序的最佳做法是什么,我认为如果你是一名高级开发人员,我的问题将非常简单。
让我们考虑一个在JavaFX中开发的基本应用程序的简单示例:与SQL数据库链接的ToDoList。
这就是我们的应用程序的样子:
我决定将我的代码分为四个部分, DAO 用于表示表中的数据的类(Task.java),访问数据库的DAO类(其行为在此无关紧要) )。代表我们TodoList的Model部分的模型(包含任务列表和执行操作,调用DAO等)。 FXML 视图和控制器:
接下来,你可以找到我们感兴趣的不同类的代码(我们认为DAO是正常的(自动设置id)我们不处理错误情况以简化代码:
Task.java
public class Task {
private int id;
private SimpleStringProperty task;
public Task(int i, String s){
this.id = i;
this.task = new SimpleStringProperty(s);
}
public void setId(int i){
this.id = i;
}
public int getId() {
return id;
}
public String getTask() {
return task.get();
}
public void setTask(String task) {
this.task.set(task);
}
@Override
public boolean equals(Object o){
if(this.id == ((Task)o).id)
return true;
return false;
}
}
ToDoListModel.java
public class ToDoListModel {
private List<Task> taskList;
private DAO dao;
public ToDoListModel(){
this.taskList = new ArrayList<Task>();
this.dao = new DAO();
}
public void loadDatabase(){
this.taskList = this.dao.getAllTasks();
}
public void addTask(Task t){
// Operations throwing Exceptions such as : Does the task t is already in the list, etc...
this.taskList.add(t);
this.dao.createTask(t);
}
public void deleteTask(Task t){
this.taskList.remove(t);
this.dao.deleteTask(t);
}
public List<Task> getTaskList() {
return taskList;
}
}
Controller.java
public class Controller {
private final ToDoListModel model;
@FXML
private TableView<Task> taskTable;
@FXML
private TableColumn<Task, String> taskColumn;
@FXML
private TextField taskTextField;
public Controller(ToDoListModel m){
this.model = m;
}
@FXML
protected void initialize() {
this.model.loadDatabase();
// Setting up data table
taskColumn.setCellValueFactory(new PropertyValueFactory<Task, String>("task"));
ObservableList<Task> taskObservableList = FXCollections.observableList(this.model.getTaskList());
taskTable.setItems(taskObservableList);
}
@FXML
public void handleAddButton(ActionEvent e) {
Task t = new Task(-1, this.taskTextField.getText());
// What operations to do here ?
this.model.addTask(t);
this.taskTable.getItems().add(t);
this.taskTable.refresh();
}
}
Main.java
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
ToDoListModel model = new ToDoListModel();
primaryStage.setTitle("My Todo");
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("views/View.fxml"));
loader.setController(new Controller(model));
Parent root = loader.load();
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
最后,我的问题是:我的做法好吗?我的意思是我已经创建了一个带有任务列表的ToDoListModel这一事实,我在同一任务中更新了对象列表 Task 我用DAO更新了我的数据库(创建在DAO中将在列表中添加后执行)并且最重要的是:我应该在Controller的 handleAddButton 中执行哪些操作?这里我首先使用了我的TodoListModel中的add方法但是它还不够,因为我的可观察列表被错误地更新了(添加的任务出现但我们不能用鼠标选择它)。然后,当我在TableView项目中添加它时,任务出现两次,并在列表中添加了两次。
结果我已经知道ObservableList链接到我在ToDoListModel中的List,但是如果我只想在我的模型中对该列表进行操作但是更新ObservableList,我该怎么办?对吗? (可选项目等......)
提前感谢您的帮助和耐心, 此致 保罗
答案 0 :(得分:1)
这是一个示例实现
DAO
类负责连接数据库(可以使用池或其他东西)。在这种情况下,它建立了一个简单的连接。
public class DAO {
public Connection getConnection() throws SQLException {
return DriverManager.getConnection("jdbc:mysql://192.168.40.5:3306/test", "root", "");
}
}
ToDoListModel
类通过使用DAO
实例来处理数据库,以获得有效的连接。
public class ToDoListModel {
private DAO dao;
public static ToDoListModel getInstance() {
ToDoListModel model = new ToDoListModel();
model.dao = new DAO();
return model;
}
private ToDoListModel() {
}
public void addTask(Task task) throws SQLException {
try(Connection connection = dao.getConnection()) {
String q = "insert into todo (name) values (?)";
try(PreparedStatement statement = connection.prepareStatement(q, Statement.RETURN_GENERATED_KEYS)) {
statement.setString(1, task.getName());
statement.executeUpdate();
try(ResultSet rs = statement.getGeneratedKeys()) {
if(rs.next()) {
task.setId(rs.getInt(1));
}
}
}
}
}
public void deleteTask(Task task) throws SQLException {
try(Connection connection = dao.getConnection()) {
String q = "delete from todo where id = ?";
try(PreparedStatement statement = connection.prepareStatement(q)) {
statement.setInt(1, task.getId());
statement.executeUpdate();
}
}
}
public ObservableList<Task> getTaskList() throws SQLException {
try(Connection connection = dao.getConnection()) {
String q = "select * from todo";
try(Statement statement = connection.createStatement()) {
try(ResultSet rs = statement.executeQuery(q)) {
ObservableList<Task> tasks = FXCollections.observableArrayList();
while (rs.next()) {
Task task = new Task();
task.setId(rs.getInt("id"));
task.setName(rs.getString("name"));
tasks.add(task);
}
return tasks;
}
}
}
}
}
控制器使用ToDoListModel
初始化TableView
控件并添加操作(编辑和阅读 - 我没有实现它们,因为我坚持使用您的代码)
public class Controller {
@FXML
private TextField textField;
@FXML
private TableView<Task> tableView;
@FXML
private TableColumn<Task, String> nameTableColumn;
@FXML
private Button addButton;
@FXML
private void initialize() {
nameTableColumn.setCellValueFactory(cdf -> cdf.getValue().nameProperty());
addButton.disableProperty().bind(Bindings.isEmpty(textField.textProperty()));
CompletableFuture.supplyAsync(this::loadAll)
.thenAccept(list -> Platform.runLater(() -> tableView.getItems().setAll(list)))
.exceptionally(this::errorHandle);
}
@FXML
private void handleAddButton(ActionEvent event) {
CompletableFuture.supplyAsync(this::addTask)
.thenAccept(task -> Platform.runLater(() -> {
tableView.getItems().add(task);
textField.clear();
textField.requestFocus();
}))
.exceptionally(this::errorHandle);
}
private Task addTask() {
try {
Task task = new Task(textField.getText());
ToDoListModel.getInstance().addTask(task);
return task;
}
catch (SQLException e) {
throw new RuntimeException(e);
}
}
private ObservableList<Task> loadAll() {
try {
return ToDoListModel.getInstance().getTaskList();
}
catch (SQLException e) {
throw new RuntimeException(e);
}
}
private Void errorHandle(Throwable throwable) {
throwable.printStackTrace();
return null;
}
}
任何数据库操作都与CompletableFuture
异步,但您可以使用您喜欢的任何内容。重要的是要记住UI线程只能由它做出唯一的。