Directory
- 1. Introduction to freemarker
-
-
-
- Create test project
- 2.2.2) Configuration file
- 2.2.3) Create model class
- 2.2.4) Create template
- 2.2.5) Create controller
- 2.2.6) Create startup class
- 2.2.7) Testing
- 2.3) freemarker basics
-
- 2.3.1) Basic grammar types
- 2.3.2) Collection instructions (List and Map)
- 2.3.3) if instruction
- 2.3.4) Operators
- 2.3.5) Null value handling
- 2.3.6) Built-in functions
- 2.4) Static testing
-
- 2.4.1) Requirements analysis
- 2.4.2) Static testing
-
-
1. Freemarker introduction
? FreeMarker is a template engine: a universal tool based on templates and data to be changed, and used to generate output text (HTML web pages, emails, configuration files, source code, etc.). It is not for end users, but a Java class library, a component that programmers can embed into the products they develop.
? Freemarker is a view format of springmvc. SpringMVC supports freemarker view format by default.
A Spring Boot + Freemarker project needs to be created for testing the template.
Create test project
Create a freemarker-demo test project specifically for freemarker functional testing and template testing.
pom.xml is as follows
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>heima-leadnews-test</artifactId> <groupId>com.heima</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>freemarker-demo</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- apache's encapsulation tool library for java io --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> </dependency> </dependencies> </project>
2.2.2) Configuration file
Configure application.yml
server: port: 8881 #Service port spring: application: name: freemarker-demo #Specify service name freemarker: cache: false #Turn off template caching to facilitate testing settings: template_update_delay: 0 #Check the template update delay time. Set to 0 to check immediately. If the time is greater than 0, caching will be inconvenient for template testing. suffix: .ftl #Specify the suffix name of the Freemarker template file
2.2.3) Create model class
Create a model type under the freemarker test project for testing
package com.heima.freemarker.entity; import lombok.Data; import java.util.Date; @Data public class Student {<!-- --> private String name;//name private int age;//Age private Date birthday;//birthday private Float money;//wallet }
2.2.4) Create template
Create templates under resources. This directory is the default template storage directory of freemarker.
Create the template file 01-basic.ftl under templates. The interpolation expression in the template will eventually be replaced by freemarker with specific data.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Hello World!</title> </head> <body> <b>Normal text String display:</b><br><br> Hello ${name}<br> <b>Data display in the object Student:</b><br/> Name: ${stu.name}<br/> Age: ${stu.age} </body> </html>
2.2.5) Create controller
Create the Controller class, add name to the Map, and finally return the template file.
package com.xuecheng.test.freemarker.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.client.RestTemplate; import java.util.Map; @Controller public class HelloController {<!-- --> @GetMapping("/basic") public String test(Model model) {<!-- --> //1. Parameters in plain text form model.addAttribute("name", "freemarker"); //2. Entity class related parameters Student student = new Student(); student.setName("Xiao Ming"); student.setAge(18); model.addAttribute("stu", student); return "01-basic"; } }
01-basic.ftl, fill data using interpolation expressions
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Hello World!</title> </head> <body> <b>Normal text String display:</b><br><br> Hello ${name}<br> <b>Data display in the object Student:</b><br/> Name: ${stu.name}<br/> Age: ${stu.age} </body> </html>
2.2.6) Create startup class
package com.heima.freemarker; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class FreemarkerDemotApplication {<!-- --> public static void main(String[] args) {<!-- --> SpringApplication.run(FreemarkerDemotApplication.class,args); } }
2.2.7) Test
Request: http://localhost:8881/basic
2.3) freemarker basics
2.3.1) Basic grammar types
1. Comments, i.e. <#-- -->, the content between them will be ignored by freemarker
<#--I am a freemarker comment-->
2. Interpolation: In the ${..}
part, freemarker will replace **${..}
with the real value **
Hello ${name}
3. FTL command: Similar to HTML tags, add # before the name to distinguish it. Freemarker will parse the expression or logic in the tag.
<# >FTL command</#>
4. Text, only text information. Contents that are not comments, interpolations, and FTL instructions of freemarker will be ignored and parsed by freemarker and the content will be output directly.
<#--Normal text in freemarker--> I am an ordinary text
2.3.2) Collection instructions (List and Map)
1. Data model:
Add the following methods in HelloController:
@GetMapping("/list") public String list(Model model){<!-- --> //---------------------------------------- Student stu1 = new Student(); stu1.setName("Xiaoqiang"); stu1.setAge(18); stu1.setMoney(1000.86f); stu1.setBirthday(new Date()); //Xiaohong object model data Student stu2 = new Student(); stu2.setName("小红"); stu2.setMoney(200.1f); stu2.setAge(19); //Store the two object model data into the List collection List<Student> stus = new ArrayList<>(); stus.add(stu1); stus.add(stu2); //Store the List collection data in the model model.addAttribute("stus",stus); //---------------------------------------- //Create Map data HashMap<String,Student> stuMap = new HashMap<>(); stuMap.put("stu1",stu1); stuMap.put("stu2",stu2); // 3.1 Store Map data in the model model.addAttribute("stuMap", stuMap); return "02-list"; }
2. Template:
Add 02-list.ftl
file in templates
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Hello World!</title> </head> <body> <#-- Display of list data --> <b>Display the stu data in the list:</b> <br> <br> <table> <tr> <td>Serial number</td> <td>Name</td> <td>Age</td> <td>Wallet</td> </tr> </table> <#-- Display of Map data --> <b>Display of map data:</b> <br/><br/> <a href="###">Method 1: Through map['keyname'].property</a><br/> Output student information of stu1:<br/> Name:<br/> Age:<br/> <br/> <a href="###">Method 2: Through map.keyname.property</a><br/> Output student information of stu2:<br/> Name:<br/> Age:<br/> <br/> <a href="###">Traverse the two student information in the map:</a><br/> <table> <tr> <td>Serial number</td> <td>Name</td> <td>Age</td> <td>Wallet</td> </tr> </table> </body> </html>
Example code:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Hello World!</title> </head> <body> <#-- Display of list data --> <b>Display the stu data in the list:</b> <br> <br> <table> <tr> <td>Serial number</td> <td>Name</td> <td>Age</td> <td>Wallet</td> </tr> <#list stus as stu> <tr> <td>${stu_index + 1}</td> <td>${stu.name}</td> <td>${stu.age}</td> <td>${stu.money}</td> </tr> </#list> </table> <#-- Display of Map data --> <b>Display of map data:</b> <br/><br/> <a href="###">Method 1: Through map['keyname'].property</a><br/> Output student information of stu1:<br/> Name: ${stuMap['stu1'].name}<br/> Age: ${stuMap['stu1'].age}<br/> <br/> <a href="###">Method 2: Through map.keyname.property</a><br/> Output student information of stu2:<br/> Name: ${stuMap.stu2.name}<br/> Age: ${stuMap.stu2.age}<br/> <br/> <a href="###">Traverse the two student information in the map:</a><br/> <table> <tr> <td>Serial number</td> <td>Name</td> <td>Age</td> <td>Wallet</td> </tr> <#list stuMap?keys as key > <tr> <td>${key_index}</td> <td>${stuMap[key].name}</td> <td>${stuMap[key].age}</td> <td>${stuMap[key].money}</td> </tr> </#list> </table> </body> </html>
Explanation of the above code:
${k_index}:
Index: Get the subscript of the loop. To use it, add “_index” after stu. Its value starts from 0.
2.3.3) if directive
? The if instruction is a judgment instruction, which is a commonly used FTL instruction. Freemarker will make a judgment when it encounters if during parsing. If the condition is true, the content in the if will be output, otherwise the content will be skipped and will not be output.
- Command format
<#if ></if>
1. Data model:
Use the list command to test the data model and determine that the data font named Xiaohong is displayed in red.
2. Template:
<table> <tr> <td>Name</td> <td>Age</td> <td>Wallet</td> </tr> <#list stus as stu> <tr> <td >${stu.name}</td> <td>${stu.age}</td> <td >${stu.mondy}</td> </tr> </#list> </table>
Example code:
<table> <tr> <td>Name</td> <td>Age</td> <td>Wallet</td> </tr> <#list stus as stu> <#if stu.name='小红'> <tr style="color: red"> <td>${stu_index}</td> <td>${stu.name}</td> <td>${stu.age}</td> <td>${stu.money}</td> </tr> <#else> <tr> <td>${stu_index}</td> <td>${stu.name}</td> <td>${stu.age}</td> <td>${stu.money}</td> </tr> </#if> </#list> </table>
3. Output:
If the name is “Xiaoqiang”, the font color will be displayed in red.
2.3.4) Operator
1. Arithmetic operators
Arithmetic operations are fully supported in FreeMarker expressions. The arithmetic operators supported by FreeMarker include:
- Addition:
+
- Subtraction:
-
- Multiplication:
*
- Division:
/
- Find the modulus (remainder):
%
template code
<b>Arithmetic operators</b> <br/><br/> 100 + 5 operation: ${100 + 5}<br/> 100 - 5 * 5 operation: ${100 - 5 * 5}<br/> 5 / 2 operation: ${5 / 2}<br/> 12 % 10 operation: ${12 % 10}<br/>
Except for the + operation, other operations can only be calculated with the number type.
2. Comparison operators
=
or==
: Determine whether two values are equal.!=
: Determine whether two values are not equal.>
orgt
: Determine whether the value on the left is greater than the value on the right>=
orgte
: Determine whether the value on the left is greater than or equal to the value on the right<
orlt
: Determine whether the value on the left is less than the value on the right<=
orlte
: Determine whether the value on the left is less than or equal to the value on the right
= and == template code
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Hello World!</title> </head> <body> <b>Comparison operators</b> <br/> <br/> <dl> <dt> == and != comparison: </dt> <dd> <#if "xiaoming" == "xiaoming"> String comparison "xiaoming" == "xiaoming" </#if> </dd> <dd> <#if 10 != 100> Comparison of values 10 != 100 </#if> </dd> </dl> <dl> <dt>Other comparisons</dt> <dd> <#if 10 gt 5 > Form 1: Use special characters to compare values 10 gt 5 </#if> </dd> <dd> <#-- Date comparison requires converting the attribute to data type through ?date before comparison --> <#if (date1?date >= date2?date)> Form 2: Use parentheses to compare times date1?date >= date2?date </#if> </dd> </dl> <br/> </body> </html>
Controller’s data model code
@GetMapping("operation") public String testOperation(Model model) {<!-- --> //Construct Date data Date now = new Date(); model.addAttribute("date1", now); model.addAttribute("date2", now); return "03-operation"; }
Note on comparison operators
- **
=
and!=
** can be used to compare strings, values and dates for equality. - **
=
and!=
**Both sides must be the same type of value, otherwise an error will occur - String
"x"
,"x "
, **"X "
**The comparison is not equal. Because FreeMarker is an exact comparison - Other operators can operate on numbers and dates, but not on strings
- Using alphabetic operators such as **
gt
instead of>
will have better results, because FreeMarker will>
** is interpreted as the end character of the FTL tag - You can use parentheses to avoid this situation, such as:
<#if (x>y)>
3. Logical operators
- Logical AND: & amp; & amp;
- Logical OR:||
- Logical negation:!
Logical operators can only operate on Boolean values, otherwise an error will occur.
template code
<b>Logical operators</b> <br/> <br/> <#if (10 lt 12 ) & amp; & amp;( 10 gt 5 ) > (10 lt 12 ) & amp; & amp;( 10 gt 5 ) is shown as true </#if> <br/> <br/> <#if !false> False is inverted to true </#if>
2.3.5) Null value handling
1. Use “” to determine whether a variable exists
Usage: variable, if the variable exists, return true, otherwise return false
Example: To prevent an error when stus is empty, you can add the following judgment:
<#if stus> <#list stus as stu> ... </#list> </#if>
2. Use “!” as the default value for missing variables
-
Use ! to specify a default value and display the default value when the variable is empty.
Example: ${name!’} means if name is empty, an empty string will be displayed.
-
If it is a nested object, it is recommended to use () to enclose it
Example: ${(stu.bestFriend.name)!’} means that if stu or bestFriend or name is empty, an empty string will be displayed by default.
2.3.6) Built-in functions
Built-in function syntax format: Variable + ? + function name
1. Sum to the size of a certain set
${collection name?size}
2. Date formatting
Display year, month and day: ${today?date}
Display hours, minutes and seconds: ${today?time}
Display date + time: ${today?datetime}
Custom formatting: ${today?string("yyyyyearMMmonth")}
3. Built-in functions c
model.addAttribute(“point”, 102920122);
Point is a numeric type. Using ${point} will display the value of this number. Every three digits are separated by commas.
If you don’t want to display numbers separated by three digits, you can use the c function to convert the number into a string for output.
${point?c}
4. Convert json string into object
one example:
The assign tag is used, and the role of assign is to define a variable.
<#assign text="{'bank':'ICBC','account':'10101920201920212'}" /> <#assign data=text?eval /> Account opening bank: ${data.bank} Account number: ${data.account}
Template code:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>inner Function</title> </head> <body> <b>Get collection size</b><br> Collection size: <b>Obtained date</b><br> Display year, month and day:<br> Display hours, minutes and seconds:<br> Display date + time:<br> Custom formatting:<br> <b>Built-in function C</b><br> There is no numerical value displayed by the C function:<br> There are values displayed by the C function: <b>Declare variable assign</b><br> </body> </html>
Built-in function template page:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>inner Function</title> </head> <body> <b>Get collection size</b><br> Collection size: ${stus?size} <b>Obtained date</b><br> Display year, month and day: ${today?date}<br> Display hours, minutes and seconds: ${today?time}<br> Display date + time: ${today?datetime}<br> Custom formatting: ${today?string("Yyyy year MM month")}<br> <b>Built-in function C</b><br> There is no numerical value displayed by the C function: ${point}<br> There is a value displayed by the C function: ${point?c} <b>Declare variable assign</b><br> <#assign text="{'bank':'ICBC','account':'10101920201920212'}" /> <#assign data=text?eval /> Account opening bank: ${data.bank} Account number: ${data.account} </body> </html>
Built-in function Controller data model:
@GetMapping("innerFunc") public String testInnerFunc(Model model) {<!-- --> //1.1 Xiaoqiang object model data Student stu1 = new Student(); stu1.setName("Xiaoqiang"); stu1.setAge(18); stu1.setMoney(1000.86f); stu1.setBirthday(new Date()); //1.2 Xiaohong object model data Student stu2 = new Student(); stu2.setName("小红"); stu2.setMoney(200.1f); stu2.setAge(19); //1.3 Store the two object model data into the List collection List<Student> stus = new ArrayList<>(); stus.add(stu1); stus.add(stu2); model.addAttribute("stus", stus); // 2.1 Add date Date date = new Date(); model.addAttribute("today", date); // 3.1 Add value model.addAttribute("point", 102920122); return "04-innerFunc"; }
2.4) Static testing
Previous tests used SpringMVC to integrate Freemarker into the project as a view parser (ViewReporter). During work, sometimes it is necessary to use Freemarker's native API to generate static content. Let's learn how to generate text files using the native API.
2.4.1) Requirements analysis
Use freemarker's native API to generate html files from the page. This section tests the method of generating html files:
2.4.2) Static testing
Generate html files based on template files
①: Modify the application.yml file and add the following configuration information for the template storage location. The complete configuration is as follows:
server: port: 8881 #Service port spring: application: name: freemarker-demo #Specify service name freemarker: cache: false #Turn off template caching to facilitate testing settings: template_update_delay: 0 #Check the template update delay time. Set to 0 to check immediately. If the time is greater than 0, caching will be inconvenient for template testing. suffix: .ftl #Specify the suffix name of the Freemarker template file template-loader-path: classpath:/templates #template storage location
②: Create a test class under test
package com.heima.freemarker.test; import com.heima.freemarker.FreemarkerDemoApplication; import com.heima.freemarker.entity.Student; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.io.FileWriter; import java.io.IOException; import java.util.*; @SpringBootTest(classes = FreemarkerDemoApplication.class) @RunWith(SpringRunner.class) public class FreemarkerTest {<!-- --> @Autowired private Configuration configuration; @Test public void test() throws IOException, TemplateException {<!-- --> //freemarker template object, get the template Template template = configuration.getTemplate("02-list.ftl"); Map params = getData(); //synthesis //First parameter data model //Second parameter output stream template.process(params, new FileWriter("d:/list.html")); } private Map getData() {<!-- --> Map<String, Object> map = new HashMap<>(); //Xiaoqiang object model data Student stu1 = new Student(); stu1.setName("Xiaoqiang"); stu1.setAge(18); stu1.setMoney(1000.86f); stu1.setBirthday(new Date()); //Xiaohong object model data Student stu2 = new Student(); stu2.setName("小红"); stu2.setMoney(200.1f); stu2.setAge(19); //Store the two object model data into the List collection List<Student> stus = new ArrayList<>(); stus.add(stu1); stus.add(stu2); //Store List collection data in map map.put("stus", stus); //Create Map data HashMap<String, Student> stuMap = new HashMap<>(); stuMap.put("stu1", stu1); stuMap.put("stu2", stu2); //Store Map data in map map.put("stuMap", stuMap); //Return to Map return map; } }