2012.7.20 星期五 天气晴朗
很久没有写学习文档了。今天就最近在做的文档管理模块中的文档上传和下载,写一篇实现过程的日志,仅供学习和参考。如果疑问,邮电:457151376@qq.com。
那么首先,来讲讲如何实现上传。
一般文档上传和下载我们通过通用的Servlet来实现。当然也有人把代码写在JSP里面实现。实现的方式有很多种,但是原理是一样的。那么我们找一种可以持久使用和重复使用的方式。用Servlet实现上传和下载。
先给出FileUploadServlet和FileDownloadServlet实现的代码:
package cn.trymore.core.web.servlet;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.shengrui.oa.model.system.ModelAppUser;
import org.shengrui.oa.util.ContextUtil;
import cn.trymore.core.util.UtilApp;
import cn.trymore.core.util.UtilFile;
import cn.trymore.oa.model.system.ModelFileAttach;
import cn.trymore.oa.service.system.ServiceFileAttach;
/**
* The servlet for file uploading.
*
* @author Jeccy.Zhao
*
*/
public class FileUploadServlet
extends HttpServlet
{
private static final long serialVersionUID = 4757212133352817333L;
/**
* The file attach service.
*/
private ServiceFileAttach serviceFileAttach = (ServiceFileAttach) UtilApp.getBean("serviceFileAttach");
/**
* The servlet configuration
*/
private ServletConfig servletConfig = null;
/**
* The file upload destination path.
*/
private String uploadPath = "";
/**
* The file upload temporary path.
*/
private String tempPath = "";
/**
* The file category
*/
private String fileCat = "others";
public void init(ServletConfig servletConfig) throws ServletException
{
this.servletConfig = servletConfig;
super.init(servletConfig);
}
/**
* Initializations, like:
*
* 1. Define the temporary path for file upload. <br/>
* 2. Define the destination path for file upload. <br/>
* 3. Create the above directories if not existed.
*
*/
public void init() throws ServletException
{
this.uploadPath = servletConfig.getServletContext().getRealPath("/uploads/");
System.out.println(this.uploadPath);
File localFile = new File(this.uploadPath);
if (!localFile.exists())
{
localFile.mkdirs();
}
this.tempPath = this.uploadPath + "/temp";
File tmpFile = new File(this.tempPath);
if (!tmpFile.exists())
{
tmpFile.mkdirs();
}
}
/*
* (non-Javadoc)
* @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
@SuppressWarnings("unchecked")
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException
{
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
try
{
DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
diskFileItemFactory.setSizeThreshold(4096);
diskFileItemFactory.setRepository(new File(this.tempPath));
String fileIds="";
ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
List<FileItem> fileList = (List<FileItem>) servletFileUpload.parseRequest(request);
Iterator<FileItem> itor = fileList.iterator();
FileItem fileItem;
while (itor.hasNext())
{
fileItem = itor.next();
if (fileItem.getContentType() == null)
{
continue;
}
// obtains the file path and name
String filePath = fileItem.getName();
String fileName = filePath.substring(filePath.lastIndexOf("/") + 1);
// generates new file name with the current time stamp.
String newFileName = this.fileCat + "/" + UtilFile.generateFilename(fileName);
// ensure the directory existed before creating the file.
File dir = new File(this.uploadPath + "/" + newFileName.substring(0, newFileName.lastIndexOf("/") + 1));
if (!dir.exists())
{
dir.mkdirs();
}
// stream writes to the destination file
fileItem.write(new File(this.uploadPath + "/" + newFileName));
// storages the file into database.
ModelFileAttach fileAttach = new ModelFileAttach();
fileAttach.setFileName(fileName);
fileAttach.setFilePath(newFileName);
fileAttach.setTotalBytes(Long.valueOf(fileItem.getSize()));
fileAttach.setNote(this.getStrFileSize(fileItem.getSize()));
fileAttach.setFileExt(fileName.substring(fileName.lastIndexOf(".") + 1));
fileAttach.setCreatetime(new Date());
fileAttach.setDelFlag(ModelFileAttach.FLAG_NOT_DEL);
fileAttach.setFileType(this.fileCat);
ModelAppUser user = ContextUtil.getCurrentUser();
if (user != null)
{
fileAttach.setCreatorId(Long.valueOf(user.getId()));
fileAttach.setCreator(user.getFullName());
}
else
{
fileAttach.setCreator("Unknow");
}
this.serviceFileAttach.save(fileAttach);
//add by Tang 这部分代码用于临时保存fileIds,用完后一定要注意及时销毁。
fileIds=(String) request.getSession().getAttribute("fileIds");
if(fileIds==null)
{
fileIds=fileAttach.getId();
}
else
{
fileIds=fileIds+","+fileAttach.getId();
}
response.setContentType("text/html;charset=UTF-8");
PrintWriter writer = response.getWriter();
writer.println("{\"status\": 1, \"data\":{\"id\":" + fileAttach.getId() + "}}");
}
request.getSession().setAttribute("fileIds", fileIds);
}
catch (Exception e)
{
e.printStackTrace();
response.getWriter().write("{\"status\":0, \"message\":\"上传失败:" + e.getMessage() + "\"");
}
}
/**
* Obtains the decimal formated file size.
*
* @param size
* @return
*/
protected String getStrFileSize (double size)
{
DecimalFormat decimalFormat = new DecimalFormat("0.00");
double byteSize;
if (size > 1048576.0D)
{
byteSize = size / 1048576.0D;
return decimalFormat.format(byteSize) + " M";
}
if (size > 1024.0D)
{
byteSize = size / 1024.D;
return decimalFormat.format(byteSize) + " KB";
}
return size + " bytes";
}
public void setServletConfig(ServletConfig servletConfig)
{
this.servletConfig = servletConfig;
}
public ServletConfig getServletConfig()
{
return servletConfig;
}
public void setUploadPath(String uploadPath)
{
this.uploadPath = uploadPath;
}
public String getUploadPath()
{
return uploadPath;
}
public void setTempPath(String tempPath)
{
this.tempPath = tempPath;
}
public String getTempPath()
{
return tempPath;
}
public void setServiceFileAttach(ServiceFileAttach serviceFileAttach)
{
this.serviceFileAttach = serviceFileAttach;
}
public ServiceFileAttach getServiceFileAttach()
{
return serviceFileAttach;
}
}
package cn.trymore.core.web.servlet;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 文档下载
* @author Tang
* 使用方法:直接写/download?path=""就可以
*/
public class FileDownloadServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = -5563238888658319929L;
/**
* The servlet configuration
*/
private ServletConfig servletConfig = null;
public void init(ServletConfig servletConfig) throws ServletException
{
this.servletConfig = servletConfig;
super.init(servletConfig);
}
protected void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
// 服务器相对路径
String path = req.getParameter("path");
// 服务器绝对路径
path = servletConfig.getServletContext().getRealPath("/uploads/")+"/"+path;
System.out.println(path);
// 检查文件是否存在
File obj = new File(path);
if (!obj.exists()) {
res.setContentType("text/html;charset=GBK");
res.getWriter().print("指定文件不存在!");
return;
}
// 读取文件名:用于设置客户端保存时指定默认文件名
int index = path.lastIndexOf("/");
// 前提:传入的path字符串以“\”表示目录分隔符
String fileName = path.substring(index + 1);
// 写流文件到前端浏览器
ServletOutputStream out = res.getOutputStream();
res.setHeader("Content-disposition", "attachment;filename=" + fileName);
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
bis = new BufferedInputStream(new FileInputStream(path));
bos = new BufferedOutputStream(out);
byte[] buff = new byte[2048];
int bytesRead;
while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
bos.write(buff, 0, bytesRead);
}
} catch (IOException e) {
throw e;
} finally {
if (bis != null) {
bis.close();
}
if (bos != null) {
bos.close();
}
}
}
}
这些代码初看有些复杂,但是仔细研究一下,还是都能理解和看懂的,都是Java基础的输入输出流操作。还有就是路径操作了。
主要的还是路径问题我说一下,因为这个问题我比较印象深刻。一般来说,我们正常操作的话是不会遇到这个问题,那么我是个不正常的人,所以我进行了不正常操作,导致我对这一方面有了一定的深入了解。
Windows默认的文档路径是以反斜杠显示的:D:\快盘资料\安卓日记\Activity的详细讲解。所以在Eclipse中获取系统绝对路径的时候,也是反斜杠的,刚开始我不懂,以为路径就应该是这样的,我还特地把文档上传部分保存的path相对路径也改成了反斜杠。后来前辈告诉我,这样是不行的。反斜杠在Liunx系统中是不支持的,所以如果web项目部署到liunx的系统中的话,这样的代码就存在严重的问题。但是为什么windows会支持反斜杠呢,而且更强悍的是,windows还支持混乱斜杠,也就是正反斜杠它都能识别。这就是导致我一开始怎么也想不明白,为什么明明是反斜杠,而保存的path路径设置成正斜杠。那是因为如果在liunx中获取到的绝对路径就是正斜杠的了,后面的相对路径path就需要正斜杠的了,不然不支持的。
看看windows的混乱支持:
D:\ProgramExamples\Workspaces\Eclipse\app-oaShengRui\src\main\web\uploads/others/201207/d302121e8a534ed29747e60557fe7b87.htm
这样也是可以下载和访问的呀。
最后说一下Servlet的配置和使用方法:
在web.xml中写如下配置
<servlet>
<servlet-name>fileUpload</servlet-name>
<servlet-class>cn.trymore.core.web.servlet.FileUploadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>fileUpload</servlet-name>
<url-pattern>/file-upload</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>FileDownload</servlet-name>
<servlet-class>cn.trymore.core.web.servlet.FileDownloadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FileDownload</servlet-name>
<url-pattern>/file-download</url-pattern>
</servlet-mapping>
然后使用的话,file-upload直接用就可以了。download?path=?跟一个参数就可以了。