Spring整合JSP,Freemarker(ftl)基本使用

FTL自己用得比较少,这里做个备份记录,以免忘记。

Freemarker这里先扯淡两句,在单纯的页面使用上来说和JSP个人感觉没有太大的区别,都有比较多的类库支持,不过相对的如果FTL没有做静态化相对的还是JSP的速度要快一些。但是为什么还是有很多项目用freemarker,网上也有很多文章,这里偷个懒,传送门:http://blog.csdn.net/qq897958555/article/details/53560655

我这里比较传统用的IDE工具是Myeclipse2014,所有如果想要有ftl格式的东东高亮支持的话需要配置下插件,同样的网上一大把,这里也偷懒了,传送门:http://blog.csdn.net/ylyanglei/article/details/50464515

在项目中,Spring是支持多个前段引擎的,只是需要在Spring的配置文件中去配置一下,就可以同时支持JSP和FLT了。除了Spring需要的jar外还需要Freemarker的jar支持,这里我用的freemarker.jar
完整的XML

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-3.0.xsd
                        http://www.springframework.org/schema/mvc
                        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <!-- 开启springmvc的注解支持 -->
    <mvc:annotation-driven conversion-service="tc" />
    <!-- 定义静态资源 -->
    <mvc:resources location="/static/" mapping="/static/**" />

    <!-- 制定扫描规则 -->
    <context:component-scan base-package="com">
        <!-- 制定过滤器 -->
        <context:include-filter type="annotation"
            expression="org.springframework.stereotype.Controller" />
        <context:exclude-filter type="annotation"
            expression="org.springframework.stereotype.Repository" />
        <context:exclude-filter type="annotation"
            expression="org.springframework.stereotype.Service" />
    </context:component-scan>

    <!-- 可以配置一个全局类型转换器 -->
    <!-- 配置spring定义的转换工厂类 -->
    <bean id="tc"
        class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="com.lovo.converter.GlobalDateConverter"></bean>
            </set>
        </property>
    </bean>


    <!-- 配置http消息体数据与JSON转换 -->
    <bean
        class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
            <list>
                <ref bean="mappingJackson2HttpMessageConverter"></ref>
            </list>

        </property>
    </bean>
    <!-- 配置HTTP消息信息与JSON对象之间的一个转换器 -->
    <bean id="mappingJackson2HttpMessageConverter"
        class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
    </bean>

    <!-- 视图解析器 JSP -->
    <bean id="urlBasedViewResolver"
        class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass"
            value="org.springframework.web.servlet.view.JstlView"></property>
        <property name="prefix" value="/WEB-INF/jsp/"></property>
        <property name="suffix" value=".jsp"></property>
        <property name="order" value="1"/>
    </bean>
    
    <!-- 视图解析器 FTL -->
    <bean id="viewResolverFtl" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView"/>
        <property name="contentType" value="text/html; charset=UTF-8"/>
        <!-- 将请求和会话属性作为变量暴露给FreeMarker模板使用。要做到这一点,
                       可以设置exposeRequestAttributes或者exposeSessionAttributes为true 
        -->
        <property name="exposeRequestAttributes" value="true" />
        <property name="exposeSessionAttributes" value="true" />
        <!-- 使用这些宏,必须设置FreeMarkerViewResolver的exposeMacroHelpers属性为true -->  
        <property name="exposeSpringMacroHelpers" value="true" />
        <!-- 使用缓存 -->
        <property name="cache" value="true" />
        <property name="suffix" value=".ftl" />
        <property name="order" value="0"/>
    </bean>
    <!-- 配置freeMarker的模板路径 -->
    <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
        <property name="templateLoaderPath" value="/WEB-INF/ftl/"/>
        <property name="freemarkerVariables">
            <map>
                <entry key="xml_escape" value-ref="fmXmlEscape" />
            </map>
        </property>
        <property name="defaultEncoding" value="UTF-8"/>
        <!-- FreeMarker默认每隔5秒检查模板是否被更新,如果已经更新了,就会重新加载并分析模板。 
                       但经常检查模板是否更新可能比较耗时。如果你的应用运行在生产模式下,而且你预期模板不会经常更新,   
             则可以将更新的延迟时间延长至一个小时或者更久。 可以通过为freemarkerSettings属性设置template_update_delay达到这一目的 
        -->  
        <property name="freemarkerSettings">
            <props>
                <prop key="template_update_delay">3600</prop>
                <!-- 设置标签类型 两种:[] 和 <> 。[] 这种标记解析要快些 --> 
                <prop key="tag_syntax">auto_detect</prop> 
                <prop key="default_encoding">UTF-8</prop>  
                <prop key="output_encoding">UTF-8</prop>  
                <prop key="locale">zh_CN</prop>
                <!-- 设置时间格式 -->
                <prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop>
                <prop key="date_format">yyyy-MM-dd</prop>
                <!-- 设置数字格式 -->  
                <prop key="number_format">#.##</prop>
                <!-- 可以满足一般需要。默认情况变量为null则替换为空字符串,如果需要自定义,写上${empty!"EmptyValue of fbysss"}的形式即可  -->
                 <prop key="classic_compatible">true</prop>
            </props>
        </property>
    </bean>
    <bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape"/>

    <!-- 配置MultipartResolver 用于文件上传 使用spring的CommosMultipartResolver 说明: p:defaultEncoding="UTF-8":这里设置默认的文件编码为UTF-8,必须与用户JSP的默认编码一致; 
        p:maxUploadSize="5000000":指定文件上传大小,单位为字节; p:uploadTempDir="fileUpload/temp":文件上传临时目录,上传完成后,就会将临时文件删除; -->
    <bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
        p:defaultEncoding="UTF-8" p:maxUploadSize="5000000" p:uploadTempDir="fileUpload/temp">
    </bean>
