struts基础2

Result配置详解 
说明:在前面的许多案例中我们所用到的Action基本都继承自ActionSupport这个类,而在这个类中我们定义了五个字段:SUCCESS,NONE,ERROR,INPUT,LOGING。我们可以直接返回这些字段值,这些字段值实质是被定义成:String SUCCESS=”success”这样的形式,所以我们只要在Result元素中用它们的小写即可。 
<result>标准完整形式如下: 
<result name="success" type="dispatcher">  
 
<param name="location">/default.jsp</param> 
</result> 
如果我们都采用默认的形式,最终可以简写成:<result>/default.jsp</result> 

 

探讨type类型: 

Type类型值               作用说明                                              对应类 
chain                用来处理Action链                              com.opensymphony.xwork2.ActionChainResult  

dispatcher        用来转向页面,通常处理JSP                 org.apache.struts2.dispatcher.ServletDispatcherResult 

redirect            重定向到一个URL                              org.apache.struts2.dispatcher.ServletRedirectResult 

redirectAction    重定向到一个Action                           org.apache.struts2.dispatcher.ServletActionRedirectResult  

plainText       显示源文件内容,如文件源码                    org.apache.struts2.dispatcher.PlainTextResult 

freemarker    处理FreeMarker模板                             org.apache.struts2.views.freemarker.FreemarkerResult

 httpheader 控制特殊http行为的结果类型                    org.apache.struts2.dispatcher.HttpHeaderResult 

stream     向浏览器发送InputSream对象,通              org.apache.struts2.dispatcher.StreamResult 

              常用来处理文件下载,还可用于返回AJAX数据。
 velocity   处理Velocity模板                                     org.apache.struts2.dispatcher.VelocityResult 

xslt         处理XML/XLST模板                                  org.apache.struts2.views.xslt.XSLTResult  
以上对type类型作简要的说明,下面来看实例:当一个Action处理后要返回的Result是另一个Action时,作如何配置,关键就是配置type类型。下面建立struts2result项目说明 步骤一:建立两个Action:TestAction、Test2Action 
步骤二:web.xml配置省略。struts.xml主要配置内容如下: 
<struts>  <package name="resultTest" extends="struts-default">   <action name="test" class="com.asm.TestAction">    <result name="success" type="chain">     
<param name="actionName">test2</param>    
</result> 
  
</action> 
   <action name="test2" class="com.asm.Test2Action">    
<result name="success">/test2Suc.jsp</result>   
</action>  
 
</package> 
</struts> 
说明:在名为“test”的action中,我们配置result元素的type类型值为chain,意为将继续把Action传递到下一个名为test2的Action中去,在test2.action中会把页面转向到test2Suc.jsp中去。在type类型为chain时,它的param有4个值可配,除了这里用到的name=”actionName”外(必须配置,否则报错),还有name=namespace|method|skipActions。其中namespace指定要转向到action的名字空间,由于此处是转到Action位于同一个namespace下,而namesapace的默认值the current namespace,所以可以省略不写(需要说明的是如果要跳到别的名称空间的action中去,除了使用namespace指定外,还可以用:/要跳去action所在名称空间的值/要跳去的action的name值)。Method用于指定转向到一个目标action所调用的方法,默认是调用下一个action的execute方法,所以此处仍可以省略。SkipActions是一个可选的属性,一般不用。具体可以参看chain所对应类的api帮助。 
在本实例中,我们还在TestAction中设定一个username字段,并在execute方法执行为它赋了值,并在test2Suc.jsp中引用了此值。其实这种做法在web开发中还是很有用处,比如可以代替隐藏域。需要注意的是之所以在action的传递中能把设定的这个值保存下去,主要是因为转向都是服务器跳转。如果我们跳转时采取了客户端跳转,比如在test2 action的result中指定type类型为redirect,要想传递参数可以在result指向的jsp页面中附加参数即可,我们可以在test2 action的result中写成: 
<result name="success" type="redirect">  

/test2Suc.jsp?username=${username} 
</result>   随后在test2Suc.jsp页面中引用时会出现三个问题:1.EL表达式引用失效,(EL表达式
应该使用${param.username}形式)。我们也可以使用<%=request.getParameter("username")%>获取参数值。  2.由于在前面的TestAction中设定的值为中文,而附加到这里的uri请求的参数后面时会出现乱码问题。(可以使用URI编码再解码解决此问题)3.值栈取值失效:因为每一次request共享同一个值栈,所以服务器端的forward跳转也是能共享同一值栈得。但是着当test action执行后把请求交由test2 action时,test2 action采取的是redirect重定向到test2Suc.jsp页面,这时其实就是重发的一次request,所以在test action保存的值栈内容全部失效。这也就是为什么我们要附加参数的原因。而参数是保存在actionContext中,所以采用了#的方式来取出值。图示说明: 
  
