需求:将文件上传到服务器,在服务器上保存,并提供下载。
相当于实现了网络硬盘的功能。
上传文件
思路:
1,首先通过表单的<input type=”file” name=”uploadFileName”>实现从浏览器选择文件的功能,
2,表单提交时,会将文件提交到服务器,但这时只是提交了这个文件的文件名,并没有提交文件的内容,如何提交文件的内容呢?要在表单中设置enctype属性:
<formaction="${pageContext.request.contextPath }/servlet/UploadServlet"method="post" enctype="multipart/form-data">
这样服务器就可以获取上传的文件的内容了。
3,表单提交到一个servlet,这个servlet处理上传文件的内容,负责读取上传的文件,并将文件保存在服务器上,
4,文件上传过程中用到了两个第三方的jar包,分别是commons-fileupload.jar和commons-io.jar,其中最核心的类是ServletFileUpload。
5,整个执行流程为:先获取工厂类DiskFileItemFactory,通过工厂类实例可以设大小和临时文件保存地址。然后创建核心类ServletFileUpload,以工厂类实例为参数创建其对象,再通过parseRequest方法解析请求消息,通过getName方法获取上传的文件名称,为了防止提交的文件在服务器重复,可以使用在头部添加UUID唯一随机码解决。通过getInputStream方法可以获取从浏览器读取数据的流对象,然后再创建输出流对象,指定输出地址,通过频繁的读写操作,完成保存动作。
6,上传完毕,将页面转发到下载页面,显示可供下载的信息。
7,下载页面的超链接通过在链接尾部追加文件名来确定下载哪个文件。
下载文件
8,下载的超链接链接到一个servlet,servlet通过文件名获取服务器的资源,并解决乱码问题。
9,如果直接通过流写出到浏览器,那么浏览器会直接将文件解析在浏览器中显示,并不提供下载功能。要想下载文件,其核心是要在servlet的response对象中设置响应头信息:
response.setHeader("content-disposition", "attachment;filename=" + fileName);
10,设置以后,再通过流输出到浏览器时,浏览器就会通过下载的方式与用户交互了。
核心代码:
上传:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //判断是否支持上传。 if(!ServletFileUpload.isMultipartContent(request)) { throw new RuntimeException("请填写enctype"); } //创建工厂。 DiskFileItemFactory fileItemFactory = new DiskFileItemFactory(); fileItemFactory.setSizeThreshold(1024*1024*2); fileItemFactory.setRepository(new File(this.getServletContext().getRealPath("/WEB-INF/temp"))); //创建核心类 ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory); //设置上传文件名的编码。 servletFileUpload.setHeaderEncoding("utf-8"); //解析request上传的内容。 try { List<FileItem> allFileItem = servletFileUpload.parseRequest(request); //遍历 for(FileItem fileItem : allFileItem) { //检查普通字段. if(fileItem.isFormField()) { //是普通字段. String fieldName = fileItem.getFieldName();//获取名称。 String value = fileItem.getString("utf-8");//获取内容,并设置编码 System.out.println(fieldName+":"+value); } else { //上传字段。 //上传文件名称 String fileName = fileItem.getName(); //截取文件名 fileName.substring(fileName.lastIndexOf(File.separator)+1); //用UUID解决上传的文件名重复的问题。 fileName = UUIDUtils.getUUID()+"_"+fileName; //文件上传 InputStream is = fileItem.getInputStream(); //保存 String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload"); //文件输出流。 OutputStream out = new FileOutputStream(new File(uploadPath,fileName)); int len = -1; byte[] buffer = new byte[1024]; while((len = is.read(buffer))!= -1) { out.write(buffer, 0, len); } out.close(); is.close(); //删除临时文件,必须先关闭输入输出流。 fileItem.delete(); } } } catch (FileUploadException e) { throw new RuntimeException(e.getMessage(),e); } //上传完成,重定向到下载页面查看自己的下载资源 response.sendRedirect(request.getContextPath()+"/servlet/DownloadServlet"); }
下载:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取要下载的文件名 String fileName = request.getParameter("fileName"); //解决中文乱码。 fileName = new String(fileName.getBytes("iso-8859-1"),"utf-8"); //获得在服务器端的实际路径,对应的资源流 InputStream filePathIs = this.getServletContext().getResourceAsStream("/WEB-INF/upload/" + fileName); //3 通知浏览器下载 // * 截取前缀 fileName = fileName.substring(33); // * 处理中文乱码 fileName = new String(fileName.getBytes("GBK"),"ISO-8859-1"); // * 设置头 response.setHeader("content-disposition", "attachment;filename=" + fileName); OutputStream out = response.getOutputStream(); int len = -1; byte[] buffer = new byte[1024]; while((len = filePathIs.read(buffer))!= -1) { out.write(buffer, 0, len); } request.getRequestDispatcher(request.getContextPath()+"/servlet/DownloadServlet"); }