SlideShare a Scribd company logo
Tobias	
  Mattsson	
  
@sigget
Spring	
  first	
  in	
  Magnolia	
  CMS
USE	
  SPRING	
  OR	
  USE	
  A	
  CMS?
CMS
• CONTENT	
  AUTHORING	
  
• IMAGE	
  MANIPULATION	
  
• MULTI-­‐LINGUAL	
  
• USER	
  INTERFACE	
  
• CONTENT	
  VERSIONING
SPRING
• SPRING	
  MVC	
  
• DEPENDENCY	
  INJECTION	
  
• DECLARATIVE	
  SERVICES	
  
• INTEGRATIONS	
  
• AOP
CMS	
  IN	
  FRONTAPP	
  IN	
  FRONT
ORApp
CMS
CMS
App
CMS	
  IN	
  FRONTAPP	
  IN	
  FRONT
ORApp
CMS
CMS
App
CMS	
  IN	
  FRONTAPP	
  IN	
  FRONT
App
CMS
CMS
App
OR
Presentation	
  layer
Service	
  layer
SPRING	
  AND	
  CMS
CMS
App
Credit:	
  	
  Simplicity	
  of	
  Spring	
  by	
  ladydragonflyherworld	
  
Licensed	
  under	
  the	
  CreaOve	
  Commons	
  APribuOon	
  License	
  v2.0	
  
hPps://www.flickr.com/photos/ladydragonflyherworld/7009032119	
  	
  
	
  
MAGNOLIA	
  CMS	
  
+	
  SPRING	
  
=	
  BLOSSOM
Spring first in Magnolia CMS - Spring I/O 2015
 
Credit:	
  	
  UnOtled	
  by	
  mwichary	
  
Licensed	
  under	
  the	
  CreaOve	
  Commons	
  APribuOon	
  License	
  v2.0	
  
hPps://www.flickr.com/photos/mwichary/13660842584
@Template
CMS
TEMPLATEREQUEST CONTENT
CMS	
  with	
  Blossom
TEMPLATEREQUEST CONTENT
CONTROLLER
MODEL
VIEW
@Controller	
  
@Template(id="myModule:pages/main",	
  title="Main")	
  
public	
  class	
  MainTemplate	
  {	
  
	
  	
  	
  	
  @RequestMapping("/main")	
  
	
  	
  	
  	
  public	
  String	
  render(ModelMap	
  model)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  "pages/main";	
  
	
  	
  	
  	
  }	
  
}
@Template
Page,	
  area,	
  component	
  model
PAGE
Page,	
  area,	
  component	
  model
AREA
A
R
E
A
AREA
Page,	
  area,	
  component	
  model
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
Rendering	
  sequence
C M V
Page Area Component
ComponentComponent
C M V
C M V
C M V
C M V
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";	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  …	
  
}
Rendering	
  an	
  area
FreeMarker	
  
[@cms.area	
  name="main"	
  /]	
  
JSP	
  
<cms:area	
  name="main"	
  />	
  
Component	
  template
@Controller	
  
@Template(id="myModule:components/shoppingCart",	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  title="Shopping	
  Cart")	
  
public	
  class	
  ShoppingCartComponent	
  {	
  
	
  	
  	
  	
  @RequestMapping("/shoppingCart")	
  
	
  	
  	
  	
  public	
  String	
  handleRequest()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  return	
  "components/shoppingCart";	
  
	
  	
  	
  	
  }	
  
...	
  
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>	
  
Available	
  components
@Controller	
  
@Area("promos")	
  
@AvailableComponentClasses({TextComponent.class,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ShoppingCartComponent.class})	
  
public	
  static	
  class	
  PromosArea	
  {	
  
	
  	
  	
  	
  @RequestMapping("/main/promos")	
  
	
  	
  	
  	
  public	
  String	
  render()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  "areas/promos";	
  
	
  	
  	
  	
  }	
  
}
Component	
  categories
@Retention(RetentionPolicy.RUNTIME)	
  
@Target(ElementType.TYPE)	
  
@ComponentCategory	
  
public	
  @interface	
  Promo	
  {	
  }	
  
