I'm trying to make an application that uses Tiles, Spring, and FreeMarker together. I have the project working with just Tiles and Spring but when I try to use ftl files in my Tiles template I get the error
org.apache.tiles.request.render.NoSuchRendererException: Cannot find a renderer named 'freemarker'
at org.apache.tiles.request.render.BasicRendererFactory.getRenderer(BasicRendererFactory.java:57)
at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:252)
at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:397)
at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:238)
at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:221)
at org.apache.tiles.renderer.DefinitionRenderer.render(DefinitionRenderer.java:59)
at org.springframework.web.servlet.view.tiles3.TilesView.renderMergedOutputModel(TilesView.java:132)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1244)
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1027)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:971)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Thread.java:745)
This is what my tiles template looks like
<!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>
<!-- Default Main Template -->
<definition name=".mainTemplate" template="/templates_ftl/main.ftl" templateType="freemarker">
<put-attribute name="title" value="Permissions Editor" type="string" />
<put-attribute name="footer" value="/templates_ftl/footer.ftl" type="freemarker" />
<put-attribute name="body" value="/templates_ftl/blank.ftl" type="freemarker" />
</definition>
<definition name="login" extends=".mainTemplate">
</definition>
</tiles-definitions>
This is just a small example I'm working on to get FreeMarker working so I can use it with the rest of my project. Here is the controller.
#RequestMapping(value = "/")
public String login(#ModelAttribute("LoginInfo") LoginInfo info, HttpServletRequest request) {
logger.info("First visit to login page");
if (HttpUtility.getInstance().compareSession(request)) {
logger.info("Leaving initial login page with user already logged in, sending to show_roles page");
return "show_roles";
}
logger.info("Leaving initial login page sending to login submit");
return "login";
}
I solved it by adding
<#assign tiles=JspTaglibs["http://tiles.apache.org/tags-tiles"]>
<!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">
to the top of my ftl files
Related
Hi I am very new to Spring MVC. I am trying to create 1 login page with annotation based validation. Since I have kept #NonEmpty for user ID and password, I am expecting when user enters nothing and submit then validation should fail. But my if block(result.hasErrors()) in login controller is not getting executed when user do not enters anything.I have tried different approach but still no good result for me.
LoginController.java
public ModelAndView doLogin(HttpServletRequest request, #Valid #ModelAttribute("user") User user, BindingResult result, Model model) {
if(result.hasErrors()) {
return new ModelAndView("loginForm");
}
}
User.java
public class User {
#NonEmpty
private String userID;
#NonEmpty
private String password;
.
.
.
}
loginForm.jsp
<body>
<form:form modelAtrribute="user" method="POST" commandName="user">
User ID:
<input type="text" name="userID"/>
<form:errors path="userID"/>
Password:
<form:password path="password"/>
<form:errors path="password"/>
<input type="submit" value="Login"/>
</form>
</body>
spring-servlet.xml
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver" id="viewResolver">
<property name="viewClass">
<value>
org.springframework.web.servlet.view.tiles2.TilesView
</value>
</property
</bean>
<bean class="org.springframework.web.servlet.view.tiles2.TilesConfigurer" id="tilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/tiles.xml</value>
</list>
</peroperty>
</bean>
tiles.xml
<tiles-definitions>
<definition name="plain.definition" template="/WEB-INF/plain/plain.jsp">
<put-attribute name="body" value=""></put-attribute>
</definition>
<definition extends="plain.definition" name="loginForm">
<put-attribute name="title" value="Login"></put-attribute>
<put-attribute name="body" value="/WEB-INF/jsp/loginForm.jsp"></put-attribute>
</definition>
</tiles-definitions>
Found solution for this problem. In my spring-servlet.xml I had <context:annotation-config> but not <mvc:annotation-driven />.
<context:annotation-config> supported some annotations but for #Valid I needed <mvc:annotation-driven />. After adding this my validations are running fine.
Though I have not figured out completely differences between these 2 tags.
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?
tl;dr - I want to set a put-attribute in my tiles definitions based on the individual model passed to a view in tiles
I'm trying to create a page to display a user using spring and tiles. Right now my page gets the model fine, but I want the title of the page to include the username (which it would have to get from the model). I've included some excerpts from my code below:
tiles.xml:
<definition name="baseLayout" template="/WEB-INF/jsp/layout/layout.jsp">
<put-attribute name="title" value="FitterBlog" />
<put-attribute name="header" value="/WEB-INF/jsp/layout/header.jsp" />
<put-attribute name="nav" value="/WEB-INF/jsp/layout/nav.jsp" />
<put-attribute name="body" value="" />
<put-attribute name="footer" value="/WEB-INF/jsp/layout/footer.jsp" />
<put-attribute name="ads" value="/WEB-INF/jsp/layout/ads.jsp" />
<put-attribute name="css-layout" value="/FitterBlog/resources/css/layout.css" />
</definition>
<definition name="user/display" extends="baseLayout">
<put-attribute name="title" value="FitterBlog - ${user.username}" />
<put-attribute name="body" value="/WEB-INF/jsp/user/display.jsp" />
</definition>
As you can see, I've tried using the same syntax as I would in a jsp to display the username. ie. I tried using ${user.username} to display the username, however that doesn't work and I just get the text "${user.username}" displayed in the title instead of the actual username.
display.jsp:
//output the username from the user model, this works fine
${user.username}
UserController.java
#RequestMapping(value="display/**")
public ModelAndView displayUser(#ModelAttribute("user") User user, BindingResult result) {
//TODO
//retrieve user number from the URL
//retrieve user from database
//display user details
user.setUsername("Awesome username!");
return new ModelAndView("user/display", "user", user);
}
as you can see, I'm still in heavy development and currently set the username on the user object myself (instead of getting it from the database), but that's beside the point.
After reading a few different sites (also, thanks for the link Ralph, it gave me a place to start) I have found a solution.
Basically what I needed to do was edit my DTD to use version 2.1 and also to use an expression put-attribute instead of a value put-attribute. Here is the relevant part to the tiles.xml file:
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN"
"http://tiles.apache.org/dtds/tiles-config_2_1.dtd">
<definition name="user/view" extends="baseLayout">
<put-attribute name="title" expression="FitterBlog | ${user.username}" />
<put-attribute name="body" value="/WEB-INF/jsp/user/view.jsp" />
</definition>
See this part of the tiles documentation: Expression Language support
It looks like you need to enable the EL-Support first.
I know this is not a complete solution, but I hope this hint helps to resolve the problem. -- If it helps, please post the solution you found.
I'm experimenting with Spring MVC for an upcoming project. I'll need some web pages in the application to render multiple reusable "components" and figured that Tiles should help me accomplish this? Each component would have it's own controller.
The example I've put together is only partially working. It's a page with 3 tiles. The 3rd tile has a controller that's trying to return an ArrayList (via #ModelAttribute annotation) to the client but the ArrayList is empty when the view is included as a tile.
Here's the tiles setup in *-servlet.xml:
<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
<property name="order" value="0"/>
</bean>
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/tiles-config/tiles.xml</value>
</list>
</property>
</bean>
<bean id="viewResolver2" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="order" value="1" />
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
Here's my tiles config (tiles.xml):
<tiles-definitions>
<definition name="parent" template="/WEB-INF/jsp/tiles/parent_layout.jsp">
<put-attribute name="header" value="/WEB-INF/jsp/tiles/header.jsp"/>
<put-attribute name="body" value=""/>
<put-attribute name="recordsSection" value=""/>
<put-attribute name="widgetsSection" value=""/>
</definition>
<definition name="_n/list.htm" extends="parent">
<put-attribute name="recordsSection" value="/WEB-INF/jsp/_n/list.jsp"/>
<put-attribute name="widgetsSection" value="/WEB-INF/jsp/_n/widgets.jsp"/>
</definition>
</tiles-definitions>
Here's the JSP code behind the tile in question. The "widgetsList" expression is what is bound to the controller method but coming back empty when this view is included as a tile.
<%#page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" isELIgnored="false"%>
<%#taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%#taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%#taglib prefix="display" uri="http://displaytag.sf.net" %>
<h3>Widgets</h3>
<p>widgetsList=${widgetsList}</p>
<div id="displaylist">
<display:table id="items" name="${widgetsList}" cellspacing="0" export="true">
<display:column title="Widget ID" property="widgetId"/>
<display:column title="Widget Name" property="widgetName"/>
<display:column title="Widget State" property="widgetState"/>
</display:table>
</div>
Here's the controller:
#Controller
public class WidgetController {
#Autowired
private WidgetDaoImpl widgetDao = new WidgetDaoImpl();
#RequestMapping("_n/widgets.htm")
public String widgets() {
return "_n/widgets.htm";
}
#ModelAttribute("widgetsList")
public ArrayList<Widget> getWidgets() {
System.out.println("executing getWidgets()");
ArrayList<Widget> records = widgetDao.listWidgets();
return records;
}
}
When I access the the view "widgets.jsp" directly, the "widgetsList" attribute gets populated, it's only when it's added as a tile that it returns nothing.
Tiles only gives you a composite view and with Spring MVC a controller can only return one view, in this case a whole tiles-defined page will be returned by a single controller.
I don't have much experience with tiles configuration, but what you're trying to achieve is only possible if you can have controller-mapped URLs (and not JSPs) as tiles elements, so that the tiles processor will invoke the spring controllers for each of the "components".
But since you're talking about components and you seem to need them here, why not start with a component oriented framework (Wicket for instance can easily be integrated with Spring out-of-the box).
A pattern i found great while doing this is using jQuery, ajax and json with tiles. On the pages you want your widgets include a marker div like
<div id="displayWidgets"></>
With jQuery check for this div on page load and if it exists do a json call to the controller for this content.
This approach is great because when you include the javascript below, the controller for each page doesn't need to know about any model information except its own. I use this for populating common information like headers and footers that are dynamic.
$.ready(){
if($('div#displayWidgets')){
$.getJSON('/widgetsList', function(data) {
//loop over json and create your html, url below has great examples
}
}
}
http://api.jquery.com/jQuery.getJSON/
Json tutorial from spring controller using jackson
http://www.mkyong.com/spring-mvc/spring-3-mvc-and-json-example/