尝试创建允许用户轻松监控和维护嵌入式 derby 数据库中的网站列表的 javafx 应用程序

Trying to create javafx app that allows the user to easily monitor and maintain a list of websites in embedded derby database

我想允许用户将 link 拖放到列表中,这会将 URL 输入数据库,允许用户查看所有 link , articles, 或者类似页面右上角的东西(即使是简单的细节,比如标题和什么时候添加的 link 也可以),然后查看webview。我无法让它在右上角正确显示 URL 详细信息,或者在右下角正确显示 webview。我对 javafx 和 derby 非常熟悉,只是不太熟悉网络方面。任何帮助将不胜感激。截至目前,URL 可以拖放到列表中,标题和一些细节在右上角显示不正确。大多数时候 webview 都不起作用。 hyperlink 也没有在列表中正确显示,但这只是一些需要修复的格式。最终目标只是让用户在他们输入的 URL 上监控新帖子、文章或新闻。

DBUtils.java

public class DBUtils {
    final static Properties props = new Properties(); 
    static {
        props.put("user", "admin");
        props.put("password", "letmein");
    }
    private static String framework = "embedded";
    private static String driver = "org.apache.derby.jdbc.EmbeddedDriver";
    private static String protocol = "jdbc:derby:";
    public static void setupDb() {
        loadDriver();
        Connection conn = null;
        ArrayList statements = new ArrayList(); 
        Statement s = null;
        ResultSet rs = null;
        try {
            String dbName = "UrlDB"; 
            conn = DriverManager.getConnection(protocol + dbName + ";create=true", props);
            System.out.println("Creating database " + dbName);
            boolean createTable = false;
            s = conn.createStatement();
            try {
                s.executeQuery("SELECT count(*) FROM urlFeed");
            } catch (Exception e) {
                createTable = true;
            }     
            if (createTable) {
                conn.setAutoCommit(false);
                s = conn.createStatement();
                statements.add(s);
                s.execute("CREATE TABLE UrlFeed(ID INT, Title VARCHAR(255), Url VARCHAR(600))");
                System.out.println("Created table UrlFeed ");
                conn.commit();
            }         
            shutdown();
        } catch (SQLException sqle) {
            sqle.printStackTrace();
        } finally {         
            close(rs);
            int i = 0;
            while (!statements.isEmpty()) {
                Statement st = (Statement) statements.remove(i);
                close(st);
            }
            close(conn);
        }} 
    public static List<UrlFeed> loadFeeds() {
        loadDriver();
        Connection conn = null;
        ResultSet rs = null;
        List<UrlFeed> feeds = new ArrayList<>();
        try {
            String dbName = "UrlDB"; 
            conn = DriverManager.getConnection(protocol + dbName + ";create=true", props);
            rs = conn.createStatement().executeQuery("SELECT ID, Title, Url FROM UrlFeed");
            while (rs.next()) {
                String title = rs.getString("title");
                String url = rs.getString("url");
                UrlFeed urlFeed = new UrlFeed(title, url);
                urlFeed.id = urlFeed.link.hashCode();
                feeds.add(urlFeed);
            } 
            shutdown();
        } catch (SQLException sqle) {
            sqle.printStackTrace();
        } finally {         
            close(rs);
            close(conn);
        }
        return feeds;
    }
    private static void shutdown() {
        if (framework.equals("embedded")) {
            try {
                DriverManager.getConnection("jdbc:derby:;shutdown=true");
            } catch (SQLException se) {
                if (((se.getErrorCode() == 50000)
                        && ("XJ015".equals(se.getSQLState())))) {
                    System.out.println("Derby shut down normally");
                } else {
                    System.err.println("Derby did not shut down normally");
                    se.printStackTrace();
                }}
        }}  
    public static int saveUrlFeed(UrlFeed urlFeed) {
        int pk = urlFeed.link.hashCode();
        loadDriver();
        Connection conn = null;
        ArrayList statements = new ArrayList(); 
        PreparedStatement psInsert = null;
        Statement s = null;
        ResultSet rs = null;
        try {
            String dbName = "UrlDB"; 
            conn = DriverManager.getConnection(protocol + dbName + ";create=true", props);
            rs = conn.createStatement().executeQuery("SELECT COUNT(id) FROM UrlFeed WHERE id = " + urlFeed.link.hashCode());           
            rs.next();
            int count = rs.getInt(1);           
            if (count == 0) {
                conn.setAutoCommit(false);
                s = conn.createStatement();
                statements.add(s);
                psInsert = conn.prepareStatement("INSERT INTO UrlFeed VALUES (?, ?, ?)");
                statements.add(psInsert);
                psInsert.setInt(1, pk);
                String escapeTitle = urlFeed.channelTitle.replaceAll("\'", "''");
                psInsert.setString(2, escapeTitle);
                psInsert.setString(3, urlFeed.link);
                psInsert.executeUpdate();
                conn.commit();
                System.out.println("Inserted " + urlFeed.channelTitle + " " + urlFeed.link);
                System.out.println("Committed the transaction");
            }
            shutdown();
        } catch (SQLException sqle) {
            sqle.printStackTrace();
        } finally {
            close(rs);
            int i = 0;
            while (!statements.isEmpty()) {
                Statement st = (Statement) statements.remove(i);
                close(st);
            }
            close(conn);
        }
        return pk;
    }
    private static void close(AutoCloseable closable) {
        try {
            if (closable != null) {
                closable.close();
                closable = null;
            }
        } catch (Exception sqle) {
            sqle.printStackTrace();
        }
    }
    private static void loadDriver() {     
            try {
                Class.forName(driver);
                System.out.println("Loaded driver");           
            } catch (Exception e) {
                e.printStackTrace();
            }    
    }
}
DisplayContentsFromDatabase.java

