JAVAWEB开发之文件的上传与下载(开源组件commons-fileupload的详细使用)

文件上传简介

什么是文件上传?为什么使用文件上传?
文件上传就是将客户端资源,通过网路传递到服务器端。
因为文件数据比较大,必须通过文件上传才可以完成将数据保存到数据库端的操作。
文件上传的本质就是IO流操作。
演示:文件上传应该如何操作?
浏览器端:
1.method=post 只有post才可以携带大数据
2.必须使用<input type='file' name='f'>要有name属性
3.encType="multipart/form-data"
服务器端:
request对象是用于获取请求信息。
它有一个方法 getInputStream(); 可以获取一个字节输入流,通过这个流,可以读取到
所有的请求正文信息.
文件上传原理:
浏览器端注意上述三件事,在服务器端通过流将数据读取到,在对数据进行解析.
将上传文件内容得到,保存在服务器端,就完成了文件上传。
注意: 在实际开发中,不需要我们进行数据解析,完成文件上传。因为我们会使用文件上传的工具,它们已经封装好的, 提供API,只要调用它们的API就可以完成文件上传操作. 我们使用的commons-fileupload,它是apache提供的一套开源免费的文件上传工具。

代码演示文件上传的原理:
在WebRoot下新建upload1.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
</head>

<body>
  <!-- encType 默认是application/x-www-form-urlencoded -->
	<form action="${pageContext.request.contextPath }/upload1"
		method="POST" enctype="multipart/form-data">
		<input type="text" name="content"><br>
		<input type="file" name="f"><br> <input type="submit"
			value="上传">
	</form>
</body>
</html>
新建Upload1Servlet 路径:/upload1
package cn.itcast.web.servlet;

import java.io.IOException;
import java.io.InputStream;

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

public class Upload1Servlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// System.out.println("upload1 servlet......");
		// 通过request获取一个字节输入流,将所有的请求正文信息读取到,打印到控制台
		InputStream is = request.getInputStream();

		byte[] b = new byte[1024];
		int len = -1;
		while ((len = is.read(b)) != -1) {
			System.out.println(new String(b, 0, len));
		}
		is.close();
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doGet(request, response);
	}

}
在浏览器端访问信息如下:



后台打印正文信息如下:

文件上传概述

实现web开发中的文件上传功能,需要完成如下二步操作:
  • 在web页面中添加上传输入项。
  • 在Servlet中读取上传文件的数据,并保存在服务器硬盘中。
如何在web页面中添加上传输入项?
<input type="file">标签用于在web页面中添加文件上传输入项,设置文件上传输入项时注意:
  • 1、必须设置input输入项的name属性,否则浏览器将不会发送上传文件的数据。
  • 2、必须把form的encType属性设为multipart/form-data 设置该值后,浏览器在上传文件时,并把文件数据附带在http请求消息体内,并使用MIME协议对上传的文件进行描述,以方便接收方对上传数据进行解析和处理。
  • 3、表单的提交方式要设置为post。
如何在Servlet中读取文件上传数据,并保存到本地硬盘中?
  • Request对象提供了一个getInputStream方法,通过这个方法可以读取到客户端提交过来的数据。但由于用户可能会同时上传多个文件,在servlet端编程直接读取上传数据,并分别解析出相应的文件数据是一项非常麻烦的工作,示例。
  • 为方便用户处理文件上传数据,Apache 开源组织提供了一个用来处理表单文件上传的一个开源组件( Commons-fileupload ),该组件性能优异,并且其API使用极其简单,可以让开发人员轻松实现web文件上传功能,因此在web开发中实现文件上传功能,通常使用Commons-fileupload组件实现。
  • 使用Commons-fileupload组件实现文件上传,需要导入该组件相应支撑jar包:Commons-fileupload和commons-io。commo-io不属于文件上传组件的开发jar文件,但Commons-fileupload组件从1.1版本开始,它工作时需要commons-io包的支持。

fileupload组件工作流程和文件上传步骤:

fileupload组件工作流程:

fileupload组件上传步骤:
1、创建DiskFileItemFactory对象,设置缓冲区大小和临时文件目录。
2、使用DiskFileItemFactory对象创建ServletFileUpload对象,并设置上传文件的大小限制。
3、调用ServletFileUpload.parseRequest方法解析request对象,得到了一个保存了所有上传内容的List对象。
4、对list进行迭代,每迭代一个FileItem对象,调用其isFormField方法判断是否是上传文件。
4.1 true为普通表单字段,则调用getFiledName、getString方法得到字段名称和字段值。
4.2 false为上传组件,则调用getInputStream方法得到数据输入流,从而读取上传数据。

fileupload快速入门:

1.创建upload2.jsp页面
<form action="${pageContext.request.contextPath}/upload2" method="post" encType="multipart/form-data">
<input type="file" name="f"><br>
<input type="submit" value="上传">
</form>
2.创建Upload2Servlet
2.1创建一个DiskFileItemFactory
DiskFileItemFactory factory = new DiskFileItemFactory();
2.2创建ServletFileUpload类
ServletFileUpload upload = new ServletFileUpload(factory);
2.3解析所有上传数据
List<FileItem> items = upload.parseRequest(request);
3.遍历items集合,集合中的每一项,就是一个上传数据
3.1 isFormField();
3.2 getFieldName
返回值为String,得到组件名称 <input name=" ">
3.3 getName();
返回值为String,得到的是上传文件的名称。
注意:浏览器不同,它们得到的效果就不一样。
3.3.1 包含全路径名称 例如:C:\Users\xxxx\Desktop\a.txt
3.3.2 只包含上传文件名称 例如:a.txt
3.4 getString
这个方法可以获取非上传组件的内容,相当于 getParameter方法的作用
如果是上传组件,上传的文件时文本文件,仍然可以获取到文件内容。
但如果不是文本文件,而是二进制文件 例如 一张图片 就会获取到一堆卡哇伊的符号或内容。
3.5 获取上传文件的内容,保存到服务器端
item.getInputStream(); 它是用于读取上传文件内容的输入流。
使用文件复制操作就可以完成文件上传。
IOUtils.copy(item.getInputStream(),fos);

