• 【温故知新】Java web 开发(三)Form表单与上传下载文件


      简介:在一和二的基础之上,这次来记录下如何在页面提交表单数据,以及文件的上传和下载整个流程,请求也不仅限于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 + "&nbsp;&nbsp;&nbsp; <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"

    useBodyEncodingForURI参数表示是否用request.setCharacterEncoding参数对URL提交的数据和表单中GET方式提交的数据进行重新编码,在默认情况下,该参数为false。
     
    URIEncoding参数指定对所有GET方式请求进行统一的重新编码(解码)的编码。
     
    前者优先级高,如果你前者设置了true,但是代码里没有写request.setCharacterEncoding,那么即便后者有设置也不管用,也就是说一旦设置了前者后者就失效了

    <Connector port="8080" protocol="HTTP/1.1"   
            connectionTimeout="20000"   
            redirectPort="8444"   
            useBodyEncodingForURI="true" URIEncoding="UTF-8"/>

      

    7. input 与 button

    <input type="submit" />
    <input type="button" />
    <button type="submit" />
    <button type="button" /
     
    只有 type 为 submit的能够提交表单,type 为 button 的只能通过 js 或者 ajax 事件来实现发送请求传递参数。
    那么为什么存在 button 呢?因为它比单纯的 input 表现力更强,它的 value 值可以是图片等,input 只能是文字。
    另外,input 里边必须有 name 才能被表单伴随提交。

  • 相关阅读:
    spring security 单一账户多地方登陆提醒, ajax 拦截器 Interceptor
    Maven 项目打包发布
    jQuery使用on()绑定动态生成元素的事件无效
    ie下li标签中span加float:right不换行问题解决方案
    IE使用多彩文档上传数据库报错
    对象数组中删除指定元素
    jquery 文本框内容清空
    SQL删除重复数据方法
    静态数据的初始化
    java变量初始化顺序
  • 原文地址:https://www.cnblogs.com/bityinjd/p/9292008.html
Copyright © 2020-2023  润新知