Статьи

Выполнение пользовательских запросов в Activiti

(Это, вероятно, окажется в руководстве пользователя к выпуску Activiti 5.15, но я уже хотел поделиться им)

Activiti API позволяет взаимодействовать с базой данных, используя API высокого уровня. Например, для извлечения данных API Query и Native Query API являются мощными в его использовании. Однако для некоторых случаев использования они могут быть недостаточно гибкими. В следующем разделе описывается, как можно выполнить полностью настраиваемый оператор SQL (возможны операции выбора, вставки, обновления и удаления) для хранилища данных Activiti, но полностью в сконфигурированном Process Engine (и, таким образом, например, управлять настройкой транзакции).

Чтобы определить пользовательские операторы SQL, механизм Activiti использует возможности своей базовой структуры, MyBatis. Первое, что нужно сделать при использовании пользовательского SQL, это создать класс сопоставления MyBatis. Более подробную информацию можно прочитать в руководстве пользователя MyBatis . Например, предположим, что для некоторого варианта использования нужны не все данные задачи, а лишь небольшая их часть. Mapper, который мог бы сделать это, выглядит следующим образом:

1
2
3
4
5
6
public interface MyTestMapper {
 
  @Select("SELECT ID_ as id, NAME_ as name, CREATE_TIME_ as createTime FROM ACT_RU_TASK")
  List<Map<String, Object>> selectTasks();
 
}

Этот преобразователь должен быть предоставлен для конфигурации Process Engine следующим образом:

1
2
3
4
5
6
7
...
<property name="customMybatisMappers">
  <set>
    <value>org.activiti.standalone.cfg.MyTestMapper</value>
  </set>
</property>
...

Обратите внимание, что это интерфейс. Базовая структура MyBatis создаст экземпляр, который можно использовать во время выполнения. Также обратите внимание, что возвращаемое значение метода — не типизированный, а список карт (который соответствует списку строк со значениями столбцов). При желании печатать можно с помощью картографов MyBatis.

Для выполнения вышеуказанного запроса необходимо использовать метод managementService.executeCustomSql . Этот метод принимает экземпляр CustomSqlExecution . Это обертка, которая скрывает внутренние биты двигателя, необходимые для его работы.

К сожалению, обобщения Java делают его менее читабельным, чем могло бы быть. Ниже приведены два универсальных типа: класс mapper и класс возвращаемого типа. Однако действительная логика заключается в простом вызове метода отображения и возвращении его результатов (если применимо).

01
02
03
04
05
06
07
08
09
10
CustomSqlExecution<MyTestMapper, List<Map<String, Object>>> customSqlExecution =
    new AbstractCustomSqlExecution<MyTestMapper, List<Map<String, Object>>>(MyTestMapper.class) {
 
  public List<Map<String, Object>> execute(MyTestMapper customMapper) {
    return customMapper.selectTasks();
  }
 
};
 
List<Map<String, Object>> results = managementService.executeCustomSql(customSqlExecution);

В этом случае записи карты в приведенном выше списке будут содержать только идентификатор, имя и время создания, а не полный объект задачи.

Любой SQL возможен при использовании подхода выше. Еще один более сложный пример:

1
2
3
4
5
6
@Select({
    "SELECT task.ID_ as taskId, variable.LONG_ as variableValue FROM ACT_RU_VARIABLE variable",
    "inner join ACT_RU_TASK task on variable.TASK_ID_ = task.ID_",
    "where variable.NAME_ = #{variableName}"
  })
  List<Map<String, Object>> selectTaskWithSpecificVariable(String variableName);

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

Это будет возможно в Activiti 5.15. Тем не менее, код (а точнее реализация Command и интерфейс оболочки ) можно использовать в любой более старой версии Activiti.