SSM项目——FreeMarKer

介绍

1、什么是FrreMarker?

中文文档:http://freemarker.foofun.cn/

FreeMarker最初的设计,是被用来在MVC模式的WEB开发框架中生成HTML页面的,它没有被绑定ServletHTML或任意Web相关的东西,它也可以用在非Web应用环境中。

FrreMarker是一款模板引擎:即一种基于模板要改变的数据,并用来生成输出文本(HTML页面,电子邮件,配置文件,源代码等)的通用工具。它不是面向最终用户的,而是一个类库,是一款程序员可以嵌入他们开发产品的组件!

​ 模板编写为FreeMarker Template Language(FTL)。它是简单的,专业的语言,不是想PHP那样成熟的编程语言,那就意味着要准备数据在真实变成虚言中来展示,比如数据库查询和业务运算,之后模板显示已经准备好的数据。在模板中,你可以专注于如何展现数据,而在模板之外可以专注于要展示什么数据。

FreeMarker是 免费的, 基于Apache许可证2.0版本发布。

模板 + 数据模型 = 输出

环境搭建

  1. 创建web项目,在web.xml添加Servet配置

    <!-- FreeMarker 的 Servlet 配置 -->
    <servlet>
        <servlet-name>freemarker</servlet-name>
        <servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class>
        <init-param>
            <!-- 模板路径 -->
            <param-name>TemplatePath</param-name>
            <!-- 默认在 webapp 目录下查找对应的模板文件 -->
            <param-value>/</param-value>
        </init-param>
        <init-param>
            <!-- 模板默认的编码: UTF-8 -->
            <param-name>default_encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </servlet>
    <!-- 处理所有以 .ftl 结尾的文件; ftl 是freemarker默认的文件后缀 -->
    <servlet-mapping>
        <servlet-name>freemarker</servlet-name>
        <url-pattern>*.ftl</url-pattern>
    </servlet-mapping>
    
  2. 创建类继承HttpServlet变成Servlet

    @WebServlet("/ce")
    public class FtlServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doPost(request,response);
        }
    
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
            request.getRequestDispatcher("模板路径.ftl").forward(request,response);
        }
    }
    
  3. 创建模板,用于展示后台数据index.ftl

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>${user}</title>
    </head>
    <body>
        
    </body>
    </html>
    
  4. 配置tomcat运行测试。

FreeMarker 模板中的数据类型,有如下几种:

  • 布尔型:等价于 java 的 Boolean 类型,不同的是不能直接输出,可转换为字符串输出。
  • 日期型:等价于 java 的 Date类型,不同的是不能直接输出,需要转换成字符串再输出。
  • 数字型:等价于 java 的 int,float,double 等数值类型。
    • 有三种显示形式:数值型(默认),货币型,百分比型
  • 字符型:等价于 java 中的 java 中的数组,list,set 等集合类型。
  • hash类型: 等价于 java 中的 Map 类型

一、数据类型

1、布尔类型

  1. 在Servlet中设置布尔类型的数据

    // 布尔类型
    request.setAttribute("flag",true);
    
  2. ftl表达

    <h3>布尔类型</h3>
    ${flag?c}
    ${flag?string}
    ${flag?string("今天你真棒!老陈","糟糕透了,伙计")}
    ${flag?then("yes","no")}
    

2、日期类型

在freemarker 中日期类型不能直接输出;如果输出 要先转成日期型 或字符串

  1. 年月日 ?date
  2. 时分秒 ?time
  3. 年月日时分秒 ?datetime
  4. 指定格式 ?string(“自定义格式”) y:年 M:月 d:日 H:时 m:分 s:秒
  • 在Servlet中设置日期类型的数据

    // 日期类型
    request.setAttribute("creatDate",new Date());
    
  • 在ftl表达展示

    <h3>日期类型</h3>
    ${creatDate?date} <br>
    ${creatDate?time} <br>
    ${creatDate?datetime} <br>
    ${creatDate?string("yyyy/MM/dd HH:mm:ss")} <br>
    