代码演示如下:
创建upload2.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
</head>

<body>
  <!-- encType 默认是application/x-www-form-urlencoded -->
	<form action="${pageContext.request.contextPath }/upload2"
		method="POST" enctype="multipart/form-data">
		<input type="text" name="content"><br>
		<input type="file" name="f"><br> <input type="submit"
			value="上传">
	</form>
</body>
</html>
创建Upload2Servlet 路径是 /upload2
package cn.itcast.web.servlet;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

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.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;

public class Upload2Servlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 1.创建DiskFileItemFactory
		DiskFileItemFactory factory = new DiskFileItemFactory();
		// 2.创建
		ServletFileUpload upload = new ServletFileUpload(factory);
		try {
			// 底层通过request获取数据,进行解析,将解析的数据封装到List<FileItem>
			List<FileItem> items = upload.parseRequest(request);

			// 3.遍历集合
			for (FileItem item : items) {
				if (item.isFormField()) {
					// 是表单组件 就得到了 <input type="text" name="content"> 这样的组件
					// String fieldName = item.getFieldName();
					// System.out.println(fieldName);

					// 上传文件的名称
					// String name = item.getName();
					// System.out.println(name);

					// String string = item.getString();
					// System.out.println(string);
				} else {
					// 不是表单组件 这就得到了<input type="file" name="f"> 这样的组件
					// String fieldName = item.getFieldName();
					// System.out.println("上传组件的名称: " + fieldName);

					// 上传文件的名称
					String name = item.getName();
					name = name.substring(name.lastIndexOf("\\") + 1);
					// System.out.println(name);
					//
					// String string = item.getString();
					// System.out.println(string);

					// 获取上传文件内容,完成文件上传操作
					// InputStream is = item.getInputStream();
					// byte[] b = new byte[1024];
					// int len = -1;
					FileOutputStream fos = new FileOutputStream(
							"C:/Users/lx/Desktop/upload/" + name);
					// while ((len = is.read(b)) != -1) {
					// // System.out.println(new String(b, 0, len));
					// fos.write(b, 0, len);
					// }
					// fos.close();
					// is.close();
					IOUtils.copy(item.getInputStream(), fos);
				}
			}
		} catch (FileUploadException e) {
			e.printStackTrace();
		}
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doGet(request, response);
	}

}
deploy 访问upload2.jsp 上传文件 运行结果如下图所示:


在浏览器端查捕捉请求正文信息如下:


FileUpload核心API

DiskFileItemFactory

DiskFileItemFactory是创建FileItem对象的工厂

作用:可以设置缓存大小以及临时文件保存位置。
默认缓存大小是10240(10k)
临时文件默认存储在系统的临时文件目录下(可以在环境变量中查看)
1. new DiskFileItemFactory(); 缓存大小与临时文件存储位置使用默认的
2.new DiskFileItemFactory(int sizeThreshould, File repository);
sizeThreshold :缓存大小
repository:临时文件存储位置
注意:对于无参数构造,也可以设置缓存大小以及临时文件存储位置
public void setSizeThreshold(int sizeThreshold)
设置内存缓冲区的大小,默认值为10K。当上传文件大于缓冲区大小时, fileupload组件将使用临时文件缓存上传文件。
public void setRepository(java.io.File repository)
指定临时文件目录,默认值为System.getProperty("java.io.tmpdir").

ServletFileUpload

ServletFileUpload负责处理上传的文件数据,并将表单中每个输入项封装成一个FileItem对象中。常用的方法有:
(1)ServletFileUpload upload=new ServletFileUpload(factory);
创建一个上传工具,指定使用缓存区与临时文件存储位置
(2)List parseRequest(HttpServletRequest request)
List<FileItem> items = upload.parseRequest(request);
它是用于解析request对象,得到所有上传项,每一个FileItem就相当于一个上传项。
(3)boolean flag=upload.isMultipartContent(request);
用于判断是否是上传.
可以简单理解,就是判断encType="multipart/form-data";
(4)设置上传文件大小
void setFileSizeMax(long fileSizeMax) 设置单个文件上传大小
void setSizeMax(long sizeMax) 设置总文件上传大小
(5)解决上传文件中文名称乱码
void setHeaderEncoding("utf-8");
注意:如果使用reqeust.setCharacterEncoding("utf-8")也可以,但不建议使用。
(6)setProgressListener(ProgressListener pListener)
实时监听文件上传状态

FileItem

