我的实体模型中有以下字段。
@Column(name="key")
@ColumnTransformer(
read="AES_DECRYPT(key, SHA1('passcode'))",
write="AES_ENCRYPT(?, SHA1('passcode'))")
private String secret_key;
我正在使用MySql数据库,而hibernate将使用AES_ENCRYPT和AES_DECRYPT函数完美地加密/解密密钥值。但是,spring嵌入式数据库(HSQL或H2)不知道这个特定的MySql函数。它会引发以下错误:
javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not insert: [com.xxx.Table]
at ...
Caused by: org.hibernate.exception.SQLGrammarException: could not insert: [com.xxx.Table]
at ...
Caused by: java.sql.SQLSyntaxErrorException: user lacks privilege or object not found: AES_ENCRYPT
所以我的问题是,
谢谢
答案 0 :(得分:1)
将此类添加到测试配置中:
@Component
public class RemoveAesFunction {
@PostConstruct
public void postConstruct() {
setKey(MyEntity.class);
}
private void setKey(Class<?> clazz) {
try {
Field field = clazz.getDeclaredField("firstName");
ColumnTransformer columnTransformer = field.getDeclaredAnnotation(ColumnTransformer.class);
updateAnnotationValue(columnTransformer, "read","");
updateAnnotationValue(columnTransformer, "write","?");
} catch (NoSuchFieldException | SecurityException e) {
throw new RuntimeException();
}
}
@SuppressWarnings("unchecked")
private void updateAnnotationValue(Annotation annotation, String annotationProperty,String value) {
Object handler = Proxy.getInvocationHandler(annotation);
Field merberValuesField;
try {
merberValuesField = handler.getClass().getDeclaredField("memberValues");
} catch (NoSuchFieldException | SecurityException e) {
throw new IllegalStateException(e);
}
merberValuesField.setAccessible(true);
Map<String, Object> memberValues;
try {
memberValues = (Map<String, Object>) merberValuesField.get(handler);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
memberValues.put(annotationProperty, value);
}
}
答案 1 :(得分:0)
您的实体类和dbms函数之间存在强大的耦合
在这里,最大的问题是耦合是在运行时无法轻易禁用的元数据上。因此,要编写一些单元测试,它将鼓励您在运行时使用字节码修改来拥有您想要的。但它会给您的单元测试带来复杂性和潜在的副作用
此外,代码应该尽可能自然地测试(只是一句话:使用TDD方法,这种问题可能会被快速注意和处理)。
因此,如果您可以修改代码,我认为更好的想法是将加密/解密问题与域事项分开,以便您可以选择加密/解密问题的实现。
这样,在应用范围中,您可以使用真正的实现和
在单元测试中,你可以使用一个虚假的实现,它什么都不做,甚至没有更好的实现
Hibernate提供了实体监听器机制。有了它们,你可以在实体生命周期的某个时候有钩子。
在这里您可以找到更多信息: https://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/listeners.h TML
这些回调可能让您感兴趣:
@PrePersist在实体管理器持久运行之前执行 实际执行或级联。此调用与 坚持不懈。
加密价值。
@PostLoad将实体加载到当前后执行 持久化上下文或实体已刷新。
解密价值。
最后,你可以有两个用于hibernate的配置文件,一个用于监听器,另一个用于没有用于单元测试的监听器。
答案 2 :(得分:0)
使用HSQLDB,您可以创建这些功能以进行测试。
CREATE FUNCTION AES_DECRYPT(VAL VARCHAR(32000), KEY VARCHAR(32000)) RETURNS VARCHAR(32000) RETURN VAL;
CREATE FUNCTION AES_ENCRYPT(VAL VARCHAR(32000), KEY VARCHAR(32000)) RETURNS VARCHAR(32000) RETURN VAL;