在Struts2中的action()方法中执行动作类中的CRUD操作

时间:2014-01-08 14:55:39

标签: java validation struts2 crud struts2-interceptors

假设有以下动作类。

@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>)相关联的操作被触发,就会首先执行<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操作之后获取此列表。由于从数据库中获取此列表的成本很高,因此在 每个操作(插入,编辑,更新,删除)完成后,只应初始化此列表。

1 个答案:

答案 0 :(得分:3)

执行为每个操作执行的prepare方法,诸如填充列表之类的繁重操作不是一个好方法。因为并非所有操作都需要执行此类操作。但是当与验证一起使用时,根本不执行任何操作。如果发生验证错误,则返回INPUT结果。此结果是您的用例中的dispatcher结果,并且需要在执行此结果之前填充列表。在validate方法结束并返回validate结果之前,您正在使用INPUT方法手动检查验证错误,然后重新填充列表。这个逻辑已经由workflow拦截器实现,defaultStack拦截器是public String input() throws Exception { list = service.getList((int)(currentPage-1)*pageSize, pageSize); return INPUT; } 的成员。您可以配置此拦截器以在发生验证错误时调用方法。在此方法中,您可以重新填充列表。

workflow

现在,您应该将此方法配置为与insert()拦截器一起使用,方法是将注释放入您的crud方法delete()@InputConfig(methodName="input")

edit()

load()input()方法中,如果操作返回调度程序结果,则可以手动调用INPUT,可能与{{1}}结果位置相同。