手把手教你学javaweb(五)文件的上传和下载

javaweb项目文件的上传和下载

在进行文件的上传和下载之前,我们先把javaweb项目做一点点的改动,那就是将LoginServlet的跳转由原来的forward方式改为 redirect方式

重定向到项目内部的另一个servlet里面。这样我们就可以将登录逻辑和home页数据的加载放在不同的servlet来处理了

  • 新建HomeServlet 用来加载首页数据,暂时先只做页面跳转。代码如下

    package com.cgy.demos.web.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    @WebServlet("/home")
    public class HomeServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doPost(req,resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            req.getRequestDispatcher("/WEB-INF/home.jsp").forward(req, resp);
        }
    }
    
    
  • 改造LoginServlet,将页面转发改为 servlet重定向,改造完的LoginServlet代码如下

    package com.cgy.demos.web.servlet;
    
    import org.apache.commons.lang3.StringUtils;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    public class LoginServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doPost(req, resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String userName = req.getParameter("userName");
            String password = req.getParameter("password");
            String verifyCode = req.getParameter("verifyCode");
            //为防止机器请求 第一步要先验证验证码是否正确
            String cacheCode = (String) req.getSession().getAttribute("verifyCode");
            if (StringUtils.isBlank(verifyCode)) {
                req.setAttribute("msg", "验证码不能为空");
                req.getRequestDispatcher("/WEB-INF/index.jsp").forward(req, resp);
                return;
            }
            if (!verifyCode.equalsIgnoreCase(cacheCode)) {//这里验证码不区分大小写
                req.setAttribute("msg", "验证码错误");
                req.getRequestDispatcher("/WEB-INF/index.jsp").forward(req, resp);
                return;
            }
    
            if (StringUtils.isBlank(password)) {
                req.setAttribute("msg", "密码不能为空");
                req.getRequestDispatcher("/WEB-INF/index.jsp").forward(req, resp);
                return;
            }
            if (StringUtils.isBlank(userName)) {
                req.setAttribute("msg", "用户名不能为空");
                req.getRequestDispatcher("/WEB-INF/index.jsp").forward(req, resp);
                return;
            }
            if (!userName.equals("admin")) {
                req.setAttribute("msg", "用户名不正确");
                req.getRequestDispatcher("/WEB-INF/index.jsp").forward(req, resp);
                return;
            }
            if (!password.equals("123456")) {
                req.setAttribute("msg", "密码不正确");
                req.getRequestDispatcher("/WEB-INF/index.jsp").forward(req, resp);
                return;
            }
            req.getSession().setAttribute("userName", userName);
            req.getSession().removeAttribute("verifyCode");
    
            resp.sendRedirect(req.getContextPath()+"/home");
    
    
               return;
        }
    }
    
    

这里的处理流程是,页面填写用户名密码—> LoginServlet 处理登录—>重定向到HomeServlet —> forward到页面Home.jsp

