JAVA SE 實戰篇 C6 基於CSFramework的聊天室 (上) 伺服器APP

雫#1999發表於2020-12-19

P1 伺服器監視器 ChatRoomServerMonitor

在完成CSFramework後,現在基於CSFramework來完成一個聊天室,這個聊天室分為兩部分,Server和Client,這裡的Server和Client與CSFramework內的不同,這裡的Server和Client是APP,是真正提供給使用者使用的應用程式,一個良好的應用程式,應該有友善的介面且能夠偵聽使用者的操作並作出反饋,程式要足夠健壯,設計時,要考慮周全

最終效果:

在這裡插入圖片描述
在這裡插入圖片描述

1 監視視窗的初始化

現在先完成伺服器監視視窗的初始化:

	/**
	 * 伺服器監視視窗視窗初始化
	 */
	@Override
	public void init() {
		
		this.jfrmView = new JFrame("雫-聊天室-伺服器-監視器");
		this.jfrmView.setMinimumSize(new Dimension(viewWidth, viewHeight));
		//設定主視窗可以被最大化
		this.jfrmView.setExtendedState(JFrame.MAXIMIZED_BOTH);
		this.jfrmView.setLayout(new BorderLayout());
		//設定預設居中
		this.jfrmView.setLocationRelativeTo(null);
		//設定點選右上關閉鍵無操作
		this.jfrmView.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		
		//設定主標籤
		JLabel jlblTopic = new JLabel("雫-聊天室-伺服器-監視器");
		jlblTopic.setFont(topicFont);
		jlblTopic.setForeground(topicColor);
		this.jfrmView.add(jlblTopic, BorderLayout.NORTH);
		
		//設定系統資訊滑動框
		this.jtatSystemMessage = new JTextArea();
		this.jtatSystemMessage.setFont(normalFont);
		JScrollPane jscpSystemMessage = new JScrollPane(this.jtatSystemMessage);
		this.jfrmView.add(jscpSystemMessage, BorderLayout.CENTER);
		
		//設定系統資訊滑動框標題
		TitledBorder ttbdSystemMessage = new TitledBorder("系統訊息");
		ttbdSystemMessage.setTitleFont(normalFont);
		ttbdSystemMessage.setTitleColor(topicColor);
		ttbdSystemMessage.setTitleJustification(TitledBorder.CENTER);
		ttbdSystemMessage.setTitlePosition(TitledBorder.TOP);
		jscpSystemMessage.setBorder(ttbdSystemMessage);
		
		//設定命令輸入框
		JPanel jpnlFooter = new JPanel(new FlowLayout());
		this.jfrmView.add(jpnlFooter, BorderLayout.SOUTH);
		JLabel jlblCommand = new JLabel("命令");
		jlblCommand.setFont(normalFont);
		jpnlFooter.add(jlblCommand);
		this.jtxtCommand = new JTextField(30);
		this.jtxtCommand.setFont(normalFont);
		jpnlFooter.add(this.jtxtCommand);
		
	}

2 提供給使用者選擇的配置檔案

在APP中,一些資料應該可以被使用者修改,如連線的埠號,最大連線數量等,這些資料應該寫到properties檔案中,在伺服器啟動前先解析properties檔案後,才能啟動伺服器,使用者可以修改properties檔案來更改伺服器的一些屬性,或者為使用者提供合適的setter和getter方法:

properties檔案:

在這裡插入圖片描述

解析properties檔案:

	/**
	 * 開啟介面時解析配置檔案
	 * 獲取埠號和是否要自動開啟伺服器的資訊
	 * 以及最大連線數
	 */ 
	public void initChatServer(String configPath) throws IOException, PropertiesNotFound {
		
		PropertiesParser.loadProperties(configPath);
		
		String strPort = PropertiesParser.getValue("port");
		if(strPort != null && strPort.length() > 0) {
			int port = Integer.valueOf(strPort);
			setPort(port);
		}
		
		
		String strAutoStartUp = PropertiesParser.getValue("auto_startup");
		if(strAutoStartUp != null && strAutoStartUp.length() > 0) {
			boolean autoStartUp = Boolean.valueOf(strAutoStartUp);
			this.autoStartUp = autoStartUp;
		}
		
		String strMaxClientCount = PropertiesParser.getValue("max_client_count");
		if(strMaxClientCount != null && strMaxClientCount.length() > 0) {
			this.setMaxChatCount(Integer.valueOf(strMaxClientCount));
		}
		
	}