public class DisplayContentsFromDatabase extends Application {
    @Override public void start(Stage stage) {
        Group root = new Group();
        Scene scene = new Scene(root, 640, 480, Color.WHITE);
        final Map<String, Hyperlink> hyperLinksMap = new TreeMap<>();      
        final WebView newsBrief = new WebView(); 
        final WebEngine webEngine = new WebEngine();
        final WebView websiteView = new WebView();      
        webEngine.getLoadWorker().stateProperty().addListener(new ChangeListener<State>() {
            public void changed(ObservableValue<? extends State> observable, State oldValue, State newValue){
                if (newValue != State.SUCCEEDED) {
                    return;
                }               
                UrlFeed urlFeed = parse(webEngine.getDocument(), webEngine.getLocation());
                hyperLinksMap.get(webEngine.getLocation()).setText(urlFeed.channelTitle);               
                StringBuilder urlSource = new StringBuilder();
                urlSource.append("<head>\n")
                         .append("</head>\n")
                         .append("<body>\n");
                urlSource.append("<b>")
                         .append(urlFeed.channelTitle)
                         .append(" (")
                         .append(urlFeed.news.size())
                         .append(")")
                         .append("</b><br />\n");
                 StringBuilder htmlArticleSb = new StringBuilder();
                for (NewsArticle article:urlFeed.news) {                   
                    htmlArticleSb.append("<hr />\n")
                         .append("<b>\n")
                         .append(article.title)
                         .append("</b><br />")
                         .append(article.pubDate)
                         .append("<br />")
                         .append(article.description)
                         .append("<br />\n")
                         .append("<input type=\"button\" onclick=\"alert('")
                            .append(article.link)
                            .append("')\" value=\"View\" />\n");
                }
                String content = urlSource.toString() + "<form>\n" + htmlArticleSb.toString() + "</form></body>\n";
                System.out.println(content);
                newsBrief.getEngine().loadContent(content);
                DBUtils.saveUrlFeed(urlFeed);
            }
        }); 
        newsBrief.getEngine().setOnAlert(new EventHandler<WebEvent<String>>(){
            public void handle(WebEvent<String> evt) {
                websiteView.getEngine().load(evt.getData());
            }
        });        
        SplitPane splitPane = new SplitPane();
        splitPane.prefWidthProperty().bind(scene.widthProperty());
        splitPane.prefHeightProperty().bind(scene.heightProperty());
        final VBox leftArea = new VBox(10);
        final TextField urlField = new TextField();
        urlField.setOnAction(new EventHandler<ActionEvent>(){
            public void handle(ActionEvent ae){
                String url = urlField.getText();
                final Hyperlink jfxHyperLink = createHyperLink(url, webEngine);
                hyperLinksMap.put(url, jfxHyperLink);
                HBox rowBox = new HBox(20);
                rowBox.getChildren().add(jfxHyperLink);
                leftArea.getChildren().add(rowBox);
                webEngine.load(url);
                urlField.setText("");
            }
        });     
        leftArea.getChildren().add(urlField);        
        List<UrlFeed> urlFeeds = DBUtils.loadFeeds();
        for (UrlFeed feed:urlFeeds) {
            HBox rowBox = new HBox(20);
            final Hyperlink jfxHyperLink = new Hyperlink(feed.channelTitle);
            jfxHyperLink.setUserData(feed);
            final String location = feed.link;
            hyperLinksMap.put(feed.link, jfxHyperLink);
            jfxHyperLink.setOnAction(new EventHandler<ActionEvent>() {
                    public void handle(ActionEvent evt) {
                        webEngine.load(location);
                    }
                }
            );
            rowBox.getChildren().add(jfxHyperLink);
            leftArea.getChildren().add(rowBox);            
        }                 
        scene.setOnDragOver(new EventHandler<DragEvent>() {
            @Override
            public void handle(DragEvent event) {
                Dragboard db = event.getDragboard();
                if (db.hasUrl()) {
                    event.acceptTransferModes(TransferMode.COPY);
                } else {
                    event.consume();
                }
            }
        }); 
        scene.setOnDragDropped(new EventHandler<DragEvent>() {
            @Override
            public void handle(DragEvent event) {
                Dragboard db = event.getDragboard();
                boolean success = false;
                HBox rowBox = new HBox(20);
                if (db.hasUrl()) {
                    if (!hyperLinksMap.containsKey(db.getUrl())) {                        
                        final Hyperlink jfxHyperLink = createHyperLink(db.getUrl(), webEngine);
                        hyperLinksMap.put(db.getUrl(), jfxHyperLink);
                        rowBox.getChildren().add(jfxHyperLink);
                        leftArea.getChildren().add(rowBox);
                    }
                    webEngine.load(db.getUrl());
                }    
                event.setDropCompleted(success);
                event.consume();
            }
        });        
        leftArea.setAlignment(Pos.TOP_LEFT);        
        SplitPane splitPane2 = new SplitPane();
        splitPane2.setOrientation(Orientation.VERTICAL);
        splitPane2.prefWidthProperty().bind(scene.widthProperty());
        splitPane2.prefHeightProperty().bind(scene.heightProperty());
        HBox centerArea = new HBox();     
        centerArea.getChildren().add(newsBrief);
        HBox rightArea = new HBox();
        rightArea.getChildren().add(websiteView);
        splitPane2.getItems().add(centerArea);
        splitPane2.getItems().add(rightArea);
        splitPane.getItems().add(leftArea);
        splitPane.getItems().add(splitPane2);
        newsBrief.prefWidthProperty().bind(scene.widthProperty());
        websiteView.prefWidthProperty().bind(scene.widthProperty());
        ObservableList<SplitPane.Divider> dividers = splitPane.getDividers();
        for (int i = 0; i < dividers.size(); i++) {
            dividers.get(i).setPosition((i + 1.0) / 3);
        }
        HBox hbox = new HBox();
        hbox.getChildren().add(splitPane);
        root.getChildren().add(hbox);       
        stage.setScene(scene);
        stage.show();       
    }
    private static UrlFeed parse(Document doc, String location) {        
        UrlFeed urlFeed = new UrlFeed();
        urlFeed.link = location;        
        urlFeed.channelTitle = doc.getElementsByTagName("title")
             .item(0)
             .getTextContent();
        NodeList items = doc.getElementsByTagName("item");
        for (int i=0; i<items.getLength(); i++){
            Map<String, String> childElements = new HashMap<>();
            NewsArticle article = new NewsArticle();
            for (int j=0; j<items.item(i).getChildNodes().getLength(); j++) {
                Node node = items.item(i).getChildNodes().item(j);
                childElements.put(node.getNodeName().toLowerCase(), node.getTextContent());
            }
            article.title = childElements.get("title");
            article.description = childElements.get("description");
            article.link = childElements.get("link");
            article.pubDate = childElements.get("pubdate");           
            urlFeed.news.add(article);
        }
        return urlFeed;
    }  
    private Hyperlink createHyperLink(String url, final WebEngine webEngine) {
        final Hyperlink jfxHyperLink = new Hyperlink("Loading News...");
        UrlFeed aFeed = new UrlFeed();
        aFeed.link = url;
        jfxHyperLink.setUserData(aFeed);
        jfxHyperLink.setOnAction(new EventHandler<ActionEvent>() {
            public void handle(ActionEvent evt) {
                UrlFeed urlFeed = (UrlFeed)jfxHyperLink.getUserData();
                webEngine.load(urlFeed.link);
            }
        });
        return jfxHyperLink;
    } 
    public static void main(String[] args){
        DBUtils.setupDb();
        Application.launch(args);
    }
}
class UrlFeed {
    int id;
    String channelTitle = "News...";
    String link;
    List<NewsArticle> news = new ArrayList<>();

    public String toString() {
        return "urlFeed{" + "id=" + id + ", channelTitle=" + channelTitle + ", link=" + link + ", news=" + news + '}';
    }
    public UrlFeed() {
    }
    public UrlFeed(String title, String link) {
        this.channelTitle = title;
        this.link = link;
    }
}
class NewsArticle {
    String title;
    String description;
    String link;
    String pubDate;
    public String toString() {
        return "NewsArticle{" + "title=" + title + ", description=" + description + ", link=" + link + ", pubDate=" + pubDate + ", enclosure=" + '}';
    }  
}

我复制了你的代码并重构了它。

捕获异常并只打印堆栈跟踪意味着程序将继续运行。例如,如果您无法加载 JDBC 驱动程序,那么继续有什么意义呢?整个程序依赖于能够与数据库进行交互。

您无法从中恢复的异常会导致程序终止。异常要么不受您的控制,要么表明您的程序中存在错误。

但是请注意,当您无法关闭 StatementResultSet 时忽略 SQLException 是安全的,因为即使 ResultSet/Statement 没有关闭。

  • 您的 JDBC 代码应使用 try-with-resources.
  • 您可以使用class java.sql.DatabaseMetaData 来检查table 是否存在。
  • 您只需要加载 JDBC 驱动 class 一次。
  • 您应该只在程序终止时关闭数据库。

