`

struts2之拦截器栈paramsPrepareParamsStack

 
阅读更多

 

拦截器栈paramsPrepareParamsStack概述

 

1. 拦截器栈paramsPrepareParamsStack中三个重点的拦截器params,prepare和modelDriven。

 

params:com.opensymphony.xwork2.interceptor.ParametersInterceptor

prepare:com.opensymphony.xwork2.interceptor.PrepareInterceptor

modelDriven: com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor

 

2. paramsPrepareParamsStack拦截器栈的主流程为:

params->prepare->modelDriven->params

 

此流程为:

第一步params[参数]拦截器把表单数据注入到栈顶的Action对象中;

第二步prepare[准备]拦截器为modelDriven[模型驱动]拦截器准备向ValueStack[值栈]栈顶添加的对象,此对象作为第一步中Action对象的属性;

第三部modelDriven[模型驱动]拦截器把prepare[准备]拦截器创建的对象压入ValueStack[值栈]栈顶;

第四部params[参数]拦截器把表单数据注入到栈顶的Action的一个属性对象中;

 

通过以上的流程,Struts2可以简洁轻便并且高性能的完成业务的增删改查操作。

 

拦截器栈paramsPrepareParamsStack使用

 

下面,通过一个员工管理的案例来深入了解该拦截器栈的使用:

 

本案例通过四个版本不断优化,最终成为一个相对完美的解决方案。案例的处理难点是表单数据的提交与回填。 下面依次说明各个版本的实现方式和存在的缺点。

版本一:

实现方式:表单数据提交是把模型的属性直接添加到Action类中完成,表单回填测试在Action类中把数据写入request对象,在JSP页面中使用s:push标签将数据取出压入值栈完成回填;

存在缺点:Action类中加入模型类的属性以及get和set方法,造成代码大量冗余;

版本二:

实现方式:在版本一的基础上,直接办模型类作为Action类的属性,并把JSP页面中attr改为object.attr;

存在缺点:JSP页面获取数据代码不简洁,原来id变成employee.id;

版本三:

实现方式:使用拦截器栈paramsPrepareParamsStack,由系统自动把数据添加到值栈栈顶,从而简洁的完成数据映射;

存在缺点:执行每次请求到EmployeeAction执行view,add,edit,delete,create,update任意一个方法时,都会执行prepare方法。 其中,view,add,delete是不需要执行prepare方法的。特别是执行delete方法会执行"dao.selectEmployee(id);"代码浪费数据库资源。 view,add方法会产生不需要的对象,浪费内存。

解决办法:要解决资源浪费的问题,就需要程序能够做到在需要资源的时候执行prepare方法。幸运的是,struts2已经为此准备好了。 其解决办法是为每一个action方法提供了一个私人订制的prepare方法。其名称为prepare加原方法名首字符大写。因此,可以在此方法中完成必要的资源准备。 对于不使用的prepare方法,可以在struts.xml中配置使其不再被系统调用。

版本四:

实现方式:在版本三的基础上,禁用通用的prepare方法,使用每个方法自己的prepare方法。

 

拦截器栈paramsPrepareParamsStack详解 

 

ParametersInterceptor拦截器

 

作用:把action请求参数注入到值栈栈顶对象的对应属性中,没有对应属性则忽略。

源码:

 

 

    @Override
    public String doIntercept(ActionInvocation invocation) throws Exception {
        Object action = invocation.getAction();
        if (!(action instanceof NoParameters)) {
            ActionContext ac = invocation.getInvocationContext();
            //1. 获取请求参数
            final Map<String, Object> parameters = retrieveParameters(ac);

            if (LOG.isDebugEnabled()) {
                LOG.debug("Setting params " + getParameterLogMap(parameters));
            }

            if (parameters != null) {
                Map<String, Object> contextMap = ac.getContextMap();
                try {
                    ReflectionContextState.setCreatingNullObjects(contextMap, true);
                    ReflectionContextState.setDenyMethodExecution(contextMap, true);
                    ReflectionContextState.setReportingConversionErrors(contextMap, true);
                    //2. 获取值栈
                    ValueStack stack = ac.getValueStack();
                    //3. 向值栈栈顶对象注入参数
                    setParameters(action, stack, parameters);
                } finally {
                    ReflectionContextState.setCreatingNullObjects(contextMap, false);
                    ReflectionContextState.setDenyMethodExecution(contextMap, false);
                    ReflectionContextState.setReportingConversionErrors(contextMap, false);
                }
            }
        }
        return invocation.invoke();
    }
protected void setParameters(final Object action, ValueStack stack, final Map<String, Object> parameters) {
        Map<String, Object> params;
        Map<String, Object> acceptableParameters;
        if (ordered) {
            params = new TreeMap<String, Object>(getOrderedComparator());
            acceptableParameters = new TreeMap<String, Object>(getOrderedComparator());
            params.putAll(parameters);
        } else {
            params = new TreeMap<String, Object>(parameters);
            acceptableParameters = new TreeMap<String, Object>();
        }
        //3.1 过滤可接受的参数 
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            String name = entry.getKey();
            if (isAcceptableParameter(name, action)) {
                acceptableParameters.put(name, entry.getValue());
            }
        }
        //3.2 基于目前值栈生成一个新的值栈
        ValueStack newStack = valueStackFactory.createValueStack(stack);
        boolean clearableStack = newStack instanceof ClearableValueStack;
        if (clearableStack) {
            //if the stack's context can be cleared, do that to prevent OGNL
            //from having access to objects in the stack, see XW-641
            ((ClearableValueStack)newStack).clearContextValues();
            Map<String, Object> context = newStack.getContext();
            ReflectionContextState.setCreatingNullObjects(context, true);
            ReflectionContextState.setDenyMethodExecution(context, true);
            ReflectionContextState.setReportingConversionErrors(context, true);

            //keep locale from original context
            context.put(ActionContext.LOCALE, stack.getContext().get(ActionContext.LOCALE));
        }

        boolean memberAccessStack = newStack instanceof MemberAccessValueStack;
        if (memberAccessStack) {
            //block or allow access to properties
            //see WW-2761 for more details
            MemberAccessValueStack accessValueStack = (MemberAccessValueStack) newStack;
            accessValueStack.setAcceptProperties(acceptParams);
            accessValueStack.setExcludeProperties(excludeParams);
            if (action instanceof ParameterNameAware)
            accessValueStack.setPropertiesJudge(new PropertiesJudge() {
                public boolean acceptProperty(String propertyName) {
                    return ((ParameterNameAware) action).acceptableParameterName(propertyName);
                }
            });
        }
        //3.3 遍历将每个参数注入值栈栈顶属性中
        for (Map.Entry<String, Object> entry : acceptableParameters.entrySet()) {
            String name = entry.getKey();
            Object value = entry.getValue();
            try {
                //3.4 将参数注入值栈栈顶属性中
                newStack.setParameter(name, value);
            } catch (RuntimeException e) {
                if (devMode) {
                    String developerNotification = LocalizedTextUtil.findText(ParametersInterceptor.class, "devmode.notification", ActionContext.getContext().getLocale(), "Developer Notification:\n{0}", new Object[]{
                             "Unexpected Exception caught setting '" + name + "' on '" + action.getClass() + ": " + e.getMessage()
                    });
                    LOG.error(developerNotification, e);
                    if (action instanceof ValidationAware) {
                        ((ValidationAware) action).addActionMessage(developerNotification);
                    }
                }
            }
        }

        if (clearableStack && (stack.getContext() != null) && (newStack.getContext() != null))
            stack.getContext().put(ActionContext.CONVERSION_ERRORS, newStack.getContext().get(ActionContext.CONVERSION_ERRORS));

        addParametersToContext(ActionContext.getContext(), acceptableParameters);
    }
 

 

PrepareInterceptor拦截器

 

作用:为ModelDrivenInterceptor拦截器准备/创建准备压入值栈栈顶的对象。

源码:

 

 

    @Override
    public String doIntercept(ActionInvocation invocation) throws Exception {
        //1. 获取请求action
        Object action = invocation.getAction();
        //2. 判断请求Action是否实现Preparable接口
        if (action instanceof Preparable) {
            try {
                String[] prefixes;
                //3. 判断先执行目标方法的prepareDoXxx方法还是prepareXxx,这两个方法只执行一个,默认执行prepareXxx方法
                if (firstCallPrepareDo) {
                    prefixes = new String[] {ALT_PREPARE_PREFIX, PREPARE_PREFIX};
                } else {
                    prefixes = new String[] {PREPARE_PREFIX, ALT_PREPARE_PREFIX};
                }
                PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes);
            }
            catch (InvocationTargetException e) {
                /*
                 * The invoked method threw an exception and reflection wrapped it
                 * in an InvocationTargetException.
                 * If possible re-throw the original exception so that normal
                 * exception handling will take place.
                 */
                Throwable cause = e.getCause();
                if (cause instanceof Exception) {
                    throw (Exception) cause;
                } else if(cause instanceof Error) {
                    throw (Error) cause;
                } else {
                    /*
                     * The cause is not an Exception or Error (must be Throwable) so
                     * just re-throw the wrapped exception.
                     */
                    throw e;
                }
            }
            //4. 判断是否执行action类实现的prepare方法,默认执行
            if (alwaysInvokePrepare) {
                ((Preparable) action).prepare();
            }
        }

        return invocation.invoke();
    }
 

 

配置:可以通过以下配置改变此拦截器中和属性的默认值,其他方式可以查阅struts2文档。

 

 

    <package name="employee-manage-v4" extends="struts-default">
    
                <!-- 配置使用 paramsPrepareParamsStack 作为默认的拦截器栈 -->
		<!-- 修改 PrepareInterceptor 拦截器的 alwaysInvokePrepare 属性值为 false,Struts2将不执行Preparable接口的prepare方法 -->
		<interceptors>
		    <interceptor-stack name="rabbitx-paramsPrepareParamsStack">
		        <interceptor-ref name="paramsPrepareParamsStack">
                            <!--使用拦截器在struts.xml中配置的name的值加点号再加属性值的方式设置属性的值-->
		            <param name="prepare.alwaysInvokePrepare">false</param>
		            <param name="prepare.firstCallPrepareDo">true</param>
		        </interceptor-ref>
		    </interceptor-stack>
		</interceptors>
 
		<default-interceptor-ref name="rabbitx-paramsPrepareParamsStack"/>
		
        <action name="employee-v4-*"
                class="org.rabbitx.web.struts2.paramsPrepareParamsStack.action.v4.EmployeeAction"
                method="{1}">
            <result name="{1}">/v4/{1}.jsp</result>
            <result name="success" type="redirectAction">employee-v4-view</result>
        </action>
        
    </package>
 

 

 

ModelDrivenInterceptor拦截器

作用:把PrepareInterceptor拦截器准备好的或其他方式准备好的对象压入值栈栈顶。

源码:

 

 

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        //1. 获取请求Action对象
        Object action = invocation.getAction();
        //2. 判断Action对象是否实现ModelDriven接口
        if (action instanceof ModelDriven) {
            ModelDriven modelDriven = (ModelDriven) action;
            //3. 获取值栈
            ValueStack stack = invocation.getStack();
            //4. 获取Action对象中创建好的对象;
            Object model = modelDriven.getModel();
            if (model !=  null) {
                //5. 把对象压入值栈栈顶
            	stack.push(model);
            }
            if (refreshModelBeforeResult) {
                invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
            }
        }
        return invocation.invoke();
    }
 

 

 

拦截器栈paramsPrepareParamsStack执行流程

 

下面以员工管理案例中修改用户信息为例分析拦截器栈paramsPrepareParamsStack的处理流程:

 

<interceptor-stack name="paramsPrepareParamsStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="alias"/>
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="multiselect"/>
                <interceptor-ref name="params">
                    <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</param>
                </interceptor-ref>
                <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">
                    <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</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-stack>

  

01) 用户点击编辑按钮发送employee-v4-edit.action?id=10001请求;

02) params拦截器把请求参数id:10001注入到EmployeeAction对象的属性id中;

03) prepare拦截器调用EmployeeAction的edit对应的prepare方法perpareEdit,此方法根据id获取Employee对象并赋值给EmployeeAction的employee属性;

04) modelDriven拦截器把赋值好的employee对象压入值栈栈顶;

05) params拦截器把请求参数id:10001注入到employee对象的id属性中(此步骤无意义);

06) 拦截器执行完毕;

07) 执行对应action[EmployeeAction]方法edit;

08) 返回edit.jsp,页面根据栈顶对象employee的属性值回填表单;

 

到此,一个完整的paramsPrepareParamsStack拦截器栈执行流程完毕。

 

分享到:
评论

相关推荐

    Gromacs中文手册5.0.2.pdf

    Gromacs中文手册5.0.2

    tensorflow_transform-0.1.0-py2-none-any.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    tensorflow_recommenders-0.3.1-py3-none-any.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    python冒泡排序(Bubble Sort).docx

    python冒泡排序(Bubble Sort) 冒泡排序(Bubble Sort)是一种简单的排序算法。它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。 以下是一个用Python实现的冒泡排序的例子: ```python def bubble_sort(lst): n = len(lst) for i in range(n): # 创建一个标记,用于优化 swapped = False # 遍历所有未排序的元素 for j in range(0, n-i-1): # 交换相邻元素,如果它们的顺序错误 if lst[j] > lst[j+1] : lst[j], lst[j+1] = lst[j+1], lst[j] swapped = True # 如果在内循环中没有交换

    A1_SSE_123090177.py

    A1_SSE_123090177.py

    asp代码ASP基于WEB的商场管理系统的设计与实现(源代码+论文)

    asp代码ASP基于WEB的商场管理系统的设计与实现(源代码+论文)本资源系百度网盘分享地址

    tensorflow_onmttok_ops-0.2.0-cp35-cp35m-manylinux2014_x86_64.whl

    算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    三菱PLC例程源码S2401佑倡油压机

    三菱PLC例程源码S2401佑倡油压机本资源系百度网盘分享地址

    Modown v4.3资源下载WordPress主题

    Modown是模板兔基于Erphpdown wordpress下载插件开发的一款全新的针对收费付费下载资源的WordPress主题,一款为erphpdown而生的wp主题。此主题不包含erphpdown插件(免激活版)价值199元。注意在其他地方购买可能不包含插件,还要自己去购买插件,而且不一定是免激活版。 自适应响应式设计,兼容主流浏览器 网格样式与瀑布流样式任意切换 自带与主题UI完美兼容搭配的erphpdown前端用户中心页面(此功能若单独找我们定制也需要几百) 首页banner处可以换成幻灯片、增加搜索框、按钮等 分类多重筛选(每个分类的筛选标签可自定义) 自定义文章类型(博客或教程等等),文章列表显示 一键社交账号登录,自定义的登录注册找回密码页面模板(含验证码) 多个小工具以及页面模板(前端投稿页面) CMS式首页模板(显示多个分类板块,可子分类筛选) Ajax无刷新评论 集成ckplayer视频播放器(使用短代码 [ckplayer]视频地址[/ckplayer]) 外链特色图片,列表页文章图片可自定义高度 文章单栏与双栏切换,可点赞收藏 特点说多了等于扯淡,惊喜等你来

    python冒泡排序.md

    python冒泡排序 冒泡排序的时间复杂度为O(n^2),其中n是列表的长度。这是因为对于每个元素,我们可能需要与其后面的所有元素进行比较和交换。尽管冒泡排序在某些情况下可能不是最优的选择,特别是当处理大型数据集时,但它易于理解和实现,对于初学者来说是一个很好的起点。 值得注意的是,冒泡排序在最好的情况下(即列表已经排序)的时间复杂度为O(n),但这种情况很少发生。通常,我们讨论冒泡排序的时间复杂度时,我们指的是其平均和最坏情况,即O(n^2)。 冒泡排序的一个优化是,如果在一次遍历中没有发生任何交换,那么列表已经排序完成,我们可以提前终止算法。这可以避免不必要的比较和交换操作。下面是优化后的冒泡排序代码:

    理工科研究生简历模板,美观且信息量足

    春招秋招应届生必备,美观大方排版好看简历模板,需要word版本或者需要简历指导可以私。

    基于深度学习的USPS手写体识别模型.zip

    人工智能毕业设计&课程设计

    基于PaddleOCR重构,并且脱离PaddlePaddle深度学习训练框架的OCR.zip

    人工智能毕业设计&课程设计

    asp代码ASP基于WEB网上聊天室设计(源代码+论文)

    asp代码ASP基于WEB网上聊天室设计(源代码+论文)本资源系百度网盘分享地址

    三菱PLC例程源码层绕机

    三菱PLC例程源码层绕机本资源系百度网盘分享地址

    三菱PLC例程源码YX细伸拉丝机三菱FXPLC程序(有注解)张力控制与传统的指拔开关不一样

    三菱PLC例程源码YX细伸拉丝机三菱FX PLC程序(有注解)张力控制与传统的指拔开关不一样本资源系百度网盘分享地址

    三菱PLC例程源码pp復卷機三菱伺服編程

    三菱PLC例程源码pp復卷機三菱伺服編程本资源系百度网盘分享地址

    基于ssm+web的微博网站.zip

    基于ssm+web的微博网站.zip

    基于深度学习的口罩佩戴检测,Keras-YOLOv3 实现。.zip

    人工智能毕业设计&课程设计

    tensorflow_privacy-0.2.2-py3-none-any.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

Global site tag (gtag.js) - Google Analytics