FreeMarker

前人关于FreeMarker 的总结
         一宗罪:freemarker的变量必须有值,没有被赋值的变量就会抛出异常,那个黄黄的freemarker出错页面,真是让人看了太难过了。
         freemarkerFAQ上面冠冕堂皇的说,未赋值的变量强制抛错可以杜绝很多潜在的错误,如缺失潜在的变量命名,或者其他变量错误。但是实际的效果是:带来的是非常大的编程麻烦,程序里面几乎所有可能出现空值的变量统统需要加上${xxx?if_exists},有些循环条件还需要写if判断,这样不但没有杜绝应该杜绝的错误,反而极大增加了编程的麻烦。
         二宗罪:freemarkermap限定key必须是string,其他数据类型竟然无法操作!这一点就不讲了,JavaEye上面已经有人抱怨过了。连Webwork的开发人员Pat Lightboy都在抱怨这一点。
         三宗罪:freemarker为了编程方便把不可序列化的东西往session里面放!
freemarker支持在页面里面直接操作Sessionrequest等,例如${Session[...]},方便确实很方便,但是一旦需要做群集,就会报错。
         但是这些小错误,个人认为无伤大雅,毕竟WebWork开发小组就是用FreeMaker,那么我们在项目的时候肯会接触到 .ftl 文件,所以花几个单位时间学习下,还是必要的
 

 
现在来看看 FreeMaker 有哪些变量
  • Strings: "Foo" or 'Foo' or "It's /"quoted/"" or  r"C:/raw/string" 最后一种用法要注意
  • Numbers: 123.45
  • Booleans: true, false
  • Sequences: ["foo", "bar", 123.45],   1..100
  • Hashes: {"name":"green mouse", "price":150} 这里注意,lookup name必须是String

下面来看看关于 StringSequenceHash的操作方法
 
有一种很典型的用法错误 <#if ${isBig}>Wow!</#if> ,
Interpolations work only in text sections (e.g. <h1>Hello ${name}!</h1> ) and in string literals
 (e.g. <#include "/footer/${company}.html"> )
you should use the substring built-in; 里面关于String的处理应该是应有尽有了。
 
这里有几个关于Sequence的例子,值得看一下
 

<#assign x = ["red", 16, "blue", "cyan"]>
"blue": ${x?seq_contains("blue")?string("yes", "no")}
"yellow": ${x?seq_contains("yellow")?string("yes", "no")}
16: ${x?seq_contains(16)?string("yes", "no")}
"16": ${x?seq_contains("16")?string("yes", "no")} 
The output will be:

"blue": yes
"yellow": no
16: yes
"16": no 
 
seq_index_of
 
seq_last_index_of 
 
还发现里面居然有排序功能
 

     
 
<#assign ls = ["whale", "Barbara", "zeppelin", "aardvark", "beetroot"]?sort>
<#list ls as i>${i} </#list> 
 
 

     
 
<#assign ls = [
 {"name":"whale", "weight":2000},
 {"name":"Barbara", "weight":53},
 {"name":"zeppelin", "weight":-200},
 {"name":"aardvark", "weight":30},
 {"name":"beetroot", "weight":0.3}
]>
Order by name:
<#list ls?sort_by("name") as i>
- ${i.name}: ${i.weight}
</#list>
 
Order by weight:
<#list ls?sort_by("weight") as i>
- ${i.name}: ${i.weight}
</#list> 
 
 
最后还有一个函数非常之实用
 

<#assign seq = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']>
 
<#list seq?chunk(4) as row>
 <#list row as cell>${cell} </#list>
</#list>
 
<#list seq?chunk(4, '-') as row>
 <#list row as cell>${cell} </#list>
</#list> 
The output will be:

 
 a b c d
 e f g h
 i j
 
 a b c d
 e f g h
 i j - -
 
 
想想以前写网上商城购物系统的时候,从数据库里出来的数据都要把它们转换成几行几列的样子,算法都是自己写的,这种时代要过去了,呵呵
 
