Struts2 的 Preparable, ModelDriven 接口方法里无法获得参数,理解 拦截器与责任链

动作类实现了 Preparable,ModelDriven 这两个接口,但是却无法在其方法 prapare 和 getModel 方法里获得 其它参数,进而无法根据其它参数来查询数据库。

在 prapare,getModel 这两个方法都断点了,显示执行顺序为 prapare——》 getModel,但是其它参数(如 categoryId (有对应的get / set 方法)JSP 页面上已确定没有写错。

一、业务场景:

自己想要的结果是:先根据 参数 categoryId 来查询数据库,

public void prepare() throws Exception {
		// 前端传递了参数,表示 需要 查看详细属性
		if( categoryId !=null ) {
			//查询数据库 该类对应的 Java 类名,因为 不同种类的属性差异很大,必须获得 对应的 类
			String detailsClassName = categoryService.getDetailsClassName(categoryId);
			// 安全起见:只允许加载 com.jian.vo 包下的 类
			if(detailsClassName !=null && detailsClassName.startsWith("com.jian.vo") ) {
				try {
					itemInfo = Class.forName(detailsClassName).newInstance();
					logger.info("顾客需要浏览商品详情:" + itemInfo.getClass().getName() );
				} catch (InstantiationException | IllegalAccessException
						| ClassNotFoundException e) {
					logger.error("没有对应的 VO 类:" + detailsClassName );
					e.printStackTrace();
				}
			}
		}else {
			itemInfo = new ItemBaseInfoVO();
		}
	}
	@Override
	public Object getModel() {
		// 让模型 去接收 前端传递过来的 参数,最后保存这个模型即可
		return itemInfo;
	}
但是 categoryId 的值却为 null,这就导致 查询数据库失败,后者无法查到正确值。



二、分析:

(1)因为方法执行顺序为:prapare——》getModel,并且参数没有获得,所以拦截器执行的执行顺序为:prapare——》modelDriven——》params。

默认的拦截器栈为 defaultStack( 因为 struts2 配置文件里 的 package 设置 extends="struts-default" ,在 struts-core.jar 包下的 struts-default.xml 配置文件里有 设置

 <default-interceptor-ref name="defaultStack"/> )。

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">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-ref name="debugging"/>
            </interceptor-stack>


这里验证了 拦截器的先后顺序为:prepare——》modelDriven——》params,所以方法的先后顺序为:prapare——》getModel——》setXXX(属性),所以 categoryId 为空值

(2)解决之道:

调整 拦截器的先后顺序:params——》prepare——》modelDrive,去 struts-core.jar 里的 struts-default.xml 搜索 符合这要求得 拦截器执行栈,(*^__^*) 嘻嘻……还真发现了有这一执行栈: 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>
最后在 自个的 struts.xml 配置文件里的 引用这个 执行栈: paramsPrepareParamsStack

<struts>
	
	<package name="normal" namespace="/" extends="struts-default">
		
		<!-- 因为需要根据 参数来查询数据库,所以不再使用 defaultStack
				原因是拦截器执行顺序为:prepare—》modelDriven—》params
				参数还不能获取,params拦截器被排在了后面
				所以改用其他拦截器栈,执行顺序改为:params—》prepare—》modelDriven
		 
		<default-interceptor-ref name="paramsPrepareParamsStack"/>
		-->
		<!-- 没有匹配的动作时,默认跳转到首页 -->
		<default-action-ref name="homePage" />
		
		<action name="homePage" method="welcome" class="homeAction">
			<result name="success" >/jsp/home/HomeLayout.jsp</result>
		</action>

最后:

感知到了 Struts2 的优良设计,把一些功能模块划分成拦截器,也渐渐理解了 责任链模式的 解耦合,谢谢Struts2 作者 的无私奉献!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值