77
© 2013 SpringOne 2GX. All rights reserved. Spring & Web Content Management Tobias Mattsson & Daniel Lipp Magnolia International

Spring and Web Content Management

Embed Size (px)

DESCRIPTION

Want Spring seamlessly available inside a CMS? How about being able to integrate existing Spring apps into your CMS without rewriting a bunch of code? What about a robust CMS solution for Grails? Meet Magnolia, a mature open source CMS written in Java on the best of the Java stack (including Spring and Groovy.) This session will introduce Magnolia's Spring integration and give you a tour of its architecture, key features and use. Along the way, you'll also get insights into the development of Magnolia's Spring integration, an overview of Magnolia's key features (like workflows, innovative multi-channel support and a damn fine user experience that includes touch devices), and brief tutorials on solving some key content management challenges faced by Spring developers. There will also be a quick detour into Magnolia's Groovy shell and MagLev, a Grails plugin for Magnolia.

Citation preview

Page 1: Spring and Web Content Management

© 2013 SpringOne 2GX. All rights reserved.

Spring & WebContent Management

Tobias Mattsson & Daniel LippMagnolia International

Page 2: Spring and Web Content Management

2

Page 3: Spring and Web Content Management

3

Page 4: Spring and Web Content Management

4

Page 5: Spring and Web Content Management

Sr. Software Engineer, MagnoliaLead developer of Magnolia’s Spring integration

Spring Framework user since 2005

Tobias Mattsson

5

Page 6: Spring and Web Content Management

Daniel LippSr. Software Engineer, Magnolia

17 years of experience as software architect and Java developerGrateful to Spring for inspiring improvements to JEE 6

Page 7: Spring and Web Content Management

®

7

Page 8: Spring and Web Content Management

8

Page 9: Spring and Web Content Management

@magnolia_cms#magnolia_cms

9

Page 10: Spring and Web Content Management

SpringSpring MVC

Code, beautiful codeDependency Injection

IntegrationsBusiness logic

10

Page 11: Spring and Web Content Management

CMSSecurityMulti-lingualUser interfaceImage manipulationContent versioning

11

Page 12: Spring and Web Content Management

CMSSecurityMulti-lingualUser interfaceImage manipulationContent versioning

SpringSpring MVC

Code, beautiful codeDependency Injection

IntegrationsBusiness logic

12

Page 13: Spring and Web Content Management

USES IFRAMES

LIKE IT'S 1999 13

Page 14: Spring and Web Content Management

Magnolia + Spring = Blossom 14

Page 15: Spring and Web Content Management

@Template

15

or, "How Blossom is Built"

Page 16: Spring and Web Content Management

TEMPLATEREQUEST CONTENT

CMS

16

Page 17: Spring and Web Content Management

TEMPLATEREQUEST CONTENT

CMS + Blossom

17

CONTROLLER

MODEL

VIEW

Page 18: Spring and Web Content Management

Page Template

@Controller

@Template(id="myModule:pages/main", title="Main")public class MainTemplate {

   @RequestMapping("/main")

   public String render(ModelMap model) {

       return "pages/main";

   }

}

18

Page 19: Spring and Web Content Management

PAGES CONTAIN 0:n AREAS

19

PAGE

Page 20: Spring and Web Content Management

PAGES CONTAIN 0:n AREAS

19

PAGE

AREA

AREA

AREA

Page 21: Spring and Web Content Management

PAGES CONTAIN 0:n AREAS

19

PAGE

AREA

AREA

AREA

AREAS HAVE 0:n COMPONENTSCOMPONENT

COMPONENTEtiam porta sem malesuada magna mollis euismod. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.

COMPONENTEtiam 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.

COMPONENT

Page 22: Spring and Web Content Management

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

Page 23: Spring and Web Content Management

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";

   }

...

21

Page 24: Spring and Web Content Management

Views 22

Page 25: Spring and Web Content Management

Rendering an Area

FreeMarker[@cms.area name="main" /]

JSP<cms:area name="main" />

23

Page 26: Spring and Web Content Management

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>

24

Page 27: Spring and Web Content Management

About Magnolia CMS100% Java/J2EE compliantBest of breed open technology stack, including:

JSR-283 / JCR 2.0Vaadin / GWTServlet APIHTML5

Highly Customizable

25

Page 28: Spring and Web Content Management

Java Content Repository

26

“… defines an abstract model and a Java API for data storage and related services commonly used by content-oriented applications.” – JSR-283