@Controller	
  
@Template(title	
  =	
  "Text",	
  id	
  =	
  "myModule:components/text")	
  
@Promo	
  
public	
  class	
  TextComponent	
  {	
  …	
  }
Component	
  categories
@Controller	
  
@Area("promos")	
  
@AvailableComponentClasses(Promo.class)	
  
public	
  static	
  class	
  PromosArea	
  {	
  
	
  	
  	
  	
  @RequestMapping("/main/promos")	
  
	
  	
  	
  	
  public	
  String	
  render()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  "areas/promos";	
  
	
  	
  	
  	
  }	
  
}
 
Credit:	
  Hard	
  Disk	
  by	
  Jeff	
  Kubina	
  
Licensed	
  under	
  the	
  CreaOve	
  Commons	
  APribuOon	
  License	
  v2.0	
  
hPps://www.flickr.com/photos/kubina/326629411	
  	
  
PERSISTENCE
JCR
Magnolia
JCR API
Persistence Manager
Jackrabbit Hierarchical
content repository
In memoryDatabaseFile system
or or
“…	
  defines	
  an	
  abstract	
  model	
  
and	
  a	
  Java	
  API	
  for	
  data	
  storage	
  
and	
  related	
  services	
  commonly	
  
used	
  by	
  content-­‐oriented	
  
applications.”	
  –	
  JSR-­‐283	
  
Content	
  structure
Component
template=…/textComponent
header=Company news
Component
template=…/videoComponent
header=Buy more soda!
Page
template=myModule:pages/pageTemplate
title=About
Area
name=main
border=1
Area
name=banners
Accessing	
  content	
  in	
  controllers
@Controller	
  
@Template(id="myModule:components/text",	
  title="Text")	
  
public	
  class	
  TextComponent	
  {	
  
	
  	
  	
  	
  @RequestMapping("/text")	
  
	
  	
  	
  	
  public	
  String	
  render(ModelMap	
  model,	
  Node	
  node)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  String	
  text	
  =	
  node.getProperty("text").getString();	
  
	
  	
  	
  	
  	
  	
  	
  	
  model.addAttribute("text",	
  text);	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  "components/text";	
  
	
  	
  	
  	
  }	
  
}
HandlerMethodArgumentResolver
@Override	
  
public	
  boolean	
  supportsParameter(MethodParameter	
  parameter)	
  {	
  
	
  	
  	
  	
  Class<?>	
  parameterType	
  =	
  parameter.getParameterType();	
  
	
  	
  	
  	
  return	
  parameterType.isAssignableFrom(Node.class);	
  
}	
  
@Override	
  
public	
  Object	
  resolveArgument(MethodParameter	
  methodParameter,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ModelAndViewContainer	
  mavContainer,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  NativeWebRequest	
  webRequest,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  WebDataBinderFactory	
  binderFactory)	
  throws	
  Exception	
  {	
  
	
  	
  	
  return	
  renderingContext.getCurrentContent();	
  
}
 
Credit:	
  Apple	
  Keyboard	
  by	
  DeclanTM	
  
Licensed	
  under	
  the	
  CreaOve	
  Commons	
  APribuOon	
  License	
  v2.0	
  
hPps://www.flickr.com/photos/declanjewell/2687934126	
  	
  
DIALOGS
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")	
  
	
  	
  	
  	
  );

}
@Controller	
  
@Template(id="myModule:pages/article",	
  title="Article")	
  
public	
  class	
  ArticleTemplate	
  {	
  
	
  	
  	
  	
  @TabFactory("Content")	
  
	
  	
  	
  	
  public	
  void	
  contentTab(UiConfig	
  cfg,	
  TabBuilder	
  tab)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  tab.fields(cfg.fields.text("title").label("Title"));	
  
	
  	
  	
  	
  }	
  
}
Page	
  template	
  with	
  dialog
@Controller	
  
@Template(id="myModule:pages/article",	
  title="Article")	
  
