Создание Struts 2 Action в Groovy

Экшины в Struts 2 это POJO. Экшины также служат той же цели что и ActionForm в Struts 1 и хранят все данные, представленные пользователем. Кроме того классы экшинов Struts 2 хранят информацию, которую вы хотели бы показать на страницах пользователя. (Struts 2 также поддерживает ModelDriven стиль, в котором экшины не должны хранить эти данные, но идеи в основном та же.)

В ходе разработки Struts 2 приложения Вами будет писать много аксессоров, setThis(String in), getThat(). Лично мне скушно написание этих методов. Да, я знаю, Eclipse может написать их за меня, но я не люблю Eclipse, и я не выучил другую IDE. Мне нравится моя Unix оболочка, Maven, screen и vi (vim), большое спасибо им.

Итак, к чему мы это? Groovy Beans! Groovy Beans является способ ом написания классов в Groovy, которые соответствуют спецификации Java Beans. Так они намного короче.

 

Пример:

class Person {
String firstName, lastName, address1, address2, city, state, zip, country;
}


Пример создает бин по умолчанию без конструктора. Все объявленные String свойства, FirstName и т.д., имеют приватный доступ, и Groovy создает setXxx () и getXxx () для каждого свойства. Для получения дополнительной информации см. Groovy beans.

Что это дает нам в Struts 2? Простые экшины. Вот пример экшина, который принимает ID в качестве параметра запроса, использует бин сервиса чтобы найти или сохранить бин и возвращает его в презентационный слой (JPS's, FreeMarker и т.д.).

 

 

package example;

import com.opensymphony.xwork2.ActionSupport;

public class MyAction extends ActionSupport {

// Service Bean
def myServiceBean;

// Model Beans
String id; // Id of an order in the database to go look up.
def order; // The order we're going to display.

String execute () throws Exception {
order = myServiceBean.findOrder (id);
return SUCCESS;
}
}

 

Просто, не правда ли. Нет сеттеров и геттеров захламляющих код. Groovy создает всех их, для вас. Кроме того, бин сервиса можно вводить с помощью Spring. (Только не забудьте о findOrder методе, или вы получите исключение. Вам нужно проверить это тестами интеграции.)

Один трюк заключается в том, что надо убедиться, что параметер который вы объявляете соответсвует типу параметра который вы хотите взять из HTTP запроса. Это позволит Struts 2 cделать конверсиию для вас. Объявив ID свойство типа String позволяет Struts 2 для заполнить его с HTTP-запроса строкой. If you wanted it to be an int you could also declare it as an int. Если бы вы хотели его int можно был объявить его в Int.

Просто, не правда ли. Он также во многом выглядит как Java тоже. Итак, почему мы хотим это сделать? Для меня мотивацией является поиск форм, которые не делают маппинг на модель домена объекта. Часто это много полей на них. Searching for a purchase order you might want to be able to search by customer, person who entered it, date entered from, date entered to, date of shipping from, date of shipping to, product, and the list could go on. Поиск заказа вы можете быть в состоянии поиска заказчика, лицом, которое он вступил, вступил с даты, даты вступило на даты отгрузки от даты отгрузки к продукту, и этот список можно продолжить. In Java you would need a setter and getter for each of these form properties. В Java вы должны сеттер и удачливый человек по каждой из этих форм свойств. (I've tried using Map backed forms in Struts 2, but you loose the type conversion.) In Groovy this Action could be very small. (Я попытался с помощью карты поддержке формы Струц 2, но вы потеряете типа преобразования.) Groovy При этом действия могут быть очень небольшими.

 

 

package net.vitarara.quadran.core.web.order.purchasing;

import com.opensymphony.xwork2.Preparable;
import net.vitarara.quadran.core.business.api.purchasing.PurchasingManager;
import net.vitarara.quadran.core.web.QActionSupport;
import net.vitarara.utils.VRContext;
import org.apache.commons.lang.StringUtils;

class ListPurchaseOrdersAction extends QActionSupport implements Preparable {

    // Service Beans
    PurchasingManager purchasingManager;

    // Model Bean(s)
    List carriers, issuers, destinationAreas, products, purchaseOrders, vendors;

    // Form Properties
    Date dateEnteredFrom, dateEnteredTo, dateOfReceiptFrom, dateOfReceiptTo;
    String status, issuedById, orderNumber, vendorId;
    String destinationAreaId, carrierId, productId, fob;
    Boolean dutyPrepaid;

    void prepare () throws Exception {
        // Get the data for the drop downs.
        carriers =  purchasingManager.getCarriers ();
        destinationAreas = purchasingManager.getDestinationAreas ();
        products = purchasingManager.getProducts ();
        vendors = purchasingManager.getVendors ();
        issuers = purchasingManager.getIssuers ();
    }

    /** 
     * Marshall that data from our form input to the service layer to 
     * find purchase orders.
     */
    String execute () throws Exception {
        if (isFormFilledIn () ) {
            VRContext context = new VRContext ();
            context.dateEnteredFrom = dateEnteredFrom;
            context.dateEnteredTo = dateEnteredTo;
            context.dateOfReceiptFrom = dateOfReceiptFrom;
            context.dateOfReceiptTo = dateOfReceiptTo;
            context.status = status;
            context.issuedById = issuedById;
            context.orderNumber = orderNumber;
            context.vendorId = vendorId;
            context.destinationAreaId = destinationAreaId;
            context.carrierId = carrierId;
            context.productId = productId;
            context.fob = fob;
            context.dutyPrepaid = dutyPrepaid;
            context = purchasingManager.listPurchaseOrders (context);
            this.purchaseOrders = context.purchaseOrders;
        }
        return SUCCESS;
    }
    /** Determine if the user has filled out web the form. */
    boolean isFormFilledIn () {
        if (status || issuedById || orderNumber || vendorId || 
            destinationAreaId || carrierId ||
            productId || fob || dateEnteredFrom || dateEnteredTo || 
            dateOfReceiptFrom || dateOfReceiptTo ) {
            
            return true;
        } else {
            return false;
        }   
    }   

}  

Этот пример, безусловно, сложнее. First and foremost for me, the vi loving guy, I didn't have to write 20 sets of setter and getter methods. Прежде всего для меня, VI любящий парень, у меня не было писать 20 наборов сеттер и добытчик методах. That's about 80 lines of saved typing. Это примерно 80 линий ввода сохранены. All of the code in the class actually does something or declares the existence of a property of the class. Все код в класс действительно ли то или заявляет о существовании собственностью класса. The boilerplate code is gone. Стереотипных кода нет.

This action still uses the type conversion that Struts 2 provides. Это решение все еще используется тип преобразования, что обеспечивает Струц 2. When the user fills in the dateEnteredFrom field on the HTML form, Struts 2 will convert that to a Date object for me, because dateEnteredFrom is of type java.util.Date. Когда пользователь заполняет поля на dateEnteredFrom HTML форма, Струц 2 конвертирует что дата объекта для меня, потому что dateEnteredFrom имеет вид java.util.Date. Also notice I didn't need to import java.util.blah blah blah... Также уведомление Мне не нужно импортировать java.util.blah Blah Blah ... How many time have I wished javac just imported it. Сколько раз я хотела javac просто импортировать его. No need to worry, Groovy does. Нет необходимости беспокоиться, Groovy делает.

Walking through the example. Прогулка по примеру. The class starts with property declaration. Класс начинается с имуществом декларации. The purchasingManger is injected using Spring in my application. PurchasingManger вводится с помощью Весна в моей заявке. The rest of the properties are either used for display purposes in the form, or are used to collect user input. Остальные свойства являются либо используется для отображения в форме, или используются для сбора пользовательского ввода.