3 偵聽使用者的操作

接下來需要完成對使用者操作的偵聽,完成互動式程式設計,伺服器的管理員可以通過輸入各種命令來進行對伺服器的開機,關機等操作:

	/**
	 * 偵聽互動操作
	 */
	@Override
	public void dealAction() {
		
		//新增視窗偵聽器,實現關閉主視窗操作
		this.jfrmView.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				server.shutDown();
				closeMonitor();
			}
		});
		
		//新增命令文字框偵聽器,實現命令的處理,回車後處理
		this.jtxtCommand.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				//獲取文字框中的命令
				String command = jtxtCommand.getText().trim();
				if(command.length() <= 0) {
					ViewTool.showWarnning(jfrmView, "命令不能為空");
				} else {
					dealCommand(command);
				}
				jtxtCommand.setText("");
			}
		});	
	}
	
	
	
	/**
	 * 處理輸入的命令
	 */
	private void dealCommand(String command) {
		if(command.equalsIgnoreCase("startup")
				|| command.equalsIgnoreCase("s")) {
			this.server.startUp();
		} else if(command.equalsIgnoreCase("shutdown")
				|| command.equalsIgnoreCase("d")) {
			this.server.shutDown();
		} else if(command.equalsIgnoreCase("forcedown")
				|| command.equalsIgnoreCase("f")) {
			this.server.forceDown();; 
		} else if(command.equalsIgnoreCase("exit")
				|| command.equalsIgnoreCase("x")) {
			closeMonitor();
		}
		
	}

4 將伺服器監視器作為Listener接收CSFramework傳來的資訊

在CSFramework會話層內提到了Speaker和Listener,即將框架內需要輸出資訊的Server作為Speaker,將伺服器APP作為Listener,框架向APP傳遞訊息,實現了ISpeaker介面的就是Speaker,實現了IListener介面的就是Listener,且需要實現介面中的方法,這裡需要讓伺服器監視器實現IListener,將框架傳來的系統資訊顯示在伺服器監視器上:

	/**
	 * 初始化server,將本類加入聽眾列表
	 * 設定開啟視窗自動啟動為false
	 */
	public ChatRoomServerMonitor() {
		this.server = new Server();
		setPort(DEFAULT_PORT);
		//將本類作為server的聽眾
		this.server.addListener(this);
		this.autoStartUp = false;
	}

	/**
	 * 本類作為Server的聽眾應該處理來自Server的訊息
	 * 將server傳來的訊息顯示到系統資訊滑動框
	 */
	@Override
	public void readMessage(String message) {
		this.jtatSystemMessage.append(message + "\n");
		this.jtatSystemMessage.setCaretPosition(this.jtatSystemMessage.getText().length());
	}

5 彈窗提示 ViewTool

對於APP還應該對使用者一些操作做出提示,如在伺服器APP上,當伺服器管理員需要對伺服器關機時,但此時有客戶端線上,此時就應該彈出視窗提示:

在這裡插入圖片描述

package com.my.util;

import javax.swing.JFrame;
import javax.swing.JOptionPane;

public class ViewTool {
	
	public static String TITLE_MESSAGE = "來自雫的提示";
	
	public ViewTool() {
	}
	
	public static void showWarnning(JFrame parentView, String message) {
		JOptionPane.showMessageDialog(parentView, message, TITLE_MESSAGE, JOptionPane.WARNING_MESSAGE);
	}
	
	public static void showError(JFrame parentView, String message) {
		JOptionPane.showMessageDialog(parentView, message, TITLE_MESSAGE, JOptionPane.ERROR_MESSAGE);
	}
	
	public static void showInformation(JFrame parentView, String message) {
		JOptionPane.showMessageDialog(parentView, message, TITLE_MESSAGE, JOptionPane.INFORMATION_MESSAGE);
	}
	
	public static int getUserChoice(JFrame parentView, String message) {
		return JOptionPane.showConfirmDialog(parentView, message, TITLE_MESSAGE, JOptionPane.YES_NO_OPTION);
	}

}

P2 啟動伺服器

1 啟動類 ChatRoomServerMain

至此就完成了基於CSFramework的伺服器監視器ChatRoomServerMonitor,接下來只需一個啟動伺服器開始偵聽執行緒的類:

在這裡插入圖片描述

使用者可以通過在命令文字框輸入命令來管理伺服器,同時框架內也會開始工作:
在這裡插入圖片描述

相關文章