我正在集成 struts2、tiles3 和 Freemarker(来自数据库的模板)。集成已基本完成,但 freemarker 渲染器会立即渲染结果,而不是将其内容插入到模板中预期位置的位置。
关于如何纠正这个问题的任何建议?
预期输出:
<!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>
瓷砖-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>
使用键“db_freemarker”创建并注册了一个 DbFreemarkerTilesRenderer,这是 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 模板,但是一旦解决了这个问题,它将从数据库中加载(请参阅渲染 方法,该类的其余部分包含在上下文中,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;
}
}