zl程序教程

您现在的位置是:首页 >  后端

当前栏目

ssi框架学习总结(mvc三层架构)

架构学习框架MVC 总结 三层 SSI
2023-06-13 09:15:45 时间

相信大家对于mvc的三层架构已经灰常熟悉了,在这就不细讲了,个人感觉ssi的框架结构还是比较典型的mvc三层架构,还是比较容易上手的。关于这块的入门我想特别感谢下FrankHui童鞋,在他的帮助下,我才能比较快滴熟悉了这个架构,对我学习ssi的框架还是很有帮助滴。ssi的框架主要是由struts2,spring以及ibatis组成,他们负责各层之间的交互与协作,从而实现整个web端的功能实现与整合。Struts目前主要负责数据传递和控制方面,spring则依靠其强大的依赖注入技术实现了类似bean托管和整合等功能,当然这只是spring功能中的冰山一角,而ibatis作为一种轻量级的ORMapping框架,提供了半自动化对象关系映射的实现,自由度相对于hibernate更高。

框架结构:

这是我在网上找到的一张关于ssi框架的结构图,个人感觉画的还是蛮不错的,对于入门者来说,层次机构很清晰,比较实用(感谢这位大大的分享):

在这里可以很明显的看出ssi框架的大体结构以及各层之间的交互情况,顶层表现层的话,就java而言主要是jsp,html等视图层技术的编写,其中涉及我们熟悉的javascript,jquery以及extjs等。在控制层来说的话,主要是利用strust2标签功能实现action与视图层的数据交互,当然也可以使用ajax的技术实现同样的功能,这个就按个人喜好而来了。在业务逻辑层。主要是利用spring的依赖注入实现对业务逻辑类和dao类的实例托管,当然各类的实例都可以托管在spring中进行统一管理和关联,包括事务,数据源等等。在持久层,利用ibatis提供的半自动化对象关系映射的实现,开发人员可以根据需要编写具体的sql语句,通过相应的xml的配置实现对数据库的操作。

总之,SSI框架能够降低我们代码的耦合度,增强了代码的健壮性和可重用性,加快了开发速度,但是也有一些不足之处,比如由于三种框架的配置文件较多,也给我们带来了一些不便,特别是对于较小的应用来说更是如此。

相关demo介绍:

基于之前对ssi框架的学习,我也不能免俗滴选择了做一个用户管理的web实现,项目的大致框架如下:

大体上还是按照三层的分层模型来是分的,具体就不详细说了,相信大家也应该很了解整个结构的。

Ø 开发环境简介:

工具:eclipse3.6+tomcat7+mysql5.1

框架:struts2,spring3.0.5,ibatis2.3.4.726

开发步骤及配置简介:

第一步,众所周知肯定是导入相关的lib库啦,由于我使用的前端是extjs,所以还需要导入extjs相关的js以及css依赖文件。由于lib库太多就不截图了,只截取extjs的相关依赖文件:

这样基本的环境就有了,数据库的设计则需要根据model层的对象来确定。 

第二步,建立相关的model层,代码如下:

User.java:

packagecom.broada.demo.entity; /** * *@authorsmm * */ publicclassUser{ privateintid;//用户id privateStringname; //用户名称 privateStringpassword; //用户密码 privateStringusername; //用户昵称 privateStringaddress; //地址 publicStringgetUsername(){ returnusername; } publicvoidsetUsername(Stringusername){ this.username=username; } publicStringgetAddress(){ returnaddress; } publicvoidsetAddress(Stringaddress){ this.address=address; } publicintgetId(){ returnid; } publicvoidsetId(intid){ this.id=id; } publicStringgetName(){ returnname; } publicvoidsetName(Stringname){ this.name=name; } publicStringgetPassword(){ returnpassword; } publicvoidsetPassword(Stringpassword){ this.password=password; } }

第三步,strust的相关配置,这里就不详细讲述strust的单独配置及原理了,直接上实例中的相关配置文件,主要是strust.xml以及web.xml的相关配置,部分主要配置如下:

Web.xml:

<!--struts2模块--> <filter> <filter-name>struts2</filter-name> <!--这个就是struts2的核心过滤器--> <filter-class> org.apache.struts2.dispatcher.FilterDispatcher </filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

strust.xml:

<?xmlversion="1.0"encoding="UTF-8"?> <!DOCTYPEstrutsPUBLIC"-//ApacheSoftwareFoundation//DTDStrutsConfiguration2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <!--这是一个重要的地方,很多人在使用<s:include>子页面后,发现子页面乱码,怎么改都不行,原因就在次,struts2的默认编码为UTF-8,乱码的同志请看看你的jsp页面上的编码是不是和这个不一致呢。只要把这里和jsp编码改一致就行了--> <constantname="struts.i18n.encoding"value="UTF-8"/> <!--告诉struts2,我要用spring装配工厂,其实默认就是这个了-_-!!!--> <constantname="struts.objectFactory"value="spring"/> <!--struts2的扩展名,比如struts1的时候,用的.do,struts2默认为.action,可以改成其它的,比如.dxd--> <constantname="struts.action.extension"value="action"/> <!--资源文件--> <constantname="struts.custom.i18n.resources" value="messageResource"> </constant> <!--用户注册类--> <!--abstract属性就说明了该action继承自自己定义的基础action,而class采用的registerAction是由spring产生的--> <packagename="register"extends="struts-default"> <actionname="register"class="registerAction"method="addUser"> <!--注册成功--> <resultname="success">success.jsp</result> <!--注册失败--> <resultname="input">error.jsp</result> </action> <actionname="login"class="registerAction"method="loginUser"> <!--注册成功--> <resultname="success">success.jsp</result> <!--注册失败--> <resultname="error">error.jsp</result> </action> </package> </struts>

这样strust的配置大致就完成了。 

第四步:配置ibatis的相关配置文件,主要是jdbc.propertiesSqlMapConfig.xml以及User.xml的配置,jdbc.properties主要用于配置数据库的数据源参数,会在加载spring的时候自动初始化,ibatis数据源的配置到时可以托管给spring初始化,所以这里就不细讲了。SqlMapConfig.xml主要是配置ibatis的配置文件的位置,User.xml则用于编写相关的数据库语句等,配置大致如下:

jdbc.properties:

jdbc.driverClass=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/userinfo jdbc.user=root jdbc.password=123456 jdbc.minPoolSize=5 jdbc.maxPoolSize=20 jdbc.maxIdleTime=1800 jdbc.acquireIncrement=5 jdbc.maxStatements=50 jdbc.initialPoolSize=10 jdbc.idleConnectionTestPeriod=1800 jdbc.acquireRetryAttempts=30

详细的参数含义在spring的配置文件会提及,就不细说了。

SqlMapConfig.xml

<?xmlversion="1.0"encoding="UTF-8"?> <!DOCTYPEsqlMapConfigPUBLIC"-//ibatis.apache.org//DTDSQLMapConfig2.0//EN" "http://ibatis.apache.org/dtd/sql-map-config-2.dtd"> <sqlMapConfig> <!--用户信息表--> <sqlMapresource="com/broada/demo/dao/ibaties/map/User.xml"/> </sqlMapConfig>

User.xml:

<?xmlversion="1.0"encoding="UTF-8"?> <!DOCTYPEsqlMapPUBLIC"-//ibatis.apache.org//DTDSQLMap2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd"> <sqlMap> <typeAliasalias="User"type="com.broada.demo.entity.User"/> <!--保存注册信息--> <insertid="insertUser"parameterClass="User"> insertinto user(name,password,username,address)values(#name#,#password#,#username#,#address#) </insert> <selectid="selsectUser"parameterClass="java.lang.String"resultClass="User"> select*fromuser wherename=#name#; </select> </sqlMap>

这样,ibatis的配置大致就完成。

第五步:配置spring的相关配置文件,主要是整合ibatis以及strust中用到的bean,需要配置web.xml以及applicationContext-web.xml两个配置文件:

web.xml:

<listener> <!--这个就是今后用到的WebApplicationUtilContent--> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <!--springframeworkconfigfiles--> <context-param> <param-name>contextConfigLocation</param-name> <!--把spring的配置文件放到了/WEB-INF/下的springframework包里,方便统一管理,命名规则是以applicationContent-开头的xml文件,初始化时会自动搜索所有符合规则的配置文件--> <param-value> /WEB-INF/spring/applicationContext-*.xml </param-value> </context-param>

applicationContext-web.xml:

<?xmlversion="1.0"encoding="UTF-8"?> <beansxmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <!--配置数据源,连接池采用的是c3p0,具体各参数代表意义参看c3p0自带的doc,非常详细。--> <beanid="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <propertyname="driverClass"value="${jdbc.driverClass}"/> <propertyname="jdbcUrl"value="${jdbc.url}"/> <propertyname="user"value="${jdbc.user}"/> <propertyname="password"value="${jdbc.password}"/> <propertyname="minPoolSize"value="${jdbc.minPoolSize}"/> <propertyname="maxPoolSize"value="${jdbc.maxPoolSize}"/> <propertyname="maxIdleTime"value="${jdbc.maxIdleTime}"/> <propertyname="acquireIncrement" value="${jdbc.acquireIncrement}"/> <propertyname="maxStatements"value="${jdbc.maxStatements}"/> <propertyname="initialPoolSize" value="${jdbc.initialPoolSize}"/> <propertyname="idleConnectionTestPeriod" value="${jdbc.idleConnectionTestPeriod}"/> <propertyname="acquireRetryAttempts" value="${jdbc.acquireRetryAttempts}"/> </bean> <!--上面的数据源的value值用的是表达式,原因就在这里,这将配置文件放到了iBatis目录下,也就是jdbc.properties,设置了c3p0的各项参数--> <beanid="propertyConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <propertyname="location"> <value>/WEB-INF/ibatis/jdbc.properties</value> </property> </bean> <!--配置iBatis的sqlMapClient,这里当然是交给了spring去处理,其中,将SqlMapConfig文件放到了WEB-INF的iBatis目录下,也是便于管理--> <beanid="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> <propertyname="configLocation"> <value>/WEB-INF/ibatis/SqlMapConfig.xml</value> </property> <!--这里使用的数据源就是上面配置的数据源--> <propertyname="dataSource"> <refbean="dataSource"/> </property> </bean> <beanid="userdaoId"class="com.broada.demo.daoImpl.UserDaoImpl"> <propertyname="sqlMapClient"ref="sqlMapClient"></property> </bean> <beanid="userDaoServiceId"class="com.broada.demo.serviceImpl.UserDaoServiceImpl"> <propertyname="userdao"ref="userdaoId"> </property> </bean> <!--用户注册action--> <beanid="registerAction"name="registerAction"class="com.broada.demo.action.RegisterAction"scope="prototype"> <propertyname="userdaoServiceInter"ref="userDaoServiceId"></property> </bean> </beans>

这样,ssi框架的大致配置就完成了。 

最后编写相关的dao层,service层,action层以及jsp等等,我就不详细说明了,直接上相关代码:

RegisterAction.java:

packagecom.broada.demo.action; /** *@authorsmm */ importcom.broada.demo.entity.User; importcom.broada.demo.service.UserDaoServiceInter; importcom.opensymphony.xwork2.ActionSupport; publicclassRegisterActionextendsActionSupport{ privatestaticfinallongserialVersionUID=1L; privateUserDaoServiceInteruserdaoServiceInter; publicUserDaoServiceIntergetUserdaoServiceInter(){ returnuserdaoServiceInter; } publicvoidsetUserdaoServiceInter(UserDaoServiceInteruserdaoServiceInter){ this.userdaoServiceInter=userdaoServiceInter; } privateStringname;//用户名 privateStringpassword; //密码 privateStringusername; //昵称 privateStringaddress; //地址 publicStringgetUsername(){ returnusername; } publicvoidsetUsername(Stringusername){ this.username=username; } publicStringgetAddress(){ returnaddress; } publicvoidsetAddress(Stringaddress){ this.address=address; } publicStringgetName(){ returnname; } publicvoidsetName(Stringname){ this.name=name; } publicStringgetPassword(){ returnpassword; } publicvoidsetPassword(Stringpassword){ this.password=password; } publicStringaddUser(){ System.out.println("添加成功!"); Useruser=newUser(); Stringname=this.name; Stringpassword=this.password; Stringusername=this.username; Stringaddress=this.address; user.setName(name); user.setPassword(password); user.setUsername(username); user.setAddress(address); booleanb=userdaoServiceInter.insertUser(user); if(b==true){ returnSUCCESS; }else returnINPUT; } publicStringloginUser(){ System.out.println("登陆======="); Stringname=this.name; Stringpassword=this.password; Useruser=userdaoServiceInter.querybyname(name); if(user!=null&&password.equals(user.getPassword())){ returnSUCCESS; }else returnERROR; } }

UserDao.java

packagecom.broada.demo.dao; /** *@authorsmm */ importjava.util.List; importcom.broada.demo.entity.User; publicinterfaceUserDao{ /** *用户注册 *@paramuser *@return */ publicbooleaninsertUser(Useruser); /** *根据用户名获取用户信息 *@paramname *@return */ publicUserqueryByname(Stringname); }

UserDaoImpl.java

packagecom.broada.demo.daoImpl; /** *@authorsmm */ importorg.springframework.orm.ibatis.support.SqlMapClientDaoSupport; importcom.broada.demo.dao.UserDao; importcom.broada.demo.entity.User; publicclassUserDaoImplextendsSqlMapClientDaoSupportimplementsUserDao{ @Override publicbooleaninsertUser(Useruser){ try{ getSqlMapClientTemplate().insert("insertUser",user); returntrue; }catch(Exceptione){ e.printStackTrace(); returnfalse; } } @Override publicUserqueryByname(Stringname){ //TODOAuto-generatedmethodstub try{ Useruser=(User)getSqlMapClientTemplate().queryForObject("selsectUser",name); returnuser; }catch(Exceptione){ e.printStackTrace(); returnnull; } } }

UserDaoServiceInter.java

packagecom.broada.demo.service; /** *@authorsmm */ importcom.broada.demo.entity.User; publicinterfaceUserDaoServiceInter{ /** *用户注册服务接口 *@paramuser *@return */ publicbooleaninsertUser(Useruser); /** *根据用户名获取用户信息接口 *@paramname *@return */ publicUserquerybyname(Stringname); }

UserDaoServiceImpl.java

packagecom.broada.demo.serviceImpl; /** *@authorsmm */ importcom.broada.demo.dao.UserDao; importcom.broada.demo.entity.User; importcom.broada.demo.service.UserDaoServiceInter; publicclassUserDaoServiceImplimplementsUserDaoServiceInter{ privateUserDaouserdao; publicUserDaogetUserdao(){ returnuserdao; } publicvoidsetUserdao(UserDaouserdao){ this.userdao=userdao; } @Override publicbooleaninsertUser(Useruser){ returnuserdao.insertUser(user); } @Override publicUserquerybyname(Stringname){ //TODOAuto-generatedmethodstub returnuserdao.queryByname(name); } }

Index.jsp

<%@pagelanguage="java"contentType="text/html;charset=utf8" pageEncoding="utf8"%> <%@taglibprefix="s"uri="/struts-tags"%> <!DOCTYPEhtmlPUBLIC"-//W3C//DTDHTML4.01Transitional//EN""http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <metahttp-equiv="Content-Type"content="text/html;charset=utf8"> <linkrel="stylesheet"type="text/css"href="css/ext-all.css"/> <linkrel="stylesheet"type="text/css" href="css/ext-theme-classic-all.css"/> <scripttype="text/javascript"src="js/ext-all.js"></script> <title>用户登陆</title> <scripttype="text/javascript"> Ext.onReady(function(){ initPanel(); }); initPanel=function(){ varformPanel=newExt.FormPanel({ id:"loginPanel", labelWidth:75, frame:true, bodyStyle:"margin:0auto", width:350, defaults:{width:250}, defaultType:"textfield", items:[{id:"username",fieldLabel:"用户名",name:"name",allowBlank:false,blankText:"账号不能为空"}, {id:"password",fieldLabel:"密码",name:"password",inputType:"password",allowBlank:false,blankText:"密码不能为空"}] }); varwin=newExt.Window({ title:"登陆界面", width:380, autoHeight:"true", resizable:false, modal:true, closeAction:"hide", buttonAlign:"center", items:formPanel, buttons:[{text:"登陆",handler:function(){land();}}, {text:"重置",handler:function(){ Ext.getCmp("username").setValue(""); Ext.getCmp("password").setValue(""); }},{text:"注册",handler:function(){register();}}] }); win.show(); }; varwin1; register=function(){ varregisterPanel=newExt.FormPanel({ id:"registerPanel", labelWidth:75, frame:true, bodyStyle:"margin:0auto", width:350, defaults:{width:250}, defaultType:"textfield", items:[{id:"registername",fieldLabel:"用户名",name:"name1",allowBlank:false,blankText:"账号不能为空"}, {id:"registerpassword",fieldLabel:"登陆密码",name:"password1",inputType:"password",allowBlank:false,blankText:"密码不能为空"}, {id:"registerpassword2",fieldLabel:"密码确认",name:"password2",inputType:"password",allowBlank:false,blankText:"密码不能为空"}, {id:"nichen",fieldLabel:"昵称",name:"nichen1"}, {id:"address",fieldLabel:"地址",name:"address1"}] }); win1=newExt.Window({ title:"注册界面", width:380, autoHeight:"true", resizable:false, modal:true, buttonAlign:"center", items:registerPanel, buttons:[{text:"提交",handler:function(){login();}}, {text:"取消",handler:function(){win1.close();}}] }); win1.show(); }; login=function(){ varname=Ext.getCmp("registername").getValue(); varpassword=Ext.getCmp("registerpassword").getValue(); varpassword2=Ext.getCmp("registerpassword2").getValue(); varnichen=Ext.getCmp("nichen").getValue(); varaddress=Ext.getCmp("address").getValue(); if(name==""||password==""||password2==""){ Ext.MessageBox.alert("提示","账号或密码不能为空!"); } elseif(password!=password2){ Ext.MessageBox.alert("提示","两次密码输入不一致!"); }else{ Ext.Ajax.request({ url:"<s:urlvalue="/register.action"/>", method:"post", params:{ name:name, password:password, username:nichen, address:address }, success:function(response,options){ Ext.MessageBox.alert("提示","注册成功",function(e){ if(e=="ok"){ win1.close(); } }); }, failure:function(response,options){ Ext.MessageBox.alert("注册失败","请检查您的注册信息!"); } }); } }; land=function(){ varname=Ext.getCmp("username").getValue(); varpassword=Ext.getCmp("password").getValue(); if(name==""||password==""){ Ext.MessageBox.alert("提示","账号或密码不能为空!"); } else{ Ext.Ajax.request({ url:"<s:urlvalue="/login.action"/>", method:"post", params:{ name:name, password:password }, success:function(response,options){ Ext.MessageBox.alert("提示","登陆成功!"); }, failure:function(response,options){ Ext.MessageBox.alert("登陆失败","您输入的账号或密码错误!"); } }); } }; </script> </head> <body> </body> </html>

大致的步骤就是这样,个人觉得ssi的框架还是蛮不错的,起码定制和自由度都比较好。