一、Struts
在没有学习SSH框架前,我们一般采用Jsp+javabean+servlet开发,这里就是MVC架构。而Struts其实就是替代了Servlet,我们知道Servlet在一般的开发中做控制页面跳转,同时调用系统的业务逻辑层。现在想想Struts是不是做一样的是?只是它能够更加的提高开发速度。我们Servlet开发时,是要创建一个Servlet其实就是继承了HttpServlet这个类。而现在Struts里面的Action也要集成一个ActionSupport类。这里可以看到其实Struts基本上和Servlet差不多,但是其中也各有不同。下面就介绍一下其中的差异:
首先从接收参数上,Struts可以避免我们重复的调用request.getParameter("pName")这个方法,Struts可以貌似可以是用四种方式:
1.使用ModelDriven
在创建Action的时候,发现Action实现了ModelDriven接口,去调用接口的getModel()方法,取到了相关对象。相应提交方式可以用get和post,如:testAction? name=admin
public class TestAction extends BaseAction implements ModelDriven<ResBananRc> { private static final long serialVersionUID = -7463970150000893325L; private ResBananRc resBananRc = new ResBananRc();//这里要手动的New下 public ResBananRc getModel() { return resBananRc; } public void execeute() { System.out.println("姓名:" + resBananRc.getName()); } }
2.用Action 的属性
在action中定义要接收的参数,并创建getter,setter方法,参数变量名要和传递过来的参数名一样,并不用做数据类型的转换。相应提交方式可以用get和post,如:testAction? name=admin
public class TestAction extends BaseAction { private static final long serialVersionUID = -7463970150000893325L; private String name; public void execeute() { System.out.println(name +" : " + name); } public String getName() { return name; } public void setName(String name) { this.name = name; } }
3.使用Domain Model
在Action里面不存很多的属性,而是用Model层用到的模型,保存它的一个对象。相应提交方式可以用get和post,如:testAction?resBananRc.name=admin(这是比较常用的)
public class TestAction extends BaseAction { private static final long serialVersionUID = -7463970150000893325L; private ResBananRc resBananRc; public ResBananRc getResBananRc() { return resBananRc; } public void setResBananRc(ResBananRc resBananRc) { this.resBananRc = resBananRc; } public void execeute() { System.out.println("姓名: " + resBananRc.getName()); } }
4.使用request 对象
此方法与与传统的JSP 等传接参数一样,即使用request. getParameter("")方法
public class TestAction extends BaseAction { private static final long serialVersionUID = -7463970150000893325L; public void execeute() { String name = super.getRequest().getParameter("paraName"); System.out.println("姓名:" + name); } }
那么在Servlet里面接收参数只能使用上面的第四种方法,这种方法接受参数重复代码量比较大,所以使用Struts在接收参数方面可以简化开发。
再次就是上传文件方面,Struts也做了比较不错的简化。我们知道在使用Servlet上传文件时,那代码量是比较大的(相对于Struts),但是使用Struts,我们可以不用写实现上传文件的代码,而只要在Action中定义接受文件的参数就够了,我们唯一做的就是接收文件,具体怎么上传的交给了Struts。这也是Struts在开发上的简化。
当我们使用Servlet写控制部分的时候,我们可能会创建很对的Servlet,那么web.xml中就会配置相当对的Servlet,这样第一不方便管理,第二维护比较麻烦。而Struts如果可以我们可以只做简单的配置可以满足所有的控制要求。但是为了更好的维护,一般不这样做,一般值将Action分块,和代码分包一样,例如这块Action处理用户的,包括用户的注册,用户修改信息,用户登录,以及用户其他的其操作。那么这样可以方面代码的管理和代码维护。这也是Struts一方面的优化。这也并不是说Servlet不好,我就用Servlet开发了一两年的时间。
以上只是介绍了Struts比较常用的几个方面,其实Struts在很多方面对开发做了简化,例如可以添加拦截器对用户操作进行过滤,防止非法的操作,可以在展现层作出改进,例如它有一套的标签库。
其实我觉得在Struts底层就是通过拦截器,拦截用户访问的路劲,并通过对xml的解析,查看用户访问的路径是否是一个ACTION,如果是,则通过反射机制调用我们配置的action。其实Struts的底层就是xml解析,拦截器和反射机制。这是我的个人理解!如有不对,欢迎指出!
二 、Hibernate
Hibernate实现了对象到数据库端的封装。就是常说的ORM(Object-Relation-Mapping),它的出现使得编程更加的面向对象,在传统的编程上,我们要将对象存储到关系数据库中,是一个非常繁琐的过程,需要写很多代码来实现。而且需要考虑跨数据库的平台的问题。有了Hibernate(是实现JPA框架中的一种)可以方便的实现从对象转换到关系数据库。这就是对象持久化。
我们可以使用注解和配置文件来交给Hibernate实现持久化的工作,现在大部分喜欢使用注解,这样的开发效率更快,而且使用简单。可以使用一个@Entity注解来标记该类为一个实体对象,需要对齐进行持久化,那么Hibernate检查到这个后,就将该对象和数据库中的某个表关联在一起。
Hibernate在数据库查询方面就行了优化,不用我们创建对象,它会自动将结果进行封装返回给我们。在Hibernate里面提供了六种查询方法:
1.HQL查询(它是一种Hibernate自己的查询语言,是一中面向对象的查询语言)
HQL是hibernate自己的一套查询语言,于SQL语法不同,具有跨数据库的优点。示例代码:
static void query(String name) { Session s=null; try { s=HibernateUtil.getSession(); //from后面是对象,不是表名 String hql="from Admin as admin where admin.aname=:name";//使用命名参数,推荐使用,易读。 Query query=s.createQuery(hql); query.setString("name", name); List<Admin> list=query.list(); for(Admin admin:list) { System.out.println(admin.getAname()); } } finally { if(s!=null) s.close(); } }
适用情况:常用方法,比较传统,类似jdbc。
缺点:新的查询语言,适用面有限,仅适用于Hibernate框架。
2.对象化查询Criteria方法
static void cri(String name,String password) { Session s=null; try { s=HibernateUtil.getSession(); Criteria c=s.createCriteria(Admin.class);//指定查询的类 c.add(Restrictions.eq("aname",name));//eq是等于,gt是大于,lt是小于,or是或 c.add(Restrictions.eq("apassword", password)); List<Admin> list=c.list(); for(Admin admin:list) { System.out.println(admin.getAname()); } } finally { if(s!=null) s.close(); } }
3.动态分离查询DetachedCriteria
static List dc(DetachedCriteria dc) { Session s = HibernateUtil.getSession(); Criteria c = dc.getExecutableCriteria(s); List rs = c.list(); s.close(); return rs; } DetachedCriteria dc = DetachedCriteria.forClass(User.class); int id = 1; if (id != 0) dc.add(Restrictions.eq("id", id)); Date age = new Date(); if (age != null) dc.add(Restrictions.le("birthday", age)); List users = dc(dc); System.out.println("离线查询返回结果:" + users);
适用情况:面向对象操作,分离业务与底层,不需要字段属性摄入到Dao实现层。
缺点:适用面较HQL有限。
4.例子查询
static List example(User user) { Session s = HibernateUtil.getSession(); List<User> users = s.createCriteria(User.class).add(Example.create(user)).list(); // List<User> // users2=s.createCriteria(User.class).add((Example.create(user)).ignoreCase()) // .createCriteria("child").add((Example.create(user))).list(); return users; }
适用情况:面向对象操作。
缺点:适用面较HQL有限,不推荐。
5.sql查询
static List sql() { Session s = HibernateUtil.getSession(); Query q = s.createSQLQuery("select * from user").addEntity(User.class); List<User> rs = q.list(); s.close(); return rs; }
适用情况:不熟悉HQL的朋友,又不打算转数据库平台的朋友,万能方法。
缺点:破坏跨平台,不易维护,不面向对象。
6.命名查询
static List namedQuery(int id) { Session s = HibernateUtil.getSession(); Query q = s.getNamedQuery("getUserById"); q.setInteger("id", id); return q.list(); }
<?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.sy.vo.User" table="user" catalog="news"> </class> <!-- 命名查询:定义查询条件 --> <query name="getUserById"> <![CDATA[from User where id=:id]]> </query> <!-- 命名查询中使用sql,不推荐使用,影响跨数据库 <sql-query name="getUserById2"> <![CDATA[select * from User where ]]> </sql-query> --> </hibernate-mapping>
适用情况:万能方法,有点像ibatis轻量级框架的操作,方便维护。
缺点:不面向对象。基于hql和sql,有一定缺陷。
Hibernate的底层是通过解析XML文件,在通过反射机制将配置的类内容映射到数据库中,它就是是我们编程避免了和数据库打交道,一切和数据库交互的过程全都由Hibernate来实现,这样就减少了我们传统编程的访问数据库端的代码,使得开发效率更快,系统的跨平台能力更强。
三、Spring
Spring总共包括IOC和AOP两部分,也就是常说的依赖注入和面向切面编程。IOC使得我们的系统的耦合度更低,方便对代码的修改和更新。IOC使得java的多态更加的强大,充分的利用了java的多态(父类定义调用子类实现)。使得系统架构更加的清晰,系统的生命力也就更强。使得系统的架构只需先定义好接口,而具体的实现可以更具实际的需求来更改。这就是IOC的功能。我们只需在我们想要调用具有某功能的地方定义其父类,而具体是通过哪种实现只需在实际情况下注入实现给父类方法的子类。
而AOP这是一种面向切面的编程思想,这种思想使得编程思想上得到了历史性的进步。它将程序的执行过程切割成不同的面,在面之间可以插入我们想执行的逻辑。例如:检测用户权限(有点类似于filter)。由于Spring有这种功能,所以用Spring来管理数据库的事务,是一种非常好的手段。因为Spring具有AOP的功能可以在访问数据库的事务前后都可以执行我们向执行的操作,例如在执行插入数据库记录之前让Spring获得数据库的连接,然后封装到Hibernate中,在执行插入操作后可以关闭数据库。这就将操作数据库分割成前后两个部分。就不用我们手动的来获得连接和关闭连接。
Spring其实就是一个对象的容易,里面装了我们配置的对象,在系统初始化的时候Spring将这些对象都放到其容器中(也可以设置在调用时候初始化对象,这种是考虑了系统的性能方面,如果太多的对象可能会消耗服务器的态太多内存),如果系统运行需要该对象,则从Spring容器中取出。将这些将对象实例化然后放到容器是通过对XML解析(或者是读取注解),获得需要实例化的对象,并为每个对象分配一个唯一ID(类是于Map类中的key),当系统运行过程中需要给ID的对象,那么就从这个容器中获取。这就实现了IOC的依赖注入。这里面的底层实现肯定有对XML解析,在通过反射机制来实例化对象。
而AOP是通过动态代理来实现的,实现动态代理jdk提供两个类来实现(Proxy,InvocationHandler)这个是要实例化的类实现接口,而没有实现接口的类Spring需要调用cglib.jar库通过修改类的二进制文件来实现。
以上都是本人个人对Spring的理解,可能存在很多的错误。欢迎指出!共同提高!共同学习!
四、 SSH整合
在MVC结构里,我们使用Struts来实现里面的‘C’,也就是用之层。而Hibernate是实现‘M’层,Jsp则实现‘V’。当用户访问时,提交给Struts,然后Struts通过Service(Manage)层,然后Service(Manage)层访问DAO层,DAO层通过Hibernate访问数据库。到现在一直没用到Spring,Spring是干什么的呢?Spring就是控制业务逻辑层。例如:给Struts的action注入Service(Manage)层的对象,向Service(Manage)层注入DAO层的对象。通过Spring的AOP来控制Hibernate访问数据库的事务,来管理数据库访问事务。这就是SSH整合的基本思想。
开发环境:
(1) OS:Windows XP SP3
(2) DB:MySql 5.1.6
(3) JDK:1.6.0_17
(4) Server:Apache Tomcat 6.0.26
(5) IDE:MyEclipse 5.5
SSH框架:
(1) Struts2.1.8
(2) Spring2.0.2
(3) Hibernate3.2.5
注:由于SSH框架中的Jar包众多,有些Jar包要选择性的添加,全部添加会异常,比如Spring的Jar包,而且Jar包还可能会发生版本冲突。所在在整个整合过程中,Jar包的添加采取最精简的配置原则,详细配置请参照整合步骤中的相关说明。
整合步骤:
1.新建Web Project
2.添加Struts2.1的支持
(1) 添加Jar包
basic
|__ freemarker-2.3.15.jar
|__ struts2-core-2.1.8.1.jar
|__ xwork-core-2.1.6.jar
|__ ognl-2.7.3.jar
|__ commons-io-1.3.2.jar
|__ commons-logging-1.0.4.jar
(2) 修改配置文件WebRoot/WEB-INF/web.xml
<!-- Struts2.1 --> <filter> <filter-name>struts2</filter-name> <filter-class> org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter </filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
(3) 配置src/struts.xml
<package name="example" extends="struts-default"> <action name="hello" class="com.tarena.action.HelloAction"> <result name="success">/jsp/hello.jsp</result> </action> </package>
(4) 添加WebRoot/jsp/hello.jsp页面
内容任意
(5) 添加com.tarena.action.HelloAction.java
public class HelloAction extends ActionSupport { @Override public String execute() throws Exception { System.out.println("HelloAction:execute()..."); return "success"; } }
(6) 部署ssh项目
将应用程序部署到Tomcat中。
(7) 测试hello.action
启动Tomcat
测试URL:http://localhost:8080/ssh/hello.action
3.添加Spring2.0的支持
(1) 添加Jar包
dist
|__sping.jar
(2) 修改WebRoot/WEB-INF/web.xml文件
<!-- Spring 2.0 --> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener>
(3) 添加WebRoot/WEB-INF/applicationContext.xml
配置信息为空
(4) 更新ssh项目
异常:java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
补充Spring中的Jar包
lib
|__ jakarta-commons
|__commons-logging.jar
(5) 重新启动Tomcat
如果没有异常,进行下一步。
(6) 测试Spring的IOC
可以利用静态测试的方法测试Spring的IOC,这样在不启用应用服务器的情况下就可以测试Spring。具体操作如下:
拷贝WebRoot/WEB-INF/applicationContext.xml文件到com.tarena.config下
在com.tarena.config.applicationContext.xml添加内容:
<bean id="helloService" class="com.tarena.service.HelloService"> <property name="str" value="hello"></property> </bean>
添加com.tarena.service.HelloService
测试类com.tarena.test.TestHelloService
注:为了方便测试引入JUnit4。
测试没有异常,进行下一步。
4.添加Hibernate3.2的支持
(1) 添加访问MySql数据库的驱动Jar包
mysql-connector-java-5.1.6-bin.jar
(2) 添加Hibernate3.2的Jar包
hibernate3.jar
(3) 创建实体类和DAO接口
com.tarena.entity.User
映射文件:com.tarena.entity.User.hbm.xml
com.tarena.dao.UserDao
(4) 应用IOC实现DAO接口
使用HibernateTemplate实现User的增、删、改、查等操作。
(5) 测试com.tarena.dao.UserDaoImpl
测试类:com.tarena.test.TestUserDao
异常:java.lang.ClassNotFoundException: org.apache.commons.dbcp.BasicDataSource
解决方法:添加Jar包commons-dbcp.jar
lib
|__ jakarta-commons
|__ commons-dbcp.jar
异常:java.lang.NoClassDefFoundError: org/apache/commons/pool/impl/GenericObjectPool
解决方法:添加Jar包commons-pool.jar
lib
|__ jakarta-commons
|__ commons-pool.jar
以下的异常解决方法同上,Jar包全在Spring的lib目录下选取。
java.lang.NoClassDefFoundError: org/dom4j/DocumentException
解决方法:添加Jar包dom4j.jar
java.lang.NoClassDefFoundError: org/apache/commons/collections/SequencedHashMap
解决方法:添加Jar包commons-collections.jar
java.lang.NoClassDefFoundError: net/sf/cglib/proxy/CallbackFilter
解决方法:添加Jar包cglib.jar
java.lang.NoClassDefFoundError: antlr/ANTLRException
解决方法:添加Jar包antlr.ajr
(6) 测试DAO结果
5.用户登录注册实例
详细说明请参照具体的代码。
注:
(1) 在把项目利用JUnit测试Sping和Hibernate都没有任何问题,但是把项目部署到Tomcat,启动应用服务器时会有一个很奇怪的异常:
java.lang.ClassNotFoundException: javax.transaction.TransactionManager
经过上网查资料得到解决办法:添加Spring的Jar包jta.jar
lib
|__j2ee
|__jta.jar
(2) 由于在Tomcat应用服务器中测试SSH,所以还要添加必须的Struts2整合Spring的包struts2-spring-plugin-2.1.8.1.jar,否则当Tomcat正常启动后,在Login页面
提交表单测试会出现异常:
异常信息:LoginAction中的UserService为null