【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
Result
一、Result基础
Result是什么和能干什么?
- 简单的说,Result是当Action处理完数据后返回的一个字符串,它指定了下一个页面的位置。比如:
<action name="action_1" class="struts2.com.test.ActionSupport_1">
<!--suppress Struts2ModelInspection -->
<result name="success">hellowordactionsuccess.jsp</result>
<!--suppress Struts2ModelInspection -->
<result name="input">hellowordactionerror_1.jsp</result>
</action>
action返回的字符串对应的就是result标签里的name属性值。
Result有什么
对于Result
- 在struts2中,预定义了以下一些Result的字符常量:
- SUCCESS:表示Action执行成功,显示结果视图给用户,值为字符串“success”。
- NONE:表示Action执行成功,不需要显示视图给用户,值为字符串“none”。
- ERROR:表示Action执行失败,显示错误页面给用户,值为字符串“error”。
- INPUT:表示Action需要更多的输入信息,回到input对应的页面,值为“input”。
- LOGIN:表示因用户没有登陆而没有正确执行,将返回该视图,值为字符串“login”。
我们也可以自己定义字符常量,只要能和Action里面的execute里面的返回值对应。
对于ResultType
- 在Struts2种ResultType也分成了预定义和自定义两种情况,下面我们讲解。
二、预定义的Result
预定义的ResultType
- 在Struts2定义的包中有一个struts-default.xml文件,里面有相关的<result-type>的定义,<result-types>元素是<package>元素的直接子元素。
<result-types>
<result-type name="dispatcher" class="org.apache.Struts2.dispatcher.ServletDispatcherResult" default="true"/>
......
</result-types>
- 上面的每一个<result-type>元素都是一种视图技术或跳转方式的封装。其中name的属性是在<result>元素中如何引用这种视图技术或跳转方式,对应着<result>元素的type属性的值。
- 在<result>元素中,我们常常是没有书写type的,其实这里我们是使用的默认type,也就是上边的这一段代码,默认的就是dispatcher,相当于Servlet技术里面的RequestDispatcher的技术,也就是服务器跳转技术。
如何配置使用
- 在前面我们已经看过很多了在Action中的讲解,Action类返回的字符串对应的就是<resulet>元素里name属性的值。只要完成对应,就会根据type的跳转方式来跳转页面。
- 配置type属性可以是任意字符串,不过一定是某一个<result-type>元素的name属性。我们可以使用其中Struts2定义好的,也可以使用自定义的。
dispatcher的ResultType
基本使用
<result-types>
<result-type name="dispatcher" class="org.apache.Struts2.dispatcher.ServletDispatcherResult" default="true"/>
......
</result-types>
- 如果使用jsp作为视图技术,那么这个ResultType是最常用的。在这个ResultType的实现中,调用了javax.servlet.RequestDispatcher类的forward方法,也就是说它相当于RequsetDispatcher的一个封装。
- 我们在使用中这个type="dispatcher"是可以不用书写的,name也有默认值"success":
<result name="success" type="dispatcher">getcollection.jsp</result>
几个小的知识点
- 对于dispatcher的使用范围,除了可以配置jsp外,还可以配置其他的web资源,比如servlet等,我们只需要在web.xml文件中映射一下<result>中要跳转的页面。比如:
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>struts2.com.test.ModelDriven_1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
在struts.xml中可以配置:
<result name="success">/login</result>
但是请注意,如果这里访问的是一个Action的资源,那么在web.xml文件里就会报错,我们需要使用另一种type名称为”chain“的ResultType。 2. 使用dispatcher的ResultType,不能访问其他web应用中的web资源,因为属于服务器跳转,所以无法跨域跳转,由servlet的forward方法决定。 3. dispatcher有两个参数也是可以配置的:
- location:默认参数,定位下一个jsp页面的。
- parse:决定了location是否可以通过使用OGNL来引用参数,默认为true。
<result>
<param name="location">login.jsp</param>
<param name="parse">true</param>
</result>
redirect的ResultType
基本使用
- 名称为redirect的ResultType,在struts-default.xml里的配置如下:
<result-type name="redirect" class="org.apache.struts2.result.ServletRedirectResult"/>
这个ResultType包装的是javax.servlet.http.HttpServletResponse类的sendRedirect方法,属于客户端跳转。 2. 与dispatcher不同的是,他属于全新的请求,这就是说这一次请求就变为新的了,本次请求和跳转到下一个页面的请求是两个请求对象,所以跳转页面之后请求的数据会不存在。这里我们拿redirect和dispatcher来做一下对比。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>dispatcher和redirect</title>
</head>
<body>
<form action="result_1">
姓名:<input type="text" name="name">
<input type="submit" value="提交">
</form>
</body>
</html>
package struts2.com.result;
import com.opensymphony.xwork2.ActionSupport;
public class RedirectParse extends ActionSupport {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String execute() throws Exception {
System.out.println(name);
return SUCCESS;
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>获取页面跳转后的值</title>
</head>
<body>
值:<s:property value="name"/>
</body>
</html>
<action name="result_1" class="struts2.com.result.RedirectParse" >
<result type="redirect">
<!-- <param name="location">getRedirectParse.jsp</param>-->
<param name="location">page/result/getRedirectParse.jsp</param>
<param name="parse">true</param>
</result>
</action>
dispatcher输出:
值:teayeon
redirect输出:
值:
两种方式控制台都输出:
teayeon
通过上面的执行结果我们可以看出因为dispatcher是将请求转发了的,所以他能够保存请求的数据,但是redirect是重新定义的一个请求地址,会失去所有请求数据,所以页面上就获取不到name的值。和servlet中的重定向和请求转发性质一样,只不过这里是封装起来了。可以参考我之前写的servlet的页面跳转来理解。
注意:请求转发dispatcher是在之前的url上跳转的,比如我上面的这个程序两个jsp页面是在一个目录下的,所以跳转只需要写jsp文件名.jsp就可以,但是使用重定向redirect来跳转,则需要我们写出全路径名从webapp之后开始。
小知识点:由于采用redirect重定向的方式来跳转,会取不到最初请求页面的值,如果要传值的话我们可以利用get的方式来传参:
result type="redirect">
<param name="location">page/result/getRedirectParse.jsp?name=${name}</param>
<param name="parse">true</param>
</result>
- 这里涉及到了值栈的问题,后面会说到(${name})。
- Struts2是在有请求到达的时候为每个请求创建一个新的值栈,也就是说值栈和请求是一一对应的,值栈封装了一次请求所需要的所有数据
- 其实这里我们还是取不到值的,这里Struts2的标签会到值栈里取值,而这里是执行Result的时候,才在请求上 添加的name参数,然后就直接回到跳转的页面了,根本不会再走一次Struts2的运行过程,也就是说,这里传递的这个参数,根本不会进入到这个请求对应的值栈,因此这样写是取不到值的。所以我们可以利用servlet或者EL来获取值。
使用redirect的ResultType,可以访问其他的web应用中的web资源,跨服务器访问
chain的ResultType
基本使用
<result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>
- chain是一种特殊的视图结果,用来将Action执行完之后链接到另一个Action中继续执行,新的Action使用上一个Action的上下文,数据也会被传递。
- 当遇到一个请求需要多个action处理才能完成的请求,那么这个ResultType就很常用了。不会立即响应,而是将数据传递到下一个Action中处理。这里的请求都是同一个请求。
请求页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>使用chain传递参数在Action中</title>
</head>
<body>
<form action="result_2">
姓名:<input type="text" name="name">
<input type="submit" value="提交">
</form>
</body>
</html>
第一个处理请求的action
package struts2.com.result;
import com.opensymphony.xwork2.ActionSupport;
public class ChainParse extends ActionSupport {
@Override
public String execute() throws Exception {
System.out.println("我是chain的传递者。");
return SUCCESS;
}
}
第二个处理请求的action
package struts2.com.result;
import com.opensymphony.xwork2.ActionSupport;
public class ChainParse1 extends ActionSupport {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String execute() throws Exception {
System.out.println("我是chain的接收者。");
return SUCCESS;
}
}
作为请求的第一个处理action我们的result元素要跳转的位置就是下一个要处理请求的action元素的name属性,这样才能链接起来。
<action name="result_2" class="struts2.com.result.ChainParse">
<result type="chain">
<param name="actionName">ChainParse1</param>
</result>
</action>
<action name="ChainParse1" class="struts2.com.result.ChainParse1">
<result >
<param name="location">getchainparse.jsp</param>
</result>
</action>
接收参数页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>获取chain传递处理后的参数</title>
</head>
<body>
值:<s:property value="name"/>
</body>
</html>
控制台输出
我是chain的传递着。
我是chain的接收者。
从上面我们可以看出使用chain来作为ResultType的类型,可以传递一次请求的参数,而不是直接响应,可以经过多个Action来处理一个请求,这样可以让每一个Action来实现自己特有的功能。注意这里我们在Action中互相跳转的时候不能传递参数即不能出现地址后面跟?参数;这种形式的东西。
chain的参数namespace
参数namespace是可以保证我们可以访问不同包里的action来作为跳转。
<param name="namespace">其他package里的namespace</param>
RedirectAction的ResultType
基本使用
- 这种结果类型与Redirect结果类型的行为有几分相似,但RedirectAction不是重定向到另一个资源,而是重定向到另一个Action。
- 有以下几种参数
- actionName:用来指定”目的“动作的名字。他是RedirectAction结果类型的默认属性。
- namespace:用来指定”目的“动作的命名空间,可以跨包跳转。
- 既然是重定向所以这样传递的请求一定会失去原来的值的。
FreeMarker的ResultType
- Struts2除了支持jsp作为视图技术之外,还支持其他的模版技术,比如FreeMarker和Velocity。
- FreeMarker是一个纯java模版引擎,是一种基于模版来生成文本的工具。
- FreeMarker配置如下:
<result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/>
- 示例
- 制作FreeMarker的页面welcome.ftl
<html> <head> <title>FreeMarker</title> </head> <body> helloword${name}! </body> </html>
- Freemarker的参数
- location:用于指定FTL文件的位置
- parse:默认为true,指定NOGL能够使用
- contentType:默认为text/html,指定输出方式
- writeIfCompleted:默认为false,指定是否不存在FTL解析错误的时候写入到流中。
- 我们要注意一下welcome.ftl应该放在哪里?
- FreeMarker对应的FTL文件,并不是直接放在项目下,而是放在classes的路径下。
其他的ResultType
- velocity:用来处理velocity模版,Velocity是一个模版引擎,可以将Velocity模版转换成数据流的形式,直接通过javaServlet输出。
- xslt:用来处理XML/SLST模版,将结果转换为xml输出。
- httpheader:用来控制特殊HTTP行为。
- stream:用来向浏览器进行流输出
三、全局Result
全局Result概述
- 以前的<result>都是以<action>的子元素出现的,这被成为局部Result,只可以有本部的action元素使用。
- 当我们需要一个Result被多个Action共用时,我们不用麻烦的为每一个action元素都写上同一个result元素,这个时候我们就可以使用全局Result,让多个Action公用;比如多个界面判断该用户是否登陆,如果没有则需要跳转到登陆页面。
配置和使用
- 全局Result和局部的Result没有什么大的区别,同样是配置name和type。只不过这里的result元素不再是action元素的子元素,而是作为<global-results>元素的子元素,而<global-results>元素又是<package>元素的子元素,比如:
<global-results>
<result name="global" >login.jsp</result>
</global-results>
在实际使用中我发现全局的result不能放在action的后面,一定要放在他们的前面,我是用的idea开发的,会在struts.xml文件中报红出错。
搜寻Result的顺序
- 在有了全局Result之后,需要讨论的是当Action运行之后,根据execute方法的返回值,会去对应struts.xml文件里的Result。那么是怎样的一噶顺序呢?
- 首先,先找自己action元素里的result元素是否有匹配的name,如果没有则继续查找
- 其次,再找自己package里的全局result,如果没有则继续向上找。
- 再次,递归寻找自己继承的父包、祖父包中的全局result,如果没有则继续查找。
- 最后,如果上述3种情况都没有找到对应的result,则会抛出Exception。
- 在开发中我们常常会使用子模块的struts配置文件,然后再classes下的struts.xml配置文件里引用进来。这里我们可以把所有子模块中的全局Result抽出来,放在他们的一个公用的父包里,然后struts.xml文件引用该父包就好,这样看起来自己的配置文件更加的整洁。
四、使用通配符
- 这里的通配符也适用于action。比如:
<action name="*_*" class="struts2.com.result.ChainParse.{1}" method="{2}">
</action>
name属性中的”*“代表长度不为0的任意字符串,因此它可以响应的Action只需要名称中间有一个下划线就行。比如使用helloworld_create作为访问的Action的话,那么第一个通配符 *就代表匹配helloworld,第二个通配符代表create。然后在具体要使用的地方我们可以使用{i}i代表下标,从1开始,来使用。
五、Struts2的异常映射
异常映射的基础
在Action中的execute方法签名为public String execute() throws Exception
,这样,Action可以抛出任何异常,那么它是抛给谁了呢?
自己实现异常处理
- 比如我们自己写一个会报异常的Action
package struts2.com.result;
import com.opensymphony.xwork2.ActionSupport;
public class Exception_1 extends ActionSupport {
@Override
public String execute() throws Exception {
int i =5/0;
return SUCCESS;
}
}
- 运行之后发现这个异常会抛给Struts2去处理。但是Struts2也没有去处理这个异常而是直接抛给了Web容器,在实际的项目中很显然不能这么简单粗暴的处理这些异常,一种简单的处理方法就是跳转到一个自定义的错误页面,提示用户或者管理员。
- 这里我们只要指定了异常跳转的页面,程序就会正常的运行下去了。
- 处理异常的Action
package struts2.com.result;
import com.opensymphony.xwork2.ActionSupport;
public class Exception_1 extends ActionSupport {
@Override
public String execute() throws Exception {
try {
int i = 5 / 0;
} catch (Exception e) {
e.printStackTrace();
return "exception";
}
return SUCCESS;
}
}
这里的catch可以写的更具体一点,比如你知道会抛出什么异常,注意子异常要写在父异常的上边。
- result配置
<action name="exception" class="struts2.com.result.Exception_1">
<result>Exception_1.jsp</result>
<result name="exception">Exception_2.jsp</result>
</action>
- 错误页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>处理异常的页面</title>
</head>
<body>
<h2 style="color: red;align-content: center">出错啦!</h2>
</body>
</html>
这时当出现异常的时候就会跳转到当前页面,让程序走完。
使用Struts2的异常机制
- 之前的介绍中我们都没有接触到Struts2的异常机制,是我们自己写的异常处理方法。
- 在<action>元素中设置<exception-mapping>元素,可以指定在execute方法抛出指定错误的时候,跳转在那么页面。
- 修改上面的代码,我们不需要书写try-catch了,使用Struts2的异常处理机制就可以解决。
package struts2.com.result;
import com.opensymphony.xwork2.ActionSupport;
public class Exception_2 extends ActionSupport {
@Override
public String execute() throws Exception {
int i = 5 / 0;
return SUCCESS;
}
}
<action name="exception1" class="struts2.com.result.Exception_2">
<result>Exception_1.jsp</result>
<exception-mapping exception="java.lang.Exception" result="exception1"/>
<result name="exception1">Exception_2.jsp</result>
</action>
在Action里不用去自己捕获处理异常,直接让Action抛给Struts2,这时Struts2在struts.xml配置文件里配置了当请求的处理Action发生异常时就会找到对应的异常类型,然后映射一个result名称,通过该result名称调用result元素的页面。
局部异常映射与全局异常映射
- 上面的<exception-mapping>元素是作为action元素的子元素来使用的,只对该action元素有效,我们也可以配置全局的异常映射。
- 全局异常映射任然是<exception-mapping>元素,只不过不再是action元素的子元素,而是
<global-exception-mappings>
元素的子元素,而 <global-exception-mappings>也是package的直接子元素。
<global-exception-mappings>
<exception-mapping exception="" result=""></exception-mapping>
</global-exception-mappings>
- 当然配置
<global-exception-mappings>
,自然也要配置<global-results>
,而且<global-results>
必须配置在<global-exception-mappings>
之前。
<global-results>
<result name="globalexception">exception.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping exception="java.lang.Exception" result="globalexception"></exception-mapping>
</global-exception-mappings>
这里的局部异常和全局异常处理的查找顺序和前面的全局Result查找顺序是一致的。
在页面上输出异常信息
- 当我们跳转到指定的异常处理页面后,我们有可能需要输出一些异常的信息,为什么报异常。
- 我们可以使用Struts2提供的标签,来输出Exception的错误信息,比如:
- <s:property value="exception"/><%--打印出exception的消息--%>
- <s:property value="exceptionStack"/><%--打印出exception的堆栈消息--%>
五、PreResultListener
什么是PreResultListener?
- PreResultListener监听的事件是发生在Action处理完之后Result处理之前的,在创建事件监听类的时候我们需要实现PreResultListener的类。
PreResultListener实现示例
- 先要书写一个类来实现PreResultListener,创建事件监听处理类。
package struts2.com.result;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.PreResultListener;
public class PreResultListener_1 implements PreResultListener {
@Override
public void beforeResult(ActionInvocation invocation, String resultCode) {
System.out.println("我是事件监听函数");
}
}
- 书写一个Action类
package struts2.com.result;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.interceptor.PreResultListener;
public class PreResultListenerTest extends ActionSupport {
@Override
public String execute() throws Exception {
System.out.println("我是Action处理类");
PreResultListener listener=new PreResultListener_1();
ActionInvocation context=ActionContext.getContext().getActionInvocation();
context.addPreResultListener(listener);
return SUCCESS;
}
}
- 书写提交测试页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>测试监听事件的提交页面</title>
</head>
<body>
<form action="listener.action">
<input type="submit" value="提交">
</form>
</body>
</html>
- 配置struts.xml
<action name="listener" class="struts2.com.result.PreResultListenerTest">
<result>listenerResult.jsp</result>
</action>
- 书写result跳转页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>监听器触发之后跳转的页面</title>
</head>
<body>
<%
System.out.println("我是result的页面");
%>
</body>
</html>
- 输出结果
我是Action处理类
我是事件监听函数
我是result的页面
七、自定义Result
自定义Result的概述
- 自定义Result就是我们自己开发的ResultType,之前我们使用的是Struts2自带的一些ResultType。这里我们要学会自己定义Result。
开发自定义Result
- 开发自定义Result我们只需要实现Result接口,该接口定义如下:
public interface Result extends Serializable {
public void execute(ActionInvocation invocation) throws Exception;
}
在execute方法里面书写具体的Result处理,就是如何去展示视图。这些数据在ActionInvocation(动作调用)里面都能获取到。 2. 示例
- 书写MyResult类
package struts2.com.result;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.Result;
//自定义result
public class MyResult implements Result {
@Override
public void execute(ActionInvocation invocation) throws Exception {
System.out.println("我要处理的Result字符串是"+invocation.getResultCode());
}
}
只是简单的输出了Action返回的要处理的Result的字符串的值,至于想要获取跟多的值,可以通过ActionInvocation去获取ActionContext,在ActionContext里面封装这所有需要的值。 - 配置MyResult
<!-- 自定义Result-->
<result-types>
<result-type name="MyResult" class="struts2.com.result.MyResult"></result-type>
</result-types>
<!-- 使用自定义Result-->
<action name="myresult" class="struts2.com.result.MyResultAction">
<result type="MyResult">myresulttest.jsp</result>
</action>
- 控制台输出
我要处理的Result字符串是success
上面的页面使用的是之前的提交页面,可以自己书写。在具体的开发中我们也会很少使用到自定义Result,如果用到,那么我们将具体的Result操作写在execute方法中就可以了。
来源:oschina
链接:https://my.oschina.net/u/4045839/blog/3144309