基于SSH的图片上传与下载的实例

时间:2022-08-28 20:23:24

图片的上传,一般是将图片的路径或图片名保存在数据库中,而不是把图片直接保存在数据库中。下载的时候也是先通过路径来查找图片是否存在再下载。

后台Form(在本例中为CertificateInfoForm)代码:

 private String  cer_picture ;   //图片名,保存于数据库中。
private FormFile picture_path; //用于在页面上获取文件的路径以及将图片以流的形式进行保存

//省略get、set方法。

前台JSP代码:

<td width="16%" class="edit_content">
证书图片:
</td>
<td width="33%" class="edit_content_text" colspan="3">
<input type="file" name="picture_path" onkeydown="return false;" class="input_text" />
</td>

这个JSP页面有一个地方需要提醒一下,一般新手都会碰到一个“argument type mismatch”的问题,那是因为如果提交的表单中有图片或者其他文件,则需要在form中添加enctype="multipart/form-data",如:

<html:form action="/certificate_info/certificateinfo.do?method=showCertificateInfo" method="post" enctype="multipart/form-data">

上传图片重要的一点就是要将图片以流的形式保存在本地服务器上。

后台Action代码:

CertificateInfoForm beanForm = (CertificateInfoForm) form;
CertificateInfo certificateInfo = new CertificateInfo();
//使用反射将form的值赋给bean
BeanFormConvertor.formToBean(certificateInfo,beanForm);
FormFile file = beanForm.getPicture_path();
String fileName = "";
if(file!=null&&!"".equals(file.getFileName())){
fileName = file.getFileName();
String operator = ((PrivilegeUserregister)request.getSession().getAttribute("user")).getOperator();
fileName = certificateInfoService.getFileNameByOperatorAndTimestamp(operator, fileName);//上一行与本行的作用是对图片名进行重命名
String newDir = servlet.getServletContext().getRealPath("/certificate_info/uploadFile/");
String path = "";
//路径不存在的话,就先创建。
if(!(new File(newDir)).isDirectory()){
new File(newDir).mkdir();
path = servlet.getServletContext().getRealPath("/certificate_info/uploadFile/") + "\\"+ fileName;
}else{
path = servlet.getServletContext().getRealPath("/certificate_info/uploadFile/") + "\\"+ fileName;
}
certificateInfoService.uploadFile(file, path);
//将
certificateInfo.setCer_picture(fileName);

}
certificateInfoService.addCertificateInfo(certificateInfo);
以上代码所做的事有:对文件进行重命名、判断路径是否存在,不存在还得先创建好文件夹、保存文件(图片)、将页面上传的图片的名字赋值给cer_picture,保存于数据库中。

对文件进行重命名,依个人需求而定。第一次上传图片,文件夹并没有存在,于是要先创建好文件夹,此后上传图片后就不用再次创建文件夹。

保存图片的uploadFile方法的代码如下:

public void uploadFile(FormFile file, String path) {
InputStream is = null;
OutputStream os = null;
try {
is = file.getInputStream();
os = new FileOutputStream(path);
byte[] content = new byte[file.getFileSize()];
while(is.read(content)!=-1){
os.write(content);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
if(is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(os!=null){
try {
os.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}

}

至此,图片的上传基本解决。接下来说下,图片下载的问题。

图片下载,一般都会给定一个链接,然后根据ID查找此图片的路径,再判断图片是否存在。我这里简单地用到了dwr,一个Ajax的框架。

JSP页面代码 :

<tr>
<td width="16%" class="edit_content">
证书图片:
</td>
<td width="33%" class="edit_content_text" colspan="3">
<a href="#" onclick="return downloadAttachment(${certificateInfo.id});return false;">
<c:out value="${certificateInfo.cer_picture}" escapeXml="true" />
<input type="hidden" name="uploadFilePath" value="<%=session.getServletContext().getRealPath("/certificate_info/uploadFile/") %>"/>
</a>
</td>
</tr>
从这里可以看出来,为什么我只保存图片的名字而不是路径加名字,因为下载的时候,会从页面上将路径传到后台。

这里可以看下JS中downloadAttachment方法的代码:

 var selectId = "";
function downloadAttachment(id){

selectId = id;
var uploadFilePath = document.getElementById("uploadFilePath").value;
//checkFileIsExit返回的是一个boolean型,同时调用result函数。
certificateInfoService.checkFileIsExist(uploadFilePath,selectId,result);
return false;
}
顺便在此贴出JS中的result方法的代码:

function result(rel){
//附件存在
if(rel){
window.location.href="<%=request.getContextPath()%>/certificate_info/certificateinfo.do?method=downloadAttachment&id="+selectId;
}else{
alert("对不起,你所请求的附件不存在!");
}
}


在downloadAttachment方法中可以看到,此方法直接调用了后台service中的checkFileIsExist方法。如何做到这一点呢,那是因为使用了我之前说的DWR。

在dwr文件中只需简单的配置即可。

<dwr>
<allow>
<!-- 证书信息 -->
<create creator="spring" javascript="certificateInfoService">
<param name="beanName" value="certificateInfoService" />
<include method="checkFileIsExist" />
</create>
</allow>
</dwr>

在JS中调用到后台中的哪个方法就进行配置,当然<include/>可以包含多个,即一个JS方法中调用了多个后台中的方法。

然后,在JSP中还需添加:

<script type='text/javascript' src='<%=request.getContextPath()%>/dwr/interface/certificateInfoService.js'></script>
不然,会出现你所调用的方法没有定义的异常。

这样配置好DWR之后,downloadAttachment就可以直接调用checkFileIsExist方法了。在后台中其实现代码如下:

public boolean checkFileIsExist(String uploadFilePath, String id) {
CertificateInfo bean = certificateInfoDAO.findCertificateInfo(Integer.parseInt(id));
if(bean.getCer_picture()!=null&&!bean.getCer_picture().trim().equals("")){
String path = uploadFilePath+"\\"+bean.getCer_picture();

File file = new File(path);
if (file.exists()) {
System.out.println("0000");
return true;
} else {
return false;
}
}else{
return false;
}
}
以上代码很容易理解,就是找到路径及图片名字,再调用File的exists方法就可以判断文件是否存在了。

上面说过,执行完downloadAttachment会调用 result方法,这样就可以直接进行图片的下载了。

可以看下后台的downloadAttachment的代码:

CertificateInfo bean = certificateInfoDAO.findCertificateInfo(Integer.parseInt(id));
String attachment = bean.getCer_picture();
FileInputStream fis = null;
OutputStream os = null;

try {
response.setContentType("application/x-msdownload");
response.setHeader("Content-Disposition","attachment;" + " filename="+ new String(attachment.getBytes(), "iso-8859-1"));
String path = servlet.getServletContext().getRealPath("/certificate_info/uploadFile/")+"\\"+attachment;
fis = new FileInputStream(path);
os = response.getOutputStream();
byte[] b = new byte[1024];
int leng;
while((leng=fis.read(b)) != -1){
os.write(b, 0, leng);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if (fis != null) {
try {
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (os != null) {
try {
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
setContentType()是告诉浏览器此文件是纯下载方式(另外有在线打开方式),setHeader中设置了文件类型的后缀名、文件名以及防止图片出现乱码进行了编码设置。

之后就是再读取图片,以流的形式进行下载。这样,图片的下载也实现了。


另外,在更新的时候,有时也会更换图片,但是在更新页面回显的时候,不仅需要显示图片的名字或路径,还需要有图片上传的选择框。这样,如果对于图片没有更改,那么再次点击提交的时候,就会发现,图片不存在了。原因是显而易见的。本人愚笨,想了一个比较笨的方法,具体代码不贴出来了,只说下自己的思路。

在回显的时候,将已存入的图片名或路径用一个隐藏域赋值给一个属性,然后在后台再接收到这个属性的值。接着再判断页面上的图片File是否存在,如果存在则表示图片已更换,如果不存在,则将之前的图片名再次存入至数据库中。这样就可以解决了。。

虽然方法有点笨拙,但好歹也解决了问题。望大神能提供更好的方法。。


另:本文中有说得不好的地方,望各位指出来。在下不甚感激。