Uvod u Spring DispatcherServlet

1. Uvod

Jednostavno rečeno, u Prednji kontroler uzorak dizajna, jedan kontroler je odgovoran za usmjeravanje dolaznih HttpRequests svim ostalim kontrolerima i voditeljima aplikacije.

Proljetni DispatcherServlet provodi ovaj obrazac i stoga je odgovoran za ispravnu koordinaciju HttpRequests njihovim desnim voditeljima.

U ovom ćemo članku ispitati Proljeće DispatcherServlet's tijek obrade zahtjeva i kako implementirati nekoliko sučelja koja sudjeluju u ovom tijeku rada.

2. DispatcherServlet Obrada zahtjeva

U osnovi, a DispatcherServlet obrađuje dolazni HttpRequest, delegira zahtjev i obrađuje taj zahtjev prema konfiguriranom HandlerAdapter sučelja koji su implementirani unutar aplikacije Spring zajedno s pripadajućim bilješkama koje specificiraju rukovatelje, krajnje točke kontrolera i objekte odgovora.

Idemo detaljnije o tome kako a DispatcherServlet obrađuje komponentu:

  • the WebApplicationContext povezan s a DispatcherServlet ispod ključa DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE traži se i stavlja na raspolaganje svim elementima procesa
  • The DispatcherServlet pronalazi sve implementacije HandlerAdapter sučelje konfigurirano za vašeg dispečera pomoću getHandler () - svaka pronađena i konfigurirana implementacija obrađuje zahtjev putem ručka () kroz ostatak postupka
  • the LocaleResolver je neobavezno vezan za zahtjev za omogućavanje elemenata u procesu za rješavanje lokalizacije
  • the ThemeResolver je neobavezno vezan uz zahtjev da elementi, poput pogleda, odrede koju će temu koristiti
  • ako a MultipartResolver je naveden, zahtjev se pregledava MultipartFiles - svi pronađeni umotani su u MultipartHttpServletRequest za daljnju obradu
  • HandlerExceptionResolver implementacije deklarirane u WebApplicationContext preuzima iznimke koje se pojavljuju tijekom obrade zahtjeva

Možete saznati više o svim načinima registracije i postavljanja a DispatcherServlet ovdje.

3. HandlerAdapter Sučelja

The HandlerAdapter sučelje olakšava upotrebu kontrolera, servleta, HttpRequestsi HTTP staze kroz nekoliko određenih sučelja. The HandlerAdapter Sučelje tako igra ključnu ulogu kroz mnoge faze DispatcherServlet tijek obrade zahtjeva.

Prvo, svaki HandlerAdapter implementacija je smještena u HandlerExecutionChain od vašeg dispečera getHandler () metoda. Zatim, svaka od tih implementacija ručka () the HttpServletRequest objekt dok se izvršava lanac.

U sljedećim odjeljcima istražit ćemo nekoliko najvažnijih i najčešće korištenih HandlerAdapters detaljnije.

3.1. Mapiranja

Da bismo razumjeli preslikavanja, prvo moramo pogledati kako dodavati komentare kontrolerima jer su kontrolori toliko bitni za HandlerMapping sučelje.

The SimpleControllerHandlerAdapter omogućuje implementaciju kontrolera izričito bez a @Controller bilješka.

The RequestMappingHandlerAdapter podržava metode označene s @RequestMapping bilješka.

Usredotočit ćemo se na @Controller ovdje, ali koristan izvor s nekoliko primjera koji koriste SimpleControllerHandlerAdapter je također dostupan.

The @RequestMapping napomena postavlja određenu krajnju točku na kojoj će obrađivač biti dostupan unutar WebApplicationContext povezano s tim.

Pogledajmo primjer a Kontroler koja razotkriva i obrađuje ‘/ Korisnik / primjer’ krajnja točka:

@Controller @RequestMapping ("/ user") @ResponseBody javna klasa UserController {@GetMapping ("/ example") javni korisnik fetchUserExample () {// ...}}

Putovi navedeni u @RequestMapping anotacijama se interno upravlja putem HandlerMapping sučelje.

Struktura URL-ova prirodno se odnosi na DispatcherServlet sam - i određen mapiranjem servleta.

Dakle, ako je DispatcherServlet se preslikava na '/', tada će sva preslikavanja biti pokrivena tim mapiranjem.

Ako je, međutim, mapiranje servleta '/dispečer'Umjesto toga, bilo koji @Zahtjev za mapiranje napomene će biti u odnosu na taj korijenski URL.

Imajte na umu da '/' nije isto što i '/ *' za preslikavanja servleta! ‘/’ Je zadano mapiranje i izlaže sve URL-ove zoni odgovornosti dispečera.

‘/ *’ Zbunjuje mnoge novije programere Springa. Ne navodi da su svi putovi s istim kontekstom URL-a u zoni odgovornosti dispečera. Umjesto toga, nadjačava i zanemaruje ostala mapiranja dispečera. Dakle, ‘/ primjer’ će se pojaviti kao 404!

Zbog tog razloga, "/ *" Se ne smije koristiti, osim u vrlo ograničenim okolnostima (poput konfiguriranja filtra).

3.2. Rukovanje HTTP zahtjevima

Osnovna odgovornost a DispatcherServlet je slanje dolaznih HttpRequests ispravnim voditeljima navedeno s @Controller ili @RestController bilješke.

Kao popratna napomena, glavna razlika između @Controller i @RestController je način na koji se generira odgovor - @RestController također definira @ResponseBody prema zadanim postavkama.

Ovdje možete pronaći spisak u kojem ulazimo u mnogo veću dubinu vezano za Springove kontrolere.

3.3. The ViewResolver Sučelje

A ViewResolver je priključen na a DispatcherServlet kao postavka konfiguracije na ApplicationContext objekt.

A ViewResolver određuje i kakve poglede služi dispečer i odakle se pružaju.

Evo primjera konfiguracije koju ćemo smjestiti u našu AppConfig za prikazivanje JSP stranica:

@Configuration @EnableWebMvc @ComponentScan ("com.baeldung.springdispatcherservlet") javna klasa AppConfig implementira WebMvcConfigurer {@Bean public UrlBasedViewResolver viewResolver () {UrlBasedViewResoll Resolution; resolver.setPrefix ("/ WEB-INF / view /"); resolver.setSuffix (". jsp"); resolver.setViewClass (JstlView.class); povratnik; }}

Vrlo ravno naprijed! Postoje tri glavna dijela:

  1. postavljanje prefiksa, koji postavlja zadani URL put za pronalaženje postavljenih prikaza u
  2. zadani tip prikaza koji se postavlja putem sufiksa
  3. postavljanje klase pogleda na rješavaču koja omogućuje povezivanje tehnologija poput JSTL ili Tiles s prikazanim prikazima

Jedno često pitanje uključuje koliko precizno dispečerovo ViewResolveri ukupna struktura direktorija projekta su povezani. Pogledajmo osnove.

Evo primjera konfiguracije puta za InternalViewResolver pomoću Springove XML konfiguracije:

Radi našeg primjera pretpostavit ćemo da je naša aplikacija hostirana na:

// localhost: 8080 /

Ovo je zadana adresa i priključak za lokalno hostirani Apache Tomcat poslužitelj.

Pod pretpostavkom da je naša aplikacija pozvana dispečerni primjer-1.0.0, našim JSP pogledima moći će se pristupiti sa:

//localhost:8080/dispatcherexample-1.0.0/jsp/

Put za ove poglede u okviru uobičajenog proljetnog projekta s Mavenom je sljedeći:

src - | glavni - | Java resursi webapp - | jsp WEB-INF

Zadana lokacija prikaza je unutar WEB-INF. Put naveden za naš InternalViewResolver u gornjem isječku određuje poddirektorij "src / main / webapp" u kojem će biti dostupni vaši pogledi.

3.4. The LocaleResolver Sučelje

Primarni način prilagodbe podataka o sesiji, zahtjevu ili kolačićima za našeg dispečera je putem LocaleResolver sučelje.

CookieLocaleResolver je implementacija koja omogućuje konfiguraciju svojstava aplikacije bez državljanstva pomoću kolačića. Dodajmo je u AppConfig.

@Bean public CookieLocaleResolver cookieLocaleResolverExample () {CookieLocaleResolver localeResolver = novi CookieLocaleResolver (); localeResolver.setDefaultLocale (Locale.ENGLISH); localeResolver.setCookieName ("locale-cookie-resolver-example"); localeResolver.setCookieMaxAge (3600); return localeResolver; } @Bean public LocaleResolver sessionLocaleResolver () {SessionLocaleResolver localeResolver = new SessionLocaleResolver (); localeResolver.setDefaultLocale (Locale.US); localResolver.setDefaultTimeZone (TimeZone.getTimeZone ("UTC")); return localeResolver; } 

SessionLocaleResolver omogućuje konfiguraciju specifičnu za sesiju u aplikaciji sa statusom.

The setDefaultLocale() metoda predstavlja geografsko, političko ili kulturno područje, dok setDefaultTimeZone() određuje mjerodavno Vremenska zona objekt za aplikaciju Grah u pitanju.

Obje su metode dostupne na svakoj od gore navedenih implementacija LocaleResolver.

3.5. The ThemeResolver Sučelje

Proljeće pruža stilsku tematiku našim pogledima.

Pogledajmo kako konfigurirati našeg dispečera za obradu tema.

Prvi, postavimo svu potrebnu konfiguraciju za pronalaženje i korištenje naših statičnih datoteka s temama. Moramo postaviti statično mjesto resursa za naš ThemeSource za konfiguriranje stvarnog Teme sami (Tema objekti sadrže sve podatke o konfiguraciji predviđene u tim datotekama). Dodajte ovo u AppConfig:

@Override public void addResourceHandlers (Registry ResourceHandlerRegistry) {registry.addResourceHandler ("/ resources / **") .addResourceLocations ("/", "/ resources /") .setCachePeriod (3600) .resourceChaines (true). ()); } @Bean public ResourceBundleThemeSource themeSource () {ResourceBundleThemeSource themeSource = novi ResourceBundleThemeSource (); themeSource.setDefaultEncoding ("UTF-8"); themeSource.setBasenamePrefix ("teme."); povratak themeSource; } 

Zahtjevi kojima upravlja DispatcherServlet može izmijeniti temu kroz navedeni parametar u koji je proslijeđen setParamName() dostupno na ThemeChangeInterceptor objekt. Dodaj u AppConfig:

@Bean javni CookieThemeResolver themeResolver () {CookieThemeResolver razrješivač = novi CookieThemeResolver (); resolver.setDefaultThemeName ("primjer"); resolver.setCookieName ("example-theme-cookie"); povratnik; } @Bean public ThemeChangeInterceptor themeChangeInterceptor () {ThemeChangeInterceptor interceptor = novi ThemeChangeInterceptor (); interceptor.setParamName ("tema"); povratni presretač; } @Override public void addInterceptors (Registar registra InterceptorRegistry) {registry.addInterceptor (themeChangeInterceptor ()); } 

Sljedeća JSP oznaka dodana je u naš prikaz kako bi se prikazao ispravan stil:

Sljedeći zahtjev za URL prikazuje primjer tema pomoću parametra ‘tema’ proslijeđenog u našu konfiguriranu ThemeChangeIntercepter:

//localhost:8080/dispatcherexample-1.0.0/?theme=example

3.6. The MultipartResolver Sučelje

A MultipartResolver provedba pregledava zahtjev za više dijelova i umotava ih u a MultipartHttpServletRequest za daljnju obradu od strane ostalih elemenata u procesu ako se pronađe barem jedan višedijelni. Dodaj u AppConfig:

@Bean public CommonsMultipartResolver multipartResolver () baca IOException {CommonsMultipartResolver resolver = new CommonsMultipartResolver (); resolver.setMaxUploadSize (10000000); povratnik; } 

Sad kad smo konfigurirali svoj MultipartResolver grah, postavimo kontroler za obradu MultipartFile zahtjevi:

@Controller javna klasa MultipartController {@Autowired ServletContext context; @PostMapping ("/ upload") javni ModelAndView FileuploadController (@RequestParam ("datoteka") MultipartFile datoteka) baca IOException {ModelAndView modelAndView = novi ModelAndView ("indeks"); InputStream u = file.getInputStream (); Niz puta = nova datoteka ("."). GetAbsolutePath (); FileOutputStream f = novi FileOutputStream (path.substring (0, path.length () - 1) + "/ uploads /" + file.getOriginalFilename ()); int ch; while ((ch = in.read ())! = -1) {f.write (ch); } f.flush (); f.close (); in.close (); modelAndView.getModel () .put ("poruka", "Datoteka je uspješno prenesena!"); vrati modelAndView; }}

Možemo koristiti uobičajeni obrazac za slanje datoteke na navedenu krajnju točku. Prenesene datoteke bit će dostupne u "CATALINA_HOME / bin / uploads".

3.7. The HandlerExceptionResolver Sučelje

Proljetni HandlerExceptionResolver pruža jedinstveno postupanje s pogreškama za cijelu web aplikaciju, jedan kontroler ili skup kontrolera.

Da biste pružili prilagođeno rukovanje iznimkama za cijelu aplikaciju, stvorite klasu označenu s @ControllerAdvice:

@ControllerAdvice javna klasa ExampleGlobalExceptionHandler {@ExceptionHandler @ResponseBody javni niz HandExampleException (izuzetak e) {// ...}}

Sve metode unutar te klase označene s @ExceptionHandler bit će dostupan na svakom kontroloru unutar područja odgovornosti dispečera.

Provedbe HandlerExceptionResolver sučelje u Koncept konteksta aplikacije DispatcherServlet dostupni su presretnuti određeni kontroler u zoni odgovornosti tog dispečera kad god @ExceptionHandler koristi se kao bilješka, a ispravna klasa se predaje kao parametar:

@Controller javna klasa FooController {@ExceptionHandler ({CustomException1.class, CustomException2.class}) public void handleException () {// ...} // ...}

The handleException () metoda sada će služiti kao rukovatelj iznimkama za FooController u našem gornjem primjeru, ako bilo koja iznimka CustomException1 ili CustomException2 javlja se.

Evo članka koji detaljnije govori o rukovanju iznimkama u web aplikaciji Spring.

4. Zaključak

U ovom uputstvu pregledali smo Spring's DispatcherServlet i nekoliko načina za njegovo konfiguriranje.

Kao i uvijek, izvorni kod korišten u ovom vodiču dostupan je na Githubu.