虽然 WebEngine 将成功加载您在 urlField 中输入的 URL,但通过方法 getLocation() 编辑的值 return 可能不相同到您输入的内容,因此 hyperLinksMap 将不包含您搜索的密钥。结果 hyperLinksMap.get(webEngine.getLocation()) 将 return null 这意味着您的代码的以下行将抛出 NullPointerException.

hyperLinksMap.get(webEngine.getLocation()).setText(urlFeed.channelTitle);

您还应该处理 WebEngine 无法加载用户输入的 URL 的情况。

这是重构后的代码。请注意,我制作了所有 classes public classes.

  1. ClassDisplayContentsFromDatabase
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.concurrent.Worker;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.SplitPane;
import javafx.scene.control.TextField;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebEvent;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

public class DisplayContentsFromDatabase extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        Group root = new Group();
        Scene scene = new Scene(root, 640, 480, Color.WHITE);
        final Map<String, Hyperlink> hyperLinksMap = new TreeMap<>();
        final WebView newsBrief = new WebView();
        final WebEngine webEngine = new WebEngine();
        final WebView websiteView = new WebView();
        webEngine.getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
            public void changed(ObservableValue<? extends Worker.State> observable,
                                Worker.State oldValue,
                                Worker.State newValue) {
                if (newValue != Worker.State.SUCCEEDED) {
                    System.out.println("Worker.State = " + newValue);
                    if (newValue == Worker.State.FAILED) {
                        System.out.println("Failed to load URL.");
                    }
                    return;
                }
                UrlFeed urlFeed = parse(webEngine.getDocument(), webEngine.getLocation());
                String location = webEngine.getLocation();
                System.out.println("Web location: " + location);
                Hyperlink link = hyperLinksMap.get(location);
                if (link == null) {
                    System.out.println("Web location mismatch.");
                    return;
                }
                link.setText(urlFeed.channelTitle);
                StringBuilder urlSource = new StringBuilder();
                urlSource.append("<head>\n").append("</head>\n").append("<body>\n");
                urlSource.append("<b>").append(urlFeed.channelTitle).append(" (")
                        .append(urlFeed.news.size()).append(")").append("</b><br />\n");
                StringBuilder htmlArticleSb = new StringBuilder();
                for (NewsArticle article : urlFeed.news) {
                    htmlArticleSb.append("<hr />\n").append("<b>\n").append(article.title)
                            .append("</b><br />").append(article.pubDate).append("<br />")
                            .append(article.description).append("<br />\n")
                            .append("<input type=\"button\" onclick=\"alert('").append(article.link)
                            .append("')\" value=\"View\" />\n");
                }
                String content = urlSource.toString() + "<form>\n" + htmlArticleSb.toString()
                        + "</form></body>\n";
                System.out.println(content);
                newsBrief.getEngine().loadContent(content);
                try {
                    DBUtils.saveUrlFeed(urlFeed);
                }
                catch (ClassNotFoundException | SQLException x) {
                    throw new RuntimeException(x);
                }
            }
        });
        newsBrief.getEngine().setOnAlert(new EventHandler<WebEvent<String>>() {
            public void handle(WebEvent<String> evt) {
                websiteView.getEngine().load(evt.getData());
            }
        });
        SplitPane splitPane = new SplitPane();
        splitPane.prefWidthProperty().bind(scene.widthProperty());
        splitPane.prefHeightProperty().bind(scene.heightProperty());
        final VBox leftArea = new VBox(10);
        final TextField urlField = new TextField();
        urlField.setOnAction(new EventHandler<ActionEvent>() {
            public void handle(ActionEvent ae) {
                String url = urlField.getText();
                final Hyperlink jfxHyperLink = createHyperLink(url, webEngine);
                hyperLinksMap.put(url, jfxHyperLink);
                HBox rowBox = new HBox(20);
                rowBox.getChildren().add(jfxHyperLink);
                leftArea.getChildren().add(rowBox);
                webEngine.load(url);
                urlField.setText("");
            }
        });
        leftArea.getChildren().add(urlField);
        List<UrlFeed> urlFeeds = DBUtils.loadFeeds();
        for (UrlFeed feed : urlFeeds) {
            HBox rowBox = new HBox(20);
            final Hyperlink jfxHyperLink = new Hyperlink(feed.channelTitle);
            jfxHyperLink.setUserData(feed);
            final String location = feed.link;
            hyperLinksMap.put(feed.link, jfxHyperLink);
            jfxHyperLink.setOnAction(new EventHandler<ActionEvent>() {
                public void handle(ActionEvent evt) {
                    webEngine.load(location);
                }
            });
            rowBox.getChildren().add(jfxHyperLink);
            leftArea.getChildren().add(rowBox);
        }
        scene.setOnDragOver(new EventHandler<DragEvent>() {
            @Override
            public void handle(DragEvent event) {
                Dragboard db = event.getDragboard();
                if (db.hasUrl()) {
                    event.acceptTransferModes(TransferMode.COPY);
                }
                else {
                    event.consume();
                }
            }
        });
        scene.setOnDragDropped(new EventHandler<DragEvent>() {
            @Override
            public void handle(DragEvent event) {
                Dragboard db = event.getDragboard();
                boolean success = false;
                HBox rowBox = new HBox(20);
                if (db.hasUrl()) {
                    if (!hyperLinksMap.containsKey(db.getUrl())) {
                        final Hyperlink jfxHyperLink = createHyperLink(db.getUrl(), webEngine);
                        hyperLinksMap.put(db.getUrl(), jfxHyperLink);
                        rowBox.getChildren().add(jfxHyperLink);
                        leftArea.getChildren().add(rowBox);
                    }
                    webEngine.load(db.getUrl());
                }
                event.setDropCompleted(success);
                event.consume();
            }
        });
        leftArea.setAlignment(Pos.TOP_LEFT);
        SplitPane splitPane2 = new SplitPane();
        splitPane2.setOrientation(Orientation.VERTICAL);
        splitPane2.prefWidthProperty().bind(scene.widthProperty());
        splitPane2.prefHeightProperty().bind(scene.heightProperty());
        HBox centerArea = new HBox();
        centerArea.getChildren().add(newsBrief);
        HBox rightArea = new HBox();
        rightArea.getChildren().add(websiteView);
        splitPane2.getItems().add(centerArea);
        splitPane2.getItems().add(rightArea);
        splitPane.getItems().add(leftArea);
        splitPane.getItems().add(splitPane2);
        newsBrief.prefWidthProperty().bind(scene.widthProperty());
        websiteView.prefWidthProperty().bind(scene.widthProperty());
        ObservableList<SplitPane.Divider> dividers = splitPane.getDividers();
        for (int i = 0; i < dividers.size(); i++) { dividers.get(i).setPosition((i + 1.0) / 3); }
        HBox hbox = new HBox();
        hbox.getChildren().add(splitPane);
        root.getChildren().add(hbox);
        stage.setScene(scene);
        stage.show();
    }

    public void stop() throws Exception {
        DBUtils.shutdown();
    }

    private static UrlFeed parse(Document doc, String location) {
        UrlFeed urlFeed = new UrlFeed();
        urlFeed.link = location;
        urlFeed.channelTitle = doc.getElementsByTagName("title").item(0).getTextContent();
        NodeList items = doc.getElementsByTagName("item");
        for (int i = 0; i < items.getLength(); i++) {
            Map<String, String> childElements = new HashMap<>();
            NewsArticle article = new NewsArticle();
            for (int j = 0; j < items.item(i).getChildNodes().getLength(); j++) {
                Node node = items.item(i).getChildNodes().item(j);
                childElements.put(node.getNodeName().toLowerCase(), node.getTextContent());
            }
            article.title = childElements.get("title");
            article.description = childElements.get("description");
            article.link = childElements.get("link");
            article.pubDate = childElements.get("pubdate");
            urlFeed.news.add(article);
        }
        return urlFeed;
    }

    private Hyperlink createHyperLink(String url, final WebEngine webEngine) {
        final Hyperlink jfxHyperLink = new Hyperlink("Loading News...");
        UrlFeed aFeed = new UrlFeed();
        aFeed.link = url;
        jfxHyperLink.setUserData(aFeed);
        jfxHyperLink.setOnAction(new EventHandler<ActionEvent>() {
            public void handle(ActionEvent evt) {
                UrlFeed urlFeed = (UrlFeed) jfxHyperLink.getUserData();
                webEngine.load(urlFeed.link);
            }
        });
        return jfxHyperLink;
    }

    public static void main(String[] args) {
        try {
            DBUtils.setupDb();
            Application.launch(args);
        }
        catch (Exception x) {
            x.printStackTrace();
        }
    }
}
  1. ClassDBUtil
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

