เขียนก่อน:
เมื่อวานนี้ฉันบันทึกการออกแบบเริ่มต้นของโปรแกรมแชทซ็อกเก็ตที่ฉันใช้เวลาเขียนในบล็อกของฉัน มันเป็นการออกแบบโดยรวมของโปรแกรมนี้ เพื่อความสมบูรณ์วันนี้ฉันจะบันทึกการออกแบบด้านเซิร์ฟเวอร์โดยละเอียด หน้าแรกจะโพสต์แผนภาพการออกแบบทั่วไปของโปรแกรมแชทซ็อกเก็ตดังที่แสดงด้านล่าง:
ฟังก์ชั่นคำอธิบาย:
เซิร์ฟเวอร์มีการดำเนินการหลักสองประการ: หนึ่งคือการบล็อกซ็อกเก็ตของไคลเอนต์ที่ได้รับและทำการประมวลผลการตอบกลับและอีกอย่างคือการตรวจจับการเต้นของหัวใจของไคลเอนต์ หากลูกค้าไม่ได้ส่ง HeartBeat เป็นระยะเวลาหนึ่งให้ลบไคลเอนต์สร้าง Serversocket แล้วเริ่มพูลสองเธรดเพื่อจัดการสองสิ่งนี้ (NewFixedThreadPool, NewsCheduleDTHREADPOOL) คลาสการประมวลผลที่สอดคล้องกันคือ SocketDispatcher และ SocketSchedule SocketDispatcher ถูกแจกจ่ายให้กับถุงเท้าที่แตกต่างกันตามคำขอซ็อกเก็ตที่แตกต่างกัน SocketWrapper เพิ่มเสื้อคลุมเชลล์ลงในซ็อกเก็ตและบันทึกเวลาการโต้ตอบล่าสุดของซ็อกเก็ตด้วย Socketholder เก็บคอลเลกชันซ็อกเก็ตที่โต้ตอบกับเซิร์ฟเวอร์ในปัจจุบัน
การใช้งานเฉพาะ:
[Server.java]
เซิร์ฟเวอร์คือทางเข้าสู่เซิร์ฟเวอร์ Serversocket เริ่มต้นด้วยวิธีการเริ่มต้น () ของเซิร์ฟเวอร์จากนั้นบล็อกคำขอของไคลเอนต์ที่ได้รับและส่งมอบให้กับ SocketDispatcher เพื่อแจกจ่าย SocketDispatcher เริ่มต้นด้วยพูลเธรดของประเภท newfixedThread เมื่อจำนวนการเชื่อมต่อเกินข้อมูลสูงสุดจะถูกประมวลผลโดยคิว ScheduleatFixedrate ใช้เพื่อเริ่มต้นการกำหนดเวลา SocketSchedule เพื่อฟังแพ็คเกจการเต้นของหัวใจของลูกค้า ทั้งสองประเภทใช้อินเทอร์เฟซ Runnable ต่อไปนี้เป็นรหัสสำหรับเซิร์ฟเวอร์:
แพ็คเกจ yaolin.chat.server; นำเข้า java.io.ioexception; นำเข้า java.net.serversocket; นำเข้า java.util.date นำเข้า java.util.concurrent.executorservice; นำเข้า java.util.Current.executors; java.util.concurrent.timeUnit; นำเข้า yaolin.chat.common.constantValue; นำเข้า yaolin.chat.util.loggerutil;/*** เซิร์ฟเวอร์* @author yaolin*/เซิร์ฟเวอร์คลาสสาธารณะ Private Executorservice Pool; เซิร์ฟเวอร์สาธารณะ () พ่น IOException {เซิร์ฟเวอร์ = ใหม่ Serversocket (ConstantValue.server_port); pool = executors.newFixedThreadPool (ConstantValue.max_pool_size); } public void start () {ลอง {scheduleDexecutorservice schedule = executors.newscheduledThreadPool (1); // ดูสุนัข ข้อยกเว้น ?? กำหนดการ SCHEDULEATFIXEDRATE (SOCKETSCHEDULE ใหม่ (), 10, ConstantValue.Time_Out, TimeUnit.Seconds); ในขณะที่ (จริง) {pool.execute (SocketDispatcher ใหม่ (Server.accept ())); loggerutil.info ("ยอมรับไคลเอนต์ที่" + วันที่ใหม่ ()); }} catch (ioexception e) {pool.shutdown (); }} โมฆะคงที่สาธารณะหลัก (สตริง [] args) {ลอง {เซิร์ฟเวอร์ใหม่ (). start (); } catch (ioexception e) {loggerutil.error ("เซิร์ฟเวอร์เริ่มล้มเหลว! ->" + e.getMessage (), e); -[SocketDispatcher.java]
เซิร์ฟเวอร์เป็นเพียงทางเข้าสู่เซิร์ฟเวอร์และศูนย์คำสั่ง SocketDispatcher เป็นศูนย์กลางคำสั่งของเซิร์ฟเวอร์ มันแจกจ่ายคำขอประเภทข้อความที่แตกต่างจากไคลเอนต์ทำให้นักซ็อกเซิ ธ แลนด์ที่แตกต่างกันสามารถประมวลผลคำขอข้อความที่สอดคล้องกันได้ ที่นี่การโต้ตอบข้อความระหว่างเซิร์ฟเวอร์และไคลเอนต์ใช้ข้อมูล JSON คลาสข้อความทั้งหมดสืบทอด basemessage ดังนั้นข้อมูลที่ได้รับจะถูกแปลงเป็นประเภท basemessage และจากนั้นประเภทจะถูกตัดสิน (โมดูลชนิดข้อมูลเป็นของโมดูลทั่วไป) ควรกล่าวถึงที่นี่ว่าเมื่อประเภทข้อความเป็นประเภทไฟล์มันจะนอนหลับเพื่อกำหนดค่าช่วงเวลาการดำเนินการเพื่อให้ FileHandler สามารถมีเวลาอ่านและส่งสตรีมไฟล์ไปยังไคลเอนต์ที่ระบุโดยไม่ต้องป้อนลูปถัดไปทันทีเพื่อตัดสินประเภทข้อความ (การออกแบบอาจเป็นปัญหาเล็กน้อยที่นี่ ต่อไปนี้เป็นรหัสของ SocketDispatcher:
/** * SocketDispatcher * * @author yaolin */คลาสสาธารณะ SocketDispatcher ใช้งาน {ซ็อกเก็ตซ็อกเก็ตสุดท้ายส่วนตัว; SocketDispatcher สาธารณะ (ซ็อกเก็ตซ็อกเก็ต) {this.socket = ซ็อกเก็ต; } @Override โมฆะสาธารณะเรียกใช้ () {ถ้า (ซ็อกเก็ต! = null) {ในขณะที่ (! socket.isclosed ()) {ลอง {inputstream คือ = socket.getInputStream (); สตริงบรรทัด = null; StringBuffer SB = NULL; if (is.available ()> 0) {bufferedReader bufr = bufferedReader ใหม่ (ใหม่ inputStreamReader (IS)); sb = new StringBuffer (); ในขณะที่ (is.available ()> 0 && (line = bufr.readline ())! = null) {sb.append (บรรทัด); } loggerutil.trach ("รับ [" + sb.toString () + "] ที่" + วันที่ใหม่ ()); ข้อความ basemessage = json.parseObject (sb.toString (), basemessage.class); switch (message.getType ()) {case messageType.alive: handlerfactory.gethandler (messagetype.alive) .handle (ซ็อกเก็ต, sb.toString ()); หยุดพัก; Case Messagetype.chat: handlerfactory.gethandler (messagetype.chat) .handle (ซ็อกเก็ต, sb.toString ()); หยุดพัก; Case MessageType.File: HandlerFactory.Gethandler (MessageType.File) .handle (ซ็อกเก็ต, sb.toString ()); หยุดพัก; Case MessageType.File: HandlerFactory.Gethandler (MessageType.File) .handle (ซ็อกเก็ต, sb.toString ()); loggerutil.trach ("sever: หยุดชั่วคราวเพื่อรับไฟล์"); thread.sleep (constantvalue.message_period); หยุดพัก; Case Messagetype.login: handlerfactory.gethandler (messagetype.login) .handle (ซ็อกเก็ต, sb.toString ()); หยุดพัก; Case Messagetype.logout: BREAK; Case Messagetype.register: handlerfactory.gethandler (Messagetype.register) .handle (ซ็อกเก็ต, sb.toString ()); หยุดพัก; }} else {thread.sleep (ConstantValue.message_period); }} catch (Exception e) {// จับ Handler Exception Loggerutil.error ("SocketDispatcher Error!" + E.getMessage (), e); -[SocketSchedule.java]
คลาสอื่น (ส่วนประกอบ) ที่เกี่ยวข้องโดยตรงกับเซิร์ฟเวอร์คือ SocketSchedule SocketSchedule ส่วนใหญ่รับผิดชอบในการตรวจจับว่าเวลาการโต้ตอบล่าสุดระหว่างไคลเอนต์และเซิร์ฟเวอร์เกินกว่าเวลาที่อนุญาตสูงสุดในการกำหนดค่าระบบหรือไม่ หากเกินกว่าซ็อกเก็ตไคลเอนต์จะถูกลบออกจากเซิร์ฟเวอร์มิฉะนั้นเวลาโต้ตอบล่าสุดระหว่างไคลเอนต์และเซิร์ฟเวอร์จะได้รับการอัปเดต ต่อไปนี้คือการใช้งานเฉพาะ:
/** * ถอดซ็อกเก็ตออกจาก Socketholder หาก Lastalivetime> time_out * @author yaolin * */socketschedule คลาสสาธารณะใช้งาน runnable {@Override โมฆะสาธารณะเรียกใช้ () {สำหรับ (คีย์สตริง: socketholder.keyset ()) if (wrapper! = null && wrapper.getLastalivetime ()! = null) {ถ้า (((วันที่ใหม่ (). getTime ()) - wrapper.getLastalivetime (). getTime ()) / 1000)> ConstantValue.time_out) -[Socketholder.java, SocketWrapper.java]
จากรหัสข้างต้นเราจะเห็นว่า SocketSchedule#run () เป็นเพียงการตัดสินเวลาง่ายๆ สิ่งที่มีความหมายจริงๆคือ Socketholder และ SocketWrapper SocketWrapper เพิ่มเสื้อคลุมเชลล์ลงในซ็อกเก็ต Socketholder จัดเก็บลูกค้าทั้งหมดที่โต้ตอบกับเซิร์ฟเวอร์ในช่วงเวลาที่ถูกต้องปัจจุบัน Socketholder ถูกระบุโดยไคลเอนต์ (ชื่อผู้ใช้ที่นี่) ในฐานะที่เป็นกุญแจสำคัญซ็อกเก็ตที่ไคลเอนต์จะถูกเก็บไว้เป็นคู่ของค่าคีย์-ค่า ตรรกะการประมวลผลของ Socketholder#FlushClientStatus () ใช้เพื่อแจ้งลูกค้าอื่น ๆ เกี่ยวกับสถานะออนไลน์/ออฟไลน์ของไคลเอนต์ปัจจุบัน การใช้งานเฉพาะของสองคลาสนี้ได้รับด้านล่าง:
/** * ห่อซ็อกเก็ต, SocketSchedule ลบซ็อกเก็ตถ้า LastAlivetime> time_out * @author yaolin * */socketwrapper คลาสสาธารณะ {ซ็อกเก็ตซ็อกเก็ตส่วนตัว; วันที่ส่วนตัว Lastalivetime; // Full Constructor Public SocketWrapper (ซ็อกเก็ตซ็อกเก็ต, วันที่ lastalivetime) {this.socket = ซ็อกเก็ต; this.lastalivetime = Lastalivetime; } ซ็อกเก็ตสาธารณะ getSocket () {return socket; } โมฆะสาธารณะ setSocket (ซ็อกเก็ตซ็อกเก็ต) {this.socket = ซ็อกเก็ต; } วันที่สาธารณะ getLastalivetime () {return lastalivetime; } โมฆะสาธารณะ setLastalivetime (วันที่ LastAlivetime) {this.lastalivetime = Lastalivetime; - /** * Socketholder * @author yaolin */คลาสสาธารณะ Socketholder {private static oncurrentMap <String, socketWrapper> listsocketWrap = ใหม่พร้อมกันใหม่ ชุดคงที่สาธารณะ <String> keyset () {return listsocketWrap.keyset (); } socketWrapper สาธารณะคงที่รับ (คีย์สตริง) {return listsocketWrap.get (คีย์); } โมฆะคงที่สาธารณะพัตต์ (คีย์สตริง, ค่า SocketWrapper) {listsocketWrap.put (คีย์, ค่า); FlushClientStatus (คีย์จริง); } socketWrapper สาธารณะคงที่ลบ (คีย์สตริง) {flushClientStatus (คีย์, เท็จ); return listsocketWrap.remove (คีย์); } โมฆะคงที่สาธารณะ clear () {listsocketWrap.clear (); } /** * <pre> เนื้อหา: {ชื่อผู้ใช้: "", Flag: False} < /pre> * @param Flag จริง: Put, False: ลบ; */ Void Private Void FlushClientStatus (คีย์สตริง, ธงบูลีน) {clientNotifydto dto = ใหม่ clientNotifydto (แฟล็ก, คีย์); returnMessage rm = new returnMessage (). setKey (key.notify) .SetSuccess (จริง) .setContent (DTO); RM.SetFrom (ConstantValue.server_name); สำหรับ (String tokey: listsocketwrap.keyset ()) {ถ้า (! tokey.equals (คีย์)) {// ไม่ส่งไปยังตัวเอง rm.setto (tokey); SocketWrapper wrap = listsocketWrap.get (tokey); if (wrap! = null) {sendhelper.send (wrap.getSocket (), rm); -[Sockethandler.java, handlerfactory.java, otherhandlerimpl.java]
SocketDispatcher อนุญาตให้ Sockethandlers ที่แตกต่างกันจัดการคำขอข้อความที่สอดคล้องกัน การออกแบบของ Sockethandler เป็นชุดส่วนประกอบของโรงงานที่เรียบง่าย (returnhandler ถูกส่งโดย Sendhelper ชั่วคราว แต่มันไม่ได้ใช้ในเวลานั้นมันได้รับ @Deprecated และยังคงได้รับที่นี่) แผนภาพคลาสที่สมบูรณ์มีดังนี้:
รหัสสำหรับส่วนนี้ได้รับด้านล่าง เพื่อลดพื้นที่ใช้งานรหัสทั้งหมดที่ใช้โดยตัวจัดการจะถูกรวบรวม
/** * Sockethandler * @author yaolin */อินเตอร์เฟสสาธารณะ Sockethandler {/** * จัดการซ็อกเก็ตไคลเอ็นต์ */ด้ามจับวัตถุสาธารณะ (ซ็อกเก็ตไคลเอนต์ข้อมูลวัตถุ);} /** * SockethandlerFactory * @author yaolin */คลาสสาธารณะ handlerFactory {// ไม่สามารถสร้างอินสแตนซ์ส่วนตัว handlerFactory () {} sockethandler คงที่สาธารณะ Gethandler (ประเภท int) {switch (ประเภท) Case Messagetype.chat: ส่งคืน Chathandler ใหม่ (); Case MessageType.login: ส่งคืนใหม่ loginHandler (); // case messagetype.return: // ส่งคืนใหม่ returnHandler (); Case Messagetype.logout: ส่งคืน Logouthandler ใหม่ (); Case MessageType.Register: ส่งคืน RegisterHandler ใหม่ (); Case MessageType.File: ส่งคืน FileHandler ใหม่ (); } return null; // nullpointException}} /** * alivesockethandler * @author yaolin */คลาสสาธารณะ Alivehandler ใช้ Sockethandler {/** * @@return null */@Override วัตถุสาธารณะที่จับ (ซ็อกเก็ตไคลเอนต์ข้อมูลวัตถุ) {ถ้า (ข้อมูล! = null) if (stringUtil.isnotEmpty (message.getFrom ())) {socketWrapper wrapper = socketholder.get (message.get.getFrom ()); if (wrapper! = null) {wrapper.setLastalivetime (วันที่ใหม่ ()); // เก็บซ็อกเก็ต ... Socketholder.put (message.getFrom (), wrapper); }}} return null; - /** * chathandler * * @author yaolin */คลาสสาธารณะ Chathandler ใช้ Sockethandler {@Override การจัดการวัตถุสาธารณะ (ซ็อกเก็ตไคลเอนต์, ข้อมูลวัตถุ) {ถ้า (ข้อมูล! if (stringutil.isnotEmpty (message.getFrom ()) && stringUtil.isnotEmpty (message.getto ())) {// มีอยู่ & ส่งถ้า (socketholder.keyset (). มี (message.getFrom ()) message.setOwner (เจ้าของ); // เจ้าของจะแสดงผลถ้า (ConstantValue.to_all.equals (message.getto ())) {// แท็บหนึ่งถึงทั้งหมด // to_all แท็บจะถูกเลือก; message.setFrom (ConstantValue.to_all); สำหรับ (คีย์สตริง: socketholder.keyset ()) {// ส่งไปยัง songetWrapper wrapper = socketholder.get (คีย์); if (wrapper! = null) {sendhelper.send (wrapper.getSocket (), ข้อความ); }}} else {// one-to-one socketWrapper wrapper = socketholder.get (message.getto ()); if (wrapper! = null) {// owner = จาก sendhelper.send (wrapper.getSocket (), ข้อความ); // ส่งไปยังตัวเอง // ไปที่แท็บจะถูกเลือก; message.setFrom (message.getto ()). setto (เจ้าของ); SendHelper.Send (ไคลเอนต์, ข้อความ); }}}}} return null; - FileDler คลาสสาธารณะใช้ Sockethandler {@Override ที่จับวัตถุสาธารณะ (ซ็อกเก็ตไคลเอนต์ข้อมูลวัตถุ) {ถ้า (ไคลเอนต์! = null) {ข้อความ fileMessage = json.parseObject (data.toString (), fileMessage.class); if (stringutil.isnotEmpty (message.getFrom ()) && stringutil.isnotEmpty (message.getto ())) {// มีอยู่ & ส่งถ้า (socketholder.keyset (). มี (message.getFrom ()) {if (! Socketholder.get (message.getto ()); if (wrapper! = null) {sendhelper.send (wrapper.getSocket (), ข้อความ); ลอง {ถ้า (ไคลเอนต์! = null && wrapper.getSocket ()! = null && message.getSize ()> 0) {inputStream คือ = client.getInputStream (); OutputStream OS = wrapper.getSocket (). getOutputStream (); int ทั้งหมด = 0; ในขณะที่ (! client.isclosed () &&! wrapper.getSocket (). isclosed ()) {ถ้า (is.available ()> 0) {byte [] buff = byte ใหม่ [constantvalue.buff_size]; int len = -1; ในขณะที่ (is.available ()> 0 && (len = is.read (buff))! = -1) {os.write (buff, 0, len); ทั้งหมด += len; loggerutil.debug ("ส่งบัฟ [" + len + "]"); } os.flush (); if (total> = message.getSize ()) {loggerutil.info ("ส่งบัฟ [ตกลง]"); หยุดพัก; }}} // หลังจากส่งไฟล์ // ส่งผลลัพธ์ returnMessage ที่ประสบความสำเร็จ = new ReturnMessage (). setKey (key.tip) .setsuccess (จริง) .setContent (i18n.info_file_send_successly); result.setFrom (message.getto ()). setto (message.getFrom ()) .setOwner (ConstantValue.server_name); sendhelper.send (ลูกค้า, ผลลัพธ์); // รับผลลัพธ์ที่ประสบความสำเร็จ setContent (i18n.info_file_receive_successingly) .setFrom (message.getFrom ()) .setto (message.getto ()); sendhelper.send (wrapper.getSocket (), ผลลัพธ์); }} catch (exception e) {loggerutil.error ("มือจับไฟล์ล้มเหลว!" + e.getMessage (), e); }}}}}}} return null; - /** * loginHandler * * @author yaolin * */คลาสสาธารณะ LoginHandler ใช้ Sockethandler {ส่วนตัว USRService USRService = ใหม่ USRService (); @Override ที่จับวัตถุสาธารณะ (ซ็อกเก็ตไคลเอนต์ข้อมูลวัตถุ) {returnMessage result = new ReturnMessage (); result.setsuccess (เท็จ); if (data! = null) {ข้อความ loginMessage = json.parseObject (data.toString (), loginMessage.class); if (stringutil.isnotEmpty (message.getUserName ()) && stringUtil.isnotEmpty (message.getPassword ())) {ถ้า (usrservice.login (message.getUserName (), message.get.getPassword ())! = null) } else {result.setMessage (i18n.info_login_error_data); } result.setFrom (ConstantValue.server_name) .setto (message.getUserName ()); } else {result.setMessage (i18n.info_login_empty_data); } // หลังจากลงชื่อเข้าใช้ผลลัพธ์ SetKey (key.login); if (result.issuccess ()) {// ถือ Socket Socketholder.put (result.getTo (), SocketWrapper ใหม่ (ไคลเอนต์, วันที่ใหม่ ())); } sendhelper.send (ไคลเอนต์ผลลัพธ์); if (result.issuccess ()) {// ส่ง list user clientlistuserdto dto = new clientlistuserdto (); dto.setListuser (socketholder.keyset ()); result.setContent (DTO) .setKey (key.listUser); sendhelper.send (ลูกค้า, ผลลัพธ์); }} return null; - Logouthandler คลาสสาธารณะใช้ Sockethandler {@Override ที่จับวัตถุสาธารณะ (ซ็อกเก็ตไคลเอนต์ข้อมูลวัตถุ) {ถ้า (data! = null) {ข้อความ logoutMessage = json.parseObject (data.toString (), logoutMessage.class); if (message! = null && stringUtil.isnotEmpty (message.getFrom ())) {socketWrapper wrapper = socketholder.get (message.getFrom ()); ซ็อกเก็ตซ็อกเก็ต = wrapper.getSocket (); if (socket! = null) {ลอง {socket.close (); ซ็อกเก็ต = null; } catch (ข้อยกเว้นละเว้น) {}} socketholder.remove (message.getFrom ()); }} return null; - Public Class RegisterHandler ใช้ Sockethandler {ส่วนตัว USRService USRService = ใหม่ USRService (); @Override ที่จับวัตถุสาธารณะ (ซ็อกเก็ตไคลเอนต์ข้อมูลวัตถุ) {returnMessage result = new ReturnMessage (); result.setsuccess (false) .setfrom (ConstantValue.server_name); if (data! = null) {message registerMessage = json.parseObject (data.toString (), registerMessage.class); if (stringutil.isnotEmpty (message.getUserName ()) && stringUtil.isnotEmpty (message.getPassword ())) {ถ้า (usrservice.register (message.getUserName (), message.get.getPassword ())! = null) } else {result.setMessage (i18n.info_register_client_exist); }} else {result.setMessage (i18n.info_register_empty_data); } if (StringUtil.isNotEmpty (message.getUserName ())) {result.setto (message.getUserName ()); } // หลังจากลงทะเบียน result.setkey (key.register); sendhelper.send (ลูกค้า, ผลลัพธ์); } return null; - /** * ใช้ sendhelper เพื่อส่ง returnMessage, * @See yaolin.chat.server.socketDispatcher#run () * @author yaolin */ @คลาสสาธารณะ = (returnMessage) ข้อมูล; if (stringutil.isnotEmpty (message.getFrom ()) && stringUtil.isnotEmpty (message.getto ())) {socketWrapper wrap = socketholder.get (message.getto ()); if (wrap! = null) {sendhelper.send (wrap.getSocket (), ข้อความ); }}} return null; -ธุรกิจผู้ใช้:
นอกเหนือจากซ็อกเก็ตแล้วเซิร์ฟเวอร์ยังมีธุรกิจที่เฉพาะเจาะจงเล็กน้อยนั่นคือการลงทะเบียนผู้ใช้การเข้าสู่ระบบ ฯลฯ ที่นี่เราเพียงแค่แสดงรายการ USR และ USRService สองคลาส ธุรกิจเหล่านี้ยังไม่ได้ดำเนินการในขณะนี้ ฉันไม่ได้ตั้งใจที่จะแนะนำกรอบ ORM ในโปรแกรมนี้ดังนั้นฉันจึงเขียนชุดของ dbutil (เพื่อปรับปรุง) และโพสต์ที่นี่
มีการตรวจสอบอย่างง่าย ๆ เท่านั้นที่นี่และไม่คงอยู่ที่จะเก็บไว้ใน DB นี่คือ USR และ USRService:
ชั้นเรียนสาธารณะ USR {Private Long ID; ชื่อผู้ใช้สตริงส่วนตัว; รหัสผ่านสตริงส่วนตัว Public Long getId () {return id; } โมฆะสาธารณะ setId (Long id) {this.id = id; } สตริงสาธารณะ getUserName () {ส่งคืนชื่อผู้ใช้; } โมฆะสาธารณะ setUserName (ชื่อผู้ใช้สตริง) {this.userName = ชื่อผู้ใช้; } สตริงสาธารณะ getPassword () {ส่งคืนรหัสผ่าน; } โมฆะสาธารณะ setPassword (รหัสผ่านสตริง) {this.password = รหัสผ่าน; - /** * // toDo * @See yaolin.chat.server.usr.repository.usrrepository * @author yaolin * */ชั้นเรียนสาธารณะ usrservice {// todo db map แบบคงที่ส่วนตัว <String, usr> db = new hashmap <string, usr> (); การลงทะเบียน USR สาธารณะ (ชื่อผู้ใช้สตริง, รหัสผ่านสตริง) {ถ้า (StringUtil.isEmpty (ชื่อผู้ใช้) || stringUtil.isEmpty (รหัสผ่าน)) {return null; } if (db.containskey (ชื่อผู้ใช้)) {return null; // มีอยู่; } usr usr = new usr (); usr.setUserName (ชื่อผู้ใช้); usr.setPassword (md5util.getmd5code (รหัสผ่าน)); db.put (ชื่อผู้ใช้, USR); คืน USR; } การเข้าสู่ระบบ USR สาธารณะ (ชื่อผู้ใช้สตริง, รหัสผ่านสตริง) {ถ้า (StringUtil.isEmpty (ชื่อผู้ใช้) || stringUtil.isEmpty (รหัสผ่าน)) {return null; } if (db.containskey (ชื่อผู้ใช้)) {usr usr = db.get (ชื่อผู้ใช้); if (md5util.getmd5code (รหัสผ่าน) .equals (usr.getPassword ())) {ส่งคืน USR; }} return null; - นี่คือเครื่องมือ dbutil:
/*** dbutils // todo จำเป็นต้องปรับและปรับให้เหมาะสม !! * @author yaolin */คลาสสาธารณะ dbutil {// ทำการเชื่อมต่อที่ใช้ซ้ำรายการสุดท้ายส่วนตัวคงที่ <การเชื่อมต่อ> cache = ใหม่ linkedList <การเชื่อมต่อ> (); URL สตริงคงที่ส่วนตัว; ไดรเวอร์สตริงแบบคงที่ส่วนตัว ผู้ใช้สตริงคงที่ส่วนตัว; รหัสผ่านสตริงแบบคงที่ส่วนตัว การดีบักบูลีนแบบคงที่ส่วนตัว; Static {inputStream คือ = dButil.class.getResourceasstream ("/db.properties"); ลอง {คุณสมบัติ p = คุณสมบัติใหม่ (); p.load (IS); url = p.getProperty ("url"); Driver = P.GetProperty ("ไดรเวอร์"); ผู้ใช้ = P.GetProperty ("ผู้ใช้"); รหัสผ่าน = P.GetProperty ("รหัสผ่าน"); // สำหรับการดีบักลอง {debug = boolean.valueof (P.GetProperty ("debug")); } catch (ข้อยกเว้นละเว้น) {debug = false; }} catch (exception e) {โยน runtimeException ใหม่ (e); } ในที่สุด {ถ้า (คือ! = null) {ลอง {is.close (); IS = NULL; } catch (ข้อยกเว้นที่ละเว้น) {}}}} การเชื่อมต่อแบบคงที่แบบซิงโครไนซ์สาธารณะ getConnection () {ถ้า (cache.isempty ()) {cache.add (makeConnection ()); } การเชื่อมต่อ conn = null; int i = 0; ลอง {do {conn = cache.remove (i); } ในขณะที่ (conn! = null && conn.isclosed () && i <cache.size ()); } catch (ข้อยกเว้นละเว้น) {} ลอง {if (conn == null || conn.isclosed ()) {cache.add (makeConnection ()); conn = cache.remove (0); } return conn; } catch (exception e) {โยน runtimeException ใหม่ (e); }} โมฆะแบบคงที่แบบซิงโครไนซ์สาธารณะปิด (การเชื่อมต่อการเชื่อมต่อ) {ลอง {if (การเชื่อมต่อ! = null &&! connection.isclosed ()) {ถ้า (debug) debug ("การเชื่อมต่อปล่อย!"); cache.add (การเชื่อมต่อ); }} catch (sqlexception ละเว้น) {}} การสืบค้นวัตถุสแตติกสาธารณะ (String SQL, ResultSetMapper Mapper, Object ... args) {if (debug) debug (SQL); Connection conn = getConnection (); PreparedStatement PS = NULL; ผลลัพธ์ RS = NULL; ผลลัพธ์ของวัตถุ = null; ลอง {ps = conn.prepareStatement (SQL); int i = 1; สำหรับ (วัตถุวัตถุ: args) {ps.setObject (i ++, วัตถุ); } rs = ps.executeQuery (); ผลลัพธ์ = mapper.mapper (RS); } catch (exception e) {โยน runtimeException ใหม่ (e); } ในที่สุด {ลอง {ถ้า (rs! = null) {rs.close (); rs = null; } if (ps! = null) {ps.close (); ps = null; }} catch (ข้อยกเว้นละเว้น) {}} ปิด (conn); ผลการกลับมา; } public Static Int Modify (String SQL, Object ... args) {ถ้า (debug) debug (SQL); Connection conn = getConnection (); PreparedStatement PS = NULL; แถว int = 0; ลอง {ps = conn.prepareStatement (SQL); int i = 1; สำหรับ (วัตถุวัตถุ: args) {ps.setObject (i ++, วัตถุ); } row = ps.executeUpdate (); } catch (exception e) {โยน runtimeException ใหม่ (e); } ในที่สุด {ลอง {ถ้า (ps! = null) {ps.close (); ps = null; }} catch (ข้อยกเว้นละเว้น) {}} ปิด (conn); แถวกลับ; } public Static int [] batch (รายการ <String> SQLS) {if (debug) debug (sqls.toString ()); Connection conn = getConnection (); คำสั่ง stmt = null; int [] แถว; ลอง {stmt = conn.createstatement (); สำหรับ (String SQL: SQLS) {STMT.ADDBATCH (SQL); } row = stmt.executeBatch (); } catch (exception e) {โยน runtimeException ใหม่ (e); } ในที่สุด {ลอง {ถ้า (stmt! = null) {stmt.close (); stmt = null; }} catch (ข้อยกเว้นละเว้น) {}} ปิด (conn); แถวกลับ; } สาธารณะคงที่ int [] batch (String SQL, PreparedStatementSetter setter) {ถ้า (debug) debug (SQL); Connection conn = getConnection (); PreparedStatement PS = NULL; int [] แถว; ลอง {ps = conn.prepareStatement (SQL); setter.setter (ps); row = ps.executeBatch (); } catch (exception e) {โยน runtimeException ใหม่ (e); } ในที่สุด {ลอง {ถ้า (ps! = null) {ps.close (); ps = null; }} catch (ข้อยกเว้นละเว้น) {}} ปิด (conn); แถวกลับ; } การเชื่อมต่อแบบคงที่ส่วนตัว makeConnection () {ลอง {class.forname (ไดรเวอร์) .newinstance (); Connection Conn = driverManager.getConnection (URL, ผู้ใช้, รหัสผ่าน); if (debug) debug ("สร้างการเชื่อมต่อ!"); กลับ Conn; } catch (exception e) {โยน runtimeException ใหม่ (e); }} การดีบักโมฆะแบบคงที่ส่วนตัว (สตริง SQLS) {SimpledateFormat SDF = New SimpleDateFormat ("YYYY-MM-DD HH: MM: SS"); System.out.println (sdf.format (วันที่ใหม่ ()) + "debug" + thread.currentthread (). getId () + "--- [" + thread.currentthread (). getName () + "]" + "SQLS:" + SQLS); -/** i
/** * resultsetMapper * @author yaolin */อินเทอร์เฟซสาธารณะ ResultSetMapper {Mapper Object Public (Resultset RS);} ดาวน์โหลดซอร์สโค้ด: สาธิต
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น