myBatis3,spring3,struts2.2整合
2011-08-04 08:47
387 查看
开发环境: System:Windows WebBrowser:IE6+、Firefox3+ JavaEEServer:tomcat5.0.2.8、tomcat6 IDE:eclipse、MyEclipse8 Database:MySQL 开发依赖库: JavaEE5、Spring3.0.5、Mybatis3.0.4、myBatis-spring-1.0、Struts2.2.3、junit4.8.2、ext2.2.2 Email: Blog: 上次介绍过Spring3、SpringMVC、MyBatis3整合,在线博文: 一、准备工作 1、下载jar包 Struts2jar下载: Spring3jar下载: MyBatis3jar下载: 2、添加的jar包如下: 二、Spring、MyBatis整合 1、需要的jar文件如下: 2、在src目录中加入mybatis.xml,内容如下: <?xmlversion="1.0"encoding="UTF-8"?> <!DOCTYPEconfigurationPUBLIC"-//mybatis.org//DTDConfig3.0//EN"" <configuration> <!--别名--> <typeAliases> <typeAliastype="com.hoo.entity.Account"alias="account"/> </typeAliases> </configuration> 上面的配置文件中,可以加入一些公共、常用的MyBatis方面的全局配置。如handler、objectFactory、plugin、以及mappers的映射路径(由于在applicationContext-common中的SqlSessionFactoryBean有配置mapper的location,这里就不需要配置)等。这个类的文件名称和下面的applicationContext-common.xml中的configLocation中的值对应,不是随便写的。 3、在src目录中添加applicationContext-common.xml中加入内容如下: <?xmlversion="1.0"encoding="UTF-8"?> <beansxmlns=" xmlns:aop=" xmlns:tx=" xmlns:xsi=" xsi:schemaLocation=" <!--配置DataSource数据源--> <beanid="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <propertyname="driverClassName"value="com.mysql.jdbc.Driver"/> <propertyname="url"value="jdbc:mysql://10.0.0.131:3306/ash2"/> <propertyname="username"value="dev"/> <propertyname="password"value="dev"/> </bean> <!--配置SqlSessionFactoryBean--> <beanid="sqlSessionFactory"class="org.mybatis.spring.SqlSessionFactoryBean"> <propertyname="dataSource"ref="dataSource"/> <propertyname="configLocation"value="classpath:mybatis.xml"/> <!--mapper和resultmap配置路径--> <propertyname="mapperLocations"> <list> <!--表示在com.hoo.resultmap包或以下所有目录中,以-resultmap.xml结尾所有文件--> <value>classpath:com/hoo/resultmap/**/*-resultmap.xml</value> <value>classpath:com/hoo/entity/*-resultmap.xml</value> <value>classpath:com/hoo/mapper/**/*-mapper.xml</value> </list> </property> </bean> <!--配置事务管理器,注意这里的dataSource和SqlSessionFactoryBean的dataSource要一致,不然事务就没有作用了--> <beanid="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <propertyname="dataSource"ref="dataSource"/> </bean> <!--配置事务的传播特性--> <beanid="baseTransactionProxy"class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"abstract="true"> <propertyname="transactionManager"ref="transactionManager"/> <propertyname="transactionAttributes"> <props> <propkey="add*">PROPAGATION_REQUIRED</prop> <propkey="edit*">PROPAGATION_REQUIRED</prop> <propkey="remove*">PROPAGATION_REQUIRED</prop> <propkey="insert*">PROPAGATION_REQUIRED</prop> <propkey="update*">PROPAGATION_REQUIRED</prop> <propkey="del*">PROPAGATION_REQUIRED</prop> <propkey="*">readOnly</prop> </props> </property> </bean> <!--通过扫描的模式,扫描目录在com/hoo/mapper目录下,所有的mapper都继承SqlMapper接口的接口,这样一个bean就可以了--> <beanclass="org.mybatis.spring.mapper.MapperScannerConfigurer"> <propertyname="basePackage"value="com.hoo.mapper"/> <propertyname="markerInterface"value="com.hoo.mapper.SqlMapper"/> </bean> </beans> DataSource,这里的是采用jdbc的dataSource; SqlSessionFactory,是MyBatis团队提供整合Spring的SqlSession工厂Bean用它可以完成Spring和MyBatis的整合。SqlSessionFactoryBean需要注入DataSource,配置myBatis配置文件的location,以及配置mapper.xml和resultMap.xml文件的路径,可以用通配符模式配置。其实mapper里面是可以存放resultMap的内容的。由于resultMap文件的内容是和JavaBean及数据库表对象进行映射的。一般一张表、一个JavaBean(Model)对应一个resultMap文件。将resultMap独立出来提供可读性、维护性。 TransactionManager,事务管理器是采用jdbc的管理器。需要注入DataSource数据源,这里注入的数据源和SqlSessionFactory是同一个数据源。如果不同的数据源,事务将无法起到作用。 baseTransactionProxy,事务的传播特性才有spring提供的TransactionProxyFactoryBean这个事务代理工厂的拦截器类来完成。其他的暂时还没有可以支持事务配置的传播特性和隔离级别的方法,关于这里你可以参考: MapperScannerConfigurer是MyBatis的mapper接口的扫描器,通过这个配置可以完成对指定basePackage报下的类进行扫描,如果这些类有继承SqlMapper这个类的,将会是MyBatis的接口。不需要单独配置mapper,而完成注入。 4、在src目录添加applicationContext-beans.xml这个文件,文件内容如下: <?xmlversion="1.0"encoding="UTF-8"?> <beansxmlns=" xmlns:context=" xmlns:xsi=" xsi:schemaLocation=" <!--注解探测器--> <context:component-scanbase-package="com.hoo"/> </beans> 这里面可以完成一下Action、Bean的注入配置 5、JavaBean(Model、Entity)相关类、及resultMap.xml文件内容 Bean packagecom.hoo.entity; importjava.io.Serializable; importjava.util.Date; publicclassAccountimplementsSerializable{ privatestaticfinallongserialVersionUID=-7970848646314840509L; privateIntegeraccountId; privateStringusername; privateStringpassword; privateDatecreateTime; publicAccount(){ super(); } //getter、setter @Override publicStringtoString(){ returnthis.accountId+"#"+this.username+"#"+this.password+"#"+this.createTime; } } account-resultMap.xml <?xmlversion="1.0"encoding="UTF-8"?> <!DOCTYPEmapperPUBLIC"-//mybatis.org//DTDMapper3.0//EN" " <mappernamespace="accountMap"> <resultMaptype="com.hoo.entity.Account"id="accountResultMap"> <idproperty="accountId"column="account_id"/> <resultproperty="username"column="username"/> <resultproperty="password"column="password"/> <resultproperty="createTime"column="create_time"/> </resultMap> </mapper> resultMap的type属性和对应的classpath对应,id会在mapper.xml文件中用到。下面的属性property是JavaBean的属性,column和数据库的字段对应。 6、上面的applicationContext-common.xml中配置了SqlMapper,下面是SqlMapper代码,就一个空接口 packagecom.hoo.mapper; /** *<b>function:</b>所有的Mapper继承这个接口 *@authorhoojo *@createDate2011-4-12下午04:00:31 *@fileSqlMapper.java *@packagecom.hoo.mapper *@projectMyBatisForSpring *@blog *@version1.0 */ publicinterfaceSqlMapper{ } 7、定制我们自己的增删改查(CRUD)组件,接口如下 packagecom.hoo.mapper; importjava.util.List; importorg.springframework.dao.DataAccessException; /** *<b>function:</b>BaseSqlMapper继承SqlMapper,对Mapper进行接口封装,提供常用的增删改查组件; *也可以对该接口进行扩展和封装 *@authorhoojo *@createDate2011-4-14上午11:36:41 *@fileBaseSqlMapper.java *@packagecom.hoo.mapper *@projectMyBatisForSpring *@blog *@version1.0 */ publicinterfaceBaseSqlMapper<T>extendsSqlMapper{ publicvoidadd(Tentity)throwsDataAccessException; publicvoidedit(Tentity)throwsDataAccessException; publicvoidremvoe(Tentity)throwsDataAccessException; publicTget(Tentity)throwsDataAccessException; publicList<T>getList(Tentity)throwsDataAccessException; } 当然实际开发中,增删改查组件一定不止这几个方法。这里只是随便挪列几个方法做一个示例。实际中可以根据需求进行添加方法,这里添加的方法可以用一个mapper.xml进行实现,然后注入这个mapper即可完成操作。也可以定义其他的mapper,如AccountMapper继承这个接口。然后为AccountMapper提供实现也是可以的。 8、下面看看AccountMapper接口 packagecom.hoo.mapper; importjava.util.List; importcom.hoo.entity.Account; /** *<b>function:</b>继承SqlMapper,MyBatis数据操作接口;此接口无需实现类 *@authorhoojo *@createDate2010-12-21下午05:21:20 *@fileAccountMapper.java *@packagecom.hoo.mapper *@projectMyBatis *@blog *@version1.0 */ publicinterfaceAccountMapper<TextendsAccount>extendsBaseSqlMapper<T>{ publicList<T>getAllAccount(); } 上面的AccountMapper继承了BaseSqlMapper,并且提供了自己所需要的方法。下面实现这个Mapper中和父接口的方法。 account-mapper.xml <?xmlversion="1.0"encoding="UTF-8"?> <!DOCTYPEmapperPUBLIC"-//mybatis.org//DTDMapper3.0//EN" " <!--namespace和定义的Mapper接口对应,并实现其中的方法--> <mappernamespace="com.hoo.mapper.AccountMapper"> <selectid="getList"parameterType="com.hoo.entity.Account"resultType="list"resultMap="accountResultMap"> select*fromaccountwhereusernamelike'%'#{username}'%' </select> <selectid="getAllAccount"resultType="list"resultMap="accountResultMap"> select*fromaccount </select> <!--accountResultMap是account-resultmap.xml中定义的resultmap--> <selectid="get"parameterType="account"resultType="com.hoo.entity.Account"resultMap="accountResultMap"> <![CDATA[ select*fromaccountwhereaccount_id=#{accountId} ]]> </select> <!--自动生成id策略--> <insertid="add"useGeneratedKeys="true"keyProperty="account_id"parameterType="account"> insertintoaccount(account_id,username,password) values(#{accountId},#{username},#{password}) </insert> <updateid="edit"parameterType="account"> updateaccountset username=#{username}, password=#{password} whereaccount_id=#{accountId} </update> <deleteid="remove"parameterType="account"> deletefromaccountwhereaccount_id=#{accountId} </delete> </mapper> mapper的namespace和接口的classpath对应,里面的sql语句的id和方法名称对应。这样就完成了AccountMapper的实现。 9、下面来测试下AccountMapper的功能,代码如下: packagecom.hoo.mapper; importjava.util.List; importjavax.inject.Inject; importorg.springframework.test.context.ContextConfiguration; importorg.springframework.test.context.junit38.AbstractJUnit38SpringContextTests; importcom.hoo.entity.Account; /** *<b>function:</b>AccountMapperJUnit测试类 *@authorhoojo *@createDate2011-4-12下午04:21:50 *@fileAccountMapperTest.java *@packagecom.hoo.mapper *@projectMyBatisForSpring *@blog *@version1.0 */ @ContextConfiguration("classpath:applicationContext-*.xml") publicclassAccountMapperTestextendsAbstractJUnit38SpringContextTests{ @Inject privateAccountMapper<Account>mapper; publicvoidtestGetAccount(){ Accountacc=newAccount(); acc.setAccountId(28); System.out.println(mapper.get(acc)); } publicvoidtestAdd(){ Accountaccount=newAccount(); account.setUsername(" account.setPassword("abc"); mapper.add(account); } publicvoidtestEditAccount(){ Accountacc=newAccount(); acc.setAccountId(28); acc=mapper.get(acc); System.out.println(acc); acc.setUsername("Zhangsan22"); acc.setPassword("123123"); mapper.edit(acc); System.out.println(mapper.get(acc)); } publicvoidtestRemoveAccount(){ Accountacc=newAccount(); acc.setAccountId(28); mapper.remvoe(acc); System.out.println(mapper.get(acc)); } publicvoidtestAccountList(){ List<Account>acc=mapper.getAllAccount(); System.out.println(acc.size()); System.out.println(acc); } publicvoidtestList(){ Accountacc=newAccount(); acc.setUsername("@qq.com"); List<Account>list=mapper.getList(acc); System.out.println(list.size()); System.out.println(list); } } 运行上面的方法,没有错误基本上就算完成了Mapper的功能了。 10、下面来写一个数据库操作的基类Dao,代码如下: packagecom.hoo.dao; importjava.util.List; importcom.hoo.mapper.BaseSqlMapper; /** *<b>function:</b> *@authorhoojo *@createDate2011-4-14上午11:30:09 *@fileBaseMapperDao.java *@packagecom.hoo.dao *@projectMyBatisForSpring *@blog *@version1.0 */ publicinterfaceBaseMapperDao<T>{ @SuppressWarnings("unchecked") publicvoidsetMapperClass(Class<?extendsBaseSqlMapper>mapperClass); publicBaseSqlMapper<T>getMapper(); publicbooleanadd(Tentity)throwsException; publicbooleanedit(Tentity)throwsException; publicbooleanremove(Tentity)throwsException; publicTget(Tentity)throwsException; publicList<T>getAll(Tentity)throwsException; } 这个Dao定义了BaseSqlMapper中的方法,还提供了一个setMapperClass的方法。目的是在使用这个dao的时候,需要设置一个Mapper的class。且这个Mapper必须要是BaseSqlMapper或它的子类。所有的dao都可以用BaseMapperDao来完成CRUD操作即可,当BaseMapperDao的方法不够用的情况下,可以在接口中提供SqlSession、SqlSessionTemplate方法,让底层人员自己扩展所需要的方法。这里的dao和mapper好像有点冗余,因为dao和mapper完成的功能都是类似或是相同的。但是你可以在dao中,同时调用不同的mapper,来完成当前模块的dao所需要的功能。 11、看看BaseMapperDao的实现代码 packagecom.hoo.dao.impl; importjava.util.List; importjavax.inject.Inject; importorg.apache.ibatis.session.SqlSessionFactory; importorg.mybatis.spring.SqlSessionTemplate; importorg.springframework.stereotype.Repository; importcom.hoo.dao.BaseMapperDao; importcom.hoo.mapper.BaseSqlMapper; /** *<b>function:</b>运用SqlSessionTemplate封装Dao常用增删改方法,可以进行扩展 *@authorhoojo *@createDate2011-4-14下午12:22:07 *@fileBaseMapperDaoImpl.java *@packagecom.hoo.dao.impl *@projectMyBatisForSpring *@blog *@version1.0 */ @SuppressWarnings("unchecked") @Repository publicclassBaseMapperDaoImpl<T>extendsSqlSessionTemplateimplementsBaseMapperDao<T>{ @Inject publicBaseMapperDaoImpl(SqlSessionFactorysqlSessionFactory){ super(sqlSessionFactory); } privateClass<?extendsBaseSqlMapper>mapperClass; publicvoidsetMapperClass(Class<?extendsBaseSqlMapper>mapperClass){ this.mapperClass=mapperClass; } publicBaseSqlMapper<T>getMapper(){ returnthis.getMapper(mapperClass); } publicbooleanadd(Tentity)throwsException{ booleanflag=false; try{ this.getMapper().add(entity); flag=true; }catch(Exceptione){ flag=false; throwe; } returnflag; } publicbooleanedit(Tentity)throwsException{ booleanflag=false; try{ this.getMapper().edit(entity); flag=true; }catch(Exceptione){ flag=false; throwe; } returnflag; } publicTget(Tentity)throwsException{ returnthis.getMapper().get(entity); } publicList<T>getAll()throwsException{ returnthis.getMapper().getList(null); } publicbooleanremove(Tentity)throwsException{ booleanflag=false; try{ this.getMapper().remvoe(entity); flag=true; }catch(Exceptione){ flag=false; throwe; } returnflag; } } 这个实现类继承了SqlSessionTemplate,并且要注入SqlSessionFactory。提供的setMapperClass方法需要设置其BaseSqlMapper或它的子类。 好了,至此基本的CRUD的mapper和dao就算完成了。现在我们可以定义我们自己的业务模块,调用公共组件来完成增删改查操作。 12、下面测试下这个BaseMapperDao功能 packagecom.hoo.dao; importjavax.inject.Inject; importorg.junit.Before; importorg.springframework.test.context.ContextConfiguration; importorg.springframework.test.context.junit38.AbstractJUnit38SpringContextTests; importcom.hoo.entity.Account; importcom.hoo.mapper.AccountMapper; /** *<b>function:</b> *@authorhoojo *@createDate2011-4-14下午01:08:49 *@fileBaseMapperDaoImplTest.java *@packagecom.hoo.dao *@projectMyBatisForSpring *@blog *@version1.0 */ @ContextConfiguration("classpath:applicationContext-*.xml") publicclassBaseMapperDaoImplTestextendsAbstractJUnit38SpringContextTests{ @Inject privateBaseMapperDao<Account>dao; @Before publicvoidinit(){ System.out.println(dao); dao.setMapperClass(AccountMapper.class); } publicvoidtestGet()throwsException{ init(); Accountacc=newAccount(); acc.setAccountId(28); System.out.println(dao.get(acc)); } publicvoidtestAdd()throwsException{ init(); Accountaccount=newAccount(); account.setUsername(" account.setPassword("abc"); System.out.println(dao.add(account)); } } 13、下面定义AccountDao接口 packagecom.hoo.dao; importjava.util.List; importorg.springframework.dao.DataAccessException; /** *<b>function:</b>Account数据库操作dao接口 *@authorhoojo *@createDate2011-4-13上午10:21:38 *@fileAccountDao.java *@packagecom.hoo.dao *@projectMyBatisForSpring *@blog *@version1.0 */ publicinterfaceAccountDao<T>{ /** *<b>function:</b>添加Account对象信息 *@authorhoojo *@createDate2011-4-13上午11:50:05 *@paramentityAccount *@returnboolean是否成功 *@throwsDataAccessException */ publicbooleanaddAccount(Tentity)throwsDataAccessException; /** *<b>function:</b>根据id对到Account信息 *@authorhoojo *@createDate2011-4-13上午11:50:45 *@paramid编号id *@returnAccount *@throwsDataAccessException */ publicTgetAccount(Integerid)throwsDataAccessException; /** *<b>function:</b>查询所有Account信息 *@authorhoojo *@createDate2011-4-13上午11:51:45 *@paramid编号id *@returnAccount *@throwsDataAccessException */ publicList<T>getList()throwsDataAccessException; } 14、AccountDao实现类 packagecom.hoo.dao.impl; importjava.util.List; importjavax.inject.Inject; importorg.springframework.dao.DataAccessException; importorg.springframework.stereotype.Repository; importcom.hoo.dao.AccountDao; importcom.hoo.dao.BaseMapperDao; importcom.hoo.entity.Account; importcom.hoo.mapper.AccountMapper; /** *<b>function:</b>Account数据库操作dao *@authorhoojo *@createDate2011-4-13上午10:25:02 *@fileAccountDaoImpl.java *@packagecom.hoo.dao.impl *@projectMyBatisForSpring *@blog *@version1.0 */ @SuppressWarnings("unchecked") @Repository publicclassAccountDaoImpl<TextendsAccount>implementsAccountDao<T>{ @Inject privateBaseMapperDao<Account>dao; publicbooleanaddAccount(Tentity)throwsDataAccessException{ dao.setMapperClass(AccountMapper.class); booleanflag=false; try{ dao.add(entity); flag=true; }catch(DataAccessExceptione){ flag=false; throwe; }catch(Exceptione){ thrownewRuntimeException(e); } returnflag; } publicTgetAccount(Integerid)throwsDataAccessException{ dao.setMapperClass(AccountMapper.class); Accountacc=newAccount(); Tentity=null; try{ acc.setAccountId(id); entity=(T)dao.get(acc); }catch(DataAccessExceptione){ throwe; }catch(Exceptione){ thrownewRuntimeException(e); } returnentity; } publicList<T>getList()throwsDataAccessException{ dao.setMapperClass(AccountMapper.class); List<T>list=null; try{ list=(List<T>)((AccountMapper)dao.getMapper()).getAllAcount(); }catch(DataAccessExceptione){ throwe; }catch(Exceptione){ thrownewRuntimeException(e); } returnlist; } } 注意,上面的方法都设置了MapperClass,表示当前dao的Mapper是AccountMapper对象。所有的mapper方法都是调用AccountMapper这个对象中的方法。 15、下面定义服务器层接口 packagecom.hoo.biz; importjava.util.List; importorg.springframework.dao.DataAccessException; /** *<b>function:</b>biz层Account接口 *@authorhoojo *@createDate2011-4-13上午11:33:04 *@fileAccountBiz.java *@packagecom.hoo.biz *@projectMyBatisForSpring *@blog *@version1.0 */ publicinterfaceAccountBiz<T>{ /** *<b>function:</b>添加Account对象信息 *@authorhoojo *@createDate2011-4-13上午11:50:05 *@paramentityAccount *@returnboolean是否成功 *@throwsDataAccessException */ publicbooleanaddAccount(Tentity)throwsDataAccessException; publicbooleanexecute(Tentity)throwsDataAccessException; /** *<b>function:</b>根据id对到Account信息 *@authorhoojo *@createDate2011-4-13上午11:50:45 *@paramid编号id *@returnAccount *@throwsDataAccessException */ publicTgetAccount(Integerid)throwsDataAccessException; /** *<b>function:</b>查询所有Account信息 *@authorhoojo *@createDate2011-4-13上午11:51:45 *@paramid编号id *@returnAccount *@throwsDataAccessException */ publicList<T>getList()throwsDataAccessException; } 16、AccountBiz的实现代码 packagecom.hoo.biz.impl; importjava.util.List; importjavax.inject.Inject; importorg.springframework.dao.DataAccessException; importorg.springframework.stereotype.Component; importcom.hoo.biz.AccountBiz; importcom.hoo.dao.AccountDao; importcom.hoo.entity.Account; importcom.hoo.exception.BizException; /** *<b>function:</b>AccountBiz接口实现 *@authorhoojo *@createDate2011-4-13上午11:34:39 *@fileAccountBizImpl.java *@packagecom.hoo.biz.impl *@projectMyBatisForSpring *@blog *@version1.0 */ //@Component @Service publicclassAccountBizImpl<TextendsAccount>implementsAccountBiz<T>{ @Inject privateAccountDao<T>dao; publicbooleanaddAccount(Tentity)throwsDataAccessException{ if(entity==null){ thrownewBizException(Account.class.getName()+"对象参数信息为Empty!"); } returndao.addAccount(entity); } publicTgetAccount(Integerid)throwsDataAccessException{ returndao.getAccount(id); } publicList<T>getList()throwsDataAccessException{ returndao.getList(); } publicbooleanexecute(Tentity)throwsDataAccessException{ if(entity==null){ thrownewBizException(Account.class.getName()+"对象参数信息为Empty!"); } returndao.addAccount(entity); } } 直接注入AccountDao完成相关操作即可 17、如果你需要在业务层设置事务传播特性,需要在applicationContext-bean.xml中加入配置如下: <!--为AccountBiz接口配置事务拦截器,baseTransactionProxy是事务拦截器,在Action中获取这个对象--> <beanid="accountBiz"parent="baseTransactionProxy"> <!--设置target,也就是AccountBiz的实现类--> <propertyname="target"ref="accountBizImpl"/> </bean> 这样在Action中注入accountBiz这个对象后,那么当这个对象出现DataAccessException异常的时候,就会自动回滚事务。 至此,Spring和MyBatis的整合就完成了。 作者:hoojo 出处: blog: |
三、加入Struts2框架
1、准备工作添加jar文件如下:
org.springframework.web-3.0.5.RELEASE.jar
org.springframework.aop-3.0.5.RELEASE.jar
这2个jar包是spring的context所依赖的jar包
struts2-spring-plugin-2.2.3.jar是struts整合spring的jar包
2、在web.xml加入struts2的控制器
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3、在src目录添加struts.xml
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEstrutsPUBLIC
"-//ApacheSoftwareFoundation//DTDStrutsConfiguration2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constantname="struts.i18n.encoding"value="UTF-8"/>
<packagename="ssMyBatis"extends="struts-default">
</package>
</struts>
启动后,可以看到首页index的页面就基本整合完成。
4、首先看看Action代码,代码如下:
packagecom.hoo.action;
importjava.util.ArrayList;
importjava.util.List;
importjavax.inject.Inject;
importjavax.inject.Named;
importorg.springframework.stereotype.Component;
importcom.hoo.biz.AccountBiz;
importcom.hoo.entity.Account;
importcom.opensymphony.xwork2.ActionSupport;
/**
*<b>function:</b>AccountAction
*@authorhoojo
*@createDate2011-5-11下午12:03:05
*@fileAccountAction.java
*@packagecom.hoo.action
*@projectS2SMyBatis
*@blog'target='_blank'>http://blog.csdn.net/IBM_hoojo[/code] *@emailhoojo_@126.com*@version1.0*/@ComponentpublicclassAccountActionextendsActionSupport{/***@authorHoojo*/privatestaticfinallongserialVersionUID=-973535478139284399L;@Inject@Named("accountBiz")privateAccountBiz<Account>biz;privateAccountacc;privateList<Account>results=newArrayList<Account>();publicList<Account>getResults(){returnresults;}publicAccountgetAcc(){returnacc;}publicvoidsetAcc(Accountacc){this.acc=acc;}publicStringadd()throwsException{if(!biz.addAccount(acc)){this.addActionMessage("添加数据失败");returnERROR;}returnSUCCESS;}publicStringshow()throwsException{results=biz.getList();return"show";}publicStringremove()throwsException{returnSUCCESS;}publicStringedit()throwsException{returnSUCCESS;}publicStringtreeData()throwsException{results=biz.getList();return"tree";}}
这个Action被注解成Component,那么在spring的applicationContext配置文件中就不需要进行<bean/>标签的配置了。上面注入了AccountDao,完成相关操作。
5、由于Struts2要和Spring进行整合,所以struts的配置会有点不同<actionname="account"class="accountAction"><resulttype="redirect">account!show.action</result><resultname="show">/show.jsp</result></action>
上面的class不再是AccountAction的classpath,而是spring容器中配置的bean。就是通过@Component注解过的AccountAction,被注解注释过后它的id默认是类名称首字母小写。所以上面的action的配置是accountAction。
6、由于要整合ExtJS,所以这里用到struts2-json-plugin-2.2.3.jar这个插件,将其加入到lib库中,struts.xml更改成:<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEstrutsPUBLIC"-//ApacheSoftwareFoundation//DTDStrutsConfiguration2.0//EN""http://struts.apache.org/dtds/struts-2.0.dtd"><struts><constantname="struts.i18n.encoding"value="UTF-8"/><packagename="ssMyBatis"extends="json-default"><global-results><resultname="error">/error.jsp</result></global-results><actionname="account"class="accountAction"><resulttype="redirect">account!show.action</result><resultname="show">/show.jsp</result><resultname="tree"type="json"><paramname="excludeProperties">acc</param></result></action></package></struts>
AccountAction中的treeData方法返回的tree,在account这个action配置中找到tree的result,将result的type配置成json。表示该result的数据以json的方式展示。tree这个result还配置了一个param,名称为excludeProperties表示排除的属性。这个参数将排除当前Action中的acc属性。也就是说这个属性将不会得到json的转换。其他属性将会被转换成json。
7、前台页面
index.jsp<body><ahref="account!show.action">显示所有</a><br><ahref="add.jsp">添加数据</a><br/><ahref="account!treeData.action">JSON</a><br/></body>
show.jsp<%@pagelanguage="java"import="java.util.*"pageEncoding="UTF-8"%><%@taglibprefix="s"uri="/struts-tags"%><%Stringpath=request.getContextPath();StringbasePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.01Transitional//EN"><html><head><basehref="<%=basePath%>"><title>showalldata</title><metahttp-equiv="pragma"content="no-cache"><metahttp-equiv="cache-control"content="no-cache"><metahttp-equiv="expires"content="0"></head><body><s:iteratorvalue="results"status="s"var="data">${data}<===><s:propertyvalue="#data.accountId"/>#<s:propertyvalue="#data.username"/>#<s:propertyvalue="#data.password"/>#<s:propertyvalue="#data.createTime"/>#<s:datename="#data.createTime"format="yyyy-MM-dd"/>#<ahref="account!remove.action">删除</a>|<ahref="account!edit.action">修改</a><br/></s:iterator></body></html>
Struts标签和OGNL表达式显示数据
add.jsp<%@pagelanguage="java"import="java.util.*"pageEncoding="UTF-8"%><%@taglibprefix="s"uri="/struts-tags"%><%Stringpath=request.getContextPath();StringbasePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.01Transitional//EN"><html><head><basehref="<%=basePath%>"><title>add</title><metahttp-equiv="pragma"content="no-cache"><metahttp-equiv="cache-control"content="no-cache"><metahttp-equiv="expires"content="0"></head><body><s:formaction="account!add.action"method="post"><s:textfieldname="acc.username"/><s:passwordname="acc.password"/><s:submitvalue="提交"></s:submit></s:form></body></html>四、整合ExtJS
1、添加ext的库,版本是2.2.2
需要添加column-tree.css/**ExtJSLibrary2.2.1*Copyright(c)2006-2009,ExtJS,LLC.*licensing@extjs.com**'target='_blank'>http://extjs.com/license[/code] */.x-column-tree.x-tree-node{zoom:1;}.x-column-tree.x-tree-node-el{/*border-bottom:1pxsolid#eee;borders?*/zoom:1;}.x-column-tree.x-tree-selected{background:#d9e8fb;}.x-column-tree.x-tree-nodea{line-height:18px;vertical-align:middle;}.x-column-tree.x-tree-nodeaspan{}.x-column-tree.x-tree-node.x-tree-selectedaspan{background:transparent;color:#000;}.x-tree-col{float:left;overflow:hidden;padding:01px;zoom:1;}.x-tree-col-text,.x-tree-hd-text{overflow:hidden;-o-text-overflow:ellipsis;text-overflow:ellipsis;padding:3px3px3px5px;white-space:nowrap;font:normal11pxarial,tahoma,helvetica,sans-serif;}.x-tree-headers{background:#f9f9f9url(../ext2/resources/images/default/grid/grid3-hrow.gif)repeat-x0bottom;cursor:default;zoom:1;}.x-tree-hd{float:left;overflow:hidden;border-left:1pxsolid#eee;border-right:1pxsolid#d0d0d0;}.task{background-image:url(../shared/icons/fam/cog.png)!important;}.task-folder{background-image:url(../shared/icons/fam/folder_go.png)!important;}
Ext.tree.ColumnTree.js/**ExtJSLibrary2.2.1*Copyright(c)2006-2009,ExtJS,LLC.*licensing@extjs.com**'target='_blank'>http://extjs.com/license[/code] */Ext.tree.ColumnTree=Ext.extend(Ext.tree.TreePanel,{lines:false,borderWidth:Ext.isBorderBox?0:2,//thecombinedleft/rightborderforeachcellcls:'x-column-tree',onRender:function(){Ext.tree.ColumnTree.superclass.onRender.apply(this,arguments);this.headers=this.body.createChild({cls:'x-tree-headers'},this.innerCt.dom);varcols=this.columns,c;vartotalWidth=0;for(vari=0,len=cols.length;i<len;i++){c=cols[i];totalWidth+=c.width;this.headers.createChild({cls:'x-tree-hd'+(c.cls?c.cls+'-hd':''),cn:{cls:'x-tree-hd-text',html:c.header},style:'width:'+(c.width-this.borderWidth)+'px;'});}this.headers.createChild({cls:'x-clear'});//preventfloatsfromwrappingwhenclippedthis.headers.setWidth(totalWidth);this.innerCt.setWidth(totalWidth);}});Ext.tree.ColumnNodeUI=Ext.extend(Ext.tree.TreeNodeUI,{focus:Ext.emptyFn,//preventoddscrollingbehaviorrenderElements:function(n,a,targetNode,bulkRender){this.indentMarkup=n.parentNode?n.parentNode.ui.getChildIndent():'';vart=n.getOwnerTree();varcols=t.columns;varbw=t.borderWidth;varc=cols[0];varbuf=['<liclass="x-tree-node"><divext:tree-node-id="',n.id,'"class="x-tree-node-elx-tree-node-leaf',a.cls,'">','<divclass="x-tree-col"style="width:',c.width-bw,'px;">','<spanclass="x-tree-node-indent">',this.indentMarkup,"</span>",'<imgsrc="',this.emptyIcon,'"class="x-tree-ec-iconx-tree-elbow">','<imgsrc="',a.icon||this.emptyIcon,'"class="x-tree-node-icon',(a.icon?"x-tree-node-inline-icon":""),(a.iconCls?""+a.iconCls:""),'"unselectable="on">','<ahidefocus="on"class="x-tree-node-anchor"href="',a.href?a.href:"#",'"tabIndex="1"',a.hrefTarget?'target="'+a.hrefTarget+'"':"",'>','<spanunselectable="on">',n.text||(c.renderer?c.renderer(a[c.dataIndex],n,a):a[c.dataIndex]),"</span></a>","</div>"];for(vari=1,len=cols.length;i<len;i++){c=cols[i];buf.push('<divclass="x-tree-col',(c.cls?c.cls:''),'"style="width:',c.width-bw,'px;">','<divclass="x-tree-col-text">',(c.renderer?c.renderer(a[c.dataIndex],n,a):a[c.dataIndex]),"</div>","</div>");}buf.push('<divclass="x-clear"></div></div>','<ulclass="x-tree-node-ct"style="display:none;"></ul>',"</li>");if(bulkRender!==true&&n.nextSibling&&n.nextSibling.ui.getEl()){this.wrap=Ext.DomHelper.insertHtml("beforeBegin",n.nextSibling.ui.getEl(),buf.join(""));}else{this.wrap=Ext.DomHelper.insertHtml("beforeEnd",targetNode,buf.join(""));}this.elNode=this.wrap.childNodes[0];this.ctNode=this.wrap.childNodes[1];varcs=this.elNode.firstChild.childNodes;this.indentNode=cs[0];this.ecNode=cs[1];this.iconNode=cs[2];this.anchor=cs[3];this.textNode=cs[3].firstChild;}});
2、编写静态ColumnTree/***@functioncolumntreecolumntree多列信息的tree*@auhor:hoojo*@createDate:Aug29,201010:39:02PM*@blog:blog.csdn.net/IBM_hoojo*@email:hoojo_@126.com*/Ext.ns("Ext.hoo.tree");Ext.hoo.tree.UserColumnTree=Ext.extend(Ext.tree.ColumnTree,{constructor:function(){Ext.hoo.tree.UserColumnTree.superclass.constructor.call(this,{renderTo:"show",title:"用户信息columntree",width:450,hieght:400,autoScroll:true,rootVisible:true,columns:[{header:"名称",width:100,dataIndex:"name"},{header:"性别",width:100,dataIndex:"sex"},{header:"年龄",width:100,dataIndex:"age"},{header:"班级",width:100,dataIndex:"classes"}],loader:newExt.tree.TreeLoader({baseAttrs:{uiProvider:Ext.tree.ColumnNodeUI}}),root:newExt.tree.AsyncTreeNode({text:"用户基本信息",children:[{name:"大二一班",classes:"二(1)班",children:[{name:"微微",sex:"女",age:20,classes:"二(1)班",leaf:true},{name:"筱筱",sex:"女",age:22,classes:"二(1)班",leaf:true},{name:"珠珠",sex:"女",age:19,classes:"二(1)班",leaf:true},{name:"拉拉",sex:"女",age:19,classes:"二(1)班",leaf:true}]},{name:"二二班",classes:"二(2)班",children:[{name:"放放",sex:"男",age:22,classes:"二(2)班",leaf:true},{name:"枫枫",sex:"男",age:22,classes:"二(2)班",leaf:true}]},{name:"未成立",sex:"",age:0,classes:"二(3)班",leaf:true}]})});this.on("click",this.onNodeClick,this);},onNodeClick:function(node,e){alert(Ext.encode(node.attributes)+"###"+node.leaf+"###"+Ext.encode(e.getPoint())+"##"+e.getXY());}});Ext.onReady(function(){Ext.BLANK_IMAGE_URL="ext2/resources/images/default/s.gif";newExt.hoo.tree.UserColumnTree();});
上面的就是一个静态的ColumnTree,在Ext的onReady函数中运行它。
3、、需要在页面中导入ext库、css、即我们编写的js<!DOCTYPEhtmlPUBLIC"-//W3C//DTDXHTML1.0Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><head><title>TreePanel示例</title><metahttp-equiv="Content-Type"content="text/html;charset=UTF-8"/><metahttp-equiv="author"content="hoojo"/><metahttp-equiv="email"content="hoojo_@126.com"/><metahttp-equiv="ext-lib"content="version2.2"/><metahttp-equiv="blog"content="http://blog.csdn.net/IBM_hoojo"/><metahttp-equiv="blog"content="http://hoojo.cnblogs.com"/><linkrel="stylesheet"type="text/css"href="ext2/resources/css/ext-all.css"/><linkrel="stylesheet"type="text/css"href="jslib/column-tree.css"/><scripttype="text/javascript"src="ext2/adapter/ext/ext-base.js"></script><scripttype="text/javascript"src="ext2/ext-all.js"></script><scripttype="text/javascript"src="ext2/build/locale/ext-lang-zh_CN-min.js"></script><scripttype="text/javascript"src="jslib/Ext.tree.ColumnTree.js"></script><scripttype="text/javascript"src="jslib/Ext.hoo.tree.UserColumnTree.js"></script></head><body><divid="show"style="margin-left:200px;"></div><divid="showBasic"style="margin-left:200px;margin-top:50px;"></div></body></html>
在浏览器中请求http://localhost:8080/S2SMyBatis/columnTree.htm
结果如下
4、下面编写远程数据的ColumnTree,代码如下:Ext.ns("Ext.hoo.tree");Ext.hoo.tree.UserBasicColumnTree=Ext.extend(Ext.tree.ColumnTree,{constructor:function(){Ext.hoo.tree.UserBasicColumnTree.superclass.constructor.call(this,{renderTo:"showBasic",title:"远程数据",width:550,hieght:400,autoScroll:true,rootVisible:true,columns:[{header:"编号",width:100,dataIndex:"accountId"},{header:"用户名称",width:100,dataIndex:"username"},{header:"密码",width:100,dataIndex:"password"},{header:"创建时间",width:150,dataIndex:"createTime"}],loader:newExt.tree.TreeLoader({baseAttrs:{uiProvider:Ext.tree.ColumnNodeUI}}),root:newExt.tree.AsyncTreeNode({text:"用户基本信息",children:[]}),listeners:{expandnode:{fn:this.onExpandNode,scope:this}}});},onExpandNode:function(node){//只对未加载过的添加子结点,加载后不在重复加载;避免增加请求,浪费资源if(!node.attributes.isLoad){Ext.Ajax.request({url:Ext.hoo.tree.UserBasicColumnTree.TREE_DATA_URL,success:function(response,options){node.attributes.isLoad=true;//设置加载标识varnodes=Ext.decode(response.responseText);//将json的text转换成js对象node.appendChild(nodes.results);},failure:function(response){Ext.Msg.alert("程序异常",response.responseText);}});}}});Ext.hoo.tree.UserBasicColumnTree.TREE_DATA_URL="account!treeData.action";
由于服务器端返回来的数据是一个对象,而不是一个Array。所以客户端要将数据稍作处理,然后再添加到columnTree的children中。
5、在上面的onReady中创建这个对象就可以了运行Ext.onReady(function(){Ext.BLANK_IMAGE_URL="ext2/resources/images/default/s.gif";newExt.hoo.tree.UserColumnTree();newExt.hoo.tree.UserBasicColumnTree();});
同样在浏览器中请求http://localhost:8080/S2SMyBatis/columnTree.htm
可以看到
由于Account对象的数据形式不是一个完整的tree形态。所以展示效果就是上面的样子。正确的数据的格式的话,Account中至少包含以下属性:
Booleanleaf;Listchildren;这样就知道当前节点是否是叶子节点,并且知道其子元素。
作者:hoojo
出处:http://www.cnblogs.com/hoojo/archive/2011/05/11/2043453.html
blog:http://blog.csdn.net/IBM_hoojo
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章推荐
- spring+struts+mybatis三大框架整合配置
- myeclipse+struts+spring+mybatis+mave的框架整合---spring+mybatis
- Spring-Struts-Mybatis整合
- 一个整合Struts+Spring+MyBatis
- spring+struts2+mybatis整合
- 整合Struts,Spring,mybatis三个框架的helloworld
- Spring+Struts2+mybatis 整合(详细解释+完整流程)
- Struts+mybatis+spring整合tomcat启动报错
- struts-spring-mybatis整合项目搭建
- ssm整合(Struts、spring、mybatis)
- Struts+spring+mybatis框架整合
- 三大框架整合struts+spring+mybatis
- Spring+Struts2+Mybatis整合
- struts2.2+hibernate3.2+spring2.5整合所需要的包
- spring+struts2+mybatis整合
- 整合Struts、Spring、Mybatis
- struts+spring+mybatis框架整合
- struts2.2+hibernate3.2+spring2整合入门实例
- spring-struts-mybatis整合错误集锦
- struts、spring、mybatis 整合(spring.xml)