zoukankan      html  css  js  c++  java
  • Struts2拦截器的简单应用,登录权限拦截器及与过滤器的区别(八)

    勿以恶小而为之,勿以善小而不为--------------------------刘备

    劝诸君,多行善事积福报,莫作恶

    上一章简单介绍了Struts2的%,#,$的区别,UI标签及其表单radio,checkbox,select回显数据(七),如果没有看过,请观看上一章

    Struts2的拦截器,功能非常强大,很多强有力的功能都是通过拦截器实现的。我们输入一个网址,为什么只配置了过滤器和struts.xml文件中的action,就会去执行Action呢? 就是因为拦截器的存在。

    Struts2框架已经默认为我们的每一个自定义的action都实现了一个拦截器default-stack。 其中拦截器的相关配置在struts-core核心包下的struts-default.xml文件中。

    在这里插入图片描述

    拦截器是在Action执行方法前被调用,在方法执行后被销毁。

    一. Struts2提供的关于拦截器的接口和类

    一.一 Struts2官方提供的拦截器Interceptor接口

    package com.opensymphony.xwork2.interceptor;
    
    import com.opensymphony.xwork2.ActionInvocation;
    import java.io.Serializable;
    
    public abstract interface Interceptor
      extends Serializable
    {
      public abstract void destroy();
      
      public abstract void init();
      
      public abstract String intercept(ActionInvocation paramActionInvocation)
        throws Exception;
    }
    
    

    destroy()方法是销毁,init()是初始化, intercept() 方法才是我们真正要关注的方法。

    我们编写拦截器,一般不使用实现这个接口,而是继承它的实现类AbstractInterceptor

    一.二 抽象类AbstractInterceptor

    package com.opensymphony.xwork2.interceptor;
    
    import com.opensymphony.xwork2.ActionInvocation;
    
    public abstract class AbstractInterceptor
      implements Interceptor
    {
      public void init() {}
      
      public void destroy() {}
      
      public abstract String intercept(ActionInvocation paramActionInvocation)
        throws Exception;
    }
    
    

    这个抽象类AbstractInterceptor实现了Interceptor接口,并且重写了init()方法和destroy()方法,用户只需要实现interceptor()方法即可。

    我们用这个抽象类做一个简单的拦截器,实际开发中也并不用这一个抽象类AbstractInterceptor。

    二. 简单自定义一个拦截器

    二.一 新建拦截器类MyInterceptor ,继承AbstractInterceptor类

    前堤已经有了一个基本的Struts2的运行环境,延用上一章的struts2的配置和Action

    在com.yjl.web.interceptor包下新建一个MyInterceptor类,让其继承AbstractInterceptor类

    package com.yjl.web.interceptor;
    import org.apache.log4j.Logger;
    
    import com.opensymphony.xwork2.ActionInvocation;
    import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
    /**
    * @author 两个蝴蝶飞
    * @version 创建时间:Aug 25, 2018 4:03:21 PM
    * 类说明
    */
    public class MyInterceptor extends AbstractInterceptor{
    	private static final long serialVersionUID = -6424208964705287809L;
    	private Logger logger=Logger.getLogger(MyInterceptor.class);
    	@Override
    	public String intercept(ActionInvocation actionInvocation)
    			throws Exception {
    		logger.info("******开始执行拦截器*******");
    		String result=actionInvocation.invoke();
    		logger.info("执行后的结果为:"+result);
    		logger.info("********结束执行拦截器**********");
    		return result;
    	}
    }
    

    二.二 创建Action控制器,MyInterceptorAction

    在MyInterceptorAction中,返回SUCCESS字符串

    public class MyInterceptorAction extends ActionSupport{
    	private static final long serialVersionUID = 8278845997106407817L;
    	public String getForm(){
    		return SUCCESS;
    	}
    	
    }
    
    

    二.三 在struts.xml中package标签下实例化拦截器

    自定义的拦截器,刚开始定义好后,并不知道属于哪一个action,所以实例化拦截器放在 包下,用一个标签包起来,里面放置标签,这个标签有name和class两个属性,通过反射可以自己实例化自定义的拦截器。

    <package name="interceptor" extends="struts-default" namespace="/">
    		<interceptors>
    			<!-- 定义单个拦截器 -->
    			<interceptor name="myInterceptor" class="com.yjl.web.interceptor.MyInterceptor">
    			</interceptor>
    		</interceptors>
    		<!-- 配置跳转页面 -->
    		<action name="*">
    			<result>/WEB-INF/content/{1}.jsp</result>
    		</action>
    </package>
    

    二. 四 在struts.xml中action标签下引用具体的拦截器

    <package name="interceptor" extends="struts-default" namespace="/">
    		<interceptors>
    			<!-- 定义单个拦截器 -->
    			<interceptor name="myInterceptor" class="com.yjl.web.interceptor.MyInterceptor">
    			</interceptor>
    		</interceptors>
    		
    		<action name="Interceptor_*" class="com.yjl.web.action.MyInterceptorAction" method="{1}">
    			<!-- 引入自定义拦截器 -->
    			<interceptor-ref name="myInterceptor"></interceptor-ref>
    			
    			<!-- 配置跳转页面  -->
    			<result name="success">/WEB-INF/content/form.jsp</result>
    		</action>
    		<!-- 配置跳转页面 -->
    		<action name="*">
    			<result>/WEB-INF/content/{1}.jsp</result>
    		</action>
    </package>
    

    二.五 编写 /content/form.jsp 页面

    <body>
    拦截器跳转后页面
    </body>
    

    二.六 测试验证拦截器

    重启服务器,输入网址:http://localhost:8080/Struts_Interceptor/Interceptor_getForm

    查看控制台日志打印:

    在这里插入图片描述

    可以发现拦截器配置完成.

    提示: (在操作时,不要忘记配置web.xml中struts的过滤器)

    三. 拦截器配置过程中的扩展

    上面例子只是一个简单的拦截器,在实际项目中可能会配置多个拦截器,每个拦截器有不同的功能。复杂的拦截器该如何配置呢?

    三.一 默认拦截器 defaultStack

    可以查看struts-core.jar包下的struts-default.xml中的配置,注意查看示例. 这里简单一下里面的配置

    <!--注意名称: defaultStack-->
    <interceptor-stack name="defaultStack">
            <interceptor-ref name="exception"/>
            <interceptor-ref name="alias"/>
            <interceptor-ref name="servletConfig"/>
            <interceptor-ref name="i18n"/>
            <interceptor-ref name="prepare"/>
            <interceptor-ref name="chain"/>
            <interceptor-ref name="scopedModelDriven"/>
            <interceptor-ref name="modelDriven"/>
            <interceptor-ref name="fileUpload"/>
            <interceptor-ref name="checkbox"/>
            <interceptor-ref name="multiselect"/>
            <interceptor-ref name="staticParams"/>
            <interceptor-ref name="actionMappingParams"/>
            <interceptor-ref name="params">
                <param name="excludeParams">^action:.*,^method:.*</param>
            </interceptor-ref>
            <interceptor-ref name="conversionError"/>
            <interceptor-ref name="validation">
                <param name="excludeMethods">input,back,cancel,browse</param>
            </interceptor-ref>
            <interceptor-ref name="workflow">
                <param name="excludeMethods">input,back,cancel,browse</param>
            </interceptor-ref>
            <interceptor-ref name="debugging"/>
            <interceptor-ref name="deprecation"/>
        </interceptor-stack>
    
    <!--留意这一个-->
      <default-interceptor-ref name="defaultStack"/>
    	<!--每一个继承ActionSupport类的Action都具有基本拦截器的功能-->
    	<default-class-ref class="com.opensymphony.xwork2.ActionSupport" />
    

    三.二 自定义配置多个拦截器

    <interceptors>
    	<!-- 定义单个拦截器 -->
    	<interceptor name="myInterceptor1" class="com.yjl.web.interceptor.MyInterceptor1">
    	</interceptor>
    	<interceptor name="myInterceptor2" class="com.yjl.web.interceptor.MyInterceptor2">
    	</interceptor>
    	<interceptor name="myInterceptor3" class="com.yjl.web.interceptor.MyInterceptor3">
    	</interceptor>
    </interceptors>
    

    那么在Action中引用中,用到了哪一个拦截器,就用哪一个拦截器.

    假如 MyInterceptorAction中用了第二个和第三个。

            <action name="Form_*" class="com.yjl.web.action.MyInterceptorAction" method="{1}">
    				<!-- 引入自定义拦截器 -->
    				<interceptor-ref name="myInterceptor2"></interceptor-ref>
    				<interceptor-ref name="myInterceptor3"></interceptor-ref>
    				<result name="success">/WEB-INF/content/form.jsp/result>
    		</action>
    
    

    用到哪一个就配置哪一个。

    三.三 拦截器栈 <interceptor-stack> </interceptor-stack>

    我们的package包下开发中有多个Action(当然前堤也是interceptor拦截器多的情况下如1~30),

    现在情况是 Form1Action引入了111拦截器,Form2Action引入了212拦截器,
    Form3Action引入了3~13拦截器,

    要是按照上面的样式配置的话,4~11会被配置成3遍,很显然不太好。

    这个时候,可以将4~11配置成一个拦截器栈, 这样在引用了就比较容易引用了。

    拦截器栈放在package标签下,用的是 <interceptor-stack > </interceptor-stack>

    <interceptors>
    	<!-- 定义单个拦截器 -->
    	<interceptor name="myInterceptor1" class="com.yjl.web.interceptor.MyInterceptor1">
    	</interceptor>
    	<interceptor name="myInterceptor2" class="com.yjl.web.interceptor.MyInterceptor2">
    	</interceptor>
    	<interceptor name="myInterceptor3" class="com.yjl.web.interceptor.MyInterceptor3">
    	</interceptor>
    	<!-- 配置拦截器栈,里面有三个拦截器 -->
    	<interceptor-stack name="myInterceptor">
    		<interceptor-ref name="myInterceptor1"></interceptor-ref>
    		<interceptor-ref name="myInterceptor2"></interceptor-ref>
    		<interceptor-ref name="myInterceptor3"></interceptor-ref>
    	</interceptor-stack>
    </interceptors>
    

    可以根据不同的action,配置不同的interceptor-stack, 可以配置多个。

    这样在配置MyInterceptorAction时,只需要简单一句

    <action name="Interceptor_*" class="com.yjl.web.action.MyInterceptorAction" method="{1}">
    	<!-- 引入自定义拦截器栈 -->
    	<interceptor-ref name="myInterceptor"></interceptor-ref>
    	<result name="success">/WEB-INF/content/form.jsp</result>
    </action>
    

    便具有1,2,3三个拦截器的功能了。

    配置FormAction 时,也同样引用:

    <action name="Form_*" class="com.yjl.web.action.FormAction" method="{1}">
    	<!-- 引入自定义拦截器栈 -->
    	<interceptor-ref name="myInterceptor"></interceptor-ref>
    	<result name="success">/WEB-INF/content/form2.jsp</result>
    </action>
    

    也就具有了1,2,3三个拦截器的功能了。

    三.四 默认拦截器栈 default-stack

    如同Java中默认构造函数一样,Struts2提供了一个默认的拦截器栈default-stack,

    如果用户自己引用了一个拦截器,无论是框架提供的,还是自定义的,

    原有的拦截器栈将不在起作用了,将失效了。

    默认的拦截器 default-stack中有很多的功能,如异常,别名,国际化,参数,文件上传等。 所以这些功能很重要,所以,默认的拦截器不能丢掉。

    我们在引入自定义拦截器后,还需要引入默认的拦截器

    <action name="Interceptor_*" class="com.yjl.web.action.MyInterceptorAction" method="{1}">
    		<!-- 引入自定义拦截器 -->
    		<interceptor-ref name="myInterceptor"></interceptor-ref>
    		<!-- 放置原有的默认的拦截器 -->
    		<interceptor-ref name="defaultStack"></interceptor-ref>
    		<result name="success">/WEB-INF/content/form.jsp</result>
    </action>
    

    这样, MyInterceptorAction 将具有原先拦截器的功能,也具有自定义拦截器的功能。

    三.五 将新的拦截器配置成默认的拦截器

    可以利用 将原有的默认的defaultStack给其改变。

    	<interceptors>
    		<!-- 定义单个拦截器 -->
    		<interceptor name="myInterceptor1" class="com.yjl.web.interceptor.MyInterceptor1">
    		</interceptor>
    		<interceptor name="myInterceptor2" class="com.yjl.web.interceptor.MyInterceptor2">
    		</interceptor>
    		<interceptor name="myInterceptor3" class="com.yjl.web.interceptor.MyInterceptor3">
    		</interceptor>
    		<!-- 注意看拦截器的配置 -->
    		<interceptor-stack name="myInterceptor">
    			<interceptor-ref name="myInterceptor1"></interceptor-ref>
    			<interceptor-ref name="myInterceptor2"></interceptor-ref>
    			<interceptor-ref name="myInterceptor3"></interceptor-ref>
    			<interceptor-ref name="defaultStack"></interceptor-ref>
    		</interceptor-stack>
    	</interceptors>
    	<!-- 写在Action外面 -->
    	<default-interceptor-ref name="myInterceptor"></default-interceptor-ref>
    

    这样,就改变了默认的拦截器的值。

    在Action中就不用在配置拦截器了

    <action name="Interceptor_*" class="com.yjl.web.action.MyInterceptorAction" method="{1}">
    			<result name="success">/WEB-INF/content/form.jsp</result>
    </action>
    

    注意,这个新定义的默认拦截器的作用范围是 package.

    Struts2以 package 包 作为划分区域。

    三.六 拦截器配置参数

    用<param> </param> 进行引用。

    <interceptor name="myInterceptor" class="com.yjl.web.interceptor.MyInterceptor">
    		<!--添加参数-->
    		<param name="charset">UTF-8</param>
    </interceptor>
    

    在MyInterceptor拦截器中,添加这个charset属性,实现setter和getter方法即可。

    public class MyInterceptor extends AbstractInterceptor{
    	private static final long serialVersionUID = -6424208964705287809L;
    	private Logger logger=Logger.getLogger(MyInterceptor.class);
    	private String charset;
    	public String getCharset() {
    		return charset;
    	}
    	public void setCharset(String charset) {
    		this.charset = charset;
    	}
        //后面还有很多代码,没有复制
    

    这样,在 struts.xml 中定义传入参数值,在过滤器中就可以引用这个参数了。

    这个参数可以在拦截器定义时注入,也可以在拦截器被Action引入时注入。

    **拦截器定义时引入: **

    <interceptor-ref name="myInterceptor">
    	<param name="charset">UTF-8</param>
    </interceptor-ref>
    

    拦截器被Action 引入时注入:

    <interceptor name="myInterceptor" class="com.yjl.web.interceptor.MyInterceptor">
    		<!--添加参数-->
    		<param name="charset">UTF-8</param>
    </interceptor>
    

    三.七 公共功能拦截器配置

    在项目中,常常有登录拦截器,权限验证拦截器,日志拦截器等,对于这些公共的拦截器配置,

    推荐将新的拦截器栈名变成 defaultStack, 与原先的保持一致。

    <interceptors>
    	<interceptor name="loginInterceptor" class="com.yjl.web.interceptor.LoginInterceptor">
    	</interceptor>
    	<interceptor-stack name="defaultStack">
    		<interceptor-ref name="loginInterceptor">
    		<interceptor-ref name="logInterceptor">
    		<interceptor-ref name="defaultStack"></interceptor-ref>
    	</interceptor-stack>
    </interceptors>
    

    四 MethodFilterInterceptor类 源码分析

    在实际开发中,配置拦截器,常常使用的是 MethodFilterInterceptor,

    从方法名称中,也可以看出,拦截的是Action中的某些方法。

    尝试着分析一下源码.(老蝴蝶偷偷不要脸一次)

    package com.opensymphony.xwork2.interceptor;
    import java.util.Collections;
    import java.util.HashSet;
    import java.util.Set;
    
    import org.omg.CORBA.PRIVATE_MEMBER;
    
    import com.opensymphony.xwork2.ActionInvocation;
    import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
    import com.opensymphony.xwork2.interceptor.MethodFilterInterceptorUtil;
    import com.opensymphony.xwork2.util.TextParseUtil;
    import com.opensymphony.xwork2.util.logging.Logger;
    import com.opensymphony.xwork2.util.logging.LoggerFactory;
    //继承了AbstractInterceptor类,实现的方法由以前的interceptor()方法改成了doIntercept()方法
    public abstract class MethodFilterInterceptor extends AbstractInterceptor {
    	private static final long serialVersionUID = 1L;
    	protected transient Logger log = LoggerFactory.getLogger(getClass());
    	/**
    	 * MethodFilterInterceptor 类的两个参数 ,均用Set集合
    	 * 学到一招,在类中实例时时,不要在private Set<User> userSet=new HashSet<User>();了
    	 * 试试Collections.emptySet()实例化. List时用Collections.emptyList();方法
    	 * @param excludeMethods 不拦截器的方法. 如注册,找回密码等方法
    	 * @param includeMethods 要拦截的方法, 如登录,查看用户列表等方法
    	 */
    	protected Set<String> excludeMethods = Collections.emptySet();
    	protected Set<String> includeMethods = Collections.emptySet();
    	//实现两个参数的setter和getter方法
    	public void setExcludeMethods(String excludeMethods) {
    		//这个方法如下
    		this.excludeMethods = TextParseUtil.commaDelimitedStringToSet(excludeMethods);
    		/*
    		 * 这个方法很明显,就是将字符串按照,进行分隔,然后分别放置到set集合中。
    		 *public static Set<String> commaDelimitedStringToSet(String s)
    				 {
    			    	Set<String> set = new HashSet();
    				    String[] split = s.split(",");
    			   		for (String aSplit : split) {
    			   			//你看看人处理的,先将两边的空格去掉.
    				    	String trimmed = aSplit.trim();
    				    	//又判断一下长度
    					     if (trimmed.length() > 0)
    						       set.add(trimmed);
    						    }
    				    	return set;
    				   }
    		   */
    	}
    	public Set<String> getExcludeMethodsSet() {
    		return excludeMethods;
    	}
    	public void setIncludeMethods(String includeMethods) {
    		this.includeMethods = TextParseUtil.commaDelimitedStringToSet(includeMethods);
    	}
    	public Set<String> getIncludeMethodsSet() {
    		return includeMethods;
    	}
    	//实现了intercept()方法.
    	public String intercept(ActionInvocation invocation) throws Exception {
    		if (applyInterceptor(invocation)) {
    			//如果包括的方法,执行这一个
    			return doIntercept(invocation);
    		}
    		//不是包括的方法,执行这一个。
    		return invocation.invoke();
    	}
    	protected boolean applyInterceptor(ActionInvocation invocation) {
    		//利用代理模式的方式得到方法
    		String method = invocation.getProxy().getMethod();
    		/*
    		 * 进入看了看这个方法,如果是排除的方法,就返回false.
    		 * 				如果是包括的方法,就返回true。
    		 */
    		boolean applyMethod = MethodFilterInterceptorUtil.applyMethod(excludeMethods, includeMethods, method);
    		if ((log.isDebugEnabled()) && (!applyMethod)) {
    			log.debug("Skipping Interceptor... Method [" + method + "] found in exclude list.", new String[0]);
    		}
    
    		return applyMethod;
    	}
    	//需要实现的核心方法
    	protected abstract String doIntercept(ActionInvocation paramActionInvocation) throws Exception;
    }
    
    

    五. MethodFilterInterceptor类 的具体使用

    用一个具体的登录实例验证一下吧。

    其中实例是按照第四章的两个小例子进行相应的仿写的。

    五.一 编写控制器类UserAction

    在UserAction中常用的方法如下:

    public class UserAction extends BaseAction<User>{
    	private static final long serialVersionUID = 1L;
    	private Logger logger=Logger.getLogger(UserAction.class);
    	private UserService userSerive=new UserService();
    	/**
    	 * 转到登录的页面
    	 */
    	public String toLogin(){
    		logger.info("跳转到登录的界面");
    		return "toLogin";
    	}
    	/**
    	 * 具体的登录方法
    	 */
    	public String login(){
    		logger.info("执行具体的登录操作");
    		User user=userSerive.login(getModel());
    		if(user!=null) {
    			//说明存在这个用户
    			//登录成功后,将登录的用户放置到session中.
    			ActionContext.getContext().getSession().put("currentUser",user);
    			return LOGIN;
    		}else {
    			HttpServletRequest request=ServletActionContext.getRequest();
    			request.setAttribute("message","用户名或者密码错误");
    			return "toLogin";
    		}
    	}
    	/**
    	 * 跳转到注册的页面
    	 */
    	public String toRegisterUI(){
    		logger.info("跳转到注册的界面");
    		return "toRegisterUI";
    	}
    	/**
    	 * 进行用户的注册,注册成功之后跳转到登录的界面
    	 * 注册成功之后,不把数据带到登录页面进行填充.
    	 */
    	public String register(){
    		logger.info("执行具体的注册功能");
    		return "toLogin";
    	}
    	/**
    	 * 用户点击忘记密码后跳转到忘记密码的界面
    	 */
    	public String forgetPasswordUI(){
    		logger.info("跳转到忘记密码的界面");
    		return "forgetPasswordUI";
    	}
    	/**
    	 * 用户在忘记密码界面添加新的密码后执行修改密码
    	 * 修改密码成功后跳转到登录界面
    	 */
    	public String forgetPassword(){
    		logger.info("添加新的密码后修改密码");
    		return "toLogin";
    	}
    	/**
    	 * 显示列表
    	 */
    	public String list(){
    		logger.info("显示用户列表");
    		List<User> userList=userSerive.findAll();
    		ActionContext.getContext().put("userList",userList);
    		return "list";
    	}
    	/**
    	 *跳转到添加的界面
    	 */
    	public String addUI(){
    		logger.info("跳转到添加的界面");
    		return "addUI";
    	}
    	/**
    	 *执行具体的添加操作后,返回到list列表显示。
    	 */
    	public String add(){
    		logger.info("执行具体的添加操作");
    		return "toList";
    	}
    	/**
    	 * 跳转到修改的界面
    	 */
    	public String editUI(){
    		logger.info("跳转到修改的界面");
    		return "editUI";
    	}
    	/**
    	 * 执行具体的修改操作,修改完成后返回到列表的界面
    	 */
    	public String edit(){
    		logger.info("执行具体的修改操作");
    		return "toList";
    	}
    	/**
    	 * 执行具体的删除操作,删除成功后返回到列表的界面
    	 */
    	public String delete(){
    		logger.info("执行具体的删除操作");
    		return "toList";
    	}
    	/**
    	 * 点击名字,显示具体的详情
    	 */
    	public String detailUI(){
    		logger.info("显示具体的详情操作");
    		return "detailUI";
    	}
    }
    
    

    其中
    toLogin(); login(); toRegisterUI(); register();forgetPasswordUI();forgetPassword();是不需要进行登陆拦截的,

    list()及其以下方法,是需要登录拦截的。

    如果toRegisterUI()方法也被拦截的话,那么是无法进行注册功能的。

    五.二 根据Action中的返回值配置相应的struts.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>
    	<!--修改国际化编码 -->
    	<constant name="struts.i18n.encoding" value="UTF-8"></constant>
    	<!--修改是否为开发者模式 -->
    	<constant name="struts.devMode" value="true"></constant>
    	<!--修改ui样式表 -->
    	<constant name="struts.ui.theme" value="simple"></constant>
    
    	<package name="methodInterceptor" extends="struts-default" namespace="/">
    		<!-- 配置全局错误页面 -->
    		<global-results>
    			<result name="error">/WEB-INF/content/error.jsp</result>
    		</global-results>
    		<action name="User_*" class="com.yjl.web.action.UserAction" method="{1}">
    				<!-- 转到登录页面的配置 -->
    				<result name="toLogin">/WEB-INF/content/login.jsp</result>
    				<!-- 登录的配置 -->
    				<result name="login" type="redirectAction">User_list.action</result>
    				<result name="toRegisterUI">/WEB-INF/content/register.jsp</result>
    				<result name="forgetPasswordUI">/WEB-INF/content/forgetPassword.jsp</result>
    				<result name="list">/WEB-INF/content/list.jsp</result>
    				<result name="addUI">/WEB-INF/content/add.jsp</result>
    				<result name="toList" type="redirectAction">User_list.action</result>
    				<result name="editUI">/WEB-INF/content/edit.jsp</result>
    				<result name="detailUI">/WEB-INF/content/detail.jsp</result>
    				<result name="success">/WEB-INF/content/form.jsp</result>
    		</action>
    	</package>
    </struts>
    
    

    五.三 根据struts.xml中的配置视图编写相应的jsp页面

    有图片

    每一个jsp 页面 都引入了 struts2 标签库

    <%@ taglib uri="/struts-tags"  prefix="s"%>
    

    五.三.一 编写登录页面 /content/login.jsp

    <body>
    	${message}
    	<s:form action="User_login.action" namespace="/" method="post">
    			用户名: <s:textfield  name="name"/>  <br/>
    			密码: <s:password name="password"/><br/>
    			<s:a action="User_forgetPasswordUI" namespace="/">忘记密码</s:a><br/>
    			<s:a action="User_toRegisterUI" namespace="/">注册新用户</s:a><br/>
       			<s:submit value="提交"/>
       			<s:reset value="重置"/>
    	</s:form>
    </body>
    
    

    五.三.二 编写注册页面 /content/register.jsp

    <body>
    	这是注册的界面
    	<s:form action="User_register" namespace="/" method="post">
    		<s:submit value="注册"></s:submit>
    	</s:form>
    </body>
    

    五.三.三 编写忘记密码页面 /content/forgetPassword.jsp

    <body>
    	这是忘记密码的界面
    	<s:form action="User_forgetPassword" namespace="/" method="post">
    		<s:submit value="确认找回密码"></s:submit>
    	</s:form>
    </body>
    
    

    五.三.四 编写查看页面 /content/list.jsp

    <body>
    	<div class="container">
    		<div class="row">
    			<table class="table table-bordered table-hover">
    				<caption>查看学生信息</caption>
    				<thead>
    					<tr>
    						<th class="col-xs-2">姓名</th>
    						<th class="col-xs-2">性别</th>
    						<th class="col-xs-2">年龄</th>
    						<th class="col-xs-2">关系</th>
    						<th class="col-xs-4" colspan="3">相关操作 
    									<span style="padding-left:40px">
    											<s:a action="User_addUI" namespace="/">添加</s:a>
    									</span>
    						</th>
    					</tr>
    				</thead>
    				<tbody>
    					<s:iterator var="user" value="%{userList}">
    							<tr>
    								<td><s:a action="User_detailUI?id=%{id}" namespace="/">${user.name}</s:a></td>
    								<td>${user.sex}</td>
    								<td>${user.age}</td>
    								<td>${user.relation}</td>
    								<td>
    									<s:a action="User_editUI?id=%{id}" namespace="/">修改</s:a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    									<s:a action="User_delete?id=%{id}" namespace="/">删除</s:a>
    							</tr>
    					</s:iterator>
    				</tbody>
    			</table>
    		</div>
    	</div>
    </body>
    
    

    五.三.五 编写添加页面 /content/add.jsp

    <body>
    	这是添加的界面
    	<s:form action="User_add" namespace="/" method="post">
    		<s:submit value="添加"></s:submit>
    	</s:form>
    </body>
    

    五.三.六 编写修改页面 /content/edit.jsp

    <body>
    	这是修改的界面
    	<s:form action="User_edit" namespace="/" method="post">
    		<s:submit value="修改"></s:submit>
    	</s:form>
    </body>
    

    五.三.七 编写查看详情页面 /content/detail.jsp

    <body>
    	查看详情的页面
    	<s:a action="User_list" namespace="/">返回</s:a>
    </body>
    

    五.四 重启服务器,看各个链接是否正常跳转

    输入网址: http://localhost:8080/Struts_Interceptor/User_toLogin

    点击各个链接,发现各个功能正常跳转,

    链接跳转显示页面正确,日志打印输出正确。

    五.五 编写登录拦截器 LoginInterceptor

    package com.yjl.web.interceptor;
    import javax.servlet.http.HttpSession;
    
    import org.apache.log4j.Logger;
    import org.apache.struts2.ServletActionContext;
    
    import com.opensymphony.xwork2.ActionInvocation;
    import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
    import com.yjl.pojo.User;
    /**
    * @author 两个蝴蝶飞
    * @version 创建时间:Aug 27, 2018 8:49:26 AM
    * 类说明  登录拦截器
    */
    public class LoginInterceptor extends MethodFilterInterceptor{
    	private static final long serialVersionUID = 1L;
    	private static Logger logger=Logger.getLogger(LoginInterceptor.class);
    	@Override
    	protected String doIntercept(ActionInvocation actionInvocation) throws Exception {
    		HttpSession session=ServletActionContext.getRequest().getSession();
    		User currentUser=(User) session.getAttribute("currentUser");
    		//判断currentUser的值
    		if(currentUser==null){
    			//获取请求的方法
    			String method=actionInvocation.getProxy().getMethod();
    			//为空,表示没有登录
    			logger.info(method+"方法需要被拦截,必须登录后使用");
    			//没有登录,就跳转到登录的页面
    			return "toLogin";
    		}else{
    			//登录,就放行  实际操作中,还有一个权限的判断
    			String result=actionInvocation.invoke();
    			logger.info("我操作:"+result);
    			return result;
    		}
    	}
    
    }
    

    五.六 在struts.xml 配置登录拦截器,注意拦截和不需拦截方法的配置

    <package name="methodInterceptor" extends="struts-default" namespace="/">
    		<!-- 配置拦截器  注意顺序,放在global-results前面-->
    		<interceptors>
    			<interceptor name="loginInterceptor" class="com.yjl.web.interceptor.LoginInterceptor">
    			</interceptor>
    		</interceptors>
    		<!-- 配置全局错误页面 -->
    		<global-results>
    			<result name="error">/WEB-INF/content/error.jsp</result>
    			<!-- 转到登录页面的配置 -->
    			<result name="toLogin">/WEB-INF/content/login.jsp</result>
    		</global-results>
    		<action name="User_*" class="com.yjl.web.action.UserAction" method="{1}">
    				<interceptor-ref name="defaultStack"></interceptor-ref>
    				<interceptor-ref name="loginInterceptor">
    					<param name="excludeMethods">toLogin,login,toRegisterUI,register,forgetPasswordUI,forgetPassword</param>
    					<param name="includeMethods">list,toList,addUI,add,editUI,edit,delete,detail</param>
    				</interceptor-ref>
    				<!-- 转到登录页面的配置 -->
    				<result name="toLogin">/WEB-INF/content/login.jsp</result>
    				<!-- 登录的配置 -->
    				<result name="login" type="redirectAction">User_list.action</result>
    				<result name="toRegisterUI">/WEB-INF/content/register.jsp</result>
    				<result name="forgetPasswordUI">/WEB-INF/content/forgetPassword.jsp</result>
    				<result name="list">/WEB-INF/content/list.jsp</result>
    				<result name="addUI">/WEB-INF/content/add.jsp</result>
    				<result name="toList" type="redirectAction">User_list.action</result>
    				<result name="editUI">/WEB-INF/content/edit.jsp</result>
    				<result name="detailUI">/WEB-INF/content/detail.jsp</result>
    				<result name="success">/WEB-INF/content/form.jsp</result>
    		</action>
    </package>
    

    开发中,不需要拦截的方法少, 一般只需要注入参数excludeMethods即可。

    excludeMethods为不需要拦截的方法,

    includeMethods为需要拦截的方法。

    如果拦截的和不拦截的都有,那么以拦截为主。

    五.七 重启服务器,验证拦截器是否起作用

    重启服务器,

    未登录成功时:

    输入 http://localhost:8080/Struts_Interceptor/User_addUI 等网址,会跳转到登录页面,

    输入 http://localhost:8080/Struts_Interceptor/User_forgetPasswordUI 等网址,会跳转到指定的 jsp页面。

    登录成功后:

    输入 http://localhost:8080/Struts_Interceptor/User_addUI 等网址,会正常跳转到指定的 jsp页面。

    六. 拦截器与过滤器的区别

    摘录于 https://www.cnblogs.com/joyang/p/4973435.html

    过滤器,是在java web中,你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,
    然后再传入servlet或者struts的 action进行业务逻辑,
    比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),
    或者在传入servlet或者 struts的action前统一设置字符集,或者去除掉一些非法字符

    拦截器,是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,
    或者在方法后调用一个方法比如动态代理就是拦截器的简单实现,在你调用方法前打印出字符串(或者做其它业务逻辑的操作),
    也可以在你调用方法后打印出字符串,甚至在你抛出异常的时候做业务逻辑的操作。

    拦截器是基于java的反射机制的,而过滤器是基于函数回调。
    拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
    拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
    拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
    在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次

    这一章是关于拦截器的介绍,非常重要。

    本章节的代码链接为:

    链接:https://pan.baidu.com/s/18lQmPQzMVfpLF7lyfPKKHQ 
    提取码:enw4
    

    谢谢您的观看!!!

  • 相关阅读:
    Cocos2dx-demo演示项目:Part2
    利用Python抓取亚马逊评论列表数据
    Cocos2dx-demo演示项目:Part1
    正则表达式匹配原理
    js正则函数中test和match的区别
    【别人家的孩子系列之】浅析正则表达式—(原理篇)
    JS 获取浏览器窗口大小
    javascript的insertBefore、insertAfter和appendChild简单介绍
    javascript 限制字符串字数换行 带BUG
    一行一行分析JQ源码学习笔记-06
  • 原文地址:https://www.cnblogs.com/yjltx/p/13071628.html
Copyright © 2011-2022 走看看