Struts2拦截器详解

Struts2拦截器详解成功的花儿,其间浸透了奋斗的泪水和汗水;然而,用泪水和汗水就可以实现一切的美好。Struts2拦截器概述拦截器的概念是在Struts2里面有的。在其它地方没有。Struts2是框架,封装了很多的功能,struts2里面封装的功能都是在拦截器里面。Struts2里面封装了很多的功能,有很多拦截器,不是每次这些拦截器都执行,每次执行默认的拦截器。Struts2里面默认的拦截器位置:struts

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

成功的花儿,其间浸透了奋斗的泪水和汗水;然而,用泪水和汗水就可以实现一切的美好。

Struts2拦截器概述

  • 拦截器的概念是在Struts2里面有的。在其它地方没有。

  • Struts2是框架,封装了很多的功能,struts2里面封装的功能都是在拦截器里面。

  • Struts2里面封装了很多的功能,有很多拦截器,不是每次这些拦截器都执行,每次执行默认的拦截器。

Struts2里面默认的拦截器位置:

  • struts2-core-2.xxxx.jar—->struts-default.xml,在这里面配置了很多的拦截器,但是只执行默认配置的那些拦截器。
    <interceptors><!-- 这里定义了很多的拦截器 -->
<interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
<interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
<interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>
<interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>
<interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/>
<interceptor name="cookieProvider" class="org.apache.struts2.interceptor.CookieProviderInterceptor"/>
<interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" />
<interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" />
<interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />
<interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
<interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
<interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
<interceptor name="i18n" class="org.apache.struts2.interceptor.I18nInterceptor"/>
<interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
<interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
<interceptor name="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/>
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
<interceptor name="actionMappingParams" class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/>
<interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
<interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>
<interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/>
<interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
<interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/>
<interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
<interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>
<interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
<interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>
<interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" />
<interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" />
<interceptor name="datetime" class="org.apache.struts2.interceptor.DateTextFieldInterceptor" />
<interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />
<interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" />
<interceptor name="annotationWorkflow" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor" />
<interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" />
<!-- Basic stack -->
<interceptor-stack name="basicStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="datetime"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
</interceptor-stack>
<!-- Sample validation and workflow stack -->
<interceptor-stack name="validationWorkflowStack">
<interceptor-ref name="basicStack"/>
<interceptor-ref name="validation"/>
<interceptor-ref name="workflow"/>
</interceptor-stack>
<!-- Sample file upload stack -->
<interceptor-stack name="fileUploadStack">
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="basicStack"/>
</interceptor-stack>
<!-- Sample model-driven stack -->
<interceptor-stack name="modelDrivenStack">
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="basicStack"/>
</interceptor-stack>
<!-- Sample action chaining stack -->
<interceptor-stack name="chainStack">
<interceptor-ref name="chain"/>
<interceptor-ref name="basicStack"/>
</interceptor-stack>
<!-- Sample i18n stack -->
<interceptor-stack name="i18nStack">
<interceptor-ref name="i18n"/>
<interceptor-ref name="basicStack"/>
</interceptor-stack>
<!-- An example of the paramsPrepareParams trick. This stack
is exactly the same as the defaultStack, except that it
includes one extra interceptor before the prepare interceptor:
the params interceptor.
This is useful for when you wish to apply parameters directly
to an object that you wish to load externally (such as a DAO
or database or service layer), but can't load that object
until at least the ID parameter has been loaded. By loading
the parameters twice, you can retrieve the object in the
prepare() method, allowing the second params interceptor to
apply the values on the object. -->
<interceptor-stack name="paramsPrepareParamsStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="datetime"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="params"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params"/>
<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-stack>
<!-- A complete stack with all the common interceptors in place.
Generally, this stack should be the one you use, though it
may do more than you need. Also, the ordering can be
switched around (ex: if you wish to have your servlet-related
objects applied before prepare() is called, you'd need to move
servletConfig interceptor up.
This stack also excludes from the normal validation and workflow
the method names input, back, and cancel. These typically are
associated with requests that should not be validated.
-->
<!-- 初略的看了上面注释的翻译: -->
<!-- 一个与所有地方共同拦截系统完整的堆栈。一般来说,这个堆栈应该是你使用的,虽然它可能比你需要的更多。 -->
<!-- 这就是我们的默认拦截器列表 -->
<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="datetime"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params"/>
<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-stack>
<!-- The completeStack is here for backwards compatibility for
applications that still refer to the defaultStack by the
old name -->
<interceptor-stack name="completeStack">
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
<!-- Sample execute and wait stack.
Note: execAndWait should always be the *last* interceptor. -->
<interceptor-stack name="executeAndWaitStack">
<interceptor-ref name="execAndWait">
<param name="excludeMethods">input,back,cancel</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="execAndWait">
<param name="excludeMethods">input,back,cancel</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="defaultStack"/>
<default-class-ref class="com.opensymphony.xwork2.ActionSupport" />

拦截器的执行时间

action代理对象创建之后,action目标处理逻辑方法执行之前!!可以在代码中进行调试断点测试(测试时是通过debug调试项目)!!!

通过调试你就可以发现,如果你的拦截器配置的是struts-default或者其它的拦截器组,那么你就会发现,即使你没有在项目中用到某个拦截器,比如我这里并没有实现ModelDriven接口,但是它被运行了。所以,只要你配置了相关的拦截器组,拦截器组里面的所有拦截器不管用或不用都会被执行。

拦截器底层原理

底层依赖两个技术:动态代理,过滤链

拦截器底层使用的两个原理:

1.aop思想(一种开发思想)

文字描述: Aop是面向切面(方面) 编程,比如有一个基本功能,想要扩展功能,不通过修改源代码方式扩展功能,经常用的是通过配置文件。(上面的描述还是一个浅显的认识。在讲解Spring时,会更深入了解aop),同时,aop使用了一个技术,那就是动态代理。

2.责任链模式

  • 在java中有很多的设计模式,责任链模式就是其中的一种。
  • 责任链模式和过滤链很相似。

过滤链:一个请求可有多个过滤器进行过滤,每个过滤器只有做放行才能到下一个过滤器。

在责任链场景:

要执行多个操作,有添加,修改,删除三个操作。

首先执行添加操作,添加操作执行之后,做类似于放行的操作,执行修改操作,修改操作执行之后做类似于放行操作,执行删除操作。

这里action目标逻辑方法的执行是通过动态代理方式执行,动态代理的方式执行和直接创建action对象执行方法效果是没有区别的。

aop思想和责任链模式如何应用到拦截器里面

文字描述:

  • 拦截器在aciton代理对象创建之后,action的目标方法执行之前执行。在拦截器执行之后再执行action方法!!!
  • 在action方法执行之前执行默认拦截器,执行过程使用aop思想,在action没有直接调用拦截器的方法,使用配置文件方式进行操作。使用配置文件是关键,把拦截器通过配置引入到项目功能的方式叫做aop思想。
  • 在执行拦截器时候,执行很多的拦截器,这个过程使用责任链模式。
  • 假如执行三个拦截器,执行拦截器1,执行拦截器1之后做放行操作,执行拦截器2,执行拦截器2之后做放行操作,执行拦截器3,执行拦截器3之后放行,最后执行action目标逻辑方法。

在我们的默认拦截器配置里面,那些默认拦截器其实是都会执行的。只是关乎我们到底用不用其具体实现而已,就像是ModelDriven这个类

下面我们来看看源代码中的执行:

首先进入Struts2的过滤器中,org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter,进入doFilter方法里面,(这里声明下,filter过滤器是在web容器执行时,就会创建对象,其中三大组件加载顺序为: listener -> filter -> servlet)。

进入doFilter后就会进入:

为什么进入doFilter方法里面???因为每次用户访问的时候就会进入doFilter里面。

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
try {
String uri = RequestUtils.getUri(request);
if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
LOG.trace("Request {} is excluded from handling by Struts, passing request to other filters", uri);
chain.doFilter(request, response);
} else {
LOG.trace("Checking if {} is a static resource", uri);
boolean handled = execute.executeStaticResourceRequest(request, response);
if (!handled) {
LOG.trace("Assuming uri {} as a normal action", uri);
prepare.setEncodingAndLocale(request, response);
prepare.createActionContext(request, response);
prepare.assignDispatcherToThread();
request = prepare.wrapRequest(request);
ActionMapping mapping = prepare.findActionMapping(request, response, true);
if (mapping == null) {
LOG.trace("Cannot find mapping for {}, passing to other filters", uri);
chain.doFilter(request, response);
} else {
LOG.trace("Found mapping {} for {}", mapping, uri);
execute.executeAction(request, response, mapping);//在doFilter里面就会进入这个方法。executeAction。执行action方法。
}
}
}
} finally {
prepare.cleanupRequest(request);
}
}

