简介:在一和二的基础之上,这次来记录下如何在页面提交表单数据,以及文件的上传和下载整个流程,请求也不仅限于GET了,也有POST了。
1. 为了方便,在 webapp 下直接新建一个 index.html,内容如下
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <title>欢迎页</title> </head> <body>
<form action="/upload" method="POST" enctype="multipart/form-data">
站点名: <input type="text" name="name"><br />
网址: <input type="text" name="url" /><br />
作者: <input type="text" name="author" /><br />
上传文件: <input type="file" name="file" /><br />
上传文件2: <input type="file" name="file2" /><br />
<input type="submit" value="提交" />
</form>
</body> </html>
form 的 action指定请求路径,这里是/upload,也可以是 process.jsp这种。
method 这里用的是 POST, 其它 GET 也可以用在这里。
enctype 表示的是提交请求中的Content-Type是 multipart/form-data,适用于文件上传。这里展示下请求的样式:
input type="file" 使用的是 文件上传的组件
input type="submit" 会把有 name 属性的 input 字段提交给 action 所指示的请求。
2. 新建 FileUploadServlet 来处理文件上传
这里文件上传处理,使用了开源组件 commons-fileupload,maven 依赖如下:
<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency>
Servlet主要业务代码如下(代码里用到了jdk8的lamda表达式,确实省代码)
逻辑比较简单,就是用 ServletFileUpload 来解析 request,获取到提交的文件信息,由于几个非文件也一并提交了,所以需要判断分类处理。
文件的上传和下载都是要使用流的。
@WebServlet(name = "fileUploadServlet", urlPatterns = {"/upload"}) public class FileUploadServlet extends HttpServlet { @Override public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String message=""; try { String savePath = request.getServletContext().getRealPath("/WEB-INF/upload"); String tmpPath = request.getServletContext().getRealPath("/WEB-INF/temp"); File file = new File(savePath); if (!file.exists() && !file.isDirectory()) { System.out.println(savePath + "目录不存在,需要创建"); file.mkdir(); } File tmpFile = new File(tmpPath); if (!tmpFile.exists() && !tmpFile.isDirectory()) { System.out.println(tmpPath + "目录不存在,需要创建"); tmpFile.mkdir(); } DiskFileItemFactory factory = new DiskFileItemFactory(); // 缓冲区大小设置 factory.setSizeThreshold(1024 * 100); factory.setRepository(tmpFile); ServletFileUpload upload = new ServletFileUpload(factory); upload.setProgressListener((pBytesRead, pContentLength, arg2) -> System.out.println("文件大小为:" + pContentLength + ",当前已处理:" + pBytesRead)); upload.setHeaderEncoding("UTF-8"); if (!ServletFileUpload.isMultipartContent(request)) { //按照传统方式获取数据 return; } //设置上传单个文件的大小的最大值,目前是设置为1024*1024字节,也就是1MB upload.setFileSizeMax(1024 * 1024 *10); //设置上传文件总量的最大值,最大值=同时上传的多个文件的大小的最大值的和,目前设置为10MB upload.setSizeMax(1024 * 1024 * 100); List<FileItem> list = upload.parseRequest(request); for (FileItem item : list) { if (item.isFormField()) { String name = item.getFieldName(); String value = item.getString("UTF-8"); // form 表单提交过的 enctype="multipart/form-data" request.setAttribute(name,value); System.out.println(name + "=" + value); } else { String filename = item.getName(); System.out.println(filename); if (filename == null || "".equals(filename.trim())) { continue; } filename = filename.substring(filename.lastIndexOf(File.separator) + 1); InputStream in = item.getInputStream(); FileOutputStream out = new FileOutputStream(savePath + File.separator + filename); byte[] buffer = new byte[1024]; int len; while ((len = in.read(buffer)) > 0) { out.write(buffer, 0, len); } in.close(); out.close(); //删除处理文件上传时生成的临时文件 item.delete(); } } } catch (FileUploadBase.FileSizeLimitExceededException e) { message = "单个文件超出最大值!"; System.out.println(message); request.setAttribute("message", message); request.getRequestDispatcher("/WEB-INF/page/message.jsp").forward(request, response); } catch (FileUploadBase.SizeLimitExceededException e) { message = "上传文件总大小超出最大值!"; System.out.println(message); request.setAttribute("message", message); request.getRequestDispatcher("/WEB-INF/page/message.jsp").forward(request, response); } catch (FileUploadException e) { message = "上传文件失败!"; System.out.println(message); request.setAttribute("message", message); request.getRequestDispatcher("/WEB-INF/page/message.jsp").forward(request, response); } request.getRequestDispatcher("/WEB-INF/page/file_upload_result.jsp").forward(request, response); } }
3. file_upload_result.jsp 是展示上传结果的页面
这里有个细节需要注意,就是之前传的几个字段是用 multipart/form-data 上传的,那么解析的时候就不能直接用 getParameter了,为了方便起见,我在之前的处理过程中,事先 setAttribute 了一下。
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <title>表单处理展示</title> </head> <body> <% String name = (String)request.getAttribute("name"); String url = (String)request.getAttribute("url"); String author = (String)request.getAttribute("author"); %> <li>您输入的网站是:<%=name%></li> <li>网站名是:<%=url%></li> <li>作者:<%=author%></li><br /> <div>点击这里查看上传过的文件类别:<a href="/list">这里</a></div> </body> </html>
4. 上传文件列表展示
@WebServlet(name = "fileListServlet", urlPatterns = {"/list"}) public class FileListServlet extends HttpServlet { @Override public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String filePath = request.getServletContext().getRealPath("/WEB-INF/upload"); Map<String, String> map = new HashMap<>(8); listFile(new File(filePath), map); request.setAttribute("fileMap", map); request.getRequestDispatcher("/WEB-INF/page/file_list.jsp").forward(request, response); } private void listFile(File file, Map<String, String> fileNameMap) { if (file.isDirectory()) { File[] fileList = file.listFiles(); for (File innerFile : fileList) { listFile(innerFile, fileNameMap); } } else { String fileName = file.getName(); fileNameMap.put(fileName, fileName); } } }
展示的页面
<%@ page import="java.util.Map" %> <%@ page import="java.net.URLEncoder" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <title>文件展示页</title> </head> <body> <% Map<String, String> map = (Map<String, String>)request.getAttribute("fileMap"); if(map == null ||map.size() == 0) { out.println("您还没有上传文件,请点击这里上传:<a href=/index.html>上传文件</a>"); } for (String str: map.keySet()) { out.println("文件名:" + str + " <a href=/download?fileName=" + URLEncoder.encode(map.get(str), "utf-8")+ ">下载</a><br />"); } %> </body> </html>
5. 文件下载
下载文件有个需要注意的地方就是文件名的乱码问题。由于 HTTP 请求头必须是 ISO-8859-1 编码,传送的时候一定要改成这个编码
@WebServlet(name = "fileDownloadServlet", urlPatterns = {"/download"}) public class FileDownloadServlet extends HttpServlet { @Override public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String fileName = request.getParameter("fileName"); System.out.println("fileName before ============" + fileName); String uploadPath = request.getServletContext().getRealPath("/WEB-INF/upload"); File file = findFilePath(fileName, new File(uploadPath)); if (file != null) { response.setContentType("application/octet-stream"); fileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1"); response.setHeader("content-disposition", "attachment;filename=" + fileName); FileInputStream input = new FileInputStream(file); OutputStream out = response.getOutputStream(); byte[] buffer = new byte[1024]; int len; while ((len = input.read(buffer)) > 0) { out.write(buffer, 0, len); } input.close(); out.close(); } else { request.setAttribute("message", "您要下载的资源不存在或者已被删除!"); request.getRequestDispatcher("/WEB-INF/page/message.jsp").forward(request, response); } } private File findFilePath(String fileName, File file) { if (file == null || !file.isDirectory()) { return null; } else { for (File innerFile : file.listFiles()) { if (innerFile.isFile()) { if (innerFile.getName().equals(fileName)) { return innerFile; } } else { return findFilePath(fileName, innerFile); } } } return null; } }
6. 乱码问题(非全面总结,近记录下个人遇到的问题)
不是设置了 request.setCharacterEncoding("UTF-8"); 就不会出现乱码问题,还得看容器的设置,比如说 Tomcat 的话,得看 server.xml 中的两个配置 useBodyEncodingForURI="true" URIEncoding="UTF-8"
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8444" useBodyEncodingForURI="true" URIEncoding="UTF-8"/>
7. input 与 button