Concatenation: passwords + {"joe":"secret42"}   这个没什么好说的了,就一个Concatenation
 

 
·  Arithmetical calculations : (x * 1.5 + 10) / 2 - y % 100  5 个运算符
·  Comparison : x == y , x != y , x < y , x > y , x >= y , x <= y , x &lt; y , ...etc.  因为FreeMarker无法区分大于号和结尾符>的区别,所以最好用括号括起来
·  Logical operations : !registered && (firstVisit || fromEurope)
·  Method call : repeat("What", 3)
·  White-space in expressions   FTL ignores superfluous white-space in expressions
·  Operator precedence  下面是运算符的优先权

Operator group

Operators

postfix operators

[subvarName] [subStringRange] . ? (methodParams) expr!default expr! expr??

unary operators

+expr -expr !expr

multiplicative

* / %

additive

+ -

relational

< > <= >= (and quivalents: gt, lt, etc.)

equality

== != (and equivalents: =)

logical AND

&&

logical OR

||

numerical range

..

Escape sequence
Meaning
/"
Quotation mark (u0022)
/'
Apostrophe (a.k.a. apostrophe-quote) (u0027)
//
Back slash (u005C)
/n
Line feed (u000A)
/r
Carriage return (u000D)
/t
Horizontal tabulation (a.k.a. tab) (u0009)
/b
Backspace (u0008)
/f
Form feed (u000C)
/l
Less-than sign: <
/g
Greater-than sign: >
/a
Ampersand: &
/{
Curly bracket: {
/x Code
Character given with its hexadecimal Unicode code (UCS code)
 
 
<#list 1..8 as x>   注意不要写成 [1..8]
    ${x}<br>
</#list> 
 
/*-----------------以下会出错--------------------*/
 
<#list ["aa",3,true] as x>
    ${x}<br>
</#list> 
 
<#list ["aa",3,[1,2]] as x>
    ${x}<br>
</#list> 
 
Expecting a string, date or number here, Expression x is instead a freemarker.template.TemplateBooleanModel$2
可见,list中只能是string, date or number


先来看看最基本的innerHTML用法

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
>
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Using responseText with innerHTML</title>
    
<script type="text/javascript">
var xmlHttp;

function createXMLHttpRequest() {
    
if (window.ActiveXObject) {
        xmlHttp 
= new ActiveXObject("Microsoft.XMLHTTP");
    }
 
    
else if (window.XMLHttpRequest) {
        xmlHttp 
= new XMLHttpRequest();
    }

}

    
function startRequest() {
    createXMLHttpRequest();
    xmlHttp.onreadystatechange 
= handleStateChange;
    xmlHttp.open(
"GET""innerHTML.xml"true);
    xmlHttp.send(
null);
}

    
function handleStateChange() {
    
if(xmlHttp.readyState == 4{
        
if(xmlHttp.status == 200{
            document.getElementById(
"results").innerHTML = xmlHttp.responseText;
        }    这个地方通过DOM API得到元素

    }

}

</script>
</head>

<body>
    
<form action="#">
        
<input type="button" value="Search for Today's Activities" onclick="startRequest();"/>
    
</form>
    
<div id="results"></div>
</body>
</html>

 
innerHTML.xml

<table border="1">
        
<tr>
            
<th>Activity Name</th>
            
<th>Location</th>
            
<th>Time</th>
        
</tr>
        
<tr>
            
<td>Waterskiing</td>
            
<td>Dock #1</td>
            
<td>9:00 AM</td>
        
</tr>    
        
<tr>
            
<td>Volleyball</td>
            
<td>East Court</td>
            
<td>2:00 PM</td>
        
</tr>      
</table>

下面的例子看看如何用DOM API来修改页面中的信息
<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
>
< html  xmlns ="http://www.w3.org/1999/xhtml" >
< head >
< title > Dynamically Editing Page Content </ title >

< script  type ="text/javascript" >
var xmlHttp;

function createXMLHttpRequest() {
    
if (window.ActiveXObject) {
        xmlHttp 
= new ActiveXObject("Microsoft.XMLHTTP");
    }
 
    
else if (window.XMLHttpRequest) {
        xmlHttp 
= new XMLHttpRequest();
    }

}

    
function doSearch() {
    createXMLHttpRequest();
    xmlHttp.onreadystatechange 
= handleStateChange;
    xmlHttp.open(
"GET""dynamicContent.xml"true);
    xmlHttp.send(
null);
}

    
function handleStateChange() {
    
if(xmlHttp.readyState == 4{
        
if(xmlHttp.status == 200{
            clearPreviousResults();
            parseResults();
        }

    }

}


function clearPreviousResults() {
    
var header = document.getElementById("header");
    
if(header.hasChildNodes()) {
        header.removeChild(header.childNodes[
0]);
    }


    
var tableBody = document.getElementById("resultsBody");
    
while(tableBody.childNodes.length > 0{
        tableBody.removeChild(tableBody.childNodes[
0]);
    }

}


function parseResults() {
    
var results = xmlHttp.responseXML;

    
var property = null;
    
var address = "";
    
var price = "";
    
var comments = "";

    
var properties = results.getElementsByTagName("property");
    
for(var i = 0; i < properties.length; i++{
        property 
= properties[i];
        address 
= property.getElementsByTagName("address")[0].firstChild.nodeValue;
        price 
= property.getElementsByTagName("price")[0].firstChild.nodeValue;
        comments 
= property.getElementsByTagName("comments")[0].firstChild.nodeValue;
        
        addTableRow(address, price, comments);
    }

    
    
var header = document.createElement("h2");
    
var headerText = document.createTextNode("Results:");
    header.appendChild(headerText);
    document.getElementById(
"header").appendChild(header);
    
    document.getElementById(
"resultsTable").setAttribute("border""1");
}



function addTableRow(address, price, comments) {
    
var row = document.createElement("tr");
    
var cell = createCellWithText(address);
    row.appendChild(cell);
    
    cell 
= createCellWithText(price);
    row.appendChild(cell);
    
    cell 
= createCellWithText(comments);
    row.appendChild(cell);
    
    document.getElementById(
"resultsBody").appendChild(row);
}


function createCellWithText(text) {
    
var cell = document.createElement("td");
    
var textNode = document.createTextNode(text);
    cell.appendChild(textNode);
    
    
return cell;
}

</ script >
</ head >

< body >
  
< h1 > Search Real Estate Listings </ h1 >
  
  
< form  action ="#" >
    Show listings from 
        
< select >
            
< option  value ="50000" > $50,000 </ option >
            
< option  value ="100000" > $100,000 </ option >
            
< option  value ="150000" > $150,000 </ option >
        
</ select >  
        to 
        
< select >
            
< option  value ="100000" > $100,000 </ option >
            
< option  value ="150000" > $150,000 </ option >
            
< option  value ="200000" > $200,000 </ option >
        
</ select >  
    
< input  type ="button"  value ="Search"  onclick ="doSearch();" />     
  
</ form >
  
  
  
  
< span  id ="header" >
  
  
</ span >

  
< table  id ="resultsTable"  width ="75%"  border ="0" >
    
< tbody  id ="resultsBody" >
    
</ tbody >
  
</ table >
</ body >
</ html >

<? xml version="1.0" encoding="UTF-8" ?>
< properties >
    
< property >
        
< address > 812 Gwyn Ave </ address >
        
< price > $100,000 </ price >
        
< comments > Quiet, serene neighborhood </ comments >
    
</ property >     
    
< property >
        
< address > 3308 James Ave S </ address >
        
< price > $110,000 </ price >
        
< comments > Close to schools, shopping, entertainment </ comments >
    
</ property >     
    
< property >
        
< address > 98320 County Rd 113 </ address >
        
< price > $115,000 </ price >
        
< comments > Small acreage outside of town </ comments >
    
</ property >     
</ properties >

接下来一个例子实现的是:通过JSON来做到客户端与服务端的大量数据提交,而不再是简单的   .action?id=1&name=wxy&color=red   而是可以传递类似XML的数据结构,甚至对象的传递

<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
>
< html  xmlns ="http://www.w3.org/1999/xhtml" >
< head >
< title > JSON Example </ title >

< script  type ="text/javascript"  src ="json.js" ></ script >
< script  type ="text/javascript" >

var xmlHttp;

function createXMLHttpRequest() {
    
if (window.ActiveXObject) {
        xmlHttp 
= new ActiveXObject("Microsoft.XMLHTTP");
    }
 
    
else if (window.XMLHttpRequest) {
        xmlHttp 
= new XMLHttpRequest();
    }

}

    
function doJSON() {
    
var car = getCarObject();
    
    
//Use the JSON JavaScript library to stringify the Car object
    var carAsJSON = JSON.stringify(car);
将对象通过JSON转化传递到服务器上去,在那里再进行解析
    alert(
"Car object as JSON:  " + carAsJSON);
    
    
var url = "JSONExample?timeStamp=" + new Date().getTime();
    
    createXMLHttpRequest();
    xmlHttp.open(
"POST", url, true);
    xmlHttp.onreadystatechange 
= handleStateChange;
    xmlHttp.setRequestHeader(
"Content-Type""application/x-www-form-urlencoded");    
    xmlHttp.send(carAsJSON);
}    注意这里的POST 与 GET 是不同的。

    
function handleStateChange() {
    
if(xmlHttp.readyState == 4{
        
if(xmlHttp.status == 200{
            parseResults();
        }

    }

}


function parseResults() {
    
var responseDiv = document.getElementById("serverResponse");
    
if(responseDiv.hasChildNodes()) {
        responseDiv.removeChild(responseDiv.childNodes[
0]);
    }

    
    
var responseText = document.createTextNode(xmlHttp.responseText);
    responseDiv.appendChild(responseText);
}


function getCarObject() {
    
return new Car("Dodge""Coronet R/T"1968"yellow");
}


function Car(make, model, year, color) {
    
this.make = make;
    
this.model = model;
    
this.year = year;
    
this.color = color;
}


</ script >
</ head >

< body >

  
< br />< br />
  
< form  action ="#" >
      
< input  type ="button"  value ="Click here to send JSON data to the server"
        onclick
="doJSON();" />
  
</ form >
  
  
< h2 > Server Response: </ h2 >

  
< div  id ="serverResponse" ></ div >

</ body >
</ html >

package  ajaxbook.chap3;

import  java.io. * ;
import  java.net. * ;
import  java.text.ParseException;
import  javax.servlet. * ;
import  javax.servlet.http. * ;
import  org.json.JSONObject;

public   class  JSONExample  extends  HttpServlet  {
    
    
protected void doPost(HttpServletRequest request, HttpServletResponse response)
    
throws ServletException, IOException {
        String json 
= readJSONStringFromRequestBody(request);
        
        
//Use the JSON-Java binding library to create a JSON object in Java
        JSONObject jsonObject = null;
        
try {
            jsonObject 
= new JSONObject(json);
        }

        
catch(ParseException pe) {
            System.out.println(
"ParseException: " + pe.toString());
        }

        
        String responseText 
= "You have a " + jsonObject.getInt("year"+ " "
            
+ jsonObject.getString("make"+ " " + jsonObject.getString("model")
            
+ " " + " that is " + jsonObject.getString("color"+ " in color.";
       
                   轻松进行类型转换
        response.setContentType(
"text/xml");
        response.getWriter().print(responseText);
    }


    
private String readJSONStringFromRequestBody(HttpServletRequest request){
        StringBuffer json 
= new StringBuffer();
        String line 
= null;
        
try {
            BufferedReader reader 
= request.getReader();
            
while((line = reader.readLine()) != null{
                json.append(line);
            }

        }

        
catch(Exception e) {
            System.out.println(
"Error reading JSON string: " + e.toString());
        }

        
return json.toString();
    }

}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值