FileItem用来表示文件上传表单中的一个上传文件对象或者普通表单对象。
(1)isFormField
用于判断是否是上传组件.
如果是<input type="file">返回的就是false,否则返回true.
(2)getFieldName();
返回值String,得到组件名称 <input name="">
(3)getName();
返回值是String,得到的是上传文件的名称.
注意:浏览器不同,它们得到的效果不一样。
1.包含全路径名称 例如: C:\Users\Administrator\Desktop\a.txt
2.只包含上传文件名称 例如:a.txt
(4)getString();
这个方法可以获取非上传组件的内容,相当于 getParameter方法作用。
问题:如果信息是中文,会出现乱码,解决方案 getString("utf-8");
如果是上传组件,上传的文件是文本文件,可以获取到文件文件的内容。
但是如果不是文件文件,例如:是一张图片,是二进制文件 就不合适了。
(5)获取上传文件的内容,保存到服务器端.
item.getInputStream();它是用于读取上传文件内容的输入流.
使用文件复制操作就可以完成文件上传。
(6)删除临时文件
item.delete();
示例代码如下:
在WebRoot下新建临时文件夹temp 用来存储缓存(上传中产生的临时文件)
新建upload3.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
</head>

<body>
  <!-- encType 默认是application/x-www-form-urlencoded -->
	<form action="${pageContext.request.contextPath }/upload3"
		method="POST" enctype="multipart/form-data">
		<input type="text" name="content"><br>
		<input type="file" name="f"><br> <input type="submit"
			value="上传">
	</form>
</body>
</html>

新建Upload3Servlet 访问路径:/upload3
package cn.itcast.web.servlet;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

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.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;

//commons-fileupload api详解
@SuppressWarnings("all")
// 去除所有警告
public class Upload3Servlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		// 1.创建DiskFileItemFactory
		// DiskFileItemFactory factory = new DiskFileItemFactory(); // 使用默认的
		File file = new File(this.getServletContext().getRealPath("/temp"));// 获取temp目录部署到tomcat后的绝对磁盘路径
		DiskFileItemFactory factory = new DiskFileItemFactory(1024 * 100, file);

		// 2.创建ServletFileUpload
		ServletFileUpload upload = new ServletFileUpload(factory);
		// 判断是否是上传操作(即检测encType是否为"multipart/form-data")
		boolean flag = upload.isMultipartContent(request);
		if (flag) {
			// 解决上传文件中文名称乱码
			// 注意:也可以使用request.setCharacterEncoding("utf-8"); 不建议使用
			upload.setHeaderEncoding("utf-8");
			
			// 设置上传文件大小
//			upload.setSizeMax(1024*1024*10); // 设置文件总大小为10M
			
			try {
				List<FileItem> items = upload.parseRequest(request);// 解析request,得到所有上传项FileItem

				// 3.得到所有上传项
				for (FileItem item : items) {
					if (item.isFormField()) { // 判断是否是上传组件 如果是上传组件就返回false
						// 非上传组件
						System.out.println("组件名称:" + item.getFieldName());
						System.out.println("内容:" + item.getString("utf-8"));
					} else {
						// 上传组件
						System.out.println("非上传组件:" + item.getFieldName());
						System.out.println("上传文件名:" + item.getName());

						String name = item.getName(); // 上传文件名
						name = name.substring(name.lastIndexOf("\\") + 1);

						IOUtils.copy(item.getInputStream(),
								new FileOutputStream(
										"c:/Users/lx/Desktop/upload/" + name));

						// 删除临时文件
						item.delete();
					}
				}
			} catch (FileUploadException e) {
				// e.printStackTrace();
				response.getWriter().write(e.getMessage());
			}
		} else {
			response.getWriter().write("不是上传操作");
			return;
		}
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doGet(request, response);
	}

}

总结:关于文件上传时的乱码问题:
(1)上传文件名乱码 ServletFileUpload.setHeaderEncoding("utf-8");
(2)非上传组件内容乱码 FileItem.getString("utf-8");
注意:上传文件信息一定不会乱码,不需要解决,因为我们在上传时,使用的是字节流来进行的复制。

多文件上传时的JS编码

技巧:
每次动态增加一个文件上传输入框,都把它和删除按纽放置在一个单独的div中,并对删除按纽的onclick事件进行响应,使之删除删除按纽所在的div。
如:this.parentNode.parentNode.removeChild(this.parentNode);
代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>多文件上传</title>
<script type="text/javascript">
	function addFile() {
		var div = document.getElementById("content");
		div.innerHTML += "<div><input type='file' name='f'><input type='button' value='remove file' οnclick='removeFile(this)'></div>";
	}
	function removeFile(btn) {
		document.getElementById("content").removeChild(btn.parentNode);
	}
</script>
</head>

<body>
	<input type="button" value="add File" οnclick="addFile();">
	<br>
	<form action="${pageContext.request.contextPath }/upload3"
		method="POST" enctype="multipart/form-data">
		<input type="file" name="f"><br>
		<div id="content"></div>
		<input type="submit" value="上传">
	</form>
</body>
</html>
运行结果如下:


关于文件上传的注意事项:

事项一:上传文件在服务器端保存位置问题

(1)保存在可以被浏览器直接访问的位置
例如:商城中的商品图片
保存在工程的WebRoot下的路径(但不包含META-INF以及WEB_INF目录及其子目录)
(2)保存在不能被浏览器直接访问的位置
例如:付费的视频
保存在工程中 META-INF WEB_INF目录及其子目录下
或者保存到不在工程中的服务器的磁盘目录下

事项二:上传文件在同一目录重名问题

可以在开发中为上传文件起一个随机名称
  • 使用当前的毫秒值
  • 或使用UUID工具类生成随机字符串

