Я интегрирую struts2, tiles3 и Freemarker (шаблоны из БД). Интеграция в основном выполняется, но рендеринг freemarker представляет собой результат сразу же, вместо того, чтобы вставлять его содержимое в шаблон в ожидаемом месте.Apache-Tiles3 и Freemarker, где результат freemarker обрабатывается из String, вывод визуализации слишком рано
Любые советы о том, как исправить это?
Ожидаемый результат:
<!DOCTYPE html>
<html>
<body>
<h1>Template</h1>
<strong>A bold statement!</strong><div>a message from the Action...</div><div> I came from: the_location</div><div>a message from the Action...</div>
</body>
</html>
Фактический выход (не отформатирован для удобства чтения, потому что это проблема шаблона, а не HTML вопрос так точность выходных отсчетов):
<strong>A bold statement!</strong><div>a message from the Action...</div><div> I came from: the_location</div>
<!DOCTYPE html>
<html>
<body>
<h1>Template</h1>
</body>
</html>
tiles-defs.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="test_def2" template="/WEB-INF/template/template.jsp">
<put-attribute name="body" value="the_location" type="db_freemarker"/>
</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>
<body>
<h1>Template</h1>
<tiles:insertAttribute name="body"/>
</body>
</html>
создал и зарегистрировал DbFreemarkerTilesRenderer с ключом "db_freemarker", это реализация DbFreemarkerTilesRenderer:
package com.quaternion.struts2.result.freemarker;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.tiles.request.Request;
import org.apache.tiles.request.freemarker.render.FreemarkerRenderer;
import org.apache.tiles.request.render.CannotRenderException;
import org.apache.tiles.request.servlet.ServletRequest;
public class DbFreemarkerTilesRenderer extends FreemarkerRenderer{
public DbFreemarkerTilesRenderer(){
super(null); //Expects a AttributeValueFreemarkerServlet
}
/** {@inheritDoc} */
@Override
public void render(String location, Request request) throws IOException {
if (location == null) {
throw new CannotRenderException("Cannot dispatch a null path");
}
ServletRequest servletRequest = org.apache.tiles.request.servlet.ServletUtil.getServletRequest(request);
HttpServletRequest httpRequest = servletRequest.getRequest();
HttpServletResponse httpResponse = servletRequest.getResponse();
DataBaseTemplateLoader dataBaseTemplateLoader = new DataBaseTemplateLoader();
try {
dataBaseTemplateLoader.render(location, httpRequest, httpResponse);
} catch (Exception ex) {
Logger.getLogger(DbFreemarkerTilesRenderer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
«DataBaseTemplateLoader» фактически загружает шаблон freemarker из жестко закодированной строки, но он будет загружаться из базы данных после того, как эта проблема будет res olved (см визуализацииметод остальная часть класса входит в контекст, разработчики Struts2 распознает его как тип результата, идея в том, функциональность Freemarker DB могут быть предоставлены непосредственно Struts2 как результат):
package com.quaternion.struts2.result.freemarker;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.inject.Inject;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.ServletDispatcherResult;
import org.apache.struts2.views.freemarker.FreemarkerManager;
import org.apache.struts2.views.util.ContextUtil;
public class DataBaseTemplateLoader extends ServletDispatcherResult {
private static final Logger log = Logger.getLogger(DataBaseTemplateLoader.class.getName());
private String defaultEncoding = "ISO-8859-1"; //TODO: Hardcoded?
private FreemarkerManager freemarkerManager;
private Configuration configuration;
//Inject works if this is a Struts2 component (Result) however
//when using this from Tiles, the following is not injected...
@Inject
public void setFreemarkerManager(FreemarkerManager mgr) {
this.freemarkerManager = mgr;
}
public DataBaseTemplateLoader() {
super();
}
public DataBaseTemplateLoader(String location) {
super(location); //TODO: look up template based on "location" string
}
protected Configuration getConfiguration() throws TemplateException {
if (freemarkerManager == null){
//Force injection
freemarkerManager = ActionContext.getContext().getContainer().getInstance(FreemarkerManager.class);
}
return freemarkerManager.getConfiguration(ServletActionContext.getServletContext());
}
@Override
public void doExecute(String location, ActionInvocation invocation) throws Exception {
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
render(location, request, response);
}
public void render(String location, HttpServletRequest request, HttpServletResponse response) throws Exception {
//location is String passed from Struts2 action which will formated
//in such a way to apply conventions though to view
//Format: namespace#action#method
//setLocation(location);
StringTemplateLoader stringLoader = new StringTemplateLoader();
//BOTH "name" and "source" will be retrieved from the DB
String name = "firstTemplate";
String source = "<strong>A bold statement!</strong><div>${action.message}</div><div> I came from: " + location + "</div>";
stringLoader.putTemplate(name, source);
// It's possible to add more than one template (they might include each other)
// String secondTemplate = "<#include \"greetTemplate\"><@greet/> World!";
// stringLoader.putTemplate("greetTemplate", secondTemplate);
freemarker.template.Configuration cfg = getConfiguration();
cfg.setTemplateLoader(stringLoader);
Template template = cfg.getTemplate(name);
Map map = ContextUtil.getStandardContext(ActionContext.getContext().getValueStack(), request, response);
response.setContentType("text/html;charset=" + defaultEncoding);
template.process(map, response.getWriter());
}
}
Struts2 Действие (не требуется, просто показывает, где "сообщение от действий ..." приходит от:
package com.quaternion.tilesdb.action;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
/**
* Tests Tiles with Freemarker integration, where the freemarker template
* is parsed from a String, this is to allow later integration with freemarker
* database templates
*/
@ParentPackage("quaternion-results")
@Result(type="tiles", location="test_def2")
public class TilesFtlTest2 extends ActionSupport{
private String message = "a message from the Action...";
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
У вас есть SSCCE на GitHub/и т.д.? –
Пока не я. – Quaternion