文件上传功能的开发
  • 在home.jsp添加上传文件的form表单代码如下

    <%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
    
    <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <script type="text/javascript" src="static/js/jquery-1.8.3.min.js"></script>
    <title>Insert title here</title>
    </head>
    <body>
     <img src="static/img/userinfo.jpg" height="40" width="40" />:<font size="6px">${userName}</font>
    <h1>欢迎进入IT技术学习系统</h1>
    <hr/>
    <h2>文件上传</h2>
    <form action="<%=request.getContextPath()%>/upload" method = "post" enctype="multipart/form-data">
    
    
    <form action="<%=request.getContextPath()%>/upload" method = "post" enctype="multipart/form-data">
    
    描述:<input type="text" name = "desc" /><br/><br/>
    文件:<input type="file" name = "file"/><br/><br/>
    <input type="submit" value="上传"/>
    </form>
    <hr/>
    <br/><br/>
    <form action="<%=request.getContextPath()%>/logout" method = "post">
    <input type="submit" value="退出登录"/>
    
    </form>
    </body>
    </html>
    
  • 新增上传文件处理的UploadServlet 代码如下

    package com.cgy.demos.web.servlet;
    
    import org.apache.commons.fileupload.FileItem;
    import org.apache.commons.fileupload.FileItemFactory;
    import org.apache.commons.fileupload.disk.DiskFileItemFactory;
    import org.apache.commons.fileupload.servlet.ServletFileUpload;
    import org.apache.commons.lang3.StringUtils;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.File;
    import java.io.IOException;
    import java.util.List;
    import java.util.UUID;
    
    @WebServlet("/upload")
    public class UploadServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doPost(req, resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
            try {
                // 1. 创建工厂对象
                FileItemFactory factory = new DiskFileItemFactory();
                // 2. 文件上传核心工具类
                ServletFileUpload upload = new ServletFileUpload(factory);
                // 设置大小限制参数
                upload.setFileSizeMax(10 * 1024 * 102400);    // 单个文件大小限制
                upload.setSizeMax(50 * 1024 * 102400);        // 总文件大小限制
                upload.setHeaderEncoding("UTF-8");        // 对中文文件编码处理
    
                // 判断
                if (upload.isMultipartContent(request)) {
                    // 3. 把请求数据转换为list集合
                    List<FileItem> list = upload.parseRequest(request);
                    // 遍历
                    for (FileItem item : list) {
                        // 判断:普通文本数据
                        if (item.isFormField()) {
                            // 获取名称
                            String name = item.getFieldName();
                            // 获取值
                            String value = item.getString("UTF-8");//这里要用UTF-8编码,不然中文会乱码 默认ISO8859-1
                            System.out.println(value);
                        }
                        // 文件表单项
                        else {
                            /******** 文件上传 ***********/
                            // a. 获取文件名称
                            String name = item.getName();
                            if (StringUtils.isBlank(name)){
                                continue;
                            }
                            // ----处理上传文件名重名问题----
                            // a1. 先得到唯一标记
                            String id = UUID.randomUUID().toString();
                            // a2. 拼接文件名
                            name = id + "#" + name;
    
                            // b. 得到上传目录
                            String basePath = getServletContext().getRealPath("/upload");
    
                            // c. 创建要上传的文件对象
                            File file = new File(basePath, name);
                            // d. 上传
                            item.write(file);
                            item.delete();  // 删除组件运行时产生的临时文件
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
    
    
            resp.sendRedirect(request.getContextPath()+"/home");
    
        }
    }
    
    

这里使用到了 file-upload 类库来完成文件的上传与配置

在webapp目录下建好上传文件的存放目录 upload

文件名一部分是固定原文件名,一部分是UUID 防止文件覆盖,中间用#相连

文件的下载功能开发

我们要下载的文件就是刚刚上传至upload目录下的文件,要下载必须先把文件在页面上展示出来。

  • 在HomeServlet新增读取upload文件的逻辑 代码如下

    package com.cgy.demos.web.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.File;
    import java.io.IOException;
    import java.math.BigDecimal;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    @WebServlet("/home")
    public class HomeServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doPost(req,resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            //加载要下载的文件
            List<Map<String,String>> list = new ArrayList<>();
            String basePath = getServletContext().getRealPath("/upload");
            File file = new File(basePath);
            File[] files = file.listFiles();
            for (File f : files) {
                if (f.isFile()){
                    Map<String,String> info = new HashMap<>();
                    String fileName = f.getName();
                    String[]  arr = fileName.split("#");
                    info.put("name",arr[1]);
                    info.put("id",arr[0]);
                    BigDecimal decimal = new BigDecimal(f.length());
                    String temSize = null;
                    BigDecimal gSize = decimal.divide(new BigDecimal(1024*1024*1024),2,BigDecimal.ROUND_HALF_UP);
                    BigDecimal mSize = decimal.divide(new BigDecimal(1024*1024),2,BigDecimal.ROUND_HALF_UP);
                    BigDecimal kSize = decimal.divide(new BigDecimal(1024),2,BigDecimal.ROUND_HALF_UP);
    
                    if (gSize.compareTo(BigDecimal.ONE)>=0){
                        temSize = gSize.toString()  + "G";
                    }else if (mSize.compareTo(BigDecimal.ONE)>=0){
                        temSize = mSize.toString()  + "M";
                    }else if (kSize.compareTo(BigDecimal.ONE)>=0){
                        temSize = kSize.toString()  + "K";
                    }else {
                        temSize = decimal.toString()  + "B";
                    }
    
                    info.put("size",temSize);
                    list.add(info);
                }
            }
            req.setAttribute("files",list);
            req.getRequestDispatcher("/WEB-INF/home.jsp").forward(req, resp);
        }
    }
    
    

    这里是将upload目录下所有的文件都读取到,并且获取文件的 名称,唯一标识(上传时生成的),文件大小(这里获取文件大小的逻辑非常不错,用户体验极佳)

  • 在home.jsp页面新增 文件展示的表格 用到了 经典的jsp c标签 。在我开发的过程中,明显的感觉出 jsp的渲染速度极快,是thymeleaf、freemarker这些模板引擎所不能比的! home.jsp代码如下

    <%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
    
    <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <script type="text/javascript" src="static/js/jquery-1.8.3.min.js"></script>
    <title>Insert title here</title>
    </head>
    <body>
     <img src="static/img/userinfo.jpg" height="40" width="40" />:<font size="6px">${userName}</font>
    <h1>欢迎进入IT技术学习系统</h1>
    <hr/>
    <h2>文件上传</h2>
    <form action="<%=request.getContextPath()%>/upload" method = "post" enctype="multipart/form-data">
    
    
    <form action="<%=request.getContextPath()%>/upload" method = "post" enctype="multipart/form-data">
    
    描述:<input type="text" name = "desc" /><br/><br/>
    文件:<input type="file" name = "file"/><br/><br/>
    <input type="submit" value="上传"/>
    </form>
    <hr/>
     <font color="green" size="5px">${msg}</font>
    	<table id="fileTable" >
    		<thead><tr><th>文件名称</th><th>唯一标识</th><th>文件大小</th><th>操作</th></thead>
    		<tbody>
    		<c:forEach items="${files}" var="file">
    			<tr>
    				<td style="width: 150px;">${file.name}</td>
    				<td style="width: 380px;">${file.id}</td>
    				<td style="width: 60px;">${file.size}</td>
    		        <td style="width: 100px;"><a href='<%=request.getContextPath()%>/download?name=${file.name}&id=${file.id}'>下载</a> &nbsp;&nbsp;
    		                                  <a href='<%=request.getContextPath()%>/download?name=${file.name}&id=${file.id}&option=del'>删除</a>
                    </td>
     	         </tr>
    		</c:forEach>
    		</tbody>
    	</table>
    	<hr/>
    <br/><br/>
    <form action="<%=request.getContextPath()%>/logout" method = "post">
    <input type="submit" value="退出登录"/>
    
    </form>
    </body>
    </html>
    
  • 展示一下home.jsp的显示效果

    在这里插入图片描述

这里专门挑选了 三个不同数量级大小的文件,展示一下文件大小的效果

  • 文件下载和删除的DownloadServlet 开发 代码如下

    package com.cgy.demos.web.servlet;
    
    import sun.misc.BASE64Encoder;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.*;
    import java.net.URLEncoder;
    
    @WebServlet("/download")
    public class DownloadServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doPost(req, resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
            String name = req.getParameter("name");
            String id = req.getParameter("id");
            String fullName = id + "#" + name;
            String basePath = getServletContext().getRealPath("/upload");
            File file = new File(basePath, fullName);
            String option = req.getParameter("option");
            if ("del".equals(option)){
             boolean flag =   file.delete();
             if (flag){
                 req.setAttribute("msg","删除成功");
             }else {
                 req.setAttribute("msg","文件不存在");
             }
    
                req.getRequestDispatcher( "/home").forward(req,resp);
                return;
            }
            InputStream in = new FileInputStream(file);
            String downloadName = processFileName(req, name);
            resp.setHeader("content-disposition", "attachment;fileName=" + downloadName);
            resp.setContentLength((int) file.length());
            OutputStream out = resp.getOutputStream();
            byte[] b = new byte[1024];
            int len = -1;
            while ((len = in.read(b)) != -1) {
                out.write(b, 0, len);
            }
            // 关闭
            out.close();
            in.close();
        }
    
        public static String processFileName(HttpServletRequest request, String fileName) {
            String codedfilename = null;
            try {
                String agent = request.getHeader("USER-AGENT");
                if (agent.contains("MSIE")) {
                    // IE浏览器
                    codedfilename = URLEncoder.encode(fileName, "utf-8");
                    codedfilename = codedfilename.replace("+", " ");
                } else if (agent.contains("Firefox")) {
                    // 火狐浏览器
                    BASE64Encoder base64Encoder = new BASE64Encoder();
                    codedfilename = "=?utf-8?B?" + base64Encoder.encode(fileName.getBytes("utf-8")) + "?=";
                } else {
                    // 其它浏览器
                    codedfilename = URLEncoder.encode(fileName, "utf-8");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return codedfilename;
        }
    
    }
    
    
    
  • 功能测试

在这里插入图片描述

文件的删除和下载都是好用的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cgycro

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值