تطبيق ويب مع IoC Starter. تخطيط الاستعلام الأساسي باستخدام سياق ioc و ioc web و ioc orm

الصورة

مقدمة


منذ الإصدار الأول ، مر الكثير من الوقت ( رابط إلى المقالة السابقة ). ما الذي تغير؟


  • تحسين استقرار النظام ككل ؛
  • تنفيذ تحميل كسول المكون ؛
  • نظام استماع أساسي مدمج
  • دعم مضمن للبرمجة ذات المنحى الجانبي (لحل المشكلات متوسطة الصعوبة ، وإلا أنصحك باستخدام مكتبة AspectJ للبقية)
  • جديد BootFactory bootloader
  • المدمج في ذاكرة التخزين المؤقت على أساس EhCache ، الجوافة
  • تم دمج العمل مع التدفقات (كلا التهيئة عبر التعليق التوضيحيSimpleTask والعمل المباشر مع التجمع)

** الوحدات


  • وحدة للعمل مع قاعدة البيانات (ORM خفيف الوزن مع دعم JPA والمعاملات وبرنامج NO-SQL Driver - Orient وطرق Crud ونظام المستودعات والاستعلامات التي يتم إنشاؤها تلقائيًا من وظيفة فئة المستودع)
  • وحدة كمامة الويب (ربط الروابط عبر التعليقات التوضيحية ، دعم المنتجين / المستهلكات المخصصة ، صفحة عرض قالب السرعة ، طلبات الأمان الأساسية ، الجلسات ، ملفات تعريف الارتباط ، SSL) استنادًا إلى Netty 4.1.30.

هيكل الإطار
هيكل


تقول ، "هذا ، بالطبع ، كل شيء جيد ، ولكن في الواقع هل يعمل كل شيء؟"
"نعم ، إنه يعمل. أطلب قطع".


عملية تنفيذ مثال


لتنفيذ المثال ، سأستخدم Maven 3 و Intelijj Idea 2018.2.


1) ربط التبعيات:


<?xml version="1.0" encoding="UTF-8"?> <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <artifactId>example-webapp</artifactId> <groupId>org.ioc</groupId> <packaging>jar</packaging> <version>0.0.1</version> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> <configuration> <.source>1.8</source> <target>1.8</target> </configuration> <executions> <execution> <id>default-testCompile</id> <phase>test-compile</phase> <goals> <goal>testCompile</goal> </goals> </execution> </executions> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.ioc</groupId> <artifactId>context-factory</artifactId> <version>2.2.4.STABLE</version> </dependency> <dependency> <groupId>org.ioc</groupId> <artifactId>orm-factory</artifactId> <version>2.2.4.STABLE</version> </dependency> <dependency> <groupId>org.ioc</groupId> <artifactId>web-factory</artifactId> <version>2.2.4.STABLE</version> </dependency> </dependencies> <repositories> <repository> <id>context</id> <url>https://raw.github.com/GenCloud/ioc_container/context</url> </repository> <repository> <id>cache</id> <url>https://raw.github.com/GenCloud/ioc_container/cache</url> </repository> <repository> <id>threading</id> <url>https://raw.github.com/GenCloud/ioc_container/threading</url> </repository> <repository> <id>orm</id> <url>https://raw.github.com/GenCloud/ioc_container/orm</url> </repository> <repository> <id>web</id> <url>https://raw.github.com/GenCloud/ioc_container/web</url> </repository> </repositories> </project> 

** لم ينتقل بعد إلى وسط مخضرم ، للأسف.


هيكل المشروع:
الهيكل
نمط MVC القياسي ، أليس كذلك؟


إنشاء نقطة دخول للتطبيق:


 package org.examples.webapp; import org.ioc.annotations.context.ScanPackage; import org.ioc.annotations.modules.CacheModule; import org.ioc.annotations.modules.DatabaseModule; import org.ioc.annotations.modules.ThreadingModule; import org.ioc.annotations.modules.WebModule; import org.ioc.context.starter.IoCStarter; @WebModule @CacheModule @ThreadingModule @DatabaseModule @ScanPackage(packages = {"org.examples.webapp"}) public class AppMain { public static void main(String[] args) { IoCStarter.start(AppMain.class); } } 