</beans>

需要注意一下的是如果只需要FTL作为模板不作为前段引擎,可以不配置视图解析器,如果配置了多个视图解析器,其他视图解析器的优先级一定要高于JSP才行。

 <property name="order" value="0"/>

配置完了后写个简单的controller,用法和传统的后台封装参数,前台写JSP写EL表达式一样

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping(value="/ftl")
public class ftlController {
    
    @RequestMapping(value="/firstFtl.do",method=RequestMethod.GET)
    public String  index(HttpServletRequest requset,HttpServletResponse response,Model mode) {
       
        mode.addAttribute("msg", "hi freemarker");
        
        return "MyFtl";
    }

}

<!DOCTYPE html>
<html>
  <head>
    <title>MyHtml.html</title>
    
    <meta name="keywords" content="keyword1,keyword2,keyword3">
    <meta name="description" content="this is my page">
    <meta name="content-type" content="text/html; charset=UTF-8">
    
    <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->

  </head>
  
  <body>
    <b>${msg}</b>
  </body>
</html>
image.png

首先科普下
FreeMarker模板文件主要有4个部分组成
1、文本,直接输出的部分
2、注释,即<#--...-->格式不会输出
3、插值(Interpolation):即${..}或者#{..}格式的部分,将使用数据模型中的部分替代输出
4、FTL指令:FreeMarker指令,和HTML标记类似,名字前加#予以区分,不会输出。

Freemarker支持各种后台的常用类型,页面也支持条件判断,逻辑运算,首先,我们测试下最常用的后台封装list,前台循环出来,在通过条件去判断

 @RequestMapping(value="/expression.do")
    public String expressionTest(HttpServletRequest requset,HttpServletResponse response,Model mode)
    {
        //页面测试用集合,简单数据类型
        
        List<Object> testList = new ArrayList<Object>();
        
        testList.add("1");
        testList.add("2");
        testList.add("3");
        mode.addAttribute("list",testList);
        return "expressionTest";
        
    }`这里写代码片`
<!DOCTYPE html>
<html>
  <head>
    <title>MyHtml.html</title>
    
    <meta name="keywords" content="keyword1,keyword2,keyword3">
    <meta name="description" content="this is my page">
    <meta name="content-type" content="text/html; charset=UTF-8">
    
    <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->

  </head>
  
  <body>
    <div >
        <#--在jsp中${}表达式会直接忽略不显示,而freemarker会报异常,还是一大堆,freemarker就需要您手动去处理-->
        <#--  ?? 用于判断是否为空   ?number将字符串转换为数字-->
        <#if list??>
        <span>集合长度:${list?size} </span><br>
        <#list list as a >
            集合的下标:${a_index}
            当前集合值:${a}&nbsp;
            <#if a?number%2==0>偶数
            <#else>奇数
            </#if>
            <br>
        </#list>
        <#else>
        集合为空
        </#if>
        
    
    </div>
  </body>
</html>

image.png

这里可以发现在用JSP的过程中我们一般不会对null值进行特殊的处理判断,JSP默认会处理,当为null时显示为空。但是在FLT模板中并不会这样,如果未进行非空判断,而直接进行取值,会抛出异常。通常有两种方式进行处理。

例如现在有个user对象,里面有角色属性
方式1:配置classic_compatible=true,此种方式只能判断一层,如user.role为null,显示为空,若user为空,则仍会发生异常。
方式2:使用!或者??

${list!'集合为空'}

如果集合为空会显示空

?? 用于判断是否为空

<#if user.role??>
 当前用户没有权限角色
 <#else>
 当前用户有权限角色
</#if>

${user.role???string}<#--这里将结果以字符串的形式输出:true 或者false-->
${user.role???string("YES","NO")} <#--这判定用户权限角色为空 -->
${user.role!"当前用户没有角色"}
<#--获取当前用户的角色:${user.role.rolename!}  而role任然没值的时候依然会报错,而正确的方式<br/>获取当前用户的角色:${(user.role.rolename)!}-->

