一般网站在处理用户上传图片时通常采用两种策略:一是直接把图片存入数据库中的Blob字段;二是数据库中只存储图片的在服务器上的路径信息?,图片存放在分门别类的文件中,使用的时候从数据库读取路径信息到页面img元素即可.在此不讨论两种方案的优劣,我只是写了个hibernate的例子来实现第一种策略.例子很简单,t_user表主要两个字段,name和photo,其中photo字段类型为Blob.在此例中数据库我采用mysql, oracle的Blob字段比较特殊,你必须自定义类型,具体的请自行搜索,这方面的资料很多.

//User.java  

package com.denny_blue.hibernate;

import java.io.Serializable;
import java.sql.Blob;

public class User implements Serializable{
private Integer id;
private String name;
private Blob photo;
/**
 * @return the id
 */
public User(){
}
public Integer getId() {
return id;
}
/**
 * @param id the id to set
 */
public void setId(Integer id) {
this.id = id;
}
/**
 * @return the name
 */
public String getName() {
return name;
}
/**
 * @param name the name to set
 */
public void setName(String name) {
this.name = name;
}
/**
 * @return the photo
 */
public Blob getPhoto() {
return photo;
}
/**
 * @param photo the photo to set
 */
public void setPhoto(Blob photo) {
this.photo = photo;
}

}



类User有3个属性,id,name,photo,相应的getter和setter方法以及一个无参构造函数.应该注意的是photo的类型java.sql.Blob



相应的user.hbm.xml应该如下:


<?xml version="1.0">
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping
package="com.denny_blue.hibernate">

<class name="com.denny_blue.hibernate.User"
 table="t_user"
 dynamic-update="true"
 dynamic-insert="true"
 batch-size="3">
<id name="id"
 column="id"
 type="java.lang.Integer">
<generator class="native"/>
</id>
<property name="name" column="name" type="java.lang.String" lazy="true"/>
<property name="photo" column="photo" type="java.sql.Blob"/>

</class>

</hibernate-mapping>



对应的hibernate.cfg.xml配置文件,不再列出,请参照hibernate文档自行设定.


OK,做了这一步,我们写个测试类来进行单元测试:




package com.denny_blue.test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Blob;

import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

import com.denny_blue.hibernate.User;

import junit.framework.TestCase;

public class HibernateTest extends TestCase {
 private Session session;
protected void setUp() throws Exception {
try{
Configuration config=new Configuration().configure();
SessionFactory sf=config.buildSessionFactory();
session=sf.openSession();
}catch(HibernateException e){
e.printStackTrace();
}
}

protected void tearDown() throws Exception {
try{
session.close();
}catch(HibernateException e){
e.printStackTrace();
}
}

public void testSave()throws FileNotFoundException,IOException{
User user=new User();
user.setName("jordan");
FileInputStream in=new FileInputStream("C://test.gif");
Blob photo=Hibernate.createBlob(in);
user.setPhoto(photo);
Transaction tx=null;
try{
tx=session.beginTransaction();
session.saveOrUpdate(user);
tx.commit();
}catch(HibernateException e){
if(tx!=null)
tx.rollback();
e.printStackTrace();
}finally{
in.close();
}
}
public void testLoad()throws Exception{
try{
User user=(User)session.load(User.class, new Integer(1));
Blob photo=user.getPhoto();
InputStream in=photo.getBinaryStream();
FileOutputStream out=new FileOutputStream("C://out//test2.gif");
byte [] buf=new byte[1024];
int len;
while((len=in.read(buf))!=-1){
out.write(buf, 0, len);
}
in.close();
out.close();
}catch(HibernateException e){
e.printStackTrace();
}
}

}



我们读取C盘目录下的test.gif并存储到数据库中,然后再取出来写入C:/out目录,此时你可以查看下数据表中photo显示为blob,表示已经成功存入.值的注意的代码片段就是:



FileInputStream in=new FileInputStream("C://test.gif");


Blob photo=Hibernate.createBlob(in);


我们这里是从磁盘中读取图片,实际应用中你可以利用上传组件得到图片的2进制数据流,并利用Hibernate.createBlob方法来构造相应的Blob对象.而取图片则使用



InputStream in=photo.getBinaryStream();



这只是个简单的测试类,如果我想从数据库中取出图片并现实在页面上该如何做呢?其实也很简单,我们先要写一个servlet,在它的service方法中取出图片,并"画"到指定页面上.



package com.easyjf.asp.action;

import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Blob;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.denny)blue.hibernate.User;


public class Test extends HttpServlet {

/**
 * Destruction of the servlet. <br>
 */
private Session session;
public void destroy() {
try{
session.close();
}catch(HibernateException e){
e.printStackTrace();
}
}

/**
 * Initialization of the servlet. <br>
 *
 * @throws ServletException if an error occure
 */
public void init() throws ServletException {
try{
Configuration config=new Configuration().configure();
SessionFactory sf=config.buildSessionFactory();
session=sf.openSession();
}catch(HibernateException e){
e.printStackTrace();
}
}
 public void doGet(HttpServletRequest request,HttpServletResponse response)
 {
 try{
User user=(User)session.load(User.class, new Integer(1));
Blob photo=user.getPhoto();
InputStream in=photo.getBinaryStream();
OutputStream out=response.getOutputStream();
byte [] buf=new byte[1024];
int len;
while((len=in.read(buf))!=-1){
out.write(buf, 0, len);
}
in.close();
out.close();
}catch(Exception e){
e.printStackTrace();
}
 }

}



通过response.getOutputStream取得输出流,其他就与上段代码一致.servlet写好了,怎么在页面调用呢?那就更简单啦,直接在页面的img标签的src属性上调用该servlet即可,如:


<img id="test" src="/servlet/Test"/>


简单的例子,希望对初学者有帮助.



附记:如果不希望在servlet(或者action之类)中进行保存操作,希望在DAO进行此操作,那么InputStream的关闭问题可以通过hibernate的interceptor机制解决