** التفسيرات:
التعليق التوضيحيScanPackages - يحدد الحزم السياقية لتحديد المكونات (في عامة الناس - "حاويات").
التعليق التوضيحيWebModule - يعمل على توصيل وتهيئة مصنع ويب.
التعليق التوضيحيCacheModule - يستخدم لتوصيل وتهيئة مصنع ذاكرة التخزين المؤقت ، ويستخدم للتشغيل الصحيح لـ ORM (في الإصدارات المستقبلية ، لن تكون هناك حاجة إلى تعليق توضيحي).
التعليق التوضيحيThreadingModule - يعمل على توصيل وتهيئة مصنع سلسلة رسائل ، يتم استخدامه لمصنع الويب للعمل بشكل صحيح (في الإصدارات المستقبلية ، لن تكون هناك حاجة إلى تعليق توضيحي).
التعليق التوضيحيDatabaseModule - يستخدم لتوصيل وتهيئة مصنع ORM.
تحتوي جميع المصانع على مكوِّنات افتراضية ، والتي يمكنك تغييرها إلى إعداداتك الخاصة مع إعادة تعريف وظائف الإعدادات التي تستخدمها المصانع (في كل تعليق توضيحي للوحدة ، تتم إعادة تعريف مكوّن الفئة - Class <؟> AutoConfigurationClass () الافتراضي WebAutoConfiguration.class ) أو تعطيل أي تكوين باستخدام التعليق التوضيحي Exclude في الصفحة الرئيسية الفصل الدراسي.
الأداة المساعدة IoCStarter هي فئة مُهيئ السياق الرئيسي.


حسنًا ، يبدو أن كل شيء جاهز ، تتم تهيئة السياق ، ويعمل الويب على المنفذ الافتراضي 8081 ، ولكن لا يوجد رابط ، وعندما نذهب إلى الموقع ، لا يمنحنا أي شيء. حسنا ، المضي قدما.


لنقم بإنشاء ملف تكوين للوحدات النمطية الخاصة بنا. بشكل افتراضي ، يتم تحميل جميع التكوينات من {working_dir} /configs/default_settings.properties - سنقوم بإنشائها على المسار الصحيح.


 # Threading ioc.threads.poolName=shared ioc.threads.availableProcessors=4 ioc.threads.threadTimeout=0 ioc.threads.threadAllowCoreTimeOut=true ioc.threads.threadPoolPriority=NORMAL # Event dispather # -  ()    ( ) ioc.dispatcher.availableDescriptors=4 # Cache #   (EhFactory|GuavaFactory) cache.factory=org.ioc.cache.impl.EhFactory # Datasource #   (-, -  ) #LOCAL, LOCAL_SERVER, REMOTE datasource.orient.database-type=LOCAL #   datasource.orient.url=./database #    (   ) datasource.orient.database=orient #   datasource.orient.username=admin #   datasource.orient.password=admin #       (create, dropCreate, refresh, none) datasource.orient.ddl-auto=dropCreate #   ,      datasource.orient.showSql=true # Web server #     web.server.port=8081 #   SSL  web.server.ssl-enabled=false # in seconds #   ( 7200 . = 2 ) web.server.security.session.timeout=300 #  - web.server.velocity.input.encoding=UTF-8 web.server.velocity.output.encoding=UTF-8 #  - web.server.velocity.resource.loader=file #   web.server.velocity.resource.loader.class=org.apache.velocity.runtime.resource.loader.FileResourceLoader #    - web.server.velocity.resource.loading.path=./public 

بعد ذلك ، نحتاج إلى كيان مستخدم ومستودع إداري خاص به:
تنفيذ الكيان TblAccount:


 package org.examples.webapp.domain.entity; import org.ioc.web.security.user.UserDetails; import javax.persistence.*; import java.util.Collections; import java.util.List; @Entity public class TblAccount implements UserDetails { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) private long id; @Column(name = "username") private String username; @Column(name = "password") private String password; @Transient private String repeatedPassword; public String getRepeatedPassword() { return repeatedPassword; } public void setRepeatedPassword(String repeatedPassword) { this.repeatedPassword = repeatedPassword; } @Override public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } @Override public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public List<String> getRoles() { return Collections.singletonList("ROLE_USER"); } } 

** التفسيرات:
كل شيء قياسي كما هو الحال مع جميع أطر عمل دعم JPA. قم بتعيين الكيان باستخدام @ .Entity ، وأنشئ المفتاح الأساسي باستخدام التعليق التوضيحي @ .Id ، وقم بتعيين الأعمدة باستخدام التعليق التوضيحي Column. وترث من UserDetails لتحديد الكيان في وحدة الأمن .


