博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
第十五部分_Struts2.1拦截器深度剖析、异常处理
阅读量:4590 次
发布时间:2019-06-09

本文共 8283 字,大约阅读时间需要 27 分钟。

恢复拦截器:interceptor。

在我们声明拦截器(这时候默认的拦截器就不起作用了)的同时,我们一定要加上struts2提供的默认拦截器(否则访问页面的返回信息可能出乎你的意料,比如提交的表单信息出现一堆乱七八糟的信息),且我们自己声明的拦截器一定要在默认的之前。

使用拦截器的步骤:

  1. 定义相应的拦截器类,实现Interceptor或是继承AbstractInterceptor(该抽象类空实现实现了Interceptor接口的init和destroy方法)
  2. 在struts.xml中声明拦截器,在相关Action中配置,配置的最后记得一点要添加默认的拦截器

下面我们使用拦截器帮助我们读取xml中的参数(类比与之前用过滤器实现黑名单禁止留言的例子,这里不需要用getParameter方法就可以方便的读取参数值)。

下面举个例子:

新建一个com.test.interceptor包,在该包下面新建一个类MyInterceptor:

package com.test.interceptor;import com.opensymphony.xwork2.ActionInvocation;import com.opensymphony.xwork2.interceptor.Interceptor;import com.opensymphony.xwork2.interceptor.PreResultListener;public class MyInterceptor implements Interceptor{	private String hello; // 接收拦截器在struts.xml配置中的hello属性中的值		public String getHello()	{		return hello;	}	public void setHello(String hello)	{		this.hello = hello; 	}	public void destroy()	{		System.out.println("destroy invoked");	}		public void init()	{		System.out.println("init invoked");		System.out.println("hello :" + hello);	}		public String intercept(ActionInvocation invocation) throws Exception	{		System.out.println("intercept invoked");				String result = invocation.invoke();				System.out.println(result);				return result;	}}

为了更加清楚地了解拦截器的运转流程,我们多写几个拦截器,MyInterceptor2:

package com.test.interceptor;import com.opensymphony.xwork2.ActionInvocation;import com.opensymphony.xwork2.interceptor.AbstractInterceptor;public class MyInterceptor2 extends AbstractInterceptor{	@Override	public String intercept(ActionInvocation invocation) throws Exception	{		System.out.println("myInterceptor2 invoked");				String result = invocation.invoke();				System.out.println("result2: " + result);				return result;	}}

再来一个MyInterceptor3(前面是基于类的拦截器,这个是基于方法的):

package com.test.interceptor;import com.opensymphony.xwork2.ActionInvocation;import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;public class MyInterceptor3 extends MethodFilterInterceptor{	@Override	protected String doIntercept(ActionInvocation invocation) throws Exception	{		System.out.println("myInterceptor3 invoked");				String result = invocation.invoke();				System.out.println("result3 : " + result);				return result;	}}

然后在struts.xml中原来的基础之上进行配置:

world
/success.jsp
/register.jsp

服务器启动过程中会输出的与我们相关的信息(截取一部分):

信息: Parsing configuration file [struts-plugin.xml]

2015-7-23 9:21:28 com.opensymphony.xwork2.util.logging.commons.CommonsLogger info
信息: Parsing configuration file [struts.xml]
init invoked
hello :world
2015-7-23 9:21:30 org.apache.catalina.startup.HostConfig deployDescriptor
信息: Deploying configuration descriptor host-manager.xml
2015-7-23 9:21:30 org.apache.catalina.startup.HostConfig deployDescriptor
信息: Deploying configuration descriptor manager.xml

访问http://localhost:8080/struts2/register.action,成功转移到结果页面时,控制台输出如下:

intercept invoked

myInterceptor2 invoked
myInterceptor3 invoked
validate~~~~~~~~~~~~~~~~
execute invoked
result3: success
result2: success
success

这里validate~~~~~~~~~~~~~~得到输出是因为我们在RegisterAction的validate方法中打印了改行语句,从输出中我们可以窥得拦截器的执行时机和执行流程,它和过滤器的运行机理基本一致。

正如我们在之前MyInterceptor3中写的,它是一个基于方法的拦截器,如何让其生效呢?那就是在配置的时候给它添加额外的参数:

execute

这样,访问页面,输出变成这个样子:

intercept invoked

myInterceptor2 invoked
validate~~~~~~~~~~~~~~~~
execute invoked
result2: success
success

通过这种方法,我们禁掉了第三个拦截器对execute方法的拦截。

另外,会不会觉得当拦截器很多的时候,一个Action配置多个拦截器有些麻烦?我们想到了这个问题,Struts2的设计者也早就想到了,解决方案可以在struts-default.xml中得到一些启示:

方法就是使用拦截器栈:

world

这样在action中我们只要引入myStack,myInterceptor和myInterceptor2还有defaultStack就都起作用了。

此外,如果在struts.xml中我们这样做:

world

也就是给它添加一个默认的拦截器,这样所有的action到会引用到这个默认的拦截器。

 

一个应用场景:

拦截器最重要的使用场合是进行权限验证: 定义一个拦截器去拦截用户的请求,如果用户没有登录的话,我们就让用户登录,不让他往后走了,如果用户登录了,直接让用户进入到相应的主界面。

struts为我们提供了一个:全局结果(global-results),所有action所共享的。

struts2默认使用请求转发,我们可以改变它的行为,使用重定向的方式。type="redirect",我们如何知道有这么一个类型呢,回到struts-default.xml中(下面截取与我们相关的一部分):

可以看到默认的是请求转发dispatcher。下面是我们的程序AuthInterceptor:

package com.test.interceptor;import java.util.Map;import com.opensymphony.xwork2.Action;import com.opensymphony.xwork2.ActionInvocation;import com.opensymphony.xwork2.interceptor.AbstractInterceptor;public class AuthInterceptor extends AbstractInterceptor{	@Override	public String intercept(ActionInvocation invocation) throws Exception	{		// 通常我们检查用户是否登录了,是通过session来完成的		// 注意到这个session不是HttpSession,它是被struts2封装好的Map,很好的实现了隐藏,此外,便于用单元测试框架进行测试,而不必借助于容器		Map map = invocation.getInvocationContext().getSession();				if(null == map.get("user")) // 用户没有登录		{			return Action.LOGIN; // 返回到登录界面		}		else		{			return invocation.invoke();		}	}}

接下来是structs.xml中相关的配置:

world
/login.jsp
/success.jsp
/register.jsp

访问http://localhost:8080/struts2/register.jsp,请求转发的方式登录地址栏显示http://localhost:8080/struts2/register.action,重定向显示http://localhost:8080/struts2/login.jsp;

 

扩展——防止表单重复提交: 一般有两种方式

  • 使用重定向。
  • 使用token(令牌)。

 

补充:异常处理机制

我们还以login.jsp为例:

  
username:
password:

首先在com.test.exception包下面建立两个类UsernameException:

package com.test.exception;public class UsernameException extends Exception{	private String message;	public String getMessage()	{		return message;	}	public void setMessage(String message)	{		this.message = message;	}		public UsernameException(String message)	{		super(message);		this.message = message;	}}

还有一个PasswordException:

package com.test.exception;public class PasswordException extends Exception{	private String message;	public String getMessage()	{		return message;	}	public void setMessage(String message)	{		this.message = message;	}		public PasswordException(String message)	{		super(message);		this.message = message;	}}

我们在LoginAction中,假定用户名不为"hello"就抛异常,密码不为"world"也抛异常:

package com.test.action;import com.opensymphony.xwork2.ActionSupport;import com.test.exception.PasswordException;import com.test.exception.UsernameException;public class LoginAction extends ActionSupport{	private String username;		private String password;	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 execute() throws Exception	{		if(!"hello".equals(username))		{			throw new UsernameException("username invalid");		}		else if(!"world".equals(password))		{			throw new PasswordException("password invalid");		}		else		{			return SUCCESS;		}	}	}

做到这里,访问login页面,输入非"hello"用户名,一大堆异常信息就抛给用户了,这显然是不友好的,因此我们这样处理,使得用户名非法时提示username invalid:

在struts.xml中struts标签下的嵌套标签:

/login.jsp
/usernameInvalid.jsp

或者mapping信息或result信息也可以放到局部:

/result.jsp
/login2.jsp

因此,既可以局部异常映射/结果(mapping/result),也可以全局映射。寻找规则:先找局部,在找全局。

转载于:https://www.cnblogs.com/Code-Rush/p/4669384.html

你可能感兴趣的文章
LeetCode 589. N叉树的前序遍历
查看>>
LeetCode 145. 二叉树的后序遍历
查看>>
Java | JDK8下的ConcurrentHashMap#putValue
查看>>
Java | JDK8 | Integer
查看>>
Java | JDK8下的ConcurrentHashMap#get
查看>>
计网 | 文件传输协议
查看>>
LeetCode 144. 二叉树的前序遍历
查看>>
RabbitMQ | 消息队列模式简介
查看>>
LeetCode 94. 二叉树的中序遍历
查看>>
Java | JDK8 | HashMap
查看>>
RabbitMQ | 交换器类型
查看>>
并发 线程 进程
查看>>
第三章-网络编程基础
查看>>
java -- 面向对象
查看>>
python-粘包,切换目录
查看>>
第一章--Java基础语法
查看>>
Java基础 ---数组
查看>>
第一章--Java基础
查看>>
Rdd 、dataframe、dataset共性与区别
查看>>
spark并行查询
查看>>