步骤三,编写链接页面index.jsp。发布测试: 
全局result: 
如果我们所有的action均有可能跳到相同的页面,则不防使用全局result。为了方便引用我们专门建立一个package来存放公共的result。在会用到个全局的跳转时,只需要把继承自这个公共的package即可。 建立公共包,代码如下: 
<package name="pubResult" extends="struts-default" abstract="true">   <global-results>    
<result name="error">/error.jsp</result>  
 
</global-results> 
</package>  
由于它下面没的action配置,所以我们可以像默认的struts-default包一样,声明abstract=true,这样声明表示此packgage下不会有action,它一般是用来让别的package继承。随后再在要用到全局result中引用这个公共的package。代码如下: 
<package name="testGlobal" extends="pubResult" >  <action name="error" class="com.asm.ErrorAction"></action>  
<action name="error2" class="com.asm.Error2Action"></action> 
</package>这样操作相当于把全局的result加到了此package下的所有action中去。

 

异常处理 
步骤一、建立struts2exception项目下,在该项目下建立登录页面login.jsp。主要代码如下: 
<form action="<%=request.getContextPath() %>/login.action">   username:<input type="username" name="username"><br>  
 
<input type="submit" value="login"> 
</form>  

 
步骤二、建立LoginAction,代码如下: 
package com.asm; 
public class LoginAction extends ActionSupport {  private String username; 
 public String execute() throws Exception {   if (username.equals("exception")) { 
   throw new ClassNotFoundException("类未被找到");   } else if (username.equals("global")) {    throw new Exception("全局异常");   } else {    return SUCCESS; 
  } 
 

 ...省力get/set方法 } 
步骤三、struts.xml配置文件如下: 
<struts>  <package name="ex" extends="def">   <action name="login" class="com.asm.LoginAction">    <exception-mapping result="myException"     
exception="java.lang.ClassNotFoundException">    </exception-mapping> 
   <result name="myException">/exception.jsp</result>    
<result name="success">/main.jsp</result> 
  
</action> 
 </package> 
  <package name="def" extends="struts-default" abstract="true">   <global-results>    
<result name="myGlobal">/globalException.jsp</result>   
</global-results> 
   <global-exception-mappings>    <exception-mapping result="myGlobal"     
exception="java.lang.Exception">    
</exception-mapping> 
  
</global-exception-mappings> 
 
</package> 
</struts> 
分析:异常处理机制较为简单,所以在此只略作说明。当登录时输入“exception”时,在LoginAction中会抛出会一个ClassNotFoundException异常,此异常我们采取的局部异常处理的方式,如果登录时输入“globla”,则会抛出Exception异常,此异常我们采取的是全局异常的处理方式,在ex包中我们继承了全局异常所在的包。提示:<exception-mapping>中的result属性的值来源于<result>元素中的name属性的值。从实例可以看出,我们一般把这种全局性的异常放在一个抽象包中供其实包继承。

 

 

在Action获取Scope对象 
引言:在前面的Action操作中,关键就是Action中的exectue方法,但是此方法并没有request、session、application等对象作为参数,自然就不能利用这些对象来操作。下面我们建立struts2scope项目,并用四种方式来获取这些对象: 

方式一、与Servlet解耦合的非IOC方式 
获取的scope对象与容器无关,通过ActionContext获取。 LoginAction代码如下: 
package com.asm; 
public class LoginAction extends ActionSupport {  private String username;  ActionContext context;  Map request;  Map session;  Map application; 
 public String execute() throws Exception {   context=ActionContext.getContext();   request=(Map) context.get("request");   session=context.getSession(); 
  application=context.getApplication();    
  request.put("req", "requst属性");   session.put("ses", "sesion属性"); 
  application.put("app", "application属性");   return SUCCESS; 
 

 ...省略username的get/set方法 } 
struts.xml配置如下: 
<struts>  <package name="scope" extends="struts-default">   <action name="login" class="com.asm.LoginAction">  
 
 
<result>/loginSuc.jsp</result> 
</action> </package>   
</struts> 
login.jsp内容如下: 
<form action="<%=request.getContextPath() %>/login.action">   用户名:<input type="text" name="username"><br>  
 
<input type="submit" value="login">  
</form> 
loginSuc.jsp的主要内容如下: 
${requestScope.req} ${sessionScope.ses} ${applicationScope.app} 
<h4>以下使用scope.getAttribute的形式来接受</h4>   request: <%=request.getAttribute("req") %><br>  
 session: <%=session.getAttribute("ses") %><br> 
 
 
application:<%=application.getAttribute("app") %><br> 
分析:通过ActionContext的getContext静态方法得到ActionContext对象,然后ActionContext对象调用get方法来获取一个存储在request范围中的对象。我们使用el或通过request.getAttribute这样的方式  

均可以获取对象值,这说明了这些Map request对象实际是存储在request范围内的对象。 方式二、与Servlet解耦合的IOC方式 我们建立Login2Action,主要代码如下: 
package com.asm; 
public class Login2Action extends ActionSupport implements RequestAware,SessionAware,ApplicationAware {  private String username;  Map request;  Map session;  Map application; 
 public String execute() throws Exception {   request.put("req", "requst属性");   session.put("ses", "sesion属性"); 
  application.put("app", "application属性");   return SUCCESS; 
 } 
 public void setRequest(Map<String, Object> request) {   this.request=request; 
 } 
 public void setSession(Map<String, Object> session) {   this.session=session;  } 
 public void setApplication(Map<String, Object> application) {   this.application=application;  

 ...省略username的get/set方法  } 
注册此Action的name为login2,随后修改登录提交为.../login2.action。便可以发布测试。说明:此方法其实和方式一很相似,只是在方式一中我们需要手动的为Map request赋值,但是在方式二中它是通过实现接口,在重写接口中的方法中完成对Map requset的赋值,所以称之IOC方式。借助此例,略谈下依赖注入与控制反转:所谓依赖注入就是一个对象自己本身的初始化是依赖其它对象。比如这里Map request这些对象会依赖struts2来给其初始化,称为依赖注入,而依赖注入的就表示,这些对象的控制权不再由此类本身掌握,而是交给了别的对象,即是控制权反转了。 强调:方式二是开发中主要用的方式,应重点掌握 
方式三、与Servlet耦合的非IOC方式 建立Login3Action,代码如下: 
package com.asm; 
public class Login3Action extends ActionSupport {  private String username;  HttpServletRequest request;  HttpSession session; 
 ServletContext application; 
 public String execute() throws Exception {   request = ServletActionContext.getRequest();   session = request.getSession(); 
  
application = ServletActionContext.getServletContext();  

  request.setAttribute("req", "requst属性");   session.setAttribute("ses", "sesion属性"); 
  application.setAttribute("app", "application属性");   return SUCCESS; 
 

 ...省略username的get/set方法。 } 
此方法获取的纯粹的Scope对象,它与容器相关,这些Scope对象操作更强。同样只需要注册此Action并修改登录页面便可进行测试。 方式四、与Servlet耦合的IOC方式 建立Login4Action,代码如下: 
package com.asm; 
public class Login4Action extends ActionSupport implements ServletRequestAware,ServletContextAware{  private String username;  ActionContext context;  HttpServletRequest request;  HttpSession session; 
 ServletContext application; 
 public String execute() throws Exception {   context=ActionContext.getContext();   session=request.getSession();  
  request.setAttribute("req", "requst属性");   session.setAttribute("ses", "sesion属性"); 
  application.setAttribute("app", "application属性");   return SUCCESS; 
 }   
 public void setServletRequest(HttpServletRequest request) {   System.out.println("测试:"+request);   this.request=request; 
 } 
 public void setServletContext(ServletContext application) {   System.out.println("测试:"+application);   this.application=application; 
 

 ...省略username的get/set方法 } 
同样只需要注册此Action并修改登录页面便可发布测试 

 

OGNL与ValueStack(VS) 
1.值栈入门 
下面我们建立struts2ognl项目来练习ognl的使用。 步骤一、搭建strust2的开发环境 
步骤二、建立LoginAction,主要代码如下: 
package com.asm; 
public class LoginAction extends ActionSupport{  
private User user; 

