Struts2框架
概述
1. JavaEE中有三层结构,struts2框架应用在JavaEE三层结构中的Web层的框架。
2. struts2框架是在struts1和webwork基础之上发展的一个全新的框架。(完全脱胎换骨)
3. struts2可以解决问题:
需要的jar包
依赖
<!-- Struts2的核心包 --> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-core</artifactId> <version>2.3.16</version> </dependency>
创建action
我们之前的Servlet,Servlet本身就是一个类,而action本身也是一个类,所以我们现在就可以创建一个action。
配置Action路径的访问路径
struts.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <constant name="struts.i18n.encoding" value="UTF-8" ></constant> <package name="hello_demo" extends="struts-default" namespace="/"> <!-- name:最终访问的名称 --> <action name="hello" class="org.atwyl.action.HelloAction" method="execute"> <!-- 配置方法的返回值,到不同的页面中去 --> </action> </package> <!-- 包含了四个配置文件,不指定路径,默认在src路径下时的方式 --> <!-- <include file="struts-order.xml" /> <include file="struts-book.xml" /> <include file="struts-user.xml" /> <include file="struts-cart.xml" /> --> <!-- 配置文件在具体包中的方式 --> <!-- <include file="cn/atwyl/action/struts-right.xml" /> --> <!-- <package name="demo" extends="struts-default" namespace="/"> <action name="saveUserAction" class="org.atwyl.action.UserAction" method="save"> </action> <action name="saveUserAction" class="org.atwyl.action.UserAction" method="update"> </action> <action name="saveUserAction" class="org.atwyl.action.UserAction" method="delete"> </action> <action name="saveUserAction" class="org.atwyl.action.UserAction" method="find"> </action> </package> --> </struts>
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"> <display-name>Struts Blank</display-name> <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.html</welcome-file> </welcome-file-list> <!-- Restricts access to pure JSP files - access available only via Struts action --> <security-constraint> <display-name>No direct JSP access</display-name> <web-resource-collection> <web-resource-name>No-JSP</web-resource-name> <url-pattern>*.jsp</url-pattern> </web-resource-collection> <auth-constraint> <role-name>no-users</role-name> </auth-constraint> </security-constraint> <security-role> <description>Don't assign users to this role</description> <role-name>no-users</role-name> </security-role> </web-app>
Struts2执行的基本过程
当我们从地址栏输入一个地址,点击回车,他相当于发送了一个请求给服务器,发送请求之后,它首先会到过滤器中,其实我们的这个过程都是由这个过滤器帮我们决定的。过滤器会在启动服务器的时候,被创建过滤器一旦创建会做很多的事情:如下图五个步骤
Struts2源代码的查看
这里本身是个过滤器,StrutsPrepareAndExecuteFilter这个过滤器的名称,防止面试的时候问起。
-① 过滤器会在服务器启动的时候被创建,他会执行里面的init()方法
-② 在init方法里面会加载很多的配置文件
- 有些是struts2自带的,也会加载我们自己写的struts.xml。我们可以通过源代码来查看一下:
第一步是进入过滤器init方法,然后找到init.initDispatcher(config); 按住Ctrl键点击进去,然后找到
一、在init方法中,调用了init的initDispatcher的方法来加载配置文件,进入该代码中……
二、我们发现这个方法有调用了dispatcher的init方法,进入init方法内部……
三、下面这些[1]、[2]、[3]、[5]、[6]、[7]就是用来加载Struts2配置文件的。
init_DefaultProperties(); // [1]
- 加载org.apache.struts2.default.properties配置的是struts2的所有的常量
init_TraditionalXmlConfigurations(); // [2]
- 加载struts-default.xml、struts-plugin.xml
init_LegacyStrutsProperties(); // [3]
-加载用户自定义的struts.properties
init_CustomConfigurationProviders(); // [5]
-加载用户配置的提供对象
init_FilterInitParameters() ; // [6]
-加载web.xml
init_AliasStandardObjects() ; // [7]
-加载标准对象
四、
五、
加载顺序:
* default.properties
* struts-default.xml
* struts-plugin.xml
* struts.xml ------配置action以及常量
* struts.properties ------配置常量
* web.xml ------配置核心过滤器及常量
前三个配置文件我们不用关心,是struts2的内部配置文件,我们无法修改,能修改的文件就是struts.xml、struts.properties、web.xml配置文件,这几个配置文件的加载是有一定的顺序的,这三个配置文件都可以修改struts2的常量的值,要记住的是,加载配置文件中的常量的值会将先加载的配置文件中的常量的给覆盖。
Struts2核心配置文件
一、 这个核心配置文件的名称和位置是固定的。
二、 在配置文件中有三个标签 package、action、result标签里面的属性
package标签
1. package类似与代码中的包的概念,区别不同的action,要配置action,必须先写package标签,在package里面才能写action
2. package标签里面的属性
- ① name:该属性值跟程序功能本身没有什么关系, 在一个配置文件中, 可以写多个package但是name属性值不能相同。
-② extends:该属性表示继承,这个属性的值是固定的,写了这个属性之后,package里面配置的类,就具有了action的功能,就表示让我们的类具有action的功能
- ③ namespace:名称空间,namespace属性值和我们action标签里面的name属性值构成访问路径。namespace有一个默认值,默认值就是‘/’,如下图:
action标签
1. 作用:配置action的访问的路径
2. Action标签里面的属性
- ① name属性:namespace属性值和我们action标签里面的name属性值构成访问路径,注意:在package标签里面,可以写多个action,但是他的name属性的值不能相同。
- ② class属性:
- Action类的全路径,他的底层是需要通过反射来解析类的,所以要提供全路径
- ③ method属性:
- 比如在Action类里面,默认执行的是execute方法,但是我在action里面,可以写其他的一些方法.
- 让action里面的多个方法进行执行,可以使用method属性来进行配置
result标签
1. 作用:根据Action方法的返回值,配置到不同路径中去,跳转不一定是页面,也可以跳转到另外的action中去。
2. result标签里面的属性
- ① name属性:name属性的值要与action方法的返回值对应,路径/表示根路径,
hello.jsp表示action方法返回的是字符串OK要跳转到的页面名称。
- ② type属性:用来配置如何到一个路径中去,可以转发,也可以重定向,该属性的默认值是是转发。
Struts2常量的配置
在Struts2中的这些常量,大多数在默认配置文件中已经配置好了,但根据用户需求的不同,开发的要求也不同,可能需要修改这些常量的值,修改方法就是在配置文件对常量进行重新配置。
在Struts2中常量配置共有三种方式,分别如下:
- ① 在struts.xml中使用<constant>元素配置常量
- ② 在struts.properties文件中配置常量
- ③ 在web.xml中,通过<init-param>元素配置常量
- 为了让大家更好地掌握着三种Struts2常见配置方式,接下来,分别对他们进行讲解,具体如下:
- ① 在struts.xml文件中通过<constant>元素配置常量
- 在struts.xml文件中通过<constant>元素来配置常量,是最常见的方式。在struts.xml文件中通过<constant>来配置常量时,需要指定两个必填的的属性name和value。
- name : 该属性指定了常量的常量名。
- value : 该属性指定了常量的常量值。
- 在struts.xml文件中配置示例代码如下:
- 在上述示例代码中,配置了常量struts.i18n.encoding和struts.devMode,用于指定struts2应用程序的默认编码集为UTF-8,并使用开发模式。值得一提的是,struts.properties文件能配置的常量都可以在struts.xml中使用<constant>元素来配置。
- ② 在struts.properties文件中配置常量
struts.properties 文件是一个标准的properties文件, 其格式是key-value对, 即每个key对应一个value,key表示的是struts2框架中的常量,而value则是其常量值。 在struts.properties文件中配置常量的方式具体如下:
- 在上述代码片段中,“=”号左边的是key,右边的是每个key对应的value,另外,代码片段中的### 表示properties文件中的注释信息,用于解释说明。
- ③ 在web.xml文件中通过初始化参数配置常量
- 在web.xml文件中,配置核心过滤器StrutsPrepareAndExecuteFilter时,通过初始化参数来配置常量。通过<filter>元素的<init-param>子元素指定,每个<init-param>元素配置了一个struts2常量。在web.xml文件中,通过初始化参数配置常量的方式,具体如下代码片段所示:
<filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> <!- - 通过init-param元素配置struts2常量,配置默认编码集为:UTF-8 - -> <init-param> <param-name>struts.i18n.encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
在上述web.xml文件的代码片段中,当配置StrutsPrepareAndExecuteFilter时,还是通过<init-param>子元素配置了常量struts.i18n.encoding,指定其值为UTF-8 . 需要注意的是, 在web.xml文件配置常量时,<init-param>标签必须放在<filter>标签下。
Struts2所支持的常量众多,在struts2-core-2.3.24.jar压缩文件的org.apache.struts2路径下有一个default.properties文件,该文件里面为struts2的所有的常量都指定了默认的值,读者可以通过查看该文件来了解struts2所支持的常量。
之前我们就已经介绍过了struts2的配置文件的加载顺序,后加载的配置文件的常量的值会覆盖先加载的配置文件中的常量的值。所以大家这个要注意。
1. struts2框架中,帮我们实现一部分功能,struts2里面有常量,在常量里面封装了一部分功能
2. struts2默认的常量的位置(记住)
1. 修改struts2默认常量值
- ① 常用方式:在struts.xml中进行配置
- ② 还有两种方式(了解)
- 一、在src下创建一个struts.properties,进行修改
- 二、在web.xml中进行配置
- 这两种大家了解即可,不需要掌握,掌握第一种方式就可以了。
1. 最常用的常量
- (1)表单提交数据到action中去,在action中可以获取到表单提交数据,
- (2)表单提交数据有中文,有乱码问题,之前解决:
- post提交,直接设置request.setChara….Encoding(“UTF-8”)
- get提交,需要做编码的转换
(3)如果在action获取表单数据是通过post方式提交的中文,中文乱码问题struts会帮我们解决乱码问题,不需要我们自己处理这个问题,这是常量帮我们封装的功能
分模块开发的配置
在实际开发过程中,我们都是协同开发,我们通常很多人需要修改通过一个配置文件就是struts.xml。因为这个文件是Struts2的核心配置文件,而且这个文件一旦改错了一点,那么会导致整个项目都出现问题,所以Struts2提供了<include>标签解决这个问题。
<include>元素用来在一个struts.xml配置文件中包含其他的配置文件,包含配置体现的是软件工程中的“分而治之”的原则。Struts2允许将一个配置文件分解多个配置文件,从而提高配置文件的可读性。Struts2默认只加载WEB-INF/classes下的struts.xml文件,一旦通过多个xml文件来配置Action,就必须通过struts.xml文件来包含其他配置文件。
<struts> <!-- 包含了四个配置文件,不指定路径,默认在src路径下时的方式 --> <include file="struts-order.xml" /> <include file="struts-book.xml" /> <include file="struts-user.xml" /> <include file="struts-cart.xml" /> <!-- 配置文件在具体包中的方式 --> <include file="cn/atwyl/action/struts-right.xml" /> </struts>
在上述代码片段中,struts.xml文件包含了四个配置文件,这个4个配置文件都包含在 <include> 元素中,配置<include>元素时,指定了一个必须的file属性,该属性指定了被包含的配置文件的文件名。
Action的编写方式
在Struts2中,Action编写方式一共有三种方式。
第一种:创建普通类,这个类不继承任何类,不实现任何的接口;
- ① 刚才我们创建的就是这个第一种的方式
- ②
第二种:创建一个类,这个类实现接口Action;
第三种:创建类,让它继承自ActionSupport(主要用这种方式,一般都使用这种方式);
观察源码
- 我们发现他也实现了Action接口
Action的访问(重点)
Action 的访问不是难题,因为之前已经访问过,但是出现一个问题一次请求现在对应一个Action类,那么如果请求很多,对应的很多的Action,现在要处理的问题就是要让一个模块的操作提交到一个Action中。
其实我们学过在<action>标签中有一个属性method,通过method的配置来指定Action中的某个方法执行。
1. 有三种方式可以实现
- ① method:使用action标签的method属性,在这个属性里面写要执行的action的方法
【解决Action的访问问题的方式一:通过配置method属性完成】 编写页面: <h1>用户的管理</h1> <a href=”${ pageContext.request.contextPath}/saveUserAction.action”>添加用户</a> <a href=”${pageContext.request.contextPath}/updateUserAction.action”>更新用户</a> <a href=”${ pageContext.request.contextPath}/deleteUserAction.action”>删除用户</a> <a href=”${ pageContext.request.contextPath}/findUserAction.action”>查询用户</a>
- 编写Action
import com.opensymphony.xwork2.ActionSupport; public class UserAction extends ActionSupport { public String save(){ System.out.println("UserAction中save方法被执行了...."); return NONE; } public String update(){ System.out.println("UserAction中update方法被执行...."); return NONE; } public String delete(){ System.out.println("UserAction中delete方法被执行..."); return NONE; } public String find(){ System.out.println("UserAction中find方法被执行......"); return NONE; } }
- 配置Action
<package name="demo" extends="struts-default" namespace="/"> <action name="saveUserAction" class="org.atwyl.action.UserAction" method="save"> </action> <action name="saveUserAction" class="org.atwyl.action.UserAction" method="update"> </action> <action name="saveUserAction" class="org.atwyl.action.UserAction" method="delete"> </action> <action name="saveUserAction" class="org.atwyl.action.UserAction" method="find"> </action> </package>
- 但是这种方式我们会发现,同一个Action类就被配置了很多次,只 是 修 改 了method属性的值,那么能不能简化呢?也就是说一个Action类,只配置一次就好了,这个时候我们就需要使用通配符的配置方式了。
- ② 使用通配符的方式(使用的最多的)
- 编写页面
【解决Action的访问访问的问题的方式二:通过通配符完成】 <h1>用户的管理</h1> <a href=”${ pageContext.request.contextPath}/users_save.action”>添加用户</a> <a href=”${pageContext.request.contextPath}/ users_update.action”>更新用户</a> <a href=”${ pageContext.request.contextPath}/ users_delete.action”>删除用户</a> <a href=”${ pageContext.request.contextPath}/ users_find.action”>查询用户</a>
- 编写Action
import com.opensymphony.xwork2.ActionSupport; public class UserAction extends ActionSupport { public String save(){ System.out.println("UserAction中save方法被执行了...."); return NONE; } public String update(){ System.out.println("UserAction中update方法被执行...."); return NONE; } public String delete(){ System.out.println("UserAction中delete方法被执行..."); return NONE; } public String find(){ System.out.println("UserAction中find方法被执行......"); return NONE; }
- 配置Action
<action name=" users_*" class="org.atwyl.action.UserAction" method="{1}">
- 在Action的name属性中使用 * 号代替任意字符,method中的{1}代表name属性中出现的第一个 * 所代替的字符。
- 这个时候我们发现只配置一个就可以了,在上述代码中,当客户端发送:
- /users_save.action的时候,method的属性就被设置成了save。当客户端发送的请求是:
/users_update.action的时候,method的属性就被设置成了update。
- ③ 动态访问的方式(很少用或者不用)
【解决Action的访问问题的方式三:动态方法访问】 动态方法访问在Struts2中默认是不开启的,如果想要使用需要先去开启一个常量。 <constant name=”struts.enable.DynamicMethodInvocation” value=”true” /> 动态方法访问,主要的控制是在页面端,所以编写Action和配置Action都很简单,关键是访问路径的编写。
- 编写Action
import com.opensymphony.xwork2.ActionSupport; public class UserAction extends ActionSupport { public String save(){ System.out.println("UserAction中save方法被执行了...."); return NONE; } }
- 配置Action
<!- - 动态的方法访问配置 - -> <action name="userAction" class="org.action.UserAction"> </action>
页面路径的写法
<h1>用户的管理</h1> <a href=”${ pageContext.request.contextPath}/userAction!save.action”>添加用户</a> <a href=”${pageContext.request.contextPath}/userAction!update.action”>更新用户</a> <a href=”${ pageContext.request.contextPath}/userAction!delete.action”>删除用户</a> <a href=”${ pageContext.request.contextPath}/userAction!find.action”>查询用户</a>
错误演示
- 1.如果说我们的Action的方法的返回值,再配置文件中没有进行配置,会出现如下错误:没有结果的定义
1. 在action里面的方法可以有返回值,但是如果有返回值的时候,类型必须是String类型
2. Action里面的方法也可以没有返回值,没有返回值的时候,就不需要配置result标签
-可以把方法的返回值写成void
-一般做法是:让方法的返回值是String,但最终返回的是:NONE. 这种情况也不需要配置result。
结果页面的配置
全局结果页面
1. <result name="OK">/hello1.jsp</result>
2. result标签配置action方法的返回值,到不同的路径里面
3. 业务:创建两个action,执行默认的方法:execute方法,让两个action方法都返回一个值:success,配置都到同一个页面里面去
4. 具体实现步骤:
创建一个工程,里面有两个Action类
struts.xml配置文件如下:
- 如果说我们有多个Action,他的Action方法里面返回值是相同的,他们到的页面也是相同的,这个时候,我们就可以使用全局结果页面
局部结果页面
① 如果你配置了全局的结果页面,有配置了局部结果页面,那么它局部结果页面的优先级要高于全局结果页面,也就是说,他会跳转到你在局部配置的结果页面里面去
result标签中的type属性
在result标签里面,除了name属性之外,还有一个属性叫:type
- ① 表示我们如何到路径里面去的(转发还是重定向)
- ② type的属性值:
- 默认值:dispatcher 转发是一次请求,浏览器地址栏不发生改变。
- 重定向:redirect 这是两次请求,浏览器地址栏发生改变。
- 默认:默认的是 type=”dispatcher”
- 当我们改成重定向的时候
- 配置文件:
- ③ 上面两个值dispatcher、redirect,这两个值一般针对到页面中配置,配置到其他Action的action方法里面:
- (1) chain:转发到Action (一般不用)会有缓存问题,可能得不到最新数据
- (2) redirectAction:重定向到Action
Action获取表单提交的数据
1. 之前在Web阶段,提交表单都是到Servlet,在Servlet里面,使用request对象的方法获取。request.getParameter(“表单元素的名称”); getParameterMap
2. 现在我们要把表单填写的数据提交到Action,但Action本身没有request,不能直接使用request。
3. Action中获取表单提交的数据主要有如下三种方式:
- ① 使用ActionContext类
- ② 使用ServletActionContext类
- ③ 使用接口注入的方式实现(基本不用)
使用ActionContext类获取
Struts2框架提供了ActionContext类来访问ServletAPI,ActionContext是Action执行上下文对象,在ActionContext中保存了Action执行所需要的所有对象,包括parameters,request,session,application等下面列举ActionContext类访问Servlet API 的几个常用方法,具体如表所示:
1. Map<String,Object> getParameters()因为这个方法不是静态方法,需要创建ApplicationContext对象
2. 这个ApplicationContext类对象不是new出来的,是通过下面这个静态方法获取
3. 具体演示:
① 创建表单提交表单到action里面
- ② 配合struts.xml文件
- ③ 在action里面使用ActionContext获取到数据
控制台输出
使用ServletActionContext来访问 (程序员比较喜欢用)
为了直接访问Servlet API,Struts2框架还提供了ServletActionContext类,该类包含了几个常用的静态方法具体如下:
static HttpServletRequest getRequest():获取Web应用的HttpServletRequest对象
static HttpServletResponse getResponse():获取Web应用的HttpServletResponse
static ServletContext getServletContext():获取Web应用的ServletContext
static PageContext getPageContext():获取Web应用的PageContext对象
接下来,讲解如何通过ServletActionContext来访问Servlet API
1. 调用类里面的静态的方法,得到Request对象,login2.jsp如下
- struts.xml
- LoginAction2
- 控制台结果:
通过特定接口访问一般不用
Struts2框架提供了ActionContext类来访问Servlet API,虽然这种方法可以访问Sservlet API,但是无法直接获取Servlet API 实例,为了在Action中直接访问ServletAPI,Strus2还提供了一系列的接口,具体如下:
ServletRequestAware : 实现该接口的Action可以直接访问Web应用的HttpServletRequest实例
ServletResponseAware : 实现该接口的Action可以直接访问Web应用的HttpServletResponse实例
SessionAware:实现该接口的Action 可以直接访问Web应用的HttpSession实例
ServletContextAware:实现该接口的Action可以直接访问web应用的ServletContext实例。
login3.jsp
struts.xml
LoginAction3,实现接口ServletRequestAware,实现接口里面的方法setServletRequest。
在Action里操作域对象
1. Request域对象,session域对象,ServletContext域对象
2. 使用ServletActionContext类操作
Struts2的数据的封装
原始的方式获取表单封装到实体对象
配置struts.xml
LoginAction4.java
在Struts2中,可以直接在Action中定义各种Java基本数据类型的字段,使这些字段
与表单数据相对应,并利用这些字段进行数据传递。
【属性驱动方式一:提供属性的set方法的方式】
1. 直接把表单提交属性封装到action属性里面
2. 实现步骤
- ① 在action成员变量位置定义变量
- ② 生成变量的set方法(为了方便记忆,我们把get和set都生成)
// 使用ServletActionContext获取表单数据封装到实体类的对象里面去 public class LoginAction5 extends ActionSupport { // 1、定义变量 // 变量的名称要与表单元素的name属性值保持一致 private String username; private String password; private String address; @Override public String execute() throws Exception { System.out.println(username + " : " + password + " : " + address); return NONE; } // 生成get and set 方法 public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address;
模型驱动封装(重点,最常用的方式)
1. 使用模型驱动方式,可以直接把表单数据封装到实体类对象里面
2. 实现步骤
- ① action类要实现一个接口ModelDriven
- ② 实现接口里面的方法,getModel,把创建对象返回
- ③ 手动创建实体类对象
- 实体类:
- 前提条件:表单输入项的name属性值要与实体类属性保持一致
1. 使用模型驱动和属性封装需要注意的问题:
- ① 在一个action中,获取表单数据,可以使用属性封装,也可以使用模型驱动封装,但是不能同时使用属性封装和模型驱动封装获取通过一个表单数据,如果同时使用,它只会执行模型驱动。
表达式封装
1. 实现过程
- 使用表达式封装(有些书本也叫属性封装)
- 使用表达式封装可以把表单数据封装到实体类对象里面
- ① 在action里面生命实体类
- ② 生成实体类变量的set和get方法
- ③ 在表单输入项的name属性值里面写表达式形式
具体过程如下:
比较表达式封装和模型驱动封装
1. 使用表达式封装和模型驱动封装,都可以把数据封装到实体类对象
2. 不同点
- ① 使用模型驱动只能把数据封装到一个实体类对象里面,在一个Action里面不能把数据封装到不同的实体类对象里面
- ② 使用表达式封装可以把数据封装到不同的实体类对象里面
Struts2中封装到集合类型的数据
在实际开发过程中,有些时候我们需要批量插入用户或者批量插入其他的对象,在Action中需要接受到多个Action中封装的对象,然后传递给业务层,那么这个时候需要将表单数据封装到集合中,一般我们通常使用的集合无非是List或者Map集合,下面就以这两种集合进行数据封装的实例演示:
封装数据到list里面
编写页面
<form action="${pageContext.request.contextPath }/login8.action" method="post"> <p> username:<input type="text" name="list[0].username" /> </p> <p> password:<input type="password" name="list[0].password" /> </p> <p> address:<input type="text" name="list[0].address" /> </p> <p> username:<input type="text" name="list[1].username" /></p> <p> password:<input type="password" name="list[1].password" /> </p> <p>address:<input type="text" name="list[1].address" /></p> <input type="submit" value="submit" /> </form>
编写Action
public class LoginAction8 extends ActionSupport { private List<User> list; public List<User> getList() { return list; } public void setList(List<User> list) { this.list = list; } @Override public String execute() throws Exception { for (User user : list) { System.out.println(user.getUsername()+" : " +user.getPassword()+" : " +user.getAddress()); } return NONE; } }
配置文件struts.xml
封装数据到Map里面
1. 声明一个Map集合
2. 生成get 和 set 方法
3. 在表单输入项的name属性值里面写表达式
页面代码:
<form action="${pageContext.request.contextPath }/login9.action" method="post"> <h1>批量插入用户:封装到Map集合</h1> <p> username:<input type="text" name="map['one'].username" /> </p> <p> password:<input type="password" name="map['one'].password" /> </p> <p> address:<input type="text" name="map['one'].address" /> </p> <p> username:<input type="text" name="map['two'].username" /> </p> <p> password:<input type="password" name="map['two'].password" /> </p> <p> address:<input type="text" name="map['two'].address" /> </p> <input type="submit" value="submit" /> </form>
配置文件:struts.xml
Action里面的代码:LoginAction9.java
public class LoginAction9 extends ActionSupport { private Map<String, User> map; public Map<String, User> getMap() { return map; } public void setMap(Map<String, User> map) { this.map = map; } @Override public String execute() throws Exception { for (Map.Entry<String, User> entry : map.entrySet()) { System.out.println(entry.getKey() + " >>> " +entry.getValue().getUsername()+" : " +entry.getValue().getPassword()+" : " +entry.getValue().getAddress()); } return NONE; }
OGNL概述
OGNL的全称是对象图导航语言(Object-Graph Navigation Language),他是一种功能强大的开源表达式语言,使用这种表达式语言,可以通过某种表达式语法,存取Java对象的任意属性,调用Java对象的方法,同时能够自动实现必要的类型转换。如果把表达式看做是一个带有语义的字符串,那么OGNL无疑成为了这个语义字符串与Java对象之间沟通的桥梁。
【OGNL的作用】
Struts2默认的表达式语言就是OGNL,它具有一下特点
♥ 支持对象方法调用。例如:objName.methodName().
♥ 支持类静态方法调用和值访问,表达式的格式为:@[类全名(包括包路径)]@[方法名 | 值名]。例如:@java.lang.String@format(‘foo%s’,’bar’);
♥ 支持赋值操作和表达式串联
例如:price=100,discount=0.8,calculatePrice(),在方法中进行乘法计算会返回90.
♥ 访问OGNL上下文(OGNL context)和 ActionContext
♥ 操作集合对象
1. 之前在Web阶段学过EL表达式,EL表达式,是在JSP中获取域对象里面的值
2. OGNL也是一种表达式,功能更加强大,很多功能是EL表达式做不到的
- ① struts2里面操作值栈数据
- ② 一般把ognl在struts2操作:和struts2标签一起使用操作值栈
3. OGNL不是struts2的一部分,他是一个单独的项目,经常和Struts2一起使用。
- ① 使用OGNL时候首先导入jar包,Struts2提供jar包
OGNL入门案例
了解了什么是OGNL及其特点之后,接下来,分析一下OGNL的结构,OGNL的操作实际上是围绕OGNL结构的三个要素而进行的,分别是表达式(Expression),根对象(Root Object),上线文环境(Context)。
♥ 支持对象方法调用
使用OGNL+Struts2的标签,计算字符串的长度
- ① 在Java代码中,调用字符串.length()
- ② 要使用到Struts2的标签
- ③ 使用JSTL时候,我们除了导入jstl的jar包之外,在jsp页面引入标签库,
- 使用Struts2的时候,也需要在页面中引入Struts2的标签库。
- ④ 使用Ognl+Struts2标签实现计算字符串长度
什么是值栈
1. 之前在Web阶段,在Servlet里面进行操作,把数据放到域对象里面 , 在页面中使用 EL表达式获取到,域对象是在一定范围内,存值和取值。
2. 在Struts2里面,它提供了一种存储的这种机制,类似于我们之前学的那个域对象,叫做值栈,可以存值和取值。
- ① 在action里面,我们可以把数据存到值栈里面,在页面中获取值栈的里面的数据
3. Servlet跟Action的区别
- ① Servlet:在第一次访问的时候创建,只创建一次,它是一个单实例对象。
- ② Action:在访问的时候创建,每次访问Action的时候,都会创建一个新的Action对象,Action是一个多实例对象。
- 验证Action是一个多实例的对象:
创建一个Action类,把构造器写出来,然后再构造器里面写一句输出语句:
- 配置Struts2核心配置文件:struts.xml
- 每刷新一次,控制台都会打印构造器里面的信息,说明每次访问Action,都会实例化Action实例。
1. 值栈存储的位置
- ① 每次访问Action的时候,都会创建一个Action的对象
- ② 在每个Action对象里面,都有一个值栈的对象(只有一个)
-
获取值栈对象
1. 获取值栈对象一共有多种方式
- ① 常用的方式:使用ActionContext类里面的方法得到值栈对象
- 栈的概念:
值栈的内部结构
1. 值栈分为两部分:
- ① 第一部分 root,结构是list集合
- (1)一般操作都是root里面数据,通过调试可以查看
- ② 第二部分 context ,结构map集合
1. struts2里面有标签<s:debug> 使用这个标签可以查看值栈的结构和存储值
- ① 访问action,执行action的方法的返回值,配置返回值到jsp的页面中,在jsp中,使用这个标签。
- 具体实现:ValueStackAction.java
- Struts.xml
-
浏览器访问该Action,然后看到了超级链接:Debug,点击超级链接可以看到结构
- 点击页面中的Debug,我们看到了两部分:第一部分就是root,第二部分是键值对的,context;
- 在Action里面没有做任何的操作,栈顶的元素就是Action的引用,Action如上图所示;
- Action里面会有值栈对象
- 值栈对象里面有action引用,存的不是真正的Action的对象,而是一个Action的引用
向值栈放数据
1. 向值栈中存放数据多种方式
- ① 获取到值栈对象,调用值栈对象里面的set方法
- ② 获取到值栈对象,调用值栈对象里面的push方法
- ③ 最常用的方式,在Action里面定义一个变量,生成这个变量的get方法
2. 具体实现:
- ♥ 第一种方式:set
- 浏览器查看【Debug】,多了一个HashMap对象
- ♥ 第二种方式:push
-
- 浏览器查看【Debug】,多了一个String对象
-
- ♥ 第三种方式:这是我们最常用的方式:定义变量,然后生成get方法
-
- 浏览器查看【Debug】,多了一个String对象
1. 总结:我们使用set是分配了一个Map空间,push,他分配了一个字符串的空间,第三种方式,他就直接存到Action里面进行存储,这么做可以减少空间的分配。
从值栈中存放对象
1. 实现的步骤:
- ① 在成员变量的位置,定义一个对象的变量
- ② 生成这个对象变量的get方法
- ③ 在执行的方法里面,向这个对象中设置值
- 具体操作:
- 查看浏览器:【Debug】,可以看到Action里面就有了user对象
向值栈存放list对象
场景:比如我们从表中查询一些记录,在Java里面我们把查询到的数据存入集合,然后集合要传递到JSP页面,这个时候,我们就可以使用到值栈的List对象
1. 定义一个list集合的变量
2. 生成变量的get方法
3. 在执行的方法里面,给设置集合的值
4. 具体实现
- 查看浏览器,就可以看到存储的数据:
从值栈中获取数据
Ognl是根据Struts2标签一起来获取值栈的数据。
使用Struts2的标签+ognl表达式获取值栈数据
- ① <s:property value=“ognl表达式”>
从值栈中获取字符串
具体实现:
在ValueStackAction里面定义成员变量username:
在核心配置文件 struts.xml配置访问
在valuestack.jsp里面进行获取字符串数据
浏览器访问,测试,得到数据:“无崖子”
从值栈中获取对象
集体实现步骤:在实体类里面生命user对象变量
Struts2核心配置文件,如下配置
在页面中获取对象里面的数据:
从值栈中获取List集合
实现步骤:
1. 声明Action
- 核心配置文件:struts.xml
- valuestack3.jsp,使用两种方式来获取list集合里面的数据:
- 观察浏览器效果:两种方式都获取到了集合里面的数据:
- 第三种方式:
其他操作
1. 使用set方法向值栈中放数据,如何取出
1. 使用push方法向值栈中放数据,如何取出
- ① 使用push方法设置值,没有名称,只有设置的值
- ② 向值栈中存放数据,他会把值栈放数据存到数组里面去,数组的名称:top,根据数组来获取值
- 取出数组中的第一个值,栈顶的值,如下:
- 查看浏览器:栈顶的值,如下图所示:
EL表达式获取值栈数据
1. 具体实现方式:
- EL表达式可以获取值栈数据,为什么呢?
- ① EL表达式是获取域对象里面的值
- ② 向域对象里面放值使用setAttribute()方法,获取值是:getAttribute()方法
- ③ 底层增强request对象里面的方法:getAttribute()方法
- (1)首先从request域里面获取值,如果获取到,直接返回
- (2)如果从request域里面没有获取到值,他会到值栈里面去获取值,然后把值放入我们的域对象里面,然后返回
1. 查看源代码:
继续点击
- 在这个类里面,他主要增强了getAttribute() 方法
- 最终:
OGNL#、%的使用
#使用
1. 使用#获取context里面的数据
1. 演示#的使用
- 向request域中放值
- 在页面中使用ognl获取
- ValueStackAction4.java
- 核心配置文件struts.xml
- valuestck4.jsp
- 查看浏览器:值已经取出来
%的使用
1. 在Struts2标签里面表单标签
- % : 在struts2标签里面使用ognl表达式,如果直接在struts2表单标签里面使用ognl表达式不识别,只有使用%之后才能识别。
Struts2拦截器概述
1. 拦截器只是Struts2里面的一个概念,在其他里面没有,Struts2是一个框架中封装了很多的功能,Struts2里面封装的很多功能都是在拦截器里面的,比如,之前用过的功能,比如说在Struts2里面的到表单数据,有属性封装,还有模型驱动封装。这些功能都是封装在Struts2的拦截器里面的,我们可以直接用里面的内容完成我们的操作。一句话,Struts2的拦截器帮我们封装了很多的功能。
2. Struts2里面封装了很多的功能,有很多拦截器,不是每次这些拦截器都运行,每次只会执行一些默认的拦截器。
3. Struts2里面默认的拦截器的位置
1. 拦截器在什么时候执行
- ♡ 在action对象创建之后,action的方法执行之前执行
- ♡ 通过调试查看源代码,来分析拦截器执行的时机:
- ♡ 选择这一行代码,按Ctrl、Shift、T,跳转到源代码,到了这个模型驱动的类里面,我们设置一个断点,然后调试查看执行时机:
- 具体实现:
- ♡ InterAction.action.java
- 核心配置文件struts.xml
- 通过调试,我们发现,首先:执行我们定义的构造函数,然后:程序会执行到拦截器里面去,最后:会执行我们的Action方法。
拦截器的底层的原理
1. 拦截器底层使用到了两个原理
- ① AOP的思想
- ② 责任链模式
AOP的思想
- ① AOP本身是一种开发的思想:
- 面向切面编程(面向方面编程):假如我有一个功能,我需要扩展这个功能,按照我们之前的写法是,改写我们的源代码,但是AOP的模式是不通过修改源代码的方式就可以扩展我们的功能,比如:通过配置文件扩展。
- ② AOP理解图:不需要修改源代码,就可以扩展功能
责任链模式
1. 在Java里面有很多的设计模式,责任链模式是其中的一种。
2. 之前过滤器,我们说过过滤器链,责任链模式跟这个过滤器链是很相似的
- 过滤链:一个请求可以有多个过滤器进行过滤,每个过滤器只有做放行的操作才能到下一个过滤器。
3. 责任链模式:要执行有多个操作,假如有添加、修改、删除,首先执行添加操作,添加操作执行完毕之后,他要做一个类似过滤器放行的操作,然后执行修改,修改操作执行完毕之后,然后执行类似过滤器放行的操作,最后执行删除操作。
AOP的思想和责任链应用到拦截器里
1. 拦截器在action对象创建之后,action的方法执行之前被执行。
2. 在action方法执行之前,会执行默认拦截器,执行的过程使用到的是AOP的思想 。在action里面,并没有直接调用拦截器的方法,它是使用配置文件的方式进行操作,这就是AOP 的思想,不改源代码,实现功能。
3. 执行拦截器的时候,会执行到很多的拦截器,这个过程使用到的就是责任链模式。
- 假如有三个拦截器,先执行拦截器1,执行完拦截器1之后,做一个类似与放行的操作,在执行拦截器2,执行拦截器2之后,放行,再执行拦截器3,当拦截器3放行,执行Action里面的方法。
- 拦截器执行过程如下图:
-
- 接线来,我们来查看一下源代码:
- 第一步:在9行,按住Ctrl 点击进去
- 第二步:在99行,按住Ctrl 点击进去
- 第三步:在81行,按住Ctrl键点击进去
-第四步:观察代码565行:创建Action代理对象,在575行,执行Action方法,
- 第五步:我们在575行,按住Ctrl点击下面的第二个选项:Open Implementation,查看接口的实现类:然后,双击StrutsActionProxy,进去:
第六步: 在54行,按住Ctrl键,选择第二个选项,点击进去查看代码
- 最后,我们就看到了执行拦截器的代码了:
过滤器和拦截器的区别
1. 过滤器
- 过滤器:理论上可以过滤任意的内容,比如:HTML,JSP,servlet,图片。
2. 拦截器
- 拦截器:只会拦截Action。
Servlet和Action的区别
Servlet:默认是第一次访问的时候创建,它会创建一次,是一个单实例对象。
Action:每次访问的时候创建,会创建多次,是一个多实例对象。
自定义拦截器
1. 在Struts2里面有很多的拦截器,这些拦截器都是Struts2封装的功能,但是在实际的开发中,有的时候,Struts2里面封装的没有我们需要的功能,这个时候,需要我们自己写拦截器来实现功能:
2. 关于拦截器的一个基本的结构:
- 查看源代码,来查看拦截器的结构
- 在导入的jar包中,找到struts-default.xml中,选择如下代码,按 Ctrl + Shift + T
- 到源代码中,看到如下:该拦截器继承了 AbstractInterceptor
- 实现了Intercepter接口:
- 在如下接口里面,有三个方法,分别是:destory()销毁的操作;init()方法是初始化操作,和intercept() 拦截逻辑的的操作。
1. 在实际开发过程中,我们就自定义一个类,让这个自定义的类继承自
- MethodFilterInterceptor来实现,实现这个类的好处:可以让我们的Action里面的某个方法不进行拦截。
- 让拦截器跟我们的Action有关系(AOP的应用):
- ① 不是在Action里面调用拦截器的方法,而是通过配置文件的方式来建立这种关系。
自定义登录拦截器
1. 需求:在项目中,有很多的Action的超链接,每个Action的超链接都对应着一个功能,实现只有是登录的状态,你才能点击这些超链接实现功能,如果说你不是登录状态,点击Action的超链接,返回到登录页面。
2. 登录的状态:使用session的域对象来实现
- ① 登录成功之后,客户把登录这的信息存入session里面
- ② 判断session里面是否有值,可以知道是否是登录的状态
3. 实现基本的登录的功能
- ① 查询数据库,判断用户名和密码(我就直接写固定的了)
4. 具体实现:
- 登录页面:
- 核心配置文件struts.xml
LoginAction.java
- index.jsp
1. 添加拦截器
- ① 判断是否登录,判断session里面是否有你存入的值
- ② 拦截器的具体的实现
- (1)创建一个类,继承自MethodFilterInterceptor类
-
- (2)重写方法:doIntercept,实现拦截逻辑
- (3)配置Action和拦截器的关系,其实就是:注册拦截器
- 第一步:在要拦截的Action标签所在的package标签里面先声明拦截器
- 第二步:在具体的Action标签里面使用我们声明的拦截器
- 第三步: 在Struts2里面,会执行很多的默认的拦截器,但是如果我们在Action里面配置了自定义的拦截器,这时候会有一个问题:默认的拦截器就不会执行了,只会执行你配置的拦截器,这样以来,Struts2的很多功能我们就不能使用,因为Struts2里面的功能都是通过拦截器配置来实现的;解决方案:把默认的拦截器手动使用一次。
- ** 配置的拦截器,会对Action里面的所有的方法都进行拦截
1. 通过调试发现,拦截器对Action里面所有的方法都进行了拦截
- ① 在Action里面有一个登录的方法,而这个登录的方法不能拦截,如果这个方法也拦截,他永远没有登录的机会,还没有到Action的登录的方法,页面有转到登录页面去了。
- ② 解决方案:让登录的方法不进行拦截
- ③ 我们继承的是MethodFilterInterceptor类,好处就是直接通过配置的方式,让Action里面的某些方法不进行拦截,在实际开发过程中,都是继承自MethodFilterInterceptor
Struts2的标签库
对于一个MVC框架而言,重点是实现两部分:业务逻辑控制器部分和视图页面部分。Struts2作为一个优秀的MVC框架,也把重点放在了这两个部分上。控制器主要由Action来提供支持,而视图则是有大量的标签来提供支持。
Struts2标准标签库概述
1. Struts标签库概述
- 在JavaWeb中,Struts2标签库是一个比较完善,而且功能强大的标签库,它将所有标签都统一到一个标签库中,从而简化了标签的使用,它还提供主题和模板的支持,极大的简化了视图页面代码的编写,同时它还提供对Ajax的支持,大大的丰富了视图的表现效果。与JSTL(JSP Standard Library,JSP标准标签库)相比,Struts2标签库更加易用和强大。
Struts2标签库的分类
早期的JSP页面需要嵌入大量的Java脚本来进行输出,这样使得一个简单的JSP页面加入了大量的代码,不利于代码的可维护性和可读性,随着技术的发展,逐渐的采用标签库来进行JSP页面的开发,这使得JSP页面能够在很短的时间内开发完成,而且代码通俗易懂,大大的方便了开发者,Struts2的标签库就是这样发展起来的。
Struts2框架对整个标签库进行了分类,按照功能大体可以分为两类,如图所示:
由图中可以看出,Struts2标签库主要分为两类,普通标签和UI标签。普通标签主要是在页面生成的时,控制执行的流程。UI标签则是以丰富而可复用的HTML文件来显示数据。
普通标签又分为控制标签(Control Tags)和数据标签(Data Tags)。控制标签用来完成条件逻辑,循环逻辑的控制,也可用来做集合的操作。数据标签用来输出后台的数据和完成其他数据访问功能。
UI标签又分为表单标签(Form Tags)、非表单标签(Non-Form Tags)和Ajax标签,表单标签主要用来生成HTML页面中的表单元素,非表单标签主要用来生成HTML的<div>标签及输出Action中封装的信息等,Ajax标签主要用来提供Ajax的技术支持。
Struts标签的使用
Struts2标签库被定义在struts-tags.tld文件中,我们可以在struts2-core-2.3.34.jar中的META-INF目录下找到它。要使用Struts2的标签库,一般只需要在JSP文件使用taglib指令导入Struts2标签库,具体代码如下:
<%@taglib uri="/struts-tags" prefix="s" %>
在上述代码中,taglib指令的uri属性用于指定引入标签库描述符文件的URI,prefix属性用于指定引入标签库描述符文件的前缀。需要注意的是,在JSP文件中,所有的Struts2标签都使用 ’s’ 前缀。
Struts2的控制标签
在Struts2开发中,经常要用流程控制语句实现分支,循环操作,为此,Struts2标签库中提供了控制标签,常用的逻辑控制标签主要包括:<s:if>、<s:elseif>、<s:else>、<s:iterator>等。
1. <s:if>、<s:elseif>、<s:else>标签
- 与多数编程语言中的if、elseif、和else语句功能类似,<s:if>、<s:elseif>、<s:else>这三个标签用于程序的分支逻辑控制。其中,只有<s:if> 标签可以单独使用,而<s:seleif>、 <s:else>必须与<s:if>标签结合使用,其语法格式如下所示:
<s:if test=”表达式1”> 标签体 </s:if> <s:elseif test=”表达式2”> 标签体 </s:elseif> <s:else> 标签体 </s:else>
- 上述语句表达式中,<s:if>、和<s:elseif>标签必须指定test属性,该属性用于设置标签的判断条件,其值为 boolean 型的条件表达式。
1. <s:iterator>标签
- <s:iterator>标签主要用于对集合中的数据进行迭代,它可以根据条件遍历集合中的数据。<s:iterator>标签的属性及相关说明如下表所示:
Iterator 标签的属性
- 在表中,如果在<s:iterator>标签中指定status属性,那么通过该属性可以获取迭代过程中的状态信息,如:与素数、当前索引值等。通过status属性获取信息的方法如下表所示:
status 获取状态信息
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="/struts-tags" prefix="s" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <table border="1" width="300" cellpadding="0" cellspacing="0"> <s:iterator var="name" value="{'Java','Python','Oracle','MySQL','HTML','SSH'}" status="st"> <s:if test="#st.odd"> <tr style="background-color:white;"> <td><s:property value="name" /> </td> </tr> </s:if> <s:else> <tr style="background-color:gray;"> <td><s:property value="name" /> </td> </tr> </s:else> </s:iterator> </table> </body> </html>
在文件的table标签内,首先使用 <s:iterator> 标签来循环输出集合里面的值 , 然后使用status.odd来获取值,作为<s:if>、<s:else>标签的判断条件,来对行数显示进行控制。
<s:if>、<s:elseif>、<s:iterator>标签的效果如下:
从图中运行结果可以看出,表格的奇数行变为了白色,偶数行变成了灰色。这是因为文件中,使用 <s:iterator> 遍历新创建的List集合时,通过判断其所在索引的奇偶数来决定表格的颜色。
Struts2的数据标签
在Struts2标签中,数据标签主要用于各种数据访问相关的功能以及Action的调用等。常用的数据标签有<s:property>、<s:a>、<s:debug>、<s:include>、<s:param>等
1. <s:property>标签
- <s:property> : 和ognl表达式在jsp页面中获取值栈数据。
- <s:property>标签用于输出指定的值,通常输出的是value属性指定的值,<s:property>标签的属性以及属性说明如下:
- id : 可选属性,指定该元素的标识。
- default : 可选属性,如果要输出的属性值为null,则显示default属性指定的值
- escape : 可选属性,指定是否忽略HTML代码
- value : 可选属性,指定需要输出的属性值 , 如果没有指定该属性 , 则默认输出ValueStack栈顶的值
- propertyTags.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="/struts-tags" prefix="s" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> 输出字符串: <s:property value="www.atwyl.com" /> <br /><br /> 忽略HTML代码: <s:property value="'<h1>www.atwyl.com</h1>'" escape="true" /> <br /><br /> 不忽略HTML代码: <s:property value="'<h1>www.atwyl.com</h1>'" escape="false" /> <br /><br /> 输出默认值: <s:property value="" default="defaultValue" /> </body> </html>
- 在文件中, 定义了四个不同属性的<s:property>标签,第一个标签中,只有一个value属性,所以会直接输出value的值;第二个标签中,使用了value和escape两个属性,其中value属性值包含了HTML标签,但其escape属性值为true,表示忽略HTML代码,所以会直接输出value的值;第三个标签,同样使用了value和default两个属性,其value值依然包括了HTML标签,但其escape的属性值为false,表示不能忽略HTML代码,所以输出的value值为3号标题的值,最后一个标签,使用了value和default两个属性,但是value值为空,指定了default属性的值为:defaultValue , 所以最后会输出defaultValue,如下图所示:
2. <s:a>标签
- <s:a> 标签用于构造 HTML页面中的超链接,其使用方式与HTML中的 <a> 标签类似。<s:a>标签属性及相关说明如下:
a 标签的常用属性以及描述
<s:a> 标签的使用格式,如下所示:
<s:a href=””>链接地址</a> <s:a namespace=”” action=””>atwyl.com</a>
3. <s:debug>标签
- <s:debug>标签用于在调试程序时输出更多的调试信息,主要输出ValueStack和StackContext中的信息,该标签只有一个id属性,且一般不用。
- 在使用debug标签后,网页中会生成一个[Debug]的链接,单机该链接,网页中将输出各种服务器对象的信息。
Struts2的表单标签
Struts2的表单标签用来向服务器提交用户输入的信息,绝大多数的表单标签都有其对应的HTML标签,通过表单标签可以简化表单的开发,还可以实现HTML中难以实现的功能,我们可以结合HTML的标签对比学习Struts2的表单标签。
表单标签的公共属性
Struts2的表单标签用来向服务器提交用户输入信息,在org.apache.struts2.components包中都有一个对应的类,所有表单标签对应的类都继承自UIBean类,UIBean类提供了一组公共的属性,这些属性是完全通用的。
表单标签的通用属性
除了这些常用的通用属性外,还有很多其它属性。由于篇幅有限,这里就不一一列举。需要注意的是,表单标签的name和value属性基本等同于HTML组件的name和value,但是也有些不同的地方:表单标签在生成HTML的时候,如果标签没有设置value属性的话,就会从值栈中按照name获取响应的值,把这个值设置成HTML组件的value。简单的说,就是表单标签的value在生成HTML的时候会自动设置值,其值从值栈中获取。
1. <s:form>标签
<s:form> 标签用来呈现HTML语言中的表单元素,其常用的属性如下表所示。
Form 标签常用的属性及描述
在使用<s:form>标签时,一般会包含其他的表单元素,如textfield,radio等标签,通过这些表单元素对应name属性,在提交表单时,将其作为参数传入Struts2框架进行处理。
2. <s:submit>标签
<s:submit>标签主要用于产生HTML中的提交按钮,该表单元素中, 可以指定提交的Action对应的方法。通常和<s:form>标签一起使用,常用属性如下:
<s:submit> 标签的常用属性
3. <s:textfield>和<s:textarea>标签
<s:textfield>和<s:textarea>标签的作用比较相似,都用于创建文本框,区别在于<s:textfield>创建的是单行文本框,而<s:textarea>创建的是多行文本框。二者使用也比较简单,一般指定其label和name属性即可。两个标签用法如下:
<s:textfield>标签的用法
<s:textfield label=”用户名” name=”username” />
<s:textarea>标签用法如下:
< s:textarea label=”描述” name=”description” />
name属性用来指定单行/多行文本框的名称,在Action中,通过该属性获取单行/多行文本框的值。其value属性用来指定单行/多行文本框当前值。
此外,<textarea>标签可以通过使用cols和rows属性分别指定多行文本框的列数和行数。
4. <s:password>标签
<s:password>标签用于创建一个密码输入框,它可以生成HTML中的<input type=”password” /> 标签,常用与在登录和注册表单中输入用户名的登录密码。
password 标签的常用属性说明
<s:password> 标签的使用方法如下:
< s:password label=”password” name=”password” maxlength=”15” />
需要注意的是Struts2的password标签与HTML的<input type=”password” />标签有一点不同,<input type=”password” /> 标签只要设置了value属性,就可以将value属性的值作为默认显示值而Struts2的<s:password>标签除了要设置value属性,还要设置showPassword属性为true。
5. <s:radio> 标签
<s:radio>标签用于创建单选按钮,生成HTML中的<input type=”radio” />标签。<s:radio>标签的常用属性如下:
<s:radio> 标签的属性及说明
表中的三个属性,必须要配合使用,由list属性指定从集合中获取元素,有listKey属性指定获得元素之后使用元素的哪个属性作为生成<input type=””radio” /> 的value属性,listValue属性指定生成的<input type=””radio” />后给用户看到的文字。
接下来,通过一个简单的用户注册的案例,来演示<s:form>标签、<s:textfield>标签、<s:textarea>标签和<s:radio>标签的使用。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="/struts-tags" prefix="s"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> <style type="text/css"> body { background-color: #ccc; } table { border-collapse: collapse; border: 1px solid black; width: 600px; margin: 50px auto; } table tr td, caption { padding: 10px; border: 1px solid black; } </style> </head> <body> <s:form action="register"> <s:textfield label="用户名" name="username" /> <s:password label="密码" name="password1" /> <s:password label="确认密码" name="password2" /> <s:radio label="性别" name="sex" list="#{'0':'男','1':'女' }" value="0" /> <s:textarea label="个性签名" name="description" rows="5" cols="20" /> <s:submit value="提交" /> </s:form> </body> </html>
在文件中,分别使用了<s:form>、<s:textfield>、<s:textarea>、<s:password>、<s:submit> 和 <s:radio>六种表单标签,其中<s:radio标签中>,使用list元素定义Map集合,并使用了其value元素指定其默认显示值为 ”男” ,其 0 值代表集合中key为0的元素。效果如下:
6. <s:checkboxlist>标签
<s:checkboxlist>标签用于一次性创建多个复选框,用户可以选择创建零个到多个,他用来产生一组 <input type=“checkbox” />标签 ,<s:checkboxlist>标签常用属性如下:
需要注意的是,listKey和listValue属性主要用在集合中,其中存放JavaBean,可以使用这两个属性从JavaBean众多属性中筛选需要的值。
我们常见一个页面,来用一用这个标签:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="/struts-tags" prefix="s"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <s:form> <s:checkboxlist label="爱好" name="hobbies" list="{'篮球','足球','气球','排球','地球'}" labelposition="left" /> <s:checkboxlist label="课程" name="course" list="#{'a':'Java','b':'Python','c':'BigData' }" labelposition="left" listKey="key" listValue="value" /> </s:form> </body> </html>
在文件中, 创建了两个<s:checkboxlist>标签,标签中,list表示要显示的集合元素 , 通过labelposition 属性将 label 属性的文字内容显示在标签的左侧。
7. <s:select>标签
<s:select>标签用于创建一个下拉框,生成HTML中的<select>标签。<s:select>标签常用属性说明如下:
select 标签的常用属性及说明
在表中,headerKey和headerValue属性需要同时使用,可以在所有的真实选项之前加一项作为标题项。比如选择省份的时候,可以在所有的具体省份之前加一个”请选择”,这个项不作为备选的值。
multiple属性和size属性类似与HTML的<select>标签,size属性可以让下拉框同时显示多个值,multiple属性让用户同时选择多个值,只是在后台的Action接受下拉框的时候,不能使用String类型,而应该使用String[]或者List<String>。
8. <s:hidden> 标签
<s:hidden>标签用于创建隐藏表单元素,会生成HTML中的<input type=”hidden” />隐藏域标签, 该标签在页面中没有任何的显示,可以保存或者交换数据,其使用也比较简单通常只设置其name和value属性值即可。其一般用法如下:
<s:hidden name=”id” value=”%{id }” />
该标签主要用来需要提交的表单传值时使用,比如需要提交表单时,要传一个值到请求参数中去,就可以使用该标签。
9.<s:reset>标签
<s:reset>标签用于创建一个重置按钮,会生成HTML中的<input type=”reset” />标签,该标签的使用比较简单,其常用属性为name和value。其中,name属性用于指定重置按钮的名称,在Action中,可以通过name属性来获取重置按钮的值,value属性用于显示该按钮的值,该标签用法如下:
<s:reset value=”Reset” /> <s:reset name=”reset” value=”重置” />
%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="/struts-tags" prefix="s"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> <style type="text/css"> body { background-color: #ccc; } table { border-collapse: collapse; border: 1px solid black; width: 600px; margin: 50px auto; } table tr td, caption { padding: 10px; border: 1px solid black; } </style> </head> <body> <s:form action="register"> <s:textfield label="用户名" name="username" /> <s:password label="密码" name="password1" /> <s:password label="确认密码" name="password2" /> <s:radio label="性别" name="sex" list="#{'0':'男','1':'女' }" value="0" /> <s:checkboxlist label="爱好" name="hobbies" list="{'羽毛球','足球','游泳','篮球'}" /> <s:select label="所在城市" name="city" list="#{'beijing':'北京','shanghai':'上海','hongkong':'香港', 'taibei':'台北','xiamen':'厦门','suzhou':'苏州' }" /> <s:textarea label="个性签名" name="description" rows="5" cols="20" /> <s:file label="头像" /> <s:reset value="重置" /> <s:submit value="提交" /> </s:form> </body> </html>
1. JavaEE中有三层结构,struts2框架应用在JavaEE三层结构中的Web层的框架。
2. struts2框架是在struts1和webwork基础之上发展的一个全新的框架。(完全脱胎换骨)