บทความนี้มีความคิดเท่านั้นและไม่ได้ให้การใช้งานที่เฉพาะเจาะจงและสมบูรณ์ (บล็อกเกอร์ขี้เกียจเกินไปที่จะเรียงลำดับ) หากคุณมีคำถามใด ๆ หรือต้องการทราบคุณสามารถส่งข้อความส่วนตัวหรือความคิดเห็น
พื้นหลัง
ในโครงการ Java Web ขนาดเล็กและขนาดกลางแบบดั้งเดิมเซสชันมักใช้เพื่อจัดเก็บข้อมูลเซสชันชั่วคราวเช่นข้อมูลข้อมูลประจำตัวของเครื่องบันทึก กลไกนี้ถูกนำไปใช้โดยการยืมกลไกคุกกี้ของ HTTP แต่มันเป็นปัญหามากขึ้นสำหรับแอพที่จะบันทึกและแบ่งปันข้อมูลคุกกี้ทุกครั้งที่ร้องขอและเซสชั่นดั้งเดิมไม่เป็นมิตรกับคลัสเตอร์
ทุกคนรู้กลไกเซสชันของ J2EE ซึ่งสะดวกมากในการใช้งานและมีประโยชน์มากในแอปพลิเคชันเว็บ Java แบบดั้งเดิม อย่างไรก็ตามบางโครงการที่สามารถใช้ในโครงการอินเทอร์เน็ตหรือกลุ่มมีปัญหาบางอย่างเช่นปัญหาการทำให้เป็นอนุกรมปัญหาการหน่วงเวลาการซิงโครไนซ์ ฯลฯ ดังนั้นเราจึงต้องการเครื่องมือที่สามารถแก้ปัญหาคลัสเตอร์ที่คล้ายกับเซสชัน
วางแผน
เราใช้กลไกแคชเพื่อแก้ปัญหานี้ Redis ที่ได้รับความนิยมมากขึ้นคือฐานข้อมูลหน่วยความจำ NOSQL และมีกลไกความล้มเหลวของแคชซึ่งเหมาะมากสำหรับการจัดเก็บข้อมูลเซสชัน สตริงโทเค็นจะต้องถูกส่งกลับไปยังลูกค้าในคำขอแรกและลูกค้าใช้โทเค็นนี้เพื่อระบุตัวตนทุกครั้งที่เขาร้องขอในอนาคต เพื่อให้โปร่งใสเกี่ยวกับการพัฒนาธุรกิจเราได้ห่อหุ้มแพ็คเก็ตที่ทำตามคำขอและการตอบสนองของแอป เราเพียงแค่ต้องใช้กลอุบายบางอย่างกับคลาสเครื่องมือคำขอ HTTP ของลูกค้าและกรอบ MVC ของเซิร์ฟเวอร์ การปรับเปลี่ยนคลาสเครื่องมือ HTTP ของไคลเอ็นต์นั้นง่ายมากส่วนใหญ่เป็นการห่อหุ้มโปรโตคอลของเซิร์ฟเวอร์
แนวคิดการใช้งาน
1. กำหนดโปรโตคอลข้อความตอบกลับคำขอ
2. โปรโตคอลการแยกวิเคราะห์กระบวนการโทเค็นสตริง
3. ใช้ Redis เพื่อจัดเก็บเพื่อจัดการโทเค็นและข้อมูลเซสชันที่เกี่ยวข้อง
4. จัดเตรียม API สำหรับการจัดเก็บและรับข้อมูลเซสชัน
เราจะอธิบายแผนการดำเนินงานของแต่ละขั้นตอน
1. กำหนดโปรโตคอลข้อความตอบกลับคำขอ
เนื่องจากคุณต้องการห่อหุ้มโปรโตคอลข้อความคุณต้องพิจารณาว่าฟิลด์สาธารณะคืออะไรฟิลด์บริการโครงสร้างข้อมูลของข้อความ ฯลฯ คืออะไร
ฟิลด์สาธารณะที่ร้องขอโดยทั่วไปรวมถึงโทเค็นเวอร์ชันแพลตฟอร์มโมเดล IMEI แหล่งที่มาของแอพ ฯลฯ ซึ่งโทเค็นเป็นตัวเอกของเราในครั้งนี้
ฟิลด์ทั่วไปของการตอบสนองโดยทั่วไปรวมถึงโทเค็นสถานะผลลัพธ์ (ความสำเร็จล้มเหลว) รหัสผลลัพธ์ (รหัส) ข้อมูลผลลัพธ์ ฯลฯ
สำหรับโครงสร้างข้อมูลแพ็คเก็ตเราเลือก JSON เนื่องจาก JSON เป็นเรื่องธรรมดามีการสร้างภาพข้อมูลที่ดีและมีการเข้าพักแบบไบต์ต่ำ
ข้อความคำขอมีดังนี้และร่างกายเก็บข้อมูลธุรกิจเช่นชื่อผู้ใช้และรหัสผ่านที่บันทึกไว้ ฯลฯ
{"โทเค็น": "ไคลเอ็นต์โทเค็น", / ** ไคลเอนต์บิลด์หมายเลขเวอร์ชัน* / "เวอร์ชัน": 11, / ** ประเภทแพลตฟอร์มไคลเอนต์* / "แพลตฟอร์ม": "ios", / ** รุ่นอุปกรณ์ไคลเอนต์* / "Machinemodel": "iPhone 6S", ":" คีย์ {"key21": "value21"}, "key3": [1,]}}ข้อความตอบสนอง
{ /** ความสำเร็จ* /"ความสำเร็จ": false, /** ทุกคำขอจะกลับไปที่โทเค็นและลูกค้าควรใช้โทเค็นล่าสุดสำหรับแต่ละคำขอ* /"โทเค็น": "เซิร์ฟเวอร์เลือกโทเค็นสำหรับการร้องขอปัจจุบัน" "body": null}}2. โปรโตคอลการแยกวิเคราะห์กระบวนการโทเค็นสตริง
สำหรับเฟรมเวิร์ก MVC ฝั่งเซิร์ฟเวอร์เราใช้เฟรมเวิร์ก SpringMVC ซึ่งเป็นเรื่องธรรมดาและจะไม่ถูกอธิบาย
อย่าพูดถึงการประมวลผลโทเค็นในขณะนี้ ขั้นแรกวิธีการส่งพารามิเตอร์หลังจากกำหนดแพ็คเก็ต
เนื่องจากข้อมูลคำขอถูกห่อหุ้มเพื่อให้เฟรมเวิร์ก SpringMVC เพื่อฉีดพารามิเตอร์ที่เราต้องการในคอนโทรลเลอร์อย่างถูกต้องเราจึงต้องแยกวิเคราะห์และแปลงแพ็กเก็ต
ในการแยกวิเคราะห์ข้อมูลคำขอเราจำเป็นต้องปรับแต่งตัวแปลงพารามิเตอร์ของ SpringMVC โดยการใช้งานอินเตอร์เฟส handlermethodargumentResolver เราสามารถกำหนดตัวแปลงพารามิเตอร์
RequestBodyResolver ใช้วิธีการแก้ไขปัญหาและการฉีดพารามิเตอร์ รหัสต่อไปนี้เป็นรหัสตัวอย่างและอย่าใช้โดยตรง
@Override วัตถุสาธารณะ ResolvearGument (พารามิเตอร์เมธอด PARAMETER, MODELANDVIEWCONTAINER MAVCONTAINER, NativeWebRequest WebRequest, WebDatabinderFactory BinderFactory) โยนข้อยกเว้น {String RequestBodystr = WebRequest.getParameter if (stringutils.isnotblank (requestbodystr)) {string paramname = parameter.getParameterName (); // รับชื่อพารามิเตอร์ในคลาสคอนโทรลเลอร์ <?> paramclass = parameter.getParameterType (); if (paramclass.equals (servicerequest.class)) {// servicerequest เป็น vo ที่สอดคล้องกับแพ็คเก็ตคำขอ servicerequest servicerequest = ObjectMapper.readValue (jsonNode.traverse (), servicerequest.class); ส่งคืน servicerequest; // ส่งคืนวัตถุนี้เพื่อฉีดเข้าไปในพารามิเตอร์มันจะต้องสอดคล้องกับประเภทมิฉะนั้นข้อยกเว้นจะไม่ถูกจับได้ง่าย} ถ้า (jsonNode! = null) {// ค้นหาพารามิเตอร์ที่จำเป็นในคอนโทรลเลอร์จากข้อความ if (paramjsonNode! = null) {return ObjectMapper.ReadValue (paramjsonNode.traverse (), paramclass); }}} return null; -กำหนดค่าตัวแปลงพารามิเตอร์ที่คุณกำหนดไว้ในไฟล์การกำหนดค่า SRPINGMVC <MVC: อาร์กิวเมนต์-Resolvers>
<MVC: อาร์กิวเมนต์-ตัวกระตุ้น> <!-การประมวลผลข้อมูลการร้องขอแบบครบวงจรดึงข้อมูลจาก Servicerequest-> <bean id = "RequestBodyResolver"> <property name = "ObjectMapper"> <Bean> name = "requestbodyparamname"> <value> requestbody </value> </property> </ebean> </mvc: อาร์กิวเมนต์-Resolvers>
สิ่งนี้อนุญาตให้พารามิเตอร์ในข้อความระบุได้อย่างถูกต้องโดย SpringMVC
ต่อไปเราต้องประมวลผลโทเค็น เราจำเป็นต้องเพิ่ม SRPINGMVC Interceptor เพื่อสกัดกั้นการร้องขอแต่ละครั้ง นี่เป็นฟังก์ชั่นทั่วไปและจะไม่ได้รับการอธิบายในรายละเอียด
matcher m1 = pattern.compile ("/" โทเค็น /":/"(.*?)/ ""). matcher (requestbodystr); if (m1.find ()) {token = m1.group (1);} tokenmappool.verifytoken (โทเค็น); // ดำเนินการประมวลผลสาธารณะของโทเค็นและตรวจสอบด้วยวิธีนี้คุณสามารถรับโทเค็นและคุณสามารถทำการประมวลผลสาธารณะได้
3. ใช้ Redis เพื่อจัดเก็บเพื่อจัดการโทเค็นและข้อมูลเซสชันที่เกี่ยวข้อง
ในความเป็นจริงมันเป็นเพียงการเขียนคลาสเครื่องมือการทำงานของ Redis เนื่องจากสปริงถูกใช้เป็นกรอบหลักของโครงการและเราไม่ได้ใช้ฟังก์ชั่นมากมายของ Redis เราจึงใช้ฟังก์ชั่น CacheManager โดยตรงจากฤดูใบไม้ผลิ
กำหนดค่า org.springframework.data.redis.cache.rediscachemanager
<!-Cache Manager ตัวแปรส่วนกลาง ฯลฯ สามารถใช้ในการเข้าถึง-> <bean id = "cachemanager"> <constructor-Arg> <ref bean = "redistemplate"/> </constructor-Arg> <property name = "useprefix" value = "true"/> < value = ":@webServiceInterface"/> </ebean> </perty> <property name = "Expires"> <!-ระยะเวลาความถูกต้องของแคช-> <map> <intry> <sident> <dange> tokenPoolCache </value> </key> <!
4. จัดเตรียม API สำหรับการจัดเก็บและรับข้อมูลเซสชัน
ผ่านการเล่นหน้าข้างต้นเราเกือบจะประมวลผลโทเค็น ต่อไปเราจะใช้งานการจัดการโทเค็น
เราจำเป็นต้องทำให้การพัฒนาธุรกิจสะดวกในการประหยัดและรับข้อมูลเซสชันและโทเค็นมีความโปร่งใส
นำเข้า java.util.hashmap; นำเข้า java.util.map; นำเข้า org.apache.commons.logging.log; นำเข้า org.apache.commons.logging.logfactory; นำเข้า org.springframework.cache.cache; org.springframework.cache.cache.valuewrapper; นำเข้า org.springframework.cache.cachemanager;/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * {บันทึกสุดท้ายคงที่ส่วนตัวบันทึก = logfactory.getLog (tokenmappoolbean.class); / ** โทเค็นที่สอดคล้องกับคำขอปัจจุบัน*/ Private ThreadLocal <String> currentToken; cachemanager ส่วนตัว cachemanager; cachename สตริงส่วนตัว; Tokengenerator ส่วนตัว; Public Tokenmappoolbean (CacheManager Cachemanager, String Cachename, Tokengenerator Tokengenerator) {this.cachemanager = cachemanager; this.cachename = cachename; this.tokengenerator = tokengenerator; currentToken = new ThreadLocal <String> (); } /*** หากโทเค็นถูกกฎหมายให้กลับมาโทเค็น สร้างโทเค็นใหม่และส่งคืน * ใส่โทเค็นใน ThreadLocal และเริ่มต้น tokenMap * @param โทเค็น * @@Return token */ สตริงสาธารณะ VerifyToken (โทเค็นสตริง) {// log.info("CheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheC heCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheC VerifyedToken = null; ถ้า (tokengenerator.checktokenformat (โทเค็น)) {// log.info ("checktoken ประสบความสำเร็จ:/"+โทเค็น+"/" "); verifyedToken = token; CacheManager.getCache (cachename); ถ้า (cache == null) {โยน runtimeException ใหม่ ("Cache Pool ที่ไม่สามารถเก็บไว้ได้ null || ค่า () == null) {VerifyedToken = newToken (); Newtoken () {cache cache = cachemanager.getcache (cachename); } ในขณะที่ (cache.get (newtoken)! = null); คำขอจำลองเซสชัน */ วัตถุสาธารณะ getAttribute (คีย์สตริง) {แคชแคช = cacheManager.getCache (cachename); cache.get (currenttoken.get ()); cache.get (currenttoken.get ()); cache.put (currenttoken.get (), tokenmap); CacheManager.getCache (cachename); ถ้า (cache == null) {โยน runtimeException ใหม่ ("ไม่สามารถรับแคชพูลที่โทเค็นถูกเก็บไว้ (tokenmapwrapper! = null) {tokenmap = (แผนที่ <string, object>) tokenmapwrapper.get (); tokenMapwrapper.get (); if (currenttoken.get () == null) {// เริ่มต้นโทเค็นเมื่อ VerifyToken (null); CacheManager.getCache (Cachename); หาก (Cache == NULL) {โยน RuntimeException ใหม่ ("Cachename:" Cachename); SetCacheManager (CacheManager CacheManager) {This.CacheManager = CacheManager; Settokengenerator (Tokengenerator Tokengenerator) {this.tokengenerator = tokengenerator;ตัวแปร ThreadLocal ถูกใช้ที่นี่เนื่องจากคำขอสอดคล้องกับเธรดในคอนเทนเนอร์ servlet และอยู่ในเธรดเดียวกันในระหว่างวงจรชีวิตของคำขอและหลายเธรดแบ่งปันตัวจัดการโทเค็นในเวลาเดียวกัน
หมายเหตุ:
1. การเรียกใช้วิธีการตรวจสอบจะต้องเรียกใช้ในตอนต้นของการร้องขอแต่ละครั้ง และหลังจากคำขอเสร็จสมบูรณ์แล้ว Clear จะถูกเรียกให้ชัดเจนเพื่อไม่ให้ VerificationToken ถูกดำเนินการในครั้งต่อไป แต่โทเค็นจะถูกนำออกมาจาก ThreadLocal เมื่อมันกลับมา (ข้อผิดพลาดนี้ทำให้ฉันรำคาญเป็นเวลาหลายวันและไม่พบรหัสตรวจสอบการพัฒนาของ บริษัท ในที่สุดหลังจากการทดสอบฉันพบว่าตัวดักจับไม่ได้ป้อนเมื่อ 404 เกิดขึ้นดังนั้นฉันไม่ได้เรียกวิธีการตรวจสอบความถูกต้อง
2. ไคลเอนต์จะต้องบันทึกโทเค็นแต่ละตัวเมื่อห่อหุ้มเครื่องมือ HTTP และใช้สำหรับคำขอถัดไป การพัฒนา iOS ของ บริษัท ร้องขอการเอาท์ซอร์ส แต่การเอาท์ซอร์สไม่ได้ทำตามที่ต้องการ เมื่อไม่เข้าสู่ระบบโทเค็นจะไม่ถูกบันทึกไว้ ทุกครั้งที่โทเค็นถูกส่งผ่านมันจะเป็นโมฆะส่งผลให้โทเค็นถูกสร้างขึ้นสำหรับแต่ละคำขอและเซิร์ฟเวอร์สร้างโทเค็นไร้ประโยชน์จำนวนมาก
ใช้
วิธีการใช้งานก็ง่ายมาก ต่อไปนี้เป็นตัวจัดการการเข้าสู่ระบบที่ห่อหุ้ม คุณสามารถอ้างถึงแอปพลิเคชันของ Token Manager สำหรับ Login Manager
นำเข้า org.apache.commons.logging.log; นำเข้า org.apache.commons.logging.logfactory; นำเข้า org.springframework.cache.cache; นำเข้า org.springframework.cache.cache.valuewrapper; com.niuxz.base.constants;/** * ชื่อคลาส: LoginManager * คำอธิบาย: LoginManager * แก้ไขบันทึก: * @version v1.0 * @date 19 กรกฎาคม 2016 * @author niuxz */คลาสสาธารณะ LoginManager cachemanager ส่วนตัว cachemanager; cachename สตริงส่วนตัว; Tokenmappoolbean ส่วนตัว Tokenmappool; Public LoginManager (CacheManager CacheManager, String Cachename, TokenMappoolebean Tokenmappool) {this.cacheManager = CacheManager; this.cachename = cachename; this.tokenmappool = tokenmappool; } การเข้าสู่ระบบโมฆะสาธารณะ (String userId) {log.info ("ผู้ใช้เข้าสู่ระบบ: userId =" + userId); แคชแคช = cachemanager.getCache (cachename); ValueWrapper ValueWrapper = cache.get (userId); สตริงโทเค็น = (สตริง) (valueWrapper == null? null: valueWrapper.get ()); tokenmappool.removetokenmap (โทเค็น); // บันทึกการเข้าสู่ระบบก่อนที่จะเข้าสู่ระบบ tokenmappool.setAttribute (ค่าคงที่ logged_user_id, userid); cache.put (userId, tokenmappool.getToken ()); } โมฆะสาธารณะ logoutcurrent (สตริง phonetel) {String curuserId = getCurrentUserId (); log.info ("การออกจากระบบผู้ใช้: userId =" + curuserId); tokenmappool.removetokenmap (tokenmappool.getToken ()); // เข้าสู่ระบบถ้า (curuserid! = null) {แคชแคช = cachemanager.getCache (cachename); cache.evict (Curuserid); cache.evict (Phonetel); }} / ** * รับ ID ของผู้ใช้ปัจจุบัน * @return * / สตริงสาธารณะ getCurrentUserId () {return (สตริง) tokenMappool.getAttribute (ค่าคงที่ logged_user_id); } Public CacheManager getCacheManager () {return cachemanager; } สตริงสาธารณะ getCachename () {return cachename; } สาธารณะ tokenmappoolbean getTokenMappool () {return tokenmappool; } โมฆะสาธารณะ SetCacheManager (CacheManager CacheManager) {this.CacheManager = CacheManager; } โมฆะสาธารณะ setCachename (สตริง cachename) {this.cachename = cachename; } โมฆะสาธารณะ SettokenMappool (TokenMappoolebean TokenMappool) {this.tokenmappool = tokenmappool; -ด้านล่างนี้เป็นอินเทอร์เฟซรหัสตรวจสอบ SMS ทั่วไป บางแอปพลิเคชันยังใช้เซสชันเพื่อจัดเก็บรหัสการตรวจสอบ ฉันไม่แนะนำให้ใช้วิธีนี้ ข้อเสียของการจัดเก็บเซสชันค่อนข้างใหญ่ แค่ดูมันไม่ใช่สิ่งที่ฉันเขียน
โมฆะสาธารณะ sendvalicodebyphonenum (สตริง phonenum, สตริง hintmsg, สตริง logsuffix) {validatephonetimespace (); // รับรหัสสตริงหมายเลขสุ่ม 6 บิต = codeUtil.getValidateCode (); log.info (รหัส + "------>" + phonenum); // เรียกรหัสการตรวจสอบ SMS เพื่อส่งอินเตอร์เฟส retstatus retstatus = msgsendutils.sendsms (รหัส + hintmsg, phonenum); if (! retstatus.getisok ()) {log.info (retstatus.toString ()); โยน ThrowstodataException ใหม่ (ServicerEsponsecode.fail_invalid_params, "รหัสการตรวจสอบโทรศัพท์มือถือล้มเหลวในการรับโปรดลองอีกครั้งในภายหลัง"); } // รีเซ็ตเซสชัน tokenmappool.setAttribute (ค่าคงที่ validate_phone, phonenum); tokenmappool.setAttribute (ค่าคงที่ validate_phone_code, code.toString ()); tokenmappool.setAttribute (ค่าคงที่ SEND_CODE_WRONGNU, 0); tokenmappool.setAttribute (ค่าคงที่ send_code_time, วันที่ใหม่ (). getTime ()); log.info (logsuffix + phonenum + "รหัสการตรวจสอบ SMS:" + รหัส); -การตอบสนองการประมวลผล
นักเรียนบางคนจะถามว่ามีบรรจุภัณฑ์ข้อความตอบสนองหรือไม่?
@RequestMapping ("บันทึก")@ResponseBodyPublic ServiceResponse Record (ข้อความสตริง) {string userId = loginManager.getCurrentUserId (); Messageboardservice.RecordMessage (USERID, ข้อความ); Return ServicerEsponSebuilder.buildSuccess (NULL);}ในหมู่พวกเขา ServicerEsponse เป็นแพ็คเก็ตตอบสนองที่ห่อหุ้มด้วย VO เราแค่ต้องใช้คำอธิบายประกอบ @ResponseBody ของ SpringMVC กุญแจสำคัญคือผู้สร้างนี้
นำเข้า org.apache.Commons.lang3.Stringutils; นำเข้า com.niuxz.base.pojo.serviceresponse; นำเข้า com.niuxz.utils.spring.springcontextutil; นำเข้า com.niuxz.web.server.token.token @date 25 เมษายน 2016 * @author niuxz * */คลาสสาธารณะ serviceresponseBuilder {/** * สร้างข้อความตอบกลับที่ประสบความสำเร็จ * * @param body * @return a serviceresponse ด้วยการดำเนินการที่ประสบความสำเร็จ */สาธารณะ SpringContextutil.getBean ("Tokenmappool")) .getToken (), "ความสำเร็จในการกระทำ", ร่างกาย); } / ** * สร้างข้อความตอบกลับที่ประสบความสำเร็จ * * @param body * @@return a serviceresponse ด้วยการดำเนินการที่ประสบความสำเร็จ * / สาธารณะ serviceresponse แบบคงที่ buildsuccess (โทเค็นสตริง, วัตถุวัตถุ) {ส่งคืน serviceresponse ใหม่ (โทเค็น, "การกระทำที่ประสบความสำเร็จ", ร่างกาย); } / ** * สร้างข้อความตอบกลับที่ล้มเหลว * * @param FailCode * msg * @return a servicerEsponse ที่ล้มเหลวการดำเนินการ * / สาธารณะ serviceresponse buildfail (int failcode, สตริง msg) {ส่งคืน buildfail (failcode, msg, null); } / ** * สร้างข้อความตอบกลับที่ล้มเหลว * * @param failcode * msg body * @return a serviceresponse ที่ล้มเหลวการทำงาน * / สาธารณะ serviceresponse buildfail (int failcode, string msg, body วัตถุ) stringutils.isnotblank (msg)? msg: "การดำเนินการล้มเหลว", ร่างกาย); -เนื่องจากเราใช้รูปแบบของคลาสเครื่องมือแบบคงที่เราจึงไม่สามารถฉีดไปยังวัตถุ Tokenmappool (Token Manager) ผ่านฤดูใบไม้ผลิจากนั้นเราสามารถรับมันผ่าน API ที่ให้ไว้ในฤดูใบไม้ผลิ จากนั้นเมื่อสร้างข้อมูลการตอบกลับให้เรียกใช้วิธีการ getToken () โดยตรงของ tokenmappool วิธีนี้จะส่งคืนสตริงโทเค็นที่ถูกผูกไว้ด้วยเธรดปัจจุบัน อีกครั้งมันเป็นสิ่งสำคัญที่จะเรียก Clear ด้วยตนเองหลังจากคำขอสิ้นสุดลง (ฉันเรียกมันว่าผ่านตัวดักจับทั่วโลก)
ตัวอย่างข้างต้นของการจัดการข้อมูลเซสชันแอปแบ็กเอนด์ที่เลียนแบบกลไกเซสชันของ J2EE คือเนื้อหาทั้งหมดที่ฉันแบ่งปันกับคุณ ฉันหวังว่าคุณจะให้ข้อมูลอ้างอิงและฉันหวังว่าคุณจะสนับสนุน wulin.com มากขึ้น