3、数字类型

  1. 转字符串
    1. 普通字符串 ?c
    2. 货币型字符串 ?string.currency
    3. 百分比型字符串 ?string.percent
  2. 保留浮点型数值指定小数位(#表示一个小数位) ?string[“0.###”]
  • 在Servlet中设置数值类型的数据

    // 数据类型
    request.setAttribute("age",20);
    request.setAttribute("salary",50000);
    request.setAttribute("avg",0.56);
    
  • 在ftl表达展示

    <h3>数值类型</h3>
    ${age}  ${salary}   ${avg} <br>
    ${age?c}  ${salary?c}   ${avg?c} <br>
    ${age?c}  ${salary?string.currency}   ${avg?c} <br>
    ${age?c}  ${salary?string.currency}   ${avg?string.percent} <br>
    ${avg?string["0.#"]} <br>
    

4、字符串操作

  1. 截取字符串(左闭右开) ?substring(start,end)
  2. 首字母小写输出 ?uncap_first
  3. 首字母大写输出 ?cap_first
  4. 字母转小写输出 ?lower_case
  5. 字母转大写输出 ?upper_case
  6. 获取字符串长度 ?length
  7. 是否以指定字符串开头(boolean类型) ?srarts_with(“xx”)?string
  8. 是否以指定字符串结尾(boolean类型) ?ends_with(“xx”)?string
  9. 获取指定字符的索引 ?index_of(“xx”)
  10. 替换指定字符串 ?replace(“xx”,“xx”)
  • 在Servlet中设置数值类型的数据

    //         字符串的操作
            request.setAttribute("msg","Hello freemarker");
    
  • 在ftl表达展示

    <h3>字符串操作</h3>
    <#--hello freemarker-->
    字符截取:${msg?substring(1,6)} <br>
    首字母小写:${msg?uncap_first} <br>
    首字母大写:${msg?cap_first} <br>
    转成小写:${msg?lower_case} <br>
    转成大写:${msg?upper_case} <br>
    字符长度:${msg?length} <br>
    是否以'H'开头:${msg?starts_with("H")?string} <br>
    是否以's'结尾::${msg?ends_with("r")?string} <br>
    获取指定字符的索引::${msg?index_of("o")} <br>
    替换指定字符串::${msg?replace("ello","hhh")} <br>
    

5、字符串空值的处理

​ FreeMarker的变量必须赋值,否则会抛出异常,而对于FreeMarker来说,null值和不存在的变量是完全一样的,因为FreeMarker无法理解null值

FreeMarker提供两个运算符来避免空值

  1. ‘!’指定确实变量的默认值
    1. ${value!}:如果 value 值为空,则默认值是空字符串
    2. ${value!“默认值”}:如果 value 值为空,则默认值是‘字符串’默认值
  2. ‘??’:判断是否存在
    1. 如果变量存在返回 true,否则返回false
    2. ${(value??)?string}
  • 在ftl表达展示

    <h3>避免空值</h3>
    <h4>第一种方式~</h4>
    <p>设置默认值</p>
    <#--设置默认值为空字符串-->
    <#--${scr}-->
    <#--如果是空值的话,就指定一个默认的字符-->
    ${scr!"不存在的变量"}
    <h4>第二种方式</h4>
    <p>第二种方式:空值的判断,存在true,不存在 false</p>
    ${scr???then("老陈,今天看起来你真棒","老陈,看起来你今天糟糕透了!")}
    <hr>
    

6、sequence类型

作用代码
遍历集合<#list starts as str>
下标?index
获取数组长度?size
获取第一个元素?first
获取最后一个元素?last
顺序输出<#list citysList as city>
倒序输出<#list citysList?reverse as city>
升序输出<#list citysList?sort as city>
降序输出<#list citysList?sort?reverse as city>
对象集合操作${person.id}
指定字段排序<#list personList?sort_by("id") as person>
  1. 在Servlet中设置序列类型的数据

    //          sequence类型
            String[] starts = new String[]{"周杰伦","林俊杰","陈奕迅","五月天"};
            request.setAttribute("starts",starts);
            List<String> citys = Arrays.asList("北京","上哈","广州","深圳");
            request.setAttribute("citysList",citys);
    
            List<Person> personList = new ArrayList<Person>();
            personList.add(new Person(1,"小明"));
            personList.add(new Person(2,"小华"));
            personList.add(new Person(3,"校长"));
            request.setAttribute("personList",personList);
    
  2. 在ftl表达展示

    <#--遍历集合和数组,index是下标-->
    <#list starts as str>
        ${str?index}--${str}
    </#list>
    <br>
    <#list citysList as city>
        ${city?index}--${city}
    </#list>
    <#--获取数组长度-->
    city数组的长度:${citysList?size} <br>
    <#--获取第一个元素-->
    获取第一个元素:${citysList?first}  <br>
    <#--获取最后一个元素-->
    获取最后一个元素:${citysList?last} <br>
    <#--顺序输出-->
    顺序输出:
    <#list citysList as city>
        ${city}
    </#list><br>
    <#--倒序输出-->
    倒序输出:
    <#list citysList?reverse as city>
        ${city}
    </#list><br>
    <#--升序输出-->
    升序输出:
    <#list citysList?sort as city>
        ${city}
    </#list><br>
    <#--降序输出-->
    降序输出:
    <#list citysList?sort?reverse as city>
        ${city}
    </#list><br>
    <#--对象序列操作 通过get获取私有字段-->
    <span>对象序列操作:</span>
    <#list personList as person>
        编号:${person.id} -- 姓名:${person.name}<br>
    </#list>
    <#--指定字段排序-->
    <span>指定字段排序:</span>
    <#list personList?sort_by("id") as person>
        编号:${person.id} -- 姓名:${person.name}<br>
    </#list>
    

7、Hash Map类型

  • Map两种遍历的方法

    1. 获取键的集合,然后遍历键的集合

      <#list cityMap?keys as key>
          ${key}--${cityMap[key]} <br>
      </#list>
      
    2. 直接获取值得集合,进行遍历

      <#list cityMap?values as value>
          ${value} <br>
      </#list>
      
  1. 在Serv;et中设置hash类型的数据

    //        Map操作
    Map<String,String> cityMap = new HashMap<String, String>(3);
    cityMap.put("sh","上海");
    cityMap.put("bj","北京");
    cityMap.put("sz","深圳");
    request.setAttribute("cityMap",cityMap);
    
  2. 在ftl页面展示

    <h3>hash数据类型</h3>
    <#--key遍历输出-->
    <#list cityMap?keys as key>
        ${key}--${cityMap[key]} <br>
    </#list>
    <#--value遍历输出-->
    <#list cityMap?values as value>
        ${value} <br>
    </#list>
    

二、常见指令

1、自定义变量指令

​ 使用assign指令,可以创建一个新的变量,或者替换一个已经存在的变量

  • assign
    <#assign str = "hello">
    ${str}
    
    <#assign num=1 names=["长大","w阿萨德","电饭锅"]>
    ${num} -- ${names?join(",")}

2、逻辑判断指令

​ 可以使用if,elseif和else指令来条件判断是否满足某些条件。

  • if
  • elseif
  • else
    <#assign score=75>
    <br>
    <#if score gt 90>
        优秀
        <#elseif score gt 70>
        还行
        <#else>
        继续努力
    </#if>
<#--判断数据是否存在-->
    <#assign list = "">
    <#if list??>
        数据存在
        <#else>
        数据不存在
    </#if>

3、自定义指令

​ 可以使用macro指令来自定义一些自定义指令

<#--    自定义宏-->
    <#macro nm>
        指令内容
    </#macro>
    <@nm></@nm>

带参数的宏

<#--    带参宏-->
    <#macro nm2 score>
        <#if score=90>
            天才
            <#elseif score=70>
            中不溜
            <#else>
            糟糕透了
        </#if>
    </#macro>
    <@nm2 score=60></@nm2>

定义指令中包含内置指令的自定义指令

<#macro cfb num>
    <#list 1..num as i>
        <#list 1..i as j>
            ${j} * ${i} = ${j*i}&nbsp;
        </#list>
        <br>
    </#list>
</#macro>
<@cfb num=9></@cfb>

4、占位指令

​ nested指令执行自定义指令开始和结束标签中间的模板片段,嵌套的片段可以包含模板中任意合法的阵容

<#macro nm>
    <#nested>
    指令内容
    <#nested>
</#macro>
<@nm>站位指令</@nm>

5、improt导入指令

​ import指令可以引入一个库,它创建一个新的空命名空间,然后在哪个命名空间中执行路径的模板,可以使用引入空间中的指令。

  • commons.ftl (组件:可能被多个页面调用)

    • <#--    带内置指令的宏-->
      <#macro cfb num>
          <#list 1..num as i>
              <#list 1..i as j>
                  ${j} * ${i} = ${j*i}&nbsp;
              </#list>
              <br>
          </#list>
      </#macro>
      <@cfb num=9></@cfb>
      
  • order.ftl(调用组件:import)

    • <#import "commons.ftl" as commons>
      <@commons.cfb num=10></@commons.cfb>
      

6、include包含指令

​ 可以使用include指令在你的模板中插入另一个FreeMarker模板文件,被包含模板的输出格式是include标签中出现的位置插入的,被包含的文件和包含它的模板共享变量,就像是被复制站填进去一样的。

  • indes.ftl

    • <#assign str="老陈你真棒!">
      
  • Order.ftl(include 可以就和粘贴到这里一样,)

    • <h3>包含模板</h3>
          <#include "indes.ftl">
          ${str}
      

三、页面静态化

​ 通过上述介绍可知FreeMarker是一种基于模板的,用来生成输出文本的通用工具,所以我们必须要定制符合自己业务的模板,然后生成自己的html页面,FreeMarker是通过freemarker,template,Configuration这个对象对模板进行加载的(它也处理创建和缓存与解析模板的工作)然后我们通过getTemplate方法获得你想要的模板,有一点要记住,freemarker,template,Configuration在你整个应用必须保证唯一实例。

  1. 什么是网页静态化技术:
    • 随着用户访问量及数据量的增大,网页静态化技术方案如今越来越流行。到底什么是网页静态化技术呢?简单来说就是将页面以纯静态方式的形式展现。
  2. 网页静态化技术与缓存技术的比较。
    1. 共同点,都可以减小数据库的访问压力。
    2. 区别:
      1. 缓存技术适用于小规模的数据,以及一些不经仓变动的数据。
      2. 网页静态化技术适用于大规模但是变化不太频繁的数据。
  3. 网页静态化技术的应用场景:
    1. 新闻门户网站的文章类型频道一般都用到了网页静态化技术,点击新闻直接跳到静态化而页面。
    2. 电商网站的商品详情页也十分常见,我们在存储商品的时候会生成静态化页面,点击商品详情,会直接跳到生成的商品详情的静态化页面。
    3. 此外网页静态化及数可以结合inx这种高性能web服务器来提高并发访问量。
  4. 什么是FreeMarker?
    • FreeMarker是一款用于Java语言编写的模板引擎,用它可以通过模板和要更改的数据来生成输出文本(例如HTML网页,配置文件,源代码等)作为用来实现网页静态化及技术的一种手段,FreeMarker的使用大大超过了其他一些技术,对于系统中频繁使用数据库进行查询但是内容更新很小的应用,都可以用FreeMarker将网页静态化,这样就避免了大量的数据库访问请求,从而提高网站的性能。

定义模板

  • news.ftl

    <!DOCTYPE html>
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title>Aaron</title>
    </head>
    <body>
        <h2 align="center">${title}</h2>
        <p align="center">
            新闻来源:${source} &nbsp;&nbsp;
            发布时间:${pubTime}
        </p>
        <p style="text-indent: 2em">
            ${content}
        </p>
    </body>
    </html>
    
  • 编写Servlet

    NewsServlet.java

    // 创建一个模板对象
    Configuration configuration = new Configuration();
    // 设置加载上下文
    configuration.setServletContextForTemplateLoading(getServletContext(),"/template");
    // 设置模板的编码
    configuration.setDefaultEncoding("utf-8");
    // 获取对应的模板对象
    Template template = configuration.getTemplate("news.ftl");
    // 设置填充的数据
    Map<String,Object> map = new HashMap<String, Object>(4);
    map.put("title","新闻中心");
    map.put("source","中国");
    map.put("pubTime",new Date());
    map.put("content","网页静态化,这样就避免了大量的数据库访问请求,从而提高网站的性能。");
    // 获得项目的目录
    String realPath = request.getServletContext().getRealPath("/");
    // 在根目录创建文件夹
    File newsFile = new File(realPath+"/html");
    if (!newsFile.exists()){
        newsFile.mkdirs();
    }
    // 获取生成的文件名(生成随机名称)
    
    String fileName = System.currentTimeMillis()+".html";
    // 创建文件对象
    File file = new File(newsFile,fileName);
    // 获取输出流
    OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file),"utf-8");
    // 生成HTML文件
    try {
        template.process(map,writer);
    } catch (TemplateException e) {
        e.printStackTrace();
    }finally {
        writer.flush();
        writer.close();
    }
    