 public String execute() throws Exception {  
   
return SUCCESS; 
 

 ...省略user的get/set方法  } 
步骤三、配置此Action,struts.xml的主要内容如下: 
<struts>  <constant name="struts.devMode" value="true"></constant>   <package name="ognl" extends="struts-default">   <action name="login" class="com.asm.LoginAction">    
<result>/loginSuc.jsp</result>   
</action> 
 
</package> 
</struts> 
步骤四、编写login.jsp页面,主要代码如下: 
<body>  <form action="<%=request.getContextPath()%>/login.action"  method="get">   用户名:<input type="text" name="user.username"><br>   密  码:<input type="password" name="user.password"><br>   
<input type="submit" value="login"> 
 
</form> 
</body> 
步骤五、编写loginSuc.jsp页面,主要代码如下: 
<body>   
 
调试:<s:debug></s:debug> 
  获取值栈中的username属性:<s:property value="user.username"/> <br> </body> 
步骤六、发布测试及说明 
当我们输入用户名并成功跳到logSuc.jsp页面后,会得到登录时输入的用户名信息。下面简要说明这一过程: 
(1).login.jsp登录提交登录信息给login.action 
(2).struts2监听到客户端的login.action请求,按配置文件要求,把此请求交给LoginAction处理。这表示会去new LoginAction(), 当struts2  new出此Action对象后会把这个对象放在context map中,只是这个Action非常特殊,所以放在值栈中,而放在值栈中的对象是可以直接引用的,放在其它context map中的对象引用时会要求加#。 
(3).当new LoginAction时,表示它也会初始化此类中的对象,比如这里会去初始化User对象,但是要注意的是如果我们在用户名和密码什么都不输,再来用debug来看值栈中的user是,发现它仍会new此对象,因为尽管我们没用输入值,但是后台的set方法还是要被调用,所以会new出此对象,但是如果我们直接输入.../struts2ognl/login.action时我们会发现跳转到loginSuc.jsp页面时,用debug来看值栈中此User user,发现它的值为null。第二点要注意的是我们必须为User类提供默认的构造方法,否则将会出现如下错误: java.lang.InstantiationException: com.asm.vo.User 总结:1.Action会在请求时被创建,且会把创建的对象放到值栈中。 
2.Action中的对象字段只有在需要时才会以new 的形式初始化,而且这些对象字段必须提供默认的构造方法。 
3.ValueStack对象贯穿整个Action的生命周期(每个Action类的对象实例会拥有一个ValueStack对象)。当Struts 2接收到一个.action的请求后,会先建立Action类的对象实例,但并不会调用Action方法,而是先将Action类的相应属性放到ValueStack对象的顶层节点(vs对象相当于一个栈)。 

补充:值栈(根)对象也可以直接使用EL表达式访问,比如这里可以直接通过${user.username}来获取username的值,我们知道el表达式只能访问四种scope范围内的对象,那为什么这里能访问到值栈对象呢?原因是struts2对HttpServletRequet进行了一次封装,封装的代码主要是重写了getAttribute方法,简述重写此方法的核心代码:首先在原始的HttpServletRequest对象中查找el表达式中的属性,如果找不到再通过ActionContext获取值栈对象,进而再从值栈对象中查找el表达式中要访问的属性。 2.OGNL入门 
下面我们在com.asm.vo.User类中增加一个字段private Address addres;,并提供此字段的get/set方法,随后再在login.jsp中增加如下代码: 
城  市:<input type="text" name="user.addres.city"><br> 然后再在loginSuc.jsp中增加如下代码: 
获取城市属性:<s:property value="user.addres.city"/><br> 
然后测试,会得到登录时输入的城市信息(中文会有乱码)。下面借助此例谈ognl的定义:在这个例子中,我们的LoginAction中有一个User对象,而在User对象中又有一个Address对象,这些对象之间依靠这种类的字段进行关联,或者说是依靠字段属性进行导航,这也就是OGNL的定义:Object Graph Navigation Language:对象图导航图语言,它是建立在值栈技术之上的一种全新语言。 
补充:用%{}可以取出存在值堆栈中的Action对象,直接调用它的方法.我们在loginSuc.jsp中增加如下内容调用LoginAction中的get方法: 
调用值栈对象中的方法:<s:property value="%{get()}"/>  
LoginACtion中增加的get方法如下: 
public String get(){   return "这是User中的get方法"; 

3.普通方法访问 
首先在User中增加一个成员方法,代码如下: 
public String get(){   return "这是User中的get方法"; 

在LoginAction中也有类似的get方法,随后再在loginSuc.jsp中增加如下代码: 
调用值栈对象中的普通方法(2):<s:property value="user.username.length()"/><br> 调用值栈对象中的普通方法(1):<s:property value="user.get()"/><br> 调用LoginAction中的普通方法:<s:property value="get()"/><br> 
最后测试,发现这些方法都可以访问到。 4.静态方法访问 
在LoginAction中增加如下方法: 
public static String getSta() {   return "这是LoginAction中的静态方法"; 

然后在loginSuc.jsp中增加如下代码: 
调用Action中的静态方法:<s:property value="@com.asm.LoginAction@getSta()"/><br> 调用LoginAction中的静态方_方式(2):<s:property value="@vs@getSta()"/><br> 
说明:我们在方式二中用到@vs,只有那些值栈中的对象才可以这样写。 然后访问,发现访问不到,因为在struts2.1.6的版本中,struts.ognl.allowStaticMethodAccess的默认值为false,我们只需在struts.xml中增加如下内容: 
<constant name="struts.ognl.allowStaticMethodAccess" value="true"/> 再来访问时便可以访问到。

 

posted @ 2015-02-28 17:29  萧雪痕  阅读(165)  评论(0编辑  收藏  举报