事项三:同一目录下文件过多

需要进行目录分离,因为同一文件夹下的文件过多会影响查询速率
目录分离的几种方案:
(1)按照上传时间进行目录分离(月、周)
(2)按照上传用户进行目录分离(为每个用户建立单独的目录)
(3)按照文件固定数量进行分离(假设每个目录只能存放3000个文件,每当一个目录存满3000个文件后,创建一个 新的目录)
(4)按照文件名的hashcode进行目录分离
public static String generateRandomDir(String uuidFileName) {
// 获得唯一文件名的hashcode
int hashcode = uuidFileName.hashCode();
// 获得一级目录
int d1 = hashcode & 0xf;
// 获得二级目录
int d2 = (hashcode >>> 4) & 0xf;
return "/" + d2 + "/" + d1;// 共有256目录l
}
几种目录分离的方法优缺点:
按照时间分离的话 不稳定 比如淘宝双十一访问量最多 按照时间会造成某一时期文件数量过多。
按照用户目录进行分离也不是太好,因为有的用户上传文件数量多 有的少。
按照文件固定数量进行分离固然好,但是需要判断文件夹内文件的数量 相当繁琐。
最好按照文件名的hashcode进行分离

实例演示:按照文件名哈希值进行目录分离
还使用多文件上传的upload4.jsp 进行上传
首先新建一个FileUploadUtils工具类
package cn.itcast.utils;

import java.io.File;
import java.util.UUID;

public class FileUploadUtils {

	// 得到上传文件真实名称 c:\a.txt a.txt
	// 如果参数为c:\a.txt 得到a.txt 如果为a.txt index=-1+1=0; 仍然正确
	public static String getRealName(String filename) {
		int index = filename.lastIndexOf("\\") + 1;
		return filename.substring(index);
	}

	// 获取随机名称
	public static String getUUIDFileName(String filename) {
		int index = filename.lastIndexOf(".");
		if (index != -1) {
			return UUID.randomUUID() + filename.substring(index);
		} else {
			return UUID.randomUUID().toString();
		}

	}

	// 目录分离算法
	public static String getRandomDirectory(String filename) {
		// 方式一:
		int hashcode = filename.hashCode();
		System.out.println(hashcode);

		// int数据类型在内存中占32位字节,转换成16进制数(4位),就得到8个16进制数
		String hex = Integer.toHexString(hashcode);
		System.out.println(hex);
		return "/" + hex.charAt(0) + "/" + hex.charAt(1);

		/*
		 * 方式二: int hashcode = filename.hashCode();
		 * 
		 * System.out.println(Integer.toBinaryString(hashcode));
		 * 
		 * int a = hashcode & 0xf;
		 * 
		 * hashcode = hashcode >>> 4;
		 * 
		 * int b = hashcode & 0xf;
		 * 
		 * return "/" + a + "/" + b;
		 */
	}

	/*
	 * public static void main(String[] args) { String path =
	 * getRandomDirectory("a.txt");
	 * 
	 * File file = new File("C:/Users/lx/Desktop/upload"); File directory = new
	 * File(file, path); if (!directory.exists()) { directory.mkdirs(); } }
	 */
}


新建UploadServlet4
package cn.itcast.web.servlet;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

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.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;

import cn.itcast.utils.FileUploadUtils;

public class Upload4Servlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		// 1.创建DiskFileItemFactory
		File file = new File(this.getServletContext().getRealPath("/temp"));// 获取temp目录部署到tomcat后的绝对磁盘路径
		DiskFileItemFactory factory = new DiskFileItemFactory(1024 * 100, file);

		// 2.创建ServletFileUpload
		ServletFileUpload upload = new ServletFileUpload(factory);
		// 判断是否是上传操作(即检测encType是否为"multipart/form-data")
		boolean flag = upload.isMultipartContent(request);
		if (flag) {
			// 解决上传文件中文名称乱码
			// 注意:也可以使用request.setCharacterEncoding("utf-8"); 不建议使用
			upload.setHeaderEncoding("utf-8");

			// 设置上传文件大小
			// upload.setSizeMax(1024*1024*10); // 设置文件总大小为10M

			try {
				List<FileItem> items = upload.parseRequest(request);// 解析request,得到所有上传项FileItem

				// 3.得到所有上传项
				for (FileItem item : items) {
					if (!item.isFormField()) {
						String name = item.getName(); // 上传文件名
						// 得到上传文件真实名称
						String filename = FileUploadUtils.getRealName(name);

						// 得到随机名称
						String uuidname = FileUploadUtils
								.getUUIDFileName(filename);

						// 得到随机目录
						String randomDirectory = FileUploadUtils
								.getRandomDirectory(filename);

						// 注意:随机目录可能不存在,需要创建
						File rd = new File("C:/Users/lx/Desktop/upload/",
								randomDirectory);
						if (!rd.exists()) {
							rd.mkdirs();
						}

						IOUtils.copy(item.getInputStream(),
								new FileOutputStream(new File(rd, uuidname)));

						// 删除临时文件
						item.delete();
					}
				}
			} catch (FileUploadException e) {
				// e.printStackTrace();
				response.getWriter().write(e.getMessage());
			}
		} else {
			response.getWriter().write("不是上传操作");
			return;
		}
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doGet(request, response);
	}

}
运行如下:

文件下载

(1)超连接下载

