我正在通过查询字符串将一些参数传递给实现ModelDriven<Transporter>的 Action 类。

<s:form namespace="/admin_side" action="Test" id="dataForm" name="dataForm">
    <s:url id="editURL" action="EditTest" escapeAmp="false">
        <s:param name="transporterId" value="1"/>
        <s:param name="transporterName" value="'DHL'"/>
    </s:url>
    <s:a href="%{editURL}">Click</s:a>
</s:form>

Action 类如下。

@Namespace("/admin_side")
@ResultPath("/WEB-INF/content")
@ParentPackage(value = "struts-default")
public final class TestAction extends ActionSupport
                           implements Serializable, Preparable, ModelDriven<Transporter>
{
    private static final long serialVersionUID = 1L;
    private Transporter transporter = new Transporter();

    @Action(value = "Test",
    results = {
        @Result(name = ActionSupport.SUCCESS, location = "Test.jsp"),
        @Result(name = ActionSupport.INPUT, location = "Test.jsp")},
    interceptorRefs = {
        @InterceptorRef(value = "paramsPrepareParamsStack",
                 params = {"params.acceptParamNames", "transporterId, transporterName"})})
    public String load() throws Exception {
        return ActionSupport.SUCCESS;
    }

    @Action(value = "EditTest",
    results = {
        @Result(name = ActionSupport.SUCCESS, location = "Test.jsp"),
        @Result(name = ActionSupport.INPUT, location = "Test.jsp")},
    interceptorRefs = {
        @InterceptorRef(value = "paramsPrepareParamsStack",
                 params = {"params.acceptParamNames", "transporterId, transporterName"})})
    public String edit() {
        System.out.println(transporter.getTransporterId()
                         + " : " + transporter.getTransporterName());
        return ActionSupport.SUCCESS;
    }

    @Override
    public Transporter getModel() {
        return transporter;
    }

    @Override
    public void prepare() throws Exception {}
}

服务器终端显示以下消息。

Jan 09, 2014 4:06:32 PM com.opensymphony.xwork2.interceptor.ParametersInterceptor error
SEVERE: Developer Notification (set struts.devMode to false to disable this message):
Unexpected Exception caught setting 'transporterId' on 'class actions.TestAction: Error setting expression 'transporterId' with value ['1', ]
Jan 09, 2014 4:06:32 PM com.opensymphony.xwork2.interceptor.ParametersInterceptor error
SEVERE: Developer Notification (set struts.devMode to false to disable this message):
Unexpected Exception caught setting 'transporterName' on 'class actions.TestAction: Error setting expression 'transporterName' with value ['DHL', ]

即使日志级别为SEVERE,这些参数的值也可以在操作类中以

System.out.println(transporter.getTransporterId()
                 + " : " + transporter.getTransporterName());

edit()方法中。

如果将paramsPrepareParamsStack替换为defaultStack,则这些消息将消失。

['DHL', ]这样的表达式表示一个数组。但是,模型中的transporterIdtransporterName分别为LongString类型。

我究竟做错了什么?

最佳答案

这里不涉及数组问题(即使看起来像这样):这种异常意味着Struts找不到参数的Setter:

ParametersInterceptor documentation:



通过将JSP中不存在的元素放入Action中,可以轻松地重现此错误。

由于您的属性在模型中存在(及其 setter ),并且您正在使用ModelDrivenparamsPrepareParamsStack,所以我认为是:

  • ModelDriven Interceptor被委托(delegate)处理Model对象;
  • 第一次调用Parameters Interceptor时,ModelDriven Interceptor尚未运行。
  • 然后,您的操作对Model对象一无所知,并尝试在Action中找到参数的Setter,而不是在Model中。
  • 相反,第二个拦截器在ModelDriven拦截器之后运行,并且确切知道在哪里设置参数。这就是为什么要在Action方法中正确设置参数的原因。

  • 但是,如果这是真的,那么您应该 NOT 能够在prepare()方法中检索那些参数(这就是您使用此堆栈的原因...):请尝试,然后将结果发布在此处。

    解决此问题的第一件事是将ModelDriven Interceptor放在第一个Parameters Interceptor之前(通过复制或移动它,我不确定它会产生哪种副作用(如果有)在这两种情况下,您都应再次尝试并在此处进行报告)。

    然后定义以下堆栈,并使用它。

    <interceptor-stack name="modelParamsPrepareParamsStack">
        <interceptor-ref name="exception"/>
        <interceptor-ref name="alias"/>
        <interceptor-ref name="i18n"/>
        <interceptor-ref name="checkbox"/>
        <interceptor-ref name="multiselect"/>
    
        <!-- NEW ModelDriven Position -->
        <interceptor-ref name="modelDriven"/>
    
        <interceptor-ref name="params">
            <param name="excludeParams">^dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,^parameters\..*,^action:.*,^method:.*</param>
        </interceptor-ref>
        <interceptor-ref name="servletConfig"/>
        <interceptor-ref name="prepare"/>
        <interceptor-ref name="chain"/>
    
        <!-- OLD ModelDriven Position -->
        <!--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\..*,^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-stack>
    

    希望能有所帮助。

    10-01 00:06