From d74cae4ce8029f02a1438b09d35d57e8ac3ddcde Mon Sep 17 00:00:00 2001 From: CaptainB Date: Mon, 17 Apr 2023 16:27:30 +0800 Subject: [PATCH] build: db interceptor --- .../io/metersphere/config/MybatisConfig.java | 33 +++ .../sdk/interceptor/MybatisInterceptor.java | 204 +++++++++++++++ .../io/metersphere/sdk/util/BeanUtils.java | 66 +++++ .../io/metersphere/sdk/util/CodingUtil.java | 167 ++++++++++++ .../metersphere/sdk/util/CompressUtils.java | 237 ++++++++++++++++++ .../io/metersphere/sdk/util/EncryptUtils.java | 42 ++++ .../sdk/util/MybatisInterceptorConfig.java | 45 ++++ 7 files changed, 794 insertions(+) create mode 100644 backend/app/src/main/java/io/metersphere/config/MybatisConfig.java create mode 100644 backend/framework/sdk/src/main/java/io/metersphere/sdk/interceptor/MybatisInterceptor.java create mode 100644 backend/framework/sdk/src/main/java/io/metersphere/sdk/util/BeanUtils.java create mode 100644 backend/framework/sdk/src/main/java/io/metersphere/sdk/util/CodingUtil.java create mode 100644 backend/framework/sdk/src/main/java/io/metersphere/sdk/util/CompressUtils.java create mode 100644 backend/framework/sdk/src/main/java/io/metersphere/sdk/util/EncryptUtils.java create mode 100644 backend/framework/sdk/src/main/java/io/metersphere/sdk/util/MybatisInterceptorConfig.java diff --git a/backend/app/src/main/java/io/metersphere/config/MybatisConfig.java b/backend/app/src/main/java/io/metersphere/config/MybatisConfig.java new file mode 100644 index 0000000000..e208c7c194 --- /dev/null +++ b/backend/app/src/main/java/io/metersphere/config/MybatisConfig.java @@ -0,0 +1,33 @@ +package io.metersphere.config; + +import io.metersphere.sdk.interceptor.MybatisInterceptor; +import io.metersphere.sdk.util.CompressUtils; +import io.metersphere.sdk.util.MybatisInterceptorConfig; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import java.util.ArrayList; +import java.util.List; + +@Configuration +@MapperScan(basePackages = {"io.metersphere.*.mapper"}, sqlSessionFactoryRef = "sqlSessionFactory") +@EnableTransactionManagement +public class MybatisConfig { + @Bean + @ConditionalOnMissingBean + public MybatisInterceptor dbInterceptor() { + MybatisInterceptor interceptor = new MybatisInterceptor(); + List configList = new ArrayList<>(); +// configList.add(new MybatisInterceptorConfig(FileContent.class, "file", CompressUtils.class, "zip", "unZip")); +// configList.add(new MybatisInterceptorConfig(ApiTestReportDetail.class, "content", CompressUtils.class, "gzip", "unGzip")); +// configList.add(new MybatisInterceptorConfig(TestResource.class, "configuration")); +// configList.add(new MybatisInterceptorConfig(AuthSource.class, "configuration")); +// configList.add(new MybatisInterceptorConfig(LoadTestReportLog.class, "content", CompressUtils.class, "zipString", "unZipString")); + interceptor.setInterceptorConfigList(configList); + return interceptor; + } + +} diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/interceptor/MybatisInterceptor.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/interceptor/MybatisInterceptor.java new file mode 100644 index 0000000000..01b980c0c4 --- /dev/null +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/interceptor/MybatisInterceptor.java @@ -0,0 +1,204 @@ +package io.metersphere.sdk.interceptor; + +import io.metersphere.sdk.util.BeanUtils; +import io.metersphere.sdk.util.MybatisInterceptorConfig; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.ibatis.cache.CacheKey; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.plugin.*; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; + +import java.lang.reflect.Method; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +@Intercepts({ + @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}), + @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}), + @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}), +}) +public class MybatisInterceptor implements Interceptor { + + private List interceptorConfigList; + + private ConcurrentHashMap classMap = new ConcurrentHashMap<>(); + private ConcurrentHashMap>> interceptorConfigMap = new ConcurrentHashMap<>(); + + @Override + public Object intercept(Invocation invocation) throws Throwable { + String methodName = invocation.getMethod().getName(); + Object parameter = invocation.getArgs()[1]; + if (parameter != null && methodName.equals("update")) { + invocation.getArgs()[1] = process(parameter); + } + Object returnValue = invocation.proceed(); + Object result = returnValue; + if (returnValue instanceof ArrayList) { + List list = new ArrayList<>(); + boolean isDecrypted = false; + for (Object val : (ArrayList) returnValue) { + Object a = undo(val); + if (a != val) { + isDecrypted = true; + list.add(a); + } else { + break; + } + } + if (isDecrypted) { + result = list; + } + } else { + result = undo(returnValue); + } + return result; + } + + private Map> getConfig(Object p) { + Map> result = new HashMap<>(); + if (p == null) { + return null; + } + String pClassName = p.getClass().getName(); + if (interceptorConfigMap.get(pClassName) != null) { + return interceptorConfigMap.get(pClassName); + } + Map> m = new HashMap<>(); + for (MybatisInterceptorConfig interceptorConfig : interceptorConfigList) { + String className = interceptorConfig.getModelName(); + String attrName = interceptorConfig.getAttrName(); + if (StringUtils.isNotBlank(className)) { + Class c = classMap.get(className); + if (c == null) { + try { + c = Class.forName(className); + classMap.put(className, c); + } catch (ClassNotFoundException e) { + continue; + } + } + if (c.isInstance(p)) { + if (result.get(attrName) == null) { + result.put(attrName, new HashMap<>()); + } + if (StringUtils.isNotBlank(interceptorConfig.getInterceptorMethod())) { + result.get(attrName).put(Methods.encrypt.name(), interceptorConfig); + } + if (StringUtils.isNotBlank(interceptorConfig.getInterceptorMethod())) { + result.get(attrName).put(Methods.decrypt.name(), interceptorConfig); + } + } + } + } + interceptorConfigMap.put(pClassName, result); + return result; + } + + private Object process(Object obj) throws Throwable { + if (obj instanceof Map) { + Map paramMap = (Map) obj; + for (Object key : paramMap.keySet()) { + if (paramMap.get(key) != null) { + paramMap.put(key, process(paramMap.get(key))); + } + } + return paramMap; + } + Map> localInterceptorConfigMap = getConfig(obj); + if (MapUtils.isEmpty(localInterceptorConfigMap)) { + return obj; + } + Object newObject = obj.getClass().newInstance(); + BeanUtils.copyBean(newObject, obj); + for (String attrName : localInterceptorConfigMap.keySet()) { + if (MapUtils.isEmpty(localInterceptorConfigMap.get(attrName))) { + continue; + } + MybatisInterceptorConfig interceptorConfig = localInterceptorConfigMap.get(attrName).get(Methods.encrypt.name()); + if (interceptorConfig == null || StringUtils.isBlank(interceptorConfig.getInterceptorClass()) + || StringUtils.isBlank(interceptorConfig.getInterceptorMethod())) { + continue; + } + Object fieldValue = BeanUtils.getFieldValueByName(interceptorConfig.getAttrName(), newObject); + if (fieldValue != null) { + Class processClazz = Class.forName(interceptorConfig.getInterceptorClass()); + Method method = processClazz.getMethod(interceptorConfig.getInterceptorMethod(), Object.class); + Object processedValue = method.invoke(null, fieldValue); + if (processedValue instanceof byte[]) { + BeanUtils.setFieldValueByName(newObject, interceptorConfig.getAttrName(), processedValue, byte[].class); + } else { + BeanUtils.setFieldValueByName(newObject, interceptorConfig.getAttrName(), processedValue, fieldValue.getClass()); + } + } + } + + return newObject; + } + + private Object undo(Object obj) throws Throwable { + Map> localDecryptConfigMap = getConfig(obj); + Object result; + if (MapUtils.isEmpty(localDecryptConfigMap)) { + return obj; + } + result = obj.getClass().newInstance(); + BeanUtils.copyBean(result, obj); + for (String attrName : localDecryptConfigMap.keySet()) { + if (MapUtils.isEmpty(localDecryptConfigMap.get(attrName))) { + continue; + } + MybatisInterceptorConfig interceptorConfig = localDecryptConfigMap.get(attrName).get(Methods.decrypt.name()); + if (interceptorConfig == null || StringUtils.isBlank(interceptorConfig.getUndoClass()) + || StringUtils.isBlank(interceptorConfig.getUndoMethod())) { + continue; + } + Object fieldValue = BeanUtils.getFieldValueByName(interceptorConfig.getAttrName(), result); + if (fieldValue != null) { + Class processClazz = Class.forName(interceptorConfig.getUndoClass()); + Object undoValue; + if (fieldValue instanceof List) { + Method method = processClazz.getMethod(interceptorConfig.getUndoMethod(), List.class, String.class); + //fieldValue获取的是list的引用,所以list类型的属性不需要再调用setFieldValueByName了 + method.invoke(null, fieldValue, interceptorConfig.getAttrNameForList()); + } else { + Method method = processClazz.getMethod(interceptorConfig.getUndoMethod(), Object.class); + undoValue = method.invoke(null, fieldValue); + if (undoValue instanceof byte[]) { + BeanUtils.setFieldValueByName(result, interceptorConfig.getAttrName(), undoValue, byte[].class); + } else { + BeanUtils.setFieldValueByName(result, interceptorConfig.getAttrName(), undoValue, fieldValue.getClass()); + } + } + } + } + return result; + } + + @Override + public Object plugin(Object target) { + return Plugin.wrap(target, this); + } + + @Override + public void setProperties(Properties properties) { + // TODO Auto-generated method stub + + } + + public List getInterceptorConfigList() { + return interceptorConfigList; + } + + public void setInterceptorConfigList(List interceptorConfigList) { + this.interceptorConfigList = interceptorConfigList; + } + + private enum Methods { + encrypt, decrypt + } + +} \ No newline at end of file diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/BeanUtils.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/BeanUtils.java new file mode 100644 index 0000000000..2626722b11 --- /dev/null +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/BeanUtils.java @@ -0,0 +1,66 @@ +package io.metersphere.sdk.util; + +import org.apache.commons.lang3.StringUtils; + +import java.lang.reflect.Method; + +public class BeanUtils { + + public static T copyBean(T target, Object source) { + try { + org.springframework.beans.BeanUtils.copyProperties(source, target); + return target; + } catch (Exception e) { + throw new RuntimeException("Failed to copy object: ", e); + } + } + + public static T copyBean(T target, Object source, String... ignoreProperties) { + try { + org.springframework.beans.BeanUtils.copyProperties(source, target, ignoreProperties); + return target; + } catch (Exception e) { + throw new RuntimeException("Failed to copy object: ", e); + } + } + + public static Object getFieldValueByName(String fieldName, Object bean) { + try { + if (StringUtils.isBlank(fieldName)) { + return null; + } + String firstLetter = fieldName.substring(0, 1).toUpperCase(); + String getter = "get" + firstLetter + fieldName.substring(1); + Method method = bean.getClass().getMethod(getter); + return method.invoke(bean); + } catch (Exception e) { + return null; + } + } + + public static void setFieldValueByName(Object bean, String fieldName, Object value, Class type) { + try { + if (StringUtils.isBlank(fieldName)) { + return; + } + String firstLetter = fieldName.substring(0, 1).toUpperCase(); + String setter = "set" + firstLetter + fieldName.substring(1); + Method method = bean.getClass().getMethod(setter, type); + method.invoke(bean, value); + } catch (Exception ignore) { + } + } + + public static Method getMethod(Object bean, String fieldName, Class type) { + try { + if (StringUtils.isBlank(fieldName)) { + return null; + } + String firstLetter = fieldName.substring(0, 1).toUpperCase(); + String setter = "set" + firstLetter + fieldName.substring(1); + return bean.getClass().getMethod(setter, type); + } catch (Exception e) { + return null; + } + } +} diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/CodingUtil.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/CodingUtil.java new file mode 100644 index 0000000000..56b285bb98 --- /dev/null +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/CodingUtil.java @@ -0,0 +1,167 @@ +package io.metersphere.sdk.util; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.StringUtils; + +import javax.crypto.*; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.security.MessageDigest; + +/** + * 加密解密工具 + * + * @author kun.mo + */ +public class CodingUtil { + + private static final String UTF_8 = "UTF-8"; + + private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + /** + * MD5加密 + * + * @param src 要加密的串 + * @return 加密后的字符串 + */ + public static String md5(String src) { + return md5(src, UTF_8); + } + + /** + * MD5加密 + * + * @param src 要加密的串 + * @param charset 加密字符集 + * @return 加密后的字符串 + */ + public static String md5(String src, String charset) { + try { + byte[] strTemp = StringUtils.isEmpty(charset) ? src.getBytes() : src.getBytes(charset); + MessageDigest mdTemp = MessageDigest.getInstance("MD5"); + mdTemp.update(strTemp); + + byte[] md = mdTemp.digest(); + int j = md.length; + char[] str = new char[j * 2]; + int k = 0; + + for (byte byte0 : md) { + str[k++] = HEX_DIGITS[byte0 >>> 4 & 0xf]; + str[k++] = HEX_DIGITS[byte0 & 0xf]; + } + + return new String(str); + } catch (Exception e) { + throw new RuntimeException("MD5 encrypt error:", e); + } + } + + /** + * BASE64解密 + * + * @param src 待解密的字符串 + * @return 解密后的字符串 + */ + public static String base64Decoding(String src) { + byte[] b; + String result = null; + if (src != null) { + try { + b = Base64.decodeBase64(src); + result = new String(b, UTF_8); + } catch (Exception e) { + throw new RuntimeException("BASE64 decoding error:", e); + } + } + return result; + } + + /** + * BASE64加密 + * + * @param src 待加密的字符串 + * @return 加密后的字符串 + */ + public static String base64Encoding(String src) { + String result = null; + if (src != null) { + try { + result = Base64.encodeBase64String(src.getBytes(UTF_8)); + } catch (Exception e) { + throw new RuntimeException("BASE64 encoding error:", e); + } + } + return result; + } + + /** + * AES加密 + * + * @param src 待加密字符串 + * @param secretKey 密钥 + * @param iv 向量 + * @return 加密后字符串 + */ + public static String aesEncrypt(String src, String secretKey, String iv) { + if (StringUtils.isBlank(secretKey)) { + throw new RuntimeException("secretKey is empty"); + } + + try { + byte[] raw = secretKey.getBytes(UTF_8); + SecretKeySpec secretKeySpec = new SecretKeySpec(raw, "AES"); + // "算法/模式/补码方式" ECB + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + IvParameterSpec iv1 = new IvParameterSpec(iv.getBytes()); + cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, iv1); + byte[] encrypted = cipher.doFinal(src.getBytes(UTF_8)); + return Base64.encodeBase64String(encrypted); + } catch (Exception e) { + throw new RuntimeException("AES encrypt error:", e); + } + + } + + /** + * AES 解密 + * + * @param src 待解密字符串 + * @param secretKey 密钥 + * @param iv 向量 + * @return 解密后字符串 + */ + public static String aesDecrypt(String src, String secretKey, String iv) { + if (StringUtils.isBlank(secretKey)) { + throw new RuntimeException("secretKey is empty"); + } + try { + byte[] raw = secretKey.getBytes(UTF_8); + SecretKeySpec secretKeySpec = new SecretKeySpec(raw, "AES"); + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + IvParameterSpec iv1 = new IvParameterSpec(iv.getBytes()); + cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, iv1); + byte[] encrypted1 = Base64.decodeBase64(src); + byte[] original = cipher.doFinal(encrypted1); + return new String(original, UTF_8); + } catch (BadPaddingException | IllegalBlockSizeException e) { + // 解密的原字符串为非加密字符串,则直接返回原字符串 + return src; + } catch (Exception e) { + throw new RuntimeException("decrypt error,please check parameters", e); + } + } + + public static String secretKey() { + try { + KeyGenerator keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(128); + SecretKey secretKey = keyGen.generateKey(); + return Base64.encodeBase64String(secretKey.getEncoded()); + } catch (Exception e) { + throw new RuntimeException("generate secretKey error", e); + } + + } +} diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/CompressUtils.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/CompressUtils.java new file mode 100644 index 0000000000..b34376962f --- /dev/null +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/CompressUtils.java @@ -0,0 +1,237 @@ +package io.metersphere.sdk.util; + +import org.apache.commons.codec.binary.Base64; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.zip.*; + +public class CompressUtils { + private final static String ZIP_PATH = "/opt/metersphere/data/tmp/"; + + /*** + * Zip压缩 + * + * @param data 待压缩数据 + * @return 压缩后数据 + */ + public static Object zip(Object data) { + if (!(data instanceof byte[])) { + return data; + } + + byte[] temp = (byte[]) data; + byte[] b = (byte[]) data; + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ZipOutputStream zip = new ZipOutputStream(bos); + ZipEntry entry = new ZipEntry("zip"); + entry.setSize(temp.length); + zip.putNextEntry(entry); + zip.write(temp); + zip.closeEntry(); + zip.close(); + b = bos.toByteArray(); + bos.close(); + } catch (Exception ignore) { + } + + return b; + } + + + private static File getFile(String fileName) throws IOException { + // 创建文件对象 + File file; + if (ZIP_PATH != null && !ZIP_PATH.equals("")) { + file = new File(ZIP_PATH, fileName); + } else { + file = new File(fileName); + } + if (!file.exists()) { + file.createNewFile(); + } + // 返回文件 + return file; + } + + public static FileOutputStream getFileStream(File file) throws FileNotFoundException { + return new FileOutputStream(file); + } + + private static void zipFile(File file, ZipOutputStream zipOutputStream) throws IOException { + if (file.exists()) { + if (file.isFile()) { + FileInputStream fis = new FileInputStream(file); + BufferedInputStream bis = new BufferedInputStream(fis); + ZipEntry entry = new ZipEntry(file.getName()); + zipOutputStream.putNextEntry(entry); + + final int MAX_BYTE = 10 * 1024 * 1024; // 最大流为10MB + long streamTotal = 0; // 接收流的容量 + int streamNum = 0; // 需要分开的流数目 + int leaveByte = 0; // 文件剩下的字符数 + byte[] buffer; // byte数据接受文件的数据 + + streamTotal = bis.available(); // 获取流的最大字符数 + streamNum = (int) Math.floor(streamTotal / MAX_BYTE); + leaveByte = (int) (streamTotal % MAX_BYTE); + + if (streamNum > 0) { + for (int i = 0; i < streamNum; i++) { + buffer = new byte[MAX_BYTE]; + bis.read(buffer, 0, MAX_BYTE); + zipOutputStream.write(buffer, 0, MAX_BYTE); + } + } + + // 写入剩下的流数据 + buffer = new byte[leaveByte]; + bis.read(buffer, 0, leaveByte); // 读入流 + zipOutputStream.write(buffer, 0, leaveByte); // 写入流 + zipOutputStream.closeEntry(); // 关闭当前的zip entry + + // 关闭输入流 + bis.close(); + fis.close(); + } + } + } + + /** + * 将多个文件压缩 + * + * @param fileList 待压缩的文件列表 + * @param zipFileName 压缩文件名 + * @return 返回压缩好的文件 + * @throws IOException + */ + public static File zipFiles(String zipFileName, List fileList) throws IOException { + File zipFile = getFile(zipFileName); + // 文件输出流 + FileOutputStream outputStream = getFileStream(zipFile); + // 压缩流 + ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream); + + int size = fileList.size(); + // 压缩列表中的文件 + for (int i = 0; i < size; i++) { + File file = fileList.get(i); + zipFile(file, zipOutputStream); + } + // 关闭压缩流、文件流 + zipOutputStream.close(); + outputStream.close(); + return zipFile; + } + + /*** + * Zip解压 + * + * @param data 待解压数据 + * @return 解压后数据 + */ + public static Object unZip(Object data) { + if (!(data instanceof byte[])) { + return data; + } + byte[] temp = (byte[]) data; + byte[] b = (byte[]) data; + try { + ByteArrayInputStream bis = new ByteArrayInputStream(temp); + ZipInputStream zip = new ZipInputStream(bis); + while (zip.getNextEntry() != null) { + byte[] buf = new byte[1024]; + int num; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + while ((num = zip.read(buf, 0, buf.length)) != -1) { + baos.write(buf, 0, num); + } + b = baos.toByteArray(); + baos.flush(); + baos.close(); + } + zip.close(); + bis.close(); + } catch (Exception ignore) { + } + return b; + } + + /** + * GZip压缩 + * + * @param data 待压缩数据 + * @return 压缩后数 + */ + public static Object gzip(Object data) { + if (!(data instanceof byte[])) { + return data; + } + byte[] bytes = (byte[]) data; + try (ByteArrayOutputStream obj = new ByteArrayOutputStream(); GZIPOutputStream gzip = new GZIPOutputStream(obj)) { + gzip.write(bytes); + gzip.flush(); + gzip.finish(); + return obj.toByteArray(); + } catch (Exception e) { + return data; + } + } + + /** + * GZip解压 + * + * @param data 待解压数据 + * @return 解压后数据 + */ + public static Object unGzip(Object data) { + if (!(data instanceof byte[])) { + return data; + } + byte[] bytes = (byte[]) data; + if (bytes.length == 0) { + return bytes; + } + try (GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(bytes)); ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + byte[] buffer = new byte[8192]; + int len; + while ((len = gis.read(buffer)) > 0) { + baos.write(buffer, 0, len); + } + baos.flush(); + return baos.toByteArray(); + } catch (Exception e) { + return data; + } + } + + public static Object zipString(Object data) { + if (!(data instanceof String)) { + return data; + } + try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { + try (DeflaterOutputStream deflaterOutputStream = new DeflaterOutputStream(out)) { + deflaterOutputStream.write(((String) data).getBytes(StandardCharsets.UTF_8)); + } + return Base64.encodeBase64String(out.toByteArray()); + } catch (Exception e) { + return data; + } + } + + public static Object unZipString(Object data) { + if (!(data instanceof String)) { + return data; + } + try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { + try (OutputStream outputStream = new InflaterOutputStream(os)) { + outputStream.write(Base64.decodeBase64((String) data)); + } + return os.toString(StandardCharsets.UTF_8); + } catch (Exception e) { + return data; + } + } +} diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/EncryptUtils.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/EncryptUtils.java new file mode 100644 index 0000000000..555a2a3414 --- /dev/null +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/EncryptUtils.java @@ -0,0 +1,42 @@ +package io.metersphere.sdk.util; + +import java.util.List; +import java.util.stream.Collectors; + +public class EncryptUtils extends CodingUtil { + + private static final String secretKey = "www.fit2cloud.co"; + private static final String iv = "1234567890123456"; + + + public static Object aesEncrypt(Object o) { + if (o == null) { + return null; + } + return aesEncrypt(o.toString(), secretKey, iv); + } + + public static Object aesDecrypt(Object o) { + if (o == null) { + return null; + } + return aesDecrypt(o.toString(), secretKey, iv); + } + + public static Object aesDecrypt(List o, String attrName) { + if (o == null) { + return null; + } + return o.stream() + .filter(element -> BeanUtils.getFieldValueByName(attrName, element) != null) + .peek(element -> BeanUtils.setFieldValueByName(element, attrName, aesDecrypt(BeanUtils.getFieldValueByName(attrName, element).toString(), secretKey, iv), String.class)) + .collect(Collectors.toList()); + } + + public static Object md5Encrypt(Object o) { + if (o == null) { + return null; + } + return md5(o.toString()); + } +} diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/MybatisInterceptorConfig.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/MybatisInterceptorConfig.java new file mode 100644 index 0000000000..cae6fea17a --- /dev/null +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/MybatisInterceptorConfig.java @@ -0,0 +1,45 @@ +package io.metersphere.sdk.util; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class MybatisInterceptorConfig { + private String modelName; + private String attrName; + private String attrNameForList; + private String interceptorClass; + private String interceptorMethod; + private String undoClass; + private String undoMethod; + + public MybatisInterceptorConfig() { + } + + /** + * 用时需谨慎!!!!! + * 主要配置多个的时候,参数少一点 + * + * @param modelClass + * @param attrName + */ + public MybatisInterceptorConfig(Class modelClass, String attrName) { + this.modelName = modelClass.getName(); + this.attrName = attrName; + this.interceptorClass = EncryptUtils.class.getName(); + this.interceptorMethod = "aesEncrypt"; + this.undoClass = EncryptUtils.class.getName(); + this.undoMethod = "aesDecrypt"; + } + + public MybatisInterceptorConfig(Class modelClass, String attrName, Class interceptorClass, String interceptorMethod, String undoMethod) { + this.modelName = modelClass.getName(); + this.attrName = attrName; + this.interceptorClass = interceptorClass.getName(); + this.interceptorMethod = interceptorMethod; + this.undoClass = interceptorClass.getName(); + this.undoMethod = undoMethod; + } + +}