JavaFX-MVC应用程序与数据库的最佳实践
我是JavaFX新手,我想知道用这种语言开发MVC数据库应用程序的最佳实践是什么,如果你是一名高级开发人员,我想我的问题会很简单JavaFX-MVC应用程序与数据库的最佳实践,java,database,model-view-controller,javafx,fxml,Java,Database,Model View Controller,Javafx,Fxml,我是JavaFX新手,我想知道用这种语言开发MVC数据库应用程序的最佳实践是什么,如果你是一名高级开发人员,我想我的问题会很简单 让我们考虑一个在JavaFX中开发的基本应用程序的简单示例:链接到SQL数据库的ToLoister. 数据库只是一个带有id和taskDescr VARCHAR字段的表 目的非常简单:我们只想在TableView或ListView中显示任务,并能够添加一些任务 这就是我们的应用程序的外观: 我决定将代码分为四个部分,DAO用于表示表中数据的类(Task.java
让我们考虑一个在JavaFX中开发的基本应用程序的简单示例:链接到SQL数据库的ToLoister.
- 数据库只是一个带有id和taskDescr VARCHAR字段的表
- 目的非常简单:我们只想在TableView或ListView中显示任务,并能够添加一些任务
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;
}
}
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;
}
}
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();
}
}
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.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;
}
}
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;
}
}
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();
}
}
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,我在同一个任务中更新了我的对象列表任务,我用DAO更新了我的数据库(DAO中的创建将在列表中的外接程序之后执行)最重要的是:我应该在控制器的handleAddButton中执行什么操作?这里我首先在TodoListModel中使用add方法,但这还不够,因为我的可观察列表被错误地更新(添加的任务出现了,但我们无法用鼠标选择它)。然后,当我也将其添加到TableView项目中时,该任务会出现两次,并且已在列表中添加了两次
因此,我知道ObservableList链接到我的ToDoListModel中的列表,但是如果我只想在我的模型中对该列表执行操作,但得到ObservableList的正确更新,我应该怎么做?(可选项等)
提前感谢您的帮助和耐心,
真诚地
Paul这里是一个示例实现
DAO
类负责连接到数据库(可能使用池或其他东西)。在这种情况下,它进行简单的连接
public class DAO {
public Connection getConnection() throws SQLException {
return DriverManager.getConnection("jdbc:mysql://192.168.40.5:3306/test", "root", "");
}
}
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
类通过使用DAO
的实例获取有效连接来处理数据库
public class DAO {
public Connection getConnection() throws SQLException {
return DriverManager.getConnection("jdbc:mysql://192.168.40.5:3306/test", "root", "");
}
}
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;
}
}
}
}
}
任何数据库操作都与
CompletableFuture
是异步的,但您可以使用任何您喜欢的方法。重要的是要记住,UI线程只能由它唯一地创建。没有错误处理逻辑。在UI线程中使用数据库是不好的。ToDoListModel
可以与一起使用>ObservableList
,不需要保留其实例(她坐在控件中).handleAddButton
可以使用ToDoListModel
立即将元素保存到数据库中,但这在进行小更改时非常有用。当您进行更多编辑时,最好使用单独的保存按钮,只允许对数据库进行一次请求(upsert
)保存整个列表和一个delete
删除。您好,是的,正如我所说,我编写错误处理代码并不是为了简化此处发布的代码。好的,所以我必须用一个可观察列表替换TaskListModel中的列表,并对其进行操作?我想我不明白您的第二篇帖子:/好的,我明白您的意思,因此我理解了在这里,经典的“模型-视图-控制器”模式不能在JavaFX中实现,因为模型(通常携带所有数据并和和数据库交互的类DAO交互)是由控制器本身在JavaFX中表示的?我认为在繁重的应用程序中操纵大量数据(数据库数据和无数据库数据)我们使用了一个模型来管理所有思考并将其提供给控制器。“UI线程只能由它唯一地生成。”->我没有理解这一点:/?哦,好的,我理解了,你的意思是我的this.Model.addTask(t)
更改了UI?我在之前的评论中是否正确理解了MVC原则?对于那些必须管理其模型中其他数据的大型应用程序呢?@PaulThirozier,是的,对您使用的数据(模型)的所有更改反映在用户界面中。因此,这些更改只应在应用程序线程中执行。在您的示例中,没有异步数据加载,因此无需担心(用户界面将冻结除外)。这是大型项目的方法。这里的模型是任务
,如果您习惯了Swing
体系结构,这可能会让您感到困惑(需要制作一个模型来保持数据收集)哦,是的,我认为我对这些不同的方法有点困惑。所以,我理解,如果我构建了一个沉重的JavaFX应用程序,我应该考虑异步数据加载的方法(我理解代码,谢谢你)。如果我需要处理不在数据库中的其他数据,我会为每种类型的数据创建另一个类。但是,为所有数据实现“ModelContainer”并不是一个好的做法?问题在于。MVC类型体系结构背后的驱动动机是使同一数据(模型)具有多个视图成为可能。如果从一个视图修改数据,则其他视图应该能够更新(当然,这是在模型不依赖于视图的情况下完成的)。您的设计不允许这样做:例如,想象一个相同数据的列表视图
(可能在另一个视图中)