最近在客户需求的要求就定制开发一套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);
}
}
未完待续....就像这人世间错综复杂、乱七八糟的种种破事
分享到:
相关推荐
【标题】"Spring MVC MyBatis Freemarker 开发CMS代码" 涉及到的是一个基于Java技术栈的内容管理系统(CMS)开发项目。这个项目利用了Spring MVC作为控制层框架,MyBatis作为数据访问层框架,以及Freemarker作为视图...
easycms可能包括了用户管理、权限控制、内容分类、内容发布、模板管理等功能,允许用户自定义网站布局和样式。开源意味着源代码对公众开放,开发者可以根据需求对其进行修改和扩展。 综上所述,easycms开源系统利用...
优秀的CMS系统应具备良好的扩展性和定制性,允许用户根据需求添加自定义插件、模块,以及调整界面风格。 综上所述,这个名为“cms第五部分代码”的项目似乎是一个基于Java和Freemarker的CMS系统实现,包含多个功能...
OFCMS 是一个基于 Java 的内容管理系统(CMS),它提供了栏目模板自定义、内容模型自定义、多个站点管理、在线模板页面编辑等功能。然而,在 OFCMS 1.1.2 版本中,开发者未对网站后台的“模板文件”功能处的“所存储...
5. **模板引擎**:CMS中的模板引擎允许设计者使用HTML模板并嵌入动态内容标签,如FreeMarker或Velocity,来生成最终的网页。 6. **插件与模块化**:开源CMS往往支持插件机制,用户可以通过安装插件来扩展功能,如...
通过上述步骤,用户可以顺利完成Magnolia的搭建与基本配置工作,从而实现自定义页面模板的创建及应用。Magnolia的强大之处在于其高度可定制化的特点,用户可以根据自身需求定制各种模板和页面布局。此外,Magnolia还...
它允许用户自定义模板,这些模板包含了特定语言的结构和模式,例如类、函数、变量等。当用户输入必要的参数和信息后,代码生成器会根据模板生成相应的代码片段,生成的代码可以是单个文件,也可以是整个项目结构。...
7. **模板引擎**:为了方便页面设计,TOT-JSP-CMS可能采用了模板引擎,如FreeMarker或Velocity,这些引擎可以将静态HTML模板与动态数据结合,生成最终的HTML页面。 8. **国际化与本地化**:CMS系统通常需要支持多...
【freeMarker】是铭飞CMS中使用的模板引擎,用于生成动态网页内容。FreeMarker与后端Java代码解耦,使得视图层的开发更为独立,开发者可以通过定义模板语言来控制HTML的生成,提高开发效率和代码可维护性。 【j2ee...
- 自定义指令:FreeMarker模板引擎允许用户创建自己的指令,增强模板语言的灵活性和扩展性。 - 0关联查询:系统设计时尽量避免数据库中的关联查询,以优化性能。 - 0xml配置:减少XML配置文件,使得系统更加简洁...
//这个模板就是自己声明的,即content_list.html,如果采用自定义模板的话,页面中可以只写上标签,并添加上标签内需要的几个参数,不需要写标签体的内容,会去自动调用模板中的标签体。 FrontUtils.includeTpl(TPL...
9. **JEECMS标签简介**:JEECMS官方帮助文档中的JEE CMS标签简介.txt列出了系统提供的各种标签及其用法,这对于理解和使用JEECMS模板语言非常关键。 10. **jeecms学习笔记**:jeecms学习笔记.txt可能是某位开发者的...
4. **模板引擎与前台展示**:PublicCMS允许用户通过模板设计来自定义网站的外观,这可能涉及到FreeMarker、Velocity等模板引擎。同时,它可能提供了一些预设的模板供用户选择,以便快速搭建网站。 5. **内容管理**...
Magnolia 是一种开放式 Java 内容管理系统,可在企业规模上...支持 Freemarker、JSP 或自定义模板语言 支持各种工作区(脚本、资源、模板)的 WebDAV 用于用户生成内容的公共用户注册模块 自动生成菜单、网站地图等)
- 模板设计:提供自定义模板功能,方便调整网站布局和样式。 - 导航管理:构建网站的层级结构和导航菜单。 - 搜索功能:集成全文搜索引擎,帮助用户快速找到所需内容。 - 部署与更新:支持热部署,便于系统维护...
3. **模板引擎**:如FreeMarker或Velocity,用于生成动态网页,与Struts紧密集成,将后台数据渲染成用户友好的格式。 4. **工作流**:对于复杂的发布流程,可能需要实现工作流管理,例如内容审核、审批等,这可以...
4. **View**:视图层,通常由Freemarker或者JSP等模板引擎生成,用于展示数据。 5. **Config**:配置文件,定义路由、插件、全局配置等,是整个项目运行的基础。 6. **Plugin**:插件,JFinal支持自定义插件,可以...
Jeecms使用Freemarker作为模板语言,它是一种简单的、声明式的模板引擎。熟悉Freemarker的语法,如变量、条件语句、循环等,是制作Jeecms模板的基础。同时,理解Jeecms的目录结构和模板文件命名规则也非常重要。 3...
FreeMarker作为模板语言,与Struts2结合使用,可以将Java对象的数据渲染到HTML页面上。开发者可以定义模板文件,其中包含动态内容,FreeMarker引擎会在运行时解析这些模板,填充数据并生成最终的网页。这种方式让...
Java CMS的重要功能包括内容创作与发布、用户管理、权限控制、模板引擎、搜索集成和插件扩展。内容创作工具允许管理员创建、编辑和发布各种格式的内容,而用户管理则涉及用户注册、登录、角色分配和权限控制。模板...