Your SlideShare is downloading. ×
Blossom Q&A Webinar
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Blossom Q&A Webinar

8,756
views

Published on

Webinar with Tobias Mattsson, Lead developer of Blossom, the Spring integration for Magnolia CMS. Tobias answers submitted questions and gives a short introduction to the module and outlines what's …

Webinar with Tobias Mattsson, Lead developer of Blossom, the Spring integration for Magnolia CMS. Tobias answers submitted questions and gives a short introduction to the module and outlines what's new in the 3.0 update.

Published in: Technology, Business

0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
8,756
On Slideshare
0
From Embeds
0
Number of Embeds
23
Actions
Shares
0
Downloads
23
Comments
0
Likes
2
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Blossom Q&A Webinar 1 Monday, September 30, 13
  • 2. 2 Zak Greant Community Manager, Magnolia Monday, September 30, 13
  • 3. Questions? Use the questions tool built into the GoToWebinar client. 3 Monday, September 30, 13
  • 4. 4 forums.magnolia-cms.com Monday, September 30, 13
  • 5. #blossomqa 5 Monday, September 30, 13
  • 6. Sr. Software Engineer, Magnolia Lead developer of Magnolia’s Spring integration Spring Framework user since 2005 Tobias Mattsson 6 Monday, September 30, 13
  • 7. Blossom 3.0 7 Update for Magnolia 5 series Requires Magnolia 5.1 Release candidate available Final release next week Monday, September 30, 13
  • 8. Magnolia + Spring = Blossom 8 Monday, September 30, 13
  • 9. @Template 9 Monday, September 30, 13
  • 10. TEMPLATEREQUEST CONTENT CMS 10 Monday, September 30, 13
  • 11. TEMPLATEREQUEST CONTENT CMS + Blossom 11 CONTROLLER MODEL VIEW Monday, September 30, 13
  • 12. Page Template @Controller @Template(id="myModule:pages/main", title="Main") public class MainTemplate {    @RequestMapping("/main")    public String render(ModelMap model) {        return "pages/main";    } } 12 Monday, September 30, 13
  • 13. 13 PAGE Monday, September 30, 13
  • 14. PAGES CONTAIN 0:n AREAS 14 PAGE AREA A R E A AREA Monday, September 30, 13
  • 15. PAGES CONTAIN 0:n AREAS 15 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 Monday, September 30, 13
  • 16. 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";        }    ... 16 Monday, September 30, 13
  • 17. 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";    } ... 17 Monday, September 30, 13
  • 18. SERVLET CONTAINER RENDERING FILTER RENDERING ENGINE BLOSSOM DISPATCHER SERVLET CONTROLLER 18 How Blossom Works Monday, September 30, 13
  • 19. Blossom 3.0 19 What’s new? Monday, September 30, 13
  • 20. 20 Dialogs Monday, September 30, 13
  • 21. 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")  ); } 21 Monday, September 30, 13
  • 22. Blossom 2 Style Dialog @TabFactory("Content") public void contentTab(TabBuilder tab) { DialogEdit dialogEdit = tab.addEdit("title", "Title", ""); dialogEdit.setRequired(true); dialogEdit.setConfig("i18n", "true"); dialogEdit.setConfig("rows", 5); } 22 Monday, September 30, 13
  • 23. Page Template with Dialog @Controller @Template(title="Article", id="myModule:pages/article") public class ArticleTemplate {    @TabFactory("Content")    public void contentTab(UiConfig cfg, TabBuilder tab) {        tab.fields(cfg.fields.text("title").label("Title"));    } } 23 Monday, September 30, 13
  • 24. Page Template with Dialog @Controller @Template(title="Article", id="myModule:pages/article") public class ArticleTemplate {    @TabFactory("Content")    public void contentTab(UiConfig cfg, TabBuilder tab) {        tab.fields(cfg.fields.text("title").label("Title"));    } } 23 Monday, September 30, 13
  • 25. Page Template with Dialog @Controller @Template(title="Article", id="myModule:pages/article") public class ArticleTemplate {    @TabFactory("Content")    public void contentTab(UiConfig cfg, TabBuilder tab) {        tab.fields(cfg.fields.text("title").label("Title"));    } } <title>${content.title}</title> <!-- In the view --> 23 Monday, September 30, 13
  • 26. @Controller @Template(title="Article", id="myModule:pages/article") public class ArticleTemplate { @Area("main") @Controller public static class MainArea { @TabFactory("Content") public void contentTab(UiConfig cfg, TabBuilder tab) { tab.fields( cfg.fields.text("heading").label("Heading"), cfg.fields.text("border").label("Border width") ); Area Template with Dialog 24 Monday, September 30, 13
  • 27. @Controller @Template(title="Article", id="myModule:pages/article") public class ArticleTemplate { @Area("main") @Controller public static class MainArea { @TabFactory("Content") public void contentTab(UiConfig cfg, TabBuilder tab) { tab.fields( cfg.fields.text("heading").label("Heading"), cfg.fields.text("border").label("Border width") ); Area Template with Dialog 24 Monday, September 30, 13
  • 28. @Controller @Template(title="Article", id="myModule:pages/article") public class ArticleTemplate { @Area("main") @Controller public static class MainArea { @TabFactory("Content") public void contentTab(UiConfig cfg, TabBuilder tab) { tab.fields( cfg.fields.text("heading").label("Heading"), cfg.fields.text("border").label("Border width") ); Area Template with Dialog 24 <div id="main" style="border:${content.border}px solid #000"> <h2>${content.heading}</h2> <c:forEach items="${components}" var="component"> <cms:component content="${component}" /> </c:forEach> </div> <!-- In the view --> Monday, September 30, 13
  • 29. Component Template with Dialog @Controller @Template(title="Text", id="myModule:components/text") public class TextComponent { @RequestMapping("/text") public String render() { return "components/text"; } @TabFactory("Content") public void contentTab(UiConfig cfg, TabBuilder tab) { tab.fields( cfg.fields.text("heading").label("Heading"), cfg.fields.richText("body").label("Text body") 25 Monday, September 30, 13
  • 30. Component Template with Dialog @Controller @Template(title="Text", id="myModule:components/text") public class TextComponent { @RequestMapping("/text") public String render() { return "components/text"; } @TabFactory("Content") public void contentTab(UiConfig cfg, TabBuilder tab) { tab.fields( cfg.fields.text("heading").label("Heading"), cfg.fields.richText("body").label("Text body") 25 Monday, September 30, 13
  • 31. Component Template with Dialog @Controller @Template(title="Text", id="myModule:components/text") public class TextComponent { @RequestMapping("/text") public String render() { return "components/text"; } @TabFactory("Content") public void contentTab(UiConfig cfg, TabBuilder tab) { tab.fields( cfg.fields.text("heading").label("Heading"), cfg.fields.richText("body").label("Text body") 25 <h1>${content.heading}</h1> <p>${cmsfn:decode(content).body}</p> <!-- In the view --> Monday, September 30, 13
  • 32. YouTube Video Component @Controller @Template(title="YouTube Video", id="myModule:components/youtube") @TemplateDescription("Embed a YouTube video") public class YoutubeComponent { @RequestMapping("/youtube") public String render(Node node, ModelMap model) throws RepositoryException { model.put("videoId", node.getProperty("videoId").getString()); return "components/youtube"; } @TabFactory("Content") public void contentTab(UiConfig cfg, TabBuilder tab) { tab.fields( cfg.fields.text("videoId").label("Video ID") ); } } 26 Monday, September 30, 13
  • 33. YouTube Video Component @Controller @Template(title="YouTube Video", id="myModule:components/youtube") @TemplateDescription("Embed a YouTube video") public class YoutubeComponent { @RequestMapping("/youtube") public String render(Node node, ModelMap model) throws RepositoryException { model.put("videoId", node.getProperty("videoId").getString()); return "components/youtube"; } @TabFactory("Content") public void contentTab(UiConfig cfg, TabBuilder tab) { tab.fields( cfg.fields.text("videoId").label("Video ID") ); } } 26 Monday, September 30, 13
  • 34. YouTube Video Component @Controller @Template(title="YouTube Video", id="myModule:components/youtube") @TemplateDescription("Embed a YouTube video") public class YoutubeComponent { @RequestMapping("/youtube") public String render(Node node, ModelMap model) throws RepositoryException { model.put("videoId", node.getProperty("videoId").getString()); return "components/youtube"; } @TabFactory("Content") public void contentTab(UiConfig cfg, TabBuilder tab) { tab.fields( cfg.fields.text("videoId").label("Video ID") ); } } 26 <iframe width="100%" height="400" src="//www.youtube.com/ embed/${videoId}" frameborder="0" allowfullscreen></iframe> <!-- In the view --> Monday, September 30, 13
  • 35. 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")    );  } } 27 Monday, September 30, 13
  • 36. 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()) ); } ... 28 Monday, September 30, 13
  • 37. 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)        );    } } 29 Monday, September 30, 13
  • 38. 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)        );    } } 30 Monday, September 30, 13
  • 39. 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)        );    } } 31 Monday, September 30, 13
  • 40. Questions 32 Monday, September 30, 13
  • 41. How do I get started on my project? 33 Monday, September 30, 13
  • 42. 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 Monday, September 30, 13
  • 43. How would I build a REST interface to my CMS content using Blossom? 35 Monday, September 30, 13
  • 44. 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 Monday, September 30, 13
  • 45. REST Controller @Controller public class ProductsRestController { @RequestMapping("/products/{productId}") public Product findProduct(@PathVariable String productId) { // implementation omitted } } 37 Monday, September 30, 13
  • 46. Can I leverage Magnolia's caching functionality to improve the performance of my Spring app? 38 Monday, September 30, 13
  • 47. 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"; } } Monday, September 30, 13
  • 48. How can I present dialogs in different languages using Blossom? 40 Monday, September 30, 13
  • 49. @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 Monday, September 30, 13
  • 50. /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 Monday, September 30, 13
  • 51. How do I migrate my existing site to Magnolia/ Blossom? 43 Monday, September 30, 13
  • 52. How can I integrate Spring Security? 44 Monday, September 30, 13
  • 53. 45 Monday, September 30, 13
  • 54. How can I dependency inject spring beans into RenderingModels? 46 Monday, September 30, 13
  • 55. Autowired RenderingModel public class MyRenderingModel extends RenderingModelImpl<TemplateDefinition> { @Autowired private MyService service; public MyRenderingModel(ServletContext servletContext, Node content, TemplateDefinition definition, Render super(content, definition, parent); WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(servletContext); AutowireCapableBeanFactory beanFactory = wac.getAutowireCapableBeanFactory(); beanFactory.autowireBean(this); } 47 Monday, September 30, 13
  • 56. Autowired RenderingModel public class MyRenderingModel extends AbstractAutowiredRenderingModel<TemplateDefinition> { @Autowired private MyService service; public MyRenderingModel(ServletContext servletContext, Node content, TemplateDefinition definition, Render super(content, definition, parent, servletContext); } 48 Monday, September 30, 13
  • 57. More questions? 49 Monday, September 30, 13
  • 58. Magnolia + Spring = Blossom 50 Monday, September 30, 13
  • 59. Thank You! 51 Monday, September 30, 13
  • 60. 52 magnolia-cms.com/spring Monday, September 30, 13