四、整合FreeMarker

  1. 首先在pom.xml导入FreeMarker依赖

    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.23</version>
    </dependency>
    
  2. 配置freemarker,告诉项目模板的位置,/WEB-INF/views/ 并将视图解析器,换成freemarker的视图解析器

       <!--配置freeMarker的模板路径 -->
    <bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
       <!-- 配置freemarker的文件编码 -->
       <property name="defaultEncoding" value="UTF-8" />
       <!-- 配置freemarker寻找模板的路径 -->
       <property name="templateLoaderPath" value="/WEB-INF/views/" />
    </bean>
    
    <!--freemarker视图解析器 -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
       <!-- 是否在model自动把session中的attribute导入进去; -->
       <property name="exposeSessionAttributes" value="true" />
       <!-- 配置逻辑视图自动添加的后缀名 -->
       <property name="suffix" value=".ftl" />
       <!-- 配置视图的输出HTML的contentType -->
       <property name="contentType" value="text/html;charset=UTF-8" />
    </bean>
    

当把freemarker和springmvc进行结合后,就可以编写页面的内容了

分析personal.ftl模板(嵌套信息)

  1. 导入头部组件<#include "common/head-tpl.ftl"/>

  2. 在个人中心创建变量作为标识<#assign currentNav="personal" />

    1. 在外部组件中有判断这个变量是否为空,

      1. 为空证明是登录过来的,让指定导航项选中
      2. 不为空证明不是登录过来的,不选选中
      <#if currentMenu??>
      <script type="text/javascript">
         $(".list-group-item li[name=${currentMenu}]").addClass("active");
      </script>
      </#if>
      
  3. 导入菜单组件<#include "common/navbar-tpl.ftl"/>

  4. 导入左部导航组件<#include "common/leftmenu-tpl.ftl" />

  5. 判断用户是否绑定Email<#if !userinfo.isBindPhone >

  6. 导入底部导航<#include "common/footer-tpl.ftl" />

