6

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

<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>

动作类如下。

@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

我究竟做错了什么?

4

2 回答 2

6

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

来自ParametersInterceptor 文档

缺少参数的警告

当给定参数名称没有设置器时,将在 devMode 中记录如下警告消息:

SEVERE: Developer Notification (set struts.devMode to false to disable this 
message):
Unexpected Exception caught setting 'search' on 'class demo.ItemSearchAction: 
Error setting expression 'search' with value ['search', ]
Error setting expression 'search' with value ['search', ] - [unknown location] 
  at com.opensymphony.xwork2.ognl.OgnlValueStack.handleRuntimeException(OgnlValueStack.java:201)
  at com.opensymphony.xwork2.ognl.OgnlValueStack.setValue(OgnlValueStack.java:178)
  at com.opensymphony.xwork2.ognl.OgnlValueStack.setParameter(OgnlValueStack.java:152)

因此,预期行为允许开发人员在参数名称或 setter 中发现缺少的 setter 或拼写错误。

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

由于模型中存在您的属性(及其设置器),并且您正在使用ModelDrivenand paramsPrepareParamsStack,我认为正在发生的事情是:

  • ModelDriven Interceptor被委托处理模型对象;
  • 第一次调用Parameters InterceptorModelDriven Interceptor还没有运行;
  • 然后您的 Action 对 Model 对象一无所知,并尝试在 Action 中而不是在 Model 中查找参数的 Setter。
  • 第二个拦截器在 ModelDriven 之后运行,并且确切地知道在哪里设置参数。这就是您在 Action 方法中正确设置参数的原因。

但如果这是真的,那么您应该无法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>

希望有帮助。

于 2014-01-09T13:05:49.370 回答
0

在您提供的代码中,我找不到 Transporter 类的声明。

所以我想这可能是因为您的 Transpoter 类的参数多于 2 个,而不仅仅是 id 和 name。

事实上,这个错误信息总是出现在我提到的情况下。

为了解决这个问题,你可以定义一个只有 id 和 name 两个属性的数据传输对象(DTO)。使用此 DTO 接受来自 jsp 的参数,然后将属性值传递给 Transporter 对象。

我在2019年看到了这个问题,并提供了一个解决方案,希望将来可以被其他人使用。

于 2019-04-16T21:44:59.463 回答