一份完整的Spring+Hibernate+DWR+extJs的生成树及下拉comBoboxTree

一份完整的Spring+Hibernate+DWR+extJs的生成树及下拉comBoboxTree

在各种论坛上看了很久,没见到完整extJs树的生成代码。研究了很久终于实现了Spring+Hibernate+DWR+extJs的生成树及下拉comBoboxTree。

    一、树的对象模型。
      Java代码

  1. package com.ssgly.model;
  2. import java.util.List;
  3. import java.util.Set;
  4. public class Region {
  5. private Long id;
  6. private String name;
  7. private String code;
  8. private Region parent;
  9. private Set<Region> children = new java.util.HashSet<Region>();
  10. public Region() {}
  11. public Region(String name, String code, Region parent) {
  12. this.name = name;
  13. this.code = code;
  14. if(parent!=null) parent.addChild(this);
  15. }
  16. public Long getId() {
  17. return id;
  18. }
  19. public void setId(Long id) {
  20. this.id = id;
  21. }
  22. public String getName() {
  23. return name;
  24. }
  25. public void setName(String name) {
  26. this.name = name;
  27. }
  28. public String getCode() {
  29. return code;
  30. }
  31. public void setCode(String code) {
  32. this.code = code;
  33. }
  34. public Region getParent() {
  35. return parent;
  36. }
  37. public void setParent(Region parent) {
  38. this.parent = parent;
  39. }
  40. public Set<Region> getChildren() {
  41. return children;
  42. }
  43. public void setChildren(Set<Region> children) {
  44. this.children = children;
  45. }
  46. }
  47. 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; } }  
    二、树结构的数据库(mySql)DDL
          Java代码
  48. CREATE TABLE `region` (
  49. `id` bigint(20) NOT NULL,
  50. `name` varchar(100) default NULL,
  51. `code` varchar(100) default NULL,
  52. `parent_id` bigint(20) default NULL,
  53. PRIMARY KEY  (`id`),
  54. KEY `FK91AD1314568C1D72` (`parent_id`),
  55. CONSTRAINT `FK91AD1314568C1D72` FOREIGN KEY (`parent_id`) REFERENCES `region` (`id`)
  56. ) 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;  
    三、对象模型到数据库的Hibernate映射关系
          Java代码
  57. <?xml version="1.0" encoding="UTF-8"?>
  58. <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  59. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  60. <hibernate-mapping>
  61. <class name="com.ssgly.model.Region" table="region"  >
  62. <id       name="id"   column="id"  type="java.lang.Long">
  63. <generator class="assigned" />
  64. </id>
  65. <property name="code" column="code" type="java.lang.String" />
  66. <property name="name" column="name"  type="java.lang.String"  />
  67. <many-to-one name="parent"   column="parent_id"    cascade="save-update"  />
  68. <set name="children"   inverse="true" cascade="save-update"  lazy="false">
  69. <key column="parent_id"  ></key>
  70. <one-to-many class="com.ssgly.model.Region"></one-to-many>
  71. </set>
  72. </class>
  73. </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框架来管理和支撑持久层、业务逻辑层和展示层
    【一】持久层采用了DAO模式 。具体设计了一个类型安全的泛型DAO。由于这不是我要讲的重点部分,感兴趣的朋友可以
    查阅有关文档。要生成一个树,必须要从后台数据库中按一定类型(我用了适配器模式)取出java对象--TreeNode 对象  。及要实现方法 public List<Region> listRegionByParent(Region parent)。
    TreeNode类型为:
          Java代码
  74. package com.ssgly.model;
  75. ublic  class TreeNode {
  76. private String id;
  77. private String Text;
  78. private boolean leaf;
  79. private String cls="";
  80. private Region region;
  81. public TreeNode(Region region)
  82. {
  83. this.region=region;
  84. }
  85. public String getId() {
  86. return region.getId().toString();
  87. }
  88. public boolean getLeaf() {
  89. return region.getChildren().size()<1;
  90. }
  91. public String getText() {
  92. return region.getName();
  93. }
  94. public String getCls() {
  95. return region.getChildren().size()<1?"file":"folder";
  96. }
  97. 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"; } }  

    具体生成树的泛型DAO实现是:
          Java代码
  98. package com.ssgly.dao;
  99. import java.io.IOException;
  100. import java.sql.SQLException;
  101. import java.text.SimpleDateFormat;
  102. import java.util.List;
  103. import com.ssgly.model.Region;
  104. import com.ssgly.model.Page;
  105. public class RegionDAOImpl extends GenericHibernateDAOCrud<Region> implements IRegionDAO {
  106. public RegionDAOImpl(){
  107. super(Region.class);
  108. }
  109. public void deleteRegion(Region region) {
  110. hibernateTemplate.delete(region);
  111. }
  112. public void deleteRegion(Long id) {
  113. hibernateTemplate.delete(hibernateTemplate.get(Region.class, id));
  114. }
  115. public Region getRegion(Long id) {
  116. return (Region)hibernateTemplate.get(Region.class, id);
  117. }
  118. public Long saveRegion(Region region) {
  119. hibernateTemplate.save(region);
  120. return region.getId();
  121. }
  122. public void updateRegion(Region region) {
  123. hibernateTemplate.saveOrUpdate(region);
  124. }
  125. /**
  126. * 查询父节点的所有子节点
  127. * @param parent   父节点
  128. * @return  该父节点对应的子节点
  129. *
  130. *
  131. **/
  132. public List<Region> listRegionByParent(Region parent) {
  133. if (parent==null){
  134. return (List<Region>)hibernateTemplate.find("from Region as r where r.parent is null");
  135. }else{
  136. return (List<Region>)queryForLists("from Region as r where r.parent=?"
  137. ,new Object[]{parent});
  138. }
  139. }
  140. }    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); } /** * 查询父节点的所有子节点 * @param parent   父节点 * @return  该父节点对应的子节点 * * **/ 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> 类型的对象。
    【二】业务逻辑层主要采用一个实现类BusinessServiceImp 。将所有的业务逻辑放在一个类中,一是便于spring中bean好管理,二是方便权限控制。BusinessServiceImp 中的一个很重要的属性是: private IRegionDAO regionDAO; regionDAO的生命周期依赖于spring容器,在spring中管理和维护。逻辑层的代码如下:
          Java代码
  141. package com.ssgly.business.impl;
  142. import java.io.IOException;
  143. import java.io.Serializable;
  144. import java.sql.SQLException;
  145. import java.util.ArrayList;
  146. import java.util.Iterator;
  147. import java.util.List;
  148. import com.ssgly.model.*;
  149. import com.ssgly.util.Hzxs;
  150. import com.ssgly.business.BusinessService;
  151. import com.ssgly.dao.*;
  152. public class BusinessServiceImpl implements BusinessService {
  153. private IRegionDAO regionDAO;
  154. public void setRegionDAO(IRegionDAO regionDAO) {
  155. this.regionDAO = regionDAO;
  156. }
  157. public List<TreeNode> getAllChildren(Long parentId) throws IOException,
  158. SQLException {
  159. List<Region> listRegion=regionDAO.listRegionByParent(regionDAO.getRegion(parentId));
  160. List<TreeNode> listTreeNode=new ArrayList<TreeNode>();
  161. for(Region region:listRegion){
  162. System.out.println(">>"+region.getName());
  163. listTreeNode.add(new TreeNode(region));
  164. }
  165. //System.out.println("List<TreeNode> getAllChildren 方法已执行!");
  166. return listTreeNode;
  167. }
  168. }    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 方法已执行!"); return listTreeNode; } }  
    【三】Spring容器的配置主要是通过xml方式体现。
    一是:web.xml的配置如下:
          Java代码
  169. <?xml version="1.0" encoding="UTF-8"?>
  170. <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
  171. "http://java.sun.com/dtd/web-app_2_3.dtd">
  172. <web-app>
  173. <context-param>
  174. <param-name>contextConfigLocation</param-name>
  175. <param-value>
  176. /WEB-INF/dispatcherServlet-servlet.xml,
  177. /WEB-INF/model-config.xml
  178. </param-value>
  179. </context-param>
  180. <!-- log4j config -->
  181. <context-param>
  182. <param-name>log4jConfigLocation</param-name>
  183. <param-value>/WEB-INF/log4j.properties</param-value>
  184. </context-param>
  185. <!--========================================================================
  186. Filters
  187. =========================================================================-->
  188. <filter>
  189. <filter-name>encodingFilter</filter-name>
  190. <filter-class>com.ssgly.web.filter.EncodingFilter</filter-class>
  191. <init-param>
  192. <param-name>encoding</param-name>
  193. <param-value>utf-8</param-value>
  194. </init-param>
  195. </filter>
  196. <filter-mapping>
  197. <filter-name>encodingFilter</filter-name>
  198. <url-pattern>*</url-pattern>
  199. </filter-mapping>
  200. <!--========================================================================
  201. Listeners
  202. =========================================================================-->
  203. <listener>
  204. <listener-class>
  205. org.springframework.web.util.Log4jConfigListener
  206. </listener-class>
  207. </listener>
  208. <listener>
  209. <listener-class>
  210. org.springframework.web.context.ContextLoaderListener
  211. </listener-class>
  212. </listener>
  213. <!--========================================================================
  214. Servlets
  215. =========================================================================-->
  216. <servlet>
  217. <servlet-name>dispatcherServlet</servlet-name>
  218. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  219. <load-on-startup>0</load-on-startup>
  220. </servlet>
  221. <servlet-mapping>
  222. <servlet-name>dispatcherServlet</servlet-name>
  223. <url-pattern>*.do</url-pattern>
  224. </servlet-mapping>
  225. <!--========================================================================
  226. DWR 配置
  227. =========================================================================-->
  228. <!--配置DWR拦截器-->
  229. <servlet>
  230. <servlet-name>dwr-invoker</servlet-name>
  231. <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
  232. <init-param>
  233. <param-name>debug</param-name>
  234. <param-value>true</param-value>
  235. </init-param>
  236. <init-param>
  237. <param-name>classes</param-name>
  238. <param-value>java.lang.Object</param-value>
  239. </init-param>
  240. <load-on-startup>100</load-on-startup>
  241. </servlet>
  242. <servlet-mapping>
  243. <servlet-name>dwr-invoker</servlet-name>
  244. <url-pattern>/dwr/*</url-pattern>
  245. </servlet-mapping>
  246. <!--========================================================================
  247. Session
  248. =========================================================================-->
  249. <session-config>
  250. <session-timeout>30</session-timeout>
  251. </session-config>
  252. </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
          Java代码
  253. <?xml version="1.0" encoding="UTF-8"?>
  254. <!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN"
  255. "http://www.springframework.org/dtd/spring-beans.dtd">
  256. <beans>
  257. <bean id="propertyConfigurer"
  258. class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  259. <property name="locations">
  260. <list>
  261. <value>/WEB-INF/jdbc.properties</value>
  262. </list>
  263. </property>
  264. </bean>
  265. <bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  266. <property name="driverClassName" value="${jdbc.driver}" />
  267. <property name="url" value="${jdbc.url}" />
  268. <property name="username" value="${jdbc.username}" />
  269. <property name="password" value="${jdbc.password}" />
  270. </bean>
  271. <bean id="sessionFactory"
  272. class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"  destroy-method="close">
  273. <property name="dataSource">
  274. <ref local="myDataSource" />
  275. </property>
  276. <property name="mappingResources">
  277. <list>
  278. <value> com/ssgly/model/Region.hbm.xml</value>
  279. </list>
  280. </property>
  281. <property name="hibernateProperties">
  282. <props>
  283. <prop key="connection.characterEncoding">utf-8</prop>
  284. <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
  285. <prop key="hibernate.jdbc.batch_size">50</prop>
  286. <prop key="hibernate.show_sql">true</prop>
  287. <prop key="hibernate.query.factory_class">org.hibernate.hql.classic.ClassicQueryTranslatorFactory</prop>
  288. </props>
  289. </property>
  290. </bean>
  291. <bean id="transactionManager"
  292. class="org.springframework.orm.hibernate3.HibernateTransactionManager">
  293. <property name="sessionFactory">
  294. <ref bean="sessionFactory"/>
  295. </property>
  296. </bean>
  297. <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
  298. <property name="sessionFactory"> <ref bean="sessionFactory"/> </property>
  299. </bean>
  300. <bean id="regionDao"  class="com.ssgly.dao.RegionDAOImpl">
  301. <property name="hibernateTemplate">
  302. <ref bean="hibernateTemplate"/>
  303. </property>
  304. </bean>
  305. <bean id="businessService" class="com.ssgly.business.impl.BusinessServiceImpl">
  306. <property name="regionDAO"><ref  bean="regionDao" /></property>
  307. </bean>
  308. <bean id="todoSsglyService"  class="com.ssgly.ext.ToDoImpl">
  309. <property name="businessServiceImpl">
  310. <ref bean="businessService"/>
  311. </property>
  312. </bean>
  313. </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
          Java代码
  314. <?xml version="1.0" encoding="utf-8"?>
  315. <!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN"
  316. "http://www.springframework.org/dtd/spring-beans.dtd">
  317. <beans>
  318. <!--============================================================================
  319. URL Mapping configuration
  320. =============================================================================-->
  321. <bean id="beanNameUrlMapping"
  322. class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
  323. <property name="alwaysUseFullPath" value="true" />
  324. </bean>
  325. <!--============================================================================
  326. Velocity configuration
  327. =============================================================================-->
  328. <bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
  329. <property name="contentType"><value>text/html;charset=GBK</value></property>
  330. </bean>
  331. <bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
  332. <property name="configLocation" value="/WEB-INF/velocity.properties" />
  333. <property name="resourceLoaderPath" value="/" />
  334. </bean>
  335. <bean id="treeRegionServlet"  name="/treeRegionServlet.do" class="com.ssgly.web.TreeRegionServlet">
  336. <property name="businessService">
  337. <ref bean="businessService"/>
  338. </property>
  339. </bean>
  340. </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能将三层很好地组合起来。以上是java部分。还没有讲到extJs。extJs可以接受asp、php、java等服务器端生成的json格式的对象。就java来说 ,extJs能接受三种方式的json对象,一是servlet中拼接json对象;其次是引用json lib 包;三是DWR方式,绕过Controller(就Spring来说)或servlet,在javascript中 直接调用java业务逻辑层中的方法(通过DWR引擎),利用dwr代理或者javascript 回调函数返回json对象并在页面展示。
       本人采用了第三种DWR方式实现ExtJs生成树。要使用dwr 就的要在以上几个配置文件中配置DWR(已配)。具体的下次再说吧。
       今天就写到这里吧。不知写的怎么样?有朋友关注这一块?若支持,请鼓励一下;写的不好、不对或不懂的地方,请拍砖。(续)

       抱歉啊,这几天忙着考驾照,把这事给耽搁啊。书接上回吧。
    【四】基于Spring方式的DWR配置说明。
    一、首先在WEB.xml中配置dwr拦截器 代码如下(节选):
          Java代码
  341. <!--配置DWR拦截器-->
  342. <servlet>
  343. <servlet-name>dwr-invoker</servlet-name>
  344. <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
  345. <init-param>
  346. <param-name>debug</param-name>
  347. <param-value>false</param-value>
  348. </init-param>
  349. <init-param>
  350. <param-name>classes</param-name>
  351. <param-value>java.lang.Object</param-value>
  352. </init-param>
  353. <load-on-startup>100</load-on-startup>
  354. </servlet>
  355. <servlet-mapping>
  356. <servlet-name>dwr-invoker</servlet-name>
  357. <url-pattern>/dwr/*</url-pattern>
  358. </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操作的对象。更直观的说法就是使得页面中javascript能直接使用java中对象的方法。代码如下:
          Java代码
  359. <?xml version="1.0" encoding="utf-8"?>
  360. <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN"
  361. "http://getahead.ltd.uk/dwr/dwr20.dtd">
  362. <dwr>
  363. <allow>
  364. <convert converter="bean"  match="com.ssgly.model.*"/>
  365. <convert converter="map" match="org.directwebremoting.convert.MapConverter"/>
  366. <create creator="spring" javascript="treeBusinessService">
  367. <param name="beanName" value="businessService"/>
  368. <include method="getAllChildren" />
  369. </create>
  370. </allow>
  371. </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维持的业务逻辑层定义的bean----- businessService。从而完成了DWR的功能。这里当然存在安全问题,在这里暂时没有讨论,关于如何在DWR中进行安全控制,大家可以参考有关文档。本文暂不考虑。
    【五】ext和服务器端交互的机制和具体实现
       一般说来,按照上面DWR的配置,就已经实现了在页面中使用java的方法。但java方法执行后生成的List 传回到页面还需要靠回调函数实现。例如下面代码就是包含了回调函数的测试页。
          Java代码
  372. <html>
  373. <head>
  374. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  375. <title>ExtJS-树示例</title>
  376. <link rel="stylesheet" type="text/css" href="ext2/resources/css/ext-all.css" />
  377. <script type="text/javascript" src="ext2/adapter/ext/ext-base.js"></script>
  378. <script type="text/javascript" src="ext2/ext-all.js"></script>
  379. <PRE class=java name="code"><script type="text/javascript" src="dwr/interface/treeBusinessService.js "></script>
  380. <script type="text/javascript" src="dwr/engine.js "></script>
  381. <script type="text/javascript" src="dwr/util.js "></script></PRE>
  382. <BR><script type="text/javascript">
  383. <BR>
  384. <BR>    treeBusinessService.getAllChildren(1,function(ret){
  385. <BR>                                     alert("一共有"+ret.length+"个子节点");
  386. <BR>                                   });
  387. <BR>
  388. <BR></script>
  389. <BR></head>
  390. <BR>
  391. <BR><body>
  392. <BR><div id="tree-div"></div>
  393. <BR></body>
  394. <BR></html>
  395. <BR>    <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>ExtJS-树示例</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>    Java代码
  396. <script type="text/javascript" src="dwr/interface/treeBusinessService.js "></script>
  397. <script type="text/javascript" src="dwr/engine.js "></script>
  398. <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+"个子节点");
                                    });

    </script>
    </head>

    <body>
    <div id="tree-div"></div>
    </body>
    </html>


    现在分析一下上面页面主要代码:

          Java代码
  399. <script type="text/javascript" src="dwr/interface/treeBusinessService.js "></script>
  400. <script type="text/javascript" src="dwr/interface/treeBusinessService.js "></script>  
    这句中的treeBusinessService就是DWR.xml中定义的       Java代码
  401. <create creator="spring" javascript="treeBusinessService">    <create creator="spring" javascript="treeBusinessService">

    下面两句是使用DWR所必需的,原样加上即可。
          Java代码
  402. <script type="text/javascript" src="dwr/engine.js "></script>
  403. <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的方法啦:
          Java代码
  404. <script type="text/javascript">
  405. treeBusinessService.getAllChildren(1,function(ret){
  406. alert("一共有"+ret.length+"个子节点");
  407. });
  408. </script>    <script type="text/javascript"> treeBusinessService.getAllChildren(1,function(ret){ alert("一共有"+ret.length+"个子节点"); }); </script>  
      function(ret)就是回调函数。因为treeBusinessService.getAllChildren执行的结果是List类型,DWR解析List到页面应该是javascript的对象数组,所以ret应该是个数组,ret.length是这个数组的长度。

      上面的例子只不过是原理性的介绍,帮助我们理解javascript如何和后台进行的交互。真正要实现DWRTree 还需要专门的DWRTreeLoader代理。下面这段代码很是重要,参考了ext官方bbs上的代码,并做了修改。先提供如下:
          Java代码
  409. Ext.tree.DWRTreeLoader = function(config) {
  410. Ext.tree.DWRTreeLoader.superclass.constructor.call(this, config);
  411. };
  412. Ext.extend(Ext.tree.DWRTreeLoader, Ext.tree.TreeLoader, {
  413. args:[],
  414. requestData : function(node, callback) {
  415. if (this.fireEvent("beforeload", this, node, callback) !== false) {
  416. var callParams = new Array();
  417. var success = this.handleResponse.createDelegate(this, [node, callback], 1);
  418. var error = this.handleFailure.createDelegate(this, [node, callback], 1);
  419. callParams.push(node.id);
  420. callParams.push({callback:success, errorHandler:error});
  421. //todo: do we need to set this to something else?
  422. this.transId=true;
  423. this.dataUrl.apply(this, callParams);
  424. } else {
  425. // if the load is cancelled, make sure we notify
  426. // the node that we are done
  427. if (typeof callback == "function") {
  428. //alert(callback);
  429. callback();
  430. }
  431. }
  432. },
  433. processResponse : function(response, node, callback){
  434. try {
  435. for(var i = 0; i < response.length; i++){
  436. var n = this.createNode(response[i]);
  437. if(n){
  438. node.appendChild(n);
  439. }
  440. }
  441. if(typeof callback == "function"){
  442. callback(this, node);
  443. }
  444. }catch(e){
  445. this.handleFailure(response);
  446. }
  447. },
  448. handleResponse : function(response, node, callback){
  449. this.transId = false;
  450. this.processResponse(response, node, callback);
  451. this.fireEvent("load", this, node, response);
  452. },
  453. handleFailure : function(response, node, callback){
  454. this.transId = false;
  455. this.fireEvent("loadexception", this, node, response);
  456. if(typeof callback == "function"){
  457. callback(this, node);
  458. }
  459. }
  460. });      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 done if (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); } } });  

    上面的代码可以直接在项目中使用,无需修改。
    【六】最终DWRTree的实现包括 tree.js和 tree.html
    tree.js完整代码如下:
          Java代码
  461. Ext.onReady(function(){
  462. Ext.tree.DWRTreeLoader = function(config) {
  463. Ext.tree.DWRTreeLoader.superclass.constructor.call(this, config);
  464. };
  465. Ext.extend(Ext.tree.DWRTreeLoader, Ext.tree.TreeLoader, {
  466. args:[],
  467. requestData : function(node, callback) {
  468. if (this.fireEvent("beforeload", this, node, callback) !== false) {
  469. var callParams = new Array();
  470. var success = this.handleResponse.createDelegate(this, [node, callback], 1);
  471. var error = this.handleFailure.createDelegate(this, [node, callback], 1);
  472. callParams.push(node.id);
  473. callParams.push({callback:success, errorHandler:error});
  474. //todo: do we need to set this to something else?
  475. this.transId=true;
  476. this.dataUrl.apply(this, callParams);
  477. } else {
  478. // if the load is cancelled, make sure we notify
  479. // the node that we are done
  480. if (typeof callback == "function") {
  481. //alert(callback);
  482. callback();
  483. }
  484. }
  485. },
  486. processResponse : function(response, node, callback){
  487. try {
  488. for(var i = 0; i < response.length; i++){
  489. var n = this.createNode(response[i]);
  490. if(n){
  491. node.appendChild(n);
  492. }
  493. }
  494. if(typeof callback == "function"){
  495. callback(this, node);
  496. }
  497. }catch(e){
  498. this.handleFailure(response);
  499. }
  500. },
  501. handleResponse : function(response, node, callback){
  502. this.transId = false;
  503. this.processResponse(response, node, callback);
  504. this.fireEvent("load", this, node, response);
  505. },
  506. handleFailure : function(response, node, callback){
  507. this.transId = false;
  508. this.fireEvent("loadexception", this, node, response);
  509. if(typeof callback == "function"){
  510. callback(this, node);
  511. }
  512. }
  513. });
  514. var myTree = new Ext.tree.TreePanel({
  515. el:Ext.getBody(),
  516. autoScroll:true,
  517. animate:true,
  518. width:'300px',
  519. height:'800px',
  520. enableDD:true,
  521. containerScroll: true,
  522. root:new Ext.tree.AsyncTreeNode({
  523. text: '单位',
  524. draggable:false,
  525. id:'1' }),
  526. loader:new Ext.tree.DWRTreeLoader({
  527. dataUrl:treeBusinessService.getAllChildren,
  528. listeners : {
  529. 'beforeload' : function( node) {
  530. myTree.getLoader().args[0]=(node.id!='root'?node.id:"1");
  531. }
  532. }
  533. })
  534. });
  535. myTree.render();
  536. });     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 done if (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(); });  
    提个醒:这句       Java代码
  537. myTree.getLoader().args[0]=(node.id!='root'?node.id:"1");     myTree.getLoader().args[0]=(node.id!='root'?node.id:"1"); 不能错哦,它是和 DWRTreeLoader耦合的。

    tree.html是这样的:
          Java代码
  538. <html>
  539. <head>
  540. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  541. <title>ExtJS-树示例</title>
  542. <link rel="stylesheet" type="text/css" href="ext2/resources/css/ext-all.css" />
  543. <script type="text/javascript" src="ext2/adapter/ext/ext-base.js"></script>
  544. <script type="text/javascript" src="ext2/ext-all.js"></script>
  545. <script type="text/javascript" src="dwr/interface/treeBusinessService.js "></script>
  546. <script type="text/javascript" src="dwr/engine.js "></script>
  547. <script type="text/javascript" src="dwr/util.js "></script>
  548. <script type="text/javascript" src="js/tree.js"></script>
  549. </head>
  550. <body>
  551. </body>
  552. </html>    <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>ExtJS-树示例</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的实现就是这样。

就是那个下拉树。。。
ComboTree

      Java代码

  1. Ext.QuickTips.init();
  2. var Artform = new Ext.form.FormPanel({
  3. labelAlign: 'right',
  4. labelWidth: 150,
  5. width: 600,
  6. frame: true,
  7. items: [{
  8. layout: 'column',
  9. items: [{
  10. width:580,
  11. xtype:'fieldset',
  12. title: '输入标题',
  13. autoHeight:true,
  14. defaults: {width: 300},
  15. defaultType: 'textfield',
  16. items: [{
  17. fieldLabel: '标题',
  18. name: 'title',
  19. id:'title',
  20. allowBlank:false,
  21. blankText:'标题不能为空'
  22. // value:'adfadsfasd'
  23. },{
  24. xtype:"combo",
  25. fieldLabel: '选择',
  26. name: 'combo',
  27. id:'combotree',
  28. store: new Ext.data.SimpleStore({fields:[],data:[[]]}),
  29. editable:false,//是否可编辑的表格
  30. selectClass:'',//适用于所有样式
  31. mode: 'local',   //本地数据
  32. triggerAction:'all',  //是否自动匹配
  33. autoHeight: true,
  34. tpl: "<tpl for='.'><div style='height:200px'><div id='tree'></div></div></tpl>",   //模板 循环
  35. emptyText:'请选择'
  36. }]
  37. }]
  38. },{
  39. layout: 'form',
  40. labelAlign: 'top',
  41. items: [{
  42. xtype: 'htmleditor',
  43. fieldLabel: '请输入文章内容',
  44. id: 'context',
  45. height:400,
  46. allowBlank:false,
  47. blankText:'内容不能为空',
  48. anchor: '98%'
  49. //   value:'adfadfasd'
  50. }]
  51. }] ,
  52. buttons: [{text: '保存',handler:add},
  53. {text: '取消'}]
  54. });
  55. var treedata = new Ext.tree.TreeLoader({
  56. url:'http://localhost:8080/pkm/register!queryChild.action'
  57. });
  58. var tree = new Ext.tree.TreePanel({
  59. loader:treedata,
  60. border:false,
  61. root:new Ext.tree.AsyncTreeNode({text:'目录结构',id:'1'})
  62. });
  63. tree.on('click',function(node){
  64. Artform.findById('combotree').value=node.id;//设置combo的键值
  65. Artform.findById('combotree').setRawValue(node.text);   //给combo设置显示的值
  66. Artform.findById('combotree').collapse();   //隐藏下拉列表中,如果它展开,这个属性将会完成数据的加载
  67. });
  68. Artform.findById('combotree').on('expand',function(){
  69. tree.render('tree');//ComboBox的tpl里的<div id='tree'>这个ID可以改成别的, 但必须要在'expand'事件里, 将树显示在这个div上
  70. });
  71. function add(){
  72. if(Artform.form.isValid()){
  73. //btn.disabled=true;//确认按钮有效默认为false
  74. Ext.MessageBox.show({
  75. msg: '正在请求数据, 请稍侯',
  76. progressText: '正在请求数据',
  77. width:300,
  78. wait:true,
  79. waitConfig: {interval:200}
  80. });//进度条显示
  81. Ext.Ajax.request({
  82. url:'http://localhost:8080/pkm/article!saveOrupdate.action',
  83. params:{
  84. title:Ext.getCmp('title').getValue(),
  85. context:Ext.getCmp('context').getValue(),
  86. type:Artform.findById('combotree').value
  87. },
  88. failure:function(){
  89. Ext.MessageBox.alert('友情提示',"异步通讯失败,请与管理员联系!");
  90. },
  91. success:function(request){
  92. Ext.MessageBox.hide();
  93. Ext.MessageBox.alert("友情提示","信息保存成功");
  94. }
  95. });
  96. }else{
  97. Ext.MessageBox.alert("信息","请填写完整");
  98. }
  99. }
  100. Artform.render("form");
  101. });        Ext.QuickTips.init(); var Artform = new Ext.form.FormPanel({ labelAlign: 'right', labelWidth: 150, width: 600, frame: true, items: [{ layout: 'column', items: [{ width:580, xtype:'fieldset', title: '输入标题', autoHeight:true, defaults: {width: 300}, defaultType: 'textfield', items: [{ fieldLabel: '标题', name: 'title', id:'title', allowBlank:false, blankText:'标题不能为空' // value:'adfadsfasd' },{ xtype:"combo", fieldLabel: '选择', name: 'combo', id:'combotree', store: new Ext.data.SimpleStore({fields:[],data:[[]]}), editable:false,//是否可编辑的表格 selectClass:'',//适用于所有样式 mode: 'local',   //本地数据 triggerAction:'all',  //是否自动匹配 autoHeight: true, tpl: "<tpl for='.'><div style='height:200px'><div id='tree'></div></div></tpl>",   //模板 循环 emptyText:'请选择' }] }] },{ layout: 'form', labelAlign: 'top', items: [{ xtype: 'htmleditor', fieldLabel: '请输入文章内容', id: 'context', height:400, allowBlank:false, blankText:'内容不能为空', anchor: '98%' //   value:'adfadfasd' }] }] , buttons: [{text: '保存',handler:add}, {text: '取消'}] }); var treedata = new Ext.tree.TreeLoader({ url:'http://localhost:8080/pkm/register!queryChild.action' }); var tree = new Ext.tree.TreePanel({ loader:treedata, border:false, root:new Ext.tree.AsyncTreeNode({text:'目录结构',id:'1'}) }); tree.on('click',function(node){ Artform.findById('combotree').value=node.id;//设置combo的键值 Artform.findById('combotree').setRawValue(node.text);   //给combo设置显示的值 Artform.findById('combotree').collapse();   //隐藏下拉列表中,如果它展开,这个属性将会完成数据的加载 }); Artform.findById('combotree').on('expand',function(){ tree.render('tree');//ComboBox的tpl里的<div id='tree'>这个ID可以改成别的, 但必须要在'expand'事件里, 将树显示在这个div上 }); function add(){ if(Artform.form.isValid()){ //btn.disabled=true;//确认按钮有效默认为false Ext.MessageBox.show({ msg: '正在请求数据, 请稍侯', progressText: '正在请求数据', width:300, wait:true, waitConfig: {interval:200} });//进度条显示 Ext.Ajax.request({ url:'http://localhost:8080/pkm/article!saveOrupdate.action', params:{ title:Ext.getCmp('title').getValue(), context:Ext.getCmp('context').getValue(), type:Artform.findById('combotree').value }, failure:function(){ Ext.MessageBox.alert('友情提示',"异步通讯失败,请与管理员联系!"); }, success:function(request){ Ext.MessageBox.hide(); Ext.MessageBox.alert("友情提示","信息保存成功"); } }); }else{ Ext.MessageBox.alert("信息","请填写完整"); } } Artform.render("form"); });




我这是一个form 里面生成的下拉树,单独测试的时候 其实可以用一个简单的comboBox 做的,我这里为了方便就直接把我的代码拿过来和大家分享下

其实上面的代码 最重要的就只有一个部分,下拉树写出来很简单,问题就是怎么能取到值给form 让它提交到后台,

      Java代码

  1. tree.on('click',function(node){
  2. Artform.findById('combotree').value=node.id;设置combo的键值
  3. Artform.findById('combotree').setRawValue(node.text);   //给combo设置显示的值
  4. Artform.findById('combotree').collapse();   //隐藏下拉列表中,如果它展开,这个属性将会完成数据的加载
  5. });       tree.on('click',function(node){ Artform.findById('combotree').value=node.id;设置combo的键值 Artform.findById('combotree').setRawValue(node.text);   //给combo设置显示的值 Artform.findById('combotree').collapse();   //隐藏下拉列表中,如果它展开,这个属性将会完成数据的加载 });



秘诀就在这里,这里能给你提交到后台什么的 ,什么父节点不能选择,根节点不能选择什么的,那个简单,你直接把你的树写好,就OK 在哪里判断 如有不对,请拍砖—-—!!

Read more

都用HTTPS了,还能被查出浏览记录?

都用HTTPS了,还能被查出浏览记录?

最近,群里一个刚入职的小伙因为用公司电脑访问奇怪的网站,被约谈了。他很困惑 —— 访问的都是HTTPS的网站,公司咋知道他访问了啥? 实际上,由于网络通信有很多层,即使加密通信,仍有很多途径暴露你的访问地址,比如: * DNS查询:通常DNS查询是不会加密的,所以,能看到你DNS查询的观察者(比如运营商)是可以推断出访问的网站 * IP地址:如果一个网站的IP地址是独一无二的,那么只需看到目标 IP地址,就能推断出用户正在访问哪个网站。当然,这种方式对于多网站共享同一个IP地址(比如CDN)的情况不好使 * 流量分析:当访问一些网站的特定页面,可能导致特定大小和顺序的数据包,这种模式可能被用来识别访问的网站 * cookies或其他存储:如果你的浏览器有某个网站的cookies,显然这代表你曾访问过该网站,其他存储信息(比如localStorage)同理 除此之外,还有很多方式可以直接、间接知道你的网站访问情况。 本文将聚焦在HTTPS协议本身,聊聊只考虑HTTPS协议的情况下,你的隐私是如何泄露的。 HTTPS简介 我们每天访问的网站大部分

By Ne0inhk
美团今年的校招薪资。。。

美团今年的校招薪资。。。

美团校招情况分析 老规矩了,校招薪资分析和建议,这次轮到美团。 先来看看和公众号读者相关性较高的岗位对应的校招待遇: 开发算法产品运营白菜18k~21k21k~24k18k~19k10k~14kSP22k~27k25k~30k20k~22k15k~16kSSP28k~32k31k~46k23k~25k17k~18k 以上所有岗位 * 15.5 即为年包收入。 部分岗位(例如算法的 SP 及以上)还会有签字费(一般为 55W)和股票(不定,最高去到 70w70w,分四年归属)。 虽然「大厂校招薪资」系列文章我们已经写到了第 55 篇了,但还是有同学会对一些概念比较模糊。 这一定程度上也反映了确实不少首次参与校招的同学会关注这个系列。 既然这个系列本就以帮助他们为初衷,那么有义务连带着对一些概念进行解释。 * base:每月的税前底薪; * 签字费:你可以理解成新员工的红包奖金,只有部分面试阶段特别优秀的人选或重要岗位会有。会在入职的时候的直接发放,只发放一次;

By Ne0inhk
3个小 bug,直接损失近千万

3个小 bug,直接损失近千万

0x0. 背景介绍 再过几天就是 1024 程序员节了,提前祝广大程序员工友们节日快乐,少写 bug,早点下班回家,不熬夜,尽量 delay 秃头的上线时间😭 上篇文章《因为月薪过高,我的工资发放失败了。。。》中,我分享了中行的骚操作导致我收不到工资的故事。简单的说,就是中行的码农老哥上线了一个 bug,误伤了普通用户,将正常的银行卡标记为风险账户导致入账失败。 这个 bug 看似没有带来实际损失,但是浪费了客户、客服、柜台人员的大量时间,这些都是成本。更重要的是,中行损失了潜在的高净值客户,某网友撰文吐槽此事,试图搞个大新闻,居然获得了几万的阅读。万一读者里有未来的首富,发誓不跟中行做生意,中行怎么也得损失几个小目标吧🐶。 作为码农,我们和 bug 的相处时间可能比另一半都多,毕竟咱们就是以写 bug 为生。写代码赚大钱的故事,大家见的多了,尤以逼乎和卖卖为甚。可能是大多数开发离钱太远,亦或是因为家丑不可外扬,

By Ne0inhk
为什么忘记密码时只能重设,不把旧密码告诉我?

为什么忘记密码时只能重设,不把旧密码告诉我?

某天小明在整理他的收藏夹时发现了一个以前很常逛,但已经将近半年多没去的一个论坛。小明想回去看看那边变得怎么样了,于是点进去那个论坛,输入了帐号密码,得到了密码错误的提示。 尝试了几次之后,系统提示小明可以使用「忘记密码」的功能,所以小明填了自己的 email 之后去收件箱里查看,发现系统传来一个「重设密码」的链接。虽然说最后小明成功利用重新设定的密码登入,但有个问题让他百思不得其解: 奇怪呀,为啥要我重新设置密码,把旧的密码发到邮箱里给我不就好了? 应该有许多人都跟小明一样,有过类似的疑惑。把旧密码发给我不是很好吗,干嘛强迫我换密码? 这一个看似简单的问题,背后其实藏了许多信息安全相关的概念,就让我们慢慢寻找问题的答案,顺便学习一些基本的信息安全知识吧! 被偷走的数据库 大家应该很常看到新闻说哪个网站的数据又被偷走了,顾客个人数据全部都泄露出去。像是国外知名的网域代管网站 GoDaddy[1] 就泄露了 120 万笔用户数据,像国内的微博、淘宝等也有过数据泄露的情况发生。 这边我想带大家探讨的两个问题是: 1. 数据真的这么容易泄露吗? 1. 数据泄露之

By Ne0inhk