欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-06-05 13:15:16
相信大家对于mvc的三层架构已经灰常熟悉了,在这就不细讲了,个人感觉ssi的框架结构还是比较典型的mvc三层架构,还是比较容易上手的。关于这块的入门我想特别感谢下frank...

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

框架结构:

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

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

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

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

相关demo介绍:

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

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

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

ø  开发环境简介:

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

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

开发步骤及配置简介:

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

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

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

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

user.java:

package com.broada.demo.entity;
/**
 * 
 * @author smm
 *
 */
public class user {
 
	private int id;     //用户id
	private string name;		//用户名称
	private string password;	//用户密码
	private string username;	//用户昵称
	private string address;		//地址
 
	
	public string getusername() {
		return username;
	}
 
	public void setusername(string username) {
		this.username = username;
	}
 
	public string getaddress() {
		return address;
	}
 
	public void setaddress(string address) {
		this.address = address;
	}
 
	public int getid() {
		return id;
	}
 
	public void setid(int id) {
		this.id = id;
	}
 
	public string getname() {
		return name;
	}
 
	public void setname(string name) {
		this.name = name;
	}
 
	public string getpassword() {
		return password;
	}
 
	public void setpassword(string password) {
		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:

<?xml version="1.0" encoding="utf-8"?>
<!doctype struts public "-//apache software foundation//dtd struts configuration 2.0//en"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
  <!-- 这是一个重要的地方,很多人在使用<s:include>子页面后,发现子页面乱码,怎么改都不行,原因就在次,struts2的默认编码为utf-8,乱码的同志请看看你的jsp页面上的编码是不是和这个不一致呢。只要把这里和jsp编码改一致就行了 -->
  <constant name="struts.i18n.encoding" value="utf-8" />
	<!-- 告诉struts2,我要用spring装配工厂,其实默认就是这个了-_-!!! -->
  <constant name="struts.objectfactory" value="spring" />
	<!-- struts2的扩展名,比如struts1的时候,用的.do,struts2默认为.action,可以改成其它的,比如.dxd -->
  <constant name="struts.action.extension" value="action" />
	<!-- 资源文件 -->
  <constant name="struts.custom.i18n.resources"
    value="messageresource">
  </constant> 
 
  <!-- 用户注册类 -->
	<!-- abstract属性就说明了该action继承自自己定义的基础action,而class采用的registeraction是由sprin*生的 -->
  <package name="register" extends="struts-default">
    <action name="register" class="registeraction" method="adduser">
      <!-- 注册成功 -->
      <result name="success">success.jsp</result>
      <!-- 注册失败 -->
      <result name="input">error.jsp</result>
    </action>
    <action name="login" class="registeraction" method="loginuser">
    	<!-- 注册成功 -->
      <result name="success">success.jsp</result>
      <!-- 注册失败 -->
      <result name="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

<?xml version="1.0" encoding="utf-8" ?>
<!doctype sqlmapconfig public "-//ibatis.apache.org//dtd sql map config 2.0//en"
"http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
<sqlmapconfig>
<!-- 用户信息表 -->
<sqlmap resource="com/broada/demo/dao/ibaties/map/user.xml" />
</sqlmapconfig>

user.xml:

<?xml version="1.0" encoding="utf-8" ?>
<!doctype sqlmap public "-//ibatis.apache.org//dtd sql map 2.0//en"   
"http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlmap>
  <typealias alias="user" type="com.broada.demo.entity.user" />
  <!-- 保存注册信息 -->
  <insert id="insertuser" parameterclass="user">
    insert into
    user (name,password,username,address)values(#name#,#password#,#username#,#address#)
  </insert>
  
  <select id="selsectuser" parameterclass="java.lang.string" resultclass="user">
  	select * from user
  	where name = #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>
  <!-- springframework config files -->
  <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:

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
  xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
  <!-- 配置数据源,连接池采用的是c3p0,具体各参数代表意义参看c3p0自带的doc,非常详细。 -->
  <bean id="datasource"
    class="com.mchange.v2.c3p0.combopooleddatasource"
    destroy-method="close">
    <property name="driverclass" value="${jdbc.driverclass}" />
    <property name="jdbcurl" value="${jdbc.url}" />
    <property name="user" value="${jdbc.user}" />
    <property name="password" value="${jdbc.password}" />
    <property name="minpoolsize" value="${jdbc.minpoolsize}" />
    <property name="maxpoolsize" value="${jdbc.maxpoolsize}" />
    <property name="maxidletime" value="${jdbc.maxidletime}" />
    <property name="acquireincrement"
      value="${jdbc.acquireincrement}" />
    <property name="maxstatements" value="${jdbc.maxstatements}" />
    <property name="initialpoolsize"
      value="${jdbc.initialpoolsize}" />
    <property name="idleconnectiontestperiod"
      value="${jdbc.idleconnectiontestperiod}" />
    <property name="acquireretryattempts"
      value="${jdbc.acquireretryattempts}" />
  </bean>
 
  
  <!-- 上面的数据源的value值用的是表达式,原因就在这里,这将配置文件放到了ibatis目录下,也就是jdbc.properties,设置了c3p0的各项参数 -->
  <bean id="propertyconfig"
    class="org.springframework.beans.factory.config.propertyplaceholderconfigurer">
    <property name="location">
      <value>/web-inf/ibatis/jdbc.properties</value>
    </property>
  </bean> 
  
  <!-- 配置ibatis的sqlmapclient,这里当然是交给了spring去处理,其中,将sqlmapconfig文件放到了web-inf的ibatis目录下,也是便于管理 -->
  <bean id="sqlmapclient"
    class="org.springframework.orm.ibatis.sqlmapclientfactorybean">
    <property name="configlocation">
      <value>/web-inf/ibatis/sqlmapconfig.xml</value>
    </property>
    <!-- 这里使用的数据源就是上面配置的数据源 -->
    <property name="datasource">
      <ref bean="datasource" />
    </property>
  </bean> 
 
  <bean id="userdaoid" class="com.broada.demo.daoimpl.userdaoimpl">
   	<property name="sqlmapclient" ref="sqlmapclient"></property>
  </bean>
   
  <bean id="userdaoserviceid" class="com.broada.demo.serviceimpl.userdaoserviceimpl">
   <property name="userdao" ref="userdaoid">
  </property>
  </bean> 
   <!-- 用户注册action--> 
  <bean id="registeraction" name="registeraction" class="com.broada.demo.action.registeraction" scope="prototype">    
   <property name="userdaoserviceinter" ref="userdaoserviceid"></property>
  </bean> 
  
  
</beans>

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

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

registeraction.java:

package com.broada.demo.action;
 
/**
 * @author smm
 */
 
import com.broada.demo.entity.user;
import com.broada.demo.service.userdaoserviceinter;
import com.opensymphony.xwork2.actionsupport;
 
public class registeraction extends actionsupport {
	
	private static final long serialversionuid = 1l;
	
private userdaoserviceinter userdaoserviceinter;	
 
	public userdaoserviceinter getuserdaoserviceinter() {
		return userdaoserviceinter;
	}
 
	public void setuserdaoserviceinter(userdaoserviceinter userdaoserviceinter) {
		this.userdaoserviceinter = userdaoserviceinter;
	}
 
	private string name;  //用户名
	private string password;	//密码
	private string username;	//昵称
	private string address;		//地址
 
	public string getusername() {
		return username;
	}
 
	public void setusername(string username) {
		this.username = username;
	}
 
	public string getaddress() {
		return address;
	}
 
	public void setaddress(string address) {
		this.address = address;
	}
 
	public string getname() {
		return name;
	}
 
	public void setname(string name) {
		this.name = name;
	}
 
	public string getpassword() {
		return password;
	}
 
	public void setpassword(string password) {
		this.password = password;
	}
 
	public string adduser() {
		system.out.println("添加成功!");
		user user = new user();
		
		string name = this.name;
		string password = this.password;
		string username = this.username;
		string address = this.address;
		
		user.setname(name);
		user.setpassword(password);
		user.setusername(username);
		user.setaddress(address);
		
		boolean b = userdaoserviceinter.insertuser(user);
		
		if (b==true) {
			return success;
		} else
			return input;
	}
	
	public string loginuser(){
		system.out.println("登陆=======");
		
		string name = this.name;
		string password = this.password;
		
		user user = userdaoserviceinter.querybyname(name);
		
		if(user != null && password.equals(user.getpassword())){
			return success;
		} else 
			return error; 
	}
}

userdao.java

package com.broada.demo.dao;
 
/**
 * @author smm
 */
 
import java.util.list;
 
import com.broada.demo.entity.user;
 
public interface userdao {
	
	/**
	 * 用户注册
	 * @param user
	 * @return
	 */
	
	public boolean insertuser(user user);
	
	/**
	 * 根据用户名获取用户信息
	 * @param name
	 * @return
	 */
	
	public user querybyname(string name);	
}

userdaoimpl.java

package com.broada.demo.daoimpl;
/**
 * @author smm
 */
import org.springframework.orm.ibatis.support.sqlmapclientdaosupport;
 
import com.broada.demo.dao.userdao;
import com.broada.demo.entity.user;
 
public class userdaoimpl extends sqlmapclientdaosupport implements userdao{
 
 
 
	@override
	public boolean insertuser(user user) {
		try {
			getsqlmapclienttemplate().insert("insertuser", user);
			return true;
		} catch (exception e) {
			e.printstacktrace();
			return false;
		}	
	}
 
	@override
	public user querybyname(string name) {
		// todo auto-generated method stub
		try {
			user user =(user) getsqlmapclienttemplate().queryforobject("selsectuser", name);
			return user;
		} catch (exception e) {
			e.printstacktrace();
			return null;
		}		
	}
	
}

userdaoserviceinter.java

package com.broada.demo.service;
 
/**
 * @author smm
 */
 
import com.broada.demo.entity.user;
 
public interface userdaoserviceinter {
	
	/**
	 * 用户注册服务接口
	 * @param user
	 * @return
	 */
	
	public boolean insertuser(user user);
	
	/**
	 * 根据用户名获取用户信息接口
	 * @param name
	 * @return
	 */
	
	public user querybyname(string name);
}

userdaoserviceimpl.java

package com.broada.demo.serviceimpl;
 
/**
 * @author smm
 */
 
import com.broada.demo.dao.userdao;
import com.broada.demo.entity.user;
import com.broada.demo.service.userdaoserviceinter;
 
public class userdaoserviceimpl implements userdaoserviceinter {
 
	private userdao userdao;
	public userdao getuserdao() {
		return userdao;
	}
	public void setuserdao(userdao userdao) {
		this.userdao = userdao;
	}
	@override
	public boolean insertuser(user user) {
		return userdao.insertuser(user);
	}
	@override
	public user querybyname(string name) {
		// todo auto-generated method stub
		return userdao.querybyname(name);
	}
 
}

index.jsp

<%@ page language="java" contenttype="text/html; charset=utf8"
	pageencoding="utf8"%>
	<%@ taglib prefix="s" uri="/struts-tags"%>
<!doctype html public "-//w3c//dtd html 4.01 transitional//en" "http://www.w3.org/tr/html4/loose.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf8">
<link rel="stylesheet" type="text/css" href="css/ext-all.css" />
<link rel="stylesheet" type="text/css"
	href="css/ext-theme-classic-all.css" />
<script type="text/javascript" src="js/ext-all.js"></script>
 
 
<title>用户登陆</title>
<script type="text/javascript">
ext.onready(function(){
		initpanel();	 
	});
	
	initpanel=function(){
		 var formpanel = new ext.formpanel({
			  id: 'loginpanel',
			  labelwidth: 75, 
			  frame:true,
			  bodystyle:'margin:0 auto',
			  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: '密码不能为空'}]
			     });
		var win = new ext.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();
	};
	
	var win1;
	
	register = function(){	
		
		var registerpanel = new ext.formpanel({
		  id: 'registerpanel',
		  labelwidth: 75, 
		  frame:true,
		  bodystyle:'margin:0 auto',
		  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 = new ext.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(){
		var name = ext.getcmp('registername').getvalue(); 
		var password = ext.getcmp('registerpassword').getvalue();
		var password2 = ext.getcmp('registerpassword2').getvalue();
		var nichen = ext.getcmp('nichen').getvalue();
		var address = ext.getcmp('address').getvalue();
		
		if(name==" "|| password==" " || password2==""){
			ext.messagebox.alert('提示','账号或密码不能为空!');
		}
		else if(password != password2){
			ext.messagebox.alert('提示','两次密码输入不一致!');
		}else{
		 ext.ajax.request({
       url: "<s:url value='/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(){
		var name = ext.getcmp('username').getvalue(); 
		var password = ext.getcmp('password').getvalue();
		
		
		if(name == " " || password == ""){
			 ext.messagebox.alert('提示', '账号或密码不能为空!');
		}
		else{
		 ext.ajax.request({
       url: "<s:url value='/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的框架还是蛮不错的,起码定制和*度都比较好。