zk+hibernate+spring零配置
zk5.0.5
hibernate3.6
spring3.05
也许你在使用apply或者use一个类名的或者<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
那么下面的方法对你也许是一种更优雅的方式
一,spring自动扫描注解配置,如果熟悉ss2h,看起来没什么不同
<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:lang="http://www.springframework.org/schema/lang" xmlns:oxm="http://www.springframework.org/schema/oxm" xmlns:task="http://www.springframework.org/schema/task" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"> <description>系统配置信息</description> <!-- 定义受环境影响易变的变量 --> <context:property-placeholder location="/WEB-INF/config/application.properties" /> <!-- --> <!-- 数据源配置 --> <!-- --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driverClass}" /> <property name="jdbcUrl" value="${jdbc.url}" /> <property name="user" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property> <property name="minPoolSize" value="${jdbc.minPoolSize}"> </property> <property name="initialPoolSize" value="${jdbc.initialPoolSize}"> </property> <property name="maxIdleTime" value="${jdbc.maxIdleTime}"> </property> <property name="acquireIncrement" value="${jdbc.acquireIncrement}"> </property> <property name="acquireRetryAttempts" value="${jdbc.acquireRetryAttempts}"> </property> <property name="acquireRetryDelay" value="${jdbc.acquireRetryDelay}"> </property> <property name="idleConnectionTestPeriod" value="${jdbc.idleConnectionTestPeriod}"> </property> <property name="preferredTestQuery" value="${jdbc.preferredTestQuery}"> </property> <property name="numHelperThreads" value="${jdbc.numHelperThreads}"> </property> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">${hibernate.dialect}</prop> <prop key="hibernate.show_sql">${hibernate.show_sql}</prop> <prop key="hibernate.format_sql">${hibernate.format_sql}</prop> <prop key="hibernate.generate_statistics">${hibernate.generate_statistics}</prop> <prop key="hibernate.max_fetch_depth">${hibernate.max_fetch_depth}</prop> <prop key="hibernate.jdbc.fetch_size">${hibernate.jdbc.fetch_size}</prop> <prop key="hibernate.jdbc.batch_size">${hibernate.jdbc.batch_size}</prop> <prop key="hibernate.connection.autocommit">${hibernate.connection.autocommit}</prop> <prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop> <prop key="hibernate.cache.provider_class">${hibernate.cache.provider_class}</prop> <prop key="hibernate.cache.use_second_level_cache">${hibernate.cache.use_second_level_cache}</prop> <prop key="hibernate.cglib.use_reflection_optimizer">${hibernate.cglib.use_reflection_optimizer}</prop> </props> </property> <property name="packagesToScan" value="org.zkway.entity" /> </bean> <!-- 事务管理器配置,单数据源事务 --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <!-- 使用annotation 自动注册bean,并检查@Required,@Autowired的属性已被注入 --> <context:component-scan base-package="org.zkway" /> <!-- 使用annotation定义事务 --> <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" /> </beans>
二,zk controller 注解配置,注意scope必须是prototype,因为composer是一个状态对象
@Controller @Scope("prototype") public class LoginController extends GenericAutowireComposer {
三,页面中使用ctrl
首先要引入我自定义的el函数库,zktools工具将在下面讲到
<?taglib uri="http://www.zkoss.org/zktools/zktools" prefix="z" ?>
然后在window apply中使用,其中z是prefix="z" 中的z,ctrl是zktools.jar中定义的一个el函数,这个和c标签很类 似, 'loginController'是【二】中LoginController类spring 受管理bean名字,通常我们喜欢使用
长长的类路径apply="org.zkway.web.controller.LoginController",
但这样创建的对象不是spring管理,你无法向LoginController类里注入service,当然你可以使用SpringUtil.getBean
获取bean事例,但就丧失使用annotation的好处了
<window apply="${z:ctrl('loginController')}" width="300px"
完整使用
<?xml version="1.0" encoding="utf-8"?> <?page cacheable="false" language="xul/html" zscriptLanguage="Java" contentType="text/html;charset=UTF-8"?> <?taglib uri="http://www.zkoss.org/dsp/web/core" prefix="c" ?> <?taglib uri="http://www.zkoss.org/zktools/zktools" prefix="z" ?> <div style="background: url('images/headerbg.png') repeat-x; background-position:0 -53px;height:100%;" xmlns:w="client" xmlns:n="native" xmlns="http://www.zkoss.org/2005/zul" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.zkoss.org/2005/zul http://www.zkoss.org/2005/zul/zul.xsd"> <window apply="${z:ctrl('loginController')}" width="300px" height="140px" onOK="Events.postEvent("onClick",btnLogin,null);" mode="overlapped" position="center,top" style="margin-top:100px;">
四,获取spring bean的el函数
在【三】中的页面zul中,我们仅仅简单的使用了一个表达式${z:ctrl('loginController')}, 这个表达式由
zk框架解释,还记的我们在页面首部添加的一个指令吗?
<?taglib uri="http://www.zkoss.org/zktools/zktools" prefix="z" ?>
和jsp c标签类似, zk中的标签也是在tld文件中定义的,大部分的web容器都可以自动加载tld文件,
zk也是一样,但zk不会自动加载tld,它自动加载类路径下的一个metainfo/tld/config.xml文件,这是zk的约定
在config.xml文件中我定义了如下内容,当然这些也是zk的约定,taglib-location告诉zk框架tld文件位置,
那么zk自动去找这个文件并解析
<?xml version="1.0" encoding="UTF-8"?> <!-- by sunflower --> <config> <version> <version-class>org.zkway.zktools.Version</version-class> <version-uid>1.0</version-uid> </version> <taglib> <taglib-uri>http://www.zkoss.org/zktools/zktools</taglib-uri> <taglib-location>/web/WEB-INF/tld/zktools/zktools.tld</taglib-location> </taglib> </config>
那么我们看看zktools.tld里如何定义的
<!-- --> <!-- 获取spring 管理bean --> <!-- --> <function> <name>ctrl</name> <function-class>org.zkway.zktools.ZkCommonTools</function-class> <function-signature>java.lang.Object getController(java.lang.String)</function-signature> <description>获取spring 管理controller</description> </function> <function> <name>comp</name> <function-class>org.zkway.zktools.ZkCommonTools</function-class> <function-signature>java.lang.Object getComponent(java.lang.String)</function-signature> <description>获取spring 管理组件对象</description> </function> <function> <name>bean</name> <function-class>org.zkway.zktools.ZkCommonTools</function-class> <function-signature>java.lang.Object getBean(java.lang.String)</function-signature> <description>获取spring 管理bean对象</description> </function> <!-- --> <!-- 工具函数 --> <!-- --> <function> <name>size</name> <function-class>org.zkway.zktools.ZkCommonTools</function-class> <function-signature>int size(java.lang.Object)</function-signature> <description>获取一个对象的大小</description> </function> <function> <name>length</name> <function-class>org.zkway.zktools.ZkCommonTools</function-class> <function-signature>int size(java.lang.Object)</function-signature> <description>获取一个对象的大小</description> </function> <function> <name>empty</name> <function-class>org.zkway.zktools.ZkCommonTools</function-class> <function-signature>boolean isEmpty(java.lang.Object)</function-signature> <description>判断一个对象是否是空对象</description> </function> <!-- --> <!-- 日期工具函数 --> <!-- --> <function> <name>now</name> <function-class>org.zkway.zktools.ZkCommonTools</function-class> <function-signature>java.util.Date currentTime()</function-signature> <description>获取当前时间</description> </function> <function> <name>today</name> <function-class>org.zkway.zktools.ZkCommonTools</function-class> <function-signature>java.util.Date today(int, int, int)</function-signature> <description>获取今天的日期时间,可以指定今天时分秒,-1表示不设置</description> </function> <function> <name>firstDayOfMonth</name> <function-class>org.zkway.zktools.ZkCommonTools</function-class> <function-signature>java.util.Date firstDayOfMonth()</function-signature> <description>获取当前月的第一天</description> </function> <function> <name>lastDayOfMonth</name> <function-class>org.zkway.zktools.ZkCommonTools</function-class> <function-signature>java.util.Date lastDayOfMonth()</function-signature> <description>获取当前月的最后一天</description> </function> <function> <name>fmtDate</name> <function-class>org.zkway.zktools.ZkCommonTools</function-class> <function-signature>java.lang.String formatDate(java.lang.String)</function-signature> <description>根据参数指定的模式,格式化当前日期</description> </function>
1)<name>定义了el函数的名字,例如${z:ctrl('loginController')}中的ctrl对应以下中的ctrl
<function> <name>ctrl</name> <function-class>org.zkway.zktools.ZkCommonTools</function-class> <function-signature>java.lang.Object getController(java.lang.String)</function-signature> <description>获取spring 管理controller</description> </function>
2)function-signature函数指定了函数签名,具体哪个函数
3)function-class为function-signature函数所属的类
4)description为函数描述
那么这个函数必须符合什么规范呢:public,static 可以不是final
public class ZkCommonTools { /** * 获取spring管理的控制器对象, * <p> * * 支持的类型为:{@link Composer},{@link Component},{@link FullComposer} * * @param beanName * @return */ public static final Object getController(String beanName) { Object controller = SpringUtil.getBean(beanName); if (controller instanceof Composer) return controller; else if (controller instanceof FullComposer) return controller; else if (controller instanceof Component) return controller; return null; }
五,总结
首先我们在spring的配置中开启自动扫描
<!-- 使用annotation 自动注册bean,并检查@Required,@Autowired的属性已被注入 --> <context:component-scan base-package="org.zkway" />
将controller注册为spring bean
@Controller @Scope("prototype") public class LoginController extends GenericAutowireComposer {
然后我们需要解决的问题是如何获取bean,如果直接apply或use一个类名,
那么类实例由zk创建,我们无法享受spring管理bean给我们带来的任何好处。
也许会这么做,就是在forward到一个zul页面前,先将spring bean放在可用作用域(execution,request,session,ThreadLocal),
然后目标页面直接使用el表达式获取${reqeustScope['loginController']},但实际项目中,下一站到底是什么,大多数情况我们是无法预知的,
只有到达目标你才能知道结果,所以预先读取bean很多情况下有他的局限性。
在本文中我定义了一个el函数ctrl,这个函数的参数为spring bean名字,el函数的返回值是spring管理的bean事例
大致流程如下
spring scan bean ---> register controller bean ---> el function 获取 spring bean -->zk interpret -