cum funcționează cu adevărat Spring Web MVC

Introducere

aceasta este o privire aprofundată asupra caracteristicilor puternice și a lucrărilor interne ale Spring Web MVC, care face parte din cadrul Spring.

codul sursă pentru acest articol este disponibil pe GitHub.

configurare proiect

pe parcursul acestui articol, vom folosi cel mai recent și cel mai mare cadru de primăvară 5., Ne concentrăm aici pe clasicul Stack Web al primăverii, care a fost disponibil încă de la primele versiuni ale cadrului și este încă modul principal de construire a aplicațiilor web cu Spring.

Pentru început, pentru a configura proiectul de test, veți folosi Spring Boot și unele dintre dependențele sale de starter; de asemenea, va trebui să definiți părintele:

rețineți că, pentru a utiliza Spring 5, trebuie să utilizați și Spring Boot 2.x. la momentul scrierii, aceasta este o versiune milestone, disponibilă în depozitul Spring Milestone., Să adăugăm acest depozit la proiectul dvs. Maven:

puteți verifica versiunea curentă a Spring Boot pe Maven Central.pentru a înțelege cum funcționează Spring Web MVC, veți implementa o aplicație simplă cu o pagină de conectare. Pentru a afișa pagina de conectare, a crea un @ Controller-adnotat clasa InternalController cu o mapare GET pentru rădăcina context.

metoda hello () este fără parametri. Returnează un șir care este interpretat de Spring MVC ca nume de vizualizare (în cazul nostru, login-ul.,html template):

import org.springframework.web.bind.annotation.GetMapping;@GetMapping("/")public String hello() { return "login";}

pentru a procesa o autentificare utilizator, creați o altă metodă care se ocupă de cereri POST cu datele de conectare. Apoi redirecționează utilizatorul fie la pagina de succes sau eșec, în funcție de rezultat.,

Rețineți că login() metodă primește un domeniu obiect ca argument și returnează o ModelAndView obiect:

ModelAndView este un deținător a două obiecte distincte:

  • Model – o cheie-valoare hartă de date folosit pentru a randa pagina
  • View – un șablon de pagină, care este umplut cu date din modelul

Acestea sunt unite pentru comoditate, astfel încât operatorul metodă le poate reveni atât la o dată.pentru a reda pagina HTML, utilizați Thymeleaf ca motor de vizualizare șablon, care are o integrare solidă, out-of-the-box cu Spring.,

Servlets ca fundament al unei aplicații Web Java

deci, ce se întâmplă de fapt când tastați http://localhost:8080/ în browser, apăsați Enter, iar solicitarea lovește serverul web? Cum ajungi de la această solicitare la a vedea un formular web în browser?având în vedere că proiectul este o aplicație simplă de pornire de primăvară, veți putea să o rulați prin intermediul aplicației Spring5Application.

boot-ul de primăvară utilizează în mod implicit Apache Tomcat., Prin urmare, rulând aplicația, este posibil să vedeți următoarele informații în jurnal:

deoarece Tomcat este un container Servlet, în mod natural, fiecare cerere HTTP trimisă unui server web Tomcat este procesată de un servlet Java. Deci, punctul de intrare al aplicației web Spring este, nu este surprinzător, un servlet.

un servlet este, pur și simplu, o componentă de bază a oricărei aplicații Web Java; este de nivel scăzut și nu impune prea mult în modul de modele de programare specifice, cum ar fi MVC.

un servlet HTTP poate primi doar o solicitare HTTP, o poate procesa într-un fel și poate trimite un răspuns înapoi.,

și, începând cu API-ul Servlet 3.0, puteți trece acum dincolo de configurația XML și puteți începe să utilizați configurația Java (cu restricții minore).,

DispatcherServlet ca Inima de Primăvară MVC

ceea Ce vrem să facem ca dezvoltatorii de aplicații web este de a abstract departe următoarele plictisitor și șabloane sarcini și să se concentreze pe afaceri utile logica:

  • cartografiere o cerere HTTP pentru o anumită metodă de prelucrare
  • analiza de cerere HTTP de date și anteturile în obiecte de transfer de date (DTOs) sau domeniu de obiecte
  • model-view-controller interacțiune
  • generarea de răspunsuri de la DTOs, domeniu de obiecte, etc.

dispecerul de Primăvarăservletul oferă exact acest lucru., Este inima cadrului Spring Web MVC; această componentă de bază primește toate cererile către aplicația dvs.

după cum veți vedea, DispatcherServlet este foarte extensibil.,placare motoare, XML, XSLT sau orice alte tehnologia vedere (implementări ale ViewResolver interface)

  • analiza mai multe cereri prin utilizarea default Apache Commons fișier încărcarea punerea în aplicare sau scrierea ta MultipartResolver
  • rezolva locale cu orice LocaleResolver punere în aplicare, inclusiv cookie, sesiune, Accepta HTTP antet, sau orice alt mod de determinare locale așteptat de către utilizator
  • Prelucrare de o Cerere HTTP

    în Primul rând, haideți să urmărim prelucrarea simple cereri HTTP la o metodă în strat controler și înapoi la browser-ul/client.,

    Dispecerulservletul are o ierarhie lungă de moștenire, merită să înțelegeți aceste aspecte individuale unul câte unul, de sus în jos. Metodele de procesare a solicitărilor ne vor interesa cel mai mult.

    înțelegerea cererii HTTP, atât la nivel local în timpul dezvoltării standard, cât și de la distanță, este o parte critică a înțelegerii arhitecturii MVC.

    GenericServlet

    GenericServlet este o parte a specificației Servlet care nu se concentrează direct pe HTTP. Acesta definește serviciul () metoda care primește cererile primite și produce răspunsuri.,

    Notă cum ServletRequest și ServletResponse metoda argumente nu sunt legate de protocolul HTTP:

    public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;

    Aceasta este metoda care este numit în cele din urmă cu privire la orice cerere la server, inclusiv o simplă cerere GET.

    HttpServlet

    clasa HttpServlet este, după cum sugerează și numele, implementarea servlet-ului axat pe HTTP, definită și de specificație.,

    În mai multe punct de vedere practic, HttpServlet este o clasă abstractă cu un service() punerea în aplicare metoda care desparte cereri de metoda HTTP tip si arata aproximativ ca aceasta:

    HttpServletBean

    Apoi, HttpServletBean este primul Izvor conștient de clasă în ierarhie. Se injectează proprietățile fasole folosind valorile init-param servlet primite de pe web.xml sau de la WebApplicationInitializer.

    în cazul solicitărilor către aplicația dvs., metodele doGet(), doPost(), etc sunt solicitate pentru acele solicitări HTTP specifice.,

    FrameworkServlet

    FrameworkServlet integrează Servlet funcționalitate cu o aplicație web context, punerea în aplicare a ApplicationContextAware interfață. Dar este, de asemenea, capabil să creeze un context de aplicație web pe cont propriu.după cum ați văzut deja, superclasa HttpServletBean injectează init-params ca proprietăți de fasole. Deci, dacă un nume de clasă context este furnizat în contextClass init-param din servlet, atunci o instanță a acestei clase va fi creată ca context de aplicație. În caz contrar, va fi utilizată o clasă implicită xmlwebapplicationcontext.,

    ca configurație XML este de stil în zilele noastre, Spring Boot configurează DispatcherServlet cu Adnotationconfigwebapplicationcontext implicit. Dar ai putea schimba asta cu ușurință.de exemplu, dacă trebuie să configurați aplicația Spring Web MVC cu un context de aplicație Groovy, puteți utiliza următoarea configurație a DispatcherServlet în web.fișier xml:

     dispatcherServlet org.springframework.web.servlet.DispatcherServlet contextClass org.springframework.web.context.support.GroovyWebApplicationContext 

    aceeași configurație poate fi făcut într-un mod mai moderne bazate pe Java folosind WebApplicationInitializer clasa.,

    DispatcherServlet: Unificarea Cererea de Procesare

    HttpServlet.serviciu () Punerea în aplicare, care rutează cererile de tipul de verb HTTP, are sens perfect în contextul servlets de nivel scăzut. Cu toate acestea, la nivelul de abstractizare Spring MVC, tipul metodei este doar unul dintre parametrii care pot fi utilizați pentru a mapa cererea către handler-ul său.,

    Și astfel, alte principala funcție a FrameworkServlet clasă este de a adera la manipularea logica înapoi într-o singură processRequest() metodă, care, la rândul său, solicită doService() metodă:

    @Overrideprotected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response);}@Overrideprotected final void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response);}// …

    DispatcherServlet: Îmbogățirea Cerere

    în cele din Urmă, DispatcherServlet implementează doService() metodă. Aici, se adaugă la cererea unor obiecte utile care pot veni la îndemână în jos conducta de procesare: context aplicație web, locale resolver, tema resolver, tema sursă etc.de asemenea, metoda doService() pregătește hărți flash de intrare și ieșire., Flash map este de fapt un model pentru a trece parametrii de la o cerere la alta cerere care urmează imediat. Acest lucru poate fi foarte util în timpul redirecționează (ca și cum arată utilizatorului un one-shot mesaj de informare după redirect):

    Apoi, doService() metodă solicită doDispatch() metodă, care este responsabil pentru solicitarea de expediere.

    DispatcherServlet: expedierea cererii

    scopul principal al metodei de expediere () este de a găsi un handler adecvat pentru cerere și de a alimenta parametrii de solicitare/răspuns., Handler-ul este practic orice fel de Obiect și nu se limitează la o interfață specifică. Acest lucru înseamnă, de asemenea, că Spring trebuie să găsească un adaptor pentru acest handler care știe să „vorbească” cu handler-ul.pentru a găsi handler-ul care se potrivește cu cererea, Spring trece prin implementările înregistrate ale interfeței HandlerMapping. Există multe implementări diferite care s-ar putea potrivi nevoilor dvs.SimpleUrlHandlerMapping permite maparea unei cereri prin URL-ul său la o anumită fasole de procesare. De exemplu, poate fi configurat prin injectarea proprietății mapări cu un java.util.,Proprietăți exemplu similar cu acesta:

    /welcome.html=ticketController/show.html=ticketController

    Probabil cel mai utilizat pe scară largă pentru clasa handler de cartografiere este RequestMappingHandlerMapping, care prezintă o cerere pentru o @RequestMapping-adnotat metoda de a @Controller class. Aceasta este exact maparea care conectează dispecerul cu metodele hello () și login () ale controlerului.

    rețineți că metodele dvs. conștiente de primăvară sunt adnotate cu @GetMapping și @PostMapping corespunzător. Aceste adnotări, la rândul lor, sunt marcate cu meta-adnotare @RequestMapping.,

    expediere() metodă, de asemenea, are grijă de alte HTTP-sarcini specifice:

    • scurt-circuit de prelucrare a PRIMI cerere în cazul în care resursa nu a fost modificat de
    • aplicarea multipart resolver pentru solicitările corespunzătoare
    • scurt-circuit de procesare a cererii dacă utilizatorul a ales să-l ocupe în mod asincron

    Manipularea Cerere

    Acum că Primăvara a determinat handler pentru cererea și adaptorul pentru handler, e timpul să se ocupe de cerere. Iată semnătura manipulatorului.mâner () metodă., Este important să rețineți că agentul și-a făcut o alegere în cum să se ocupe de cerere:

    • scrie datele la răspunsul obiect de sine și a reveni nul

    se întoarcă un ModelAndView obiect care urmează să fie prestate de către DispatcherServlet

    @NullableModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    Există mai multe furnizate tipuri de stivuitoare. Iată cum procesează SimpleControllerHandlerAdapter o instanță de controler de primăvară MVC (nu-l confunda cu un @Pojo adnotat-controler).,

    Observați cum controller handler se întoarce ModelAndView obiect și nu afectează imaginea de sine:

    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return ((Controller) handler).handleRequest(request, response);}

    Cea de-a doua este SimpleServletHandlerAdapter, care se adaptează un regulat Servlet ca o cerere handler.

    un Servlet nu știe nimic despre ModelAndView și pur și simplu gestionează cererea de la sine, făcând rezultatul în obiectul de răspuns., Deci, acest adaptor pur și simplu se întoarce null în loc de ModelAndView:

    In cazul tau, un controller este un POJO cu mai multe @RequestMapping adnotări, astfel încât orice handler este de fapt o metodă de această clasă înfășurat într-o HandlerMethod exemplu. Pentru a se adapta la acest tip de handler, Spring utilizează clasa RequestMappingHandlerAdapter.,

    procesarea argumentelor și returnarea valorilor metodelor Handler

    rețineți că metodele controlerului nu iau de obicei argumente HttpServletRequest și HttpServletResponse, ci primesc și returnează multe tipuri diferite de date, cum ar fi obiecte de domeniu, parametri de cale etc.de asemenea, rețineți că nu vi se cere să returnați o instanță ModelAndView dintr-o metodă de control. Puteți returna un nume de vizualizare sau un ResponseEntity sau un POJO care va fi convertit într-un răspuns JSON etc.,

    RequestMappingHandlerAdapter asigură că argumentele metodei sunt rezolvate din HttpServletRequest. De asemenea, creează obiectul ModelAndView din valoarea returnată a metodei.

    Există o importantă bucată de cod în RequestMappingHandlerAdapter care face sigur că toată această transformare magică are loc:

    ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);if (this.argumentResolvers != null) { invocableMethod.setHandlerMethodArgumentResolvers( this.argumentResolvers);}if (this.returnValueHandlers != null) { invocableMethod.setHandlerMethodReturnValueHandlers( this.returnValueHandlers);}

    argumentResolvers obiect este un compozit de diferite HandlerMethodArgumentResolver cazuri.

    există peste 30 de implementări diferite argument resolver., Acestea permit extragerea de orice fel de informații din cerere și furnizarea acesteia ca argumente de metodă. Aceasta include variabilele căii URL, parametrii corpului de solicitare, anteturile de solicitare, cookie-urile, datele sesiunii etc.

    obiectul returnValueHandlers este un compozit de obiecte HandlerMethodReturnValueHandler. Există, de asemenea, o mulțime de manipulatori de valori diferite care pot procesa rezultatul metodei dvs. pentru a crea obiectul ModelAndView așteptat de adaptor.

    de exemplu, când returnați un șir din metoda hello (), ViewNameMethodReturnValueHandler procesează valoarea., Dar când reveniți un ModelAndView gata de conectare () metoda, Spring utilizează ModelAndViewMethodReturnValueHandler.până acum, Spring a procesat cererea HTTP și a primit un obiect ModelAndView, deci trebuie să redea pagina HTML pe care utilizatorul o va vedea în browser. Face asta pe baza modelului și a vizualizării selectate încapsulate în obiectul ModelAndView.

    de asemenea, rețineți că ați putea face un obiect JSON, sau XML, sau orice alt format de date care pot fi transferate prin protocolul HTTP., Vom atinge mai multe despre asta în secțiunea viitoare concentrată aici.

    să ne întoarcem la Dispecerservlet. Render () metoda stabilește mai întâi locale de răspuns folosind instanța LocaleResolver furnizate. Să presupunem că browserul dvs. modern stabilește corect antetul Accept și că AcceptHeaderLocaleResolver este utilizat în mod implicit.

    în timpul randării, obiectul ModelAndView ar putea conține deja o referință la o vizualizare selectată sau doar un nume de vizualizare sau nimic dacă controlerul se baza pe o vizualizare implicită.,

    deoarece ambele hello () și login () metode specifica vizualizarea dorită ca un nume de șir, trebuie să fie privit în sus de acest nume. Deci, acest lucru este în cazul în care viewResolvers listă intră în joc:

    Aceasta este o listă de ViewResolver instanțe, inclusiv ThymeleafViewResolver furnizate de thymeleaf-spring5 integrare bibliotecă. Acest rezolvator știe unde să caute vizualizările și oferă instanțele de vizualizare corespunzătoare.,după apelarea metodei render() a vizualizării, Spring finalizează procesarea solicitării prin trimiterea paginii HTML către browserul utilizatorului:

    suport REST

    dincolo de scenariul tipic MVC, putem folosi și Cadrul pentru a crea servicii web REST.

    pur și simplu, puteți accepta o resursă ca intrare, specificați un POJO ca argument de metodă și adnotați-l cu @RequestBody., De asemenea, puteți adnota metoda în sine cu @ResponseBody pentru a specifica că rezultatul său trebuie transformat direct într-un răspuns HTTP:

    Acest lucru este posibil și datorită extensibilității Spring MVC.

    pentru a marshall DTOs interne la o reprezentare REST, cadrul face uz de infrastructura HttpMessageConverter. De exemplu, una dintre implementări este MappingJackson2HttpMessageConverter, care este capabil să convertească obiecte model în și de la JSON folosind biblioteca Jackson.,și pentru a simplifica și mai mult crearea unui API REST, Spring introduce adnotarea @RestController. Acest lucru este util pentru a presupune semantica @ResponseBody în mod implicit și pentru a evita setarea explicită a fiecărui controler REST:

    concluzie

    în acest articol, ați trecut prin procesarea unei solicitări în cadrul Spring MVC în detaliu. Ați văzut cum diferite extensii ale cadrului lucrează împreună pentru a oferi toată magia și pentru a vă scuti de necesitatea de a gestiona părțile dure ale protocolului HTTP.,îmbunătățiți continuu aplicațiile Java utilizând Stackify Retrace, instrumentul complet de gestionare a performanței aplicațiilor pentru ciclul de viață. Încearcă.

    Author: admin

    Lasă un răspuns

    Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *