3.Struts 2对Action的具体操作

目录


Struts 2专栏目录(点击进入…)



MVC模式

MVC模式核心是控制器对所有请求的进行统一的处理。

Struts 2的控制器StrutsPrepareAndExecuteFilter由Servlet API中的Filter充当,当Web容器接收到登录请求后,将请求交由在web.xml中配置的过滤器StrutsPrepareAndExecuteFilter。


Struts 2执行流程

(1)当Web容器接收到请求后,将请求交由在web.xml中配置的struts 2框架的控制器StrutsPrepareAndExecuteFilter(核心控制器)
(2)由StrutsPrepareAndExecuteFilter确定请求对应的Action(业务控制器)
(3)框架根据Action返回的结果字符串,由StrutsPrepareAndExceuteFilter(核心控制器)选择对应的result,将结果呈现给用户

在这里插入图片描述


1.web.xml

任何一个Web应用程序都是基于请求/响应模式进行构建的,无论是采用哪种MVC框架,都离不开web.xml的文件配置。web.xml是所有Java Web应用程序都需要的核心文件

Struts 2框架需要在web.xml中配置其核心控制器StrutsPrepareAndExecuteFilter,用于对框架进行初始化,以及处理所有的请求。

StrutsPrepareAndExecuteFilter可以包含一些参数,经常使用config,要加载的XML形式的配置文件列表(多个配置文件以逗号分隔),如果没有设置这个参数,Struts 2框架将默认加载struts-default.xml、struts-plugin.xml和struts.xml。

StrutsPrepareAndExecuteFilter作为一个Filter在Web应用中运行,它负责拦截所有的用户请求,当用户请求到达时,该Filter或过滤用户请求。如果用户请求以“.action”结尾,该请求将被输入Struts 2框架进行处理。

Struts 2核心控制器

<filter>
	<filter-name>demo</filter-name>
	<filter-class>
		org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
	</filter-class>
</filter>
<filter-mapping>
	<filter-name>demo</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

2.struts.xml

包含package、action、result等的配置,主要负责管理Struts 2框架的业务控制器。

constant元素用于配置常量,通过配置常量可以改变Struts 2框架的一些行为,包含两个属性:
①name:常量的名称
②value:常量的值

当Struts 2接收到一个请求时,框架会将URL分为namespace和action名称两部分,框架首先在namespace命名空间中查找这个action,若没有找到则再在默认命名空间中查找。

|- package元素:Struts 2框架会将action、result等组织在一个名为package(定义包)的逻辑单元中,从而简化维护工作,提高重用性。每个包都包含了将要用到的action、result等的定义

|- package属性
	|-  name属性:必须的并且唯一的,用来指定包的名称(被其他包引用)
	|- extends属性:类似于Java的extends关键字,指定要扩展的包。在开发的过程,除非有令人信服的理由,否则所定义的包应该总是扩展struts-default	包。Struts-default包由Struts 2框架定义,其中配置了大量常用的Struts 2的特性;若是没有这些特性,则连简单地在action中获取请求数据都无法完成
	|- namespace属性:可选,该属性定义该包中action的命名空间。若果没有设置该属性,则action被放入默认命名空间中。

Struts 2框架使用action的名称和它所在包的命名空间来标识一个action,默认命名空间用””表示,也可以使用”/”定义一个根命名空间,二者是由区别的。

当请求Web应用程序根路径下的action,框架在根命名空间中查找对应的action,如果在根路径下未找到,则再到默认命名空间中去查找


处理中文乱码

<constant name=”struts.il8n.encoding” value=”utf-8”/>

可配置的常量均可在struts2-core-2.3.16.3.jar下的org/apache/struts2/default.properties文件中找到
另外一种方式,是在源文件根目录下创建struts.properties来覆盖default.properties中的设置,格式和default.properties相同,都属于properties文件。


拆分配置文件

将所有的配置文件都放在一个配置文件中必然会导致struts.xml文件变得臃肿,为了提高struts.xml文件的可读性,Struts 2允许将一个配置文件拆分为多个配置文件,但默认只加载WEB-INF/classes下的struts.xml文件
一旦拆分后,还要能够拆分过的文件整合在一起,可以在struts.xml文件中通过include元素将其他配置文件包含进来。include元素提供file属性,该属性指定了被包含配置文件的文件名。