download1.jsp
<a href='${pageContext.request.contextPath}/upload/a.jpg'>a.jpg</a><br>
<a href='${pageContext.request.contextPath}/upload/a.docx'>a.docx</a><br>
<a href='${pageContext.request.contextPath}/upload/a.txt'>a.txt</a><br>
<a href='${pageContext.request.contextPath}/upload/就算没有如果.flac'>就算没有如果.flac</a><br>
注意:如果文件可以直接被浏览器解析,那么会在浏览器中直接打开,不能被浏览器直接解析,就是下载操作。
直接打开的要想下载 ,右键另存为。
超连接下载,要求下载 的资源,必须是可以直接被浏览器直接访问的。
客户端访问服务器静态资源文件时,静态资源文件是通过 缺省Servlet返回的,
在tomcat配置文件conf/web.xml 找到 --- org.apache.catalina.servlets.DefaultServlet

(2)在服务器端编程完成下载.

1.创建download2.jsp
<a href='${pageContext.request.contextPath}/download?filename=a.jpg'>a.jpg</a><br>
<a href='${pageContext.request.contextPath}/download?filename=a.docx'>a.docx</a><br>
<a href='${pageContext.request.contextPath}/download?filename=a.txt'>a.txt</a><br>
<a href='${pageContext.request.contextPath}/download?filename=就算没有如果.flac'>就算没有如果.flac</a><br>

2.创建DownloadServlet
// 1.得到要下载 的文件名称
String filename = request.getParameter("filename");

//2.判断文件是否存在
File file = new File("d:/upload/" + filename);
if (file.exists())
//3.进行下载
原理:就是通过response获取一个输出流,将要下载的文件内容写回到浏览器端就可以了.

注意:要想通过编程的方式,实现文件下载,
1.要设置mimetype类型
resposne.setContextType(String mimeType);
问题:怎样可以得到要下载文件的mimeType类型?
ServletContext.getMimeType(String filename);
如果设置了mimeType,浏览器能解析的就直接展示了,不能解析的,直接下载.
2.设置一个响应头,设置后的效果,就是无论返回的是否可以被浏览器解析,就是下载 。
response.setHeader("content-disposition","attachment;filename=下载文件名称");
总结:服务器端编程下载:
1.将下载的文件通过resposne.getOutputStream()流写回到浏览器端。
2.设置mimeType response.setContentType(getServletContext.getMimeType(String filename));
3.设置响应头,目的是永远是下载操作
response.setHeader("content-disposition","attachment;filename=下载文件名称");

(3)文件下载时的乱码问题:

下载乱码一:关于下载时中文名称资源查找不到
原因:<a href='${pageContext.request.contextPath}/download?filename=就算没有如果.flac'>就算没有如果.flac</a>
这是get请求。
在服务器端需要做如下处理:
String filename = request.getParameter("filename");
解决: new String(filename.getBytes("iso8859-1"),"utf-8");
下载乱码二:下载文件显示时的中文乱码问题
response.setHeader("content-disposition", "attachment;filename="+filename);
IE:要求filename必须是utf-8码
firefox:要求filename必须是base64编码.
问题:怎样判断浏览器?
String agent=request.getHeader("user-agent");
if (agent.contains("MSIE")) {
// IE浏览器
filename = URLEncoder.encode(filename, "utf-8");
} else if (agent.contains("Firefox")) {
// 火狐浏览器
BASE64Encoder base64Encoder = new BASE64Encoder();
filename = "=?utf-8?B?"
+ base64Encoder.encode(filename.getBytes("utf-8"))
+ "?=";
}else {
// 其它浏览器
filename = URLEncoder.encode(filename, "utf-8");
}

代码示例:浏览器端超链接下载

在WebRoot目录下新建名称为upload的文件夹 拖进去几个文件如下所示:
新建download1.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'index.jsp' starting page</title>
  </head>
  
  <body>
    <a href='${pageContext.request.contextPath}/upload/a.jpg'>a.png</a><br>
	<a href='${pageContext.request.contextPath}/upload/a.docx'>a.docx</a><br>
	<a href='${pageContext.request.contextPath}/upload/a.txt'>a.txt</a><br>
	<a href='${pageContext.request.contextPath}/upload/就算没有如果.flac'>就算没有如果.flac</a><br>
  </body>
</html>



发现浏览器能解析的就直接显示在页面中了 而不是直接下载

代码示例:服务器端下载

在桌面新建upload文件夹 在文件夹内将上面几个资源文件拖进去
新建download2.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'index.jsp' starting page</title>
  </head>
  
  <body>
    <a href='${pageContext.request.contextPath}/download?filename=a.jpg'>a.jpg</a><br>
	<a href='${pageContext.request.contextPath}/download?filename=a.docx'>a.docx</a><br>
	<a href='${pageContext.request.contextPath}/download?filename=a.txt'>a.txt</a><br>
	<a href='${pageContext.request.contextPath}/download?filename=就算没有如果.flac'>就算没有如果.flac</a><br>
  </body>
</html>
新建DownloadServlet
package cn.liuxun.web.servlet;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;

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

import sun.misc.BASE64Encoder;

