【问题标题】:Skip validation for certain fields in Struts2跳过对 Struts2 中某些字段的验证
【发布时间】:2013-12-28 18:09:22
【问题描述】:

比如有一个action类如下。

@Namespace("/admin_side")
@ResultPath("/WEB-INF/content")
@InterceptorRefs({@InterceptorRef(value="defaultStack", params={"validation.excludeMethods", "load"})})
public final class TestAction extends ActionSupport implements Serializable, ValidationAware, ModelDriven<Transporter>
{
    @Autowired
    private final transient TransporterService transporterService=null;
    private static final long serialVersionUID = 1L;

    private Boolean deleteOneRow=false; //Getter and setter.
    private Transporter entity=new Transporter(); //Getter and setter.
    private List<Transporter>transporters=new ArrayList<Transporter>();
    private String message; //Getter and setter.
    private List<Long>chk; //Getter and setter.

    @Action(value = "Transporter", results = {@Result(name=ActionSupport.SUCCESS, location="Transporter.jsp"), @Result(name = ActionSupport.INPUT, location = "Transporter.jsp")})
    public String load() throws Exception
    {
        return ActionSupport.SUCCESS;
    }

    @Validations(
            requiredStrings={
                @RequiredStringValidator(fieldName="transporterName", type= ValidatorType.FIELD, key = "transporter.name.required"),
                @RequiredStringValidator(fieldName="transporterWebsite", type= ValidatorType.FIELD, key = "transporter.website.required")},
            stringLengthFields={
                @StringLengthFieldValidator(fieldName="transporterName", type= ValidatorType.FIELD, minLength="2", maxLength="45", key="transporter.name.length", messageParams={"2", "45"}),
                @StringLengthFieldValidator(fieldName="transporterWebsite", type= ValidatorType.FIELD, minLength="10", maxLength="1000", key="transporter.website.length", messageParams={"10", "1000"})})
    @Action(value = "addTransporter",
        results = {@Result(name=ActionSupport.SUCCESS, type="redirectAction", location="Transporter.jsp", params={"namespace", "/admin_side", "actionName", "Transporter", "message", "${message}"}),
        @Result(name = ActionSupport.INPUT, location = "Transporter.jsp")},
        interceptorRefs={@InterceptorRef(value="defaultStack", params={"params.acceptParamNames", "transporterName, transporterWebsite", "validation.validateAnnotatedMethodOnly", "true"})})
    public String insert()
    {
        if(entity.getTransporterId()==null)
        {
            transporterService.insert(entity.getTransporterName(), entity.getTransporterWebsite());
            setMessage(getText("insert.success"));
        }
        else
        {
            setMessage(transporterService.update(entity)?getText("update.success", new String[]{String.valueOf(entity.getTransporterId())}) :getText("update.failed", new String[]{String.valueOf(entity.getTransporterId())}));
        }
        return ActionSupport.SUCCESS;
    }

    @Validations(requiredFields={@RequiredFieldValidator(fieldName="transporterId", type= ValidatorType.FIELD, key = "delete.id.missing")})
    @Action(value = "editTransporter",
            results = {
                @Result(name=ActionSupport.SUCCESS, location="Transporter.jsp"),
                @Result(name = ActionSupport.INPUT, location = "Transporter.jsp")},
            interceptorRefs={
                @InterceptorRef(value="defaultStack", params={"params.acceptParamNames", "transporterId, transporterName, transporterWebsite", "validation.validateAnnotatedMethodOnly", "true"}),
                @InterceptorRef(value="conversionError")})
    public String edit()
    {
        return ActionSupport.SUCCESS;
    }