<struts>
	<!-- 文件名,默认加载WEB-INF/classes下的struts.xml文件 -->
	<include file=”struts-name.xml”>
</struts>

被保存在WIN-INF/classes下,与struts.xml的结构完全一样。当系统加载struts.xml后便会自动加载所包含的所有配置文件。


struts-default.xml
Struts 2框架的默认配置文件,为框架提供默认的设置,该配置文件会自动加载

struts-plugin.xml
Struts 2插件使用的配置文件,如果不是开发插件,则不需要编写这个配置文件

基本结构:

<struts>
	<package name="default" namespace="/" extends="struts-default">
		<action name="world"uri class="全限定类名" method="world"Action方法名>
			<result name="success"Action返回值>/show.jsp</result>
		</action>
	</package>
</struts>

Result的配置

result元素的作用是实现结构视图的调用,并决定视图以哪种形式展现给客户端(用来设定Action处理结果后,下一步准备干什么)

Struts 2的Action处理用户请求结束后,返回一个普通字符串(逻辑视图名称)。必须在struts.xml文件中完成逻辑视图和物理视图资源的映射,才可以让系统转到实际的视图资源。

通过strtuts.xml文件中使用<result……/>元素类配置结果

Result的配置有两部分组成:
①一部分是Result所代表的实际资源的位置及Result名称(name)
②另一部分是Result的类型(type)

Result的类型(type)描述
dispatherAction元素的type属性的默认结果类型,采用转发的形式请求指定的视图资源,请求中数据信息不回丢失
redirect采用重定向的方式请求指定的视图资源,通过HttpServletResponse对象的sendRedirect()方法重新生成一个请求,原请求中的数据或丢失
redirectAction采用重定向的方式请求一个新的Action,原请求中的数据信息会丢失
常用的结果类型(type)
1.dispatcher类型

默认结果类型,用来转发;Action的处理结果将自动以dispatcher(转发)方式请求指定的视图资源

2.redirect类型

与上者的主要差别是在于,使用dipatcher结果类型是将请求转发(forward)到指定的视图资源,所以请求中包含数据信息依然存在;而redirect结果类型是在内部使用HttpServletResponse对象的sendRedirect()方法将请求重定向至指定的URL,这意味着请求中包含的参数、属性、Action实例及Action封装的属性将全部丢失

3.redirectAction类型

与redirect类型相似。都使用HttpResponse对象的sendRedirect()方法将请求重定向至指定的URL。但redirectAction类型主要用于重定向到另一个Action。也就是说,当请求处理完成后,需要在另一个Action中继续处理请求时,就要使用redirectAction结果类型重定向到指定的Action。

redirect和redirectAction
对于redirect和redirectAction二者,都是使用HttpResponse对象的sendRedirect()方法将请求重定向至指定的URL
redirect主要用于执行对一个具体的资源(JSP)
redirectAction主要用于执行对一个Action的请求(也就是URL)


动态结果

动态结果就是指在配置时,不知道执行后的结果是哪一个,只有在运行时才能知道哪个结果作为视图显示给用户,即在配置时使用表达式,在运行时,由框架根据表达式的值来确定要使用哪个结果。

例如:
使用${nextDispose}来获取Action中nextDispose属性的值,这个值在运行时才能知道,框架在解析出${nextDispose}的值,然后将请求重定向到指定的Action。

需要注意的是,使用${属性名}语法访问的属性一定要在Action中存在(也就是咋class属性绑定的Action类中存在nextDispose属性),并且Action要提供该属性的getter方法。


全局结果

也就是多个Action共享一个结果。全局结果也在包中定义(package元素),这个包中的多有Action都可以共享这个结果(result)。

语法:

<global-results>
	<result name=”” type=””></result>
</global-results>

全局结果也同样使用result元素配置,与action配置result元素的区别在于,全局结果需要在global-results元素中嵌套result元素,如果在Action中的result元素的名称与全局结果的名称相同时,Action中的result元素会覆盖global-results的属性。

