Java休眠有条件地将注释应用于字段吗?

如何解决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 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res