[TOC]
# Freemarker 从入门到放弃
## site 官网
http://freemarker.org/
当前版本version 2.3.23 ~ 2.3.25
文件大小size: freemarker-2.3.23.jar 1.35MB
## 基础知识
模板 + 数据 = 视图
模板 ftl = freemarker template language, 即freemarker是一种语言
数据 java : bean map method
ftl : function, macros
jstl : buildin objects
保留关键字
true: boolean value ``true''
false: boolean value ``false''
gt: comparison operator ``greater than''
gte: comparison operator ``greater than or equivalent''
lt: comparison operator ``less than''
lte: comparison operator ``less than or equivalent''
as: used by a few directives
in: used by a few directives
using: used by a few directives
### 注释
<#-- uses mouse as a string -->
#@$%&?![]<>{},
\用来转义
### 系统指令directive #list #if #else #items #assign #macro
#if + #else
#list + #else
#include
### ?
二目?
fruits?join(", ")?upper_case
三目 a ? b : c
### !
<h1>Welcome ${user!"visitor"}!</h1>
### 比较与运算
<#if cargo.weight < 100>Light cargo</#if>
${cargo.weight / 2 + 100}
### 小抄 Quick overview (cheat sheet)
**类型值 Specify values directly**
Strings: "Foo" or 'Foo' or "It's \"quoted\"" or 'It\'s "quoted"' or r"C:\raw\string"
Numbers: 123.45
Booleans: true, false
Sequences: ["foo", "bar", 123.45]; Ranges: 0..9, 0..<10 (or 0..!10), 0..
Hashes: {"name":"green mouse", "price":150}
**获取值 Retrieving variables**
Top-level variables: user
Retrieving data from a hash: user.name, user["name"]
Retrieving data from a sequence: products[5]
Special variable: .main
**字符串操作 String operations**
Interpolation and concatenation: "Hello ${user}!" (or "Hello " + user + "!")
Getting a character: name[0]
String slice: Inclusive end: name[0..4], Exclusive end: name[0..<5], Length-based (lenient): name[0..*5], Remove starting: name[5..]
**序列操作 Sequence operations**
Concatenation: users + ["guest"]
Sequence slice: Inclusive end: products[20..29], Exclusive end: products[20..<30], Length-based (lenient): products[20..*10], Remove starting: products[20..]
**哈希操作 Hash operations**
Concatenation: passwords + { "joe": "secret42" }
Arithmetical calculations: (x * 1.5 + 10) / 2 - y % 100
Comparison: x == y, x != y, x < y, x > y, x >= y, x <= y, x lt y, x lte y, x gt y, x gte y, ...etc.
Logical operations: !registered && (firstVisit || fromEurope)
Built-ins: name?upper_case, path?ensure_starts_with('/')
Method call: repeat("What", 3)
**空值处理 Missing value handler operators:**
Default value: name!"unknown" or (user.name)!"unknown" or name! or (user.name)!
Missing value test: name?? or (user.name)??
*赋值操作*
Assignment operators: =, +=, -=, *=, /=, %=, ++, --
## macros @
定义
<#macro greet>
<font size="+2">Hello Joe!</font>
</#macro>
使用
<@greet/>
定义
<#macro greet person>
<font size="+2">Hello ${person}!</font>
</#macro>
使用
<@greet person="Fred"/> and <@greet person="Batman"/>
定义
<#macro greet person color>
<font size="+2" color="${color}">Hello ${person}!</font>
</#macro>
使用
<@greet person="Fred" color="black"/>
可以嵌套,可以子传入局部变量
<#macro repeat count>
<#list 1..count as x>
<#nested x, x/2, x==count>
</#list>
</#macro>
<@repeat count=4 ; c, halfc, last>
${c}. ${halfc}<#if last> Last!</#if>
</@repeat>
## tags @ 用户自定义指令
## Configurations
1. IDE eclipse要安装JBoss套件,编辑语法高亮等
2. Sublime也有支持ftl的插件
3. Freemarker的各种参数
### 用Spring进行配置
```xml
<bean id="freemarkerConfig"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath">
<value>/WEB-INF/ftl/</value>
</property>
<property name="freemarkerSettings">
<props>
<prop key="locale">zh_CN</prop>
<prop key="number_format">0.####</prop>
<prop key="default_encoding">UTF8</prop>
</props>
</property>
<property name="freemarkerVariables">
<map>
<entry key="t_mainSite_topic" value-ref="t_mainSite_topic"/>
<entry key="t_cms_content" value-ref="t_cms_content"/>
<entry key="t_ceiling" value-ref="t_ceiling"/>
......
</map>
</property>
</bean>
```
### 直接Java代码配置 freemarker.template.Configuration
// Create your Configuration instance, and specify if up to what FreeMarker
// version (here 2.3.25) do you want to apply the fixes that are not 100%
// backward-compatible. See the Configuration JavaDoc for details.
Configuration cfg = new Configuration(Configuration.VERSION_2_3_25);
// Specify the source where the template files come from. Here I set a
// plain directory for it, but non-file-system sources are possible too:
cfg.setDirectoryForTemplateLoading(new File("/where/you/store/templates"));
// Set the preferred charset template files are stored in. UTF-8 is
// a good choice in most applications:
cfg.setDefaultEncoding("UTF-8");
// Sets how errors will appear.
// During web page *development* TemplateExceptionHandler.HTML_DEBUG_HANDLER is better.
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
// Don't log exceptions inside FreeMarker that it will thrown at you anyway:
cfg.setLogTemplateExceptions(false);
#如何开始一个项目的七种办法
## Freemarker CLI, 难度等级 ★★★
~/workspace/freemarker_cli
*make.sh*
1 #!/bin/bash
2 cls=~/.m2/repository/org/freemarker/freemarker/2.3.23/freemarker-2.3.23.jar
3 ls -al $cls
4 javac -classpath $cls *.java
*run.sh*
1 #!/bin/bash
2 cls=~/.m2/repository/org/freemarker/freemarker/2.3.23/freemarker-2.3.23.jar:.
3 java -classpath $cls Free
## Freemarker as Servlet, 难度等级 ★★
~/workspace/freemarker_servlet
1. 拷贝freemarker-2.3.25.jar到lib
2. 编辑web.xml, 增加
```
<servlet>
<servlet-name>freemarker</servlet-name>
<servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>freemarker</servlet-name>
<url-pattern>*.ftl</url-pattern>
<!-- HTML and XML auto-escaped if incompatible_improvements >= 2.3.24: -->
<url-pattern>*.ftlh</url-pattern>
<url-pattern>*.ftlx</url-pattern>
</servlet-mapping>
```
3. 增加你的servlet和模板 hello.ftl, 可参考waterproofnet项目
[Context Menu] -> [new] -> [Sevlet]
```java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("hello.ftl")
.forward(request, response);
}
```
## Freemarker maven in Eclipse, 难度等级 ★
>>「eclipse」·「new」·「Maven Project」·「Select a Archetype」
>>「Catalog:Nexus Indexer」
>> spring-boot-sample-web-freemarker-archetype
>> [next] -> 写上你项目的组名和项目名,Group Id, Artifact Id, Version, Package
>>[Finish]
And Rock!
## Freemarker Online, 难度等级 ★
[Maven Archetype Generate](https://start.spring.io)
~/workspace/freemarker_online
## spring-boot, 难度等级 ★★
[Copy](https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples)
mvn archetype:generate
mvn spring-boot:run
## 项目用例之jeecms, 难度等级 ★★★★
(略)
## 项目用例之adminssll, 难度等级 ★★★★★
项目里在致有三种不同的使用方式
首页模板
StaticPageGenerator.java
找家门
NeighborhoodController.java
动态专题
SpecialTopicController.java
### To configure your project to inherit from the spring-boot-starter-parent simply set the parent:
<!-- Inherit defaults from Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.6.RELEASE</version>
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
<version>1.3.6.RELEASE</version>
</dependency>
### Using Spring Boot *without* the parent POM
Not everyone likes inheriting from the spring-boot-starter-parent POM. You may have your own corporate standard parent that you need to use, or you may just prefer to explicitly declare all your Maven configuration.
If you don’t want to use the spring-boot-starter-parent, you can still keep the benefit of the dependency management (but not the plugin management) by using a scope=import dependency:
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.3.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
## docker、docker、docker
j360-docker打包发布j360-boot到docker
https://github.com/xuminwlt/j360-docker
spring-boot入门工程之
https://github.com/xuminwlt/j360-boot
## spring-boot官方地址
http://projects.spring.io/spring-boot/
## 思考题
. 如何在页面上显示 ${...}
. 如何缩略字符串
. 如何显示中文日期时间
## 参考答案
1. 使用转义或raw类型
$\{...\}
${...}
${r"${...}"}
2. 全用区间类型 Ranges, *Length limited ranges were introduced in FreeMarker 2.3.21*
Ranges are just sequences, but they are created by specifying what range of whole numbers they contain, instead of specifying their items one by one. For example, 0..<m, assuming the m variable stores 5, will give a sequence that contains [0, 1, 2, 3, 4]. Ranges are primarily used for iterating over a range of numbers with <#list ...> and for slicing sequences and slicing strings.
The generic forms of range expressions are (where start and end can be any expression that evaluates to a number):
_start..end_: Range with inclusive end. For example, 1..4 gives [1, 2, 3, 4], and 4..1 gives [4, 3, 2, 1]. Beware, ranges with inclusive end never give an empty sequence, so 0..length-1 is WRONG, because when length is 0 it gives [0, -1].
_start..<end_ or _start..!end_: Range with exclusive end. For example, 1..<4 gives [1, 2, 3], 4..<1 gives [4, 3, 2], and 1..<1 gives []. Note the last example; the result can be an empty sequence. There's no difference between ..< and ..!; the last form is used in applications where using the < character causes problems (for HTML editors and such).
_start..*length_: Length limited range. For example, 10..*4 gives [10, 11, 12, 13], 10..*-4 gives [10, 9, 8, 7], and 10..*0 gives []. When these kind of ranges are used for slicing, the slice will end without error if the end of the sliced sequence or string is reached before the specified range length was reached; see slicing sequences for more.
<#assign s = "ABCDEF">
${s[2..3]}
${s[2..<4]}
${s[2..*3]}
${s[2..*100]}
${s[2..]}
will print:
CD
CD
CDE
CDEF
CDEF
3. format
可以统一配置,如spring
```xml
<#-- Parsing with SimpleDateFormat patterns: -->
<#assign someDate = "10/25/1995"?date("MM/dd/yyyy")>
<#assign someTime = "15:05:30"?time("HH:mm:ss")>
<#assign someDatetime = "1995-10-25 03:05 PM"?datetime("yyyy-MM-dd hh:mm a")>
<#-- Parsing with custom date formats: -->
<#assign someDatetime = "October/25/1995 03:05 PM"?datetime.@worklog>
```
Warning!
A frequent mistake of users is the usage of interpolations in places where they needn't/shouldn't/can't be used. Interpolations work only in text sections (e.g. <h1>Hello ${name}!</h1>) and in string literals (e.g. <#include "/footer/${company}.html">). A typical WRONG usage is <#if ${big}>...</#if>, which will cause a syntactical error. You should simply write <#if big>...</#if>. Also, <#if "${big}">...</#if> is WRONG, since it converts the parameter value to string and the if directive wants a boolean value, so it will cause a runtime error.
Alternatively, you can use the + operator to achieve similar result:
<#assign s = "Hello " + user + "!">
${testString?upper_case}
${testString?html}
${testString?upper_case?html}
${testSequence?size}
${testSequence?join(", ")}
Assuming that testString stores the string ``Tom & Jerry'', and testSequnce stores the strings "foo", "bar" and "baz", the output will be:
TOM & JERRY
Tom & Jerry
TOM & JERRY
3
foo, bar, baz
**顺序执行**
${mouse!"No mouse."}
<#assign mouse="Jerry">
${mouse!"No mouse."}
The output will be:
No mouse.
Jerry
*优先级的问题*
用
x!(y + 1)
或
(x!y) + 1
不要写成
x!y + 1