在进行文件的上传和下载之前,我们先把javaweb项目做一点点的改动,那就是将LoginServlet的跳转由原来的forward方式改为 redirect方式
重定向到项目内部的另一个servlet里面。这样我们就可以将登录逻辑和home页数据的加载放在不同的servlet来处理了
- 新建HomeServlet 用来加载首页数据,暂时先只做页面跳转。代码如下
package com.cgy.demos.web.servlet; import javax.; import javax.; import javax.; import javax.Request; import javax.Response; import java.io.IOException; @WebServlet("/home") public class HomeServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { (req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.getRequestDispatcher("/WEB-INF;).forward(req, resp); } }
改造LoginServlet,将页面转发改为 servlet重定向,改造完的LoginServlet代码如下
package com.cgy.demos.web.servlet; import org.a; import javax.; import javax.; import javax.Request; import javax.Response; import java.io.IOException; public class LoginServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { (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 (verifyCode)) { req.setAttribute("msg", "验证码不能为空"); req.getRequestDispatcher("/WEB-INF;).forward(req, resp); return; } if (!veri(cacheCode)) {//这里验证码不区分大小写 req.setAttribute("msg", "验证码错误"); req.getRequestDispatcher("/WEB-INF;).forward(req, resp); return; } if (password)) { req.setAttribute("msg", "密码不能为空"); req.getRequestDispatcher("/WEB-INF;).forward(req, resp); return; } if (userName)) { req.setAttribute("msg", "用户名不能为空"); req.getRequestDispatcher("/WEB-INF;).forward(req, resp); return; } if (!u("admin")) { req.setAttribute("msg", "用户名不正确"); req.getRequestDispatcher("/WEB-INF;).forward(req, resp); return; } if (!("123456")) { req.setAttribute("msg", "密码不正确"); req.getRequestDispatcher("/WEB-INF;).forward(req, resp); return; } req.getSession().setAttribute("userName", userName); req.getSession().removeAttribute("verifyCode"); re()+"/home"); return; } }
这里的处理流程是,页面填写用户名密码---> LoginServlet 处理登录--->重定向到HomeServlet ---> forward到页面Home.jsp
文件上传功能的开发
在添加上传文件的form表单代码如下
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@taglib uri="; prefix="c" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" ";> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <script type="text/javascript" src="static/j;></script> <title>Insert title here</title> </head> <body> <img src="static/img; height="40" width="40" />:<font size="6px">${userName}</font> <h1>欢迎进入IT技术学习系统</h1> <hr/> <h2>文件上传</h2> <form action="<%=reque()%>/upload" method = "post" enctype="multipart/form-data"> <form action="<%=reque()%>/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="<%=reque()%>/logout" method = "post"> <input type="submit" value="退出登录"/> </form> </body> </html>
新增上传文件处理的UploadServlet 代码如下
package com.cgy.demos.web.servlet; import org.a; import org.aFactory; import org.a; import org.a; import org.a; import javax.; import javax.; import javax.; import javax.Request; import javax.Response; import java.io.File; import java.io.IOException; import java.u; import java.u; @WebServlet("/upload") public class UploadServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { (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); // 设置大小限制参数 u(10 * 1024 * 102400); // 单个文件大小限制 u(50 * 1024 * 102400); // 总文件大小限制 u("UTF-8"); // 对中文文件编码处理 // 判断 if (request)) { // 3. 把请求数据转换为list集合 List<FileItem> list = u(request); // 遍历 for (FileItem item : list) { // 判断:普通文本数据 if ()) { // 获取名称 String name = i(); // 获取值 String value = i("UTF-8");//这里要用UTF-8编码,不然中文会乱码 默认ISO8859-1 Sy(value); } // 文件表单项 else { /******** 文件上传 ***********/ // a. 获取文件名称 String name = i(); if (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. 上传 i(file); i(); // 删除组件运行时产生的临时文件 } } } } catch (Exception e) { e.printStackTrace(); } re(reque()+"/home"); } }
这里使用到了 file-upload 类库来完成文件的上传与配置
在webapp目录下建好上传文件的存放目录 upload
文件名一部分是固定原文件名,一部分是UUID 防止文件覆盖,中间用#相连
文件的下载功能开发
我们要下载的文件就是刚刚上传至upload目录下的文件,要下载必须先把文件在页面上展示出来。
- 在HomeServlet新增读取upload文件的逻辑 代码如下
package com.cgy.demos.web.servlet; import javax.; import javax.; import javax.; import javax.Request; import javax.Response; import java.io.File; import java.io.IOException; import java.ma; import java.u; import java.u; import java.u; import java.u; @WebServlet("/home") public class HomeServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { (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 = (); for (File f : files) { if ()){ Map<String,String> info = new HashMap<>(); String fileName = f.getName(); String[] arr = ("#"); in("name",arr[1]); in("id",arr[0]); BigDecimal decimal = new BigDecimal()); 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 )>=0){ temSize = gSize.toString() + "G"; }else if )>=0){ temSize = mSize.toString() + "M"; }else if )>=0){ temSize = kSize.toString() + "K"; }else { temSize = decimal.toString() + "B"; } in("size",temSize); li(info); } } req.setAttribute("files",list); req.getRequestDispatcher("/WEB-INF;).forward(req, resp); } }
- 这里是将upload目录下所有的文件都读取到,并且获取文件的 名称,唯一标识(上传时生成的),文件大小(这里获取文件大小的逻辑非常不错,用户体验极佳)
- 在页面新增 文件展示的表格 用到了 经典的jsp c标签 。在我开发的过程中,明显的感觉出 jsp的渲染速度极快,是thymeleaf、freemarker这些模板引擎所不能比的! 代码如下
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@taglib uri="; prefix="c" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" ";> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <script type="text/javascript" src="static/j;></script> <title>Insert title here</title> </head> <body> <img src="static/img; height="40" width="40" />:<font size="6px">${userName}</font> <h1>欢迎进入IT技术学习系统</h1> <hr/> <h2>文件上传</h2> <form action="<%=reque()%>/upload" method = "post" enctype="multipart/form-data"> <form action="<%=reque()%>/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;">${}</td> <td style="width: 380px;">${}</td> <td style="width: 60px;">${}</td> <td style="width: 100px;"><a href='<%=reque()%>/download?name=${}&id=${}'>下载</a> <a href='<%=reque()%>/download?name=${}&id=${}&option=del'>删除</a> </td> </tr> </c:forEach> </tbody> </table> <hr/> <br/><br/> <form action="<%=reque()%>/logout" method = "post"> <input type="submit" value="退出登录"/> </form> </body> </html>
展示一下的显示效果
这里专门挑选了 三个不同数量级大小的文件,展示一下文件大小的效果
- 文件下载和删除的DownloadServlet 开发 代码如下
package com.cgy.demos.web.servlet; import ; import javax.; import javax.; import javax.; import javax.Request; import javax.Response; 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 { (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 = (); 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); re("content-disposition", "attachment;fileName=" + downloadName); re((int) ()); OutputStream out = re(); 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 = reque("USER-AGENT"); if ("MSIE")) { // IE浏览器 codedfilename = URLEncoder.encode(fileName, "utf-8"); codedfilename = coded("+", " "); } else if ("Firefox")) { // 火狐浏览器 BASE64Encoder base64Encoder = new BASE64Encoder(); codedfilename = "=?utf-8?B?" + ba("utf-8")) + "?="; } else { // 其它浏览器 codedfilename = URLEncoder.encode(fileName, "utf-8"); } } catch (Exception e) { e.printStackTrace(); } return codedfilename; } }
功能测试
文件的删除和下载都是好用的