FTL自己用得比較少换团,這里做個(gè)備份記錄悉稠,以免忘記。
Freemarker這里先扯淡兩句艘包,在單純的頁面使用上來說和JSP個(gè)人感覺沒有太大的區(qū)別的猛,都有比較多的類庫支持耀盗,不過相對(duì)的如果FTL沒有做靜態(tài)化相對(duì)的還是JSP的速度要快一些。但是為什么還是有很多項(xiàng)目用freemarker卦尊,網(wǎng)上也有很多文章叛拷,這里偷個(gè)懶,傳送門:http://blog.csdn.net/qq897958555/article/details/53560655
我這里比較傳統(tǒng)用的IDE工具是Myeclipse2014猫牡,所有如果想要有ftl格式的東東高亮支持的話需要配置下插件胡诗,同樣的網(wǎng)上一大把,這里也偷懶了,傳送門:http://blog.csdn.net/ylyanglei/article/details/50464515
在項(xiàng)目中淌友,Spring是支持多個(gè)前段引擎的煌恢,只是需要在Spring的配置文件中去配置一下,就可以同時(shí)支持JSP和FLT了震庭。除了Spring需要的jar外還需要Freemarker的jar支持瑰抵,這里我用的freemarker.jar
完整的XML
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<!-- 開啟springmvc的注解支持 -->
<mvc:annotation-driven conversion-service="tc" />
<!-- 定義靜態(tài)資源 -->
<mvc:resources location="/static/" mapping="/static/**" />
<!-- 制定掃描規(guī)則 -->
<context:component-scan base-package="com">
<!-- 制定過濾器 -->
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Repository" />
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Service" />
</context:component-scan>
<!-- 可以配置一個(gè)全局類型轉(zhuǎn)換器 -->
<!-- 配置spring定義的轉(zhuǎn)換工廠類 -->
<bean id="tc"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.lovo.converter.GlobalDateConverter"></bean>
</set>
</property>
</bean>
<!-- 配置http消息體數(shù)據(jù)與JSON轉(zhuǎn)換 -->
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="mappingJackson2HttpMessageConverter"></ref>
</list>
</property>
</bean>
<!-- 配置HTTP消息信息與JSON對(duì)象之間的一個(gè)轉(zhuǎn)換器 -->
<bean id="mappingJackson2HttpMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
</bean>
<!-- 視圖解析器 JSP -->
<bean id="urlBasedViewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView"></property>
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
<property name="order" value="1"/>
</bean>
<!-- 視圖解析器 FTL -->
<bean id="viewResolverFtl" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView"/>
<property name="contentType" value="text/html; charset=UTF-8"/>
<!-- 將請(qǐng)求和會(huì)話屬性作為變量暴露給FreeMarker模板使用。要做到這一點(diǎn)器联,
可以設(shè)置exposeRequestAttributes或者exposeSessionAttributes為true
-->
<property name="exposeRequestAttributes" value="true" />
<property name="exposeSessionAttributes" value="true" />
<!-- 使用這些宏二汛,必須設(shè)置FreeMarkerViewResolver的exposeMacroHelpers屬性為true -->
<property name="exposeSpringMacroHelpers" value="true" />
<!-- 使用緩存 -->
<property name="cache" value="true" />
<property name="suffix" value=".ftl" />
<property name="order" value="0"/>
</bean>
<!-- 配置freeMarker的模板路徑 -->
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/ftl/"/>
<property name="freemarkerVariables">
<map>
<entry key="xml_escape" value-ref="fmXmlEscape" />
</map>
</property>
<property name="defaultEncoding" value="UTF-8"/>
<!-- FreeMarker默認(rèn)每隔5秒檢查模板是否被更新,如果已經(jīng)更新了拨拓,就會(huì)重新加載并分析模板肴颊。
但經(jīng)常檢查模板是否更新可能比較耗時(shí)。如果你的應(yīng)用運(yùn)行在生產(chǎn)模式下渣磷,而且你預(yù)期模板不會(huì)經(jīng)常更新婿着,
則可以將更新的延遲時(shí)間延長至一個(gè)小時(shí)或者更久。 可以通過為freemarkerSettings屬性設(shè)置template_update_delay達(dá)到這一目的
-->
<property name="freemarkerSettings">
<props>
<prop key="template_update_delay">3600</prop>
<!-- 設(shè)置標(biāo)簽類型 兩種:[] 和 <> 醋界。[] 這種標(biāo)記解析要快些 -->
<prop key="tag_syntax">auto_detect</prop>
<prop key="default_encoding">UTF-8</prop>
<prop key="output_encoding">UTF-8</prop>
<prop key="locale">zh_CN</prop>
<!-- 設(shè)置時(shí)間格式 -->
<prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop>
<prop key="date_format">yyyy-MM-dd</prop>
<!-- 設(shè)置數(shù)字格式 -->
<prop key="number_format">#.##</prop>
<!-- 可以滿足一般需要竟宋。默認(rèn)情況變量為null則替換為空字符串,如果需要自定義形纺,寫上${empty!"EmptyValue of fbysss"}的形式即可 -->
<prop key="classic_compatible">true</prop>
</props>
</property>
</bean>
<bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape"/>
<!-- 配置MultipartResolver 用于文件上傳 使用spring的CommosMultipartResolver 說明: p:defaultEncoding="UTF-8":這里設(shè)置默認(rèn)的文件編碼為UTF-8丘侠,必須與用戶JSP的默認(rèn)編碼一致;
p:maxUploadSize="5000000":指定文件上傳大小逐样,單位為字節(jié)蜗字; p:uploadTempDir="fileUpload/temp":文件上傳臨時(shí)目錄,上傳完成后脂新,就會(huì)將臨時(shí)文件刪除秽澳; -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
p:defaultEncoding="UTF-8" p:maxUploadSize="5000000" p:uploadTempDir="fileUpload/temp">
</bean>
</beans>
需要注意一下的是如果只需要FTL作為模板不作為前段引擎,可以不配置視圖解析器戏羽,如果配置了多個(gè)視圖解析器,其他視圖解析器的優(yōu)先級(jí)一定要高于JSP才行楼吃。
<property name="order" value="0"/>
配置完了后寫個(gè)簡單的controller,用法和傳統(tǒng)的后臺(tái)封裝參數(shù)始花,前臺(tái)寫JSP寫EL表達(dá)式一樣
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping(value="/ftl")
public class ftlController {
@RequestMapping(value="/firstFtl.do",method=RequestMethod.GET)
public String index(HttpServletRequest requset,HttpServletResponse response,Model mode) {
mode.addAttribute("msg", "hi freemarker");
return "MyFtl";
}
}
<!DOCTYPE html>
<html>
<head>
<title>MyHtml.html</title>
<meta name="keywords" content="keyword1,keyword2,keyword3">
<meta name="description" content="this is my page">
<meta name="content-type" content="text/html; charset=UTF-8">
<!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
</head>
<body>
<b>${msg}</b>
</body>
</html>
首先科普下
FreeMarker模板文件主要有4個(gè)部分組成
1妄讯、文本,直接輸出的部分
2酷宵、注釋亥贸,即<#--...-->格式不會(huì)輸出
3、插值(Interpolation):即${..}或者#{..}格式的部分,將使用數(shù)據(jù)模型中的部分替代輸出
4浇垦、FTL指令:FreeMarker指令炕置,和HTML標(biāo)記類似,名字前加#予以區(qū)分男韧,不會(huì)輸出朴摊。
Freemarker支持各種后臺(tái)的常用類型,頁面也支持條件判斷此虑,邏輯運(yùn)算甚纲,首先,我們測試下最常用的后臺(tái)封裝list朦前,前臺(tái)循環(huán)出來介杆,在通過條件去判斷
@RequestMapping(value="/expression.do")
public String expressionTest(HttpServletRequest requset,HttpServletResponse response,Model mode)
{
//頁面測試用集合,簡單數(shù)據(jù)類型
List<Object> testList = new ArrayList<Object>();
testList.add("1");
testList.add("2");
testList.add("3");
mode.addAttribute("list",testList);
return "expressionTest";
}`這里寫代碼片`
<!DOCTYPE html>
<html>
<head>
<title>MyHtml.html</title>
<meta name="keywords" content="keyword1,keyword2,keyword3">
<meta name="description" content="this is my page">
<meta name="content-type" content="text/html; charset=UTF-8">
<!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
</head>
<body>
<div >
<#--在jsp中${}表達(dá)式會(huì)直接忽略不顯示,而freemarker會(huì)報(bào)異常韭寸,還是一大堆春哨,freemarker就需要您手動(dòng)去處理-->
<#-- ?? 用于判斷是否為空 ?number將字符串轉(zhuǎn)換為數(shù)字-->
<#if list??>
<span>集合長度:${list?size} </span><br>
<#list list as a >
集合的下標(biāo):${a_index}
當(dāng)前集合值:${a}
<#if a?number%2==0>偶數(shù)
<#else>奇數(shù)
</#if>
<br>
</#list>
<#else>
集合為空
</#if>
</div>
</body>
</html>
這里可以發(fā)現(xiàn)在用JSP的過程中我們一般不會(huì)對(duì)null值進(jìn)行特殊的處理判斷,JSP默認(rèn)會(huì)處理恩伺,當(dāng)為null時(shí)顯示為空赴背。但是在FLT模板中并不會(huì)這樣,如果未進(jìn)行非空判斷莫其,而直接進(jìn)行取值癞尚,會(huì)拋出異常。通常有兩種方式進(jìn)行處理乱陡。
例如現(xiàn)在有個(gè)user對(duì)象浇揩,里面有角色屬性
方式1:配置classic_compatible=true,此種方式只能判斷一層憨颠,如user.role為null胳徽,顯示為空,若user為空爽彤,則仍會(huì)發(fā)生異常养盗。
方式2:使用!或者适篙?往核?
${list!'集合為空'}
如果集合為空會(huì)顯示空
?? 用于判斷是否為空
<#if user.role??>
當(dāng)前用戶沒有權(quán)限角色
<#else>
當(dāng)前用戶有權(quán)限角色
</#if>
${user.role???string}<#--這里將結(jié)果以字符串的形式輸出:true 或者false-->
${user.role???string("YES","NO")} <#--這判定用戶權(quán)限角色為空 -->
${user.role!"當(dāng)前用戶沒有角色"}
<#--獲取當(dāng)前用戶的角色:${user.role.rolename!} 而role任然沒值的時(shí)候依然會(huì)報(bào)錯(cuò),而正確的方式<br/>獲取當(dāng)前用戶的角色:${(user.role.rolename)!}-->
來完整的處理個(gè)null嚷节,首先建立一個(gè)簡單的user對(duì)象
package com.lovo.beans;
import java.io.Serializable;
public class UserBean implements Serializable{
/**
* 省略get set方法
*/
private static final long serialVersionUID = -2959897964759682757L;
private Long id;
private String name;
private String sex;
private Long age;
}
控制器
@RequestMapping(value="/expressionUser.do")
public String expressionUset(HttpServletRequest requset,HttpServletResponse response,Model mode)
{
UserBean bean = new UserBean();
bean.setName("小明");
bean.setAge(20L);
bean.setSex(null);
//不對(duì)classBean做null處理
bean.setClassBean(null);
mode.addAttribute("user", bean);
return "expressionUser";
}
FTL模板
<!DOCTYPE html>
<html>
<head>
<title>MyHtml.html</title>
<meta name="keywords" content="keyword1,keyword2,keyword3">
<meta name="description" content="this is my page">
<meta name="content-type" content="text/html; charset=UTF-8">
<!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
</head>
<body>
<div >
姓名:<input type = "text" value="${user.name}"/><br>
性別:<input type = "text" value="${user.age}"/><br>
年齡:<input type = "text" value="${user.sex}"/><br>
班級(jí):<input type = "text" value="${user.classBean.className}"/>
</div>
</body>
</html>
會(huì)發(fā)現(xiàn)報(bào)錯(cuò)
這個(gè)時(shí)候用!和聂儒?虎锚?處理下!是直接做null判斷衩婚,后面可以跟值窜护,如果不寫,顯示為空字符串非春,柱徙??是做是否為空判斷奇昙,多用作if else中护侮,也可以輸出默認(rèn)值???需用???string("yes","no")
<!DOCTYPE html>
<html>
<head>
<title>MyHtml.html</title>
<meta name="keywords" content="keyword1,keyword2,keyword3">
<meta name="description" content="this is my page">
<meta name="content-type" content="text/html; charset=UTF-8">
<!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
</head>
<body>
<div >
姓名:<input type = "text" value="${user.name}"/><br>
性別:<input type = "text" value="${user.age}"/><br>
年齡:<input type = "text" value="${user.sex!}"/><br>
班級(jí):<input type = "text" value="${(user.classBean.className)!}"/>
班級(jí):<input type = "text" value="<#if (user.classBean.className)??></#if>"/>
班級(jí):<input type = "text" value="${(user.classBean.className)???string("班級(jí)不為空","班級(jí)為空")}"/>
</div>
</body>
</html>
在頁面使用FTL時(shí),不可避免的會(huì)操作變量敬矩,在Freemarker中變大大致可以分為4種概行。
- 數(shù)據(jù)模型變量,后臺(tái)封裝的變量參數(shù)傳遞到模板中
- 模板中的變量使用弧岳,用<#assign>定義
- 局部變量凳忙,在指令中的變量
- 循環(huán)變量,在循環(huán)中的變量
數(shù)據(jù)模型變量禽炬,可以在后臺(tái)封裝成對(duì)象涧卵,list,map等腹尖,這里舉例字符串
@RequestMapping(value="/expressionAssagin.do")
public String expressionAssagin(HttpServletRequest requset,HttpServletResponse response,Model mode)
{
mode.addAttribute("root", "后臺(tái)封裝的變量");
return "expressionAssagin";
}
<b>${root}</b>
頁面顯示
<#assign>定義的變量
<body>
后臺(tái)封裝的變量:<b>${root}</b></br>
頁面定義的變量:
<#assign username="李四">
${username}
</body>
當(dāng)頁面定義的assign變量名與數(shù)據(jù)模型變量名相同時(shí)柳恐,優(yōu)先展示頁面定義的assign變量,不是覆蓋數(shù)據(jù)模型變量热幔,可以使用.globals進(jìn)行展示
<body>
<#assign root="頁面變量優(yōu)先于數(shù)據(jù)模型變量展示">
優(yōu)先展示:<b>${root}</b></br>
指定展示:<b>${.globals.root}</b></br>
頁面定義的變量:
<#assign username="李四">
${username}
</body>
局部變量
<body>
<#assign root="頁面變量優(yōu)先于數(shù)據(jù)模型變量展示">
優(yōu)先展示:<b>${root}</b></br>
指定展示:<b>${.globals.root}</b></br>
頁面定義的變量:
<#assign username="李四">
${username}<br>
<#--使用local可以聲明局部變量乐设,所以在marco宏中局部變量-->
<#macro test>
<#--此時(shí)當(dāng)調(diào)用該指令之后,會(huì)將模板中的變量覆蓋绎巨,不能使用globals捧韵,一般不使用這種方式在指令中定義變量-->
<#local username="我的名字變了"/>
<#local sex="性別是保密的"/>
姓名:${username!} 性別${sex!}</br>
</#macro>
<#--調(diào)用宏-->
<@test/>
${sex!"局部變量外部是調(diào)用不到的"}
</body>
循環(huán)變量移稳,就是在循環(huán)體重使用的變量
<#--循環(huán)變量-->
<#list 1..3 as num>
<#--只能在循環(huán)體中使用-->
${num}
</#list>
${num!"循環(huán)變量出了循環(huán)體就消失了"}