You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring+Kotlin环境下如何用配置动态值替换硬编码表名?

动态替换表名及Spring接口注入动态值解决方案

场景与问题

使用Spring + Kotlin开发Web应用,现有MyBatis Mapper及表定义类如下:

MyEntityMapper代码

@Mapper
@Repository
interface MyEntityMapper {
    /**
     * Поиск MyEntity.
     *
     * @param selectStatement Параметры запроса.
     * @return List MyEntity.
     */
    @SelectProvider(type = SqlProviderAdapter::class, method = "select")
    @Results(
        id = "myEntityMap",
        value = [
            Result(property = "name", column = "NAME"),
            Result(property = "price", column = "PRICE"),
            Result(property = "age", column = "AGE")
        ]
    )
    fun findListBy(selectStatement: SelectStatementProvider): List<MyEntity>

    /**
     * Обновление MyEntity.
     *
     * @param updateStatement MyEntity
     * @return Количество обновленных записей.
     */
    @UpdateProvider(type = SqlProviderAdapter::class, method = "update")
    fun update(updateStatement: UpdateStatementProvider): Int
}

fun MyEntityMapper.selectMany(completer: SelectCompleter) =
    selectList(this::findListBy, myEntity_.all, myEntity, completer)

fun MyEntityMapper.update(completer: UpdateCompleter) =
    update(this::update, MyEntity_, completer)

MyEntity_表定义类(非Spring组件)

class MyEntity_ : SqlTable("my_entity") {
    val name = column<String>(name = "NAME", jdbcType = VARCHAR)
    val price = column<String>(name = "PRICE", jdbcType = VARCHAR)
    val age = column<String>(name = "AGE", jdbcType = VARCHAR)

    val all = listOf(
        name,
        price,
        age
    )

    companion object {
        val myEntity_ = MyEntity_()
    }
}

当前核心问题:class MyEntity_ : SqlTable("my_entity")中的表名"my_entity"为硬编码,希望替换为application.properties中的配置值;同时想了解Spring中如何为接口注入动态值。


一、动态替换表名的实现方案

方案1:将MyEntity_转为Spring组件,通过构造函数注入表名

修改MyEntity_类,移除静态单例,通过@Value注入配置中的表名:

@Component
class MyEntity_(@Value("\${table.names.my_entity}") tableName: String) : SqlTable(tableName) {
    val name = column<String>(name = "NAME", jdbcType = VARCHAR)
    val price = column<String>(name = "PRICE", jdbcType = VARCHAR)
    val age = column<String>(name = "AGE", jdbcType = VARCHAR)

    val all = listOf(name, price, age)
}

在application.properties中添加配置:

table.names.my_entity=my_entity

后续使用时,通过Spring的@Autowired注入MyEntity_实例,修改原扩展函数:

fun MyEntityMapper.selectMany(myEntity_: MyEntity_, completer: SelectCompleter) =
    selectList(this::findListBy, myEntity_.all, myEntity, completer)

方案2:通过配置类创建MyEntity_实例(不修改类本身为组件)

如果不想将MyEntity_标记为Spring组件,可通过配置类动态传入表名:

首先修改MyEntity_构造函数:

class MyEntity_(tableName: String) : SqlTable(tableName) {
    val name = column<String>(name = "NAME", jdbcType = VARCHAR)
    val price = column<String>(name = "PRICE", jdbcType = VARCHAR)
    val age = column<String>(name = "AGE", jdbcType = VARCHAR)

    val all = listOf(name, price, age)
}

创建配置类提供Bean:

@Configuration
class TableConfig {
    @Value("\${table.names.my_entity}")
    private lateinit var myEntityTableName: String

    @Bean
    fun myEntity_(): MyEntity_ {
        return MyEntity_(myEntityTableName)
    }
}

同样在application.properties中配置表名,使用时通过@Autowired注入MyEntity_实例即可。


二、Spring中为接口注入动态值的方法

接口无法直接实例化,需通过以下方式实现动态值注入:

方法1:为接口编写实现类,注入动态值

定义接口后,创建Spring管理的实现类,在实现类中注入配置值:

interface TableNameProvider {
    fun getMyEntityTableName(): String
}

@Component
class TableNameProviderImpl(@Value("\${table.names.my_entity}") private val tableName: String) : TableNameProvider {
    override fun getMyEntityTableName(): String {
        return tableName
    }
}

后续在需要的地方注入TableNameProvider接口即可获取动态值。

方法2:结合MyBatis Provider注入动态值(针对Mapper场景)

如果需要在MyBatis的Provider类中使用动态值,可将Provider类转为Spring组件,注入配置值:

@Component
class SqlProviderAdapter {
    @Value("\${table.names.my_entity}")
    private lateinit var myEntityTableName: String

    fun select(selectStatement: SelectStatementProvider): String {
        // 动态拼接SQL时使用myEntityTableName
        return "SELECT NAME, PRICE, AGE FROM $myEntityTableName ${selectStatement.whereClause}"
    }
}

注意确保MyBatis能识别Spring管理的Provider类,可通过@MapperScan配置或在Mapper的@SelectProvider中指定Spring Bean的名称。


内容的提问来源于stack exchange,提问作者Pavel Bukhalov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 03:10:11