freemark就是一个对静态页面上的标签进行动态解析、填充数据的一个框架。

  • 语法(转:http://zhuyuehua.iteye.com/blog/1975251): 

1. freemarker获取list的size :
Java

ArrayList<String> list = new ArrayList<String>();

Freemaker

${list?size}

2. list的遍历:

<#list animals as being>
<tr>
<td>${being.name}${being.price}<td>
</tr>
</#list>

3. 遍历MAP 

<#list map?keys as k>
<option value="${k}">${map[k]}</option>
</#list>

4.list遍历中的下标序号:

_index是list的一个属性

<#list list as a>
${a_index}
</#list>

5.取LIST中第i个元素的值

${list[i]} 

嵌套时前面要有括号,如下,将字符串变成list,然后取第i个元素的值

${(str?split(","))[i]} 

6. list的嵌套:

<#list jsskList as jsskVO>
<#list kcList as kcVO>
<#if kcVO.kch=jsskVO.kch> (kcVO里有编号和名称,而jsskVO里只有编号)
${kcVO.kcm}
</#if>
</#list>
</#list>

7. list排序:

升序 .sort_by()

<#list list?sort_by("字段") as x>
</#list>

降序 .sort_by()?reverse

<#list list?sort_by("字段")?reverse as x>
</#list>

8.item_has_next,size使用:

<#list userList as user>
<#if !user_has_next>
共有${userList?size}最后一个用户是:${user.userName}
</#if>
</#list>
  • 实际项目中的用法:

\My-SSH-Blog\WebContent\blog\template\template.ftl

  <!DOCTYPE HTML>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1.0,maximum-scale=1,user-scalable=no">
<title>DX博客</title>
<link rel="stylesheet" type="text/css" media="all" href="${contextPath}/style.css" />
<link rel="stylesheet" type="text/css" media="all" href="${contextPath}/style/css/font-awesome.min.css" />
<link href="http://fonts.googleapis.com/css?family=Open+Sans:400,400italic,300italic,300,700,700italic|Open+Sans+Condensed:300,700" rel="stylesheet" type="text/css">
<!--[if IE 7]>
<link rel="stylesheet" type="text/css" href="${contextPath}/style/css/font-awesome-ie7.min.css"/>
<![endif]-->
<!--[if IE 8]>
<link rel="stylesheet" type="text/css" href="${contextPath}/style/css/ie8.css" media="all" />
<![endif]-->
<!--[if IE 9]>
<link rel="stylesheet" type="text/css" href="${contextPath}/style/css/ie9.css" media="all" />
<![endif]-->
<script type="text/javascript" src="${contextPath}/style/js/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="${contextPath}/style/js/ddsmoothmenu.js"></script>
<script type="text/javascript" src="${contextPath}/style/js/retina.js"></script>
<script type="text/javascript" src="${contextPath}/style/js/selectnav.js"></script>
<script type="text/javascript" src="${contextPath}/style/js/jquery.backstretch.min.js"></script>
<script type="text/javascript">
$.backstretch("${contextPath}/style/images/bg/16.jpg");
</script>
</head>
<body>
<div class="scanlines"></div> <div class="header-wrapper opacity">
<div class="header">
<div class="logo">
<a href="${contextPath}">
<h1>DX博客</h1>
</a>
</div> <div id="menu-wrapper">
<div id="menu" class="menu">
<ul id="tiny">
<li class="active">
<a href="${contextPath}">博客</a>
<ul>
<li><a href="${contextPath}/listArticle.action">所有博文</a></li>
</ul>
</li>
<li>
<a href="#" title="进入我的Github">Github</a>
</li>
<li>
<a href="#" title="进入我的CSDN博客">CSDN博客</a>
</li>
<li>
<a href="${contextPath}/commentUI.action" title="给我留言">留言板</a>
</li>
<li><a href="">Menu</a>
<ul>
<li><a href="/s/">短网址</a></li>
<li><a href="/WorkUpload/">作业提交系统</a></li>
</ul>
</li>
</ul>
</div>
</div>
<div class="clear"></div>
</div>
</div> <div class="wrapper"><!--
<ul class="social">
<li><a class="rss" href="#" title="博客订阅"></a></li>
<li><a class="qq" href="#" title="QQ"></a></li>
<li><a class="weibo" href="#" title="新浪微博"></a></li>
<li><a class="wechat" href="${contextPath}/public/wechat.jsp" title="微信"></a></li>
<li><a class="email" href="#" title="邮件"></a></li>
<li><a class="phone" href="#" title="手机"></a></li>
</ul>
<div class="intro">Intro...</div>
-->
<div class="content box">
<h1 class="title article-title">${title}</h1>
<div class="info">
<div><a href="${listCategoryArticle}" title="查看该类型博文"><i class="icon-folder-open-alt"></i>:${categoryName}</a></div>
<div><a href=""><i class="icon-user"></i>:${author}</a></div>
<div><i class="icon-time"></i>:${time}</div>
</div>
${typeString}
${content}
${typeString}
<div class="record">
<div>
<a id="looked" href=""><i class="icon-eye-open"></i> ${looked} 已阅</a>
</div>
&nbsp;&nbsp;
<div>
<a id="likes" href="javascript:like('${contextPath}/likeAction.action?artid=${articleId}')"><i class="icon-heart-empty"></i> ${likes} 喜爱</a>
</div>
<a class="comment-btn" href="javascript:onComment('#')"><i class="icon-comments"></i> 给我留言</a>
</div>
<div class="last-next">
<div>
<a href="${lastArticle.staticUrl}" title="上一篇">
<i class="icon-double-angle-left"></i>${lastArticle.title}
</a>
</div>
<div>
<a href="${nextArticle.staticUrl}" title="下一篇">
<i class="icon-double-angle-right"></i>${nextArticle.title}
</a>
</div>
</div>
</div> <div class="sidebar box">
<div class="sidebox widget">
<h3 class="widget-title">最近更新</h3>
<ul class="post-list">
<#list lastArticlesList as la>
<li>
<div class="meta">
<h5><a href="${contextPath}${la.staticUrl}.html">${la.title}</a></h5>
<em>${la.createDate?string("yyyy-MM-dd HH:mm:ss")}</em>
</div>
</li>
</#list>
<li class="more"><a href="${contextPath}/listArticle.action">more</a></li>
</ul>
</div> <div class="sidebox widget">
<h3 class="widget-title"><i class="icon-search icon"></i></h3>
<form class="searchform" method="post" action="#">
<input type="text" name="key" value="输入关键字搜索博客..." onFocus="this.value=''" onBlur="this.value='输入关键字搜索博客...'"/>
</form>
</div> <div class="sidebox widget">
<h3 class="widget-title categories">分类</h3>
<ul class="categories">
<#list categoryList as cl>
<li><a href="${contextPath}/listArticle.action?categoryId=${cl.id}">${cl.title}</a></li>
</#list>
</ul>
</div>
</div> <div class="clear"></div> </div> <div class="footer-wrapper">
<div id="footer" class="four">
<a href="/s/">短网址</a>&nbsp;&nbsp;
<a href="/WorkUpload/">作业提交系统</a>&nbsp;&nbsp;
</div>
</div>
<div class="site-generator-wrapper">
<div class="site-generator">
Copyright &copy;2017.DX &nbsp;Design by <a href="http://elemisfreebies.com">elemis.</a> All rights reserved.
</div>
</div>
<script type="text/javascript" src="${contextPath}/style/js/scripts.js"></script>
<script type="text/javascript">
function onComment(url){
var form = document.createElement('form');
form.action = url;
form.method = "post";
form.style.display = "none"; var input = document.createElement("input");
input.name = "title";
input.value = "${title}";
form.appendChild(input); var input2 = document.createElement("input");
input2.name = "articleId";
input2.value = "${articleId}";
form.appendChild(input2); document.body.appendChild(form);
form.submit();
}
</script>
</body>
</html>

我访问的对应网址:http://localhost:8080/My-SSH-Blog/blog/5/5-4.html,呈现效果:

这里我使用的是一个url重写的方式实现的,因此这里博客文章页面的template.ftl的解析过程是在filter中实现的。

web.xml中定义了filter过滤规则:

 <?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>My-SSH-Blog</display-name> <welcome-file-list>
<welcome-file>/index.jsp</welcome-file>
</welcome-file-list> <error-page>
<error-code>404</error-code>
<location>/public/404.html</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/public/500.html</location>
</error-page> <!-- html请求过滤器 -->
<filter>
<filter-name>articleFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>articleFilter</filter-name>
<url-pattern>*.html</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>articleFilter</filter-name>
<url-pattern>*.htm</url-pattern>
</filter-mapping> <context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext*.xml</param-value>
</context-param> <!-- 监听session,在线人员信息(登录账户,不包括访客和前台在线用户) -->
<listener>
<listener-class>com.dx.ssh.listener.SessionListener</listener-class>
</listener>
<!-- Bootstraps the root web application context before servlet initialization -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener> <!-- Struts2 filter -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter> <filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> <session-config>
<session-timeout>30</session-timeout>
</session-config>
</web-app>

ArticleFilter.java

 package com.dx.ssh.filter;

 import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern; import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils; import com.dx.ssh.service.ArticleService;
import com.dx.ssh.utils.TemplateUtils;
import com.opensymphony.xwork2.ActionContext; public class ArticleFilter implements Filter {
public static final String ARTICLE_TOKEN = "view";
private ArticleService articleService; public ArticleService getArticleService() {
return articleService;
} public void setArticleService(ArticleService articleService) {
this.articleService = articleService;
} // protected Object getBean(ServletContext servletContext, String id) {
// WebApplicationContext context =
// WebApplicationContextUtils.getWebApplicationContext(servletContext);
// return context.getBean(id);
// } @Override
public void init(FilterConfig filterConfig) throws ServletException {
} @Override
public void destroy() {
} @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse; // ArticleService articleService = (ArticleService)
// this.getBean(request.getServletContext(), "articleService"); String path = request.getRequestURL().toString();
// 模式匹配
Pattern pattern = Pattern.compile("/blog/([0-9]+)/([0-9]+)-([0-9]+)");
Matcher matcher = pattern.matcher(path); // 不匹配,路径不正确
if (!matcher.find()) {
// 路径不对,报错404
response.sendError(404, "您输入路径的不存在!");
return;
}
// 模版文件绝对路径
String realPath = request.getServletContext().getRealPath("/");
// 文件路径
String filePath = realPath + matcher.group() + ".ftl"; filePath = realPath + matcher.group() + ".ftl";
filePath = realPath + "blog/template/template.ftl";
filePath = filePath.replace("/", "\\");
filePath = filePath.replace("\\\\", "\\"); System.out.println(filePath);
// 查看服务器资源是否存在
File file = new File(filePath);
if (!file.exists()) {
// 路径不对,报错404
response.sendError(404, "您输入路径的不存在!");
return;
}
// 解析路径中的文章id
int articleId = Integer.parseInt(matcher.group(3));
System.out.println("articleId = " + articleId); // 防止同一用户session添加多次访问量
boolean isNew = false;
// 获取当前用户session
HttpSession session = request.getSession();
// 还没看过就能添加访问量
if (session.getAttribute(ARTICLE_TOKEN + articleId) == null) {
isNew = true;
// 设置当前的用户session已经看过文章了
session.setAttribute(ARTICLE_TOKEN + articleId, "true");
} // 填充模版信息
Map<String, Object> params = null;
try {
// 得到freemarker模版文件所需参数
params = this.getArticleService().getTemplateParams(articleId, request.getContextPath(), isNew);
params.put("contextPath", request.getContextPath());
} catch (Exception e) {
e.printStackTrace();
} String templateDir = realPath + File.separator + "blog";
String templateFile = matcher.group(1) + "/" + matcher.group(2) + "-" + matcher.group(3) + ".ftl";
templateFile = "template/template.ftl";
boolean result = TemplateUtils.parserTemplate(templateDir, templateFile, params, response.getOutputStream()); if (!result) {
// 服务器异常
response.sendError(500, "服务器未知异常!");
}
response.getOutputStream().close();
} }