تنفيذ مستودع TblAccountRepository للكيانات:


 package org.examples.webapp.domain.repository; import org.examples.webapp.domain.entity.TblAccount; import org.ioc.annotations.context.IoCRepository; import org.ioc.orm.repositories.CrudRepository; import javax.transaction.Transactional; @IoCRepository public interface TblAccountRepository extends CrudRepository<TblAccount, Long> { @Transactional TblAccount findByUsernameEq(String username); } 

** التفسيرات:
التعليق التوضيحيIoCRepository - يعمل على تحديد السياق أن الفئة عبارة عن مستودع ويجب معالجتها "بشكل مختلف" .
يدعم وظائف CRUD القياسية:


  • جلب الكيان (معرف ID) - يحصل على كيان من نوع الكيان من قاعدة البيانات ، أو من ذاكرة التخزين المؤقت بواسطة المفتاح الأساسي ؛
  • قائمة fetchAll () - تحصل على جميع الكيانات من نوع الكيان ، وتحميلها مسبقًا في ذاكرة التخزين المؤقت ؛
  • void save (كيان كيان) - إنشاء / تحديث كيان من نوع الكيان في كل من قاعدة البيانات وذاكرة التخزين المؤقت ؛
  • void delete (كيان كيان) - يحذف كيانًا من نوع الكيان من قاعدة البيانات ومن ذاكرة التخزين المؤقت ؛
  • boolean موجود (معرف ID) - للتحقق من وجود كيان في قاعدة البيانات باستخدام المفتاح الأساسي.
    تحدث جميع طلبات CRUD في المعاملة.

يدعم الإنشاء التلقائي للاستعلامات عن طريق إعادة تعريف الوظائف بالكلمات الرئيسية ، كما في التنفيذ أعلاه ( TblAccount findByUsernameEq (String username) ) واستدعاء الاستعلامات المسجلة ( NamedQuery )


دالة findByUsernameEq (اسم مستخدم السلسلة) - يبحث عن كيان حسب حقل اسم المستخدم الخاص به. الطلب الذي تم إنشاؤه:


  select * from tbl_account where username = 'username' 

بعد ذلك ، نحتاج إلى مستوى لإدارة منطق الأعمال.
تطبيقات AccountService:


 package org.examples.webapp.service; import org.examples.webapp.domain.entity.TblAccount; import org.examples.webapp.domain.repository.TblAccountRepository; import org.examples.webapp.responces.IMessage; import org.ioc.annotations.context.IoCComponent; import org.ioc.annotations.context.IoCDependency; import org.ioc.web.model.http.Request; import org.ioc.web.security.configuration.SecurityConfigureAdapter; import org.ioc.web.security.encoder.bcrypt.BCryptEncoder; import org.ioc.web.security.user.UserDetails; import org.ioc.web.security.user.UserDetailsProcessor; import java.util.Objects; import static org.examples.webapp.responces.IMessage.Type.ERROR; import static org.examples.webapp.responces.IMessage.Type.OK; @IoCComponent public class AccountService implements UserDetailsProcessor { @IoCDependency private TblAccountRepository tblAccountRepository; @IoCDependency private BCryptEncoder bCryptEncoder; @IoCDependency private SecurityConfigureAdapter securityConfigureAdapter; @Override public UserDetails loadUserByUsername(String username) { return tblAccountRepository.findByUsernameEq(username); } public void save(TblAccount tblAccount) { tblAccountRepository.save(tblAccount); } public void delete(TblAccount tblAccount) { tblAccountRepository.delete(tblAccount); } public IMessage tryCreateUser(String username, String password, String repeatedPassword) { if (username == null || username.isEmpty() || password == null || password.isEmpty() || repeatedPassword == null || repeatedPassword.isEmpty()) { return new IMessage(ERROR, "Invalid request parameters!"); } if (!Objects.equals(password, repeatedPassword)) { return new IMessage(ERROR, "Repeated password doesn't match!"); } final UserDetails userDetails = loadUserByUsername(username); if (userDetails != null) { return new IMessage(ERROR, "Account already exists!"); } final TblAccount account = new TblAccount(); account.setUsername(username); account.setPassword(bCryptEncoder.encode(password)); save(account); return new IMessage(OK, "Successfully created!"); } public IMessage tryAuthenticateUser(Request request, String username, String password) { if (username == null || username.isEmpty() || password == null || password.isEmpty()) { return new IMessage(ERROR, "Invalid request parameters!"); } final UserDetails userDetails = loadUserByUsername(username); if (userDetails == null) { return new IMessage(ERROR, "Account not found!"); } if (!bCryptEncoder.match(password, userDetails.getPassword())) { return new IMessage(ERROR, "Password does not match!"); } securityConfigureAdapter.getContext().authenticate(request, userDetails); return new IMessage(OK, "Successfully authenticated"); } public IMessage logout(Request request) { if (securityConfigureAdapter.getContext().removeAuthInformation(request)) { return new IMessage(OK, "/"); } return new IMessage(ERROR, "Credentials not found or not authenticated!"); } } 

