Modelis-Update-View modelis un atkarīgie veidi. Pieteikšanās un izrakstīšanās skati Izglītības atteikšanās html skats

Rediģēt failu urls.py lietojumprogrammas kontu:

no django.conf.urls importa URL no . importēt skatus urlpatterns = [ # iepriekšējais pieteikšanās skats # url(r"^login/$", views.user_login, name = "pieteikšanās"),# login / logout urls url(r"^login/$" , "django.contrib.auth.views.login", name="login" ), url(r"^logout/$" , "django.contrib.auth.views.logout", name="logout" ), url(r"^logout-then-login/$" , "django.contrib.auth.views.logout_then_login", name="logout_then_login" ), ]

Mēs esam komentējuši skata URL veidni user_login, kas izveidota iepriekš, lai izmantotu skatu pieteikšanās Django.

Lietojumprogrammu veidņu direktorijā izveidojiet jaunu direktoriju kontu un nosauc to reģistrācija. Izveidojiet jaunu failu jaunā direktorijā, nosauciet to login.html

(% paplašina "base.html" %) (% bloka nosaukums %)Pieteikšanās (% beigu bloks %) (% bloka saturs %)

Pieteikties

(% ja forma.kļūdas %)

Jūsu lietotājvārds un parole nesakrita. Lūdzu, mēģiniet vēlreiz.

(%else%)

Lūdzu, izmantojiet šo formu, lai pieteiktos:

(% endif %) (%endblock%)

Šī pieteikšanās veidne ir ļoti līdzīga iepriekš izveidotajai. Django izmanto Autentifikācijas veidlapa, kas atrodas django.contrib.auth.forms. Šī veidlapa mēģina autentificēt lietotāju un ģenerē validācijas kļūdu, ja lietotājvārds bija nepareizs. Šajā gadījumā mēs varam meklēt kļūdas, izmantojot komandu (% if form.errors %) . Lūdzu, ņemiet vērā, ka esam pievienojuši slēptu elementu lai nosūtītu mainīgā ar nosaukumu vērtību nākamais.

Parametrs nākamais jābūt vietrādim URL. Ja šis parametrs ir norādīts, tad pēc lietotāja pieteikšanās viņš tiek novirzīts uz norādīto URL.

Tagad izveidojiet veidni logged_out.html veidņu direktorijā reģistrācija un ielīmējiet tajā šādu kodu:

(% paplašina "base.html" %) (% bloka nosaukums %)Atteicies (% endblock %) (% bloka saturs %)

Atteicies

Jūs esat veiksmīgi atteicies. Jūs varat pieteikties vēlreiz.

(%endblock%)

Šī ir veidne, kas tiks parādīta pēc lietotāja pieteikšanās.

Pēc URL veidņu un veidņu pievienošanas ievades un izvades skatiem vietne ir gatava pieteikšanās, izmantojot Django autentifikācijas skatus.

Lūdzu, ņemiet vērā, ka prezentācija logout_then_login iekļauts mūsu urlconf, nav nepieciešama veidne, jo tā novirza uz pieteikšanās skatā.

Tagad izveidosim jaunu skatu, lai lietotājam parādītu informācijas paneli, lai mēs zinātu, kad lietotājs piesakās savā kontā. Atveriet failu views.py lietojumprogrammas kontu un pievienojiet tam šādu kodu:

no django.contrib.auth.decorators importēt login_required @login_required def informācijas panelis (pieprasījums): atgriezties renderēšanā(pieprasījums, "account/dashboard.html" , ("sadaļa" : "informācijas panelis"))

Mēs savam skatam pievienojam dekoratoru login_required autentifikācijas ietvars. Dekorators login_required pārbauda, ​​vai pašreizējais lietotājs ir autentificēts. Ja lietotājs ir autentificēts, iesniegšana tiks izpildīta; Ja lietotājs nav autentificēts, viņš tiks novirzīts uz pieteikšanās lapu.

Mēs arī definējām mainīgo sadaļā. Mēs izmantosim šo mainīgo, lai izsekotu, kuru vietnes sadaļu lietotājs skatās.

Tagad jums ir jāizveido veidne informācijas paneļa skatam. Veidnēs/kontā izveidojiet jaunu failu veidnes/konts/ un nosauc to dashboard.html :

(% paplašina "base.html" %) (% bloka nosaukums %)Informācijas panelis (% beigu bloks %) (% bloka saturs %)

Informācijas panelis

Laipni lūdzam informācijas panelī.

(%endblock%)

Pēc tam šim izmaiņu failam pievienojiet tālāk norādīto URL šablonu urls.py lietojumprogrammas kontu:

Urlpatterns = [ # ... url(r"^$" , views.dashboard, name="dashboard" ), ]

Tagad rediģējiet failu settings.py:

no django.core.urlresolvers importēt reverse_lazy LOGIN_REDIRECT_URL = reverse_lazy("informācijas panelis") LOGIN_URL = reverse_lazy("pieteikšanās" ) LOGOUT_URL = reverse_lazy("atteikties")
  • LOGIN_REDIRECT_URL: norāda, uz kuru URL novirzīt lietotāju pēc pieteikšanās.
  • LOGIN_URL: URL, lai novirzītu lietotāju uz pieteikšanos (piemēram, izmantojot dekoratoru login_required)
  • LOGOUT_URL: URL, lai novirzītu lietotāju uz izeju

Tagad mēs pievienosim pieteikšanās un atteikšanās saites mūsu pamata veidnei.

Lai to izdarītu, ir jānosaka, vai pašreizējais lietotājs ir vai nav pieteicies, lai parādītu saiti, kas atbilst pašreizējam lietotāja stāvoklim. Pašreizējais lietotājs ir norādīts HttpRequest autentifikācijas starpklases objekts. Tam var piekļūt, izmantojot pieprasījums.lietotājs. Pieprasījums atradīs lietotāja objektu, pat ja lietotājs nav autentificēts. Neautentificēts lietotājs, kas norādīts pieprasījumā kā gadījums Anonīms lietotājs. Labākais veids, kā pārbaudīt pašreizējā lietotāja autentifikācijas statusu, ir piezvanīt request.user.is_authenticated()

Rediģējiet veidnē base.html

ar ID galveni:

Kā redzat, vietnes izvēlne tiek parādīta tikai autentificētiem lietotājiem. Mēs arī pārbaudām pašreizējo sadaļu, lai pievienotu atlasīto klases atribūtu atbilstošajam elementam

  • lai izceltu pašreizējo sadaļu izvēlnē, izmantojot CSS. Tajā tiek parādīts arī lietotājvārds un saite, lai izietu, ja lietotājs ir autentificēts, vai saite, lai pieteiktos.

    Pārlūkprogrammā atveriet http://127.0.0.1:8000/account/login/. Jums vajadzētu redzēt pieteikšanās lapu. Ievadiet derīgu lietotājvārdu un paroli. Jūs redzēsiet tālāk norādīto.

    Varat redzēt, ka sadaļa Mans informācijas panelis ir izcelta ar CSS, jo tai ir klase atlasīts. Tā kā lietotājs ir autentificēts, lietotājvārds tiek parādīts galvenes labajā pusē. Noklikšķiniet uz saites Atteikties. Jūs redzēsit šādu lapu:

    Šajā lapā var redzēt, ka lietotājs ir atteicies un līdz ar to vietnes izvēlne vairs netiek rādīta. Tagad tiek rādīta saite galvenes labajā pusē Pieteikties.

    Ja redzat atteikšanās lapu no Django administratora vietnes, nevis savu atteikšanās lapu, pārbaudiet savus INSTALLED_APPS iestatījumus un pārliecinieties, vai django.contrib.admin ir pēc kontu. Abas veidnes atrodas vienā relatīvajā ceļā, un Django veidņu ielādētājs izmantos pirmo atrasto.

    Django ir aprīkots ar daudziem iebūvētiem resursiem visizplatītākajiem tīmekļa lietojumprogrammu lietošanas gadījumiem. Reģistrācijas lietotne ir ļoti labs piemērs, un tajā ir labi tas, ka funkcijas var izmantot jau sākotnēji.

    Izmantojot Django reģistrācijas lietotni, varat izmantot šādas funkcijas:

    • Pieteikties
    • Atteikties
    • Pierakstīties
    • Paroles atiestatīšana

    Šajā apmācībā mēs pievērsīsimies pieteikšanās un atteikšanās funkcijām. Lai reģistrētos un atiestatītu paroli, skatiet tālāk norādītās apmācības.

    Darba sākšana

    Pirms sākam, pārbaudiet, vai jūsu INSTALLED_APPS ir django.contrib.auth un pareizi konfigurēta autentifikācijas starpprogrammatūra MIDDLEWARE_CLASSES iestatījumos.

    Abi ir jau konfigurēti, kad sākat jaunu Django projektu, izmantojot komandu startproject. Tātad, ja jūs nenoņēmāt sākotnējās konfigurācijas, jums ir jābūt iestatītam.

    Ja sākat jaunu projektu, lai tikai sekotu šai apmācībai, izveidojiet lietotāju, izmantojot komandrindu, lai mēs varētu pārbaudīt pieteikšanās un atteikšanās lapas.

    $ python manage.py createsuperuser

    Šī raksta beigās es sniegšu piemēra pirmkodu ar minimālo konfigurāciju.

    Konfigurējiet URL maršrutus

    Vispirms importējiet moduli django.contrib.auth.views un pievienojiet URL maršrutu pieteikšanās un atteikšanās skatiem:

    no django.conf.urls importa URL no django.contrib importa admin no django.contrib.auth importa skati kā auth_views urlpatterns = [ url (r"^login/$" , auth_views . login , name = "login" ), url ( r"^logout/$" , auth_views logout , name = "logout" ), url (r"^admin/" , admin . site . urls ), ].

    Izveidojiet pieteikšanās veidni

    Pēc noklusējuma skats django.contrib.auth.views.login mēģinās renderēt veidni register/login.html. Tātad pamata konfigurācija būtu izveidot mapi ar nosaukumu reģistrācija un tajā ievietot veidni login.html.

    Pēc minimālas pieteikšanās veidnes:

    (% paplašina "base.html" %) (% bloka nosaukums %)Pieteikšanās (% beigu bloks %) (% bloka saturs %)

    Pieteikties

    (% csrf_token %) (( form.as_p ))
    (%endblock%)

    Šis vienkāršais piemērs jau apstiprina lietotājvārdu un paroli un pareizi autentificē lietotāju.

    Pieteikšanās skata pielāgošana

    Ir daži parametri, kurus varat nodot pieteikšanās skatam, lai tas atbilstu jūsu projektam. Piemēram, ja vēlaties saglabāt savu pieteikšanās veidni kaut kur citur, nevis reģistrācija/login.html, varat nodot veidnes nosaukumu kā parametru:

    url (r"^login/$" , auth_views . login , ( "template_name" : "core/login.html" ), name = "login" ),

    Varat arī nodot pielāgotu autentifikācijas veidlapu, izmantojot parametru authentication_form , ja esat ieviesis pielāgotu lietotāja modeli.

    Tagad failā settings.py ir veikta ļoti svarīga konfigurācija, kas ir URL, kas pēc veiksmīgas autentifikācijas novirzīs lietotāju.

    Failā settings.py pievienojiet:

    LOGIN_REDIRECT_URL = "mājas"

    Vērtība var būt kodēts URL vai URL nosaukums. LOGIN_REDIRECT_URL noklusējuma vērtība ir /accounts/profile/ .

    Ir arī svarīgi atzīmēt, ka Django mēģinās novirzīt lietotāju uz nākamo GET parametru.

    Atteikšanās skata iestatīšana

    Pēc piekļūšanas skatam django.contrib.auth.views.logout, Django atveidos veidni register/logged_out.html. Līdzīgi kā mēs to darījām pieteikšanās skatā, varat nodot citu veidni, piemēram:

    url (r"^logout/$" , auth_views . logout , ( "veidnes_nosaukums" : "logged_out.html" ), name = "logout" ),

    Parasti es labprātāk izmantoju parametru next_page un novirzu uz sava projekta sākumlapu vai pieteikšanās lapu, kad tas ir lietderīgi.

    Galvenokārt lietotāja interfeisu izstrādei. Lai to izmantotu, jums ir jāizveido modeļa tips, kas attēlo pilnu programmas stāvokli, ziņojuma veids, kas apraksta ārējos vides notikumus, uz kuriem programmai jāreaģē, mainot savu stāvokli, atjauninātāja funkcija, kas izveido jaunu programmas stāvokli. no vecā stāvokļa un ziņojuma, un skata funkciju, kas Pamatojoties uz programmas stāvokli, aprēķina nepieciešamo ietekmi uz ārējo vidi, kas ģenerē Ziņojuma tipa notikumus. Modelis ir ļoti ērts, taču tam ir neliels trūkums - tas neļauj aprakstīt, kuri notikumi ir jēgpilni konkrētiem programmas stāvokļiem.

    Līdzīga problēma rodas (un tiek atrisināta), izmantojot valsts OO modeli.

    Elm valoda ir vienkārša, bet ļoti stingra – tā pārbauda, ​​vai atjauninātāja funkcija kaut kā apstrādā visas iespējamās modeļa stāvokļa un ziņojuma notikumu kombinācijas. Tāpēc jums ir jāraksta papildu, kaut arī triviāls kods, kas parasti atstāj modeli nemainīgu. Es vēlos parādīt, kā no tā var izvairīties sarežģītākās valodās - Idris, Scala, C++ un Haskell.

    Viss šeit parādītais kods ir pieejams GitHub eksperimentēšanai. Apskatīsim interesantākās vietas.


    Ziņojuma funkcija ir neparasta — tā atgriež veidu, nevis vērtību. Izpildes laikā nekas nav zināms par vērtību veidiem - kompilators izdzēš visu nevajadzīgo informāciju. Tas ir, šādu funkciju var izsaukt tikai kompilācijas stadijā.

    MUV ir konstruktors. Tas pieņem parametrus: modelis - programmas sākotnējais stāvoklis, atjauninātājs - funkcija stāvokļa atjaunināšanai pēc ārēja notikuma un skats - funkcija ārēja skata izveidošanai. Ņemiet vērā, ka atjauninātāja un skata funkciju veids ir atkarīgs no modeļa vērtības (izmantojot msg funkciju no tipa parametriem).

    Tagad redzēsim, kā palaist šo lietojumprogrammu

    MuvRun: (Application modelType msgType IO) -> IO a muvRun (MUV modeļa atjauninātāja skats) = do msg<- view model muvRun (MUV (updater model msg) updater view)
    Mēs izvēlējāmies ievades/izvades operāciju kā ārējo attēlojumu (skatu) (Idris, tāpat kā Haskell, ievades/izvades darbības ir pirmās klases vērtības; lai tās izpildītu, ir jāveic papildu darbības, parasti atgriežot šādu darbību no galvenās funkcijas).

    Īsi par IO

    Veicot (IO a) tipa operāciju, notiek kāda ietekme uz ārpasauli, iespējams, tukša, un programmai tiek atgriezta a tipa vērtība, bet standarta bibliotēkas funkcijas ir veidotas tā, lai tā varētu apstrādāt, tikai ģenerējot jaunu IO tipa vērtību b. Tādā veidā tīras funkcijas tiek atdalītas no funkcijām ar blakusparādībām. Tas ir neparasti daudziem programmētājiem, taču tas palīdz rakstīt uzticamāku kodu.


    Tā kā funkcija muvRun ģenerē I/O, tai ir jāatgriež IO, taču, tā kā tā nekad netiks pabeigta, darbības veids var būt jebkas - IO a.

    Tagad aprakstīsim entītiju veidus, ar kuriem mēs strādāsim

    Datu modelis = Izrakstīts | Pieteikšanās virknes dati MsgOuted = Pieteikšanās virknes dati MsgIned = Atteikšanās | Sveicināt kopējo msgType: Modelis -> Tips msgType Logouted = MsgOuted msgType (Pieteicies _) = Ziņojums
    Šeit mēs aprakstām modeļa veidu, kas atspoguļo divu interfeisa stāvokļu klātbūtni - lietotājs nav pieteicies, un lietotājs ar nosaukumu String ir pieteicies.

    Tālāk mēs aprakstam divi dažādi dažādiem modeļa variantiem aktuāli ziņojumu veidi - ja esam atteikušies, tad varam ielogoties tikai ar noteiktu vārdu, un, ja jau esam pieteikušies, varam vai nu iziet, vai arī pasveicināties. Idris ir stingri drukāta valoda, kas neļaus sajaukt dažādus veidus.

    Visbeidzot, funkcija, kas nosaka modeļa vērtības atbilstību ziņojuma veidam.

    Funkcija tiek deklarēta kā kopējā - tas ir, tai nevajadzētu avarēt vai sastingt, kompilators mēģinās to uzraudzīt. msgType tiek izsaukts kompilācijas laikā, un tā kopums nozīmē, ka kompilācija netiks iesaldēta mūsu kļūdas dēļ, lai gan tas nevar garantēt, ka šīs funkcijas izpilde iztērēs sistēmas resursus.
    Tiek arī garantēts, ka tas neizpildīs "rm -rf /", jo tā parakstā nav IO.

    Aprakstīsim atjauninātāju:

    Kopējais atjauninātājs: (m:Modelis) -> (msgType m) -> Modeļa atjauninātājs Atteicies (Pieteikšanās vārds) = Pieteikšanās vārda atjauninātājs (Pieteikšanās vārds) Atteikšanās = Atteikšanās atjauninātājs (Pieteikšanās vārds) Sveicināt = Pieteikšanās vārds
    Es domāju, ka šīs funkcijas loģika ir skaidra. Vēlreiz gribu atzīmēt totalitāti - tas nozīmē, ka Idris kompilators pārbaudīs, vai esam apsvēruši visas tipa sistēmas atļautās alternatīvas. Elm arī veic šo pārbaudi, taču nevar zināt, ka mēs nevaram izrakstīties, ja vēl neesam pieteikušies, un būs nepieciešama nepārprotama nosacījuma apstrāde.

    Atjauninātājs atteicās Logout = ???
    Idris nevajadzīgā pārbaudē atradīs veidu neatbilstības.

    Tagad pāriesim uz skatu – kā jau UI parasti, šī būs koda grūtākā daļa.

    Kopējā pieteikšanās lapa: IO MsgOuted loginPage = do putStr "Pieteikšanās: " karte Pieteikšanās getLine total genMsg: String -> MsgIned genMsg "" = Atteikšanās genMsg _ = Sveicināt kopējo darbuLapa: String -> IO MsgIned workPage name = do putStr ("Sveiki, " ++ name ++ "\n") putStr "Ievadiet tukšu virkni, lai atteiktos vai netukšu sveicienam\n" kartes genMsg getLine kopējais skats: (m: Modelis) -> IO (msgType m) skats Logouted = pieteikšanāsLapas skats (Pieteikšanās vārds ) = darba lapas nosaukums
    skatam ir jāizveido I/O operācija, kas atgriež ziņojumus, kuru veids atkal ir atkarīgs no modeļa vērtības. Mums ir divas iespējas: loginPage, kas izdrukā ziņojumu "Pieteikties:", nolasa virkni no tastatūras un iesaiņo to Pieteikšanās ziņojumā, un workPage ar lietotājvārda parametru, kas izdrukā sveiciena ziņojumu un atgriež dažādus ziņojumus (bet tos pašus). tips — MsgIned) atkarībā no tā, vai lietotājs ievada tukšu vai netukšu virkni. View atgriež vienu no šīm darbībām atkarībā no modeļa vērtības, un kompilators pārbauda to veidu, lai gan tas atšķiras.

    Tagad mēs varam izveidot un palaist savu lietojumprogrammu

    Lietojumprogramma: Lietojumprogrammas modelis Main.msgType IO app = MUV Atteicies atjauninātāja skats galvenais: IO () galvenais = muvRun app
    Šeit jāatzīmē smalks punkts - funkcija muvRun atgriežas IO a, kur a netika norādīts un galvenā vērtība ir tipa IO(), Kur () ir tāda veida nosaukums, ko parasti sauc Vienība, kurai ir viena vērtība, kas arī rakstīta kā tukšs kortežs () . Bet kompilators ar to var viegli tikt galā. tā vietā aizstājot a().

    Scala un no ceļa atkarīgie veidi

    Scala pilnībā neatbalsta atkarīgos tipus, taču ir veidi, kas ir atkarīgi no objekta gadījuma, caur kuru uz to ir atsauce (no ceļa atkarīgie veidi). Atkarīgo tipu teorijā tos var raksturot kā sigmas tipa variantu. No ceļa atkarīgie veidi ļauj aizliegt vektoru pievienošanu no dažādām vektoru telpām vai aprakstīt, kurš var kuru noskūpstīt. Bet mēs tos izmantosim vienkāršākiem uzdevumiem.

    Aizzīmogota abstraktā klase MsgLogouted gadījuma klase Pieteikšanās(nosaukums: Virkne) paplašina MsgLogouted aizzīmogotā abstraktā klase MsgLogined case class Logout() paplašina MsgLogined case class Greet() paplašina MsgLogined abstraktā klase Skats ( def run() : Msg ) class aizzīmogots ab types def view() : View ) case class Logouted() extends Model ( type Message = MsgLogined override def view() : View .... ) case class Logined(name: String) extensions Model ( type Message = MsgLogined override def view() ): Skatīt .... )
    Scala algebriskie veidi tiek modelēti, izmantojot iedzimtību. Veids atbilst dažiem aizzīmogotā abstraktā klase, un katrs konstruktors no tā mantojis lietu klase. Mēs mēģināsim tos izmantot tieši kā algebriskos tipus, aprakstot visus mainīgos kā piederīgus vecākajam aizzīmogotā abstraktā klase.

    Mūsu programmas klasēm MsgLogined un MsgLogouted nav kopīga priekšteča. Skatīšanas funkcijai bija jābūt sadalītai dažādās modeļa klasēs, lai varētu piekļūt noteikta veida ziņojumam. Tam ir savas priekšrocības, ko OO atbalstītāji novērtēs – kods ir sagrupēts atbilstoši biznesa loģikai, blakus ir viss, kas saistīts ar vienu lietošanas gadījumu. Bet es drīzāk nodalītu skatījumu atsevišķā funkcijā, kuras izstrādi varētu nodot citam cilvēkam.

    Tagad ieviesīsim atjauninātāju

    Objekta atjauninātājs ( def update(modelis: modelis)(īsziņa: modelis.Ziņojums) : Model = ( modeļa atbilstība ( case Logouted() => msg match ( case Login(name) => Logined(name) ) case Logined(name)) => īsziņu atbilstība ( case Logout() => Logouted() case Greet() => model ) ) ) )
    Šeit mēs izmantojam no ceļa atkarīgos veidus, lai aprakstītu otrā argumenta veidu no pirmā argumenta vērtības. Lai Scala pieņemtu šādas atkarības, funkcijas ir jāapraksta izmainītā formā, tas ir, kā funkcija no pirmā argumenta, kas atgriež funkciju no otrā argumenta. Diemžēl Scala šajā brīdī neveic daudzas tipa pārbaudes, par kurām kompilatoram ir pietiekami daudz informācijas.

    Tagad sniegsim pilnīgu modeļa un skata ieviešanu

    Gadījuma klase Logouted() paplašina modeli ( type Message = MsgLogouted override def view() : View = new View ( ignore def run() = ( println("Ievadiet nosaukumu ") val name = scala.io.StdIn.readLine() Pieteikšanās (nosaukums) ) ) gadījuma klase Pieteicies(nosaukums: String) paplašina Modelis ( type Message = MsgLogined override def view() : View = new View ( ignore def run() = ( println(s"Sveiki, $name") println ( "Tukša virkne atteikšanās, nonempy sveicienam.") scala.io.StdIn.readLine() atbilst ( case "" => Logout() case _ => Greet() ) ) ) abstrakta klase Skats ( def run( ) ): Msg ) object Viewer ( def view(modelis: Model): View = ( model.view() ) )
    Skata funkcijas atgriešanas veids ir atkarīgs no tās argumenta gadījuma. Bet ieviešanai tas vēršas pie modeļa.

    Šādā veidā izveidotā lietojumprogramma tiek palaista šādi:

    Object Main ( import scala.annotation.tailrec @tailrec def process(m: Model) ( val msg = Viewer.view(m).run() process(Updater.update(m)(msg)) ) def main(args: Masīvs) = ( process (Atteicies()) ) )
    Tādējādi izpildlaika sistēmas kods neko nezina par modeļu iekšējo struktūru un ziņojumu veidiem, taču kompilators var pārbaudīt, vai ziņojums atbilst pašreizējam modelim.

    Šeit mums nebija vajadzīgas visas iespējas, ko nodrošina no ceļa atkarīgie veidi. Interesantas īpašības parādīsies, ja strādāsim paralēli ar vairākiem Model-Updater-View sistēmu gadījumiem, piemēram, simulējot vairāku aģentu pasauli (skats pēc tam attēlo aģenta ietekmi uz pasauli un atgriezeniskās saites saņemšanu). Šajā gadījumā kompilators pārbaudīja, vai ziņojumu apstrādāja tieši tas aģents, kuram tas bija paredzēts, neskatoties uz to, ka visiem aģentiem ir vienāds veids.

    C++

    C++ joprojām ir jutīgs pret definīciju secību, pat ja tās visas ir izveidotas vienā failā. Tas rada zināmas neērtības. Es iesniegšu kodu ideju demonstrēšanai ērtā secībā. Kompilējamo versiju var atrast vietnē GitHub.

    Algebriskos tipus var realizēt tāpat kā Scala - abstrakta klase atbilst tipam, bet konkrētie pēcteči atbilst algebriskās konstruktoriem (sauksim tos par “konstruktoru klasēm”, lai nesajauktu ar parastajiem C++ konstruktoriem). veids.

    C++ atbalsta no ceļa atkarīgos tipus, taču kompilators nevar izmantot veidu abstraktā veidā, nezinot īsto tipu, ar kuru tas ir saistīts. Tāpēc ar viņu palīdzību nav iespējams ieviest Model-Updater-View.

    Bet C++ ir jaudīga veidņu sistēma. Tipa atkarību no modeļa vērtības var paslēpt izpildsistēmas specializētās versijas veidnes parametrā.

    Struktūras procesors ( virtual const Processor *next() const = 0; ); veidni struct ProcessorImpl: publiskais procesors ( const CurModel * modelis; ProcessorImpl (const CurModel* m) : modelis(m) ( ); const Procesors *next() const ( const Skats
    Mēs aprakstām abstraktu izpildes sistēmu ar vienu metodi, lai veiktu visu nepieciešamo un atgrieztu jaunu izpildes sistēmu, kas piemērota nākamajai iterācijai. Konkrētajai versijai ir veidnes parametrs, un tā tiks specializēta katrai modeļa “konstruktoru klasei”. Šeit ir svarīgi, lai visas CurModel tipa īpašības tiktu pārbaudītas veidnes specializācijas laikā ar noteiktu tipa parametru, un pašas veidnes kompilēšanas brīdī tās nav jāapraksta (lai gan tas ir iespējams, izmantojot koncepcijas vai citi veidu klašu īstenošanas veidi). Scala ir arī diezgan jaudīga parametrizēto tipu sistēma, taču tā pārbauda parametru tipu īpašības parametrizētā tipa kompilēšanas laikā. Tur šāda modeļa ieviešana ir sarežģīta, bet iespējama, pateicoties tipa nodarbību atbalstam.

    Aprakstīsim modeli.

    Struktūras modelis ( virtual ~Model() (); virtual const Procesors *processor() const = 0; ); struct Logined: public Model ( struct Message ( const virtual Model * process(const Logined * m) const = 0; virtual ~Message() (); struct Logout: public Message ( const Model * process(const Logined * m) const; struct Sveiciens: public Message ( const Modelis * process(const Pieteicies * m) const; std:: virknes nosaukums public View; (...); const Skats * view() const (atgriezt jaunu LoginedView(nosaukums); ); (...); const Procesors *processor() const (atgriezt jaunu ProcessorImpl (šis);
    ); ); struct Logouted: public Model ( struct Message ( const virtual Model * process(const Logouted * m) const = 0; virtual ~Message() (); struct Login: public Message ( const std:: virknes nosaukums; Pieteikšanās(std :: string lname) : name(lname) ( const Modelis * process(const Logouted * m) const ;

    * view() const (atgriezt jaunu LogoutedView(); );

    Const Model * Logouted::Login::process(const Logouted * m) const ( dzēst m; atgriezt jaunu Pieteicies(vārds); ); const Modelis * Pieteicies::Iziet::process(const Pieteicies * m) const ( dzēst m; atgriezties jauns Atteicies(); ); const Modelis * Pieteicies::Greet::process(const Pieteicies * m) const (atgriezties m; );
    Tagad apkoposim visu, kas attiecas uz skatu, ieskaitot modeļu iekšējās entītijas

    Veidne struct View ( virtual const Message * run() const = 0; virtual ~ View () (); ); struct Pieteicies: publisks Modelis ( struct LoginedView: publisks skats ( const std::string name; LoginedView(std::string lname) : name(lname) (); virtual const Ziņojums * palaist() const ( char buf; printf("Sveiki, %s", name.c_str()) fgets(buf, 15, stdin) return (*buf == 0 || *buf == "\n" || *buf == "\r") ? (jauns Logout()) : static_cast (jauns Greet); ); ); const Skats
    * view() const (atgriezt jaunu LoginedView(nosaukums); ); ); struct Logouted: publisks Modelis ( struct LogoutedView: publisks skats

    ( virtual const Ziņojums * run() const ( char buf; printf ("Pieteikšanās: "); fgets(buf, 15, stdin); return new Login(buf); ); ); const Skats

    * view() const (atgriezt jaunu LogoutedView(); ); );

    Un visbeidzot, rakstīsim galveno

    Int main(int argc, char ** argv) ( const Processor * p = new ProcessorImpl

    (jauns Logouted());


    while(true) (const Procesors * pnew = p-> next(); dzēst p; p = pnew; ) atgriež 0; )

    Klase ProcesorsImpl(modelis: M)(netiešais atjauninātājs: (M, Ziņojums) => Modelis, skats: M => Skats) paplašina Procesors ( def next(): Procesors = ( val v = skats(modelis) val msg = v. palaist() val newModel = updater(model,msg) newModel.processor() ) )
    Šeit mēs redzam jaunus noslēpumainus parametrus (netiešais atjauninātājs: (M, ziņojums) => Modelis, skats: M => Skatīt). Netiešais atslēgvārds nozīmē, ka, izsaucot šo funkciju (precīzāk, klases konstruktoru), kompilators meklēs piemērotu tipu objektus, kas kontekstā atzīmēti kā implicit, un nodos tos kā atbilstošus parametrus. Šī ir diezgan sarežģīta koncepcija, kuras viens no pielietojumiem ir tipa klašu ieviešana. Šeit viņi sola kompilatoram, ka konkrētām modeļa un ziņojuma implementācijām visas nepieciešamās funkcijas nodrošināsim mēs. Tagad pildīsim šo solījumu.

    Objektu atjauninātāji ( implicit def logoutedUpdater(modelis: Logouted, msg: LogoutedMessage): Model = ( (modelis, msg) match ( case (Logouted(), Login(name)) => Logined(name) ) ) implicit def viewLogouted(modelis) : Logouted) = new View ( ignore def run() : LogoutedMessage = ( println("Ievadiet nosaukumu ") val name = scala.io.StdIn.readLine() Login(name) ) ) implicit def loginedUpdater(modelis: Pieteicies, msg : PieteiktiesZiņojums): Modelis = ( (modelis, ziņa) atbilst ( case (Logined(name), Logout()) => Logouted() case (Logined(name), Greet()) => model ) ) implicit def viewPieteicies( modelis: Pieteicies) = new View ( val name = model.name ignore def run() : LoginedMessage = ( println(s"Sveiks, $name") println("Tukša virkne atteikšanās, nonempy sveicienam.") scala.io .StdIn.readLine() atbilst ( case "" => Logout() case _ => Greet() ) ) ) importēt atjauninātājus._

    Haskels

    Galvenajā Haskellā nav atkarīgu tipu. Tam arī trūkst mantojuma, ko mēs ievērojami izmantojām, ieviešot modeli Scala un C++. Bet viena līmeņa mantojumu (ar atkarīgo tipu elementiem) var modelēt, izmantojot vairāk vai mazāk standarta valodas paplašinājumus - TypeFamilies un ExistentialQuantification. Bērna OOP klašu kopējam interfeisam tiek izveidota tipa klase, kurā ir atkarīgs “ģimenes” tips, pašas bērnu klases tiek attēlotas ar atsevišķu tipu un pēc tam ietītas “eksistenciālā” tipā ar vienu konstruktoru. .

    Datu modelis = visiem m. (Atjaunināms m, Skatāms m) => Modeļa m klase Atjaunināms m kur dati Ziņojums m:: * atjauninājums:: m -> (Ziņojums m) -> Modeļa klase (Atjaunināms m) => Skatāms m kur skats:: m -> (Skatīt (Ziņojums m)) dati Logouted = Atteikušies dati Logined = Pieteikties String
    Es mēģināju pēc iespējas nodalīt atjauninātāju un skatu, tāpēc izveidoju divas dažādas tipa klases, taču līdz šim tas nav izdevies.

    Atjauninātāja ieviešana ir vienkārša

    Gadījums Atjaunināms Atteicies, kur dati Ziņojums atteicies = Pieteikšanās virknes atjauninājums Atteicies (Pieteikšanās vārds) = Modelis (Pieteikšanās vārds) Instancē Atjaunināms Pieteikties, kur dati Ziņojums pieteicies = Iziet | Apsveikuma atjauninājums m Atteikties = modelis Atteicies atjauninājums m Sveiciens = modelis m
    Man bija jālabo IO kā View. Mēģinājumi padarīt to abstraktāku ļoti sarežģīja visu un palielināja koda savienošanu - modeļa tipam ir jāzina, kuru View mēs izmantosim.

    Importēt System.IO tipu Skats a = IO instanci Skatāms Atteicies kur skats Atteicies = do putStr "Pieteikšanās: " hFlush stdout fmap Pieteikšanās getLine instance Skatāma Pieteikusies kur skats (Pieteikšanās vārds) = do putStr $ "Sveiki " ++ name ++ " !\n" hFlush stdout l<- getLine pure $ if l == "" then Logout else Greeting
    Labi, izpildāmā vide maz atšķiras no līdzīgās Idris

    RunMUV::Model -> IO a runMUV (Modelis m) = do msg<- view m runMUV $ update m msg main:: IO () main = runMUV (Model Logouted)

    Šis piemērs parāda, kā automātiski atteikties, izmantojot noklusējuma Spring drošības konfigurāciju.

    Lai atteiktos, mums vienkārši jāpiekļūst vietrādim URL "/logout" ar POST pieprasījumu.

    POST/logout veidlapā ir jāiekļauj arī CSRF marķieris, kas ir aizsardzība pret CSRF uzbrukumu.

    Apskatīsim piemēru, kā to izdarīt.

    Java konfigurācijas klase

    @Configuration @EnableWebSecurity @EnableWebMvc @ComponentScan publisko klasi AppConfig paplašina WebSecurityConfigurerAdapter ( Protected Void configure(HttpSecurity http) rada izņēmumu ( http.authorizeRequests() .anyRequest().authenticated() @Over public() .and()ri); void configure(AuthenticationManagerBuilder veidotājs) rada izņēmumu ( builder.inMemoryAuthentication() .withUser("joe") .password("123") .roles("ADMIN"); ) @Bean public ViewResolver viewResolver() ( InternalResourceViewResolver view (); viewResolver.setPrefix("/WEB-INF/views/");

    Ņemiet vērā, ka iepriekš minētajā konfigurācijā mēs arī ignorējam konfigurāciju (HttpSecurity http), lai izlaistu noklusējuma pamata autentifikāciju (skatiet sākotnējo metodi WebSecurityConfigurerAdapter avota kodā) un izmantotu veidlapu balstītu autentifikāciju. Mēs to darām, jo ​​pārlūkprogrammas agresīvi (pēc pirmās veiksmīgas pieteikšanās) kešatmiņā saglabā pamata autentifikācijas informāciju un pašreizējā sesijā nav iespējams atteikties no lietotāja. Lielākajā daļā piemēru mēs neizmantosim pamata autentifikācijas mehānismu.

    Kontrolieris

    @Controller publiskā klase PiemērsController ( @RequestMapping("/") public String handleRequest2(ModelMap map) ( map.addAttribute("time", LocalDateTime.now().toString()); atgriež "mana lapa"; ) )

    JSP lapa

    src/main/webapp/WEB-INF/views/my-page.jsp

    Pavasara drošības piemērs

    Laiks: $(laiks)

    Lai izmēģinātu piemērus, palaidiet iegulto runci (kas konfigurēts tālāk norādītā paraugprojekta failā pom.xml):

    Mvn tomcat7:run-war

    Izvade

    Sākotnējā piekļuve URI "/" tiks novirzīta uz "/login":

    Pēc lietotājvārda un paroles iesniegšanas, kā mēs iestatījām mūsu AppConfig klasē:

    Noklikšķinot uz pogas "Iziet":


    Projekta piemērs

    Atkarības un izmantotās tehnoloģijas:

    • spring-security-web 4.2.3.IZLAIDI: spring-security-web.
    • spring-security-config 4.2.3.RELEASE: spring-security-config.
    • spring-webmvc 4.3.9.IZLAIDS: Spring Web MVC.
    • javax.servlet-api 3.1.0 Java Servlet API
    • JDK 1.8
    • Maven 3.3.9