1. 程式人生 > >Java學習不走彎路教程(4.用SQL查詢遠程服務器的文件)

Java學習不走彎路教程(4.用SQL查詢遠程服務器的文件)

通過 abc buffer [] pri tar red 思路 pen

用SQL查詢遠程服務器的文件

一. 前言

在前上一章教程中,介紹了用SQL查詢本地文件。
本章將在上一章的基礎上,進一步擴展程序。

實際的生產環境中,一般查詢的文件都放在遠程的文件或數據服務器上,
下面我將帶大家一步一步實現遠程查詢的程序。

註:
1.本文針對初學Java的同學訓練學習思路,請不要太糾結於細節問題。
2.本文旨在達到拋磚引玉的效果,希望大家擴展本例子,以學到更多知識的精髓。

二. 寫給初學Java的同學
在介紹本章內容之前,首先介紹一下Java的學習方法。
相信大家在看本文的時候已經已經拿到了各種Java學習路徑,大體都是一樣。
我想說的是,不要讓知識的學習成為負擔,Java技術種類繁多,是無論如何也學不完的。
正確的學習方法是興趣驅動,實例驅動。
即通過一個簡單的實例,不斷加入所學知識進行擴展,最終擴展為一個大項目,達到系統學習,學以致用的效果。

三. 步入正題
話不多說,大家自己理解,下面步入正題:

本章系統的流程如下:

【客戶端】
1.連接遠程服務器。
2.向遠程服務器發送查詢SQL。
3.將遠程服務器反饋的查詢結果輸出。

【服務器】
1.在指定端口監聽,等待客戶端連接。
2.有客戶端連接後,讀取客戶端傳來的SQL。
3.調用文件查詢模塊,查詢數據。
4.將查詢的數據反饋給客戶端。
5.轉到步驟1。

工程的結構如下:

技術分享圖片

其中文件查詢模塊復用上一章的代碼,在此不做講解。
我們著重介紹客戶端與服務器通訊的過程。

要想與網絡中的一臺機器的某個程序進行通訊,首先我們需要定位這臺機器的某個程序。
IP地址標識了網絡中唯一的機器,這臺機器的不同的端口則標示了不同的程序。

所以,客戶端要知道連接服務器的IP地址和端口號,來完成於服務器的連接。
而服務器程序之需要在特定的端口監聽,等待客戶端的連接。

服務器連接成功後,即可通過輸入輸出流進行通訊。
通訊協議分為兩種TCP/IP協議和UDP協議:
前者能維持穩定的通訊,確保每一個發送的信息對方都收到。
後者只負責發送信息而不管對方有沒有收到。

比如文字通訊的軟件一般采用TCP/IP協議,因為要確保發送的每條消息對方都能收到。
音頻視頻通訊軟件一般采用UDP協議,因為缺了一點信息也不影響對聲音圖像的識別。

本項目我們采用TCP/IP協議,在Java中用ServerSocket和Socket封裝了TCP/IP協議,所以我們直接拿來用即可,感興趣的同學可以研究一下底層的實現。

四. 服務端程序
我們首先看單個客戶端與服務器的通訊流程,如下圖所示:

技術分享圖片

多個客戶端連接後,如下圖所示:

技術分享圖片

所以,我們首先做一個類ClientThread,用來負責服務器與客戶端通訊的線程,代碼如下:

 1 /**
 2  * 
 3  * @author http://www.java123.vip
 4  *
 5  */
 6 public class ClientThread implements Runnable{
 7 
 8     private Socket socket;
 9     private BufferedReader br;
10     private PrintWriter pw;
11     
12     public ClientThread(Socket socket) {
13         try {
14             
15             // 創建輸入輸出流
16             InputStream is = socket.getInputStream();
17             InputStreamReader isr = new InputStreamReader(is);
18             br = new BufferedReader(isr);
19             
20             OutputStream os = socket.getOutputStream();
21             OutputStreamWriter osw = new OutputStreamWriter(os);
22             pw = new PrintWriter(osw,true);
23             
24         } catch (IOException e) {
25             e.printStackTrace();
26         }
27     }
28     
29     public void run() {
30         
31         GetFile gf = new GetFile("c:/temp/");
32         
33         while(true) {
34             try {
35                 
36                 // 讀取客戶端的一行信息
37                 String message = br.readLine();
38                 System.out.println("get message:"+message);
39                 
40                 // 用冒號(:)來分隔信息的頭與內容
41                 String header = message.split(":")[0];
42                 String body = message.substring(message.indexOf(":")+1);
43                 
44                 // 查詢請求
45                 if(header.equals("query")) {
46                     String result = gf.queryFile(body);
47                     pw.println(result);
48                     
49                 // 斷開連接請求
50                 }else if(header.equals("bye")) {
51                     if(socket != null) {
52                         socket.close();
53                     }
54                     break;
55                 }
56                 
57             } catch(IOException e) {
58                 e.printStackTrace();
59             } catch (Exception e) {
60                 e.printStackTrace();
61             }
62         }
63     }
64     
65 }

