简体   繁体   English

在动作类中执行 CRUD 操作以及 Struts2 中的 prepare() 方法

[英]Performing CRUD operations in an action class along with the prepare() method in Struts2

Assuming the following action class.假设有以下动作类。

@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);
    }
}

I have excuded annotations and other things to avoid code noise.我已经排除了注释和其他东西以避免代码噪音。 The actions mapped to these methods use the paramsPrepareParamsStack interceptor.映射到这些方法的操作使用paramsPrepareParamsStack拦截器。

Here, when an action associated with the insert() method, for example is triggered (it done by <s:submit> ), the result will be redirect action.在这里,例如,当与insert()方法关联的操作被触发(由<s:submit> )时,结果将是重定向操作。 Accordingly, a new instance of the action class will be created which causes the load() method to be executed which in turn causes the prepare() method to be executed once again.因此,将创建 action 类的一个新实例,这将导致执行load()方法,这又导致再次执行prepare()方法。 The same thing will happen while updating and deleting.更新和删除时也会发生同样的事情。

The prepare() method is first executed as soon as an action associated with <s:submit> (or <s:link> ) is triggered and then again when the request is redirected (this can be understood because redirection of a request results in creating a new instance of the action class which causes the action associated with the load() method to be executed and prepare() is executed once on every action). prepare()方法在与<s:submit> (或<s:link> )相关联的动作被触发时首先执行,然后在请求重定向时再次执行(这可以理解,因为请求的重定向导致创建 action 类的一个新实例,它会导致执行与load()方法关联的 action,并且prepare()在每个 action 上执行一次)。

The only line inside the prepare() method has costly operations. prepare()方法中的唯一一行是代价高昂的操作。 To prevent the getList() method from being executed twice, I do some conditional checks like as follows.为了防止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);
    }
}

There could be more conditional checks and complex code in this method.在这个方法中可能有更多的条件检查和复杂的代码。

Doing so is still insufficient.这样做还是不够的。 The list will not be initialized, if any validation/conversion error(s) occur(s) because of the condition.如果由于条件而发生任何验证/转换错误,则不会初始化列表。 None of hasErrors() , hasActionErrors() and hasFieldErrors() will be evaluated to true in the prepare() method after any errors. hasErrors()hasActionErrors()hasFieldErrors()都不会在出现任何错误后在prepare()方法中被评估为真。 This requires the list to be loaded inside the validate() method like as follows.这需要将列表加载到validate()方法中,如下所示。

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

This now fulfills the requirements but looks very ugly to have such conditional checks and cannot be considered to be a good approach.这现在满足了要求,但是有这样的条件检查看起来很丑陋,不能被认为是一个好方法。

Is there a better way to have some mechanism that guarantees that the retrieval of the list from the database happens only once after a request to perform operations like insert, update, delete is made?有没有更好的方法来保证在执行插入、更新、删除等操作的请求后,从数据库中检索列表只发生一次?

It should be independent of how many actions are executed behind the scene per request.它应该独立于每个请求在幕后执行的操作数。 The list should be retrieved just before the completion of the request only once event though there are some conversion/validation errors.尽管存在一些转换/验证错误,但应仅在请求完成之前检索列表一次事件。

None of the @Before , @BeforeResult , @After annotations seem to work to get around this situation. @Before@BeforeResult@After注释似乎都@BeforeResult这种情况。


Using such code in the validate() method which is meant to retrieve/initialize a list does not seem to be a good practice.在用于检索/初始化列表的validate()方法中使用此类代码似乎不是一个好习惯。

I expect that there is a way of getting this list after CRUD operations.我希望有一种方法可以CRUD 操作获取此列表。 Since getting this list from the database is costly, this list should be initialized only once after every operation (insert, edit, update, delete) is finished.由于从数据库获取此列表的成本很高,因此该列表应仅每次操作(插入、编辑、更新、删除)完成初始化一次。

Doing in prepare() method which is executed for every action, heavy operation such as populating lists is not a good way.在为每个动作执行的prepare()方法中prepare() ,诸如填充列表之类的繁重操作不是一个好方法。 Because not all actions need to perform such operation.因为并不是所有的动作都需要执行这样的操作。

But when used with validation, no action is executed at all.但是当与验证一起使用时,根本不执行任何操作。 If validation errors are occurred, the INPUT result is returned.如果发生验证错误,则返回INPUT结果。 This result is a dispatcher result in your usecase and it requires the lists to be populated before this result is executed.此结果是您的用例中的dispatcher结果,它需要在执行此结果之前填充列表。

You are doing manual checks in the validate method for validation errors, before the validate method ends and INPUT result is returned, then you repopulate the lists.validate方法结束并返回INPUT结果之前,您正在validate方法中手动检查验证错误,然后重新填充列表。

This logic is already implemented by the workflow interceptor which is a member of defaultStack .此逻辑已由作为defaultStack成员的workflow拦截器实现。 You can configure this interceptor to invoke a method when validation errors occurred.您可以配置此拦截器以在发生验证错误时调用方法。 In this method you can repopulate lists.在此方法中,您可以重新填充列表。

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

Now you should configure this method to use with workflow interceptor via placing annotation to your crud methods insert() , delete() .现在,您应该通过在 crud 方法insert()delete()放置注释来配置此方法以与workflow拦截器一起使用。

@InputConfig(methodName="input")

In the edit() and load() methods you can just call input() manually if the action is returning a dispatcher result, possibly the same location as INPUT result.edit()load()方法中,如果操作返回调度程序结果(可能与INPUT结果相同的位置load()您可以手动调用input()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM