- 1. 简介
- 2. 开始
- 3. 配置
- 4. Flowable API
- 5. 集成 Spring
- 6. 部署
- 7. BPMN 2.0 介绍
- 8. BPMN 2.0 结构
- 9. 表单
- 10. JPA
- 11. 历史
- 12. 身份管理
- 13. Eclipse Designer
- 14. Flowable UI 应用
- 15. REST API
- 16. 集成 CDI
- 17. 集成 LDAP
- 18. 高级
- 19. 工具
18.5. 执行自定义 SQL
Flowable提供了与数据库交互的高级API。例如,要获取数据,查询API与原生(Native)查询API各有用武之地。但有时会需要更高的灵活性。下面介绍如何在Flowable流程引擎范围内(所以可以使用相同的事务设置等)的数据存储中,执行完全自定义的SQL语句(select、insert、update与delete都可以)。
Flowable引擎使用其底层框架MyBatis的功能自定义SQL语句。可以在MyBatis用户手册找到更多信息。
18.5.1. 基于注解的映射语句
使用基于注解的映射语句(Annotation based Mapped Statement)时,首先要做的是创建一个MyBatis映射类。例如,假设在某个用例中,不需要完整的任务数据,而只需要其中很少一部分,就可以通过映射类(Mapper)完成,像是这样:
public interface MyTestMapper {
@Select("SELECT ID_ as id, NAME_ as name, CREATE_TIME_ as createTime FROM ACT_RU_TASK")
List<Map<String, Object>> selectTasks();
}
必须像下面这样为流程引擎配置映射类:
...
<property name="customMybatisMappers">
<set>
<value>org.flowable.standalone.cfg.MyTestMapper</value>
</set>
</property>
...
请注意这是一个接口。底层的MyBatis框架会构造一个它的实例,并在运行时使用。也请注意方法的返回值没有类型,而只是一个map的list(代表了带有列数据的行的列表)。如果需要,可以通过MyBatis映射类设置类型。
使用managementService.executeCustomSql方法执行上面的查询。这个方法使用CustomSqlExecution的实例作为包装器,将引擎需要处理的内部数据隐藏起来。
不幸的是,Java泛型降低了可读性。下面的两个泛型类是映射类与其返回类型类。只是简单的调用映射方法,并返回其结果(若有)。
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);
在这个例子里,上面列出的Map只包含id, name与创建时间,而不是完整的任务对象。
按照上面的方法可以使用任何SQL。另一个更复杂的例子:
@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);
任务表join变量表,只选择变量有特定名字的记录,并返回任务id与对应的数字值。
请参考单元测试org.flowable.standalone.cfg.CustomMybatisMapperTest及src/test/java/org/flowable/standalone/cfg/与src/test/resources/org/flowable/standalone/cfg/目录中的其它类与资源,了解基于注解的映射语句的更多使用例子。
18.5.2. 基于XML的映射语句
可以使用基于XML的映射语句(XML based Mapped Statement),在XML文件中定义语句。对于不需要完整的任务数据,而只需要其中很少一部分数据的用例,XML文件像是下面这样:
<mapper namespace="org.flowable.standalone.cfg.TaskMapper">
<resultMap type="org.flowable.standalone.cfg.CustomTask">
<id property="id" column="ID_" jdbcType="VARCHAR"/>
<result property="name" column="NAME_" jdbcType="VARCHAR"/>
<result property="createTime" column="CREATE_TIME_" jdbcType="TIMESTAMP" />
</resultMap>
<select resultMap="customTaskResultMap">
select RES.ID_, RES.NAME_, RES.CREATE_TIME_ from ACT_RU_TASK RES
</select>
</mapper>
结果映射为如下的org.flowable.standalone.cfg.CustomTask类的实例:
public class CustomTask {
protected String id;
protected String name;
protected Date createTime;
public String getId() {
return id;
}
public String getName() {
return name;
}
public Date getCreateTime() {
return createTime;
}
}
必须像下面这样为流程引擎配置提供映射XML文件:
...
<property name="customMybatisXMLMappers">
<set>
<value>org/flowable/standalone/cfg/custom-mappers/CustomTaskMapper.xml</value>
</set>
</property>
...
这样执行语句:
List<CustomTask> tasks = managementService.executeCommand(new Command<List<CustomTask>>() {
@SuppressWarnings("unchecked")
@Override
public List<CustomTask> execute(CommandContext commandContext) {
return (List<CustomTask>) commandContext.getDbSqlSession().selectList("selectCustomTaskList");
}
});
XML映射语句在需要更复杂语句的时候很好用。Flowable内部就使用XML映射语句,所以能使用底层功能。
假设某个用例下,需要基于id、name、type、userId等字段,查询附件数据。要实现这个用例,可以创建下面这样的扩展了org.flowable.engine.impl.AbstractQuery的查询类AttachmentQuery:
public class AttachmentQuery extends AbstractQuery<AttachmentQuery, Attachment> {
protected String attachmentId;
protected String attachmentName;
protected String attachmentType;
protected String userId;
public AttachmentQuery(ManagementService managementService) {
super(managementService);
}
public AttachmentQuery attachmentId(String attachmentId){
this.attachmentId = attachmentId;
return this;
}
public AttachmentQuery attachmentName(String attachmentName){
this.attachmentName = attachmentName;
return this;
}
public AttachmentQuery attachmentType(String attachmentType){
this.attachmentType = attachmentType;
return this;
}
public AttachmentQuery userId(String userId){
this.userId = userId;
return this;
}
@Override
public long executeCount(CommandContext commandContext) {
return (Long) commandContext.getDbSqlSession()
.selectOne("selectAttachmentCountByQueryCriteria", this);
}
@Override
public List<Attachment> executeList(CommandContext commandContext, Page page) {
return commandContext.getDbSqlSession()
.selectList("selectAttachmentByQueryCriteria", this);
}
请注意在扩展AbstractQuery时,子类需要为super构造函数传递一个ManagementService的实例,并需要实现executeCount与executeList来调用映射语句。
包含映射语句的XML文件如下:
<mapper namespace="org.flowable.standalone.cfg.AttachmentMapper">
<select parameterType="org.flowable.standalone.cfg.AttachmentQuery" resultType="long">
select count(distinct RES.ID_)
<include refid="selectAttachmentByQueryCriteriaSql"/>
</select>
<select parameterType="org.flowable.standalone.cfg.AttachmentQuery" resultMap="org.flowable.engine.impl.persistence.entity.AttachmentEntity.attachmentResultMap">
${limitBefore}
select distinct RES.* ${limitBetween}
<include refid="selectAttachmentByQueryCriteriaSql"/>
${orderBy}
${limitAfter}
</select>
<sql>
from ${prefix}ACT_HI_ATTACHMENT RES
<where>
<if test="attachmentId != null">
RES.ID_ = #{attachmentId}
</if>
<if test="attachmentName != null">
and RES.NAME_ = #{attachmentName}
</if>
<if test="attachmentType != null">
and RES.TYPE_ = #{attachmentType}
</if>
<if test="userId != null">
and RES.USER_ID_ = #{userId}
</if>
</where>
</sql>
</mapper>
可以在语句中使用例如分页、排序、表名前缀等功能(因为parameterType为AbstractQuery的子类)。可以使用引擎定义的org.flowable.engine.impl.persistence.entity.AttachmentEntity.attachmentResultMap来映射结果。
最后,可以这样使用AttachmentQuery:
....
// 获取附件的总数
long count = new AttachmentQuery(managementService).count();
// 获取id为10025的附件
Attachment attachment = new AttachmentQuery(managementService).attachmentId("10025").singleResult();
// 获取前10个附件
List<Attachment> attachments = new AttachmentQuery(managementService).listPage(0, 10);
// 获取用户kermit上传的所有附件
attachments = new AttachmentQuery(managementService).userId("kermit").list();
....
请参考单元测试org.flowable.standalone.cfg.CustomMybatisXMLMapperTest_及src/test/java/org/flowable/standalone/cfg/与src/test/resources/org/flowable/standalone/cfg/目录中的其它类与资源,了解基于XML的映射语句的更多使用例子。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论