** التفسيرات:
يعمل التعليق التوضيحيIoCComponent - على تهيئة فئة كمكون.
التعليق التوضيحيIoCDependency - يعمل على ضخ التبعيات في مثيل الفئة.
الأداة المساعدة BCryptEncoder هي تنفيذ برنامج ترميز BCrypt لتشفير كلمة المرور (حتى الآن برنامج الترميز الوحيد).
مثيل النظام SecurityConfigureAdapter - يُستخدم للعمل مع طلبات التعيين وجلسات المستخدم.
الوظيفة UserDetails loadUserByUsername - وظيفة موروثة UserDetailsProcessor ، تعمل على تحميل المستخدم في الجلسة وتعيين علامة المصادقة (في المستقبل لرسم الخرائط القياسية للتفويض في الأمان )
وظيفة IMessage tryCreateUser هي وظيفة إنشاء مستخدم.
وظيفة IMessage tryAuthenticateUser - وظيفة مصادقة المستخدم.
وظيفة تسجيل الخروج من الرسائل هي وظيفة لمسح جلسة من مستخدم معتمد.
فئة IMessage هي فئة أداة مساعدة لعرض المعلومات التي نحتاجها في المتصفح (استجابة json).


 package org.examples.webapp.responces; public class IMessage { private final String message; private final Type type; public IMessage(String message) { this.message = message; type = Type.OK; } public IMessage(Type type, String message) { this.message = message; this.type = type; } public String getMessage() { return message; } public Type getType() { return type; } public enum Type { OK, ERROR } } 

الآن أنت بحاجة إلى تنفيذ الرابط نفسه (تعيين الطلب):


 package org.examples.webapp.mapping; import org.examples.webapp.domain.entity.TblAccount; import org.examples.webapp.responces.IMessage; import org.examples.webapp.service.AccountService; import org.ioc.annotations.context.IoCDependency; import org.ioc.annotations.web.IoCController; import org.ioc.web.annotations.Credentials; import org.ioc.web.annotations.MappingMethod; import org.ioc.web.annotations.RequestParam; import org.ioc.web.annotations.UrlMapping; import org.ioc.web.model.ModelAndView; import org.ioc.web.model.http.Request; @IoCController @UrlMapping("/") public class MainMapping { @IoCDependency private AccountService accountService; @UrlMapping public ModelAndView index() { final ModelAndView modelAndView = new ModelAndView(); modelAndView.setView("index"); return modelAndView; } @UrlMapping(value = "signup", method = MappingMethod.POST) public IMessage createUser(@RequestParam("username") String username, @RequestParam("password") String password, @RequestParam("repeatedPassword") String repeatedPassword) { return accountService.tryCreateUser(username, password, repeatedPassword); } @UrlMapping(value = "signin", method = MappingMethod.POST) public IMessage auth(Request request, @RequestParam("username") String username, @RequestParam("password") String password) { return accountService.tryAuthenticateUser(request, username, password); } @UrlMapping("signout") public IMessage signout(Request request) { return accountService.logout(request); } @UrlMapping("loginPage") public ModelAndView authenticated(@Credentials TblAccount account) { final ModelAndView modelAndView = new ModelAndView(); modelAndView.setView("auth"); modelAndView.addAttribute("account", account); return modelAndView; } } 