TemplateUtils.java

 package com.dx.ssh.utils;

 import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Map; import freemarker.template.Configuration;
import freemarker.template.Template; public class TemplateUtils {
private static Configuration configuration = null; private TemplateUtils() {
} public static Configuration getConfiguration(String templateDir) throws IOException {
if (configuration == null) {
configuration = new Configuration();
configuration.setDirectoryForTemplateLoading(new File(templateDir));
}
return configuration;
} /**
* 向ftl模版中的数据替换
* */
public static boolean parserTemplate(String templateDir, String ftlPath, Map<String, Object> map, OutputStream os) {
try {
Template template = getConfiguration(templateDir).getTemplate(ftlPath, "UTF-8");
template.process(map, new OutputStreamWriter(os, "UTF-8"));
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}

模版填充数据类型整理方法:

 /**
* 得到freemarker模版文件所需参数
*/
@Override
public Map<String, Object> getTemplateParams(int articleId, String contextPath, boolean isNew) {
System.out.println("articleId=" + articleId);
// 要看的文章
ArticleEntity article = getArticleDao().findById(articleId); if (article == null || article.getId() <= 0)
return null; // 最新三篇文章
List<ArticleEntity> lastArticles = getArticleDao().findAllLastArticle(3); // 所有类别
List<ArticleCategoryEntity> categories = getArticleCategoryDao().findAll(); // 下一篇
ArticleEntity next = null;
List<ArticleEntity> nextArticles = articleDao.findNextArticle(3, article.getCreateDate());
if (nextArticles == null || nextArticles.size() <= 0) {
next = new ArticleEntity();
next.setStaticUrl("#");
next.setTitle("这是最后一篇了哦!");
} else {
next = nextArticles.get(0);
next.setStaticUrl(contextPath + next.getStaticUrl() + ".html");
} // 上一篇文章
ArticleEntity last = null;
List<ArticleEntity> lastAs = articleDao.findLastArticle(3, article.getCreateDate());
if (lastAs == null || lastAs.size() <= 0) {
last = new ArticleEntity();
last.setStaticUrl("#");
last.setTitle("这是第一篇哦!");
} else {
last = lastAs.get(0);
last.setStaticUrl(contextPath + last.getStaticUrl() + ".html");
} java.text.SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 封装模版所需参数
Map<String, Object> params = new HashMap<String, Object>();
params.put("looked", article.getLooks());
params.put("articleId", article.getId());
params.put("time", format.format(article.getCreateDate()));
params.put("title", article.getTitle());
params.put("content", article.getContent());
params.put("typeString", "------------------------------------------------------");
params.put("author", article.getAuthor());
params.put("categoryName", getArticleCategoryDao().findById(article.getCategoryId()).getTitle());
params.put("likes", article.getLikes());
params.put("listCategoryArticle", contextPath + "/listArticle.action?categoryId=" + article.getCategoryId());
params.put("lastArticlesList", lastArticles);
params.put("categoryList", categories);
params.put("likesURL", contextPath + "/likeAction.action?articleId=" + article.getId());
params.put("nextArticle", next);
params.put("lastArticle", last);
params.put("staticURL", article.getStaticUrl()); return params;
}

FreeMarker的用法的更多相关文章

  1. Freemarker简单用法

    Freemarker 最简单的例子程序   freemarker-2.3.18.tar.gz http://cdnetworks-kr-1.dl.sourceforge.net/project/fre ...

  2. Freemarker 程序开发

    Freemarker 程序开发 现在web开发中,多使用freemarker 来描述页面.通常会使用的macro来定义各种组件,从而达到UI组件的复用.结合使用其它的指定,可快速的描述一个html页面 ...

  3. 【JavaWeb】FreeMarker快速入门

    FreeMarker Freemarker是免费开源的模板引擎技术: Freemarker脚本为Freemarker Template Language: Freemarker提供了大量内建函数来简化 ...

  4. freemark学习

    学习地址: http://blog.csdn.net/hejinxu/article/details/6694890   对freemarker的用法与语法进行了详细的讲解 http://freema ...

  5. JAVA生成Word文档(经过测试)

    首先告诉大家这篇文章的原始出处:http://www.havenliu.com/java/514.html/comment-page-1#comment-756 我也是根据他所描述完成的,但是有一些地 ...

  6. springBoot入门教程(图文+源码+sql)

    springBoot入门 1   springBoot 1.1 SpringBoot简介 Spring Boot让我们的Spring应用变的更轻量化.比如:你可以仅仅依靠一个Java类来运行一个Spr ...

  7. springboot2.0(二)

    三. Web开发 3.1.静态资源访问 在我们开发Web应用的时候,需要引用大量的js.css.图片等静态资源. 默认配置 Spring Boot默认提供静态资源目录位置需置于classpath下,目 ...

  8. 【学习】019 SpringBoot

    一.SpringBoot介绍 1.1.SpringBoot简介 在您第1次接触和学习Spring框架的时候,是否因为其繁杂的配置而退却了?在你第n次使用Spring框架的时候,是否觉得一堆反复黏贴的配 ...

  9. SpringBoot之WEB开发-专题二

    SpringBoot之WEB开发-专题二 三.Web开发 3.1.静态资源访问 在我们开发Web应用的时候,需要引用大量的js.css.图片等静态资源. 默认配置 Spring Boot默认提供静态资 ...

随机推荐

  1. go语言defer panic recover用法总结

    defer defer是go提供的一种资源处理的方式.defer的用法遵循3个原则 在defer表达式被运算的同时,defer函数的参数也会被运算.如下defer的表达式println运算的同时,其入 ...

  2. 解决Centos7本机时间与实际时间相差8小时

    # timedatectl Local -- :: CST Universal -- :: UTC #相差8小时 RTC -- :: Time zone: Asia/Shanghai (CST, +) ...

  3. JavaSE中常见的工具类

    Arrays 用来操作数组, 常用方法是 sort()和toString()方法 Iterator 我们常说的迭代器就是这哥们,专门用来操作集合元素的工具类 常用方法是: hasNex()t和next ...

  4. 巧用linux版powershell,管理linux下的docker

    大家好,我把用powershell的docker马甲命令的好处,放在了页面下方,从第五章开始. powershell 传教士 原创文章 始于 2017-09-07 允许转载,但必须保留名字和出处,否则 ...

  5. 【Django】 视图层说明

    [Django视图层] 视图层的主要工作是衔接HTTP请求,Python程序和HTML模板,使他们能够有机互相合作从模型层lou到数据并且反馈.说到视图层的工作就有以下几个方面要说 ■ URL映射 对 ...

  6. DotNetBar控件,superTabControl多文档界面(MDI)的风格、多Tab的创建方法

    最近在做一个条码系统的项目,第一次用dotnetbar控件,,查找资料时看到伍老师一篇文章(链接),但是没有关于加载tab窗口的方法,自己摸索做了一个此类风格出来,并写了一个通用方法,供大家参考. 风 ...

  7. php中heredoc与nowdoc的使用方法

    一.heredoc结构及用法 Heredoc 结构就象是没有使用双引号的双引号字符串,这就是说在 heredoc 结构中单引号不用被转义.其结构中的变量将被替换,但在 heredoc 结构中含有复杂的 ...

  8. [Java反射机制]用反射改进简单工厂模式设计

    如果做开发的工作,工厂设计模式大概都已经深入人心了,比较常见的例子就是在代码中实现数据库操作类,考虑到后期可能会有数据库类型变换或者迁移,一般都会对一个数据库的操作类抽象出来一个接口,然后用工厂去获取 ...

  9. JavaScript(第八天)【时间与日期】

    ECMAScript提供了Date类型来处理时间和日期.Date类型内置一系列获取和设置日期时间信息的方法. 一.Date类型 ECMAScript中的Date类型是在早期Java中java.util ...

  10. 20162327WJH第五周作业

    学号 20162327 <程序设计与数据结构>第5周学习总结 教材学习内容总结 1.java是一种面向对象的语言.面向对象是一种编程方法.更是一种思维方式. 2.面向对象编程的终极目标是消 ...