在executeAction方法里面又会继续调用一个方法:

public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {
dispatcher.serviceAction(request, response, mapping);
}
//以下继续进入方法
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping)
throws ServletException {
Map<String, Object> extraContext = createContextMap(request, response, mapping);
// If there was a previous value stack, then create a new copy and pass it in to be used by the new Action
ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
boolean nullStack = stack == null;
if (nullStack) {
ActionContext ctx = ActionContext.getContext();
if (ctx != null) {
stack = ctx.getValueStack();
}
}
if (stack != null) {
extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack));
}
String timerKey = "Handling request from Dispatcher";
try {
UtilTimerStack.push(timerKey);
String namespace = mapping.getNamespace();
String name = mapping.getName();
String method = mapping.getMethod();
ActionProxy proxy = getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
namespace, name, method, extraContext, true, false);//注意这里,这里就会通过动态代理的方式执行action,但是现在并没有执行action,只是创建了action动态代理对象。(这里有一个经验,在好的框架中,一般创建用户的类对象都会使用到动态代理创建或者使用反射来创建。),动态代理创建的对象叫做代理对象。
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
// if the ActionMapping says to go straight to a result, do it!
if (mapping.getResult() != null) {
Result result = mapping.getResult();
result.execute(proxy.getInvocation());
} else {
proxy.execute();//这里执行action里面的方法。但是在执行里面还有注意的地方。拦截器也没有执行。所以现在的程序是要执行配置好的拦截器。
}
// If there was a previous value stack then set it back onto the request
if (!nullStack) {
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
}
} catch (ConfigurationException e) {
logConfigurationException(request, e);
sendError(request, response, HttpServletResponse.SC_NOT_FOUND, e);
} catch (Exception e) {
e.printStackTrace();
if (handleException || devMode) {
sendError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
} else {
throw new ServletException(e);
}
} finally {
UtilTimerStack.pop(timerKey);
}
}

