Общая информация

ERP это веб-приложение на базе servlet-api. В качестве контейнера сервлетов используется embedded tomcat, в качестве web-mvc фреймворка apache struts 1

Обработка запросов

При описании будут приводиться аналогии с spring-mvc ввиду большей распространенности последнего

Маршрутизация запросов

Точкой входа является ru.bgcrm.servlet.ActionServlet, выполняющий роль DispatcherServlet. Сервлет обрабатывает все входящие запросы формата *.do и передает управление соответствующему "экшену". Экшены исполняют функцию контроллеров и описываются в конфигурациях struts-config*.xml

<action path="/login" parameter="action" type="ru.bgcrm.struts.action.LoginAction" name="form" scope="request">
	<forward name="default" path="/login.jsp"/>
</action>

Классы экшенов наследуют ru.bgcrm.struts.action.BaseAction, если в хттп запросе передан параметр action то в классе экшена вызовется метод с таким названием, в ином случае вызовется метод unspecified тип хттп-метода не задается, метод экшена будет вызван независимо будь то GET,POST, использование отличных от get/post методов при запросах не имеет особого смысла данные запроса инкапсулируются в объекте типа ru.bgcrm.struts.form.DynActionForm в него же помещаются данные для ответа, если они предусмотрены также объект содержит данные о пользователе и его правах.

Формирование ответа

Результатом работы экшена могут являться

  • перенаправление в jsp

  • ответ в формате json

  • ответ в виде файла

Распространенным вариантом является реализация экшенов с предоставлением клиенту типа ответа ("UserTypedForward"):

  • html с помощью определенного в методе экшена форварда (по умолчанию)

  • html с помощью переданной в хттп параметре jsp

  • json если клиентом передан хттп-аргумент responseType=json или заголовок Accept: application/json

Все запросы транзакционные, продолжительность и результат выполнения за рядом исключений фиксируются в таблице web_request_log и могут быть просмотрены через оснастку Администрирование - web-запросы

Обработка событий

Некоторые экшены в процессе своей работы генерируют события. Путем реагирования на них можно осуществлять расширение функционала ерп. Реагирование на события представляет основной способ автоматизации процессов.

ru.bgcrm.event.EventProcessor - осуществляет подписку и генерацию событий ru.bgcrm.event.listener.EventListener - интерфейс слушателя

Подписка

Самым простым и распространенным способом подписки является указание класса обработки в соответствующей сущности, например в типе процесса или параметре в системе предусмотрено несколько системных типов слушателей, которые регистрирутся при старте сервера

ru.bgcrm.event.listener.DynamicEventListener - базовый класс для динамических пописчиков, имплементация непосредственно этого класса является устаревшим способом реализации и не рекомендуется ru.bgcrm.plugin.ufanet.common.CommonProcessListener, ru.bgcrm.plugin.ufanet.common.CommonParamListener - обертки над DynamicEventListener для процессов и параметров соответственно ru.bgcrm.event.listener.dispatcher.AnnotatedEventListener - наиболее современный вариант на текущий момент, использует декларативный способ описания

Вызов слушателей

Когда в рамках обработки запроса происходит формирование события, происходит синхронный последовательный вызов notify всех подписчиков, классы-наследники DynamicEventListener выполняются в отдельном потоке (синхронно), максимальный таймаут для работы таких скриптов по умолчанию 15 секунд

Фронтенд

Исторически сложилось что большая часть использует jsp+jstl+struts taglib+кастомный taglib. Интерактивные элементы построены средствами ajax с помощью jquery либо jstl-компонентов.

Актуальным способом построения нового функционала на фронте является использование vuejs2. Список используемых библиотек прописан в script_css.jsp

Взаимодействие с бэкендом

для выполнения запросов к апи рекомендуется использовать репозитории, описанные в thesaurus.js при отсутствии экшена в thesaurus.js добавить экшен в thesaurus.js в качестве транспорта в репозиториях используется axios

Использование VueJs

Допустимо и рекомендуется использование однофайловых компонентов существующий перечень компонентов содержится в webapps/components пример использования компонента из jsp

<c:set var="uuid" value="${u:uiid()}"/>

<div id="${uuid}">
    <create-linked-process-widget></create-linked-process-widget>
</div>

<script>
    window["${uuid}"] = new Vue( {
        el: "#${uuid}",
        name: "CreateLinkedProcessStep${uuid}",
        components: {
            "create-linked-process-widget": "url:/components/ui/process/CreateLinkedProcessWidget.vue"
        },
        data: {
            config: JSON.parse( '${stepData.config}' )
        },
...

u:uiid() здесь кастомная jsp функция служит для формирования уникального идентификатора html элемента, для избежания конфликтов однотипных приложений

Клиентские события

Для передачи сообщений со стороны сервера (например всплывающие сообщения, счетчики, открытие контрагента при приеме входящих звонков итп) используются пуллинг и клиентские события. Когда в ответе от сервера приходит ответ содержащий свойство eventList, для каждого элемента списка будут вызваны зарегистрированные на данный тип события подписчики клиентские события имплементят java-класс ru.bgcrm.event.client.ClientEvent, подписка происходит с помощью метода crm.js#addEventProcessor

Ссылки