在各種論壇上看了很久,沒(méi)見(jiàn)到完整extJs樹(shù)的生成代碼。研究了很久終于實(shí)現(xiàn)了Spring+Hibernate+DWR+extJs的生成樹(shù)及下拉comBoboxTree。
不敢獨(dú)享收獲 ,借javaeye這一平臺(tái)將我的成果和大家分享。不足和錯(cuò)誤之處敬請(qǐng)批評(píng)指正。有疑問(wèn)歡迎聯(lián)系我。qq:446702119 msn: wh_aq@hotmail.com
廢話少說(shuō),還是從生成樹(shù)開(kāi)始吧。
一、樹(shù)的對(duì)象模型。
- package com.ssgly.model;
-
- import java.util.List;
- import java.util.Set;
-
-
- public class Region {
-
- private Long id;
- private String name;
- private String code;
- private Region parent;
- private Set<Region> children = new java.util.HashSet<Region>();
-
- public Region() {}
-
- public Region(String name, String code, Region parent) {
- this.name = name;
- this.code = code;
- if(parent!=null) parent.addChild(this);
- }
-
- public Long getId() {
- return id;
- }
-
- public void setId(Long id) {
- this.id = id;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getCode() {
- return code;
- }
-
- public void setCode(String code) {
- this.code = code;
- }
-
- public Region getParent() {
- return parent;
- }
-
- public void setParent(Region parent) {
- this.parent = parent;
- }
-
- public Set<Region> getChildren() {
- return children;
- }
-
- public void setChildren(Set<Region> children) {
- this.children = children;
- }
-
-
- }
-
package com.ssgly.model;import java.util.List;import java.util.Set;public class Region {private Long id;private String name;private String code;private Region parent;private Set<Region> children = new java.util.HashSet<Region>();public Region() {}public Region(String name, String code, Region parent) {this.name = name;this.code = code;if(parent!=null) parent.addChild(this);}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getCode() {return code;}public void setCode(String code) {this.code = code;}public Region getParent() {return parent;}public void setParent(Region parent) {this.parent = parent;}public Set<Region> getChildren() {return children;}public void setChildren(Set<Region> children) {this.children = children;}}
二、樹(shù)結(jié)構(gòu)的數(shù)據(jù)庫(kù)(mySql)DDL
- CREATE TABLE `region` (
- `id` bigint(20) NOT NULL,
- `name` varchar(100) default NULL,
- `code` varchar(100) default NULL,
- `parent_id` bigint(20) default NULL,
- PRIMARY KEY (`id`),
- KEY `FK91AD1314568C1D72` (`parent_id`),
- CONSTRAINT `FK91AD1314568C1D72` FOREIGN KEY (`parent_id`) REFERENCES `region` (`id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `region` (`id` bigint(20) NOT NULL,`name` varchar(100) default NULL,`code` varchar(100) default NULL,`parent_id` bigint(20) default NULL,PRIMARY KEY (`id`),KEY `FK91AD1314568C1D72` (`parent_id`),CONSTRAINT `FK91AD1314568C1D72` FOREIGN KEY (`parent_id`) REFERENCES `region` (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
三、對(duì)象模型到數(shù)據(jù)庫(kù)的Hibernate映射關(guān)系
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
-
- <class name="com.ssgly.model.Region" table="region" >
- <id name="id" column="id" type="java.lang.Long">
- <generator class="assigned" />
- </id>
- <property name="code" column="code" type="java.lang.String" />
- <property name="name" column="name" type="java.lang.String" />
- <many-to-one name="parent" column="parent_id" cascade="save-update" />
- <set name="children" inverse="true" cascade="save-update" lazy="false">
- <key column="parent_id" ></key>
- <one-to-many class="com.ssgly.model.Region"></one-to-many>
- </set>
- </class>
- </hibernate-mapping>
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.ssgly.model.Region" table="region" ><id name="id" column="id" type="java.lang.Long"><generator class="assigned" /></id><property name="code" column="code" type="java.lang.String" /><property name="name" column="name" type="java.lang.String" /><many-to-one name="parent" column="parent_id" cascade="save-update" /><set name="children" inverse="true" cascade="save-update" lazy="false"><key column="parent_id" ></key><one-to-many class="com.ssgly.model.Region"></one-to-many></set></class></hibernate-mapping>
四、用Spring框架來(lái)管理和支撐持久層、業(yè)務(wù)邏輯層和展示層
【一】持久層采用了DAO模式 。具體設(shè)計(jì)了一個(gè)類型安全的泛型DAO。由于這不是我要講的重點(diǎn)部分,感興趣的朋友可以
查閱有關(guān)文檔。要生成一個(gè)樹(shù),必須要從后臺(tái)數(shù)據(jù)庫(kù)中按一定類型(我用了適配器模式)取出java對(duì)象--TreeNode 對(duì)象 。及要實(shí)現(xiàn)方法 public List<Region> listRegionByParent(Region parent)。
TreeNode類型為:
- package com.ssgly.model;
-
-
-
- ublic class TreeNode {
- private String id;
- private String Text;
- private boolean leaf;
- private String cls="";
-
- private Region region;
-
- public TreeNode(Region region)
- {
- this.region=region;
- }
-
- public String getId() {
- return region.getId().toString();
- }
-
- public boolean getLeaf() {
- return region.getChildren().size()<1;
- }
-
- public String getText() {
- return region.getName();
- }
-
- public String getCls() {
- return region.getChildren().size()<1?"file":"folder";
- }
-
-
-
-
package com.ssgly.model;public class TreeNode {private String id;private String Text;private boolean leaf;private String cls="";private Region region;public TreeNode(Region region){this.region=region;}public String getId() {return region.getId().toString();}public boolean getLeaf() {return region.getChildren().size()<1;}public String getText() {return region.getName();}public String getCls() {return region.getChildren().size()<1?"file":"folder";}}
具體生成樹(shù)的泛型DAO實(shí)現(xiàn)是:
- package com.ssgly.dao;
-
-
-
- import java.io.IOException;
- import java.sql.SQLException;
- import java.text.SimpleDateFormat;
- import java.util.List;
-
- import com.ssgly.model.Region;
-
- import com.ssgly.model.Page;
-
-
- public class RegionDAOImpl extends GenericHibernateDAOCrud<Region> implements IRegionDAO {
-
- public RegionDAOImpl(){
-
- super(Region.class);
- }
-
- public void deleteRegion(Region region) {
- hibernateTemplate.delete(region);
-
- }
-
- public void deleteRegion(Long id) {
- hibernateTemplate.delete(hibernateTemplate.get(Region.class, id));
-
- }
-
- public Region getRegion(Long id) {
-
- return (Region)hibernateTemplate.get(Region.class, id);
- }
-
- public Long saveRegion(Region region) {
- hibernateTemplate.save(region);
- return region.getId();
- }
-
- public void updateRegion(Region region) {
-
- hibernateTemplate.saveOrUpdate(region);
- }
-
-
-
-
-
-
-
-
- public List<Region> listRegionByParent(Region parent) {
- if (parent==null){
- return (List<Region>)hibernateTemplate.find("from Region as r where r.parent is null");
- }else{
- return (List<Region>)queryForLists("from Region as r where r.parent=?"
- ,new Object[]{parent});
-
- }
-
- }
-
-
- }
package com.ssgly.dao;import java.io.IOException;import java.sql.SQLException;import java.text.SimpleDateFormat;import java.util.List;import com.ssgly.model.Region;import com.ssgly.model.Page;public class RegionDAOImpl extends GenericHibernateDAOCrud<Region> implements IRegionDAO {public RegionDAOImpl(){super(Region.class);}public void deleteRegion(Region region) {hibernateTemplate.delete(region);}public void deleteRegion(Long id) {hibernateTemplate.delete(hibernateTemplate.get(Region.class, id));}public Region getRegion(Long id) {return (Region)hibernateTemplate.get(Region.class, id);}public Long saveRegion(Region region) {hibernateTemplate.save(region);return region.getId();}public void updateRegion(Region region) {hibernateTemplate.saveOrUpdate(region);}/*** 查詢父節(jié)點(diǎn)的所有子節(jié)點(diǎn)* @param parent 父節(jié)點(diǎn)* @return 該父節(jié)點(diǎn)對(duì)應(yīng)的子節(jié)點(diǎn)****/public List<Region> listRegionByParent(Region parent) {if (parent==null){return (List<Region>)hibernateTemplate.find("from Region as r where r.parent is null");}else{return (List<Region>)queryForLists("from Region as r where r.parent=?",new Object[]{parent});}}}
從上面java代碼中可以看到:DWR需要解析的是 List<Region> 類型的對(duì)象。
【二】業(yè)務(wù)邏輯層主要采用一個(gè)實(shí)現(xiàn)類BusinessServiceImp 。將所有的業(yè)務(wù)邏輯放在一個(gè)類中,一是便于spring中bean好管理,二是方便權(quán)限控制。BusinessServiceImp 中的一個(gè)很重要的屬性是: private IRegionDAO regionDAO; regionDAO的生命周期依賴于spring容器,在spring中管理和維護(hù)。邏輯層的代碼如下:
- package com.ssgly.business.impl;
-
- import java.io.IOException;
- import java.io.Serializable;
- import java.sql.SQLException;
- import java.util.ArrayList;
- import java.util.Iterator;
- import java.util.List;
-
- import com.ssgly.model.*;
- import com.ssgly.util.Hzxs;
-
- import com.ssgly.business.BusinessService;
- import com.ssgly.dao.*;
-
-
- public class BusinessServiceImpl implements BusinessService {
-
- private IRegionDAO regionDAO;
-
- public void setRegionDAO(IRegionDAO regionDAO) {
- this.regionDAO = regionDAO;
- }
-
- public List<TreeNode> getAllChildren(Long parentId) throws IOException,
- SQLException {
- List<Region> listRegion=regionDAO.listRegionByParent(regionDAO.getRegion(parentId));
- List<TreeNode> listTreeNode=new ArrayList<TreeNode>();
- for(Region region:listRegion){
- System.out.println(">>"+region.getName());
- listTreeNode.add(new TreeNode(region));
- }
-
- return listTreeNode;
- }
-
-
- }
package com.ssgly.business.impl;import java.io.IOException;import java.io.Serializable;import java.sql.SQLException;import java.util.ArrayList;import java.util.Iterator;import java.util.List;import com.ssgly.model.*;import com.ssgly.util.Hzxs;import com.ssgly.business.BusinessService;import com.ssgly.dao.*;public class BusinessServiceImpl implements BusinessService {private IRegionDAO regionDAO;public void setRegionDAO(IRegionDAO regionDAO) {this.regionDAO = regionDAO;}public List<TreeNode> getAllChildren(Long parentId) throws IOException,SQLException {List<Region> listRegion=regionDAO.listRegionByParent(regionDAO.getRegion(parentId));List<TreeNode> listTreeNode=new ArrayList<TreeNode>();for(Region region:listRegion){System.out.println(">>"+region.getName());listTreeNode.add(new TreeNode(region));}//System.out.println("List<TreeNode> getAllChildren 方法已執(zhí)行!");return listTreeNode;}}
【三】Spring容器的配置主要是通過(guò)xml方式體現(xiàn)。
一是:web.xml的配置如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
- "http://java.sun.com/dtd/web-app_2_3.dtd">
- <web-app>
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>
- /WEB-INF/dispatcherServlet-servlet.xml,
- /WEB-INF/model-config.xml
- </param-value>
- </context-param>
- <!-- log4j config -->
- <context-param>
- <param-name>log4jConfigLocation</param-name>
- <param-value>/WEB-INF/log4j.properties</param-value>
- </context-param>
- <!--========================================================================
- Filters
- =========================================================================-->
-
- <filter>
- <filter-name>encodingFilter</filter-name>
- <filter-class>com.ssgly.web.filter.EncodingFilter</filter-class>
- <init-param>
- <param-name>encoding</param-name>
- <param-value>utf-8</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>encodingFilter</filter-name>
- <url-pattern>*</url-pattern>
- </filter-mapping>
- <!--========================================================================
- Listeners
- =========================================================================-->
-
- <listener>
- <listener-class>
- org.springframework.web.util.Log4jConfigListener
- </listener-class>
- </listener>
- <listener>
- <listener-class>
- org.springframework.web.context.ContextLoaderListener
- </listener-class>
- </listener>
-
- <!--========================================================================
- Servlets
- =========================================================================-->
- <servlet>
- <servlet-name>dispatcherServlet</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <load-on-startup>0</load-on-startup>
- </servlet>
-
- <servlet-mapping>
- <servlet-name>dispatcherServlet</servlet-name>
- <url-pattern>*.do</url-pattern>
- </servlet-mapping>
- <!--========================================================================
- DWR 配置
- =========================================================================-->
- <!--配置DWR攔截器-->
- <servlet>
- <servlet-name>dwr-invoker</servlet-name>
- <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
- <init-param>
- <param-name>debug</param-name>
- <param-value>true</param-value>
- </init-param>
- <init-param>
- <param-name>classes</param-name>
- <param-value>java.lang.Object</param-value>
- </init-param>
- <load-on-startup>100</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>dwr-invoker</servlet-name>
- <url-pattern>/dwr/*</url-pattern>
- </servlet-mapping>
- <!--========================================================================
- Session
- =========================================================================-->
-
- <session-config>
- <session-timeout>30</session-timeout>
- </session-config>
-
-
-
-
- </web-app>
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd"><web-app><context-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/dispatcherServlet-servlet.xml,/WEB-INF/model-config.xml</param-value></context-param><!-- log4j config --><context-param><param-name>log4jConfigLocation</param-name><param-value>/WEB-INF/log4j.properties</param-value></context-param><!--========================================================================Filters=========================================================================--><filter><filter-name>encodingFilter</filter-name><filter-class>com.ssgly.web.filter.EncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param></filter><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>*</url-pattern></filter-mapping><!--========================================================================Listeners=========================================================================--><listener><listener-class>org.springframework.web.util.Log4jConfigListener</listener-class></listener><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!--========================================================================Servlets=========================================================================--><servlet><servlet-name>dispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><load-on-startup>0</load-on-startup></servlet><servlet-mapping><servlet-name>dispatcherServlet</servlet-name><url-pattern>*.do</url-pattern></servlet-mapping><!--========================================================================DWR 配置=========================================================================--><!--配置DWR攔截器--><servlet><servlet-name>dwr-invoker</servlet-name><servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class><init-param><param-name>debug</param-name><param-value>true</param-value></init-param><init-param><param-name>classes</param-name><param-value>java.lang.Object</param-value></init-param><load-on-startup>100</load-on-startup></servlet><servlet-mapping><servlet-name>dwr-invoker</servlet-name><url-pattern>/dwr/*</url-pattern></servlet-mapping><!--========================================================================Session=========================================================================--><session-config><session-timeout>30</session-timeout></session-config></web-app>
二是:bean生成的配置。model-config.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN"
- "http://www.springframework.org/dtd/spring-beans.dtd">
- <beans>
-
- <bean id="propertyConfigurer"
- class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
- <property name="locations">
- <list>
- <value>/WEB-INF/jdbc.properties</value>
- </list>
- </property>
- </bean>
-
- <bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
- <property name="driverClassName" value="${jdbc.driver}" />
- <property name="url" value="${jdbc.url}" />
- <property name="username" value="${jdbc.username}" />
- <property name="password" value="${jdbc.password}" />
- </bean>
-
-
- <bean id="sessionFactory"
- class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" destroy-method="close">
- <property name="dataSource">
- <ref local="myDataSource" />
- </property>
- <property name="mappingResources">
- <list>
- <value> com/ssgly/model/Region.hbm.xml</value>
- </list>
- </property>
- <property name="hibernateProperties">
- <props>
- <prop key="connection.characterEncoding">utf-8</prop>
- <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
- <prop key="hibernate.jdbc.batch_size">50</prop>
- <prop key="hibernate.show_sql">true</prop>
- <prop key="hibernate.query.factory_class">org.hibernate.hql.classic.ClassicQueryTranslatorFactory</prop>
- </props>
- </property>
- </bean>
-
- <bean id="transactionManager"
- class="org.springframework.orm.hibernate3.HibernateTransactionManager">
- <property name="sessionFactory">
- <ref bean="sessionFactory"/>
- </property>
- </bean>
-
- <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
- <property name="sessionFactory"> <ref bean="sessionFactory"/> </property>
- </bean>
-
-
- <bean id="regionDao" class="com.ssgly.dao.RegionDAOImpl">
- <property name="hibernateTemplate">
- <ref bean="hibernateTemplate"/>
- </property>
- </bean>
- <bean id="businessService" class="com.ssgly.business.impl.BusinessServiceImpl">
- <property name="regionDAO"><ref bean="regionDao" /></property>
-
- </bean>
-
- <bean id="todoSsglyService" class="com.ssgly.ext.ToDoImpl">
- <property name="businessServiceImpl">
- <ref bean="businessService"/>
- </property>
- </bean>
-
-
- </beans>
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN""http://www.springframework.org/dtd/spring-beans.dtd"><beans><bean id="propertyConfigurer"class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="locations"><list><value>/WEB-INF/jdbc.properties</value></list></property></bean><bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="${jdbc.driver}" /><property name="url" value="${jdbc.url}" /><property name="username" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /></bean><bean id="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" destroy-method="close"><property name="dataSource"><ref local="myDataSource" /></property><property name="mappingResources"><list><value> com/ssgly/model/Region.hbm.xml</value></list></property><property name="hibernateProperties"><props><prop key="connection.characterEncoding">utf-8</prop><prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop><prop key="hibernate.jdbc.batch_size">50</prop><prop key="hibernate.show_sql">true</prop><prop key="hibernate.query.factory_class">org.hibernate.hql.classic.ClassicQueryTranslatorFactory</prop></props></property></bean><bean id="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager"><property name="sessionFactory"><ref bean="sessionFactory"/></property></bean><bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate"><property name="sessionFactory"> <ref bean="sessionFactory"/> </property></bean><bean id="regionDao" class="com.ssgly.dao.RegionDAOImpl"><property name="hibernateTemplate"><ref bean="hibernateTemplate"/></property></bean><bean id="businessService" class="com.ssgly.business.impl.BusinessServiceImpl"><property name="regionDAO"><ref bean="regionDao" /></property></bean><bean id="todoSsglyService" class="com.ssgly.ext.ToDoImpl"><property name="businessServiceImpl"><ref bean="businessService"/></property></bean></beans>
三是:servlet配置 dispatcherServlet-servlet.xml
- <?xml version="1.0" encoding="utf-8"?>
- <!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN"
- "http://www.springframework.org/dtd/spring-beans.dtd">
-
- <beans>
- <!--============================================================================
- URL Mapping configuration
- =============================================================================-->
-
- <bean id="beanNameUrlMapping"
- class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
- <property name="alwaysUseFullPath" value="true" />
- </bean>
- <!--============================================================================
- Velocity configuration
- =============================================================================-->
-
- <bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
- <property name="contentType"><value>text/html;charset=GBK</value></property>
- </bean>
-
- <bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
- <property name="configLocation" value="/WEB-INF/velocity.properties" />
- <property name="resourceLoaderPath" value="/" />
- </bean>
-
- <bean id="treeRegionServlet" name="/treeRegionServlet.do" class="com.ssgly.web.TreeRegionServlet">
- <property name="businessService">
- <ref bean="businessService"/>
- </property>
- </bean>
- </beans>
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN""http://www.springframework.org/dtd/spring-beans.dtd"><beans><!--============================================================================URL Mapping configuration=============================================================================--><bean id="beanNameUrlMapping"class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"><property name="alwaysUseFullPath" value="true" /></bean><!--============================================================================Velocity configuration=============================================================================--><bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"><property name="contentType"><value>text/html;charset=GBK</value></property></bean><bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer"><property name="configLocation" value="/WEB-INF/velocity.properties" /><property name="resourceLoaderPath" value="/" /></bean><bean id="treeRegionServlet" name="/treeRegionServlet.do" class="com.ssgly.web.TreeRegionServlet"><property name="businessService"><ref bean="businessService"/></property></bean></beans>
有了這些xml的配置。Spring能將三層很好地組合起來(lái)。以上是java部分。還沒(méi)有講到extJs。extJs可以接受asp、php、java等服務(wù)器端生成的json格式的對(duì)象。就java來(lái)說(shuō) ,extJs能接受三種方式的json對(duì)象,一是servlet中拼接json對(duì)象;其次是引用json lib 包;三是DWR方式,繞過(guò)Controller(就Spring來(lái)說(shuō))或servlet,在javascript中 直接調(diào)用java業(yè)務(wù)邏輯層中的方法(通過(guò)DWR引擎),利用dwr代理或者javascript 回調(diào)函數(shù)返回json對(duì)象并在頁(yè)面展示。
本人采用了第三種DWR方式實(shí)現(xiàn)ExtJs生成樹(shù)。要使用dwr 就的要在以上幾個(gè)配置文件中配置DWR(已配)。具體的下次再說(shuō)吧。
今天就寫(xiě)到這里吧。不知寫(xiě)的怎么樣?有朋友關(guān)注這一塊?若支持,請(qǐng)鼓勵(lì)一下;寫(xiě)的不好、不對(duì)或不懂的地方,請(qǐng)拍磚。(續(xù))
抱歉啊,這幾天忙著考駕照,把這事給耽擱啊。書(shū)接上回吧。
【四】基于Spring方式的DWR配置說(shuō)明。
一、首先在WEB.xml中配置dwr攔截器 代碼如下(節(jié)選):
- <!--配置DWR攔截器-->
- <servlet>
- <servlet-name>dwr-invoker</servlet-name>
- <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
- <init-param>
- <param-name>debug</param-name>
- <param-value>false</param-value>
- </init-param>
- <init-param>
- <param-name>classes</param-name>
- <param-value>java.lang.Object</param-value>
- </init-param>
- <load-on-startup>100</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>dwr-invoker</servlet-name>
- <url-pattern>/dwr/*</url-pattern>
- </servlet-mapping>
<!--配置DWR攔截器--><servlet><servlet-name>dwr-invoker</servlet-name><servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class><init-param><param-name>debug</param-name><param-value>false</param-value></init-param><init-param><param-name>classes</param-name><param-value>java.lang.Object</param-value></init-param><load-on-startup>100</load-on-startup></servlet><servlet-mapping><servlet-name>dwr-invoker</servlet-name><url-pattern>/dwr/*</url-pattern></servlet-mapping>
二、dwr.xml的配置。這里將Spring管理的bean映射成javascipt操作的對(duì)象。更直觀的說(shuō)法就是使得頁(yè)面中javascript能直接使用java中對(duì)象的方法。代碼如下:
- <?xml version="1.0" encoding="utf-8"?>
- <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN"
- "http://getahead.ltd.uk/dwr/dwr20.dtd">
-
- <dwr>
- <allow>
- <convert converter="bean" match="com.ssgly.model.*"/>
- <convert converter="map" match="org.directwebremoting.convert.MapConverter"/>
- <create creator="spring" javascript="treeBusinessService">
- <param name="beanName" value="businessService"/>
- <include method="getAllChildren" />
- </create>
- </allow>
-
- </dwr>
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN""http://getahead.ltd.uk/dwr/dwr20.dtd"><dwr><allow><convert converter="bean" match="com.ssgly.model.*"/><convert converter="map" match="org.directwebremoting.convert.MapConverter"/><create creator="spring" javascript="treeBusinessService"><param name="beanName" value="businessService"/><include method="getAllChildren" /></create></allow></dwr>
從上面的代碼可以看出,javascript使用treeBusinessService.getAllChildren 方法就能夠直接取出 Spring維持的業(yè)務(wù)邏輯層定義的bean----- businessService。從而完成了DWR的功能。這里當(dāng)然存在安全問(wèn)題,在這里暫時(shí)沒(méi)有討論,關(guān)于如何在DWR中進(jìn)行安全控制,大家可以參考有關(guān)文檔。本文暫不考慮。
【五】ext和服務(wù)器端交互的機(jī)制和具體實(shí)現(xiàn)
一般說(shuō)來(lái),按照上面DWR的配置,就已經(jīng)實(shí)現(xiàn)了在頁(yè)面中使用java的方法。但java方法執(zhí)行后生成的List 傳回到頁(yè)面還需要靠回調(diào)函數(shù)實(shí)現(xiàn)。例如下面代碼就是包含了回調(diào)函數(shù)的測(cè)試頁(yè)。
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <title>ExtJS-樹(shù)示例</title>
- <link rel="stylesheet" type="text/css" href="ext2/resources/css/ext-all.css" />
- <script type="text/javascript" src="ext2/adapter/ext/ext-base.js"></script>
- <script type="text/javascript" src="ext2/ext-all.js"></script>
-
- <PRE class=java name="code"><script type="text/javascript" src="dwr/interface/treeBusinessService.js "></script>
- <script type="text/javascript" src="dwr/engine.js "></script>
- <script type="text/javascript" src="dwr/util.js "></script></PRE>
- <BR><script type="text/javascript">
- <BR>
- <BR> treeBusinessService.getAllChildren(1,function(ret){
- <BR> alert("一共有"+ret.length+"個(gè)子節(jié)點(diǎn)");
- <BR> });
- <BR>
- <BR></script>
- <BR></head>
- <BR>
- <BR><body>
- <BR><div id="tree-div"></div>
- <BR></body>
- <BR></html>
- <BR>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>ExtJS-樹(shù)示例</title><link rel="stylesheet" type="text/css" href="ext2/resources/css/ext-all.css" /><script type="text/javascript" src="ext2/adapter/ext/ext-base.js"></script><script type="text/javascript" src="ext2/ext-all.js"></script> - <script type="text/javascript" src="dwr/interface/treeBusinessService.js "></script>
- <script type="text/javascript" src="dwr/engine.js "></script>
- <script type="text/javascript" src="dwr/util.js "></script>
<script type="text/javascript" src="dwr/interface/treeBusinessService.js "></script><script type="text/javascript" src="dwr/engine.js "></script><script type="text/javascript" src="dwr/util.js "></script>
<script type="text/javascript">
treeBusinessService.getAllChildren(1,function(ret){
alert("一共有"+ret.length+"個(gè)子節(jié)點(diǎn)");
});
</script>
</head>
<body>
<div id="tree-div"></div>
</body>
</html>
現(xiàn)在分析一下上面頁(yè)面主要代碼:
- <script type="text/javascript" src="dwr/interface/treeBusinessService.js "></script>
-
<script type="text/javascript" src="dwr/interface/treeBusinessService.js "></script>
這句中的treeBusinessService就是DWR.xml中定義的
- <create creator="spring" javascript="treeBusinessService">
<create creator="spring" javascript="treeBusinessService">
下面兩句是使用DWR所必需的,原樣加上即可。
- <script type="text/javascript" src="dwr/engine.js "></script>
- <script type="text/javascript" src="dwr/util.js "></script>
<script type="text/javascript" src="dwr/engine.js "></script><script type="text/javascript" src="dwr/util.js "></script>
有了上面的這些DWR配置,就能夠以DWR的方式使用java的方法啦:
- <script type="text/javascript">
-
- treeBusinessService.getAllChildren(1,function(ret){
- alert("一共有"+ret.length+"個(gè)子節(jié)點(diǎn)");
- });
-
- </script>
<script type="text/javascript">treeBusinessService.getAllChildren(1,function(ret){alert("一共有"+ret.length+"個(gè)子節(jié)點(diǎn)");});</script>
function(ret)就是回調(diào)函數(shù)。因?yàn)閠reeBusinessService.getAllChildren執(zhí)行的結(jié)果是List類型,DWR解析List到頁(yè)面應(yīng)該是javascript的對(duì)象數(shù)組,所以ret應(yīng)該是個(gè)數(shù)組,ret.length是這個(gè)數(shù)組的長(zhǎng)度。
上面的例子只不過(guò)是原理性的介紹,幫助我們理解javascript如何和后臺(tái)進(jìn)行的交互。真正要實(shí)現(xiàn)DWRTree 還需要專門(mén)的DWRTreeLoader代理。下面這段代碼很是重要,參考了ext官方bbs上的代碼,并做了修改。先提供如下:
- Ext.tree.DWRTreeLoader = function(config) {
- Ext.tree.DWRTreeLoader.superclass.constructor.call(this, config);
- };
-
- Ext.extend(Ext.tree.DWRTreeLoader, Ext.tree.TreeLoader, {
- args:[],
- requestData : function(node, callback) {
- if (this.fireEvent("beforeload", this, node, callback) !== false) {
-
-
- var callParams = new Array();
- var success = this.handleResponse.createDelegate(this, [node, callback], 1);
- var error = this.handleFailure.createDelegate(this, [node, callback], 1);
- callParams.push(node.id);
- callParams.push({callback:success, errorHandler:error});
-
-
- this.transId=true;
- this.dataUrl.apply(this, callParams);
- } else {
-
-
- if (typeof callback == "function") {
-
- callback();
- }
- }
- },
- processResponse : function(response, node, callback){
- try {
- for(var i = 0; i < response.length; i++){
- var n = this.createNode(response[i]);
- if(n){
- node.appendChild(n);
- }
- }
- if(typeof callback == "function"){
- callback(this, node);
- }
- }catch(e){
- this.handleFailure(response);
- }
- },
-
- handleResponse : function(response, node, callback){
- this.transId = false;
- this.processResponse(response, node, callback);
- this.fireEvent("load", this, node, response);
- },
-
- handleFailure : function(response, node, callback){
- this.transId = false;
- this.fireEvent("loadexception", this, node, response);
- if(typeof callback == "function"){
- callback(this, node);
- }
- }
-
- });
Ext.tree.DWRTreeLoader = function(config) {Ext.tree.DWRTreeLoader.superclass.constructor.call(this, config);};Ext.extend(Ext.tree.DWRTreeLoader, Ext.tree.TreeLoader, {args:[],requestData : function(node, callback) {if (this.fireEvent("beforeload", this, node, callback) !== false) {var callParams = new Array();var success = this.handleResponse.createDelegate(this, [node, callback], 1);var error = this.handleFailure.createDelegate(this, [node, callback], 1);callParams.push(node.id);callParams.push({callback:success, errorHandler:error});//todo: do we need to set this to something else?this.transId=true;this.dataUrl.apply(this, callParams);} else {// if the load is cancelled, make sure we notify// the node that we are doneif (typeof callback == "function") {//alert(callback);callback();}}},processResponse : function(response, node, callback){try {for(var i = 0; i < response.length; i++){var n = this.createNode(response[i]);if(n){node.appendChild(n);}}if(typeof callback == "function"){callback(this, node);}}catch(e){this.handleFailure(response);}},handleResponse : function(response, node, callback){this.transId = false;this.processResponse(response, node, callback);this.fireEvent("load", this, node, response);},handleFailure : function(response, node, callback){this.transId = false;this.fireEvent("loadexception", this, node, response);if(typeof callback == "function"){callback(this, node);}}});
上面的代碼可以直接在項(xiàng)目中使用,無(wú)需修改。
【六】最終DWRTree的實(shí)現(xiàn)包括 tree.js和 tree.html
tree.js完整代碼如下:
- Ext.onReady(function(){
-
- Ext.tree.DWRTreeLoader = function(config) {
- Ext.tree.DWRTreeLoader.superclass.constructor.call(this, config);
- };
-
- Ext.extend(Ext.tree.DWRTreeLoader, Ext.tree.TreeLoader, {
- args:[],
- requestData : function(node, callback) {
- if (this.fireEvent("beforeload", this, node, callback) !== false) {
-
-
- var callParams = new Array();
- var success = this.handleResponse.createDelegate(this, [node, callback], 1);
- var error = this.handleFailure.createDelegate(this, [node, callback], 1);
- callParams.push(node.id);
- callParams.push({callback:success, errorHandler:error});
-
-
- this.transId=true;
- this.dataUrl.apply(this, callParams);
- } else {
-
-
- if (typeof callback == "function") {
-
- callback();
- }
- }
- },
- processResponse : function(response, node, callback){
- try {
- for(var i = 0; i < response.length; i++){
- var n = this.createNode(response[i]);
- if(n){
- node.appendChild(n);
- }
- }
- if(typeof callback == "function"){
- callback(this, node);
- }
- }catch(e){
- this.handleFailure(response);
- }
- },
-
- handleResponse : function(response, node, callback){
- this.transId = false;
- this.processResponse(response, node, callback);
- this.fireEvent("load", this, node, response);
- },
-
- handleFailure : function(response, node, callback){
- this.transId = false;
- this.fireEvent("loadexception", this, node, response);
- if(typeof callback == "function"){
- callback(this, node);
- }
- }
-
- });
-
-
- var myTree = new Ext.tree.TreePanel({
- el:Ext.getBody(),
- autoScroll:true,
- animate:true,
- width:'300px',
- height:'800px',
- enableDD:true,
- containerScroll: true,
- root:new Ext.tree.AsyncTreeNode({
- text: '單位',
- draggable:false,
- id:'1' }),
- loader:new Ext.tree.DWRTreeLoader({
- dataUrl:treeBusinessService.getAllChildren,
- listeners : {
- 'beforeload' : function( node) {
- myTree.getLoader().args[0]=(node.id!='root'?node.id:"1");
- }
- }
- })
- });
-
- myTree.render();
-
-
-
- });
Ext.onReady(function(){Ext.tree.DWRTreeLoader = function(config) {Ext.tree.DWRTreeLoader.superclass.constructor.call(this, config);};Ext.extend(Ext.tree.DWRTreeLoader, Ext.tree.TreeLoader, {args:[],requestData : function(node, callback) {if (this.fireEvent("beforeload", this, node, callback) !== false) {var callParams = new Array();var success = this.handleResponse.createDelegate(this, [node, callback], 1);var error = this.handleFailure.createDelegate(this, [node, callback], 1);callParams.push(node.id);callParams.push({callback:success, errorHandler:error});//todo: do we need to set this to something else?this.transId=true;this.dataUrl.apply(this, callParams);} else {// if the load is cancelled, make sure we notify// the node that we are doneif (typeof callback == "function") {//alert(callback);callback();}}},processResponse : function(response, node, callback){try {for(var i = 0; i < response.length; i++){var n = this.createNode(response[i]);if(n){node.appendChild(n);}}if(typeof callback == "function"){callback(this, node);}}catch(e){this.handleFailure(response);}},handleResponse : function(response, node, callback){this.transId = false;this.processResponse(response, node, callback);this.fireEvent("load", this, node, response);},handleFailure : function(response, node, callback){this.transId = false;this.fireEvent("loadexception", this, node, response);if(typeof callback == "function"){callback(this, node);}}});var myTree = new Ext.tree.TreePanel({el:Ext.getBody(),autoScroll:true,animate:true,width:'300px',height:'800px',enableDD:true,containerScroll: true,root:new Ext.tree.AsyncTreeNode({text: '單位',draggable:false,id:'1' }),loader:new Ext.tree.DWRTreeLoader({dataUrl:treeBusinessService.getAllChildren,listeners : {'beforeload' : function( node) {myTree.getLoader().args[0]=(node.id!='root'?node.id:"1");}}})});myTree.render();});
提個(gè)醒:這句
- myTree.getLoader().args[0]=(node.id!='root'?node.id:"1");
myTree.getLoader().args[0]=(node.id!='root'?node.id:"1");
不能錯(cuò)哦,它是和 DWRTreeLoader耦合的。
tree.html是這樣的:
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <title>ExtJS-樹(shù)示例</title>
- <link rel="stylesheet" type="text/css" href="ext2/resources/css/ext-all.css" />
- <script type="text/javascript" src="ext2/adapter/ext/ext-base.js"></script>
- <script type="text/javascript" src="ext2/ext-all.js"></script>
-
- <script type="text/javascript" src="dwr/interface/treeBusinessService.js "></script>
- <script type="text/javascript" src="dwr/engine.js "></script>
- <script type="text/javascript" src="dwr/util.js "></script>
- <script type="text/javascript" src="js/tree.js"></script>
-
- </head>
-
- <body>
-
- </body>
- </html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>ExtJS-樹(shù)示例</title><link rel="stylesheet" type="text/css" href="ext2/resources/css/ext-all.css" /><script type="text/javascript" src="ext2/adapter/ext/ext-base.js"></script><script type="text/javascript" src="ext2/ext-all.js"></script><script type="text/javascript" src="dwr/interface/treeBusinessService.js "></script><script type="text/javascript" src="dwr/engine.js "></script><script type="text/javascript" src="dwr/util.js "></script><script type="text/javascript" src="js/tree.js"></script></head><body></body></html>
好了,基于Spring+hibernate+dwr+EXTJs的DWRTreeLoader的實(shí)現(xiàn)就是這樣。本想提供完整代碼下載。但想來(lái)想去還是讓讀者自己結(jié)合我的文章邊做邊體會(huì)比較好。說(shuō)不定還能優(yōu)化我的代碼呢。你說(shuō)是嗎?
還有comBoboxTree的實(shí)現(xiàn)沒(méi)有寫(xiě)。也不知大家感興趣沒(méi)?還是歡迎大家多提意見(jiàn)吧。