java 如何使用 Hibernate 映射 byte[] 属性?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10591004/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to map a byte[] property with Hibernate?
提问by Sayo Oladeji
I'm using Hibernate/Java to persist an entity to a database. The entity has a passwordfield which is a String. When registring a user in my application, I hash the password using SHA-1 (I acknowledge this is a little weak). This produces a byte[]which I then convert to Stringusing
new String(byte[] arr);
Whenever I want to log a user in, I simply retrieve the hashed password from the database (as String) and compare it with the digest of the input password at login using
hashedPasswordFromDatabase.equals(SHA1_HASH(inputPassword));
我正在使用 Hibernate/Java 将实体持久化到数据库。该实体有一个密码字段,它是一个String。在我的应用程序中注册用户时,我使用 SHA-1 散列密码(我承认这有点弱)。这将产生一个字节[]我再转换为字符串使用
new String(byte[] arr);
每当我要登录用户,我只是从数据库中检索哈希密码(如字符串),并将其与消化输入密码在登录时使用比较
hashedPasswordFromDatabase.equals(SHA1_HASH(inputPassword));
This worked perfectlyon my development system (Windows 7, JDK 1.6.0_23 / JDK 1.7, MySQL 5.5, Tomcat 6.0.26) but upon deploying it on our server (running JDK 1.6 on Linux), the equalsmethod never evaluates to TRUE even for equal passwords. I quickly setup a new development system (Ubuntu 12.04, MySQL 5.5, JDK 1.7.0_03, Tomcat 7.0.22) and it doesn't work there too.
这在我的开发系统(Windows 7、JDK 1.6.0_23 / JDK 1.7、MySQL 5.5、Tomcat 6.0.26)上运行良好,但是在我们的服务器上部署它(在 Linux 上运行 JDK 1.6)时,equals方法甚至从未评估为 TRUE对于相同的密码。我很快设置了一个新的开发系统(Ubuntu 12.04、MySQL 5.5、JDK 1.7.0_03、Tomcat 7.0.22),但它在那里也不起作用。
I'm aware of the possible encoding issues stated in the Java API documentation for the Stringclass and also stated in several places here on SO. I've tried a couple of encodings suggested on this forum (e.g Base64, Latin-1) and I ended up with UnsupportedEncodingException. I think I'll be better off avoiding the String conversion. So how do I design my database such that the Hibernate-generated entity class comes up with byte[]for the passwordfield instead of String?
我知道String类的 Java API 文档中所述的可能编码问题,并且在 SO 上的几个地方也有说明。我尝试了本论坛上建议的几种编码(例如 Base64、Latin-1),但最终得到了UnsupportedEncodingException。我想我最好避免字符串转换。那么我如何设计我的数据库,以便 Hibernate 生成的实体类为密码字段提供byte[]而不是String?
回答by Tomasz Nurkiewicz
Yes, the problem is most likely in byte[]
to String
conversion. You must know that SHA produces raw byte
array and there is no guarantee that arbitrary byte[]
will produce valid String
, irrespective to encoding. Thus your code was only working by accident.
是的,问题很可能出在byte[]
对String
转换。您必须知道 SHA 生成原始byte
数组,并且不能保证任意byte[]
会生成有效的String
,而不管编码如何。因此,您的代码只是偶然工作。
Avoid the problem altogether by:
通过以下方式完全避免问题:
storing raw
byte[]
in BLOB - the safest and most storage-effective way. In Hibernate just usebyte[]
property on your POJO.encode
byte[]
using base64(check out Decode Base64 data in Java) and store it as a string.
byte[]
在 BLOB 中存储原始数据- 最安全和最有效的存储方式。在 Hibernate 中,只需byte[]
在 POJO 上使用属性。byte[]
使用base64编码(查看Java 中的解码 Base64 数据)并将其存储为字符串。
顺便说一句,请记住盐渍!
回答by Elidio Marquina
In my case, the bad database design push me to use a Blob in case of Clob. The solution was Map in hibernate the property with the Lob annotation and put another property in String type.
就我而言,糟糕的数据库设计促使我在 Clob 的情况下使用 Blob。解决方案是使用 Lob 注释在休眠属性中映射 Map 并将另一个属性放入 String 类型。
In other level of the code, when i call the get or set, i use the String property and this one, get or set the byte array value.
在代码的其他级别,当我调用 get 或 set 时,我使用 String 属性,而这个属性,获取或设置字节数组值。
@Entity
@Table(name = "CMUN_TAGS")
@SequenceGenerator(name = "idSeqTag", sequenceName = "SEQ_CMUN_TAGS")
public class CmunTagsDO implements java.io.Serializable {
private BigDecimal lngIdTag;
private byte[] blobValTag;
private String strValTag;
@Id
@Column(name = "LNG_ID_TAG", unique = true, nullable = false, precision = 20, scale = 0)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "idSeqTag")
public BigDecimal getLngIdTag() {
return this.lngIdTag;
}
public void setLngIdTag(BigDecimal lngIdTag) {
this.lngIdTag = lngIdTag;
}
@Column(name = "BLOB_VAL_TAG", nullable = false)
@Lob
public byte[] getBlobValTag() {
return this.blobValTag;
}
public void setBlobValTag(byte[] blobValTag) {
this.blobValorTag = blobValorTag;
}
@Transient
public String getStrValTag() {
strValTag = new String(getBlobValTag());
return strValTag;
}
public void setStrValTag(String strValTag) {
setBlobValTag(strValTag.getBytes());
this.strValTag = strValTag;
}
}
回答by Guillaume Polet
You can convert your byte to an hexadecimal representation like this:
您可以将字节转换为十六进制表示,如下所示:
public String encryptPassword(String passwordInClear) {
// Salt all you want here.
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
byte[] digest = sha256.digest(passwordInClear.getBytes());
return digestToString(digest);
}
private String digestToString(byte[] digest) {
StringBuilder hashString = new StringBuilder();
for (int i = 0; i < digest.length; i++) {
String hex = Integer.toHexString(digest[i]);
if (hex.length() == 1) {
hashString.append('0');
hashString.append(hex.charAt(hex.length() - 1));
} else {
hashString.append(hex.substring(hex.length() - 2));
}
}
return hashString.toString();
}