diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
index 2d48df367..5567cedc7 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
@@ -58,6 +58,14 @@
com.baomidou
dynamic-datasource-spring-boot-starter
+
+
+
+ com.github.ulisesbocchio
+ jasypt-spring-boot-starter
+ true
+
+
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/EncryptTypeHandler.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/EncryptTypeHandler.java
new file mode 100644
index 000000000..da55e057c
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/EncryptTypeHandler.java
@@ -0,0 +1,63 @@
+package cn.iocoder.yudao.framework.mybatis.core.type;
+
+import cn.hutool.core.lang.Assert;
+import cn.hutool.extra.spring.SpringUtil;
+import org.apache.ibatis.type.BaseTypeHandler;
+import org.apache.ibatis.type.JdbcType;
+import org.jasypt.encryption.StringEncryptor;
+
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * 字段字段的 TypeHandler 实现类,基于 {@link StringEncryptor} 实现
+ * 可通过 jasypt.encryptor.password 配置项,设置密钥
+ *
+ * @author 芋道源码
+ */
+public class EncryptTypeHandler extends BaseTypeHandler {
+
+ private static StringEncryptor encryptor;
+
+ @Override
+ public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
+ ps.setString(i, getEncryptor().encrypt(parameter));
+ }
+
+ @Override
+ public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
+ String value = rs.getString(columnName);
+ return getResult(value);
+ }
+
+ @Override
+ public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
+ String value = rs.getString(columnIndex);
+ return getResult(value);
+ }
+
+ @Override
+ public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
+ String value = cs.getString(columnIndex);
+ return getResult(value);
+ }
+
+ private String getResult(String value) {
+ if (value == null) {
+ return null;
+ }
+ return getEncryptor().decrypt(value);
+ }
+
+ private StringEncryptor getEncryptor() {
+ if (encryptor != null) {
+ return encryptor;
+ }
+ encryptor = SpringUtil.getBean(StringEncryptor.class);
+ Assert.notNull(encryptor, "StringEncryptor 不能为空");
+ return encryptor;
+ }
+
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/StringLiSTTypeHandler.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/StringListTypeHandler.java
similarity index 96%
rename from yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/StringLiSTTypeHandler.java
rename to yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/StringListTypeHandler.java
index f9811c418..598a15ef7 100644
--- a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/StringLiSTTypeHandler.java
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/StringListTypeHandler.java
@@ -21,7 +21,7 @@ import java.util.List;
*/
@MappedJdbcTypes(JdbcType.VARCHAR)
@MappedTypes(List.class)
-public class StringLiSTTypeHandler implements TypeHandler> {
+public class StringListTypeHandler implements TypeHandler> {
private static final String COMMA = ",";
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/db/DataSourceConfigDO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/db/DataSourceConfigDO.java
index 9b4c36084..138babe52 100644
--- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/db/DataSourceConfigDO.java
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/db/DataSourceConfigDO.java
@@ -1,7 +1,9 @@
package cn.iocoder.yudao.module.infra.dal.dataobject.db;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.framework.mybatis.core.type.EncryptTypeHandler;
import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@@ -10,7 +12,7 @@ import lombok.Data;
*
* @author 芋道源码
*/
-@TableName("infra_data_source_config")
+@TableName(value = "infra_data_source_config", autoResultMap = true)
@KeySequence("infra_data_source_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
public class DataSourceConfigDO extends BaseDO {
@@ -40,6 +42,7 @@ public class DataSourceConfigDO extends BaseDO {
/**
* 密码
*/
+ @TableField(typeHandler = EncryptTypeHandler.class)
private String password;
}
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImpl.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImpl.java
index acc8faa1c..f2fd0a408 100755
--- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImpl.java
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImpl.java
@@ -8,7 +8,6 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO;
import cn.iocoder.yudao.module.infra.dal.mysql.db.DataSourceConfigMapper;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
-import org.jasypt.encryption.StringEncryptor;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@@ -32,9 +31,6 @@ public class DataSourceConfigServiceImpl implements DataSourceConfigService {
@Resource
private DataSourceConfigMapper dataSourceConfigMapper;
- @Resource
- private StringEncryptor stringEncryptor;
-
@Resource
private DynamicDataSourceProperties dynamicDataSourceProperties;
@@ -44,7 +40,6 @@ public class DataSourceConfigServiceImpl implements DataSourceConfigService {
checkConnectionOK(dataSourceConfig);
// 插入
- dataSourceConfig.setPassword(stringEncryptor.encrypt(createReqVO.getPassword()));
dataSourceConfigMapper.insert(dataSourceConfig);
// 返回
return dataSourceConfig.getId();
@@ -58,7 +53,6 @@ public class DataSourceConfigServiceImpl implements DataSourceConfigService {
checkConnectionOK(updateObj);
// 更新
- updateObj.setPassword(stringEncryptor.encrypt(updateObj.getPassword()));
dataSourceConfigMapper.updateById(updateObj);
}
@@ -83,12 +77,7 @@ public class DataSourceConfigServiceImpl implements DataSourceConfigService {
return buildMasterDataSourceConfig();
}
// 从 DB 中读取
- DataSourceConfigDO dataSourceConfig = dataSourceConfigMapper.selectById(id);
- try {
- dataSourceConfig.setPassword(stringEncryptor.decrypt(dataSourceConfig.getPassword()));
- } catch (Exception ignore) { // 解码失败,则不解码
- }
- return dataSourceConfig;
+ return dataSourceConfigMapper.selectById(id);
}
@Override
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImplTest.java b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImplTest.java
index c66e92b79..990067e3a 100755
--- a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImplTest.java
+++ b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/db/DataSourceConfigServiceImplTest.java
@@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.infra.service.db;
+import cn.hutool.core.util.ReflectUtil;
+import cn.iocoder.yudao.framework.mybatis.core.type.EncryptTypeHandler;
import cn.iocoder.yudao.framework.mybatis.core.util.JdbcUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.infra.controller.admin.db.vo.DataSourceConfigCreateReqVO;
@@ -8,8 +10,10 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.db.DataSourceConfigDO;
import cn.iocoder.yudao.module.infra.dal.mysql.db.DataSourceConfigMapper;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import org.jasypt.encryption.StringEncryptor;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
+import org.mockito.stubbing.Answer;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
@@ -21,7 +25,10 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.DATA_SOURCE_CONFIG_NOT_EXISTS;
import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.Mockito.*;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
/**
* {@link DataSourceConfigServiceImpl} 的单元测试类
@@ -43,13 +50,20 @@ public class DataSourceConfigServiceImplTest extends BaseDbUnitTest {
@MockBean
private DynamicDataSourceProperties dynamicDataSourceProperties;
+ @BeforeEach
+ public void setUp() {
+ // mock 一个空实现的 StringEncryptor,避免 EncryptTypeHandler 报错
+ ReflectUtil.setFieldValue(EncryptTypeHandler.class, "encryptor", stringEncryptor);
+ when(stringEncryptor.encrypt(anyString())).then((Answer) invocation -> invocation.getArgument(0));
+ when(stringEncryptor.decrypt(anyString())).then((Answer) invocation -> invocation.getArgument(0));
+ }
+
@Test
public void testCreateDataSourceConfig_success() {
try (MockedStatic databaseUtilsMock = mockStatic(JdbcUtils.class)) {
// 准备参数
DataSourceConfigCreateReqVO reqVO = randomPojo(DataSourceConfigCreateReqVO.class);
// mock 方法
- when(stringEncryptor.encrypt(eq(reqVO.getPassword()))).thenReturn("123456");
databaseUtilsMock.when(() -> JdbcUtils.isConnectionOK(eq(reqVO.getUrl()),
eq(reqVO.getUsername()), eq(reqVO.getPassword()))).thenReturn(true);
@@ -59,8 +73,7 @@ public class DataSourceConfigServiceImplTest extends BaseDbUnitTest {
assertNotNull(dataSourceConfigId);
// 校验记录的属性是否正确
DataSourceConfigDO dataSourceConfig = dataSourceConfigMapper.selectById(dataSourceConfigId);
- assertPojoEquals(reqVO, dataSourceConfig, "password");
- assertEquals("123456", dataSourceConfig.getPassword());
+ assertPojoEquals(reqVO, dataSourceConfig);
}
}
@@ -75,7 +88,7 @@ public class DataSourceConfigServiceImplTest extends BaseDbUnitTest {
o.setId(dbDataSourceConfig.getId()); // 设置更新的 ID
});
// mock 方法
- when(stringEncryptor.encrypt(eq(reqVO.getPassword()))).thenReturn("123456");
+// when(stringEncryptor.encrypt(eq(reqVO.getPassword()))).thenReturn("123456");
databaseUtilsMock.when(() -> JdbcUtils.isConnectionOK(eq(reqVO.getUrl()),
eq(reqVO.getUsername()), eq(reqVO.getPassword()))).thenReturn(true);
@@ -83,8 +96,7 @@ public class DataSourceConfigServiceImplTest extends BaseDbUnitTest {
dataSourceConfigService.updateDataSourceConfig(reqVO);
// 校验是否更新正确
DataSourceConfigDO dataSourceConfig = dataSourceConfigMapper.selectById(reqVO.getId()); // 获取最新的
- assertPojoEquals(reqVO, dataSourceConfig, "password");
- assertEquals("123456", dataSourceConfig.getPassword());
+ assertPojoEquals(reqVO, dataSourceConfig);
}
}
diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sensitiveword/SensitiveWordDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sensitiveword/SensitiveWordDO.java
index 0f56bfb3b..37dc57968 100644
--- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sensitiveword/SensitiveWordDO.java
+++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sensitiveword/SensitiveWordDO.java
@@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
-import cn.iocoder.yudao.framework.mybatis.core.type.StringLiSTTypeHandler;
+import cn.iocoder.yudao.framework.mybatis.core.type.StringListTypeHandler;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
@@ -46,7 +46,7 @@ public class SensitiveWordDO extends BaseDO {
* 例如说,tag 有短信、论坛两种,敏感词 "推广" 在短信下是敏感词,在论坛下不是敏感词。
* 此时,我们会存储一条敏感词记录,它的 name 为"推广",tag 为短信。
*/
- @TableField(typeHandler = StringLiSTTypeHandler.class)
+ @TableField(typeHandler = StringListTypeHandler.class)
private List tags;
/**
* 状态
diff --git a/yudao-server/src/main/java/cn/iocoder/yudao/server/framework/tip/core/TipApplicationRunner.java b/yudao-server/src/main/java/cn/iocoder/yudao/server/framework/tip/core/TipApplicationRunner.java
index 469256f6d..18460f99e 100644
--- a/yudao-server/src/main/java/cn/iocoder/yudao/server/framework/tip/core/TipApplicationRunner.java
+++ b/yudao-server/src/main/java/cn/iocoder/yudao/server/framework/tip/core/TipApplicationRunner.java
@@ -23,7 +23,7 @@ public class TipApplicationRunner implements ApplicationRunner {
"项目启动成功!\n\t" +
"接口文档: \t{} \n\t" +
"开发文档: \t{} \n\t" +
- "视频教程: \t{} \n" +
+ "视频教程: \t{} \n\t" +
"源码解析: \t{} \n" +
"----------------------------------------------------------",
"https://mtw.so/6w48hX",