06、文件上传下载
一、引言
1.1、场景
在项目中,文件的上传和下载是常见的功能。很多程序或者软件中都经常使用到文件的上传和下载。
邮箱中有附件的上传和下载
OA办公系统中有附件材料的上传
二、文件上传
2.1、概念
当用户在前端页面点击文件上传后,用户上传的文件数据提交给服务器端,实现保存。
2.2、文件上传实现步骤
2.2.1、提交方式
提供form表单,method必须是post。因为post请求无数据限制。
<form method="post"> </form>
2.2.2、提交数据格式
表单的enctype属性值必须为multipart/form-data。
以多段的形式进行拼接提交。以二进制流的方式来处理表单数据,会把指定的文件内容封装进请求参数中。
<form enctype="multipart/form-data" method="post"></form>
2.2.3、提供组件
提供file表单组件,提供给用户上传文件
<form enctype="multipart/form-data" method="post"> 上传用户:<input type="text" name="username "><br /> 上传文件1:<input type="file" name="file1"><br /> <input type=" submit" value="提交"> </form>
2.2.4、Controller编写
在Servlet 3.0及其以上版本的容器中进行服务器端文件上传的编程,是围绕着注解类型MultipartConfig和javax. servlet.http.Part接口进行的。处理已上传文件的Servlet必须以@MultipartConfig进行注解。
@WebServlet(name = "UploadController", value = "/uploadController") @MultipartConfig(maxFileSize = 1024 * 1024 * 100, maxRequestSize = 1024 * 1024 * 200) public class UploadController extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //设置乱码 request.setCharacterEncoding("UTF-8"); response.setContentType("text/html ; charset=utf-8"); //通过getPart方法获取文件组件 Part file1 = request.getPart("file1"); //获取上传文件保存路径(真实路径) String uploadPath = request.getServletContext().getRealPath("WEB-INF/upload"); System.out.println(uploadPath); //创建文件夹对象 File file = new File(uploadPath); //如果文件夹不存在,新建 if (!file.exists()) { file.mkdirs(); } //如果上传的文件不是空,进行保存 if (file1 != null) { file1.write(uploadPath + File.separator + file1.getSubmittedFileName()); } response.getWriter().println("上传成功!" + file1.getSubmittedFileName()); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
2.3、文件上传细节注意
上述的代码虽然可以成功将文件上传到服务器的指定目录当中,但是文件上传功能有许多需要注意的小细节问题。
2.3.1、安全问题
为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下。
2.3.2、文件覆盖
当上传重名的文件时,为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名。
//使用UUID生成唯一标识码,拼接上图片的名称。 public static String newFileName(String filename){ return UUID.randomUUID().toString().replaceAll("-","")+"_"+filename; }
2.3.3、散列存储
为防止一个目录下面出现太多文件,要使用hash算法生成二级、三级目录,散列存储上传的文件。
//生成二级、三级目录 public static String newFilePath(String basepath,String filename){ int hashCode = filename.hashCode(); int path1 = hashCode & 15;//二级目录 与运算 0~15 int path2 = (hashCode>>4) & 15;//三级目录 0~15 String newPath = basepath+"\\"+path1+"\\"+path2; File file = new File(newPath); if(!file.exists()){ file.mkdirs(); } return newPath; }

2.3.4、文件类型限制
要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。
//4.文件上传 //生成唯一文件名 String oldName = part.getSubmittedFileName(); List<String> nameList = new ArrayList<>(); nameList.add(".jpg"); nameList.add(".png"); nameList.add(".jpeg"); String extName = oldName.substring(oldName.lastIndexOf(".")); if(!nameList.contains(extName)){ response.getWriter().println(oldName+"不符合文件上传的规则!"); return; }
2.4、多文件上传
@WebServlet(name = "MoreUploadController",value = "/moreUpload") @MultipartConfig(maxFileSize = 1024*1024*100,maxRequestSize = 1024*1024*200) public class MoreUploadController extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); // 得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全 String basePath = request.getServletContext().getRealPath("/WEB-INF/upload"); File file = new File(basePath); if(!file.exists()){ file.mkdirs(); } //获得表单提交的所有数据 Collection<Part> parts = request.getParts(); for (Part part : parts) { // 获取文件提交的名字 String filename = part.getSubmittedFileName(); if(filename!=null){ // 文件 if(filename.trim().equals("")){ continue; } // 获得包含UUID的文件名 String newName = UploadUtils.newFileName(filename); // 获取分散后的路径 String newPath = UploadUtils.newFilePath(basePath,filename); part.write(newPath+"\\"+newName); }else{//普通表单项 String username = request.getParameter(part.getName()); System.out.println(username); } } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
三、文件下载
3.1、概念
我们要将Web应用系统中的文件资源提供给用户进行下载,首先我们要有一个页面列出上传文件目录下的所有文件,当用户点击文件下载超链接时就进行下载操作。
3.2、获取文件列表
3.2.1、DownLoadUtils
public class UploadUtils { //使用UUID生成唯一标识码,拼接上图片的名称。 public static String newFileName(String filename){ return UUID.randomUUID().toString().replaceAll("-","")+"_"+filename; } //生成二级、三级目录 public static String newFilePath(String basepath,String filename){ int hashCode = filename.hashCode(); int path1 = hashCode & 15;//二级目录 与运算 0~15 int path2 = (hashCode>>4) & 15;//三级目录 0~15 String newPath = basepath+"\\"+path1+"\\"+path2; File file = new File(newPath); if(!file.exists()){ file.mkdirs(); } return newPath; } }
3.2.2、FileListController
@WebServlet(name = "FileListController",value = "/fileList") public class FileListController extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=utf-8"); //集合,map,key=UUID value=源文件名称 HashMap<String,String> fileMap = new HashMap<>(); String basePath = request.getServletContext().getRealPath("/WEB-INF/upload"); DownLoadUtils.getFileList(new File(basePath),fileMap); request.setAttribute("fileMap",fileMap); request.getRequestDispatcher("/list.jsp").forward(request,response); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
3.3、下载
3.3.1、fileList.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>文件下载页面</title>
</head>
<body>
<table>
<tr>
<th>文件名</th>
<th>操作</th>
</tr>
<c:forEach items="${fileMap}" var="entry">
<tr>
<td>${entry.value}</td>
<td><a href="${pageContext.request.contextPath}/downLoad?filename=${entry.key}">下载</a></td>
</tr>
</c:forEach>
</table>
</body>
</html>
3.3.2、DownLoadController
@WebServlet(name = "DownLoadController",value = "/downLoad") public class DownLoadController extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); String basePath = request.getServletContext().getRealPath("/WEB-INF/upload"); //UUID文件名 String uuidFilename = request.getParameter("filename"); //通过_拆分,UUID和源文件名称 String filename = uuidFilename.split("_")[1]; //通过工具类,使用源文件名称获得散列存储的路径,就是下载的路径 String downPath = UploadUtils.newFilePath(basePath,filename); //设置响应头,响应的文件类型和如何处理该文件 附件下载 response.setHeader("content-disposition","attachment;filename="+ URLEncoder.encode(filename,"UTF-8")); FileInputStream is = new FileInputStream(downPath+"\\"+uuidFilename); ServletOutputStream sos = response.getOutputStream(); byte[] buffer = new byte[1024*1024*100]; int len = 0; while((len=is.read(buffer))!=-1){ sos.write(buffer,0,len); } sos.close(); is.close(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }

浙公网安备 33010602011771号