Parcourir la source

+ warmflow流程引擎,改造 & 针对租户拦截器进行改造

chen.cheng il y a 2 mois
Parent
commit
2841a986ef

+ 12 - 0
bd-park/park-backend/park-application/pom.xml

@@ -51,6 +51,12 @@
         <dependency>
             <groupId>com.huashe.application</groupId>
             <artifactId>ruoyi-flow</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.huashe.application</groupId>
+                    <artifactId>ruoyi-common</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
         <dependency>
             <groupId>com.huashe.application</groupId>
@@ -82,6 +88,12 @@
         <dependency>
             <groupId>org.dromara.warm</groupId>
             <artifactId>warm-flow-mybatis-sb-starter</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.mybatis.spring.boot</groupId>
+                    <artifactId>mybatis-spring-boot-starter</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
         <dependency>
             <groupId>org.dromara.warm</groupId>

+ 4 - 0
bd-park/park-backend/park-application/src/main/resources/application.yml

@@ -48,6 +48,10 @@ logging:
     org.springframework: warn
     com:
       huashe.park.infrastructure.socket.client: info
+    org:
+      dromara:
+        warm:
+          flow: debug
 
 # 用户配置
 user:

+ 8 - 2
bd-park/park-backend/park-infrastructure/src/main/java/com/huashe/park/infrastructure/cfg/mybatis/MybatisInterceptor.java

@@ -78,8 +78,14 @@ public class MybatisInterceptor extends BaseInterceptor implements Interceptor {
         if (SqlCommandType.INSERT == sqlCommandType) {
             ReflectionUtils.doWithFields(target.getClass(), field -> {
                 field.setAccessible(true);
-                if (field.isAnnotationPresent(TenantField.class)) {
-                    field.set(target, sysUser.getUser().getTenantId());
+                if (field.isAnnotationPresent(TenantField.class) || "tenantId".equals(field.getName())) {
+                    // 判断field 是否是String类型
+                    if (field.getType().equals(String.class)) {
+                        field.set(target, Long.toString(sysUser.getUser().getTenantId()));
+                    }
+                    else {
+                        field.set(target, sysUser.getUser().getTenantId());
+                    }
                 }
                 if ("createBy".equals(field.getName())) {
                     Object local_createBy = field.get(target);

+ 1 - 1
bd-park/park-backend/park-infrastructure/src/main/java/com/huashe/park/infrastructure/cfg/mybatis/TenantIdInterceptor.java

@@ -70,7 +70,7 @@ public class TenantIdInterceptor extends BaseInterceptor implements Interceptor
         // 处理实体对象
         else {
             ReflectionUtils.doWithFields(target.getClass(), field -> {
-                if (field.isAnnotationPresent(TenantField.class)) {
+                if (field.isAnnotationPresent(TenantField.class) || "tenantId".equals(field.getName())) {
                     field.setAccessible(true);
                     field.set(target, getLoginUser().getUser().getTenantId());
                     field.setAccessible(false);

+ 29 - 6
bd-park/park-backend/park-infrastructure/src/main/java/com/huashe/park/infrastructure/cfg/mybatis/TenantSqlInterceptor.java

@@ -5,6 +5,7 @@ import java.sql.Connection;
 import java.util.List;
 import java.util.Properties;
 
+import net.sf.jsqlparser.statement.select.SubSelect;
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.ibatis.executor.statement.StatementHandler;
 import org.apache.ibatis.mapping.MappedStatement;
@@ -20,6 +21,7 @@ import org.springframework.stereotype.Component;
 import com.huashe.common.annotation.mybatis.Tenant;
 import com.huashe.park.common.animations.mybatis.MethodMetadataCache;
 
+import cn.hutool.core.lang.Pair;
 import net.sf.jsqlparser.expression.Expression;
 import net.sf.jsqlparser.expression.LongValue;
 import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
@@ -47,9 +49,9 @@ public class TenantSqlInterceptor extends BaseInterceptor implements Interceptor
         // 获取原始 SQL 和 MappedStatement
         String originalSql = (String) metaObject.getValue("delegate.boundSql.sql");
         MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
-        Method mapperMethod = getMapperMethod(mappedStatement);
+        Pair<Method,Boolean> mapperMethod = getMapperMethod(mappedStatement);
         // 判断是否需要添加租户条件
-        if (!ObjectUtils.allNotNull(mapperMethod, getLoginUser().getUser().getTenantId())) {
+        if (!ObjectUtils.allNotNull(mapperMethod.getKey(), getLoginUser().getUser().getTenantId())) {
             return invocation.proceed();
         }
         // 解析 SQL 语法树
@@ -65,8 +67,27 @@ public class TenantSqlInterceptor extends BaseInterceptor implements Interceptor
         PlainSelect plainSelect = (PlainSelect) selectBody;
         // 构建租户条件表达式(tenant_id = ?)
         EqualsTo tenantCondition = new EqualsTo();
-        tenantCondition.setLeftExpression(handleColumn(mapperMethod));
+        tenantCondition.setLeftExpression(handleColumn(mapperMethod.getKey()));
         tenantCondition.setRightExpression(new LongValue(getLoginUser().getUser().getTenantId()));
+        // *_COUNT 结尾的查询方法添加租户条件
+        if (mapperMethod.getValue()) {
+            SelectBody subSelect = ((SubSelect)plainSelect.getFromItem()).getSelectBody();
+
+            if (subSelect instanceof PlainSelect) {
+                PlainSelect subPlainSelect = (PlainSelect) subSelect;
+                // 添加到原有WHERE条件
+                if (subPlainSelect.getWhere() != null) {
+                    subPlainSelect.setWhere(new AndExpression(subPlainSelect.getWhere(), tenantCondition));
+                } else {
+                    subPlainSelect.setWhere(tenantCondition);
+                }
+            }
+            // 生成修改后的 SQL
+            String modifiedSql = plainSelect.toString();
+            metaObject.setValue("delegate.boundSql.sql", modifiedSql);
+
+            return invocation.proceed();
+        }
 
         // 修改 WHERE 条件
         Expression where = plainSelect.getWhere();
@@ -87,17 +108,19 @@ public class TenantSqlInterceptor extends BaseInterceptor implements Interceptor
         return invocation.proceed();
     }
 
-    private Method getMapperMethod(MappedStatement mappedStatement) {
+    private Pair<Method, Boolean> getMapperMethod(MappedStatement mappedStatement) {
         String methodId = mappedStatement.getId();
         int lastDotIndex = methodId.lastIndexOf(".");
         String methodName = methodId.substring(lastDotIndex + 1);
         List<Method> annotatedMethods = MethodMetadataCache.getAnnotatedMethods(mappedStatement);
+        boolean endWithCount = false;
         if (methodName.endsWith("_COUNT")) {
             methodName = methodName.replaceFirst("_COUNT", "");
+            endWithCount = true;
         }
         String finalMethodName = methodName;
-        return annotatedMethods.stream().filter(method -> method.getName().equals(finalMethodName)).findFirst()
-            .orElse(null);
+        return Pair.of(annotatedMethods.stream().filter(method -> method.getName().equals(finalMethodName)).findFirst()
+            .orElse(null), endWithCount);
     }
 
     private Column handleColumn(Method mapperMethod) {

+ 1 - 1
common-application/ruoyi-flow/pom.xml

@@ -26,7 +26,7 @@
             <artifactId>warm-flow-mybatis-sb-starter</artifactId>
             <exclusions>
                 <exclusion>
-                    <groupId>org.springframework.boot</groupId>
+                    <groupId>org.mybatis.spring.boot</groupId>
                     <artifactId>mybatis-spring-boot-starter</artifactId>
                 </exclusion>
             </exclusions>

+ 11 - 2
common-application/ruoyi-flow/src/main/java/com/ruoyi/flow/mapper/WarmFlowMapper.java

@@ -1,8 +1,10 @@
 package com.ruoyi.flow.mapper;
 
+import com.huashe.common.annotation.mybatis.IgnoreTenant;
+import com.huashe.common.annotation.mybatis.Tenant;
 import com.ruoyi.common.core.domain.entity.SysUser;
-import com.ruoyi.flow.vo.WarmFlowInteractiveTypeVo;
 import com.ruoyi.flow.vo.FlowTaskVo;
+import com.ruoyi.flow.vo.WarmFlowInteractiveTypeVo;
 import org.apache.ibatis.annotations.Param;
 import org.dromara.warm.flow.core.entity.HisTask;
 import org.dromara.warm.flow.core.entity.Task;
@@ -23,6 +25,7 @@ public interface WarmFlowMapper {
      *
      * @param task 条件实体
      */
+    @Tenant(tableAlias = "t")
     List<FlowTaskVo> toDoPage(@Param("task") Task task);
 
     /**
@@ -31,13 +34,16 @@ public interface WarmFlowMapper {
      * @param hisTask
      * @return
      */
+    @IgnoreTenant
     List<FlowHisTask> donePage(@Param("hisTask") HisTask hisTask);
 
     /**
      * 分页获取抄送任务
+     *
      * @param flowTask
      * @return
      */
+    @Tenant(tableAlias = "a")
     List<FlowHisTask> copyPage(@Param("task") FlowTask flowTask);
 
     /**
@@ -48,6 +54,7 @@ public interface WarmFlowMapper {
      * @author liangli
      * @date 2024/8/21 17:11
      **/
+    @IgnoreTenant
     List<SysUser> idReverseDisplayName(@Param("ids") Long[] ids);
 
     /**
@@ -56,6 +63,7 @@ public interface WarmFlowMapper {
      * @param warmFlowInteractiveTypeVo 输入用户编号集合
      * @return 用户列表
      */
+    @IgnoreTenant
     List<SysUser> selectNotUserIds(@Param("warmFlowInteractiveTypeVo") WarmFlowInteractiveTypeVo warmFlowInteractiveTypeVo);
 
     /**
@@ -64,5 +72,6 @@ public interface WarmFlowMapper {
      * @param warmFlowInteractiveTypeVo 输入用户编号集合
      * @return 用户列表
      */
-    List<SysUser> selectUserIds(@Param("warmFlowInteractiveTypeVo")WarmFlowInteractiveTypeVo warmFlowInteractiveTypeVo);
+    @IgnoreTenant
+    List<SysUser> selectUserIds(@Param("warmFlowInteractiveTypeVo") WarmFlowInteractiveTypeVo warmFlowInteractiveTypeVo);
 }

+ 43 - 39
common-application/ruoyi-flow/src/main/resources/mapper/flow/WarmFLowMapper.xml

@@ -98,44 +98,45 @@
 
     <select id="donePage" resultMap="FlowHisTaskResult">
         select
-            t.id,
-            t.node_code,
-            t.node_name,
-            t.cooperate_type,
-            t.approver,
-            t.collaborator,
-            t.node_type,
-            t.target_node_code,
-            t.target_node_name,
-            t.definition_id,
-            t.instance_id,
-            i.flow_status,
-            t.message,
-            t.ext,
-            t.create_time,
-            t.update_time,
-            t.tenant_id,
-            i.business_id,
-            t.form_path,
-            d.flow_name
+        t.id,
+        t.node_code,
+        t.node_name,
+        t.cooperate_type,
+        t.approver,
+        t.collaborator,
+        t.node_type,
+        t.target_node_code,
+        t.target_node_name,
+        t.definition_id,
+        t.instance_id,
+        i.flow_status,
+        t.message,
+        t.ext,
+        t.create_time,
+        t.update_time,
+        t.tenant_id,
+        i.business_id,
+        t.form_path,
+        d.flow_name
         from ( SELECT MAX(id) as id
-               FROM flow_his_task
-               <where>
-                   <if test="hisTask.permissionList != null and hisTask.permissionList.size > 0">
-                       AND approver in
-                       <foreach item="permission" collection="hisTask.permissionList" open="(" separator="," close=")">
-                           #{permission}
-                       </foreach>
-                   </if>
-                   <if test="hisTask.nodeCode != null  and hisTask.nodeCode != ''">and node_code =
-                       #{hisTask.nodeCode}
-                   </if>
-                   <if test="hisTask.nodeName != null  and hisTask.nodeName != ''">and node_name like concat('%',
-                       #{hisTask.nodeName}, '%')
-                   </if>
-                   <if test="hisTask.instanceId != null ">and instance_id = #{hisTask.instanceId}</if>
-               </where>
-              GROUP BY instance_id ) tmp
+        FROM flow_his_task
+        <where>
+            <if test="hisTask.permissionList != null and hisTask.permissionList.size > 0">
+                AND approver in
+                <foreach item="permission" collection="hisTask.permissionList" open="(" separator="," close=")">
+                    #{permission}
+                </foreach>
+            </if>
+            <if test="hisTask.nodeCode != null  and hisTask.nodeCode != ''">and node_code =
+                #{hisTask.nodeCode}
+            </if>
+            <if test="hisTask.nodeName != null  and hisTask.nodeName != ''">and node_name like concat('%',
+                #{hisTask.nodeName}, '%')
+            </if>
+            <if test="hisTask.instanceId != null ">and instance_id = #{hisTask.instanceId}</if>
+            <if test="hisTask.tenantId != null ">and tenant_id = #{hisTask.tenantId}</if>
+        </where>
+        GROUP BY instance_id ) tmp
         LEFT JOIN flow_his_task t ON t.id = tmp.id
         LEFT JOIN flow_definition d on t.definition_id = d.id
         LEFT JOIN flow_instance i on t.instance_id = i.id
@@ -218,7 +219,9 @@
     </resultMap>
 
     <select id="selectNotUserIds" parameterType="com.ruoyi.flow.vo.WarmFlowInteractiveTypeVo" resultMap="SysUserResult">
-        select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user u
+        select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status,
+        u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user
+        u
         left join sys_dept d on u.dept_id = d.dept_id
         where u.del_flag = '0'
         <if test="warmFlowInteractiveTypeVo.userIds != null and warmFlowInteractiveTypeVo.userIds.size() > 0">
@@ -228,7 +231,8 @@
             </foreach>
         </if>
         <if test="warmFlowInteractiveTypeVo.deptId != null and warmFlowInteractiveTypeVo.deptId != 0">
-            AND (u.dept_id = #{warmFlowInteractiveTypeVo.deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{warmFlowInteractiveTypeVo.deptId}, ancestors) ))
+            AND (u.dept_id = #{warmFlowInteractiveTypeVo.deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t
+            WHERE find_in_set(#{warmFlowInteractiveTypeVo.deptId}, ancestors) ))
         </if>
         <!-- 数据范围过滤 -->
         ${warmFlowInteractiveTypeVo.params.dataScope}

+ 23 - 0
prod-common/src/main/java/com/huashe/common/clone/CloneSupport.java

@@ -0,0 +1,23 @@
+package com.huashe.common.clone;
+
+import com.huashe.common.exception.UtilException;
+
+/**
+ * 克隆支持类,提供默认的克隆方法
+ *
+ * @param <T> 继承类的类型
+ * @author Looly
+ */
+public class CloneSupport<T> implements Cloneable<T> {
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public T clone() {
+        try {
+            return (T) super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new UtilException(e);
+        }
+    }
+
+}

+ 17 - 0
prod-common/src/main/java/com/huashe/common/clone/Cloneable.java

@@ -0,0 +1,17 @@
+package com.huashe.common.clone;
+
+/**
+ * 克隆支持接口
+ *
+ * @param <T> 实现克隆接口的类型
+ * @author Looly
+ */
+public interface Cloneable<T> extends java.lang.Cloneable {
+
+    /**
+     * 克隆当前对象,浅复制
+     *
+     * @return 克隆后的对象
+     */
+    T clone();
+}

+ 88 - 0
prod-common/src/main/java/com/huashe/common/lang/Pair.java

@@ -0,0 +1,88 @@
+package com.huashe.common.lang;
+
+
+import com.huashe.common.clone.CloneSupport;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/**
+ * 键值对对象,只能在构造时传入键值
+ *
+ * @param <K> 键类型
+ * @param <V> 值类型
+ * @author looly
+ * @since 4.1.5
+ */
+public class Pair<K, V> extends CloneSupport<Pair<K, V>> implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    protected K key;
+    protected V value;
+
+    /**
+     * 构建{@code Pair}对象
+     *
+     * @param <K>   键类型
+     * @param <V>   值类型
+     * @param key   键
+     * @param value 值
+     * @return {@code Pair}
+     * @since 5.4.3
+     */
+    public static <K, V> Pair<K, V> of(K key, V value) {
+        return new Pair<>(key, value);
+    }
+
+    /**
+     * 构造
+     *
+     * @param key   键
+     * @param value 值
+     */
+    public Pair(K key, V value) {
+        this.key = key;
+        this.value = value;
+    }
+
+    /**
+     * 获取键
+     *
+     * @return 键
+     */
+    public K getKey() {
+        return this.key;
+    }
+
+    /**
+     * 获取值
+     *
+     * @return 值
+     */
+    public V getValue() {
+        return this.value;
+    }
+
+    @Override
+    public String toString() {
+        return "Pair [key=" + key + ", value=" + value + "]";
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o instanceof Pair) {
+            Pair<?, ?> pair = (Pair<?, ?>) o;
+            return Objects.equals(getKey(), pair.getKey()) &&
+                    Objects.equals(getValue(), pair.getValue());
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        //copy from 1.8 HashMap.Node
+        return Objects.hashCode(key) ^ Objects.hashCode(value);
+    }
+}