Spring Boot修改PersistentTokenRepository的Catalog存储persistent_logins表
我正在使用SpringBoot,通过以下配置启用持久化认证机制:
@Bean public PersistentTokenRepository persistentTokenRepository() { JdbcTokenRepositoryImpl tokenRepo = new JdbcTokenRepositoryImpl(); tokenRepo.setDataSource(dataSource); return tokenRepo; }
当前数据源包含data和useraccount两个catalog,默认情况下PersistentTokenRepository会在主catalog「data」中查找,但我希望将persistent_logins表存储在「useraccount」中,因此编写了如下实体类:
@Entity(name="PersistentLogin") @Table(name = "persistent_logins", catalog = "useraccount") @Data public class PersistentLogin implements Serializable { @Id private String series; private String username; private String token; private Timestamp last_used; }
但问题是系统始终在主catalog中查找persistent_logins表,请问有什么方法可以修改这个设置?
你编写的PersistentLogin实体类不会被JdbcTokenRepositoryImpl采用——这个实现类是通过原生JDBC执行硬编码SQL来操作表的,完全不依赖JPA的实体映射配置。要让它指向useraccount catalog下的表,有两种直接可行的方法:
方法一:设置表名前缀(推荐)
JdbcTokenRepositoryImpl提供了setTablePrefix()方法,直接指定包含catalog的前缀即可让SQL定位到目标表:
@Bean public PersistentTokenRepository persistentTokenRepository() { JdbcTokenRepositoryImpl tokenRepo = new JdbcTokenRepositoryImpl(); tokenRepo.setDataSource(dataSource); // 前缀带上catalog,格式为「catalog.」 tokenRepo.setTablePrefix("useraccount."); return tokenRepo; }
配置后,框架生成的SQL会自动变为SELECT ... FROM useraccount.persistent_logins ...,直接访问目标catalog下的表。
方法二:继承重写SQL语句(灵活定制)
如果需要更个性化的SQL调整,可以继承JdbcTokenRepositoryImpl并替换它的SQL属性:
public class CustomJdbcTokenRepository extends JdbcTokenRepositoryImpl { @Override protected void initDao() { super.initDao(); String targetTable = "useraccount.persistent_logins"; // 替换所有操作表的SQL语句 this.setCreateTableSql("CREATE TABLE IF NOT EXISTS " + targetTable + " (series VARCHAR(64) PRIMARY KEY, username VARCHAR(64) NOT NULL, token VARCHAR(64) NOT NULL, last_used TIMESTAMP NOT NULL)"); this.setInsertTokenSql("INSERT INTO " + targetTable + " (series, username, token, last_used) VALUES (?, ?, ?, ?)"); this.setUpdateTokenSql("UPDATE " + targetTable + " SET token = ?, last_used = ? WHERE series = ?"); this.setRemoveUserTokensSql("DELETE FROM " + targetTable + " WHERE username = ?"); this.setGetTokenSql("SELECT username, series, token, last_used FROM " + targetTable + " WHERE series = ?"); } }
然后在配置类中使用这个自定义实现:
@Bean public PersistentTokenRepository persistentTokenRepository() { CustomJdbcTokenRepository tokenRepo = new CustomJdbcTokenRepository(); tokenRepo.setDataSource(dataSource); return tokenRepo; }
注意:不同数据库对Catalog/Schema的语法可能有差异(比如MySQL中Catalog和Schema基本等价,Oracle中Schema对应用户),需要根据你的数据库类型调整表名的格式。
内容的提问来源于stack exchange,提问作者Discipulos

