getting healthy with magnolia, blossom and spring
DESCRIPTION
This presentation was given at Amplify Miami 2014 by Jan Haderka, Senior Developer at Magnolia International, and Casey Dement, VP of Architecture at Sharecare, Inc. Casey showed how Sharecare integrated Magnolia and Blossom with Spring MVC and Akamai to build a highly flexible and scalable website. Jan gives an introduction and an update on the new features in Blossom 3.TRANSCRIPT
![Page 1: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/1.jpg)
!1
Blossom in the Real World
![Page 2: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/2.jpg)
Sr. Software Engineer, Magnolia Lead developer of Blossom Module Spring Framework user since 2005
Tobias Mattsson
2@sigget
![Page 3: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/3.jpg)
3
Jan HaderkaHead of Support, Magnolia
@rah003
![Page 4: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/4.jpg)
4
Casey DementVP of Architecture, Sharecare
@casey_dement
![Page 5: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/5.jpg)
#Mplify
5
![Page 6: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/6.jpg)
Magnolia + Spring = Blossom 6
![Page 7: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/7.jpg)
@Template
7
![Page 8: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/8.jpg)
TEMPLATEREQUEST CONTENT
CMS
8
![Page 9: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/9.jpg)
TEMPLATEREQUEST CONTENT
CMS + Blossom
9
CONTROLLER
MODEL
VIEW
![Page 10: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/10.jpg)
Page Template
@Controller @Template(id="myModule:pages/main", title="Main") public class MainTemplate { !
@RequestMapping("/main") public String render(ModelMap model) { return "pages/main"; } }
10
![Page 11: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/11.jpg)
11
PAGE
![Page 12: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/12.jpg)
PAGES CONTAIN 0:n AREAS
12
PAGE
AREA
A R E A
AREA
![Page 13: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/13.jpg)
PAGES CONTAIN 0:n AREAS
13
PAGE
AREA
A R E A
AREA
AREAS HAVE 0:n COMPONENTS
COMPONENT
COMPONENT Etiam porta sem malesuada magna mollis euismod. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.
COMPONENT Etiam porta sem malesuada magna mollis euismod. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed posuere consectetur est at lobortis.
C O M P O N E N T
![Page 14: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/14.jpg)
Area Template
@Controller @Template(id="myModule:pages/main",title="Main Template") public class MainTemplate { @Controller @Area("main") public static class MainArea { @RequestMapping("/main/mainArea") public String render() { return "areas/main"; } ...
14
![Page 15: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/15.jpg)
Component Template
@Controller @Template(id="myModule:components/shoppingCart", title="Shopping Cart") @TemplateDescription("Shopping cart") public class ShoppingCartComponent { @RequestMapping("/shoppingCart") public String handleRequest() { ... return "components/shoppingCart"; } ...
15
![Page 16: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/16.jpg)
SERVLET CONTAINER
RENDERING FILTER
RENDERING ENGINE
BLOSSOM DISPATCHER SERVLET CONTROLLER
16
How Blossom Works
![Page 17: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/17.jpg)
Blossom 3.0
17
What’s new?
![Page 18: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/18.jpg)
Blossom 3.0
18
Update for Magnolia 5 series Requires Magnolia 5.1 new ways of building dialogs availability annotation
![Page 19: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/19.jpg)
19
Dialogs
![Page 20: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/20.jpg)
Fluent Builder-style API
!
@TabFactory("Content") public void contentTab(UiConfig cfg, TabBuilder tab) { tab.fields( cfg.fields.text("heading").label("Heading"), cfg.fields.richText("body").label("Text body"), cfg.fields.websiteLink("categoryLink").label("Link"), cfg.fields.basicUpload("image").label("Image"), cfg.fields.checkbox("inlineImage").label("Inline Image") ); }
20
![Page 21: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/21.jpg)
Dialogs and the Class Hierarchy
public abstract class BasePageTemplate { @TabFactory("Meta") public void metaTab(UiConfig cfg, TabBuilder tab) { tab.fields( cfg.fields.text("metaAuthor").label("Author"), cfg.fields.text("metaKeywords").label("Keywords"), cfg.fields.text("metaDescription").label("Description") ); } }
21
![Page 22: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/22.jpg)
Input Validation
... public void contentTab(UiConfig cfg, TabBuilder tab) { tab.fields( cfg.fields.text("name").label("Name").required(), cfg.fields.text("email").label("Email")⏎ .validator(cfg.validators.email()) ); } ...
22
![Page 23: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/23.jpg)
Dynamic Dialog
!!@Template(id="myModule:components/bookCategory", title="Book category") @TemplateDescription("A list of books in a given category.") @Controller public class BookCategoryComponent { @Autowired private SalesApplicationWebService service; @RequestMapping("/bookcategory") public String render(Node content, ModelMap model) throws RepositoryException { String category = content.getProperty("category").getString(); model.put("books", service.getBooksInCategory(category)); return "components/bookCategory"; } @TabFactory("Content") public void contentTab(UiConfig cfg, TabBuilder tab) { Collection<String> categories = service.getBookCategories(); tab.fields( cfg.fields.select("category").label("Category").options(categories) ); } }
23
![Page 24: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/24.jpg)
Dynamic Dialog
!@Template(id="myModule:components/bookCategory", title="Book category") @TemplateDescription("A list of books in a given category.") @Controller public class BookCategoryComponent { @Autowired private SalesApplicationWebService service;
@RequestMapping("/bookcategory") public String render(Node content, ModelMap model) throws RepositoryException { String category = content.getProperty("category").getString(); model.put("books", service.getBooksInCategory(category)); return "components/bookCategory"; } @TabFactory("Content") public void contentTab(UiConfig cfg, TabBuilder tab) { Collection<String> categories = service.getBookCategories(); tab.fields( cfg.fields.select("category").label("Category").options(categories) ); } }
24
![Page 25: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/25.jpg)
@AvailableComponentClasses
25
![Page 26: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/26.jpg)
Components Availability
! @ComponentCategory @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Banner { } ! @Area("banners") @AvailableComponentClasses({Banner.class}) @Controller public class BannersArea { … } ! @Banner @Template(id="myModule:components/largePromoBanner"), title="Large banner”) @Controller("banner") public class LargePromoBannerComponent { … }
26
![Page 27: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/27.jpg)
@More
27
![Page 28: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/28.jpg)
Content, content, more content
!@Template(id="myModule:components/bookCategory", title="Book category") @TemplateDescription("A list of books in a given category.") @Controller public class BookCategoryComponent { @Autowired private SalesApplicationWebService service; @RequestMapping("/bookcategory") public String render(Node content, ModelMap model) throws RepositoryException { String category = content.getProperty("category").getString(); model.put("books", service.getBooksInCategory(category)); return "components/bookCategory"; } @TabFactory("Content") public void contentTab(UiConfig cfg, TabBuilder tab) { Collection<String> categories = service.getBookCategories(); tab.fields( cfg.fields.select("category").label("Category").options(categories) ); } }
28
![Page 29: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/29.jpg)
Now The Real World 29
![Page 30: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/30.jpg)
Thank You!
30
![Page 32: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/32.jpg)
32
![Page 33: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/33.jpg)
How do I get started on my project?
33
![Page 34: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/34.jpg)
mvn archetype:generate -DarchetypeCatalog=http://nexus.magnolia-cms.com/content/groups/public/ !choose magnolia-blossom-module-archetype !Define value for property 'groupId': : com.acme Define value for property 'artifactId': : acme-module Define value for property 'version': 1.0-SNAPSHOT: Define value for property 'package': com.acme: Define value for property 'magnolia-version': : 4.5.11 Define value for property 'module-class-name': : AcmeModule Define value for property 'module-name': acme-module: acmeModule !!!! http://wiki.magnolia-cms.com/display/WIKI/
Creating+a+new+Blossom+project+using+maven+archetypes
![Page 35: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/35.jpg)
How would I build a REST interface to my CMS content using Blossom?
35
![Page 36: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/36.jpg)
REST servlet in module descriptor
<servlets> <servlet> <name>rest</name> <class>org.springframework.web.servlet.DispatcherServlet</class> <mappings> <mapping>/rest/*</mapping> </mappings> <params> <param> <name>contextConfigLocation</name> <value>classpath:/rest-servlet.xml</value> </param> </params> </servlet> </servlets>
36
![Page 37: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/37.jpg)
REST Controller
@Controller public class ProductsRestController { !
@RequestMapping("/products/{productId}") public Product findProduct(@PathVariable String productId) { // implementation omitted } }
37
![Page 38: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/38.jpg)
Can I leverage Magnolia's caching functionality to improve the performance of my Spring app?
38
![Page 39: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/39.jpg)
Influencing caching 39
@Controller @Template(title="Text", id="myModule:components/text") public class TextComponent { !
@RequestMapping("/text") public String render(HttpResponse response) { response.setHeader("Cache-Control", "no-cache"); return "components/text.jsp"; } }
![Page 40: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/40.jpg)
How can I present dialogs in different languages using Blossom?
40
![Page 41: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/41.jpg)
!@Controller @Template(title = "Text", id = "blossomSampleModule:components/text") @I18nBasename("info.magnolia.blossom.sample.messages") public class TextComponent { !
@TabFactory("textComponent.contentTab.label") public void contentTab(UiConfig cfg, TabBuilder tab) { tab.fields( cfg.fields.text("heading").label("textComponent.contentTab.heading") ); } }
41I18n Blossom Dialog
![Page 42: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/42.jpg)
!!/info/magnolia/blossom/sample/messages_en.properties textComponent.contentTab.label = Content textComponent.contentTab.heading = Heading !!!/info/magnolia/blossom/sample/messages_sv.properties textComponent.contentTab.label = Innehåll textComponent.contentTab.heading = Rubrik !
42I18n Blossom Dialog
![Page 43: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/43.jpg)
How do I migrate my existing site to Magnolia/Blossom?
43
![Page 44: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/44.jpg)
How can I integrate Spring Security?
44
![Page 45: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/45.jpg)
45
![Page 46: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/46.jpg)
How can I dependency inject spring beans into RenderingModels?
46
![Page 47: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/47.jpg)
Autowired RenderingModel
public class MyRenderingModel extends RenderingModelImpl<TemplateDefinition> { ! @Autowired private MyService service; ! public MyRenderingModel(ServletContext servletContext, Node content, TemplateDefinition definition, RenderingModel<?> parent) { super(content, definition, parent); WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(servletContext); AutowireCapableBeanFactory beanFactory = wac.getAutowireCapableBeanFactory(); beanFactory.autowireBean(this); }
47
![Page 48: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/48.jpg)
Autowired RenderingModel
!public class MyRenderingModel extends AbstractAutowiredRenderingModel<TemplateDefinition> { ! @Autowired private MyService service; ! public MyRenderingModel(ServletContext servletContext, Node content, TemplateDefinition definition, RenderingModel<?> parent) { super(content, definition, parent, servletContext); } !!!!
48
![Page 49: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/49.jpg)
Views 49
![Page 50: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/50.jpg)
Rendering an Area
FreeMarker [@cms.area name="main" /] !
JSP <cms:area name="main" />
50
![Page 51: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/51.jpg)
Rendering Components in an Area
FreeMarker [#list components as component] [@cms.component content=component /] [/#list] !
JSP <c:forEach items="${components}" var="component"> <cms:component content="${component}" /> </c:forEach>
51
![Page 52: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/52.jpg)
Page Template Availability
@Controller @Template(title="Article", id="myModule:/pages/article") public class ArticleTemplate { ... @Available public boolean isAvailable(Node node) { return node.getPath().startsWith("/articles/"); } }
52
![Page 53: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/53.jpg)
Available Components
@Controller @Area("promos") @AvailableComponentClasses({TextComponent.class, ShoppingCartComponent.class}) public static class PromosArea { @RequestMapping("/main/promos") public String render() { return "areas/promos"; } }
53
![Page 54: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/54.jpg)
Area Inheritance
@Controller @Area("promos") @Inherits @AvailableComponentClasses({TextComponent.class, ShoppingCartComponent.class}) public static class PromosArea { @RequestMapping("/main/promos") public String render() { return "areas/promos"; } }
54
![Page 55: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/55.jpg)
Form Submission
/* Standard annotations omitted */ public class ContactFormComponent { @RequestMapping(value="/contact", method=RequestMethod.GET) public String viewForm(@ModelAttribute ContactForm contactForm) { return "components/contactForm";
} @RequestMapping(value="/contact", method=RequestMethod.POST) public String handleSubmit(@ModelAttribute ContactForm contactForm, ⏎ BindingResult result) { new ContactFormValidator().validate(contactForm, result); if (result.hasErrors()) { return "components/contactForm"; } return "redirect:/home/contact/thankyou.html";
}
55
![Page 56: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/56.jpg)
But wait a minute …
56
Caused by: org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:894) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778) at javax.servlet.http.HttpServlet.service(HttpServlet.java:617) at info.magnolia.module.blossom.render.BlossomDispatcherServlet.forward(BlossomDispatcherServlet.java:123) at info.magnolia.module.blossom.render.BlossomTemplateRenderer.render(BlossomTemplateRenderer.java:78) ... 92 more Caused by: java.lang.IllegalStateException at org.apache.catalina.connector.ResponseFacade.sendRedirect(ResponseFacade.java:435)
… the response has been sent.
![Page 57: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/57.jpg)
Controller Pre-execution
57
C M V
PAGE
C M V
Area
C M V
Component
C M V
Component
C M V
Component
C
![Page 58: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/58.jpg)
CPE Implementation 58
Code in View <form> <blossom:pecid-input /> <input type=”text” name=”email” /> ... !
HTML Output <form> <input type=”hidden” name=”_pecid” value=”ff6cefa6-d958-47b1-af70-c82a414f17e1” /> <input type=”text” name=”email” /> ...
![Page 59: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/59.jpg)
Spring Web MVC +
Content
59
![Page 60: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/60.jpg)
Spring Web Flow
60
REQUEST LANDING PAGE
SPRING WEB FLOW
![Page 61: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/61.jpg)
Spring Web Flow
61
REQUEST LANDING PAGE
FORM SUBMIT?
SPRING WEB FLOW
![Page 62: Getting Healthy with Magnolia, Blossom and Spring](https://reader034.vdocument.in/reader034/viewer/2022042512/554f5088b4c905423f8b51ea/html5/thumbnails/62.jpg)
62
Trademarks
Other trademarks are the property of their respective owners.
MagnoliaThe Pulse are trademarks of
Magnolia International Limited.}