public class DBUtils {
    final static Properties props = new Properties();
    static {
        props.put("user", "admin");
        props.put("password", "letmein");
    }
    private static boolean  loaded;
    private static String framework = "embedded";
    private static String driver = "org.apache.derby.jdbc.EmbeddedDriver";
    private static String protocol = "jdbc:derby:";

    public static void setupDb() throws ClassNotFoundException, SQLException {
        loadDriver();
        Statement s = null;
        ResultSet rs = null;
        String dbName = "UrlDB";
        try (Connection conn = DriverManager.getConnection(protocol + dbName + ";create=true",
                                                           props)) {
            System.out.println("Creating database " + dbName);
            DatabaseMetaData dbmd = conn.getMetaData();
            rs = dbmd.getTables(null, null, "URLFEED", null);
            boolean createTable = !rs.next();
            if (createTable) {
                s = conn.createStatement();
                s.execute("CREATE TABLE UrlFeed(ID INT, Title VARCHAR(255), Url VARCHAR(600))");
                System.out.println("Created database table 'UrlFeed'.");
            }
            else {
                System.out.println("Database table 'UrlFeed' already exists.");
            }
        }
        finally {
            if (rs != null) {
                try {
                    rs.close();
                }
                catch (SQLException xSql) {
                    // Ignore.
                }
            }
            if (s != null) {
                try {
                    s.close();
                }
                catch (SQLException xSql) {
                    // Ignore.
                }
            }
        }
    }