也就是说,当Action处理用户请求结束后,会首先在本Action中result结果中搜索与逻辑视图名称对应的结果,只有在Action中无法找到与逻辑视图对应的结果时,才会去全局结果中寻找并执行(可以说Java类的全局变量和局部变量的关系)


3.Action

Action类在处理完用户请求后,会返回一个处理结果。这个结果是一个简单的字符串,框架根据这个字符串选择对应的Result,因此称其为逻辑视图名称;这个逻辑视图名称由result元素的name属性来表示。

result元素的值用来指定这个逻辑视图对应的物理视图资源(JSP,HTML,CSS)的位置;逻辑视图名称只有与物理视图资源联系在一起,才能发挥作用

注意:
1.Action作为业务控制器,只负责返回结果,而不与视图相关联,这样做的优势在于,当视图发生变化时,无须修改Action类的代码,仅需修改配置文件
2.当StrutsPrepareAndExecuteFilter(核心控制器)调用相应的视图时,默认采用转发的形式跳转到指定的JSP页面

使用Struts 2框架,主要的编码工作就是编码处理 请求的Action类。在Struts 2中,提供了多种实现Action的方式。在Action中,所有用于处理请求的方法都必须返回一个字符串类型的逻辑结果,用于标识要呈现给用户的结果

可以直接使用Action类的属性接收用户的输入,即当表单提交时,Struts 2自动对请求参数进行转换,并对具有相同名字的Action属性进行赋值(通过setter方法)

Action类的属性除了可以用来接收请求的数据,还可以用来输出处理结果,依然借助setter和getter方法对结果属性进行处理。只要对属性设置了setter和gettter方法,该属性就可以被自动处理。此外,Action类中还可以使用复杂的属性,如用户自定义类、数组、集合对象等

Action接口中常量字符串的逻辑含义

常量逻辑含义
SUCCESS“success”表示程序处理正常,并返回给用户成功后的结果
NONE“none”表示处理正常结束,但不返回给用户任何显示
ERROR“error”表示处理结果失败
INPUT“input”表示需要更多用户输入才能顺利执行
LOGIN“login”表示需要用户正确登录后才能顺利执行

在Struts 2中控制器由两部分组成
(1)核心控制器(Filter):用于拦截请求,对请求进行处理
(2)业务控制器(Action):调用相应的Model类实现业务处理,返回结果

在Struts 2配置文件中,包含了以下元素:
(1)package元素
用于定义处理请求的逻辑单元,name属性为必需的并且唯一,用来指定包的名称(被其他包引用);

①extends属性
类似于Java的关键字,用于指定扩展的包;namespace指定命名空间


(2)package元素的action子元素
用于配置Struts 2框架的“工作单元”Action类。action元素将一个请求的URI(action的名字)对应到一个Action类。name属性是必需的,用来表示action的名字;class属性可选,用于设定Action类的全限定名。

result元素用来设定Action类处理结束后,系统下一步将要做什么。name属性表示result的逻辑视图名称,必须与Action类返回的字符串进行匹配;而result元素的值表示与逻辑视图名称对应的物理资源之间的映射,用来指定这个结果对应的实际资源的位置

Filter用来接收用户请求,在对数据进行简单处理后创建Action实例,然后调用Action的方法;Action实例的创建由web.xml中的配置决定

在配置文件中将一个请求的URI(action的名字)对应到一个Action类,当一个请求匹配某个Action的名字时,框架就会使用者个Action类处理请求。

action元素中的name属性是必需的,表示action的名字,用于匹配请求的URI;class属性表示Action类的全限定类名,即决定了该action的实现类。


Action配置

Action的作用?

Action是应用的核心。开发者需要提供大量的Action类,并在struts.xml文件中配置Action

主要有三个作用:
①Action最重要的作用是为给定的请求封装需要做的实际工作(调用特定的业务处理类)
②为数据的转移提供场所
③帮助框架决定由哪个结果呈现请求响应

1.封装工作单元

