如何解决Java休眠有条件地将注释应用于字段吗?
方案::持久存在于数据库表中的数据对象。表中有一些旧条目。现在,我必须对表中的其他新条目应用加密。因此,我添加了一个新列,默认情况下该字段的加密字段设置为False,以检查值是否已加密。
问题::我想写一个注释来对数据模型(POJO)中的字段进行加密,然后再持久保存并仅在加密后的getter()调用中解密。
上下文:
用户模型。
public class UserData {
@Id
@Column(name = "ID",length = 36)
private String id;
@Column(name = "IS_ENCRYPTED")
private boolean isEncrypted;
@Column(name = "NAME")
@Convert(converter = EncryptionConverter.class)
private String name;
// more fields ....
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
// more similar getter and setters
}
我编写的加密类。
@Converter
public class EncryptionConverter implements AttributeConverter<String,String>{
private final String secretKey= "someSecret";
UserData Data = new UserData();
@Override
public String convertToDatabaseColumn(String str) {
if(!isNullOrBlank(str))
return AesEncrypt.encrypt(str,secretKey);
return str;
}
@Override
public String convertToEntityAttribute(String encrypedStr) {
if(!isNullOrBlank(encrypedStr) && Data.isEncrypted)
return AesEncrypt.decrypt(encrypedStr,secretKey);
return encrypedStr;
}
}
此类在模型类中。 (可以移到外面,但是如何将isencrypted标志传递给注释)
我该怎么做,我的方法正确吗?
编辑:有多个字段需要加密/解密,而不仅仅是名称。
解决方法
您可以在另一个配置类(例如EncryptedPropertyConfig)中创建加密行为,在此您可以从jasypt-spring-boot中创建一个bean,EncryptablePropertyResolver
@EnableAutoConfiguration
public class EncryptedPropertyConfig {
public EncryptedPropertyConfig() {
}
@Bean
public EncryptablePropertyResolver encryptablePropertyResolver() {
EncryptablePropertyResolver r = new MyPropertyPlaceholderConfigurer();
return r;
}
}
public final class MyPropertyPlaceholderConfigurer implements EncryptablePropertyResolver {
private StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
private EnvironmentStringPBEConfig envConfig = new EnvironmentStringPBEConfig();
public MyPropertyPlaceholderConfigurer() {
// set the encryption key and config
}
public String resolvePropertyValue(String passedValue) {
if (!PropertyValueEncryptionUtils.isEncryptedValue(passedValue)) {
return passedValue;
} else {
String returnValue = "";
try {
returnValue = PropertyValueEncryptionUtils.decrypt(passedValue,this.encryptor);
return returnValue;
} catch (Exception var4) {
throw new RuntimeException("Error in decryption of property value:" + passedValue,var4);
}
}
}
}
,
我建议使用Entity Listeners
的替代解决方案import javax.persistence.PostLoad;
import javax.persistence.PreUpdate;
public class UserData {
private final String secretKey= "someSecret";
// ...
@PreUpdate
private void onUpdate() {
// triggered before saving entity to DB (both create & update)
if(!isNullOrBlank(name)) {
name = AesEncrypt.encrypt(name,secretKey);
}
}
@PostLoad
private void onLoad() {
// triggered after entity is fetched from Entity Provider
if (!isNullOrBlank(name) && isEncrypted) {
name = AesEncrypt.decrypt(name,secretKey);
}
}
}
,
您可以通过以下方式实现休眠user type,而不是使用JPA AttributeConverter:
import java.util.Objects;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.type.StringType;
import org.hibernate.usertype.UserType;
public class CustomNameType implements UserType
{
private String secretKey = "someSecret";
public CustomNameType()
{
}
@Override
public Object deepCopy(Object value) throws HibernateException
{
if (null == value) return null;
return ((CustomName) value).clone();
}
@Override
public Object assemble(Serializable cached,Object owner) throws HibernateException
{
return cached;
}
@Override
public Serializable disassemble(Object value) throws HibernateException
{
return (Serializable) value;
}
@Override
public Object replace(Object original,Object target,Object owner) throws HibernateException
{
return original;
}
@Override
public boolean equals(Object one,Object two) throws HibernateException
{
return Objects.equals(one,two);
}
@Override
public int hashCode(Object obj) throws HibernateException
{
return Objects.hashCode(obj);
}
@Override
public boolean isMutable()
{
return true;
}
@Override
public Object nullSafeGet(ResultSet rs,String[] names,SharedSessionContractImplementor session,Object owner)
throws HibernateException,SQLException
{
boolean isEncrypted = rs.getBoolean(0); // IS_ENCRYPTED
String name = rs.getString(1); // NAME
if (isEncrypted) {
name = AesEncrypt.decrypt(name,secretKey);
}
return new CustomName(isEncrypted,name);
}
@Override
public void nullSafeSet(PreparedStatement statement,Object value,int index,SharedSessionContractImplementor session)
throws HibernateException,SQLException
{
CustomName customName = (CustomName) value;
String name = customName.getName();
if (customName.isEncrypted()) {
name = AesEncrypt.encrypt(name,secretKey);
}
statement.setBoolean(0,customName.isEncrypted());
statement.setString(1,name);
}
@Override
public Class<?> returnedClass()
{
return CustomName.class;
}
@Override
public int[] sqlTypes()
{
// I do not know the types of your IS_ENCRYPTED and NAME fields
// So,this place maybe require correction
int[] types = {BooleanType.INSTANCE.sqlType(),StringType.INSTANCE.sqlType()};
return types;
}
}
其中CustomName
是:
public class CustomName implements Serializable,Cloneable
{
private boolean isEncrypted;
private String name;
public CustomName(boolean isEncrypted,String name)
{
this.isEncrypted = isEncrypted;
this.name = name;
}
// getters,equals,hashCode ...
@Override
public CustomName clone()
{
return new CustomName(isEncrypted,name);
}
}
然后使用它:
import org.hibernate.annotations.Type;
import org.hibernate.annotations.Columns;
@Entity
public class UserData {
@Type(type = "com.your.CustomNameType")
@Columns(columns = {
@Column(name = "IS_ENCRYPTED"),@Column(name = "NAME")
})
private CustomName name;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。