??xml version="1.0" encoding="utf-8" standalone="yes"?> 在项目中使用Spring的注解,关于spring的注解,׃U注解方式, Z注释QAnnotationQ的配置有越来越行的趋势,Spring 2.5 应q种势Q提供了完全Z注释配置 Bean、装?Bean 的功能,您可以用基于注释的 Spring IoC 替换原来Z XML 的配|。本文通过实例详细讲述?Spring 2.5 Z注释 IoC 功能的用?/p>
注释配置相对?XML 配置h很多的优势: 因此在很多情况下Q注释配|比 XML 配置更受Ƣ迎Q注释配|有q一步流行的势。Spring 2.5 的一大增强就是引入了很多注释c,现在您已l可以用注释配|完成大部分 XML 配置的功能。在q篇文章里,我们向您讲qC用注释进?Bean 定义和依赖注入的内容?/p>
Spring 2.5 引入? Spring 通过一? 在Spring中配|如下: <!-- ?BeanPostProcessor 自动v作用Q对标注 @Autowired ?Bean q行自动注入 --> 按照上面的配|,Spring 直接采?Java 反射机制?Boss 中的 当然Q您也可以通过 在默认情况下使用 当不能确?Spring 容器中一定拥有某个类?Bean Ӟ可以在需要自动注入该c?Bean 的地方可以? 一般情况下Q? 和找不到一个类型匹?Bean 相反的一个错误是Q如?Spring 容器中拥有多个候?BeanQSpring 容器在启动时也会抛出 Spring 允许我们通过 Ҏ员变量进行注释: Ҏ员变量?@Qualifier 注释 Ҏ造函数入参进行注释: Spring 不但支持自己定义? Resource 注释cM?Spring 发布包的 lib/j2ee/common-annotations.jar cd中,因此在用之前必d其加入到目的类库中。来看一个? 一般情况下Q我们无需使用cM? 要让 JSR-250 的注释生效,除了?Bean cM标注q些注释外,q需要在 Spring 容器中注册一个负责处理这些注释的 Spring 容器中的 Bean 是有生命周期的,Spring 允许?Bean 在初始化完成后以?Bean 销毁前执行特定的操作,您既可以通过实现 InitializingBean/DisposableBean 接口来定制初始化之后 / 销毁之前的操作ҎQ也可以通过 <bean> 元素?init-method/destroy-method 属性指定初始化之后 / 销毁之前调用的操作Ҏ。关?Spring 的生命周期,W者在《精?Spring 2.x—企业应用开发精解》第 3 章进行了详细的描qͼ有兴的读者可以查阅?/p>
JSR-250 为初始化之后/销毁之前方法的指定定义了两个注释类Q分别是 @PostConstruct ?@PreDestroyQ这两个注释只能应用于方法上。标注了 @PostConstruct 注释的方法将在类实例化后调用Q而标注了 @PreDestroy 的方法将在类销毁之前调用?/p>
您只需要在Ҏ前标? 我们知道Q不是通过实现 通过以下的测试代码,您将可以看到 Bean 的初始化 / 销毁方法是如何被执行的Q?/p>
q时Q您看到标注了 使用 <context:annotation-config/> 化配|?/span> Spring 2.1 d了一个新?context ?Schema 命名I间Q该命名I间Ҏ释驱动、属性文件引入、加载期l入{功能提供了便捷的配|。我们知道注释本w是不会做Q何事情的Q它仅提供元数据信息。要使元数据信息真正起作用,必须让负责处理这些元数据的处理器工作h? 而我们前面所介绍? <context:annotationconfig/> 隐式地?Spring 容器注册 在配|文件中使用 context 命名I间之前Q必d <beans> 元素中声?context 命名I间?/p>
虽然我们可以通过 下面Q我们完全用注释定?Bean q完?Bean 之间装配Q?/p>
仅需要在cd义处Q? q样Q我们就可以?Boss cM通过 在? q里Q所有通过 <bean> 元素定义 Bean 的配|内容已l被U除Q仅需要添加一?<context:component-scan/> 配置px有问题了——Spring XML 配置文g得到了极致的化(当然配置元数据还是需要的Q只不过以注释Ş式存在Ş了)?lt;context:component-scan/> ?base-package 属性指定了需要扫描的cdQ类包及光归子包中所有的c都会被处理?/p>
<context:component-scan/> q允许定义过滤器基包下的某些类U_或排除。Spring 支持以下 4 U类型的qo方式Q通过下表说明Q?/p>
下面是一个简单的例子Q?/p>
值得注意的是 <context:component-scan/> 配置不但启用了对类包进行扫描以实施注释驱动 Bean 定义的功能,同时q启用了注释驱动自动注入的功能(卌隐式地在内部注册? 默认情况下通过 q样Q当?Spring 容器中获? Spring 2.5 中除了提? 是否有了q些 IOC 注释Q我们就可以完全摒除原来 XML 配置的方式呢Q答案是否定的。有以下几点原因Q?/p>
所以在实现应用中,我们往往需要同时用注释配|和 XML 配置Q对于类U别且不会发生变动的配置可以优先考虑注释配置Q而对于那些第三方cM及容易发生调整的配置则应优先考虑使用 XML 配置。Spring 会在具体实施 Bean 创徏?Bean 注入之前这两种配置方式的元信息融合在一赗?/p>
Spring ?2.1 以后Ҏ释配|提供了强力的支持,注释配置功能成ؓ Spring 2.5 的最大的亮点之一。合理地使用 Spring 2.5 的注释配|,可以有效减少配置的工作量Q提高程序的内聚性。但是这q不意味着传统 XML 配置走向消亡,在第三方c?Bean 的配|,以及那些诸如数据源、缓存池、持久层操作模板cR事务管理等内容的配|上QXML 配置依然拥有不可替代的地位?/p>
什么叫控制反{呢?套用好莱坞的一句名a是Q你呆着别动Q到时我会找你? 饥男去扑ְ姐出台很ȝQ不仅得找,用完后还得把姐l还回去 而皇帝爽MQ什么都不用,交给太监d理,控制权{Ud太监手中M而不是皇帝, 必要时候由太监l注进d可以?/font> FreeMarkerZ设计者和E序员是h不同专业技能的不同个体的观念他们是分工力_的: 先来解释一下freemaker的基本语法了Q?br />
<# ... > 中存放所有freemaker的内容,之外的内容全部原栯出?br />
<@ ... /> 是函数调?br />
两个定界W内的内容中Q第一个符可C指令或者函数名Q其后的跟随参数。freemaker提供的控制包括如下: 下面是一个例子: 下面是一个可能的数据模型Q? 在快速入门中介绍了在模板中用的三种基本对象cdQscalars、hashes 和sequencesQ其实还可以有其它更多的能力Q? 通常每个变量只具有上q的一U能力,但一个变量可以具有多个上q能力,如下面的例子Q? Scalar变量存储单|可以是: 有些变量不包含Q何可昄的内容,而是作ؓ容器包含其它变量Q者有两种cdQ? 集合变量通常cMsequencesQ除非无法访问它的大和不能使用索引来获得它的子变量Q集合可以看作只能由<#list …>指o使用的受限sequences Ҏ变量通常是基于给出的参数计算倹{? 下面的例子假讄序员已经方法变量avg攑ֈ数据模型中,用来计算数字q_| 宏和变换器变量是用户自定义指令(自定义FTL标记Q,会在后面讲述q些高Ҏ? 节点变量表示为树型结构中的一个节点,通常在XML处理中用,会在后面的专门章节中? 模板使用FTLQFreeMarker模板语言Q编写,是下面各部分的一个组合: 下面是以一个具体模板例子: 注意事项Q? 在FreeMarker中,使用FTL标记引用指o。有三种FTL标记Q这和HTML标记是类似的Q? 有两U类型的指oQ预定义指o和用户定义指令? 用户定义指o要用@替换#Q如<@mydirective>...</@mydirective>Q会在后面讲qͼ? FTL标记不能够交叉,而应该正的嵌套Q如下面的代码是错误的: FreeMarker会忽略FTL标记中的I白字符Q如下面的例子: 直接指定?/strong> 如果包含Ҏ字符需要{义,如下面的例子Q? 有一cȝD的字符串称为raw字符Ԍ被认为是U文本,其中的\和{{不hҎ含义Q该cdW串在引号前面加rQ下面是一个例子: 直接输入Q不需要引? _ֺ数字使用“.”分隔Q不能用分l符? 目前版本不支持科学计数法Q所?#8220;1E3”是错误的 不能省略数点前面的0Q所?#8220;.5”是错误的 数字8?8?8?.00都是相同? true和falseQ不使用引号 由逗号分隔的子变量列表Q由Ҏ号限定,下面是一个例子: 可以定义反递增的数字范_?..2 获取变量 可以使用点语法或Ҏ可法,假设有下面的数据模型Q? 序列片断Q用[startIndex..endIndex]语法Q从序列中获得序列片断(也是序列Q;startIndex和endIndex是结果ؓ数字的表辑ּ 字符串操? 可以使用${..}Q或#{..}Q在文本部分插入表达式的|例如Q? 例子Q假设user的gؓ“Big Joe”Q: 使用=Q或==Q完全相{)试两个值是否相{,使用!= 试两个值是否不相等 =?=两边必须是相同类型的|否则会生错误,例如<#if 1 = "1">会引起错? Freemarker是精比较,所以对"x"?x "?X"是不相等? Ҏ字和日期可以使用<?lt;=?gt;?gt;=Q但不能用于字符? ׃Freemarker会将>解释成FTL标记的结束字W,所以对?gt;?gt;=可以使用括号来避免这U情况,例如<#if (x > y)> 另一U替代的Ҏ是,使用lt、lte、gt和gte来替?lt;?lt;=?gt;?gt;= &&QandQ、||QorQ?QnotQ,只能用于布尔|否则会生错? 例子Q? 内徏函数的用法类D问散列的子变量,只是使用“?”替代“.”Q下面列出常用的一些函? htmlQ对字符串进行HTML~码 cap_firstQ字符串第一个字母大? lower_caseQ将字符串{换成写 upper_caseQ将字符串{换成大写 trimQ去掉字W串前后的空白字W? sizeQ获得序列中元素的数? intQ取得数字的整数部分Q如-1.9?int的结果是-1Q? 例子Q假设test保存字符?Tom & Jerry"Q: Interpolation有两U类型: 注意QInterpolation只能用于文本部分 插入字符串|直接输出表达式结? 插入数字|Ҏ~省格式Q由#setting指o讄Q将表达式结果{换成文本输出Q可以用内建函数string格式化单个InterpolationQ下面是一个例子: mXQ小数部分最X? MXQ小数部分最大X? 例子Q? 宏和变换器变量是两种不同cd的用户定义指令,它们之间的区别是宏是在模板中使用macro指o定义Q而变换器是在模板外由E序定义Q这里只介绍? 宏是和某个变量关联的模板片断Q以便在模板中通过用户定义指o使用该变量,下面是一个例子: 在macro指o中可以在宏变量之后定义参敎ͼ如: 宏的参数是FTL表达式,所以下面的代码h不同的意思: 可以有多参数Q下面是一个例子: 宏的参数是局部变量,只能在宏定义中有? 用户定义指o可以有嵌套内容,使用<#nested>指o执行指o开始和l束标记之间的模板片? 例子Q? <#nested>指o可以被多ơ调用,例如Q? 用户定义指o可以有@环变量,通常用于重复嵌套内容Q基本用法是Q作为nested指o的参C递@环变量的实际|而在调用用户定义指oӞ?lt;@…>开始标记的参数后面指定循环变量的名? 例子Q? 指定的@环变量的数目和用户定义指令开始标记指定的不同不会有问? 调用时少指定循环变量Q则多指定的g可见 调用时多指定循环变量Q多余的循环变量不会被创? 在模板中定义的变量有三种cdQ? 宏的参数是局部变量,而不是@环变量;局部变量隐藏(而不是覆盖)同名的plain变量Q@环变量隐藏同名的局部变量和plain变量Q下面是一个例子: 内部循环变量隐藏同名的外部@环变量,如: 通常情况Q只使用一个名字空_UCؓd字空? Z创徏可重用的宏、变换器或其它变量的集合Q通常U库Q,必须使用多名字空_其目的是防止同名冲突 下面是一个创建库的例子(假设保存在lib/my_test.ftl中)Q? 可以使用assign指o在导入的名字I间中创建或替代变量Q下面是一个例子: EG.一个对象BOOK 1.输出 ${book.name} I值判断:${book.name?if_exists }, ${book.name?default(‘xxx’)}//默认值xxx ${ book.name!"xxx"}//默认值xxx 日期格式Q?{book.date?string('yyyy-MM-dd')} 数字格式Q?{book?string.number}--20 ${book?string.currency}--<#-- $20.00 --> ${book?string.percent}?lt;#-- 20% --> 插入布尔| <#assign foo=ture /> ${foo?string("yes","no")} <#-- yes --> 2Q逻辑判断 a: <#if condition>... <#elseif condition2>... <#elseif condition3>...... <#else>... 其中I值判断可以写?lt;#if book.name?? > b: <#switch value> <#case refValue1> ... <#break> <#case refValue2> ... <#break> ... <#case refValueN> ... <#break> <#default> ... 3Q@环读?/p>
<#list sequence as item> ... I值判?lt;#if bookList?size = 0> e.g. <#list employees as e> ${e_index}. ${e.name} 输出: 1. Readonly 2. Robbin
]]>
<!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
@Autowired
注释Q它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作?/p>
BeanPostProcessor
?@Autowired
q行解析Q所以要?@Autowired
起作用必M先在 Spring 容器中声?AutowiredAnnotationBeanPostProcessor
Bean?/p>
<bean class="org.springframework.beans.factory.annotation.
AutowiredAnnotationBeanPostProcessor"/>
?Spring 容器启动ӞAutowiredAnnotationBeanPostProcessor
扫?Spring 容器中所?BeanQ当发现 Bean 中拥?@Autowired
注释时就扑ֈ和其匚wQ默认按cd匚wQ的 BeanQƈ注入到对应的地方中去?/p>
car
?office
q两个私有成员变量进行自动注入。所以对成员变量使用 @Autowired
后,您大可将它们?setter ҎQ?code>setCar() ?setOffice()
Q从 Boss 中删除?/p>
@Autowired
Ҏ法或构造函数进行标注,@Autowired
注释q行自动注入ӞSpring 容器中匹配的候?Bean 数目必须有且仅有一个。当找不C个匹配的 Bean ӞSpring 容器抛?BeanCreationException
异常Qƈ指出必须臛_拥有一个匹配的 Bean?/p>
@Autowired(required = false)
Q这{于告诉 SpringQ在找不到匹?Bean 时也不报错?/p>
@Autowired
的地斚w是需要注?Bean 的,使用了自动注入而又允许不注入的情况一般仅会在开发期或测试期到Q如Z快速启?Spring 容器Q仅引入一些模块的 Spring 配置文gQ,所?@Autowired(required = false)
会很用到?/p>
BeanCreationException
异常?/p>
@Qualifier
注释指定注入 Bean 的名Uͼq样歧义消除了Q可以通过下面的方法解军_常:
清单 13. 使用 @Qualifier 注释指定注入 Bean 的名U?/strong>
@Autowired
public void setOffice(@Qualifier("office")Office office) {
this.office = office;
}
@Qualifier("office")
中的 office
?Bean 的名Uͼ所?@Autowired
?@Qualifier
l合使用Ӟ自动注入的策略就?byType 转变?byName 了?code>@Autowired 可以Ҏ员变量、方法以及构造函数进行注释,?@Qualifier
的标注对象是成员变量、方法入参、构造函数入参。正是由于注释对象的不同Q所?Spring 不将 @Autowired
?@Qualifier
l一成一个注释类。下面是Ҏ员变量和构造函数入参进行注释的代码Q?/p>
public class Boss {
@Autowired
private Car car;
@Autowired
@Qualifier("office")
private Office office;
…
}
public class Boss {
private Car car;
private Office office;
@Autowired
public Boss(Car car , @Qualifier("office")Office office){
this.car = car;
this.office = office ;
}
}
@Qualifier
只能?@Autowired
l合使用Q是?@Autowired
有益的补充。一般来Ԍ@Qualifier
Ҏ法签名中入参q行注释会降低代码的可读性,而对成员变量注释则相对好一些?/p>
@Autowired
的注释,q支持几个由 JSR-250 规范定义的注释,它们分别?@Resource
?code>@PostConstruct 以及 @PreDestroy
?/p>
@Resource
的作用相当于 @Autowired
Q只不过 @Autowired
?byType 自动注入Q面 @Resource
默认?byName 自动注入|了?code>@Resource 有两个属性是比较重要的,分别?name ?typeQSpring ?@Resource
注释?name 属性解析ؓ Bean 的名字,?type 属性则解析?Bean 的类型。所以如果?name 属性,则?byName 的自动注入策略,而?type 属性时则?byType 自动注入{略。如果既不指?name 也不指定 type 属性,q时通过反射机制使用 byName 自动注入{略?/p>
@Resource
的例子:
清单 16. 使用 @Resource 注释?Boss.java
package com.baobaotao;
import javax.annotation.Resource;
public class Boss {
// 自动注入cd?Car ?Bean
@Resource
private Car car;
// 自动注入 bean 名称?office ?Bean
@Resource(name = "office")
private Office office;
}
@Resource(type=Car.class)
的注释方式,因ؓ Bean 的类型信息可以通过 Java 反射从代码中获取?/p>
BeanPostProcessor
Q?/p>
<bean
class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>
CommonAnnotationBeanPostProcessor
实现?BeanPostProcessor
接口Q它负责扫描使用?JSR-250 注释?BeanQƈ对它们进行相应的操作?/p>
清单 17. 使用 @PostConstruct ?@PreDestroy 注释?Boss.java
package com.baobaotao;
import javax.annotation.Resource;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class Boss {
@Resource
private Car car;
@Resource(name = "office")
private Office office;
@PostConstruct
public void postConstruct1(){
System.out.println("postConstruct1");
}
@PreDestroy
public void preDestroy1(){
System.out.println("preDestroy1");
}
…
}
@PostConstruct
?@PreDestroy
Q这些方法就会在 Bean 初始化后或销毁之前被 Spring 容器执行了?/p>
InitializingBean
/DisposableBean
接口Q还是通过 <bean> 元素?init-method/destroy-method
属性进行配|,都只能ؓ Bean 指定一个初始化 / 销毁的Ҏ。但是?@PostConstruct
?@PreDestroy
注释却可以指定多个初始化 / 销毁方法,那些被标?@PostConstruct
?@PreDestroy
注释的方法都会在初始?/ 销毁时被执行?/p>
package com.baobaotao;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AnnoIoCTest {
public static void main(String[] args) {
String[] locations = {"beans.xml"};
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(locations);
Boss boss = (Boss) ctx.getBean("boss");
System.out.println(boss);
ctx.destroy();// 关闭 Spring 容器Q以触发 Bean 销毁方法的执行
}
}
@PostConstruct
?postConstruct1()
Ҏ在 Spring 容器启动Ӟ创徏 Boss
Bean 的时候被触发执行Q而标注了 @PreDestroy
注释?preDestroy1()
Ҏ在 Spring 容器关闭前销?Boss
Bean 的时候被触发执行?/p>
回页?/span>
AutowiredAnnotationBeanPostProcessor
?CommonAnnotationBeanPostProcessor
是处理q些注释元数据的处理器。但是直接在 Spring 配置文g中定义这?Bean 昑־比较W拙。Spring 为我们提供了一U方便的注册q些 BeanPostProcessor
的方式,q就?<context:annotation-config/>。请看下面的配置Q?/p>
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config/>
<bean id="boss" class="com.baobaotao.Boss"/>
<bean id="office" class="com.baobaotao.Office">
<property name="officeNo" value="001"/>
</bean>
<bean id="car" class="com.baobaotao.Car" scope="singleton">
<property name="brand" value=" U旗 CA72"/>
<property name="price" value="2000"/>
</bean>
</beans>
AutowiredAnnotationBeanPostProcessor
?code>CommonAnnotationBeanPostProcessor?code>PersistenceAnnotationBeanPostProcessor 以及 equiredAnnotationBeanPostProcessor
q?4 ?BeanPostProcessor?/p>
回页?/span>
@Autowired
?@Resource
?Bean cM使用自动注入功能Q但?Bean q是?XML 文g中通过 <bean> q行定义 —?也就是说Q在 XML 配置文g中定?BeanQ通过 @Autowired
?@Resource
?Bean 的成员变量、方法入参或构造函数入参提供自动注入的功能。能否也通过注释定义 BeanQ从 XML 配置文g中完全移?Bean 定义的配|呢Q答案是肯定的,我们通过 Spring 2.5 提供?@Component
注释可以达到这个目标了?/p>
清单 20. 使用 @Component 注释?Car.java
package com.baobaotao;
import org.springframework.stereotype.Component;
@Component
public class Car {
…
}
@Component
注释可以将一个类定义?Spring 容器中的 Bean。下面的代码?Office
定义Z?BeanQ?/p>
清单 21. 使用 @Component 注释?Office.java
package com.baobaotao;
import org.springframework.stereotype.Component;
@Component
public class Office {
private String officeNo = "001";
…
}
@Autowired
注入前面定义?Car
?Office Bean
了?/p>
清单 22. 使用 @Component 注释?Boss.java
package com.baobaotao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component("boss")
public class Boss {
@Autowired
private Car car;
@Autowired
private Office office;
…
}
@Component
有一个可选的入参Q用于指?Bean 的名Uͼ?Boss 中,我们将 Bean 名称定义?#8220;boss
”。一般情况下QBean 都是 singleton 的,需要注?Bean 的地方仅需要通过 byType {略可以自动注入了Q所以大可不必指?Bean 的名U?/p>
@Component
注释后,Spring 容器必须启用cL描机制以启用注释驱动 Bean 定义和注释驱?Bean 自动注入的策略。Spring 2.5 ?context 命名I间q行了扩展,提供了这一功能Q请看下面的配置Q?/p>
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:component-scan base-package="com.baobaotao"/>
</beans>
qo器类?/th>
说明
注释
假如 com.baobaotao.SomeAnnotation 是一个注释类Q我们可以将使用该注释的c过滤出来?/td>
cd指定
通过全限定类名进行过滤,如您可以指定?com.baobaotao.Boss U_扫描Q而将 com.baobaotao.Car 排除在外?/td>
正则表达?/td>
通过正则表达式定义过滤的c,如下所C: com\.baobaotao\.Default.*
AspectJ 表达?/td>
通过 AspectJ 表达式定义过滤的c,如下所C: com. baobaotao..*Service+
<context:component-scan base-package="com.baobaotao">
<context:include-filter type="regex"
expression="com\.baobaotao\.service\..*"/>
<context:exclude-filter type="aspectj"
expression="com.baobaotao.util..*"/>
</context:component-scan>
AutowiredAnnotationBeanPostProcessor
?CommonAnnotationBeanPostProcessor
Q,因此当?<context:component-scan/> 后,可以将 <context:annotation-config/> U除了?/p>
@Component
定义?Bean 都是 singleton 的,如果需要用其它作用范围的 BeanQ可以通过 @Scope
注释来达到目标,如以下代码所C:
清单 24. 通过 @Scope 指定 Bean 的作用范?/strong>
package com.baobaotao;
import org.springframework.context.annotation.Scope;
…
@Scope("prototype")
@Component("boss")
public class Boss {
…
}
boss
Bean Ӟ每次q回的都是新的实例了?/p>
回页?/span>
@Component
注释外,q定义了几个拥有Ҏ语义的注释,它们分别是:@Repository
?code>@Service ?@Controller
。在目前?Spring 版本中,q?3 个注释和 @Component
是等效的Q但是从注释cȝ命名上,很容易看 3 个注释分别和持久层、业务层和控制层QWeb 层)相对应。虽然目前这 3 个注释和 @Component
相比没有什么新意,?Spring 在以后的版本中为它们添加特D的功能。所以,如果 Web 应用E序采用了经典的三层分层l构的话Q最好在持久层、业务层和控制层分别采用 @Repository
?code>@Service ?@Controller
对分层中的类q行注释Q而用 @Component
寚w些比较中立的c进行注释?/p>
回页?/span>
JdbcTemplate
?code>SessionFactoryBean {)Q注释配|将无法实施Q此?XML 配置是唯一可用的方式?@Transaction
事务注释Q?aop/tx 命名I间的事务配|更加灵zd单?
回页?/span>
什么意思呢Q就好比一个皇帝和太监
有一天皇帝想宠幸某个女Q于是跟太监_今夜我要宠幸女
皇帝往往不会告诉太监Q今晚几点会回宫Q会回哪张龙床,他只会告诉太监他要哪位美?/font>
其它一切都交由太监d排,C晚上皇帝回宫Ӟ自然会有女出现在皇帝的龙床?
q就是控制反转,而把女送到皇帝的寝宫里面去是注射
太监是是框枉面的注射控制器类BeanFactoryQ负责找到美奛_ƈ送到龙床上去
整个后宫可以看成是Spring框架Q美奛_是Spring控制下的JavaBean
而传l的模式是一个饥渴男L姐出台
N班,帮助l介l一个云云,于是领班开始给他张|?br />
介绍一个合适的l他Q完事后Q再把小姐还l领班,下次再来
q个q程中,领班是查询上下文ContextQ领班的一个职能就是给客户扑ֈ他们所要的姐
q就是lookup()ҎQ领班手中的姐名录是JNDI//Java Naming and Directory Interface
姐是EJBQ?font color="#0000ff">饥h客户?/font>Q?font color="#ff0000">青楼是EJB容器
看到区别了么Q?/font>
]]>
* @author liuguangyi
* @content ejb3注解的API定义在javax.persistence.*包里面?br />
*
* 注释说明Q?br />
* @Entity —?一个类声明Z个实体bean(即一个持久化POJOc?
* @Id —?注解声明了该实体bean的标识属性(对应表中的主键)?br />
* @Table —?注解声明了该实体bean映射指定的表QtableQ?目录QcatalogQ和schema的名?br />
* @Column —?注解声明了属性到列的映射。该注解有如下的属?br />
* name 可选,列名Q默认值是属性名Q?br />
* unique 可选,是否在该列上讄唯一U束Q默认值falseQ?br />
* nullable 可选,是否讄该列的值可以ؓI(默认值falseQ?br />
* insertable 可选,该列是否作ؓ生成的insert语句中的一个列Q默认值trueQ?br />
* updatable 可选,该列是否作ؓ生成的update语句中的一个列Q默认值trueQ?br />
* columnDefinition 可选,个特定列覆盖sql ddl片段Q这可能D无法在不同数据库间移植)
* table 可选,定义对应的表Q默认ؓ主表Q?br />
* length 可选,列长度(默认?55Q?br />
* precision 可选,列十q制_ֺQdecimal precision)(默认?Q?br />
* scale 可选,如果列十q制数D_decimal scaleQ可用,在此讄Q默认?Q?br />
* @GeneratedValue —?注解声明了主键的生成{略。该注解有如下属?br />
* strategy 指定生成的策略(JPA定义的)Q这是一个GenerationType。默认是GenerationType. AUTO
* GenerationType.AUTO 主键q序控?br />
* GenerationType.TABLE 使用一个特定的数据库表格来保存主键
* GenerationType.IDENTITY 主键由数据库自动生成Q主要是自动增长cdQ?br />
* GenerationType.SEQUENCE Ҏ底层数据库的序列来生成主键,条g是数据库支持序列。(q个D与generator一起用)
* generator 指定生成主键使用的生成器Q可能是orcale中的序列Q?br />
* @SequenceGenerator —?注解声明了一个数据库序列。该注解有如下属?br />
* name 表示该表主键生成{略名称Q它被引用在@GeneratedValue中设|的“gernerator”g
* sequenceName 表示生成{略用到的数据库序列名称?br />
* initialValue 表示主键初始|默认?.
* allocationSize 每次主键值增加的大小Q例如设|成1Q则表示每次创徏新记录后自动?Q默认ؓ50.
* @GenericGenerator —?注解声明了一个hibernate的主键生成策略。支持十三种{略。该注解有如下属?br />
* name 指定生成器名U?br />
* strategy 指定具体生成器的cdQ指定生成策略)?br />
* parameters 得到strategy指定的具体生成器所用到的参数?br />
* 其十三种{略Qstrategy属性的|如下Q?br />
* 1.native 对于orcale采用Sequence方式Q对于MySQL和SQL Server采用identity(处境主键生成机制)Q?br />
* native是主键的生成工作由数据库完成,hibernate不管Q很常用Q?br />
* 例:@GeneratedValue(generator = "paymentableGenerator")
* @GenericGenerator(name = "paymentableGenerator", strategy = "native")
* 2.uuid 采用128位的uuid法生成主键Quuid被编码ؓ一?2?6q制数字的字W串。占用空间大Q字W串cdQ?br />
* 例:@GeneratedValue(generator = "paymentableGenerator")
* @GenericGenerator(name = "paymentableGenerator", strategy = "uuid")
* 3.hilo 要在数据库中建立一张额外的表,默认表名为hibernate_unque_keyQ默认字DؓintegercdQ名U是next_hiQ比较少用)
* 例:@GeneratedValue(generator = "paymentableGenerator")
* @GenericGenerator(name = "paymentableGenerator", strategy = "hilo")
* 4.assigned 在插入数据的时候主键由E序处理Q很常用Q,q是<generator>元素没有指定时的默认生成{略。等同于JPA中的AUTO?br />
* 例:@GeneratedValue(generator = "paymentableGenerator")
* @GenericGenerator(name = "paymentableGenerator", strategy = "assigned")
* 5.identity 使用SQL Server和MySQL的自增字D,q个Ҏ不能攑ֈOracle中,Oracle不支持自增字D,要设定sequence(MySQL和SQL Server中很常用)。等同于JPA中的IDENTITY
* 例:@GeneratedValue(generator = "paymentableGenerator")
* @GenericGenerator(name = "paymentableGenerator", strategy = "identity")
* 6.select 使用触发器生成主键(主要用于早期的数据库主键生成机制Q少用)
* 例:@GeneratedValue(generator = "paymentableGenerator")
* @GenericGenerator(name = "paymentableGenerator", strategy = "select")
* 7.sequence 调用谨慎数据库的序列来生成主键,要设定序列名Q不然hibernate无法扑ֈ?br />
* 例:@GeneratedValue(generator = "paymentableGenerator")
* @GenericGenerator(name = "paymentableGenerator", strategy = "sequence",
* parameters = { @Parameter(name = "sequence", value = "seq_payablemoney") })
* 8.seqhilo 通过hilo法实现Q但是主键历史保存在Sequence中,适用于支持Sequence的数据库Q如Orcale(比较用Q?
* 例:@GeneratedValue(generator = "paymentableGenerator")
* @GenericGenerator(name = "paymentableGenerator", strategy = "seqhilo",
* parameters = { @Parameter(name = "max_lo", value = "5") })
* 9.increnment 插入数据的时候hibernate会给主键d一个自增的主键Q但是一个hibernate实例q护一个计数器Q所以在多个实例q行的时候不能用这个方法?br />
* 例:@GeneratedValue(generator = "paymentableGenerator")
* @GenericGenerator(name = "paymentableGenerator", strategy = "increnment")
* 10.foreign 使用另一个相关的对象的主键。通常?lt;on
* @GeneratedValue(generator = "idGenerator")
* @GenericGenerator(name = "idGenerator", strategy = "foreign",
* parameters = { @Parameter(name = "property", value = "info") })
* Integer id;
* @On
* EmployeeInfo info;
* 11.guid 采用数据库底层的guid法机制Q对应MySQL的uuid()函数QSQL Server的newid()函数QORCALE的rawtohex(sys_guid())函数{?br />
* 例:@GeneratedValue(generator = "paymentableGenerator")
* @GenericGenerator(name = "paymentableGenerator", strategy = "guid")
* 12.uuid.hex 看uudi,用uuid替换
* 例:@GeneratedValue(generator = "paymentableGenerator")
* @GenericGenerator(name = "paymentableGenerator", strategy = "uuid.hex")
* 13.sequence-identity sequence{略的扩展,采用立即索策略来获取sequence|需要JDBC3.0和JDK4以上Q含1.4Q版?br />
* 例:@GeneratedValue(generator = "paymentableGenerator")
* @GenericGenerator(name = "paymentableGenerator", strategy = "sequence-identity",
* parameters = { @Parameter(name = "sequence", value = "seq_payablemoney") })
*
* @On
* Ҏ一
* 主表Q??@On
* @PrimaryKeyJoinColumn
* public 从表c?get从表c?){return 从表对象}
* 从表Q没有主表类?br />
* 注意Q这U方法要求主表与从表的主键值想对应?br />
* Ҏ?br />
* 主表Q?@On
* @JoinColumn(name="主表外键") //q里指定的是数据库中的外键字Dc?br />
* public 从表c?get从表c?){return 从表c}
* 从表Q@On
* public 主表c?get主表c?){return 主表对象}
* 注意Q@JoinColumn是可选的。默认值是从表变量?"_"+从表的主键(注意Q这里加的是主键。而不是主键对应的变量Q?br />
* Ҏ?br />
* 主表Q@On
* @JoinTable( name="兌表名",
* joinColumns = @JoinColumn(name="主表外键"),
* inverseJoinColumns = @JoinColumns(name="从表外键")
* )
* 从表Q@On
* public 主表c?get主表c?){return 主表对象}
* @ManyToOne 讄多对一兌
* Ҏ一
* @ManyToOne(cascade={CasCadeType.PERSIST,CascadeType.MERGE})
* @JoinColumn(name="外键")
* public 主表c?get主表c?){return 主表对象}
* Ҏ?br />
* @ManyToOne(cascade={CascadeType.PERSIST,CascadeType.MERGE})
* @JoinTable(name="兌表名"Q?br />
* joinColumns = @JoinColumn(name="主表外键"),
* inverseJoinColumns = @JoinColumns(name="从表外键")
* )
* @On
* Ҏ一 使用q种配置Q在?#8220;一?#8221;d“多端”Ӟ不会修改“多端”的外键。在“一?#8221;加蝲Ӟ不会得到“多端”。如果用gq加载,在读“多端”列表时会出异常,立即加蝲在得到多端时Q是一个空集合Q集合元素ؓ0Q?br />
* “一?#8221;配置
* @On
* public List<“多端”c?gt; get“多端”列表(){return “多端”列表}
* “多端”配置参考@ManyToOne.
* Ҏ?br />
* “一?#8221;配置
* @On
* @MapKey(name="“多端”做ؓKey的属?)
* public Map<“多端”做ؓKey的属性的c?主表c?gt; get“多端”列表Q){return “多端”列表}
* “多端”配置参考@ManyToOne.
* Ҏ?使用q种配置Q在?#8220;一?#8221;d“多端”Ӟ可以修改“多端”的外键?br />
* “一?#8221;配置
* @On
* @JoinColumn(name="“多端”外键")
* public List<“多端”c?gt; get“多端”列表(){return “多端”列表}
* “多端”配置参考@ManyToOne.
*
*
*/
]]>
1、重写只能出现在l承关系之中。当一个类l承它的父类ҎӞ都有Z重写该父cȝҎ。一个特例是父类的方法被标识为final。重写的主要优点是能够定义某个子cdҎ的行为?br />
class Animal {
public void eat(){
System.out.println ("Animal is eating.");
}
}
class Horse extends Animal{
public void eat(){
System.out.println ("Horse is eating.");
}
}
2、对于从父类l承来的抽象ҎQ要么在子类用重写的方式设计该方法,要么把子cM标识为抽象的。所以抽象方法可以说是必要被重写的Ҏ?br />
3、重写的意义?br />
重写Ҏ可以实现多态,用父cȝ引用来操U子cd象,但是在实际运行中对象运行其自己Ҏ的方法?br />
public class Test {
public static void main (String[] args) {
Animal h = new Horse();
h.eat();
}
}
class Animal {
public void eat(){
System.out.println ("Animal is eating.");
}
}
class Horse extends Animal{
public void eat(){
System.out.println ("Horse is eating.");
}
public void buck(){
}
}
一个原则是Q用了什么引用,~译器就会只调用引用cL拥有的方法。如果调用子cȝ有的ҎQ如上例的h.buck(); ~译器会抱怨的。也是_~译器只看引用类型,而不是对象类型?br />
4、重写方法的规则?br />
若想实现一个合格重写方法,而不是重载,那么必须同时满下面的要求!
A、重写规则之一Q重写方法不能比被重写方法限制有更严格的讉KU别?br />
Q但是可以更q泛Q比如父cL法是包访问权限,子类的重写方法是public讉K权限。)
比如QObjectcL个toString()ҎQ开始重写这个方法的时候我们d易忘记public修饰W,~译器当然不会放qQ何教训我们的Z。出错的原因是Q没有加M讉K修饰W的Ҏh包访问权限,包访问权限比public当然要严gQ所以编译器会报错的?br />
B、重写规则之二:参数列表必须与被重写Ҏ的相同?br />
重写有个孪生的弟弟叫重蝲Q也是后面要出场的。如果子cL法的参数与父cd应的Ҏ不同Q那么就是你认错ZQ那是重载,不是重写?br />
C、重写规则之三:q回cd必须与被重写Ҏ的返回类型相同?br />
父类ҎAQvoid eat(){} 子类ҎBQint eat(){} 两者虽然参数相同,可是q回cd不同Q所以不是重写?br />
父类ҎAQint eat(){} 子类ҎBQlong eat(){} q回cd虽然兼容父类Q但是不同就是不同,所以不是重写?br />
D、重写规则之四:重写Ҏ不能抛出新的异常或者比被重写方法声明的查异常更q的查异常。但是可以抛出更,更有限或者不抛出异常?br />
import java.io.*;
public class Test {
public static void main (String[] args) {
Animal h = new Horse();
try {
h.eat();
}
catch (Exception e) {
}
}
}
class Animal {
public void eat() throws Exception{
System.out.println ("Animal is eating.");
throw new Exception();
}
}
class Horse extends Animal{
public void eat() throws IOException{
System.out.println ("Horse is eating.");
throw new IOException();
}
}
q个例子中,父类抛出了检查异常ExceptionQ子cL出的IOException是Exception的子c,也即是比被重写的Ҏ抛出了更有限的异常,q是可以的。如果反q来Q父cL出IOExceptionQ子cL出更为宽泛的ExceptionQ那么不会通过~译的?br />
注意Q这U限制只是针Ҏ查异常,至于q行时异常RuntimeException及其子类不再q个限制之中?br />
E、重写规则之五:不能重写被标识ؓfinal的方法?br />
F、重写规则之六:如果一个方法不能被l承Q则不能重写它?br />
比较典型的就是父cȝprivateҎ。下例会产生一个有的现象?br />
public class Test {
public static void main (String[] args) {
//Animal h = new Horse();
Horse h = new Horse();
h.eat();
}
}
class Animal {
private void eat(){
System.out.println ("Animal is eating.");
}
}
class Horse extends Animal{
public void eat(){
System.out.println ("Horse is eating.");
}
}
q段代码是能通过~译的。表面上看来q反了第六条规则Q但实际上那是一点y合。Animalcȝeat()Ҏ不能被承,因此HorsecM的eat()Ҏ是一个全新的ҎQ不是重写也不是重蝲Q只是一个只属于Horsecȝ全新的方法!q点让很多hqh了,但是也不是那么难以理解?br />
main()Ҏ如果是这P
Animal h = new Horse();
//Horse h = new Horse();
h.eat();
~译器会报错Qؓ什么呢QHorsecȝeat()Ҏ是public的啊Q应该可以调用啊Q请牢记Q多态只看父cd用的ҎQ而不看子cd象的ҎQ?br />
二、方法的重蝲?br />
重蝲是有好的Q它不要求你在调用一个方法之前{换数据类型,它会自动地寻扑配的Ҏ。方法的重蝲是在~译时刻决定调用哪个方法了Q和重写不同。最最常用的地方就是构造器的重载?br />
1、基本数据类型参数的重蝲?br />
public class Test {
static void method(byte b){
System.out.println ("method:byte");
}
static void method(short s){
System.out.println ("method:short");
}
static void method(int i){
System.out.println ("method:int");
}
static void method(float f){
System.out.println ("method:float");
}
static void method(double d){
System.out.println ("method:double");
}
public static void main (String[] args) {
method((byte)1);
method('c');
method(1);
method(1L);
method(1.1);
method(1.1f);
}
}
输出l果Q?br />
method:byte
method:int
method:int
method:float
method:double
method:float
可以看出Q首先要L的是数据cd正好匚wҎ。如果找不到Q那么就提升达能力更强的数据cdQ如上例没有正好容纳long的整数类型,那么p{换ؓfloatcd的。如果通过提升也不能找到合适的兼容cdQ那么编译器׃报错。反正是不会自动转换的数据cd的,必须自己强制转换Q自己来承担转变后果?br />
charcd比较ҎQ如果找不到正好匚w的类型,它会转化为int而不是shortQ虽然char?6位的?br />
2、重载方法的规则?br />
A、被重蝲的方法必L变参数列表?br />
参数必须不同Q这是最重要的!不同有两个方面,参数的个敎ͼ参数的类型,参数的顺序?br />
B、被重蝲的方法与q回cd无关?br />
也就是说Q不能通过q回cd来区分重载方法?br />
C、被重蝲的方法可以改变访问修饰符?br />
没有重写Ҏ那样严格的限制?br />
D、被重蝲的方法可以声明新的或者更q的查异常?br />
没有重写Ҏ那样严格的限制?br />
E、方法能够在一个类中或者在一个子cM被重载?br />
3、带对象引用参数的方法重载?br />
class Animal {}
class Horse extends Animal{}
public class Test {
static void method(Animal a){
System.out.println ("Animal is called.");
}
static void method(Horse h){
System.out.println ("Horse is called.");
}
public static void main (String[] args) {
Animal a = new Animal();
Horse h = new Horse();
Animal ah = new Horse();
method(a);
method(h);
method(ah);
}
}
输出l果是:
Animal is called.
Horse is called.
Animal is called.
前两个输出没有Q何问题。第三个ҎZ么不是输?#8220;Horse is called.”呢?q是那句老话Q要看引用类型而不是对象类型,Ҏ重蝲是在~译时刻决定的了,引用cd军_了调用哪个版本的重蝲Ҏ?br />
4、重载和重写Ҏ区别的小l?br />
如果能彻底弄明白下面的例子,说明你对重蝲和重写非怺解了Q可以结束这节的复习了?br />
class Animal {
public void eat(){
System.out.println ("Animal is eating.");
}
}
class Horse extends Animal{
public void eat(){
System.out.println ("Horse is eating.");
}
public void eat(String food){
System.out.println ("Horse is eating " + food);
}
}
public class Test {
public static void main (String[] args) {
Animal a = new Animal();
Horse h = new Horse();
Animal ah = new Horse();
a.eat();
h.eat();
h.eat("apple");
ah.eat();
//a.eat("apple");
//ah.eat("apple");
}
}
四个输出分别是什么?被注释的两条语句Z么不能通过~译Q?br />
W一条:a.eat(); 普通的Ҏ调用Q没有多态,没什么技术含量。调用了Animalcȝeat()ҎQ输出:Animal is eating.
W二条:h.eat(); 普通的Ҏ调用Q也没什么技术含量。调用了Horsecȝeat()ҎQ输出:Horse is eating.
W三条:h.eat("apple"); 重蝲。Horsecȝ两个eat()Ҏ重蝲。调用了Horsecȝeat(String food)ҎQ输出:Horse is eating apple
W四条:ah.eat(); 多态。前面有例子了,不难理解。输出:Horse is eating.
W五条:a.eat("apple"); 低的错误,AnimalcM没有eat(String food)Ҏ。因此不能通过~译?br />
W六条:ah.eat("apple"); 关键点就在这里。解决的Ҏq是那句老话Q不能看对象cdQ要看引用类型。AnimalcM没有eat(String food)Ҏ。因此不能通过~译?br />
结一下:多态不军_调用哪个重蝲版本Q多态只有在军_哪个重写版本时才起作用?br />
重蝲对应~译Ӟ重写对应q行时。够z的了吧Q?br />
三、构造方法?br />
构造方法是一U特D的ҎQ没有构造方法就不能创徏一个新对象。实际上Q不仅要调用对象实际cd的构造方法,q要调用其父cȝ构造方法,向上q溯Q直到ObjectcR构造方法不必显式地调用Q当使用new关键字时Q相应的构造方法会自动被调用?br />
1、构造方法的规则?br />
A、构造方法能使用M讉K修饰W。包括privateQ事实上javacd有很多都是这LQ设计者不希望使用者创cȝ对象?br />
B、构造方法的名称必须与类名相同。这样得构造方法与众不同,如果我们遵守sun的编码规范,g只有构造方法的首字母是大写的?br />
C、构造方法不能有q回cd?br />
反过来说Q有q回cd的不是构造方?br />
public class Test {
int Test(){
return 1;
}
}
q个Ҏ是什么东西?一个冒充李늚李鬼而已Qint Test()和其他Q何普通方法没什么两P是普通的ҎQ只不过看v来很恶心Q类似恶心的东西在考试卷子里比较多?br />
D、如果不在类中创q构造方法,~译器会自动生成默认的不带参数的构造函数?br />
q点很容易验证!写一个这L单的c,~译?br />
class Test {
}
对生成的Test.class文g反编译:javap TestQ可以看刎ͼ
D:"JavaCode"bin>javap Test
Compiled from "Test.java"
class Test extends java.lang.Object{
Test();
}
看到~译器自动添加的默认构造函C吧!
E、如果只创徏了带参数的构造方法,那么~译器不会自动添加无参的构造方法的Q?br />
F、在每个构造方法中Q如果用了重蝲构造函数this()ҎQ或者父cȝ构造方法super()ҎQ那么this()Ҏ或者super()Ҏ必须攑֜W一行。而且q两个方法只能选择一个,因此它们之间没有序问题?br />
G、除了编译器生成的构造方法,而且没有昑ּ地调用super()ҎQ那么编译器会插入一个super()无参调用?br />
H、抽象类有构造方法?br />
四、静态方法的重蝲与重写(覆盖Q?br />
1、静态方法是不能被覆盖的。可以分两种情况讨论Q?br />
A、子cȝ非静态方?#8220;覆盖”父类的静态方法?br />
q种情况下,是不能通过~译的?br />
static void print(){
System.out.println ("in father method");
}
}
class Child extends Father{
void print(){
System.out.println ("in child method");
}
}
staticҎ表示该方法不兌具体的类的对象,可以通过cd直接调用Q也是~译的前期就l定了,不存在后期动态绑定,也就是不能实现多态。子cȝ非静态方法是与具体的对象l定的,两者有着不同的含义?br />
B、子cȝ静态方?#8220;覆盖”父类静态方法?br />
q个覆盖依然是带引号的。事实上把上面那个例子ChildcȝprintҎ前面加上static修饰W,实能通过~译Q但是不要以是多态!多态的特点是动态绑定,看下面的例子Q?br />
static void print(){
System.out.println ("in father method");
}
}
class Child extends Father{
static void print(){
System.out.println ("in child method");
}
}
class Test{
public static void main (String[] args) {
Father f =new Child();
f.print();
}
}
输出l果是:in father method
从这个结果可以看出,q没有实现多态?br />
但是q种形式很迷惑hQ貌似多态,实际~程中千万不要这hQ会把大家搞늚Q?br />
它不W合覆盖表现出来的特性,不应该算是覆盖!
总而言之,静态方法不能被覆盖?br />
2、静态方法可以和非静态方法一栯重蝲?br />
q样的例子太多了Q我不想写例E了。看看javacd中很多这L例子?br />
如java.util.Arrayscȝ一堆重载的binarySearchҎ?br />
在这里提一下是因ؓ查资料时看到q样的话“sun的SL275评_静态方法只能控刉态变量(他们本n没有Q,静态方法不能被重蝲和覆?#8230;…”
大家不要怿啊!可以重蝲的。而且静态与非静态方法可以重载?br />
从重载的机制很容易就理解了,重蝲是在~译时刻决定的了,非静态方法都可以Q静态方法怎么可能不会呢?
]]>
1、String中的每个字符都是一?6位的Unicode字符Q用Unicode很容易表达丰富的国际化字W集Q比如很好的中文支持。甚至Java的标识符都可以用汉字Q但是没Z用吧Q只在一本清华的《Java2实用教程》看q)?br />
2、判断空字符丌Ӏ根据需要自己选择某个或者它们的l合
if ( s == null ) //从引用的角度
if ( s.length() == 0 ) //从长度判?br />
if ( s.trim().length () == 0 ) //是否有多个空白字W?br />
trim()Ҏ的作用是是移除前导和N的Unicode值小?"u0020'的字W,q返?#8220;修剪”好的字符丌Ӏ这U方法很常用Q比如需要用戯入用户名Q用户不心加了前导或者尾部空|一个好的程序应该知道用户不是故意的Q即使是故意的也应该点地处理?br />
判断IZ是很常用的操作,但是Javacd直到1.6才提供了isEmpty()Ҏ。当且仅?length() ?0 时返?true?br />
3、未初始化、空?"与null。它们是不同的概c对未初始化的对象操作会被编译器挡在门外Qnull是一个特D的初始化|是一个不指向M对象的引用,对引用ؓnull的对象操作会在运行时抛出异常NullPointerExceptionQ而空串是长度?的字W串Q和别的字符串的唯一区别是长度??br />
例子Q?br />
public class StringTest{
static String s1;
public static void main(String[] args) {
String s2;
String s3 = "";
System.out.print(s1.isEmpty()); //q行时异?br />
System.out.print(s2.isEmpty()); //~译出错
System.out.print(s3.isEmpty()); //okQ输出true
}
}
4、StringcȝҎ很多Q在~写相关代码的时候看看JDK文档时有好处的,要不然花了大量时间实C个已l存在的Ҏ是很不值得的,因ؓ~写、测试、维护自q代码佉K目的成本增加Q利润减,严重的话会导致开不出工资……
5、字W串的比较?br />
Java不允许自定义操作W重载,因此字符串的比较要用compareTo() 或?compareToIgnoreCase()。s1.compareTo(s2)Q返回值大?则,则前者大Q等?Q一般大Q小?Q后者大。比较的依据是字W串中各个字W的Unicode倹{?br />
6、toString()Ҏ?br />
Java的Q何对象都有toString()ҎQ是从Object对象l承而来的。它的作用就是让对象在输出时看v来更有意义,而不是奇怪的对象的内存地址。对试也是很有帮助的?br />
7、String对象是不变的Q可以变化的是String对象的引用?br />
String name = "ray";
name.concat("long"); //字符串连?br />
System.out.println(name); //输出nameQokQ还?ray"
name = name.concat("long"); //把字W串对象q接的结果赋l了name引用
System.out.println(name); //输出nameQohQ,变成?raylong"
上述三条语句其实产生?个String对象Q?ray"Q?long"Q?raylong"。第2条语句确实生了"raylong"字符Ԍ但是没有指定把该字符串的引用赋给谁,因此没有改变name引用。第3条语句根据不变性,q没有改?ray"QJVM创徏了一个新的对象,?ray"Q?long"的连接赋l了name引用Q因此引用变了,但是原对象没变?br />
8、String的不变性的机制昄会在String帔R内有大量的冗余。如Q?1" + "2" + "3" +......+ "n" 产生了n+(n+1)个String对象Q因此JavaZ更有效地使用内存QJVM留出一块特D的内存区域Q被UCؓ“String帔R?#8221;。对String多么照顾啊!当编译器遇见String帔R的时候,它检查该池内是否已经存在相同的String帔R。如果找刎ͼ把新常量的引用指向现有的StringQ不创徏M新的String帔R对象?br />
那么可能出现多个引用指向同一个String帔RQ会不会有别名的危险呢?No problemQString对象的不变性可以保证不会出现别名问题!q是String对象与普通对象的一点区别?br />
乍看hq是底层的机ӞҎ们编E没什么媄响。而且q种机制会大q度提高String的效率,实际上却不是q样。ؓq接n个字W串使用字符串连接操作时Q要消耗的旉是n的^方Q因为每两个字符串连接,它们的内定w要被复制。因此在处理大量的字W串q接Ӟ而且要求性能Ӟ我们不要用StringQStringBuffer是更好的选择?br />
8、StringBuffercRStringBuffercL可变的,不会在字W串帔R池中Q而是在堆中,不会留下一大堆无用的对象。而且它可字W串~冲区安全地用于多个U程。每个StringBuffer对象都有一定的定w。只要StringBuffer对象所包含的字W序列的长度没有出此容量,无需分配新的内部~冲区数l。如果内部缓冲区溢出Q则此容量自动增大。这个固定的定w?6个字W。我l这U算法v个名字叫“添饭法”。先l你一满碗饭,不够了再l你一满碗饭?br />
例子Q?br />
StringBuffer sb = new StringBuffer(); //初始定w?16 个字W?br />
sb.append("1234"); //q是4个字W,那么16个字W的定wp够了Q没有溢?br />
System.out.println(sb.length()); //输出字符串长度是4
System.out.println(sb.capacity()); //输出该字W串~冲区的定w?6
sb.append("12345678901234567"); //q是17个字W,16个字W的定w不够了,扩容?7+16个字W的定w
System.out.println(sb.length()); //输出字符串长度是17
System.out.println(sb.capacity()); //输出该字W串~冲区的定w?4
sb.append("890").reverse().insert(10,"-");
System.out.println(sb); //输出0987654321-09876543214321
字符串的长度和字W缓冲区的容量是两个概念Q注意区别?br />
q有串联的方式看h是不是很P用返回D接v来可以实现这U简z和优雅?br />
10、StringBuildercR?从J2SE 5.0 提供了StringBuilderc,它和StringBuffercL孪生兄弟Q很像。它存在的h值在于:对字W串操作的效率更高。不的是线E安全无法保证,不保证同步。那么两者性能到底差多呢Q很多!
请参阅:http://book.csdn.net/bookfiles/135/1001354628.shtml
实践Q?br />
单个U程的时候用StringBuilderc,以提高效率,而且它的API和StringBuffer兼容Q不需要额外的学习成本Q物h廉。多U程时用StringBufferQ以保证安全?br />
11、字W串的比较?br />
下面q条可能会让你晕Q所以你可以选择看或者不看。它不会对你的职业生涯造成M影响。而且谨记一条,比较字符串要用equals()ok了!一旦用?#8220;==”׃出现很怪异的现象。之所以把q部分放在最后,是想节省大家的时_因ؓq条又臭又长。推荐三UhQ一、没事闲着型。二、想深入地理解Java的字W串Q即使明明知道学了也没用。三、和我一L好研I?#8220;?#8221;字有几种写法?br />
q是那句老话QString太特D了Q以至于某些规则对String不v作用。个人感觉这U特D性ƈ不好。看例子Q?br />
例子AQ?br />
String str1 = "java";
String str2 = "java";
System.out.print(str1==str2);
地球上有点Java基础的h都知道会输出falseQ因?=比较的是引用Qequals比较的是内容。不是我忽悠大家Q你们可以在自己的机子上q行一下,l果是trueQ原因很单,String对象被放q常量池里了Q再ơ出?#8220;java”字符串的时候,JVM很兴奋地把str2的引用也指向?#8220;java”对象Q它认ؓ自己节省了内存开销。不隄解吧 呵呵
例子BQ?br />
String str1 = new String("java");
String str2 = new String("java");
System.out.print(str1==str2);
看过上例的都学聪明了Q这ơ肯定会输出trueQ很不幸QJVMq没有这么做Q结果是false。原因很单,例子A中那U声明的方式实是在String帔R池创?#8220;java”对象Q但是一旦看到new关键字,JVM会在堆中为String分配I间。两者声明方式貌合神,q也是我?#8220;如何创徏字符串对?#8221;攑ֈ后面来讲的原因。大家要沉住气,q有一个例子?br />
例子CQ?br />
String str1 = "java";
String str2 = "blog";
String s = str1+str2;
System.out.print(s=="javablog");
再看q个例子Q很多同志不敢妄a是trueq是false了吧。爱玩脑{急{弯的Z说是false?#8230;…恭喜你,你会抢答了!把那?#8220;?#8221;字去掉你完全正。原因很单,JVM实会对型如String str1 = "java"; 的String对象攑֜字符串常量池里,但是它是在编译时刻那么做的,而String s = str1+str2; 是在q行时刻才能知道Q我们当然一眼就看穿了,可是Java必须在运行时才知道的Qh脑和电脑的结构不同)Q也是说str1+str2是在堆里创徏的,s引用当然不可能指向字W串帔R池里的对象。没崩溃的hl箋看例子D?br />
例子DQ?br />
String s1 = "java";
String s2 = new String("java");
System.out.print(s1.intern()==s2.intern());
intern()是什么东东?反正l果是true。如果没用过q个ҎQ而且训练有素的程序员会去看JDK文档了。简单点说就是用intern()Ҏ可以用“==”比较字符串的内容了。在我看到intern()Ҏ到底有什么用之前Q我认ؓ它太多余了。其实我写的q一条也很多余,intern()Ҏq存在诸多的问题Q如效率、实C的不l一……
例子EQ?br />
String str1 = "java";
String str2 = new String("java");
System.out.print(str1.equals(str2));
无论在常量池q是堆中的对象,用equals()Ҏ比较的就是内容,p么简单!看完此条的h一定很后悔Q但是在开始我劝你别看?#8230;…
后记Q用彪哥的话?#8220;有意思吗Q?#8221;Q确实没劌Ӏ在写这D늚时候我也是思量再三Q感觉自己像孔乙q耀“?#8221;字有几种写法。我查了一下茴 Q回Q囘Q囬Q还有一U是“?#8221;字里面有?#8220;?#8221;字,后面q四个都加上草字?#8230;…
]]>Q?Q模?+ 数据模型 = 输出
设计者专注于表示——创建HTML文g、图片、Web面的其它可视化斚wQ?br />
E序员创建系l,生成设计面要显C的数据?br />
l常会遇到的问题是:在Web面Q或其它cd的文档)中显C的信息在设计页面时是无效的Q是Z动态数据的。在q里Q你可以在HTMLQ或其它要输出的文本Q中加入一些特定指令,FreeMarker会在输出面l最l用hQ用适当的数据替代这些代码?/p>
<#if condition><#elseif condition><#else> 条g判断
<#list hash_or_seq as var> 遍历hash表或者collectionQfreemakerUCsequenceQ的成员
<#macro name param1 param2 ... ><#nested param> 宏,无返回参?br />
<#function name param1 param2><#return val>函数Q有q回参数
var?member_function(...) 用函数对varq行转换QfreemakerUCؓbuild-ins。实际内部实现类似member_function(var, ...)
stringA[M .. N] 取子字符ԌcMsubstring(stringA, M, N)
{key:value, key2:value2 ...} 直接定义一个hash?br />
[item0, item1, item2 ...] 直接定义一个序?br />
hash0[key0] 存取hash表中key对应的元?br />
seq0[5] 存取序列指定下标的元?br />
<@function1 param0 param1 ... /> 调用函数function1
<@macro0 param0 param1 ; nest_param0 nest_param1 ...> nest_body </@macro> 调用宏,q处理宏的嵌?br />
<#assign var = value > 定义变量q初始化
<#local var = value> ?macro 或?function 中定义局部变量ƈ初始?br />
<#global var = value > 定义全局变量q初始化
${var} 输出q替换ؓ表达式的?br />
<#visit xmlnode> 调用macro匚wxmlnode本n及其子节?br />
<#recurse xmlnode> 调用macro匚wxmlnode的子节点
<html>
q个例子是在单的HTML中加入了一些由${…}包围的特定代码,q些特定代码是FreeMarker的指令,而包含FreeMarker的指令的文gq为模板(TemplateQ?br />
至于user、latestProduct.url和latestProduct.name来自于数据模型(data modelQ?br />
数据模型q序员~程来创建,向模板提供变化的信息Q这些信息来自于数据库、文Ӟ甚至于在E序中直接生成?br />
模板设计者不兛_数据从那儿来Q只知道使用已经建立的数据模型?br />
<head>
<title>Welcome!</title>
</head>
<body>
<h1>Welcome ${user}!</h1>
<p>Our latest product:
<a href="${latestProduct.url}">${latestProduct.name}</a>!
</body>
</html>
(root)
数据模型cM于计机的文件系l,latestProduct可以看作是目录?
|
+- user = "Big Joe"
|
+- latestProduct
|
+- url = "products/greenmouse.html"
|
+- name = "green mouse"
2、数据模?
Q?Q基
(root)
mouse既是scalars又是hashesQ将上面的数据模型合q到下面的模板:
|
+- mouse = "Yerri"
|
+- age = 12
|
+- color = "brown">
${mouse} <#-- use mouse as scalar -->
输出l果是:
${mouse.age} <#-- use mouse as hash -->
${mouse.color} <#-- use mouse as hash -->
Yerri
12
brown
Q?QScalar变量
Q?Qhashes 、sequences和集?
Q?Q方?
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)}
Q?Q宏和变换器
Q?Q节?
3、模?
Q?Q整体结?
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<#-- Greet the user with his/her name -->
<h1>Welcome ${user}!</h1>
<p>We have these animals:
<ul>
<#list animals as being>
<li>${being.name} for ${being.price} Euros
</#list>
</ul>
</body>
</html>
<#if <#include 'foo'>='bar'>...</if>
<h1>Welcome ${user <#-- The name of user -->}!</h1>
<p>We have these animals:
<ul>
<#list <#-- some comment... --> animals as <#-- again... --> being>
...
Q?Q指?
<ul>
如果使用不存在的指oQFreeMarker不会使用模板输出Q而是产生一个错误消息?
<#list animals as being>
<li>${being.name} for ${being.price} Euros
<#if use = "Big Joe">
(except for you)
</#list>
</#if> <#-- WRONG! -->
</ul>
<#list
但是Q?lt;?lt;/和指令之间不允许有空白字W?
animals as
being
>
${being.name} for ${being.price} Euros
</#list >
Q?Q表辑ּ
使用单引h双引号限?
${"It's \"quoted\" and
输出l果是:
this is a backslash: \\"}
${'It\'s "quoted" and
this is a backslash: \\'}
It's "quoted" and
下面是支持的转义序列Q?
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?6q制Unicode代码
${r"${foo}"}
输出的结果是Q?
${r"C:\foo\bar"}
${foo}
C:\foo\bar
<#list ["winter", "spring", "summer", "autumn"] as x>
输出的结果是Q?
${x}
</#list>
winter
列表的项目是表达式,所以可以有下面的例子:
spring
summer
autumn
[2 + 2, [1, 2, 3, 4], "whatnot"]
可以使用数字范围定义数字序列Q例?..5{同于[2, 3, 4, 5]Q但是更有效率,注意数字范围没有Ҏ?
由逗号分隔的键/值列表,由大括号限定Q键和g间用冒号分隔Q下面是一个例子:
{"name":"green mouse", "price":150}
键和值都是表辑ּQ但是键必须是字W串
(root)
下面都是{h的:
|
+- book
| |
| +- title = "Breeding green mouses"
| |
| +- author
| |
| +- name = "Julia Smith"
| |
| +- info = "Biologist, 1923-1985, Canada"
|
+- test = "title"
book.author.name
使用点语法,变量名字有顶层变量一L限制Q但Ҏ可法没有该限制Q因为名字是L表达式的l果
book["author"].name
book.author.["name"]
book["author"]["name"]
${"Hello ${user}!"}
可以使用+操作W获得同Ll果
${"${user}${user}${user}${user}"}
${"Hello " + user + "!"}
${..}只能用于文本部分Q下面的代码是错误的Q?
${user + user + user + user}
<#if ${isBig}>Wow!</#if>
应该写成Q?
<#if "${isBig}">Wow!</#if>
<#if isBig>Wow!</#if>
${user[0]}${user[4]}
l果是(注意W一个字W的索引?Q:
${user[1..4]}
BJ
序列操作
ig J
<#list ["Joe", "Fred"] + ["Julia", "Kate"] as user>
输出l果是:
- ${user}
</#list>
- Joe
散列操作
- Fred
- Julia
- Kate
<#assign ages = {"Joe":23, "Fred":25} + {"Joe":30, "Julia":18}>
输出l果是:
- Joe is ${ages.Joe}
- Fred is ${ages.Fred}
- Julia is ${ages.Julia}
- Joe is 30
术q算
- Fred is 25
- Julia is 18
${x * x - 100}
输出l果是(假设x?Q:
${x / 2}
${12 % 10}
-75
操作W两边必L数字Q因此下面的代码是错误的Q?
2.5
2
${3 * "5"} <#-- WRONG! -->
使用+操作W时Q如果一Ҏ数字Q一Ҏ字符Ԍ׃自动数字{换ؓ字符Ԍ例如Q?
${3 + "5"}
输出l果是:
35
使用内徏的intQ后面讲qͼ获得整数部分Q例如:
${(x/2)?int}
输出l果是(假设x?Q:
${1.1?int}
${1.999?int}
${-1.1?int}
${-1.999?int}
2
1
1
-1
-1
<#if x < 12 && color = "green">
We have less than 12 things, and they are green.
</#if>
<#if !hot> <#-- here hot must be a boolean -->
It's not hot.
</#if>
${test?html}
输出l果是:
${test?upper_case?html}
Tom & Jerry
TOM & JERRY
操作W组
操作W?
后缀
[subvarName] [subStringRange] . (methodParams)
一?
+expr?expr?
内徏
?
乘法
*?/ ?
加法
+?
关系
<?gt;?lt;=?gt;=Qlt、lte、gt、gteQ?
相等
==Q?Q?=
逻辑and
&&
逻辑or
双竖U?/td>
数字范围
..
Q?QInterpolation
<#setting number_format="currency"/>
输出l果是:
<#assign answer=42/>
${answer}
${answer?string} <#-- the same as ${answer} -->
${answer?string.number}
${answer?string.currency}
${answer?string.percent}
$42.00
插入日期|Ҏ~省格式Q由#setting指o讄Q将表达式结果{换成文本输出Q可以用内建函数string格式化单个InterpolationQ下面是一个用格式模式的例子Q?
$42.00
42
$42.00
4,200%
${lastUpdated?string("yyyy-MM-dd HH:mm:ss zzzz")}
输出的结果类g面的格式Q?
${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
插入布尔|Ҏ~省格式Q由#setting指o讄Q将表达式结果{换成文本输出Q可以用内建函数string格式化单个InterpolationQ下面是一个例子:
Tue, Apr 8, '03
Tuesday, April 08, 2003, 09:24:44 PM (PDT)
<#assign foo=true/>
输出l果是:
${foo?string("yes", "no")}
yes
<#-- 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、杂?
Q?Q用户定义指?
<#macro greet>
作ؓ用户定义指o使用宏变量时Q用@替代FTL标记中的#
<font size="+2">Hello Joe!</font>
</#macro>
<@greet></@greet>
如果没有体内容,也可以用:
<@greet/>
<#macro greet person>
可以q样使用q个宏变量:
<font size="+2">Hello ${person}!</font>
</#macro>
<@greet person="Fred"/> and <@greet person="Batman"/>
输出l果是:
<font size="+2">Hello Fred!</font>
and <font size="+2">Hello Batman!</font>
<@greet person=Fred/>
q意味着Fred变量的glperson参数Q该g仅是字符Ԍq可以是其它cdQ甚x复杂的表辑ּ
<#macro greet person color>
可以q样使用该宏变量Q?
<font size="+2" color="${color}">Hello ${person}!</font>
</#macro>
<@greet person="Fred" color="black"/>
其中参数的次序是无关的,因此下面是等LQ?
<@greet color="black" person="Fred"/>
只能使用在macro指o中定义的参数Qƈ且对所有参数赋|所以下面的代码是错误的Q?
<@greet person="Fred" color="black" background="green"/>
可以在定义参数时指定~省|如:
<@greet person="Fred"/>
<#macro greet person color="black">
q样<@greet person="Fred"/>正了
<font size="+2" color="${color}">Hello ${person}!</font>
</#macro>
<#macro border>
q样使用该宏变量Q?
<table border=4 cellspacing=0 cellpadding=4><tr><td>
<#nested>
</tr></td></table>
</#macro>
<@border>The bordered text</@border>
输出l果Q?
<table border=4 cellspacing=0 cellpadding=4><tr><td>
The bordered text
</tr></td></table>
<#macro do_thrice>
输出l果Q?
<#nested>
<#nested>
<#nested>
</#macro>
<@do_thrice>
Anything.
</@do_thrice>
Anything.
嵌套内容可以是有效的FTLQ下面是一个有些复杂的例子Q?<@border> <ul> <@do_thrice> <li><@greet person="Joe"/> </@do_thrice> </ul> </@border> }}} 输出l果Q?
Anything.
Anything.
<table border=4 cellspacing=0 cellpadding=4><tr><td>
宏定义中的局部变量对嵌套内容是不可见的,例如Q?
<ul>
<li><font size="+2">Hello Joe!</font>
<li><font size="+2">Hello Joe!</font>
<li><font size="+2">Hello Joe!</font>
</ul>
</tr></td></table>
<#macro repeat count>
输出l果Q?
<#local y = "test">
<#list 1..count as x>
${y} ${count}/${x}: <#nested>
</#list>
</#macro>
<@repeat count=3>${y?default("?")} ${x?default("?")} ${count?default("?")}</@repeat>
test 3/1: ? ? ?
test 3/2: ? ? ?
test 3/3: ? ? ?
<#macro repeat count>
输出l果Q?
<#list 1..count as x>
<#nested x, x/2, x==count>
</#list>
</#macro>
<@repeat count=4 ; c, halfc, last>
${c}. ${halfc}<#if last> Last!</#if>
</@repeat>
1. 0.5
2. 1
3. 1.5
4. 2 Last!
Q?Q在模板中定义变?
<#assign x = "plain">
输出l果Q?
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. -->
</#list>
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. -->
</#list>
5. ${x} <#-- now we see the local var. again -->
</#macro>
1. plain
2. plain
3. local
4. loop
5. local
6. plain
7. loop
8. loop
9. plain2
<#list ["loop 1"] as x>
输出l果Q?
${x}
<#list ["loop 2"] as x>
${x}
<#list ["loop 3"] as x>
${x}
</#list>
${x}
</#list>
${x}
</#list>
loop 1
模板中的变量会隐藏(而不是覆盖)数据模型中同名变量,如果需要访问数据模型中的同名变量,使用Ҏ变量globalQ下面的例子假设数据模型中的user的值是Big JoeQ?
loop 2
loop 3
loop 2
loop 1
<#assign user = "Joe Hider">
${user} <#-- prints: Joe Hider -->
${.globals.user} <#-- prints: Big Joe -->
Q?Q名字空?
<#macro copyright date>
使用import指o导入库到模板中,Freemarker会ؓ导入的库创徏新的名字I间Qƈ可以通过import指o中指定的散列变量讉K库中的变量:
<p>Copyright (C) ${date} Julia Smith. All rights reserved.
<br>Email: ${mail}</p>
</#macro>
<#assign mail = "jsmith@acme.com">
<#import "/lib/my_test.ftl" as my>
输出l果Q?
<#assign mail="fred@acme.com">
<@my.copyright date="1999-2002"/>
${my.mail}
${mail}
<p>Copyright (C) 1999-2002 Julia Smith. All rights reserved.
可以看到例子中用的两个同名变量q没有冲H,因ؓ它们位于不同的名字空?
<br>Email: jsmith@acme.com</p>
jsmith@acme.com
fred@acme.com
<#import "/lib/my_test.ftl" as my>
输出l果Q?
${my.mail}
<#assign mail="jsmith@other.com" in my>
${my.mail}
jsmith@acme.com
数据模型中的变量M地方都可见,也包括不同的名字I间Q下面是修改的库Q?
jsmith@other.com
<#macro copyright date>
假设数据模型中的user变量的值是FredQ则下面的代码:
<p>Copyright (C) ${date} ${user}. All rights reserved.</p>
</#macro>
<#assign mail = "${user}@acme.com">
<#import "/lib/my_test.ftl" as my>
输出l果Q?
<@my.copyright date="1999-2002"/>
${my.mail}
<p>Copyright (C) 1999-2002 Fred. All rights reserved.</p>
Fred@acme.com
补充Q静态方法的调用Q:
Ҏ1Q?/strong>
##定义配置文g freemarkerstatic.properties
_Validator=com.longyou.util.Validator
_Functions=com.longyou.util.Functions
_EscapeUtils=com.longyou.util.EscapeUtils
/调用代码
${_Functions.toUpperCase("Hello")}<br>
${_EscapeUtils.escape("狼的原野")}
Ҏ2Q?/strong>
${stack.findValue("@package.ClassName@method")}
补充Q常用语?/strong>
freemarker中Map的?/strong>
<#list testMap?keys as testKey>
< option value="${testKey}" >
</#list>
freemarker的Eclipse插g
]]>
]]>
Ctrl+N 查找c?span style="display: none"> }8dN-@%
Ctrl+Shift+N 查找文g
Ctrl+Alt+L 格式化代?span style="display: none"> ^vz>q?)N
Ctrl+Alt+O 优化导入的类和包
Alt+Insert 生成代码(如get,setҎ,构造函数等)
Ctrl+E或者Alt+Shift+C 最q更改的代码
Ctrl+R 替换文本
Ctrl+F 查找文本
Ctrl+Shift+Space 自动补全代码
Ctrl+I格 代码提示
Ctrl+Alt+Space cd或接口名提示
Ctrl+P Ҏ参数提示
Ctrl+Shift+Alt+N 查找cM的方法或变量
Alt+Shift+C Ҏ最q修改的代码
Shift+F6 重构-重命?span style="display: none"> H["Jg)kJ
Ctrl+Shift+先上?span style="display: none"> ==ko,FJSV
Ctrl+X 删除?span style="display: none"> rL 2+5|
Ctrl+D 复制?span style="display: none"> gJmr $
Ctrl+/ ?Ctrl+Shift+/ 注释Q?/ 或?*...*/ Q?span style="display: none"> hrkkRl
Ctrl+J 自动代码
Ctrl+E 最q打开的文?span style="display: none"> TM~yQ6K
Ctrl+H 昄cȝ构图
Ctrl+Q 昄注释文档
Alt+F1 查找代码所在位|?span style="display: none"> Fv}![ 7|
Alt+1 快速打开或隐藏工E面?span style="display: none"> ]N='WJ(8/
Ctrl+Alt+ left/right q回至上ơ浏览的位置
Alt+ left/right 切换代码视图
Alt+ Up/Down 在方法间快速移动定?span style="display: none"> ^N=<b0rq
Ctrl+Shift+Up/Down 代码向上/下移动?span style="display: none"> m4$mF/-Ny+
F2 或Shift+F2 高亮错误或警告快速定?span style="display: none"> %}V4b
代码标签输入完成后,按TabQ生成代码?span style="display: none"> &3"n7 fmT
选中文本Q按Ctrl+Shift+F7 Q高亮显C所有该文本Q按Esc高亮消失?span style="display: none"> 5H`rQKU
Ctrl+W 选中代码Q连l按会有其他效果
选中文本Q按Alt+F3 Q逐个往下查扄同文本,q亮显C?span style="display: none"> ?Ge~7h-
Ctrl+Up/Down 光标跌{到第一行或最后一行下
Ctrl+B 快速打开光标处的cLҎ