服務器實現代碼如下:

 1 /**
 2  * 
 3  * @author http://www.java123.vip
 4  *
 5  */
 6 public class FileViewServer {
 7 
 8     private int port;
 9     
10     public FileViewServer(int port) {
11         this.port = port;
12     }
13     
14     /**
15      * 啟動服務器
16      */
17     public void startServer() {
18         try {
19             
20             ServerSocket ss = new ServerSocket(port);
21             System.out.println("listening at port:"+port);
22             
23             while(true) {
24                 Socket s = ss.accept();
25                 System.out.println("get connection:"+s.getInetAddress().toString());
26                 
27                 // 得到連接後,啟動新線程負責通訊
28                 ClientThread clientThread = new ClientThread(s);
29                 new Thread(clientThread).start();
30             }
31             
32         } catch (IOException e) {
33             e.printStackTrace();
34         }
35     }
36     
37     public static void main(String[] args) {
38         FileViewServer fvs = new FileViewServer(8000);
39         fvs.startServer();
40     }
41 }

五. 客戶端程序
我們需要做三個方法:
?連接服務器方法
?斷開服務器方法
?查詢遠程文件方法

代碼如下:
連接服務器方法

 1 private Socket socket;
 2     private BufferedReader br;
 3     private PrintWriter pw;
 4     
 5     /**
 6      * 連接遠程服務器
 7      * 
 8      * @param ip
 9      * @param port
10      */
11     public void connect(String ip, int port) {
12         try {
13             
14             // 連接服務器
15             socket = new Socket(ip, port);
16             
17             // 創建輸入輸出流
18             InputStream is = socket.getInputStream();
19             InputStreamReader isr = new InputStreamReader(is);
20             br = new BufferedReader(isr);
21             
22             OutputStream os = socket.getOutputStream();
23             OutputStreamWriter osw = new OutputStreamWriter(os);
24             pw = new PrintWriter(osw,true);
25             
26         } catch (IOException e) {
27             e.printStackTrace();
28         }
29     }

斷開服務器方法

 1 /**
 2      * 斷開連接
 3      */
 4     public void disConnect() {
 5         try {
 6             
 7             // 發送斷開連接請求
 8             pw.println("bye:bye");
 9             socket.close();
10         } catch (IOException e) {
11             e.printStackTrace();
12         }
13     }

查詢遠程文件方法

 1 /**
 2      * 查詢
 3      * 
 4      * @param sql
 5      * @return
 6      */
 7     public String query(String sql) {
 8         
 9         StringBuffer result = new StringBuffer("");
10         
11         try {
12             
13             // 發送查詢請求
14             pw.println("query:"+sql);
15             
16             while(true) {
17                 
18                 // 讀取查詢結果的每一行
19                 String queryResultLine = br.readLine();
20                 
21                 // 讀到空字符串表示結果讀取完畢
22                 if("".equals(queryResultLine)) {
23                     break;
24                     
25                 // 否則,把讀到的內容存起來
26                 }else {
27                     result.append(queryResultLine);
28                     result.append("\n");
29                 }
30             }
31         } catch (IOException e) {
32             e.printStackTrace();
33         }
34         
35         // 返回查詢結果
36         return result.toString();
37     }

六. 測試
最後我們來測試這個程序,測試代碼如下:

 1 /**
 2      * 測試
 3      * @param args
 4      */
 5     public static void main(String[] args) {
 6         FileViewClient fvc = new FileViewClient();
 7         fvc.connect("127.0.0.1",8000);
 8         
 9         String sql1 = "select * from abc.csv ";
10         String sql2 = "select id from abc.csv ";
11         String sql3 = "select id,username from abc.csv where id=2 ";
12         String sql4 = "select id,username from abc.csv where username=abc and password=aaa ";
13         String sql5 = "select id,username from abc.csv where username=abc and password=bbb ";
14         
15         System.out.println("Execute:"+sql1);
16         System.out.println(fvc.query(sql1));
17         
18         System.out.println("Execute:"+sql2);
19         System.out.println(fvc.query(sql2));
20         
21         System.out.println("Execute:"+sql3);
22         System.out.println(fvc.query(sql3));
23         
24         System.out.println("Execute:"+sql4);
25         System.out.println(fvc.query(sql4));
26         
27         System.out.println("Execute:"+sql5);
28         System.out.println(fvc.query(sql5));
29         
30         fvc.disConnect();
31     }

首先啟動服務器,輸出如下:

listening at port:8000

啟動客戶端測試程序:
客戶端輸出如下:

Execute:select * from abc.csv 
1,abc,aaa
2,def,bbb
3,xyz,ccc

Execute:select id from abc.csv 
1
2
3

Execute:select id,username from abc.csv where id=2 
2,def

Execute:select id,username from abc.csv where username=abc and password=aaa 
1,abc

Execute:select id,username from abc.csv where username=abc and password=bbb

服務器輸出如下:

listening at port:8000
get connection:/127.0.0.1
get message:query:select * from abc.csv 
get message:query:select id from abc.csv 
get message:query:select id,username from abc.csv where id=2 
get message:query:select id,username from abc.csv where username=abc and password=aaa 
get message:query:select id,username from abc.csv where username=abc and password=bbb 
get message:bye:bye

完整代碼請在這裏下載

如有問題,大家來我的網站進行提問。
https://www.java123.vip/qa

七. 後續
本例為通過簡單的SQL語句查詢遠程存在的文件,大家可以擴展此程序,比如用線程池來管理線程,對於異常信息的處理等。
後續章節我將在此程序的基礎上,其支持JDBC接口,然後換成數據庫,並且一步一步實現ORM,Service,HTTP查詢等功能。

版權聲明:本教程版權歸java123.vip所有,禁止任何形式的轉載與引用。

Java學習不走彎路教程(4.用SQL查詢遠程服務器的文件)