** التفسيرات:
التعليق التوضيحيIoCController - يعمل على تحديد الفئة في السياق كوحدة تحكم (مخطط طلب المتصفح)
تعليق توضيحيUrlMapping - يشير إلى أنه من الضروري تحليل وظيفة / فئة لوجود الطلبات التي تتم معالجتها بواسطة معالجات القنوات.
معلمات:


  • القيمة - الطلب الذي نحتاجه ؛
  • الطريقة - طريقة http للمعالجة (GET ، POST ، PUT ، إلخ) ؛
  • يستهلك - نوع mime http للتحقق من وجود طلب من نوع معين (اختياري) ؛
  • ينتج - نوع محتوى http لإرجاع نوع محتوى معين في الاستجابة (نوع المحتوى: text / html؛ charset = utf-8 ، Content-Type: multipart / form-data؛ الحد = شيء ، وما إلى ذلك اختياري ؛

التعليق التوضيحيRequestParam - يعمل على تحديد اسم المعلمة المتلقاة من الطلب. نظرًا لأنه من المستحيل الحصول على الاسم الحالي لمعلمة الأسلوب عن طريق وسائل انعكاس افتراضية ، فقد كنت كسولًا جدًا لربط تبعية الجاواسي الإضافية ، إلى الشامان مع ASM. لذلك ، فإن هذه الطريقة لتحديد اسم المعلمة لتضمين قيم هذه المعلمة التي تم الحصول عليها من الطلب. يوجد نظير لنوع GET -PathVariable - نفس مبدأ التشغيل (غير متوافق مع POST ).
التعليق التوضيحي لـCredentials - يعمل على إدراج البيانات الحالية للمستخدم المصرح له ، وإلا فقد يكون فارغًا إذا لم تكن معلومات المستخدم المصرح به في الجلسة.
نظام فئة الطلب هو المعلومات الحالية حول طلب وارد يحتوي على كوكا ورؤوس وقناة مستخدم ، والتي يمكن إرسالها لاحقًا إلى Push Message's ... الذي لديه نوع من الخيال بالفعل في هذا الصدد.
إن فئة الأداة المساعدة ModelAndView هي نموذج صفحة باسم المورد بدون ملحق ، وسمات للتضمين في المورد.


يبدو أن الأمر كله ، ولكن لا - يجب عليك بالتأكيد تكوين الخرائط المتاحة لطلبات المستخدمين.


 package org.examples.webapp.config; import org.ioc.annotations.configuration.Property; import org.ioc.annotations.configuration.PropertyFunction; import org.ioc.web.security.configuration.HttpContainer; import org.ioc.web.security.configuration.SecurityConfigureProcessor; import org.ioc.web.security.encoder.Encoder; import org.ioc.web.security.encoder.bcrypt.BCryptEncoder; import org.ioc.web.security.filter.CorsFilter; import org.ioc.web.security.filter.CsrfFilter; @Property public class SecurityConfig implements SecurityConfigureProcessor { @Override public void configure(HttpContainer httpContainer) { httpContainer. configureRequests(). anonymousRequests("/", "/signup", "/signin"). resourceRequests("/static/**"). authorizeRequests("/loginPage", "ROLE_USER"). authorizeRequests("/signout", "ROLE_USER"). and(). configureSession(). expiredPath("/"); } @PropertyFunction public CsrfFilter csrfFilter() { return new CsrfFilter(); } @PropertyFunction public CorsFilter corsFilter() { return new CorsFilter(); } @PropertyFunction public Encoder encoder() { return new BCryptEncoder(); } } 

** التفسيرات:
التعليق التوضيحيProperty - يخبر السياق بأن هذا ملف تكوين ويجب أن تتم تهيئته.
التعليق التوضيحيPropertyFunction - يخبر محلل التكوين أن هذه الوظيفة تُرجع نوعًا ما ويجب أن تهيئته كمكون (سلة).
Interface SecurityConfigureProcessor - أداة مساعدة تستخدم لتكوين تعيين الطلبات.
فئة طراز HttpContainer هي أداة مساعدة تقوم بتخزين تعيين الطلبات المحددة من قبل المستخدم.
فئة CsrfFilter هي مرشح للطلبات غير الصالحة (تطبيقات ميكانيكا CSRF).
فئة CorsFilter هو عامل تصفية "مشاركة الموارد".


وظيفة AnonymousRequests - تقبل مجموعة غير محدودة من الطلبات ، ولا تتطلب المستخدمين المعتمدين والتحقق من الأدوار (ROLE_ANONYMOUS).
وظيفة ResourceRequests - تأخذ في مجموعة غير محدودة من الطلبات ، تعمل على وجه التحديد لتحديد المسار الذي سيكون فيه ملف المورد الذي لا يتطلب معالجة معقدة (css ، js ، صور ، إلخ).
الوظيفة AuthorizeRequests - تستقبل مجموعة غير محدودة من الطلبات ، وتتطلب مستخدمًا مصرحًا به والدور المحدد المتأصل في المستخدم.
وظيفة ExpiredPath - عند مسح جلسة انتهت صلاحيتها في الوقت المحدد ، تتم إعادة توجيه المستخدم من خلال هذا التعيين (رابط إعادة التوجيه).


حسنًا ، كانت هناك صفحات ونصوص وأنماط مواقع (لن أتعمق).


عنوان المفسد

index.vm - الصفحة الرئيسية


 <html> <head> <meta charset="utf-8"/> <title>IoC Test</title> <link rel="stylesheet" href="/static/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/css/style.css"/> <link rel="stylesheet" href="/static/css/pnotify.custom.min.css"/> <link rel="stylesheet" href="/static/css/pnotify.css"/> <link rel="stylesheet" href="/static/css/pnotify.buttons.css"/> </head> <body> <div class="container"> <h1>IoC Starter Test</h1> <br> <h4>Create user</h4> <br> <form id="creation"> <label for="username">Username: </label> <input type="text" id="username" name="username" class="color-input-field"/> <label for="password">Password: </label> <input type="password" id="password" name="password" class="color-input-field"/> <label for="repeatedPassword">Repeate: </label> <input type="password" id="repeatedPassword" name="repeatedPassword" class="color-input-field"/> <button type="button" class="btn btn-success btn-create">Sing up!</button> </form> <h4>Authenticate</h4> <br> <form id="auth"> <label for="username">Username: </label> <input type="text" id="username" name="username" class="color-input-field"/> <label for="password">Password: </label> <input type="password" id="password" name="password" class="color-input-field"/> <button type="button" class="btn btn-danger btn-auth">Sing in!</button> </form> </div> <script type="text/javascript" src="/static/js/jquery.js"></script> <script type="text/javascript" src="/static/js/bootstrap.min.js"></script> <script type="text/javascript" src="/static/js/scripts.js"></script> <script type="text/javascript" src="/static/js/pnotify.js"></script> <script type="text/javascript" src="/static/js/pnotify.buttons.js"></script> </body> </html> 

auth.vm - لعرض مستخدم معتمد


 <html> <head> <meta charset="utf-8"/> <title>IoC Test</title> <link rel="stylesheet" href="/static/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/css/style.css"/> <link rel="stylesheet" href="/static/css/pnotify.custom.min.css"/> <link rel="stylesheet" href="/static/css/pnotify.css"/> <link rel="stylesheet" href="/static/css/pnotify.buttons.css"/> </head> <body> <div class="container"> <h1>Authorized page</h1> <br> <h4>Test auth data</h4> <div id="auth_data"> #if($!account) <h4>Hello @$!account.username, You successfully authenticated!</h4> <br> <button type="button" class="btn btn-success btn-logout">Logout!</button> #end </div> </div> <script type="text/javascript" src="/static/js/jquery.js"></script> <script type="text/javascript" src="/static/js/bootstrap.min.js"></script> <script type="text/javascript" src="/static/js/scripts.js"></script> <script type="text/javascript" src="/static/js/pnotify.js"></script> <script type="text/javascript" src="/static/js/pnotify.buttons.js"></script> </body> </html> 

scripts.js - جهاز تحكم ، لإرسال واستلام معلومات الطلب إلى الخادم


 $(function () { $(".btn-create").click(function () { var cooki = cookie(); document.cookie = 'CSRF-TOKEN=' + cooki; $.ajax({ url: "/signup", data: $('#creation').serialize(), headers: {'X-CSRF-TOKEN': cooki}, crossDomain: true, xhrFields: { withCredentials: true }, type: "POST" }).done(function (data) { switch (data.type) { case 'OK': new PNotify({ title: 'Success', text: data.message, type: 'success', hide: false }); break; case 'ERROR': new PNotify({ title: 'Error', text: data.message, type: 'error', hide: false }); break; } }); }); $(".btn-auth").click(function () { var cooki = cookie(); document.cookie = 'CSRF-TOKEN=' + cooki; $.ajax({ url: "/signin", data: $('#auth').serialize(), headers: {'X-CSRF-TOKEN': cooki}, crossDomain: true, xhrFields: { withCredentials: true }, type: "POST" }).done(function (data) { switch (data.type) { case 'OK': new PNotify({ title: 'Success', text: data.message, type: 'success', hide: false }); setTimeout(function () { window.location = "/loginPage"; }, 5000); break; case 'ERROR': new PNotify({ title: 'Error', text: data.message, type: 'error', hide: false }); break; } }); }); $(".btn-logout").click(function () { $.ajax({ url: "/signout", crossDomain: true, xhrFields: { withCredentials: true }, type: "GET" }).done(function (data) { switch (data.type) { case 'OK': new PNotify({ title: 'Success', text: 'Logouting...', type: 'success', hide: false }); setTimeout(function () { window.location = data.message; }, 5000); break; case 'ERROR': new PNotify({ title: 'Error', text: data.message, type: 'error', hide: false }); break; } }); }); }); function cookie(a) { return a // if the placeholder was passed, return ? ( // a random number from 0 to 15 a ^ // unless b is 8, Math.random() // in which case * 16 // a random number from >> a / 4 // 8 to 11 ).toString(16) // in hexadecimal : ( // or otherwise a concatenated string: [1e7] + // 10000000 + -1e3 + // -1000 + -4e3 + // -4000 + -8e3 + // -80000000 + -1e11 // -100000000000, ).replace( // replacing /[018]/g, // zeroes, ones, and eights with cookie // random hex digits ) } 

تجميع وتشغيل كل ما لدينا.
إذا كان كل شيء صحيحًا ، فسنرى شيئًا كهذا في نهاية التنزيل:


سجل

[21.10.18 22: 29: 510] INFO web.model.mapping.MappingContainer: الطريقة المعينة [/] ، الطريقة = [GET] ، إلى [public org.ioc.web.model.ModelAndView org.examples.webapp .mapping.MainMapping.index ()]
[21.10.18 22: 29: 51: 993] INFO web.model.mapping.MappingContainer: الطريقة المعينة [/ signup] ، الطريقة = [POST] ، إلى [public org.examples.webapp.responces.IMessage org.examples. webapp.mapping.MainMapping.createUser (java.lang.String، java.lang.String، java.lang.String)]
[21.10.18 22: 29: 51: 993] INFO web.model.mapping.MappingContainer: الطريقة المعينة [/ signin] ، الطريقة = [POST] ، إلى [public org.examples.webapp.responces.IMessage org.examples. webapp.mapping.MainMapping.auth (org.ioc.web.model.http.Request، java.lang.String، java.lang.String)]
[21.10.18 22: 29: 51: 993] INFO web.model.mapping.MappingContainer: الطريقة المعينة [/ signout] ، الطريقة = [GET] ، إلى [public org.examples.webapp.responces.IMessage org.examples. webapp.mapping.MainMapping.signout (org.ioc.web.model.http.Request)]
[21.10.18 22: 29: 51: 995] INFO web.model.mapping.MappingContainer: الطريقة المعينة [/ loginPage] ، الطريقة = [GET] ، إلى [public org.ioc.web.model.ModelAndView org.examples. webapp.mapping.MainMapping.authenticated (org.examples.webapp.domain.entity.TblAccount)]
[21.10.18 22: 29: 51: 997] INFO ioc.web.factory.HttpInitializerFactory: بدأ خادم Http على المنفذ (المنافذ): 8081 (http)


النتيجة:
1) الصفحة الرئيسية
فهرس
2) التسجيل
الاشتراك
3) المصادقة
المصادقة
4) الصفحة التي تحتوي على نتيجة التفويض (إعادة التوجيه بعد إدخال تسجيل الدخول وكلمة المرور بشكل صحيح)
النتيجة
5) مسح معلومات التفويض من الجلسة وإعادة توجيه المستخدم إلى الصفحة الرئيسية
الصورة
6) محاولة مستخدم غير مصرح له للوصول إلى الصفحة بمعلومات مصادقة الجلسة
الصورة


النهاية


يتطور المشروع ، "المساهمون" والأفكار الأصلية مرحب بها ، لأنه من الصعب القيام بهذا المشروع بمفرده.
مستودع المشروع .
السياق
مصنع ORM
مصنع الويب
أمثلة
المثال الحالي من المقالة
أيضًا في المستودع هناك أمثلة على استخدام جميع الوظائف في وحدة "الأمثلة" ، وكما يقولون ، "حظًا سعيدًا ، استمتع" ، شكرًا لكم جميعًا على انتباهكم.

Source: https://habr.com/ru/post/ar427247/


All Articles