来完整的处理个null,首先建立一个简单的user对象

package com.lovo.beans;

import java.io.Serializable;

public class UserBean implements Serializable{

    /**
     * 省略get set方法
     */
    private static final long serialVersionUID = -2959897964759682757L;
    
    private Long id;
    private String name;
    private String sex;
    private Long age;
    
}

控制器

@RequestMapping(value="/expressionUser.do")
    public String expressionUset(HttpServletRequest requset,HttpServletResponse response,Model mode)
    {
        
        UserBean bean = new UserBean();
        bean.setName("小明");
        bean.setAge(20L);
        bean.setSex(null);
        //不对classBean做null处理
        bean.setClassBean(null);
        mode.addAttribute("user", bean);
        
        return "expressionUser";
    }

FTL模板

<!DOCTYPE html>
<html>
  <head>
    <title>MyHtml.html</title>
    
    <meta name="keywords" content="keyword1,keyword2,keyword3">
    <meta name="description" content="this is my page">
    <meta name="content-type" content="text/html; charset=UTF-8">
    
    <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->

  </head>
  
  <body>
    <div >
        姓名:<input type = "text" value="${user.name}"/><br>
        性别:<input type = "text" value="${user.age}"/><br>
        年龄:<input type = "text" value="${user.sex}"/><br>
        班级:<input type = "text" value="${user.classBean.className}"/>
    </div>
  </body>
</html>

会发现报错

image.png
image.png

这个时候用!和??处理下!是直接做null判断,后面可以跟值,如果不写,显示为空字符串,??是做是否为空判断,多用作if else中,也可以输出默认值???需用???string("yes","no")

<!DOCTYPE html>
<html>
  <head>
    <title>MyHtml.html</title>
    
    <meta name="keywords" content="keyword1,keyword2,keyword3">
    <meta name="description" content="this is my page">
    <meta name="content-type" content="text/html; charset=UTF-8">
    
    <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->

  </head>
  
  <body>
    <div >
        姓名:<input type = "text" value="${user.name}"/><br>
        性别:<input type = "text" value="${user.age}"/><br>
        年龄:<input type = "text" value="${user.sex!}"/><br>
        班级:<input type = "text" value="${(user.classBean.className)!}"/>
        班级:<input type = "text" value="<#if (user.classBean.className)??></#if>"/>
        班级:<input type = "text" value="${(user.classBean.className)???string("班级不为空","班级为空")}"/>
    </div>
  </body>
</html>


image.png

在页面使用FTL时,不可避免的会操作变量,在Freemarker中变大大致可以分为4种。

  1. 数据模型变量,后台封装的变量参数传递到模板中
  2. 模板中的变量使用,用<#assign>定义
  3. 局部变量,在指令中的变量
  4. 循环变量,在循环中的变量

数据模型变量,可以在后台封装成对象,list,map等,这里举例字符串

@RequestMapping(value="/expressionAssagin.do")
    public String expressionAssagin(HttpServletRequest requset,HttpServletResponse response,Model mode)
    {
        mode.addAttribute("root", "后台封装的变量");
        return "expressionAssagin";
    }
<b>${root}</b>

页面显示


image.png

<#assign>定义的变量

<body>
        后台封装的变量:<b>${root}</b></br>
        页面定义的变量:
     <#assign username="李四">
     ${username}
    
  </body>
image.png

当页面定义的assign变量名与数据模型变量名相同时,优先展示页面定义的assign变量,不是覆盖数据模型变量,可以使用.globals进行展示

<body>
    <#assign root="页面变量优先于数据模型变量展示">
        优先展示:<b>${root}</b></br>
        指定展示:<b>${.globals.root}</b></br>
        
     页面定义的变量:
     <#assign username="李四">
     ${username}
</body>
image.png

局部变量

<body>
    <#assign root="页面变量优先于数据模型变量展示">
        优先展示:<b>${root}</b></br>
        指定展示:<b>${.globals.root}</b></br>
        
        页面定义的变量:
     <#assign username="李四">
     ${username}<br>
     
     <#--使用local可以声明局部变量,所以在marco宏中局部变量-->
     <#macro test>
        <#--此时当调用该指令之后,会将模板中的变量覆盖,不能使用globals,一般不使用这种方式在指令中定义变量-->
        <#local  username="我的名字变了"/>
        <#local  sex="性别是保密的"/>
        姓名:${username!}&nbsp;性别${sex!}</br>
     </#macro>
     <#--调用宏-->
     <@test/>
     ${sex!"局部变量外部是调用不到的"}
  </body>
image.png

循环变量,就是在循环体重使用的变量

<#--循环变量-->
     <#list 1..3 as num>
     <#--只能在循环体中使用-->
        ${num}
     </#list>
     ${num!"循环变量出了循环体就消失了"}
image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容