public	
  class	
  ArticleTemplate	
  {	
  
	
  	
  	
  	
  @TabFactory("Content")	
  
	
  	
  	
  	
  public	
  void	
  contentTab(UiConfig	
  cfg,	
  TabBuilder	
  tab)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  tab.fields(cfg.fields.text("title").label("Title"));	
  
	
  	
  	
  	
  }	
  
}
Page	
  template	
  with	
  dialog
@Controller	
  
@Template(id="myModule:pages/article",	
  title="Article")	
  
public	
  class	
  ArticleTemplate	
  {	
  
	
  	
  	
  	
  @TabFactory("Content")	
  
	
  	
  	
  	
  public	
  void	
  contentTab(UiConfig	
  cfg,	
  TabBuilder	
  tab)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  tab.fields(cfg.fields.text("title").label("Title"));	
  
	
  	
  	
  	
  }	
  
}
Page	
  template	
  with	
  dialog
<title>${content.title}<title>
@Controller

@Template(id="myModule:pages/article",	
  title="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	
  with	
  dialog
@Controller

@Template(id="myModule:pages/article",	
  title="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	
  with	
  dialog
@Controller	
  
@Template(id="myModule:components/text",	
  title="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”));	
  
	
  	
  	
  	
  }
Component	
  template	
  with	
  dialog
@Controller	
  
@Template(id="myModule:components/text",	
  title="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”));	
  
	
  	
  	
  	
  }
Component	
  template	
  with	
  dialog
@Controller

@Template(id="myModule:components/youtube",	
  title="YouTube")

public	
  class	
  YoutubeComponent	
  {	
  
	
  	
  	
  @TabFactory("Content")

	
  	
  	
  public	
  void	
  contentTab(UiConfig	
  cfg,	
  TabBuilder	
  tab)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  tab.fields(cfg.fields.text("videoId").label("Video	
  Id”));	
  
	
  	
  	
  }

	
  	
  	
  	
  @RequestMapping(“/youtube")	
  
	
  	
  	
  	
  public	
  String	
  render(Node	
  node,	
  ModelMap	
  model)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  model.put("videoId",	
  node.getProperty(“videoId").getString());	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  “components/youtube";	
  
	
  	
  	
  }	
  
}
Youtube	
  video	
  component
Dynamic	
  dialog
@Autowired	
  
private	
  SalesApplicationWebService	
  service;	
  
@TabFactory("Content")

public	
  void	
  contentTab(UiConfig	
  cfg,	
  TabBuilder	
  tab)	
  {	
  
	
  	
  	
  Collection<String>	
  categories	
  =	
  service.getBookCategories();	
  
	
  	
  	
  tab.fields(	
  
	
  	
  	
  	
  	
  	
  	
  cfg.fields.select(“category").label("Category").options(categories));	
  
	
  	
  	
  }	
  
}	
  
@RequestMapping("/bookcategory")

public	
  String	
  render(ModelMap	
  model,	
  Node	
  content)	
  {	
  
	
  	
  	
  String	
  category	
  =	
  content.getProperty(“category").getString();	
  
	
  	
  	
  model.put("books",	
  service.getBooksInCategory(category));	
  
	
  	
  	
  	
  return	
  "components/bookCategory";

}
Dialogs	
  and	
  class	
  hierarchies
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")	
  
	
  	
  	
  	
  	
  	
  	
  	
  );

	
  	
  	
  	
  }

}
Dialogs	
  and	
  class	
  hierarchies
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")	
  
	
  	
  	
  	
  	
  	
  	
  	
  );

	
  	
  	
  	
  }

}
Dialog	
  factories
@DialogFactory("front-­‐page-­‐dialog")	
  
