小说阅读器
小說閱讀器
1.需求分析
2.架構設計
C(Client客戶端)/S(Server服務端)架構
客戶端:Socket相關API
服務端:ServerSocket Thread
數據庫:XML DOM4J
3.難點分析
如何讓服務端區分不同的請求
Data Transfer Object 它一般用于后端->前端的交互使用
VO -> View Object 它一般用于前端視圖層->后端的交互使用
POJO -> Plain Old Java Object 主要用于后期ORM框架映射使用
創建DTO作為數據交換對象
上傳需要客戶端再開啟線程
下載需要服務器在開啟線程
這兩者socket、輸入輸出不能太早關閉
上傳的文件要添加到對應小說分類和小說XML中,并更新MAP集合
如何講服務處理進行拆分
我們定義了一系列的服務類,不同的服務類專門用于處理不同的請求。
LoginService
RegisterService
GetNovelClassesService
GetNovelsService
DownloadService
UploadService
在抽取一個接口Service
讓服務繼承
簡單工廠模式
場景:根據客戶的描述 產生符合要求的實例。
1.產品規范 接口
Service
2.符合規范的產品 接口的實現類
LoginService
RegisterService
GetNovelClassesService
GetNovelsService
DownloadService
UploadService
3.生產產品的工廠
ServiceFactory
4.客戶
main
反射
字節碼類型 Class
3種獲取方法
1.類名.class
2.對象名.getClass()
3.Class.forName(全類名)
可以獲取一個類的所有構造、方法、屬性、注解…
也可以對這些構造…進行使用
利用自定義的XML存儲一些類信息
借鑒于未來一些框架思想
如小說分類
<?xml version="1.0" encoding="UTF-8"?> <!-- 服務器小說分類 --> <novelClasses><novelClass><classname>武俠</classname><catalog>txtcatalog/wuxia/</catalog><config>resource/novel/txt_wuxia.xml</config></novelClass><novelClass><classname>言情</classname><catalog>txtcatalog/yanqing/</catalog><config>resource/novel/txt_yanqing.xml</config></novelClass> </novelClasses>小說
<?xml version="1.0" encoding="UTF-8"?> <!-- 武俠小說 --> <novellist> <novel> <name>古俠今遇</name> <author>醉人歲月</author> <description>與世隔絕三百多年的“碧湖山莊”四少俠出現在大都市中,既有古人的風采,又有現代人的韻味!</description> <filename>古俠今遇.txt</filename> </novel> <novel> <name>寒劍孤燈</name> <author>憂郁丁香</author> <description>寒劍孤燈,傳奇故事</description> <filename>寒劍孤燈.txt</filename> </novel> </novellist>5.使用BasiceService去實現了接口中的方法
接口實現類都需要重復實現某些方法。
繼承:減少重復代碼 ,提升代碼復用性。
package org.sunshine.server.service;import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.Socket;import org.sunshine.server.utility.DTO;/*** 服務器基本方法* 實現Service接口* 提取輸入輸出流的開啟與關閉* 和繼承service方法* @author 周太陽* 2019年5月15日*/ public abstract class BasicService implements Service{/**創建接收套接字的屬性*/private Socket socket;private ObjectInputStream ois;private ObjectOutputStream oos;/**創建保存傳輸的data對象*/private Object data;private int receive;/*** 初始化輸入輸出* @param socket */public void init(Socket socket, ObjectInputStream ois, ObjectOutputStream oos, Object data) throws Exception {// 得到當前對象的socketthis.socket = socket;this.ois = ois;this.oos = oos;// 返回數據傳輸對象DTOthis.data = data;this.receive = receive;}/*** Service方法* @throws Exception */@Overridepublic abstract void service() throws Exception;/*** 釋放資源*/@Overridepublic void destroy() throws Exception {ois.close();oos.close();socket.close();}public Socket getSocket() {return socket;}public void setSocket(Socket socket) {this.socket = socket;}public ObjectInputStream getOis() {return ois;}public void setOis(ObjectInputStream ois) {this.ois = ois;}public ObjectOutputStream getOos() {return oos;}public void setOos(ObjectOutputStream oos) {this.oos = oos;}public Object getData() {return data;}public void setData(Object data) {this.data = data;}public int getReceive() {return receive;}public void setReceive(int receive) {this.receive = receive;}}DAO專門用于存放數據操作代碼
JAVA三層架構:表現層 業務邏輯層 數據訪問層
Data Access Object 數據存取對象
常用基本取名代碼:
舉例:對用戶的操作
User getUserById(Long id);
User getUserByUserName(String name);
List getUserListByConditions(Map<String,Object> conditions);
void addUser(User user);
void deleteUser(User user);
void updateUser(User user);
客戶端的"永動機"
執行某個服務的方法的時候,這個服務的返回值是一個服務,然后通過循環繼續執行。
public class ClientMain {private static Service service = ServiceFactory.getService(ServiceConstants.START_SERVICE);public static void main(String[] args) {while(true) {if (service == null) {System.out.println("程序結束!");break;}try {service = service.service();} catch (Exception e) {e.printStackTrace();}}}}服務端和客戶端公用一些代碼 common 開發階段采用工程型依賴
如user,constructs
/*** 用戶類常量* @author 周太陽* 2019年5月19日*/ public class UserConstants {/**用戶登錄成功*/public static final int USER_LOGIN_SUCCESS = 1;/**登錄失敗*/public static final int USER_LOGIN_FAILED = 2;/**登錄發生錯誤*/public static final int USER_LOGIN_ERROR = 3;/**用戶注冊名存在*/public static final int USER_REGISTER_ALREADY_EXISTS = 4;/**用戶注冊發生錯誤*/public static final int USER_REGISTER_ERROR = 5;/**用戶注冊成功*/public static final int USER_REGISTER_SUCCES = 6;}常量解決"魔法值"
提升系統中的代碼閱讀性和維護性。
發現有很多值使用比較頻繁,又不好記,可能后期要修改可以定義為常量
服務常量
反射類的服務常量
字符串常量等……
/*** 反射類的服務常量* @author 周太陽* 2019年5月19日*/ public class ServiceConstants {/**開始*/public static final String START_SERVICE = "start";/**登錄*/public static final String LOGIN_SERVICE = "login";/**注冊*/public static final String REGISTER_SERVICE = "register";/**獲得小說分類*/public static final String GET_NOVEL_CLASS_SERVICE = "getNovelClasses";/**獲得小說*/public static final String GET_NOVEL_SERVICE = "getNovels";/**獲得小說預覽*/public static final String GET_NOVEL_PREVIEW_SERVICE = "getPreview";/**下載*/public static final String DOWNLOAD_SERVICE = "downLoad";/**上傳*/public static final String UPLOAD_SERVICE = "upLoad"; }properties配置文件和Properties類
Properties是繼承HashTable的,里面內容=左邊是鍵,=右邊是值
可以將其用到反射上,配合永動機更方便。
#服務器配置 #服務器端口號 sunshine.socket.server.port=8080 #獲取服務器配置文件 sunshine.server.config.service=resource/Service.xml #用戶配置文件地址 sunshine.server.config.user=resource/user/UserInfo.xml #小說分類配置文件地址 sunshine.server.config.novel.class=resource/novel/NovelClass.xml將配置信息存放在配置文件中(XML不推薦,因為XML需要DOM解析,使用比較復雜)
總結
- 上一篇: linux openssh升级8.1,C
- 下一篇: java学习(96):线程的睡眠