Page 29: Spring and Web Content Management

Magnolia

JCR API

Persistence Manager

Jackrabbit Hierarchical content repository

In memoryDatabaseFile system

or or

27

Page 30: Spring and Web Content Management

Why JCR?

28

Hierarchical

Event Notification(Observation)

Role-basedsecurity

Locking

Fine-grained contentand large binaries

Full-textSearch

StructuredQueries

ReferentialIntegrity

TransactionalSchema-less or Strongly-typed

Versioning

Page 31: Spring and Web Content Management

29

Dialogs

Page 32: Spring and Web Content Management

30

GWT with server-side stateComponent-based UICross-browser compatibility (via GWT)Rich component libraryFast development pace

Page 33: Spring and Web Content Management

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")  );}

31

Page 34: Spring and Web Content Management

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"));    }

}

32

Page 35: Spring and Web Content Management

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 -->

32

Page 36: Spring and Web Content Management

@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 33

Page 37: Spring and Web Content Management

@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 33

Page 38: Spring and Web Content Management

@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 33

<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 -->

Page 39: Spring and Web Content Management

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")

34

Page 40: Spring and Web Content Management

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")

34

<h1>${content.heading}</h1><p>${cmsfn:decode(content).body}</p><!-- In the view -->

Page 41: Spring and Web Content Management

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") ); }}

35

Page 42: Spring and Web Content Management

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") ); }}

35

<iframe width="100%" height="400" src="//www.youtube.com/embed/${videoId}" frameborder="0" allowfullscreen></iframe><!-- In the view -->

Page 43: Spring and Web Content Management

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")    );  }}

36

Page 44: Spring and Web Content Management

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")    );  }}

36

<head> <meta name="description" content="${content.metaDescription}"/> <meta name="keywords" content="${content.metaKeywords}" />  <meta name="author" content="${content.metaAuthor}" /></head> <!-- In the view -->

Page 45: Spring and Web Content Management

Dynamic Dialog

@Template(id="myModule:components/bookCategory", title="Book category")

@TemplateDescription("A list of books in a given category.")@Controllerpublic class BookCategoryComponent {    @Autowired    private SalesApplicationWebService service;

   @RequestMapping("/bookcategory")    public String render(ModelMap model, Node content) 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)        );    }}

37

Page 46: Spring and Web Content Management

Dynamic Dialog

...

@TabFactory("Content")public void contentTab(UiConfig cfg, TabBuilder tab) {

Collection<String> categories = service.getBookCategories();

tab.fields(

cfg.fields.select("category").label("Category").options(categories)

 );}

...

38

Page 47: Spring and Web Content Management

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()) );

}

...

39

Page 48: Spring and Web Content Management

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/");    }}

40

Page 49: Spring and Web Content Management

Available Components

@Controller

@Area("promos")

@AvailableComponentClasses({TextComponent.class,                            ShoppingCartComponent.class})public static class PromosArea {

   @RequestMapping("/main/promos")

   public String render() {

       return "areas/promos";

   }

}

41

Page 50: Spring and Web Content Management

Area Inheritance

@Controller

@Area("promos")

@Inherits@AvailableComponentClasses({TextComponent.class,

                           ShoppingCartComponent.class})

public static class PromosArea {

   @RequestMapping("/main/promos")

   public String render() {

       return "areas/promos";

   }

}

42

Page 51: Spring and Web Content Management

SERVLETCONTAINER

RENDERINGFILTER

RENDERINGENGINE

BLOSSOM DISPATCHERSERVLET CONTROLLER

43

How Blossom Works

Page 52: Spring and Web Content Management

Magnolia Server

Dat

a

Wor

kflo

w

STK Mod

ules

Magnolia Core

Cus

tom

m

odul

e

Cus

tom

m

odul

e

DM

S Imag

ing

Cus

tom

Th

eme

Module JAR - templates - resources

44

Page 53: Spring and Web Content Management

Web container (Tomcat)

Web Archive

Magnolia CMS

Filter chain CMS

Context Security Cache Aggregation

Hierarchical content repository

Content

Custom filter

RequestRendering

Rendering engine

Response

45

Page 54: Spring and Web Content Management

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";

}

46

Page 55: Spring and Web Content Management

But wait a minute …

47

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 moreCaused by: java.lang.IllegalStateException

… the response has been sent.

Page 56: Spring and Web Content Management