public class DownloadServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		// 1.得到要下载的文件名称
		String filename = request.getParameter("filename");

		filename = new String(filename.getBytes("iso8859-1"), "utf-8"); // 解决中文乱码

		// 2.在c:/Users/lx/Desktop/upload目录下查找这个文件是否存在
		File file = new File("c:/Users/lx/Desktop/upload", filename);
		if (file.exists()) {
			// 文件存在,完成下载

			// 下载注意事项1--设置下载文件的mimeType
			String mimeType = this.getServletContext().getMimeType(filename);
			response.setContentType(mimeType);

			String agent = request.getHeader("user-agent");
			if (agent.contains("MSIE")) {
				// IE浏览器
				filename = URLEncoder.encode(filename, "utf-8");

			} else if (agent.contains("Firefox")) {
				// 火狐浏览器
				BASE64Encoder base64Encoder = new BASE64Encoder();
				filename = "=?utf-8?B?"
						+ base64Encoder.encode(filename.getBytes("utf-8"))
						+ "?=";
			} else {
				// 其它浏览器
				filename = URLEncoder.encode(filename, "utf-8");
			}

			// 下载注意事项2--永远是下载 设置以附件的形式进行打开下载
			response.setHeader("content-disposition", "attachment;filename="
					+ filename);

			FileInputStream fis = new FileInputStream(file); // 读取要下载文件的内容
			OutputStream os = response.getOutputStream();// 将要下载的文件内容通过输出流写回到浏览器
			int len = -1;
			byte[] b = new byte[1024 * 100];

			while ((len = fis.read(b)) != -1) {
				os.write(b, 0, len);
				os.flush();
			}
			os.close();
			fis.close();
		} else {
			throw new RuntimeException("下载资源不存在");
		}
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doGet(request, response);
	}

}


遍历文件夹操作

(1)方式一:递归遍历
在项目中新建如下文件夹

递归遍历如下:
<%@page import="java.io.File"%>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>使用递归完成下载upload目录下的所有文件</title>
</head>

<body>
	<!-- 使用递归操作 -->

	<%!//声明一个方法
	public void getFile(File file) {
		if (file.isDirectory()) { //是目录
			File[] fs = file.listFiles();
			for (int i = 0; i < fs.length; i++) {
				getFile(fs[i]); //递归调用
			}
		} else if (file.isFile()) { //是文件
			System.out.println(file.getName()+"  路径:"+file.getPath());
		}
	}%>
	<%
		String path = application.getRealPath("/upload");
		File uploadDirectory = new File(path);
		getFile(uploadDirectory);
	%>
</body>
</html>


(2)方式二:使用队列替代递归
队列特点:先进先出.
在jdk中有一个接口Queue 它有一个实现类叫LinkedList它其时就是一个队列。
如果要使用队列,插入 offer 获取使用 poll
使用队列来优化递归操作:是可以解决目录层次过多问题。
  • 因为:递归操作可以理解成是纵向的遍历,如果目录层次比较多,在内存中存储的数据也多,会引起溢出。
  • 使用队列,它是横向遍历,一层一层遍历,可以解决目录层次比较多问题。
  • 因为使用队列,最多时候在内存中只存储了一层的信息
<%@page import="java.io.File"%>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>使用队列来完成下载upload目录下所有文件</title>
  </head>
  
  <body>
  <!-- 使用队列操作 -->
  <%
    String path=application.getRealPath("/upload");
   File uploadDirectory=new File(path);
   //创建一个队列
   
   Queue<File> queue=new LinkedList<File>();
   
   queue.offer(uploadDirectory);
   
   while(!queue.isEmpty()){ //如果队列不为空
	   File f=queue.poll(); //从队列中获取一个File
	   
	   if(f.isDirectory()){ //是目录,将目录下所有文件遍历出来,存储在队列中
		   File[] fs=f.listFiles();
	     for(int i=0;i<fs.length;i++){
	    	 queue.offer(fs[i]);
	     }
	   }else{
		   String absolutePath=f.getAbsolutePath();
		   
		   String  p=absolutePath.substring(absolutePath.lastIndexOf("\\upload"));
		   
		   out.println("<a href='"+application.getContextPath()+p+"'>"+f.getName()+"</a><br>");
	   }
	   
   }
  %>
  
  </body>
</html>
访问如下:



网盘系统(实例演示上传和下载)

实现步骤如下:
(1)创建表
                create table resources(
		  id int primary key auto_increment,
		  uuidname varchar(100) unique not null,
		  realname varchar(40) not null,
		  savepath varchar(100) not null,
		  uploadtime timestamp ,
		  description varchar(255)
		);

(2)导入jar包
C3P0、BeanUtils、DbUtils、FileUpload、JSTL、MySQL驱动
C3P0:c3p0-0.9.1.2.jar
BeanUtils:commons-beanutils-1.8.3.jar、commons-logging-1.1.1.jar
DbUtils:commons-dbutils-1.4.jar
FileUpload:commons-fileupload-1.2.1.jar、commons-io-1.4.jar
JSTL:jstl.jar、standard.jar

MySQL驱动:mysql-connector-java-5.1.28-bin.jar

(3)编码实现上传

1.在index.jsp页面添加上传连接
<a href='${pageContext.request.contextPath}/upload.jsp'>上传</a><br>
2.创建upload.jsp页面
上传操作浏览器端三个注意事项:
1.method=post
2.encType="multipart/form-data"
3.要使用<input type="file" name='f'>

<form action="${pageContext.request.contextPath}/upload" method="post" enctype="multipart/form-data">
<input type="file" name="f"><br>
描述:<input type="text" name="description"><br>
<input type="submit" value="提交">
</form>
3.创建UploadServlet
1.完成上传操作
2.将数据封装,存储到数据库。