    public static List<UrlFeed> loadFeeds() throws ClassNotFoundException, SQLException {
        loadDriver();
        List<UrlFeed> feeds = new ArrayList<>();
        String dbName = "UrlDB";
        try (Connection conn = DriverManager.getConnection(protocol + dbName + ";create=true",
                                                           props);
             Statement s = conn.createStatement();
             ResultSet rs = s.executeQuery("SELECT ID, Title, Url FROM UrlFeed")) {
            while (rs.next()) {
                String title = rs.getString("title");
                String url = rs.getString("url");
                UrlFeed urlFeed = new UrlFeed(title, url);
                urlFeed.id = urlFeed.link.hashCode();
                feeds.add(urlFeed);
            }
        }
        return feeds;
    }

    public static void shutdown() {
        if (framework.equals("embedded")) {
            try {
                DriverManager.getConnection("jdbc:derby:;shutdown=true");
            }
            catch (SQLException se) {
                if (((se.getErrorCode() == 50000) && ("XJ015".equals(se.getSQLState())))) {
                    System.out.println("Derby shut down normally");
                }
                else {
                    System.err.println("Derby did not shut down normally");
                    se.printStackTrace();
                }
            }
        }
    }

    public static int saveUrlFeed(UrlFeed urlFeed) throws ClassNotFoundException, SQLException {
        int pk = urlFeed.link.hashCode();
        loadDriver();
        PreparedStatement psInsert = null;
        ResultSet rs = null;
        String dbName = "UrlDB";
        try (Connection conn = DriverManager.getConnection(protocol + dbName + ";create=true",
                               props);
             PreparedStatement s = conn.prepareStatement("SELECT COUNT(id) FROM UrlFeed WHERE id = ?")) {
            s.setInt(1, pk);
            rs = s.executeQuery();
            rs.next();
            int count = rs.getInt(1);
            if (count == 0) {
                psInsert = conn.prepareStatement("INSERT INTO UrlFeed VALUES (?, ?, ?)");
                psInsert.setInt(1, pk);
                String escapeTitle = urlFeed.channelTitle.replaceAll("\'", "''");
                psInsert.setString(2, escapeTitle);
                psInsert.setString(3, urlFeed.link);
                count = psInsert.executeUpdate();
                System.out.println("Inserted " + urlFeed.channelTitle + " " + urlFeed.link);
            }
        }
        finally {
            close(rs);
            close(psInsert);
        }
        return pk;
    }