//进入实现类StrutsActionProxy里面
public String execute() throws Exception {
ActionContext previous = ActionContext.getContext();
ActionContext.setContext(invocation.getInvocationContext());
try {
// This is for the new API:
// return RequestContextImpl.callInContext(invocation, new Callable<String>() { 

//public String call() throws Exception { 

// return invocation.invoke();
//}
// });
return invocation.invoke();//这里的invoke可不是反射里面的invoke,这点要注意。这里的目的相当于放行操作。继续进入这个方法。
} finally {
if (cleanupContext)
ActionContext.setContext(previous);
}
}
//继续进入invoke方法里面的实现类DefaultActionInvocation类
public String invoke() throws Exception {
String profileKey = "invoke: ";
try {
UtilTimerStack.push(profileKey);
if (executed) {
throw new IllegalStateException("Action has already executed");
}
if (interceptors.hasNext()) {
//这里就是遍历拦截器。是否还有下一个拦截器。虽然没有看到什么for和while循环,猜测应该是通过递归循环。因为被遍历对象是一个这样的变量Iterator<InterceptorMapping> interceptors;很明显,不论用任何方式进行遍历,肯定会遍历完的。而这里面装的是被配置进来的拦截器。
final InterceptorMapping interceptorMapping = interceptors.next();
String interceptorMsg = "interceptorMapping: " + interceptorMapping.getName();
UtilTimerStack.push(interceptorMsg);
try {
Interceptor interceptor = interceptorMapping.getInterceptor();
if (interceptor instanceof WithLazyParams) {
interceptor = lazyParamInjector.injectParams(interceptor, interceptorMapping.getParams(), invocationContext);
}
resultCode = interceptor.intercept(DefaultActionInvocation.this);
} finally {
UtilTimerStack.pop(interceptorMsg);
}
} else {
resultCode = invokeActionOnly();//最后,当拦截器执行完毕后就执行action的方法。
}
// this is needed because the result will be executed, then control will return to the Interceptor, which will
// return above and flow through again
if (!executed) {
if (preResultListeners != null) {
LOG.trace("Executing PreResultListeners for result [{}]", result);
for (Object preResultListener : preResultListeners) {
PreResultListener listener = (PreResultListener) preResultListener;
String _profileKey = "preResultListener: ";
try {
UtilTimerStack.push(_profileKey);
listener.beforeResult(this, resultCode);
}
finally {
UtilTimerStack.pop(_profileKey);
}
}
}
// now execute the result, if we're supposed to
if (proxy.getExecuteResult()) {
executeResult();
}
executed = true;
}
return resultCode;
}
finally {
UtilTimerStack.pop(profileKey);
}
}
//继续进入invokeActionOnly方法
public String invokeActionOnly() throws Exception {
return invokeAction(getAction(), proxy.getConfig());
}
//继续进入
protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {
String methodName = proxy.getMethod();//这里可以看到获取代理对象的方法。
LOG.debug("Executing action method = {}", methodName);
String timerKey = "invokeAction: " + proxy.getActionName();
try {
UtilTimerStack.push(timerKey);
Object methodResult;
try {
methodResult = ognlUtil.callMethod(methodName + "()", getStack().getContext(), action);//这里就是真正该action方法执行,并返回了结果!
} catch (MethodFailedException e) {
// if reason is missing method, try checking UnknownHandlers
if (e.getReason() instanceof NoSuchMethodException) {
if (unknownHandlerManager.hasUnknownHandlers()) {
try {
methodResult = unknownHandlerManager.handleUnknownMethod(action, methodName);
} catch (NoSuchMethodException ignore) {
// throw the original one
throw e;
}
} else {
// throw the original one
throw e;
}
// throw the original exception as UnknownHandlers weren't able to handle invocation as well
if (methodResult == null) {
throw e;
}
} else {
// exception isn't related to missing action method, throw it
throw e;
}
}
return saveResult(actionConfig, methodResult);
} catch (NoSuchPropertyException e) {
throw new IllegalArgumentException("The " + methodName + "() is not defined in action " + getAction().getClass() + "");
} catch (MethodFailedException e) {
// We try to return the source exception.
Throwable t = e.getCause();
if (actionEventListener != null) {
String result = actionEventListener.handleException(t, getStack());
if (result != null) {
return result;
}
}
if (t instanceof Exception) {
throw (Exception) t;
} else {
throw e;
}
} finally {
UtilTimerStack.pop(timerKey);
}
}

