4

假设以下动作类。

@Namespace("/admin_side")
@ResultPath("/WEB-INF/content")
@ParentPackage(value="struts-default")
public final class TestAction extends ActionSupport implements Serializable, ValidationAware, Preparable
{
    private Long currentPage=1L;

    //This method is called on page load. 
    //Validation is skipped, location is set to a valid action, not "redirectAction", the request is dispatched. 
    //It is mapped to an action of <s:form>.
    public String load() throws Exception
    {
        //Nothing to see here. Leave it empty.
        return ActionSupport.SUCCESS;
    }

    //Assuming necessary validators and action whose result type is set to "redirectAction". 
    //It is mapped to an action of <s:submit>.
    public String insert()
    {
        //Do something to either add or update data in a model based on a conditional check.
        return ActionSupport.SUCCESS;
    }

    //Assuming necessary validators and action whose loction is set to a valid action. not "redirectAction". 
    //The request is dispatched/forwarded. 
    //It is mapped to an action of <s:a>.
    public String edit()
    {
        //Nothing to see here. Leave it empty.
        return ActionSupport.SUCCESS;
    }

    //Assuming necessary validators and action whose result type is set to "redirectAction". 
    //It is mapped to an action of <s:submit>.
    public String delete()
    {
        //Do something to delete data from a model.
        return ActionSupport.SUCCESS;
    }

    @Override
    public void prepare() throws Exception
    {
        list= service.getList((int)(currentPage-1)*pageSize, pageSize);
    }
}

我排除了注释和其他东西以避免代码噪音。映射到这些方法的操作使用paramsPrepareParamsStack拦截器。

在这里,当一个与方法关联的动作insert()被触发时(它由 完成<s:submit>),结果将是重定向动作。因此,将创建动作类的新实例,该实例导致load()方法被执行,这反过来又导致该prepare()方法再次被执行。更新和删除时也会发生同样的事情。

prepare()方法首先在与<s:submit>(or <s:link>) 关联的动作被触发时立即执行,然后在请求被重定向时再次执行(这可以理解,因为请求的重定向导致创建动作类的新实例,从而导致关联的动作与load()要执行的方法并prepare()在每个动作上执行一次)。

prepare()方法中唯一的一行具有昂贵的操作。为了防止该getList()方法被执行两次,我做了一些条件检查,如下所示。

@Override
public void prepare() throws Exception
{
    String actionName = ActionContext.getContext().getName();
    if(actionName.equals("load")||actionName.equals("edit"))
    {
        list= service.getList((int)(currentPage-1)*pageSize, pageSize);
    }
}

这种方法可能有更多的条件检查和复杂的代码。

这样做仍然不够。如果由于条件而发生任何验证/转换错误,则不会初始化列表。没有hasErrors()hasActionErrors()并且hasFieldErrors()prepare()在任何错误后在方法中评估为真。这需要在validate()方法中加载列表,如下所示。

@Override
public void validate()
{
    if(hasErrors())
    {
        list= service.getList((int)(currentPage-1)*pageSize, pageSize);
    }
}

这现在满足了要求,但看起来非常难看,有这样的条件检查,不能被认为是一个好方法。

有没有更好的方法来保证在请求执行插入、更新、删除等操作后从数据库中检索列表只发生一次?

它应该与每个请求在后台执行多少操作无关。尽管存在一些转换/验证错误,但应仅在请求完成之前检索该列表一次事件。

@Before, @BeforeResult,@After注释似乎都不能解决这种情况。


在旨在检索/初始化列表的方法中使用此类代码validate()似乎不是一个好习惯。

我希望在CRUD 操作之后有一种方法可以获取此列表。由于从数据库中获取此列表的成本很高,因此该列表应仅在每个操作(插入、编辑、更新、删除)完成后初始化一次。

4

1 回答 1

3

prepare()为每个操作执行的方法中执行操作,诸如填充列表之类的繁重操作不是一个好方法。因为并不是所有的动作都需要执行这样的操作。

但是当与验证一起使用时,根本不会执行任何操作。如果发生验证错误,INPUT则返回结果。此结果是dispatcher您的用例中的结果,它需要在执行此结果之前填充列表。

在方法结束并返回结果之前,您正在validate方法中手动检查验证错误,然后重新填充列表。validateINPUT

这个逻辑已经被workflow拦截器实现了,它是defaultStack. 您可以将此拦截器配置为在发生验证错误时调用方法。在这种方法中,您可以重新填充列表。

public String input() throws Exception {
  list = service.getList((int)(currentPage-1)*pageSize, pageSize);
  return INPUT;
}

workflow现在,您应该通过在 crud 方法中添加注释来配置此方法以与拦截器一起使用insert()delete().

@InputConfig(methodName="input")

edit()andload()方法中,如果操作返回调度程序结果,您可以input()手动调用,可能与结果相同的位置INPUT

于 2014-01-26T12:39:46.807 回答