一.文件的上传
<form action="/upload" method="post" enctype="multipart/form-data" ><br>
姓名:<input type="text" name="username" ><br>
年龄:<input type="text" name="age" ><br>
文件:<input type="file" name="headImage1" ><br>
文件:<input type="file" name="headImage2" ><br>
<input type="submit" value="提交" >
</form>
@WebServlet("/upload")
public class uploadServlet extends HttpServlet{
@Override
protected void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
Map<String,Object> map = new HashMap<>();
try {
FileUploadUtils.upload(request,map);
System.out.println(map);
} catch (LoginException e) {
request.setAttribute("errorMeg", e.getMessage());
request.getRequestDispatcher("/upload/upload.jsp").
forward(request, response);
System.out.println(e.getMessage());
}
}
}
public class FileUploadUtils {
// 文件的上传操作
public static void upload(HttpServletRequest request,
Map<String, Object> map) throws UnsupportedEncodingException {
/*
* 1 得到上传文件保存的目录,将文件存放在WEB-INF目录下,
* 不允许外界直接访问,保证上传文件的安全 通过相对路径获得绝对路径 带盘符
*/
String savePath = request.getServletContext().getRealPath("WEB-INF/upload");
// 2 设置上传文件时,如果文件过多,保存的临时目录
String tempPath = request.getServletContext().getRealPath("WEB-INF/temp");
File tempFile = new File(tempPath);
if (!tempFile.exists()) {
// 创建临时文件夹
tempFile.mkdirs();
}
// 3 解析请求
// 验证请求是否满足要求(post和enctype是否为multipart/开头)
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
// 如果不满足条件,就立即结束对该请求的处理
if (!isMultipart) {
return;
}
try {
// FileItem实际上就是表单中的每一个表单元素的封装
// <input type="text" name="username" ><br>
// 3.1 创建FileItem的工厂类
DiskFileItemFactory factory = new DiskFileItemFactory();
/* 3.2 设置工厂的缓冲区的大小,当上传的文件大小超过缓冲区的大小时,
就会生成一个临时文件存放到指定的临时目录当中。 */
factory.setSizeThreshold(1024 * 500);
// 3.3 设置临时目录
factory.setRepository(tempFile);
// 3.4 创建一个文件上传处理器(装饰者模式)
ServletFileUpload upload = new ServletFileUpload(factory);
// 3.5 监听文件上传的进度
upload.setProgressListener(new ProgressListener() {
@Override
public void update(long pBytesRead, long pContentLength, int pItems) {
System.out.println("当前的文件大小为:" + pContentLength +
",当前文件已处理:" + pBytesRead);
}
});
// 3.6 解决上传文件过程中文件名出现的乱码问题
upload.setHeaderEncoding("UTF-8");
// 3.7 设置单个文件上传的大小5M
upload.setFileSizeMax(1024 * 5000);
// 3.8 设置整个请求中上传文件和数据的大小 10M
upload.setSizeMax(1024 * 10000);
// 解析请求
List<FileItem> items = upload.parseRequest(request);
for (FileItem fileItem : items) {
// 3.9 判断控件是否是普通控件
if (fileItem.isFormField()) {
map.put(fileItem.getFieldName(), fileItem.getString("UTF-8"));
} else {
String fileName = null;
if (null == fileItem.getName() ||
"".equals(fileItem.getName().trim())) {
continue;
} else {
/* 不同的浏览器提交的文件名是不一样的
,有些浏览器提交上来的文件名是带有路径的,如: c:\a\2.png */
if (fileItem.getName().contains("\\")) {
fileName = fileItem.getName().substring(
fileItem.getName().lastIndexOf("\\") + 1);
// 得到文件的扩展名
// String fileExtName =
// FilenameUtils.getExtension(fileItem.getName());
String fileExtName = fileItem.getName().substring
(fileItem.getName().lastIndexOf(".") + 1);
} else {
fileName = fileItem.getName();
}
}
// 3.10 保存文件的文件名 避免文件名重复 用工具类获得文件的拓展名
String saveFileName = UUID.randomUUID().toString() + "_" + fileName;
System.out.println(fileItem.isInMemory());
// 3.11 上传文件的约束
String contentType = fileItem.getContentType();
if (!contentType.startsWith("image/")) {
throw new LoginException("亲,您的文件格式不正确!");
}
// 3.12 保存文件的文件目录
// 为防止一个目录下面出现太多文件,要使用hash算法打散存储
/* 得到文件名的hashCode的值,得到的就是filename这个
字符串对象在内存中的地址 */
int hashCode = saveFileName.hashCode();
int dir1 = hashCode & 0xf; // 0--15
int dir2 = (hashCode & 0xf0) >> 4; // 0-15
// 构建一个新的保存目录 // upload\1\2
String realSavePath = savePath + "\\" + dir1 + "\\" + dir2;
// File 可以是目录结构
File saveFileDir = new File(realSavePath);
// 目录不存在就创建目录
if (!saveFileDir.exists()) {
saveFileDir.mkdirs();
}
System.out.println("通过相对路径获取绝对路径:" + realSavePath);
fileItem.write(new File(realSavePath, saveFileName));
map.put(fileItem.getFieldName(), saveFileName);
}
}
// 自定义异常,抛出去在Servlet中统一处理,返回给前端
} catch (SizeLimitExceededException e) {
throw new LoginException("多个文件上传大小不超过700kb", e);
} catch (FileSizeLimitExceededException e) {
throw new LoginException("上传文件大小不超过500KB", e);
} catch (LoginException e1) {
throw e1;
} catch (Exception e) {
throw new LoginException("文件上传失败!", e);
}
}
}
二.文件的下载
1.得到所有上传文件夹下面的文件
@WebServlet(value="/listFile")
public class ListFileServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
/******要有一个页面列出上传文件目录下的所有文件,
当用户点击文件下载超链接时就进行下载操作**/
// 1 获取上传文件的目录
String uploadFilePath = request.getServletContext()
.getRealPath("/WEB-INF/upload");
// 2 获得将要存放下载文件的文件名
Map<String,Object> fileNameMap = new HashMap<>();
// 3 遍历获得所有指定目录下面的文件
File fileOrFolder = new File(uploadFilePath);
listFile( fileOrFolder, fileNameMap);
// 4 将文件名发送到前端进行显示
request.setAttribute("fileNameMap", fileNameMap);
// 5 请求转发
request.getRequestDispatcher("/download.jsp").forward(request, response);
}
public void listFile(File file,Map<String, Object> fileNameMap){
// file是目录
if(!file.isFile()){
File[] listFiles = file.listFiles();
for (File f : listFiles) {
// 递归遍历
listFile(f,fileNameMap);
}
}else{
/*处理文件名,上传后的文件是以uuid_文件名的形
* 式去重新命名的,去除文件名的uuid_部分*/
String realName = file.getName().substring(
file.getName().indexOf("_")+1);
// file.getName() 得到是带有uuid的文件名,是唯一的,可以作为key
fileNameMap.put(file.getName(), realName);
}
}
}
2.前端页面显示要下载的文件
<h1>资源下载</h1>
<!--遍历map集合 -->
<c:forEach items="${fileNameMap}" var="fnm" >
<c:url value="/download" var="downloadurl" >
<c:param name="fileName" value="${fnm.key }" ></c:param>
</c:url>
${fnm.key }<a href="${downloadurl}" >下载</a><br>
</c:forEach>
3.对文件进行下载
@WebServlet("/download")
public class DownLoadServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=utf-8");
// 设置响应数据的MIME类型
response.setContentType("application/x-msdownload");
// 1 获取前端传过来的文件名称
String filename = request.getParameter("fileName");
String fileName = new String(filename.getBytes("ISO-8859-1"),"UTF-8");
// 2 获得文件上传的子目录 WEB-INF/upload
String fileSaveRootPath = this.getServletContext().
getRealPath("/WEB-INF/upload");
// 3 通过文件名找出文件所在的目录
int hashCode = fileName.hashCode();
int dir1 = hashCode & 0xf; // 0--15
int dir2 = (hashCode & 0xf0) >> 4; // 0-15
// 4 得到文件所在的目录
String realSavePath = fileSaveRootPath + "\\" + dir1 + "\\" + dir2; // upload\1\2
File saveFileDir = new File(realSavePath);
if (!saveFileDir.exists()) {
saveFileDir.mkdirs();
}
// 5 得到要下载的文件 绝对路径+文件名
File downloadFile = new File(realSavePath,fileName);
if(!downloadFile.exists()){
request.setAttribute("message", "您要下载的资源已被删除!!");
request.getRequestDispatcher("/error.jsp").forward(request, response);
return;
}
// 6 判断浏览器是否是IE浏览器
String userAgent = request.getHeader("User-Agent");
// 7 解决下载保存文件乱码问题
//处理文件名
String realname = fileName.substring(fileName.indexOf("_")+1);
if(userAgent.contains("MSIE")){
// IE 设置响应抱头
realname = URLEncoder.encode(realname, "UTF-8");
response.setHeader("Content-disposition", "attachment;filename="+ realname);
}else{
// FireFox
realname = new String(realname.getBytes("UTF-8"),"ISO-8859-1");
response.setHeader("Content-disposition", "attachment;filename="+realname );
System.out.println(realname);
}
ServletOutputStream outStream = response.getOutputStream();
// 8 将文件复制到输出流中,响应给浏览器
Files.copy(Paths.get(downloadFile.getAbsolutePath()), outStream);
}
}