public	
  class	
  FrontPageDialog	
  {	
  
	
  	
  @TabFactory("Margins")	
  
	
  	
  public	
  void	
  marginsTab(UiConfig	
  cfg,	
  TabBuilder	
  tab)	
  {	
  
	
  	
  	
  	
  tab.fields(	
  
	
  	
  	
  	
  	
  	
  	
  cfg.fields.text("leftMargin").label("Left	
  Margin"),	
  
	
  	
  	
  	
  	
  	
  	
  cfg.fields.text("rightMargin").label("Right	
  Margin"));	
  
	
  	
  }	
  
}	
  
@Controller	
  
@Template(id="myModule:pages/main",	
  title=“Main",	
  dialog="front-­‐page-­‐dialog")	
  
public	
  class	
  MainTemplate	
  {	
  
DEMO
 
Credit:	
  NASA	
  
www.nasa.gov/vision/space/features/apollo_lor.html	
  	
  
HOW	
  IT	
  
WORKS
BeanPostProcessor
@Override	
  
public	
  Object	
  postProcessBeforeInitialization(Object	
  bean,	
  String	
  beanName)	
  
throws	
  BeansException	
  {	
  
	
  	
  	
  	
  return	
  bean;	
  
}	
  
@Override	
  
public	
  Object	
  postProcessAfterInitialization(Object	
  bean,	
  String	
  beanName)	
  
throws	
  BeansException	
  {	
  
	
  	
  	
  	
  if	
  (bean	
  instanceof	
  RequestMappingInfoHandlerMapping)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  RequestMappingInfoHandlerMapping	
  m	
  =	
  (RequestMappingInfoHandlerMapping)	
  bean;	
  
	
  	
  	
  	
  	
  	
  	
  	
  Map<RequestMappingInfo,HandlerMethod>	
  methods	
  =	
  m.getHandlerMethods();	
  
	
  	
  	
  	
  	
  	
  	
  	
  for	
  (Map.Entry<RequestMappingInfo,	
  HandlerMethod>	
  entry	
  :	
  methods.entrySet())	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  Object	
  handler	
  =	
  handlerMethod.createWithResolvedBean().getBean();	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (handlerClass.isAnnotationPresent(Template.class))	
  {	
  …	
  }	
  
	
  	
  	
  	
  }	
  }	
  }	
  
	
  	
  	
  	
  return	
  bean;	
  
}
Rendering	
  integration
Handler Adapter Controller
Handler Mapping
View Resolver View
Dispatcher Servlet
Rendering EngineFilter Chain Blossom Renderer
fake wrappers
Forms	
  and	
  redirects
@RequestMapping(value="/contact",	
  method=RequestMethod.GET)	
  
public	
  String	
  viewForm(@ModelAttribute	
  ContactForm	
  form)	
  {	
  
	
  	
  	
  return	
  "components/contactForm";	
  
}	
  
@RequestMapping(value="/contact",	
  method=RequestMethod.POST)	
  
public	
  String	
  handleSubmit(@Valid	
  ContactForm	
  form,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  BindingResult	
  result)	
  {	
  
	
  	
  	
  	
  if	
  (result.hasErrors())	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  “components/contactForm";	
  
	
  	
  return	
  "redirect:/contact/thankyou.html";	
  
}
Redirects
C M V
Page Area Component
ComponentComponent
C M V C M V
C M VC M V
X
Controller	
  pre-­‐execution
C M V
Page Area Component
Component
C M V
Component
C C M V C M V
C M V
Pre-­‐execution	
  in	
  view
In	
  JSP	
  
<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"	
  />
SPRING	
  WEB	
  MVC	
  
with	
  
CONTENT
QUESTIONS?
 THANK	
  YOU!

More Related Content

PDF
Getting Healthy with Magnolia, Blossom and Spring
PDF
Spring and Web Content Management
PDF
Start Developing Apps for Magnolia CMS
ODP
springmvc-150923124312-lva1-app6892
PPTX
Integration of Backbone.js with Spring 3.1
PPTX
Spring MVC
PDF
Spring mvc
ODP
Java Spring MVC Framework with AngularJS by Google and HTML5
Getting Healthy with Magnolia, Blossom and Spring
Spring and Web Content Management
Start Developing Apps for Magnolia CMS
springmvc-150923124312-lva1-app6892
Integration of Backbone.js with Spring 3.1
Spring MVC
Spring mvc
Java Spring MVC Framework with AngularJS by Google and HTML5

What's hot (20)

KEY
MVC on the server and on the client
PPT
Spring 3.x - Spring MVC
PPT
Spring MVC Basics
KEY
Multi Client Development with Spring
PPTX
Modern android development
KEY
Multi client Development with Spring
PDF
Spring MVC Annotations
PDF
Java Web Programming on Google Cloud Platform [2/3] : Datastore
PDF
Java Web Programming on Google Cloud Platform [1/3] : Google App Engine
PPTX
[DSBW Spring 2009] Unit 06: Conallen's Web Application Extension for UML (WAE2)
PDF
Java Web Programming [3/9] : Servlet Advanced
PDF
Java Web Programming on Google Cloud Platform [3/3] : Google Web Toolkit
PPTX
Rest with Java EE 6 , Security , Backbone.js
PDF
Building Highly Reusable Taskflows
PDF
Jsf intro
PDF
Introducing Rendr: Run your Backbone.js apps on the client and server
PDF
Create an application with ember
DOCX
Server side programming bt0083
PDF
Java Web Programming [6/9] : MVC
PDF
Spring MVC 3.0 Framework (sesson_2)
MVC on the server and on the client
Spring 3.x - Spring MVC
Spring MVC Basics
Multi Client Development with Spring
Modern android development
Multi client Development with Spring
Spring MVC Annotations
Java Web Programming on Google Cloud Platform [2/3] : Datastore
Java Web Programming on Google Cloud Platform [1/3] : Google App Engine
[DSBW Spring 2009] Unit 06: Conallen's Web Application Extension for UML (WAE2)
Java Web Programming [3/9] : Servlet Advanced
Java Web Programming on Google Cloud Platform [3/3] : Google Web Toolkit
Rest with Java EE 6 , Security , Backbone.js
Building Highly Reusable Taskflows
Jsf intro
Introducing Rendr: Run your Backbone.js apps on the client and server
Create an application with ember
Server side programming bt0083
Java Web Programming [6/9] : MVC
Spring MVC 3.0 Framework (sesson_2)
Ad

Viewers also liked (8)

PDF
Surrealpete Art - Body of Work
PDF
Les Jeunes et le Vin, un désamour, vraiment ? Une étude Verallia
PPTX
You Can't Buy Agile
PDF
Mean Time to Sleep: Quantifying the On-Call Experience
KEY
Magnolia CMS 5.0 - Architecture
PDF
Using Magnolia in a Microservices Architecture
PDF
Integrating multiple CDNs at Etsy
PPT
Funny pranks to do on friends
Surrealpete Art - Body of Work
Les Jeunes et le Vin, un désamour, vraiment ? Une étude Verallia
You Can't Buy Agile
Mean Time to Sleep: Quantifying the On-Call Experience
Magnolia CMS 5.0 - Architecture
Using Magnolia in a Microservices Architecture
Integrating multiple CDNs at Etsy
Funny pranks to do on friends
Ad

Similar to Spring first in Magnolia CMS - Spring I/O 2015 (16)

PDF
Spring MVC introduction HVA
PDF
CIRCUIT 2015 - Content API's For AEM Sites
KEY
Summer - The HTML5 Library for Java and Scala
KEY
Multi Client Development with Spring
PDF
Blossom on the web
PDF
Content-Driven Web Applications with Magnolia CMS and Ruby on Rails
PDF
REST based web applications with Spring 3
KEY
Domain Specific Languages (EclipseCon 2012)
PDF
PrimeFaces: Next-Generation JSF Component Suite - Ian Hlavats
PDF
Spring Framework 4.1
PDF
Optaros Surf Code Camp Lab 4
KEY
App Engine ja Night Sapporo #1
PDF
Web Components With Rails
PDF
CQ5 and Sling overview
PDF
Creating Modular Test-Driven SPAs with Spring and AngularJS
PDF
Alfresco Custom Model
Spring MVC introduction HVA
CIRCUIT 2015 - Content API's For AEM Sites
Summer - The HTML5 Library for Java and Scala
Multi Client Development with Spring
Blossom on the web
Content-Driven Web Applications with Magnolia CMS and Ruby on Rails
REST based web applications with Spring 3
Domain Specific Languages (EclipseCon 2012)
PrimeFaces: Next-Generation JSF Component Suite - Ian Hlavats
Spring Framework 4.1
Optaros Surf Code Camp Lab 4
App Engine ja Night Sapporo #1
Web Components With Rails
CQ5 and Sling overview
Creating Modular Test-Driven SPAs with Spring and AngularJS
Alfresco Custom Model

Recently uploaded (20)

PDF
AI in Product Development-omnex systems
PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PDF
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
PDF
Navsoft: AI-Powered Business Solutions & Custom Software Development
PPTX
VVF-Customer-Presentation2025-Ver1.9.pptx
PPTX
Introduction to Artificial Intelligence
PDF
2025 Textile ERP Trends: SAP, Odoo & Oracle
PDF
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
PDF
Nekopoi APK 2025 free lastest update
PDF
System and Network Administraation Chapter 3
PDF
Adobe Illustrator 28.6 Crack My Vision of Vector Design
PDF
How to Migrate SBCGlobal Email to Yahoo Easily
PPTX
L1 - Introduction to python Backend.pptx
PDF
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
PDF
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
PPTX
Reimagine Home Health with the Power of Agentic AI​
PPTX
Essential Infomation Tech presentation.pptx
PPTX
Transform Your Business with a Software ERP System
PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
AI in Product Development-omnex systems
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
Navsoft: AI-Powered Business Solutions & Custom Software Development
VVF-Customer-Presentation2025-Ver1.9.pptx
Introduction to Artificial Intelligence
2025 Textile ERP Trends: SAP, Odoo & Oracle
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
Nekopoi APK 2025 free lastest update
System and Network Administraation Chapter 3
Adobe Illustrator 28.6 Crack My Vision of Vector Design
How to Migrate SBCGlobal Email to Yahoo Easily
L1 - Introduction to python Backend.pptx
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
Reimagine Home Health with the Power of Agentic AI​
Essential Infomation Tech presentation.pptx
Transform Your Business with a Software ERP System
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
Which alternative to Crystal Reports is best for small or large businesses.pdf

Spring first in Magnolia CMS - Spring I/O 2015

  • 1. Tobias  Mattsson   @sigget Spring  first  in  Magnolia  CMS
  • 2. USE  SPRING  OR  USE  A  CMS?
  • 3. CMS • CONTENT  AUTHORING   • IMAGE  MANIPULATION   • MULTI-­‐LINGUAL   • USER  INTERFACE   • CONTENT  VERSIONING
  • 4. SPRING • SPRING  MVC   • DEPENDENCY  INJECTION   • DECLARATIVE  SERVICES   • INTEGRATIONS   • AOP
  • 5. CMS  IN  FRONTAPP  IN  FRONT ORApp CMS CMS App
  • 6. CMS  IN  FRONTAPP  IN  FRONT ORApp CMS CMS App
  • 7. CMS  IN  FRONTAPP  IN  FRONT App CMS CMS App OR
  • 9. Credit:    Simplicity  of  Spring  by  ladydragonflyherworld   Licensed  under  the  CreaOve  Commons  APribuOon  License  v2.0   hPps://www.flickr.com/photos/ladydragonflyherworld/7009032119       MAGNOLIA  CMS   +  SPRING   =  BLOSSOM
  • 11.   Credit:    UnOtled  by  mwichary   Licensed  under  the  CreaOve  Commons  APribuOon  License  v2.0   hPps://www.flickr.com/photos/mwichary/13660842584 @Template
  • 13. CMS  with  Blossom TEMPLATEREQUEST CONTENT CONTROLLER MODEL VIEW
  • 14. @Controller   @Template(id="myModule:pages/main",  title="Main")   public  class  MainTemplate  {          @RequestMapping("/main")          public  String  render(ModelMap  model)  {                  return  "pages/main";          }   } @Template
  • 16. Page,  area,  component  model AREA A R E A AREA
  • 17. Page,  area,  component  model 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
  • 18. Rendering  sequence C M V Page Area Component ComponentComponent C M V C M V C M V C M V
  • 19. 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";                  }          …   }
  • 20. Rendering  an  area FreeMarker   [@cms.area  name="main"  /]   JSP   <cms:area  name="main"  />  
  • 21. Component  template @Controller   @Template(id="myModule:components/shoppingCart",                                              title="Shopping  Cart")   public  class  ShoppingCartComponent  {          @RequestMapping("/shoppingCart")          public  String  handleRequest()  {                return  "components/shoppingCart";          }   ...  
  • 22. 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>  
  • 23. Available  components @Controller   @Area("promos")   @AvailableComponentClasses({TextComponent.class,                                                                                                                  ShoppingCartComponent.class})   public  static  class  PromosArea  {          @RequestMapping("/main/promos")          public  String  render()  {                  return  "areas/promos";          }   }
  • 24. Component  categories @Retention(RetentionPolicy.RUNTIME)   @Target(ElementType.TYPE)   @ComponentCategory   public  @interface  Promo  {  }   @Controller   @Template(title  =  "Text",  id  =  "myModule:components/text")   @Promo   public  class  TextComponent  {  …  }
  • 25. Component  categories @Controller   @Area("promos")   @AvailableComponentClasses(Promo.class)   public  static  class  PromosArea  {          @RequestMapping("/main/promos")          public  String  render()  {                  return  "areas/promos";          }   }
  • 26.   Credit:  Hard  Disk  by  Jeff  Kubina   Licensed  under  the  CreaOve  Commons  APribuOon  License  v2.0   hPps://www.flickr.com/photos/kubina/326629411     PERSISTENCE
  • 27. JCR Magnolia JCR API Persistence Manager Jackrabbit Hierarchical content repository In memoryDatabaseFile system or or “…  defines  an  abstract  model   and  a  Java  API  for  data  storage   and  related  services  commonly   used  by  content-­‐oriented   applications.”  –  JSR-­‐283  
  • 28. Content  structure Component template=…/textComponent header=Company news Component template=…/videoComponent header=Buy more soda! Page template=myModule:pages/pageTemplate title=About Area name=main border=1 Area name=banners
  • 29. Accessing  content  in  controllers @Controller   @Template(id="myModule:components/text",  title="Text")   public  class  TextComponent  {          @RequestMapping("/text")          public  String  render(ModelMap  model,  Node  node)  {                  String  text  =  node.getProperty("text").getString();                  model.addAttribute("text",  text);                  return  "components/text";          }   }
  • 30. HandlerMethodArgumentResolver @Override   public  boolean  supportsParameter(MethodParameter  parameter)  {          Class<?>  parameterType  =  parameter.getParameterType();          return  parameterType.isAssignableFrom(Node.class);   }   @Override   public  Object  resolveArgument(MethodParameter  methodParameter,                            ModelAndViewContainer  mavContainer,                            NativeWebRequest  webRequest,                            WebDataBinderFactory  binderFactory)  throws  Exception  {        return  renderingContext.getCurrentContent();   }
  • 31.   Credit:  Apple  Keyboard  by  DeclanTM   Licensed  under  the  CreaOve  Commons  APribuOon  License  v2.0   hPps://www.flickr.com/photos/declanjewell/2687934126     DIALOGS
  • 32. 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")          );
 }
  • 33. @Controller   @Template(id="myModule:pages/article",  title="Article")   public  class  ArticleTemplate  {          @TabFactory("Content")          public  void  contentTab(UiConfig  cfg,  TabBuilder  tab)  {                  tab.fields(cfg.fields.text("title").label("Title"));          }   } Page  template  with  dialog
  • 34. @Controller   @Template(id="myModule:pages/article",  title="Article")   public  class  ArticleTemplate  {          @TabFactory("Content")          public  void  contentTab(UiConfig  cfg,  TabBuilder  tab)  {                  tab.fields(cfg.fields.text("title").label("Title"));          }   } Page  template  with  dialog
  • 35. @Controller   @Template(id="myModule:pages/article",  title="Article")   public  class  ArticleTemplate  {          @TabFactory("Content")          public  void  contentTab(UiConfig  cfg,  TabBuilder  tab)  {                  tab.fields(cfg.fields.text("title").label("Title"));          }   } Page  template  with  dialog <title>${content.title}<title>
  • 36. @Controller
 @Template(id="myModule:pages/article",  title="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  with  dialog
  • 37. @Controller
 @Template(id="myModule:pages/article",  title="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  with  dialog
  • 38. @Controller   @Template(id="myModule:components/text",  title="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”));          } Component  template  with  dialog
  • 39. @Controller   @Template(id="myModule:components/text",  title="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”));          } Component  template  with  dialog
  • 40. @Controller
 @Template(id="myModule:components/youtube",  title="YouTube")
 public  class  YoutubeComponent  {        @TabFactory("Content")
      public  void  contentTab(UiConfig  cfg,  TabBuilder  tab)  {                tab.fields(cfg.fields.text("videoId").label("Video  Id”));        }
        @RequestMapping(“/youtube")          public  String  render(Node  node,  ModelMap  model)  {                  model.put("videoId",  node.getProperty(“videoId").getString());                  return  “components/youtube";        }   } Youtube  video  component
  • 41. Dynamic  dialog @Autowired   private  SalesApplicationWebService  service;   @TabFactory("Content")
 public  void  contentTab(UiConfig  cfg,  TabBuilder  tab)  {        Collection<String>  categories  =  service.getBookCategories();        tab.fields(                cfg.fields.select(“category").label("Category").options(categories));        }   }   @RequestMapping("/bookcategory")
 public  String  render(ModelMap  model,  Node  content)  {        String  category  =  content.getProperty(“category").getString();        model.put("books",  service.getBooksInCategory(category));          return  "components/bookCategory";
 }
  • 42. Dialogs  and  class  hierarchies 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")                  );
        }
 }
  • 43. Dialogs  and  class  hierarchies 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")                  );
        }
 }
  • 44. Dialog  factories @DialogFactory("front-­‐page-­‐dialog")   public  class  FrontPageDialog  {      @TabFactory("Margins")      public  void  marginsTab(UiConfig  cfg,  TabBuilder  tab)  {          tab.fields(                cfg.fields.text("leftMargin").label("Left  Margin"),                cfg.fields.text("rightMargin").label("Right  Margin"));      }   }   @Controller   @Template(id="myModule:pages/main",  title=“Main",  dialog="front-­‐page-­‐dialog")   public  class  MainTemplate  {  
  • 45. DEMO
  • 47. BeanPostProcessor @Override   public  Object  postProcessBeforeInitialization(Object  bean,  String  beanName)   throws  BeansException  {          return  bean;   }   @Override   public  Object  postProcessAfterInitialization(Object  bean,  String  beanName)   throws  BeansException  {          if  (bean  instanceof  RequestMappingInfoHandlerMapping)  {                  RequestMappingInfoHandlerMapping  m  =  (RequestMappingInfoHandlerMapping)  bean;                  Map<RequestMappingInfo,HandlerMethod>  methods  =  m.getHandlerMethods();                  for  (Map.Entry<RequestMappingInfo,  HandlerMethod>  entry  :  methods.entrySet())  {                              Object  handler  =  handlerMethod.createWithResolvedBean().getBean();                              if  (handlerClass.isAnnotationPresent(Template.class))  {  …  }          }  }  }          return  bean;   }
  • 48. Rendering  integration Handler Adapter Controller Handler Mapping View Resolver View Dispatcher Servlet Rendering EngineFilter Chain Blossom Renderer fake wrappers
  • 49. Forms  and  redirects @RequestMapping(value="/contact",  method=RequestMethod.GET)   public  String  viewForm(@ModelAttribute  ContactForm  form)  {        return  "components/contactForm";   }   @RequestMapping(value="/contact",  method=RequestMethod.POST)   public  String  handleSubmit(@Valid  ContactForm  form,                                                                                                      BindingResult  result)  {          if  (result.hasErrors())                  return  “components/contactForm";      return  "redirect:/contact/thankyou.html";   }
  • 50. Redirects C M V Page Area Component ComponentComponent C M V C M V C M VC M V X
  • 51. Controller  pre-­‐execution C M V Page Area Component Component C M V Component C C M V C M V C M V
  • 52. Pre-­‐execution  in  view In  JSP   <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"  />
  • 53. SPRING  WEB  MVC   with   CONTENT