تطبيق ويب MVC الأساسي في GO
يوضح هذا المشروع كيفية هيكلة وإنشاء موقع ويب باستخدام لغة GO بدون إطار عمل. هناك مقالة مدونة يمكنك قراءتها على http://www.josephspurrier.com/go-web-app-example/. يوجد تطبيق كامل قمت ببنيه مع إصدار سابق من المشروع على https://github.com/verifiedninja/webapp. يوجد إصدار API من هذا المشروع على https://github.com/josephspurrier/gowebapi.
للتنزيل ، قم بتشغيل الأمر التالي:
go get github.com/josephspurrier/gowebapp
إذا كنت مستمراً في GO 1.5 ، فأنت بحاجة إلى تعيين Govendorexperiment على 1. إذا كنت مستمراً 1.4 أو قبل ذلك ، فلن يعمل الرمز لأنه يستخدم مجلد البائع.
سيتم إنشاء ملف gowebapp.db بمجرد بدء التطبيق.
بناء وتشغيل من دليل الجذر. افتح متصفح الويب الخاص بك إلى: http: // localhost. يجب أن ترى صفحة الترحيب.
انتقل إلى صفحة تسجيل الدخول ، ثم إلى صفحة التسجيل. قم بإنشاء مستخدم جديد ويجب أن تكون قادرًا على تسجيل الدخول. هذا كل شيء.
ابدأ mongodb.
افتح config/config.json وقم بتحرير قسم قاعدة البيانات بحيث تتطابق معلومات الاتصال على مثيل MongoDB الخاص بك. أيضا ، تغيير النوع من الترباس إلى mongodb.
بناء وتشغيل من دليل الجذر. افتح متصفح الويب الخاص بك إلى: http: // localhost. يجب أن ترى صفحة الترحيب.
انتقل إلى صفحة تسجيل الدخول ، ثم إلى صفحة التسجيل. قم بإنشاء مستخدم جديد ويجب أن تكون قادرًا على تسجيل الدخول. هذا كل شيء.
ابدأ MySQL واستيراد config/mysql.sql لإنشاء قاعدة البيانات والجداول.
افتح config/config.json وقم بتحرير قسم قاعدة البيانات بحيث تتطابق معلومات الاتصال على مثيل MySQL الخاص بك. أيضا ، تغيير النوع من الترباس إلى MySQL.
بناء وتشغيل من دليل الجذر. افتح متصفح الويب الخاص بك إلى: http: // localhost. يجب أن ترى صفحة الترحيب.
انتقل إلى صفحة تسجيل الدخول ، ثم إلى صفحة التسجيل. قم بإنشاء مستخدم جديد ويجب أن تكون قادرًا على تسجيل الدخول. هذا كل شيء.
يحتوي تطبيق الويب على صفحة رئيسية عامة ، وصفحة منزلية مصادقة ، وصفحة تسجيل الدخول ، وصفحة التسجيل ، والصفحة ، ومفكرة بسيطة لإظهار عمليات CRUD.
نقطة الدخول لتطبيق الويب هي gowebapp.go. يقوم الملف بتحميل إعدادات التطبيق ، ويبدأ الجلسة ، ويتصل بقاعدة البيانات ، ويقوم بإعداد القوالب ، ويقوم بتحميل الطرق ، ويعلق على البرامج الوسيطة ، ويبدأ خادم الويب.
تم تصميم الواجهة الأمامية باستخدام bootstrap مع بعض التغييرات الصغيرة على الخطوط والتباعد. يتم تخصيص رسائل الفلاش بحيث تظهر في أسفل يمين الشاشة.
يجب عرض جميع رسائل الخطأ ورسائل التحذير إما إلى المستخدم أو في وحدة التحكم. يتم عرض الرسائل المعلوماتية إلى المستخدم عبر رسائل الفلاش التي تختفي بعد 4 ثوان. يتم التحكم في رسائل الفلاش بواسطة JavaScript في المجلد الثابت.
في الآونة الأخيرة ، تغير بنية المجلد. بعد النظر إلى جميع الشوكات وإعادة استخدام مشروعي في أماكن مختلفة ، قررت نقل رمز GO إلى مجلد التطبيق داخل مجلد البائع حتى لا يتم تناثر مسار الجيش في جميع الواردات. لم أكن أرغب في استخدام المسارات النسبية ، لذا بدا مجلد البائع وكأنه الخيار الأفضل.
تم تنظيم المشروع في المجلدات التالية:
config - application settings and database schema
static - location of statically served files like CSS and JS
template - HTML templates
vendor/app/controller - page logic organized by HTTP methods (GET, POST)
vendor/app/shared - packages for templates, MySQL, cryptography, sessions, and json
vendor/app/model - database queries
vendor/app/route - route information and middleware
هناك بعض الحزم الخارجية:
github.com/gorilla/context - registry for global request variables
github.com/gorilla/sessions - cookie and filesystem sessions
github.com/go-sql-driver/mysql - MySQL driver
github.com/haisum/recaptcha - Google reCAPTCHA support
github.com/jmoiron/sqlx - MySQL general purpose extensions
github.com/josephspurrier/csrfbanana - CSRF protection for gorilla sessions
github.com/julienschmidt/httprouter - high performance HTTP request router
github.com/justinas/alice - middleware chaining
github.com/mattn/go-sqlite3 - SQLite driver
golang.org/x/crypto/bcrypt - password hashing algorithm
يتم تنظيم القوالب في مجلدات تحت مجلد القالب :
about/about.tmpl - quick info about the app
index/anon.tmpl - public home page
index/auth.tmpl - home page once you login
login/login.tmpl - login page
notepad/create.tmpl - create note
notepad/read.tmpl - read a note
notepad/update.tmpl - update a note
partial/footer.tmpl - footer
partial/menu.tmpl - menu at the top of all the pages
register/register.tmpl - register page
base.tmpl - base template for all the pages
هناك عدد قليل من الفانكات القالب المتاحة لجعل العمل مع القوالب والملفات الثابتة أسهل:
<!-- CSS files with timestamps -->
{{CSS "static/css/normalize3.0.0.min.css"}}
parses to
< link rel =" stylesheet " type =" text/css " href =" /static/css/normalize3.0.0.min.css?1435528339 " />
<!-- JS files with timestamps -->
{{JS "static/js/jquery1.11.0.min.js"}}
parses to
< script type =" text/javascript " src =" /static/js/jquery1.11.0.min.js?1435528404 " > </ script >
<!-- Hyperlinks -->
{{LINK "register" "Create a new account."}}
parses to
< a href =" /register " > Create a new account. </ a >
<!-- Output an unescaped variable (not a safe idea, but I find it useful when troubleshooting) -->
{{.SomeVariable | NOESCAPE}}
<!-- Time format -->
{{.SomeTime | PRETTYTIME}}
parses to format
3:04 PM 01/02/2006هناك بعض المتغيرات التي يمكنك استخدامها في القوالب أيضًا:
<!-- Use AuthLevel=auth to determine if a user is logged in (if session.Values["id"] != nil) -->
{{if eq .AuthLevel "auth"}}
You are logged in.
{{else}}
You are not logged in.
{{end}}
<!-- Use BaseURI to print the base URL of the web app -->
< li > < a href =" {{.BaseURI}}about " > About </ a > </ li >
<!-- Use token to output the CSRF token in a form -->
< input type =" hidden " name =" token " value =" {{.token}} " >من السهل أيضًا إضافة رمز خاص بالقالب قبل الإغلاق والعلامات:
<!-- Code is added before the closing </head> tag -->
{{define "head"}} < meta name =" robots " content =" noindex " > {{end}}
...
<!-- Code is added before the closing </body> tag -->
{{define "foot"}}{{JS "//www.google.com/recaptcha/api.js"}}{{end}}يمكنك تشغيل إشعار فلاش باستخدام JavaScript.
flashError ( "You must type in a username." ) ;
flashSuccess ( "Record created!" ) ;
flashNotice ( "There seems to be a piece missing." ) ;
flashWarning ( "Something does not seem right..." ) ; تشترك ملفات وحدة التحكم في نفس اسم الحزمة. هذا يقلل من عدد الحزم عندما تقوم بتخطيط الطرق. كما أنه يجبرك على استخدام اتفاقية تسمية جيدة لكل من funcs حتى تعرف مكان وجود كل من funcs ونوع طلب HTTP الذي يتم تعيينه لكل منهما.
الوصول إلى جلسة غوريلا:
// Get the current session
sess := session . Instance ( r )
...
// Close the session after you are finished making changes
sess . Save ( r , w )Trigger 1 من 4 أنواع مختلفة من رسائل الفلاش في تحميل الصفحة التالية (لا حاجة إلى رمز آخر):
sess . AddFlash (view. Flash { "Sorry, no brute force :-)" , view . FlashNotice })
sess . Save ( r , w ) // Ensure you save the session after making a change to itحقول النموذج التحقق من صحة ليست فارغة:
// Ensure a user submitted all the required form fields
if validate , missingField := view . Validate ( r , [] string { "email" , "password" }); ! validate {
sess . AddFlash (view. Flash { "Field missing: " + missingField , view . FlashError })
sess . Save ( r , w )
LoginGET ( w , r )
return
}تقديم قالب:
// Create a new view
v := view . New ( r )
// Set the template name
v . Name = "login/login"
// Assign a variable that is accessible in the form
v . Vars [ "token" ] = csrfbanana . Token ( w , r , sess )
// Refill any form fields from a POST operation
view . Repopulate ([] string { "email" }, r . Form , v . Vars )
// Render the template
v . Render ( w )إرجاع رسائل الفلاش أثناء طلب أياكس:
// Get session
sess := session . Instance ( r )
// Set the flash message
sess . AddFlash (view. Flash { "An error occurred on the server. Please try again later." , view . FlashError })
sess . Save ( r , w )
// Display the flash messages as JSON
v := view . New ( r )
v . SendFlashes ( w )التعامل مع استعلام قاعدة البيانات:
// Get database result
result , err := model . UserByEmail ( email )
if err == sql . ErrNoRows {
// User does not exist
} else if err != nil {
// Display error message
} else if passhash . MatchString ( result . Password , password ) {
// Password matches!
} else {
// Password does not match
}أرسل بريدًا إلكترونيًا:
// Email a user
err := email . SendEmail ( email . ReadConfig (). From , "This is the subject" , "This is the body!" )
if err != nil {
log . Println ( err )
sess . AddFlash (view. Flash { "An error occurred on the server. Please try again later." , view . FlashError })
sess . Save ( r , w )
return
}التحقق من صحة نموذج إذا تم تمكين Google Recaptcha في التكوين:
// Validate with Google reCAPTCHA
if ! recaptcha . Verified ( r ) {
sess . AddFlash (view. Flash { "reCAPTCHA invalid!" , view . FlashError })
sess . Save ( r , w )
RegisterGET ( w , r )
return
}من الجيد تجريد طبقة قاعدة البيانات ، لذا إذا كنت بحاجة إلى إجراء تغييرات ، فلن تضطر إلى النظر في منطق العمل للعثور على الاستعلامات. يتم تخزين جميع الاستعلامات في مجلد النماذج.
يدعم هذا المشروع BoltDB و MongoDB و MySQL. يتم تخزين جميع الاستعلامات في نفس الملفات بحيث يمكنك بسهولة تغيير قاعدة البيانات دون تعديل أي شيء سوى ملف التكوين.
تكون ملفات user.go و note.go في جذر دليل النموذج وهي عملية لجميع الاستعلامات لكل نوع قاعدة بيانات. هناك عدد قليل من الاختراقات في النماذج للحصول على الهياكل للعمل مع جميع قواعد البيانات المدعومة.
الاتصال بقاعدة البيانات (مرة واحدة فقط الحاجة في التطبيق الخاص بك):
// Connect to database
database . Connect ( config . Database )اقرأ من قاعدة البيانات:
result := User {}
err := database . DB . Get ( & result , "SELECT id, password, status_id, first_name FROM user WHERE email = ? LIMIT 1" , email )
return result , errاكتب إلى قاعدة البيانات:
_ , err := database . DB . Exec ( "INSERT INTO user (first_name, last_name, email, password) VALUES (?,?,?,?)" , firstName , lastName , email , password )
return err هناك عدد قليل من قطع الوسيطة المشمولة. تحمي الحزمة التي تسمى CSRFBanana من هجمات التزوير عبر المواقع وتمنع الخطر المزدوج. توفر الحزمة httprouterwrapper وظائف مساعد لجعل funcs متوافقة مع httprouter. ستقوم حزمة LogRequest بتسجيل كل طلب مقدمة على موقع الويب إلى وحدة التحكم. تتيح الحزمة PprofHandler PPROF بحيث تعمل مع HTTProuter. في Route.go ، تستخدم جميع الطرق الفردية أليس لجعل التسلسل سهلاً للغاية.
لجعل تطبيق الويب أكثر مرونة قليلاً ، يمكنك إجراء تغييرات على مكونات مختلفة في مكان واحد من خلال ملف config.json. إذا كنت ترغب في إضافة أي من الإعدادات الخاصة بك ، فيمكنك إضافتها إلى config.json وتحديث الهياكل في gowebapp.go والملفات الفردية حتى تتمكن من الرجوع إليها في الكود الخاص بك. هذا هو config.json:
{
"Database" : {
"Type" : " Bolt " ,
"Bolt" : {
"Path" : " gowebapp.db "
},
"MongoDB" : {
"URL" : " 127.0.0.1 " ,
"Database" : " gowebapp "
},
"MySQL" : {
"Username" : " root " ,
"Password" : " " ,
"Name" : " gowebapp " ,
"Hostname" : " 127.0.0.1 " ,
"Port" : 3306 ,
"Parameter" : " ?parseTime=true "
}
},
"Email" : {
"Username" : " " ,
"Password" : " " ,
"Hostname" : " " ,
"Port" : 25 ,
"From" : " "
},
"Recaptcha" : {
"Enabled" : false ,
"Secret" : " " ,
"SiteKey" : " "
},
"Server" : {
"Hostname" : " " ,
"UseHTTP" : true ,
"UseHTTPS" : false ,
"HTTPPort" : 80 ,
"HTTPSPort" : 443 ,
"CertFile" : " tls/server.crt " ,
"KeyFile" : " tls/server.key "
},
"Session" : {
"SecretKey" : " @r4B?EThaSEh_drudR7P_hub=s#s2Pah " ,
"Name" : " gosess " ,
"Options" : {
"Path" : " / " ,
"Domain" : " " ,
"MaxAge" : 28800 ,
"Secure" : false ,
"HttpOnly" : true
}
},
"Template" : {
"Root" : " base " ,
"Children" : [
" partial/menu " ,
" partial/footer "
]
},
"View" : {
"BaseURI" : " / " ,
"Extension" : " tmpl " ,
"Folder" : " template " ,
"Name" : " blank " ,
"Caching" : true
}
}لتمكين HTTPS ، قم بتعيين useHTTPs على TRUE ، وإنشاء مجلد يسمى TLS في الجذر ، ثم ضع الشهادة والمفاتيح في هذا المجلد.
المنزل العام:
عن:
يسجل:
تسجيل الدخول:
المنزل المصادق عليه:
ملاحظات العرض:
أضف ملاحظة:
ملاحظة تحرير:
كل التعليقات موضع ترحيب. اسمحوا لي أن أعرف إذا كان لديك أي اقتراحات أو أسئلة أو انتقادات. إذا لم يكن هناك شيء ما من الاصطلاح ، فيرجى إخبارنا بذلك حتى نتمكن من تحسينه.