javafx实现读者文摘上的文章预览及下载
功能设计:
1.实现读者文章的预览及下载
(实现了单击预览,双击下载)
2.实现文章查找
(实现了通过文章名查找(关键字)或者文章期数或年份(或者年份加期数))
实现步骤:
首先是数据库设计:
数据库使用一个数据表即可,三个字段,一个是filename用于储存文章名,一个是filepath用于储存文章链接,最后一个是time用于储存文章年份及期数。
create table duzhefile ( filename char(20), filepath char(100), time char(6) )
数据库创建成功后先将数据写入:
Duzhecurl.java
1 package All; 2 3 import java.sql.Connection; 4 import java.sql.PreparedStatement; 5 6 import org.jsoup.Jsoup; 7 import org.jsoup.nodes.Document; 8 import org.jsoup.select.Elements; 9 10 public class Duzhecurl { 11 12 public static void main(String[] args) throws Exception { 13 // 第一步:访问读者首页 14 String url = "https://www.dzwzzz.com/"; 15 Document document = Jsoup.connect(url).get(); 16 17 // 第二步:解析页面 18 Elements datatime = document.select("a"); 19 //获取a标签 20 for(int num=0;num<datatime.size();num++) { 21 //判断文章链接 22 if(datatime.get(num).attr("href").charAt(4)=='_') { 23 //获取a标签中href属性的值 24 String deHref = datatime.get(num).attr("href"); 25 System.out.println("开始获取"+deHref.substring(0, 4)+"年第"+deHref.substring(5,7)+"期"); 26 String time = deHref.substring(0,4)+deHref.substring(5,7); 27 //访问不同期刊页面 28 String DuZhe = "https://www.dzwzzz.com/"+deHref; 29 Document newdocu = Jsoup.connect(DuZhe).get(); 30 //获取a标签 31 Elements a_Elements = newdocu.select("a"); 32 for(int i=0;i<a_Elements.size();i++) { 33 //判断是否是文章链接 34 if (a_Elements.get(i).attr("href").charAt(0)=='d' 35 &&a_Elements.get(i).attr("href").charAt(1)=='u') 36 { 37 //访问文章所在页 38 String purpose = "https://www.dzwzzz.com/"+deHref.substring(0, 8)+a_Elements.get(i).attr("href"); 39 Document finaldocu = Jsoup.connect(purpose).get(); 40 //获取文章标题 41 Elements h1_elements = finaldocu.select("h1"); 42 String title = h1_elements.text(); 43 //获取文章内容 44 Elements p_Elements = finaldocu.select("p"); 45 String Content = p_Elements.text(); 46 String sql = "insert into duzhefile values(?,?,?)"; 47 Connection conn = Connect.getConnection(); 48 PreparedStatement pstmt = conn.prepareStatement(sql); 49 pstmt.setString(1, title); 50 pstmt.setString(2, purpose); 51 pstmt.setString(3, time); 52 pstmt.execute(); 53 System.out.println("文章地址"+purpose); 54 System.out.println(title+" 写入成功!"); 55 } 56 } 57 } 58 } 59 60 } 61 62 }
数据库写入之后开始设计界面:
FirstPage.fxml
1 <?xml version="1.0" encoding="UTF-8"?> 2 3 <?import javafx.scene.paint.*?> 4 <?import javafx.scene.text.*?> 5 <?import java.lang.*?> 6 <?import javafx.scene.control.*?> 7 <?import javafx.scene.layout.*?> 8 <?import javafx.scene.layout.AnchorPane?> 9 10 <AnchorPane prefHeight="361.0" prefWidth="643.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="All.FirstPageController"> 11 <children> 12 <Pane prefHeight="420.0" prefWidth="643.0"> 13 <children> 14 <TextField fx:id="SelectFile" layoutX="27.0" layoutY="24.0" prefHeight="23.0" prefWidth="184.0" promptText="输入文件名搜索" /> 15 <Button fx:id="Select" layoutX="236.0" layoutY="24.0" mnemonicParsing="false" onMouseClicked="#ClickToSelect" text="搜索" /> 16 <TableView fx:id="FileTest" layoutY="74.0" onMouseClicked="#SelectFile" prefHeight="345.0" prefWidth="394.0"> 17 <columns> 18 <TableColumn fx:id="FileName" editable="false" prefWidth="152.0" text="文件名" /> 19 <TableColumn fx:id="FilePath" editable="false" prefWidth="241.0" text="路径" /> 20 </columns> 21 </TableView> 22 <Text fx:id="Preview" layoutX="398.0" layoutY="-170.0" strokeType="OUTSIDE" strokeWidth="0.0" text="文件名" textAlignment="CENTER" wrappingWidth="246.12109375" y="200.0"> 23 <font> 24 <Font size="18.0" /> 25 </font> 26 <fill> 27 <RadialGradient centerX="0.40555555555555556" centerY="0.5" radius="0.5"> 28 <stops> 29 <Stop color="#dd3b09" /> 30 <Stop color="#00dff8" offset="1.0" /> 31 </stops> 32 </RadialGradient> 33 </fill> 34 </Text> 35 <Text layoutX="22.0" layoutY="65.0" strokeType="OUTSIDE" strokeWidth="0.0" text="单击预览文章,双击下载文章" wrappingWidth="194.0" /> 36 <Button fx:id="reset" layoutX="305.0" layoutY="24.0" mnemonicParsing="false" onMouseClicked="#ClickToReset" text="返回" /> 37 <Text fx:id="content" layoutX="394.0" layoutY="62.0" strokeType="OUTSIDE" strokeWidth="0.0" text="内容预览" textAlignment="CENTER" wrappingWidth="253.12109375" /> 38 </children> 39 </Pane> 40 </children> 41 </AnchorPane>
界面设计完成后是这个样的:
生成控制类后插入数据并实现各个方法:
FirstPageController.java
1 package All; 2 3 import java.io.File; 4 import java.io.FileNotFoundException; 5 import java.io.FileOutputStream; 6 import java.io.IOException; 7 import java.io.OutputStreamWriter; 8 import java.io.UnsupportedEncodingException; 9 import java.net.URL; 10 import java.sql.Connection; 11 import java.sql.PreparedStatement; 12 import java.sql.ResultSet; 13 import java.sql.SQLException; 14 import java.util.ResourceBundle; 15 import java.util.Scanner; 16 import java.util.regex.Matcher; 17 import java.util.regex.Pattern; 18 19 import org.jsoup.Jsoup; 20 import org.jsoup.nodes.Document; 21 import org.jsoup.select.Elements; 22 import org.omg.CORBA.PUBLIC_MEMBER; 23 24 import javafx.collections.FXCollections; 25 import javafx.collections.ObservableList; 26 import javafx.fxml.FXML; 27 import javafx.fxml.Initializable; 28 import javafx.scene.control.Alert; 29 import javafx.scene.control.Button; 30 import javafx.scene.control.Label; 31 import javafx.scene.control.TableColumn; 32 import javafx.scene.control.TableView; 33 import javafx.scene.control.TextArea; 34 import javafx.scene.control.TextField; 35 import javafx.scene.control.Alert.AlertType; 36 import javafx.scene.input.MouseEvent; 37 import javafx.scene.text.Text; 38 39 public class FirstPageController implements Initializable { 40 @FXML 41 private TextField SelectFile;//输入框 42 @FXML 43 private Button Select;//查找按钮 44 @FXML 45 private Button reset;//返回按钮 46 @FXML 47 private Text content;//预览内容 48 @FXML 49 private TableView<Data> FileTest;//表格 50 @FXML 51 private TableColumn<Data, String> FileName;//第一列存文章名 52 @FXML 53 private TableColumn<Data, String> FilePath;//第二列存文章链接 54 @FXML 55 56 private Text Preview;//预览标题 57 58 private ObservableList<Data> cellData = FXCollections.observableArrayList(); 59 //用于存储数据Data类型的 60 @FXML 61 public void SelectFile(MouseEvent event) throws IOException { 62 Data data = FileTest.getSelectionModel().getSelectedItem();//获取所选择的行的Data对象 63 String filename = data.getFilename().getValue();//获取选择的Data对象的文章名 64 String url = data.getFilepath().getValue();//获取选择的Data对象的文章地址 65 Document doc;//用来存储爬取到的网页源码 66 String Finacontent;//用来存储文章内容 67 try { 68 doc = Jsoup.connect(url).get();//获取Data对象的文章源码 69 Elements p_Elements = doc.select("p");//查找P标签 70 String Content = p_Elements.text();//保存p标签的内容 71 Preview.setText(filename);//将文章名写入面板 72 content.setText(Content);//将P标签的内容写入预览内容框中 73 Finacontent = Content;//将文章内容传出去 74 } catch (IOException e) { 75 Finacontent = null;//告诉外面内容为空 76 } 77 if (event.getClickCount() == 2 && Finacontent.length() > 50) { 78 //如果点击了两下且文章内容大于50个字符则 79 File file = new File("E:/FileTest/" + filename + ".txt"); 80 // 创建文件输出流 81 OutputStreamWriter fileOutputStream; 82 try { 83 fileOutputStream = new OutputStreamWriter(new FileOutputStream(file, true), "UTF-8"); 84 // 这里的true功能是不覆盖原有内容,所以多次运行程序会造成重复 85 // 将文章内容写入文件 86 fileOutputStream.write(Finacontent.toString()); 87 fileOutputStream.close();//关闭流操作 88 System.out.println(filename + " 下载成功!");//提示成功 89 //弹出弹窗提示下载成功 90 Alert alert = new Alert(AlertType.INFORMATION); 91 alert.setTitle("提示"); 92 alert.setContentText("下载成功!!"); 93 alert.setHeaderText("文章已保存到"+"E:/FileTest目录下"); 94 alert.showAndWait(); 95 } catch (UnsupportedEncodingException e) { 96 e.printStackTrace(); 97 } catch (FileNotFoundException e) { 98 e.printStackTrace(); 99 } 100 101 } 102 } 103 @FXML 104 public void ClickToReset(MouseEvent event) { 105 AddData();//如果点击了返回按钮则重新将数据写入表格 106 } 107 @FXML 108 public void ClickToSelect(MouseEvent event) { 109 String prama = SelectFile.getText();//获取输入框输入输入的内容 110 String strMatch1 = "^\\d{1,6}$";//正则表达式匹配1-6位数字 111 Pattern pattern = Pattern.compile(strMatch1);//使用匹配规则 112 Matcher matcher = pattern.matcher(prama);//进行匹配 113 String regex = "[\\u4E00-\\u9FA5]"; //正则表达式匹配汉字 114 Matcher m = Pattern.compile(regex).matcher(prama);//使用匹配汉字规则进行匹配 115 if (matcher.find()==true) {//如果匹配数字成功则进行数据库查找(对文章日期进行查找) 116 cellData.removeAll(cellData);//清空原有的cellData里的数据 117 Connection conn = Connect.getConnection();//获取数据库连接 118 String sql = "select * from duzhefile where time like ?";//定义数据库查询语句 119 try { 120 // 执行查询语句 121 PreparedStatement prep = conn.prepareStatement(sql); 122 prep.setString(1, '%' + prama.replace(" ", "") + '%');//将输入的内容除去空格后绑定到数据库语句中 123 ResultSet res = prep.executeQuery();//执行数据库查询语句并将结果返回到ResultSet对象中 124 while (res.next()) {//如果结果有下一行 125 String name = res.getString("filename"); 126 String path = res.getString("filepath"); 127 cellData.add(0, new Data(name, path));//将查询到的文章名和文章地址插入cellData中 128 } 129 if (!res.absolute(1)) {//如果查询结果不存在第一行(即为空),则弹窗提示查找结果为空 130 Alert alert = new Alert(AlertType.ERROR); 131 alert.setTitle("提示"); 132 alert.setContentText("请重新输入!"); 133 alert.setHeaderText("查询结果为空!"); 134 alert.showAndWait(); 135 AddData();//将所有数据重新插入(因为查询的时候清空了) 136 } 137 } catch (SQLException e) { 138 e.printStackTrace(); 139 } 140 FileName.setCellValueFactory(cellData -> cellData.getValue().getFilename()); 141 FilePath.setCellValueFactory(cellData -> cellData.getValue().getFilepath()); 142 FileTest.setItems(cellData);//将cellData绑定到表格 143 } 144 else if (m.find()) {//如果匹配汉字成功 145 cellData.removeAll(cellData);//清空原有的数据 146 Connection conn = Connect.getConnection();//获取数据库连接 147 String sql = "select * from duzhefile where filename like ?";//定义数据库查询语句 148 try { 149 // 执行查询语句 150 PreparedStatement prep = conn.prepareStatement(sql); 151 prep.setString(1, '%'+ prama.replace(" ", "")+'%');//去除空格后绑定参数 152 ResultSet res = prep.executeQuery();//执行查询语句并返回结果 153 while (res.next()) {//如果查询结果不为空 154 String name = res.getString("filename"); 155 String path = res.getString("filepath"); 156 cellData.add(0, new Data(name, path));//将查询到的数据写入cellData中 157 158 } 159 if (!res.absolute(1)) {//如果查询结果不存在第一行(为空),则弹窗提示查找结果为空 160 Alert alert = new Alert(AlertType.ERROR); 161 alert.setTitle("提示"); 162 alert.setContentText("请重新输入!"); 163 alert.setHeaderText("查询结果为空!"); 164 alert.showAndWait(); 165 AddData();//将所有数据重新插入(因为查询的时候清空了) 166 } 167 } catch (SQLException e) { 168 e.printStackTrace(); 169 } 170 FileName.setCellValueFactory(cellData -> cellData.getValue().getFilename()); 171 FilePath.setCellValueFactory(cellData -> cellData.getValue().getFilepath()); 172 FileTest.setItems(cellData);//将cellData绑定到表格中 173 } 174 else if(prama.length()==0){//如果输入的内容为空(即没有输入)则弹窗提示重新输入 175 AddData(); 176 Alert alert = new Alert(AlertType.ERROR); 177 alert.setTitle("提示"); 178 alert.setContentText("请重新输入!"); 179 alert.setHeaderText("您输入的信息有误!\n输入文件名、年份、月份均可查找"); 180 alert.showAndWait(); 181 } 182 } 183 184 private Main main; 185 public void setMain(Main main) { 186 this.main = main; 187 } 188 189 @Override 190 public void initialize(URL location, ResourceBundle resources) { 191 AddData();//加载页面时写入数据 192 } 193 194 private void AddData() {//将数据库查询结果写入cellData中,封装成方法方便多次调用 195 Connection conn = Connect.getConnection(); 196 String Strsql = "select * from duzhefile"; 197 try { 198 // 执行查询语句 199 PreparedStatement prep = conn.prepareStatement(Strsql); 200 ResultSet res = prep.executeQuery(); 201 while (res.next()) { 202 String name = res.getString("filename"); 203 String path = res.getString("filepath"); 204 cellData.add(0, new Data(name,path)); 205 206 } 207 } catch (SQLException e) { 208 e.printStackTrace(); 209 } 210 FileName.setCellValueFactory(cellData -> cellData.getValue().getFilename()); 211 FilePath.setCellValueFactory(cellData -> cellData.getValue().getFilepath()); 212 FileTest.setItems(cellData); 213 } 214 215 }
用到的Data类如下:
Data.java
1 package All; 2 3 import javafx.beans.property.SimpleStringProperty; 4 5 public class Data { 6 private SimpleStringProperty filename; 7 private SimpleStringProperty filepath; 8 9 10 public Data(String name,String path) { 11 this.filename = new SimpleStringProperty(name); 12 this.filepath = new SimpleStringProperty(path); 13 } 14 15 16 public SimpleStringProperty getFilename() { 17 return filename; 18 } 19 20 21 public void setFilename(String filename) { 22 this.filename = new SimpleStringProperty(filename); 23 } 24 25 26 public SimpleStringProperty getFilepath() { 27 return filepath; 28 } 29 30 31 public void setFilepath(String filepath1) { 32 this.filepath = new SimpleStringProperty(filepath1); 33 } 34 }
数据库连接类如下:
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弹窗