    private static void close(AutoCloseable closable) {
        try {
            if (closable != null) {
                closable.close();
                closable = null;
            }
        }
        catch (Exception sqle) {
            sqle.printStackTrace();
        }
    }

    private static void loadDriver() throws ClassNotFoundException {
        if (!loaded) {
            Class.forName(driver);
            System.out.println("Loaded driver");
            loaded = true;
        }
    }
}
  1. ClassUrlFeed
import java.util.ArrayList;
import java.util.List;

public class UrlFeed {
    int id;
    String channelTitle = "News...";
    String link;
    List<NewsArticle> news = new ArrayList<>();

    public String toString() {
        return String.format("urlFeed{id=%s, channelTitle=%s, link=%s, news=%s}",
                             id,
                             channelTitle,
                             link,
                             news);
    }

    public UrlFeed() {
    }

    public UrlFeed(String title, String link) {
        this.channelTitle = title;
        this.link = link;
    }
}
  1. Class NewsArticle
public class NewsArticle {
    String title;
    String description;
    String link;
    String pubDate;

    public String toString() {
        return String.format("NewsArticle{title=%s, description=%s, link=%s, pubDate=%s, enclosure=}",
                             title,
                             description,
                             link,
                             pubDate);
    }
}

目前上面的代码只能打印到标准输出。您应该更改它,以便用户通过 GUI 了解程序正在做什么。例如,在加载网页时,您可以显示 progress indicator. And when WebEngine fails to load the entered URL, you could display an alert.

编辑

回应您的 ,您在其中写道:

the webview doesn't seem to be loading in the bottom right. Any suggestions?

我相信您指的是 class DisplayContentsFromDatabase 的方法 start 中的局部变量 websiteView,即

final WebView websiteView = new WebView();

您的代码中唯一引用该变量的部分如下(也在方法 start 中):

newsBrief.getEngine().setOnAlert(new EventHandler<WebEvent<String>>() {
    public void handle(WebEvent<String> evt) {
        websiteView.getEngine().load(evt.getData());
    }
});

这里引用了 javadoc 方法 setOnAlert:

Sets the value of the property onAlert.
Property Description:JavaScript alert handler property. This handler is invokedwhen a script running on the Web page calls the alert function.

因此您需要为包含 JavaScript and that JavaScript displays an alert 的网页输入 URL。只有这样,代码才会尝试加载某些内容并将其显示在 websiteView 中。对不起,我不会尝试测试该代码。