最近在学习freemarker,已经了解了freemarker的一些基本概述和常用的标签和内置函数的使用方法。
今天在学习freemarker生成静态页面时遇到一些问题,在这里记录下遇到的问题以及学习的成果。从头开始说吧。
freemarker生成静态页面需要4步
// 1.实例化Configuration,它的工作是读取模版文件
Configuration cfg = new Configuration();
// 指定Configuration寻找模版文件的目录。(它有三种方法指定,这只是其中的一种,其余两种稍后讲解)
cfg.setClassForTemplateLoading(this.getClass(), "/");
// 2.在模板文件目录中找到名称为name的模版文件
Template temp = cfg.getTemplate( "xxx.ftl");
//3.定义静态页面输出文件
FileWriter out = new FileWriter(new File("D:/xxx.html"));
//4.输出静态页面。第一个参数是Map<String,Object>格式的数据,第二个参数是文件输出流。输出后别忘了out.close();
temp.process(data, out );
Configuration寻找模版文件的目录的三种方法
2、void setClassForTemplateLoading(Class cl, String prefix);
3、void setServletContextForTemplateLoading(Object servletContext, String path);
以上第一种方式显示的指定了一个文件系统中的目录,FreeMarker 将会在此目录记载模版,不用说,此目录必须存在,否在会抛出异常。
第二种方式以一个Class作为一个输入参数,当你想使用ClassLoader的方式来加载模版的时候,你就可以使用这种方式。
第三种方式把web 应用的上下文以及基路径(相对与WEN-INF 的父路进来说)作为参数。该种方式的模版加载器将会从web 应用上下文种加载模版。
第一种方式我没用过,第二种方式我在main方法中测试成功,第三种方式只能在WEB项目中使用
遇到的问题
我搭建了一个springmvc+freemarker的测试项目
当我在Control中这样写到
Configuration cfg =new Configuration();
cfg.setServletContextForTemplateLoading(request.getSession()
.getServletContext(), "/WEB-INF/page");
Template template = cfg.getTemplate("/ceshi.html");
报错为:
freemarker.core.ParseException: Parsing error in template "ceshi.html" in line 62, column 64:
Lexical error: encountered "\ufffd" (65533), after "".
freemarker.core.TokenMgrError.toParseException(TokenMgrError.java:233)
freemarker.template.Template.<init>(Template.java:199)
freemarker.cache.TemplateCache.loadTemplate(TemplateCache.java:419)
freemarker.cache.TemplateCache.getTemplate(TemplateCache.java:330)
freemarker.cache.TemplateCache.getTemplate(TemplateCache.java:205)
freemarker.template.Configuration.getTemplate(Configuration.java:740)
freemarker.template.Configuration.getTemplate(Configuration.java:665)
com.zxsd.test.action.TestAction.getUserById(TestAction.java:87)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:601)
org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:440)
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:428)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
错误上说,在编译模版文件ceshi.html的第62行第64个字符"\ufffd" 时出现了错误。"\ufffd"是问号的unicode编码
而我之前使用动态页面访问时,ceshi.html运行正常。莫非freemarker自身的模版解析器是亲生的?我写的是捡来的?(在一个请求中,Control执行完毕后,freemarker解析器会执行,解析器加载模版+control返回的数据=返回到浏览器的页面)
解决问题的办法
我的解决方法是,我也使用freemarker自身的模版解析器。
control加入
private Configuration cfg;
public void setFreeMarkerConfigurer(
FreeMarkerConfigurer freeMarkerConfigurer) {
this.cfg = freeMarkerConfigurer.getConfiguration();
}
springmvc配置文件加入
<bean id="testAction" class="com.zxsd.test.action.TestAction">
<property name="freeMarkerConfigurer">
<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="" />
<property name="freemarkerSettings">
<props>
<prop key="tag_syntax">auto_detect</prop>
<prop key="template_update_delay">5</prop>
<prop key="defaultEncoding">UTF-8</prop>
<prop key="url_escaping_charset">UTF-8</prop>
<prop key="locale">zh_CN</prop>
<prop key="boolean_format">true,false</prop>
<prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop>
<prop key="date_format">yyyy-MM-dd</prop>
<prop key="time_format">HH:mm:ss</prop>
<prop key="number_format">0.######</prop>
<prop key="whitespace_stripping">true</prop>
</props>
</property>
</bean>
</property>
</bean>
使用freemarker亲生的视图解析器后,问题解决。