I am using spring mvc 3 and tiles 2 with wildcard definitions. I want to load additional css and javascript files inside some of my tiles. Is there way to do this? Preferably in tile jsp file, not in tiles-definitions.xml.
This is a good question because one of the main benefits of tiles is the central view it provides with regards to composition. It would be really nice if this centralization could also include CSS & JS files as well.
It happens that this is possible, here is an example. This example uses tiles3 however it should be pretty simple to adapt to tiles-2 (tiles three lets you use multiple types of expressions) you can side step this.
Also note that I use Struts2 as my action framework, this is not an issue but as I'm going to use a working example you'll know the "OGNL:" prefixed expression means that the EL Struts2 uses will be used. You should also know that if you upgrade to Tiles-3 you can also use Spring EL by prefixing your expressions with "MVEL:".
tiles.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN" "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
<definition name="default" template="/WEB-INF/template/template.jsp">
<put-list-attribute name="cssList" cascade="true">
<add-attribute value="/style/cssreset-min.css" />
<add-attribute value="/style/cssfonts-min.css" />
<add-attribute value="/style/cssbase-min.css" />
<add-attribute value="/style/grids-min.css" />
<add-attribute value="/script/jquery-ui-1.8.24.custom/css/ui-lightness/jquery-ui-1.8.24.custom.css" />
<add-attribute value="/style/style.css" />
</put-list-attribute>
<put-list-attribute name="jsList" cascade="true">
<add-attribute value="/script/jquery/1.8.1/jquery.min.js" />
<add-attribute value="/script/jquery-ui-1.8.24.custom/js/jquery-ui-1.8.24.custom.min.js" />
<add-attribute value="/script/jquery.sort.js" />
<add-attribute value="/script/custom/jquery-serialize.js" />
</put-list-attribute>
<put-attribute name="title" value="defaults-name" cascade="true" type="string"/>
<put-attribute name="head" value="/WEB-INF/template/head.jsp"/>
<put-attribute name="header" value="/WEB-INF/template/header.jsp"/>
<put-attribute name="body" value="/WEB-INF/template/body.jsp"/>
<put-attribute name="footer" value="/WEB-INF/template/footer.jsp"/>
</definition>
<definition name="REGEXP:\/recruiter#candidate-input\.(.*)" extends="default">
<put-list-attribute name="cssList" cascade="true" inherit="true">
<add-attribute value="/style/recruiter/candidate-input.css" />
</put-list-attribute>
<put-list-attribute name="jsList" cascade="true" inherit="true">
<add-attribute value="/script/widgets/resume/resume.js" />
</put-list-attribute>
<put-attribute name="body" value="/WEB-INF/content/recruiter/candidate-input.jsp"/>
</definition>
<definition name="REGEXP:(.*)#(.*)" extends="default">
<put-attribute name="title" cascade="true" expression="OGNL:#com.opensymphony.xwork2.ActionContext#getContext().name"/>
<put-attribute name="body" value="/WEB-INF/content{1}/{2}"/>
</definition>
</tiles-definitions>
/WEB-INF/template/template.jsp
<%#taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>
<%#taglib prefix="s" uri="/struts-tags"%>
<%#page contentType="text/html" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<tiles:insertAttribute name="head"/>
<body>
<%-- website header --%>
<div id="wrapper">
<div id="content">
<tiles:insertAttribute name="header"/>
<tiles:insertAttribute name="body"/>
<div class ="outer content">
<tiles:insertAttribute name="footer"/>
</div>
</div>
</div>
</body>
</html>
This is the important part getting the lists of CSS files and JS files into the head tile:
/WEB-INF/template/head.jsp
<%#taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles"%>
<%#taglib prefix="s" uri="/struts-tags"%>
<%#taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<tiles:importAttribute name="cssList"/><tiles:importAttribute name="jsList"/>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<s:iterator value="#attr.cssList" var="cssValue">
<link href="<s:url value="%{cssValue}"/>" rel="stylesheet" type="text/css">
</s:iterator>
<s:iterator value="#attr.jsList" var="jsValue">
<script src="<s:url value="%{jsValue}"/>"></script>
</s:iterator>
<title><tiles:insertAttribute name="title" defaultValue="no title"/></title>
</head>
I think you can figure out the rest. Sorry about the <s:iterator> tags in the last block, I'm not sure of the Spring equivalent nor would I be inclined to test it. But should you translate this to Spring, it would be great for you to self answer here. I'd happily up vote it.
In dispatcher-servlet.xml provide mvc static resource mapping as following :
<!-- static resource mapping for style sheets, etc. -->
<mvc:resources mapping="/styles/**" location="/WEB-INF/skins/" />
<mvc:resources mapping="/scripts/**" location="/WEB-INF/scripts/" />
And on your tiles-layout.jsp file you can access them all by writing
<script type="text/javascript" src="${context}/scripts/jquery-1.7.js></script>
<link rel="stylesheet" type="text/css" href="${context}/styles/css/superfish.css">
See: mvc:resources
That is how I did with Spring, the rest is just like Quaternion posted.
/WEB-INF/template/head.jsp
<tiles:importAttribute name="cssList"/>
<tiles:importAttribute name="jsList"/>
<head>
<c:forEach var="cssValue" items="${cssList}">
<link type="text/css" rel="stylesheet" href="<c:url value="${cssValue}"/>" />
</c:forEach>
<c:forEach var="jsValue" items="${jsList}">
<script src="<c:url value="${jsValue}"/>"></script>
</c:forEach>
</head>
And don't forget to point on each page the right definition from tiles.xml
<tiles:insertDefinition name="definitionName">
<tiles:putAttribute name="body">
//content
</tiles:putAttribute>
</tiles:insertDefinition>
Related
I'm trying to run simple Seam PageFlow example NumberGuss. I have deployed it on Jboss Server. When I access the URL it lands on the first page but if I hit any of the button provided on that page it says "The page isn't redirecting properly".On server log I found
SEVERE [javax.enterprise.resource.webcontainer.jsf.application] (default task-16) Error Rendering View[/debug.xhtml]: org.jboss.weld.context.NonexistentConversationException: WELD-000321: No conversation found to restore for id 1.
I'm using wildfly-8.1.0 and jboss-seam-2.3.1
Attaching pageflow.jpdl.xml and numberGuess.xhtml for reference. Please help me resolve the issue I'm facing.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:s="http://jboss.org/schema/seam/taglib">
<h:head>
<title>Guess a number...</title>
<link href="niceforms.css" rel="stylesheet" type="text/css" />
<script language="javascript" type="text/javascript" src="niceforms.js"><!-- --></script>
</h:head>
<body>
<h1>Guess a number...</h1>
<h:form id="NumberGuessMain" styleClass="niceform">
<div>
<h:messages id="messages" globalOnly="true"/>
<h:outputText id="Higher"
value="Higher!"
rendered="#{numberGuess.randomNumber gt numberGuess.currentGuess}"/>
<h:outputText id="Lower"
value="Lower!"
rendered="#{numberGuess.randomNumber lt numberGuess.currentGuess}"/>
</div>
<div>
I'm thinking of a number between <h:outputText id="Smallest" value="#{numberGuess.smallest}"/> and
<h:outputText id="Biggest" value="#{numberGuess.biggest}"/>. You have
<h:outputText id="RemainingGuesses" value="#{numberGuess.remainingGuesses}"/> guesses.
</div>
<div>
Your guess:
<h:inputText id="inputGuess" value="#{numberGuess.currentGuess}" required="true" size="3"
rendered="#{(numberGuess.biggest-numberGuess.smallest) gt 20}">
<f:validateLongRange maximum="#{numberGuess.biggest}"
minimum="#{numberGuess.smallest}"/>
</h:inputText>
<h:selectOneMenu id="selectGuessMenu" value="#{numberGuess.currentGuess}" required="true" rendered="#{numberGuess.selectMenuRendered}">
<s:selectItems id="PossibilitiesMenuItems" value="#{numberGuess.possibilities}" var="i" label="#{i}"/>
</h:selectOneMenu>
<h:selectOneRadio id="selectGuessRadio" value="#{numberGuess.currentGuess}" required="true" rendered="#{numberGuess.radioButtonRendered}">
<s:selectItems id="PossibilitiesRadioItems" value="#{numberGuess.possibilities}" var="i" label="#{i}"/>
</h:selectOneRadio>
<h:commandButton id="GuessButton" value="Guess" action="guess"/>
<s:button id="CheatButton" value="Cheat" action="cheat"/>
<s:button id="GiveUpButton" value="Give up" action="giveup"/>
</div>
<div>
<h:message id="message" for="inputGuess" style="color: red"/>
</div>
</h:form>
</body>
</html>
<!--
An example of pageflow in jPDL. This exemplifies the
approach where action handlers are attached transitions
and decision nodes, instead of view components.
An alternative approach would be to attach all action
handlers to view components, and let the jPDL define
only the navigation rules.
-->
<pageflow-definition
xmlns="http://jboss.org/schema/seam/pageflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://jboss.org/schema/seam/pageflow http://jboss.org/schema/seam/pageflow-2.3.xsd"
name="numberGuess">
<start-page name="displayGuess" view-id="/numberGuess.xhtml">
<redirect/>
<transition name="guess" to="evaluateGuess">
<action expression="#{numberGuess.guess}"/>
</transition>
<transition name="giveup" to="giveup"/>
<transition name="cheat" to="cheat"/>
</start-page>
<decision name="evaluateGuess" expression="#{numberGuess.correctGuess}">
<transition name="true" to="win"/>
<transition name="false" to="evaluateRemainingGuesses"/>
</decision>
<decision name="evaluateRemainingGuesses" expression="#{numberGuess.lastGuess}">
<transition name="true" to="lose"/>
<transition name="false" to="displayGuess"/>
</decision>
<page name="giveup" view-id="/giveup.xhtml">
<redirect/>
<transition name="yes" to="lose"/>
<transition name="no" to="displayGuess"/>
</page>
<process-state name="cheat">
<sub-process name="cheat"/>
<transition to="displayGuess"/>
</process-state>
<page name="win" view-id="/win.xhtml">
<redirect/>
<end-conversation/>
</page>
<page name="lose" view-id="/lose.xhtml">
<redirect/>
<end-conversation/>
</page>
</pageflow-definition>
Resolved the issue.Weld is scanning the archive, which seems to cause the problem.The Weld Docs says:
You can either set this up for your deployment only by adding the following content to the META-INF/jboss-all.xml file of your application.
jboss-all.xml file goes to your META-INF for ear archive and likely to WEB-INF for war archive
<jboss xmlns="urn:jboss:1.0">
<weld xmlns="urn:jboss:weld:1.0" require-bean-descriptor="true"/>
</jboss>
It worked for me.
I wanted to create the seperate css files and wanted to use it, Instead of duplicating the css file again.
Using this method i can reuse the cssfilecommon.html by calling it and also if i want some other css required i can add it in the seperate page and call only for that page
<tiles:insertAttribute name="cssfilecommon" /> - common css file
<tiles:insertAttribute name="pagespecific" /> - some other css file
--
can we do this, please let me know if any one tried..
layout file
<!DOCTYPE html>
<html xmlns:tiles="http://www.thymeleaf.org">
<head>
**<tiles:insertAttribute name="cssfile" />**
</head>
<body>
<div tiles:include="header">Header Block</div>
<div tiles:substituteby="body">Body Block</div>
<div tiles:substituteby="footer">Footer Block</div>
</body>
</html>
titles-def.xml file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
"http://struts.apache.org/dtds/tiles-config_2_0.dtd">
<tiles-definitions>
<definition name="home" template="basiclayout/layout" >
<put-attribute name="cssfilecommon" value="bout/cssfilecommon"/>
<put-attribute name="header" value="bout/header"/>
<put-attribute name="menu" value="bout/Menu"/>
<put-attribute name="footer" value="bout/footer"/>
</definition>
--
cssfilecommon.html
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<link href="css/jquery-ui-1.10.3.custom.css" th:href="#{css/jquery-ui-1.10.3.custom.css}" rel="stylesheet" type="text/css" />
<link href="css/ui.jqgrid.css" th:href="#{css/ui.jsd.css}" rel="stylesheet" type="text/css"/>
Yes, with plain tiles you could do this:
Layout file:
<head>
<tiles:insertAttribute name="cssfilecommon" />
<tiles:insertAttribute name="pagespecific" ignore="true" />
</head>
titles-def.xml file:
<definition name="home" template="basiclayout/layout" >
<put-attribute name="cssfilecommon" value="bout/cssfilecommon"/>
<put-attribute name="pagespecific" value="bout/pagespecific"/>
...
</definition>
Note the usage of ignore attribute:
If this attribute is set to true, and the attribute specified by the
name does not exist, simply return without writing anything. The
default value is false, which will cause a runtime exception to be
thrown.
But, as I see you are using Thymeleaf, which probably doesn't support it yet: #17
A other smart suggestion, you can declare in your tiles-def.xml an list and in this list you can simple push all your css files you need in your site, just like this:
<put-list-attribute name="jsList" cascade="true">
<add-attribute value="/Project/basic/css/basic.css" />
<add-attribute value="/Project/case2/css/example2.js" />
<add-attribute value="/Project/special/css/example3.css" />
</put-list-attribute>
after this in your jsp file you can easily iterate over your list with the following (You need the jstl taglib):
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
...
<tiles:importAttribute name="cssList"/>
...
<c:forEach items="${cssList}" var="cs">
<link href="${cs}" rel="stylesheet" type="text/css" media="screen">
</c:forEach>
i know it's like the same what #Slava Semushin say but i would that you know you can work with lists.
For example if you work with jqxwidgets you need to bind special javascripts for the elements and if you don't need all the javascript for each site, you can handle this case, with this suggestion.
If inside a controller I set
model.addAttribute("page-title", "Home");
and I would like to have it on a tiles laytou.jsp like this:
<title><tiles:getAsString name="page-title"/></title>
what should I do?
Write a preparer?
to the preparer de put-attribute definition doesn't matter so looks like it makes no sense.
Just add a <put-attribute name="page-title" value="${page-title}"/>
into definition?
When I do this I just get "${page-title} - My Website" as output. EL is not been evaluated.
So please, what's the best practice and how to make it work?
tiles-defs.xml:
<tiles-definitions>
<definition name="baseLayout" template="/WEB-INF/pages/common/layout.jsp">
<put-attribute name="website-title" value="My Website"/>
<put-attribute name="page-title" expression="Default Title"/>
<put-attribute name="header" value="/WEB-INF/pages/common/header.jsp"/>
<put-attribute name="body" value=""/>
<put-attribute name="footer" value="/WEB-INF/pages/common/footer.jsp"/>
</definition>
<definition name="*" extends="baseLayout">
<put-attribute name="page-title" value="${page-title}"/>
<put-attribute name="body" value="/WEB-INF/pages/{1}.jsp"/>
</definition>
</tiles-definitions>
layout.jsp:
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%# taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%# taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="language" content="English" />
<title><tiles:getAsString name="page-title"/> - <tiles:getAsString name="website-title"/></title>
<link rel="stylesheet" type="text/css" href="<c:url value="/resources/css/style.css" />" media="all"/>
</head>
<body>
<div id="container">
<!-- header -->
<tiles:insertAttribute name="header"/>
<!-- main central container -->
<tiles:insertAttribute name="body"/>
<!-- footer -->
<tiles:insertAttribute name="footer"/>
</div>
</body>
</html>
homeController.java:
#Controller
public class HomeController {
#RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView home(Locale locale, Model model) {
ModelAndView mav = new ModelAndView();
mav.setViewName("home");
model.addAttribute("page-title", "Home");
return mav;
}
}
servlet-context.xml:
<beans:bean id="tilesviewResolver" class="org.springframework.web.servlet.view.tiles2.TilesViewResolver" p:order="0"/>
<beans:bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<beans:property name="definitions" value="/WEB-INF/tiles/tiles-defs.xml"/>
</beans:bean>
pom.xml:
<!-- Tiles -->
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-jsp</artifactId>
<version>2.2.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-el</artifactId>
<version>2.2.2</version>
</dependency>
Just use pure EL without Tiles. Model attributes are placed on request as attributes (HttpServletRequest#getAttribute) under their name. This is accessible via requestScope['page-title'] or just simply by attribute name itself:
<title><c:out value="${page-title}" /></title>
<title>${page-title} - without HTML escaping provided by c:out</title>
This has nothing to do with Tiles. You don't need to take Tiles into account when working with model / request attributes.
Pavei is right, in your use case it's not obvious why you need to put the request attribute in as a tiles attribute.
If you really do need it as a tiles attribute then do it like
<put-attribute name="page-title" expression="${page-title}"/>
My English is poor. And I haven't use tiles2.x in my project, I use tiles3.x. If you want to use expression language support, first you should enable CompleteAutoloadTilesContainerFactory.
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/tiles/tiles-defs.xml</value>
</list>
</property>
<!--enable CompleteAutoloadTilesContainerFactory -->
<property name="completeAutoload" value="true"></property>
</bean>
then you have to configure defintions like this .
<definitions name="*" extends="baseLayout">
<put-attribute name="page-title" expression="${page-title}" />
<put-attribute name="body" value="/WEB-INF/pages/{1}.jsp" />
</definitions>
Tiles Document https://tiles.apache.org/framework/tutorial/advanced/el-support.html
Good luck to you .
Let's recap:
The EL language is supported since Tiles 2.1 without extra configuration.
If we use Tiles 3.x, we should:
Adding this dependency to pom:
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-extras</artifactId>
<version>3.0.5</version>
</dependency>
Enabling CompleteAutoloadTilesContainerFactory:
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/tiles/tiles-defs.xml</value>
</list>
</property>
<!--enable CompleteAutoloadTilesContainerFactory -->
<property name="completeAutoload" value="true"></property>
</bean>
I want put "title" attribute from JSP to template and replace default value.
Template:
<%#taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles"%>
<!doctype html>
<head>
<meta charset="utf-8">
<title><tiles:getAsString name="title" /></title>
</head>
<body>
...
</body>
</html>
Definition:
<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN" "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
<definition name="*/*" template="/WEB-INF/tiles/layout.jsp">
<put-attribute name="title" value="default value" />
...
</definition>
</tiles-definitions>
JSP:
<%#taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles"%>
<tiles:putAttribute name="title" value="Login" />
...
And my title are still "default value" - why?
I'm presuming that the "template" refers to "/WEB-INF/tiles/layout.jsp"
But what is the filename of "JSP", and where is it included?
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