Struts2拦截器的简单应用,登录权限拦截器及与过滤器的区别(八)

Struts2拦截器的简单应用,登录权限拦截器及与过滤器的区别(八)勿以恶小而为之,勿以善小而不为————————–刘备劝诸君,多行善事积福报,莫作恶主要内容有:1,拦截器的配置2权限拦截器

大家好,又见面了,我是你们的朋友全栈君。

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

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

上一章简单介绍了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

下一章简单介绍了 Struts2实现国际化操作及中英文切换(九)

谢谢您的观看!!!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/146729.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • MinGW 安装教程

    前言本文主要讲述如何安装C语言编译器——MinGW,特点是文章附有完整详细的实际安装过程截图,文字反而起说明提示作用。编写本文的原因始于我的一个观点:图片可以比文字传达更多的信息,也能让其他人更容易理解作者的意图及思想。因此,我将安装MinGW的过程和步骤,编写成了这篇以图片为主的教程,为了让看到这篇文章的任何人,都可以很容易按照图片所示正确安装MinGW。一、什么是…

  • mysql explain不准确_mysql explain预估剖析「建议收藏」

    mysql explain不准确_mysql explain预估剖析「建议收藏」引子:使用MySQL建立了一张表country,总共有才3121行记录。但是使用explainselectcount(*)fromcountry;的时候,发现行数rows达到6897,让我大吃一惊。mysql>explainselectcount(*)fromcountry;+—-+————-+———+——+————–…

    2022年10月17日
  • bytebuffer的容量极限和位置_bytebuffer写文件

    bytebuffer的容量极限和位置_bytebuffer写文件缓冲区(Buffer)就是在内存中预留指定大小的存储空间用来对输入/输出(I/O)的数据作临时存储,这部分预留的内存空间就叫做缓冲区:使用缓冲区有这么两个好处:1、减少实际的物理读写次数2、缓冲区在创建时就被分配内存,这块内存区域一直被重用,可以减少动态分配和回收内存的次数举个简单的例子,比如A地有1w块砖要搬到B地由于没有工具(缓冲区),我们一次只能搬一本,那么就要搬1w次(实际读写次数)如果A…

  • 51goc 637.可表示的数 题解

    51goc 637.可表示的数 题解51goc637.可表示的数题解题目描述有N个整数从左到右排成一行,如果某个数等于它前面的2个数的和,就称这个数是可以表示的数。问给定的数列里有多少个数是可以表示的数。输入格式第一行1个整

  • matlab中画柱状图的函数_科学柱状图怎么画

    matlab中画柱状图的函数_科学柱状图怎么画论文中需要画图进行比较,感觉还是matlab画起来比较方便,先把自己画的图及matlab代码放上。y=[300311;390425;312321;250185;550535;420432;410520;];b=bar(y);gridon;ch=get(b,’children’);set(gca,’XTickLabel’,{‘0′,’1′,’2′,’3’,’…

    2022年10月19日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号