Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Blossom Q&A Webinar
1
Monday, September 30, 13
2
Zak Greant
Community Manager, Magnolia
Monday, September 30, 13
Questions?
Use the questions tool
built into the GoToWebinar
client.
3
Monday, September 30, 13
4
forums.magnolia-cms.com
Monday, September 30, 13
#blossomqa
5
Monday, September 30, 13
Sr. Software Engineer, Magnolia
Lead developer of Magnolia’s Spring integration
Spring Framework user since 2005
Tobias Ma...
Blossom 3.0
7
Update for Magnolia 5 series
Requires Magnolia 5.1
Release candidate available
Final release next week
Monda...
Magnolia + Spring = Blossom 8
Monday, September 30, 13
@Template
9
Monday, September 30, 13
TEMPLATEREQUEST CONTENT
CMS
10
Monday, September 30, 13
TEMPLATEREQUEST CONTENT
CMS + Blossom
11
CONTROLLER
MODEL
VIEW
Monday, September 30, 13
Page Template
@Controller
@Template(id="myModule:pages/main", title="Main")
public class MainTemplate {
   @RequestMapping...
13
PAGE
Monday, September 30, 13
PAGES CONTAIN 0:n AREAS
14
PAGE
AREA
A
R
E
A
AREA
Monday, September 30, 13
PAGES CONTAIN 0:n AREAS
15
PAGE
AREA
A
R
E
A
AREA
AREAS HAVE 0:n COMPONENTS
COMPONENT
COMPONENT
Etiam porta sem malesuada ...
Area Template
@Controller
@Template(id="myModule:pages/main",title="Main Template")
public class MainTemplate {
   @Contro...
Component Template
@Controller
@Template(id="myModule:components/shoppingCart",
         title="Shopping Cart")
@TemplateD...
SERVLET
CONTAINER
RENDERING
FILTER
RENDERING
ENGINE
BLOSSOM
DISPATCHER
SERVLET
CONTROLLER
18
How Blossom Works
Monday, Sep...
Blossom 3.0
19
What’s new?
Monday, September 30, 13
20
Dialogs
Monday, September 30, 13
Fluent Builder-style API
@TabFactory("Content")
public void contentTab(UiConfig cfg, TabBuilder tab) {
tab.fields(
cfg.fie...
Blossom 2 Style Dialog
@TabFactory("Content")
public void contentTab(TabBuilder tab) {
DialogEdit dialogEdit = tab.addEdit...
Page Template with Dialog
@Controller
@Template(title="Article", id="myModule:pages/article")
public class ArticleTemplate...
Page Template with Dialog
@Controller
@Template(title="Article", id="myModule:pages/article")
public class ArticleTemplate...
Page Template with Dialog
@Controller
@Template(title="Article", id="myModule:pages/article")
public class ArticleTemplate...
@Controller
@Template(title="Article", id="myModule:pages/article")
public class ArticleTemplate {
@Area("main")
@Controll...
@Controller
@Template(title="Article", id="myModule:pages/article")
public class ArticleTemplate {
@Area("main")
@Controll...
@Controller
@Template(title="Article", id="myModule:pages/article")
public class ArticleTemplate {
@Area("main")
@Controll...
Component Template with Dialog
@Controller
@Template(title="Text", id="myModule:components/text")
public class TextCompone...
Component Template with Dialog
@Controller
@Template(title="Text", id="myModule:components/text")
public class TextCompone...
Component Template with Dialog
@Controller
@Template(title="Text", id="myModule:components/text")
public class TextCompone...
YouTube Video Component
@Controller
@Template(title="YouTube Video", id="myModule:components/youtube")
@TemplateDescriptio...
YouTube Video Component
@Controller
@Template(title="YouTube Video", id="myModule:components/youtube")
@TemplateDescriptio...
YouTube Video Component
@Controller
@Template(title="YouTube Video", id="myModule:components/youtube")
@TemplateDescriptio...
Dialogs and the Class Hierarchy
public abstract class BasePageTemplate {
@TabFactory("Meta")
public void metaTab(UiConfig ...
Input Validation
...
public void contentTab(UiConfig cfg, TabBuilder tab) {
tab.fields(
cfg.fields.text("name").label("Nam...
Dynamic Dialog
@Template(id="myModule:components/bookCategory", title="Book category")
@TemplateDescription("A list of boo...
Dynamic Dialog
@Template(id="myModule:components/bookCategory", title="Book category")
@TemplateDescription("A list of boo...
Dynamic Dialog
@Template(id="myModule:components/bookCategory", title="Book category")
@TemplateDescription("A list of boo...
Questions
32
Monday, September 30, 13
How do I get started on my project?
33
Monday, September 30, 13
mvn archetype:generate -DarchetypeCatalog=http://nexus.magnolia-cms.com/
content/groups/public/
choose magnolia-blossom-mo...
How would I build a REST interface to my CMS
content using Blossom?
35
Monday, September 30, 13
REST servlet in module descriptor
<servlets>
  <servlet>
    <name>rest</name>
    <class>org.springframework.web.servlet....
REST Controller
@Controller
public class ProductsRestController {
@RequestMapping("/products/{productId}")
public Product ...
Can I leverage Magnolia's caching functionality
to improve the performance of my Spring app?
38
Monday, September 30, 13
Influencing caching 39
@Controller
@Template(title="Text", id="myModule:components/text")
public class TextComponent {
@Re...
How can I present dialogs in different languages
using Blossom?
40
Monday, September 30, 13
@Controller
@Template(title = "Text", id = "blossomSampleModule:components/text")
@I18nBasename("info.magnolia.blossom.sam...
/info/magnolia/blossom/sample/messages_en.properties
textComponent.contentTab.label = Content
textComponent.contentTab.hea...
How do I migrate my existing site to Magnolia/
Blossom?
43
Monday, September 30, 13
How can I integrate Spring Security?
44
Monday, September 30, 13
45
Monday, September 30, 13
How can I dependency inject spring beans into
RenderingModels?
46
Monday, September 30, 13
Autowired RenderingModel
public class MyRenderingModel extends RenderingModelImpl<TemplateDefinition> {
@Autowired
private...
Autowired RenderingModel
public class MyRenderingModel extends AbstractAutowiredRenderingModel<TemplateDefinition> {
@Auto...
More questions?
49
Monday, September 30, 13
Magnolia + Spring = Blossom 50
Monday, September 30, 13
Thank You!
51
Monday, September 30, 13
52
magnolia-cms.com/spring
Monday, September 30, 13
Upcoming SlideShare
Loading in …5
×

Blossom Q&A Webinar

11,316 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 new in the 3.0 update.

Published in: Technology, Business
  • Be the first to comment

Blossom Q&A Webinar

  1. 1. Blossom Q&A Webinar 1 Monday, September 30, 13
  2. 2. 2 Zak Greant Community Manager, Magnolia Monday, September 30, 13
  3. 3. Questions? Use the questions tool built into the GoToWebinar client. 3 Monday, September 30, 13
  4. 4. 4 forums.magnolia-cms.com Monday, September 30, 13
  5. 5. #blossomqa 5 Monday, September 30, 13
  6. 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. 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. 8. Magnolia + Spring = Blossom 8 Monday, September 30, 13
  9. 9. @Template 9 Monday, September 30, 13
  10. 10. TEMPLATEREQUEST CONTENT CMS 10 Monday, September 30, 13
  11. 11. TEMPLATEREQUEST CONTENT CMS + Blossom 11 CONTROLLER MODEL VIEW Monday, September 30, 13
  12. 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. 13 PAGE Monday, September 30, 13
  14. 14. PAGES CONTAIN 0:n AREAS 14 PAGE AREA A R E A AREA Monday, September 30, 13
  15. 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. 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. 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. 18. SERVLET CONTAINER RENDERING FILTER RENDERING ENGINE BLOSSOM DISPATCHER SERVLET CONTROLLER 18 How Blossom Works Monday, September 30, 13
  19. 19. Blossom 3.0 19 What’s new? Monday, September 30, 13
  20. 20. 20 Dialogs Monday, September 30, 13
  21. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 40. Questions 32 Monday, September 30, 13
  41. 41. How do I get started on my project? 33 Monday, September 30, 13
  42. 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. 43. How would I build a REST interface to my CMS content using Blossom? 35 Monday, September 30, 13
  44. 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. 45. REST Controller @Controller public class ProductsRestController { @RequestMapping("/products/{productId}") public Product findProduct(@PathVariable String productId) { // implementation omitted } } 37 Monday, September 30, 13
  46. 46. Can I leverage Magnolia's caching functionality to improve the performance of my Spring app? 38 Monday, September 30, 13
  47. 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. 48. How can I present dialogs in different languages using Blossom? 40 Monday, September 30, 13
  49. 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. 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. 51. How do I migrate my existing site to Magnolia/ Blossom? 43 Monday, September 30, 13
  52. 52. How can I integrate Spring Security? 44 Monday, September 30, 13
  53. 53. 45 Monday, September 30, 13
  54. 54. How can I dependency inject spring beans into RenderingModels? 46 Monday, September 30, 13
  55. 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. 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. 57. More questions? 49 Monday, September 30, 13
  58. 58. Magnolia + Spring = Blossom 50 Monday, September 30, 13
  59. 59. Thank You! 51 Monday, September 30, 13
  60. 60. 52 magnolia-cms.com/spring Monday, September 30, 13

×