实习了三个月,对着SSH有着一定的认识了,就以自已认识的大概思路写一篇文章吧,留给以后的自已,也恳请各位博友们如果看到我的认识有过错的地方能帮我指正过来!
我用到的资料
在写正文之前,先说说我这段时间学习SSH所用到的资料吧!所以在我下面所认识中所说的话如果有跟我学习资料中说的差不多的或者一模一样的,还恳请各位的原谅,毕竟我的知识就是从你们那儿学的。刚接触SSH是照着一位博友的博文来搭建的(Eclipse搭建SSH(Struts2+Spring3+Hibernate3)框架项目教程),在搭建的过程中出错了好多错误,当时我还一边在看尚学堂马士兵的视频来搭建的(发现照着网上的搭建时一般会因为你下载的spring、struts、hibernate等版本的不同而出现错误,这我们搭建时还是得参考我们所下载里面的技术文档,例如我下载的hibernate为hibernate-distribution-3.6.10.Final,在这里面有hibernate-distribution-3.6.10.Finaldocumentationmanualzh-CNhtmlindex.html的技术文档,当然,我打开的是中文版的,里面还有别的语言版本的)。
在我的框架搭建好后,我便深入的去理解。这过程中我主要有用到两份资料,一份是一博友zs234的博客,这博友写的真心不错,至少对于我来说,感觉简明易懂。还有另一份资料就是李刚的书了(JavaEE企业应用实战-Struts2Spring3Hibernate整合开发第3版,这书我网上找了份有书签的pdf,又去到当当网买了本,感觉不错。这pdf我上传到了我所在的QQ技术交流群上300638185,也上传了份在百度云上面,有需要的博友可以点击此下载)
我此时的SSH框架
Struts2
先从struts2说起(说到struts1与struts2,我觉得主要的一个不同就是struts2有着线程安全吧,而struts1的线程不安全,因为它多用户共享同一线程了),struts2是一个经典的继Model1和Model2后的MVC框架,所谓的MVC,就是Model+View+Control.
Model为逻辑层,负责逻辑业务(不包括数据业务,至少我在网上看到的都是这样,但我师兄跟我说查询语句可以写到manager(有的资料也叫service,至少我第一次搭建的框架就叫service)里面,当时我就晕了,manager不是MVC里面的M吗?怎么可以写在里面了,下面讲ioc时我会说另一点为什么我不愿意丢掉dao层,到现在我还是喜欢把查询语句写在dao层里面,manager就做逻辑处理,当然我也有了解到查询语句可以写到新建的一个配置文件里面,可惜我只了解了一下,还没仔细去了解这个)。
View为显示层,主要组件有jsp页面与一些jsp页面的小插件。
Control为控制器,主要体现在action上面,学习action,会学习到5个名词,分别为:actionServlet、actionMapping、actionForm、action、actionForward,这5个名词可以构成一个小过程:客户端发送一个请求给服务器,服务器web.xml接收并分配给相应的servlet,这时的servlet就是struts.xml里面的actionServlet,actionServlet根据URL来截取配置信息,这些配置信息在actionMapping里面,然后生成相应的actionForm与action,actionForm里面放置的用户的请求信息,action实行控制,里面有个execute()方法,可以实行相应的操作,此时也可以进入逻辑业务(也就是调用Model层),最后以返回的参数实行actionForward来生成新的jsp界面.
此时也可以不生成新的jsp界面,这种情况是我在做ajax异步时发现的,此时struts.xml里面的代码如下
<action name="loginPro" class="org.crazyit.app.action.LoginAction"> <result name="success" type="stream"> <!-- 指定下载文件的文件类型 --> <param name="contentType">text/html</param> <!-- 指定由getResult()方法返回输出结果的InputStream --> <param name="inputName">result</param> </result> </action>
此时通过使用stream类型的Result,Strut2可以无需jsp视图界面,直接在Action向浏览者生成指定的响应。
更深层不生成新的jsp界面的一个就是还利用了json,此时得引入struts2-json-plugin-2.3.15.1.jar包,也对struts.xml文件有着一定的修改,如下:
<constant name="struts.i18n.encoding" value="UTF-8"></constant> <include file="struts-plugin.xml" /> <package name="ynwi" extends="json-default"> <action name="s2AA" class="s2AAa"> <result type="json"> <!-- 为该Result指定参数 --> <param name="noCache">true</param> <param name="contentType">text/html</param> </result> </action>
requery传值
上面说到action的5个名词时小谈了下SSH中一小部分的运行,下面我接着说,request有两种传值(就是actionForm)方式(在java文件里面以setter来获取这些信息),一种是get传值,这种方式传值时特点是会在地址栏后面加上你要传这值,这容易看出这种传值方式不安全与传的值量不大,另一种是form传值,是比较常用的传值方式,就是生成表格来存取数据,可以存储的数据量也比较大。
进入spring知识
当我们按jsp界面的按钮时,我们便直接来到struts.xml里面吧,我们根据action中的name来对应我们应该响应的action事件,class为指定的action的java类,如果此时不是指定java类,而是以一个名字指定到applicationContext.xml文件里面的话,这时就是说明进入了逻辑层了,此时action的java类为applicationContext.xml文件里面以那名字命名的bean的class,这个过程呢,我们叫他做“让spring来管理控制器”,此时主要内容如下:
struts.xml里面:
<action name="Login" class="userLogin"> <result name="admin">/index.jsp</result> <result name="customer">/Success_Customer.jsp</result> <result name="error">/Fail.jsp</result> </action>
applicationContext.xml里面:
<bean id="userLogin" class="com.slt.ssh.action.userLoginAction"> <property name="userManager"> <ref bean="userManager"></ref> </property> </bean>
另外还有一种方式叫做“自动装配”,这个先上代码我再说一下
struts.xml里面:
<action name="loginPro" class="org.crazyit.app.action.LoginAction"> <!-- 为两个逻辑视图配置视图页面 --> <result name="error">/WEB-INF/content/error.jsp</result> <result name="success">/WEB-INF/content/welcome.jsp</result> </action>
applicationContext.xml里面:
<bean id="ms" class="org.crazyit.app.service.impl.MyServiceImpl"/>
LoginAction.java里面:
private MyService ms; public void setMs(MyService ms) { this.ms = ms; }
自动装配就是以applicationContext.xml来自动找java文件里面的setMs方法。
现在,我们已经开始慢慢进入spring了,applicationContext.xml就是spring里面的知识点。@左潇龙博友说得好:“更准确的可以说spring是一个应用平台,可以这么理解spring就是操作系统,hibernate、struts都是网卡、显卡等插件,可插拔。操作系统管理着硬件,spring管理着这些hibernate持久层的ORM框架或者strutsMVC等框架。”对于spring,我认为最主要的知识就是AOP与IoC了,AOP简单理解就是给程度增加统一的功能的技术,是在不修改源代码的情况下,在通过编译或运行期动态代码的情况下。IoC(控制反转)简单理解就是把调用者的控制权交给第三方。IoC里面有许多概念:依赖,依赖倒置,依赖注入。
依赖:.java文件中如果A类有在自己的方法中实例化B类,那么就说A依赖于B。
依赖倒置:进行解耦,主要有两个原则
1、上级不能依赖于下级,可以共同依赖于另一抽象类(这里就是引进了接口,接口属于抽象类)。
2、抽象类不能依赖于实体类。
依赖注入:就是在spring容器中实例化的内容注入到.java文件中。依赖注入里面有两种,一种是设值注入,另一种是构造注入。我们用得多的是设值注入。
设值注入,先上主要代码再说明:
Chinese.java
private Axe axe; //设值注入所需的setter方法 public void setAxe(Axe axe) { this.axe = axe; }
applicationContext.xml
<bean id="chinese" class="org.crazyit.app.service.impl.Chinese"> <!-- 将stoneAxe注入给axe属性 --> <property name="axe" ref="stoneAxe"/> </bean> <!-- 配置stoneAxe实例,其实现类是StoneAxe --> <bean id="stoneAxe" class="org.crazyit.app.service.impl.StoneAxe"/>
我们可以看到xml文件时面property中的name为axe与java文件里面的setAxe相对应,这时也就是说我们把ref后面的stoneAxe注入给了java文件了,也就是说此时我们做的是在Chinese.java对StoneAxe类进行实例化,这样达到了松耦合的原理。
构造注入,这个就简单地上下代码吧。
Chinese.java
//构造注入所需的带参数的构造器 public Chinese(Axe axe) { this.axe = axe; }
applicationContext.xml
<bean id="chinese" class="org.crazyit.app.service.impl.Chinese"> <!-- 使用构造注入,为chinese实例注入steelAxe实例 --> <constructor-arg ref="steelAxe"/> </bean>
<bean id="steelAxe" class="org.crazyit.app.service.impl.SteelAxe"/>
参杂着hibernate
上面所说到的师兄叫我把查询语句写在manager里面,我不愿意的原因也有个感觉就是总觉得这样做不符合ioc,就是我会把applicationContext.xml看成是第三方,manager看成是调用者,dao看成是实现层,ioc不就是把实现层的控制权给第三方来控制吗?如果没了dao这一层,那这不就是不符合ioc了吗?后来慢慢觉得可不可以这样子看呢,就是把action看到是调用者,把manager看成是实现层,好像这样子想还真感觉有点道理,就是网上看了别人的都不是这样子的,奇怪奇怪,到现在还是感觉怪怪的。
下面我们回到从struts进入到spring后,一开始的进入是以“让spring管理控制器”的方式进入的,进入后都是通过ref来连接用到了多个bean,这样子就会有可能进入到逻辑层(manager),数据接口层(dao),在spring整合了hibernate与struts后,我们也是把连接数据源写在了applicationContext.xml文件里面,例如factory,session等。
另外我们要用到spring中的bean,也可以用ClassPathXmlApplicationContext、FileSystemXmlApplicationContext、XmlWebApplicationContext来获取bean.
在逻辑业务的控制下,我们进入了hibernate,hibernate就是以数据库相关连,对于hibernate的一对一,一对多等等的关联映射,我真心还没搞懂,对于注释,我也就懂了一点而已,至少还知道.hbm.xml文件主要用来对应数据库表里面的字节吧。不过hibernate我还是懂得查询是要建立工厂sessionfactory生产会议session等,在查询后还要关闭这会session什么的,但是我们现在有个getHibernateTemplate()函数,这是已经封装好的函数,我们直接用就行了,省了很多步骤。一般我们查询出来的结果以List来返回,当然也可以用别的东东来返回。
返回到action的java文件后,再传值给struts.xml文件,这时struts.xml会根据传回来的值生成一个新的页面。