企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
[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类型 $\{...\} &dollar;{...} ${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 &amp; Jerry TOM &amp; 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