1、Action标签中的method属性
我们知道action默认的执行的方法是execute方法,但是一个action只执行一个方法我们觉得有点浪费,我们希望在一个action中实现同一模块的不同功能。怎么办呢?
思考:
我们是否可以在execute()方法中添加一个判断,然后根据该判断选择我们执行的方法呢?我想struts2也是这样干的。不过是在execute之前的方法中进行的,判断的依据不是通过参数,而是通过取读配置文件或者其他得到的。
Struts2在Action中为我们提供了这样的一个属性:method,使用method属性可以指定我们希望执行的自定义方法。
<!-- struts2框架运行时,默认执行action类中的execute方法 在action标签里面的method属性:指定的是要执行的action类中的哪个方法 --> <!--<action name="bookAction" class="cn.itcast.pattern.BookAction" method="add"> <result name="success">/pattern/success.jsp</result> <result name="add">/pattern/BookAction.jsp</result> </action>
我们的自定义方法有什么规范吗?
例子:
/* *自定义方法 * 由public来修饰 * 必须是String返回类型 * 不能传参数 * 方法名自定义 * 总之,一句话:除了方法名与execute()不一样,其他所有的内容都一样 */ public String add() throws Exception{ System.out.println("bookAction ****** add"); return "add"; }
2、通配符的使用
我们又发现,当多个action都指向同一个action的某一个方法的时候,我们就需要定义好多action,但这些action的代码几乎一致。这时候,我们想?应该如何优化呢。
Struts2中提供了一种解决工具,通配符”*”.
简单例子:
需求1:
通配符映射示例(1):<br/> <a href="${pageContext.request.contextPath }/pattern/a_add.do">通配符示例(1)</a><br/> <a href="${pageContext.request.contextPath }/pattern/b_add.do">通配符示例(1)</a><br/> <a href="${pageContext.request.contextPath }/pattern/c_add.do">通配符示例(1)</a><br/> <br/> <br/>
原方案:
<action name="a_add" class="cn.itcast.pattern.BookAction" method="add"> <result name="success">/pattern/success.jsp</result> <result name="add">/pattern/BookAction.jsp</result> </action> <action name="b_add" class="cn.itcast.pattern.BookAction" method="add"> <result name="success">/pattern/success.jsp</result> <result name="add">/pattern/BookAction.jsp</result> </action> <action name="c_add" class="cn.itcast.pattern.BookAction" method="add"> <result name="success">/pattern/success.jsp</result> <result name="add">/pattern/BookAction.jsp</result> </action>
通配符方式:
<!-- *,就是通配符,匹配的是不一样的内容,表示任意一字符串 --> <!--<action name="*_add" class="cn.itcast.pattern.BookAction" method="add"> <result name="success">/pattern/success.jsp</result> <result name="add">/pattern/BookAction.jsp</result> </action>
需求2:(这里不同点不仅仅是Action名了,结果也有变化)
通配符映射示例(2):<br/> <a href="${pageContext.request.contextPath }/pattern/BookAction_add.do">图书</a><br/> <a href="${pageContext.request.contextPath }/pattern/UserAction_add.do">用户</a><br/> <br/> <br/>
原方案:
<!--<action name="BookAction_add" class="cn.itcast.pattern.BookAction" method="add"> <result name="success">/pattern/success.jsp</result> <result name="add">/pattern/BookAction.jsp</result> </action> <action name="UserAction_add" class="cn.itcast.pattern.UserAction" method="add"> <result name="success">/pattern/success.jsp</result> <result name="add">/pattern/UserAction.jsp</result> </action>
通配符方式:
<!-- 以上的两个Action配置可以改写 {1}:表示匹配通配符匹配的第一个字符串 这个action会与前面的name为*_add的冲突 --> <action name="*_add" class="cn.itcast.pattern.{1}" method="add"> <result name="success">/pattern/success.jsp</result> <result name="add">/pattern/{1}.jsp</result> </action><!--
需求3:前面的基础上,方法也有变化
通配符映射示例(3):<br/> <a href="${pageContext.request.contextPath }/pattern/BookAction_add.do">图书添加</a><br/> <a href="${pageContext.request.contextPath }/pattern/BookAction_delete.do">图书删除</a><br/> <br/> <br/> <a href="${pageContext.request.contextPath }/pattern/UserAction_add.do">用户添加</a><br/> <a href="${pageContext.request.contextPath }/pattern/UserAction_delete.do">用户删除</a><br/> <br/> <br/>
原方案:
<action name="BookAction_add" class="cn.itcast.pattern.BookAction" method="add"> <result name="add">/pattern/BookAction.jsp</result> </action> <action name="BookAction_delete" class="cn.itcast.pattern.BookAction" method="delete"> <result name="success">/pattern/success.jsp</result> </action> <action name="UserAction_add" class="cn.itcast.pattern.UserAction" method="add"> <result name="add">/pattern/UserAction.jsp</result> </action> <action name="UserAction_delete" class="cn.itcast.pattern.UserAction" method="delete"> <result name="success">/pattern/success.jsp</result> </action>
通配符方式:
<!-- 以上的配置可以改成 --> <!-- {2}匹配的就是*通配符匹配的第二个子串 {0}匹配的是通配符的整个串 --> <action name="*_*" class="cn.itcast.pattern.{1}" method="{2}"> <result name="success">/pattern/success.jsp</result> <result name="add">/pattern/{1}.jsp</result> </action>
Ok,总结一下:
“*”是struts2中的通配符
{1},{2}…等分别代表通配符匹配的第n个字符串
其实{0}这种写法也存在,比嗾使所有通配符匹配的字符串的拼接
3、动态方法调用
我们前面使用通配符的方式可以通过链接调用同一个action的不同方法,其实struts2还有一种方式可以达到前面的效果,那就是动态方法调用。
如何执行动态方法调用?
首先,对链接的url有要求。例如:
动态方法调用示例:<br/> <a href="${pageContext.request.contextPath }/pattern/BookAction!add.do">图书添加</a><br/> <a href="${pageContext.request.contextPath }/pattern/BookAction!delete.do">图书删除</a><br/> <br/> <br/>
格式为…./namespace+actionName+!+methodName
对应的action:
<!-- 动态方法调用: 页面中请求连接:namespace+actionName+"!"+执行方法名 在struts.xml文件中,不用配置method属性,而是通过页面的链接动态执行指定方法 动态方法调用,不经常使用,经常使用的是通配符 动态方法调用,默认是开启状态 关闭 动态方法调用 : <constant name="struts.enable.DynamicMethodInvocation" value="false" /> --> <action name="BookAction" class="cn.itcast.pattern.BookAction"> <result name="add">/pattern/BookAction.jsp</result> </action>
4、全局result
前面的例子可以发现,我们的result name=”success”执行的代码都是一样的,那么为什么我们不可以将它封装起来呢?一劳永逸。
Struts2中提供了一个标签:<global-result>,它可以设置全包的结果类型
例子:
<!-- 我们在这里的result中的name=success多次调用,都是同样的结果,我们希望一劳永逸,可以在package下配置全局结果 --> <!-- 配置全局结果类型,当然如果action中配置了优先执行action中的 --> <!-- 局部结果类型和全局结果类型的作用范围: 局部的:作用于某个action 全局的:作用于某个package --> <global-results> <result name="success">/pattern/successGlobal.jsp</result> </global-results>
5、action的一个小特点:多实例,线程安全
这个只是简单了解一下,我们可以在action中重写一下无参构造,可以发现,每一次调用该action,都会执行该action中构造方法的内容
上面用的部分素材:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags" %> <% 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>My JSP ‘test.jsp‘ starting page</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> 访问BookAction_add测试action标签中的method属性<br/> <a href="${pageContext.request.contextPath }/pattern/bookAction.do">测试</a><br/> <br/> <br/> 通配符映射示例(1):<br/> <a href="${pageContext.request.contextPath }/pattern/a_add.do">通配符示例(1)</a><br/> <a href="${pageContext.request.contextPath }/pattern/b_add.do">通配符示例(1)</a><br/> <a href="${pageContext.request.contextPath }/pattern/c_add.do">通配符示例(1)</a><br/> <br/> <br/> 通配符映射示例(2):<br/> <a href="${pageContext.request.contextPath }/pattern/BookAction_add.do">图书</a><br/> <a href="${pageContext.request.contextPath }/pattern/UserAction_add.do">用户</a><br/> <br/> <br/> 通配符映射示例(3):<br/> <a href="${pageContext.request.contextPath }/pattern/BookAction_add.do">图书添加</a><br/> <a href="${pageContext.request.contextPath }/pattern/BookAction_delete.do">图书删除</a><br/> <br/> <br/> <a href="${pageContext.request.contextPath }/pattern/UserAction_add.do">用户添加</a><br/> <a href="${pageContext.request.contextPath }/pattern/UserAction_delete.do">用户删除</a><br/> <br/> <br/> 动态方法调用示例:<br/> <a href="${pageContext.request.contextPath }/pattern/BookAction!add.do">图书添加</a><br/> <a href="${pageContext.request.contextPath }/pattern/BookAction!delete.do">图书删除</a><br/> <br/> <br/> 通配符示例(4):<br/> <a href="${pageContext.request.contextPath }/pattern/BookAction_add.do">图书添加</a><br/> <a href="${pageContext.request.contextPath }/pattern/BookAction_delete.do">图书删除</a><br/> <br/> <br/> 全局result:<br/> <a href="${pageContext.request.contextPath}/pattern/BookAction_find.do">图书查找</a><br/> </body> </html>
test.jsp
package cn.itcast.pattern; import com.opensymphony.xwork2.ActionSupport; public class BookAction extends ActionSupport { @Override public String execute() throws Exception { System.out.println("bookAction ****** execute"); return "success"; } /* * 在struts2框架中,action是多实例的 */ public BookAction(){ System.out.println("bookAction 的构造方法"); } /* *自定义方法 * 由public来修饰 * 必须是String返回类型 * 不能传参数 * 方法名自定义 * 总之,一句话:除了方法名与execute()不一样,其他所有的内容都一样 */ public String add() throws Exception{ System.out.println("bookAction ****** add"); return "add"; } public String delete() throws Exception{ System.out.println("bookAction ****** delete"); return "success"; } public String find() throws Exception{ System.out.println("bookAction ****** find"); return "success"; } public String update() throws Exception{ return "success"; } }
BookAction.java
<?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> <package name="pattern" namespace="/pattern" extends="struts-default"> <!-- 我们在这里的result中的name=success多次调用,都是同样的结果,我们希望一劳永逸,可以在package下配置全局结果 --> <!-- 配置全局结果类型,当然如果action中配置了优先执行action中的 --> <!-- 局部结果类型和全局结果类型的作用范围: 局部的:作用于某个action 全局的:作用于某个package --> <global-results> <result name="success">/pattern/successGlobal.jsp</result> </global-results> <!-- struts2框架运行时,默认执行action类中的execute方法 在action标签里面的method属性:指定的是要执行的action类中的哪个方法 --> <!--<action name="bookAction" class="cn.itcast.pattern.BookAction" method="add"> <result name="success">/pattern/success.jsp</result> <result name="add">/pattern/BookAction.jsp</result> </action> <action name="a_add" class="cn.itcast.pattern.BookAction" method="add"> <result name="success">/pattern/success.jsp</result> <result name="add">/pattern/BookAction.jsp</result> </action> <action name="b_add" class="cn.itcast.pattern.BookAction" method="add"> <result name="success">/pattern/success.jsp</result> <result name="add">/pattern/BookAction.jsp</result> </action> <action name="c_add" class="cn.itcast.pattern.BookAction" method="add"> <result name="success">/pattern/success.jsp</result> <result name="add">/pattern/BookAction.jsp</result> </action> --> <!-- 以上的配置可以改写如下: --> <!-- *,就是通配符,匹配的是不一样的内容,表示任意一字符串 --> <!--<action name="*_add" class="cn.itcast.pattern.BookAction" method="add"> <result name="success">/pattern/success.jsp</result> <result name="add">/pattern/BookAction.jsp</result> </action> --> <!--<action name="BookAction_add" class="cn.itcast.pattern.BookAction" method="add"> <result name="success">/pattern/success.jsp</result> <result name="add">/pattern/BookAction.jsp</result> </action> <action name="UserAction_add" class="cn.itcast.pattern.UserAction" method="add"> <result name="success">/pattern/success.jsp</result> <result name="add">/pattern/UserAction.jsp</result> </action> --> <!-- 以上的两个Action配置可以改写 {1}:表示匹配通配符匹配的第一个字符串 这个action会与前面的name为*_add的冲突 --> <action name="*_add" class="cn.itcast.pattern.{1}" method="add"> <result name="success">/pattern/success.jsp</result> <result name="add">/pattern/{1}.jsp</result> </action><!-- <action name="BookAction_add" class="cn.itcast.pattern.BookAction" method="add"> <result name="add">/pattern/BookAction.jsp</result> </action> <action name="BookAction_delete" class="cn.itcast.pattern.BookAction" method="delete"> <result name="success">/pattern/success.jsp</result> </action> <action name="UserAction_add" class="cn.itcast.pattern.UserAction" method="add"> <result name="add">/pattern/UserAction.jsp</result> </action> <action name="UserAction_delete" class="cn.itcast.pattern.UserAction" method="delete"> <result name="success">/pattern/success.jsp</result> </action> --> <!-- 以上的配置可以改成 --> <!-- {2}匹配的就是*通配符匹配的第二个子串 {0}匹配的是通配符的整个串 --> <action name="*_*" class="cn.itcast.pattern.{1}" method="{2}"> <result name="success">/pattern/success.jsp</result> <result name="add">/pattern/{1}.jsp</result> </action> <!-- 动态方法调用: 页面中请求连接:namespace+actionName+"!"+执行方法名 在struts.xml文件中,不用配置method属性,而是通过页面的链接动态执行指定方法 动态方法调用,不经常使用,经常使用的是通配符 动态方法调用,默认是开启状态 关闭 动态方法调用 : <constant name="struts.enable.DynamicMethodInvocation" value="false" /> --> <action name="BookAction" class="cn.itcast.pattern.BookAction"> <result name="add">/pattern/BookAction.jsp</result> </action> <action name="BookAction_find" class="cn.itcast.pattern.BookAction" method="find"> </action> </package> </struts>
struts_pattern.xml