所以这下也就明白了struts2过滤器的执行过程。过滤器判断用户发出的请求是否为struts2请求。如果是就创建action代理对象。在代理对象里面首先执行用户配置的拦截器,拦截器执行完毕后就执行aciton的方法。之后再返回结果。跳转到相关的页面或者其它action

重要概念(掌握,牢牢记住)

过滤器和拦截器的区别

  • 过滤器:在启动时创建。过滤器理论上可以过滤任何内容,比如 html、jsp、servlet、图片路径。
  • 拦截器:拦截器可以拦截的内容,只会拦截action类型请求。所以标准写法要在请求后面加上".action"这个后缀。

Servlet和action区别

  • Servlet默认第一次访问的时候创建,创建一次,单实例对象。
  • action每次访问的时候创建,创建多次,多实例对象。

自定义拦截器

在Struts2里面有很多的拦截器,这些拦截器是struts2封装的功能,但是在实际开发中,Struts2里面的拦截器中可能没有我们要使用的功能,这个时候需要自己写拦截器实现功能

拦截器结构:

  • 通过查看源代码来查看拦截器的基本结构!

这里我们就查看ModelDriven这个拦截器类。

找到这个类有两种方式:1.在一个action类里面写上这个类,然后ctrl+鼠标左键就可以进入。2.在struts2-core-2.xxx.jar里面的当前目录下找到,struts-default.xml这个文件,在里面配置了很多的拦截器类。可以找到ModelDriven这个类。访问的时候ctrl+shift+T,然后把ModelDriven全路径复制上去就能够进入ModelDriven这个类了。

可以看到

ModelDriven继承了一个抽象类AbstractInterceptor这个抽象类。

public class ModelDrivenInterceptor extends AbstractInterceptor { 

接下来进入AbstractInterceptor这个抽象类。

public abstract class AbstractInterceptor implements Interceptor { 
//可以看见它实现了Interceptor这个接口。

在接口里面,共有三个方法:

public interface Interceptor extends Serializable { 

/** * Called to let an interceptor clean up any resources it has allocated. */
void destroy();//拦截器的销毁
/** * Called after an interceptor is created, but before any requests are processed using * {@link #intercept(com.opensymphony.xwork2.ActionInvocation) intercept} , giving * the Interceptor a chance to initialize any needed resources. */
void init();//拦截器的初始化
/** * Allows the Interceptor to do some processing on the request before and/or after the rest of the processing of the * request by the {@link ActionInvocation} or to short-circuit the processing and just return a String return code. * * @param invocation the action invocation * @return the return code, either returned from {@link ActionInvocation#invoke()}, or from the interceptor itself. * @throws Exception any system-level error, as defined in {@link com.opensymphony.xwork2.Action#execute()}. */
String intercept(ActionInvocation invocation) throws Exception;//拦截器的逻辑操作
}

如果在我们的开发中要写一个拦截器,那么我们通常都会去继承一个类来实现拦截器。我们可以去继承抽象类AbstractInterceptor。

但是在我们的目前开发中,我们建议使用另外一种方式去实现拦截器