Controller Pre-execution

48

C M V

PAGE

C M V

Area

C M V

Component

C M V

Component

C M V

Component

C

Page 57: Spring and Web Content Management

CPE Implementation 49

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 58: Spring and Web Content Management

Spring Web MVC+

Content

50

Page 59: Spring and Web Content Management

Spring Web Flow

51

REQUEST LANDINGPAGE

SPRING WEB FLOW

Page 60: Spring and Web Content Management

Spring Web Flow

52

REQUEST LANDINGPAGE

FORMSUBMIT?

SPRING WEB FLOW

Page 61: Spring and Web Content Management

Deployment & Scaling 53

Page 62: Spring and Web Content Management

Author

MagnoliaPublic A

Magnolia

Public B

Magnolia

Firewall

Activate

Internal Network Internet

Load

Bal

ance

r

JCR

JCR

JCR

54

Page 63: Spring and Web Content Management

55

Backend Application

DB

Author

Magnolia

JCR

Public

Magnolia

JCRPublic

Magnolia

JCR

Clustering

Page 64: Spring and Web Content Management

Dealing with Change 56

Page 65: Spring and Web Content Management

Filter Chain in JCR

57

Page 66: Spring and Web Content Management

Configuring Spring Beans 58

<blossom:observed-bean

default-class="com.sample.DiscountService"

path="/modules/myModule/beans/discountService" />

Page 67: Spring and Web Content Management

example.com/vanity

59

Page 68: Spring and Web Content Management

Changing Resources Live

60

CSSFreeMarkerImagesJavascriptViews

Page 69: Spring and Web Content Management

What Do You Win? 61

Page 70: Spring and Web Content Management

62

Page 71: Spring and Web Content Management

63

Page 72: Spring and Web Content Management

64

ShorterLearning

Curve

MVC

Use ExistingSpring Apps &Components

@Annotations

LooseCoupling

DependencyInjection

Code-drivenDialogs

Test-drivenDevelopment

SpringIdiomsSecurity

Scalability

Mobile& Touch

FasterDevelopment

FasterDevelopment

Cycles

Staging

Maglev

Page 73: Spring and Web Content Management

64

ShorterLearning

Curve

MVC

Use ExistingSpring Apps &Components

@Annotations

LooseCoupling

DependencyInjection

Code-drivenDialogs

Test-drivenDevelopment

SpringIdiomsSecurity

Scalability

Mobile& Touch

FasterDevelopment

FasterDevelopment

Cycles

Staging

Questions?

Maglev

Page 74: Spring and Web Content Management

Want to Learn More?

65

Talk to us in the exhibit hall

Attend Blossom Q & A webinar on Sept. 26http://magnolia-cms.com/blossom-qa

Visit http://magnolia-cms.com/springDashboard for all things Spring in Magnolia

Page 75: Spring and Web Content Management

Thank You!

66

Page 76: Spring and Web Content Management

Image Credits

67

#2: "Long Drive" by Nicholas A. Tonelli (CC-BY 2.0)#3: "Sluggish" by Nicholas A. Tonelli (CC-BY 2.0)#4: Still from "The Matrix"#7: "South Beach Miami Sunset" by Justin Ornellas (CC-BY 2.0)#14: "HBW - Magnolia Edition" by Nana B Agyei (CC-BY 2.0)#16: "Worker" designed by James Fenton from The Noun Project#16: "Database" designed by Ed Jones from The Noun Project#16: "Document" designed by Timur Zima from The Noun Project#22: "Three levels" by Paolo Fefe (CC-ND 2.0)#43:"Headset" designed by Benoît Bâlon from The Noun Project#43: "Engine" released into the Public Domain#43: "Flower" designed by Danilo Gusmão Silveira from The Noun Project#43: "Video Game Controller" designed by "Michael Rowe" from The Noun Project#51: "Anvil" designed by Masrur Mahmood from The Noun Project#52: "Hand" designed by Mikhail Bazilevsky from The Noun Project#53: "NYC Steam" by Don O'Brien (CC-BY 2.0)#56: "Floods 2013: Riverfront Ave" by Ryan Quan (CC-SA 2.0)#61: "3 Strikes for £2.50" by Julian Frost (CC-BY 2.0)

Page 77: Spring and Web Content Management

68

Trademarks

Other trademarks are the property of their respective owners.

MagnoliaThe Pulse are trademarks of

Magnolia International Limited.}