从事JavaEE工作已经许久了,在这个期间学习了很多的知识,也熟练了很多之前总是语罢于嘴的技术,在这个过程中收获着很多的东西,但是由于现在工作的局限性,很多之前学止于书的技术都渐渐忘却,在整理这篇文章的时候,一则出于对知识的回顾,因此可以作为刚学习SSH搭建的程序员参考资料,二则在搭建框架之余,尽量去表达出我对整个过程中可能遇到的问题,并如何去解决问题的思路和方法。如果在阅读本文时候遇到了错误或者有着自己独到的见解,还请提出来,在此感激不尽。
现在JavaEE最热的框架也就属SSH了,但是每种技术所起的作用是什么我仅仅做简单介绍,最终的理解还是靠整个过程的搭建实践才可以明白。(本文搭建完成的SSH代码我已经上传到CSDN资源,有需要的读者可以通过http://download.csdn.net/detail/songdeitao/6730819这个链接进行下载)
- Struts主要是MVC思想的具体实现,
- Spring利用它的IOC和AOP来处理控制业务,
- Hibernate是操作数据库的一种框架,它简化了直接使用jdbc api的代码操作数据库的复杂性和冗余性。
下面便开始整个SSH框架的搭建过程。
本文选取struts-2.3.1,spring-framework-3.2.2,hibernate-4.1.1的搭建过程,首先这几个版本都是比较新的版本,也是通过测试,比较通用稳定的版本。
框架名称 | 版本 | 最后发布时间 | 下载链接 | |
Struts2 | 2.3.1 | 2011-12-13 |
| |
Hibernate | 4.1.1 | 2012-03-08 |
| |
Spring | 3.2.2 | 2013-03-14 |
|
下载完成之后进行解压缩,如图1所示:
图1
环境搭建:MyEclipse8.5+JDK1.6+Apache-tomcat-6.0.33
在整个搭建过程中,我尽量一步步做演示,从Struts开始,然后到Hibernate的整合,然后在整合Spring,整个过程中会遇到常见的异常,然后进行解决,并且总结出注意事项。
首先是最后搭建成功后的目录结构(项目名称为SSHDemo,下文为SSH,这里仅仅呈现的是目录结构,下文将一步步搭建成这样的结果),如图2所示:
图2
下面开始创建项目SSH,打开MyEclipse,File—>New—>Web Project,输入项目名称SSH,如图3所示:
图3
点击Finish完成项目创建,如图4所示:
紧接着需要完成Struts框架的引入,搭建成一个Struts项目,打开解压完成后的struts-2.3.1目录struts-2.3.1\apps\struts2-blank.war,解压缩struts2-blank.war到struts2-blank目录中,
步骤一:进入到struts-2.3.1\apps\struts2-blank\WEB-INF目录下,将其中web.xml文件中的内容全部复制到项目目录结构中web.xml文件中并且替换掉原来的所有内容,修改后的文件内容如下web.xml所示:
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<!-- Struts2过滤器,将所有的请求进行拦截并进行处理 -->
<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>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
步骤二:将struts-2.3.1\apps\struts2-blank\WEB-INF\lib文件夹中的所有jar包添加到web项目目录结构lib中,添加后如图5所示:
图5
其中jar包以及其作用如下讲解,
jar包(.jar) | 作用 |
asm-3.3 | 操作java字节码的类库 |
asm-commons-3.3 | 提供了基于事件的表现形式 |
asm-tree-3.3 | 提供了基于对象的表现形式 |
commons-fileupload-1.2.2 | Struts 文件的上传和下载功能的实现 |
commons-io-2.0.1 | commons项目(commons项目就是java中一些常用的公共的组件)的io子项目,是处理异常的 |
commons-lang-2.5 | 为java.lang提供扩展 |
freemarker-2.3.18 | 支持freemarker(struts2的UI标签的模板使用FreeMarker编写)的,在webwork中也有 |
javassist-3.11.0.GA | 一个开源的分析、编辑和创建Java字节码的类库(hibernate中也需要,引入其中一个即可) |
ognl-3.0.3 | 支持ognl语言(对象图导航语言(Object Graph Navigation Language))的,struts2框架通过其读写对象的属性,webwork也支持ognl语言 |
struts2-core-2.3.1 | struts2的核心jar包 |
xwork-core-2.3.1 | xwork的核心jar包,由于struts2是webwork的升级版本,所以必定对其有所依赖(struts2在其基础上构建) |
步骤三:将路径struts-2.3.1\apps\struts2-blank\WEB-INF\src\java下的struts.xml文件拷贝到项目总src下,修改后的文件内容如下所示:
struts.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>
<!--
动态方法调用,如果为true,开发时候可以使用,代表可以通过 url地址动态调用执行相应的方法,不推荐,如果为false,
不可以动态方法调用,但可以通过进行通配符的设置进行动态方法调用,推荐为false
-->
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
<!-- 开发者模式,为true时候,如果改动配置文件不需要重启服务器就可以自动更新,开发时候建议开启 -->
<constant name="struts.devMode" value="false" />
<!-- name代指包名,namespace是命名空间,是在url中照写的部分 -->
<package name="user" namespace="/" extends="struts-default">
<!-- name指代url中写在namespace中的部分,class指代将执行的action -->
<action name="user" class="com.steven.action.UserAction">
<!-- 如果方法返回success,则执行以下部分 -->
<result name="success">
WEB-INF/jsp/welcome.jsp
</result>
</action>
</package>
</struts>
紧接着按照配置文件中的class建立相应的包和类,
建立过后的目录结构如图
6
所示
:
图6
此时,文件index.jsp,welcome.jsp,UserAction.java,User.java内容分别如下:
index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>SSH index</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<h2>这是一个SSH项目,请点击<a href="user">这里</a> 显示用户列表。</h2>
</body>
</html>
welcome.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
<!-- 引入Struts2的标签库 -->
<%@taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>welcome</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<table border="1" cellpadding="0" cellspacing="0" width="600"
style="text-align: center;">
<tr>
<th>姓名</th>
<th>年龄</th>
<th>生日</th>
<th>是否是VIP</th>
</tr>
<!-- OGNL表达式的输出 -->
<s:iterator value="#request.userList" var="user">
<tr>
<td>
<!-- EL表达式输出 -->
${user.userName }
</td>
<td>${user.age }</td>
<td>
<!-- struts标签日期格式标签 -->
<s:date name="#user.birthday" format="yyyy-MM-dd" />
</td>
<td>
<!-- struts2中条件输出 -->
<s:if test="#user.isVip == true">
是VIP
</s:if>
<s:else>
不是VIP
</s:else>
</td>
</tr>
</s:iterator>
</table>
</body>
</html>
UserAction.java
package com.steven.action;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.apache.struts2.interceptor.RequestAware;
import com.opensymphony.xwork2.ActionSupport;
import com.steven.entity.User;
/**
* 通过继承ActionSupport获得Struts2的已有功能,
* 通过实现RequestAware获取request(这种方式常用,还有其他三种方式,这里不再赘述)
* 四种获取request方式请参照http://blog.csdn.net/ms2146/article/details/5406004
*
* @author Steven
*
*/
public class UserAction extends ActionSupport implements RequestAware {
private static final long serialVersionUID = 1L;
private Map<String, Object> request;
@Override
public String execute() throws Exception {
// 创建一个用户集合
List<User> userList = new ArrayList<User>();
// 创建用户并添加到用户集合中
userList.add(new User("Steven", 1, new Date(), true));
userList.add(new User("Lily", 1, new Date(), false));
userList.add(new User("Tom", 1, new Date(), false));
// 将用户存储到ActionContext中(可以通过ognl表达式获取)
request.put("userList", userList);
return SUCCESS;
}
public void setRequest(Map<String, Object> request) {
this.request = request;
}
}
User.java
package com.steven.entity;
import java.util.Date;
/**
* 实体类
*
* @author Steven
*
*/
public class User {
// 用户Id
private int userId;
// 用户名
private String userName;
// 用户年龄
private int age;
// 用户生日
private Date birthday;
// 用户是否是会员 true:是 false:不是
private boolean isVip;
public User() {
}
// 有参构造
public User(String userName, int age, Date birthday, boolean isVip) {
this.userName = userName;
this.age = age;
this.birthday = birthday;
this.isVip = isVip;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public boolean getIsVip() {
return isVip;
}
public void setIsVip(boolean isVip) {
this.isVip = isVip;
}
@Override
public String toString() {
return "用户信息: [年龄是" + this.getAge() + ", 生日是" + this.getBirthday()
+ ", 用户编号是" + this.getUserId() + ", 用户名是" + userName
+ isVip(this.getIsVip()) + "]";
}
/**
* 用来进行测试使用
*
* @param isVip
* @return
*/
public String isVip(boolean isVip) {
return ", " + (isVip == true ? "是" : "不是") + "会员";
}
}
注:在这个过程中,首先配置struts.xml中请求的URL,然后配置处理请求所需要的action以及result,更新index.jsp,建立所需要的User.java,UserAction.java,然后建立请求执行后所跳转的页面welcome.jsp,然后进行部署暂时的Struts2项目,具体的过程参照以下讲解。通过MyEclipse部署项目到Tomcat,具体的过程如下:
点击部署按钮,如图7所示:
图7
进行部署操作,如图8,9所示:
图8
图9
部署后启动服务器,如下图10,11所示:
图10
图11
然后打开浏览器,输入URL(http://localhost:8080)观察tomcat是否启动成功,成功如图12所示,成功后URL后添加项目名称SSH,即(http://localhost:8080/SSH)打开首页,如图13所示:
图12
图13
点击这里,即可显示用户列表,如图14所示:
图14
注:至此,struts2的搭建就算是完成了,在这个过程中不难看出struts2的执行原理:
- 客户端通过浏览器填写URL,发送一个请求到服务器端(Tomcat)
- 根据web.xml配置,该请求被FilterDispatcher接收
- 根据struts.xml配置,通过URL,匹配namespace和action name,这里的URL是http://localhost:8080/SSH/user,namespace 为“/”,action name为“user”,找到需要调用的action类UserAction.java和方法(默认执行方法execute()), 并通过IoC(控制反转,以后讲到spring会讲到)方式,将值注入给Aciton
- Action调用业务逻辑组件处理业务逻辑,这一步包含表单验证(本程序没有给出,可以参照其他博客进一步了解Struts的功能)
- Action执行完毕,根据struts.xml中的配置找到对应的返回结果result,并跳转到相应页面
- 将最后的结果返回,即通过HTTP协议响应到客户端浏览器