`
yulon
  • 浏览: 116600 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

补struts2.1两天快速入门之轻松搞定struts2核心--拦截器

阅读更多

由于拦截器的重要性,决定将其从(struts2.1两天快速入门第一天下午 抽取出来讲)

 

本讲将结合模拟用户权限验证展开:判断用户是否有权限请求访问某一模块或页面.

 

第九讲、自定义拦截器

 

   9.1 首先定义一个User实体类,如下:

public class User implements Serializable {
	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;
	}
}

  9.2 编写一个用户登陆的Action类,如下:

public class UserLoginAction {
	//接收复合类型的参数,与struts1.x相类似,此时表单的元素名称
	//应该为:user.username   user.password
	private User user;  
	public User getUser() {
		return user;
	}
	public void setUser(User user) {
		this.user = user;
	}
	public String execute(){
	//模拟用户登陆,实际应用是从数据库里取的,这里只是为了方便测试和学习	
	if("yulon".equals(user.getUsername())&&"123456".equals(user.getPassword())){
		//为了不让我们看到真正的session,struts2框架对其作了一层封装,用一个Map对象来存储.
		//Map map = ActionContext.getContext().getSession();
		//map.put("user", user);
		//把两段代码合成一段,就不用导入Map类
		ActionContext.getContext().getSession().put("user", user);
		return Action.SUCCESS;   //返回到欢迎页面
	 }
		ActionContext.getContext().put("msg", "用户登陆失败!");
		//返回到登陆页面,struts定义了一系列字符串常量,方便用户使用,统一的好处
		return Action.LOGIN;   
	}
}

    知识提示:注意这里返回的是login,而不是LOGIN.查看ActionContext部分源码及相关文档可知,它是一个与线程相关的类,同一个线程内获取的都是同一个ActionContext实例,原理与ThreadLocal相关,之前有讲过ThreadLocal相关知识,ThreadLocal实现在同一个线程内的数据共享,可以更深入得理解ActionContext底层的实现原理.

 

  9.3  在struts.xml配置文件里新增一个package包,名称叫testinterceptor,命名空间定义为/test2,如下配置:     
 

  <package name="testinterceptor" namespace="/test2" extends="struts-default">
      <!--定义一个转发到登陆页面的Action-->
    	<action name="loginUI">
    		<result>/WEB-INF/jsp/login.jsp</result>
    	</action>
    	<action name="login" class="cn.gkit.action.UserLoginAction" method="execute">
    	  <!--重定向到同一个包内名字叫index的Action-->
    		<result name="success" type="redirectAction">index</result>
    		<result name="login">/WEB-INF/jsp/login.jsp</result>
    	</action>
    	<!--为了方便测试,同时也定义一个登出的Action-->
    	<action name="logout" class="cn.gkit.action.UserLogoutAction" method="execute">
    		<result name="success" type="redirectAction">loginUI</result>
    	</action>
    	<!--用户登陆成功后的欢迎页面-->
    	<action name="index">
    		<result name="success">/WEB-INF/jsp/welcome.jsp</result>
    		<result name="login" type="redirectAction">loginUI</result>
    	</action>
  </package>

  9.4 编写UserLogoutAction类

public class UserLogoutAction {
	public String execute(){
		//取出当前登陆的用户
		User user = (User)ActionContext.getContext().getSession().get("user");
		if(user!=null){
			//注销用户信息
			ActionContext.getContext().getSession().remove("user");
		}
		return Action.SUCCESS;
	}
}

  9.5 编写\WEB-INF\jsp\login.jsp页面

 

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>用户登陆</title>
  </head>
  <span>${msg}</span>
  <body>
    <s:form action="login" namespace="/test2" method="post">
      用户名: <s:textfield title="填写用户名" name="user.username" ></s:textfield><br/>
      密   码 :<s:password title="填写密码" name="user.password"></s:password><br/>
        <s:submit value="登陆"></s:submit>
    </s:form>
  </body>
</html>

    知识提示:使用struts2标签首先在导入相关uri, 可以在struts2核心包下的META-INF目录下找到struts-tags.tld文件,里面就有uri的定义,具体标签的使用暂不在本章细讲,大家可以先琢磨一下.

  9.6 编写\WEB-INF\jsp\welcome.jsp

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>欢迎首页</title>
  </head>
  <body>
    欢迎用户${sessionScope.user.username}的到来!<br />
 <a href='<s:url action="logout" namespace="/test2" />'>退出</a>
  </body>
</html>

  

在没有使用拦截器之前,是可以直接访问/struts2.1/test2/index请求的.

 

  9.7实现自己的拦截器cn.gkit.web.interceptor.UserAuthInterceptor(有三种方法)

 

    第一种方法是实现com.opensymphony.xwork2.interceptor.Interceptor接口,实现相应的方法就行.

public class UserAuthInterceptor implements Interceptor{

	public void destroy() {
	}
	public void init() {
 init() 		System.out.println("服务器启动过程中自动加载");
	}

	public String intercept(ActionInvocation invocation) throws Exception {
		 //ActionContext.getContext().getSession().get("user");
		Map map = invocation.getInvocationContext().getSession();
		if(map.get("user")==null){
System.out.println("用户还没登陆");
			return Action.LOGIN;  //struts定义了一系统字符串常量,注意这里返回的是login,而不是LOGIN.
		}else
		{
			String result = invocation.invoke();//如果用户已登陆就通过验证,继承执行下一个拦截器
			System.out.println("返回结果:"+result);
			return result; 
		}
	}
}

    知识提示:invocation.getInvocationContext()获取到的是一个与ActionInvocation相关的ActionContext ,但使用ActionContext.getContext()也一样可以取得.

 

   第二种方法是继承AbstractInterceptor抽象,此类的设计思想跟之前讲的类型转换器类似.它本身也是实现了Interceptor接口,由于我们一般都不用到init()方法和destroy()方法,因此通常情况下都是通过继承AbstractInterceptor来实现我们的拦截器.如下:

public class UserAuthInterceptor extends AbstractInterceptor{
               @Override
	public String intercept(ActionInvocation invocation) throws Exception {
		 //ActionContext.getContext().getSession().get("user");
		Map map = invocation.getInvocationContext().getSession();
		if(map.get("user")==null){
System.out.println("用户还没登陆");
			return Action.LOGIN;  
		}else
		{
			String result = invocation.invoke();
			System.out.println("返回结果:"+result);
			return result; 
		}
	}
}

   知识提示:查看AbstractInterceptor源码,你会感到惊讶,如下:

 public abstract class AbstractInterceptor implements Interceptor {

    public void init() {
    }

    public void destroy() {
    }
    public abstract String intercept(ActionInvocation invocation) throws Exception;
}

    知识提示:你没有看错,就是几行代码,它只是帮我们实现了两个不常用到的方法,并且还是空实现. 但里面包含的一种设计思想值得我们去学习研究,所以说学习框架的最高境界是学习它的思想,思想就存在代码当中,大家有时间可以多查看一下它的源码.

 

  9.8 将我们编写好的拦截器类加载到struts.xml配置文件中,如下定义:

 

<interceptors>
     <!-- 加载自己编写的拦截器 -->
    <interceptor name="authInterceptor" class="cn.gkit.web.interceptor.UserAuthInterceptor" />
</interceptors>

 

    9.9 将我们编写好的拦截器应用到具体的action类上,将struts.xml 名称为index的<action>改如下:

 

<action name="index">
    	<result name="success">/WEB-INF/jsp/welcome.jsp</result>
    	<result name="login" type="redirectAction">loginUI</result>
    	<interceptor-ref name="authInterceptor"></interceptor-ref>
</action>

    此时:若访问/struts2.1/test2/index,请求将先会被自己定义的authInterceptor拦截器拦截,执行intercept方法的代码,判断用户若没有登陆则转到登陆页面,若存在才会放行(即执行下一步,这里的下一步会执行请求对应的Action方法).

    问题:为什么说拦截器是struts2的核心呢?是因为struts2的很多工作都是通过拦截器来实现的,在你定义的<package>的同时,只要你extends 了struts-default包,就同时拥有了struts-default包内定义的全部内容.通过查看struts-default.xml文件可知,它里面定义了很多拦截器,每个拦截器负责完成不同的工作.如里面名字为params的拦截器的作用是会将页面表单的参数会自动赋值到action里的属性。其中在最后定义了一个默认的拦截器栈<default-interceptor-ref name="defaultStack"/>,默认情况下默认拦截器栈会应用到包内定义的所有action身上. 但如果你手工在一个<action>添加一个额外的拦截器后,此时默认的拦截器栈对本<action>不起作用.解决的办法如下:

     第一种解决方案:重新引入defaultStack拦截器栈,将index改如下:

<action name="index">
    	<result name="success">/WEB-INF/jsp/welcome.jsp</result>
    	<result name="login" type="redirectAction">loginUI</result>
    	<interceptor-ref name="authInterceptor"></interceptor-ref>
    	<!-- 重新引入 defaultStack-->
    	<interceptor-ref name="defaultStack"></interceptor-ref>
</action>

    第二种解决方案:定义自已的拦截器栈,如下:

<interceptors>
    <!-- 加载自己编写的拦截器 -->
    <interceptor name="authInterceptor" class="cn.gkit.web.interceptor.UserAuthInterceptor" />
    <!-- 定义拦截器栈 -->
    <interceptor-stack name="myInterceptorStack">
    	<!-- 引用用户定义的拦截器 -->
    	<interceptor-ref name="authInterceptor"></interceptor-ref>
    	<!-- 同时也要重新把默认的拦截器栈引入进来 -->
    	<interceptor-ref name="defaultStack"></interceptor-ref>
    </interceptor-stack>
</interceptors>

    将自己定义好的拦截器栈应用到具体action类中,如将<action>改写成:

   

 <action name="index">
    	<result name="success">/WEB-INF/jsp/welcome.jsp</result>
    	<result name="login" type="redirectAction">loginUI</result>
    	<!-- 引入自定义拦截器栈 -->
    	<interceptor-ref name="myInterceptorStack"></interceptor-ref>
 </action>

   第三种解决方案:重新定义默认拦截器栈

  

<interceptors>
    <!-- 加载自己编写的拦截器 -->
    <interceptor name="authInterceptor" class="cn.gkit.web.interceptor.UserAuthInterceptor" />
    <!-- 定义拦截器栈 -->
    <interceptor-stack name="myInterceptorStack">
    	<!-- 引用用户定义的拦截器 -->
    	<interceptor-ref name="authInterceptor"></interceptor-ref>
    	<!-- 同时也要重新把默认的拦截器栈引入进来 -->
    	<interceptor-ref name="defaultStack"></interceptor-ref>
    </interceptor-stack>
</interceptors>
 <!-- 重新定义默认的拦截器栈,覆盖掉struts-default定义的默认拦截器栈 -->
<default-interceptor-ref name="myInterceptorStack"></default-interceptor-ref>

    注意:此时在testinterceptor包内定义的所有<action>默认都会被myInterceptorStack拦截器拦截,index不用重新定义拦截器,改如下:

<action name="index">
    <result name="success">/WEB-INF/jsp/welcome.jsp</result>
    <result name="login" type="redirectAction">loginUI</result>
</action>

 

    具体使用哪一种方法按项目需求而定

 

 9.10 在 9.7节里面还有一种自定义拦截器的方法没讲到:就是方法过滤拦截器(MethodFilterInterceptor)

     

     编写方法过滤拦截器第一步:编写继承于MethodFilterInterceptor抽象类的拦截器

cn.gkit.web.interceptor.MyMethodFilterInterceptor,如下:
public class MyMethodFilterInterceptor extends MethodFilterInterceptor {

	@Override
	protected String doIntercept(ActionInvocation invocation) throws Exception {
		System.out.println("执行了MyMethodFilterInterceptor拦截器");
		String resultString = invocation.invoke();
		System.out.println("返回的结果:"+resultString);
		return resultString;
	}
}
 第二步,在上次编写的test包内加载这个拦截器,如下:
<interceptors>
  <interceptor name="mymethodinterceptor" class="cn.gkit.web.interceptor.MyMethodFilterInterceptor"></interceptor>
</interceptors>
 第三步,在具体的action里应用该拦截器,如下:
<package name="test" namespace="/test" extends="gkit">
   <interceptors>
   	<!-- 定义方法过滤拦截器 -->
   	<interceptor name="mymethodinterceptor" class="cn.gkit.web.interceptor.MyMethodFilterInterceptor"/>
   </interceptors>
    <action name="*User" class="cn.gkit.action.HelloWorldAction" method="{1}" >
        	<param name="message">属性注入</param>
	<result name="success">/WEB-INF/jsp/helloworld.jsp</result> 
	<interceptor-ref name="mymethodinterceptor">
	<!--指定要拦截的方法  includeMethods的优先级比excludeMethods的要高-->
		<param name="includeMethods">add,execute</param>
	</interceptor-ref>
	<interceptor-ref name="defaultStack"></interceptor-ref>
     </action>
</package>
   知识提示:MethodFilterInterceptor有两个重要的属性 excludeMethods includeMethods 排除/包含action里的某个业务方法,多个方法用逗号分开.以上配置表示:cn.gkit.action.HelloWorldAction内的add与execute方法将会被mymethodinterceptor拦截器拦截.
拦截器至此已基本上讲完,谢谢大家的阅读!也希望大家能从中学到东西.如果有某处地方看不懂,大家可以与我一起讨论!
 
 

 

18
2
分享到:
评论
6 楼 明天的昨天 2010-01-03  
不错的文章
对我帮助很大
希望有更好的文章发布
期待中~~~~·
5 楼 renguistyle 2009-12-28  
我以前用filter实现过跟这类似的功能,搞不懂interceptor与filter的区别。
4 楼 yilong511 2009-12-25  
写的很详细呵,这种东东其实不用去刻意的学习。
不知不觉中就会了呵。。
3 楼 feiyan35488 2009-12-24  
谢谢   多出点这种入门的例子呀
2 楼 xiaojing3517 2009-12-24  
我都没学struts2 只不过学了1,然后进公司呆了一个多月,没学,然后看了例子,就会用了,开发了几个月也算是懂点了.这个东西入门简单,但是精通难
1 楼 海阔天空love 2009-12-23  
哈哈。支持。。我的struts2原来就学了一点、就是半瓶子也不半瓶子啊、最近看了你的几篇struts2之后、感觉有点入门了、哈哈。。谢谢。。。。。

相关推荐

    Struts2.1权威指南——基于WebWork核心的MVC开发.zip

    书中通过大量的示范性实例(全书范例近百个),逐一、详细地讲解了Struts2各知识点的用法,并细致地讲解每个用法的各种参数、选项,可以帮助读者入门到精通。 3.配合案例,快速提高 《Struts 2.1权威指南》最后配备...

    Struts 2.1权威指南:基于WebWork核心的MVC开发

    李刚的Struts 2.1权威指南:基于WebWork核心的MVC开发,写的很详细。一共有九个压缩文件。

    Struts2.1权威指南2

    Struts2.1权威指南 李刚的著作 共四个部分 用7-zip解压

    struts2.1jar包

    struts2.1jar包 struts2.1包 struts2.1源文件

    struts2.1完整jar包

    struts2.1完整jar包。内容齐全。

    Struts2.1 源码+开发包(项目依赖库)

    Struts2.1源码+Struts2.1依赖库(jar包)

    struts2.0升级到struts2.1的工具

    struts2.0升级到struts2.1的工具,自动修改配置文件和页面

    struts2.1 jar包

    struts2.1在tomcat下载的包总是报错,根据tomcat官方解释修改后无任何错误,并且已经运行

    struts-2.1.dtd

    内有 struts-2.0.dtd struts-2.1.dtd struts-2.1.7dtd struts-2.3dtd

    json-lib-2.1.jar和struts2-json-plugin-2.1.8.1.jar

    jquery和struts2结合使用的jar包

    struts2-jfreechart-plugin-2.1.8.1.jar

    struts2-jfreechart-plugin-2.1.8.1.jar

    Struts2.1的jar包

    Struts2.1的jar包

    Struts 2.1 权威指南 part13 pdf

    改为使用Convention插件提供“零配置”,Struts 2.1新增了Portlet支持……为了让众多Struts学习者、工作者快速从Struts 2.0的开发升级到Struts 2.1,笔者升级了《Struts 2权威指南》,第二版改写了第一版中所有程序...

    Struts 2.1 权威指南 part04 pdf

    改为使用Convention插件提供“零配置”,Struts 2.1新增了Portlet支持……为了让众多Struts学习者、工作者快速从Struts 2.0的开发升级到Struts 2.1,笔者升级了《Struts 2权威指南》,第二版改写了第一版中所有程序...

    Struts 2.1 权威指南 part01 pdf

    改为使用Convention插件提供“零配置”,Struts 2.1新增了Portlet支持……为了让众多Struts学习者、工作者快速从Struts 2.0的开发升级到Struts 2.1,笔者升级了《Struts 2权威指南》,第二版改写了第一版中所有程序...

    Struts 2.1 权威指南 part02 pdf

    改为使用Convention插件提供“零配置”,Struts 2.1新增了Portlet支持……为了让众多Struts学习者、工作者快速从Struts 2.0的开发升级到Struts 2.1,笔者升级了《Struts 2权威指南》,第二版改写了第一版中所有程序...

    Struts 2.1 权威指南 part06 pdf

    改为使用Convention插件提供“零配置”,Struts 2.1新增了Portlet支持……为了让众多Struts学习者、工作者快速从Struts 2.0的开发升级到Struts 2.1,笔者升级了《Struts 2权威指南》,第二版改写了第一版中所有程序...

    Struts 2.1 权威指南 part03 pdf

    改为使用Convention插件提供“零配置”,Struts 2.1新增了Portlet支持……为了让众多Struts学习者、工作者快速从Struts 2.0的开发升级到Struts 2.1,笔者升级了《Struts 2权威指南》,第二版改写了第一版中所有程序...

    Struts 2.1 权威指南 part05 pdf

    改为使用Convention插件提供“零配置”,Struts 2.1新增了Portlet支持……为了让众多Struts学习者、工作者快速从Struts 2.0的开发升级到Struts 2.1,笔者升级了《Struts 2权威指南》,第二版改写了第一版中所有程序...

    Struts 2.1 权威指南 part11 pdf

    改为使用Convention插件提供“零配置”,Struts 2.1新增了Portlet支持……为了让众多Struts学习者、工作者快速从Struts 2.0的开发升级到Struts 2.1,笔者升级了《Struts 2权威指南》,第二版改写了第一版中所有程序...

Global site tag (gtag.js) - Google Analytics