和Thymeleaf一样,FreeMarker也是一款前端模板,该模板用纯Java语言编写,能很好地同Spring Boot后端框架整合。在该模板中,不仅可以包含HTML等前端元素,也可以从Spring Boot等后端获取元素,以实现数据的动态展示。本文我们就来看看如何实现这个功能,希望小伙伴们看后有什么问题给我留言。
1. Spring Boot整合FreeMarker的简单范例
FreeMarker和Thymeleaf模板一样,都可以从后端接收参数并展示,在如下的FreeMarkerDemo项目中将展示该模板的基本用法,具体的步骤如下:
步骤一:在pom.xml中引入FreeMarker模板的依赖包,关键代码如下:
01 <dependency>
02 <groupId>org.springframework.boot</groupId>
03 <artifactId>spring-boot-starter-freemarker</artifactId>
04 </dependency>
步骤二:编写启动类SpringBootApp.java和控制器类Controller.java,这两个Java文件的代码和ModelAndViewDemo项目中的基本一致,所以不再讲解,读者可以自行查看相关源码。
步骤三:在application.properties文件中编写FreeMarker模板的相关配置,具体代码如下:
01 #指定模板文件的位置
02 spring.freemarker.tempalte-loader-path=classpath:/templates
03 #指定是否开启缓存
04 spring.freemarker.cache=false
05 #指定模板中采用的编码,用了UTF-8以后,就可以展示中文
06 spring.freemarker.charset=UTF-8
07 #指定在使用前需要检查模板的位置
08 spring.freemarker.check-template-location=true
09 #指定模板中页面的格式
10 spring.freemarker.content-type=text/html
11 #指定需要使用HttpServletRequest中的值
12 spring.freemarker.expose-request-attributes=true
13 #指定需要使用Session中的值
14 spring.freemarker.expose-session-attributes=true
15 #指定RequestContext attribute的值
16 spring.freemarker.request-context-attribute=request
17 #指定模板文件的后缀名
18 spring.freemarker.suffix=.ftl
相关的配置值都已经通过注释说明,根据这里的配置,控制器中返回的list将被加上.ftl后缀,形成list.ftl,然后FreeMarker解析器会据此到第2行指定的resources/templates目录下找这个模板文件,并展示数据。
步骤四:在resources/templates目录下编写list.ftl文件,在其中通过FreeMarker模板动态展示数据。注意该模板的前端文件扩展名是.ftl,该文件的具体代码如下:
01 <!DOCTYPE html>
02 <html lang="en">
03 <head>
04 <meta charset="UTF-8">
05 <title>库存列表</title>
06 </head>
07 <body>
08 <tableborder="2">
09 <tr>
10 <td>库存编号</td>
11 <td>库存货物</td>
12 <td>数量</td>
13 <td>描述</td>
14 </tr>
15 <#list stocks as stock>
16 <tr>
17 <td>${stock.ID}</td>
18 <td>${stock.name}</td>
19 <td>${stock.num}</td>
20 <td>${stock.description}</td>
21 </tr>
22 </#list>
23 </table>
24 </body>
25 </html>
这里请注意,是通过第15行的#list标签循环地展示数据的,展示的数据同样来自Spring Boot控制器中的stocks参数,展示时同样会用第17~20行的形式,以参数.属性的方式具体展示参数的每条数据的每个属性元素。
编写完成后启动该项目,并在浏览器中输入
http://localhost:8080/showList,就能看到如图所示的效果,其中库存数据使用FreeMarker模板中的循环语句动态展示。
2 用FreeMarker模板展示分页效果
这里将通过FreeMarker模板分页展示数据的效果,进一步给出该模板的具体用法。这里要用到的项目FreeMarkerWithDB是根据ThymeleafWithDB项目改写而成的。
项目对应的启动类是StringBootApp.java,业务逻辑类是StockService.java,访问数据库所用到的StockRepo.java和业务模型Stock.java完全一致,而控制器类Controller.java和配置文件application.yml以及前端文件listByPage.ftl需要修改。
相同的类文件之前已经分析过,读者可自行阅读本书附带的源码,需要修改的文件具体描述如下:
步骤一:需要修改的Controller.java关键代码如下:
01 @RequestMapping("/listByPage")
02 public ModelAndViewlistByPage(@RequestParam(value = "pageNum", defaultValue ="0") int pageNum, @RequestParam(value = "pageSize",defaultValue = "3") int pageSize) {
03 Page<Stock>stocks=stockService.getStockListByPage(pageNum, pageSize);
04 ModelAndView modelAndView = newModelAndView("listByPage");
05 //传递参数
06 modelAndView.addObject("stocks",stocks.getContent());
07 modelAndView.addObject("currentPage",pageNum);
08 modelAndView.addObject("totalPage",stocks.getTotalPages());
09 return modelAndView;
10 }
这里在第4行创建ModelAndView对象时,指定了该对象将要向listByPage视图返回Stock数据,结合后文提到的配置文件,这里具体会向listByPage.ftl前端文件传输数据。
为了实现分页效果,这里需要通过第7行和第8行代码传输表示当前页的currentPage参数和表示一共多少页的totalPage参数,而包含库存数据的stocks参数则是在第6行设置的,由于ftl文件在循环时只能接收List等类型的集合类数据,因此这里需要调用stocks.getContent方法把数据转换成List<Stock>类型的数据。
步骤二:在application.yml文件中加入JPA和FreeMarker的参数,这里注意配置文件的格式,具体每个参数的含义之前都已经讲过了。
01 spring:
02 jpa:
03 show-sql: true
04 hibernate:
05 dll-auto: validate
06 datasource:
07 url: jdbc:mysql://localhost:3306/stock?serverTimezone=GMT
08 username: root
09 password: 123456
10 driver-class-name: com.mysql.jdbc.Driver
11 freemarker:
12 tempalte-loader-path: classpath:/templates
13 cache: false
14 charset: UTF-8
15 check-template-location: true
16 content-type: text/html
17 expose-request-attributes: true
18 expose-session-attributes: true
19 request-context-attribute: request
20 suffix: .ftl
步骤三:在listByPage.ftl文件中,用FreeMarker模板实现分页的效果,具体代码如下:
01 <!DOCTYPE html>
02 <html lang="en">
03 <head>
04 <meta charset="UTF-8">
05 <title>库存列表</title>
06 </head>
07 <body>
08 <tableborder="2">
09 <tr>
10 <td>库存编号</td>
11 <td>库存货物</td>
12 <td>数量</td>
13 <td>描述</td>
14 </tr>
15 <#list stocks as stock>
16 <tr>
17 <td>${stock.ID}</td>
18 <td>${stock.name}</td>
19 <td>${stock.num}</td>
20 <td>${stock.description}</td>
21 </tr>
22 </#list>
23 </table>
24 <div>
25 <ul>
26 <li>
27 <ahref="/listByPage?pageNum=0">首页</a>
28 </li>
29 <#if (currentPage>0)>
30 <li>
31 <ahref="/listByPage?pageNum=${currentPage-1}">上一页</a>
32 </li>
33 </#if>
34 <#if(currentPage<totalPage-1)>
35 <li>
36 <ahref="/listByPage?pageNum=${currentPage+1}">下一页</a>
37 </li>
38 </#if>
39 <li>
40 <ahref="/listByPage?pageNum=${totalPage - 1}">尾页</a>
41 </li>
42 </ul>
43 </div>
44 </body>
45 </html>
这里在第15~22行代码中用<#list>的形式循环展示了当前页的数据,而在24~43行的<div>标签中用<#if>的形式动态展示了分页的效果。
在分页相关的代码中,在第29行中,先通过<#if>语句用currentPage参数判断当前是不是第1页,如果不是,则通过第30~32行代码展示“上一页”的链接,同样,在第34行的<#if>语句中,通过currentPage<totalPage-1的形式判断当前是不是最后一页,如果不是,则通过第35~37行代码展示“下一页”的效果。
本范例运行后,如果在浏览器中输入
http://localhost:8080/listByPage,就能看到如图所示的分页效果,和之前的范例不同,这里的分页效果是用FreeMarker模板实现的。
(本文是在学习Spring Boot+Vue.js+分布式组件全栈开发训练营一书获得的知识,想了解更多内容可以参考该书)