Action

Что такое action

Action - это объекты, реализующие интерфейс jandcode.core.web.action.IAction, которые обратывают http-запросы пользователя в контексте web-приложения и возвращают ответ клиенту.

На практике для создания action необходимо создать наследника от класса jandcode.core.web.action.BaseAction и реализовать ему метод onExec(), в котором и будет логика обработки запроса.

Каждая action регистрируется в приложении под определенным именем, которое может включать в себя /:

<root>
    <web>
        <action name="action1"
                class="mymodule.mypackage.Action1"/>
        <action name="blog/news"
                class="mymodule.mypackage.News"/>
        <action name="blog"
                class="mymodule.mypackage.Blog"/>
    </web>
</root>

Упрощенная схема преобразования url в action такова: среди всех зарегистрированных action ищется такая, имя которой совпадает с началом pathInfo http-запроса. Остаток pathInfo, из которого удалено имя action будет передано в обработчик запроса в качестве одного из атрибутов.

Что такое pathInfo? Допустим, что приложение работает по адресу http://localhost/myapp/. Тогда все, что будет в url после http://localhost/myapp/ и до начала параметров (символа ?) является pathInfo. Например в запросе http://localhost/myapp/a1/a2/a3?param1=1&param2=2 имеем pathInfo равным a1/a2/a3. pathInfo доступно через метод jandcode.core.web.Request#getPathInfo.

Для вышеприведенного примера регистрации action будут верны следующие преобразования pathInfo в action:

pathInfoactionОстаток pathInfoКоментарий
action1action1
action1/m1action1m1
blog/m1/m2blogm1/m2
blog/news/m1blog/newsm1blog/news длиннее по фасетам, чем blog

Реализация action

Простейшая реализация action выглядит так:

package web._inc.action

import jandcode.commons.variant.*
import jandcode.core.web.action.*

class SimpleAction extends BaseAction {
    protected void onExec() throws Exception {
        // это запрос, тут есть все, что известно о запросе + утилиты
        ActionRequestUtils req = getReq()
        // это параметры запроса
        IVariantMap params = getReq().getParams()
        // возвращаем результат клиенту как строку
        getReq().render("Hello! Params: " + getReq().getParams())
    }
}

Интерпретация pathInfo для action

Доупустим, что имеется action, зарегистрированая так:

<root>
    <web>
        <action name="my/simple/action"
                class="web._inc.action.SimpleAction"/>
    </web>
</root>

и ее экземпляр создан для обработки запроса с таким pathInfo:

my/simple/action/p1/p2/p3

Тогда в атрибуты getRequest().getAttrs() будут дополнительно добавлены следующие атрибуты:

Имя атрибутаКонстанта имениЗначениеКоментарий
actionPathInfoWebConsts.a_actionPathInfop1/p2/p3pathInfo, из которого убрано имя action
actionMethodWebConsts.a_actionMethodp1Первый фасет из actionPathInfo, имя "метода" для action
actionMethodPathInfoWebConsts.a_actionMethodPathInfop2/p3actionPathInfo, из которого убран первый фасет

Если соответсвующей информации нет в pathInfo, то атрибуты принимают пустые значения.

Методы в классе action

Реализация метода onExec() по умолчанию вызывает публичный метод с именем, который указан в атрибуте actionMethod. Если в этом атрибуте нет значения, то значение по умолчанию для него - index. Если метода с таком именем нет, то генерируется ошибка.

Пример:

import jandcode.core.web.action.BaseAction

class SimpleMethodsAction extends BaseAction {

    public void index() throws Exception {
        getReq().render("index")
    }

    public void p1() throws Exception {
        getReq().render("p1")
    }

}

В таблице показаны варианты обработки различных pathInfo, предполагая, что action зарегистрирована с именем my/act:

pathInfoДействие
my/actВызов метода index
my/act/indexВызов метода index
my/act/p1Вызов метода p1
my/act/p1/p2/p3Вызов метода p1, атрибут actionMethodPathInfo=p2/p3
my/act/pppОшибка, метода ppp нет

Если метод возвращает значение, то это значение будет использовано в качестве данных для рендеринга:

import jandcode.core.web.action.*

class FuncMethodsAction extends BaseAction {

    public void p1() throws Exception {
        getReq().render("data1")
    }

    public String p2() throws Exception {
        return "data1"
    }

}

В этом примере методы p1 и p2 эквивалентны.

Когда метод onExec() явно перекрыт, то, естественно, эти правила не действуют и процесс обработки будет вестись по вашим правилам.

ActionMethodExecutor

Если метод action имеет один параметр типа jandcode.core.web.action.ActionMethodExecutor, то выполнение метода action делегируется экземпляру этого класса.

Пример:

import jandcode.core.web.action.*

import java.lang.reflect.*

class ActionExecutor1 extends BaseAction {

    static class Executor1 implements ActionMethodExecutor {

        String data

        void execActionMethod(BaseAction action, Method method) throws Exception {
            // вызываем оригинальный метод и передаем себя в качестве параметра
            method.invoke(action, this)

            // пользуемся результатами
            Map m = new HashMap()
            m.put("data", data)

            // рендерим результат
            action.getReq().render(m)
        }

        void setData(String data) {
            this.data = data
        }

    }

    //////

    void m1(Executor1 ex) {
        ex.setData("hello")
    }

}

index.gsp / index.html

Когда при обработке pathInfo не найдена action, которая соответствует этому pathInfo, делается попытка интерпретировать pathInfo как виртуальную папку, в которой ищутся файлы index.gsp или index.html.

Если найден index.gsp, то клиенту возвращается результат рендеринга этого файла. url для клиента выглядит как папка.

Если найден index.html, то делается redirect на на него, соответственно url для клиента выглядит как файл.

При наличии обоих файлов приоритет имеет index.gsp.

Action 'root'

Специальная action с именем root обрабатывает запрос в корень url (http://host или http://host/). По умолчанию настроена на рендеринг заглушки gsp. Ее нужно настроить в приложении.

Можно указать шаблон gsp:

<root>
    <web>
        <action name="root"
                template="my/app/root.gsp"/>
    </web>
</root>

или класс action:

<root>
    <web>
        <action name="root"
                class="my.app.MyRootAction"/>
    </web>
</root>

Конфигурация module.cfx

web/action

Регистрация action.

Формат:

<root>
    <web>
        <action name="NAME"
                class="jandcode.core.web.action.BaseAction"
                template="template/path.gsp"
        />
    </web>
</root>
  • name - уникальное имя action. Может включать /.
  • class - класс action
  • template - шаблон gsp. Если указан шаблон и не указан атрибут class, то в качестве класса принимается jandcode.core.web.std.action.GspAction, которая рендерит указанный шаблон.