En introduksjon til Spring DispatcherServlet

1. Introduksjon

Enkelt sagt, i Frontkontroller design mønster, en enkelt kontroller er ansvarlig for å lede innkommende HttpForespørsler til alle applikasjonens andre kontrollere og håndtere.

Vårens DispatcherServlet implementerer dette mønsteret og er derfor ansvarlig for korrekt koordinering av HttpForespørsler til høyre håndterer.

I denne artikkelen vil vi undersøke våren DispatcherServlet's be om behandlingsflyt og hvordan du implementerer flere av grensesnittene som deltar i denne arbeidsflyten.

2. DispatcherServlet Be om behandling

I hovedsak, a DispatcherServlet håndterer en innkommende HttpForespørseldelegerer forespørselen og behandler forespørselen i henhold til den konfigurerte Handleradapter grensesnitt som er implementert i vårapplikasjonen sammen med tilhørende merknader som spesifiserer håndtere, endepunkter for kontrolleren og responsobjekter.

La oss få mer inngående om hvordan en DispatcherServlet behandler en komponent:

  • de WebApplicationContext knyttet til en DispatcherServlet under nøkkelen DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE blir søkt etter og gjort tilgjengelig for alle elementene i prosessen
  • De DispatcherServlet finner alle implementeringer av Handleradapter grensesnitt konfigurert for din avsender ved hjelp av getHandler () - hver funnet og konfigurerte implementering håndterer forespørselen via håndtak() gjennom resten av prosessen
  • de Lokal løsning er valgfritt bundet til forespørselen om å aktivere elementer i prosessen for å løse lokaliteten
  • de ThemeResolver er valgfritt bundet til forespørselen om å la elementer, for eksempel visninger, bestemme hvilket tema du skal bruke
  • hvis en MultipartResolver er spesifisert, blir forespørselen inspisert for MultipartFiles - alle funnet er pakket inn i en MultipartHttpServletRequest for videre behandling
  • HandlerExceptionResolver implementeringer erklært i WebApplicationContext plukker opp unntak som blir kastet under behandlingen av forespørselen

Du kan lære mer om alle måtene å registrere og sette opp en DispatcherServlet her.

3. Handleradapter Grensesnitt

De Handleradapter grensesnitt forenkler bruken av kontrollere, servlets, HttpForespørslerog HTTP-stier gjennom flere spesifikke grensesnitt. De Handleradapter grensesnittet spiller dermed en viktig rolle gjennom de mange trinnene i DispatcherServlet be om behandlingsflyt.

Først hver Handleradapter implementering er plassert i HandlerExecutionChain fra senderen din getHandler () metode. Så, hver av disse implementeringene håndtak() de HttpServletRequest objekt når kjøringskjeden fortsetter.

I de følgende avsnittene vil vi utforske noen av de viktigste og mest brukte HandlerAdapters i større detalj.

3.1. Kartlegginger

For å forstå kartlegginger, må vi først se på hvordan vi kan kommentere kontrollere siden kontrollere er så viktige for HandlerMapping grensesnitt.

De SimpleControllerHandlerAdapter tillater implementering av en kontroller eksplisitt uten en @Kontrollør kommentar.

De RequestMappingHandlerAdapter støtter metoder merket med @RequestMapping kommentar.

Vi vil fokusere på @Kontrollør kommentar her, men en nyttig ressurs med flere eksempler som bruker SimpleControllerHandlerAdapter er også tilgjengelig.

De @RequestMapping kommentar angir det spesifikke sluttpunktet som en behandler vil være tilgjengelig innen WebApplicationContext assosiert med det.

La oss se et eksempel på en Kontroller som avslører og håndterer ‘/ Bruker / eksempel ' sluttpunkt:

@Controller @RequestMapping ("/ user") @ResponseBody public class UserController {@GetMapping ("/ example") public User fetchUserExample () {// ...}}

Stiene spesifisert av @RequestMapping merknader styres internt via HandlerMapping grensesnitt.

URL-strukturen er naturlig i forhold til DispatcherServlet seg selv - og bestemt av servletkartleggingen.

Dermed, hvis DispatcherServlet er kartlagt til ‘/ ', så vil alle kartlegginger dekkes av den kartleggingen.

Hvis imidlertid servletkartleggingen er ‘/avsender‘I stedet, så hvilken som helst @RequestMapping merknader kommer til å være i forhold til rotnettadressen.

Husk at ‘/ 'ikke er det samme som‘ / *' for servletkartlegginger! ‘/ 'Er standardkartleggingen og eksponerer alle URL-er for avsenderens ansvarsområde.

‘/ * 'Er forvirrende for mange nyere Spring-utviklere. Den spesifiserer ikke at alle baner med samme URL-kontekst er under avsenderens ansvarsområde. I stedet overstyrer den og ignorerer de andre kartleggerne. Så, '/ eksempel' vil komme opp som en 404!

På grunn av det, ‘/ * 'Bør ikke brukes bortsett fra i svært begrensede omstendigheter (som å konfigurere et filter).

3.2. HTTP forespørsel håndtering

Kjerneansvaret til en DispatcherServlet er å sende innkommende HttpForespørsler til de riktige håndtererne spesifisert med @Kontrollør eller @RestController kommentarer.

Som en sidemerknad er hovedforskjellen mellom @Kontrollør og @RestController er hvordan responsen genereres - @RestController definerer også @ResponseBody som standard.

En beskrivelse der vi går i mye større dybde angående Spring's kontrollere, finner du her.

3.3. De ViewResolver Grensesnitt

EN ViewResolver er festet til en DispatcherServlet som en konfigurasjonsinnstilling på en ApplicationContext gjenstand.

EN ViewResolver bestemmer både hva slags synspunkter som serveres av utsenderen og hvorfra de blir servert.

Her er et eksempel på konfigurasjon som vi vil plassere i vår AppConfig for gjengivelse av JSP-sider:

@Configuration @EnableWebMvc @ComponentScan ("com.baeldung.springdispatcherservlet") offentlig klasse AppConfig implementerer WebMvcConfigurer {@Bean public UrlBasedViewResolver viewResolver () {UrlBasedViewResolver resolver = new UrlBas resolver.setPrefix ("/ WEB-INF / view /"); resolver.setSuffix (". jsp"); resolver.setViewClass (JstlView.class); retur resolver; }}

Veldig rett frem! Det er tre hoveddeler til dette:

  1. sette prefikset, som angir standard URL-bane for å finne settvisningene innenfor
  2. standard visningstype som er angitt via suffikset
  3. sette en visningsklasse på resolveren som gjør at teknologier som JSTL eller Tiles kan knyttes til de gjengitte visningene

Et vanlig spørsmål innebærer hvor nøyaktig en avsender er ViewResolverog den samlede prosjektkatalogstrukturen er relatert. La oss ta en titt på det grunnleggende.

Her er et eksempel på banekonfigurasjon for en InternalViewResolver ved hjelp av Spring XML-konfigurasjon:

Av hensyn til vårt eksempel antar vi at søknaden vår er vert for:

// lokal vert: 8080 /

Dette er standardadressen og porten for en lokalt hostet Apache Tomcat-server.

Forutsatt at søknaden vår heter forsendelseseksempel-1.0.0vil våre JSP-visninger være tilgjengelige fra:

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

Veien for disse synspunktene i et vanlig vårprosjekt med Maven er denne:

src - | hoved - | java resources webapp - | jsp WEB-INF

Standardplasseringen for visninger er innenfor WEB-INF. Stien spesifisert for vår InternalViewResolver i utdraget over bestemmer underkatalogen til 'src / main / webapp' der visningene dine vil være tilgjengelige.

3.4. De Lokal løsning Grensesnitt

Den primære måten å tilpasse økt-, forespørsels- eller informasjonskapselinformasjon for senderen vår er gjennom Lokal løsning grensesnitt.

CookieLocaleResolver er en implementering som tillater konfigurering av statsløse applikasjonsegenskaper ved hjelp av informasjonskapsler. La oss legge det til AppConfig.

@Bean offentlig CookieLocaleResolver cookieLocaleResolverExample () {CookieLocaleResolver localeResolver = ny CookieLocaleResolver (); localeResolver.setDefaultLocale (Locale.ENGLISH); localeResolver.setCookieName ("eksempel på sted-cookie-resolver"); 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 tillater øktspesifikk konfigurasjon i et stateful program.

De setDefaultLocale() metoden representerer en geografisk, politisk eller kulturell region, mens setDefaultTimeZone() bestemmer det aktuelle Tidssone objekt for søknaden Bønne i spørsmålet.

Begge metodene er tilgjengelige på hver av de ovennevnte implementeringene av Lokal løsning.

3.5. De ThemeResolver Grensesnitt

Våren gir stilistisk tema for våre synspunkter.

La oss ta en titt på hvordan vi konfigurerer senderen vår til å håndtere temaer.

Først, la oss sette opp all konfigurasjonen som er nødvendig for å finne og bruke våre statiske temafiler. Vi må angi en statisk ressursplassering for vår ThemeSource for å konfigurere den faktiske Temaer dem selv (Tema objekter inneholder all konfigurasjonsinformasjonen som er angitt i disse filene). Legg dette til AppConfig:

@Override public void addResourceHandlers (ResourceHandlerRegistry registry) {registry.addResourceHandler ("/ resources / **") .addResourceLocations ("/", "/ resources /") .setCachePeriod (3600) .resourceChain (true) .addResolver (new PathResourceResolver ()); } @Bean public ResourceBundleThemeSource themeSource () {ResourceBundleThemeSource themeSource = new ResourceBundleThemeSource (); themeSource.setDefaultEncoding ("UTF-8"); themeSource.setBasenamePrefix ("temaer."); returner temaKilde; } 

Forespørsler administrert av DispatcherServlet kan endre temaet gjennom en spesifisert parameter sendt inn setParamName() tilgjengelig på ThemeChangeInterceptor gjenstand. Legge til AppConfig:

@Bean offentlig CookieThemeResolver themeResolver () {CookieThemeResolver resolver = ny CookieThemeResolver (); resolver.setDefaultThemeName ("eksempel"); resolver.setCookieName ("eksempel-tema-informasjonskapsel"); retur resolver; } @Bean offentlig ThemeChangeInterceptor themeChangeInterceptor () {ThemeChangeInterceptor interceptor = ny ThemeChangeInterceptor (); interceptor.setParamName ("tema"); tilbake interceptor; } @Override public void addInterceptors (InterceptorRegistry registry) {registry.addInterceptor (themeChangeInterceptor ()); } 

Følgende JSP-tagg er lagt til i vårt syn for å få riktig styling til å vises:

Følgende URL-forespørsel gjengir eksempel tema ved hjelp av 'tema' parameteren sendt til det konfigurerte ThemeChangeIntercepter:

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

3.6. De MultipartResolver Grensesnitt

EN MultipartResolver implementering inspiserer en forespørsel om flerdeler og pakker dem inn i en MultipartHttpServletRequest for videre behandling av andre elementer i prosessen hvis det er funnet minst en flerdel. Legge til AppConfig:

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

Nå som vi har konfigurert vår MultipartResolver bønne, la oss sette opp en kontroller som skal behandles MultipartFile forespørsler:

@Controller offentlig klasse MultipartController {@Autowired ServletContext context; @PostMapping ("/ upload") offentlig ModelAndView FileuploadController (@RequestParam ("fil") MultipartFile-fil) kaster IOException {ModelAndView modelAndView = ny ModelAndView ("indeks"); InputStream in = file.getInputStream (); Strengsti = ny fil ("."). GetAbsolutePath (); FileOutputStream f = ny FileOutputStream (path.substring (0, path.length () - 1) + "/ uploads /" + file.getOriginalFilename ()); int ch; mens ((ch = in.read ())! = -1) {f.write (ch); } f.flush (); f.lukk (); i. lukk (); modelAndView.getModel () .put ("melding", "Fil lastet opp vellykket!"); returmodellAndView; }}

Vi kan bruke et vanlig skjema for å sende inn en fil til det angitte endepunktet. Opplastede filer vil være tilgjengelige i ‘CATALINA_HOME / bin / uploads '.

3.7. De HandlerExceptionResolver Grensesnitt

Vårens HandlerExceptionResolver gir ensartet feilhåndtering for en hel webapplikasjon, en enkelt kontroller eller et sett med kontrollere.

For å gi applikasjonsomfattende tilpasset unntaksbehandling, opprett en klasse merket med @ControllerAdvice:

@ControllerAdvice public class EksempelGlobalExceptionHandler {@ExceptionHandler @ResponseBody public String handleExampleException (Unntak e) {// ...}}

Alle metoder i den klassen som er merket med @ExceptionHandler vil være tilgjengelig på hver kontroller innenfor avsenderens ansvarsområde.

Implementeringer av HandlerExceptionResolver grensesnitt i DispatcherServlets ApplicationContext er tilgjengelig for avskjære en spesifikk kontroller under den avsenderens ansvarsområde når som helst @ExceptionHandler brukes som en kommentar, og riktig klasse sendes inn som parameter:

@Controller offentlig klasse FooController {@ExceptionHandler ({CustomException1.class, CustomException2.class}) offentlig ugyldig handleException () {// ...} // ...}

De handleException () metoden vil nå fungere som en unntaksbehandler for FooController i vårt eksempel ovenfor hvis begge unntak CustomException1 eller CustomException2 inntreffer.

Her er en artikkel som går mer i dybden om unntakshåndtering i en vår-webapplikasjon.

4. Konklusjon

I denne opplæringen har vi gjennomgått vårens DispatcherServlet og flere måter å konfigurere den på.

Som alltid er kildekoden som brukes i denne opplæringen, tilgjengelig på Github.