在(一)敏感信息混淆中处理了加密字段,但如果要把这个加密字段使用mybatis入库,则会报以下错误:
Caused by: java.lang.IllegalStateException: Type handler was null on parameter mapping for property 'secret'. It was either not specified and/or could not be found for the javaType (github.zhangq.secretstringtest.config.SecretString) : jdbcType (null) combination. at org.apache.ibatis.mapping.ParameterMapping$Builder.validate(ParameterMapping.java:119) at org.apache.ibatis.mapping.ParameterMapping$Builder.build(ParameterMapping.java:104) at org.apache.ibatis.builder.SqlSourceBuilder$ParameterMappingTokenHandler.buildParameterMapping(SqlSourceBuilder.java:123) at org.apache.ibatis.builder.SqlSourceBuilder$ParameterMappingTokenHandler.handleToken(SqlSourceBuilder.java:67) at org.apache.ibatis.parsing.GenericTokenParser.parse(GenericTokenParser.java:78) at org.apache.ibatis.builder.SqlSourceBuilder.parse(SqlSourceBuilder.java:45) at org.apache.ibatis.scripting.defaults.RawSqlSource.<init>(RawSqlSource.java:46) at org.apache.ibatis.scripting.defaults.RawSqlSource.<init>(RawSqlSource.java:40) at org.apache.ibatis.scripting.xmltags.XMLScriptBuilder.parseScriptNode(XMLScriptBuilder.java:72) at org.apache.ibatis.scripting.xmltags.XMLLanguageDriver.createSqlSource(XMLLanguageDriver.java:44) at org.apache.ibatis.builder.xml.XMLStatementBuilder.parseStatementNode(XMLStatementBuilder.java:94) at org.apache.ibatis.builder.xml.XMLMapperBuilder.buildStatementFromContext(XMLMapperBuilder.java:135) at org.apache.ibatis.builder.xml.XMLMapperBuilder.buildStatementFromContext(XMLMapperBuilder.java:128) at org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement(XMLMapperBuilder.java:118) ... 82 more
简单看就是自定义的类型识别不了,这个时候我们就可以用到mybatis的TypeHandler了,TypeHandler有4个参数:
public interface TypeHandler<T> { void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException; T getResult(ResultSet rs, String columnName) throws SQLException; T getResult(ResultSet rs, int columnIndex) throws SQLException; T getResult(CallableStatement cs, int columnIndex) throws SQLException; }
看参数命名,可以很简单的理解到方法的意思,那么我们定义一个TypeHandler,分别实现这4个方法,如下:
/** * @author zhangqiuyang * Created on 2018/8/17. */ @MappedTypes(value = {SecretString.class}) public class SecretStringTypeHandler implements TypeHandler<SecretString> { /** * @param rs * @param columnName * @return * @throws SQLException */ @Override public SecretString getResult(ResultSet rs, String columnName) throws SQLException { String value = rs.getString(columnName); if (value != null) { return new SecretString(value); } return null; } /** * @param rs * @param columnIndex * @return * @throws SQLException */ @Override public SecretString getResult(ResultSet rs, int columnIndex) throws SQLException { String value = rs.getString(columnIndex); if (value != null) { return new SecretString(value); } return null; } /** * @param cs * @param columnIndex * @return * @throws SQLException */ @Override public SecretString getResult(CallableStatement cs, int columnIndex) throws SQLException { String value = cs.getString(columnIndex); if (value != null) { return new SecretString(value); } return null; } /** * @param ps * @param i * @param parameter * @param arg3 * @throws SQLException */ @Override public void setParameter(PreparedStatement ps, int i, SecretString parameter, JdbcType arg3) throws SQLException { String value = ""; if (parameter != null) { value = parameter.toString(); } ps.setString(i, value); } }
实现完成后,需要指定下配置,让mybatis扫描到这个TypeHandler,在application.yml增加mybatis.type-handlers-package:typehandler所在的包名。如果想从代码中注入配置,则需要在SqlSessionFactory的时候setVfs。
@Bean(name = "sqlSessionFactory") @Primary public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource, @Qualifier("configuration") org.apache.ibatis.session.Configuration configuration) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setVfs(SpringBootVFS.class); bean.setTypeHandlersPackage("xxxxxx"); bean.setDataSource(dataSource); bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapping/*.xml")); bean.setConfiguration(configuration);return bean.getObject(); }