  • 写类,继承一个类,这个类不是上面那个类,而是MethodFilterInterceptor这个类。
  • 为什么继承这个类??这个类能够让action里面某个方法不进行拦截。
  • 如果写上面的代码,就会写一些反射的代码,但是MethodFilterInterceptor不用写反射代码,而是进行配置就行了。省去了不少的麻烦。

但是,我们如果写了一些拦截器,怎么和action有什么关系??

让拦截器和action有关系:

  • 不是在action里面调用拦截器的方法,而是通过配置文件方式来建立关系。

案例:自定义登录拦截器。

需求:在项目中,有很多action的超链接,实现只有是登录的状态,才可以点击action的超链接实现功能。如果不是登录状态,点击action超链接返回到登录页面。

登录状态:使用session域对象实现。

  • 登录成功之后,把数据放到session里面。
  • 判断session是否有值,可以知道是否是登录状态。

在写拦截器之前得实现登录的基本功能:

<!-- 客户端jsp页面 -->
<form action="selfdefinedlogin" method="post">
<input type="text" name="name" placeholder="用户名"><br>
<input type="text" name="password" placeholder="密码"><br>
<input type="submit" value="登录">
</form>
//服务端action代码
public class loginAction implements ModelDriven<User>{ 

private User us;
public String execute(){
if(us.getName()==null||us.getPassword()==null)return "error";
if(!us.getName().equals("FireLang")||!us.getPassword().equals("lang")){
return "error";
}
ActionContext.getContext().getSession().put("FireLang", us.getName());
return "success";
}
@Override
public User getModel() {
us=new User();
return us;
}
}

添加登录拦截器功能:

  • 判断是否登录:判断session里面是否有名称是username的值。

拦截器实现过程:(重点)

第一步:创建类,继承MethodFilterInterceptor类

第二步: 重写MethodFilterInterceptor类里面的方法写拦截器逻辑

public class DefinedInterceptor extends MethodFilterInterceptor{ 

@Override
protected String doIntercept(ActionInvocation invocation) throws Exception {
String name=(String)ServletActionContext.getRequest().getSession().getAttribute("FireLang");
if(name==null){
return "error";//这个返回值会去匹配result里面的name属性值。然后跳转到相关页面或者action。同时下面的值也会去匹配result中的name属性值。
}
return invocation.invoke();//这一步类似于Filter的放行。进入下一个拦截器或者运行action的逻辑方法!!然后这里也必须有return,目的是把action的运行结果返回。看过Struts2的filter源码的都知道。
}
}

第三步:配置aciton和拦截器的关系(专业术语:注册拦截器)

  • 在要拦截的action标签所在的package标签里面声明拦截器。
<!-- 声明拦截器,注意这里还没有使用拦截器 -->
<interceptors>
<interceptor name="definedlogin" class="cn.domarvel.selfdefined.DefinedInterceptor"/>
</interceptors>
  • 在你具体的action的标签里面使用声明的拦截器。
<interceptor-ref name="definedlogin"/>
  • struts2里面执行很多的默认拦截器,但是如果在action里面配置自定义拦截器。默认的拦截器就不会执行了,解决办法就是把所有默认拦截器手动使用一次。

这里的使用方法有两种:

1.把所有的拦截器都配置进来。

<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="datetime"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params"/>
<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"/>

2.把它的父标签的name值写进来也可以,因为它的父标签是一个interceptor-stack,这相当于对拦截器的一个封装。所以可以根据它父标签的name值进行索引。

<interceptor-ref name="defaultStack"/>

但是如果你在action里面什么默认拦截器都用不到的话,就不用管默认拦截器是否要执行。

  • 我们在action里面配置的拦截器,对action里面所有的方法都会进行拦截,包括登录方法,所以如果对登录方法都进行了拦截的话,那么我们永远都是登录不上的哦

解决办法:让登录方法不进行拦截就行了。

