标签:超过 throw current starting cto limit listener innerhtml 导致
所谓文件上传下载就是将本地文件上传到服务器端,从服务器端下载文件到本地的过程。例如目前网站需要上传头像、上传下载图片或网盘等功能都是利用文件上传下载功能实现的。
文件上传下载实际上是两步操作,第一是文件上传,就是将本地文件上传到服务器端,实现文件多用户之间的共享,第二是文件下载,就是将服务器端的文件下载到本地磁盘。
首先,需要知道文件是如何实现上传及下载的。文件上传及下载实现原理如下:
文件上传实现流程如下:
文件下载实现流程如下:
在Web应用程序中实现文件上传功能,只需要在客户端页面中添加需要上传输入项,在服务器端Servlet中读取上传文件的数据,并保存在服务器端硬盘中即可。
客户端浏览器页面实现文件上传功能,具体代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP ‘upload.jsp‘ starting page</title> </head> <body> <form action="/upload/upload" method="post" enctype="multipart/form-data"> 文件描述:<input type="text" name="filetext"><br> <input type="file" name="upload"><br> <input type="submit" value="上传"> </form> </body> </html>
需要注意的是:
完成客户端的文件上传功能之后,主要是在服务器端完成接收上传文件的数据内容。为了方便实现文件上传逻辑,可以使用第三方提供的文件上传包,具体如下:
commons-fileupload组件的官网地址:http://commons.apache.org/proper/commons-fileupload/。需要注意的是:在使用commons-fileupload组件时,需要依赖于commons-io包。commons-fileupload组件工作流程如下:
如何使用commons-fileupload组件实现文件上传功能,可以参考其官网的User Guide内容。
具体实现代码如下:
public class UploadServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 创建DiskFileItemFactory文件项工厂对象 DiskFileItemFactory factory = new DiskFileItemFactory(); // 通过工厂对象获取文件上传请求核心解析类ServletFileUpload ServletFileUpload upload = new ServletFileUpload(factory); try { // 使用ServletFileUpload对应Request对象进行解析 List<FileItem> items = upload.parseRequest(request); // 遍历每个fileItem for (FileItem fileItem : items) { // 判断fileItem是否是上传项 if (fileItem.isFormField()) { // 返回true:表示不是上传项 String fieldName = fileItem.getFieldName(); String str = fileItem.getString("utf-8"); System.out.println(fieldName+" : "+str); }else{ // 返回false:表示是上传项 String name = fileItem.getName(); InputStream in = fileItem.getInputStream(); String uploadPath = getServletContext().getRealPath("/upload"); OutputStream out = new FileOutputStream(new File(uploadPath, name)); int b; while ((b = in.read()) != -1) { out.write(b); } out.close(); in.close(); } } } catch (FileUploadException e) { e.printStackTrace(); } } }
上述案例实现的是单文件上传,如果想实现多文件上传功能的话,服务器端的逻辑是一样的,也就是说,只需要在客户端页面实现多文件上传控件即可。动态实现多文件上传表单代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP ‘upload.jsp‘ starting page</title> </head> <script type="text/javascript"> function add(){ // 在div中添加上传输入项 document.getElementById("uploaddiv").innerHTML += "<div><input type=‘file‘ name=‘upload‘ /><input type=‘button‘ value=‘删除‘ onclick=‘del(this);‘ /></div>"; } function del(obj){ // 传入obj 就是你点击 按钮对象 var div = obj.parentNode; div.parentNode.removeChild(div); } </script> <body> <form action="/upload/upload" method="post" enctype="multipart/form-data"> <input type="button" value="上传文件" onclick="add();"/> <div id="uploaddiv"></div> <input type="submit" value="开始上传" /> </form> </body> </html>
到目前步骤,已经可以成功从客户端浏览器向服务器端上传文件。但是上传的路径存在一些问题,上述上传路径是自定义的文件夹,而上传至这种自定义的文件夹后,通过浏览器可以正常访问,这是非常危险的。
例如一个用户上传一个JSP页面,然后通过浏览器访问该JSP页面,而该JSP页面中可以包含一些恶意代码。这时如果允许用户运行该JSP页面的话,可能会对服务器端造成很大影响。
所以,通常情况下,会将上传目录创建在Web工程的WEB-INF目录下。因为该目录下的内容,是无法通过浏览器访问到的。
获取文件上传路径的代码,应该修改为如下内容:
String uploadPath = getServletContext().getRealPath("/WEB-INF/upload");
对于上传文件的名称,可能是文件的完整路径,例如:C:\upload\aaa.jpg。在服务器端只需要保存其上传文件的名称即可,所以需要对上传文件的名称进行进一步地处理,具体处理代码如下:
String name = fileItem.getName(); // 文件名可能是绝对路径,进行切割 int index = name.lastIndexOf("\\"); // 获取"\"之后的内容(真正的文件名) if(index >= 0){ name = name.substring(index + 1); }
目前绝大多数的浏览器都不存在这个问题,仅仅只有一些比较老的浏览器版本存在,例如IE6.0版本。为保证兼容更多浏览器产品,这个问题依旧需要解决。
如果现在上传文件的名称为中文的话,会引起中文乱码问题。commons-fileupload组件为解决中文乱码问题提供了两种解决方案,如下:
一般情况下,不关心上传文件的内容,因为上传文件会保存在服务器端的磁盘中。但是,如果需要在控制台打印上传文件的内容,而刚好该上传文件的内容中包含中文的话,可以使用FileItem的getString(“UTF-8”)来处理编码。
如果同一个用户上传多个同名的文件,默认情况下会出现被覆盖的情况,即前一次上传的文件会被后一次上传的文件覆盖。而这种情况是不希望看到的,解决这个问题的方法就是可以为每一个上传的文件名称增加UUID,因为UUID类的randomUUID()可以生成一个唯一标识符。具体做法如下:
// 为上传文件名称增加UUID的前缀. name = UUID.randomUUID().toString() + "_" + name;
如果上传文件过多时,会导致上传目录中的文件过多,内容过大。这时可以考虑将不同文件存储在不同的目录中,而生成不同目录的规则参考如下:
这里以hashcode进行目录分离方式为例演示,具体思路如下:
name = UUID.randomUUID().toString() + "_" + name;
其值为2dab369c-1e4f-4e58-8b61-13c7aef855b0。
int hashcode = uuidFileName.hashCode();
其值为:166846237,转换成二进制后的值为:1001111100011101111100011101。
// 获得一级目录 int d1 = hashcode & 0xf;
// 获得二级目录 int d2 = (hashcode >>> 4) & 0xf;
根据上述步骤,可以编写一个按照hashcode方式生成目录的工具类,具体代码如下:
public class UploadUtils { // 根据唯一文件名生成 hashcode目录分离算法 public static String generateRandomDir(String uuidFileName) { // 获得唯一文件名的hashcode int hashcode = uuidFileName.hashCode(); // 获得一级目录 int d1 = hashcode & 0xf; // 获得二级目录 int d2 = (hashcode >>> 4) & 0xf; return "/" + d2 + "/" + d1; } }
上述程序代码可以改写如下:
String randomDir = UploadUtils.generateRandomDir(name); String uploadPath = getServletContext().getRealPath("/WEB-INF/upload" + randomDir); // 生成随机目录 new File(uploadPath).mkdir();
上传文件时,用户可能上传非常大的文件,可能导致上传时占用过多资源。所以,对于用户上传的单个文件大小,应做出相应限制。利用ServletFileUpload的setFileSizeMax(long)方法进行设置,其中参数表示设置的大小,单位为字节数,例如servletFileUpload.setFileSizeMax(1024*10)表示上限为10KB。
一旦上传的单个文件大小超过限制大小时,会抛出FileUploadBase.FileSizeLimitExceededException异常,可以捕获该异常后向页面输出相应的错误信息。具体实现代码如下:
public class UploadServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { DiskFileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); // 设置单个上传文件的大小 upload.setFileSizeMax(1024 * 10); try { List<FileItem> items = upload.parseRequest(request); for (FileItem fileItem : items) { if (fileItem.isFormField()) { …… }else{ String name = fileItem.getName(); …… in.close(); } } } catch (FileUploadException e) { if (e instanceof FileUploadBase.FileSizeLimitExceededException) { // 在request中保存错误信息 request.setAttribute("msg", "上传失败!上传的文件超出了10KB!"); // 转发到index.jsp页面中!在index.jsp页面中需要使用${msg}来显示错误信息 request.getRequestDispatcher("/index.jsp").forward(request, response); } e.printStackTrace(); } } }
在实现多文件上传时,还需要设置上传文件的总大小。利用ServletFileUpload的setSizeMax(long)方法进行设置,其中参数表示设置的大小,单位为字节数,例如servletFileUpload. setSizeMax(1024*10)表示上限为10KB。
一旦上传的文件大小超过限制大小时,会抛出FileUploadBase.SizeLimitExceededException异常,可以捕获该异常后向页面输出相应的错误信息。具体实现代码如下:
public class UploadServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { DiskFileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); // 设置单个上传文件的大小 upload.setSizeMax(1024 * 10); try { List<FileItem> items = upload.parseRequest(request); for (FileItem fileItem : items) { if (fileItem.isFormField()) { …… }else{ String name = fileItem.getName(); …… in.close(); } } } catch (FileUploadException e) { if (e instanceof FileUploadBase.SizeLimitExceededException) { // 在request中保存错误信息 request.setAttribute("msg", "上传失败!上传的文件超出了10KB!"); // 转发到index.jsp页面中!在index.jsp页面中需要使用${msg}来显示错误信息 request.getRequestDispatcher("/index.jsp").forward(request, response); } e.printStackTrace(); } } }
一般情况下,上传文件默认都是先存储在内存中,然后在拷贝到服务器端的磁盘中。但是这样会有一些问题出现,例如单个文件过大时,占用服务器端资源会过多,导致服务器性能变差。这时可以通过手动设置文件缓存大小和上传文件的临时目录来解决。如果不设置上传的文件缓存大小,默认值为10KB,其表示如果上传文件小于10KB的话,会先存储在服务器端的内存中,如果上传文件大小大于10KB的话,会先存储在服务器端默认指定的临时目录中,而上传文件的默认临时目录为System.getProperty("java.io.tmpdir")。
手动修改上传文件缓存大小及临时目录的方式如下:
DiskFileItemFactory.setRepository(new File(getServletContext().getRealPath(临时目录相对路径)));
具体实现代码如下:
public class UploadServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { DiskFileItemFactory factory = new DiskFileItemFactory(); // 内存缓冲区 factory.setSizeThreshold(3 * 1024 * 1024); // 3M // 临时文件位置 File repository = new File(getServletContext().getRealPath("/tmp")); factory.setRepository(repository); ServletFileUpload upload = new ServletFileUpload(factory); try { List<FileItem> items = upload.parseRequest(request); for (FileItem fileItem : items) { if (fileItem.isFormField()) { …… }else{ String name = fileItem.getName(); …… in.close(); } } } catch (FileUploadException e) { e.printStackTrace(); } } }
想要删除临时目录下的临时文件的话,只需要调用FileItem的delete()方法即可。
目前大部分具有文件上传功能的,在文件上传过程中,可以实时看到上传进度。可以使用ServletFileUpload提供的setProgressListener()方法实现,在客户端配置Ajax技术即可实现。
其中除使用setProgressListener()方法实现外,还需要计算如下几个结果:
根据上述内容,具体查看上传进度功能如下:
// 获取上传文件的开始时间 final long start = System.currentTimeMillis(); // 为文件上传对象,帮助查看进度监听器 upload.setProgressListener(new ProgressListener() { /* * update(long pBytesRead, long pContentLength, int pItems) * * 该方法用于获取文件上传过程相关数据内容. * * 参数pBytesRead:到目前为止已经读取字节总数(已上传大小) * * 参数pContentLength:正在上传字节总数 (文件大小) * * 参数pItems:当前上传文件,是表单的第几个元素 */ public void update(long pBytesRead, long pContentLength, int pItems) { if(pBytesRead == 0){ // 刚开始上传,还没有数据 return; } // 计算已经使用时间 long hasUseTime = System.currentTimeMillis() - start; // 计算上传速度 double speed = ((double)pBytesRead) / hasUseTime; // 计算剩余大小 long restBytes = pContentLength - pBytesRead; // 计算剩余时间 long restTime = (long) (restBytes / speed); System.out.println("已用时间:" + hasUseTime + ", 传输速度:" + speed + ", 剩余时间:" + restTime); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } });
实现文件上传功能后,需要做的就是文件下载功能。文件下载不需要第三方组件支持,自定义完成即可,具体操作步骤如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP ‘download.jsp‘ starting page</title> </head> <body> <a href="/upload/download?filename=1.jpg">1.jpg</a> <a href="/upload/download?filename=2.rar">2.rar</a> <a href="/upload/download?filename=3.txt">3.txt</a> </body> </html>
public class DownloadServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取下载文件名 String filename = request.getParameter("filename"); // 判断下载文件是否存在 String path = getServletContext().getRealPath("/tmp"); File file = new File(path, filename); if (file.isFile() && file.exists()) { // 说明下载文件存在 // 为下载设置ContentType和Content-Disposition response.setContentType(getServletContext().getMimeType(filename)); response.setHeader("Content-Disposition", "attachment;filename="+filename); // 读取下载文件的内容,写到客户端 InputStream in = new BufferedInputStream(new FileInputStream(file)); IOUtils.copy(in, response.getOutputStream()); in.close(); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>DownloadServlet</servlet-name> <servlet-class>app.java.servlet.DownloadServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>DownloadServlet</servlet-name> <url-pattern>/download</url-pattern> </servlet-mapping> </web-app>
下载文件功能实现后,还需要解决中文乱码问题。由于下载页面中的文件名是使用GET方式提交请求的,所以可以使用如下代码解决:
filename = new String(filename.getBytes("ISO-8859-1"),"UTF-8");
而上述代码只能解决服务器端接收客户端请求时参数的中文乱码问题,但是点击文件下载时的文件名称依旧是乱码的。这个问题是由于浏览器本身的问题,不同浏览器的解决方式不同:
filename = URLEncoder.encode(filename, "utf-8");
filename = filename.replace("+", " ");
BASE64Encoder base64Encoder = new BASE64Encoder(); filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
可以通过Http请求协议的请求头中的“User-Agent”内容,判断客户端当前使用的浏览器是哪个产品。
String agent = request.getHeader("User-Agent"); if(agent.contains("MSIE")){ // IE浏览器,使用URL编码 }else{ // 其他浏览器,使用BASE64编码 }
通过网盘案例实现文件上传和下载功能,并且将文件上传相关信息保存到MySQL数据库表中。该案例实现原理分析如下:
MySQL数据库建表语句如下:
CREATE TABLE resources( id INT PRIMARY KEY AUTO_INCREMENT, uuidname VARCHAR(100) UNIQUE NOT NULL, realname VARCHAR(40) NOT NULL, savepath VARCHAR(100) NOT NULL, uploadtime TIMESTAMP, desscription VARCHAR(255) );
创建一个JSP页面用于网盘案例的主页面(提供文件上传功能和文件下载列表功能)。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP ‘index.jsp‘ starting page</title> </head> <body> <h1>文件上传下载综合系统</h1> <a href="/netdisk/upload.jsp">文件上传</a> <a href="/netdisk/list">文件下载</a> </body> </html>
首先实现网盘中的文件上传功能,具体实现步骤如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP ‘upload.jsp‘ starting page</title> </head> <body> <h1>文件上传</h1> <form action="/netdisk/upload" method="post" enctype="multipart/form-data"> <table> <tr> <td>文件上传</td> <td><input type="file" name="upload" /></td> </tr> <tr> <td>文件描述</td> <td><textarea rows="5" cols="60" name="description" ></textarea></td> </tr> <tr> <td colspan="2"> <input type="submit" value="上传" /> </td> </tr> </table> </form> </body> </html>
public class UploadServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 判断form是否为上传表单 if (!ServletFileUpload.isMultipartContent(request)) { throw new RuntimeException("该请求不是有效编码方式!"); } // 定义与数据库关联对象 Resource resource = new Resource(); // 创建文件项工厂 DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory(); // 创建核心解析器 ServletFileUpload fileUpload = new ServletFileUpload( diskFileItemFactory); // 处理上传文件名乱码 fileUpload.setHeaderEncoding("utf-8"); // 解析请求request try { List<FileItem> fileItems = fileUpload.parseRequest(request); // 遍历每个FileItem for (FileItem fileItem : fileItems) { // 判断fileItem是否为文件上传 if (fileItem.isFormField()) { // 不是上传项 String name = fileItem.getFieldName(); // 处理乱码 String value = fileItem.getString("utf-8"); if (name.equals("description")) { resource.setDescription(value); } } else { // 是上传项 // 判断用户有没有上传 String filename = fileItem.getName(); if (filename == null || filename.trim().length() == 0) { throw new RuntimeException("必须要上传文件!"); } // 上传文件名中是否包含 文件路径 int index = filename.lastIndexOf("\\"); if (index != -1) { filename = filename.substring(index + 1); } // 控制文件名唯一 String uuidname = UploadUtils.generateUUIDFilename(filename); // 生成hashcode 分散目录 String randomDir = UploadUtils.generateRandomDir(uuidname); // 创建随机目录 String savepath = "/WEB-INF/upload" + randomDir; File dirFile = new File(getServletContext().getRealPath(savepath)); dirFile.mkdirs(); // 上传文件内容 InputStream in = new BufferedInputStream(fileItem.getInputStream()); OutputStream out = new BufferedOutputStream(new FileOutputStream(new File(dirFile, uuidname))); int b; while ((b = in.read()) != -1) { out.write(b); } in.close(); out.close(); // 删除临时文件,默认内存区 10K fileItem.delete(); // 准备插入数据库信息 resource.setUuidname(uuidname); resource.setRealname(filename); resource.setSavepath(savepath); } } } catch (FileUploadException e) { e.printStackTrace(); throw new RuntimeException("文件上传失败!"); } // 将文件相关内容保存数据库 QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); String sql = "insert into resources values(null,?,?,?,null,?)"; Object[] args = { resource.getUuidname(), resource.getRealname(), resource.getSavepath(), resource.getDescription() }; try { queryRunner.update(sql, args); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException("将文件信息存入数据库失败!"); } // 提示用户文件上传成功 response.setContentType("text/html;charset=utf-8"); response.getWriter().println("文件上传成功!"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>UploadServlet</servlet-name> <servlet-class>app.java.servlet.UploadServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>UploadServlet</servlet-name> <url-pattern>/upload</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
public class UploadUtils { /** * 根据唯一文件名,生成随机目录 */ public static String generateRandomDir(String uuidname) { int hashcode = uuidname.hashCode(); // 一级目录 int d1 = hashcode & 0xf; // 二级目录 int d2 = (hashcode >>> 4) & 0xf; return "/" + d1 + "/" + d2; } /** * 根据真实文件名 生成uuidname */ public static String generateUUIDFilename(String filename) { String uuid = UUID.randomUUID().toString(); // 不想保留源文件名 --- 保留源文件扩展名 String ext = filename.substring(filename.lastIndexOf(".")); return uuid + ext; } }
public class Resource { private int id; private String uuidname; private String realname; private String savepath; private Timestamp uploadtime; private String description; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUuidname() { return uuidname; } public void setUuidname(String uuidname) { this.uuidname = uuidname; } public String getRealname() { return realname; } public void setRealname(String realname) { this.realname = realname; } public String getSavepath() { return savepath; } public void setSavepath(String savepath) { this.savepath = savepath; } public Timestamp getUploadtime() { return uploadtime; } public void setUploadtime(Timestamp uploadtime) { this.uploadtime = uploadtime; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } }
然后实现文件下载功能,具体实现步骤如下:
public class ListServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); String sql = "select * from resources order by uploadtime desc"; try { List<Resource> resources = queryRunner.query(sql, new BeanListHandler<Resource>(Resource.class)); request.setAttribute("resources", resources); request.getRequestDispatcher("/download.jsp").forward(request, response); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException("查询资源失败!"); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>ListServlet</servlet-name> <servlet-class>app.java.servlet.ListServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>ListServlet</servlet-name> <url-pattern>/list</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP ‘download.jsp‘ starting page</title> </head> <body> <h1>文件资源列表</h1> <c:if test="${empty resources}"> <h2>无任何资源</h2> </c:if> <c:if test="${not empty resources}"> <c:forEach var="resource" items="${resources}"> <hr/> <h3>资源名称:${resource.realname } <a href="/19_netdisk/download?id=${resource.id }">下载</a></h3> <h4>上传时间:${resource.uploadtime }</h4> <p>描述:${resource.description }</p> </c:forEach> </c:if> </body> </html>
public class DownloadServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获得要下载资源id String id = request.getParameter("id"); // 传入数据库查询资源信息 QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); String sql = "select * from resources where id = ?"; try { Resource resource = queryRunner.query(sql,new BeanHandler<Resource>(Resource.class), id); if (resource == null) { throw new RuntimeException("下载资源的id不存在!"); } else { // 获得resource资源信息 File file = new File(getServletContext().getRealPath(resource.getSavepath()), resource.getUuidname()); if (file.exists()) { // 文件存在,可以下载 // 设置Content-Type response.setContentType(getServletContext().getMimeType(resource.getRealname())); // 设置Content-Disposition String agent = request.getHeader("user-agent"); String realname = resource.getRealname(); if(agent.contains("MSIE")){ // IE浏览器,使用URL编码 realname = URLEncoder.encode(realname, "utf-8"); realname = realname.replace("+", " "); }else{ // 其他浏览器,使用BASE64编码 BASE64Encoder base64Encoder = new BASE64Encoder(); realname = "=?utf-8?B?" + base64Encoder.encode(realname.getBytes("utf-8")) + "?="; } response.setHeader("Content-Disposition","attachment;filename=" + realname); // 文件内容下载 InputStream in = new BufferedInputStream(new FileInputStream(file)); OutputStream out = response.getOutputStream(); IOUtils.copy(in, response.getOutputStream()); } else { throw new RuntimeException("服务器端无法找到该资源!"); } } } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException("下载资源失败!"); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>DownloadServlet</servlet-name> <servlet-class> app.java.servlet.DownloadServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name>DownloadServlet</servlet-name> <url-pattern>/download</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
标签:超过 throw current starting cto limit listener innerhtml 导致
原文地址:http://www.cnblogs.com/aaron911/p/7797877.html