最近在客户需求的要求就定制开发一套CMS,模板采用了Freemarker。最初的时候是设想用Freemarker标签开发的模板,也做网站页面的模板。然后可以直接在页面模板中使用开发好的标签,来显示网站内容。但总还是觉得这样的模板不够灵活,局限性比较大。后来通过和领导的商议决定采用一下方式,最终可以直接在Freemarker页面模板层对已封装好的API进行调用,可以实现在模板中的简单编程。
这种做法也是在探索中,如果大家觉得有什么不妥之处还望点拨。
- 模板存放在数据库中(通常我们都是编写Freemarker的ftl模板文件)
- 采用StringTemplateLoader
- 采用BeansWrapper
首先我们要开发一个Servlet去拦截网站的请求,因为我们要去解析模板。FreeMarker为我们提供了一个现成的Servlet:freemarker.ext.servlet.FreemarkerServlet。但是这个不能满足我们的要求,它是按照URL请求的文件名称来去查找解析模板的,例如/article/demo.ftl,那么它只能去模板存放目录寻找demo.ftl模板。呵呵,其实这个 Servlet是未来让FreeMarker代替jsp使用的,而且他的它也无法装载数据库中的模板信息,所以我就参考它开发了自己的Servlet。
package freemarker.ext.servlet;
/**
* 参考自freemarker.ext.servlet.FreemarkerServlet
* 支持自定义标签的使用,支持自定义扩展名拦截.
*/
public class FreeMarkerStringTemplateViewServlet extends
javax.servlet.http.HttpServlet {
/**
* 为子类提供Log功能,方便子类使用
*/
protected Log log = LogFactory.getLog(getClass());
/** TemplatePath */
private static final String TEMPLATE_PATH = "TemplatePath";
/** NoCache */
private static final String NOCACHE = "NoCache";
/** TemplateDelay */
private static final String TEMPLATE_DELAY = "template_update_delay";
/** DefaultEncoding */
private static final String DEF_ENCODING = "default_encoding";
/** Request */
public static final String KEY_REQUEST = "Request";
/** __FreeMarkerServlet.Request__ */
public static final String KEY_REQUEST_PRIVATE =
"__FreeMarkerServlet.Request__";
/** RequestParameters */
public static final String KEY_REQUEST_PARAMETERS = "RequestParameters";
/** Session */
public static final String KEY_SESSION = "Session";
/** Application */
public static final String KEY_APPLICATION = "Application";
/** __FreeMarkerServlet.Application__ */
public static final String KEY_APPLICATION_PRIVATE =
"__FreeMarkerServlet.Application__";
/** JspTaglibs */
public static final String KEY_JSP_TAGLIBS = "JspTaglibs";
/** .freemarker.Request */
private static final String ATTR_REQUEST_MODEL = ".freemarker.Request";
/** .freemarker.RequestParameters */
private static final String ATTR_REQUEST_PARAMETERS_MODEL =
".freemarker.RequestParameters";
/** .freemarker.Session */
private static final String ATTR_SESSION_MODEL = ".freemarker.Session";
/** .freemarker.Application */
private static final String ATTR_APPLICATION_MODEL =
".freemarker.Application";
/** .freemarker.JspTaglibs */
private static final String ATTR_JSP_TAGLIBS_MODEL =
".freemarker.JspTaglibs";
/** 日期 */
private static final String EXPIRATION_DATE;
static {
GregorianCalendar expiration = new GregorianCalendar();
expiration.roll(Calendar.YEAR, -1);
SimpleDateFormat httpDate = new SimpleDateFormat(
"yyyy-MMM-dd HH:mm:ss", java.util.Locale.CHINA);
EXPIRATION_DATE = httpDate.format(expiration.getTime());
}
/**
* response返回是否使用缓存
*/
private boolean nocache;
/**
* 创新Freemarker模板的必要条件
*/
private Configuration config;
/**
* 采用BEANS_WRAPPER
*/
private ObjectWrapper wrapper;
/**
* text/html
*/
private String contentType;
/**
* 采用StringLoader,从数据库中读取模板信息
*/
//private StringTemplateLoader strTmpt;
/**
* Servlet 初始化
*/
public void init() throws ServletException {
try {
config = new Configuration();
config.setTemplateExceptionHandler(
TemplateExceptionHandler.HTML_DEBUG_HANDLER);
contentType = "text/html";
// 采用BEANS_WRAPPER
wrapper = ObjectWrapper.BEANS_WRAPPER;
config.setObjectWrapper(wrapper);
// 初始化所有的Servlet参数
Enumeration initpnames = getServletConfig().getInitParameterNames();
while (initpnames.hasMoreElements()) {
String name = (String) initpnames.nextElement();
String value = getInitParameter(name);
if (name == null) {
throw new ServletException(this.getClass().toString()
+ "需要一些初始化参数,web.xml可能尚未完成.");
}
if (value == null) {
throw new ServletException(this.getClass().toString()
+ "有部分初始化参数未被赋值,web.xml可能尚未完成.");
}
if (name.equals(TEMPLATE_PATH)) {
// ignore: we have already processed these do nothing..
log.debug("忽略" + TEMPLATE_PATH);
} else if (name.equals(DEF_ENCODING)) { // set DefaultEncoding
log.debug(DEF_ENCODING + " value is:" + value);
config.setDefaultEncoding(value);
} else if (name.equals(TEMPLATE_DELAY)) { // 模板延迟更新时间
try {
log.debug(TEMPLATE_DELAY + " value is:" + value);
config.setTemplateUpdateDelay(Integer.parseInt(value));
} catch (NumberFormatException e) {
throw new ServletException(e.getMessage() + ". '"
+ TEMPLATE_DELAY + "'必须是整数");
}
} else if (name.equals(NOCACHE)) { // 设置缓存
log.debug(NOCACHE + " value is :" + value);
nocache = StringUtil.getYesNo(value);
} else {
// 设置其它参数,嘿嘿,如果参数名称不符合Configuration要求肯定要Exception
config.setSetting(name, value);
}
}
} catch (ServletException e) {
throw e;
} catch (Exception e) {
throw new ServletException(e);
}
}
/** Get请求 */
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
process(request, response);
}
/** Post请求 */
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
process(request, response);
}
/**
* 向StringTemplateLoader中添加模板内容
* @throws ServletException
*/
private StringTemplateLoader addStringTemplate(
StringTemplateContext strTmpCtx) throws ServletException {
if (strTmpCtx == null) {
throw new ServletException("StringTemplateContext is null");
}
if (strTmpCtx.getTemplateContent() != null) {
StringTemplateLoader stl = getStrTmpt();
stl.putTemplate(strTmpCtx.getTemplateName(),
strTmpCtx.getTemplateContent());
setStrTmpt(stl);
//重写添加TemplateLoader
log.debug("StringTemplateLoader成功添加模板'"
+ strTmpCtx.getTemplateName() + "'");
}
return getStrTmpt();
}
/**
* 模板解析过程
* @throws ParseURLToTemplateException
*/
private void process(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
StringTemplateLoader strTmpt = getStrTmpt();
if (strTmpt == null) {
strTmpt = new StringTemplateLoader();
setStrTmpt(strTmpt);
}
// 自定义类型StringTemplateContext,存放[模板名称]和[模板内容]
StringTemplateContext strTmpCtx = null;
try {
strTmpCtx = reqUrlToModelCtx(req, strTmpt);
} catch (ParseURLToTemplateException pe) {
resp.sendError(HttpServletResponse.SC_NOT_FOUND);
pe.printStackTrace();
}
//添加模板
strTmpt = addStringTemplate(strTmpCtx);
config.setTemplateLoader(strTmpt);
Template template = config.getTemplate(strTmpCtx.getTemplateName());
Object attrContentType = template.getCustomAttribute("content_type");
if (attrContentType != null) {
resp.setContentType(attrContentType.toString());
} else {
resp.setContentType(contentType + "; charset="
+ template.getEncoding());
}
setBrowserCaching(resp);
ServletContext servletContext = getServletContext();
try {
TemplateModel model = createModel(wrapper, servletContext, req,
resp, strTmpCtx.getModel());
template.process(model, resp.getWriter());
} catch (TemplateException te) {
ServletException e = new ServletException(
"Error executing FreeMarker template", te);
try {
e.getClass().getMethod("initCause",
new Class[] { Throwable.class }).invoke(e,
new Object[] { te });
} catch (Exception ex) {
// Can't set init cause, we're probably running on a pre-1.4
// JDK, oh well...
}
throw e;
}
}
/**
* 创建Freemarker模板的model
*/
protected TemplateModel createModel(ObjectWrapper wrap,
ServletContext servletContext, HttpServletRequest request,
HttpServletResponse response, Map model)
throws TemplateModelException {
AllHttpScopesHashModel params = new AllHttpScopesHashModel(wrap,
servletContext, request);
// Create hash model wrapper for servlet context (the application)
ServletContextHashModel servletContextModel =
(ServletContextHashModel) servletContext
.getAttribute(ATTR_APPLICATION_MODEL);
if (servletContextModel == null) {
servletContextModel = new ServletContextHashModel(this, wrap);
servletContext.setAttribute(ATTR_APPLICATION_MODEL,
servletContextModel);
TaglibFactory taglibs = new TaglibFactory(servletContext);
servletContext.setAttribute(ATTR_JSP_TAGLIBS_MODEL, taglibs);
}
params.putUnlistedModel(KEY_APPLICATION, servletContextModel);
params.putUnlistedModel(KEY_APPLICATION_PRIVATE, servletContextModel);
params.putUnlistedModel(KEY_JSP_TAGLIBS, (TemplateModel) servletContext
.getAttribute(ATTR_JSP_TAGLIBS_MODEL));
// Create hash model wrapper for session
HttpSessionHashModel sessionModel;
HttpSession session = request.getSession();
sessionModel = (HttpSessionHashModel) session
.getAttribute(ATTR_SESSION_MODEL);
if (sessionModel == null || sessionModel.isZombie()) {
sessionModel = new HttpSessionHashModel(session, wrap);
session.setAttribute(ATTR_SESSION_MODEL, sessionModel);
}
params.putUnlistedModel(KEY_SESSION, sessionModel);
// Create hash model wrapper for request
HttpRequestHashModel requestModel = (HttpRequestHashModel) request
.getAttribute(ATTR_REQUEST_MODEL);
if (requestModel == null || requestModel.getRequest() != request) {
requestModel = new HttpRequestHashModel(request, response, wrap);
request.setAttribute(ATTR_REQUEST_MODEL, requestModel);
request.setAttribute(ATTR_REQUEST_PARAMETERS_MODEL,
new HttpRequestParametersHashModel(request));
}
params.putUnlistedModel(KEY_REQUEST, requestModel);
params.putUnlistedModel(KEY_REQUEST_PRIVATE, requestModel);
// Create hash model wrapper for request parameters
HttpRequestParametersHashModel requestParametersModel =
(HttpRequestParametersHashModel) request
.getAttribute(ATTR_REQUEST_PARAMETERS_MODEL);
params.putUnlistedModel(KEY_REQUEST_PARAMETERS, requestParametersModel);
params.putAll(model);
return params;
}
/**
* 需要有自类重写,返回需要的TemplateModelContext[templateName Model]
*
* @return
* @throws ParseURLToTemplateException
* @throws Exception
*/
protected StringTemplateContext reqUrlToModelCtx(HttpServletRequest req,
StringTemplateLoader tmLoader) throws ParseURLToTemplateException {
// 需要子类去重写,完成封装数据
return null;
}
/**
* If the parameter "nocache" was set to true, generate a set of headers
* that will advise the HTTP client not to cache the returned page.
*/
private void setBrowserCaching(HttpServletResponse res) {
if (nocache) {
// HTTP/1.1 + IE extensions
res.setHeader("Cache-Control",
"no-store, no-cache, must-revalidate, "
+ "post-check=0, pre-check=0");
// HTTP/1.0
res.setHeader("Pragma", "no-cache");
// Last resort for those that ignore all of the above
res.setHeader("Expires", EXPIRATION_DATE);
}
}
/**
* getter strTmpt
* @return
*/
private StringTemplateLoader getStrTmpt() {
return (StringTemplateLoader) getServletContext().getAttribute(
"stringTemplateLoader");
}
/**
* setter strTmpt
* @param strTmpt
*/
private void setStrTmpt(StringTemplateLoader strTmpt) {
getServletContext().setAttribute("stringTemplateLoader", strTmpt);
}
}
未完待续....就像这人世间错综复杂、乱七八糟的种种破事
分享到:
相关推荐
Magnolia 是一种开放式 Java 内容管理系统,可在企业规模上...支持 Freemarker、JSP 或自定义模板语言 支持各种工作区(脚本、资源、模板)的 WebDAV 用于用户生成内容的公共用户注册模块 自动生成菜单、网站地图等)
//这个模板就是自己声明的,即content_list.html,如果采用自定义模板的话,页面中可以只写上标签,并添加上标签内需要的几个参数,不需要写标签体的内容,会去自动调用模板中的标签体。 FrontUtils.includeTpl(TPL...
通过与主流模板引擎Freemarker,Velocity以及JSP对比,Beetl均远高于前面三个,这是因为宏观上,通过了优化的渲染引擎,IO的二进制输出,字节码属性访问增强,微观上,通过一维数组保存上下文,合并静态文本,通过...
《基于SpringMVC、MyBatis、FreeMarker架构实战CMS大型门户网站(自定义模板)》 本课程适合于各个层次的Java开发人员,对于初级程序员来说,可以在短时间内迅速提高开发能力,掌握流行的技术,把握技术的发展脉络。...
├ 自定义模板 ├ 可视化模板编辑 ├ 全文检索 ├ 友情链接管理 系统管理 ├ 内容关键字管理 ├ 自定义模型管理(自定义栏目/内容模型,一个栏目支持多种内容模型) ├ 网页信息采集 ├ 模块管理 ├ 数据备份...
java 版CMS系统、基于java技术研发的内容管理系统、功能:栏目模板自定义、内容模型自定义、多个站点管理、在线模板页面编辑等功能、代码完全开源、MIT授权协议。技术选型:jfinal DB+Record mysql freemarker ...
各个子系统前台thymeleaf模板,前端资源模块,使用nginx代理,实现动静分离。 > zheng-upms 本系统是基于RBAC授权和基于用户授权的细粒度权限控制通用平台,并提供单点登录、会话管理和日志管理。接入的系统可自由...
3、超高的性能:Beetl 远超过主流 java 模板引擎性能,如 5-6 倍于 freemarker,2 倍于传统 jsp 技术。而且消耗较低的 CPU 4、易于整合:Beetl 能很容易的与各种 web 框架整合,如 Spring MVC,JFinal,Struts,Nutz...
16、activation jcaptcha freemarker JAR部分用户反映下载不了,调整pom采用本地jar 17、栏目没有选择模型模板的情况下,发布内容选择不到模型问题处理 JEECMS简介 JEECMS是JavaEE版网站管理系统(Java ...
·强大、灵活的标签,用户自定义显示内容和显示方式 ·在设计上自身预先做了搜索引擎优化,增强对搜索引擎的友好性 ·采用伪静态页面技术,可自定义路径结构,无需urlrewrite ·轻松建设大规模网站,可通过次级域名...
16、activation jcaptcha freemarker JAR部分用户反映下载不了,调整pom采用本地jar 17、栏目没有选择模型模板的情况下,发布内容选择不到模型问题处理 JEECMS简介 JEECMS是一款支持栏目模型、内容模型交叉...
OpooPress 网站发布系统,轻松换个模板,快速搭建你的静态博客,CMS网站,企业网站。简单 - 不需要数据库,不用搭建WEB环境,傻瓜模式10秒钟搭建安装。快速 - 高效的生成引擎,1000篇文章5秒生成。静态化 全站HTML...
主题主题是整个网站的外观和感觉,通常主题是以下各项的容器: template :或主站点的模板,定义站点的主要外观,并在模板级别添加脚本,模板定义: 模板脚本:使用模板语言(目前为freemarker)对主要网站HTML结构...
继承其强大、稳定、安全、高效、跨平台等多方面的优点 · 采用hibernate3 spring mvc spring2 freemarker主流技术架构 · 懂html就能建站,提供最便利、合理的使用方式 · 强大、灵活的标签,用户自定义显示内容和...