1.項目所用到jar包:
woss-interface.jar:規范項目的各個模塊
各個接口的功能在我的上一篇文章中有介紹,感興趣的去找一下。
demo4j-1.6.1.jar:解析xml文件
log4j-1.2.15:提供日志記錄
ojdbc14.jar:jdbc的jar包
3.流程圖
畫的不好別見怪,嘿嘿。
2.項目的各個模塊的具體實現
2.1客戶端采集模塊
假如我們需要采集的數據的結構如下:
#briup1660|037:wKgB1660A|7|1239110900|44.211.221.247
#briup4418|037:wKgB4418A|7|1239138480|251.196.223.191
#|037:wKgB1660A|8|1239203860|44.211.221.247
問題:
1.怎么獲得文件路徑
2.了解每一行數據的意思
2.1 數據中使用的是|進行分割
2.2 數據一共分為倆種
遵循7上8下的規則
包含 7 的數據 表示用戶上線
包含 8 的數據 表示用戶下線
2.3 包含7的數據
數據分為五個部分
第一部分:登錄的用戶名字(去掉#號)
第二部分:NAS服務器的名稱
第三部分:一定是7
第四部分:上線的時間(單位是秒)
第五部分:登錄時的IP
2.4 包含8的數據
數據分為五個部分
第一部分:一定是個符合 #
第二部分:NAS服務器的名稱
第三部分:一定是8
第四部分:下線的時間(單位是秒)
第五部分:登錄時的IP
3.如何讀寫數據
4.如何封裝數據
5.采集的數據分倆種情況
第一種情況數據:
用戶上線了同時也下線了
第二種情況數據:
用戶上線了但是還沒有下線
6.倆種數據情況怎么處理
上面描述的第一種數據:
封裝好對象之后就准備傳給服務器端
上面描述的第二種數據:
進行數據的備份,在一下次采集中,需要把這個備份的數據重新讀出來使用,因為用戶可能在一下次采集中下線了
7.第二次讀取數據的時候,如何從第一次讀完數據的下一行開始讀
可以記錄一下本次總共讀取了多少個字節,下一次可以直接跳過這么多個字節,接着讀就可以了
8.在讀取過程中或者處理過程中,如果出現了異常,需要把數據進行備份
9.注意重要信息的日志記錄
以下是實現代碼:
1 package com.briup.woss.client; 2 3 import java.io.BufferedReader; 4 import java.io.FileInputStream; 5 import java.io.InputStream; 6 import java.io.InputStreamReader; 7 import java.sql.Timestamp; 8 import java.util.ArrayList; 9 import java.util.Collection; 10 import java.util.HashMap; 11 import java.util.List; 12 import java.util.Map; 13 import java.util.Properties; 14 15 import org.junit.Test; 16 17 import com.briup.util.BIDR; 18 import com.briup.util.Configuration; 19 import com.briup.woss.ConfigurationAWare; 20 21 public class GatherImpl implements Gather{ 22 23 private static String file; 24 private InputStream fis; 25 private InputStreamReader isr; 26 private BufferedReader br; 27 public Map<String, BIDR> map1; 28 private List<BIDR> date; 29 30 // 讀取數據/解析/封裝成BIDR對象/對象存放在集合 31 // #briup4418|037:wKgB4418A|7|1239138480|251.196.223.191 32 // #|037:wKgB1660A|8|1239203860|44.211.221.247 33 @Override 34 public void init(Properties p) { 35 file = p.getProperty("filePath");//將配置文件注入到該模塊中 36 } 37 38 //接收數據,將數據進行處理,並保存到collection集合中,並返回。 39 @Override 40 @Test 41 public Collection<BIDR> gather() throws Exception { 42 // 獲取文件內容 43 BIDR bidr = null; 44 map1 = new HashMap<String, BIDR>(); 45 date = new ArrayList<>(); 46 fis = new FileInputStream(file); 47 isr = new InputStreamReader(fis); 48 br = new BufferedReader(isr); 49 String str = null; 50 while ((str = br.readLine()) != null) { 51 bidr = new BIDR(); 52 //通過|分割字符串,由於|號比較特殊,要加[]號 53 String[] arrStr = str.split("[|]"); 54 if ("7".equals(arrStr[2])) { 55 bidr.setAAA_login_name(arrStr[0]); 56 bidr.setNAS_ip(arrStr[1]); 57 //由於bidr中時間是Timestamp類型的所以這里轉換的時候要注意下 58 bidr.setLogin_date(new Timestamp( 59 Long.parseLong(arrStr[3]) * 1000)); 60 bidr.setLogin_ip(arrStr[4]); 61 map1.put(arrStr[4], bidr); 62 } else { 63 64 BIDR b = map1.remove(arrStr[4]); 65 b.setLogin_ip(arrStr[1]); 66 b.setLogout_date(new Timestamp(Long.parseLong(arrStr[3]) * 1000)); 67 long l = (b.getLogout_date().getTime() - b.getLogin_date() 68 .getTime()); 69 b.setTime_deration((int) l); 70 date.add(b); 71 } 72 } 73 74 return date; 75 } 76 77 }
2.2備份模塊
負責備份一些沒有處理完的數據
需要實現的方法:
void store(String filePath, Object obj,
boolean append)
Object load(String filePath, boolean del)
問題:
1.如何獲得備份文件存放的目錄信息
2.如何把數據備份到文件
3.如何讀取文件中的備份數據
4.如何實現備份數據時候的追加或者是覆蓋
5.如何控制讀取備份數據后文件是否需要刪除
以下是實現代碼:
package com.briup.woss.util; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.Properties; import com.briup.util.BackUP; public class BackUpImpl implements BackUP{ static String fName; @Override public void init(Properties p) { fName = p.getProperty("bakFilePath"); } //通過對象輸出流將需要備份的數據進行備份 @Override public void store(String fileName, Object obj, boolean paramBoolean) throws Exception { File file = new File(fName+fileName); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file,paramBoolean)); out.writeObject(obj); } @Override public Object load(String fileName, boolean paramBoolean) throws Exception { File file = new File(fName+fileName); if(!file.exists()){ return null; } ObjectInputStream in = new ObjectInputStream(new FileInputStream(file)); Object object = in.readObject(); return object; } }
2.3網絡模塊
負責把采集好的數據發給服務器
需要實現的方法:
void send(Collection<BIDR> c)
問題:
1.如何得到連接服務器的相關信息
2.如何得到采集好的數據
3.如何把數據發送給服務器
4.如果發送數據失敗怎么處理
5.注意重要信息的日志記錄
以下是實現代碼
package com.briup.woss.client; import java.io.ObjectOutputStream; import java.net.Socket; import java.util.Collection; import java.util.Properties; import com.briup.util.BIDR; public class ClientImpl implements Client{ static String ip; static int port; @Override public void init(Properties p) { //通過依賴注入的方式將配置信息注入到該模塊中 ip = p.getProperty("ip"); port = Integer.parseInt(p.getProperty("port")); } //通過socket以及對象流將數據傳輸到客戶端 @Override public void send(Collection<BIDR> c) throws Exception { Socket s = new Socket(ip, port); ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream()); oos.writeObject(c); } }
2.4服務器端網絡模塊
負責接收客戶端傳過來的數據
需要實現的方法:
Collection<BIDR> revicer();
void shutdown();
問題:
1.如何獲得服務器啟動時候用的相關信息
2.如何關閉關閉服務器
3.如何接收客戶端傳過來的信息
4.如何處理客戶端並發的問題
5.接收到數據之后一下步怎么做
6.數據的接收或者處理過程備份的問題
7.注意重要信息的日志記錄
以下是實現代碼
package com.briup.woss.server; import java.io.ObjectInputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.Collection; import java.util.Properties; import com.briup.util.BIDR; import com.briup.util.Configuration; import com.briup.woss.ConfigurationAWare; public class ServerImpl implements Server,ConfigurationAWare{ static int port; private ObjectInputStream ois; private Object o; private static DBStoreImpl dbStore; @Override public void init(Properties p) { port = Integer.parseInt(p.getProperty("server_port")); } //這里通過多線程的方式接受數據,通過調用入庫模塊進行入庫 //因為服務器端可能只有一個,但是客戶端應該有多個,同時接收來自多個客戶端發來的信息時便需要實現多線程 @Override public Collection<BIDR> revicer() throws Exception { new Thread(new Runnable() { @Override public void run() { ServerSocket ss; try { ss = new ServerSocket(port); Socket s = ss.accept(); ois = new ObjectInputStream(s.getInputStream()); Collection<BIDR> c = (Collection)ois.readObject(); dbStore.saveToDB(c); } catch (Exception e) { e.printStackTrace(); } } }).start(); return null; } @Override public void shutdown() { } @Override public void setConfiguration(Configuration p) { try { dbStore = (DBStoreImpl) p.getDBStore(); } catch (Exception e) { e.printStackTrace(); } } }
2.5服務器端入庫模塊
負責接收到的數據插入到數據庫中
需要實現的方法:
void saveToDB(Collection<BIDR> c)
問題:
1.如何獲得連接數據庫的相關信息
2.怎么把數據插入到數據庫中
3.插入數據時候的效率問題
4.什么樣的數據對應哪一種表
package com.briup.woss.server; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.Timestamp; import java.util.Collection; import java.util.Properties; import javax.swing.JTextArea; import com.briup.util.BIDR; import com.briup.woss.GUI.DisData; import com.briup.woss.GUI.MyAppender; public class DBStoreImpl implements DBStore{ private static String driver; private static String url; private static String user; private static String password; private String aaa_login_name; private String login_ip; private java.sql.Date login_date; private java.sql.Date logout_date; private String nas_ip; private String time_duration; private Connection conn; private int i_date; private Properties p; public DBStoreImpl() { p = new Properties(); init(p); } @Override public void init(Properties p) { driver = p.getProperty("driver"); url = p.getProperty("url"); user = p.getProperty("username"); password = p.getProperty("password"); } @Override public void saveToDB(Collection<BIDR> p) throws Exception { //通過jdbc與數據庫建立鏈接 Class.forName(driver); conn = DriverManager.getConnection(url, user, password); for (BIDR bidr : p) { Timestamp login_d = bidr.getLogin_date(); String s_date = login_d.toString(); String[] str1 = s_date.split(" "); String[] str2 = str1[0].split("-"); i_date = Integer.parseInt(str2[2]); aaa_login_name = bidr.getAAA_login_name(); login_ip = bidr.getLogin_ip(); login_date = new java.sql.Date(bidr.getLogin_date().getTime()); logout_date = new java.sql.Date(bidr.getLogout_date().getTime()); String sql = "insert into t_detail_"+i_date+"(aaa_login_name,login_ip,login_date,logout_date,nas_ip,time_duration) " + "values(?,?,?,?,?,?)"; //通過PreparedStatement將信息存儲到數據庫中 PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, aaa_login_name); ps.setString(2, login_ip); ps.setDate(3, login_date); ps.setDate(4, logout_date); ps.setString(5, nas_ip); ps.setString(6, time_duration); ps.execute(); //將數據傳送到DisData這個類中,此類是用來將入庫信息顯示在GUI中的。 new DisData(p); } } }
2.6公共配置模塊
該模塊相當於一個工廠
負責
1.產生各個模塊對象
2.讀取各個模塊所需的信息,並且把信息注入到每個模塊中
注:這時候需要每個模塊都實現接口WossModule
3.如果某個模塊A中需要用到配置模塊,那么就需要把自己(因為自己就是配置模塊)注入到這個模塊A中
注:這時候需要模塊A實現接口ConfigurationAWare
需要實現的方法:
Logger getLogger();
BackUP getBackup();
Gather getGather();
Client getClient();
Server getServer();
DBStore getDBStore();
問題:
1.怎么獲得每個模塊的相關信息
2.如何創建每個模塊的對象
3.怎么把每個模塊需要的數據注入到模塊中
4.什么時候可以把自己(配置模塊本身)注入到需要的模塊中
以下是實現代碼:
package com.briup.woss.util; import java.util.HashMap; import java.util.Map; import java.util.Properties; import com.briup.util.BackUP; import com.briup.util.Configuration; import com.briup.util.Logger; import com.briup.woss.ConfigurationAWare; import com.briup.woss.WossModule; import com.briup.woss.client.Client; import com.briup.woss.client.Gather; import com.briup.woss.server.DBStore; import com.briup.woss.server.Server; public class ConfigurationImpl implements Configuration{ Map<String, Object> objMap; Properties p1; Properties p2; public ConfigurationImpl() { this("src/conf/conf.xml"); } public ConfigurationImpl(String filePath) { init(filePath); } public void init(String filePath){ objMap = new HashMap<String, Object>(); ParseXML p = new ParseXML(); Map<String, Properties> map = p.parseXML(filePath); p1 = map.get("p1"); p2 = map.get("p2"); for(Object obj:p1.values()){ try { Object instance = Class.forName((String)obj).newInstance(); objMap.put((String)obj, instance); } catch (Exception e) { e.printStackTrace(); } } for(Object obj:objMap.values()){ if(obj instanceof WossModule){ ((WossModule)obj).init(p2); } if(obj instanceof ConfigurationAWare){ ((ConfigurationAWare) obj).setConfiguration(this); } } } @Override public Logger getLogger() throws Exception { return (Logger) objMap.get("com.briup.woss.util.LoggerImpl"); } @Override public BackUP getBackup() throws Exception { return (BackUP) objMap.get("com.briup.woss.util.BackUpImpl"); } @Override public Gather getGather() throws Exception { return (Gather) objMap.get("com.briup.woss.client.GatherImpl"); } @Override public Client getClient() throws Exception { return (Client) objMap.get("com.briup.woss.client.ClientImpl"); } @Override public Server getServer() throws Exception { return (Server) objMap.get("com.briup.woss.server.ServerImpl"); } @Override public DBStore getDBStore() throws Exception { return (DBStore) objMap.get("com.briup.woss.server.DBStoreImpl"); } }
2.7公共日志模塊
負責記錄系統運行過程的一些重要信息
需要實現的方法:
void debug(String msg);
void info(String msg);
void warn(String msg);
void error(String msg);
void fatal(String msg);
問題:
1.怎么來實現日記記錄
2.了解日志級別
3.怎么設置日志的級別
4.怎么獲得日志對象
5.怎么控制日志的格式
6.怎么控制日志輸出到控制台和指定文件中(重難點)
一下是實現代碼:
package com.briup.woss.util; import java.util.Properties; import org.apache.log4j.PropertyConfigurator; import com.briup.util.Logger; public class LoggerImpl implements Logger{ private static org.apache.log4j.Logger logger; @Override public void init(Properties p) { String configFilePath = p.getProperty("configFilePath"); PropertyConfigurator.configure(configFilePath); logger = org.apache.log4j.Logger.getRootLogger(); } @Override public void debug(String paramString) { logger.debug(paramString); } @Override public void info(String paramString) { logger.info(paramString); } @Override public void warn(String paramString) { logger.warn(paramString); } @Override public void error(String paramString) { logger.error(paramString); } @Override public void fatal(String paramString) { logger.fatal(paramString); } }
3一些輔助類,以及GUI頁面實現
解析XML文件類
目的:所有的jdbc配置信息,以及woss-interface.jar中各個接口的信息都配置在xml文件中,所以要通過sax解析將配置信息獲取到。
然后存入map集合中,在公共配置模塊獲取到。
package com.briup.woss.util; import java.io.ByteArrayInputStream; import java.io.FileInputStream; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @SuppressWarnings("all") public class ParseXML { Map<String, Properties> map; Properties p1; Properties p2; public Map<String, Properties> parseXML(String filePath){ try { map = new HashMap<String, Properties>(); p1 = new Properties(); p2 = new Properties(); SAXReader reader = new SAXReader(); reader.setEntityResolver(new EntityResolver() { @Override public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { byte[] bytes = "".getBytes(); return new InputSource(new ByteArrayInputStream(bytes)); } }); Document document = reader.read(new FileInputStream(filePath)); Element rootElement = document.getRootElement(); List<Element> elements = rootElement.elements(); for(Element e:elements){ String name = e.getName(); String className = e.attributeValue("class"); List<Element> elements2 = e.elements(); p1.setProperty(name, className); for(Element e1:elements2){ String tagName = e1.getName(); String name1 = e1.getText(); p2.setProperty(tagName, name1); } map.put("p1",p1); map.put("p2",p2); // System.out.println(className); } } catch (Exception e) { e.printStackTrace(); } return map; } }
GUI類
目的:通過圖形界面化的方式將功能顯示在界面上,有利於用戶交互。
實現代碼:
package com.briup.woss.GUI; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import org.apache.log4j.Appender; import org.junit.Test; import com.briup.woss.server.DBStoreImpl; import com.briup.woss.util.ConfigurationImpl; @SuppressWarnings("all") public class GUI extends JFrame implements ActionListener{ private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getRootLogger(); private JPanel northJPanel; private JPanel centerJPanel; private JButton start_client; private JButton start_server; private JButton dis_data; private static JTextArea area; private static JScrollPane scrollPane; private static Appender appender; public static void main(String[] args) { new GUI(); } public GUI() { try { this.setSize(600, 400); this.setBackground(Color.BLACK); this.setLocationRelativeTo(null); this.setResizable(false); init(); initLog1(); this.setDefaultCloseOperation(EXIT_ON_CLOSE); this.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } @Test public void init(){ Container container = getContentPane(); container.setLayout(new BorderLayout()); //設置北面的JPanel northJPanel = new JPanel(); northJPanel.setBackground(Color.white); start_client = new JButton("啟動客戶端"); start_server = new JButton("啟動服務器"); dis_data = new JButton("顯示數據"); dis_data.setBackground(Color.white); start_client.setBackground(Color.white); start_server.setBackground(Color.white); northJPanel.add(start_client); northJPanel.add(start_server); northJPanel.add(dis_data); //設置中間的JPanel centerJPanel = new JPanel(); centerJPanel.setBackground(Color.white); centerJPanel.setLayout(new BorderLayout()); area = new JTextArea(); area.setLineWrap(true); area.setBackground(Color.white); area.setEditable(false); scrollPane = new JScrollPane(area); centerJPanel.add(scrollPane,BorderLayout.CENTER); container.add(northJPanel,BorderLayout.NORTH); container.add(centerJPanel,BorderLayout.CENTER); start_client.addActionListener(this); start_server.addActionListener(this); dis_data.addActionListener(this); } public static void initLog1(){ try { appender = logger.getAppender("textArea"); ((MyAppender)appender).setArea(area); ((MyAppender)appender).setPane(scrollPane); } catch (Exception e) { e.printStackTrace(); } } @Override public void actionPerformed(ActionEvent e) { Object obj = e.getSource(); if(obj == start_client){ new Thread(new ClientThread()).start(); logger.debug("客戶端啟動成功"); } if(obj == start_server){ new Thread(new ServerThread()).start(); logger.info("服務器啟動成功"); } if(obj == dis_data){ DisData d = new DisData(); d.setArea(area); d.dis_Data(); } } }
以上則是這次電信采集項目的大部分代碼,還有的沒貼出來,因為我要趕着吃飯了。有興趣的朋友們可以看一看,共同進步,共勉,加油!