-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp_faq.html
1531 lines (1099 loc) · 75.1 KB
/
app_faq.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!doctype html>
<html lang="en" class="page-type-appendix">
<head prefix="og: http://ogp.me/ns#">
<meta charset="utf-8">
<title>FAQ - FreeMarker 手册</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="format-detection" content="telephone=no">
<meta property="og:site_name" content="FreeMarker 手册">
<meta property="og:title" content="FAQ">
<meta property="og:locale" content="en_US">
<meta property="og:url" content="http://freemarker.org/docs/app_faq.html">
<link rel="canoical" href="http://freemarker.org/docs/app_faq.html">
<link rel="icon" href="favicon.png" type="image/png">
<link rel="stylesheet" type="text/css" href="docgen-resources/docgen.min.css">
</head>
<body itemscope itemtype="https://schema.org/Code">
<meta itemprop="url" content="http://freemarker.org/docs/">
<meta itemprop="name" content="FreeMarker 手册">
<!--[if lte IE 9]>
<div style="background-color: #C00; color: #fff; padding: 12px 24px;">Please use a modern browser to view this website.</div>
<![endif]--><div class="header-top-bg"><div class="site-width header-top"><a class="logo" href="http://freemarker.org" role="banner"> <img itemprop="image" src="logo.png" alt="FreeMarker">
</a><ul class="tabs"><li><a href="http://freemarker.org/">Home</a></li><li class="current"><a href="index.html">Manual</a></li><li><a class="external" href="http://freemarker.org/docs/api/index.html">Java API</a></li></ul><ul class="secondary-tabs"><li><a class="tab icon-heart" href="http://freemarker.org/contribute.html" title="Contribute"><span>Contribute</span></a></li><li><a class="tab icon-bug" href="https://sourceforge.net/p/freemarker/bugs/new/" title="Report a Bug"><span>Report a Bug</span></a></li><li><a class="tab icon-download" href="http://freemarker.org/freemarkerdownload.html" title="Download"><span>Download</span></a></li></ul></div></div><div class="header-bottom-bg"><div class="site-width search-row"><a href="toc.html" class="navigation-header">Manual</a><div class="navigation-header"></div></div><div class="site-width breadcrumb-row"><ul class="breadcrumb" itemscope itemtype="http://schema.org/BreadcrumbList"><li class="step-0" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="toc.html"><span itemprop="name">FreeMarker 手册</span></a></li><li class="step-1" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="app.html"><span itemprop="name">附录</span></a></li><li class="step-2" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a class="label" itemprop="item" href="app_faq.html"><span itemprop="name">FAQ</span></a></li></ul><div class="bookmarks" title="Bookmarks"><span class="sr-only">Bookmarks:</span><ul class="bookmark-list"><li><a href="alphaidx.html">Alpha. index</a></li><li><a href="gloss.html">Glossary</a></li><li><a href="dgui_template_exp.html#exp_cheatsheet">Expressions</a></li><li><a href="ref_builtins_alphaidx.html">?builtins</a></li><li><a href="ref_directive_alphaidx.html">#directives</a></li><li><a href="ref_specvar.html">.spec_vars</a></li><li>FAQ</li></ul></div></div></div> <div class="main-content site-width">
<div class="content-wrapper">
<div id="table-of-contents-wrapper" class="col-left">
<script>var breadcrumb = ["FreeMarker 手册","附录","FAQ"];</script>
<script src="toc.js"></script>
<script src="docgen-resources/main.min.js"></script>
</div>
<div class="col-right"><div class="page-content"><div class="page-title"><div class="pagers top"><a class="paging-arrow previous" href="app.html"><span>Previous</span></a><a class="paging-arrow next" href="app_versions.html"><span>Next</span></a></div><div class="title-wrapper">
<h1 class="content-header header-chapter" id="app_faq" itemprop="headline">FAQ</h1>
</div></div> <div class="qandaset">
<ol>
<li>
<a href="#faq_jsp_vs_freemarker">
JSP 和 FreeMarker ?
</a>
</li>
<li>
<a href="#faq_picky_about_missing_vars">
为什么 FreeMarker 对 <code class="inline-code">null</code>
和不存在的变量很敏感,如何来处理它?
</a>
</li>
<li>
<a href="#faq_number_grouping">
为什么 FreeMarker 打印奇怪的数字格式
(比如 1,000,000 或 1 000 000 而不是 1000000)?
</a>
</li>
<li>
<a href="#faq_number_decimal_point">
为什么 FreeMarker 会不好打印的小数/分组分隔符号
(比如3.14而不是3,14) ?
</a>
</li>
<li>
<a href="#faq_number_boolean_formatting">
为什么当我想用如 <code class="inline-code">${aBoolean}</code> 格式打印布尔值时,
FreeMarker 会抛出错误,又如何来修正呢 ?
</a>
</li>
<li>
<a href="#faq_template_not_found">
FreeMarker 没有找到我的模板
(<code class="inline-code">TemplateNotFoundException</code> 或
<code class="inline-code">FileNotFoundException</code>, "Template not
found" 错误消息)
</a>
</li>
<li>
<a href="#faq_check_version">
文档中编写了关于特性 <em>X</em>,
但是好像 FreeMarker 并不知道它,或者行为和文档中的不同,
或者据称已经修复的bug仍然存在。
</a>
</li>
<li>
<a href="#faq_alternative_syntax">
FreeMarker标签中的 <code class="inline-code"><</code> 和 <code class="inline-code">></code>
混淆了编辑器或XML处理器,应该怎么做 ?
</a>
</li>
<li>
<a href="#faq_legal_variable_names">
什么是合法的变量名 ?
</a>
</li>
<li>
<a href="#faq_strange_variable_name">
如何使用包含负号(<code class="inline-code">-</code>),冒号
(<code class="inline-code">:</code>),点(<code class="inline-code">.</code>),或其它特殊字符的
变量名(宏名,参数名) ?
</a>
</li>
<li>
<a href="#faq_jsp_custom_tag_syntax">
为什么当我尝试使用 <em>X</em> JSP 自定义标签时,
得到了 "java.lang.IllegalArgumentException: argument
type mismatch" ?
</a>
</li>
<li>
<a href="#faq_servlet_include">
如何像 <code class="inline-code">jsp:include</code> 一样的方式引入其它的资源 ?
</a>
</li>
<li>
<a href="#faq_parameter_unwrapping">
如何给普通Java-method/<code class="inline-code">TemplateMethodModelEx</code>/<code class="inline-code">TemplateTransformModel</code>/<code class="inline-code">TemplateDirectiveModel</code> 的实现传递普通
<code class="inline-code">java.lang.*</code>/<code class="inline-code">java.util.*</code>
对象 ?
</a>
</li>
<li>
<a href="#faq_nonstring_keys">
为什么在 <code class="inline-code">myMap[myKey]</code>
表达式中不能使用非字符串的键?那现在应该怎么做 ?
</a>
</li>
<li>
<a href="#faq_simple_map">
当使用 <code class="inline-code">?keys</code>/<code class="inline-code">?values</code>
遍历Map(哈希表)的内容时,得到了混合真正map条目的
<code class="inline-code">java.util.Map</code> 的方法。当然,只是想获取map的条目。
</a>
</li>
<li>
<a href="#faq_modify_seq_and_map">
在 FreeMarker 模板中如何修改序列(list)和哈希表(maps) ?
</a>
</li>
<li>
<a href="#faq_null">
关于 null 在 FreeMarker 模板语言是什么样的?
</a>
</li>
<li>
<a href="#faq_capture">
我该怎么在表达式(作为另外一个指令参数)中使用指令(宏)的输出 ?
</a>
</li>
<li>
<a href="#faq_questionmark">
在输出中为什么用"?"来代替字符 <em>X</em> ?
</a>
</li>
<li>
<a href="#faq_retrieve_calculated_values">
在模板执行完成后,怎么在模板中获取计算过的值 ?
</a>
</li>
<li>
<a href="#faq_assign_to_dynamic_variable_name">
How to assign to (or <code class="inline-code">#import</code> into) a
dynamically constructed variable name (like to name that's stored
in another variable)?
</a>
</li>
<li>
<a href="#faq_template_uploading_security">
Can I allow users to upload templates and what are the
security implications?
</a>
</li>
<li>
<a href="#faq_implement_function_or_macro_in_java">
How to implement a function or macro in Java Language
instead of in the template language?
</a>
</li>
<li>
<a href="#faq_nice_error_page">
In my Servlet
based application, how do I show a nice error page instead of a
stack trace when error occurs during template processing?
</a>
</li>
<li>
<a href="#faq_html_editor_mangles">
I'm using a visual HTML editor that mangles template tags.
Will you change the template language syntax to accommodate my
editor?
</a>
</li>
</ol>
<dl>
<dt class="question" id="faq_jsp_vs_freemarker">
1.
JSP 和 FreeMarker ?
</dt>
<dd class="answer">
<p>我们比较 FreeMarker 和 JSP 2.0 + JSTL 的组合。</p>
<p>FreeMarker 的优点:</p>
<ul>
<li>
<p>FreeMarker 不绑定Servlet,网络/Web环境;它仅仅是通过合并模板和Java对象
(数据模型)来生成文本输出的类库。你可以在任意地方任意时间来执行模板;
不需要HTTP的请求转发或类似的手段,也不需要Servlet环境。
出于这些特点你可以轻松的将它整合到任何系统中去。</p>
</li>
<li>
<p>更简洁的语法。看下这个JSP(假设
<code class="inline-code"><%@ taglib prefix="c"
uri="http://java.sun.com/jsp/jstl/core"
%></code>):</p>
<div class="code-wrapper"><pre class="code-block code-template"><c:if test="${t}">
True
</c:if>
<c:choose>
<c:when test="${n == 123}">
Do this
</c:when>
<c:otherwise>
Do that
</c:otherwise>
</c:choose>
<c:forEach var="i" items="${ls}">
- ${i}
</c:forEach></pre></div>
<p>相等的 FTL:</p>
<div class="code-wrapper"><pre class="code-block code-template"><#if t>
True
</#if>
<#if n == 123>
Do this
<#else>
Do that
</#if>
<#list ls as i>
- ${i}
</#list></pre></div>
</li>
<li>
<p>在模板中没有servlet特定的范围和其它高级技术
(除非,当然,你可以故意地将它们放入数据模型中)。
一开始就是为MVC设计的,它仅仅专注于展示。</p>
</li>
<li>
<p>可以从任意位置加载模板;从类路径下,从数据库中等。</p>
</li>
<li>
<p>默认情况下,数字和日期格式是本地化敏感的。
因为我们对用户输出,你所做的仅仅是书写 <code class="inline-code">${x}</code>,
而不是 <code class="inline-code"><fmt:formatNumber value="${x}"
/></code>。</p>
</li>
<li>
<p>易于定义特设的宏和函数。</p>
</li>
<li>
<p>隐藏错误并假装它不存在。丢失的变量和 <code class="inline-code">null</code>
也不会默认视为 <code class="inline-code">0</code>/<code class="inline-code">false</code>/空字符串,
但会引发错误。<a href="#faq_picky_about_missing_vars">在这里参考更多内容...</a></p>
</li>
<li>
<p>"对象包装"。允许你在模板中以自定义,面向表现的方式来展示对象。
(比如:<a href="xgui_imperative_learn.html">参看这里</a>,
来看看使用这种技术时W3C的DOM结点是如何通过模板展现出来的。)</p>
</li>
<li>
<p>宏和函数仅仅是变量,所以它们可以很容易的作为参数值来传递,
放置到数据模型中等,就像其它任意值。</p>
</li>
<li>
<p>第一次访问一个页面时几乎察觉不到的延迟
(或在它改变之后),因为没有更高级的编译发生。</p>
</li>
</ul>
<p>FreeMarker 的缺点:</p>
<ul>
<li>
<p>不是一种标准。很少的工具和IDE来集成它,少数的开发者知道它,
很少的工业化的支持。(然而,使用合适的设置,
大部分JSP标签库可以在 FreeMarker 模板中运行,除非它们基于
<code class="inline-code">.tag</code> 文件。)</p>
</li>
<li>
<p>除了一些视觉上的相似性,它的语法不同于HTML/XML语法规则,
这会使得新用户感到混乱(这就是简洁的价值所在)。JSP也不遵循它,
只是接近。</p>
</li>
<li>
<p>因为宏和函数仅仅是变量,不正确的指令,
参数名和丢失的必须变量仅仅在运行时会被检测到。</p>
</li>
<li>
<p>不能和JSF一起使用。(这在技术上可行,但是没有人来实现它)</p>
</li>
</ul>
<p>如果你认为可以用 FreeMarker 在应用程序或遗留的仅支持JSP的框架中来代替JSP,
你可以阅读这部分内容:<a href="pgui_misc_servlet.html#pgui_misc_servlet_model2">程序开发指南/其它/在Servlet中使用FreeMarker/在"Model 2"中使用FreeMarker</a></p>
</dd>
<dt class="question" id="faq_picky_about_missing_vars">
2.
为什么 FreeMarker 对 <code class="inline-code">null</code>
和不存在的变量很敏感,如何来处理它?
</dt>
<dd class="answer">
<p>概括一下这点是关于什么的:默认情况下,FreeMarker
将试图访问一个不存在的变量或 <code class="inline-code">null</code> 值
(<a href="#faq_null">这两点是一样的</a>)视为一个错误,
这会中断模板的执行。</p>
<p>首先,你应该理解敏感的原因。很多脚本语言和模板语言都能容忍不存在的变量
(还有 <code class="inline-code">null</code>),通常它们将这些变量视为空字符串和/或0,
还有逻辑false。这些行为主要有以下几点问题:</p>
<ul>
<li>
<p>它潜在隐藏了一些可能偶然发生的错误,就像变量名中的一个错字,
或者当模板编写者引用程序员没有放到数据模型中的变量时,
或程序员使用了一个不同的名字。人们是容易犯下这种偶然的错误的,
而计算机则不会,所以失去这些机会,模板引擎可以显示这些错误则是一个很糟糕的运行方式。
尽管你很小心地检查了开发期间模板输出的内容,那也很容易就忽略了如
<code class="inline-code"><#if hasWarnigs><em class="code-color">print warnings
here...</em></#if></code> 这样的错误,可能永远不会打印警告信息,
因为你已经搞乱了变量名(注意到了吗?)。也考虑一下后期的维护,当你以后修改你的应用时,
你可能不会每次都重新来仔细检查模板(很多应用程序都有数以百计的模板)。
单元测试也不会很好的覆盖到web页面内容(如果设置了它们...);
它们最多只会检查web页面中的某些手动设置模式,所以它们通常会光滑地通过,
但那些修改实际是有bug的。如果页面执行失败,那么测试人员将会注意,
单元测试也会注意(比如整个页面失败),在生产环境中,维护人员会注意
(假设一些人员检查错误日志)。</p>
</li>
<li>
<p>做了危险的假设。脚本语言或模板引擎对应用程序领域是一无所知的,
所以当它决定一些它不知道是 0/false 值时,这是一个相当不负责而且很武断的事情。
仅仅因为它不知道你当前银行账户的余额,我们能说是0么?
仅仅因为不知道一个病人是否对青霉素过敏,我们就能说他/她不对青霉素过敏?
想一想这样错误的暗示信息。展示一个错误提示页面通常要比直接显示错误信息好很多,
导致用户端的错误决定。</p>
</li>
</ul>
<p>这种情况下(不面对这种问题),不对其敏感那就是隐藏错误假装它不存在了,
这样很多用户会觉得方便,但是我们仍然相信在大多数情况下严格对待这个问题,
从长远考虑会节省你更多时间并提高软件的质量。</p>
<p>另外一方面,我们意识到你有更好的原因在有些地方不想 FreeMarker 对错误敏感,
那么对于这种情况的解决方案如下:</p>
<ul>
<li>
<p>通常数据模型中含有 <code class="inline-code">null</code> 或可选变量。
这种情况下使用 <a href="dgui_template_exp.html#dgui_template_exp_missing">这些操作符</a>。
如果你使用它们很频繁的话,那么就要重新考虑一下你的数据模型了,
因为过分依赖它们并不是那些难以使用的详细模板的结果,
但是会增加隐藏错误和打印任意不正确输出(原因前面已经说过了)的可能性。</p>
</li>
<li>
<p>在一些应用程序中,你也许想显示不完整/损坏的页面,而不是错误页面。
这种情况下,你可以 <a href="pgui_config_errorhandling.html">使用另一种错误控制器</a>
而不是默认的。自定义的错误控制器可以略过有问题的部分,或者在那儿显示错误指示,
而不会中止整个页面的呈现。请注意,尽管错误控制器没有给出变量任意的默认值,
显示危急信息的页面也可能会好过显示错误页面。</p>
</li>
<li>
<p>如果页面包含的信息不是至关重要的(比如一些侧栏),
另外一个你可能感兴趣的特性是 <a href="ref_directive_attempt.html">
<code>attempt</code>/<code>recover</code>
指令</a>。</p>
</li>
</ul>
</dd>
<dt class="question" id="faq_number_grouping">
3.
为什么 FreeMarker 打印奇怪的数字格式
(比如 1,000,000 或 1 000 000 而不是 1000000)?
</dt>
<dd class="answer">
<p>FreeMarker 使用Java平台的本地化敏感的数字格式信息。
默认的本地化数字格式可能是分组或其他不想要的格式。
为了避免这种情况,你不得不使用 <a href="pgui_config_settings.html">FreeMarker 设置</a> 中的
<code class="inline-code">number_format</code> 来重写Java平台建议的数字格式,比如:</p>
<div class="code-wrapper"><pre class="code-block code-unspecified">cfg.setNumberFormat("0.######"); // now it will print 1000000
// where cfg is a freemarker.template.Configuration object</pre></div>
<p>请注意,人们通常在没有分组分隔符时阅读大数是有些困难的。
所以通常建议保留分隔符,而在对"计算机"处理时的情况(分组分隔符会使其混乱),
就要使用 <a href="ref_builtins_number.html#ref_builtin_c"><code>c</code> 内建函数</a> 了。比如:</p>
<div class="code-wrapper"><pre class="code-block code-template"><a href="/shop/productdetails?id=${<strong>product.id?c</strong>}">Details...</a></pre></div>
<p>对于计算机,你需要 <code class="inline-code">?c</code>,而根据本地化设置,
小数分隔符还是要担心。</p>
</dd>
<dt class="question" id="faq_number_decimal_point">
4.
为什么 FreeMarker 会不好打印的小数/分组分隔符号
(比如3.14而不是3,14) ?
</dt>
<dd class="answer">
<p>不同的国家使用不同的小数/分组分隔符号。
如果你看到不正确的符号,那么可能你的本地化设置不太合适。
设置Java虚拟机的默认本地化或使用 <a href="pgui_config_settings.html">FreeMarker 设置</a> 中的
<code class="inline-code">locale</code> 来重写默认本地化。比如:</p>
<div class="code-wrapper"><pre class="code-block code-unspecified">cfg.setLocale(java.util.Locale.ITALY);
// where cfg is a freemarker.template.Configuration object</pre></div>
<p>然而有时你想输出一个数字,这个数字不是对用户的,
而是对"计算机"的(比如你想在CSS中打印大小),
不管页面的本地化(语言)是怎么样的,这种情况你必须使用点来作为小数分隔符。
这样就可以使用 <a href="ref_builtins_number.html#ref_builtin_c"><code>c</code>
内建函数</a>,比如:</p>
<div class="code-wrapper"><pre class="code-block code-template">font-size: ${<strong>fontSize?c</strong>}pt;</pre></div>
</dd>
<dt class="question" id="faq_number_boolean_formatting">
5.
为什么当我想用如 <code class="inline-code">${aBoolean}</code> 格式打印布尔值时,
FreeMarker 会抛出错误,又如何来修正呢 ?
</dt>
<dd class="answer">
<p>不像是数字,布尔值没有通用的可接受的格式,
在相同页面中也没有一个通用的格式。就像当你在HTML页面中展示一件产品是可洗的,
你可能不会想给访问者看"Washable:true",而是"Washable:yes"。
所以我们强制模板作者(由 <code class="inline-code">${washable}</code> 引起错误)去探索用户的感知,
在确定的地方布尔值应该来显示成什么。通常我们格式化布尔值的做法是:
<code class="inline-code">${washable?string("yes", "no")}</code>,
<code class="inline-code">${caching?string("Enabled", "Disabled")}</code>,
<code class="inline-code">${heating?string("on", "off")}</code>等。</p>
<p>但有两种情形这里是无用的:</p>
<ul>
<li>
<p>当打印布尔值来生成计算机语言输出,那么就想要
<code class="inline-code">true</code>/<code class="inline-code">false</code>,使用
<code class="inline-code">${<em class="code-color">someBoolean</em>?c}</code>。
(这至少需要 FreeMarker 2.3.20 版本。在那之前,通用的做法是编写
<code class="inline-code">${<em class="code-color">someBoolean</em>?string}</code>,
但这是很危险的,因为它的输出基于当前的布尔值格式设置,默认的是
<code class="inline-code">"true"</code>/<code class="inline-code">"false"</code>。)</p>
</li>
<li>
<p>当对很多布尔值进行同一方式的格式化时。这种情形可以设置
<code class="inline-code">boolean_format</code> 设置项
(<code class="inline-code">Configuration.setBooleanFormat</code>) 来影响,
从 FreeMarker 2.3.20 版本开始,你可以仅仅编写
<code class="inline-code">${<em class="code-color">someBoolean</em>}</code>。
(请注意,这对 <code class="inline-code">true</code>/<code class="inline-code">false</code>
无效 - 你还必须在那儿使用 <code class="inline-code">?c</code>。)</p>
</li>
</ul>
</dd>
<dt class="question" id="faq_template_not_found">
6.
FreeMarker 没有找到我的模板
(<code class="inline-code">TemplateNotFoundException</code> 或
<code class="inline-code">FileNotFoundException</code>, "Template not
found" 错误消息)
</dt>
<dd class="answer">
<p>首先,你应该知道 FreeMarker 是不从文件系统路径直接加载模板的。
它使用一个简单虚拟的文件系统可以读取非文件系统资源
(在jar内部的模板,从数据库表中读取模板等...)。虚拟文件由配置设置项来决定,
<code class="inline-code">Configuration.setTemplateLoader(TemplateLoader)</code>。
即便你使用的 <code class="inline-code">TemplateLoader</code> 映射到了文件系统,
它会有一个包含所有模板的基路径,那就是你不能伸到的虚拟文件系统的根
(也就是说,绝对路径仍然是相对于虚拟文件系统的)。</p>
<p>解决问题的小窍门:</p>
<ul>
<li>
<p>如果你是配置 FreeMarker 的人,请确认你设置了合适的
<code class="inline-code">TemplateLoader</code>。</p>
</li>
<li>
<p>否则,请看未找到模板的错误消息是否包含所使用的
<code class="inline-code">TemplateLoader</code> 的描述。如果没有,
那么你使用的是老版本的 FreeMarker,那么请更新版本。得到
<code class="inline-code">FileNotFoundException</code> 而不是
<code class="inline-code">TemplateNotFoundException</code> 也是版本太老,
所以你不会得到更多的错误消息。(如果
<code class="inline-code">TemplateLoader</code> 在错误消息中是形如
<code class="inline-code">foo.SomeTemplateLoader@64f6106c</code> 这样的内容,
而没有显示相关的参数,你可以请作者定义一个更好的
<code class="inline-code">toString()</code>。)</p>
</li>
<li>
<p>常犯的错误是对基于Servlet的web应用程序使用了
<code class="inline-code">FileTemplateLoader</code> 而不是
<code class="inline-code">WebappTemplateLoader</code>。 它会在一种环境中可用,
但是不会作用于在另一种,因为Servlet规范没有承诺资源可以作为普通文本来访问,
甚至当 <code class="inline-code">war</code> 文件被提取时。</p>
</li>
<li>
<p>要知道当你从其它模板中包含/引入模板时,如果没有以
<code class="inline-code">/</code> 来开始模板名称,那么它就会被解释为相对于包含模板的路径。
错误消息会包含全(分解后的)名,所以应该注意这里。</p>
</li>
<li>
<p>检查你是否正在使用 <code class="inline-code">\</code>
(反斜杠) 来代替 <code class="inline-code">/</code> (斜杠)。
(FreeMarker 2.3.22 和之后的版本会在错误消息中警告这点。)</p>
</li>
<li>
<p>作为最后的补救办法,对 <code class="inline-code">freemarker.cache</code>
类别开启debug级别的日志(在你使用的日志框架中),然后来看还会有什么。</p>
</li>
</ul>
</dd>
<dt class="question" id="faq_check_version">
7.
文档中编写了关于特性 <em>X</em>,
但是好像 FreeMarker 并不知道它,或者行为和文档中的不同,
或者据称已经修复的bug仍然存在。
</dt>
<dd class="answer">
<p>你确定你正在使用的文档和正在使用的 FreeMarker 版本号相同?
特别要注意,在线文档是对最新稳定的FreeMarker发布版。你可能使用的是老版本;
请更新它。</p>
<p>你确定Java类加载器发现了你期望使用的相同版本的
<code class="inline-code">freemarker.jar</code>?也许 <code class="inline-code">freemarker.jar</code>
是老版本的。要检查这点,尝试使用 <code class="inline-code">${.version}</code>
在模板中打印版本号。(如果以"Unknown built-in variable: version" 错误消息结束,
那么你使用的是相当相当老的版本。)</p>
<p>如果你怀疑该问题是有多个 <code class="inline-code">freemarker.jar</code>,
典型的罪魁祸首就是某些模块有Maven或Ivy依赖使用了老的
<code class="inline-code">freemarker</code> group ID, 而不是更为现代的
<code class="inline-code">org.freemarker</code> group ID。因为不同的group ID,
不会被Maven或Ivy视为构件冲突,而是把两个版本都引入。这种情况下,
不得不去掉 <code class="inline-code">freemarker</code> 依赖。</p>
<p>如果你认为文档或 FreeMarker 有错误,请在bug跟踪器或邮件列表中中报告。
谢谢你!</p>
</dd>
<dt class="question" id="faq_alternative_syntax">
8.
FreeMarker标签中的 <code class="inline-code"><</code> 和 <code class="inline-code">></code>
混淆了编辑器或XML处理器,应该怎么做 ?
</dt>
<dd class="answer">
<p>从 FreeMarker 2.3.4 版本开始,你可以使用
<code class="inline-code">[</code> 和 <code class="inline-code">]</code> 来代替
<code class="inline-code"><</code> 和 <code class="inline-code">></code>。要获取更多细节,
<a href="dgui_misc_alternativesyntax.html">阅读这里...</a></p>
</dd>
<dt class="question" id="faq_legal_variable_names">
9.
什么是合法的变量名 ?
</dt>
<dd class="answer">
<p>关于在变量名中使用的字符和变量名的长度,FreeMarker 没有限制,
但是为了你的方便,在选择变量名时最好是简单变量引用表达式(参见 <a href="dgui_template_exp.html#dgui_template_exp_var_toplevel">这里</a>)。
如果你不得不选择一个非常极端的变量名,那也不是一个问题:<a href="#faq_strange_variable_name">参加这里</a>。</p>
</dd>
<dt class="question" id="faq_strange_variable_name">
10.
如何使用包含负号(<code class="inline-code">-</code>),冒号
(<code class="inline-code">:</code>),点(<code class="inline-code">.</code>),或其它特殊字符的
变量名(宏名,参数名) ?
</dt>
<dd class="answer">
<p>如果你的变量名很奇怪,比如 "foo-bar",
当你编写如 <code class="inline-code">${foo-bar}</code> 的形式时,
FreeMarker 会曲解你想要的东西。在这种确定的情况下,
它会相信你想从 <code class="inline-code">foo</code> 中减去 <code class="inline-code">bar</code> 的值,
这个FAQ例子解释了如何控制这样的情况。</p>
<p>首先,应该清理这些句法问题。关于变量名中使用的字符和变量名的长度,
FreeMarker没有限制。</p>
<p>如果特殊字符是负号
(<code class="inline-code">-</code>, UCS 0x2D) 或点 (<code class="inline-code">.</code>, UCS
0x2E) 或冒号 (<code class="inline-code">:</code>, UCS 0x3A)中的一种,
那么你所要做的就是在这些字符前面放置反斜杠(<code class="inline-code">\</code>),
比如在 <code class="inline-code">foo\-bar</code> (从 FreeMarker 2.3.22 版本开始)。
之后 FreeMarker 就会知道你不是想要相同符号的操作符。
在你指定未被引号表示的标识符时,这都起作用,比如对宏和函数名称,
参数名称,所有种类的变量引用。(请注意,这些转义仅在标识符中起作用,
而不是在字符串中。)</p>
<p>当特殊字符不是负号,点,或冒号中的一种时,那就很微妙了。
我们来看看有问题的变量,名称为 "a+b"。那么:</p>
<ul>
<li>
<p>如果你像读取变量:如果它是子变量或其它,可以编写
<code class="inline-code">something["a+b"]</code> (请记住,
<code class="inline-code">something.x</code> 和
<code class="inline-code">something["x"])</code> 是相等的。如果它是顶级变量,
它们可以通过特殊哈希变量来访问,<code class="inline-code">.vars</code>,
所以你可以编写 <code class="inline-code">.vars["a+b"]</code>。很自然地,
这个技巧对宏和函数调用有有效:
<code class="inline-code"><@.vars["a+b"]/></code>,
<code class="inline-code">.vars["a+b"](1, 2)</code>。</p>
</li>
<li>
<p>如果你想创建或修改变量:所有允许你来创建或修改变量的指令
(比如 <code class="inline-code">assign</code>, <code class="inline-code">local</code>,
<code class="inline-code">global</code>, <code class="inline-code">macro</code>,
<code class="inline-code">function</code>,等等)允许对目的变量名的引用。
比如, <code class="inline-code"><#assign
foo = 1></code> 和 <code class="inline-code"><#assign
"foo" = 1></code> 是相同的。所以你可以编写如
<code class="inline-code"><#assign "a+b" = 1></code> 和
<code class="inline-code"><#macro "a+b"></code>。</p>
</li>
<li>
<p>不幸的是,你不能使用这样的变量名(包含不是
<code class="inline-code">-</code>,<code class="inline-code">.</code> 和
<code class="inline-code">:</code> 的特殊字符)来作为宏参数名。</p>
</li>
</ul>
</dd>
<dt class="question" id="faq_jsp_custom_tag_syntax">
11.
为什么当我尝试使用 <em>X</em> JSP 自定义标签时,
得到了 "java.lang.IllegalArgumentException: argument
type mismatch" ?
</dt>
<dd class="answer">
<p>首先,请更新 FreeMarker,因为 2.3.22 和之后的版本给出了更多有用的错误消息,
会给出该问题更好的答案。不管怎样,原因如下。在JSP页面,你对所有参数(属性)值使用引号,
如果参数的类型是字符串或布尔值或数字,它不会起作用。
但是因为自定义标签在FTL模板中是作为普通用户自定义FTL指令来访问的,
你不得不在自定义标签内使用FTL语法规则,而不是JSP规则。因此,根据FTL规则,
必须不能对布尔值和数字参数值使用引号,否则它们会被解释成字符串值,
当 FreeMarker 尝试传递这些值给自定义标签,而它们需要非字符串值时,
这会引起类型不匹配错误。</p>
<p>比如,Struts Tiles的 <code class="inline-code">insert</code> 标签参数
<code class="inline-code">flush</code> 是布尔值。在JSP中,正确的语法是:</p>
<div class="code-wrapper"><pre class="code-block code-template"><tiles:insert page="/layout.jsp" <strong>flush="true"</strong>/>
<em>...</em></pre></div>
<p>但是在FTL中,你应该编写:</p>
<div class="code-wrapper"><pre class="code-block code-template"><@tiles.insert page="/layout.ftl" <strong>flush=true</strong>/>
<em>...</em></pre></div>
<p>而且,出于相似的原因,这是错误的:</p>
<div class="code-wrapper"><pre class="code-block code-template"><tiles:insert page="/layout.jsp" <strong>flush="${needFlushing}"</strong>/>
<em>...</em></pre></div>
<p>你应该编写:</p>
<div class="code-wrapper"><pre class="code-block code-template"><tiles:insert page="/layout.jsp" <strong>flush=needFlushing</strong>/>
<em>...</em></pre></div>
<p>(不是 <code class="inline-code">flush=${needFlushing}</code>!)</p>
</dd>
<dt class="question" id="faq_servlet_include">
12.
如何像 <code class="inline-code">jsp:include</code> 一样的方式引入其它的资源 ?
</dt>
<dd class="answer">
<p>不是使用 <code class="inline-code"><#include ...></code>,
那仅仅是包含另外一个 FreeMarker 模板而不涉及Servlet容器。</p>
<p>因为你要的包含方法是和Servlet相关的,
而纯 FreeMarker 是不知道Servlet和HTTP的存在,
那是Web应用框架来决定你是否可以这样做和如何来做。
比如,在Struts2中,你可以这么来做:</p>
<div class="code-wrapper"><pre class="code-block code-template"><@s.include value="/WEB-INF/just-an-example.jspf" /></pre></div>
<p>如果Web应用框架对 FreeMarker 的支持是基于
<code class="inline-code">freemarker.ext.servlet.FreemarkerServlet</code> 的,
那么你可以这样来做(从 FreeMarker 2.3.15 版本之后):</p>
<div class="code-wrapper"><pre class="code-block code-template"><@include_page path="/WEB-INF/just-an-example.jspf" /></pre></div>
<p>但是如果Web应用框架提供它自己的解决方案,
那么你就可以参考,毕竟它可能会做一些特殊的处理。</p>
<p>更多关于 <code class="inline-code">include_page</code> 的信息,可以
<a href="pgui_misc_servlet.html#pgui_misc_servlet_include">阅读这里...</a></p>
</dd>
<dt class="question" id="faq_parameter_unwrapping">
13.
如何给普通Java-method/<code class="inline-code">TemplateMethodModelEx</code>/<code class="inline-code">TemplateTransformModel</code>/<code class="inline-code">TemplateDirectiveModel</code> 的实现传递普通
<code class="inline-code">java.lang.*</code>/<code class="inline-code">java.util.*</code>
对象 ?
</dt>
<dd class="answer">
<p>不幸的是,对于这个问题没有简单的通用解决方案。
问题在于 FreeMarker 的对象包装是很灵活的,当从模板中访问变量时是很棒的,
但是会使得在Java端解包时变成一个棘手的问题。比如,
很可能将一个非 <code class="inline-code">java.util.Map</code> 对象包装称为
<code class="inline-code">TemplateHashModel</code>(FTL哈希表变量)。
但是它就不能被解包成 <code class="inline-code">java.util.Map</code>,
因为没有包装过的 <code class="inline-code">java.util.Map</code>。</p>
<p>所以该怎么做呢?基本上有下面两种情况:</p>
<ul>
<li>
<p>对于展示目的(比如一种"工具"用来帮助 FreeMarker 模板)
指令和方法应该声明它们的形式参数为 <code class="inline-code">TemplateModel</code>
类型和它的更确切的子接口类型。毕竟,对象包装是对于表面转换数据模型,
并服务于展示层的,而这些方法是展示层的一部分。如果你仍然需要普通Java类型,
那么可以你可以转向当前 <code class="inline-code">ObjectWrapper</code> 的
<code class="inline-code">ObjectWrapperAndUnwrapper</code> 接口
(可以使用 <code class="inline-code">Environment.getObjectWrapper()</code>)。</p>
</li>
<li>
<p>和展示任务(比如,对于业务逻辑层)不相关的方法应该被实现成普通的Java方法,
而且不能使用任何 FreeMarker 特定的类,因为根据MVC范例,
它们必须独立于展示技术(FreeMarker)。如果这样的方法是从模板中调用的,那么 <a href="pgui_datamodel_objectWrapper.html">对象包装</a>
的责任就是要保证参数转换到合适的类型。如果你使用了 <a href="pgui_datamodel_objectWrapper.html#pgui_datamodel_defaultObjectWrapper"><code>DefaultObjectWrapper</code></a>
或 <a href="pgui_misc_beanwrapper.html"><code>BeansWrapper</code></a>,
那么这就会自动发生。对于 <code class="inline-code">DefaultObjectWrapper</code>,如果你 <a href="pgui_datamodel_objectWrapper.html#topic.defaultObjectWrapperIcI">设置它的
<code>incompatibleImprovements</code> 为 2.3.22</a>,
该机制运行得更好。</p>
</li>
</ul>
</dd>
<dt class="question" id="faq_nonstring_keys">
14.
为什么在 <code class="inline-code">myMap[myKey]</code>
表达式中不能使用非字符串的键?那现在应该怎么做 ?
</dt>
<dd class="answer">
<p>FreeMarker模板语言(FTL)的 "哈希表" 类型和Java的
<code class="inline-code">Map</code> 是不同的。FTL的哈希表也是一个关联数组,
但是它仅仅使用字符串的键。这是因为它是为子变量而引入的
(比如 <code class="inline-code">user.password</code> 中的 <code class="inline-code">password</code>,
它和 <code class="inline-code">user["password"]</code> 是相同的),而变量名是字符串。</p>
<p>所以,在FTL有支持非字符串键的类型之前,你还是不得不转向Java的
<code class="inline-code">Map</code> API。你可以这么来做:
<code class="inline-code">myMap?api.get(nonStringKey)</code>。然而,对于运行
<code class="inline-code">?api</code>,你可能需要配置一下 FreeMarker;
<a href="ref_builtins_expert.html#ref_buitin_api_and_has_api">在这里参考更多...</a></p>
<p>请注意,Java的 <code class="inline-code">Map</code>对键的确切类非常专注,
所以对于在模板中计算的数字类型的键,你不得不将它们转换成合适的Java类型,
否则其中的项就不能被发现。比如,如果你在Map中使用 <code class="inline-code">Integer</code>
类型的键,那么你应该编写 <code class="inline-code">${myMap.get(numKey?int)}</code>。
这是由FTL的有意简化的仅有单独数字类型的类型系统导致的非常丑陋的写法,
而Java区分很多数字类型。请注意,当键值直接从数据模型
(也就是说,你不用在模板中使用算数运算来改变它的值)中获取时是不需要转换的,
包含当它是方法返回值的情况,而且在包装之前要是合适的类,
因为这样解包的结果将会是原始的类型。</p>
</dd>
<dt class="question" id="faq_simple_map">
15.
当使用 <code class="inline-code">?keys</code>/<code class="inline-code">?values</code>
遍历Map(哈希表)的内容时,得到了混合真正map条目的
<code class="inline-code">java.util.Map</code> 的方法。当然,只是想获取map的条目。
</dt>
<dd class="answer">
<p>当然是使用了 <code class="inline-code">BeansWrapper</code> 或者你自己的对象包装器,
或者是它的自定义子类,而它的 <code class="inline-code">simpleMapWrapper</code>
属性将会置成 <code class="inline-code">false</code>。不幸的是,这是默认(出于向下兼容的考虑)的情况,
所以在你创建对象包装器的地方,你不得不明确地设置它为 <code class="inline-code">true</code>。
而且,至少从 2.3.22 版本开始,应用程序应该使用
<code class="inline-code">DefaultObjectWrapper</code> (将 <a href="pgui_datamodel_objectWrapper.html#topic.defaultObjectWrapperIcI">它的