1.上传操作
commons-fileupload
1.DiskFileItemFactory
2.ServletFileUpload
3.FileItem

2.将数据封装,存储到数据库.
问题:怎样将数据封装到javaBean?
手动创建一个Map<String,String[]>将数据封装到map集合,
通过BeanUtils完成数据封装.

(4)下载操作

1.在index.jsp页面,下载连接会访问一个servlet,得到所有可以下载的数据,在页面上展示 .
1.index.jsp页面代码
<a href="${pageContext.request.contextPath}/showDownload">下载</a>
2.创建ShowDownloadServlet
在这个servlet中,查看db,得到所有可以下载的信息.
List<Resource> rs = service.findAll();
3.创建一个download.jsp页面,展示所有可以下载的信息.

2.在download.jsp,点击下载时,传递的是要下载文件的id。
<a href='${pageContext.request.contextPath}/download?id=${r.id}'>下载</a>
1.创建一个DownloadServlet
1.查询数据库,得到要下载的文件的相关信息
2.下载操作


该项目目录图如下:

---

具体代码如下:

添加数据源配置c3p0-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
	<default-config>
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql:///mydb1</property>
		<property name="user">root</property>
		<property name="password">root</property>
	</default-config>

</c3p0-config>
	
新建工具类DataSourceUtils 获取连接池中的数据源

package cn.liuxun.utils;

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class DataSourceUtils {
	private static ComboPooledDataSource cpds = new ComboPooledDataSource();

	public static Connection getConnection() throws SQLException {
		return cpds.getConnection();
	}

	public static DataSource getDataSource() {
		return cpds;
	}
}
新建工具类 FileUploadUtils获取 文件真实名称、随机名称以及 目录分离中的随机目录

package cn.liuxun.utils;

import java.util.UUID;

public class FileUploadUtils {

	// 得到上传文件真实名称 c:\a.txt a.txt
	public static String getRealName(String filename) {
		int index = filename.lastIndexOf("\\") + 1;
		return filename.substring(index);
	}

	// 获取随机名称
	public static String getUUIDFileName(String filename) {
		int index = filename.lastIndexOf(".");
		if (index != -1) {
			return UUID.randomUUID() + filename.substring(index);
		} else {
			return UUID.randomUUID().toString();
		}
	}

	// 目录分离算法
	public static String getRandomDirectory(String filename) {
		int hashcode = filename.hashCode();
		System.out.println(Integer.toBinaryString(hashcode));

		int a = hashcode & 0xf;
		
		hashcode = hashcode >>> 4;
		
		int b = hashcode & 0xf;
		
		return "/"+a+"/"+b;
	}
}

新建Bean类Resource

package cn.liuxun.domain;

import java.sql.Timestamp;

public class Resource {
	// id INT PRIMARY KEY AUTO_INCREMENT,
	// uuidname VARCHAR(100) UNIQUE NOT NULL,
	// realname VARCHAR(40) NOT NULL,
	// savepath VARCHAR(100) NOT NULL,
	// uploadtime TIMESTAMP ,
	// description VARCHAR(255)

	private int id;
	private String uuidname;
	private String realname;
	private String savepath;
	private Timestamp uploadtime;
	private String description;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getUuidname() {
		return uuidname;
	}

	public void setUuidname(String uuidname) {
		this.uuidname = uuidname;
	}

	public String getRealname() {
		return realname;
	}

	public void setRealname(String realname) {
		this.realname = realname;
	}

	public String getSavepath() {
		return savepath;
	}

	public void setSavepath(String savepath) {
		this.savepath = savepath;
	}

	public Timestamp getUploadtime() {
		return uploadtime;
	}

	public void setUploadtime(Timestamp uploadtime) {
		this.uploadtime = uploadtime;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

}


新建DAO类ResourceDao

package cn.liuxun.dao;

import java.sql.SQLException;
import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import cn.liuxun.domain.Resource;
import cn.liuxun.utils.DataSourceUtils;

public class ResourceDao {

	public List<Resource> findAll() throws SQLException {
		QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());

		return runner.query("select * from resources",
				new BeanListHandler<Resource>(Resource.class));
	}

	public void save(Resource r) throws SQLException {
		String sql = "insert into resources values(null,?,?,?,null,?)";
		QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
		runner.update(sql, r.getUuidname(), r.getRealname(), r.getSavepath(),
				r.getDescription());
	}

	public Resource findById(String id) throws SQLException {
		QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
		return runner.query("select * from resources where id=?",
				new BeanHandler<Resource>(Resource.class), id);
	}

}


新建service类 ResourceService类

package cn.liuxun.service;

import java.sql.SQLException;
import java.util.List;

import cn.liuxun.dao.ResourceDao;
import cn.liuxun.domain.Resource;

public class ResourceService {

	public List<Resource> findAll() throws SQLException {
	 return new ResourceDao().findAll();
	}

	public void save(Resource r) throws SQLException {
		new ResourceDao().save(r);
	}

	public Resource findById(String id) throws SQLException {
        
		return new ResourceDao().findById(id);
	}

}

新建Servlet类DownloadServlet 用于下载网盘文件

package cn.liuxun.web.servlet;

import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.sql.SQLException;

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

import org.apache.commons.io.FileUtils;

import sun.misc.BASE64Encoder;
import cn.liuxun.domain.Resource;
import cn.liuxun.service.ResourceService;

