中间的周末让我痛苦不已,辞职放弃的心都有了,因为看不懂代码,不知道执行顺序,不知道怎么上传,不知道怎么获取路径,再面对着从来没有用过的oracle数据库,还有一些经理提出来的从来没有听过的问题,我真的表示压力很大,但是,很感激武让,他有远大梦想,而且是一个经得住寂寞,可以去努力钻研每一个问题的人,让他帮我看上传文件代码的时候,虽然他也没做过,也没用过,但是,他可以静下心来慢慢研究,突然之间感觉自己有些惭愧,做的不够,自己做的真的不够,突然之间期盼着周一的到来,好去认真的研究一下代码。
图片的上传,在原来的基础上,修改upload_json.jsp。首先说一下这两种上传方式的不同:
1、将图片上传到服务器文件夹
将图片上传到服务器文件夹,主要思想是将图片以<img src="/upload/xxxxxx.jpg"/>的形式放到数据库中,等读取的时候,直接根据路径读取,这个应该很好理解。
2、将图片以blob的形式存到数据库中
刚开始我有一些不解,也有很多人问为什么不用上传到文件夹的方式上传,而且,存在数据库中占有的空间很大,太耗资源了,我同样这样想过,后来我问经理,他说,公司的服务器是分布式的,这样的话,可以共享数据库,但很少共享文件夹的,所以,当你的需求能保证不会产生很多的图片上传,那么,很有必要将图片放到数据库而不是文件夹。我想了想,恩,确实很有道理,不知道还有没有其他的原因…
将图片上传到数据库中的原理基本上是这样的:对于上传而言:首先建立路径,然后以流的形式读取,获取流之后插入数据库。我将主要代码记录一下:
首先,当然要连接数据库的类:
public class DbConn {
private final static String dbDriver="oracle.jdbc.OracleDriver";
private final static String dbUrl="jdbc:oracle:thin:@218.1.69.119:9152:TJEETEST";
private final static String dbUser="db_other";
private final static String dbPwd="db_other";
private static Connection conn=null;
/**
* 获得数据库连接方法
* @return
*/
public static Connection getConnection(){
if (conn==null) {
init();
}
/**
* 否则返回conn对象
*/
return conn;
}
/**
* 如果Connection对象为空,则执行该方法
*/
public static void init(){
try {
Class.forName(dbDriver);
conn=DriverManager.getConnection(dbUrl, dbUser, dbPwd);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 关闭当前Connnection对象的方法
*/
public static void closeConnection(){
if (conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
};
}
然后存储图片主要代码:
public class UserImageDAO{
private static Connection conn=null;
private final static String SAVEIMGSQL="insert into USERPIC(USERIMG,IMGDATE,TEXTID) values(?,?,?)";
//private final static String READIMGSQL="select * from userPic order by id desc limit 1";
//ivate final static String READIMGSQL="select * from USERPIC where ID = ?";
//ivate final static String READIDSQL = "select userpicid_seq.nextval colname from dual";
//ivate final static String READTEXTIDSQL = "select userpicid_seq.nextval colname from dual";
static {
conn=DbConn.getConnection();
}
/**(non-Javadoc)
* 存储图片方法
*/
public boolean saveUserImgWithBlob(String filePath,String date){
PreparedStatement pmst =null;
int result=0;
boolean flag = false;
File file = null;
InputStream imgStream = null;
try {
file=new File(filePath);
imgStream = new FileInputStream(file);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
try {
pmst = conn.prepareStatement(SAVEIMGSQL);
pmst.setBinaryStream(1, imgStream, (int)file.length());
pmst.setString(2, date);
pmst.setInt(3, getTextId());
result= pmst.executeUpdate();
if (result>0) {
flag=true;
}
} catch (Exception e) {
e.printStackTrace();
}
return flag;
}
}
这样,就可以在之前的上传图片文件中进行修改,实例化这个类,然后调用相应的存储方法。
其次是读取图片:读取图片也是一个艰难的过程,你想啊,怎么能将id号对应好,读取到上传上去的图片呢,刚开始,我用的mysql,其中主键是建立的自动增长类型,这样,我可以试着去在js文件中创建一个一个变量,在后台添加一个方法,返回当前数据库中最新的一条记录的id值,这样,根据返回的值来决定生成的img中src的链接的id值,方法如下:
/** (non-Javadoc)
* @return imgid
*/
public static int getImgId(){
PreparedStatement pmst =null;
ResultSet rs=null;
int id = 0;
try {
pmst = conn.prepareStatement(READIDSQL);
rs= pmst.executeQuery();
if (rs.next()) {
id = rs.getInt(1);
}
} catch (Exception e) {
e.printStackTrace();
}
return id;
}
好,想到这里了又有问题了,我怎么把返回的这个值传给我的js文件呢,那可是一个实实在在的js文件,不是jsp文件…有点傻了,但是,为了能完成功能,要不惜一切代价,好吧,新建一个jsp文件,然后将那么那么长的js文件中的代码放到这个新建的jsp文件中,然后引入这个类,调用这个static方法,然后再在现实的链接里添加上id值,这样,自动生成img标签的那段代码就有点改变:那就是在读取的那个servlet中带上一个id值来决定取哪个图片。<img src="XXXX.do?id='取到的id值'"/>
好像一个大问题解决了,但是,还是有问题,因为,当我上传一个图片的时候,我从数据库中取到当前id,然后加1后赋值给id,但是,当我选择第二张第三张图片的时候,这个id就还是那个啊,因为,这个过程,不会再和后台交互了,哎,继续想办法……
为了解决这个问题,在网上查一下吧,哇,看到一个惊奇的全局变量,用吧,首先设置全局变量为1,后面没生成一个加一次1,这样,对于全局变量来说,就保证了和数据库中的值一致。
最后再记录一点,那就是图片读取的方法和显示的方法:
/**(non-Javadoc)
*读取图片
*/
public void readUserImageWithBlob(ServletOutputStream sos,HttpServletResponse response, int id){
PreparedStatement pmst =null;
ResultSet rs=null;
try {
pmst = conn.prepareStatement(READIMGSQL);
pmst.setInt(1, id);
rs= pmst.executeQuery();
if (rs.next()) {
response.setContentType("image/jpeg");
sos=response.getOutputStream();
InputStream input=rs.getBinaryStream("userImg");
byte b[]=new byte[1024];
@SuppressWarnings("unused")
int len=0;
while ((len=input.read(b))!=-1) {
sos.write(b);
}
input.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
最最后一个让我觉得惊奇的事情是,读取图片竟然可以这样:
<img src="imgeReadWithBlob.do?id=136"/>
这句话的意思竟然是:imgeReadWithBlob.do对应读取的servlet,id是传过去的值。
先记录到这,下篇要说这个的缺点了……