尝试创建允许用户轻松监控和维护嵌入式 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 驱动程序,那么继续有什么意义呢?整个程序依赖于能够与数据库进行交互。
您无法从中恢复的异常会导致程序终止。异常要么不受您的控制,要么表明您的程序中存在错误。
但是请注意,当您无法关闭 Statement
或 ResultSet
时忽略 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.
- Class
DisplayContentsFromDatabase
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();
}
}
}
- Class
DBUtil
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;
}
}
}
- Class
UrlFeed
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;
}
}
- 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
中。对不起,我不会尝试测试该代码。
我想允许用户将 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 驱动程序,那么继续有什么意义呢?整个程序依赖于能够与数据库进行交互。
您无法从中恢复的异常会导致程序终止。异常要么不受您的控制,要么表明您的程序中存在错误。
但是请注意,当您无法关闭 Statement
或 ResultSet
时忽略 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.
- Class
DisplayContentsFromDatabase
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();
}
}
}
- Class
DBUtil
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;
}
}
}
- Class
UrlFeed
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;
}
}
- 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
中。对不起,我不会尝试测试该代码。