How to automate body import with Apache Tiles and Spring MVC - spring-mvc

I have the following tiles-def.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
"http://tiles.apache.org/dtds/tiles-config_2_0.dtd">
<tiles-definitions>
<definition name="default" template="/WEB-INF/jsp/layout.jsp">
<put-attribute name="title" value="my webapp" />
<put-attribute name="header" value="/WEB-INF/jsp/header.jsp" />
<put-attribute name="menu" value="/WEB-INF/jsp/menu.jsp" />
<put-attribute name="body" value="/WEB-INF/jsp/hello.jsp" />
<put-attribute name="footer" value="/WEB-INF/jsp/footer.jsp" />
</definition>
<definition name="contact" extends="default">
<put-attribute name="body" value="/WEB-INF/jsp/contact.jsp" />
</definition>
<definition name="hello" extends="default">
<put-attribute name="body" value="/WEB-INF/jsp/hello.jsp" />
</definition>
</tiles-definitions>
As you can see, in all my pages, just the body changes. Is there a way to automate this? (so it automatically includes the jsp that has the name of the requested page, or an error page if it doesnt exist?)
Thank you!
EDIT: More details of what I want to do:
How it is now:
For each new page of my webapp, I have to add a new to my tiles-def.xml. And everytime, the only thing it does is setting the body with my content page.
What I would like to do:
Just have one default definition that automatically chose the page to display, something like this:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
"http://tiles.apache.org/dtds/tiles-config_2_0.dtd">
<tiles-definitions>
<definition name="default" template="/WEB-INF/jsp/layout.jsp">
<put-attribute name="title" value="my webapp" />
<put-attribute name="header" value="/WEB-INF/jsp/header.jsp" />
<put-attribute name="menu" value="/WEB-INF/jsp/menu.jsp" />
if(myPageName exists){
<put-attribute name="body" value="/WEB-INF/jsp/" + myPageName + ".jsp" />
else{
<put-attribute name="body" value="/WEB-INF/jsp/error404.jsp" />
}
<put-attribute name="footer" value="/WEB-INF/jsp/footer.jsp" />
</definition>
</tiles-definitions>
Where myPageName would be the name of the page requested (If the URL was "http://www.mysite.com/contact.html", then myPageName would be "contact". If it was "http://www.mysite.com/info.html", then myPageName would be "info").
How can I do this?

Check out the Dynamic Tiles Example on the springbyexample.org page. The DynamicTilesView does exactly what you want (see example config here). The full Dynamic Tiles Example can be found here on github

Related

Tiles 3 how to reference another definition in put-attribute

I'd like to be able to define a base definition, where I can inherit a list of styles and scripts. then define a page definition that inherits base definition, and adds page specific styles and scripts. Is this possible -or am I not thinking about this in the right way? I would have thought this to be a fairly basic idea.
base definitions
<tiles-definitions>
<!-- base styles -->
<definition name="base.styles" >
<put-list-attribute name="styles" cascade="true" >
<add-attribute value="/view/common/jquery-ui-theme-base-v1.12.1.css" />
</put-list-attribute>
</definition>
<!-- base scripts -->
<definition name="base.scripts" >
<put-list-attribute name="scripts" cascade="true" >
<add-attribute value="https://code.jquery.com/jquery-3.1.0.min.js" />
<add-attribute value="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js" />
</put-list-attribute>
</definition>
<!-- base definition -->
<definition name="base.definition" template="/WEB-INF/page/defaultLayout.jsp" >
<put-attribute name="title" />
<put-attribute name="styles" value="base.styles.styles" cascade="true" />
<put-attribute name="header" value="/WEB-INF/page/common/header.jsp" />
<put-attribute name="body" />
<put-attribute name="scripts" value="base.scripts.scripts" cascade="true" />
<put-attribute name="footer" value="/WEB-INF/page/common/footer.jsp" />
</definition>
</tiles-definitions>
note the values of the put-attribute match the names of the definitions above them. (my guess is this isn't correct)
page specific definitions
<tiles-definitions>
<!-- page specific styles -->
<definition name="samplePage.styles" extends="base.styles" >
<put-list-attribute name="styles" inherit="true" >
<add-attribute value="/view/page/samplePage/samplePageStyles.css" />
</put-list-attribute>
</definition>
<!-- page specific scripts -->
<definition name="samplePage.scripts" extends="base.scripts" >
<put-list-attribute name="scripts" inherit="true" >
<add-attribute value="/view/page/samplePage/samplePageScript.js" />
</put-list-attribute>
</definition>
<!-- page specific definition -->
<definition name="samplePage" extends="base.definition" >
<put-attribute name="title" value="Sample Page" />
<put-attribute name="styles" value="samplePage.styles" cascade="true" />
<put-attribute name="body" value="/WEB-INF/page/samplePage/samplePageBody" />
<put-attribute name="scripts" value="samplePage.scripts" cascade="true" />
</definition>
</tiles-definitions>
again -note the values of the put-attribute match the names of the definitions above them. (probably not correct?)
I'm currently getting an IllegalArgumentException
Caused by: java.lang.IllegalArgumentException: Cannot convert samplePage.styles of type class java.lang.String to class org.apache.tiles.Attribute
at com.sun.el.lang.ELSupport.coerceToType(ELSupport.java:428)
at com.sun.el.ExpressionFactoryImpl.coerceToType(ExpressionFactoryImpl.java:85)
... 104 more
It appears as if the put-attributes for the styles and scripts are not picking up the definitions of the same name above them... but I'm not sure what to do to correct it. Any ideas?
To answer the question how to reference another definition in put-attribute, this appears to be fairly easy with jsp components such as the following (note the definition, and the 'type' attribute):
<definition name="default.header" template="/WEB-INF/page/common/header.jsp" />
... then elsewhere...
<put-attribute name="header" type="definition" value="default.header" />
However, it doesn't look like this can be done with resources such as stylesheets and scripts, as they don't translate back to an actual template. So, I reworked my base-definition as follows, which still allows me to have 'global' resources, as well as 'page-specific' resources. Also allows me to write the jsp components once, define them once, and reference them many times.
common definitions (tiles.common.xml)
<tiles-definitions>
<definition name="default.header" template="/WEB-INF/page/common/header.jsp" />
<definition name="default.footer" template="/WEB-INF/page/common/footer.jsp" />
[... all the other common components...]
</tiles-definitions>
base definition (tiles.base.xml)
<tiles-definitions>
<definition name="base.definition" template="/WEB-INF/page/baseLayout.jsp" >
<put-attribute name="title" type="string" />
<put-attribute name="header" type="definition" value="default.header" />
<put-attribute name="body" />
<put-attribute name="footer" type="definition" value="default.footer" />
<put-list-attribute name="styles" inherit="true" >
<add-attribute value="/view/common/jquery-ui-theme-base-v1.12.1.css" />
[... other styles common to all pages...]
</put-list-attribute>
<put-list-attribute name="scripts" inherit="true" >
<add-attribute value="https://code.jquery.com/jquery-3.1.0.min.js" />
<add-attribute value="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js" />
[... other scripts common to all pages...]
</put-list-attribute>
</definition>
</tiles-definition>
page specific definition (tiles.samplePage.xml)
<tiles-definitions>
<definition name="samplePage" extends="base.definition" >
<put-attribute name="title" value="Sample Page" />
<put-attribute name="body" value="/WEB-INF/page/samplePage.jsp" />
<put-list-attribute name="styles" inherit="true" >
<add-attribute value="/view/pages/samplePage.css" />
[... other page specific styles ...]
</put-list-attribute>
<put-list-attribute name="scripts" inherit="true" >
<add-attribute value="/view/pages/samplePage.js" />
[... other page specific scripts ...]
</put-list-attribute>
</definition>
</tiles-definition>

tiles:insertAttribute throwing exception

I am trying to build an application having nested tiles.
tiles.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN"
"http://tiles.apache.org/dtds/tiles-config_2_1.dtd">
<tiles-definitions>
<definition name="base.defination" template="/WEB-INF/jsp/layout.jsp">
<put-attribute name="title" value="Ashoka Travels"/>
<put-attribute name="header" value="/WEB-INF/jsp/header.jsp"/>
<put-attribute name="body" value=""/>
<put-attribute name="footer" value="/WEB-INF/jsp/footer.jsp"/>
</definition>
<definition name="transportBody" extends="base.defination">
<put-attribute name="body" value="/WEB-INF/jsp/transportMain.jsp" cascade="true"/>
</definition>
<definition name="booking" extends="transportBody">
<put-attribute name="bookingRadio" value="/WEB-INF/jsp/bookingLayout.jsp" cascade="true"/>
</definition>
<definition name="transportBodyHeader" extends="booking">
<put-attribute name="HeaderBookingTypeSelect" value="/WEB-INF/jsp/primaryPage/bookingTypeSelect.jsp" cascade="true"/>
<put-attribute name="BodyTransportSelector" value="/WEB-INF/jsp/primaryPage/bookingTransportSelect.jsp" cascade="true"/>
<put-attribute name="FooterTransportSelectorBooking" value="/WEB-INF/jsp/primaryPage/bookingTransportSearch.jsp" cascade="true"/>
</definition>
</tiles-definitions>
bookingLayout.jsp
<body>
<div id="transportBookingLayout">
<div><tiles:insertAttribute name="HeaderBookingTypeSelect"/></div>
<div><tiles:insertAttribute name="BodyTransportSelector"/></div>
<div><tiles:insertAttribute name="FooterTransportSelectorBooking"/></div>
</div>
</body>
This is transportMain page which includes another JSP page through <tiles:insertAttribute>:
<body>
<div id="mainTransport" style="border:1px solid red">
<div id="ticketBookingDiv" class="bookTicket" >
<%-- <jsp:include page="/WEB-INF/jsp/primaryPage/hello.jsp" flush="true"/> --%>
<tiles:insertAttribute name="bookingRadio"></tiles:insertAttribute>
</div>
</div>
</body>
I am getting this exception:
Servlet.service() for servlet [SpringMVC] in context with path [/Travels_SpringMVC] threw exception [An exception occurred processing JSP page /WEB-INF/jsp/transportMain.jsp at line 32
29:
30:
31: --%>
32:
33:
34:
35:
Stacktrace:] with root cause
org.apache.tiles.template.NoSuchAttributeException: Attribute 'bookingRadio' not found.
**nested Tiles is working fine.Here is the solution.**
**tiles.xml**<tiles-definitions>
<definition name="base.defination" template="/WEB-INF/jsp/layout.jsp">
<put-attribute name="title" value="Asoka.com"/>
<put-attribute name="header" value="/WEB-INF/jsp/header.jsp"/>
<put-attribute name="body" value=""/>
<put-attribute name="footer" value="/WEB-INF/jsp/footer.jsp"/>
</definition>
<definition name="transportMain" extends="base.defination" >
<put-attribute name="body">
<definition template="/WEB-INF/jsp/transportMain.jsp" name="mainTransport" extends="transportMain">
<put-attribute name="bookingRadio">
<definition template="/WEB-INF/jsp/primaryPage/bookingLayout.jsp" name="layoutBooking" extends="mainTransport">
<put-attribute name="HeaderBookingTypeSelect" value="/WEB-INF/jsp/primaryPage/bookingTypeSelect.jsp" cascade="true"/>
<put-attribute name="BodyTransportSelector" value="/WEB-INF/jsp/primaryPage/bookingTransportSelect.jsp" cascade="true"/>
<put-attribute name="FooterTransportSelectorBooking" value="/WEB-INF/jsp/primaryPage/bookingTransportSearch.jsp" cascade="true"/>
</definition>
</put-attribute>
</definition>
</put-attribute>
</definition>
</tiles-definitions>
**transportMain.jsp**
<form:form commandName="transportBookingForm" modelAttribute="transportBookingForm">
<div id="mainTransport" style="border:1px solid red">
<div id="ticketBookingDiv" class="bookTicket" >
<tiles:insertAttribute name="bookingRadio"/>
</div>
</div>
</form:form>
**At Controller level**
#ModelAttribute("bookingTypeSelect")
public ModelAndView booking(#ModelAttribute BookingTypeSelect bookingTypeSelect){
System.out.println("Entered booking");
return new ModelAndView("bookingTypeSelect" ,"bookingTypeSelect",bookingTypeSelect);
}
**bookingLayout.jsp**
<div id="transportBookingLayout">
<div><tiles:insertAttribute name="HeaderBookingTypeSelect"/></div>
<div><tiles:insertAttribute name="BodyTransportSelector"/></div>
<div><tiles:insertAttribute name="FooterTransportSelectorBooking"/></div>
</div>

tiles 2.1: nesting templates 3 levels deep - attribute isn't replaced

I see PLACEHOLDER on result page instead of edit.jsp page content. Source of tiles-defs.xml listed below.
<definition name="layout" template="/WEB-INF/tiles/layout.jsp">
<put-attribute name="body">
<definition template="/WEB-INF/tiles/user/layout.jsp">
<put-attribute name="userMenu" value="/WEB-INF/tiles/user/menu.jsp"/>
<put-attribute name="userContent">
<definition template="/WEB-INF/tiles/user/profile/layout.jsp">
<put-attribute name="profileNav" value="/WEB-INF/tiles/user/profile/nav.jsp"/>
<put-attribute name="profileContent" value="PLACEHOLDER"/>
</definition>
</put-attribute>
</definition>
</put-attribute>
...
</definition>
<definition name="editUser" extends="layout">
<put-attribute name="profileContent" value="/WEB-INF/jsp/user/auth/edit.jsp"/>
...
</definition>
Also tried to split in 3 separate definitions without any result. Also played with cascade attribute without any result too.
Pls. add to top of /WEB-INF/tiles/user/profile/layout.jsp:
<%#taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>

Get spring.profiles.active in Tiles.xml

Can we recover the active profile in tiles.xml?
I need to display an indicator in the title of the active profile.
web.xml
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>QA</param-value>
</context-param>
Tiles.xml
<definition name="base.layout" template="/WEB-INF/views/layout/layout.jsp">
<put-attribute name="title" value="My title - GET PROFILE ACTIVE HERE" />
<put-attribute name="header" value="/WEB-INF/views/layout/header.jsp" />
<put-attribute name="contentLayout" value="" />
<put-attribute name="footer" value="/WEB-INF/views/layout/footer.jsp" />
</definition>
Why don't you use app.properties as follows?
spring.profiles.active=QA
then in your xml you can use:
<util:properties id="app.properties" location="classpath:application.properties"/>
<definition name="base.layout" template="/WEB-INF/views/layout/layout.jsp">
<put-attribute name="title" value="${spring.profiles.active}"/>
...
</definition>

Nested templates with tiles

I want to have some nested templates with tiles, but without any luck for the moment.
My main template :
[...]
<div id=body><tiles:insertAttribute name="body"/></div>
[...]
My nested template:
[...]
<div id=sub><tiles:insertAttribute name="sub"/></div>
[...]
My view definition:
<tiles-definitions>
<definition name="mainTemplate" template="/mainTemplate.jspx">
</definition>
<definition extends="mainTemplate" name="subTemplate">
<put-attribute name="body" value="/subTemplate.jspx"/>
</definition>
<definition extends="mainTemplate" name="myView">
<put-attribute name="sub" value="blablabla"/>
</definition>
</tiles-definitions>
What I expected :
<div id=body><div id=sub>blablabla</div></div>
What I got :
<div id=body><div id=sub></div></div>
I have seen the documentation on the tiles website about this subject but I can't make it work :(
Actually, "subTemplate" and "myView" are two different definitions extending "mainTemplate" both. From what I understand you want the"myView" tile to be nested inside the "subTemplate" tile.
You could try something like this :
<tiles-definitions>
<definition name="mainTemplate" template="/mainTemplate.jspx">
<definition name="subTemplate" extends="mainTemplate">
<put-attribute name="body">
<definition template="/subTemplate.jspx">
<put-attribute name="myView" value="blablabla" />
</definition>
</put-attribute>
</definition>
</tiles-definition>

Resources