Struct(二)
struct2 权威指南
这一节通过一个详细的实例来讲解Struct2框架的应用
1 下载和安装Struts 2框架
(1) 登录http://struts.apache.org/download.cgi#Struts206站点,下载Struts 2的最新GA版。在Struts 2.06下有如下几个选项:
— Full Distribution:下载Struts 2的完整版。通常建议下载该选项。
— Example Applications:下载Struts 2的示例应用,这些示例应用对于学习Struts 2有很大的帮助,下载Struts 2的完整版时已经包含了该选项下全部应用。
— Blank Application only:仅下载Struts 2的空示例应用,这个空应用已经包含在Example Applications选项下。
— Essential Dependencies:仅仅下载Struts 2的核心库,下载Struts 2的完整版时将包括该选项下的全部内容。
— Documentation:仅仅下载Struts 2的相关文档,包含Struts 2的使用文档、参考手册和API文档等。下载Struts 2的完整版时将包括该选项下的全部内容。
— Source:下载Struts 2的全部源代码,下载Struts 2的完整版时将包括该选项下的全部内容。
— Alternative Java 4 JARs:下载可选的JDK 1.4的支持JAR。下载Struts 2的完整版时将包括该选项下的全部内容。
通常建议读者下载第一个选项:下载Struts 2的完整版,将下载到的Zip文件解压缩,该文件就是一个典型的Web结构,该文件夹包含如下文件结构:
— apps:该文件夹下包含了基于Struts 2的示例应用,这些示例应用对于学习者是非常有用的资料。
— docs:该文件夹下包含了Struts 2的相关文档,包括Struts 2的快速入门、Struts 2的文档,以及API文档等内容。
— j4:该文件夹下包含了让Struts 2支持JDK 1.4的JAR文件。
— lib:该文件夹下包含了Struts 2框架的核心类库,以及Struts 2的第三方插件类库。
— src:该文件夹下包含了Struts 2框架的全部源代码。
(2)将lib文件夹下的Struts2-core-2.0.6.jar、xwork-2.0.1.jar和ognl-2.6.11.jar等必需类库复制到Web应用的WEB-INF/lib路径下。当然,如果你的Web应用需要使用Struts 2的更多特性,则需要将更多的JAR文件复制到Web应用的WEB-INF/lib路径下。如果需要在DOS或者Shell窗口下手动编译Struts 2相关的程序,则还应该将Struts2-core-2.0.6.jar和xwork-2.0.1.jar添加到系统的CLASSPATH环境变量里。
(3)编辑Web应用的web.xml配置文件
-----------------------------------------------------
<?xml version="1.0" encoding="GBK"?>
<!-- web-app是Web应用配置文件的根元素,指定Web应用的Schema信息 -->
<web-app 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">
<!-- 定义Struts 2的FilterDispatcher的Filter -->
<filter>
<!-- 定义核心Filter的名字 -->
<filter-name>struts2</filter-name>
<!-- 定义核心Filter的实现类 -->
<filter-class>org.apache.Struts2.dispatcher.FilterDispatcher
</ filter-class>
</filter>
<!-- FilterDispatcher用来初始化Struts 2并且处理所有的Web请求 -->
<filter-mapping>
<filter-name>Struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
2 创建一个JSP页面
----------------------------------------------------
<%@ page language="java" contentType="text/html; charset=GBK"%>
<html>
<head>
<title>登录页面</title>
</head>
<body>
<!-- 提交请求参数的表单 -->
<form action="Login.action" method="post">
<table align="center">
<caption><h3>用户登录</h3></caption>
<tr>
<!-- 用户名的表单域 -->
<td>用户名:<input type="text" name="username"/></td>
</tr>
<tr>
<!-- 密码的表单域 -->
<td>密 码:<input type="text" name="password"/></td>
</tr>
<tr align="center">
<td colspan="2"><input type="submit" value="登录"/><input
type="reset" value="重填" /></td>
</tr>
</table>
</form>
</body>
</html>
3. 创建WEB应用
建立一个Web应用请按如下步骤进行。
在任意目录新建一个文件夹,笔者将以该文件夹建立一个Web应用。
(1)在第1步所建的文件夹内建一个WEB-INF文件夹。
(2)进入Tomcat,或任何Web容器内,找到任何一个Web应用,将Web应用的WEB-INF下的web.xml文件复制到第2步所建的WEB-INF文件夹下。
(3) 修改复制的web.xml文件,将该文件修改成只有一个根元素的XML文件,修改后的web.xml文件代码如下
-------------------------------------------------
<?xml version="1.0" encoding="GBK"?>
<!-- web-app是Web应用配置文件的根元素,指定Web应用的Schema信息 -->
<web-app 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">
</web-app>
(4) 在第2步所建的WEB-INF路径下,新建两个文件夹:classes和lib,它们分别用于保存单个*.class文件和JAR文件。
(5)经过上面步骤,已经建立了一个空Web应用。将该Web应用复制到Tomcat的webapps路径下,该Web应用将可以自动部署在Tomcat中。
将2.2节所定义的JSP页面文件复制到第1步所建的文件夹下,该JSP页面将成为该Web应用的一个页面。该Web将有如下文件结构:
Struts2qs
|-WEB-INF
| |-classes
| |-lib
| |-web.xml
|-login.jsp
上面的Struts2qs是Web应用所对应文件夹的名字,可以更改;login.jsp是该Web应用下JSP页面的名字,也可以修改。其他文件夹、配置文件都不可以修改。
4. 增加Struct2的功能
为了给Web应用增加Struts 2功能,只需要将Struts 2安装到Web应用中即可。在Web应用中安装Struts 2框架核心只需要经过如下三个步骤。
(1) 修改web.xml文件,在web.xml文件中配置Struts 2的核心Filter。
(2)将Struts 2框架的类库复制到Web应用的WEB-INF/lib路径下。
(3) 在WEB-INF/classes下增加struts.xml配置文件。
下面是增加了Struts 2功能后Web应用的文件结构:
----------------------------------------------------------
Struts2qs
|-WEB-INF
| |-classes(struts.xml)
| |-lib(commons-logging.jar,freemarker.jar,ognl.jar,struts2-core.jar,xwork.jar)
| |-web.xml
|-login.jsp
在上面的文件结构中,lib下Struts 2框架的类库可能有版本后缀。例如commons-logging.jar,可能是commons-logging-1.1.jar;struts2-core.jar可能是struts2-core-2.0.6.jar。
修改后的web.xml文件在2.1节已经给出了,故此处不再赘述。
4.1 实现控制器
Struts 2下的控制器不再像Struts 1下的控制器,需要继承一个Action父类,甚至可以无需实现任何接口,Struts 2的控制器就是一个普通的POJO。
实际上,Struts 2的Action就是一个包含execute方法的普通Java类,该类里包含的多个属性用于封装用户的请求参数。下面是处理用户请求的Action类的代码:
//Struts 2的Action类就是一个普通的Java类
public class LoginAction
{
//下面是Action内用于封装用户请求参数的两个属性
private String username;
private String password;
//username属性对应的getter方法
public String getUsername()
{
return username;
}
//username属性对应的setter方法
public void setUsername(String username)
{
this.username = username;
}
//password属性对应的getter方法
public String getPassword()
{
return password;
}
//password属性对应的setter方法
public void setPassword(String password)
{
this.password = password;
}
//处理用户请求的execute方法
public String execute() throws Exception
{
//当用户请求参数的username等于scott,密码请求参数为tiger时,返回success
字符串
//否则返回error字符串
if (getUsername().equals("scott")
&& getPassword().equals("tiger") )
{
return "success";
}
else
{
return "error";
}
}
}
4.2 配置Action
前面已经介绍过了,struts.xml文件应该放在classes路径下,该文件主要放置Struts 2的Action定义。定义Struts 2 Action时,除了需要指定该Action的实现类外,还需要定义Action处理结果和资源之间的映射关系。下面是该应用的struts.xml文件的代码:
-----------------struts.xml-------------------
<?xml version="1.0" encoding="GBK"?>
<!-- 指定Struts 2配置文件的DTD信息 -->
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<!-- struts是Struts 2配置文件的根元素 -->
<struts>
<!-- Struts 2的Action必须放在指定的包空间下定义 -->
<package name="strutsqs" extends="struts-default">
<!-- 定义login的Action,该Action的实现类为lee.Action类 -->
<action name="Login" class="lee.LoginAction">
<!-- 定义处理结果和资源之间映射关系。 -->
<result name="error">/error.jsp</result>
<result name="success">/welcome.jsp</result>
</action>
</package>
</struts>
上面映射文件定义了name为login的Action,即:该Action将负责处理向login.action URL请求的客户端请求。该Action将调用自身的execute方法处理用户请求,如果execute方法返回success字符串,请求将被转发到/welcome.jsp页面;如果execute方法返回error字符串,则请求被转发到/error.jsp页面。
我们再增加两个页面 error.jsp和welcome.jsp也就完成了基本属性的配置
第二部分 功能扩展:
5. 改进控制器
5.1 实现Action接口
public interface Action
{
//下面定义了5个字符串常量
public static final String SUCCESS = "success";
public static final String NONE = "none";
public static final String ERROR = "error";
public static final String INPUT = "input";
public static final String LOGIN = "login";
//定义处理用户请求的execute抽象方法
public String execute() throws Exception;
}
在上面的Action代码中,我们发现该Action接口里已经定义了5个标准字符串常量:SUCCESS、NONE、ERROR、INPUT和LOGIN,它们可以简化execute方法的返回值,并可以使用execute方法的返回值标准化。例如对于处理成功,则返回SUCCESS常量,避免直接返回一个success字符串(程序中应该尽量避免直接返回数字常量、字符串常量等)。
因此,借助于上面的Action接口,我们可以将原来的Action类代码修改为如下:
//实现Action接口来实现Struts 2的Action类
public class LoginAction implements Action
{
//下面是Action内用于封装用户请求参数的两个属性
private String username;
private String password;
//username属性对应的getter方法
public String getUsername()
{
return username;
}
//username属性对应的setter方法
public void setUsername(String username)
{
this.username = username;
}
//password属性对应的getter方法
public String getPassword()
{
return password;
}
//password属性对应的setter方法
public void setPassword(String password)
{
this.password = password;
}
//处理用户请求的execute方法
public String execute() throws Exception
{
//当用户请求参数的username等于scott,密码请求参数为tiger时,返回success
字符串
//否则返回error的字符串
if (getUsername().equals("scott")
&& getPassword().equals("tiger") )
{
return SUCCESS;
}
else
{
return ERROR;
}
}
}
对比前面Action和此处的Action实现类,我们发现两个Action类的代码基本相似,除了后面的Action类实现了Action接口。因为实现了Action接口,故Action类的execute方法可以返回Action接口里的字符串常量。
5.2 跟踪用户状态
前面的Action处理完用户登录后,仅仅执行了简单的页面转发,并未跟踪用户状态信息——通常,当一个用户登录成功后,需要将用户的用户名添加为Session状态信息。
为了访问HttpSession实例,Struts 2提供了一个ActionContext类,该类提供了一个getSession的方法,但该方法的返回值类型并不是HttpSession,而是Map。这又是怎么回事呢?实际上,这与Struts 2的设计哲学有关,Struts 2为了简化Action类的测试,将Action类与Servlet API完全分离,因此getSession方法的返回值类型是Map,而不是HttpSession。
虽然ActionContext的getSession返回的不是HttpSession对象,但Struts 2的系列拦截器会负责该Session和HttpSession之间的转换。
为了可以跟踪用户信息,我们修改Action类的execute方法,在execute方法中通过ActionContext访问Web应用的Session。修改后的execute方法代码如下:
//处理用户请求的execute方法
public String execute() throws Exception
{
//当用户请求参数的username等于scott,密码请求参数为tiger时,返回success字符串
//否则返回error的字符串
if (getUsername().equals("scott")
&& getPassword().equals("tiger") )
{
//通过ActionContext对象访问Web应用的Session
ActionContext.getContext().getSession().put("user" , getUsername());
return SUCCESS;
}
else
{
return ERROR;
}
}
上面的代码仅提供了Action类的execute方法,该Action类的其他部分与前面的Action类代码完全一样。在上面的Action类通过ActionContext设置了一个Session属性:user。为了检验我们设置的Session属性是否成功,我们修改welcome.jsp页面,在welcome.jsp页面中使用JSP 2.0表达式语法输出Session中的user属性。下面是修改后的welcome.jsp页面代码:
<%@ page language="java" contentType="text/html; charset=GBK"%>
<html>
<head>
<title>成功页面</title>
</head>
<body>
欢迎,${sessionScope.user},您已经登录!
</body>
</html>
上面的JSP页面与前面的JSP页面没有太大改变,除了使用了JSP 2.0语法来输出Session中的user属性。关于JSP 2.0表达式的知识,请参看笔者所著的《轻量级J2EE企业应用实战》一书的第2章。
在如图2.1所示页面的“用户名”输入框中输入scott,在“密码”输入框中输入tiger,然后单击“登录”按钮,将看到如图2.4所示的页面。
在上面登录成功的页面中,已经输出登录所用的用户名:scott,可见在Action通过ActionContext设置Session是成功的。
5.3 添加处理信息
到目前为止,Action仅仅控制转发用户请求,JSP页面并未获得Action的处理结果。对于大部分Web应用而言,用户需要获得请求Action的处理结果,例如,在线购物系统需要查询某个种类下的商品,则Action调用业务逻辑组件的业务逻辑方法得到该种类下的全部商品,而JSP页面则获取该Action的处理结果,并将全部结果迭代输出。
下面将为应用增加一个Action,该Action负责获取某个系列的全部书籍。为了让该Action可以获取这系列的书籍,我们增加一个业务逻辑组件,它包含一个业务逻辑方法,该方法可以获取某个系列的全部书籍。
下面是系统所用的业务逻辑组件的代码:
public class BookService
{
//以一个常量数组模拟了从持久存储设备(数据库)中取出的数据
private String[] books =
new String[]{
"Spring2.0宝典" ,
"轻量级J2EE企业应用实战",
"基于J2EE的Ajax宝典",
"Struts,Spring,Hibernate整合开发"
};
//业务逻辑方法,该方法返回全部图书
public String[] getLeeBooks()
{
return books;
}
}
上面的业务逻辑组件实际上就是MVC模式中的Model,它负责实现系统业务逻辑方法。理论上,业务逻辑组件实现业务逻辑方法时,必须依赖于底层的持久层组件,但此处的业务逻辑组件则只是返回一个静态的字符串数组——因为这只是一种模拟。
注意 此处的业务逻辑组件只是模拟实现业务逻辑方法,并未真正调用持久层组件来获取数据库信息。
在系统中增加如下Action类,该Action类先判断Session中user属性是否存在,并且等于scott字符串——这要求查看图书之前,用户必须已经登录本系统。如果用户已经登录本系统,则获取系统中全部书籍,否则返回登录页面。
新增的Action类的代码如下:
public class GetBooksAction implements Action
{
//该属性并不用于封装用户请求参数,而用于封装Action需要输出到JSP页面信息
private String[] books;
//books属性的setter方法
public void setBooks(String[] books)
{
this.books = books;
}
//books属性的getter方法
public String[] getBooks()
{
return books;
}
//处理用户请求的execute方法
public String execute() throws Exception
{
//获取Session中的user属性
String user = (String)ActionContext.getContext().getSession().
get("user");
//如果user属性不为空,且该属性值为scott
if (user != null && user.equals("scott"))
{
//创建BookService实例
BookService bs = new BookService();
//将业务逻辑组件的返回值设置成该Action的属性
setBooks(bs.getLeeBooks());
return SUCCESS;
}
else
{
return LOGIN;
}
}
}
通过上面的Action类,我们发现Action类中的成员属性,并不一定用于封装用户的请求参数,也可能是封装了Action需要传入下一个JSP页面中显示的属性。
提示 Action中的成员属性,并一定用于封装用户的请求参数,也可能是封装了Action需要传入下一个页面显示的值。实际上,这些值将被封装在ValueStack对象中。
当我们的控制器需要调用业务逻辑方法时,我们直接创建了一个业务逻辑组件的实例,这并不是一种好的做法,因为控制器不应该关心业务逻辑组件的实例化过程。比较成熟的做法可以利用工厂模式来管理业务逻辑组件;当然,目前最流行的方式是利用依赖注入——这将在后面章节里介绍。
注意 实际项目中不会在控制器中直接创建业务逻辑组件的实例,而是通过工厂模式管理业务逻辑组件实例,或者通过依赖注入将业务逻辑组件实例注入控制器组件。
该Action处理用户请求时,无需获得用户的任何请求参数。将该Action配置在struts.xml文件中,配置该Action的配置片段如下:
<!-- 定义获取系统中图书的Action,对应实现类为lee.GetBooksAction -->
<action name="GetBooks" class="lee.GetBooksAction">
<!-- 如果处理结果返回login,进入login.jsp页面 -->
<result name="login">/login.jsp</result>
<!-- 如果处理结果返回success,进入showBook.jsp页面 -->
<result name="success">/showBook.jsp</result>
</action>
当用户向getBooks.action发送请求时,该请求将被转发给lee.GetBooksAction处理。
Struct(二)的更多相关文章
- <转> Struct 和 Union区别 以及 对内存对齐方式的说明
转载地址:http://blog.csdn.net/firefly_2002/article/details/7954458 一.Struct 和 Union有下列区别: 1.在存储多个成员信息时,编 ...
- C++混合编程之idlcpp教程Python篇(6)
上一篇在这 C++混合编程之idlcpp教程Python篇(5) 第一篇在这 C++混合编程之idlcpp教程(一) 工程PythonTutorial4中加入了四个文件:PythonTutorial4 ...
- C++混合编程之idlcpp教程Lua篇(6)
上一篇在这 C++混合编程之idlcpp教程Lua篇(5) 第一篇在这 C++混合编程之idlcpp教程(一) 工程LuaTutorial4中加入了四个文件:LuaTutorial4.cpp, Tut ...
- C#。总结
数据类型--变量与常量--运算符与表达式--语句(if,for)--数组--函数--结构体一.数据类型: (一)内建类型 整型(int short long byte uint ushort ulon ...
- C# 引用类型与值类型在编码上的区别
一.引入类型与值类型简介 值类型:直接存放于栈中,取的时候是直接取得值.值类型继承自System.ValueType.(自定义对象) 引用类型:存在于托管堆中,取的时候是从栈取该对象的地址,然后用这个 ...
- C# 10 总复习
数据类型--变量与常量--运算符与表达式--语句(if,for)--数组--函数--结构体 一.数据类型: (一)内建类型 整型(int short long byte uint ushort ulo ...
- C#类型简述
一.值类型 1.布尔类型 bool,范围 true false 2.整数类型 sbyte,范围 -128~127 byte,范围 0~255 short,范围 -32768~32767 ushort, ...
- 4. Go语言—值类型和引用类型
一.值类型 1. 定义 变量直接存储的值,内存通常在栈中分配: var i = 5 -> i-->5 2. 应用 int.float.bool.string.数组.struct 二.引 ...
- C#阶段小结
一.数据类型: (一)内建类型: 整型(int ,short, long ,byte ,uint ,ushort, ulong ,sbyte): 浮点型(double float decimal): ...
- VFS四大对象之二 struct inode
继上一篇文章:http://www.cnblogs.com/linhaostudy/p/7427027.html 二.inode结构体:(转自http://blog.csdn.net/shanshan ...
随机推荐
- 安装oracle11g时遇到INS-13001环境不满足最低要求
在安装oracle11g,点击setup.exe之后,弹出了如下提示框: 解决方法: 首先,打开你解压后的database文件夹,找到stage,然后cvu,找到cvu_prereq.xml文件,用记 ...
- simple简单消息队列
一:介绍 1.优缺点 简单,但是耦合性较高. 这种模式是生产者与消费者一一对应,就是一个产生者,有一个消费者来消费. 如果,多个消费者想消费一个队列中的消息就不适合了.这种情况在后面会接着介绍. 2. ...
- Unity 之 如何删除Unity项目里面没用的东西??
选中需要用到的Scene,右键选 Select Dependencies,这样会选出这个场景所有用到的文件,将这些文件导出为 .unitypackage. 用同样的办法就所有用到的几个场景的文件分别导 ...
- VsCode下代码导航
Visual Studio Code具有高效的代码编辑器,当与编程语言服务结合使用时,可以为您提供IDE的强大功能和文本编辑器的速度.在本主题中,我们将首先描述VS Code的语言智能功能(建议,参数 ...
- codeforces 366C Dima and Salad 【限制性01背包】
<题目链接> 题目大意: 在一个水果篮里有n种水果,并且这些水果每一种都有一个美味度和一个卡路里的属性, 小明要从这些水果中选出来一些做一个水果沙拉, 并且要求他的水果沙拉的美味度是卡路里 ...
- linux学习之使用fdisk命令进行磁盘分区(八)
linux下使用fdisk命令进行磁盘分区 目录 分区类型 分区方法表示 文件系统 fdisk命令分区过程 分区类型 主分区:总共最多只能分四个 扩展分区:只能有一个,也算作主分区的一种,也就是说主分 ...
- 李宏毅机器学习笔记1:Regression、Error
李宏毅老师的机器学习课程和吴恩达老师的机器学习课程都是都是ML和DL非常好的入门资料,在YouTube.网易云课堂.B站都能观看到相应的课程视频,接下来这一系列的博客我都将记录老师上课的笔记以及自己对 ...
- vue+axios实现移动端图片上传
在利用vue做一些H5页面时,或多或少会遇到有图片上传的操作,主要是运用html5里面的input[type=file]来实现,传递到后端的数据是以二进制的格式传递,所以上传图片的请求与普通的请求稍微 ...
- AGC 027C.ABland Yard(拓扑/二分图)
题目链接 \(Description\) 给定一张图(可能存在自环),每个点上有A或B.求是否存在一条路径,使得在上面不断走,能够得到所有AB串组合(可以重复经过点). \(n\leq2\times1 ...
- node+express上传图片
注意: 别用multer 上传文件了,太坑了,普通文本获取不到,折腾了半天没有解决,最后采用 multiparty 解决了: <!DOCTYPE html><html> < ...