บทความนี้เป็นส่วนที่สองของการส่งข้อความ ที่นี่เราแนะนำวิธี จำกัด ความถี่ในการส่งข้อความไปยังผู้ใช้รายเดียวกัน (ขึ้นอยู่กับหมายเลขโทรศัพท์มือถือและ IP)
1. ใช้เซสชัน
หากเป็นโปรแกรมเว็บก็เป็นไปได้ที่จะบันทึกครั้งสุดท้ายที่ส่งในเซสชัน แต่สามารถข้ามได้ สิ่งที่ง่ายที่สุดคือการรีสตาร์ทเบราว์เซอร์โดยตรงหรือล้างแคชและข้อมูลอื่น ๆ ที่สามารถทำเครื่องหมายเซสชันได้ดังนั้นระเบียนในเซสชันสามารถข้ามได้ แม้ว่าหลายคนไม่ได้เป็นมืออาชีพในคอมพิวเตอร์และยังไม่ได้เรียนรู้สิ่งเหล่านี้ แต่เราต้องทราบว่าเหตุผลในการ จำกัด ความถี่ในการส่งคือการป้องกัน "SMS Bombs" นั่นคือใครบางคนที่เป็นอันตรายและมักจะร้องขอให้ส่งข้อความไปยังหมายเลขโทรศัพท์มือถือ ดังนั้นบุคคลนี้อาจเข้าใจความรู้นี้
ต่อไปเราใช้ขีด จำกัด ข้อมูล "ทั่วโลก" เพื่อส่งความถี่ไปยังผู้ใช้รายเดียวกัน มาทำงานกันเถอะก่อน
2. กำหนดอินเตอร์เฟสและคลาสเอนทิตี
คลาสเอนทิตีที่เราต้องการมีดังนี้:
Smsentity.java
SMSENTITY ระดับสาธารณะ {ID จำนวนเต็มส่วนตัว; พกพาสตริงส่วนตัว สตริงส่วนตัว IP; ประเภทจำนวนเต็มส่วนตัว เวลาส่วนตัว Captcha สตริงส่วนตัว; // ละเว้นวิธีการสร้างและวิธี getter และ setter}อินเทอร์เฟซการกรองมีดังนี้:
smsfilter.java
อินเทอร์เฟซสาธารณะ smsfilter { / *** เริ่มต้นตัวกรอง* / void init () โยนข้อยกเว้น; /*** ตรวจสอบว่าสามารถส่งข้อความได้หรือไม่ * @param smsentity เนื้อหาของข้อความที่จะส่ง * @@return ถ้ามันสามารถส่งได้มันจะส่งคืนจริงมิฉะนั้นจะส่งคืนตัวกรอง false */ boolean (smsentity smsentity); / *** ทำลายตัวกรอง*/ โมฆะทำลาย ();}3. รหัสหลัก
ในการ จำกัด ความถี่ในการส่งคุณต้องบันทึกหมายเลขโทรศัพท์มือถือ (IP) และเวลาสุดท้ายที่คุณส่งข้อความ เหมาะสำหรับแผนที่ให้เสร็จสมบูรณ์ ที่นี่เราใช้พร้อมกันครั้งแรกเพื่อนำไปใช้:
FrequencyFilter.java
Public Class FrequencyFilter ใช้ smsfilter { / *** ส่งช่วงเวลาหน่วย: มิลลิวินาที* / ส่วนตัว sendinterval ยาวส่วนตัว; Private ConcurrentMap <String, Long> SendAdDressMap = ใหม่พร้อมกันพร้อมกัน <> (); // รหัสที่ไร้ประโยชน์บางอย่างละเว้น @Override ตัวกรองบูลีนสาธารณะ (SMSENTITY SMSENTITY) {ถ้า (setSendTime (smsentity.getMobile ()) && setSendTime (smsentity.getip ())) {return true; } return false; } /*** แก้ไขเวลาการส่งเป็นเวลาปัจจุบัน * หากช่วงเวลาจากการส่งครั้งสุดท้ายมากกว่า {@link #sendinterval} ให้ตั้งเวลาการส่งเป็นเวลาปัจจุบัน มิฉะนั้นจะไม่มีการแก้ไขเนื้อหา * * @param id ส่งหมายเลขมือถือหรือ IP * @@Return หากเวลาการส่งได้รับการแก้ไขสำเร็จเป็นเวลาปัจจุบันจะกลับมาจริง มิฉะนั้นมันจะส่งคืน false */ private boolean setSendTime (String ID) {Long CurrentTime = System.currentTimeMillis (); Long SendTime = SendAdDressMap.putIfAbsent (ID, CurrentTime); if (sendtime == null) {return true; } long nextCansEndTime = sendTime + sendInterval; if (currenttime <nextcansendtime) {return false; } return sendaddressmap.replace (id, sendtime, currenttime); -ที่นี่ตรรกะหลักถูกนำไปใช้ใน วิธีการตั้งค่าเวลา :
บรรทัด 25-28: ก่อนอื่นสมมติว่าผู้ใช้ส่ง SMS เป็นครั้งแรกจากนั้นควรใส่เวลาปัจจุบันลงใน SendAddressMap หาก Putifabsent ส่งคืน NULL หมายความว่าผู้ใช้กำลังส่ง SMS เป็นครั้งแรกและเวลาปัจจุบันได้ถูกนำไปใส่ในแผนที่และสามารถส่งได้
บรรทัดที่ 30-33: หากผู้ใช้ไม่ได้ส่ง SMS เป็นครั้งแรกคุณจำเป็นต้องพิจารณาว่าเวลาและช่วงเวลาปัจจุบันของการส่ง SMS ครั้งสุดท้ายและช่วงเวลานั้นน้อยกว่าช่วงเวลาที่ส่งหรือไม่ หากน้อยกว่าช่วงเวลาการส่งก็ไม่สามารถส่งได้
บรรทัดที่ 35: หากช่วงเวลามีขนาดใหญ่พอคุณต้องพยายามตั้งค่าเวลาการส่งเป็นเวลาปัจจุบัน
1) จากนั้นคุณสามารถทำซ้ำบรรทัด 25-35 เพื่อให้แน่ใจว่าถูกต้องอย่างแน่นอน
2) คุณสามารถคิดได้โดยตรงว่ามันไม่สามารถส่งได้เพราะถึงแม้ว่าเวลาทางทฤษฎีสำหรับ "การดำเนินการของบรรทัด 26-35" อาจมากกว่า "ช่วงเวลาส่ง" ความน่าจะเป็นเท่าไหร่? โดยทั่วไปสามารถละเว้นได้
รหัสนี้ใช้ข้อ จำกัด ความถี่ แต่ถ้ามีเพียง "ใน" แต่ไม่ใช่ "ออก" เนื้อหาที่ถูกครอบครองโดย SendAddressMap จะมีขนาดใหญ่ขึ้นเรื่อย ๆ จนกว่าจะมีการสร้างข้อยกเว้น OutofMemoryError ต่อไปเราจะเพิ่มรหัสเพื่อทำความสะอาดข้อมูลที่หมดอายุเป็นประจำ
4. ทำความสะอาดข้อมูลที่หมดอายุ
FrequencyFilter.java
/*** ขึ้นอยู่กับรหัสด้านบนเพิ่มรหัสต่อไปนี้*/คลาสสาธารณะความถี่ Filter ใช้ SMSFilter {ส่วนตัว Long Long CleanMapInterval; ตัวจับเวลาส่วนตัว = ตัวจับเวลาใหม่ ("sms_frequency_filter_clear_data_thread"); @Override โมฆะสาธารณะ init () {timer.schedule (timertask ใหม่ () {@Override โมฆะสาธารณะเรียกใช้ () {cleansendaddressmap ();}}, cleanmapinterval, cleanmapinterval); } / *** ลบข้อมูลที่หมดอายุทั้งหมดใน SendAdDressMap* / โมฆะส่วนตัว CleansEndDdressMap () {Long CurrentTime = System.CurrentTimeMillis (); Long ExpiresEndTime = currentTime - SendInterval; สำหรับ (คีย์สตริง: sendaddressmap.keyset ()) {long sendtime = sendaddressmap.get (คีย์); if (sendtime <expiresEndTime) {sendaddressmap.remove (คีย์, sendtime); }}} @Override โมฆะสาธารณะทำลาย () {timer.cancel (); -โปรแกรมนี้ไม่ซับซ้อน เริ่มต้นตัวจับเวลาและดำเนินการวิธี CleanSendDdressMap ทุกมิลลิวินาทีของ CleanMapInterval เพื่อทำความสะอาดข้อมูลที่หมดอายุ
วิธี CleanSendDdressMap ก่อนได้รับเวลาปัจจุบันและได้รับค่าเวลาตามเวลาปัจจุบัน: ข้อความทั้งหมดจะถูกส่งหลังจากเวลานี้ SMS ไม่สามารถส่งได้อีก จากนั้นลบคู่คีย์-ค่าทั้งหมดที่มีค่าเล็กกว่าค่าเวลานี้จากแผนที่ทั้งหมด
แน่นอนหลังจากเพิ่มรหัสด้านบนรหัสเริ่มต้นมีข้อผิดพลาดอื่น: เมื่อบรรทัดสุดท้าย sendaddressmap.replace (id, sendtime, currenttime) ล้มเหลวในการดำเนินการไม่จำเป็นต้องเปลี่ยนเธรดอื่น ๆ แต่ก็เป็นไปได้ที่เธรดการทำความสะอาดได้ลบข้อมูล ดังนั้นเราจำเป็นต้องปรับเปลี่ยนบรรทัดสุดท้ายของวิธีการตั้งค่าเวลา:
FrequencyFilter.java
บูลีนส่วนตัว setSendTime (รหัสสตริง) {// ละเว้นรหัสก่อนหน้าถ้า (sendaddressmap.replace (id, sendtime, currenttime)) {return true; } return sendaddressmap.putifabsent (id, currenttime) == null;}หากการแทนที่ประสบความสำเร็จที่นี่ให้กลับมาจริงโดยตรง
หากการเปลี่ยนไม่สำเร็จอาจเป็นไปได้ว่าเธรดอื่น ๆ ถูกแทนที่ก่อน (ในกรณีแรก); อาจเป็นได้ว่าพวกเขาถูกลบโดยด้ายที่ทำความสะอาด (ในกรณีที่สอง); อาจเป็นได้ว่าพวกเขาถูกลบโดยเธรดที่ทำความสะอาดก่อนและเธรดอื่น ๆ ได้แทรกค่าเวลาใหม่ (ในกรณีที่สาม)
ณ จุดนี้รหัสที่ จำกัด เวลาการส่งจะเสร็จสมบูรณ์ แน่นอนว่าโปรแกรมนี้มีข้อผิดพลาดเล็ก ๆ หรือ "คุณสมบัติ":
หากลูกค้าที่มี IP "192.168.0.1" คำขอส่งข้อความไปยังหมายเลขโทรศัพท์มือถือ "12345678900" จากนั้นขอส่งข้อความไปยังหมายเลขโทรศัพท์มือถือ "12345678900" ภายใน SendInterval บนเครื่องด้วย IP "192.168.0.2" จากนั้นข้อความจะไม่ถูกส่งและครั้งสุดท้ายของหมายเลขโทรศัพท์มือถือ "12345678900" จะถูกตั้งค่าเป็นเวลาปัจจุบัน
5. ตัวอย่างการใช้งาน
ด้านล่างเรามีเลเยอร์เซิร์ฟเวอร์เพื่อแสดงวิธีการรวมรหัสในบทความก่อนหน้าและบทความนี้:
smsservice.java
SMSService ชั้นเรียนสาธารณะ {SMS ส่วนตัว SMS; รายการส่วนตัว <Smsfilter> ตัวกรอง; เทมเพลตคุณสมบัติส่วนตัว // รหัสบางอย่างถูกละเว้น/*** ส่งรหัสการยืนยัน** @param smsentity ข้อมูลพื้นฐานสำหรับการส่งข้อความ* @ @@Return หากการส่งสำเร็จกลับไปที่ 0. มิฉะนั้นส่งคืนค่าอื่น ๆ */ public int sendcaptcha (smsentity smsentity) {สำหรับ (ตัวกรอง smsfilter: ตัวกรอง) {ถ้า (! filter.filter (smsentity)) {return 1; }} if (smsentity.register_type.equals (smsentity.getType ())) {sendregistersms (smsentity); } else {return 2; } return 0; } / *** ส่งรหัสการตรวจสอบการลงทะเบียน** @param smsentity ข้อมูลพื้นฐานสำหรับการส่งข้อความ* / โมฆะส่วนตัว sendregistersms (smsentity smsentity) {sms.sendmessage (smsentity.getMobile (), template.getProperty ("ลงทะเบียน") -จากนั้น "inject" frequencyfilter และ asyncsmsimpl ในบทความก่อนหน้าผ่านวิธีการตั้งค่า
ข้างต้นเป็นเรื่องเกี่ยวกับบทความนี้ฉันหวังว่ามันจะเป็นประโยชน์สำหรับทุกคนในการเรียนรู้การเขียนโปรแกรม Java