`
lunch
  • 浏览: 76098 次
  • 性别: Icon_minigender_1
  • 来自: 石家庄
社区版块
存档分类
最新评论

用FreeMarker做CMS模板--用户自定义模板

阅读更多

  最近在客户需求的要求就定制开发一套CMS,模板采用了Freemarker。最初的时候是设想用Freemarker标签开发的模板,也做网站页面的模板。然后可以直接在页面模板中使用开发好的标签,来显示网站内容。但总还是觉得这样的模板不够灵活,局限性比较大。后来通过和领导的商议决定采用一下方式,最终可以直接在Freemarker页面模板层对已封装好的API进行调用,可以实现在模板中的简单编程。

  这种做法也是在探索中,如果大家觉得有什么不妥之处还望点拨。razz

  • 模板存放在数据库中(通常我们都是编写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);
	}
}

 

未完待续....就像这人世间错综复杂、乱七八糟的种种破事

 

分享到:
评论
4 楼 wyh2lxy1314 2011-02-16  
待续了???
3 楼 zxs19861202 2010-03-04  
待续了??????
2 楼 talangniao 2009-02-17  
未完待续???
1 楼 wxw850227 2008-06-10  
ghhhh

相关推荐

    基于Java的CMS内容管理系统 附Windows/Liniux 完整安装文件及demo

    Magnolia 是一种开放式 Java 内容管理系统,可在企业规模上...支持 Freemarker、JSP 或自定义模板语言 支持各种工作区(脚本、资源、模板)的 WebDAV 用于用户生成内容的公共用户注册模块 自动生成菜单、网站地图等)

    cms后台管理

    //这个模板就是自己声明的,即content_list.html,如果采用自定义模板的话,页面中可以只写上标签,并添加上标签内需要的几个参数,不需要写标签体的内容,会去自动调用模板中的标签体。 FrontUtils.includeTpl(TPL...

    Beetl模板引擎-其他

    通过与主流模板引擎Freemarker,Velocity以及JSP对比,Beetl均远高于前面三个,这是因为宏观上,通过了优化的渲染引擎,IO的二进制输出,字节码属性访问增强,微观上,通过一维数组保存上下文,合并静态文本,通过...

    4、用户模块-日志管理-多条件的查询分页操作结束-代码编写

    《基于SpringMVC、MyBatis、FreeMarker架构实战CMS大型门户网站(自定义模板)》 本课程适合于各个层次的Java开发人员,对于初级程序员来说,可以在短时间内迅速提高开发能力,掌握流行的技术,把握技术的发展脉络。...

    基于SpringMVC3+Spring3+Hibernate3+Freemarker+HTML5的开源项目jeecms

    ├ 自定义模板 ├ 可视化模板编辑 ├ 全文检索 ├ 友情链接管理 系统管理 ├ 内容关键字管理 ├ 自定义模型管理(自定义栏目/内容模型,一个栏目支持多种内容模型) ├ 网页信息采集 ├ 模块管理 ├ 数据备份...

    java 版CMS系统、基于java技术研发的内容管理系统

    java 版CMS系统、基于java技术研发的内容管理系统、功能:栏目模板自定义、内容模型自定义、多个站点管理、在线模板页面编辑等功能、代码完全开源、MIT授权协议。技术选型:jfinal DB+Record mysql freemarker ...

    单点登录源码

    各个子系统前台thymeleaf模板,前端资源模块,使用nginx代理,实现动静分离。 > zheng-upms 本系统是基于RBAC授权和基于用户授权的细粒度权限控制通用平台,并提供单点登录、会话管理和日志管理。接入的系统可自由...

    spring boot集成beetl极简入门实例.zip

    3、超高的性能:Beetl 远超过主流 java 模板引擎性能,如 5-6 倍于 freemarker,2 倍于传统 jsp 技术。而且消耗较低的 CPU 4、易于整合:Beetl 能很容易的与各种 web 框架整合,如 Spring MVC,JFinal,Struts,Nutz...

    jeecms v9.3 正式版 源码包.zip

    16、activation jcaptcha freemarker JAR部分用户反映下载不了,调整pom采用本地jar 17、栏目没有选择模型模板的情况下,发布内容选择不到模型问题处理 JEECMS简介 JEECMS是JavaEE版网站管理系统(Java ...

    JEEcms目前国内的cms领跑者

    ·强大、灵活的标签,用户自定义显示内容和显示方式 ·在设计上自身预先做了搜索引擎优化,增强对搜索引擎的友好性 ·采用伪静态页面技术,可自定义路径结构,无需urlrewrite ·轻松建设大规模网站,可通过次级域名...

    jeecms v9.3 正式版 安装包.zip

    16、activation jcaptcha freemarker JAR部分用户反映下载不了,调整pom采用本地jar 17、栏目没有选择模型模板的情况下,发布内容选择不到模型问题处理 JEECMS简介 JEECMS是一款支持栏目模型、内容模型交叉...

    OpooPress 网站发布系统 v1.0 beta

    OpooPress 网站发布系统,轻松换个模板,快速搭建你的静态博客,CMS网站,企业网站。简单 - 不需要数据库,不用搭建WEB环境,傻瓜模式10秒钟搭建安装。快速 - 高效的生成引擎,1000篇文章5秒生成。静态化 全站HTML...

    d.view.layout:负责布置视图和渲染组件的模块

    主题主题是整个网站的外观和感觉,通常主题是以下各项的容器: template :或主站点的模板,定义站点的主要外观,并在模板级别添加脚本,模板定义: 模板脚本:使用模板语言(目前为freemarker)对主要网站HTML结构...

    jeecms v3.0.1 开源jsp网站管理系统.rar

    继承其强大、稳定、安全、高效、跨平台等多方面的优点 · 采用hibernate3 spring mvc spring2 freemarker主流技术架构 · 懂html就能建站,提供最便利、合理的使用方式 · 强大、灵活的标签,用户自定义显示内容和...

Global site tag (gtag.js) - Google Analytics