تحتوي هذه المقالة فقط على أفكار ولا توفر تنفيذًا محددًا وكاملًا (المدون كسول للغاية لفرزها). إذا كان لديك أي أسئلة أو تريد معرفتها ، فيمكنك إرسال رسالة خاصة أو تعليق.
خلفية
في مشاريع Java التقليدية على شبكة الإنترنت ، يتم استخدام الجلسة عمومًا لتخزين معلومات الجلسة مؤقتًا ، مثل معلومات هوية المسجل. يتم تنفيذ هذه الآلية من خلال استعارة آلية ملف تعريف الارتباط الخاصة بـ HTTP ، ولكن من المثير للقلق أن ينقذ التطبيق ومشاركة معلومات ملفات تعريف الارتباط في كل مرة يطلبها ، والجلسة التقليدية ليست صديقة للأفلام ، وبالتالي فإن خدمات خلفية التطبيق العامة تستخدم الرموز المميزة لتمييز معلومات تسجيل الدخول إلى المستخدم.
يعلم الجميع آلية الجلسة لـ J2EE ، وهي مريحة للغاية للاستخدام ومفيدة للغاية في تطبيقات الويب Java التقليدية. ومع ذلك ، فإن بعض المشاريع التي يمكن استخدامها في مشاريع الإنترنت أو المجموعات لديها بعض المشكلات ، مثل مشاكل التسلسل ، ومشاكل تأخير التزامن ، وما إلى ذلك ، لذلك نحتاج إلى أداة يمكنها حل مشاكل المجموعة التي تشبه الجلسات.
يخطط
نستخدم آلية ذاكرة التخزين المؤقت لحل هذه المشكلة. Redis الأكثر شعبية هي قاعدة بيانات ذاكرة NOSQL ولها آلية فشل ذاكرة التخزين المؤقت ، وهي مناسبة للغاية لتخزين بيانات الجلسة. يجب إرجاع سلسلة الرمز المميز إلى العميل بناءً على الطلب الأول ، ويستخدم العميل هذا الرمز المميز لتحديد الهوية في كل مرة يطلب فيها في المستقبل. من أجل أن نكون شفافين حول تطوير الأعمال ، فإننا نغلف الحزم التي يتم تقديمها حسب طلب التطبيق واستجابةها. نحتاج فقط إلى القيام ببعض الحيل لفئة أداة طلب HTTP الخاصة بالعميل وإطار MVC الخاص بالخادم. تعديل فئة أدوات HTTP الخاصة بالعميل بسيط للغاية ، وخاصة تغليف بروتوكول الخادم.
أفكار التنفيذ
1. صياغة بروتوكول رسالة استجابة الطلب.
2. بروتوكول التحليل يعالج سلاسل رمزية.
3. استخدم Redis للتخزين لإدارة الرموز ومعلومات الجلسة المقابلة.
4. توفير واجهة برمجة التطبيقات لتخزين والحصول على معلومات الجلسة.
سنشرح خطة التنفيذ لكل خطوة.
1. صياغة بروتوكول رسالة استجابة الطلب.
نظرًا لأنك ترغب في تغليف بروتوكول الرسائل ، فأنت بحاجة إلى التفكير في حقل عام ، وما هو حقل الخدمة ، وهيكل بيانات الرسالة ، إلخ.
تتضمن الحقول العامة المطلوبة عمومًا الرمز المميز ، الإصدار ، النظام الأساسي ، النموذج ، IMEI ، مصدر التطبيق ، وما إلى ذلك ، من بينها الرمز الرمزي هو بطل الرواية لدينا هذه المرة.
تشمل الحقول المشتركة للاستجابة عمومًا الرمز المميز ، وحالة النتيجة (النجاح ، الفشل) ، رمز النتيجة (الرمز) ، معلومات النتيجة ، إلخ.
بالنسبة إلى بنية بيانات الحزم ، نختار JSON لأن JSON شائع ، ولديه تصور جيد ، ولديه شغل بايت منخفض.
رسالة الطلب هي كما يلي ، وتخزن الجسم معلومات الأعمال ، مثل اسم المستخدم وكلمة المرور المسجلة ، إلخ.
{"Token": "Token Client Token" ، / ** رقم إصدار العميل* / "الإصدار": 11 ، / ** نوع منصة العميل* / "النظام الأساسي": "iOS" ، / ** نموذج جهاز العميل* / "Machinemodel": "iPhone 6S" ، "eMei": "key2": "key21": "value21"} ، "key3": [1 ،]}}رسالة مستجيبة
{ / ** نجاح* / "النجاح": خطأ ، / ** سيعود كل طلب إلى رمز الرمز المميز ، ويجب على العميل استخدام أحدث رمز لكل طلب* / "رمز الرمز المميز": }}2. بروتوكول التحليل يعالج سلاسل رمزية.
بالنسبة لإطار MVC من جانب الخادم ، نستخدم إطار عمل SpringMVC ، وهو أمر شائع أيضًا ولن يتم وصفه.
دعونا لا نذكر معالجة الرموز في الوقت الحالي. أولاً ، كيفية تمرير المعلمات بعد صياغة الحزمة.
نظرًا لأن معلومات الطلب مغلفة ، من أجل إطار SPRINGMVC لحقن المعلمات التي نحتاجها بشكل صحيح في وحدة التحكم ، نحتاج إلى تحليل الحزم وتحويلها.
لتحليل معلومات الطلب ، نحتاج إلى تخصيص محول المعلمة من springMVC. من خلال تنفيذ واجهة HandlerMethodArgumentResolver ، يمكننا تحديد محول المعلمة
requestBodyResolver يطبق طريقة Resolveargument ويحقق المعلمات. الرمز التالي هو نموذج رمز ، ولا تستخدمه مباشرة.
Override public Object Resolveargument (MethodParameter Parameter ، ModelAndViewContainer mavcontainer ، nativeWebRequest webrequest ، webdatabinderfactory binderfactory) يلقي استثناءً ، يمكنك استخدام أي طريقة ، يمكنك الحصول على أي شيء ، يمكنك الحصول على أي طريقة ، if (stringUtils.isNotBlank (requestBodystr)) {String paramname = parameter.getParameterName () ؛ // الحصول على اسم المعلمة في فئة وحدة التحكم <؟> paramclass = parameter.getParameterType () ؛ // get type in controller/* parses packets من خلال jsonnode class* if (paramclass.equals (serviceRequest.class)) {// serviceRequest هو VO المقابل لـ request serviceRequest serviceRequest = ObjectMapper.ReadValue (jsonnode.traverse () ، servicerequest.class) ؛ إرجاع serviceRequest ؛ // إرجاع هذا الكائن إلى الحقن في المعلمة ، يجب أن يتوافق مع النوع ، وإلا فلن يتم القبض على الاستثناء بسهولة} إذا (jsonnode! = null) {// ابحث عن المعلمات المطلوبة في وحدة التحكم من رسالة jsonnode paramjsonnode = jsonnode.findvalue (paramname) ؛ if (paramjsonnode! = null) {return ObjectMapper.ReadValue (paramjsonnode.traverse () ، paramClass) ؛ }}} return null ؛ }قم بتكوين محول المعلمة الذي حددته في ملف تكوين srpingmvc <mvc: repument-resolvers>
<mvc: incumber-resolvers> <!-معالجة معلومات الطلب الموحدة ، إحضار البيانات من serviceRequest-> <bean id = "requestbodyResolver"> <property name = "ObjectMapper"> <boan> </boan> </property> <! </bean> </mvc: resolvers الوسيطة>
هذا يسمح بتحديد المعلمات في الرسالة بشكل صحيح بواسطة springMVC.
بعد ذلك ، علينا لمعالجة الرمز المميز. نحتاج إلى إضافة اعتراض srpingmvc لاعتراض كل طلب. هذه وظيفة شائعة ولن يتم وصفها بالتفصيل.
Matcher M1 = pattern.compile ("/" token /":/"(.*؟)/ ""). matcher (requestBodystr) ؛ if (m1.find ()) {token = m1.group (1) ؛} tokenMappool.VerifyToken (رمز) ؛ // إجراء المعالجة العامة للرمز المميز والتحققوبهذه الطريقة ، يمكنك الحصول على الرمز المميز ويمكنك إجراء المعالجة العامة.
3. استخدم Redis للتخزين لإدارة الرموز ومعلومات الجلسة المقابلة.
في الواقع ، إنها مجرد كتابة فئة أداة تشغيل Redis. نظرًا لأن الربيع يستخدم كإطار رئيسي للمشروع ، ولا نستخدم العديد من وظائف redis ، فإننا نستخدم مباشرة وظيفة CacheManager التي توفرها الربيع.
تكوين org.springframework.data.redis.cache.rediscachemanager
<!-يمكن استخدام المتغيرات العالمية لمدير ذاكرة التخزين المؤقت ، إلخ. value = ":@webserviceInterface"/> </bean> </sprement> <property name = "expires"> <!-فترة صحة ذاكرة التخزين المؤقت-> <map> <rething> <key> <value> tokenpoolcache </value> </key> <!-اسم مخبأ Tokenpool->
4. توفير واجهة برمجة التطبيقات لتخزين والحصول على معلومات الجلسة.
من خلال المداعبة أعلاه ، قمنا بمعالجة الرمز المميز تقريبًا. بعد ذلك ، سنقوم بتنفيذ أعمال الإدارة الرمزية.
نحتاج إلى جعل تطوير الأعمال مريحًا لتوفير معلومات الجلسة والحصول عليها ، والرموز شفافة.
استيراد kava.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 ؛/** * * اسم الفئة: TokenMappoolbean * الوصف: Token و SPARITING CALL CLASS * RECORD: سجل السجل النهائي الثابت = logfactory.getLog (tokenmappoolbean.class) ؛ / ** الرمز المميز المقابل للطلب الحالي*/ private threadlocal <string> currentToken ؛ Cachemanager الخاص Cachemanager ؛ خيط خاص cachename ؛ TokenGenerator الخاص TokenGenerator ؛ TokenMappoolbean العام (Cachemanager Cachemanager ، سلسلة cachename ، tokengenerator tokengenerator) {this.cachemanager = cachemanager ؛ this.cachename = cachename ؛ this.tokengenerator = tokengenerator ؛ CurrentToken = new threadlocal <string> () ؛ } /*** إذا كان الرمز القانوني قانونيًا ، فقم بإرجاع الرمز المميز. قم بإنشاء رمز جديد وإرجاع ، * ضع الرمز المميز في threadlocal وقم بتهيئة رمز الرمز المميز * param * regurn */ سلسلة عامة VerifyToken (string token) {// log.info("CheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheC heCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheCheC التحقق من exteDtoken = null ؛ (Cache == NULL) {رمي new RunTimeException ("تجمع ذاكرة التخزين المؤقت حيث يتم تخزين الرمز المميز ، chachename:" + cachename) ؛ VerifyedToken = NewToken () ؛ Cachemonager.getcache (Cachename) ؛ ! = null) ؛ {cache cache = cachemanager.getCache (cachename) ؛ (tokenmapwrapper! = null) {tokenmap = (string ، comply) إرجاع tokenmap.get (مفتاح) ؛ الكبرى في كل مرة. Valuewrapper TokenMapper = cache.get (currentToken.) ؛ TokenMapper = cache.get (CurrentToken.) ؛ * احصل على رمز المستخدم إلى مؤشر الترابط الحالي * return */السلسلة العامة getToken () {if (currentToken.get () null) {return ؛ Cachemanager ؛ tokengenerator ؛يتم استخدام متغير ThreadLocal هنا لأن الطلب يتوافق مع مؤشر ترابط في حاوية Servlet ، وهو في نفس الخيط خلال دورة حياة الطلب ، وتشارك سلسلة رسائل Token Manager في نفس الوقت ، لذلك هناك حاجة إلى هذا المتغير المحلي في مؤشر الترابط لحفظ السلسلة الرمزية.
ملحوظات:
1. يجب استدعاء استدعاء طريقة VerifyToken في بداية كل طلب. وبعد اكتمال الطلب ، يتم استدعاء Clear إلى مسح ، حتى لا يتسبب في تنفيذ التحقق من التحقق في المرة القادمة ، ولكن يتم إخراج الرمز المميز من Threadlocal عند عودته. (أزعجني هذا الخطأ لعدة أيام ، ولم يتم العثور على رموز فحص تطوير الشركة. أخيرًا ، بعد الاختبار ، وجدت أنه لم يتم إدخال التقاطع عند حدوث 404 ، لذلك لم أسمي طريقة التحقق ، والتي تسببت في الرمز المميز في معلومات الاستثناء التي تم إرجاعها إلى أن الرمز المطلوب في المرة الأخيرة.
2. يجب على العميل حفظ كل رمز عند تغليف أداة HTTP واستخدامه للطلب التالي. طلب تطوير iOS للشركة الاستعانة بمصادر خارجية ، لكن الاستعانة بمصادر خارجية لم تفعل كما هو مطلوب. عندما لا يتم تسجيل الدخول ، لا يتم حفظ الرمز المميز. في كل مرة يتم فيها تمرير الرمز المميز ، يكون فارغًا ، مما يؤدي إلى إنشاء رمز لكل طلب ، ويقوم الخادم بإنشاء عدد كبير من الرموز غير المجدية.
يستخدم
طريقة الاستخدام بسيطة للغاية. فيما يلي مدير تسجيل الدخول المغلف. يمكنك الرجوع إلى تطبيق Manager Token for Login Manager.
استيراد org.apache.commons.logging.log ؛ import org.apache.commons.logging.logfactory ؛ استيراد org.springframework.cache.cache ؛ import org.springframework.cache.cache.valuewrapper ؛ استيراد org.springframework.cachemoark ؛ com.niuxz.base.constants ؛/** * اسم الفئة: loginManager * الوصف: loginManager * تعديل السجل: * version v1.0 * date يوليو 19 ، 2016 * Author niuxz * */public class loginmanager {private static final log = logfactory.getlog (loginmanager.class) ؛ Cachemanager الخاص Cachemanager ؛ خيط خاص cachename ؛ TokenMappoolbean TokenMappool ؛ loginmanager العامة (Cachemanager Cachemanager ، سلسلة cachename ، tokenmappoolbean tokenmappool) {this.cachemanager = cachemanager ؛ this.cachename = cachename ؛ this.tokenMappool = tokenMappool ؛ } تسجيل الدخول الفراغ العام (سلسلة userId) {log.info ("تسجيل الدخول المستخدم: userId =" + userId) ؛ ذاكرة التخزين المؤقت Cache = cachemanager.getCache (cachename) ؛ ValuewRapper ValuewRapper = cache.get (userId) ؛ TRING TOKEN = (string) (ValuewRapper == null؟ null: valuewrapper.get ()) ؛ TokenMappool.removetokenMap (رمز) ؛ // سجل تسجيل الدخول قبل تسجيل الخروج من TokenMappool.setAttribute (constants.logged_user_id ، userId) ؛ cache.put (userId ، tokenMappool.getToken ()) ؛ } public void logoutCurrent (String phonetel) {String curuserId = getCurrentUserId () ؛ log.info ("تسجيل الدخول المستخدم: userId =" + curuserId) ؛ tokenmappool.removetokenMap (tokenmappool.getToken ()) ؛ // تسجيل الدخول إذا (curuserid! = null) {cache cache = cachemanager.getCache (cachename) ؛ cache.evict (curuserid) ؛ cache.evict (phonetel) ؛ }} / ** * احصل على معرف المستخدم الحالي * regurn * / string public getCurrentuserId () {return (string) tokenMappool.getAttribute (constants.logged_user_id) ؛ } Cachemanager getCachemanager () {return Cachemanager ؛ } السلسلة العامة getCachename () {return cachename ؛ } tokenmappoolbean getTokenMappool () {return tokenmappool ؛ } public void setCachemanager (Cachemanager Cachemanager) {this.cachemanager = cachemanager ؛ } public void setCachename (String cachename) {this.cachename = cachename ؛ } public void settokenMappool (tokenmappoolbean tokenMappool) {this.tokenMappool = tokenMappool ؛ }}فيما يلي واجهة رمز التحقق من الرسائل القصيرة الشائعة. تستخدم بعض التطبيقات أيضًا جلسة لتخزين رموز التحقق. لا أوصي باستخدام هذه الطريقة. عيوب تخزين الجلسات كبيرة جدا. فقط انظر إليه ، لم يكن ما كتبته
public void sendvalicodebyphonenum (سلسلة phonenum ، hintmsg ، سلسلة logsuffix) {validatePhonetimesPace () ؛ // احصل على رمز سلسلة رقم عشوائي 6 بت = codeUtil.getValidateCode () ؛ log.info (رمز + "------>" + phonenum) ؛ // استدعاء رمز التحقق من الرسائل القصيرة لإرسال واجهة retstatus retstatus = msgSendUtils.sendsms (رمز + hintmsg ، phonenum) ؛ if (! retstatus.getisok ()) {log.info (retstatus.toString ()) ؛ رمي ThrowStodataException جديد (ServiceResponsecode.fail_invalid_params ، "لقد فشل رمز التحقق من الهاتف المحمول ، يرجى المحاولة مرة أخرى لاحقًا") ؛ } // إعادة تعيين Session TokenMappool.setAttribute (Constants.Validate_Phone ، phonenum) ؛ tokenmappool.setattribute (constants.validate_phone_code ، code.toString ()) ؛ tokenmappool.setattribute (constants.send_code_wrongnu ، 0) ؛ tokenmappool.setattribute (constants.send_code_time ، date (). getTime ()) ؛ log.info (logSuffix + phonenum + "رمز التحقق من الرسائل القصيرة:" + رمز) ؛ }استجابة المعالجة
سيسأل بعض الطلاب عما إذا كانت هناك عبوة رسائل مستجيبة؟
requestmapping ("record")@reponseBodyPublic ServiceResponse Record (string message) {String userId = loginManager.getCurrentuserId () ؛ messageBoardService.RecordMessage (userId ، message) ؛ إرجاع serviceResponsebuilder.buildsuccess (NULL) ؛}من بينها ، ServiceResponse هو حزمة الاستجابة المغلية VO. نحتاج فقط إلى استخدام شرح @ResponseBody من springMVC. المفتاح هو هذا المنشئ.
استيراد org.apache.commons.lang3.stringUtils ؛ استيراد com.niuxz.base.pojo.serviceresponse ؛ استيراد com.niuxz.utils.spring.springContextutil ؛ استيراد com.niux.web.server.tokenmoolbean ؛/** * date 25 أبريل ، 2016 * مؤلف niuxz * */public class serviceResponsBuilder {/** * إنشاء رسالة استجابة ناجحة * * param body * @Returneponse مع تشغيل ناجح */public static servicerespons SpringContextutil.getBean ("TokenMappool")) .getToken () ، "نجاح العمل" ، الجسم) ؛ } / ** * قم بإنشاء رسالة استجابة ناجحة * * param body * Return A ServiceResponse مع التشغيل الناجح * / Public Static ServiceResponse Buildsuccess (سلسلة الرمز المميز ، جسم الكائن) {إرجاع ServiceResponse الجديد (الرمز المميز ، "Action Success" ، Body) ؛ } / ** * إنشاء رسالة استجابة فاشلة * * param failcode * msg * return serviceResponse التي فشلت في التشغيل * / public static serviceResponse buildFail (int failcode ، string msg) {return buildfail (failcode ، msg ، null) ؛ } / ** * إنشاء رسالة استجابة فاشلة * * param failcode * msg body * return serviceResponse التي فشلت في التشغيل * / public static serviceSponse BuildFail (int failcode ، string msg ، body object) {return new servicerespons StringUtils.isnotblank (MSG)؟ }}نظرًا لأننا نستخدم شكل فئة الأدوات الثابتة ، لا يمكننا حقن كائن TokenMappool (المميز المميز) خلال الربيع ، ثم يمكننا الحصول عليه من خلال واجهة برمجة التطبيقات التي توفرها الربيع. ثم ، عند إنشاء معلومات الاستجابة ، اتصل مباشرة بطريقة getToken () من TokenMappool. ستعود هذه الطريقة إلى سلسلة الرمز المميز المرتبط بالخيط الحالي. مرة أخرى ، من المهم الاتصال بـ Clear يدويًا بعد انتهاء الطلب (أسميه من خلال المعترض العالمي).
المثال أعلاه لإدارة معلومات جلسة التطبيق الخلفية التي تقليد آلية جلسة J2EE هي كل المحتوى الذي أشاركه معك. آمل أن تتمكن من إعطائك مرجعًا وآمل أن تتمكن من دعم wulin.com أكثر.