  • 直接通过配置方式让action里面某些方法不进行拦截。如果是继承AbstractInterceptor来实现拦截器的话,那么想要实现不拦截某些方法,就需要写一些反射的代码。如果是继承MethodFilterInterceptor来实现拦截器的话就不需要写一些反射的代码,而是可以直接通过配置的方法来实现不拦截某些方法。
<!-- 在这里进行方法的拦截排除 -->
<interceptor-ref name="definedlogin">
<!-- param的name属性值不要写错了,不然它本身也不会报错,也会不起作用,这样很难找到错误的 -->
<!-- param里面的值为方法名称,多个方法名称用","逗号隔开 -->
<!-- 这样就能够让execute方法不会被当前配置的拦截器拦截了,但是因为不是配置的默认拦截器,所以默认拦截器还是会执行的 -->
<param name="excludeMethods">execute</param>
</interceptor-ref>
<!-- 拦截器配置的整体代码 -->
<package name="px" extends="struts-default" namespace="">
<interceptors>
<interceptor name="definedlogin" class="cn.domarvel.selfdefined.DefinedInterceptor"/>
</interceptors>
<action name="selfdefinedlogin" class="cn.domarvel.selfdefined.loginAction">
<interceptor-ref name="definedlogin">
<param name="excludeMethods">execute</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"/>
<result name="error">/WEB-INF/content/selfdefined/failed.jsp</result>
<result name="success">/WEB-INF/content/selfdefined/successx.jsp</result>
</action>
</package>

注意配置在当前action时,只对当前action有效。对其它action无效。

好了到了这里自定义拦截器也讲完了!!!OK!!!

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

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

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

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

(0)


相关推荐

  • oracle与mysql的区别面试题_oracle和db2的主要区别

    oracle与mysql的区别面试题_oracle和db2的主要区别Oracle与Mysql区别Oracle是大型数据库而Mysql是中小型数据库,Oracle市场占有率达40%,Mysql只有20%左右,同时Mysql是开源的而Oracle价格非常高。Oracle支持大并发,大访问量,是OLTP最好的工具。安装所用的空间差别也是很大的,Mysql安装完后才152M而Oracle有3G左右,且使用的时候Oracle占用特别大的内存空间和其他机器性能。Oracle也Mysql操作上的一些区别①主键Mysql一般使用自动增长类型,在创建表时只要指定表的主键为

  • break,continue,return的用法_break continue语句

    break,continue,return的用法_break continue语句1.break:直接结束一个循环,跳出循环体。break以后的循环体中的语句不会继续执行,循环体外面的会执行privatevoidtest(){for(inti=0;i&amp;lt;3;i++){Log.e(TAG,&quot;i=&quot;+i);if(i==1){brea…

  • 序列+“选择不重复的记录”(2)——每套最低纪录

    序列+“选择不重复的记录”(2)——每套最低纪录

  • 大数据分析及工具应用总结「建议收藏」

    大数据分析及工具应用总结「建议收藏」概述数据分析即从数据、信息到知识的过程,数据分析需要数学理论、行业经验以及计算机工具三者结合数据分析工具:各种厂商开发了数据分析的工具、模块,将分析模型封装,使不了解技术的人也能够快捷的实现数学建模,快速响应分析需求传统分析:在数据量较少时,传统的数据分析已能够发现数据中包含的知识,包括结构分析、杜邦分析等模型,方法成熟,应用广泛。数据挖掘:就是充分利用了统计学和人工智能技术的应用程序,并把这些高深复杂的技术封装起来,使人们不用自己掌握这些技术也能完成同样的功能,并且…

  • rpm 安装冲突「建议收藏」

    rpm 安装冲突「建议收藏」1.要安装的包比已安装的包旧,则采用降级的方式安装 rpm -Uvhkpartx-0.4.9-72.el6.x86_64.rpm –oldpackage 2.安装的包比已安装的包新,则直接升级即可 rpm -Uvhkpartx-0.4.9-72.el6.x86_64.rpm  或者末尾追加 –replacefiles  或  –repl…

  • 盘点多款国产Linux桌面操作系统[通俗易懂]

    盘点多款国产Linux桌面操作系统[通俗易懂]关注、星标公众号,不错过精彩内容编辑:strongerHuang微信公众号:strongerHuang素材来源:百度百科、网络国产操作系统多为以Linux为基础二次开发的操作系统。2014年4月8日起,美国微软公司停止了对WindowsXPSP3操作系统提供服务支持,这引起了社会和广大用户的广泛关注和对信息安全的担忧。工信部对此表示…

发表回复

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

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