展示个人中心

个人中心类personal.ftl

编码时从自底向上写,思考逻辑时从上向底思考。

思考:从上向底

  1. 点击登录

    • 控制器会调用业务层进行查询,把结果交给工具类UserContext.putCurrent(logininfo);放到Session对象中。
  2. 登录成功

    • 跳转到个人中心控制类PersonalController,通过登录用户的id(上面登录成功后把用户的信息通过工具类UserContext放到Session中了,用户信息中就包括了ID,因为这三个表的ID一致,所有可以通过此ID查出用户信息和账户信息的所有信息)可以把用户信息Account和账户信息Userinfo的信息查出来,放到Model中让个人中心展示。
    • 通过登录用户的ID想要查出用户信息Account和账户信息Userinfo的信息
      • 需要分别在各自的业务层实现通过ID查信息的功能。Account getById(Long id);
  3. 展示个人中心

    • return "personal"后,会通过视图解析器,在上面已经把视图解析器换成了FreeMarker的解析器了。
    • 通过解析器可以找到personal.ftl个人中心。

    注意点:

    • 个人中心页面会把Model的信息展示出来,不过账户总额的信息在用户的实体类中是没有对应的字段的,但是为什么会正常的显示出来呢?

      • 因为这个字段有get方法并且返回的类型是BigDecimal类型

        1. 只有get方法就能展示字段是因为:“Spring已经帮助我们对内容进行了封装操作,只需要有get相关的方法,那么就会封装一个对应的属性。
      • BigDecimal类型:可以加减乘除,进行精确运算,add(),可以进行累加操作。

        ​ 详情网址:https://www.cnblogs.com/zhangyinhua/p/11545305.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值