From 5c50c4a82c344c483b156c928a5d14c68da03a00 Mon Sep 17 00:00:00 2001 From: timyuer <524860213@qq.com> Date: Fri, 30 Aug 2024 13:51:34 +0800 Subject: [PATCH 1/4] BIGTOP-4211: Add mybatis dynamic key interceptor --- .../resources/mapper/mysql/HostMapper.xml | 2 +- .../resources/mapper/mysql/RepoMapper.xml | 2 +- .../interceptor/DynamicKeyInterceptor.java | 99 +++++++++++++++++++ 3 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/interceptor/DynamicKeyInterceptor.java diff --git a/bigtop-manager-dao/src/main/resources/mapper/mysql/HostMapper.xml b/bigtop-manager-dao/src/main/resources/mapper/mysql/HostMapper.xml index a1143a325..7eae151f6 100644 --- a/bigtop-manager-dao/src/main/resources/mapper/mysql/HostMapper.xml +++ b/bigtop-manager-dao/src/main/resources/mapper/mysql/HostMapper.xml @@ -100,7 +100,7 @@ - + insert into host (hostname, ipv4, ipv6, os, arch, available_processors, free_memory_size, total_memory_size, free_disk, total_disk, state, cluster_id) values diff --git a/bigtop-manager-dao/src/main/resources/mapper/mysql/RepoMapper.xml b/bigtop-manager-dao/src/main/resources/mapper/mysql/RepoMapper.xml index 138250733..6ec8a5808 100644 --- a/bigtop-manager-dao/src/main/resources/mapper/mysql/RepoMapper.xml +++ b/bigtop-manager-dao/src/main/resources/mapper/mysql/RepoMapper.xml @@ -40,7 +40,7 @@ limit 1 - + insert into repo (base_url, os, arch, repo_id, repo_name, cluster_id) values diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/interceptor/DynamicKeyInterceptor.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/interceptor/DynamicKeyInterceptor.java new file mode 100644 index 000000000..a8f31e8c2 --- /dev/null +++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/interceptor/DynamicKeyInterceptor.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.bigtop.manager.server.interceptor; + +import org.apache.bigtop.manager.dao.sql.TableMetaData; + +import org.apache.ibatis.binding.MapperMethod; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlCommandType; +import org.apache.ibatis.plugin.Interceptor; +import org.apache.ibatis.plugin.Intercepts; +import org.apache.ibatis.plugin.Invocation; +import org.apache.ibatis.plugin.Signature; + +import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Collection; + +@Slf4j +@Component +@Intercepts({ + @Signature( + type = Executor.class, + method = "update", + args = {MappedStatement.class, Object.class}) +}) +public class DynamicKeyInterceptor implements Interceptor { + + @Override + public Object intercept(Invocation invocation) throws Throwable { + MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; + SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); + + String[] keyColumns = mappedStatement.getKeyColumns(); + String[] keyProperties = mappedStatement.getKeyProperties(); + + if (mappedStatement.getResource().contains(".xml") && keyColumns != null && keyProperties != null) { + return invocation.proceed(); + } + + if (SqlCommandType.INSERT == sqlCommandType) { + Object parameter = invocation.getArgs()[1]; + log.debug("parameter: {}", parameter); + + Object object = parameter; + if (parameter instanceof MapperMethod.ParamMap first) { + if (first.get("param1") instanceof Collection) { + object = ((Collection) first.get("param1")) + .stream().findFirst().get(); + } + } + TableMetaData metaData = TableMetaData.forClass(object.getClass()); + + String pkColumn = metaData.getPkColumn(); + String pkProperty = metaData.getPkProperty(); + log.debug("pkColumn {} pkProperty {}", pkColumn, pkProperty); + Method delimitedStringToArray = + MappedStatement.class.getDeclaredMethod("delimitedStringToArray", String.class); + delimitedStringToArray.setAccessible(true); + // keyColumns + Field field1 = MappedStatement.class.getDeclaredField("keyColumns"); + field1.setAccessible(true); + field1.set(mappedStatement, delimitedStringToArray.invoke(mappedStatement, pkProperty)); + // keyProperties + Field field2 = MappedStatement.class.getDeclaredField("keyProperties"); + field2.setAccessible(true); + field2.set(mappedStatement, delimitedStringToArray.invoke(mappedStatement, pkColumn)); + log.debug( + "mappedStatement keyColumns: {} keyProperties: {} keyGenerator: {}", + mappedStatement.getKeyColumns(), + mappedStatement.getKeyProperties(), + mappedStatement.getKeyGenerator()); + } + + return invocation.proceed(); + } +} From 986d1f1717193eccc01c4627a326b1a64d28c7f4 Mon Sep 17 00:00:00 2001 From: timyuer <524860213@qq.com> Date: Fri, 30 Aug 2024 14:20:02 +0800 Subject: [PATCH 2/4] update --- .../manager/server/interceptor/DynamicKeyInterceptor.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/interceptor/DynamicKeyInterceptor.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/interceptor/DynamicKeyInterceptor.java index a8f31e8c2..e2824ac4e 100644 --- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/interceptor/DynamicKeyInterceptor.java +++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/interceptor/DynamicKeyInterceptor.java @@ -65,10 +65,12 @@ public Object intercept(Invocation invocation) throws Throwable { log.debug("parameter: {}", parameter); Object object = parameter; - if (parameter instanceof MapperMethod.ParamMap first) { - if (first.get("param1") instanceof Collection) { - object = ((Collection) first.get("param1")) + if (parameter instanceof MapperMethod.ParamMap paramMap) { + if (paramMap.get("param1") instanceof Collection) { + object = ((Collection) paramMap.get("param1")) .stream().findFirst().get(); + } else { + object = paramMap.get("param1"); } } TableMetaData metaData = TableMetaData.forClass(object.getClass()); From 265c368f9ad751ae526b9a2e2b1d7d4604dbae50 Mon Sep 17 00:00:00 2001 From: timyuer <524860213@qq.com> Date: Sat, 31 Aug 2024 10:01:53 +0800 Subject: [PATCH 3/4] Add audit for xml --- .../resources/mapper/mysql/HostMapper.xml | 4 +- .../resources/mapper/mysql/RepoMapper.xml | 4 +- .../interceptor/AuditingInterceptor.java | 49 ++++++++++++++----- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/bigtop-manager-dao/src/main/resources/mapper/mysql/HostMapper.xml b/bigtop-manager-dao/src/main/resources/mapper/mysql/HostMapper.xml index 7eae151f6..4c475a71d 100644 --- a/bigtop-manager-dao/src/main/resources/mapper/mysql/HostMapper.xml +++ b/bigtop-manager-dao/src/main/resources/mapper/mysql/HostMapper.xml @@ -101,10 +101,10 @@ - insert into host (hostname, ipv4, ipv6, os, arch, available_processors, free_memory_size, total_memory_size, free_disk, total_disk, state, cluster_id) + insert into host (hostname, ipv4, ipv6, os, arch, available_processors, free_memory_size, total_memory_size, free_disk, total_disk, state, cluster_id, create_by, update_by, create_time, update_time) values - (#{host.hostname}, #{host.ipv4}, #{host.ipv6}, #{host.os}, #{host.arch}, #{host.availableProcessors}, #{host.freeMemorySize}, #{host.totalMemorySize}, #{host.freeDisk}, #{host.totalDisk}, #{host.state}, #{host.clusterId}) + (#{host.hostname}, #{host.ipv4}, #{host.ipv6}, #{host.os}, #{host.arch}, #{host.availableProcessors}, #{host.freeMemorySize}, #{host.totalMemorySize}, #{host.freeDisk}, #{host.totalDisk}, #{host.state}, #{host.clusterId} ,#{host.createBy},#{host.updateBy},#{host.createTime},#{host.updateTime}) diff --git a/bigtop-manager-dao/src/main/resources/mapper/mysql/RepoMapper.xml b/bigtop-manager-dao/src/main/resources/mapper/mysql/RepoMapper.xml index 6ec8a5808..b51ab044b 100644 --- a/bigtop-manager-dao/src/main/resources/mapper/mysql/RepoMapper.xml +++ b/bigtop-manager-dao/src/main/resources/mapper/mysql/RepoMapper.xml @@ -41,10 +41,10 @@ - insert into repo (base_url, os, arch, repo_id, repo_name, cluster_id) + insert into repo (base_url, os, arch, repo_id, repo_name, cluster_id, create_by, update_by, create_time, update_time) values - (#{cluster.baseUrl},#{cluster.os},#{cluster.arch},#{cluster.repoId},#{cluster.repoName},#{cluster.clusterId}) + (#{cluster.baseUrl},#{cluster.os},#{cluster.arch},#{cluster.repoId},#{cluster.repoName},#{cluster.clusterId},#{cluster.createBy},#{cluster.updateBy},#{cluster.createTime},#{cluster.updateTime}) diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/interceptor/AuditingInterceptor.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/interceptor/AuditingInterceptor.java index 71e8d5cbe..7d7cb603a 100644 --- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/interceptor/AuditingInterceptor.java +++ b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/interceptor/AuditingInterceptor.java @@ -24,9 +24,10 @@ import org.apache.bigtop.manager.dao.annotations.CreateTime; import org.apache.bigtop.manager.dao.annotations.UpdateBy; import org.apache.bigtop.manager.dao.annotations.UpdateTime; -import org.apache.bigtop.manager.dao.po.BasePO; import org.apache.bigtop.manager.server.holder.SessionUserHolder; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.ibatis.binding.MapperMethod; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlCommandType; @@ -41,6 +42,8 @@ import java.lang.reflect.Field; import java.sql.Timestamp; +import java.util.Collection; +import java.util.Collections; import java.util.List; @Slf4j @@ -53,6 +56,7 @@ }) public class AuditingInterceptor implements Interceptor { + @SuppressWarnings("unchecked") @Override public Object intercept(Invocation invocation) throws Throwable { MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; @@ -62,39 +66,60 @@ public Object intercept(Invocation invocation) throws Throwable { Object parameter = invocation.getArgs()[1]; log.debug("sqlCommandType {}", sqlCommandType); - if (!(parameter instanceof BasePO)) { - return invocation.proceed(); + Collection objects; + if (parameter instanceof MapperMethod.ParamMap) { + MapperMethod.ParamMap paramMap = ((MapperMethod.ParamMap) parameter); + if (paramMap.get("param1") instanceof Collection) { + objects = ((Collection) paramMap.get("param1")); + } else { + objects = Collections.singletonList(paramMap.get("param1")); + } + } else { + objects = Collections.singletonList(parameter); + } + + for (Object o : objects) { + setAuditFields(o, sqlCommandType); } + return invocation.proceed(); + } + + private Pair getAuditInfo() { // Get the current time and operator Timestamp timestamp = new Timestamp(System.currentTimeMillis()); Long currentUser = SessionUserHolder.getUserId(); log.debug("timestamp: {} currentUser: {}", timestamp, currentUser); + return Pair.of(currentUser, timestamp); + } + + private void setAuditFields(Object object, SqlCommandType sqlCommandType) throws IllegalAccessException { + + Pair auditInfo = getAuditInfo(); + Long currentUser = auditInfo.getLeft(); + Timestamp timestamp = auditInfo.getRight(); - // Modify audit fields - List fields = ClassUtils.getFields(parameter.getClass()); + List fields = ClassUtils.getFields(object.getClass()); if (SqlCommandType.INSERT == sqlCommandType || SqlCommandType.UPDATE == sqlCommandType) { for (Field field : fields) { - boolean accessible = field.canAccess(parameter); + boolean accessible = field.canAccess(object); field.setAccessible(true); if (field.isAnnotationPresent(CreateBy.class) && SqlCommandType.INSERT == sqlCommandType && currentUser != null) { - field.set(parameter, currentUser); + field.set(object, currentUser); } if (field.isAnnotationPresent(CreateTime.class) && SqlCommandType.INSERT == sqlCommandType) { - field.set(parameter, timestamp); + field.set(object, timestamp); } if (field.isAnnotationPresent(UpdateBy.class) && currentUser != null) { - field.set(parameter, currentUser); + field.set(object, currentUser); } if (field.isAnnotationPresent(UpdateTime.class)) { - field.set(parameter, timestamp); + field.set(object, timestamp); } field.setAccessible(accessible); } } - - return invocation.proceed(); } } From c640a6cc9e2922423913f2d345470b23a38fe54f Mon Sep 17 00:00:00 2001 From: timyuer <524860213@qq.com> Date: Mon, 9 Sep 2024 08:28:10 +0800 Subject: [PATCH 4/4] update --- .../interceptor/DynamicKeyInterceptor.java | 101 ------------------ 1 file changed, 101 deletions(-) delete mode 100644 bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/interceptor/DynamicKeyInterceptor.java diff --git a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/interceptor/DynamicKeyInterceptor.java b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/interceptor/DynamicKeyInterceptor.java deleted file mode 100644 index e2824ac4e..000000000 --- a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/interceptor/DynamicKeyInterceptor.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.bigtop.manager.server.interceptor; - -import org.apache.bigtop.manager.dao.sql.TableMetaData; - -import org.apache.ibatis.binding.MapperMethod; -import org.apache.ibatis.executor.Executor; -import org.apache.ibatis.mapping.MappedStatement; -import org.apache.ibatis.mapping.SqlCommandType; -import org.apache.ibatis.plugin.Interceptor; -import org.apache.ibatis.plugin.Intercepts; -import org.apache.ibatis.plugin.Invocation; -import org.apache.ibatis.plugin.Signature; - -import org.springframework.stereotype.Component; - -import lombok.extern.slf4j.Slf4j; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.Collection; - -@Slf4j -@Component -@Intercepts({ - @Signature( - type = Executor.class, - method = "update", - args = {MappedStatement.class, Object.class}) -}) -public class DynamicKeyInterceptor implements Interceptor { - - @Override - public Object intercept(Invocation invocation) throws Throwable { - MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; - SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); - - String[] keyColumns = mappedStatement.getKeyColumns(); - String[] keyProperties = mappedStatement.getKeyProperties(); - - if (mappedStatement.getResource().contains(".xml") && keyColumns != null && keyProperties != null) { - return invocation.proceed(); - } - - if (SqlCommandType.INSERT == sqlCommandType) { - Object parameter = invocation.getArgs()[1]; - log.debug("parameter: {}", parameter); - - Object object = parameter; - if (parameter instanceof MapperMethod.ParamMap paramMap) { - if (paramMap.get("param1") instanceof Collection) { - object = ((Collection) paramMap.get("param1")) - .stream().findFirst().get(); - } else { - object = paramMap.get("param1"); - } - } - TableMetaData metaData = TableMetaData.forClass(object.getClass()); - - String pkColumn = metaData.getPkColumn(); - String pkProperty = metaData.getPkProperty(); - log.debug("pkColumn {} pkProperty {}", pkColumn, pkProperty); - Method delimitedStringToArray = - MappedStatement.class.getDeclaredMethod("delimitedStringToArray", String.class); - delimitedStringToArray.setAccessible(true); - // keyColumns - Field field1 = MappedStatement.class.getDeclaredField("keyColumns"); - field1.setAccessible(true); - field1.set(mappedStatement, delimitedStringToArray.invoke(mappedStatement, pkProperty)); - // keyProperties - Field field2 = MappedStatement.class.getDeclaredField("keyProperties"); - field2.setAccessible(true); - field2.set(mappedStatement, delimitedStringToArray.invoke(mappedStatement, pkColumn)); - log.debug( - "mappedStatement keyColumns: {} keyProperties: {} keyGenerator: {}", - mappedStatement.getKeyColumns(), - mappedStatement.getKeyProperties(), - mappedStatement.getKeyGenerator()); - } - - return invocation.proceed(); - } -}