解压apps目录下的struts2-blank.war:javascript
仿照这个最基本的项目,拷贝相关文件:html
1.拷贝apps/struts2-blank/WEB-INF/classes/struts.xml到咱们的项目中的src目录(由于src编译完成后会自动放在classes目录);
2.拷贝类库apps/struts2-blank/WEB-INF/lib/*.jar到本身项目的WebRoot/WEB-INF/lib下。
3.拷贝apps/struts2-blank/WEB-INF/web.xml中关于过滤器的配置到咱们的项目:java
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 5 http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> 6 <display-name></display-name> 7 8 <!-- 从struts2实例项目struts2-blank中拷贝的关于过滤器的配置 --> 9 <filter> 10 <filter-name>struts2</filter-name> 11 <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> 12 </filter> 13 <filter-mapping> 14 <filter-name>struts2</filter-name> 15 <url-pattern>/*</url-pattern> 16 </filter-mapping> 17 18 <welcome-file-list> 19 <welcome-file>index.jsp</welcome-file> 20 </welcome-file-list> 21 </web-app>
4.修改咱们本身项目下的src/struts.xml,先将struts标记下的全部内容所有注释(方便之后参考),并配置咱们本身的package:web
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE struts PUBLIC 3 "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" 4 "http://struts.apache.org/dtds/struts-2.3.dtd"> 5 6 <struts> 7 8 <!-- 注释原来的配置 9 <constant name="struts.enable.DynamicMethodInvocation" value="false" /> 10 <constant name="struts.devMode" value="true" /> 11 12 <package name="default" namespace="/" extends="struts-default"> 13 14 <default-action-ref name="index" /> 15 16 <global-results> 17 <result name="error">/WEB-INF/jsp/error.jsp</result> 18 </global-results> 19 20 <global-exception-mappings> 21 <exception-mapping exception="java.lang.Exception" result="error"/> 22 </global-exception-mappings> 23 24 <action name="index"> 25 <result type="redirectAction"> 26 <param name="actionName">HelloWorld</param> 27 <param name="namespace">/example</param> 28 </result> 29 </action> 30 </package> 31 32 <include file="example.xml"/> 33 --> 34 <!-- Add packages here --> 35 36 <!-- 配置咱们本身的package --> 37 <package name="default" namespace="/" extends="struts-default"> 38 <action name="hello"> 39 <result>/Hello.jsp</result> 40 </action> 41 </package> 42 43 </struts>
5.在WebRoot目录下新建一个Hello.jsp。apache
将项目部署到Tomcat进行访问。若是直接输入项目名称回车会出现如下错误:小程序
HTTP Status 404 - There is no Action mapped for namespace [/] and action name [] associated with context path [/Struts2].服务器
应该使用使用hello.action或者hello进行访问:session
在上面的那个项目中若是咱们在struts.xml中修改了action的名字:app
1 <package name="default" namespace="/" extends="struts-default"> 2 <!-- 咱们将action的名字由hello改为hello_struts因为不能当即生效,将出现404错误 --> 3 <action name="hello_struts"> 4 <result>/Hello.jsp</result> 5 </action> 6 </package>
在没有重启服务器的状况下将出现如下错误:jsp
HTTP Status 404 - There is no Action mapped for namespace [/] and action name [hello_struts] associated with context path [/Struts2].
若是每次更改完struts.xml都要重启服务器就会比较麻烦。在struts.xml中配置一个开发模式的常量:
1 <constant name="struts.devMode" value="true" /> <!-- 开发模式,更改就有反馈 -->
这样就能够在MyEclipse中查看其源代码和使用帮助文档了。
Struts2把用户的请求和视图(展示给用户的页面)进行了分离。
namespace决定了action的访问路径,默认为空(""),能够接收全部的action,namespace能够写成/或者/xxx/yyy(namespace必须以斜杠开头),对应的action的访问路径为/index.action,或者/xxx/yyy/index.action。namespace最好也使用模块来进行命名(例如package的名字是user,那么namespace的名字也是/user)。result的名字若是是"success"则能够省略。
1 <!-- package用来解决重名的问题 --> 2 <package name="front" namespace="/front" extends="struts-default"> 3 <action name="index"> 4 <!-- result若是名字是success则能够省略 --> 5 <result name="success">/Namespace.jsp</result> 6 </action> 7 </package>
若是namespace为空,只要是以/index结尾的请求均可以访问:
1 <!-- 不写namespace与 namespace=""等价 --> 2 <package name="main" extends="struts-default"> 3 <action name="index"> 4 <result>/Namespace.jsp</result> 5 </action> 6 </package>
不一样的package里面能够有相同的action,访问的时候是经过namespace进行查找,若是在对应的namespace下找到了action,就使用该action下的result配置;若是在指定的namespace下没有找到该action则找namespace为空的那个package的action,若是仍是没有找到就直接报错。
例若有如下的的struts.xml:
1 <!-- 不一样的package下有同名的action,一个package的namespace为/front,另外一个为空 --> 2 <package name="front" namespace="/front" extends="struts-default"> 3 <action name="index"> 4 <result name="success">/Namespace.jsp</result> 5 </action> 6 </package> 7 8 <package name="main" extends="struts-default"> 9 <action name="index"> 10 <result>/Namespace1.jsp</result> 11 </action> 12 </package>
具体视图的返回能够由用户自定义的Action来决定。具体的手段是根据返回的字符串找到对应的设置项来决定视图的内容。具体Action的实现是一个普通的Java类,里面有public String execute()方法便可。继承ActionSupport,也能够实现Action接口。通常经常使用的是继承ActionSupport,好处是能够直接使用Struts2封装好的方法。
例如struts.xml中有如下配置:
1 <package name="front" namespace="/" extends="struts-default"> 2 <action name="index" class="org.gpf.struts2.front.action.IndexAction1"> 3 <result>/ActionIntroduction.jsp</result> 4 </action> 5 </package>
org.gpf.struts2.front.action.IndexAction1以下:
1 package org.gpf.struts2.front.action; 2 3 public class IndexAction1 { 4 5 public String execute(){ 6 7 return "success"; 8 } 9 }
Struts2和Struts1的区别在于Struts1每次访问的是同一个Action对象;Struts2每次new一个新的Action,不须要担忧线程的同步问题。
上面的小程序的序列图以下:
当咱们本身没有Action类的时候默认调用的是ActionSupport类中的execute()方法。查看ActionSupport类,发现它实现了Action接口,而Action接口中定义了一系列的常量和一个execute方法:
1 public class ActionSupport implements Action....{ 2 3 public String execute() throws Exception { 4 return SUCCESS; 5 } 6 7 } 8 9 public interface Action { 10 11 public static final String SUCCESS = "success"; 12 13 public static final String NONE = "none"; 14 15 public static final String ERROR = "error"; 16 17 public static final String INPUT = "input"; 18 19 public static final String LOGIN = "login"; 20 21 public String execute() throws Exception; 22 23 }
编写Action的3种方式(在实际开发中通常使用继承自ActionSupport):
1 package org.gpf.struts2.front.action; 2 3 /** 4 * 自定义一个类,有一个public String execute()方法 5 */ 6 public class IndexAction1 { 7 8 public String execute(){ 9 10 return "success"; 11 } 12 } 13 14 package org.gpf.struts2.front.action; 15 16 import com.opensymphony.xwork2.Action; 17 /** 18 * 实现Action接口 19 * @author gaopengfei 20 * @date 2015-5-9 下午5:47:00 21 */ 22 public class IndexAction2 implements Action { 23 24 @Override 25 public String execute() throws Exception { 26 27 return SUCCESS; 28 } 29 30 } 31 32 package org.gpf.struts2.front.action; 33 34 import com.opensymphony.xwork2.ActionSupport; 35 /** 36 * 继承ActionSupport 37 * @author gaopengfei 38 * @date 2015-5-9 下午5:46:48 39 */ 40 public class IndexAction3 extends ActionSupport { 41 42 @Override 43 public String execute() throws Exception { 44 45 return super.execute(); 46 } 47 }
有如下的struts配置:
1 <package name="path" namespace="/path" extends="struts-default"> 2 <action name="path" class="org.gpf.struts2.front.action.PathAction"> 3 <result name="path">/path.jsp</result> 4 </action> 5 </package>
有如下的PathAction:
1 package org.gpf.struts2.front.action; 2 3 public class PathAction { 4 5 public String execute(){ 6 7 return "path"; 8 } 9 }
咱们经过如下的方式访问:
因为咱们访问的时候没有指定namespace,因此会在web.xml中找到项目的默认欢迎页index.jsp。在index.jsp中有一个超连接:
<a href="path/path.action">路径问题说明</a>
下面的path.jsp与index.jsp都在网站的根目录:
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 3 <html> 4 <head> 5 <title>path.jsp</title> 6 </head> 7 8 <body> 9 <h1>path.jsp</h1> 10 <a href="index.jsp">访问index.jsp将会出现404错误</a> 11 </body> 12 </html>
接下来咱们进行如下的访问:
采用../的形式解决上述问题会很是麻烦。最好的方法是获取项目的绝对路径,全部的连接都使用绝对路径,在path.jsp的连接中进行以下修改:
1 <% 2 String path = request.getContextPath(); 3 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 4 %> 5 6 <a href="<%=path %>/index.jsp">使用request.getContextPath()解决路径问题</a>
或者在html的head标签中中增长一条base标签语句:
1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 7 <html> 8 <head> 9 <title>path.jsp</title> 10 <base href="<%=basePath%>" /> 11 <!-- 有了上面的这句话,全部的连接都会默认加上basepath --> 12 </head> 13 14 <body> 15 <h1>path.jsp</h1> 16 <a href="index.jsp">index.jsp</a> 17 </body> 18 </html>
Action执行的时候不必定要执行execute()方法。能够在配置文件中配置Action的时候用method=来指定执行哪一个方法(产生太多的action),也能够在url地址中动态指定(DMI)【推荐】。
假设咱们有如下的Action和Struts配置:
1 public class UserAction extends ActionSupport { 2 3 public String add() { 4 return SUCCESS; 5 } 6 7 }
1 <!-- 注意更改Struts2的常量值为容许DMI --> 2 <constant name="struts.enable.DynamicMethodInvocation" value="true" /> 3 <constant name="struts.devMode" value="true" /> 4 <package name="user" extends="struts-default" namespace="/user"> 5 <action name="user" class="org.gpf.struts2.user.action.UserAction"> 6 <result>/User_add_success.jsp</result> 7 </action> 8 <action name="Useradd" class="org.gpf.struts2.user.action.UserAction" method="add"> 9 <result>/User_add_success.jsp</result> 10 </action> 11 </package>
咱们在访问UserAction的add方法的时候就有两种方式:①经过UserAdd这个Action的method属性指定须要访问的方法;二经过URL参数(!)动态指定。
当UserAction中新增长了一个方法的时候(例如delete方法,前者须要从新定义一个Userdelete的Action,后者只须要将!后面的参数改为delete便可)。
在配置struts的时候使用通配符能够极大地简化配置。见如下的例子:
struts.xml
1 <package name="actions" namespace="/actions" extends="struts-default"> 2 <!-- method中的{1}表示action的name属性中的第1个星号 --> 3 <action name="Student*" class="org.gpf.struts2.user.action.StudentAction" method="{1}"> 4 <result>/Student{1}_success.jsp</result> 5 </action> 6 </package>
StudentAction:
1 public class StudentAction extends ActionSupport { 2 3 public String add() { 4 return SUCCESS; 5 } 6 7 public String delete(){ 8 return SUCCESS; 9 } 10 }
在index.jsp中有2个连接:
1 <% 2 String path = request.getContextPath(); 3 %> 4 <a href="<%=path%>/actions/Studentadd">添加学生</a> 5 <a href="<%=path%>/actions/Studentdelete">删除学生</a>
当咱们访问添加学生的时候,Studentadd这个Action与action标记中定义的name属性(Action*)相匹配,此时的*表示的就是add,从而该Action的method就是add,调用StudentAction的add方法,add方法返回"success",从而在result中显示Student_add_success.jsp(将result中的Student{1}_success.jsp中的{1}用add进行了替换)。
以上的通配符配置还能够进一步简化:
struts.xml
1 <package name="actions" namespace="/actions" extends="struts-default"> 2 <action name="*_*" class="org.gpf.struts2.user.action.{1}Action" method="{2}"> 3 <result>/{1}_{2}_success.jsp</result> 4 </action> 5 </package>
TeacherAction:
1 public class TeacherAction extends ActionSupport { 2 3 public String add() { 4 return SUCCESS; 5 } 6 7 public String delete(){ 8 return SUCCESS; 9 } 10 }
在struts.xml中咱们再也不配置具体的类名和方法名,都使用通配符表示。在上面的配置中action的name有两个*,action的class属性是{1},匹配第一个*,action的method属性匹配第二个*。这样一来就比较方便。咱们能够在不改变struts.xml的状况下为TeacherAction添加其余的方法(例如update、query),还能够添加其余的Action,例如CourseAction(该Action的名字是*Action)。——采用以上这种方式能够动态地位Action添加方法,动态添加不一样的Action(只须要实现约定好jsp页面、Action的命名规则,3行代码就能够搞定Action的配置)。
约定JSP页面大写字母开头,第一个下划线以前的内容表示的是Action名,第一个下划线以后是方法名(与指定的Action中的方法对应);Action的命名大写字母开头以Action结尾。
只要全部的开发人员都遵照以上的规则,struts的配置就很是容易。约定优于配置。
当action中的name能够匹配多个的时候,优先级是先具体再模糊匹配。即:没有通配符的先匹配。若是name中有星号则无论星号的多少(即1个星号和2个星号处于1个级别),这时他们的匹配规则取决于在struct.xml中的配置的前后次序。用如下的配置能够检测匹配顺序:
1 <package name="actions" namespace="/actions" extends="struts-default"> 2 3 <!-- 2个星号 --> 4 <action name="*_*" class="org.gpf.struts2.user.action.{1}Action" method="{2}"> 5 <result>/Teacher_2_star.jsp</result> 6 </action> 7 <!-- 没有通配符,精确匹配 --> 8 <action name="Teacher" class="org.gpf.struts2.user.action.StudentAction"> 9 <result>/Teacher_0_star.jsp</result> 10 </action> 11 <!-- 1个星号 --> 12 <action name="Teacher*" class="org.gpf.struts2.user.action.StudentAction" method="{1}"> 13 <result>/Teacher_1_star.jsp</result> 14 </action> 15 16 </package>
在index.jsp中咱们经过这样的一个连接来访问(该连接同时匹配了多个Action)
1 <% 2 String path = request.getContextPath(); 3 %> 4 <a href="<%=path%>/actions/Teacher">老师</a>
总结:匹配规则:先精确匹配,后模糊匹配(一个星号和多个星号处于同一个匹配级别按照struts.xml中的前后顺序匹配)。
例若有如下的struts配置:
1 <!-- 注意更改Struts2的常量值为容许DMI --> 2 <constant name="struts.enable.DynamicMethodInvocation" value="true" /> 3 <constant name="struts.devMode" value="true" /> 4 <package name="user" extends="struts-default" namespace="/user"> 5 <action name="user" class="org.gpf.struts2.user.action.UserAction"> 6 <result>/info.jsp</result> 7 </action> 8 </package>
UserAction:
1 package org.gpf.struts2.user.action; 2 3 import com.opensymphony.xwork2.ActionSupport; 4 5 public class UserAction extends ActionSupport { 6 7 private String name; 8 private int age; 9 10 public String getName() { 11 return name; 12 } 13 14 public void setName(String name) { 15 this.name = name; 16 } 17 18 public int getAge() { 19 return age; 20 } 21 22 public void setAge(int age) { 23 this.age = age; 24 } 25 26 public String add() { 27 System.out.println("name = " + name); 28 System.out.println("age = " + age); 29 return SUCCESS; 30 } 31 32 }
在index.jsp中咱们经过如下的方式访问action:
1 <% 2 String path = request.getContextPath(); 3 %> 4 使用action属性接收参数<a href="<%=path %>/user/user!add?name=张三&age=18">添加用户</a>
在index.jsp中咱们使用DMI,先找到/user名称空间,而后找到名称为user的那个Action,并经过DMI调用其add方法。咱们经过URL传递参数的时候将name和age传递给了该Action。(须要注意的是:在咱们本身的Action中要定义和参数同名的封装属性,并写好它的getter和setter)。Action自动设置属性是经过setter,其中setXXX中的XXX就是参数的名。也就是说咱们的Action能够写成这样:
1 public class UserAction extends ActionSupport { 2 3 private String username; 4 5 public String getName() { 6 return username; 7 } 8 9 /** 10 * 属性不必定要和参数匹配,可是setXXX中的XXX必定要和参数匹配 11 */ 12 public void setName(String name) { 13 this.username = name; 14 } 15 16 17 public String add() { 18 System.out.println("name = " + username); 19 return SUCCESS; 20 } 21 22 }
域模型就是在问题域中真正存在的实体的概念,例如一个BBS中的域模型就有:板块、话题、注册用户等。
域模型User:
1 package org.gpf.struts2.user.model; 2 3 public class User { 4 5 private String name; 6 private int age; 7 private String sex; 8 9 public String getSex() { 10 System.out.println("getSex<--" + sex); 11 return sex; 12 } 13 14 public void setSex(String sex) { 15 System.out.println("setSex-->" + sex); 16 this.sex = sex; 17 } 18 19 public String getName() { 20 System.out.println("getName<--" + name); 21 return name; 22 } 23 24 public void setName(String name) { 25 System.out.println("setName-->" + name); 26 this.name = name; 27 } 28 29 public int getAge() { 30 System.out.println("getAge<--" + age); 31 return age; 32 } 33 34 public void setAge(int age) { 35 System.out.println("setAge-->" + age); 36 this.age = age; 37 } 38 39 }
UserAction:
1 package org.gpf.struts2.user.action; 2 3 import org.gpf.struts2.user.model.User; 4 5 import com.opensymphony.xwork2.ActionSupport; 6 7 public class UserAction extends ActionSupport { 8 9 private User user; // 声明一个User域模型,Struts2会自动帮咱们new 10 11 public String getInfo() { 12 System.out.println("域模型传递参数name:"+user.getName()); 13 System.out.println("域模型传递参数age:"+user.getAge()); 14 System.out.println("域模型传递参数sex:"+user.getSex()); 15 return SUCCESS; 16 } 17 18 // 提供访问器 19 public User getUser() { 20 System.out.println("getUser"); 21 return user; 22 } 23 24 public void setUser(User user) { 25 System.out.println("setUser"); 26 this.user = user; 27 } 28 29 }
Struts2配置:
1 <!-- 注意更改Struts2的常量值为容许DMI --> 2 <constant name="struts.enable.DynamicMethodInvocation" value="true" /> 3 <constant name="struts.devMode" value="true" /> 4 <package name="user" extends="struts-default" namespace="/user"> 5 <action name="user" class="org.gpf.struts2.user.action.UserAction"> 6 <result>/info.jsp</result> 7 </action> 8 </package>
咱们经过如下的连接传递参数:
<a href="<%=path%>/user/user!getInfo?user.name=张三&user.age=12&sex=男">使用DomainModel接收参数</a>
注意:Action中持有与域模型User的一个引用,并提供对该引用的getter和setter。咱们不须要对User对象进行初始化,Struts会默认new出一个对象,在进行URL传递参数的时候应该采用域模型对象.属性的方式。其中域对象的名字和Action中持有的引用名一致。
其余地方无需改动,将咱们的UserAction实现一个ModelDriven<T>接口:
1 package org.gpf.struts2.user.action; 2 3 import org.gpf.struts2.user.model.User; 4 5 import com.opensymphony.xwork2.ActionSupport; 6 import com.opensymphony.xwork2.ModelDriven; 7 8 public class UserAction extends ActionSupport implements ModelDriven<User> { 9 10 private User user = new User(); // 这里的User必须本身new! 11 12 public String getInfo() { 13 14 System.out.println("name参数:" + user.getName()); 15 System.out.println("age参数:" + user.getAge()); 16 System.out.println("sex参数:" + user.getSex()); 17 return SUCCESS; 18 } 19 20 @Override 21 public User getModel() { 22 23 System.out.println("getModel"); 24 return user; 25 } 26 27 }
Struts2中的MVC。V就是jsp页面、M是后台的那些模型、C就是Action,C控制着V和M之间的通讯(V和M进行了解耦)。
小技巧:struts.xml中的常量配置能够在/org/apache/struts2/default.properties中找到。
在UserAction中咱们定义两个属性来接收用户名和密码参数。在本程序中若是用户名和密码都是admin则验证经过,跳转到Login_success.jsp,不然跳转到Login_failure.jsp。struts的配置:
1 <constant name="struts.enable.DynamicMethodInvocation" value="true" /> 2 <constant name="struts.devMode" value="true" /> 3 <package name="user" extends="struts-default" namespace="/user"> 4 <action name="user" class="org.gpf.struts2.user.action.UserAction"> 5 <result>/Login_success.jsp</result> <!-- 成功转发至成功页 --> 6 <result name="error">/Login_failure.jsp</result> <!-- 失败转发至失败页 --> 7 </action> 8 </package>
1 public class UserAction extends ActionSupport{ 2 3 private String username; // 两个属性接收用户名和密码参数 4 private String password; 5 6 public String getUsername() { 7 return username; 8 } 9 10 public void setUsername(String username) { 11 this.username = username; 12 } 13 14 public String getPassword() { 15 return password; 16 } 17 18 public void setPassword(String password) { 19 this.password = password; 20 } 21 22 public String check(){ 23 24 if(!"admin".equals(username) || !"admin".equals(password)){ 25 this.addFieldError("errors", "错误的用户名或者密码!"); 26 return ERROR; 27 } 28 return SUCCESS; 29 } 30 }
在UserAction中咱们经过addFieldError()方法将错误信息保存了起来,在前台页面可使用struts2提供的标签库(<s:fielderror>)将错误信息显示出来:
PS:J2EE5以后不须要将标签的tld文件放在本身的WEB-INF目录,只要jar包中有会自动搜索。
1 登陆失败! 2 <%@taglib prefix="s" uri="/struts-tags"%> 3 <s:fielderror fieldName="errors"></s:fielderror><br />
以上的标签给咱们强加了一个ul>li和errorMessage的CSS类,用户定制不好,咱们可使用<s:debug>在页面上打印Struts 的Value Stack(各类各样的错误),使用<s:property>标签能够取出Value Stack Contents和Stack Context(其实就是Action Context)中的属性。在Login_failure.jsp中咱们这样写:
1 登陆失败!<br /> 2 <%@taglib prefix="s" uri="/struts-tags"%> 3 <s:property value="errors.errors[0]"/> <!-- OGNL表达式 --> 4 <s:debug></s:debug>
取出了错误信息咱们就能够本身进行样式的设置了。
其实主要就是使用Action取得Map类型的request、session、application以及真实类型HttpServletRequest、HttpSession、ServletContext。由于咱们的结果是经过result返回出去的,因此但对于response咱们能够无论。
index.jsp
1 取得Map类型request,session,application,真实类型 HttpServletRequest,HttpSession, ServletContext的引用: 2 <ol> 3 <li>前三者:依赖于容器</li> 4 <li>前三者:IOC</li> (只用这种) 5 <li>后三者:依赖于容器</li> 6 <li>后三者:IOC</li> 7 </ol> 8 <br /> 9 <form name="f" action="" method="post"> 10 用户名:<input type="text" name="name" /> 11 密码:<input type="text" name="password" /> <br /> 12 <input type="button" value="submit1" 13 onclick="javascript:document.f.action='login/login1';document.f.submit();" /> 14 <input type="button" value="submit2" 15 onclick="javascript:document.f.action='login/login2';document.f.submit();" /> 16 <input type="button" value="submit3" 17 onclick="javascript:document.f.action='login/login3';document.f.submit();" /> 18 <input type="button" value="submit4" 19 onclick="javascript:document.f.action='login/login4';document.f.submit();" /> 20 </form>
在index.jsp中咱们经过javascript代码动态指定表单提交的Action。这样咱们就能够经过多个按钮提交同一个表单。struts.xml中Action的配置以下(经过通配符动态指定):
1 <constant name="struts.enable.DynamicMethodInvocation" value="true" /> 2 <constant name="struts.devMode" value="true" /> 3 <package name="login" extends="struts-default" namespace="/login"> 4 <action name="login*" class="org.gpf.struts2.user.action.LoginAction{1}"> 5 <result>/Login_success.jsp</result> 6 </action> 7 </package>
LoginAction1.java
1 public class LoginAction1 extends ActionSupport{ 2 3 private Map request; 4 private Map session; 5 private Map application; 6 7 /** 8 * 经过ActionContext.getContext()方法 9 * 在构造器中为request、session和application初始化 10 */ 11 public LoginAction1() { 12 request = (Map) ActionContext.getContext().get("request"); 13 session = ActionContext.getContext().getSession(); 14 application = ActionContext.getContext().getApplication(); 15 } 16 17 public String execute(){ 18 19 // 向request、session和application的Map中设置内容 20 request.put("r1", "r1"); 21 session.put("s1", "s1"); 22 application.put("a1", "a1"); 23 return SUCCESS; 24 } 25 }
在Login_success.jsp中咱们将request、session、application范围内设置的属性取出:
1 登陆成功! 2 <%@taglib prefix="s" uri="/struts-tags"%> 3 <s:debug></s:debug> 4 <table> 5 <tr> 6 <th>经过ValueStack取得Web元素中的内容</th> 7 <th>经过3种属性范围取得Web元素中的内容</th> 8 </tr> 9 <tr> 10 <td>取得request</td> 11 <td><s:property value="#request.r1"/></td> 12 <td><%=request.getAttribute("r1") %></td> 13 </tr> 14 <tr> 15 <td>取得session</td> 16 <td><s:property value="#session.s1"/></td> 17 <td><%=session.getAttribute("s1") %></td> 18 </tr> 19 <tr> 20 <td>取得application</td> 21 <td><s:property value="#application.a1"/></td> 22 <td><%=application.getAttribute("a1") %></td> 23 </tr> 24 </table>
经过debug标记,咱们能够发如今StackContext(也就是ActionContext)中存在request、session、application3个键,而咱们为其设置的值r一、s1和a1则保存在它们的Value中(Value也是Map)。因此咱们能够在LoginAction1中经过ActionContext.getContext().get("request")等方法获取对应的Map集合。
除了可使用#session.属性名、#request.属性名、#application.属性名访问咱们设置在这3种属性范围以内的属性之外,咱们还可使用#attr.属性名的方式自动搜索匹配属性名的字段:
1 <s:property value="#attr.r1"/> 2 <s:property value="#attr.s1"/> 3 <s:property value="#attr.a1"/>
可是开发中这3种属性范围以内的属性应该是精肯定位的,不该该依靠自动搜索范围是从request到application(由于可能有重名属性)。
该种方式须要实现XXXaware接口。aware的意思是得知、得到。
1 /** 2 * LoginAction2实现了RequestAware,SessionAware,ApplicationAware接口 3 */ 4 public class LoginAction2 extends ActionSupport implements RequestAware,SessionAware,ApplicationAware{ 5 6 private Map<String, Object> request; // 依赖外界的环境把值注给咱们,而不是咱们本身主动拿 7 private Map<String, Object> session; 8 private Map<String, Object> application; 9 10 public String execute(){ 11 request.put("r1", "r1"); 12 session.put("s1", "s1"); 13 application.put("a1", "a1"); 14 return SUCCESS; 15 } 16 17 @Override 18 public void setApplication(Map<String, Object> application) { 19 20 this.application = application; 21 } 22 23 @Override 24 public void setSession(Map<String, Object> session) { 25 26 this.session = session; 27 } 28 29 @Override 30 public void setRequest(Map<String, Object> request) { 31 32 this.request = request; 33 } 34 35 }
IoC(Inverse of Control,控制反转)也叫作DI(dependency injection,依赖注入)。
所谓依赖注入就是咱们在LoginAction2中的3个属性依赖Struts2将值传给咱们而不是咱们本身主动取得值。所谓控制反转就是原先咱们须要本身控制3个属性的值(获取),而如今3个属性的值交给Struts2容器进行。以上的2个概念在Spring中大量应用——咱们本身定义的成员变量历来不初始化而是交给Spring进行初始化,Spring是经过配置文件的方式进行的初始化。
前面获取的方式都是获取的Map,若是想要得到HttpServletRequest、HttpSession、ServletContext可使用下面的方法:
1 public class LoginAction3 extends ActionSupport { 2 3 private HttpServletRequest request; 4 private HttpSession session; 5 private ServletContext application; 6 7 public LoginAction3() { 8 9 request = ServletActionContext.getRequest(); 10 session = request.getSession(); 11 application = ServletActionContext.getServletContext(); 12 } 13 14 public String execute(){ 15 16 request.setAttribute("r", "r"); 17 session.setAttribute("s", "s"); 18 application.setAttribute("a", "a"); 19 return SUCCESS; 20 } 21 22 }
1 public class LoginAction4 extends ActionSupport implements ServletRequestAware { 2 3 private HttpServletRequest request; 4 private HttpSession session; 5 private ServletContext application; 6 7 @Override 8 public void setServletRequest(HttpServletRequest request) { 9 10 this.request = request; 11 this.session = request.getSession(); 12 this.application = request.getServletContext(); 13 } 14 15 public String execute(){ 16 17 request.setAttribute("r", "r"); 18 session.setAttribute("s", "s"); 19 application.setAttribute("a", "a"); 20 return SUCCESS; 21 } 22 }
通常来讲struts.xml中配置的是全部struts的公共配置,将具体的业务划分红模块。例如:登陆模块、退出模块。
struts.xml
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE struts PUBLIC 3 "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" 4 "http://struts.apache.org/dtds/struts-2.3.dtd"> 5 6 <struts> 7 <!-- 公共配置 --> 8 <constant name="struts.enable.DynamicMethodInvocation" value="true" /> 9 <constant name="struts.devMode" value="true" /> 10 11 <!-- 如下是模块的划分 --> 12 <include file="login.xml"></include> 13 <include file="logout.xml"></include> 14 15 </struts>
login.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> <package name="login" extends="struts-default" namespace="/login"> <action name="login*" class="org.gpf.struts2.user.action.LoginAction{1}"> <result>/Login_success.jsp</result> </action> </package> </struts>
logout.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE struts PUBLIC 3 "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" 4 "http://struts.apache.org/dtds/struts-2.3.dtd"> 5 <struts> 6 <package name="logout" extends="struts-default" namespace="/loginlogout"> 7 <action name="logout*" class="org.gpf.struts2.user.action.LogoutAction{1}"> 8 <result>/Logout_success.jsp</result> 9 </action> 10 </package> 11 </struts>
此种方式能够进行模块的划分,项目组的各个成员各自开发,最后在struts.xml中进行全部模块的整合。
当访问的Action不存在的时候咱们能够经过如下的方式交给默认的Action处理:
1 <package name="default" extends="struts-default" namespace="/"> 2 <!-- 当找不到Action的时候跳到默认的Action --> 3 <default-action-ref name="index"></default-action-ref> 4 <action name="index"> 5 <result>/default.jsp</result> 6 </action> 7 </package>
例如:在浏览网站的时候有时候出现的404错误就能够交给默认Action处理,默认Action能够跳转到网站的主页提升用户体验。