任务17
创建ServerFrame.java, 实现以下功能:
(1)创建单独的线程接收客户端发送的数据,保存到数据接收队列
(2)创建单独的数据存储线程,每个5秒钟,将队列中的所有数据先临时保存到数据文件,然后再转存到数据
(3)设计界面,从数据库中获取数据,显示再界面上。并在增加“刷新“功能,即每次刷新操作,就是重新获取一次数据。
【任务17.1】ServerFrame主要属性
【任务17.2】读取属性文件
在本类下新增下面方法,获取server.properties文件中的配置属性
private void initConfig(){ //threadPoolSize //serverPort //tmpFile //queueSize //saveInterval }
【任务17.3】编写构造函数
【任务17.4】初始化菜单方法
【任务17.5】表格数据刷新监听
private class miShowListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub //切换显示卡片,参考ClientFrame } } private void flushMatchedLogTable() { //创建DataTableModel对象 //使用JTable的setModel设置DataTableModel对象 } private void flushMatchedTransTable() { //创建DataTableModel对象 //使用JTable的setModel设置DataTableModel对象 }
【任务17.6】数据接收线程类(ServerFrame的内容类)
//接收数据从存储队列 class MatchedDataBaseReceiver implements Runnable { Socket s; public MatchedDataBaseReceiver(Socket s) { this.s = s; } public void run() { try { //接收数据存储到数据队列 //发送响应对象 } catch (Exception e) { e.printStackTrace(); } } } class MatchedDataBaseStore extends Thread{ @Override public void run() { while(true){ try { //数据存储线程代码 ; } catch (Exception e) { e.printStackTrace(); } } } } public boolean storeToDB(File tmpFile){ //从数据文件中读取数据并存储到数据库 //存储成功,返回true //否则返回False }
【任务17.7】构造线程池和存储队列,并启动数据存储线程和网络请求监听
程序设计
package com.qst.dms.ui; import com.qst.dms.entity.*; import com.qst.dms.net.Request; import com.qst.dms.net.Response; import com.qst.dms.service.DmsNetService; import com.qst.dms.service.LogRecService; import com.qst.dms.service.TransportService; import com.qst.dms.util.AppendObjectOutputStream; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; public class ServerFrame extends JFrame{ // 菜单 private JMenuBar menuBar;// 包含多个菜单 private JMenu oper, help; private JMenuItem mCheck, mHelp, mExit, mFlush; // 显示卡片布局组件 private JPanel p;// 数据显示的界面面板,里面采用CardLayout布局,分别显示采集界面和显示界面 private JTabbedPane jShow; private CardLayout card; private JTable logrecTable; private JTable transportTable; // 数据服务对象 private LogRecService logRecService = new LogRecService(); private TransportService transService = new TransportService(); private ServerSocket serverSocket;//服务Socket private Executor threadPool;//线程池 private int threadPoolSize =100;//线程池的大小 private int serverPort = 8000;//服务端口号 private File tmpFile;//临时文件 private long saveInterval =5000;//保存数据的间隔时间 private Thread mdStore;//保存数据的线程对象 private int queueSize = 100;//队列大小 private BlockingQueue<MatchedDataBase> queue;//接收数据的队列 private final static String CONFIG_FILE = "config/server.properties"; private void initConfig(){ } public ServerFrame(){ super("DMS服务器");// 给窗口一个名称,显示左上角 initConfig();//初始化配置参数 ImageIcon icon= new ImageIcon("images\\dns.png"); this.setIconImage(icon.getImage()); //start(); initMenu(); // 数据显示界面的设计 card= new CardLayout(); p = new JPanel(card);// 显示卡片(JPanel或者 JPanel子典) this. getContentPane().add(p, BorderLayout.CENTER);// CardLayout布局的JPanel加到JFrame中 数据表格阻件 // 数据显示界面的设计(卡片2)一 jShow = new JTabbedPane(JTabbedPane.TOP); transportTable = new JTable(); logrecTable = new JTable(); p.add(jShow, "show"); this.flushMatchedLogTable(); this.flushMatchedTransTable(); // 注册监听 mHelp. addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JOptionPane. showMessageDialog(null,"本系统实现数据的采集、过滤分析匹配、保存、发送总显示功能", "帮助" ,JOptionPane.QUESTION_MESSAGE); } }); // 注册监听 mCheck. addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JOptionPane.showMessageDialog(null,"版本:1.0版", "关于", JOptionPane. WARNING_MESSAGE); } }); // 设置窗体大小 this.setSize(600, 400); // 设置窗口在屏幕中央 this.setLocationRelativeTo(null);// 居中 // 设置默认的关闭按钮操作为退出程序 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置窗体初始可见 this.setVisible(true); start(); } private void initMenu(){ menuBar = new JMenuBar(); this.setJMenuBar(menuBar); oper = new JMenu("操作"); help = new JMenu("帮助"); menuBar.add(oper); menuBar.add(help); mFlush = new JMenuItem("刷新"); mExit = new JMenuItem("退出应用"); mExit.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub System. exit(0); } }); mFlush.addActionListener(new miShowListener()); oper.add(mFlush); oper.add(mExit); mCheck = new JMenuItem("关于系统"); mHelp = new JMenuItem("查看帮助"); help.add(mCheck); help.add(mHelp); } private class miShowListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub //切换显示卡片,参考ClientFrame card.show(p,"show"); jShow.removeAll(); ServerFrame.this.flushMatchedLogTable(); ServerFrame.this.flushMatchedTransTable(); } } private void flushMatchedLogTable(){ MatchedTableModel logModel = new MatchedTableModel(logRecService.readLogResult(),1); JTable logTable = new JTable(logModel); jShow.addTab("匹配日志",new JScrollPane(logTable)); } private void flushMatchedTransTable(){ MatchedTableModel logModel = new MatchedTableModel(transService.readTransResult(),2); JTable transTable = new JTable(logModel); jShow.addTab("匹配物流",new JScrollPane(transTable)); } //接收数据从存储队列 class MatchedDataBaseReceiver implements Runnable { Socket s; public MatchedDataBaseReceiver(Socket s) { this.s = s; } public void run() { try { //接收数据存储到数据队列 Request request = DmsNetService.receiveRequest(s); System.out.println("接收请求" + request); List<MatchedDataBase> datas = request.getData(); for(MatchedDataBase data :datas){ queue.put(data); } Date time = new Date(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String formattedDate = dateFormat.format(time); //发送响应对象 Response response = new Response(formattedDate,Response.OK); DmsNetService.sendResponse(s,response); System.out.println("发送响应:" + response); } catch (Exception e) { e.printStackTrace(); } } } class MatchedDataBaseStore extends Thread { @Override public void run() { while (true) { try { // 每5秒钟将队列中的数据保存到临时文件 try { Thread.sleep(saveInterval); } catch (InterruptedException e) { e.printStackTrace(); } tmpFile = new File("tempData.dat"); AppendObjectOutputStream.setFile(tmpFile); File file = AppendObjectOutputStream.getFile(); FileOutputStream fileOut = new FileOutputStream(file, true); AppendObjectOutputStream objOut = new AppendObjectOutputStream(file); while (!queue.isEmpty()) { // 从队列中取出数据并写入临时文件 MatchedDataBase data = queue.poll(); objOut.writeObject(data); } objOut.close(); fileOut.close(); System.out.println("保存成功"); } catch (IOException e) { e.printStackTrace(); } if (tmpFile.exists() && !tmpFile.isDirectory()) { // 如果临时文件存在,则将数据转存到数据库 try { storeToDB(tmpFile); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } tmpFile.delete(); } } } } public boolean storeToDB(File tmpFile) throws IOException, ClassNotFoundException { //从数据文件中读取数据并存储到数据库 List<MatchedLogRec> matchlogs = new ArrayList<>(); List<MatchedTransport> matchtrans = new ArrayList<>(); try { AppendObjectOutputStream.setFile(tmpFile); File file = AppendObjectOutputStream.getFile(); if (!file.exists()) { file.createNewFile(); } FileInputStream fileIn = new FileInputStream(file); // 创建一个ObjectInputStream对象输入流,并连接文件输入流 ObjectInputStream objIn = new ObjectInputStream(fileIn); // 使用异常处理和EOFException异常处理读取结束 try { while (true) { MatchedDataBase data = (MatchedDataBase) objIn.readObject(); // 根据具体对象类型将数据添加到对应的列表中 if (data instanceof MatchedLogRec) { matchlogs.add((MatchedLogRec) data); } else if (data instanceof MatchedTransport) { matchtrans.add((MatchedTransport) data); } } } catch (EOFException e) { // 读取结束,不做任何操作 } objIn.close(); fileIn.close(); System.out.println("————————————————————————————————————————————————————————"); System.out.println(matchlogs); LogRecService.saveLogResult(matchlogs); System.out.println("————————————————————————————————————————————————————————"); System.out.println(matchtrans); TransportService.saveTranResult(matchtrans); System.out.println("信息读取完成\n"); //存储成功,返回true return true; } catch (IOException | ClassNotFoundException e) { System.out.println("读取信息发生异常:" + e.getMessage() + "\n"); } //否则返回False return false; } public void start() { try{ //绑定服务器端口号 serverSocket = new ServerSocket(serverPort); //创建线程池对象 threadPool= Executors.newFixedThreadPool(threadPoolSize); queue = new LinkedBlockingQueue<MatchedDataBase>(queueSize); //创建并启动数据存储线程 mdStore = new MatchedDataBaseStore(); mdStore.start(); //循环监听网络请求 while(true){ //服务器主循环,等待客户的监听 System.out.println("等待客户的连接"); Socket socket = serverSocket.accept(); //有客户连接以后,提交到线程池执行 System.out.println("提交客户处理线程!"); threadPool.execute(new MatchedDataBaseReceiver(socket)); } }catch(Exception e){ e.printStackTrace(); throw new RuntimeException(e); } } public static void main(String[] args) { new ServerFrame(); } }
【任务17.8】测试客户端和服务器段的数据交互功能,截图展示
客户端
服务端