Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 551|回复: 0

[默认分类] Struts2框架教程笔记一

[复制链接]
  • TA的每日心情
    开心
    2021-12-13 21:45
  • 签到天数: 15 天

    [LV.4]偶尔看看III

    发表于 2018-7-9 13:01:24 | 显示全部楼层 |阅读模式


      struts 2 是基于OpenSymphony的网络工程框架,所以struts的类基本都在OpenSymphony的子包下。
      在Struts 2 中的模型(model),视图(view)和控制器(controller)分别用动作(action),结果(result)和过滤调度器(FilterDispatcher)来实现的。
      控制器(controller)的任务是将用户的请求映射到合适的动作(action)。在Struts 2中,和过滤调度器(FilterDispatcher)做控制器(controller)同样的工作。
      模型(model)包含数据和业务逻辑。在Struts 2中模型(model)是由动作(action)组件来体现的。
      视图(view)是MVC模式中的描述组件。在Struts 2中视图(view)是用JSP, Velocity模板, Freemaker或一些其他描述层的技术实现的。
       
       
      控制器(controller)接收到用户的请求,决定调用哪个Struct 2的动作(action)。
      框架(Framework)创建一个动作(action)的实例并将它和动作调用器(ActionInvocation)的一个实例进行关联。
      在Struts2中, 调用的动作(action)可以通过在应用XML文件中定义的一系列拦截器(interceptor)。
      框架(Framework)调用动作调用器(ActionInvocation)的invoke()方法启动动作(action)的执行。
      invoke()方法每次被调用的时候,动作调用器(ActionInvocation)都会询问自身的状态并执行下一步的拦截器(interceptor)。
      动作调用器(ActionInvocation)通过调用拦截器(interceptor)的interceptor()方法来掌握控制在栈中的拦截器(interceptor)。
      拦截器(interceptor)的interceptor()方法依次调用动作调用器(ActionInvocation)的invoke()方法,直到所有的拦截器(interceptor)被调用。最后,动作(action)被调用并将相应的结果返回给用户。
      拦截器(interceptor)可以在动作(action)执行之前或之后,或是前后同时被调用。不是必须每次都调用它们。
      首先拦截器(interceptor)按照在栈中定义的顺序执行,然后动作(action)被调用并将结果整合,之后再倒序调用在将栈中的拦截器(interceptor)。
      抽象类com.opensymphony.xwork2.interceptor.AbstractInterceptor 继承了接口类Interceptor,下面就以国际化拦截器部分代码为例子:
      public class I18nInterceptor extends AbstractInterceptor {
        protected static final Logger LOG = LoggerFactory.getLogger(I18nInterceptor.class);
               @Override
        public String intercept(ActionInvocation invocation) throws Exception {
            if (LOG.isDebugEnabled()) {
                LOG.debug("intercept ""
                        + invocation.getProxy().getNamespace() + "/"
                        + invocation.getProxy().getActionName() + "" { ");
            }
            //get requested locale
            Map<String, Object> params = invocation.getInvocationContext().getParameters();
              boolean storeInSession = true;
            Object requested_locale = findLocaleParameter(params, parameterName);
            if (requested_locale == null) {
                requested_locale = findLocaleParameter(params, requestOnlyParameterName);
                if (requested_locale != null) {
                    storeInSession = false;
                }
            }
              //save it in session
              Map<String, Object> session = invocation.getInvocationContext().getSession();
           /*这里省略了保存session信息的代码,补充:invocation.getInvocationContext()返回一个ActionContext对象,ActionContext cd = invocation.getInvocationContext()*/
                   saveLocale(invocation, locale);
              if (LOG.isDebugEnabled()) {
                LOG.debug("before Locale=" + invocation.getStack().findValue("locale"));
            }
                   /*拦截器(interceptor)的interceptor()方法依次调用动作调用器(ActionInvocation)的invoke()方法,直到所有的拦截器(interceptor)被调用*/
              final String result = invocation.invoke();
            if (LOG.isDebugEnabled()) {
                LOG.debug("after Locale=" + invocation.getStack().findValue("locale"));
            }
              if (LOG.isDebugEnabled()) {
                LOG.debug("intercept } ");
            }
              return result;
        }
      那么Interceptor何时调用呢?
      框架(Framework)调用动作调用器(ActionInvocation)的invoke()方法启动动作(action)的执行。
      invoke()方法每次被调用的时候,动作调用器(ActionInvocation)都会询问自身的状态并执行下一步的拦截器(interceptor)。
      参考com.opensymphony.xwork2.DefaultActionInvocation
      public class DefaultActionInvocation implements ActionInvocation {
      /*其他方法略掉*/
       public String invoke() throws Exception {
            String profileKey = "invoke: ";
            try {
                UtilTimerStack.push(profileKey);
                  if (executed) {
                    throw new IllegalStateException("Action has already executed");
                }
                  if (interceptors.hasNext()) {
                    final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();
                    String interceptorMsg = "interceptor: " + interceptor.getName();
                    UtilTimerStack.push(interceptorMsg);
                    try {
                                        /*invoke()方法每次被调用的时候,动作调用器(ActionInvocation)都会询问自身的状态并执行下一步的拦截器(interceptor)*/
                                    resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
                                       }
                    finally {
                        UtilTimerStack.pop(interceptorMsg);
                    }
                } else {
                    resultCode = invokeActionOnly();
                }
                     /*首先拦截器(interceptor)按照在栈中定义的顺序执行,然后动作(action)被调用并将结果整合,之后再倒序调用在将栈中的拦截器(interceptor)*/
                  // 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) {
                        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);
            }
        }


      总结:通过上面的介绍,不难发现Interceptor的本质就是一个Action,它要达到的目的就是为了提高Action代码的复用性(比如国际化或者类型转换拦截器),降低Action的耦合性,但是Intercepetor又是一中特殊的Action,它在执行指定Action之前或者之后完成可复用的模块化业务逻辑,可以把通用的逻辑进行封装(比如国际化或者类型转换拦)。


       


      下面提供DefaultActionInvocation的完整源代码struts2.3.1.2


      /*
    * Copyright 2002-2006,2009 The Apache Software Foundation.
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    *      http://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License.
    */
    package com.opensymphony.xwork2;
      import com.opensymphony.xwork2.config.Configuration;
    import com.opensymphony.xwork2.config.ConfigurationException;
    import com.opensymphony.xwork2.config.entities.ActionConfig;
    import com.opensymphony.xwork2.config.entities.InterceptorMapping;
    import com.opensymphony.xwork2.config.entities.ResultConfig;
    import com.opensymphony.xwork2.inject.Container;
    import com.opensymphony.xwork2.inject.Inject;
    import com.opensymphony.xwork2.interceptor.PreResultListener;
    import com.opensymphony.xwork2.util.ValueStack;
    import com.opensymphony.xwork2.util.ValueStackFactory;
    import com.opensymphony.xwork2.util.logging.Logger;
    import com.opensymphony.xwork2.util.logging.LoggerFactory;
    import com.opensymphony.xwork2.util.profiling.UtilTimerStack;
      import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
      
    /**
    * The Default ActionInvocation implementation
    *
    * @author Rainer Hermanns
    * @author tmjee
    * @version $Date: 2011-06-09 00:40:33 +0200 (Thu, 09 Jun 2011) $ $Id: DefaultActionInvocation.java 1133590 2011-06-08 22:40:33Z jafl $
    * @see com.opensymphony.xwork2.DefaultActionProxy
    */
    public class DefaultActionInvocation implements ActionInvocation {
          private static final long serialVersionUID = -585293628862447329L;
          //static {
        //    if (ObjectFactory.getContinuationPackage() != null) {
        //        continuationHandler = new ContinuationHandler();
        //    }
        //}
        private static final Logger LOG = LoggerFactory.getLogger(DefaultActionInvocation.class);
          private static final Class[] EMPTY_CLASS_ARRAY   = new Class[0];
        private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
          protected Object action;
        protected ActionProxy proxy;
        protected List<PreResultListener> preResultListeners;
        protected Map<String, Object> extraContext;
        protected ActionContext invocationContext;
        protected Iterator<InterceptorMapping> interceptors;
        protected ValueStack stack;
        protected Result result;
        protected Result explicitResult;
        protected String resultCode;
        protected boolean executed = false;
        protected boolean pushAction = true;
        protected ObjectFactory objectFactory;
        protected ActionEventListener actionEventListener;
        protected ValueStackFactory valueStackFactory;
        protected Container container;
        private Configuration configuration;
        protected UnknownHandlerManager unknownHandlerManager;
          public DefaultActionInvocation(final Map<String, Object> extraContext, final boolean pushAction) {
            DefaultActionInvocation.this.extraContext = extraContext;
            DefaultActionInvocation.this.pushAction = pushAction;
        }
          @Inject
        public void setUnknownHandlerManager(UnknownHandlerManager unknownHandlerManager) {
            this.unknownHandlerManager = unknownHandlerManager;
        }
          @Inject
        public void setValueStackFactory(ValueStackFactory fac) {
            this.valueStackFactory = fac;
        }
          @Inject
        public void setConfiguration(Configuration configuration) {
            this.configuration = configuration;
        }
          @Inject
        public void setObjectFactory(ObjectFactory fac) {
            this.objectFactory = fac;
        }
          @Inject
        public void setContainer(Container cont) {
            this.container = cont;
        }
          @Inject(required=false)
        public void setActionEventListener(ActionEventListener listener) {
            this.actionEventListener = listener;
        }
          public Object getAction() {
            return action;
        }
          public boolean isExecuted() {
            return executed;
        }
          public ActionContext getInvocationContext() {
            return invocationContext;
        }
          public ActionProxy getProxy() {
            return proxy;
        }
          /**
         * If the DefaultActionInvocation has been executed before and the Result is an instance of ActionChainResult, this method
         * will walk down the chain of ActionChainResults until it finds a non-chain result, which will be returned. If the
         * DefaultActionInvocation"s result has not been executed before, the Result instance will be created and populated with
         * the result params.
         *
         * @return a Result instance
         * @throws Exception
         */
        public Result getResult() throws Exception {
            Result returnResult = result;
              // If we"ve chained to other Actions, we need to find the last result
            while (returnResult instanceof ActionChainResult) {
                ActionProxy aProxy = ((ActionChainResult) returnResult).getProxy();
                  if (aProxy != null) {
                    Result proxyResult = aProxy.getInvocation().getResult();
                      if ((proxyResult != null) && (aProxy.getExecuteResult())) {
                        returnResult = proxyResult;
                    } else {
                        break;
                    }
                } else {
                    break;
                }
            }
              return returnResult;
        }
          public String getResultCode() {
            return resultCode;
        }
          public void setResultCode(String resultCode) {
            if (isExecuted())
                throw new IllegalStateException("Result has already been executed.");
              this.resultCode = resultCode;
        }
      
        public ValueStack getStack() {
            return stack;
        }
          /**
         * Register a com.opensymphony.xwork2.interceptor.PreResultListener to be notified after the Action is executed and before the
         * Result is executed. The ActionInvocation implementation must guarantee that listeners will be called in the order
         * in which they are registered. Listener registration and execution does not need to be thread-safe.
         *
         * @param listener
         */
        public void addPreResultListener(PreResultListener listener) {
            if (preResultListeners == null) {
                preResultListeners = new ArrayList<PreResultListener>(1);
            }
              preResultListeners.add(listener);
        }
          public Result createResult() throws Exception {
              if (explicitResult != null) {
                Result ret = explicitResult;
                explicitResult = null;
                  return ret;
            }
            ActionConfig config = proxy.getConfig();
            Map<String, ResultConfig> results = config.getResults();
              ResultConfig resultConfig = null;
              try {
                resultConfig = results.get(resultCode);
            } catch (NullPointerException e) {
                // swallow
            }
            
            if (resultConfig == null) {
                // If no result is found for the given resultCode, try to get a wildcard "*" match.
                resultConfig = results.get("*");
            }
              if (resultConfig != null) {
                try {
                    return objectFactory.buildResult(resultConfig, invocationContext.getContextMap());
                } catch (Exception e) {
                    LOG.error("There was an exception while instantiating the result of type " + resultConfig.getClassName(), e);
                    throw new XWorkException(e, resultConfig);
                }
            } else if (resultCode != null && !Action.NONE.equals(resultCode) && unknownHandlerManager.hasUnknownHandlers()) {
                return unknownHandlerManager.handleUnknownResult(invocationContext, proxy.getActionName(), proxy.getConfig(), resultCode);
            }
            return null;
        }
          /**
         * @throws ConfigurationException If no result can be found with the returned code
         */
        public String invoke() throws Exception {
            String profileKey = "invoke: ";
            try {
                UtilTimerStack.push(profileKey);
                  if (executed) {
                    throw new IllegalStateException("Action has already executed");
                }
                  if (interceptors.hasNext()) {
                    final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();
                    String interceptorMsg = "interceptor: " + interceptor.getName();
                    UtilTimerStack.push(interceptorMsg);
                    try {
                                    resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
                                }
                    finally {
                        UtilTimerStack.pop(interceptorMsg);
                    }
                } else {
                    resultCode = invokeActionOnly();
                }
                  // 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) {
                        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);
            }
        }
          public String invokeActionOnly() throws Exception {
            return invokeAction(getAction(), proxy.getConfig());
        }
          protected void createAction(Map<String, Object> contextMap) {
            // load action
            String timerKey = "actionCreate: " + proxy.getActionName();
            try {
                UtilTimerStack.push(timerKey);
                action = objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);
            } catch (InstantiationException e) {
                throw new XWorkException("Unable to intantiate Action!", e, proxy.getConfig());
            } catch (IllegalAccessException e) {
                throw new XWorkException("Illegal access to constructor, is it public?", e, proxy.getConfig());
            } catch (Exception e) {
                String gripe = "";
                  if (proxy == null) {
                    gripe = "Whoa!  No ActionProxy instance found in current ActionInvocation.  This is bad ... very bad";
                } else if (proxy.getConfig() == null) {
                    gripe = "Sheesh.  Where"d that ActionProxy get to?  I can"t find it in the current ActionInvocation!?";
                } else if (proxy.getConfig().getClassName() == null) {
                    gripe = "No Action defined for "" + proxy.getActionName() + "" in namespace "" + proxy.getNamespace() + """;
                } else {
                    gripe = "Unable to instantiate Action, " + proxy.getConfig().getClassName() + ",  defined for "" + proxy.getActionName() + "" in namespace "" + proxy.getNamespace() + """;
                }
                  gripe += (((" -- " + e.getMessage()) != null) ? e.getMessage() : " [no message in exception]");
                throw new XWorkException(gripe, e, proxy.getConfig());
            } finally {
                UtilTimerStack.pop(timerKey);
            }
              if (actionEventListener != null) {
                action = actionEventListener.prepare(action, stack);
            }
        }
          protected Map<String, Object> createContextMap() {
            Map<String, Object> contextMap;
              if ((extraContext != null) && (extraContext.containsKey(ActionContext.VALUE_STACK))) {
                // In case the ValueStack was passed in
                stack = (ValueStack) extraContext.get(ActionContext.VALUE_STACK);
                  if (stack == null) {
                    throw new IllegalStateException("There was a null Stack set into the extra params.");
                }
                  contextMap = stack.getContext();
            } else {
                // create the value stack
                // this also adds the ValueStack to its context
                stack = valueStackFactory.createValueStack();
                  // create the action context
                contextMap = stack.getContext();
            }
              // put extraContext in
            if (extraContext != null) {
                contextMap.putAll(extraContext);
            }
              //put this DefaultActionInvocation into the context map
            contextMap.put(ActionContext.ACTION_INVOCATION, this);
            contextMap.put(ActionContext.CONTAINER, container);
              return contextMap;
        }
          /**
         * Uses getResult to get the final Result and executes it
         *
         * @throws ConfigurationException If not result can be found with the returned code
         */
        private void executeResult() throws Exception {
            result = createResult();
              String timerKey = "executeResult: " + getResultCode();
            try {
                UtilTimerStack.push(timerKey);
                if (result != null) {
                    result.execute(this);
                } else if (resultCode != null && !Action.NONE.equals(resultCode)) {
                    throw new ConfigurationException("No result defined for action " + getAction().getClass().getName()
                            + " and result " + getResultCode(), proxy.getConfig());
                } else {
                    if (LOG.isDebugEnabled()) {
                        LOG.debug("No result returned for action " + getAction().getClass().getName() + " at " + proxy.getConfig().getLocation());
                    }
                }
            } finally {
                UtilTimerStack.pop(timerKey);
            }
        }
          public void init(ActionProxy proxy) {
            this.proxy = proxy;
            Map<String, Object> contextMap = createContextMap();
              // Setting this so that other classes, like object factories, can use the ActionProxy and other
            // contextual information to operate
            ActionContext actionContext = ActionContext.getContext();
              if (actionContext != null) {
                actionContext.setActionInvocation(this);
            }
              createAction(contextMap);
              if (pushAction) {
                stack.push(action);
                contextMap.put("action", action);
            }
              invocationContext = new ActionContext(contextMap);
            invocationContext.setName(proxy.getActionName());

              // get a new List so we don"t get problems with the iterator if someone changes the list
            List<InterceptorMapping> interceptorList = new ArrayList<InterceptorMapping>(proxy.getConfig().getInterceptors());
            interceptors = interceptorList.iterator();
        }
          protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {
            String methodName = proxy.getMethod();
              if (LOG.isDebugEnabled()) {
                LOG.debug("Executing action method = " + actionConfig.getMethodName());
            }
              String timerKey = "invokeAction: " + proxy.getActionName();
            try {
                UtilTimerStack.push(timerKey);
                  boolean methodCalled = false;
                Object methodResult = null;
                Method method = null;
                try {
                    method = getAction().getClass().getMethod(methodName, EMPTY_CLASS_ARRAY);
                } catch (NoSuchMethodException e) {
                    // hmm -- OK, try doXxx instead
                    try {
                        String altMethodName = "do" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
                        method = getAction().getClass().getMethod(altMethodName, EMPTY_CLASS_ARRAY);
                    } catch (NoSuchMethodException e1) {
                        // well, give the unknown handler a shot
                        if (unknownHandlerManager.hasUnknownHandlers()) {
                            try {
                                methodResult = unknownHandlerManager.handleUnknownMethod(action, methodName);
                                methodCalled = true;
                            } catch (NoSuchMethodException e2) {
                                // throw the original one
                                throw e;
                            }
                        } else {
                            throw e;
                        }
                    }
                }
                  if (!methodCalled) {
                    methodResult = method.invoke(action, EMPTY_OBJECT_ARRAY);
                }
                  return saveResult(actionConfig, methodResult);
            } catch (NoSuchMethodException e) {
                throw new IllegalArgumentException("The " + methodName + "() is not defined in action " + getAction().getClass() + "");
            } catch (InvocationTargetException e) {
                // We try to return the source exception.
                Throwable t = e.getTargetException();
                  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);
            }
        }
          /**
         * Save the result to be used later.
         * @param actionConfig
         * @param methodResult the result of the action.
         * @return the result code to process.
         */
        protected String saveResult(ActionConfig actionConfig, Object methodResult) {
            if (methodResult instanceof Result) {
                this.explicitResult = (Result) methodResult;
                  // Wire the result automatically
                container.inject(explicitResult);
                return null;
            } else {
                return (String) methodResult;
            }
        }
      }



       
      
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-23 20:56 , Processed in 0.345051 second(s), 36 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表