مقدمة خدمة الراحة
خدمة Restful هي نموذج معماري أصبح أكثر شعبية في السنوات الأخيرة. تلعب خدمة الويب الخفيفة الوزن GET Native و PUT و POST و DELETE لبروتوكول HTTP. بالمقارنة مع SOAP المعقدة و XML-RPC ، من الواضح أن خدمات الويب الخاصة بوضع REST أكثر إيجازًا ، وبدأت المزيد والمزيد من خدمات الويب في اعتماد تصميم وتنفيذ أسلوب الراحة. على سبيل المثال ، يوفر Amazon.com خدمات الويب القريبة من نمط الراحة لعمليات البحث عن الكتب ؛ خدمات الويب التي توفرها Yahoo هي أيضًا أسلوب راحة. الباقي ليس دائمًا الخيار الصحيح. لقد أصبح شائعًا كوسيلة لتصميم خدمات الويب التي تعتمد بشكل أقل على البرامج الوسيطة الملكية ، مثل خادم التطبيق ، مقارنةً بالطرق المستندة إلى SOAP و WSDL. بمعنى ما ، من خلال التأكيد على معايير الإنترنت المبكرة مثل URI و HTTP ، يعد REST انحدارًا على نهج الويب قبل عصر خوادم التطبيقات الكبيرة.
مثال كما هو موضح في الشكل التالي:
مفتاح استخدام REST هو كيفية تجريد الموارد. كلما كان التجريد أكثر دقة ، كلما كان تطبيق الراحة أفضل.
المبادئ الرئيسية لخدمة الراحة:
1. أعط جميع الكائنات معرف
2. قم بتوصيل الكائنات معًا
3. استخدم الطرق القياسية
4. تمثيلات متعددة للموارد
5. الاتصالات عديمة الجنسية
تقدم هذه المقالة كيفية إنشاء إطار عمل لخدمة الراحة البسيط استنادًا إلى Boot Spring ، وكيفية تنفيذ مصادقة خدمة REST من خلال التعليقات التوضيحية المخصصة
بناء إطار عمل
pom.xml
أولاً ، إدخال التبعيات ذات الصلة ، واستخدم mongoDB لقواعد البيانات ، واستخدم Redis لذاكرة التخزين المؤقت
ملاحظة: لا يوجد Tomcat المستخدمة هنا ، ولكنه يتعهد
<Rependency> <roupED> org.springframework.boot </rougiD> <intifactid> Spring-Boot-Starter </shintifactid> </sophiledency> <sependency> <roupiD> org.springframework.boot </rougiD> <roughid> org.springframework.boot </groupId> <StifactId> Spring-boot-starter-web </shotifactid> <arvisions> <Section> <roupiD> org.springframework.boot </groupid> <Rependency> <roupeD> org.springframework.boot </rougiD> <intifactid> Spring-Boot-Starter-undertow </tenfactid> </sependency> <!-دعم-> <reperency> <roupend> org.springframework.boot </groupid> </reperency> <!-دعم mongoDB-> <redency> <roupiD> org.springframework.boot </groupid> <StifactId> spring-boot-starter-data-mongodb </shintifactid> </premency>
قدم خدمات دعم الويب الخاصة بـ spring-boot-starter-web
يمكن تقديم Dring-boot-starter-data-redis و spring-boot-starter-data-mongodb بسهولة استخدام mongodb و redis
ملف التكوين
وظيفة ملفات التعريف
من أجل تسهيل التمييز بين بيئة التطوير والبيئة عبر الإنترنت ، يمكن استخدام وظيفة الملامح لإضافتها في التطبيق.
spring.profiles.active=dev
ثم أضف Application-dev.properties كملف تكوين DEV.
تكوين موند
فقط قم بتكوين عنوان قاعدة البيانات
spring.data.mongodb.uri = mongodb: // ip: port/database؟ readpreference = primaryPreferred
تكوين redis
spring.redis.database = 0 # redis عنوان خادم spring.redis.host = ip # redis connect server port spring.redis.port = 6379 # redis connect connect spring.redis.pool.max-wait = -1 # اتصال الخمول الأقصى في تجمعات الاتصال spring.redis.pool.max-idle = 8 # اتصال الخمول الحد الأدنى في تجمعات الاتصال spring.redis.pool.min-idle = 0 # مهلة التوصيل (ms) spring.timeout = 0
الوصول إلى البيانات
mongdb
الوصول إلى mongdb بسيط للغاية. يمكنك تحديد الواجهة مباشرة يمتد mongorepository. بالإضافة إلى ذلك ، يمكن أن يدعم بناء جملة JPA ، على سبيل المثال:
@componentpublic interface userrepository يمتد mongoRepository <user ، integer> {public user findbyusername (string username) ؛}عند استخدامه ، فقط أضف التعليق التوضيحي Autowired.
ComponentPublic Class AuthService يمتد Baseservice {autowired userrepository userrepository ؛ }Redis Access
استخدم stringRediStemplate للوصول إلى redis مباشرة
ComponentPublic Class Baseservice {Autowired mongotemplate mongotemplate ؛ Autowired stringRediStemplate stringRediStemplate ؛ }بيانات المتجر:
.stringRediStemplate.OpSforValue (). set (token_key ، user.getId ()+"" ، token_max_age ، timeUnit.Seconds) ؛
حذف البيانات:
StringRediStemplate.Delete (getFormattoken (AccessToken ، Platform)) ؛
خدمات الويب
حدد فئة وحدة تحكم ، وأضف RestController ، واستخدم requestmapping لتعيين مسار عنوان URL
RestControllerPublic Class AuthController يمتد BaseController {REquestMapping (value = {"/"} ، أنتج = "application/json ؛ charset = utf-8" ، method = {requestmethod.get ، requestMethod.post}) recsponsebody public main () {return "hello! }}ابدأ الآن ، يجب أن تكون قادرًا على رؤية Hello World! إنه
مصادقة الخدمة
آلية AccessToken البسيطة
توفير واجهة تسجيل الدخول. بعد نجاح المصادقة ، يتم إنشاء AccessToken. عند الوصول إلى الواجهة في المستقبل ، يتم إحضار AccessToken معها. يستخدم الخادم AccessToken لتحديد ما إذا كان مستخدمًا قانونيًا.
للراحة ، يمكنك حفظ AccessToken في Redis وتعيين فترة الصلاحية.
TRING TOKEN = ENCRYPTIONUTILS.SHA256HEX (string.format ("٪ s ٪ s" ، user.getUserName () ، system.currentTimeMillis ())) ؛ سلسلة token_key = getFormattoken (رمز ، منصة) ؛ this.StringRediStemplate.OpSforValue (). set (token_key ، user.getId ()+"" ، token_max_age ، timeUnit.Seconds) ؛مصادقة الهوية اعتراضية
من أجل تسهيل مصادقة الهوية الموحدة ، يمكن إنشاء اعتراض بناءً على آلية اعتراض الربيع لأداء مصادقة موحدة.
الطبقة العامة AuthCheckEnterceptor تنفذ معالج {}لجعل المفعول للاعتراض ، هناك حاجة إلى خطوة أخرى لإضافة التكوين:
ConfigurationPublic Class SessionConfiguration يمتد WebMVCConfigureRadapter Override public void additpectors (سجل InterceptorRegistry) {super.addinterceptors (السجل) ؛ // إضافة interceptor registry.addInterceptor (AuthCheckInterceptor) .addpathpatterns ("/**") ؛ }}تعليقات المصادقة المخصصة
من أجل تحسين مصادقة الإذن ، على سبيل المثال ، لا يمكن الوصول إلى بعض الواجهات إلا من قبل الأشخاص الذين لديهم أذونات محددة ، ويمكن حلها بسهولة من خلال التعليقات التوضيحية المخصصة. في التعليق التوضيحي المخصص ، فقط أضف أدوارًا.
/*** تعليق مراجعة التحقق من الإذن*/@target (elementType.Method) retention (attreentionpolicy.runtime) documentedpublic interface authcheck {/*** قائمة الدور* return*/string []منطق التفتيش:
طالما تتم إضافة الواجهة مع توضيح AuthCheck ، يجب أن تكون مسجلة في المستخدم
إذا تم تحديد الأدوار ، بالإضافة إلى تسجيل الدخول ، يجب أن يكون للمستخدم أيضًا الدور المقابل.
string [] تجاهل = سلسلة جديدة [] {"/" /user/.* "،" /cat/.* "،" /app/.* "،"/error "} ؛ prehandle boolean العامة (httpservletrequest httpservletrequest ، httpservletresponse httpservletresponse ، معالج الكائن) يلقي استثناء {// 0 التحقق من المعلمات العامة if (! checkparams ("منصة" ، httpservledrequest ، httpservletsponse)) } // 1. تجاهل url url url url التحقق = httpservletrequest.getRequesturi (). toString () ؛ لـ (سلسلة تجاهل: تجاهل) {if (url.matches (dectionurl)) {return true ؛ }} // 2. طريقة طريقة = معالجة. getMethod () ؛ // Query anotation authcheck authcheck = method.getAnnotation (authcheck.class) ؛ if (authcheck == null) {// no enronotation ، no return true ؛ } // 3. إذا كان هناك تعليق توضيحي ، تحقق من AccessToken أولاً إذا (! checkparams ("AccessToken" ، httpservletrequest ، httpservletresponse)) {return false ؛ } // تحقق مما إذا كان الرمز المميز ينتهي صلاحيته userId = AuthService.getuserIdRomToken (httpservletrequest.getParameter ("AccessToken") ، httpservletrequest.getParameter ("platform")) ؛ if (userId == null) {logger.debug ("AccessToken) timeout") ؛ Output (reponseresult.builder.error ("AccessToken Epared"). build () ، httpservletponse) ؛ return false ؛} // 4. if (AuthCheck.Roles ()! = null && authcheck.roles. فشل (! ISMatch) {return false ؛ تغليف نتيجة استجابة الخدمة
أضف منشئًا لتسهيل توليد النتائج النهائية
Public Class Responsertult {public static class builder {reploysultultsultsult ؛ خريطة <سلسلة ، كائن> datamap = maps.newhashmap () ؛ Public Builder () {this.sponseresult = new reploysult () ؛ } البناء العام (String State) {this.responseresult = new replseresult (state) ؛ } puilder static builder newbuilder () {return new builder () ؛ } Success Builder Static Public () {Return New Builder ("Success") ؛ } خطأ باني ثابت عام (رسالة سلسلة) {builder builder = new Builder ("error") ؛ builder.sponseresult.seterror (رسالة) ؛ عودة باني. } Public Builder Aspend (مفتاح السلسلة ، بيانات الكائن) {this.datamap.put (المفتاح ، البيانات) ؛ إرجاع هذا ؛ } / *** تعيين بيانات قائمة* param بيانات البيانات* return* / public builder setListData (قائمة <؟> datas) {this.datamap.put ("result" ، datas) ؛ this.datamap.put ("total" ، datas.size ()) ؛ إرجاع هذا ؛ } الباني العام setData (بيانات الكائن) {this.datamap.clear () ؛ this.sponseresult.setData (البيانات) ؛ إرجاع هذا ؛ } boolean wrapdata = false ؛ / ** * التفاف البيانات في البيانات * param wrapdata * return */ public builder wrap (boolean wrapdata) {this.wrapdata = wrapdata ؛ إرجاع هذا ؛ } السلسلة العامة build () {jsonobject jsonobject = new jsonobject () ؛ jsonobject.put ("State" ، this.sponseresult.getState ()) ؛ if (this.responseresult.getState (). يساوي ("خطأ")) {jsonobject.put ("خطأ" ، this.responseresult.geterror ()) ؛ } if (this.responseresult.getData ()! = null) {jsonobject.put ("data" ، json.tojson (this.responseresult.getData ())) ؛ } آخر if (datamap.size ()> 0) {if (wrapdata) {jsonobject data = new JsonObject () ؛ datamap.foreach ((المفتاح ، القيمة) -> {data.put (المفتاح ، القيمة) ؛}) ؛ jsonobject.put ("البيانات" ، البيانات) ؛ } آخر {datamap.foreach ((المفتاح ، القيمة) -> {jsonobject.put (المفتاح ، القيمة) ؛}) ؛ }} return jsonobject.tojsonstring () ؛ }} حالة السلسلة الخاصة ؛ بيانات الكائنات الخاصة ؛ خطأ في السلسلة الخاصة ؛ السلسلة العامة geterror () {return error ؛ } public void seterror (خطأ في السلسلة) {this.error = error ؛ } Public Responseresult () {} Public Responseresult (String rc) {this.state = rc ؛ } / ** * return عندما ناجح * param rc * param result * / public replseresult (String rc ، Object result) {this.state = rc ؛ this.data = النتيجة ؛ } السلسلة العامة getState () {return state ؛ } public void setState (String State) {this.state = state ؛ } الكائن العام getData () {return data ؛ } public void setData (بيانات الكائن) {this.data = data ؛ }} كن أكثر أناقة عند الاتصال
requestmapping (value = {"/user/login" ، "/pc/user/login"} ، reduces = "application/json ؛ charset = utf-8" ، method = {requestMethod.get ، requestMethod.post}) @reginbody public (stername username ، string platform) if (user! = null) {// log in to string token = authService.upDateToken (user ، platform) ؛ إرجاع Responseresult.Builder .Sccess () .Append ("AccessToken" ، Token) .Append ("userId" ، user.getId ()) .build () ؛ } إرجاع Responseresult.builder.error ("المستخدم غير موجود أو كلمة المرور خاطئة"). Build () ؛ } خطأ في السلسلة المحمي (رسالة سلسلة) {return replostult.builder.error (message) .build () ؛ } نجاح السلسلة المحمي () {return ResponserSult.Builder .Success () .build () ؛ } String String SuccessDatalist (قائمة <؟> Data) {Return ResponserSult.Builder .Success () .wrap (true) // data package.setListData (data) .build () ؛ }لخص
ما سبق هو المحتوى الكامل لهذه المقالة. آمل أن يكون لمحتوى هذه المقالة قيمة مرجعية معينة لدراسة أو عمل الجميع. إذا كان لديك أي أسئلة ، فيمكنك ترك رسالة للتواصل. شكرا لك على دعمك إلى wulin.com.