2014-01-08 1 views
4

Предполагая следующий класс действий.Выполнение операций CRUD в классе действия вместе с методом prepare() в Struts2

@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 операции.Поскольку получение этого списка из базы данных является дорогостоящим, этот список должен быть инициализирован только один раз после каждая операция (вставка, изменение, обновление, удаление) завершена.

+2

Я не уверен, что понимаю. Если вы выполните перенаправление, вы получите новое действие и потребуете новых данных. Если есть ошибка проверки, выполняется метод 'input()'. Вы можете либо проверять жесткий код в 'prepare()', либо создавать методы 'prepareXxx()', где 'xxx' заменяется именами методов, в которых вам нужен этот список. Все это в стороне, рассмотрите кеширование. –

+0

'prepare' вызывается для каждого действия,' validate' вызывается для проверки, оба выполняют разные задания. Кажется, вы застряли с предоставленными методами. Создайте свои собственные методы или свои собственные классы и вызовите эти методы или классы, когда это необходимо. –

ответ

3

Выполнение в prepare метода, который выполняется для каждого действия, тяжелая операция, такая как заполняющие списки, не является хорошим способом. Потому что не все действия должны выполнять такую ​​операцию. Но при использовании с валидацией никакого действия не выполняется вообще. Если произошли ошибки проверки, возвращается результат INPUT. Этот результат является результатом dispatcher в вашем usecase, и для этого нужно, чтобы списки были заполнены до того, как этот результат будет выполнен. Вы выполняете ручные проверки в методе validate для ошибок проверки до того, как закончится метод validate и возвращается результат INPUT, после чего вы заселяете списки. Эта логика уже реализована перехватчиком 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() и load() методы, которые вы можете просто вызвать input() вручную, если действие возвращает диспетчерскую результат, возможно, в том же месте INPUT результата.

+0

Я пробовал этот подход. Метод 'input()' вызывается как ожидалось. Могу ли я избежать кода для инициализации списка в методе 'prepare()'? В большинстве случаев оба метода 'input()' и 'prepare()' будут иметь одинаковый фрагмент кода для инициализации списка. В моем случае, что я сейчас делаю, когда возникает ошибка проверки/преобразования, список инициализируется в методе 'input()' и при успехе, этот список заполняется методом 'prepare()' (после некоторые уродливые условные проверки). Могу ли я использовать общий метод для инициализации этого списка (оба имеют один и тот же дублирующий код)? – Tiny

+0

Удалить метод 'prepare'. Код, инициализирующий список, находится в методе 'input'. –

+0

Пройдя это тщательно, это действительно кажется правильным путем! – Tiny

 Смежные вопросы

  • Нет связанных вопросов^_^