文章目录
一、Struts2 简介
(1)Struts2是一个基于MVC设计模式的Web应用框架,Struts2现在属于Apache软件基金会,是旗下的一款开源的框架,Apache最早开发了一款Struts框架,在行业内流行了很长一段时间。其后由另外一个组织OpenSymphony开发了一款同类型框架叫做webwork,由于webwork对于web项目的表现层提供了更多的支持(例如FreeMarker),业内慢慢的将目光投向了webwork,并广泛的使用webwork进行开发,后来Apache收购了webwork,在webwork的基础上融入了Struts的优点形成了我们现在广泛应用的框架Struts2。
(2)Struts2对于web开发的整个过程中需要进行的乱码处理、参数获取、异常处理、视图层渲染,AJAX、文件上传、文件下载等进行了封装,大大的减少web项目的开发周期。而且这种封装采用的是可拔插的设计方式(Struts2拦截器),可以根据自己的业务需求灵活的集成。在其后又提供了基于注解的配置方式和完全省去繁琐配置的约定大于配置的开发方式,渐渐的被大众所接受,成为了JAVA程序员在MVC框架中的必学框架,直到现在依然有大量的企业在使用Struts2进行开发。
二、Struts2 开发示例
1、Struts2 开发示例步骤
(1)在Struts2的官网下载Struts2的开发包,截止目前为止Struts2官网推荐使用的最新版本是2.5.20,以下是下载地址:http://mirrors.tuna.tsinghua.edu.cn/apache/struts/2.5.20/struts-2.5.20-all.zip
(2)解压开发包,目录如下
- apps:示例程序
- docs:开发文档
- lib:Struts2的包以及一部分Struts2的依赖包
- src:源码
(3)在Eclipse中新建web项目
在web项目的web-inf/lib文件夹中导入以下必要的开发包
(4)在web.xml中加载Struts2的核心控制器,Struts2的核心控制器是一个Filter,该Filter是整个Struts2中最重要的组件,它负责了请求分发,结果响应,以及加载各种类型的拦截器来完成各项工作。在定义Filter过滤的地址规则时,可以直接拦截/*,Struts2会自动判断请求类型并对静态资源放行(Struts2默认无后缀和.action后缀才会进行请求分发,否则直接放行)。
配置过程如下:
<filter>
<filter-name>filter</filter-name>
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>filter</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
(5)新建业务控制器类 TestAction 并继承 ActionSupport 类。
public class TestAction extends ActionSupport{
public String test() {
System.out.println("又要打印我");
return "success";
}
}
(6)在src目录下新建 struts.xml 文件,该文件用于进行请求地址与Action的映射,以及逻辑视图与物理视图的映射,注意该文件只能写在src目录之下,并且文件名称区分大小写。配置方式如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<package name="default" namespace="/" extends="struts-default">
<action name="login" class="struts.action.RegistAction" method="regist">
<result name="success">/success.html</result>
</action>
</package>
</struts>
标签说明:
- struts:struts.xml文件的根目录
- package: 逻辑层面的包,在一个包下可以配置多个 action 请求映射信息。
- name 属性表示该包的名称
- namespace 表示该包下的所有 action 请求的根路径
- extends 表示当前包所继承的另外一个包
- struts-default 是struts2默认定义的一个包,该包位于 struts 核心 jar 包的 struts-default.xml 文件中,struts-default这个包中定义了,常规web项目中所需要引用的一系列拦截器,例如:参数拦截器、 上下文拦截器、国际化拦截器、参数校验拦截器、文件上传与下载拦截器等等。
- action:用于进行请求地址映射的标签
- name属性用于描述请求地址名称前缀
- class属性表示该请求需要执行的业务控制器类
- method表示该请求要执行的方法名称。
- result:用于进行逻辑视图与物理视图的映射
- name属性表示逻辑视图名称 name 属性默认success,result 标签之间的内容表示该逻辑视图响应的物理视图地址。(默认用转发的方式响应)
(7)在项目中新建 index.html 和 success.html,在 index.html 中通过表单请求、超链接发送test或者 test.action,请求都可以成功的执行到 TestAction 业务控制器之下的 execute 方法。
① index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="test.action">点我</a>
</body>
</html>
② success.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
测试成功
</body>
</html>
- 注意:因为 TestAction 继承的父类 ActionSupport 类中,在该类中拥有一个 execute 方法,当在 action 标签中没有明确的指定执行业务控制器的那个方法时,会默认执行 execute 方法,TestAction 中没有 execute 方法,所以自然会执行父类中的 execute 方法。
- 并且父类的 execute 方法默认返回值就是 success,在该 action 映射信息中,success 映射的地址是 success.html(result 标签之间的内容),所以最终页面成功的响应到了success.html。
2、Struts2 的执行过程
下图是 struts2 在开发文档中提供的一张 Struts2 运行流程图
分析
(1)浏览器发送请求,所有的请求通过一系列过滤器以及 Struts2 的核心控制器,进入 Filter,执行 Filter 中的 doFilter 方法。
(2)执行 ActionMapper 判断当前请求是否需要是业务请求还是静态资源请求,如果是静态资源请求则执行响应静态资源,如果是业务请求则需要执行对应的业务控制器 Action。
(3)执行 Action之前,首先 Struts2 会去读取 struts.xml 文件,判断在 struts.xml 文件中是否有映射信息,如果没有该请求地址的映射信息则会抛出异常,如果找到了该映射信息,则会创建 Action 对象、拦截器链对象,以及该映射信息中业务控制器类的代理对象 。
(4)代理对象创建完成以后,会先根据 struts.xml 中的配置执行对应的拦截器,默认情况下会执行包括参数拦截器、上下文拦截器、国际化拦截器、参数校验拦截器等等在内的多个拦截器,用于参数获取、作用域注入等等相关的工作。
(5)执行完所有的拦截器以后,才会去执行最终的业务控制器Action。
(6)根据业务控制器 Action 中返回的值得到对应逻辑视图信息,然后响应最终的物理视图信息至浏览器。
三、在 Action 中接收请求参数
接收客户端传递的参数在web项目中,是一个必不可少而又相当繁琐的一个过程,Struts2使用拦截器完成了参数的自动获取和自动注入功能以及参数自动转型的功能,我们可以很简单获取到客户端传递到服务器的数据。
1、单个或者零散的参数
(1)单个参数或者零散的参数,无论是表单提交、地址栏传参还是ajax传参,只需要根据参数名称在Action中定义对应类型的成员变量,并为变量提供get和set方法,Struts2在获取到参数以后会自动根据Action中定义的成员变量类型转换数据类型,并将参数注入到Action的成员变量中。
(2)Demo
① 表单请求
<form action="login.action" method="post">
<input placeholder="请输入账号" name="name" type="text"><br>
<input placeholder="请输入密码" name="password" type="password"><br>
<input placeholder="请输入年龄" name="age" type="text"><br>
<input name="date" type="date"><br>
<input type="submit" >
</form>
② RegistAction 类:在Action中就需要定义成员变量,并提供get和set方法
public class RegistAction extends ActionSupport{
private String name;
private String password;
private int age;
private Date date;
//省略get、set方法
public String regist() {
System.out.println(userRegist);
return "success";
}
}
接下来就可以在业务控制器对应的方法中直接使用这两个参数。
注意:Struts2在进行参数的类型转换时,如果要将参数类型转为日期类型,必须要保证客户端传入的字符 串日期是标准的yyyy-MM-dd的格式,例如:1999-01-05
2、将参数封装为对应的实体类对象
(1)表单提交、地址栏请求、Ajax中提交到服务器的参数如果比较多,用单个的参数接收方式需要定义很多的成员变量不利于使用,我们可以使用一个实体类对象对多个参数进行统一的接收。
(2)Demo
① 表单请求
<form action="login.action" method="post">
<input placeholder="请输入账号" name="userRegist.name" type="text"><br>
<input placeholder="请输入密码" name="userRegist.password" type="password"><br>
<input placeholder="请输入年龄" name="userRegist.age" type="text"><br>
<input name="userRegist.date" type="date"><br>
<input type="submit" >
</form>
在该表单中的name属性值 users.username 和 users.password 时struts2定义的一种参数传输规则,该规则的含义是,name=”users.username” 的参数会保存到Action中名字为users对象的username属性中,name=”users.password” 的参数会保存到Action中名字为users对象的password属性中。那么为了在Action中为了接收这些参数,就需要定义一个实体类的对象users,提供get和set方法,并且users的类中必须包含username属性和password属性。
② RegistAction 类
public class RegistAction extends ActionSupport{
private UserRegist userRegist = new UserRegist();
public UserRegist getUserRegist() {
return userRegist;
}
public void setUserRegist(UserRegist userRegist) {
this.userRegist = userRegist;
}
public String regist() {
System.out.println(userRegist);
return "success";
}
}
③ UserRegist 实体类
public class UserRegist {
private String name;
private String password;
private int age;
private Date date;
//省略get、set方法
@Override
public String toString() {
return "UserRegist [name=" + name + ", password=" + password + ", age="
+ age + ", date=" + date + "]";
}
}
3、使用模型驱动的方式获取参数
(1)要将多个参数封装为一个对象,除了采用第二种方式之外,还可以采用模型驱动的方式来完成,前端网页表单中的写法保持不变。
(2)Demo
① 表单请求
<form action="login.action" method="post">
<input placeholder="请输入账号" name="name" type="text"><br>
<input placeholder="请输入密码" name="password" type="password"><br>
<input placeholder="请输入年龄" name="age" type="text"><br>
<input name="date" type="date"><br>
<input type="submit" >
</form>
在 Action 中实现 ModelDriven 接口,同时定义接收的参数类型作为该接口的泛型。然后在 Action中实例化一个实体类对象,并重写接口的 getModel 方法,在方法中返回实体类对象。
② RegistAction 类
public class RegistAction extends ActionSupport implements ModelDriven<UserRegist>{
private UserRegist userRegist = new UserRegist();
@Override
public UserRegist getModel() {
return userRegist;
}
public String regist() {
System.out.println(userRegist);
return "success";
}
}
注意:在 Action 中定义的成员变量,不光可以用于接收客户端传递的参数,同时在 Action 响应网页时如果采用的转发的方式,那么 Action 作用域中的成员变量中提供了 get 方法的属性还会保存到 request 作用域中,这种设计方式是 Struts2 将数据保存到 request 作用域的主要方式,而且利用这个特性可以很便捷的实现查询条件的回显。
四、在Action中使用三大作用域
1、在 Action 中有时需要使用 Servlet 中的三大作用域,例如:登陆成功需要将查询到的用户信息保存到 HttpSession对象中,那么就需要在 Action 中获取 HttpSession 对象。
在Action中获取三大作用域对象的方式有三种:
(1)解耦和的方式
ActionContext context = ActionContext.getContext();
Map request = (Map)context.get("request");
Map session = context.getSession();
Map application = context.getApplication();
解耦和的方式并没有直接操作Servlet中的request、session和application,Struts2返回给我们的只是一个键值对,我们向该键值对中新增数据,最终Struts2会将键值对中的数据保存到三大作用域中。
(2)耦合的方式
HttpServletRequest request=ServletActionContext.getRequest();
ServletContext application=ServletActionContext.getServletContext();
HttpSession session=request.getSession();
耦合的方式直接操作三大作用域对象
(3)实现接口的解耦合方式
通过实现对应的接口,重写set方法,set方法中的参数就是Struts2提供的解耦方式的三大作用域对象。