可以把Action看作控制器的一部分,其主要职责就是控制业务逻辑,通常Action使用execute()方法实现这一功能(execute也是默认调用的方法)

2.数据转移的场所

Action作为数据转移的场所,也许有人会认为这会使Action变得复杂,实际上使得Action更加简洁
由于数据保存在Action中,在控制业务逻辑的过程中可以非常方便地访问它们
或许一系列的JavaBean属性增加Action的代码量,但执行execute()方法时引用这些属性中保存的数据,会使Action的代码变得简洁(不再需要从request对象中获取请求数据),并且使我们开发的Action与Servlet API解耦

3.返回结果字符串

Action的最后一个作用是返回结果字符串。Action根据业务逻辑执行的返回结果判断返回何种结果字符串,架构根据Action返回的结果字符串选择对应的视图组件呈现给用户


method属性

在执行程序中,每实现一个功能都会去创建一个Action,并完成相应的方法;method属性的值,对应着Action内的方法,是哪个就调用哪个

查找执行方法有两种:
(1)查找与method属性值完全一致的方法
(2)查找doMethod()形式的方法

例如:method=”login”,会先查找login()、找不到则会查找doLogin()方法。

Action中动态方法调用
为了减少配Action的数量,可以使用动态方法进行处理。

动态方法调用(Dynamic Method Invocation,DMI)是指表单元素的action并不是直接等于某个Action的名称,而是通过在Action的名称中使用感叹号(!)来标识要调用的方法名称,格式为actionName!methodName.action。

动态调用可能会带来安全隐患(通过URL可以执行Action中的任意方法),所以在确定使用动态方法调用时,应该确保Action中的所有方法都是普通的,开放的方法。基于这个原因Struts 2框架默认禁止动态方法调用,有default.properties中的struts.enable.DynamicMethodInvocation属性设置,默认为false,可以在struts.xml文件中,通过constant元素将其设置为true启用动态方法调用。

<constant name=”struts.enable.DynamicMethodInvocation” value=”true” />

使用method属性调用不同的方法与动态方法调用的适用条件如下
(1)如果同一个Action的不同方法要处理的请求使用相同的配置(result等),则使用动态方法调用
(2)如果不同方法的调用需要不同的配置,那么就要使用action元素的method属性,为同一个Action配置多个名称,但使用method属性会导致配置文件中存在大量的Action配置

从安全角度出发,建议采用method属性来实现同一个Action的不同方法处理不同的请求。但是随着Action的逐渐增多,导致在struts.xml文件中存在大量的Action配置

Action中通配符的使用
在配置<action ……/>元素时,需要指定name、class、method属性,其中name属性支持通配符,在class、method属性中可以使用表达式
这种使用通配符的方式是另一种形式的动态方法调用通配符用星号(*)表示,用于配置0个或多个字符串


配置默认的Action

Struts 2框架允许指定一个默认的Action,即如果没有一个Action匹配请求,那么默认的Action将被执行
配置默认的Action通过<default-action-ref……/>元素完成,在每个package下只能有一个<default-action-ref……/>元素。

指定其name属性为当前package、子package、父package三者中的一个Action name,如果在某一继承树上的个package中分别定义了多个<default-action-ref……/>元素

则搜索顺序:由子package往父package寻找,找到即停止


获取表单中的数据

(1)使用ActionContext类获取(继承ActionSupport)

方法描述
static ActionContext getContext()获取当前线程的ActionContext对像
Map<String,Object> getParameters()返回一个含有HttpServletRequest参数信息

(1)因为方法不是静态的,需要创建ActionContext类对象
(2)这个ActionContext对象不是new出来的

对于表单input元素的name属性的值可以随便命名

@Override
public String execute() throws Exception {
	//第一种使用ActionContext获取
	//1、获取ActionContext对象方法,获取表单数据源
	ActionContext context = ActionContext.getContext();
	//2、调用方法得到表单数据
	//key是表单name属性value是值
	Map<String, Object> map=context.getParameters();
	
	Set<String> keys=map.keySet();
	for(String key:keys){
		//根据key得到value
		//数组形式:因为输入项里可能有复选框
		Object obj[]=(Object[])map.get(key);
		System.out.println(key+":"+Arrays.toString(obj));
	}
	return NONE;
}

