第一部分:源码
AbstractConditional.java
// Copyright 2009 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.apache.tapestry5.corelib.base;
import org.apache.tapestry5.BindingConstants;
import org.apache.tapestry5.Block;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.MarkupWriter;
import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.annotations.SupportsInformalParameters;
import org.apache.tapestry5.ioc.annotations.Inject;
/**
* Base class for {@link org.apache.tapestry5.corelib.components.If} and {@link org.apache.tapestry5.corelib.components.Unless}.
* Will render its body or the block from its else parameter. If it renders anything and it has an element name, then
* it renders the element and its informal parameters.
*/
@SupportsInformalParameters
public abstract class AbstractConditional
{
@Inject
private ComponentResources resources;
/**
* Performs the test via the parameters; return true to render the body of the component, false to render the else
* block (or nothing).
*
* @return true to render body
*/
protected abstract boolean test();
/**
* An alternate {@link org.apache.tapestry5.Block} to render if {@link #test()} is false. The default, null, means
* render nothing in that situation.
*/
@Parameter(name = "else", defaultPrefix = BindingConstants.LITERAL)
private Block elseBlock;
private boolean renderTag;
/**
* Returns null if the {@link #test()} is true, which allows normal rendering (of the body). If the test parameter
* is false, returns the else parameter (this may also be null).
*/
Object beginRender(MarkupWriter writer)
{
Block toRender = test() ? resources.getBody() : elseBlock;
String elementName = resources.getElementName();
renderTag = toRender != null && elementName != null;
if (renderTag)
{
writer.element(elementName);
resources.renderInformalParameters(writer);
}
return toRender;
}
/**
* If {@link #test()} is true, then the body is rendered, otherwise not. The component does not have a template or
* do any other rendering besides its body.
*/
boolean beforeRenderBody()
{
return false;
}
void afterRenderBody(MarkupWriter writer)
{
if (renderTag)
writer.end();
}
}
If.java
// Copyright 2006, 2007 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.apache.tapestry5.corelib.components;
import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.corelib.base.AbstractConditional;
/**
* Conditionally renders its body. May render its tag and any informal parameters.
*/
public class If extends AbstractConditional
{
/**
* If true, then the body of the If component is rendered. If false, the body is omitted.
*/
@Parameter(required = true)
private boolean test;
/**
* Optional parameter to invert the test. If true, then the body is rendered when the test parameter is false (not
* true).
*
* @see Unless
*/
@Parameter
private boolean negate;
/**
* @return test parameter (if negate is false), or test parameter inverted (if negate is true)
*/
protected boolean test()
{
return test != negate;
}
}
Unless.java
// Copyright 2008 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.apache.tapestry5.corelib.components;
import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.corelib.base.AbstractConditional;
/**
* A close relative of the {@link org.apache.tapestry5.corelib.components.If} component that inverts the meaning of its
* test. This is easier than an If component with the negate parameter set to true.
*/
public class Unless extends AbstractConditional
{
/**
* If true, then the body of the If component is rendered. If false, the body is omitted.
*/
@Parameter(required = true)
private boolean test;
/**
* @return test parameter inverted
*/
protected boolean test()
{
return !test;
}
}
第二部分:简介
<t:if/>和<t:unless/>是条件判断组件,使用test属性指定要测试的条件,然后决定渲染的部分,如果test为真则渲染
<t:if/>的内部非<p:else>部分,如果test属性的结果是假,那么渲染<p:else>部分或者else属性指定的字符串、block或者
其他部分,test的测试结果的作用可以使用negate来做反转,是渲染效果相反,如果negate属性为真,那么<t:if/>和
<t:unless/>就是等效的test渲染结果。
<t:unless/>的使用就是相比较<t:if/>更加简单,可以自己试一下了。
第三部分:测试
以下是测试用的最终代码文件
Start.tml
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd" xmlns:p="tapestry:parameter">
<head>
<title>t:if and t:unless</title>
</head>
<body>
<t:if test="'field'">not use field<br/></t:if>
<hr/>
<t:if test="test1" else="block:testfalse">
Test1 t:block True<br/>
</t:if>
<t:block id="testfalse">
Test1 t:block False<br/>
</t:block>
<hr/>
<t:if test="test1" >
Test1 p:else True<br/>
<p:else>
Test1 p:else False<br/>
</p:else>
</t:if>
<hr/>
<span t:type="if" t:test="test2">test2 span</span>
<hr/>
<t:if test="test2" negate="true">
Test2 negate True<br/>
<p:else>
Test2 negate False<br/>
</p:else>
</t:if>
<hr/>
<t:if test="test2" negate="false">
Test2 negate True<br/>
<p:else>
Test2 negate False<br/>
</p:else>
</t:if>
<hr/>
<t:if test="test3">
Test3 "" True<br/>
<p:else>
Test3 "" False<br/>
</p:else>
</t:if>
<hr/>
<t:if test="test4">
Test4 "false" True<br/>
<p:else>
Test4 "false" False<br/>
</p:else>
</t:if>
<hr/>
<t:if test="test5">
Test5 "0" True<br/>
<p:else>
Test5 "0" False<br/>
</p:else>
</t:if>
<hr/>
<t:if test="test6">
Test6 int 0 True<br/>
<p:else>
Test6 int 0 False<br/>
</p:else>
</t:if>
<hr/>
<t:if test="test7">
Test7 int 7 True<br/>
<p:else>
Test7 int 7 False<br/>
</p:else>
</t:if>
<hr/>
<t:if test="test8">
Test8 <![CDATA[List<Integer>]]]>=null True<br/>
<p:else>
Test8 <![CDATA[List<Integer>]]]>=null False<br/>
</p:else>
</t:if>
<hr/>
<t:if test="test9">
Test9 <![CDATA[List<Integer>]]]> size=0 True<br/>
<p:else>
Test9 <![CDATA[List<Integer>]]]> size=0 False<br/>
</p:else>
</t:if>
<hr/>
<t:if test="test10">
Test10 <![CDATA[List<Integer>]]]> size=2 True<br/>
<p:else>
Test10 <![CDATA[List<Integer>]]]> size=2 False<br/>
</p:else>
</t:if>
<hr/>
<t:if test="test11">
Test12 Object=null True<br/>
<p:else>
Test12 Object=null False<br/>
</p:else>
</t:if>
<hr/>
<t:if test="test12">
Test13 Object!=null True<br/>
<p:else>
Test13 Object!=null False<br/>
</p:else>
</t:if>
<hr/>
</body>
</html>
Start.java
package jumpstart.web.pages;
import java.util.ArrayList;
import java.util.List;
import jumpstart.web.data.Person;
import org.apache.tapestry5.annotations.Property;
public class Start {
@Property
private boolean test1 = false;
@Property
private boolean test2 = true;
@Property
private String test3 = "";
@Property
private String test4 = "false";
@Property
private String test5 = "0";
@Property
private int test6 = 0;
@Property
private int test7 = 2;
@Property
private List<Integer> test8;
@Property
private List<Integer> test9 = new ArrayList<Integer>();
@Property
private List<Integer> test10 = new ArrayList<Integer>() {
{
add(1);
add(2);
}
};
@Property
private Person test11;
@Property
private Person test12 = new Person();
}
最终的效果
最终的效果(HTML)
<body>
not use field<br/>
<hr/>
Test1 t:block False<br/>
<hr/>
Test1 p:else False<br/>
<hr/>
<span>test2 span</span>
<hr/>
Test2 negate False<br/>
<hr/>
Test2 negate True<br/>
<hr/>
Test3 "" False<br/>
<hr/>
Test4 "false" False<br/>
<hr/>
Test5 "0" True<br/>
<hr/>
Test6 int 0 False<br/>
<hr/>
Test7 int 7 True<br/>
<hr/>
Test8 List<Integer>]=null False<br/>
<hr/>
Test9 List<Integer>] size=0 False<br/>
<hr/>
Test10 List<Integer>] size=2 True<br/>
<hr/>
Test12 Object=null False<br/>
<hr/>
Test13 Object!=null True<br/>
<hr/>
</body>
第四部分:分析
代码中if和unless两个类都是继承自AbstractConditional抽象类,在抽象类中声明了一个protected abstract boolean
test();该方法在if和unless中有不同的实现,返回值正好是相反,这也就成就了if和unless的test属性不同渲染结果。
Object beginRender(MarkupWriter writer)
{
Block toRender = test() ? resources.getBody() : elseBlock;
String elementName = resources.getElementName();
renderTag = toRender != null && elementName != null;
if (renderTag)
{
writer.element(elementName);
resources.renderInformalParameters(writer);
}
return toRender;
}
上述这段代码,首先根据test()的结果,来决定渲染的toRender是if(或者unless)所在标签的内容还是else属性指定的
block,然后下面就正常渲染if(或者unless)的elementName(就是使用<elementName t:type="if" test="'field'"/>格式
书写)。
negate的反转效果就是在实现抽象类AbstractConditional的test()方法的时候使用了一个反转判断效果。