    @Action(value = "deleteTransporter",
            results = {
                @Result(name=ActionSupport.SUCCESS, type="redirectAction", location="Transporter.action", params={"message", "${message}"}),
                @Result(name = ActionSupport.INPUT, location = "Transporter.jsp")},
            interceptorRefs={
                @InterceptorRef(value="defaultStack", params={"params.acceptParamNames", "transporterId, deleteOneRow", "validation.validateAnnotatedMethodOnly", "true"}),
                @InterceptorRef(value="conversionError")})
    public String deleteTransporter()
    {
        if(transporterService.delete(entity.getTransporterId()))
        {
            //Pagination has not not yet been implemented. Hence, it is static.
            transporters=transporterService.getList(0, 20); 
            setMessage(getText("delete.success", new String[]{String.valueOf(entity.getTransporterId())}));
        }
        else
        {
            setMessage(getText("delete.failed", new String[]{String.valueOf(entity.getTransporterId())}));
        }
        return ActionSupport.SUCCESS;
    }

    @Action(value = "deleteTransporters",
            results = {
                @Result(name=ActionSupport.SUCCESS, type="redirectAction", location="Transporter.jsp", params={"namespace", "/admin_side", "actionName", "Transporter", "message", "${message}"}),
                @Result(name = ActionSupport.INPUT, location = "Transporter.jsp")},
            interceptorRefs={
                @InterceptorRef(value="defaultStack", params={"params.acceptParamNames", "chk", "validation.validateAnnotatedMethodOnly", "true"}),
                @InterceptorRef(value="conversionError")})
    public String deleteTransporters()
    {
        setMessage(transporterService.delete(chk)?getText("delete.multiple.success", new String[]{String.valueOf(chk.size())}) :getText("delete.multiple.failed"));
        return ActionSupport.SUCCESS;
    }

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

    public List<Transporter> getTransporters()
    {
        if(CollectionUtils.isEmpty(transporters))
        {
            //Pagination has not not yet been implemented. Hence, it is static.
            transporters=transporterService.getList(0, 20);
        }
        return transporters;
    }

    public void setTransporters(List<Transporter> transporters) {
        this.transporters = transporters;
    }

    @Override
    public void validate(){}
}

JSP 页面:

<s:form namespace="/admin_side" action="Transporter" id="dataForm" name="dataForm" cssClass="search_form general_form">
    <s:if test="hasFieldErrors()">
        <s:fielderror fieldName="transporterId"/>
        <s:fielderror fieldName="chk"/>
    </s:if>

    <s:property value="message"/>
    <s:hidden id="transporterId" name="transporterId"/>
    <s:hidden id="deleteOneRow" name="deleteOneRow"/>

   <s:textfield id="transporterName" name="transporterName"/><s:fielderror fieldName="transporterName"/>
   <s:textfield id="transporterWebsite" name="transporterWebsite"/><s:fielderror fieldName="transporterWebsite"/>
   <s:submit id="btnSubmit" name="btnSubmit" value="Submit" action="addTransporter"/>

   <table cellpadding="0" cellspacing="0" width="100%">
        <tbody>
            <tr class="even">
                <th style="width: 96px;">Check</th>
                <th style="width: 96px;">Id</th>
                <th style="width: 96px;">Transporter</th>
                <th style="width: 96px;">Website</th>
                <th style="width: 96px;">Actions</th>
            </tr>
            <s:iterator value="transporters" status="loopStatus">
                <tr class="<s:if test="#loopStatus.odd == true ">first</s:if> <s:else>second</s:else>">
                    <td><s:checkbox name="chk" fieldValue="%{transporterId}" value="false"/></td>
                    <td><s:property value="transporterId" /></td>
                    <td><s:property value="transporterName" /></td>
                    <td>
                        <a href="<s:property value="transporterWebsite" />">Visit</a>
                    </td>
                    <td>
                        <div class='actions'>
                            <ul>
                                <li>
                                    <s:url id="editURL" action="editTransporter" escapeAmp="false">
                                        <s:param name="transporterId" value="%{transporterId}"/>
                                        <s:param name="transporterName" value="%{transporterName}"/>
                                        <s:param name="transporterWebsite" value="%{transporterWebsite}"/>
                                    </s:url>
                                    <s:a href="%{editURL}" cssClass="action2"/>
                                </li>

                                <li>
                                    <s:url id="deleteURL" action="deleteTransporter" escapeAmp="false">
                                        <s:param name="transporterId" value="%{transporterId}"/>
                                        <s:param name="deleteOneRow" value="%{deleteOneRow}"/>
                                    </s:url>
                                    <s:a href="%{deleteURL}" onclick="return deleteOne(%{transporterId});" cssClass="action4"/>
                                </li>
                            </ul>
                        </div>
                    </td>
                </tr>
            </s:iterator>
        </tbody>
    </table>

