A munkamenet attribútumai a tavaszi MVC-ben
1. Áttekintés
A webalkalmazások fejlesztésekor gyakran ugyanazokra az attribútumokra kell hivatkoznunk több nézetben. Például lehetnek bevásárlókosár-tartalmaink, amelyeket több oldalon kell megjeleníteni.
Az attribútumok tárolására jó helyen van a felhasználó munkamenete.
Ebben az oktatóanyagban egy egyszerű példára és vizsgálja meg a munkamenet attribútummal való munkavégzés 2 különböző stratégiáját:
- Határozott proxy használata
- Használni a @SessionAttributes annotáció
2. Maven Setup
A Spring Boot indítókat használjuk a projektünk indításához és az összes szükséges függőség behozatalához.
A beállításhoz szülői nyilatkozat, webindító és timeleaf indító szükséges.
A rugós tesztindítót is beépítjük, hogy további teszteket nyújtsunk egységeink tesztjeihez:
org.springframework.boot spring-boot-starter-parent 2.2.2.RELEASE org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-thymeleaf org.springframework.boot spring-boot- indító-teszt teszt
Ezen függőségek legfrissebb verziói a Maven Central oldalon találhatók.
3. Példa használati esetre
Példánk egy egyszerű „TODO” alkalmazást valósít meg. Létezik egy űrlap a példányok létrehozására TodoItem és egy listanézet, amely az összeset megjeleníti TodoItems.
Ha létrehozunk egy TodoItem Az űrlap használatával az űrlap későbbi hozzáférései előre feltöltésre kerülnek a legutóbb hozzáadott értékekkel TodoItem. Majd használjuk tjellemzője, hogy bemutassa, hogyan lehet „emlékezni” a formai értékekre amelyek a munkamenet hatókörében vannak tárolva.
2 modellosztályunk egyszerű POJO-ként valósul meg:
public class TodoItem {private String description; privát LocalDateTime createDate; // szerelők és beállítók}
nyilvános osztály A TodoList kiterjeszti az ArrayDeque-t {}
A mi Feladatlista osztály kiterjed ArrayDeque hogy a legutóbb hozzáadott elemhez kényelmesen hozzáférhessünk a peekLast módszer.
Szükségünk lesz 2 vezérlő osztályra: 1 az egyes megvizsgálandó stratégiákhoz. Finoman különböznek egymástól, de az alapvető funkcionalitás mindkettőben megjelenik. Mindegyiknek 3 lesz @RequestMappings:
- @GetMapping (“/ form”) - Ez a módszer felelős az űrlap inicializálásáért és az űrlapnézet rendereléséért. A módszer előre kitölti az űrlapot a legutóbb hozzáadottakkal TodoItem ha a Feladatlista nem üres.
- @PostMapping (“/ form”) - Ez a módszer felelős a beküldött adatok hozzáadásáért TodoItem hoz Feladatlista és átirányítja a lista URL-jére.
- @GetMapping (“/ todos.html”) - Ez a módszer egyszerűen hozzáadja a Feladatlista hoz Modell megjelenítéséhez és a listanézet rendereléséhez.
4. Scoped Proxy használata
4.1. Beállít
Ebben a beállításban a mi Feladatlista munkamenet hatókörűként van konfigurálva @Bab amelyet egy meghatalmazott támogat. Az a tény, hogy a @Bab a proxy azt jelenti, hogy képesek vagyunk beinjektálni a szingulett hatókörünkbe @Vezérlő.
Mivel a kontextus inicializálásakor nincs munkamenet, a Spring létrehozza a Feladatlista függőségként beadni. A célpéldány Feladatlista szükség szerint példányosítják, amikor a kérések megkövetelik.
A babszem hatókörének alaposabb megvitatásához tavasszal tekintse meg a témáról szóló cikkünket.
Először meghatározzuk a babunkat az a-n belül @ Konfiguráció osztály:
@Bean @Scope (value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS) public TodoList todos () {return new TodoList (); }
Ezután kijelentjük, hogy a bab a @Vezérlő és ugyanúgy beadja, mint bármely más függőséget:
@Controller @RequestMapping ("/ scopedproxy") nyilvános osztály TodoControllerWithScopedProxy {private TodoList todos; // konstruktor és kérés leképezések}
Végül, ha a babot egy kérésben használjuk, egyszerűen meg kell hívni a módszereit:
@GetMapping ("/ form") public String showForm (Model model) {if (! Todos.isEmpty ()) {model.addAttribute ("todo", todos.peekLast ()); } else {model.addAttribute ("todo", új TodoItem ()); } return "scopedproxyform"; }
4.2. Egység tesztelése
Annak érdekében, hogy teszteljük megvalósításunkat a hatókörű proxy segítségével, először konfiguráljuk a SimpleThreadScope. Ez biztosítja, hogy egységtesztjeink pontosan szimulálják az általunk tesztelt kód futási idejét.
Először meghatározzuk a TestConfig és a CustomScopeConfigurer:
@Configuration public class TestConfig {@Bean public CustomScopeConfigurer customScopeConfigurer () {CustomScopeConfigurer configurer = new CustomScopeConfigurer (); configurer.addScope ("session", új SimpleThreadScope ()); visszatérési konfigurátor; }}
Most azzal kezdhetjük, hogy teszteljük, hogy az űrlap kezdeti kérése tartalmaz-e inicializálatlan kérelmet TodoItem:
@RunWith (SpringRunner.class) @SpringBootTest @AutoConfigureMockMvc @Import (TestConfig.class) nyilvános osztály TodoControllerWithScopedProxyIntegrationTest {// ... @Test public void whenFirstRequest_thenContainsUmformial. form ")) .andExpect (status (). isOk ()) .andExpect (model (). attributeExists (" todo ")) .andReturn (); TodoItem item = (TodoItem) result.getModelAndView (). GetModel (). Get ("todo"); assertTrue (StringUtils.isEmpty (item.getDescription ())); }}
Megerősíthetjük azt is, hogy a beküldött küldeményünk átirányítást ad ki, és hogy egy későbbi űrlapkérés előre feltöltött lesz az újonnan hozzáadottakkal TodoItem:
@Test public void whenSubmit_thenSubsequentFormRequestContainsMostRecentTodo () dobja a (z) {mockMvc.perform (post ("/ scopedproxy / form") .param ("description", "newtodo")) .andExpect (status (). Is3xxRedirection ()) kivételt. ; MvcResult result = mockMvc.perform (get ("/ scopedproxy / form")) .andExpect (status (). IsOk ()) .andExpect (model (). AttributeExists ("todo")) .ésReturn (); TodoItem item = (TodoItem) result.getModelAndView (). GetModel (). Get ("todo"); assertEquals ("newtodo", item.getDescription ()); }
4.3. Vita
A hatókörű proxy stratégia használatának egyik legfontosabb jellemzője az nincs hatása a kérelem feltérképezési módszer aláírására. Ez nagyon magas szinten tartja az olvashatóságot a @SessionAttributes stratégia.
Hasznos lehet felidézni, hogy a vezérlőknek van szingli hatókör alapértelmezés szerint.
Ez az oka annak, hogy meg kell használnunk egy proxyt, ahelyett, hogy egyszerűen beadnánk a nem proxiált munkamenet hatókörű babot. Nem adhatunk be kisebb hatókörű babot nagyobb hatókörű babba.
Ennek megkísérlése ebben az esetben kivételt váltana ki az alábbiakat tartalmazó üzenettel: A „munkamenet” hatókör nem aktív az aktuális szálnál.
Ha hajlandóak lennénk meghatározni a vezérlőnket a munkamenet hatókörével, elkerülhetnénk a proxyMode. Ennek hátrányai lehetnek, különösen, ha a vezérlő létrehozása drága, mert minden felhasználói munkamenethez létre kellene hozni egy vezérlőpéldányt.
Vegye figyelembe, hogy Feladatlista injekcióhoz való egyéb komponensek számára elérhető. Ez a felhasználási esettől függően előny vagy hátrány lehet. Ha a komponens hozzáférhetővé tétele a teljes alkalmazás számára problémás, akkor a példány a vezérlőhöz használható @SessionAttributes amint a következő példában látni fogjuk.
5. A @SessionAttributes Megjegyzés
5.1. Beállít
Ebben a beállításban nem definiáljuk Feladatlista mint tavaszi irányítású @Bab. Ehelyett mi nyilvánítsa a @ModelAttribute és adja meg a @SessionAttributes kommentár a vezérlő munkamenetéig.
Az első alkalommal, amikor vezérlőnkhöz férnek hozzá, Spring példányt állít elő, és elhelyezi azt a Modell. Mivel a babot is ben deklaráljuk @SessionAttributes, Spring tárolja a példányt.
A @ModelAttribute tavasszal olvassa el a témával foglalkozó cikkünket.
Először deklaráljuk a babunkat azzal, hogy metódust adunk a vezérlőn, és a módszerrel jegyzeteljük @ModelAttribute:
@ModelAttribute ("todos") nyilvános TodoList todos () {return new TodoList (); }
Ezután tájékoztatjuk az irányítót a kezelésünkről Feladatlista mint a munkamenet hatóköre @SessionAttributes:
@Controller @RequestMapping ("/ sessionattributes") @SessionAttributes ("todos") nyilvános osztály TodoControllerWithSessionAttributes {// ... egyéb módszerek}
Végül, hogy a babot egy kérésen belül felhasználhassuk, utalást adunk rá az a metódus aláírásában @RequestMapping:
@GetMapping ("/ form") public String showForm (Model model, @ModelAttribute ("todos") TodoList todos) {if (! Todos.isEmpty ()) {model.addAttribute ("todo", todos.peekLast ()) ; } else {model.addAttribute ("todo", új TodoItem ()); } return "sessionattributesform"; }
Ban,-ben @PostMapping módszerrel injekciózunk RedirectAttributes és hívjon addFlashAttribute mielőtt visszaadná a mi RedirectView. Ez fontos különbség a megvalósításban az első példánkhoz képest:
@PostMapping ("/ form") nyilvános RedirectView create (@ModelAttribute TodoItem todo, @ModelAttribute ("todos") TodoList todos, RedirectAttributes attribútumok) {todo.setCreateDate (LocalDateTime.now ()); todos.add (todo); attributes.addFlashAttribute ("todos", todos); return new RedirectView ("/ sessionattributes / todos.html"); }
Tavasz használ egy speciális RedirectAttributes végrehajtása Modell az URL-paraméterek kódolását támogató átirányítási forgatókönyvekhez. Az átirányítás során a Modell általában csak akkor érhető el a keretrendszer számára, ha szerepelnek az URL-ben.
Használva addFlashAttribute azt mondjuk a keretnek, hogy szeretnénk a magunkét Feladatlista hogy túlélje az átirányítást anélkül, hogy kódolni kellene az URL-ben.
5.2. Egység tesztelése
Az űrlap nézetvezérlő módszer egység tesztelése megegyezik azzal a teszttel, amelyet az első példánkban megvizsgáltunk. A teszt a @PostMappingazonban egy kicsit más, mert a viselkedés igazolásához hozzá kell férnünk a flash attribútumokhoz:
@Test public void whenTodoExists_thenSubsequentFormRequestContainsesMostRecentTodo () dobja a (z) {FlashMap flashMap = mockMvc.perform (post ("/ sessionattributes / form") .param ("description", "newtodo") .param ("description", "newtodo") .andExpect (status ()). andReturn (). getFlashMap (); MvcResult result = mockMvc.perform (get ("/ sessionattributes / form") .sessionAttrs (flashMap)) .andExpect (status (). IsOk ()) .andExpect (model (). AttributeExists ("todo")). ÉsReturn ( ); TodoItem item = (TodoItem) result.getModelAndView (). GetModel (). Get ("todo"); assertEquals ("newtodo", item.getDescription ()); }
5.3. Vita
A @ModelAttribute és @SessionAttributes az attribútum munkamenetben való tárolásának stratégiája egyenes megoldás, amely nem igényel további kontextuskonfigurációt vagy Spring-kezelt @Babs.
Első példánkkal ellentétben injekciózásra van szükség Feladatlista ban,-ben @RequestMapping mód.
Ezenkívül a flash attribútumokat kell felhasználnunk az átirányítási forgatókönyvekhez.
6. Következtetés
Ebben a cikkben a hatókörű proxyk és @SessionAttributes mint 2 stratégia a munkamenet attribútumokkal való munkavégzéshez a Spring MVC-ben. Vegye figyelembe, hogy ebben az egyszerű példában a munkamenetben tárolt attribútumok csak a munkamenet életében maradnak fenn.
Ha meg kell tartanunk az attribútumokat a szerver újraindítása vagy a munkamenet időtúllépése között, akkor fontolóra vehetjük a Spring Session használatát az információk átlátható kezeléséhez. Tekintse meg a Tavaszi munkamenet cikkünket további információkért.
Mint mindig, a cikkben használt összes kód elérhető a GitHubon.