Freemaker_入门+深入+开发指南+学习笔记

Freemaker 入门+深入+开发指南+学习笔记

freemaker的基本语法

freemaker的基本语法:
<# ... > 中存放所有freemaker的内容,之外的内容全部原样输出。
<@ ... /> 是函数调用
两个定界符内的内容中,第一个符号表示指令或者函数名,其后的跟随参数。freemaker提供的控制包括如下:
<#if condition><#elseif condition><#else> 条件判断
<#list hash_or_seq as var> 遍历hash表或者collection(freemaker称作sequence)的成员
<#macro name param1 param2 ... ><#nested param> 宏,无返回参数
<#function name param1 param2><#return val> 函数,有返回参数
var?member_function(...) 用函数对var进行转换,freemaker称为build-ins。实际内部实现类似member_function(var, ...)
stringA[M .. N] 取子字符串,类似substring(stringA, M, N)
{key:value, key2:value2 ...} 直接定义一个hash表
[item0, item1, item2 ...] 直接定义一个序列
hash0[key0] 存取hash表中key对应的元素
seq0[5] 存取序列指定下标的元素
<@function1 param0 param1 ... /> 调用函数function1
<@macro0 param0 param1 ; nest_param0 nest_param1 ...> nest_body 调用宏,并处理宏的嵌套
<#assign var = value > 定义变量并初始化
<#local var = value> 在 macro 或者 function 中定义局部变量并初始化
<#global var = value > 定义全局变量并初始化
${var} 输出并替换为表达式的值
<#visit xmlnode> 调用macro匹配xmlnode本身及其子节点
<#recurse xmlnode> 调用macro匹配xmlnode的子节点

 

FreeMaker一篇通[【转】

FreeMaker一篇通[【转】

2007-08-09 19:38

FreeMaker一篇通

前言

Freemaker是一个强大的模板引擎,相比velocity而言,其强大的过程调用、递归和闭包回调功能让freemaker可以完成几乎所有我们所想的功能。从个人看法而言,freemaker完全有能力作为MDA的代码辅助生成工具。
本文试图越过传统的概念性介绍,通过一组例子直接把读者带入到Freemaker应用的较高层阶。

正文

大家看文章标题就应该知道,我想用一篇文章,把大家从对freemaker的陌生直接带入到比较深入的境界,所以不想说一些基础性的东西,如果大家不习惯我的表达方法,大可通过google去找习惯于自己阅读方式的相关文章。

我用过velocity,最近才用freemaker,才知道我以前的选择是错了,因为velocity不支持过程的调用,所以我为velocity增加了很多的东西,写了很多代码,而且脚本也累赘得要命。freemaker首先吸引我的是它强大的过程调用和递归处理能力,其次则是xml风格的语法结构有着明显的边界,不象velocity要注意段落之间要留空格。所以我建议大家直接使用Freemaker,虽然freemaker没有.net版本,我想不嵌入程序中使用的话,freemaker是绝对的首选。(题外话,谁有兴趣移植一个NFreeMaker?)

在使用之前我们先要设置运行环境,在使用Freemaker的时候,我们需要下载相关的程序:
freemaker: http://freemarker.sourceforge.net/
fmpp: http://fmpp.sourceforge.net/

其中fmpp是一个freemaker的辅助工具,有了它,我们可以实现更多的功能。以下例子必须fmpp辅助。

这里我们首先提出问题。大家看如下的一个xml文件,虽然freemaker的能力不仅在于处理xml文件,但是用xml作为例子更直观一些:


http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:DruleForm-Lite.xsd">
        
            
                

            
                
                    

            

            
            
            
                
                    
                         
                

            

            
        
        
            
        

    

[代码1]
我们的任务是把这个文件转化为相应的C#代码。大家先看转换模板的代码:

1<#ftl ns_prefixes={"ns": "urn:DruleForm-Lite.xsd"}>
2<#-- 定义xml namespace,以便在以下代码中使用,注意,ftl指令必须使用单独的行 -->
3<@pp.setOutputEncoding encoding="gb2312" /> <#-- 使用fmpp提供的函数来设置输出编码 -->
4
5<#recurse doc> <#-- 根入口,代码1部分的xml存放在变量doc中,doc变量的填充由fmpp根据config.fmpp中的配置进行 -->
6
7<#macro "ns:types"> <#-- xslt风格的匹配处理入口 -->
8<#recurse> <#-- 直接进行types节点内的匹配 -->
9
10
11<#macro "ns:type"> <#-- 匹配type节点 -->
12 class ${.node.@name} <#-- 其中.node是保留字,表示当前节点,引用的@name是xslt风格 -->
13 {
14   <#recurse> <#-- 继续匹配 -->
15 }
16
17
18<#macro "ns:field">
19   public ${.node.@type}${.node.@name};
20
21
22<#macro @element> <#-- 所有没有定义匹配的节点到这里处理 -->
23
24
25
[代码2]

我们使用的配置文件设置如下:

sourceRoot: src
outputRoot: out
logFile: log.fmpp
modes: [
copy(common/**/*.*, resource/*.*)
     execute(*.ftl)
ignore(templates/*.*, .project, **/*.xml, xml/*.*, *.js)
]
removeExtensions: ftl
sourceEncoding: gb2312
data: {
doc: xml(freemaker.xml)
}

[代码3]

然后我们在dos模式下运行指令:
E:\work\blogs\freemaker>f:\download\freemaker\fmpp\bin\fmpp

最后的输出结果是这样的,存放在文件out\freemaker.中:

     class Type1
     {
         public Float Field11;
         public String Field12;
         public Integer Field13;
         public Type2 Field14;
         public Float Field15;
     }

     class Type3
     {
         public Type1 Field31;
     }

[代码4]

先来解释一下freemaker的基本语法了,
<# ... > 中存放所有freemaker的内容,之外的内容全部原样输出。
<@ ... /> 是函数调用
两个定界符内的内容中,第一个符号表示指令或者函数名,其后的跟随参数。freemaker提供的控制包括如下:
<#if condition><#elseif condition><#else> 条件判断
<#list hash_or_seq as var> 遍历hash表或者collection(freemaker称作sequence)的成员
<#macro name param1 param2 ... ><#nested param> 宏,无返回参数
<#function name param1 param2><#return val>函数,有返回参数
var?member_function(...) 用函数对var进行转换,freemaker称为build-ins。实际内部实现类似member_function(var, ...)
stringA[M .. N] 取子字符串,类似substring(stringA, M, N)
{key:value, key2:value2 ...} 直接定义一个hash表
[item0, item1, item2 ...] 直接定义一个序列
hash0[key0] 存取hash表中key对应的元素
seq0[5] 存取序列指定下标的元素
<@function1 param0 param1 ... /> 调用函数function1
<@macro0 param0 param1 ; nest_param0 nest_param1 ...> nest_body 调用宏,并处理宏的嵌套
<#assign var = value > 定义变量并初始化
<#local var = value> 在 macro 或者 function 中定义局部变量并初始化
<#global var = value > 定义全局变量并初始化
${var} 输出并替换为表达式的值
<#visit xmlnode> 调用macro匹配xmlnode本身及其子节点
<#recurse xmlnode> 调用macro匹配xmlnode的子节点

[表1]


大家仔细对比xml文件,发现少了什么吗?对了,少了一个Type2定义,我们把代码2中的ns:type匹配(第11行)修改一下:

<#macro "ns:field">
   public ${.node.@type}${.node.@name};
   <#recurse > <#-- 深入处理子节点 -->


[代码5]

结果输出文件中的内容就变为如下:

     class Type1
     {
         public Float Field11;
         public String Field12;
         public Integer Field13;
         public Type2 Field14;
         class Type2
         {
             public String Field21;
             public Integer Field22;
         }
         public Float Field15;
     }

     class Type3
     {
         public Type1 Field31;
     }

[代码6]

如果各位有意向把Type2提到跟Type1和Type3同一级别的位置,那么我们要继续修改代码了。把代码2的 <#recurse doc>行(第5行)修改成如下:

<#assign inner_types=pp.newWritableHash()> <#-- 调用fmpp功能函数,生成一个可写的hash -->
<#recurse doc> <#-- 根入口,代码1部分的xml存放在变量doc中,doc变量的填充由fmpp根据config.fmpp中的配置进行 -->
<#if inner_types?size gt 0 > <#-- 如果存放有类型 -->
<#list inner_types?values as node> <#-- 遍历哈西表的值 -->
   <#visit node> <#-- 激活相应的macro处理,类似于xslt的apply-template。大家把visit改成recurse看一下不同的效果 -->


[代码7]

同时把macro ns:field(第18行)修改成如下:

<#macro "ns:field">
   public ${.node.@type}${.node.@name};
   <#if .node["ns:type"]?has_content > <#-- 如果当前节点下存在type节点 -->
    <#local t = .node["ns:type"] >
    <@pp.set hash=inner_types key="${t.@name}" value=t /> <#-- 哈西表中增加内容,key为嵌套类型的name属性,value为该类型节点 -->
  

[代码8]

运行得到输出文件类似这样:

     class Type1
     {
         public Float Field11;
         public String Field12;
         public Integer Field13;
         public Type2 Field14;
         public Float Field15;
     }

     class Type3
     {
         public Type1 Field31;
     }

     class Type2
     {
         public String Field21;
         public Integer Field22;
     }

[代码9]

大家比较一下,看看我们修改的地方出现了哪些效果?然后记得大家要做另外2件事情,
1。把第一行修改成为<#ftl ns_prefixes={"D": "urn:DruleForm-Lite.xsd"}> ,然后把所有的 <#macro "ns:type"> 修改成<#macro type>,把所有的.node["ns:type"]修改成 .node.type,看看能不能运行?是不是觉得简单方便些了?记住,第一行的那个D表示是default namespace的意思哦。
2。在第二行插入<#compress>,在最后一行添加。再运行一下看看结果有什么不同?

一个例子下来,大家基本对freemaker有了一些感觉了,为了纠正大家认为freemaker就是一个xml处理工具的误解,我们再来做一个简单的实验。这次我们要做的是一个正常的编程题目,做一个100以内的Fibonacci数列的程序。程序如下:

迭代次数:
<#list 1 .. 10 as n>
${n} = ${fibo(n)}

<#compress>
<#function fibo n>
<#if n lte 1>
   <#return 1>
<#elseif n = 2>
   <#return 1>
<#else>
   <#return fibo(n-1) + fibo(n-2)>



[代码10]

这个例子里边有一些问题需要注意,大家看我的 #if n lte 1 这一行,为什么我这么写?因为常规的大于小于号和xml的节点有冲突,为了避免问题,所以用 gt(>) gte(>=) lt(<) lte(<=) 来代表。

另外,复杂的字符串处理如何来做?就留作家庭作业吧,大家记得取substr的方法是 str[first .. last] 就可以了。如下的例子可能会给你一点提示:

<#assign str = "hello!$world!">
<#assign mid = (str?length + 1)/2-1 >
<#list mid .. 0 as cnt>
${str[(mid - cnt) .. (mid + cnt)]?left_pad(mid*2)}

[代码11]

最后,说一下非常有用的macro的nested指令,没有它,也许freemaker会失去大部分的魅力。我个人认为这也是freemaker全面超越velocity的地方。大家先看一下代码:

<#assign msg = "hello">
<@macro0 ; index >
${msg} ${index}

<#macro macro0>
<#list 0 .. 10 as number>
   <#nested number>


[代码12]

这段代码的作用就是一个闭包(closure)。我们用java的匿名类实现相同的功能就是这样:

interface ICallback
{
public void call(int index);
}

void Main()
{
String msg = "hello";
macro0(
   new ICallback()
   {
    public void call(int index)
    {
     System.out.println(msg + index.toString());
    }
   }
);
}

void macro0(ICallback callback)
{
for(int i = 0; i < 10; ++i)
{
   callback.call(i);
}
}

freemaker学习笔记--设计指导 

 

<# ... > 中存放所有freemaker的内容,之外的内容全部原样输出。
<@ ... /> 是函数调用
两个定界符内的内容中,第一个符号表示指令或者函数名,其后的跟随参数。freemaker提供的控制包括如下:
<#if condition><#elseif condition><#else> 条件判断
<#list hash_or_seq as var> 遍历hash表或者collection(freemaker称作sequence)的成员
<#macro name param1 param2 ... ><#nested param> 宏,无返回参数
<#function name param1 param2><#return val>函数,有返回参数
var?member_function(...) 用函数对var进行转换,freemaker称为build-ins。实际内部实现类似member_function(var, ...)
stringA[M .. N] 取子字符串,类似substring(stringA, M, N)
{key:value, key2:value2 ...} 直接定义一个hash表
[item0, item1, item2 ...] 直接定义一个序列
hash0[key0] 存取hash表中key对应的元素
seq0[5] 存取序列指定下标的元素
<@function1 param0 param1 ... /> 调用函数function1
<@macro0 param0 param1 ; nest_param0 nest_param1 ...> nest_body < /@macro > 调用宏,并处理宏的嵌套
<#assign var = value > 定义变量并初始化
<#local var = value> 在 macro 或者 function 中定义局部变量并初始化
<#global var = value > 定义全局变量并初始化
${var} 输出并替换为表达式的值
<#visit xmlnode> 调用macro匹配xmlnode本身及其子节点
<#recurse xmlnode> 调用macro匹配xmlnode的子节点


<#if condition >
<#list SequenceVar as variable > repeatThis
<#include "/copyright_footer.html">

一个ftl标记不能放在另外一个ftl标记里面,但是注释标记能够放在ftl标记里面。

系统预定义指令采用<#...>
用户自定义指令采用<@...>

hash片段可以采用:
products[10..19] or products[5..] 的格式。

序列也可以做加法计算:passwords +{"joe":"secret42"}

缺省值: name!"unknown" 或者 (user.name)!"unknown" 或者 name! 或者 (user.name)!

null值检查: name?? or (user.name)??

转义列表:

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: {

\xCode

Character given with its hexadecimal Unicode code (UCS code)


如果想打印${,则需要将{转义,可以写成"$\{user}",或者可以用生字符(r指令):$(r "${xx}"}

序列构成:<#list ["winter","spring", "summer", "autumn"] asx>${x}

不同的对象可以存放在一个序列里面,比如:[2 + 2,[1, 2, 3, 4], "whatnot"]. 第一个是数字,第二个是序列,第三个是字符串。

可用采用start..end的方式来定义一个数字序列,start可以小于end,同时,end也可以省略。

hash取值支持一下四种模式:book.author.name, book["author"].name, book.author.["name"], book["author"]["name"].

特殊变量是指freemaker引擎本身定义的变量。访问时,以.variable_name的语法访问。

变量表达式支持嵌套模式,比如:${"Hello${user}!"}。

变量表达式在指令中的使用情况:
变量表达式可以在指令中,用“”的方式存在,不如:<#include"/footer/${company}.html">.
但是不允许下面的方式存在: <#if ${isBig}>Wow!, 正确写法是:<#ifisBig>Wow!.
而且 <#if"${isBig}">Wow!写法也不正确,因为"${isBig}"返回的是字符串,不是boolean类型。

字符串中取字符或字符串采用以下语法:${user[0]},${user[0..2]}${user[4..]},${user?string(4)}

序列操作:
   加法:<#list ["Joe", "Fred"] + ["Julia","Kate"] as user> 但要注意串联之后的读取速度变慢。
   子序列:seq[1..4]

序列和hash的串联都只能用于两个相加,不能有多个相加的模式,hash相加,如果两个相加的hash存在相同的key,则后面会覆盖前面的。

在使用>=或者>时,需要注意一些问题,因为freemaker会将>解释成标记的关闭符,为了解决这个问题,需要在表达式加上括号,比如: <#if (x > y)>. 或者使用 > and <符号来代替。

无值变量(包括无该变量,null,返回void,无属性等):unsafe_expr!default_expr or unsafe_expr! or (unsafe_expr)!default_expr or (unsafe_expr)!
缺省值可以是任何类型,不一定是数字,比如:hits!0 或者 colors!["red","green", "blue"].

如果缺省值忽略,那么将会默认为空串、空序列或者空hash,因为freemarker支持多类型的值。不过要让默认值为0或false,则不能省略缺省值。

非顶层变量的无值处理:
   product.color!"red":只处理product不为空,color为空的缺省值处理,如果product为空,则freemaker会抛出异常。(product.color)!"red":则会处理product为空,color为空,或者没有color属性的无值情况。

无值变量的判断操作:unsafe_expr?? or (unsafe_expr)??

判断变量是否是无值。

普通变量插入方式: ${expression},${3+5);
数字变量插入方式: #{expression} or #{expression; format}:过期。
变量只能用于文本区或者是字符串里面,比如:

Hello${name}!

以及 <#include"/footer/${company}.html">

数字值的插入:根据缺省的number_format输出,以及可以通过setting来达到设置数字格式的目的,也可以通过内置函数string来改变输出格式。

日期类型的格式设置:date_format, time_format 和 datetime_format


定义宏:
   不带参数:<#macro 宏名>...,引用<@宏名 />
   带参数:<#macro宏名 参数...>...,引用<@宏名 参数1=值1.../>,带有参数的宏,调用是参数的值必须和参数的个数相同。当然也可以在宏定义时给参数一些默认值。比如:<#macro greet person color="black">


宏里面的嵌套内容:
<#macro border>
 

    <#nested>
 

 
在宏的定义body中加入<#nested>指令。嵌套的内容可以是任何正确的ftl块。

宏的本地变量在嵌套内容中是不可见的。

宏定义时,<#nest>指令相当于调用定义的内容,而使用宏时,nest body相当于定义。

<#macro repeat count>  <#list 1..count as x>    <#nested x, x/2, x==count<@repeatcount=4 ; c, halfc, last>  ${c}.${halfc}<#iflast> Last! 



定义变量:
   在模板中定义的变量将会隐藏(不是更改)数据模型根下面的同名的变量。

模板中的3种类型变量:
   1:plain variables,能够在模板中的任何地方访问,一个模板include另外一个模板,也可以访问被包含模板的变量。可以通过assign或者macro指令产生或替换变量。
   如果要访问数据模型中的变量,则可以通过.global来访问:
   <#assign user = "JoeHider">
   ${user}         <#-- prints: Joe Hider -->
   ${.globals.user} <#-- prints: Big Joe--> 
   2:Local variables,宏定义body中用local指令创建或者替换。
   3:Loop variables:由list指令产生。


namespaces:
<#import "/lib/my_test.ftl" as my> <#-- the hashcalled "my" will be the "gate" -->
<@my.copyright date="1999-2002"/>
${my.mail} 

设置命名空间里面的变量:<#assignmail="[email protected]" in my>

命名空间与数据模型:命名空间的ftl可以访问数据模型的变量。同样命名空间的变量也会隐藏数据模型中同名的变量。

空白问题:
1:White-space stripping,默认为enabled,清除ftl标记带来的空白以及缩进。处理模板的空白。
2:t, rt, lt指令。
3:ftl的参数strip_text.

用compress directive或者transform来处理输出。
<#compress>...:消除空白行。
<@compress single_line=true>.../@compress将输出压缩为一行。

可替换语法:
freemarker可用"["代替"<".在模板的文件开头加上[#ftl].

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1791781

Spring MVC 使用 Freemarker

·        Freemaker是取代JSP的又一种视图技术,和Velocity非常类似,但是它比Velocity多了一个格式化的功能,因此使用上较Velocity方便一点,但语法也稍微复杂一些。

将Velocity替换为Freemarker只需要改动一些配置文件,同样,在Spring中使用Freemarker也非常方便,根本无须与Freemarker的API打交道。我们将Spring_Velocity工程复制一份,命名为Spring_Freemarker,结构如图7-44所示。

图7-44 

修改dispatcher-servlet.xml,将velocityConfig删除,修改viewResolver为FreeMarker ViewResolver,并添加一个freemarkerConfig。

   

   

   

   

   

   

模板test.html可以稍做修改,加入Freemarker内置的格式化功能来定制Date类型的输出格式。

   

   Spring_Freemarker

   

Hello, ${name}, it is${time?string("yyyy-MM-dd HH:mm:ss")}

添加freemarker.jar到web/WEB-INF/lib目录后,启动Resin,可以看到由Freemarker渲染的页面

 

 

FreeMarker入门文章引用自:

1、快速入门
(1)模板 + 数据模型 = 输出

l         FreeMarker基于设计者和程序员是具有不同专业技能的不同个体的观念
l         他们是分工劳动的:设计者专注于表示——创建HTML文件、图片、Web页面的其它可视化方面;程序员创建系统,生成设计页面要显示的数据
l         经常会遇到的问题是:在Web页面(或其它类型的文档)中显示的信息在设计页面时是无效的,是基于动态数据的
l         在这里,你可以在HTML(或其它要输出的文本)中加入一些特定指令,FreeMarker会在输出页面给最终用户时,用适当的数据替代这些代码
l         下面是一个例子:


  Welcome!


  

Welcome ${user}!


  

Our latest product:
  ${latestProduct.name}!

  
l         这个例子是在简单的HTML中加入了一些由${…}包围的特定代码,这些特定代码是FreeMarker的指令,而包含FreeMarker的指令的文件就称为模板(Template)
l         至于user、latestProduct.url和latestProduct.name来自于数据模型(data model)
l         数据模型由程序员编程来创建,向模板提供变化的信息,这些信息来自于数据库、文件,甚至于在程序中直接生成
l         模板设计者不关心数据从那儿来,只知道使用已经建立的数据模型
l         下面是一个可能的数据模型:
(root)
  |
  +- user = "Big Joe"
  |
  +- latestProduct
      |
      +- url ="products/greenmouse.html"
      |
      +- name = "green mouse"
l         数据模型类似于计算机的文件系统,latestProduct可以看作是目录,而user、url和name看作是文件,url和name文件位于latestProduct目录中(这只是一个比喻,实际并不存在)
l         当FreeMarker将上面的数据模型合并到模板中,就创建了下面的输出:


  Welcome!


  

Welcome Big Joe!


  

Our latest product:
  greenmouse!

  
(2)数据模型
l         典型的数据模型是树型结构,可以任意复杂和深层次,如下面的例子:
(root)
  |
  +- animals
  |   |
  |   +- mouse
  |   |   |  
  |   |   +- size = "small"
  |   |   |  
  |   |   +- price = 50
  |   |
  |   +- elephant
  |   |   |  
  |   |   +- size = "large"
  |   |   |  
  |   |   +- price = 5000
  |   |
  |   +- python
  |       |  
  |       +- size = "medium"
  |       |  
  |       +- price = 4999
  |
  +- test = "It is a test"
  |
  +- whatnot
      |
      +- because = "don't know"
l         类似于目录的变量称为hashes,包含保存下级变量的唯一的查询名字
l         类似于文件的变量称为scalars,保存单值
l         scalars保存的值有两种类型:字符串(用引号括起,可以是单引号或双引号)和数字(不要用引号将数字括起,这会作为字符串处理)
l         对scalars的访问从root开始,各部分用“.”分隔,如animals.mouse.price
l         另外一种变量是sequences,和hashes类似,只是不使用变量名字,而使用数字索引,如下面的例子:
(root)
  |
  +- animals
  |   |
  |   +- (1st)
  |   |   |
  |   |   +- name = "mouse"
  |   |   |
  |   |   +- size = "small"
  |   |   |
  |   |   +- price = 50
  |   |
  |   +- (2nd)
  |   |   |
  |   |   +- name = "elephant"
  |   |   |
  |   |   +- size = "large"
  |   |   |
  |   |   +- price = 5000
  |   |
  |   +- (3rd)
  |       |
  |       +- name = "python"
  |       |
  |       +- size = "medium"
  |       |
  |       +- price = 4999
  |
  +- whatnot
      |
      +- fruits
          |
          +- (1st) ="orange"
          |
          +- (2nd) ="banana"
l         这种对scalars的访问使用索引,如animals[0].name
(3)模板
l         在FreeMarker模板中可以包括下面三种特定部分:
?         ${…}:称为interpolations,FreeMarker会在输出时用实际值进行替代
?         FTL标记(FreeMarker模板语言标记):类似于HTML标记,为了与HTML标记区分,用#开始(有些以@开始,在后面叙述)
?         注释:包含在<#--和-->(而不是)之间
l         下面是一些使用指令的例子:
?         if指令
<#if animals.python.price < animals.elephant.price>
  Pythons are cheaper than elephants today.
<#else>
  Pythons are not cheaper than elephants today.
  
?         list指令

We have these animals:


  
NamePrice
  <#list animals as being>
  
${being.name}${being.price} Euros
  
  
输出为:

We have these animals:


  
NamePrice
  
mouse50 Euros
  
elephant5000 Euros
  
python4999 Euros
  
?         include指令


  Test page


  

Test page


  

Blah blah...
<#include "/copyright_footer.html">

  
?         一起使用指令

We have these animals:


  
    
NamePrice
  <#list animals as being>
  

      <#if being.size ="large">
      ${being.name}
      <#if being.size = "large">

    
${being.price} Euros
  
  

FreeMarker设计指南

快速入门

(1)模板 + 数据模型 = 输出 
FreeMarker基于设计者和程序员是具有不同专业技能的不同个体的观念他们是分工劳动的:
设计者专注于表示——创建HTML文件、图片、Web页面的其它可视化方面;
程序员创建系统,生成设计页面要显示的数据。
经常会遇到的问题是:在Web页面(或其它类型的文档)中显示的信息在设计页面时是无效的,是基于动态数据的。在这里,你可以在HTML(或其它要输出的文本)中加入一些特定指令,FreeMarker会在输出页面给最终用户时,用适当的数据替代这些代码。
 
先来解释一下freemaker的基本语法了,
<# ... > 中存放所有freemaker的内容,之外的内容全部原样输出。
<@ ... /> 是函数调用
两个定界符内的内容中,第一个符号表示指令或者函数名,其后的跟随参数。freemaker提供的控制包括如下:
<#if condition><#elseif condition><#else> 条件判断
<#list hash_or_seq as var> 遍历hash表或者collection(freemaker称作sequence)的成员
<#macro name param1 param2 ... ><#nested param> 宏,无返回参数
<#function name param1 param2><#return val>函数,有返回参数
var?member_function(...) 用函数对var进行转换,freemaker称为build-ins。实际内部实现类似member_function(var, ...)
stringA[M .. N] 取子字符串,类似substring(stringA, M, N)
{key:value, key2:value2 ...} 直接定义一个hash表
[item0, item1, item2 ...] 直接定义一个序列
hash0[key0] 存取hash表中key对应的元素
seq0[5] 存取序列指定下标的元素
<@function1 param0 param1 ... /> 调用函数function1
<@macro0 param0 param1 ; nest_param0 nest_param1 ...> nest_body  调用宏,并处理宏的嵌套
<#assign var = value > 定义变量并初始化
<#local var = value> 在 macro 或者 function 中定义局部变量并初始化
<#global var = value > 定义全局变量并初始化
${var} 输出并替换为表达式的值
<#visit xmlnode> 调用macro匹配xmlnode本身及其子节点
<#recurse xmlnode> 调用macro匹配xmlnode的子节点
 
下面是一个例子: 


  Welcome!


  

Welcome ${user}!

 

Our latest product:   ${latestProduct.name}!  

这个例子是在简单的HTML中加入了一些由${…}包围的特定代码,这些特定代码是FreeMarker的指令,而包含FreeMarker的指令的文件就称为模板(Template)。
至于user、latestProduct.url和latestProduct.name来自于数据模型(data model)。
数据模型由程序员编程来创建,向模板提供变化的信息,这些信息来自于数据库、文件,甚至于在程序中直接生成。
模板设计者不关心数据从那儿来,只知道使用已经建立的数据模型。
下面是一个可能的数据模型: 
(root)
  |
  +- user = "Big Joe"
  |
  +- latestProduct
      |
      +- url = "products/greenmouse.html"
      |
      +- name = "green mouse"
数据模型类似于计算机的文件系统,latestProduct可以看作是目录。 
2、数据模型 
(1)基础 
在快速入门中介绍了在模板中使用的三种基本对象类型:scalars、hashes 和sequences,其实还可以有其它更多的能力: 
scalars:存储单值 
hashes:充当其它对象的容器,每个都关联一个唯一的查询名字 
sequences:充当其它对象的容器,按次序访问 
方法:通过传递的参数进行计算,以新对象返回结果 
用户自定义FTL标记:宏和变换器 
通常每个变量只具有上述的一种能力,但一个变量可以具有多个上述能力,如下面的例子: 
(root)
 |
 +- mouse = "Yerri"
     |
     +- age = 12
     |
     +- color = "brown">  
mouse既是scalars又是hashes,将上面的数据模型合并到下面的模板: 
${mouse}       <#-- use mouse as scalar -->
${mouse.age}   <#-- use mouse as hash -->
${mouse.color} <#-- use mouse as hash -->  
输出结果是: 
Yerri
12
brown  
(2)Scalar变量 
Scalar变量存储单值,可以是: 
字符串:简单文本,在模板中使用引号(单引号或双引号)括起 
数字:在模板中直接使用数字值 
日期:存储日期/时间相关的数据,可以是日期、时间或日期-时间(Timestamp);通常情况,日期值由程序员加到数据模型中,设计者只需要显示它们 
布尔值:true或false,通常在<#if …>标记中使用 
(3)hashes 、sequences和集合 
有些变量不包含任何可显示的内容,而是作为容器包含其它变量,者有两种类型: 
hashes:具有一个唯一的查询名字和它包含的每个变量相关联 
sequences:使用数字和它包含的每个变量相关联,索引值从0开始 
集合变量通常类似sequences,除非无法访问它的大小和不能使用索引来获得它的子变量;集合可以看作只能由<#list …>指令使用的受限sequences 
(4)方法 
方法变量通常是基于给出的参数计算值。 
下面的例子假设程序员已经将方法变量avg放到数据模型中,用来计算数字平均值: 
The average of 3 and 5 is: ${avg(3, 5)}
The average of 6 and 10 and 20 is: ${avg(6, 10, 20)}
The average of the price of python and elephant is: 
    ${avg(animals.python.price, animals.elephant.price)}
(5)宏和变换器 
宏和变换器变量是用户自定义指令(自定义FTL标记),会在后面讲述这些高级特性 
(6)节点 
节点变量表示为树型结构中的一个节点,通常在XML处理中使用,会在后面的专门章节中讲 
3、模板 
(1)整体结构 
模板使用FTL(FreeMarker模板语言)编写,是下面各部分的一个组合: 
文本:直接输出 
Interpolation:由${和},或#{和}来限定,计算值替代输出 
FTL标记:FreeMarker指令,和HTML标记类似,名字前加#予以区分,不会输出 
注释:由<#--和-->限定,不会输出 
下面是以一个具体模板例子: 


  Welcome!


  <#-- Greet the user with his/her name -->
  

Welcome ${user}!

 

We have these animals:  

      <#list animals as being>    
  • ${being.name} for ${being.price} Euros    
 
注意事项: 
FTL区分大小写,所以list是正确的FTL指令,而List不是;${name}和${NAME}是不同的 
Interpolation只能在文本中使用 
FTL标记不能位于另一个FTL标记内部,例如: 
<#if <#include 'foo'>='bar'>...
注释可以位于FTL标记和Interpolation内部,如下面的例子: 

Welcome ${user <#-- The name of user -->}!

We have these animals:

    <#list <#-- some comment... --> animals as <#-- again... --> being> ... 
余的空白字符会在模板输出时移除 
(2)指令 
在FreeMarker中,使用FTL标记引用指令。有三种FTL标记,这和HTML标记是类似的: 
开始标记:<#directivename parameters> 
结束标记: 
空内容指令标记:<#directivename parameters/> 
有两种类型的指令:预定义指令和用户定义指令。 
用户定义指令要使用@替换#,如<@mydirective>...(会在后面讲述)。 
FTL标记不能够交叉,而应该正确的嵌套,如下面的代码是错误的: 
    <#list animals as being>  
  • ${being.name} for ${being.price} Euros   <#if use = "Big Joe">      (except for you) <#-- WRONG! -->
 
如果使用不存在的指令,FreeMarker不会使用模板输出,而是产生一个错误消息。 
FreeMarker会忽略FTL标记中的空白字符,如下面的例子: 
<#list
  animals       as
     being
>
${being.name} for ${being.price} Euros
  
但是,<、 
  
(3)表达式 
直接指定值 
字符串 
使用单引号或双引号限定 
如果包含特殊字符需要转义,如下面的例子: 
${"It's \"quoted\" and
this is a backslash: \\"}

${'It\'s "quoted" and
this is a backslash: \\'} 
输出结果是: 
It's "quoted" and
this is a backslash: \

It's "quoted" and
this is a backslash: \ 
下面是支持的转义序列: 
转义序列 
含义 
\" 
双引号(u0022) 
\' 
单引号(u0027) 
 
反斜杠(u005C) 
\n 
换行(u000A) 
\r 
Return (u000D) 
\t 
Tab (u0009) 
\b 
Backspace (u0008) 
\f 
Form feed (u000C) 
\l 
< 
\g 
> 
\a 
& 
\{ 
{ 
\xCode 
4位16进制Unicode代码 
有一类特殊的字符串称为raw字符串,被认为是纯文本,其中的\和{等不具有特殊含义,该类字符串在引号前面加r,下面是一个例子: 
${r"${foo}"}

${r"C:\foo\bar"}  
输出的结果是: 
${foo}

C:\foo\bar  
数字 
直接输入,不需要引号 
精度数字使用“.”分隔,不能使用分组符号 
目前版本不支持科学计数法,所以“1E3”是错误的 
不能省略小数点前面的0,所以“.5”是错误的 
数字8、+8、08和8.00都是相同的 
布尔值 
true和false,不使用引号 
序列 
由逗号分隔的子变量列表,由方括号限定,下面是一个例子: 
<#list ["winter", "spring", "summer", "autumn"] as x>
${x}
 
输出的结果是: 
winter
spring
summer
autumn
列表的项目是表达式,所以可以有下面的例子: 
[2 + 2, [1, 2, 3, 4], "whatnot"]
可以使用数字范围定义数字序列,例如2..5等同于[2, 3, 4, 5],但是更有效率,注意数字范围没有方括号 
可以定义反递增的数字范围,如5..2 
散列(hash) 
由逗号分隔的键/值列表,由大括号限定,键和值之间用冒号分隔,下面是一个例子: 
{"name":"green mouse", "price":150}
键和值都是表达式,但是键必须是字符串 
获取变量 
顶层变量: ${variable},变量名只能是字母、数字、下划线、$、@和#的组合,且不能以数字开头 
从散列中获取数据 
可以使用点语法或方括号语法,假设有下面的数据模型: 
(root)
 |
 +- book
 |   |
 |   +- title = "Breeding green mouses"
 |   |
 |   +- author
 |       |
 |       +- name = "Julia Smith"
 |       |
 |       +- info = "Biologist, 1923-1985, Canada"
 |
 +- test = "title" 
下面都是等价的: 
book.author.name
book["author"].name
book.author.["name"]
book["author"]["name"]
使用点语法,变量名字有顶层变量一样的限制,但方括号语法没有该限制,因为名字是任意表达式的结果 
从序列获得数据:和散列的方括号语法语法一样,只是方括号中的表达式值必须是数字;注意:第一个项目的索引是0 
序列片断:使用[startIndex..endIndex]语法,从序列中获得序列片断(也是序列);startIndex和endIndex是结果为数字的表达式 
特殊变量:FreeMarker内定义变量,使用.variablename语法访问 
字符串操作 
Interpolation(或连接操作) 
可以使用${..}(或#{..})在文本部分插入表达式的值,例如: 
${"Hello ${user}!"}

${"${user}${user}${user}${user}"}  
可以使用+操作符获得同样的结果 
${"Hello " + user + "!"}

${user + user + user + user}
${..}只能用于文本部分,下面的代码是错误的: 
<#if ${isBig}>Wow!

<#if "${isBig}">Wow!
应该写成: 
<#if isBig>Wow!
子串 
例子(假设user的值为“Big Joe”): 
${user[0]}${user[4]}

${user[1..4]}
结果是(注意第一个字符的索引是0): 
BJ

ig J 
序列操作 
连接操作:和字符串一样,使用+,下面是一个例子: 
<#list ["Joe", "Fred"] + ["Julia", "Kate"] as user>
- ${user}
输出结果是: 
- Joe
- Fred
- Julia
- Kate
散列操作 
连接操作:和字符串一样,使用+,如果具有相同的key,右边的值替代左边的值,例如: 
<#assign ages = {"Joe":23, "Fred":25} + {"Joe":30, "Julia":18}>
- Joe is ${ages.Joe}
- Fred is ${ages.Fred}
- Julia is ${ages.Julia}  
输出结果是: 
- Joe is 30
- Fred is 25
- Julia is 18  
算术运算 
+、-、×、/、%,下面是一个例子: 
${x * x - 100}
${x / 2}
${12 % 10}
输出结果是(假设x为5): 
-75
2.5
2  
操作符两边必须是数字,因此下面的代码是错误的: 
${3 * "5"} <#-- WRONG! -->  
使用+操作符时,如果一边是数字,一边是字符串,就会自动将数字转换为字符串,例如: 
${3 + "5"}  
输出结果是: 
35
使用内建的int(后面讲述)获得整数部分,例如: 
${(x/2)?int}
${1.1?int}
${1.999?int}
${-1.1?int}
${-1.999?int}
输出结果是(假设x为5): 
2
1
1
-1
-1
比较操作符 
使用=(或==,完全相等)测试两个值是否相等,使用!= 测试两个值是否不相等 
=和!=两边必须是相同类型的值,否则会产生错误,例如<#if 1 = "1">会引起错误 
Freemarker是精确比较,所以对"x"、"x "和"X"是不相等的 
对数字和日期可以使用<、<=、>和>=,但不能用于字符串 
由于Freemarker会将>解释成FTL标记的结束字符,所以对于>和>=可以使用括号来避免这种情况,例如<#if (x > y)> 
另一种替代的方法是,使用lt、lte、gt和gte来替代<、<=、>和>= 
逻辑操作符 
&&(and)、||(or)、!(not),只能用于布尔值,否则会产生错误 
例子: 
<#if x < 12 && color = "green">
  We have less than 12 things, and they are green.

<#if !hot> <#-- here hot must be a boolean -->
  It's not hot.
  
内建函数 
内建函数的用法类似访问散列的子变量,只是使用“?”替代“.”,下面列出常用的一些函数 
 
字符串使用的: 
html:对字符串进行HTML编码 
cap_first:使字符串第一个字母大写 
lower_case:将字符串转换成小写 
upper_case:将字符串转换成大写 
trim:去掉字符串前后的空白字符 
 
序列使用的: 
size:获得序列中元素的数目 
 
数字使用的: 
int:取得数字的整数部分(如-1.9?int的结果是-1) 
例子(假设test保存字符串"Tom & Jerry"): 
${test?html}
${test?upper_case?html}
输出结果是: 
Tom & Jerry
TOM & JERRY  
操作符优先顺序 
操作符组 
操作符 
后缀 
[subvarName] [subStringRange] . (methodParams) 
一元 
+expr、-expr、! 
内建 
? 
乘法 
*、 / 、% 
加法 
+、- 
关系 
<、>、<=、>=(lt、lte、gt、gte) 
相等 
==(=)、!= 
逻辑and 
&& 
逻辑or 
双竖线
数字范围 
.. 
(4)Interpolation 
Interpolation有两种类型: 
通用Interpolation:${expr} 
数字Interpolation:#{expr}或#{expr; format} 
注意:Interpolation只能用于文本部分 
通用Interpolation 
插入字符串值:直接输出表达式结果 
插入数字值:根据缺省格式(由#setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string格式化单个Interpolation,下面是一个例子: 
<#setting number_format="currency"/>
<#assign answer=42/>
${answer}
${answer?string}  <#-- the same as ${answer} -->
${answer?string.number}
${answer?string.currency}
${answer?string.percent} 
输出结果是: 
$42.00
$42.00
42
$42.00
4,200%
插入日期值:根据缺省格式(由#setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string格式化单个Interpolation,下面是一个使用格式模式的例子: 
${lastUpdated?string("yyyy-MM-dd HH:mm:ss zzzz")}
${lastUpdated?string("EEE, MMM d, ''yy")}
${lastUpdated?string("EEEE, MMMM dd, yyyy, hh:mm:ss a '('zzz')'")}  
输出的结果类似下面的格式: 
2003-04-08 21:24:44 Pacific Daylight Time
Tue, Apr 8, '03
Tuesday, April 08, 2003, 09:24:44 PM (PDT)
插入布尔值:根据缺省格式(由#setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string格式化单个Interpolation,下面是一个例子: 
<#assign foo=true/>
${foo?string("yes", "no")}
输出结果是: 
yes
数字Interpolation的#{expr; format}形式可以用来格式化数字,format可以是: 
mX:小数部分最小X位 
MX:小数部分最大X位 
例子: 
<#-- If the language is US English the output is: -->
<#assign x=2.582/>
<#assign y=4/>
#{x; M2}   <#-- 2.58 -->
#{y; M2}   <#-- 4    -->
#{x; m1}   <#-- 2.6 -->
#{y; m1}   <#-- 4.0 -->
#{x; m1M2} <#-- 2.58 -->
#{y; m1M2} <#-- 4.0  -->  
4、杂项 
(1)用户定义指令 
宏和变换器变量是两种不同类型的用户定义指令,它们之间的区别是宏是在模板中使用macro指令定义,而变换器是在模板外由程序定义,这里只介绍宏 
基本用法 
宏是和某个变量关联的模板片断,以便在模板中通过用户定义指令使用该变量,下面是一个例子: 
<#macro greet>
  Hello Joe!
  
作为用户定义指令使用宏变量时,使用@替代FTL标记中的# 
<@greet>
如果没有体内容,也可以使用: 
<@greet/>
参数 
在macro指令中可以在宏变量之后定义参数,如: 
<#macro greet person>
  Hello ${person}!
 
可以这样使用这个宏变量: 
<@greet person="Fred"/> and <@greet person="Batman"/> 
输出结果是: 
  Hello Fred!

 and   Hello Batman!
宏的参数是FTL表达式,所以下面的代码具有不同的意思: 
<@greet person=Fred/>
这意味着将Fred变量的值传给person参数,该值不仅是字符串,还可以是其它类型,甚至是复杂的表达式 
可以有多参数,下面是一个例子: 
<#macro greet person color>
  Hello ${person}!
 
可以这样使用该宏变量: 
<@greet person="Fred" color="black"/> 
其中参数的次序是无关的,因此下面是等价的: 
<@greet color="black" person="Fred"/>
只能使用在macro指令中定义的参数,并且对所有参数赋值,所以下面的代码是错误的: 
<@greet person="Fred" color="black" background="green"/>
<@greet person="Fred"/>
可以在定义参数时指定缺省值,如: 
<#macro greet person color="black">
  Hello ${person}!
  
这样<@greet person="Fred"/>就正确了 
宏的参数是局部变量,只能在宏定义中有效 
嵌套内容 
用户定义指令可以有嵌套内容,使用<#nested>指令执行指令开始和结束标记之间的模板片断 
例子: 
<#macro border>
  
    <#nested>  
 
这样使用该宏变量: 
<@border>The bordered text
输出结果: 
  
    The bordered text  
<#nested>指令可以被多次调用,例如: 
<#macro do_thrice>
  <#nested>
  <#nested>
  <#nested>

<@do_thrice>
  Anything.
  
输出结果: 
  Anything.
  Anything.
  Anything. 
嵌套内容可以是有效的FTL,下面是一个有些复杂的例子: <@border> 
    <@do_thrice>
  • <@greet person="Joe"/>
}}}
输出结果:
  
     
       
  • Hello Joe!    
  • Hello Joe!    
  • Hello Joe!  
 
 
宏定义中的局部变量对嵌套内容是不可见的,例如: 
<#macro repeat count>
  <#local y = "test">
  <#list 1..count as x>
    ${y} ${count}/${x}: <#nested>
  

<@repeat count=3>${y?default("?")} ${x?default("?")} ${count?default("?")}
输出结果: 
    test 3/1: ? ? ?
    test 3/2: ? ? ?
    test 3/3: ? ? ?
在宏定义中使用循环变量 
用户定义指令可以有循环变量,通常用于重复嵌套内容,基本用法是:作为nested指令的参数传递循环变量的实际值,而在调用用户定义指令时,在<@…>开始标记的参数后面指定循环变量的名字 
例子: 
<#macro repeat count>
  <#list 1..count as x>
    <#nested x, x/2, x==count>
  

<@repeat count=4 ; c, halfc, last>
  ${c}. ${halfc}<#if last> Last!
  
输出结果: 
  1. 0.5
  2. 1
  3. 1.5
  4. 2 Last!
指定的循环变量的数目和用户定义指令开始标记指定的不同不会有问题 
调用时少指定循环变量,则多指定的值不可见 
调用时多指定循环变量,多余的循环变量不会被创建 
(2)在模板中定义变量 
在模板中定义的变量有三种类型: 
plain变量:可以在模板的任何地方访问,包括使用include指令插入的模板,使用assign指令创建和替换 
局部变量:在宏定义体中有效,使用local指令创建和替换 
循环变量:只能存在于指令的嵌套内容,由指令(如list)自动创建 
宏的参数是局部变量,而不是循环变量;局部变量隐藏(而不是覆盖)同名的plain变量;循环变量隐藏同名的局部变量和plain变量,下面是一个例子: 
<#assign x = "plain">
1. ${x}  <#-- we see the plain var. here -->
<@test/>
6. ${x}  <#-- the value of plain var. was not changed -->
<#list ["loop"] as x>
  7. ${x}  <#-- now the loop var. hides the plain var. -->
<#assign x = "plain2"> <#-- replace the plain var, hiding does not mater here -->
 8. ${x}  <#-- it still hides the plain var. -->

   9. ${x}  <#-- the new value of plain var. -->
<#macro test>
  2. ${x}  <#-- we still see the plain var. here -->
  <#local x = "local">
  3. ${x}  <#-- now the local var. hides it -->
  <#list ["loop"] as x>
    4. ${x}  <#-- now the loop var. hides the local var. -->
  
  5. ${x}  <#-- now we see the local var. again -->
  
输出结果: 
1. plain
  2. plain
  3. local
    4. loop
  5. local
6. plain
    7. loop
    8. loop
9. plain2
内部循环变量隐藏同名的外部循环变量,如: 
<#list ["loop 1"] as x>
  ${x}
  <#list ["loop 2"] as x>
    ${x}
    <#list ["loop 3"] as x>
      ${x}
    
    ${x}
  
  ${x}
输出结果: 
  loop 1
    loop 2
      loop 3
    loop 2
  loop 1 
模板中的变量会隐藏(而不是覆盖)数据模型中同名变量,如果需要访问数据模型中的同名变量,使用特殊变量global,下面的例子假设数据模型中的user的值是Big Joe: 
<#assign user = "Joe Hider">
${user}          <#-- prints: Joe Hider -->
${.globals.user} <#-- prints: Big Joe -->  
(3)名字空间 
通常情况,只使用一个名字空间,称为主名字空间 
为了创建可重用的宏、变换器或其它变量的集合(通常称库),必须使用多名字空间,其目的是防止同名冲突 
创建库 
下面是一个创建库的例子(假设保存在lib/my_test.ftl中): 
<#macro copyright date>
  

Copyright (C) ${date} Julia Smith. All rights reserved.  
Email: ${mail}

  <#assign mail = "[email protected]">
使用import指令导入库到模板中,Freemarker会为导入的库创建新的名字空间,并可以通过import指令中指定的散列变量访问库中的变量: 
<#import "/lib/my_test.ftl" as my>
<#assign mail="[email protected]">
<@my.copyright date="1999-2002"/>
${my.mail}
${mail}  
输出结果: 
  

Copyright (C) 1999-2002 Julia Smith. All rights reserved.  
Email: [email protected]

[email protected] [email protected]  
可以看到例子中使用的两个同名变量并没有冲突,因为它们位于不同的名字空间 
可以使用assign指令在导入的名字空间中创建或替代变量,下面是一个例子: 
<#import "/lib/my_test.ftl" as my>
${my.mail}
<#assign mail="[email protected]" in my>
${my.mail}  
输出结果: 
[email protected]
[email protected]  
数据模型中的变量任何地方都可见,也包括不同的名字空间,下面是修改的库: 
<#macro copyright date>
  

Copyright (C) ${date} ${user}. All rights reserved.

<#assign mail = "${user}@acme.com">  
假设数据模型中的user变量的值是Fred,则下面的代码: 
<#import "/lib/my_test.ftl" as my>
<@my.copyright date="1999-2002"/>
${my.mail}   
输出结果: 
  

Copyright (C) 1999-2002 Fred. All rights reserved.

[email protected]   补充(静态方法的调用): 方法1: ##定义配置文件 freemarkerstatic.properties _Validator=com.longyou.util.Validator _Functions=com.longyou.util.Functions _EscapeUtils=com.longyou.util.EscapeUtils /调用代码 ${_Functions.toUpperCase("Hello")}
${_EscapeUtils.escape("狼的原野")} 方法2: ${stack.findValue("@package.ClassName@method")} 补充:常用语法
EG.一个对象BOOK
1.输出 ${book.name}
空值判断:${book.name?if_exists },
${book.name?default(‘xxx’)}//默认值xxx
${ book.name!"xxx"}//默认值xxx
日期格式:${book.date?string('yyyy-MM-dd')}
数字格式:${book?string.number}--20
${book?string.currency}--<#-- $20.00 -->
${book?string.percent}—<#-- 20% -->
插入布尔值:
<#assign foo=ture />
${foo?string("yes","no")} <#-- yes -->
 
 
 
 
2.逻辑判断
a:
<#if condition>...
<#elseif condition2>...
<#elseif condition3>......
<#else>...
其中空值判断可以写成<#if book.name?? >
 
b:
<#switch value>
<#case refValue1>
...
<#break>
<#case refValue2>
...
<#break>
...
<#case refValueN>
...
<#break>
<#default>
...
 
3.循环读取
<#list sequence as item>
...
空值判断<#if bookList?size = 0>
e.g.
<#list employees as e>
${e_index}. ${e.name}
输出:
1. Readonly
2. Robbin

freemarker中Map的使用
<#list testMap?keys as testKey> 
       < option value="${testKey}" > 
              ${testMap[testKey]} 
      
freemarker的Eclipse插件
If you use Eclipse 2.x: 
Open the Window menu, then Open Perspective -> Install/Update 
Click with the right mouse button on the Feature Updates view, then select New -> Site Bookmark 
In the displayed dialog box, type "FreeMarker" for Name and "http://www.freemarker.org/eclipse/update" for URL. Leave the "Bookmark type" radio buttons on "Eclipse update site". 
Click Finish 
Open the tree node under the newly created update site named "FreeMarker", select the "FreeMarker X.Y.Z" feature, and install it using the Install now button in the preview pane. 
If you use Eclipse 3.x: 
Help -> Software updates -> Find and install.... 
Choose "Search for new features to install". 
Click Add Update Site..., and type "FreeMarker" for Name and "http://www.freemarker.org/eclipse/update" for URL. 
Check the box of the "FreeMarker" feature. 
"Next"-s until it is installed... 
关键字: FreeMarker  
引用地址: http://www.dlog.cn/html/trackback.do?id=13925&type=1 (复制地址) 

FreeMarker设计指南(2)  

2、数据模型

(1)基础

        在快速入门中介绍了在模板中使用的三种基本对象类型:scalars、hashes 和sequences,其实还可以有其它更多的能力:

        scalars:存储单值

        hashes:充当其它对象的容器,每个都关联一个唯一的查询名字

        sequences:充当其它对象的容器,按次序访问

        方法:通过传递的参数进行计算,以新对象返回结果

        用户自定义FTL标记:宏和变换器

        通常每个变量只具有上述的一种能力,但一个变量可以具有多个上述能力,如下面的例子:

(root)

 |

 +-mouse = "Yerri"

    |

    +- age = 12

    |

    +- color = "brown"> 

        mouse既是scalars又是hashes,将上面的数据模型合并到下面的模板:

${mouse}       <#-- use mouse as scalar -->

${mouse.age}   <#-- use mouse as hash -->

${mouse.color} <#-- use mouse as hash--> 

        输出结果是:

Yerri

12

brown 

(2)Scalar变量

        Scalar变量存储单值,可以是:

        字符串:简单文本,在模板中使用引号(单引号或双引号)括起

        数字:在模板中直接使用数字值

        日期:存储日期/时间相关的数据,可以是日期、时间或日期-时间(Timestamp);通常情况,日期值由程序员加到数据模型中,设计者只需要显示它们

        布尔值:true或false,通常在<#if …>标记中使用

(3)hashes 、sequences和集合

        有些变量不包含任何可显示的内容,而是作为容器包含其它变量,者有两种类型:

        hashes:具有一个唯一的查询名字和它包含的每个变量相关联

        sequences:使用数字和它包含的每个变量相关联,索引值从0开始

        集合变量通常类似sequences,除非无法访问它的大小和不能使用索引来获得它的子变量;集合可以看作只能由<#list…>指令使用的受限sequences

(4)方法

        方法变量通常是基于给出的参数计算值

        下面的例子假设程序员已经将方法变量avg放到数据模型中,用来计算数字平均值:

The average of 3 and 5 is: ${avg(3, 5)}

The average of 6 and 10 and 20 is: ${avg(6,10, 20)}

The average of the price of python andelephant is: ${avg(animals.python.price, animals.elephant.price)}

(5)宏和变换器

        宏和变换器变量是用户自定义指令(自定义FTL标记),会在后面讲述这些高级特性

(6)节点

        节点变量表示为树型结构中的一个节点,通常在XML处理中使用,会在后面的专门章节中讲述




Trackback:http://tb.blog.csdn.net/TrackBack.aspx?PostId=164465

 

 

解析FreeMarker视图

·        解析FreeMarker视图

 

声明一个针对FreeMarker的视图解析器:

 

           web.servlet.view.freemarker.FreeMarkerViewResolver">

    .ftl

 

 

FreeMarkerViewResolver和VelocityViewResolver或InternalResourceViewResolver的工作机制相同。模板资源是通过在视图的逻辑名上增加prefix属性的值作为前缀,以及增加suffix属性的值作为后缀进行解析的。和VelocityViewResolver一样,在这里我们又一次只设置suffix属性,因为模板的路径已经在FreeMarkerConfigurer的templateLoaderPath属性中定义了。

暴露请求和会话属性

在第9.1.3节中,你看到如何告诉VelocityViewResolver将请求和会话属性复制到模型map中,从而它们能够在模板中作为变量使用。采用同样的方式配置FreeMarkerViewResolver,可以将请求和会话属性作为变量暴露给FreeMarker模板使用。要做到这一点,可以设置exposeRequestAttributes或者exposeSessionAttributes为true:

 

           web.servlet.view.freemarker.FreeMarkerViewResolver">

 

   

      true

   

   

      true

   

 

 

这里,两个属性都被设置为true。结果是请求和会话属性都被复制到模板的属性集中,可以使用FreeMarker的表达式语言来访问并显示。

 

FreeMarker文章引用自:

发表时间:2007年11月2日 16时54分13秒        本文链接:http://user.qzone.qq.com/55117942/blog/1193993653评论/阅读(0/5)

[顶]FreeMarker

包含FreeMarker的指令的文件就称为模板(Template)。

  包含FreeMarker的指令的文件就称为模板(Template)。
模板设计者不关心数据从那儿来,只知道使用已经建立的数据模型。
数据模型由程序员编程来创建,向模板提供变化的信息,这些信息来自于数据库、文件,甚至于在程序中直接生成。

数据类型:

一、基本:
1、scalars:存储单值

字符串:简单文本由单或双引号括起来。
数字:直接使用数值。
日期:通常从数据模型获得
布尔值:true或false,通常在<#if …>标记中使用

2、hashes:充当其它对象的容器,每个都关联一个唯一的查询名字

具有一个唯一的查询名字和他包含的每个变量相关联。

3、sequences:充当其它对象的容器,按次序访问

使用数字和他包含的每个变量相关联。索引值从0开始。

4、集合变量:

除了无法访问它的大小和不能使用索引来获得它的子变量:集合可以看作只能由<#list...>指令使用的受限sequences。

5、方法:通过传递的参数进行计算,以新对象返回结果

方法变量通常是基于给出的参数计算值在数据模型中定义。

6、用户自定义FTL指令:宏和变换器

7、节点

节点变量表示为树型结构中的一个节点,通常在XML处理中使用。

模板:

使用FTL(freeMarker模板语言)编写

组成部分

一、整体结构

1、注释:<#--注释内容-->,不会输出。

2、文本:直接输出。

3、interpolation:由 ${var} 或 #{var} 限定,由计算值代替输出。

4、FTL标记

二、指令:
freemarker指令有两种:
1、预定义指令:引用方式为<#指令名称>
2、用户定义指令:引用方式为<@指令名称>,引用用户定义指令时须将#换为@。
注意:如果使用不存在的指令,FreeMarker不会使用模板输出,而是产生一个错误消息。

freemarker指令由FTL标记来引用,FTL标记和HTML标记类似,名字前加#来加以区分。如HTML标记的形式为

则FTL标记的形式是<#list>(此处h1标记和list指令没有任何功能上的对应关系,只是做为说明使用一下)。

有三种FTL标记:
1)、开始标记:<#指令名称>
2)、结束标记:
3)、空标记:<#指令名称/>

注意:

1) FTL会忽略标记之中的空格,但是,<#和指令 与 2) FTL标记不能够交叉,必须合理嵌套。每个开始标记对应一个结束标记,层层嵌套。 如:
<#list>

  • ${数据}
    <#if 变量>

    game over!






  • 注意事项:
    1)、FTL对大小写敏感。所以使用的标记及interpolation要注意大小写。name与NAME就是不同的对象。<#list>是正确的标记,而<#List>则不是。
    2)、interpolation只能在文本部分使用,不能位于FTL标记内。如<#if ${var}>是错误的,正确的方法是:<#if var>,而且此处var必须为布尔值。
    3)、FTL标记不能位于另一个FTL标记内部,注释例外。注释可以位于标记及interpolation内部。


    三、表达式

    1、直接指定值:

    1-1、字符串:
    由双引号或单引号括起来的字符串,其中的特殊字符(如' " \等)需要转义。


    1-2、raw字符串:
    有一种特殊的字符串称为raw字符串,被认为是纯文本,其中的\和{等不具有特殊含义,该类字符串在引号前面加r,下面是一个例子:
    ${r"/${data}"year""}屏幕输出结果为:/${data}"year"


    转义    含义
    序列  

    \"  双引号(u0022)

    \'  单引号(u0027)

    \\  反斜杠(u005C)

    \n  换行(u000A)

    \r  Return (u000D)

    \t  Tab (u0009)

    \b  Backspace (u0008)

    \f  Form feed (u000C)

    \l  <

    \g  >

    \a  &

    \{  {

    \xCode  4位16进制Unicode代码

    1-3、数字:直接输入,不需要引号

    1)、精度数字使用“.”分隔,不能使用分组符号
    2)、目前版本不支持科学计数法,所以“1E3”是错误的
    3)、不能省略小数点前面的0,所以“.5”是错误的
    4)、数字8、+8、08和8.00都是相同的

    1-4、布尔值:true和false,不使用引号

    1-5、序列:由逗号分隔的子变量列表,由[]方括号限定。
    1)、子变量列表可以是表达式
    2)、可以使用数字范围定义数字序列,不需要方括号限定,例如2..5等同于[2, 3, 4, 5],但是更有效率,可以定义反递增范围如:5..2。

    1-6、散列(hash)
    1)、由逗号分隔的键/值列表,由{}大括号限定,键和值之间用冒号分隔,如:{"key1":valu1,"key2":"character string"....}
    2)、键和值都是表达式,但是键必须是字符串。

    2、获取变量:

    2-1、顶层变量:${变量名}

    变量名只能是字母、数字、下划线、$、#、@ 的组合,且不能以数字开头。

    2-2、散列:有两种方法

    1)、点语法:变量名字和顶层变量的名字受同样的限制
    2)、方括号语法:变量名字无限制,可以是任意的表达式的结果
    book.author.name
    book.author.["name"]
    book["author"].name
    book["author"]["name"]
    以上是等价的。

    2-3、序列:使用散列的方括号语法获取变量,方括号中的表达式结果必须为数字。注意:第一个项目的索引为0。可以使用
    [startindex..endindex]语法获取序列片段。

    2-4、特殊变量:FreeMarker内定义变量,使用.variablename语法访问。

    3、字符串操作

    3-1、interpolation:使用${}或#{}在文本部分插入表达式的值,例如:

    ${"hello${username}!"}
    ${"${username}${username}${username}"}

    也可以使用+来获得同样的结果:
    ${"hello"+username+"!"}
    ${username+username+username}

    注意:${}只能用于文本部分而不能出现于标记内。

    <#if ${user.login}>或<#if "${user.login}">都是错误的;
    <#if user.login>是正确的。
    本例中user.login的值必须是布尔类型。

    3-2、子串:
    举例说明:假如user的值为"Big Joe"
    ${user[0]}${user[4]}结果是:BJ
    ${user[1..4]}结果是:ig J

    4、序列操作

    4-1、连接操作:可以使用+来操作,例如:
    ["title","author"]+["month","day"]

    5、散列操作
    5-1、连接操作:可以使用+来操作,如果有相同的KEY,则右边的值会替代左边的值,例如:
    {"title":散列,"author":"emma"}+{"month":5,"day":5}+{"month":6}结果month的值就是6。

    6、算术运算

    6-1、操作符:+、-、*、/、%
    除+号以外的其他操作符两边的数据,必须都是数字类型。
    如果+号操作符一边有一个字符型数据,会自动将另一边的数据转换为字符型数据,运算结果为字符型数据。

    6-2、比较操作符:
    1)、=
    2)、==
    3)、!=
    4)、<
    5)、<=
    6)、>
    7)、>=
    1-3的操作符,两边的数据类型必须相同,否则会产生错误
    4-7的操作符,对于日期和数字可以使用,字符串不可以使用。

    注意:
    1)、FreeMarker是精确比较,所以"x" "x " "X"是不等的。
    2)、因为<和>对FTL来说是开始和结束标记,所以,可以用两种方法来避免这种情况:
    一种是使用括号<#if (a
    另一是使用替代输出,对应如下:
    <  lt
    <= lte
    >  gt
    >= gte

    6-3、逻辑操作符:只能用于布尔值,否则会出现错误。

    &&(and)与运算
    ||(or)或运算
    !(not)非运算

    6-4、内建函数:使用方法类似于访问散列的子变量,只是使用?代替.例如:${test?upper_case?html}

    常用的内建函数列举如下:

    1)、字符串使用:

    html:对字符串进行HTML编码
    cap_first:字符串第一个字母大写
    lower_first:字符串第一个字母小写
    upper_case:将字符串转换成大写
    trim:去年字符前后的空白字符

    2)、序列使用:
    size:获得序列中元素的数目

    3)、数字使用:
    int:取得数字的整数部分

    7、操作符的优先顺序:

    后缀:[subbarName][subStringRange].(mathodParams)
    一元:+expr、-expr、! (not)
    内建:?
    乘法:*、/、%
    加法:+、-
    关系:<、<=、>、>= (lt、lte、gt、gte)
    相等:=、==、!=
    逻辑与:&& (and)
    逻辑或:|| (or)
    数字范围:..

    四、interpolation

    inperpolation只能用于文本,有两种类型:通用interpolation及数字interpolation

    1、通用interpolation

    如${expr}

    1-1、插入字符串值:直接输出表达式结果。
    1-2、插入数字值:根据缺省格式(由setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string来格式化单个interpolation

    如:
    <#setting number_format="currency" />
    <#assign answer=42 />
    ${answer}  <#-- ¥42.00 -->
    ${answer?string}  <#-- ¥42.00 -->
    ${answer?string.number}  <#-- 42 -->
    ${answer?string.currency}  <#-- ¥42.00 -->
    ${answer?string.percent}  <#-- 42,00% -->

    1-3、插入日期值:根据缺省格式(由setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string来格式化单个interpolation

    如:

    ${lastupdata?string("yyyy-MM-dd HH:mm:ss zzzz")}  <#-- 2003-04-08 21:24:44 Pacific Daylight Time -->
    ${lastupdata?string("EEE,MMM d, ''yy")}  <#-- tue,Apr 8, '03 -->
    ${lastupdata?string("EEEE,MMMM dd, yyyy,hh:mm:ss a '('zzz')'")}  <#-- Tuesday,April 08, 2003, 09:24:44 PM (PDT)-->

    1-4、插入布尔值:根据缺省格式(由setting指令设置)将表达式结果转换成文本输出;可以使用内建函数string来格式化单个interpolation

    如:
    <#assign foo=ture />
    ${foo?string("yes","no")} <#-- yes -->

    2、数字interpolation:

    有两种形式:
    1)、#{expr}
    2)、#{expr;format}:format可以用来格式化数字,format可以是如下:
    mX:小数部分最小X位
    MX:小数部分最大X位

    例如:
    <#assign x=2.582 />
    <#assign y=4 />
    #{x;M2} <#-- 2.58 -->
    #{y;M2} <#-- 4 -->
    #{x;m1} <#-- 2.582 -->
    #{y;m1} <#-- 4.0 -->
    #{x;m1M2} <#-- 2.58 -->
    #{y;m1M2} <#-- 4.0 -->


    杂项

    一、用户定义指令

    宏和变换器变量是两种不同类型的用户自定义指令,他们的区别是:

    宏可以在模板中用macro指令来定义
    变换器是在模板外由程序定义

    1、宏:和某个变量关联的模板片段,以便在模板中通过用户自定义指令使用该变量
    1-1、基本用法:
    例如:
    <#macro greet>
    Hello JOE!



    使用时:
    <@greet>
    如果没有体内容也可以用
    <@greet />

    1-2、变量:

    1)、可以在宏定义之后定义参数,宏参数是局部变量,只在宏定义中有效。如:

    <#macro greet person>
    Hello ${person}!

    使用时:
    <@greet person="emma"> and <@greet person="LEO">
    输出为:
    Hello emma!
    Hello LEO!

    注意:宏的参数是FTL表达式,所以,person=emma和上面的例子中具有不同的意义,这意味着将变量emma的值传给person,这个值可能是任意一种数据类型,甚至是一个复杂的表达式。


    宏可以有多个参数,使用时参数的次序是无关的,但是只能使用宏中定义的参数,并且对所有参数赋值。如:
    <#macro greet person color>
    Hello ${person}!


    使用时:
    <@greet color="black" person="emma" />正确
    <@greet person="emma" />错误,color没有赋值,此时,如果在定义宏时为color定义缺省值<#macro greet person color="black">这样的话,这个使用方法就是正确的。
    <@greet color="black" person="emma" bgcolor="yellow" />错误,宏greet定义中未指定bgcolor这个参数



    2、嵌套内容:

    2-1、自定义指令可以有嵌套内容,使用<#nested>指令,执行自定义指令开始和结束标记之间的模板片段。例如:
    <#macro greet>


    <#nested>





    <@greet>hello Emma!

    输出为

    hello Emma!



    2-2、<#nested>指令可以被多次调用,例如
    <#macro greet>


    <#nested>
    <#nested>
    <#nested>
    <#nested>




    <@greet>hello Emma!

    输出为


    hello Emma!
    hello Emma!
    hello Emma!
    hello Emma!



    2-3、嵌套的内容可以是有效的FTL,例如:
    <#macro welcome>


    <#nested>




    <#macro greet person color="black">
    Hello ${person}!


    <@welcome>
    <@greet person="Emma" color="red" />
    <@greet person="Andrew" />
    <@greet person="Peter" />


    输出为:


    Hello Emma!
    Hello Andrew!
    Hello Peter!



    2-4、宏定义中的局部变量对嵌套内容是不可见的,例如:

    <#macro repeat count>
    <#local y="test" />
    <#list 1..count as x>
    ${y}${count}/${x}:<#nested />



    <@repeat count=3>
    ${y?default("?")}
    ${x?default("?")}
    ${count?default("?")}


    输出结果为
    test 3/1:???
    test 3/2:???
    test 3/3:???

    2-5、在宏定义中使用循环变量,通常用来重复嵌套内容,基本用法为:作为nested指令的参数,传递循环变量的实际值,而在调用自定义指令时,在标记的参数后面指定循环变量的名字。
    例如:
    <#macro repeat count>
    <#list 1..count as x>
    <#nested x,x/2,x==count />



    <@repeat count=4;c,halfc,last>
    ${c}. ${halfc}
    <#if last>
    last!



    输出结果是

    1. 0.5
    2. 1
    3. 1.5
    4. 2last!

    注意:指定循环变量的数目和用户定义指令开始标记指定的不同不会有问题
    调用时,少指定循环变量,多指定的值会不见
    调用时,多指定循环变量,多余的循环变量不会被创建

    二、在模板中定义变量

    1、在模板中定义的变量有三种类型

    1-1、plain变量:可以在模板的任何地方访问,包括使用include指令插入的模板,使用assign指令创建和替换。
    1-2、局部变量:在宏定义体中有效,使用local指令创建和替换。
    1-3、循环变量:只能存在于指令的嵌套内容,由指令(如list)自动创建。

    注意:
    1)、宏的参数是局部变量,不是循环变量。
    2)、局部变量隐藏同名的plain变量
    3)、循环变量隐藏同名的plain变量和局部变量。

    例如:

    <#assign x="plain">
    1. ${x} <#-- plain -->

    <@test />

    6. ${x}
    <#list ["loop"] as x>
    7. ${x} <#-- loop -->
    <#assign x="plain2">
    8. ${x} <#-- loop -->

    9. ${x} <#-- plain2 -->

    <#macro test>
    2. ${x} <#-- plain -->
    <#local x="local">
    3. ${x} <#-- local -->
    <#list ["loop"] as x>
    4. ${x} <#-- loop -->

    5. ${x} <#-- local -->


    4)、内部循环变量隐藏同名的外部循环变量

    <#list ["loop1"] as x>
    ${x} <#-- loop1 -->
    <#list ["loop2"] as x>
    ${x} <#-- loop2 -->
    <#list ["loop3"] as x>
    ${x} <#-- loop3 -->

    ${x} <#-- loop2 -->

    ${x} <#-- loop1 -->


    5)、模板中的变量会隐藏数据模型中的同名变量,如果需访问数据模型中的变量,使用特殊变量global。

    例如:
    假设数据模型中的user值为Emma
    <#assign user="Man">
    ${user} <#-- Man -->
    ${.global.user} <#-- Emma -->

    数据源+freemarker+servlet生成xml文件  

    .步骤:

    1.server.xml文件中建立数据源.

    <Service name="Cms">
         <Connector debug="0" enableLookups="false" port="8084" protocol="AJP/1.3" redirectPort="8443"/>
        <Connector acceptCount="100" connectionTimeout="20000" debug="0" disableUploadTimeout="true" 

    enableLookups
    ="false" maxSpareThreads="75" maxThreads="150" minSpareThreads="25" port="8081" redirectPort="8443"/>
        <Engine defaultHost="localhost_Cms" name="Catalina_Cms">
          <Logger className="org.apache.catalina.logger.FileLogger" prefix="localhost_cmt_log." suffix=".txt" timestamp="true"/>
          <Realm className="org.apache.catalina.realm.UserDatabaseRealm"/>
          <Host autoDeploy="true" debug="0" name="localhost_Cms" unpackWARs="true" xmlNamespaceAware="false" xmlValidation="false">
             <Context debug="0" docBase="D:WorkspaceCMSweb" path="/" reloadable="true" workDir="D:WorkspaceCMSj2src"> 
              <Resource name="jdbc/news_DB" auth="Container" type="javax.sql.DataSource"/>
            <ResourceParams name="jdbc/news_DB">
         <parameter>
           <name>factoryname>
           
           <value>org.apache.commons.dbcp.BasicDataSourceFactoryvalue>
         parameter>
          
         <parameter>
           <name>maxActivename>
           <value>1000value>
         parameter>
         <parameter>
            <name>validationQueryname>
            <value>select 1+1value>
         parameter>
         <parameter>
           <name>maxIdlename>
           <value>100value>
         parameter>
         <parameter>
           <name>maxWaitname>
           <value>10000value>
         parameter>
         <parameter>
           <name>removeAbandonedname>
           <value>truevalue>
         parameter>
         <parameter>
           <name>removeAbandonedTimeoutname>
           <value>60value>
         parameter>
         <parameter>
           <name>logAbandonedname>
           <value>falsevalue>
         parameter>
          
         <parameter>
           <name>usernamename>
           <value>aaaavalue>
         parameter>
         <parameter>
           <name>passwordname>
           <value>bbbbbbvalue>
         parameter>
         <parameter>
           <name>driverClassNamename>
           <value>net.sourceforge.jtds.jdbc.Drivervalue>
         parameter>
         <parameter>
           <name>urlname>
           <value>jdbc:jtds:sqlserver://111.111.111.111:1433/cmsvalue>
         parameter>
          ResourceParams>
          
       Context>
          Host>
    Engine>
      Service> 

    2.web.xml文件中配置servlet 

        <servlet>
            <description>generate xml filedescription>
            <servlet-name>NewsXmlServletservlet-name>
            <servlet-class>xml.NewsXmlServletservlet-class>
        servlet>
        <servlet-mapping>
            <servlet-name>NewsXmlServletservlet-name>
            <url-pattern>/xmlServleturl-pattern>
        servlet-mapping>
        <servlet>

    3.newsXmlServlet.java

    package xml;

    import java.io.*;
    import java.nio.charset.Charset;
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;

    import javax.naming.Context;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.sql.DataSource;

    import freemarker.template.Configuration;
    import freemarker.template.Template;
    import freemarker.template.TemplateException;

    import java.util.Locale;

    public class NewsXmlServlet extends HttpServlet...{

        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException ...{
            // TODO Auto-generated method stub
            try ...{
                Connection conn=null;
                Context ctx = new InitialContext();
                DataSource ds=(DataSource)ctx.lookup("java:comp/env/jdbc/news_DB");
                conn=ds.getConnection();
                Statement stmt=conn.createStatement();
                ResultSet rs=stmt.executeQuery("select url,updatetime,tpf_edu_contentTitle,tpf_edu_contentneirong,tpf_edu_contentlaiyuan,tpf_edu_contentkeyword from tp5__edu_content where url<>'' and url is not null and dateDiff(d,updatetime,getDate())=1 order by updatetime desc");
                Configuration cfg=new Configuration();
                cfg.setDirectoryForTemplateLoading(new File("E:/wwwroot/CMS/web/WEB-INF/classes/xml"));
                Template tem=cfg.getTemplate("news.ftl");
                
                List list=new ArrayList();
                OutputStreamWriter out=new OutputStreamWriter(System.out);
                while(rs.next())...{
                    Map item=new HashMap();
                    item.put("title",rs.getString(3));
                    item.put("link","http://test.com.cn"+rs.getString(1));
                    item.put("pubdate",rs.getTimestamp(2));
                    item.put("content",DelHtml(rs.getString(4)));
                    item.put("source",rs.getString(5));
                    item.put("keywords",DelHtml(rs.getString(6)));
                    list.add(item);
                }
                Map data=new HashMap();
                data.put("items",list);
                StringWriter writer=new StringWriter();
                tem.process(data,writer);
                String content=writer.toString();
                writer.close();
                createXml(content);
                out.close();
                //resp.setContentType("text/xml; charset=utf-8");
                //resp.getWriter().write(content);
                
            } catch (NamingException e) ...{
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (SQLException e) ...{
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (TemplateException e) ...{
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
        public String DelHtml(String content)...{
            String contents=content.replaceAll("<\/?\s*(\S+)(\s*[^>]*)?\s*\/?>","");
             contents=contents.replaceAll("“", "”");
             contents=contents.replaceAll("”","”");
             contents=contents.replaceAll("“", "‘");
             contents=contents.replaceAll("”","’");
             contents=contents.replaceAll("·","·");
             contents=contents.replaceAll("—","—");
             contents=contents.replaceAll("…","…");
             contents=contents.replaceAll(" ","");
             contents=contents.replaceAll(","," ");
            return contents;        
        }
        public void createXml(String fileContent)...{
            try ...{
                String filePath="E:/wwwroot/cmsHtml/education/news.xml";
                File fileXml=new File(filePath);
                if(!fileXml.exists())...{            
                    fileXml.createNewFile();
                }
                
                /**//*FileWriter fileWriter=new FileWriter(fileXml);
                fileWriter.
                fileWriter.write(fileContent);
                fileWriter.close();*/

                    OutputStreamWriter writer=new OutputStreamWriter(new FileOutputStream(fileXml), Charset.forName("utf-8"));     
                    writer.write(fileContent);
                    writer.close();
                } catch (IOException e) ...{
                    // TODO Auto-generated catch block
                    e.printStackTrace();
            }
        }
        
        public void destroy() ...{
            // TODO Auto-generated method stub
            super.destroy();
        }

        public void init() throws ServletException ...{
            // TODO Auto-generated method stub
            super.init();
        }
        
    }

    4.news.ftl

     



        edu.aweb.com.cn
        [email protected]
        1440
        <#list items as it>
        
            <![CDATA[$<span style="color:#4B4B4B; background:white">...</span>{it.title}]]>
            $...{it.link}
            $...{it.pubdate}
            ...{it.content}]]>
            
            $...{it.source}
            ...{it.keywords}]]>
        

        

     Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1889578

    FreeMarker学习笔记3

    2007-10-18 13:11

    (3)模板

    l         在FreeMarker模板中可以包括下面三种特定部分:

    Ø         ${…}:称为interpolations,FreeMarker会在输出时用实际值进行替代

    Ø         FTL标记(FreeMarker模板语言标记):类似于HTML标记,为了与HTML标记区分,用#开始(有些以@开始,在后面叙述)

    Ø         注释:包含在<#--和-->(而不是)之间

    l         下面是一些使用指令的例子:

    Ø         if指令

    <#if animals.python.price < animals.elephant.price>

      Pythons are cheaper than elephants today.

    <#else>

      Pythons are not cheaper than elephants today.

      

    Ø         list指令

    We have these animals:

     

    NamePrice

      <#list animals as being>

     

    ${being.name}${being.price} Euros

     

      

    玩过C#的都一眼就看出来了,和foreach一样.用过java的for(xx:xx)的家伙也清楚吧.其实就是遍历这个being.

    输出为:

    We have these animals:

     

    NamePrice

     

    mouse50 Euros

     

    elephant5000 Euros

     

    python4999 Euros

      

    Ø         include指令

      Test page

     

    Test page

     

    Blah blah...

    <#include "/copyright_footer.html">

      

    这个就不用解释了,嵌入个网页

    Ø         一起使用指令

    We have these animals:

     

       

    NamePrice

      <#list animals as being>

     

          <#if being.size = "large">

          ${being.name}

          <#if being.size = "large">

       

    ${being.price} Euros

     

      

    Spring中使用FreeMaker或Vilocity模板发送邮件

            本文以用户注册后为用户发送一封邮件为例子,讲述如何在Spring中使用FreeMaker或Vilocity发送邮件。

           Spring配置文件:

     

    xml 代码

    1.   
    2.       
    3.           
    4.           
    5.           
    6.           
    7.                 
    8.                 trueprop>  
    9.               props>  
    10.         property>  
    11.     bean>  
    12.   
    13.       
    14.       
    15.           
    16.           
    17.               
    18.                 0prop>  
    19.                 GBKprop>  
    20.                 zh_CNprop>  
    21.             props>  
    22.         property>  
    23.     bean>  
    24.        
    25.       
    26.       
    27.           
    28.           
    29.               
    30.                 *.vmprop>  
    31.                 text/html; charset=utf-8prop>  
    32.                 utf-8prop>  
    33.                 utf-8prop>  
    34.             props>  
    35.         property>  
    36.     bean>  
    37.        
    38.        
    39.           
    40.     bean>  
    41.        
    42.       
    43.           
    44.           
    45.           
    46.          
    47.          
    48.     bean>  

        
     
       

    java 代码

    1.  MailEngine类:   
    2.   
    3. public class MailEngine {   
    4.     protected static final Log log = LogFactory.getLog(MailEngine.class);   
    5.   
    6. //    private FreeMarkerConfigurer freeMarkerConfigurer;   
    7.     private VelocityEngine velocityEngine;   
    8.     private MailSender mailSender;   
    9.   
    10. //    public void setFreeMarkerConfigurer(   
    11. //            FreeMarkerConfigurer freeMarkerConfigurer) {   
    12. //        this.freeMarkerConfigurer = freeMarkerConfigurer;   
    13. //    }   
    14.   
    15.     public void setMailSender(MailSender mailSender) {   
    16.         this.mailSender = mailSender;   
    17.     }   
    18.   
    19.     public void setVelocityEngine(VelocityEngine velocityEngine) {   
    20.         this.velocityEngine = velocityEngine;   
    21.     }   
    22.   
    23.     /**  
    24.      * 通过模板产生邮件正文  
    25.      * @param templateName    邮件模板名称  
    26.      * @param map            模板中要填充的对象  
    27.      * @return 邮件正文(HTML)  
    28.      */  
    29.     public String generateEmailContent(String templateName, Map map) {   
    30.         //使用FreeMaker模板   
    31. //        try {   
    32. //            Configuration configuration = freeMarkerConfigurer.getConfiguration();   
    33. //            Template t = configuration.getTemplate(templateName);   
    34. //            return FreeMarkerTemplateUtils.processTemplateIntoString(t, map);   
    35. //        } catch (TemplateException e) {   
    36. //            log.error("Error while processing FreeMarker template ", e);   
    37. //        } catch (FileNotFoundException e) {   
    38. //            e.printStackTrace();   
    39. //            //log.error("Error while open template file ", e);   
    40. //        } catch (IOException e) {   
    41. //            log.error("Error while generate Email Content ", e);   
    42. //        }   
    43.            
    44. //        使用Vilocity模板   
    45.         try {   
    46.            return VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, templateName, map);   
    47.         } catch (VelocityException e) {   
    48.             log.error("Error while processing Vilocity template ", e);   
    49.         }   
    50.            
    51.         return null;   
    52.     }   
    53.   
    54.     /**  
    55.      * 发送邮件  
    56.      * @param emailAddress        收件人Email地址的数组  
    57.      * @param fromEmail            寄件人Email地址, null为默认寄件人[email protected]  
    58.      * @param bodyText            邮件正文  
    59.      * @param subject            邮件主题  
    60.      * @param attachmentName    附件名  
    61.      * @param resource            附件  
    62.      * @throws MessagingException  
    63.      */  
    64.     public void sendMessage(String[] emailAddresses, String fromEmail,   
    65.             String bodyText, String subject, String attachmentName,   
    66.             ClassPathResource resource) throws MessagingException {   
    67.         MimeMessage message = ((JavaMailSenderImpl) mailSender)   
    68.                 .createMimeMessage();   
    69.   
    70.         // use the true flag to indicate you need a multipart message   
    71.         MimeMessageHelper helper = new MimeMessageHelper(message, true);   
    72.   
    73.         helper.setTo(emailAddresses);   
    74.         if(fromEmail != null){   
    75.             helper.setFrom(fromEmail);   
    76.         }   
    77.         helper.setText(bodyText, true);   
    78.         helper.setSubject(subject);   
    79.            
    80.         if(attachmentName!=null && resource!=null)   
    81.             helper.addAttachment(attachmentName, resource);   
    82.   
    83.         ((JavaMailSenderImpl) mailSender).send(message);   
    84.     }   
    85.   
    86.     /**  
    87.      * 发送简单邮件  
    88.      * @param msg      
    89.      */  
    90.     public void send(SimpleMailMessage msg) {   
    91.         try {   
    92.             ((JavaMailSenderImpl) mailSender).send(msg);   
    93.         } catch (MailException ex) {   
    94.             //log it and go on   
    95.             log.error(ex.getMessage());   
    96.         }   
    97.     }   
    98.        
    99.     /**  
    100.      * 使用模版发送HTML格式的邮件  
    101.      *  
    102.      * @param msg          装有to,from,subject信息的SimpleMailMessage  
    103.      * @param templateName 模版名,模版根路径已在配置文件定义于freemakarengine中  
    104.      * @param model        渲染模版所需的数据  
    105.      */  
    106.     public void send(SimpleMailMessage msg, String templateName, Map model) {   
    107.         //生成html邮件内容   
    108.         String content = generateEmailContent(templateName, model);   
    109.         MimeMessage mimeMsg = null;   
    110.         try {   
    111.             mimeMsg = ((JavaMailSenderImpl) mailSender).createMimeMessage();   
    112.             MimeMessageHelper helper = new MimeMessageHelper(mimeMsg, true, "utf-8");   
    113.             helper.setTo(msg.getTo());   
    114.                
    115.             if(msg.getSubject()!=null)   
    116.                 helper.setSubject(msg.getSubject());   
    117.                
    118.             if(msg.getFrom()!=null)   
    119.                 helper.setFrom(msg.getFrom());   
    120.                
    121.             helper.setText(content, true);   
    122.                
    123.             ((JavaMailSenderImpl) mailSender).send(mimeMsg);   
    124.         } catch (MessagingException ex) {   
    125.             log.error(ex.getMessage(), ex);   
    126.         }   
    127.   
    128.     }   
    129. }   
    130.   
    131. 发送邮件:   
    132. SimpleMailMessage message = (SimpleMailMessage) getBean("mailMessage");   
    133.                 message.setTo(user.getName() + "<" + user.getEmail() + ">");   
    134.                    
    135.                 Map model = new HashMap();   
    136.                 model.put("user", user);   
    137.                    
    138.                 MailEngine engine = (MailEngine)getBean("mailEngine");   
    139.                 //Vilocity模板   
    140.                 engine.send(message, "notifyUser.vm", model);   
    141.                 //FreeMaker模板   
    142.                 //engine.send(message, "NotifyUser.ftl", model);   
    143.   
    144. 以上的User为用户类。  

     

    xml 代码

    1. 模板:   
    2.   
    3.   
    4.   
    5. 用户注册通知title>   </li> <li>head>   </li> <li><body>   </li> <li><p>${user.name} 您好,恭喜您,已经成为本站会员!p>   </li> <li><table>   </li> <li><tr><td>用户名:td><td>${user.name}td>tr>   </li> <li><tr><td>密码:td><td>${user.password}td>tr>   </li> <li>table>   </li> <li>body>   </li> <li>html>   </li> </ol> <h3>FreeMaker开发指南 </h3> <p>本文转自福州IT信息网(http://www.fzic.net),详细出处参考:http://www.fzic.net/SrcShow.asp?Src_ID=1328</p> <p> </p> <p>ello </p> <p>类似String.split的用法 </p> <p>“abc;def;ghi”?split(“;”)返回sequence</p> <p>将字符串按空格转化成sequence,然后取sequence的长度</p> <p>     var?word_list   效果同 var?split(“ ”) </p> <p>var?word_list?size</p> <p>取得字符串长度</p> <p>var?length</p> <p>大写输出字符</p> <p>var?upper_case</p> <p>小写输出字符</p> <p>var?lower_case</p> <p>首字符大写</p> <p>var?cap_first</p> <p>首字符小写</p> <p>var?uncap_first</p> <p>去掉字符串前后空格 </p> <p>var?trim</p> <p>每个单词的首字符大写</p> <p>var?capitalize</p> <p>类似String.indexof:</p> <p>“babcdabcd”?index_of(“abc”) 返回1</p> <p>“babcdabcd”?index_of(“abc”,2) 返回5</p> <p>类似String.lastIndexOf</p> <p>last_index_of和String.lastIndexOf类似,同上</p> <p>下面两个可能在代码生成的时候使用(在引号前加”\”)</p> <p>j_string: 在字符串引号前加”\”</p> <p><#assign beanName = 'The "foo"bean.'></p> <p>String BEAN_NAME ="${beanName?j_string}";</p> <p>打印输出:</p> <p>String BEAN_NAME = "The\"foo\" bean.";</p> <p>js_string:</p> <p><#assign user = "Big Joe's\"right hand\"."></p> <p><script></p> <p>  alert("Welcome ${user}!");</p> <p></script>  </p> <p>打印输出</p> <p>alert("Welcome Big Joe\'s \"righthand\"!");</p> <p>替换字符串 replace</p> <p>${s?replace(‘ba’, ‘XY’ )}</p> <p>${s?replace(‘ba’, ‘XY’ , ‘规则参数’)}将s里的所有的ba替换成xy 规则参数包含: i r m s c f 具体含义如下:</p> <p>· i: 大小写不区分.</p> <p>· f: 只替换第一个出现被替换字符串的字符串</p> <p>· r:   XY是正则表达式</p> <p>· m:Multi-line mode for regular expressions. In multi-line mode the expressions ^and $ match just after or just before, respectively, a line terminator or theend of the string. By default these expressions only match at the beginning andthe end of the entire string.</p> <p>· s: Enablesdotall mode for regular expressions (same as Perl singe-line mode). In dotallmode, the expression . matches any character, including a line terminator. Bydefault this expression does not match line terminators.</p> <p>· c: Permitswhitespace and comments in regular expressions.</p> <p> </p> <p>在模板里对sequences和hashes初始化</p> <p>sequences </p> <p>1. [“you”,”me”,”he”] </p> <p>2. 1..100</p> <p>3. [ {“Akey”:”Avalue”},{“Akey1”:”Avalue1”},</p> <p>{“Bkey”:”Bvalue”},{“Bkey1”:”Bvalue1”},</p> <p>]</p> <p>  </p> <p>hashes      {“you”:”a”,”me”:”b”,”he”:”c”}</p> <p> </p> <p>注释标志</p> <p><#-- </p> <p>这里是注释 </p> <p>--></p> <p>旧版本的freemarker采用的是<#comment> 注释 </#comment>方法</p> <p>sequences内置方法</p> <p>sequence?first</p> <p>返回sequence的第一个值;前提条件sequence不能是null</p> <p>sequence?last</p> <p>返回sequence最后一个值</p> <p>sequence?reverse</p> <p>反转sequence的值</p> <p>sequence?size</p> <p>返回sequence的大小</p> <p>sequence?sort</p> <p>对sequence按里面的对象toString()的结果进行排序</p> <p>sequence?sort_by(value)</p> <p>对sequence 按里面的对象的属性value进行排序</p> <p>如: sequence里面放入的是10 个user对象,user对象里面包含name,age等属性</p> <p>sequence?sort_by(name) 表示所有的user按user.name进行排序</p> <p>hashes内置方法</p> <p>hash?keys</p> <p>返回hash里的所有keys, 返回结果类型sequence</p> <p>hash?values</p> <p>返回hash里的所有value, 返回结果类型sequence</p> <p>4 freemarker在web开发中注意事项</p> <p>freemarker与webwork整合</p> <p>web中常用的几个对象</p> <p>Freemarker的ftl文件中直接使用内部对象:</p> <p>${Request ["a"]}</p> <p>${RequestParameters["a"]}</p> <p>${Session ["a"]}</p> <p>${Application ["a"]}</p> <p>${JspTaglibs ["a"]}</p> <p>与webwork整合之后 通过配置的servlet 已经把request,session等对象置入了数据模型中</p> <p>在view中存在下面的对象</p> <p>   我们可以在ftl中${req}来打印req对象</p> <p>· req - thecurrent HttpServletRequest </p> <p>· res - thecurrent HttpServletResponse </p> <p>· stack - thecurrent OgnlValueStack </p> <p>· ognl - theOgnlTool instance </p> <p>· webwork - aninstance of FreemarkerWebWorkUtil </p> <p>· action - thecurrent WebWork action </p> <p>· exception -optional the Exception instance, if the view is a JSP exception or Servletexception view</p> <p>view中值的搜索顺序</p> <p>${name}将会以下面的顺序查找name值</p> <p>· freemarkervariables </p> <p>· value stack </p> <p>· requestattributes </p> <p>· sessionattributes </p> <p>· servletcontext attributes </p> <p>在模板里ftl里使用标签</p> <p>注意,如果标签的属性值是数字,那么必须采用nubmer=123方式给属性赋值</p> <p>JSP页面</p> <p><%@page contentType="text/html;charset=ISO-8859-2"language="java"%></p> <p><%@tagliburi="/WEB-INF/struts-html.tld" prefix="html"%></p> <p><%@tagliburi="/WEB-INF/struts-bean.tld" prefix="bean"%></p> <p><html></p> <p>  <body></p> <p>    <h1><bean:message key="welcome.title"/></h1></p> <p>    <html:errors/></p> <p>    <html:form action="/query"></p> <p>      Keyword: <html:text property="keyword"/><br></p> <p>      Exclude: <html:text property="exclude"/><br></p> <p>      <html:submit value="Send"/></p> <p>    </html:form></p> <p>  </body></p> <p></html> </p> <p><strong>模板ftl页面</strong></p> <p><#assignhtml=JspTaglibs["/WEB-INF/struts-html.tld"]></p> <p><#assignbean=JspTaglibs["/WEB-INF/struts-bean.tld"]></p> <p><html></p> <p>  <body></p> <p>    <h1><@bean.messagekey="welcome.title"/></h1></p> <p>    <@html.errors/></p> <p>    <@html.form action="/query"></p> <p>      Keyword: <@html.text property="keyword"/><br></p> <p>      Exclude: <@html.text property="exclude"/><br></p> <p>      <@html.submit value="Send"/></p> <p>    </@html.form></p> <p>  </body></p> <p></html>  </p> <p> </p> <p>如何初始化共享变量</p> <p>1.初始化全局共享数据模型</p> <p>freemark在web上使用的时候对共享数据的初始化支持的不够,不能在配置初始化的时候实现,而必须通过ftl文件来初始化全局变量。这是不能满主需求的,我们需要在servlet init的时候留出一个接口来初始化系统的共享数据</p> <p>具 体到和webwork整合,因为本身webwork提供了整合servlet,如果要增加全局共享变量,可以通过修改com.opensymphony.webwork.views.freemarker.FreemarkerServlet来实现,我们可以在这个 servlet初始化的时候来初始化全局共享变量</p> <p>与webwork整合配置</p> <p>配置web.xml</p> <p><servlet></p> <p>    <servlet-name>freemarker</servlet-name></p> <p>    <servlet-class>com.opensymphony.webwork.views.freemarker.FreemarkerServlet</servlet-class></p> <p>    <init-param></p> <p>      <param-name>TemplatePath</param-name></p> <p><param-value>/</param-value></p> <p><!—模板载入文件夹,这里相对context root,递归获取该文件夹下的所有模板--></p> <p>    </init-param></p> <p>    <init-param></p> <p>      <param-name>NoCache</param-name> <!—是否对模板缓存--></p> <p>      <param-value>true</param-value></p> <p>    </init-param></p> <p>    <init-param></p> <p>      <param-name>ContentType</param-name></p> <p>      <param-value>text/html</param-value></p> <p>    </init-param></p> <p>    <init-param></p> <p><param-name>template_update_delay</param-name></p> <p><!—模板更新时间,0表示每次都更新,这个适合开发时候--></p> <p>      <param-value>0</param-value></p> <p>    </init-param></p> <p>    <init-param></p> <p>      <param-name>default_encoding</param-name></p> <p>      <param-value>GBK</param-value></p> <p>    </init-param></p> <p>    <init-param></p> <p>      <param-name>number_format</param-name></p> <p>      <param-value>0.##########</param-value><!—数字显示格式--></p> <p>    </init-param></p> <p>    <load-on-startup>1</load-on-startup></p> <p>  </servlet></p> <p>  <servlet-mapping></p> <p>    <servlet-name>freemarker</servlet-name></p> <p>    <url-pattern>*.ftl</url-pattern></p> <p>  </servlet-mapping></p> <p>5高级方法</p> <p>自定义方法</p> <p>${timer("yyyy-MM-dd H:mm:ss", x)}</p> <p>${timer("yyyy-MM-dd ", x)} </p> <p>在模板中除了可以通过对象来调用方法外(${object.methed(args)})也可以直接调用java实现的方法,java类必须实现接 口TemplateMethodModel的方法exec(List args). 下面以把毫秒的时间转换成按格式输出的时间为例子</p> <p>public class LongToDate implementsTemplateMethodModel {</p> <p>    </p> <p>public TemplateModel exec(List args) throwsTemplateModelException {</p> <p>SimpleDateFormat mydate = newSimpleDateFormat((String) args.get(0)));</p> <p>        return mydate.format(new Date(Long.parseLong((String)args.get(1)));</p> <p>    }</p> <p>}  </p> <p>将LongToDate对象放入到数据模型中</p> <p>root.put("timer", newIndexOfMethod());</p> <p>ftl模板里使用</p> <p><#assign x ="123112455445"></p> <p>${timer("yyyy-MM-dd H:mm:ss", x)}</p> <p>${timer("yyyy-MM-dd ", x)} </p> <p>输出</p> <p>2001-10-12 5:21:12</p> <p>2001-10-12</p> <p>自定义 Transforms</p> <p>实现自定义的<@transform>文本或表达式</@transform>的功能,允许对中间的最终文本进行<strong>解析转换</strong></p> <p>例子:实现<@upcase>str</@upcase>将str转换成STR 的功能</p> <p>代码如下:</p> <p>import java.io.*;</p> <p>import java.util.*;</p> <p>importfreemarker.template.TemplateTransformModel;</p> <p>class UpperCaseTransform implementsTemplateTransformModel {</p> <p>    public Writer getWriter(Writer out, Map args) {</p> <p>        return new UpperCaseWriter(out);</p> <p>    }</p> <p>    private class UpperCaseWriter extends Writer {</p> <p>      </p> <p>        private Writer out;</p> <p>          </p> <p>        UpperCaseWriter (Writer out) {</p> <p>            this.out = out;</p> <p>        }</p> <p>        public void write(char[] cbuf, int off, int len)</p> <p>                 throws IOException {</p> <p>            out.write(new String(cbuf, off, len).toUpperCase());</p> <p>        }</p> <p>        public void flush() throws IOException {</p> <p>            out.flush();</p> <p>        }</p> <p>        public void close() {</p> <p>        }</p> <p>    }</p> <p>}  </p> <p>然后将此对象put到数据模型中</p> <p>root.put("upcase", newUpperCaseTransform());</p> <p>在view(ftl)页面中可以如下方式使用</p> <p><@upcase></p> <p>hello world</p> <p></@upcase></p> <p>打印输出:</p> <p>HELLO WORLD</p> <p> </p> <p>查看更多关于:FreeMaker  FreeMaker开发指南  </p> <p>本文转自福州IT信息网(http://www.fzic.net),详细出处参考:http://www.fzic.net/SrcShow.asp?Src_ID=1328</p> <p> </p> </div> </div> </div> </div> </div> <!--PC和WAP自适应版--> <div id="SOHUCS" sid="1290096292692828160"></div> <script type="text/javascript" src="/views/front/js/chanyan.js"></script> <!-- 文章页-底部 动态广告位 --> <div class="youdao-fixed-ad" id="detail_ad_bottom"></div> </div> <div class="col-md-3"> <div class="row" id="ad"> <!-- 文章页-右侧1 动态广告位 --> <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_1"> </div> </div> <!-- 文章页-右侧2 动态广告位 --> <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_2"></div> </div> <!-- 文章页-右侧3 动态广告位 --> <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_3"></div> </div> </div> </div> </div> </div> </div> <div class="container"> <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(freemarker标签)</h4> <div id="paradigm-article-related"> <div class="recommend-post mb30"> <ul class="widget-links"> <li><a href="/article/1950222725712769024.htm" title="900 万人次都在用!打印机驱动大师:兄弟 驱动安装一步到位" target="_blank">900 万人次都在用!打印机驱动大师:兄弟 驱动安装一步到位</a> <span class="text-muted">文哥工具箱2</span> <a class="tag" taget="_blank" href="/search/%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B/1.htm">软件工程</a><a class="tag" taget="_blank" href="/search/%E7%94%B5%E8%84%91/1.htm">电脑</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E6%BA%90%E8%BD%AF%E4%BB%B6/1.htm">开源软件</a> <div>各位打印界的老铁们,你们知道吗?我就是那个传说中服务PT-18R标签打印机的“最佳损友”小助手!当你想把电脑里那些花里胡哨的标签设计变成能摸得着的实物时,嘿嘿,软件下载地址本助手就闪亮登场啦!插上USB线的瞬间,我立马在你电脑里“安营扎寨”,悄悄给你和打印机搭起一座“鹊桥”,让你们无障碍沟通,那叫一个丝滑!你在编辑软件里鼓捣的文字、条形码,甚至那些可可爱爱的小图标,全靠我这个“翻译官”精准转换成打</div> </li> <li><a href="/article/1950208989954371584.htm" title="Selenium 特殊控件操作与 ActionChains 实践详解" target="_blank">Selenium 特殊控件操作与 ActionChains 实践详解</a> <span class="text-muted">小馋喵知识杂货铺</span> <a class="tag" taget="_blank" href="/search/selenium/1.htm">selenium</a><a class="tag" taget="_blank" href="/search/%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7/1.htm">测试工具</a> <div>1.下拉框单选操作(a)使用SeleniumSelect类(标准HTML标签)Selenium提供了内置的Select类用于操作标准下拉框,这种方式简单且直观。fromselenium.webdriver.support.uiimportSelect#定位下拉框dropdown=Select(driver.find_element("id","dropdown_id"))#通过以下三种方式选择单个</div> </li> <li><a href="/article/1950178814076186624.htm" title="剽悍老铁:从1到6,在危机中成功迭代的他做对了什么?" target="_blank">剽悍老铁:从1到6,在危机中成功迭代的他做对了什么?</a> <span class="text-muted">洛柒姑娘</span> <div>作者:江湖姐姐、刘亚每一个当下的决定与行动,都是一个人未来的方向盘。剽悍财富行动营老铁刘亚做过几次大的决定与行动,这些行动让他在变局驾到的时候,成功躲过危机,甚至在行业退潮的时候,还迎来自己事业小的增长。92年的他曾在毕业后几年内创办了6所培训机构,拥有省劳动局的创业讲师证、樊登翻转师证,并获得过颍州区人才创业三等奖,但他最喜欢的标签还是奶爸。在他看来,创业也好,当奶爸也好,都是生命维度的延伸,都</div> </li> <li><a href="/article/1950138508161118208.htm" title="如何学好图像处理——从小白到大神?" target="_blank">如何学好图像处理——从小白到大神?</a> <span class="text-muted">chentengkui</span> <a class="tag" taget="_blank" href="/search/%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86/1.htm">图像处理</a> <div>如何学好图像处理——从小白到大神?标签:图像处理学习方法2016-02-2617:4818439人阅读评论(25)收藏举报分类:学习方法与方法论(13)版权声明:本文为博主原创文章,未经博主允许不得转载。什么是数字图像处理?历史、以及它所研究的内容。说起图像处理,你会想到什么?你是否真的了解这个领域所研究的内容。纵向来说,数字图像处理研究的历史相当悠久;横向来说,数字图像处理研究的话题相当广泛。数</div> </li> <li><a href="/article/1950121289456873472.htm" title="native.js设置可缩放的webview并隐藏缩放控件" target="_blank">native.js设置可缩放的webview并隐藏缩放控件</a> <span class="text-muted">Nanayai</span> <div>需求明确:webview页面可以手指缩放,并且不要那个原生控件;实现思路:1.使用h5+封装好的方法:设置scalable属性,并在html中设置meta标签:user-scalable=yes或不设置,minimum-scale和maximum-scale需要注意不要都设为1:mui.openWindow({url:"someThing",id:"someThing",styles:{scala</div> </li> <li><a href="/article/1950116196418383872.htm" title="B 站关键词排名提高避坑:这些操作反降权" target="_blank">B 站关键词排名提高避坑:这些操作反降权</a> <span class="text-muted">zhuzhuyaolai</span> <a class="tag" taget="_blank" href="/search/%E5%B0%8F%E7%A8%8B%E5%BA%8F/1.htm">小程序</a><a class="tag" taget="_blank" href="/search/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F/1.htm">微信小程序</a><a class="tag" taget="_blank" href="/search/%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%B9%B3%E5%8F%B0/1.htm">微信公众平台</a><a class="tag" taget="_blank" href="/search/%E7%94%9F%E6%B4%BB/1.htm">生活</a><a class="tag" taget="_blank" href="/search/%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E/1.htm">搜索引擎</a> <div>在B站,关键词排名对视频曝光和账号发展极为关键。不少UP主绞尽脑汁提升排名,却因一些错误操作不仅没达到目的,反而让账号权重降低。今天,就为大家盘点那些导致降权的“坑”,助大家在B站运营路上少走弯路。一、关键词堆砌,自毁前程有些UP主认为,在标题、简介、标签中大量堆砌关键词,就能提升搜索排名,实则大错特错。首先,严重影响用户体验,生硬的关键词堆砌让标题和简介晦涩难懂,用户看到这样的内容,很难产生点击</div> </li> <li><a href="/article/1950100184717389824.htm" title="11. HTML 中 DOCTYPE 的作用" target="_blank">11. HTML 中 DOCTYPE 的作用</a> <span class="text-muted">yqcoder</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E9%9D%A2%E8%AF%95-CSS/1.htm">前端面试-CSS</a><a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>总结H5的声明HTML5的DOCTYPE声明HTML5中的声明用于告诉浏览器当前文档使用的是HTML5的文档类型。它必须是文档中的第一行内容(在任何HTML标签之前),以确保浏览器能够正确地解析和渲染页面。DOCTYPE的作用触发标准模式:DOCTYPE声明的主要作用是让浏览器以标准模式(StandardsMode)来解析和渲染页面,而不是以兼容模式(QuirksMode)。兼容性:在没有DOCT</div> </li> <li><a href="/article/1950094764498022400.htm" title="Coze Studio 架构拆解:AI Agent 开发平台项目结构全分析" target="_blank">Coze Studio 架构拆解:AI Agent 开发平台项目结构全分析</a> <span class="text-muted">代码简单说</span> <a class="tag" taget="_blank" href="/search/2025%E5%BC%80%E5%8F%91%E5%BF%85%E5%A4%87%28%E9%99%90%E6%97%B6%E7%89%B9%E6%83%A0%29/1.htm">2025开发必备(限时特惠)</a><a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/1.htm">架构</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/Coze/1.htm">Coze</a><a class="tag" taget="_blank" href="/search/Studio/1.htm">Studio</a><a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/1.htm">架构</a><a class="tag" taget="_blank" href="/search/AI/1.htm">AI</a><a class="tag" taget="_blank" href="/search/Agent/1.htm">Agent</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E5%B9%B3%E5%8F%B0/1.htm">开发平台</a><a class="tag" taget="_blank" href="/search/%E5%85%A8%E6%A0%88/1.htm">全栈</a><a class="tag" taget="_blank" href="/search/AI/1.htm">AI</a><a class="tag" taget="_blank" href="/search/%E5%B7%A5%E7%A8%8B%E5%8C%96/1.htm">工程化</a><a class="tag" taget="_blank" href="/search/%E5%9B%BE%E8%A7%A3%E6%9E%B6%E6%9E%84/1.htm">图解架构</a> <div>CozeStudio架构拆解:AIAgent开发平台项目结构全分析标签:CozeStudio项目架构、领域驱动设计DDD、全栈开发规范、Hertz框架、前后端协作、云原生容器、前端测试、IDL接口设计、微服务解耦、AI开发平台源码分析在最近研究AIAgent开发平台的过程中,我深入分析了刚刚开源的CozeStudio项目。这套系统是国内少有的开源全栈AI工程化项目,代码整洁、架构先进,特别是它基于</div> </li> <li><a href="/article/1950089974804180992.htm" title="9、Docker Compose 实战" target="_blank">9、Docker Compose 实战</a> <span class="text-muted">小醉你真好</span> <a class="tag" taget="_blank" href="/search/%23/1.htm">#</a><a class="tag" taget="_blank" href="/search/%E9%83%A8%E7%BD%B2%E4%B8%8D%E6%B1%82%E4%BA%BA/1.htm">部署不求人</a><a class="tag" taget="_blank" href="/search/docker/1.htm">docker</a><a class="tag" taget="_blank" href="/search/%E5%AE%B9%E5%99%A8/1.htm">容器</a><a class="tag" taget="_blank" href="/search/%E8%BF%90%E7%BB%B4/1.htm">运维</a> <div>DockerCompose实战教程(含完整Nginx案例+配置项详解)适合读者:开发者、后端工程师、运维工程师、初学者环境要求:CentOS9+Docker已安装教程亮点:实战驱动、配置项详解、挂载说明、可直接复制使用标签:#Docker#DockerCompose#运维实战#Nginx部署一、什么是DockerCompose?DockerCompose是Docker官方推出的多容器应用编排工具,</div> </li> <li><a href="/article/1950057957823672320.htm" title="DNF 与 YUM 的区别详解:从 CentOS 7 到 CentOS 9 的演进" target="_blank">DNF 与 YUM 的区别详解:从 CentOS 7 到 CentOS 9 的演进</a> <span class="text-muted"></span> <div>DNF与YUM的区别详解:从CentOS7到CentOS9的演进标签:CentOS、YUM、DNF、Linux包管理、系统升级、兼容性适用版本:CentOS7、CentOS8、CentOS9一、背景介绍CentOS中使用的包管理工具是RedHat系列系统的重要组成部分。随着系统版本升级,包管理器从yum(CentOS7)逐渐过渡到dnf(CentOS8及之后版本)。二、YUM与DNF对比表对比项Y</div> </li> <li><a href="/article/1950037805077950464.htm" title="随记:去耕与去学,无忧与不忧" target="_blank">随记:去耕与去学,无忧与不忧</a> <span class="text-muted">们那们那个们那那</span> <div>标签:论语私享版子曰:“君子谋道不谋食。耕也,馁在其中矣;学也,禄在其中矣。君子忧道不忧贫。”先生的翻译是:孔子说:君子追求的是人生理想,而不是衣食无缺。认真耕田,自然得到了食物;认真学习,自然得到了俸禄。君子挂念的是人生理想,而不是贫困生活。其实可以把‘耕也,馁在其中矣;学也,禄在其中矣。’去掉,更便于理解。这样想是因为我们知道:即使认真耕田,也还是靠天吃饭,气候不好,认真耕田也不见得就不闹饥荒</div> </li> <li><a href="/article/1950032072529735680.htm" title="《浮图缘》:肖铎的圆滑和心机不为权力,四集透露两个假身份" target="_blank">《浮图缘》:肖铎的圆滑和心机不为权力,四集透露两个假身份</a> <span class="text-muted">入骨影评</span> <div>由王鹤棣和陈钰琪合作主演的《浮图缘》播出中,观众对于这部剧已经期待已久了,王鹤棣自从通过《苍兰诀》走红之后,大家都希望能够早日看到他后续的作品能够早日开播,而且《浮图缘》这部剧中王鹤棣的人设有很大的反差,对于以往的角色也有很大的突破。走红之后王鹤棣已经被贴上了新晋流量的标签,所以后续作品的播出效果还是至关重要的,新剧开播之后一口气更新的四集,四集的内容让很多观众都觉得过瘾,节奏非常快,而且王鹤棣的</div> </li> <li><a href="/article/1950004872845783040.htm" title="[JAVAEE] Thymeleaf 基本语法: form相关标签" target="_blank">[JAVAEE] Thymeleaf 基本语法: form相关标签</a> <span class="text-muted">CN-Dust</span> <a class="tag" taget="_blank" href="/search/JAVA/1.htm">JAVA</a><a class="tag" taget="_blank" href="/search/EE/1.htm">EE</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/java-ee/1.htm">java-ee</a> <div>th:action指定表单提交地址th:value给value属性赋值th:field能自动生成id、name和value属性form表单示例运行结果更改数据点击保存控制器代码:TestController.javapackagecom.example.demo.controller;importcom.example.demo.bean.Student;importorg.springframe</div> </li> <li><a href="/article/1949966916076498944.htm" title="vue 使用 iFrame 嵌套带有登录的网站 登录成功 无法跳转" target="_blank">vue 使用 iFrame 嵌套带有登录的网站 登录成功 无法跳转</a> <span class="text-muted">WHY<=小氣鬼=></span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>这个问题有点好玩,当时做的时候没想起来,哎不说讲一下问题1.项目在使用iFrame标签嵌套其他,网址或者自己的网址的时候如果没有登录只是浏览是没有问题的2.如个你使用Frame标签嵌套的网址是带有登录的需要注意两个网站是不是在统一域名下面如果在就可以正常登录,如果不在的话会出现登录成功但是无法跳转的问题3.在Vue项目中使用iFrame嵌套本地.html文件,本地.html文件向父页面抛出的方法或</div> </li> <li><a href="/article/1949895918400630784.htm" title="前端面试题" target="_blank">前端面试题</a> <span class="text-muted">大大。</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a> <div>HTML5的新特性和CSS3的新特性引入了一系列语义化标签使文档结构更加清晰(header,nav,aside,article,footer,section),多媒体支持video,audio,Canvas绘图div上下居中对齐的几种方式第一种:flex布局display:flex;justify-content:center;/*水平居中/align-items:center;/垂直居中/第二种</div> </li> <li><a href="/article/1949891250945585152.htm" title="python和vue结合开发前端_Python--前端之路-----Vue" target="_blank">python和vue结合开发前端_Python--前端之路-----Vue</a> <span class="text-muted"></span> <div>Vue导入Vue创建vue对象加载后执行:绑定:varvm=newVue({el:"#标签的id,此处类似于选择器",属性,方法})属性:data:{属性1:"值1",属性2:值2,属性:true}方法:methods:{方法名1:function(){执行内容},方法名2:function(){执行内容}}监听:watch:{属性名:function(){监听vue属性的数据变化,属性发生修改执</div> </li> <li><a href="/article/1949889935846731776.htm" title="超时空对话" target="_blank">超时空对话</a> <span class="text-muted">唠唠呀</span> <div>没有跌宕起伏,惊天地泣鬼神的故事,也没有令人拍案叫绝的华丽辞藻,而此时此刻我只想写下我自己内心的想法,在一个虚拟的网络世界同自己进行超时空的对话,也许在哪里可以少些顾忌,可以撕下标签与在外部和自己的某种压力或其他能以控制的因素下对自己事与愿违的定义,不用考虑身边人的眼光与鄙夷或是感觉自己裸露的站在身边人的面前,也不想让别人这是所谓的矫情与伤春悲秋,但其实每个人的心里总有些迷惘与困惑,但容易在周围群</div> </li> <li><a href="/article/1949856821019734016.htm" title="踏上人工智能之旅(一)-----机器学习之knn算法" target="_blank">踏上人工智能之旅(一)-----机器学习之knn算法</a> <span class="text-muted">Sunhen_Qiletian</span> <a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/1.htm">机器学习</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>目录一、机器学习是什么(1)概述(2)三种类型1.监督学习(SupervisedLearning):2.无监督学习(UnsupervisedLearning):3.强化学习(ReinforcementLearning):二、KNN算法的基本原理:1.距离度量:2.K值的选择:3.投票机制和投票:三、Python实现KNN算法1.导入必要的库和数据:2.提取特征和标签:3.导入KNN分类器并训练模型</div> </li> <li><a href="/article/1949855686359838720.htm" title="java的break能加标签,return可以加标签吗" target="_blank">java的break能加标签,return可以加标签吗</a> <span class="text-muted">悟能不能悟</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>在Java中,return语句不能像break那样使用标签。这是由两者的设计目的决定的:关键区别:**break+标签用于跳出指定的循环/代码块**(如多层嵌套循环),在需要从深层嵌套中直接退出外层时非常有用:outerLoop:for(inti=0;i<10;i++){for(intj=0;j<10;j++){if(condition)breakouterLoop;//直接跳出外层循环}}**r</div> </li> <li><a href="/article/1949840097323053056.htm" title="20180306复盘第112天by ada" target="_blank">20180306复盘第112天by ada</a> <span class="text-muted">Ada彩英</span> <div>计划性和目标感太弱,所以做事经常抓不到重点,这也是我最大的问题了!早起打卡,复盘,演讲,原本我养成良好习惯的坚持,突然就断了,意志力崩溃了一般!总觉得工作的压力很大,或许是自己给自己加压了,想要获得老板的认可,一个人给你贴了标签,改变也是很难的。我只求做好自己的培训工作,真的培养我做高层管理者,我要学习的还太多了,昨天办公室新来了一个总经理,老板让我配合她的工作,她为人和善,很谦虚,做事情很有计划</div> </li> <li><a href="/article/1949751927382274048.htm" title="前端随堂笔录2" target="_blank">前端随堂笔录2</a> <span class="text-muted">weixin_34254823</span> <div>5.28链接标签核心属性就是href属性值可以是一个跳转的地址适用于任何带有路径的东西href;里面的内容就是路径绝对路径:从盘符开始,然后依次往下查找绝对路径分为本地和服务器本地:C:Users/Administrator/0527day01/07.html服务器:https://www.baidu.com/192.168.1.1/127.0.0.1www.baidu.com相对路径:从当前文件</div> </li> <li><a href="/article/1949744736898183168.htm" title="Rufus算法驱动转化革命:亚马逊卖家的低成本流量破局之道" target="_blank">Rufus算法驱动转化革命:亚马逊卖家的低成本流量破局之道</a> <span class="text-muted"></span> <div>在亚马逊精细化运营的下半场,流量竞争从“烧钱买量”转向“技术借势”,随着平台内部AI算法Rufus的深度应用,其衍生的“超级转化标签”正成为卖家提升转化率的秘密武器,这项由AI驱动的功能不仅重构了消费者决策路径,更以“零广告成本”的优势,为卖家开辟了一条弯道超车的新赛道。Rufus算法解码:AI如何重塑消费决策路径(一)超级转化标签的技术内核Rufus算法的核心是“评论智能提炼”,通过自然语言处理</div> </li> <li><a href="/article/1949732252623630336.htm" title="从系统架构视角解析唯识学:感官模块的二层设计 & 认知系统的漏洞修复" target="_blank">从系统架构视角解析唯识学:感官模块的二层设计 & 认知系统的漏洞修复</a> <span class="text-muted">109702008</span> <a class="tag" taget="_blank" href="/search/%E6%9D%82%E8%B0%88/1.htm">杂谈</a><a class="tag" taget="_blank" href="/search/%E7%B3%BB%E7%BB%9F%E6%9E%B6%E6%9E%84/1.htm">系统架构</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a> <div>作者:DeepSeek-R1标签:哲学与编程、认知科学、系统架构、佛教唯识引言:当哲学遇上系统设计在构建高可用系统时,我们常采用分层架构(如OSI七层模型)。有趣的是,1300年前的佛教唯识学派早已用类似思路解构人类认知系统。本文将用技术语言解析感官的二层模型(浮尘根/胜义根)与认知系统的两类漏洞(见惑/思惑),你会发现:佛学修行的本质竟是一场持续千年的“认知系统重构工程”。模块一:感官系统的硬件</div> </li> <li><a href="/article/1949714290755825664.htm" title="break continue goto" target="_blank">break continue goto</a> <span class="text-muted">一斗</span> <div>breakbreak只能跳出离它最近的一层循环使用标签后跳出到指定标签,跳出后不再执行对应for循环,标签只能放在for前面单独使用funcmain(){fori:='a';i2{break}}}}输出a0123b0123c0123使用标签funcmain(){Loop:fori:='a';i2{breakLoop}}}}输出a0123continuecontinue使用和break类似单独使用f</div> </li> <li><a href="/article/1949703348584247296.htm" title="#跟宇彤老师学习声音万人迷#" target="_blank">#跟宇彤老师学习声音万人迷#</a> <span class="text-muted">美億人生</span> <div>今天已经是打卡营第18天了,时间过得好快,不知不觉,打卡训练营就过去了三分之二了,整个人为什么感觉声音越练习问题越多呢,反思自己:用心程度不够,练习时间不够,练习数量不够,没有达到质变的数量。心不静也是一个重要的原因。声音练习,还让我发现一个很大的缺点:拖延症。接下来就要突破自己,认真学习,提升自己。人生不成功,肯定有原因,不勇敢,爱拖延,随波逐流,都是我曾经的标签,从现在起,我将树立新标签:勇敢</div> </li> <li><a href="/article/1949701105789235200.htm" title="文件改名软件Rename Pro:文件 / 目录混合改 批量改名 提升效率" target="_blank">文件改名软件Rename Pro:文件 / 目录混合改 批量改名 提升效率</a> <span class="text-muted"></span> <div>各位文件管理小能手们!今天给你们介绍一款超神的软件——RenamePro!它就像是文件改名界的超级英雄,功能强大到离谱!啥基础操作,像添加、替换、删除、加序编号啥的,那都不在话下。软件下载地址安装包还有正则表达式、文件名编辑器这些高级玩法,它也能轻松拿捏!它不仅能给文件改名,还能对文件目录和文件混合着改名。而且,Exif标签、GPS标签,甚至MSOffice文档引言写入这些功能,它也一应俱全。能批</div> </li> <li><a href="/article/1949694170553708544.htm" title="html5效果案例,10个优秀HTML5网站案例赏析" target="_blank">html5效果案例,10个优秀HTML5网站案例赏析</a> <span class="text-muted"></span> <div>随着Adobe的弃Flash转投HTML5,HTML5又开始吸引着大众的目光。与现在使用的HTML标记语言相比,HTML5有更多的标签和属性,使用更为灵活,功能更为强大。现在已经有很多前沿的HTML5网站开始使用HTML5,本文收集整理出了10个非常优秀的HTML5网站。那么,什么才是优秀的HTML5网站?因为HTML5还没有成为国际标准,旧的浏览器还无法支持HTML5,所以优秀的HTML5网站示</div> </li> <li><a href="/article/1949681688023986176.htm" title="HTML5" target="_blank">HTML5</a> <span class="text-muted">Darling02zjh</span> <a class="tag" taget="_blank" href="/search/html5/1.htm">html5</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/html/1.htm">html</a> <div>HTML:和其他的语言一样也有基础的框架和快捷键。命名规则:后缀名是“.html”每个项目最上面都有是H5的声明,处于标签之前骨架:html标签:定义HTML文档,这个元素我们浏览器看到后就明白这是个HTML文档了,所以你的其他元素要包裹在这个标签里面,标签限定了文档的开始点和结束点。...其他元素head标签:head标签用于文档的头部,文档的头部描述文档的各种属性和信息,包括文档的标题,在we</div> </li> <li><a href="/article/1949680428101201920.htm" title="html-day01笔记-01-前言&WEB标准&认识HTML&HTML常用标签" target="_blank">html-day01笔记-01-前言&WEB标准&认识HTML&HTML常用标签</a> <span class="text-muted">zhangjunzongque</span> <a class="tag" taget="_blank" href="/search/%E4%B8%AA%E4%BA%BA/1.htm">个人</a><a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/%E5%B8%B8%E7%94%A8/1.htm">常用</a><a class="tag" taget="_blank" href="/search/%E6%A0%87%E7%AD%BE/1.htm">标签</a> <div>typora-copy-images-to:media第01阶段.web基础:html-day01笔记-01-前言&WEB标准&认识HTML&HTML常用标签一、前言1.基础班学习目标目标:能根据psd文件(psd文件,其实就是一张类似于图片的格式,这个呢是用ps做的,也就叫做源文件),用HTML+CSS布局出符合W3C规范的网页(也就是说,我们写的代码,要符合标准)。简单的说,能根据美工给的图,</div> </li> <li><a href="/article/1949670849091006464.htm" title="复制富文本内容带换行" target="_blank">复制富文本内容带换行</a> <span class="text-muted"></span> <div>//拷贝详情文字copyToClipboard(stripHtmlKeepNewlines(account.details))functionstripHtmlKeepNewlines(html){//用特殊占位符替换所有换行标签(需覆盖不同写法的)constwithPlaceholders=html.replace(//gi,'\n')//处理.replace(//gi,'\n')//处理段落结</div> </li> <li><a href="/article/27.htm" title="rust的指针作为函数返回值是直接传递,还是先销毁后创建?" target="_blank">rust的指针作为函数返回值是直接传递,还是先销毁后创建?</a> <span class="text-muted">wudixiaotie</span> <a class="tag" taget="_blank" href="/search/%E8%BF%94%E5%9B%9E%E5%80%BC/1.htm">返回值</a> <div> 这是我自己想到的问题,结果去知呼提问,还没等别人回答, 我自己就想到方法实验了。。 fn main() { let mut a = 34; println!("a's addr:{:p}", &a); let p = &mut a; println!("p's addr:{:p}", &a</div> </li> <li><a href="/article/154.htm" title="java编程思想 -- 数据的初始化" target="_blank">java编程思想 -- 数据的初始化</a> <span class="text-muted">百合不是茶</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%9A%84%E5%88%9D%E5%A7%8B%E5%8C%96/1.htm">数据的初始化</a> <div>  1.使用构造器确保数据初始化      /* *在ReckInitDemo类中创建Reck的对象 */ public class ReckInitDemo { public static void main(String[] args) { //创建Reck对象 new Reck(); } }</div> </li> <li><a href="/article/281.htm" title="[航天与宇宙]为什么发射和回收航天器有档期" target="_blank">[航天与宇宙]为什么发射和回收航天器有档期</a> <span class="text-muted">comsci</span> <div>        地球的大气层中有一个时空屏蔽层,这个层次会不定时的出现,如果该时空屏蔽层出现,那么将导致外层空间进入的任何物体被摧毁,而从地面发射到太空的飞船也将被摧毁...        所以,航天发射和飞船回收都需要等待这个时空屏蔽层消失之后,再进行 &</div> </li> <li><a href="/article/408.htm" title="linux下批量替换文件内容" target="_blank">linux下批量替换文件内容</a> <span class="text-muted">商人shang</span> <a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/%E6%9B%BF%E6%8D%A2/1.htm">替换</a> <div>1、网络上现成的资料   格式: sed -i "s/查找字段/替换字段/g" `grep 查找字段 -rl 路径`   linux sed 批量替换多个文件中的字符串   sed -i "s/oldstring/newstring/g" `grep oldstring -rl yourdir`   例如:替换/home下所有文件中的www.admi</div> </li> <li><a href="/article/535.htm" title="网页在线天气预报" target="_blank">网页在线天气预报</a> <span class="text-muted">oloz</span> <a class="tag" taget="_blank" href="/search/%E5%A4%A9%E6%B0%94%E9%A2%84%E6%8A%A5/1.htm">天气预报</a> <div>网页在线调用天气预报 <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transit</div> </li> <li><a href="/article/662.htm" title="SpringMVC和Struts2比较" target="_blank">SpringMVC和Struts2比较</a> <span class="text-muted">杨白白</span> <a class="tag" taget="_blank" href="/search/springMVC/1.htm">springMVC</a> <div>1. 入口 spring mvc的入口是servlet,而struts2是filter(这里要指出,filter和servlet是不同的。以前认为filter是servlet的一种特殊),这样就导致了二者的机制不同,这里就牵涉到servlet和filter的区别了。 参见:http://blog.csdn.net/zs15932616453/article/details/8832343 2</div> </li> <li><a href="/article/789.htm" title="refuse copy, lazy girl!" target="_blank">refuse copy, lazy girl!</a> <span class="text-muted">小桔子</span> <a class="tag" taget="_blank" href="/search/copy/1.htm">copy</a> <div>       妹妹坐船头啊啊啊啊!都打算一点点琢磨呢。文字编辑也写了基本功能了。。今天查资料,结果查到了人家写得完完整整的。我清楚的认识到: 1.那是我自己觉得写不出的高度 2.如果直接拿来用,很快就能解决问题 3.然后就是抄咩~~ 4.肿么可以这样子,都不想写了今儿个,留着作参考吧!拒绝大抄特抄,慢慢一点点写!   </div> </li> <li><a href="/article/916.htm" title="apache与php整合" target="_blank">apache与php整合</a> <span class="text-muted">aichenglong</span> <a class="tag" taget="_blank" href="/search/php+apache+web/1.htm">php apache web</a> <div>一  apache web服务器 1 apeche web服务器的安装   1)下载Apache web服务器   2)配置域名(如果需要使用要在DNS上注册)   3)测试安装访问http://localhost/验证是否安装成功 2 apache管理   1)service.msc进行图形化管理   2)命令管理,配</div> </li> <li><a href="/article/1043.htm" title="Maven常用内置变量" target="_blank">Maven常用内置变量</a> <span class="text-muted">AILIKES</span> <a class="tag" taget="_blank" href="/search/maven/1.htm">maven</a> <div>Built-in properties ${basedir} represents the directory containing pom.xml ${version} equivalent to ${project.version} (deprecated: ${pom.version}) Pom/Project properties Al</div> </li> <li><a href="/article/1170.htm" title="java的类和对象" target="_blank">java的类和对象</a> <span class="text-muted">百合不是茶</span> <a class="tag" taget="_blank" href="/search/JAVA%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1+%E7%B1%BB+%E5%AF%B9%E8%B1%A1/1.htm">JAVA面向对象 类 对象</a> <div>java中的类:     java是面向对象的语言,解决问题的核心就是将问题看成是一个类,使用类来解决   java使用 class 类名   来创建类 ,在Java中类名要求和构造方法,Java的文件名是一样的   创建一个A类: class A{ }   java中的类:将某两个事物有联系的属性包装在一个类中,再通</div> </li> <li><a href="/article/1297.htm" title="JS控制页面输入框为只读" target="_blank">JS控制页面输入框为只读</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a> <div>在WEB应用开发当中,增、删除、改、查功能必不可少,为了减少以后维护的工作量,我们一般都只做一份页面,通过传入的参数控制其是新增、修改或者查看。而修改时需将待修改的信息从后台取到并显示出来,实际上就是查看的过程,唯一的区别是修改时,页面上所有的信息能修改,而查看页面上的信息不能修改。因此完全可以将其合并,但通过前端JS将查看页面的所有信息控制为只读,在信息量非常大时,就比较麻烦。   </div> </li> <li><a href="/article/1424.htm" title="AngularJS与服务器交互" target="_blank">AngularJS与服务器交互</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/AngularJS/1.htm">AngularJS</a><a class="tag" taget="_blank" href="/search/%24http/1.htm">$http</a> <div>        对于AJAX应用(使用XMLHttpRequests)来说,向服务器发起请求的传统方式是:获取一个XMLHttpRequest对象的引用、发起请求、读取响应、检查状态码,最后处理服务端的响应。整个过程示例如下: var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange</div> </li> <li><a href="/article/1551.htm" title="[Maven学习笔记八]Maven常用插件应用" target="_blank">[Maven学习笔记八]Maven常用插件应用</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/maven/1.htm">maven</a> <div>常用插件及其用法位于:http://maven.apache.org/plugins/   1. Jetty server plugin 2. Dependency copy plugin 3. Surefire Test plugin 4. Uber jar plugin           1. Jetty Pl</div> </li> <li><a href="/article/1678.htm" title="【Hive六】Hive用户自定义函数(UDF)" target="_blank">【Hive六】Hive用户自定义函数(UDF)</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/%E8%87%AA%E5%AE%9A%E4%B9%89%E5%87%BD%E6%95%B0/1.htm">自定义函数</a> <div>1. 什么是Hive UDF Hive是基于Hadoop中的MapReduce,提供HQL查询的数据仓库。Hive是一个很开放的系统,很多内容都支持用户定制,包括: 文件格式:Text File,Sequence File 内存中的数据格式: Java Integer/String, Hadoop IntWritable/Text 用户提供的 map/reduce 脚本:不管什么</div> </li> <li><a href="/article/1805.htm" title="杀掉nginx进程后丢失nginx.pid,如何重新启动nginx" target="_blank">杀掉nginx进程后丢失nginx.pid,如何重新启动nginx</a> <span class="text-muted">ronin47</span> <a class="tag" taget="_blank" href="/search/nginx+%E9%87%8D%E5%90%AF+pid%E4%B8%A2%E5%A4%B1/1.htm">nginx 重启 pid丢失</a> <div>nginx进程被意外关闭,使用nginx -s reload重启时报如下错误:nginx: [error] open() “/var/run/nginx.pid” failed (2: No such file or directory)这是因为nginx进程被杀死后pid丢失了,下一次再开启nginx -s reload时无法启动解决办法:nginx -s reload 只是用来告诉运行中的ng</div> </li> <li><a href="/article/1932.htm" title="UI设计中我们为什么需要设计动效" target="_blank">UI设计中我们为什么需要设计动效</a> <span class="text-muted">brotherlamp</span> <a class="tag" taget="_blank" href="/search/UI/1.htm">UI</a><a class="tag" taget="_blank" href="/search/ui%E6%95%99%E7%A8%8B/1.htm">ui教程</a><a class="tag" taget="_blank" href="/search/ui%E8%A7%86%E9%A2%91/1.htm">ui视频</a><a class="tag" taget="_blank" href="/search/ui%E8%B5%84%E6%96%99/1.htm">ui资料</a><a class="tag" taget="_blank" href="/search/ui%E8%87%AA%E5%AD%A6/1.htm">ui自学</a> <div>随着国际大品牌苹果和谷歌的引领,最近越来越多的国内公司开始关注动效设计了,越来越多的团队已经意识到动效在产品用户体验中的重要性了,更多的UI设计师们也开始投身动效设计领域。 但是说到底,我们到底为什么需要动效设计?或者说我们到底需要什么样的动效?做动效设计也有段时间了,于是尝试用一些案例,从产品本身出发来说说我所思考的动效设计。 一、加强体验舒适度 嗯,就是让用户更加爽更加爽的用你的产品。 </div> </li> <li><a href="/article/2059.htm" title="Spring中JdbcDaoSupport的DataSource注入问题" target="_blank">Spring中JdbcDaoSupport的DataSource注入问题</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a> <div>参考以下两篇文章: http://www.mkyong.com/spring/spring-jdbctemplate-jdbcdaosupport-examples/ http://stackoverflow.com/questions/4762229/spring-ldap-invoking-setter-methods-in-beans-configuration Sprin</div> </li> <li><a href="/article/2186.htm" title="数据库连接池的工作原理" target="_blank">数据库连接池的工作原理</a> <span class="text-muted">chicony</span> <a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%9E%E6%8E%A5%E6%B1%A0/1.htm">数据库连接池</a> <div>       随着信息技术的高速发展与广泛应用,数据库技术在信息技术领域中的位置越来越重要,尤其是网络应用和电子商务的迅速发展,都需要数据库技术支持动 态Web站点的运行,而传统的开发模式是:首先在主程序(如Servlet、Beans)中建立数据库连接;然后进行SQL操作,对数据库中的对象进行查 询、修改和删除等操作;最后断开数据库连接。使用这种开发模式,对</div> </li> <li><a href="/article/2313.htm" title="java 关键字" target="_blank">java 关键字</a> <span class="text-muted">CrazyMizzz</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div> 关键字是事先定义的,有特别意义的标识符,有时又叫保留字。对于保留字,用户只能按照系统规定的方式使用,不能自行定义。 Java中的关键字按功能主要可以分为以下几类:    (1)访问修饰符       public,private,protected       p</div> </li> <li><a href="/article/2440.htm" title="Hive中的排序语法" target="_blank">Hive中的排序语法</a> <span class="text-muted">daizj</span> <a class="tag" taget="_blank" href="/search/%E6%8E%92%E5%BA%8F/1.htm">排序</a><a class="tag" taget="_blank" href="/search/hive/1.htm">hive</a><a class="tag" taget="_blank" href="/search/order+by/1.htm">order by</a><a class="tag" taget="_blank" href="/search/DISTRIBUTE+BY/1.htm">DISTRIBUTE BY</a><a class="tag" taget="_blank" href="/search/sort+by/1.htm">sort by</a> <div>Hive中的排序语法 2014.06.22 ORDER BY hive中的ORDER BY语句和关系数据库中的sql语法相似。他会对查询结果做全局排序,这意味着所有的数据会传送到一个Reduce任务上,这样会导致在大数量的情况下,花费大量时间。 与数据库中 ORDER BY 的区别在于在hive.mapred.mode = strict模式下,必须指定 limit 否则执行会报错。</div> </li> <li><a href="/article/2567.htm" title="单态设计模式" target="_blank">单态设计模式</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">设计模式</a> <div>  单例模式(Singleton)用于为一个类生成一个唯一的对象。最常用的地方是数据库连接。 使用单例模式生成一个对象后,该对象可以被其它众多对象所使用。 <?phpclass Example{    // 保存类实例在此属性中    private static&</div> </li> <li><a href="/article/2694.htm" title="svn locked" target="_blank">svn locked</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/Lock/1.htm">Lock</a> <div>post-commit hook failed (exit code 1) with output: svn: E155004: Working copy 'D:\xx\xxx' locked svn: E200031: sqlite: attempt to write a readonly database svn: E200031: sqlite: attempt to write a </div> </li> <li><a href="/article/2821.htm" title=" ARM寄存器学习" target="_blank"> ARM寄存器学习</a> <span class="text-muted">e200702084</span> <a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/1.htm">数据结构</a><a class="tag" taget="_blank" href="/search/C%2B%2B/1.htm">C++</a><a class="tag" taget="_blank" href="/search/c/1.htm">c</a><a class="tag" taget="_blank" href="/search/C%23/1.htm">C#</a><a class="tag" taget="_blank" href="/search/F%23/1.htm">F#</a> <div>无论是学习哪一种处理器,首先需要明确的就是这种处理器的寄存器以及工作模式。     ARM有37个寄存器,其中31个通用寄存器,6个状态寄存器。 1、不分组寄存器(R0-R7)     不分组也就是说说,在所有的处理器模式下指的都时同一物理寄存器。在异常中断造成处理器模式切换时,由于不同的处理器模式使用一个名字相同的物理寄存器,就是</div> </li> <li><a href="/article/2948.htm" title="常用编码资料" target="_blank">常用编码资料</a> <span class="text-muted">gengzg</span> <a class="tag" taget="_blank" href="/search/%E7%BC%96%E7%A0%81/1.htm">编码</a> <div> List<UserInfo> list=GetUserS.GetUserList(11); String json=JSON.toJSONString(list); HashMap<Object,Object> hs=new HashMap<Object, Object>(); for(int i=0;i<10;i++) { </div> </li> <li><a href="/article/3075.htm" title="进程 vs. 线程" target="_blank">进程 vs. 线程</a> <span class="text-muted">hongtoushizi</span> <a class="tag" taget="_blank" href="/search/%E7%BA%BF%E7%A8%8B/1.htm">线程</a><a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/%E8%BF%9B%E7%A8%8B/1.htm">进程</a> <div>我们介绍了多进程和多线程,这是实现多任务最常用的两种方式。现在,我们来讨论一下这两种方式的优缺点。 首先,要实现多任务,通常我们会设计Master-Worker模式,Master负责分配任务,Worker负责执行任务,因此,多任务环境下,通常是一个Master,多个Worker。 如果用多进程实现Master-Worker,主进程就是Master,其他进程就是Worker。 如果用多线程实现</div> </li> <li><a href="/article/3202.htm" title="Linux定时Job:crontab -e 与 /etc/crontab 的区别" target="_blank">Linux定时Job:crontab -e 与 /etc/crontab 的区别</a> <span class="text-muted">Josh_Persistence</span> <a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/crontab/1.htm">crontab</a> <div>一、linux中的crotab中的指定的时间只有5个部分:* * * * * 分别表示:分钟,小时,日,月,星期,具体说来: 第一段 代表分钟 0—59 第二段 代表小时 0—23 第三段 代表日期 1—31 第四段 代表月份 1—12 第五段 代表星期几,0代表星期日 0—6   如: */1 * * * *   每分钟执行一次。 * </div> </li> <li><a href="/article/3329.htm" title="KMP算法详解" target="_blank">KMP算法详解</a> <span class="text-muted">hm4123660</span> <a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/1.htm">数据结构</a><a class="tag" taget="_blank" href="/search/C%2B%2B/1.htm">C++</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/%E5%AD%97%E7%AC%A6%E4%B8%B2/1.htm">字符串</a><a class="tag" taget="_blank" href="/search/KMP/1.htm">KMP</a> <div>     字符串模式匹配我们相信大家都有遇过,然而我们也习惯用简单匹配法(即Brute-Force算法),其基本思路就是一个个逐一对比下去,这也是我们大家熟知的方法,然而这种算法的效率并不高,但利于理解。       假设主串s="ababcabcacbab",模式串为t="</div> </li> <li><a href="/article/3456.htm" title="枚举类型的单例模式" target="_blank">枚举类型的单例模式</a> <span class="text-muted">zhb8015</span> <a class="tag" taget="_blank" href="/search/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/1.htm">单例模式</a> <div>E.编写一个包含单个元素的枚举类型[极推荐]。代码如下: public enum MaYun {himself; //定义一个枚举的元素,就代表MaYun的一个实例private String anotherField;MaYun() {//MaYun诞生要做的事情//这个方法也可以去掉。将构造时候需要做的事情放在instance赋值的时候:/** himself = MaYun() {*</div> </li> <li><a href="/article/3583.htm" title="Kafka+Storm+HDFS" target="_blank">Kafka+Storm+HDFS</a> <span class="text-muted">ssydxa219</span> <a class="tag" taget="_blank" href="/search/storm/1.htm">storm</a> <div>cd /myhome/usr/stormbin/storm nimbus &amp;bin/storm supervisor &amp;bin/storm ui &amp;Kafka+Storm+HDFS整合实践kafka_2.9.2-0.8.1.1.tgzapache-storm-0.9.2-incubating.tar.gzKafka安装配置我们使用3台机器搭建Kafk</div> </li> <li><a href="/article/3710.htm" title="Java获取本地服务器的IP" target="_blank">Java获取本地服务器的IP</a> <span class="text-muted">中华好儿孙</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/Web/1.htm">Web</a><a class="tag" taget="_blank" href="/search/%E8%8E%B7%E5%8F%96%E6%9C%8D%E5%8A%A1%E5%99%A8ip%E5%9C%B0%E5%9D%80/1.htm">获取服务器ip地址</a> <div> System.out.println("getRequestURL:"+request.getRequestURL()); System.out.println("getLocalAddr:"+request.getLocalAddr()); System.out.println("getLocalPort:&quo</div> </li> </ul> </div> </div> </div> <div> <div class="container"> <div class="indexes"> <strong>按字母分类:</strong> <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a> </div> </div> </div> <footer id="footer" class="mb30 mt30"> <div class="container"> <div class="footBglm"> <a target="_blank" href="/">首页</a> - <a target="_blank" href="/custom/about.htm">关于我们</a> - <a target="_blank" href="/search/Java/1.htm">站内搜索</a> - <a target="_blank" href="/sitemap.txt">Sitemap</a> - <a target="_blank" href="/custom/delete.htm">侵权投诉</a> </div> <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved. <!-- <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>--> </div> </div> </footer> <!-- 代码高亮 --> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script> <link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/> <script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script> </body> </html>