`
lunch
  • 浏览: 77152 次
  • 性别: 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

相关推荐

    spring mvc mybatis freemarker 开发CMS代码

    【标题】"Spring MVC MyBatis Freemarker 开发CMS代码" 涉及到的是一个基于Java技术栈的内容管理系统(CMS)开发项目。这个项目利用了Spring MVC作为控制层框架,MyBatis作为数据访问层框架,以及Freemarker作为视图...

    Spring MVC+MyBatis+FreeMarker整合开发java CMS内容发布系统easycms开源系统

    easycms可能包括了用户管理、权限控制、内容分类、内容发布、模板管理等功能,允许用户自定义网站布局和样式。开源意味着源代码对公众开放,开发者可以根据需求对其进行修改和扩展。 综上所述,easycms开源系统利用...

    cms第五部分代码

    优秀的CMS系统应具备良好的扩展性和定制性,允许用户根据需求添加自定义插件、模块,以及调整界面风格。 综上所述,这个名为“cms第五部分代码”的项目似乎是一个基于Java和Freemarker的CMS系统实现,包含多个功能...

    java代码审计.Freemarker模板命令注入.分析

    OFCMS 是一个基于 Java 的内容管理系统(CMS),它提供了栏目模板自定义、内容模型自定义、多个站点管理、在线模板页面编辑等功能。然而,在 OFCMS 1.1.2 版本中,开发者未对网站后台的“模板文件”功能处的“所存储...

    完整的开源java版CMS

    5. **模板引擎**:CMS中的模板引擎允许设计者使用HTML模板并嵌入动态内容标签,如FreeMarker或Velocity,来生成最终的网页。 6. **插件与模块化**:开源CMS往往支持插件机制,用户可以通过安装插件来扩展功能,如...

    Magnolia搭建手册

    通过上述步骤,用户可以顺利完成Magnolia的搭建与基本配置工作,从而实现自定义页面模板的创建及应用。Magnolia的强大之处在于其高度可定制化的特点,用户可以根据自身需求定制各种模板和页面布局。此外,Magnolia还...

    一套基于模版的代码生成器

    它允许用户自定义模板,这些模板包含了特定语言的结构和模式,例如类、函数、变量等。当用户输入必要的参数和信息后,代码生成器会根据模板生成相应的代码片段,生成的代码可以是单个文件,也可以是整个项目结构。...

    tot-jsp-cms.rar

    7. **模板引擎**:为了方便页面设计,TOT-JSP-CMS可能采用了模板引擎,如FreeMarker或Velocity,这些引擎可以将静态HTML模板与动态数据结合,生成最终的HTML页面。 8. **国际化与本地化**:CMS系统通常需要支持多...

    铭飞CMS源码

    【freeMarker】是铭飞CMS中使用的模板引擎,用于生成动态网页内容。FreeMarker与后端Java代码解耦,使得视图层的开发更为独立,开发者可以通过定义模板语言来控制HTML的生成,提高开发效率和代码可维护性。 【j2ee...

    PublicCMSV1.0使用手册_20151012.docx

    - 自定义指令:FreeMarker模板引擎允许用户创建自己的指令,增强模板语言的灵活性和扩展性。 - 0关联查询:系统设计时尽量避免数据库中的关联查询,以优化性能。 - 0xml配置:减少XML配置文件,使得系统更加简洁...

    cms后台管理

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

    JEECMS自学帮助集合(包括FreeMarker)

    9. **JEECMS标签简介**:JEECMS官方帮助文档中的JEE CMS标签简介.txt列出了系统提供的各种标签及其用法,这对于理解和使用JEECMS模板语言非常关键。 10. **jeecms学习笔记**:jeecms学习笔记.txt可能是某位开发者的...

    PublicCMS_A5.zip

    4. **模板引擎与前台展示**:PublicCMS允许用户通过模板设计来自定义网站的外观,这可能涉及到FreeMarker、Velocity等模板引擎。同时,它可能提供了一些预设的模板供用户选择,以便快速搭建网站。 5. **内容管理**...

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

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

    CMS内容管理系统 java源码

    - 模板设计:提供自定义模板功能,方便调整网站布局和样式。 - 导航管理:构建网站的层级结构和导航菜单。 - 搜索功能:集成全文搜索引擎,帮助用户快速找到所需内容。 - 部署与更新:支持热部署,便于系统维护...

    ssh实现的cms系统

    3. **模板引擎**:如FreeMarker或Velocity,用于生成动态网页,与Struts紧密集成,将后台数据渲染成用户友好的格式。 4. **工作流**:对于复杂的发布流程,可能需要实现工作流管理,例如内容审核、审批等,这可以...

    jfinal cms v5.1.0-源码.zip

    4. **View**:视图层,通常由Freemarker或者JSP等模板引擎生成,用于展示数据。 5. **Config**:配置文件,定义路由、插件、全局配置等,是整个项目运行的基础。 6. **Plugin**:插件,JFinal支持自定义插件,可以...

    jeecms2012模板制作教程

    Jeecms使用Freemarker作为模板语言,它是一种简单的、声明式的模板引擎。熟悉Freemarker的语法,如变量、条件语句、循环等,是制作Jeecms模板的基础。同时,理解Jeecms的目录结构和模板文件命名规则也非常重要。 3...

    Struts2.0+Spring2.5+freemarker+ajax

    FreeMarker作为模板语言,与Struts2结合使用,可以将Java对象的数据渲染到HTML页面上。开发者可以定义模板文件,其中包含动态内容,FreeMarker引擎会在运行时解析这些模板,填充数据并生成最终的网页。这种方式让...

    高效的Java编写的CMS

    Java CMS的重要功能包括内容创作与发布、用户管理、权限控制、模板引擎、搜索集成和插件扩展。内容创作工具允许管理员创建、编辑和发布各种格式的内容,而用户管理则涉及用户注册、登录、角色分配和权限控制。模板...

Global site tag (gtag.js) - Google Analytics