(2)使用ServletActionContext获取(继承ActionSupport)

方法描述
static HttpServletRequest()获取Web应用的 HttpServletRequest对象
static HttpServletResponse()获取Web应用的 HttpServletResponse对象
static ServletContext.getServletContext()获取Web应用的 ServletContext对象
static PageContext.getPageContext()获取Web应用的 PageContext对象

调用类里头的静态方法,得到request对象
对于表单input元素的name属性的值跟getParameter()中的值对应。

@Override
public String execute() throws Exception {
	// 第二种种使用ServletActionContext获取
	// 1、用ServletActionContext获取request
	HttpServletRequest request = ServletActionContext.getRequest();
	// 2、调用request里面的方法得到结果
	String username = request.getParameter("username");
	String password = request.getParameter("password");
	
	System.out.println("username:" + username);
	System.out.println("password:" + password);
	return NONE;
}

(3)使用接口注入方式获取(了解,实现ServletRequestAware接口)

实现的接口描述
ServletRequestAware实现该接口的action可以直接访问Web应用的HttpServletRequets实例
ServletResponseAware实现该接口的action可以直接访问Web应用的HttpServletResponse实例
SessionAware实现该接口的action可以直接访问Web应用的HttpSession实例
ServletContextAware实现该接口的action可以直接访问Web应用的ServletContext实例

//定义成员request
private HttpServletRequest req;

@Override
public void setServletRequest(HttpServletRequest req) {
	this.req=req;       //获取到request
}

@Override
public String execute() throws Exception {
	String username = req.getParameter("username");
	return NONE;
}

获取并封装表单中的数据

(1)采用属性封装(继承ActionSupport)

/* 属性封装
 * 提供成员变量、属性值和表单输入项的name一致需要提供set方法
 */
private String username;
private String password;

//**************省略setter方法
// 注意:表单的name值要跟属性名一致
// 默认走这个方法,NONE没有返回值
public String execute() {
	User user = new User();
	user.setUsername(username);
	user.setPassword(password);
	return NONE;
}

(2)模型驱动封装(重点)(继承ActionSupport并且实现ModelDriven)

private User user = new User();

@Override
public User getModel() {
	return user;
}

// 默认走这个方法,NONE没有返回值
public String execute() {
	System.out.println(user.getPassword() + "   " + user.getUsername());
	return NONE;
}

(3)表达式封装对象(继承ActionSupport)

/**
 * 不能实例化,框架会自动实例化
 * /
private User user;   

public User getUser() {
	return user;
}

public void setUser(User user) {
	this.user = user;
}

// 表单中的name属性使用user.username;username与User中的属性对应;也就是  实体对象.属性名
// 默认走这个方法,NONE没有返回值
public String execute() {
	System.out.println((User)user);
	return NONE;
}

(4)List集合封装(继承ActionSupport)

private List<User> list;

public List<User> getList() {
	return list;
}

public void setList(List<User> list) {
	this.list = list;
}

// 表单name属性,list[0].username   集合名[下标].User类属性
public String execute() {
	System.out.println(list);
	return NONE;
}

(5)Map集合封装(继承ActionSupport)

private Map<String,User> map;

public Map<String, User> getList() {
	return map;
}

public void setList(Map<String, User> map) {
	this.map = map;
}

// 表单元素name属性   map[‘one’].username    Map名[‘键’].User属性
public String execute() {
	System.out.println(map);
	return NONE;
}

将数据发送至表示页面

操作request、session、application

/**
 * 操作作用域:request session application
 * /
// 默认走这个方法,NONE没有返回值
// 如果使用request转发,将需要改变result的type的值为“dispatcher”
public String execute() {
	HttpServletRequest req = ServletActionContext.getRequest();
	req.setAttribute("req", "reqqqqq");
	req.getSession().setAttribute("sess", "sesssss");
	ServletActionContext.getServletContext().setAttribute("app", "appssssssssss");
	return "success";
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未禾

您的支持是我最宝贵的财富!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值