功能设计:
1.实现读者文章的预览及下载
(实现了单击预览,双击下载)
2.实现文章查找
(实现了通过文章名查找(关键字)或者文章期数或年份(或者年份加期数))
实现步骤:
首先是数据库设计:
数据库使用一个数据表即可,三个字段,一个是filename用于储存文章名,一个是filepath用于储存文章链接,最后一个是time用于储存文章年份及期数。
create table duzhefile
(
filename char(20),
filepath char(100),
time char(6)
)
数据库创建成功后先将数据写入:
Duzhecurl.java
package All; import java.sql.Connection;
import java.sql.PreparedStatement; import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements; public class Duzhecurl { public static void main(String[] args) throws Exception {
// 第一步:访问读者首页
String url = "https://www.dzwzzz.com/";
Document document = Jsoup.connect(url).get(); // 第二步:解析页面
Elements datatime = document.select("a");
//获取a标签
for(int num=0;num<datatime.size();num++) {
//判断文章链接
if(datatime.get(num).attr("href").charAt(4)=='_') {
//获取a标签中href属性的值
String deHref = datatime.get(num).attr("href");
System.out.println("开始获取"+deHref.substring(0, 4)+"年第"+deHref.substring(5,7)+"期");
String time = deHref.substring(0,4)+deHref.substring(5,7);
//访问不同期刊页面
String DuZhe = "https://www.dzwzzz.com/"+deHref;
Document newdocu = Jsoup.connect(DuZhe).get();
//获取a标签
Elements a_Elements = newdocu.select("a");
for(int i=0;i<a_Elements.size();i++) {
//判断是否是文章链接
if (a_Elements.get(i).attr("href").charAt(0)=='d'
&&a_Elements.get(i).attr("href").charAt(1)=='u')
{
//访问文章所在页
String purpose = "https://www.dzwzzz.com/"+deHref.substring(0, 8)+a_Elements.get(i).attr("href");
Document finaldocu = Jsoup.connect(purpose).get();
//获取文章标题
Elements h1_elements = finaldocu.select("h1");
String title = h1_elements.text();
//获取文章内容
Elements p_Elements = finaldocu.select("p");
String Content = p_Elements.text();
String sql = "insert into duzhefile values(?,?,?)";
Connection conn = Connect.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, title);
pstmt.setString(2, purpose);
pstmt.setString(3, time);
pstmt.execute();
System.out.println("文章地址"+purpose);
System.out.println(title+" 写入成功!");
}
}
}
} } }
数据库写入之后开始设计界面:
FirstPage.fxml
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.paint.*?>
<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?> <AnchorPane prefHeight="361.0" prefWidth="643.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="All.FirstPageController">
<children>
<Pane prefHeight="420.0" prefWidth="643.0">
<children>
<TextField fx:id="SelectFile" layoutX="27.0" layoutY="24.0" prefHeight="23.0" prefWidth="184.0" promptText="输入文件名搜索" />
<Button fx:id="Select" layoutX="236.0" layoutY="24.0" mnemonicParsing="false" onMouseClicked="#ClickToSelect" text="搜索" />
<TableView fx:id="FileTest" layoutY="74.0" onMouseClicked="#SelectFile" prefHeight="345.0" prefWidth="394.0">
<columns>
<TableColumn fx:id="FileName" editable="false" prefWidth="152.0" text="文件名" />
<TableColumn fx:id="FilePath" editable="false" prefWidth="241.0" text="路径" />
</columns>
</TableView>
<Text fx:id="Preview" layoutX="398.0" layoutY="-170.0" strokeType="OUTSIDE" strokeWidth="0.0" text="文件名" textAlignment="CENTER" wrappingWidth="246.12109375" y="200.0">
<font>
<Font size="18.0" />
</font>
<fill>
<RadialGradient centerX="0.40555555555555556" centerY="0.5" radius="0.5">
<stops>
<Stop color="#dd3b09" />
<Stop color="#00dff8" offset="1.0" />
</stops>
</RadialGradient>
</fill>
</Text>
<Text layoutX="22.0" layoutY="65.0" strokeType="OUTSIDE" strokeWidth="0.0" text="单击预览文章,双击下载文章" wrappingWidth="194.0" />
<Button fx:id="reset" layoutX="305.0" layoutY="24.0" mnemonicParsing="false" onMouseClicked="#ClickToReset" text="返回" />
<Text fx:id="content" layoutX="394.0" layoutY="62.0" strokeType="OUTSIDE" strokeWidth="0.0" text="内容预览" textAlignment="CENTER" wrappingWidth="253.12109375" />
</children>
</Pane>
</children>
</AnchorPane>
界面设计完成后是这个样的:
生成控制类后插入数据并实现各个方法:
FirstPageController.java
package All; import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ResourceBundle;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern; import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import org.omg.CORBA.PUBLIC_MEMBER; import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.input.MouseEvent;
import javafx.scene.text.Text; public class FirstPageController implements Initializable {
@FXML
private TextField SelectFile;//输入框
@FXML
private Button Select;//查找按钮
@FXML
private Button reset;//返回按钮
@FXML
private Text content;//预览内容
@FXML
private TableView<Data> FileTest;//表格
@FXML
private TableColumn<Data, String> FileName;//第一列存文章名
@FXML
private TableColumn<Data, String> FilePath;//第二列存文章链接
@FXML private Text Preview;//预览标题 private ObservableList<Data> cellData = FXCollections.observableArrayList();
//用于存储数据Data类型的
@FXML
public void SelectFile(MouseEvent event) throws IOException {
Data data = FileTest.getSelectionModel().getSelectedItem();//获取所选择的行的Data对象
String filename = data.getFilename().getValue();//获取选择的Data对象的文章名
String url = data.getFilepath().getValue();//获取选择的Data对象的文章地址
Document doc;//用来存储爬取到的网页源码
String Finacontent;//用来存储文章内容
try {
doc = Jsoup.connect(url).get();//获取Data对象的文章源码
Elements p_Elements = doc.select("p");//查找P标签
String Content = p_Elements.text();//保存p标签的内容
Preview.setText(filename);//将文章名写入面板
content.setText(Content);//将P标签的内容写入预览内容框中
Finacontent = Content;//将文章内容传出去
} catch (IOException e) {
Finacontent = null;//告诉外面内容为空
}
if (event.getClickCount() == 2 && Finacontent.length() > 50) {
//如果点击了两下且文章内容大于50个字符则
File file = new File("E:/FileTest/" + filename + ".txt");
// 创建文件输出流
OutputStreamWriter fileOutputStream;
try {
fileOutputStream = new OutputStreamWriter(new FileOutputStream(file, true), "UTF-8");
// 这里的true功能是不覆盖原有内容,所以多次运行程序会造成重复
// 将文章内容写入文件
fileOutputStream.write(Finacontent.toString());
fileOutputStream.close();//关闭流操作
System.out.println(filename + " 下载成功!");//提示成功
//弹出弹窗提示下载成功
Alert alert = new Alert(AlertType.INFORMATION);
alert.setTitle("提示");
alert.setContentText("下载成功!!");
alert.setHeaderText("文章已保存到"+"E:/FileTest目录下");
alert.showAndWait();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} }
}
@FXML
public void ClickToReset(MouseEvent event) {
AddData();//如果点击了返回按钮则重新将数据写入表格
}
@FXML
public void ClickToSelect(MouseEvent event) {
String prama = SelectFile.getText();//获取输入框输入输入的内容
String strMatch1 = "^\\d{1,6}$";//正则表达式匹配1-6位数字
Pattern pattern = Pattern.compile(strMatch1);//使用匹配规则
Matcher matcher = pattern.matcher(prama);//进行匹配
String regex = "[\\u4E00-\\u9FA5]"; //正则表达式匹配汉字
Matcher m = Pattern.compile(regex).matcher(prama);//使用匹配汉字规则进行匹配
if (matcher.find()==true) {//如果匹配数字成功则进行数据库查找(对文章日期进行查找)
cellData.removeAll(cellData);//清空原有的cellData里的数据
Connection conn = Connect.getConnection();//获取数据库连接
String sql = "select * from duzhefile where time like ?";//定义数据库查询语句
try {
// 执行查询语句
PreparedStatement prep = conn.prepareStatement(sql);
prep.setString(1, '%' + prama.replace(" ", "") + '%');//将输入的内容除去空格后绑定到数据库语句中
ResultSet res = prep.executeQuery();//执行数据库查询语句并将结果返回到ResultSet对象中
while (res.next()) {//如果结果有下一行
String name = res.getString("filename");
String path = res.getString("filepath");
cellData.add(0, new Data(name, path));//将查询到的文章名和文章地址插入cellData中
}
if (!res.absolute(1)) {//如果查询结果不存在第一行(即为空),则弹窗提示查找结果为空
Alert alert = new Alert(AlertType.ERROR);
alert.setTitle("提示");
alert.setContentText("请重新输入!");
alert.setHeaderText("查询结果为空!");
alert.showAndWait();
AddData();//将所有数据重新插入(因为查询的时候清空了)
}
} catch (SQLException e) {
e.printStackTrace();
}
FileName.setCellValueFactory(cellData -> cellData.getValue().getFilename());
FilePath.setCellValueFactory(cellData -> cellData.getValue().getFilepath());
FileTest.setItems(cellData);//将cellData绑定到表格
}
else if (m.find()) {//如果匹配汉字成功
cellData.removeAll(cellData);//清空原有的数据
Connection conn = Connect.getConnection();//获取数据库连接
String sql = "select * from duzhefile where filename like ?";//定义数据库查询语句
try {
// 执行查询语句
PreparedStatement prep = conn.prepareStatement(sql);
prep.setString(1, '%'+ prama.replace(" ", "")+'%');//去除空格后绑定参数
ResultSet res = prep.executeQuery();//执行查询语句并返回结果
while (res.next()) {//如果查询结果不为空
String name = res.getString("filename");
String path = res.getString("filepath");
cellData.add(0, new Data(name, path));//将查询到的数据写入cellData中 }
if (!res.absolute(1)) {//如果查询结果不存在第一行(为空),则弹窗提示查找结果为空
Alert alert = new Alert(AlertType.ERROR);
alert.setTitle("提示");
alert.setContentText("请重新输入!");
alert.setHeaderText("查询结果为空!");
alert.showAndWait();
AddData();//将所有数据重新插入(因为查询的时候清空了)
}
} catch (SQLException e) {
e.printStackTrace();
}
FileName.setCellValueFactory(cellData -> cellData.getValue().getFilename());
FilePath.setCellValueFactory(cellData -> cellData.getValue().getFilepath());
FileTest.setItems(cellData);//将cellData绑定到表格中
}
else if(prama.length()==0){//如果输入的内容为空(即没有输入)则弹窗提示重新输入
AddData();
Alert alert = new Alert(AlertType.ERROR);
alert.setTitle("提示");
alert.setContentText("请重新输入!");
alert.setHeaderText("您输入的信息有误!\n输入文件名、年份、月份均可查找");
alert.showAndWait();
}
} private Main main;
public void setMain(Main main) {
this.main = main;
} @Override
public void initialize(URL location, ResourceBundle resources) {
AddData();//加载页面时写入数据
} private void AddData() {//将数据库查询结果写入cellData中,封装成方法方便多次调用
Connection conn = Connect.getConnection();
String Strsql = "select * from duzhefile";
try {
// 执行查询语句
PreparedStatement prep = conn.prepareStatement(Strsql);
ResultSet res = prep.executeQuery();
while (res.next()) {
String name = res.getString("filename");
String path = res.getString("filepath");
cellData.add(0, new Data(name,path)); }
} catch (SQLException e) {
e.printStackTrace();
}
FileName.setCellValueFactory(cellData -> cellData.getValue().getFilename());
FilePath.setCellValueFactory(cellData -> cellData.getValue().getFilepath());
FileTest.setItems(cellData);
} }
用到的Data类如下:
Data.java
package All; import javafx.beans.property.SimpleStringProperty; public class Data {
private SimpleStringProperty filename;
private SimpleStringProperty filepath; public Data(String name,String path) {
this.filename = new SimpleStringProperty(name);
this.filepath = new SimpleStringProperty(path);
} public SimpleStringProperty getFilename() {
return filename;
} public void setFilename(String filename) {
this.filename = new SimpleStringProperty(filename);
} public SimpleStringProperty getFilepath() {
return filepath;
} public void setFilepath(String filepath1) {
this.filepath = new SimpleStringProperty(filepath1);
}
}
数据库连接类如下:
Connect.java
package All; import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties; public class Connect { // 连接数据库url
static String url;
// 创建Properties对象
static Properties info = new Properties(); // 驱动程序加载
static {
// 获得属性文件输入流
InputStream input = Connect.class.getResourceAsStream("config.properties"); try {
// 加载属性文件内容到Properties对象
info.load(input);
// 从属性文件中取出url
url = info.getProperty("url");
// 从属性文件中取出driver
String driverClassName = info.getProperty("driver");
Class.forName(driverClassName);
System.out.println("驱动程序加载成功..."); } catch (ClassNotFoundException e) {
System.out.println("驱动程序加载失败...");
} catch (IOException e) {
System.out.println("加载属性文件失败...");
}
}
// 获得数据库连接
public static Connection getConnection() {
// 创建数据库连接
Connection conn = null;
try {
conn = DriverManager.getConnection(url, info);
System.out.println("数据库连接成功!");
} catch (SQLException e) {
System.out.println("数据库连接失败!");
System.out.println(url);
System.out.println(info);
} return conn;
}
}
最后主类如下:
Main.java
package All; import java.io.IOException; import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage; public class Main extends Application{
private Stage primaryStage;
@Override
public void start(Stage primaryStage){
this.primaryStage = primaryStage;
try {
FirstPage();
} catch (IOException e) {
e.printStackTrace();
}
} public void FirstPage() throws IOException {
FXMLLoader loder = new FXMLLoader(Main.class.getResource("FirstPage.fxml"));
AnchorPane root = loder.load();
Scene scene = new Scene(root);
FirstPageController controller = loder.getController();
controller.setMain(this);
primaryStage.setTitle("读者文摘");
primaryStage.setScene(scene);
primaryStage.show(); }
public static void main(String[] args) {
launch(args);
}
}
最后实现的效果如下:
至此,所有功能实现。
总结:
用到了Jsoup的知识爬取网页源代码,
用到了正则表达式进行数据匹配
用到了JDBC进行数据库连接并进行数据查找
用到了javafx内的TableView绑定数据操作
用到了流操作进行数据写入文件
重温了File类文件及文件夹的创建
重温了Alter弹窗