<s:submit name="btnDelete" id="btnDelete" action="deleteTransporters" onclick="return getCheckedRows();" />

insert() 方法接受两个参数,transporterNametransporterWebsiteedit() 方法只接受一个参数 transporterId,当单击链接时,该参数作为查询字符串提供。

insert() 方法由&lt;s:submit&gt; 的操作映射,而edit() 方法由&lt;s:url&gt; 的操作映射,其id 被赋予&lt;s:a&gt;href 属性。

当点击编辑链接 &lt;s:a&gt; 时,文本字段 transporterNametransporterWebsite 都被不必要地验证,这在编辑时不能发生,即当编辑链接时,对这些文本字段的验证应该被跳过/禁用被点击。

只有被edit() 方法接受的transporterId 应该被验证。单击编辑链接时,不应验证其他字段。

在这种情况下,注释 @SkipValidation 将不起作用。

如何做到这一点?

【问题讨论】:

  • 我已经编辑了帖子以包含完整的代码。
  • 您如何检查其他字段是否已经过验证?
  • 编辑后验证标准略有变化(我已实现ModelDriven&lt;Transporter&gt;)。例如,在此示例中,它可以防止创建新行以不必要地验证 transporterId,这仅在编辑 &lt;table&gt; 中的行时需要,而不是在创建新行时需要。同样,在删除多行时(JSP 代码中的最后一行 &lt;s:submit&gt;),文本字段 transporterNametransporterWebsite 以及 transporterId 都经过验证,以防止删除不应删除的选定行不再发生。
  • transporterNametransporterWebsitetransporterId 在删除单行时也会得到验证。关于 Spring MVC,这不会发生。如果从参数的接受列表中删除了一个参数,那么对该字段的验证也将被删除。该字段随后未验证。同样的事情应该适用于 Struts,但 Struts 似乎并非如此。
  • 我看到您正在使用客户端验证和服务器端验证,但无法确定哪个不起作用?

标签: java validation struts2


【解决方案1】:

这是因为我在定义的类级别验证拦截器中缺少validateAnnotatedMethodOnly

当我将类定义修改为以下内容时,它起作用了。

@Namespace("/admin_side")
@ResultPath("/WEB-INF/content")
@InterceptorRefs({@InterceptorRef(value="defaultStack", params={"validation.validateAnnotatedMethodOnly", "true", "validation.excludeMethods", "load"})})
public final class TestAction  extends ActionSupport implements Serializable, ValidationAware, ModelDriven<Transporter>
{
    //...
}

我在方法级别包含validation.validateAnnotatedMethodOnly,但忘记在类级别包含它。

只用@SkipValidation注释动作类中的load()方法并完全消除类级别的@InterceptorRefs注释也是合适的。


来自documentation

当使用多种方法将不同的动作映射到同一个 类,其中一个用@Validations注释,那些 所有操作都会触发验证器,除非它们是 设置了@SkipValidationvalidateAnnotatedMethodOnly 注释 在validation 拦截器中为真,例如:

<interceptor-ref name="validation">
    <param name="validateAnnotatedMethodOnly">true</param>
    <param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>

【讨论】:

  • 类上的注解按照约定应用于类中的所有动作。
猜你喜欢
  • 1970-01-01
  • 2011-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多