public class DownloadServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		// 1.得到id
		String id = request.getParameter("id");

		// 2.调用service,得到Resource对象
		ResourceService service = new ResourceService();
		try {
			Resource r = service.findById(id);

			File file = new File(r.getSavepath(), r.getUuidname());

			if (file.exists()) {
				// 资源存在
				String filename = r.getRealname();
				// 下载注意事项1 -- 设置下载文件的mimeType
				String mimeType = this.getServletContext()
						.getMimeType(filename);
				response.setContentType(mimeType);

				String agent = request.getHeader("user-agent");
				if (agent.contains("MSIE")) {
					// IE浏览器
					filename = URLEncoder.encode(filename, "utf-8");

				} else if (agent.contains("Firefox")) {
					// 火狐浏览器
					BASE64Encoder base64Encoder = new BASE64Encoder();
					filename = "=?utf-8?B?"
							+ base64Encoder.encode(filename.getBytes("utf-8"))
							+ "?=";
				} else {
					// 其它浏览器
					filename = URLEncoder.encode(filename, "utf-8");
				}

				// 下载注意事项2 -- 永远是下载
				response.setHeader("content-disposition",
						"attachment;filename=" + filename);

				byte[] b = FileUtils.readFileToByteArray(file);// 将指定文件读取到byte数组中

				response.getOutputStream().write(b);
				
			} else {

			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doGet(request, response);
	}

}

新建下载列表展示类ShowDownloadServlet

package cn.liuxun.web.servlet;

import java.io.IOException;
import java.sql.SQLException;
import java.util.List;

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

import cn.liuxun.domain.Resource;
import cn.liuxun.service.ResourceService;

public class ShowDownloadServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		ResourceService service = new ResourceService();
		try {
			List<Resource> rs = service.findAll();

			request.setAttribute("rs", rs);

			request.getRequestDispatcher("/download.jsp").forward(request,
					response);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doGet(request, response);
	}

}

新建UploadServlet类 用于上传文件

package cn.liuxun.web.servlet;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;

import cn.liuxun.domain.Resource;
import cn.liuxun.service.ResourceService;
import cn.liuxun.utils.FileUploadUtils;

public class UploadServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		Map<String, String[]> map = new HashMap<String, String[]>();

		// 1.创建DiskFileItemFactory
		DiskFileItemFactory factory = new DiskFileItemFactory();

		// 2.创建ServletFileUpload
		ServletFileUpload upload = new ServletFileUpload(factory);

		// 设置上传中文名称乱码
		upload.setHeaderEncoding("utf-8");
		// upload.isMultipartContent(request);
		// 3.得到所有的FileItem
		try {
			List<FileItem> items = upload.parseRequest(request);

			// 遍历items,得到所有的上传信息
			for (FileItem item : items) {
				if (item.isFormField()) {
					// 不是上传组件
					map.put(item.getFieldName(),
							new String[] { item.getString("utf-8") });// 封装非上传组件信息
				} else {
					// 是上传组件
					// 得到上传文件名称
					String filename = item.getName();
					filename = FileUploadUtils.getRealName(filename);
					map.put("realname", new String[] { filename });// 封装上传文件真实名称
					// 得到随机名称
					String uuidname = FileUploadUtils.getUUIDFileName(filename);

					map.put("uuidname", new String[] { uuidname });// 封装上传文件随机名称

					// 得到随机目录
					String randomDirectory = FileUploadUtils
							.getRandomDirectory(filename);

					String uploadPath = this.getServletContext().getRealPath(
							"/WEB-INF/upload");

					File parentDirectory = new File(uploadPath, randomDirectory);
					if (!parentDirectory.exists()) {
						parentDirectory.mkdirs();
					}

					map.put("savepath", new String[] { uploadPath
							+ randomDirectory });// 封装上传文件保存路径

					IOUtils.copy(item.getInputStream(), new FileOutputStream(
							new File(parentDirectory, uuidname)));

					item.delete();
				}
			}

			// 将数据封装到JavaBean
			Resource r = new Resource();

			BeanUtils.populate(r, map);

			// 调用service完成保存数据到db
			ResourceService service = new ResourceService();

			service.save(r);

		} catch (FileUploadException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doGet(request, response);
	}

}

新建JSP页面

index.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'index.jsp' starting page</title>
  </head>
  
  <body>
   <a href="${pageContext.request.contextPath }/upload.jsp">上传</a>
   <a href="${pageContext.request.contextPath }/showDownload">下载</a>
  </body>
</html>

upload.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
</head>

<body>
	<form action="${pageContext.request.contextPath }/upload" method="post"
		enctype="multipart/form-data">
		<input type="file" name="f"> <br>
		描述:<input type="text" name="description"><br>
      <input type="submit" value="提交">
	</form>
</body>
</html>

download.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
</head>

<body>
	<table border="1" align="center" width="65%">
		<tr>
			<td>文件名称</td>
			<td>文件描述</td>
			<td>下载操作</td>
		</tr>
		<c:forEach items="${rs }" var="r">
			<tr>
				<td>${r.realname }</td>
				<td>${r.description }</td>
				<td><a
					href="${pageContext.request.contextPath }/download?id=${r.id}">下载</a></td>
			</tr>
		</c:forEach>
	</table>
</body>
</html>


上传几个文件进行测试 下载如下:



查看数据库中的resources表



打开发布后的文件夹


OK

注意:此网盘文件内容是保存在项目中的 如果重新部署项目 文件就会丢失

在重新部署项目之前需要将upload文件夹进行备份
























  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值