Announcement Announcement Module
Collapse
No announcement yet.
How can I do "runtime composition" with tiles and spring mvc? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How can I do "runtime composition" with tiles and spring mvc?

    Hi,

    I have a the following requirement and am trying to figure out how to make this happen in spring mvc and tiles.

    1. A user should be able to assemble a final page layout by picking or ore more page elements from a library of page element templates.
    2. A user should be able to specify the order of page elements rendered on the page.

    So, I am thinking of having various jsp pages as the page elements and a master template with a body tiles attribute which will render all the elements the user chooses to have rendered. I saw tiles has the List Attribute capability through which I would be able to populate the body attribute multiple jsps.

    http://tiles.apache.org/2.2/framewor...ttributes.html

    However, since the user has control over what goes in the page, the tiles definition happens at runtime by the user. That means I need a runtime way of expressing what jsps goes into the body tag and in what order.

    Tiles seems to have a "runtime composition" capability through the tiles container API to do the above:
    http://tiles.apache.org/2.2/framewor...d/runtime.html

    Per the examples I have tried the following in my spring mvc controller. I have also configured to use a mutable container in my TilesConfigurer.

    Code:
    @RequestMapping(method = RequestMethod.GET, value = "/")
    	public ModelAndView index(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    		
    		MutableTilesContainer container = (MutableTilesContainer) ServletUtil.getCurrentContainer(request,
    				request.getSession().getServletContext());
    					
    		ListAttribute tiles = new ListAttribute();		
    		Attribute attr = new Attribute("/WEB-INF/views/element_xyz.jspx");
    		tiles.add(attr);			
    		
    		attr = new Attribute("/WEB-INF/views/element_abc.jspx");
    		tiles.add(attr);
    				
    		AttributeContext context = container.startContext(request, response);		
    		context.putAttribute("body", tiles);
    		//don't call container.render(...) since spring mvc does that for me
    		//don't call container.stopContext(...) since spring mvc does that for me
    		
    		mv.setViewName("universaltask/index");
    		mv.getModelMap().put("app_name", "My App");
    		return mv;
    	}
    The above fails with the following error or other very similar messages depending on the renderer:

    org.apache.tiles.impl.InvalidTemplateException: Cannot render a template that is not a string: [/WEB-INF/views/element_xyz.jspx]
    at org.apache.tiles.renderer.impl.TemplateAttributeRe nderer.write(TemplateAttributeRenderer.java:46)
    at org.apache.tiles.renderer.impl.AbstractBaseAttribu teRenderer.render(AbstractBaseAttributeRenderer.ja va:106)
    at org.apache.tiles.impl.BasicTilesContainer.render(B asicTilesContainer.java:670)
    at org.apache.tiles.impl.BasicTilesContainer.render(B asicTilesContainer.java:336)
    at org.apache.tiles.template.InsertAttributeModel.ren derAttribute(InsertAttributeModel.java:210)
    at org.apache.tiles.template.InsertAttributeModel.end (InsertAttributeModel.java:126)
    at org.apache.tiles.jsp.taglib.InsertAttributeTag.doT ag(InsertAttributeTag.java:311)
    at org.apache.jsp.WEB_002dINF.layouts.default_jspx._j spx_meth_tiles_insertAttribute_1(org.apache.jsp.WE B_002dINF.layouts.default_jspx:144)
    at org.apache.jsp.WEB_002dINF.layouts.default_jspx._j spService(org.apache.jsp.WEB_002dINF.layouts.defau lt_jspx:70)
    at org.apache.jasper.runtime.HttpJspBase.service(Http JspBase.java:109)
    at javax.servlet.http.HttpServlet.service(HttpServlet .java:820)
    at org.apache.jasper.servlet.JspServletWrapper.servic e(JspServletWrapper.java:389)
    at org.apache.jasper.servlet.JspServlet.serviceJspFil e(JspServlet.java:486)
    at org.apache.jasper.servlet.JspServlet.service(JspSe rvlet.java:380)
    at javax.servlet.http.HttpServlet.service(HttpServlet .java:820)
    at org.eclipse.jetty.servlet.ServletHolder.handle(Ser vletHolder.java:538)
    at org.eclipse.jetty.servlet.ServletHandler.doHandle( ServletHandler.java:478)
    at org.eclipse.jetty.server.handler.ScopedHandler.han dle(ScopedHandler.java:119)
    at org.eclipse.jetty.security.SecurityHandler.handle( SecurityHandler.java:517)
    at org.eclipse.jetty.server.session.SessionHandler.do Handle(SessionHandler.java:225)
    at org.eclipse.jetty.server.handler.ContextHandler.do Handle(ContextHandler.java:937)
    at org.eclipse.jetty.servlet.ServletHandler.doScope(S ervletHandler.java:406)
    at org.eclipse.jetty.server.session.SessionHandler.do Scope(SessionHandler.java:183)
    at org.eclipse.jetty.server.handler.ContextHandler.do Scope(ContextHandler.java:871)
    at org.eclipse.jetty.server.handler.ScopedHandler.han dle(ScopedHandler.java:117)
    at org.eclipse.jetty.server.Dispatcher.forward(Dispat cher.java:284)
    at org.eclipse.jetty.server.Dispatcher.forward(Dispat cher.java:115)
    Last edited by canterburry; Aug 22nd, 2012, 07:36 PM.

  • #2
    Ok...figured it out...here is a sample controller:

    Code:
    @RequestMapping(method = RequestMethod.GET, value = "/")
    	public ModelAndView index(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    		
    		TilesContainer container = ServletUtil.getCurrentContainer(request,
    				request.getSession().getServletContext());
    		
    		AttributeContext attributeContext = container.startContext(request, response);
    		
    		ListAttribute tiles = new ListAttribute();
    		tiles.setRenderer("template");
    		tiles.add(new Attribute("/WEB-INF/views/element_xyz.jspx"));
    		tiles.add(new Attribute("/WEB-INF/views/element_abc.jspx"));		
    		attributeContext.putAttribute("items", tiles, true);
    		
    		mv.setViewName("universaltask/index");
    		mv.getModelMap().put("app_name", "My App");
    		return mv;
    	}
    Here is the template code:

    Code:
    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <div xmlns:jsp="http://java.sun.com/JSP/Page"
    	xmlns:spring="http://www.springframework.org/tags"
    	xmlns:tiles="http://tiles.apache.org/tags-tiles"
    	xmlns:jstl="http://java.sun.com/jstl/core_rt"
    	xmlns:util="urn:jsptagdir:/WEB-INF/tags/util" version="2.0">
    	<jsp:directive.page contentType="text/html;charset=UTF-8" />
    	<jsp:output omit-xml-declaration="yes" />
    	<tiles:useAttribute id="list" name="items" classname="java.util.List" />
    	<jstl:forEach var="item" items="${list}">
    		<tiles:insertAttribute value="${item}" flush="true" />
    		<br />
    	</jstl:forEach>
    </div>

    Comment


    • #3
      Further question about your solution.

      Good job, canterburry , I referenced your codes and they worked well.

      But as a beginner of both spring and tiles for two days, I still get questions to ask.

      In my project, I have two types of Attributions to insert . I used your code which worked fine , however I would like to make these attibutions more complex, in one attibution I want to add a spring tag <from:input /> and in another one I would like to have a drop-down box. But I have no idea about how to make these two jsp files work, the moment I wrote any codes like <form:input / > or <tiles: getAsString/>, (with the tag libraries), I got syntax errors from the server.

      So, could you post any sample about how to write these jsp files which will be inserted into the template at the runtime and how to pass value(Object, Data) into/from them?

      like in your case , the files "element_xyz.jspx" and "element_abc.jspx".


      Thank you so much if you can reply me.

      Originally posted by canterburry View Post
      Ok...figured it out...here is a sample controller:

      Code:
      @RequestMapping(method = RequestMethod.GET, value = "/")
      	public ModelAndView index(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
      		
      		TilesContainer container = ServletUtil.getCurrentContainer(request,
      				request.getSession().getServletContext());
      		
      		AttributeContext attributeContext = container.startContext(request, response);
      		
      		ListAttribute tiles = new ListAttribute();
      		tiles.setRenderer("template");
      		tiles.add(new Attribute("/WEB-INF/views/element_xyz.jspx"));
      		tiles.add(new Attribute("/WEB-INF/views/element_abc.jspx"));		
      		attributeContext.putAttribute("items", tiles, true);
      		
      		mv.setViewName("universaltask/index");
      		mv.getModelMap().put("app_name", "My App");
      		return mv;
      	}
      Here is the template code:

      Code:
      <?xml version="1.0" encoding="UTF-8" standalone="no"?>
      <div xmlns:jsp="http://java.sun.com/JSP/Page"
      	xmlns:spring="http://www.springframework.org/tags"
      	xmlns:tiles="http://tiles.apache.org/tags-tiles"
      	xmlns:jstl="http://java.sun.com/jstl/core_rt"
      	xmlns:util="urn:jsptagdir:/WEB-INF/tags/util" version="2.0">
      	<jsp:directive.page contentType="text/html;charset=UTF-8" />
      	<jsp:output omit-xml-declaration="yes" />
      	<tiles:useAttribute id="list" name="items" classname="java.util.List" />
      	<jstl:forEach var="item" items="${list}">
      		<tiles:insertAttribute value="${item}" flush="true" />
      		<br />
      	</jstl:forEach>
      </div>

      Comment

      Working...
      X