java_web 学习记录(六):文件上传和下载
来源:互联网 发布:13.3英寸笔记本知乎 编辑:程序博客网 时间:2024/04/20 02:28
文件的上传和下载是web应用中很常见的功能,下面我们具体来看实例。
这里有两篇博客写的十分详细,大家可以移步学习:
http://www.cnblogs.com/xdp-gacl/p/4200090.html
http://www.cnblogs.com/lxnlxn/p/5843636.html
我这里主要是就用过的几种方法做个综合总结,加深理解。
一, 添加依赖包
<dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.2</version></dependency>二,添加配置文件upload.properties
#文件上传目录upload.path=/WEB-INF/upload#文件缓存目录temp.path=/WEB-INF/upload#允许上传的文件类型file.type=properties,log,jpg,png#单个文件上传的大小,如果超过则会抛异常file.size.max=1048576#总文件上传的大小size.max=10485760#缓冲大小,超过则会存在缓冲文件夹中size.threshold=102400三,编写工具类,获取properties文件内容
package com.example.util;import java.util.HashMap;import java.util.Map;public class PropertiesUtil {private Map<String, String> properties = new HashMap<String, String>();private PropertiesUtil() {}private static PropertiesUtil instance = new PropertiesUtil();public static PropertiesUtil getInstance() {return instance;}public void addProperty(String propertyName, String propertyValue) {properties.put(propertyName, propertyValue);}public String getProperty(String propertyName) {return properties.get(propertyName);}}四,编写监听器,在服务器启动时就去读取指定properties文件内容,封装到工具类中
package com.example.listener;import java.io.IOException;import java.io.InputStream;import java.util.Enumeration;import java.util.Properties;import javax.servlet.ServletContextEvent;import javax.servlet.ServletContextListener;import com.example.util.PropertiesUtil;/** * 监听器,初始化读取*.properties文件内容 * @author Administrator * */public class PropertiesListener implements ServletContextListener{public void contextInitialized(ServletContextEvent sce) {ClassLoader loader = this.getClass().getClassLoader();//获取upload.properties文件内容InputStream in = loader.getResourceAsStream("/upload.properties");if (in != null) {Properties prop = new Properties();try {prop.load(in);Enumeration<?> e = prop.propertyNames();while (e.hasMoreElements()) {String key = (String) e.nextElement();String value = prop.getProperty(key);//将文件内容封装到PropertiesUtil对象中PropertiesUtil.getInstance().addProperty(key, value);}} catch (IOException e) {e.printStackTrace();}}}public void contextDestroyed(ServletContextEvent sce) {// TODO Auto-generated method stub}}
五,在web.xml中添加对监听器的配置
<!-- 监听器,读取配置文件 --> <listener> <listener-class>com.example.listener.PropertiesListener</listener-class> </listener>六,文件上传实例
1) 编写文件上传servlet类
package com.example.servlet;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.text.SimpleDateFormat;import java.util.Date;import java.util.List;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.commons.fileupload.FileItem;import org.apache.commons.fileupload.FileUploadException;import org.apache.commons.fileupload.ProgressListener;import org.apache.commons.fileupload.disk.DiskFileItemFactory;import org.apache.commons.fileupload.servlet.ServletFileUpload;import com.example.util.PropertiesUtil;public class FileuploadServlet extends HttpServlet{private static final long serialVersionUID = 7223830312220318953L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// TODO Auto-generated method stubsuper.doGet(req, resp);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//设置输入输出编码request.setCharacterEncoding("utf-8");response.setCharacterEncoding("utf-8");//文件上传保存目录String realPath = this.getServletContext().getRealPath(PropertiesUtil.getInstance().getProperty("upload.path"));//上传时生成的临时文件保存目录String tempPath = this.getServletContext().getRealPath(PropertiesUtil.getInstance().getProperty("temp.path"));File file_temp = new File(tempPath);if (!file_temp.exists()) {file_temp.mkdirs();}DiskFileItemFactory factory = new DiskFileItemFactory();//临时文件存放目录factory.setRepository(file_temp);//缓冲区大小,当文件大小超过设置的缓冲值时就会存储到临时目录中factory.setSizeThreshold(Integer.parseInt(PropertiesUtil.getInstance().getProperty("size.threshold")));//创建一个文件上传解析器ServletFileUpload upload = new ServletFileUpload(factory);//是否表单提交if (!ServletFileUpload.isMultipartContent(request)) {return;}//监听文件上传进度upload.setProgressListener(new ProgressListener() {public void update(long pBytesRead, long pContentLength, int arg2) {System.out.println("文件大小为:" + pContentLength + ",当前已处理:" + pBytesRead);}});//上传文件名编码设置upload.setHeaderEncoding("utf-8");//上传单个文件大小upload.setFileSizeMax(Integer.parseInt(PropertiesUtil.getInstance().getProperty("file.size.max")));//上传总文件大小upload.setSizeMax(Integer.parseInt(PropertiesUtil.getInstance().getProperty("size.max")));//表单提交支持多文件上传 try {List<FileItem> list = upload.parseRequest(request);for (FileItem item : list) {//获取表单的属性名字 String name = item.getFieldName(); //如果获取的 表单信息是普通的 文本 信息 if(item.isFormField()){ //获取提交的参数 String value = item.getString("utf-8") ; System.out.println("表单参数:"+name+"="+value); }else{ /** * 以下三步,主要获取 上传文件的名字 */ //获取上传文件路径名 String fileName = item.getName() ; if(fileName==null || fileName.trim().equals("")){ continue; } //截取 上传文件的 字符串名字,加1是 去掉反斜杠, fileName = fileName.substring(fileName.lastIndexOf("\\")+1); //由于文件名有可能会重复,这里需要改一个唯一文件名,用时间戳方式 //先获取文件名,不含后缀 String preName = fileName.substring(0, fileName.lastIndexOf(".")); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); preName = preName + "-"+sdf.format(new Date()); //获取文件名后缀,作为存储目录 String fileType = fileName.substring(fileName.lastIndexOf(".")+1); //获取到文件后缀后可以校验文件类型是否允许上传 String alownType = PropertiesUtil.getInstance().getProperty("file.type"); if (!alownType.contains(fileType)) { response.getWriter().println("暂不支持该文件类型上传"); return; } String dir = realPath+"\\" + fileType; //创建文件夹 File file_dir = new File(dir); if (!file_dir.exists()) { file_dir.mkdirs(); } //文件目录 String url = dir+"\\"+preName+"."+ fileType; //真正写到磁盘上 //获取输入流 InputStream in = item.getInputStream(); //创建输出流 OutputStream out = new FileOutputStream(url); int length = 0; byte[] buffer = new byte[1024]; while ((length = in.read(buffer)) != -1) { out.write(buffer, 0, length); } in.close(); out.flush(); out.close(); }}} catch (FileUploadException e) {e.printStackTrace();}}}
2) 在web.xml中添加映射:
<!-- 文件上传 --> <servlet> <servlet-name>FileuploadServlet</servlet-name> <servlet-class>com.example.servlet.FileuploadServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>FileuploadServlet</servlet-name> <url-pattern>/upload</url-pattern> </servlet-mapping>3) 编写文件上传upload.html,表单提交
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Insert title here</title></head><body><form action="/webDemo/upload" method="post" enctype="multipart/form-data"><label>上传用户</label><input type="text" name="userName"><br/><br/><label>上传文件</label><input type="file" name="file" /><br/><br/><input type="submit" value="提交" /></form></body></html>这里需要注意,设置enctype="multipart/form-data",否则无法接收到文件
4)启动 测试:
查看控制台打印日志:
四月 20, 2017 11:30:58 上午 org.apache.tomcat.util.digester.SetPropertiesRule begin警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclipse.jst.j2ee.server:webDemo' did not find a matching property.四月 20, 2017 11:30:58 上午 org.apache.catalina.startup.VersionLoggerListener log信息: Server version: Apache Tomcat/8.0.38四月 20, 2017 11:30:58 上午 org.apache.catalina.startup.VersionLoggerListener log信息: Server built: Oct 6 2016 20:51:55 UTC四月 20, 2017 11:30:58 上午 org.apache.catalina.startup.VersionLoggerListener log信息: Server number: 8.0.38.0四月 20, 2017 11:30:58 上午 org.apache.catalina.startup.VersionLoggerListener log信息: OS Name: Windows 8.1四月 20, 2017 11:30:58 上午 org.apache.catalina.startup.VersionLoggerListener log信息: OS Version: 6.3四月 20, 2017 11:30:58 上午 org.apache.catalina.startup.VersionLoggerListener log信息: Architecture: amd64四月 20, 2017 11:30:58 上午 org.apache.catalina.startup.VersionLoggerListener log信息: Java Home: D:\installFile\JDK\jdk1.8.0_102\jre四月 20, 2017 11:30:58 上午 org.apache.catalina.startup.VersionLoggerListener log信息: JVM Version: 1.8.0_102-b14四月 20, 2017 11:30:58 上午 org.apache.catalina.startup.VersionLoggerListener log信息: JVM Vendor: Oracle Corporation四月 20, 2017 11:30:58 上午 org.apache.catalina.startup.VersionLoggerListener log信息: CATALINA_BASE: H:\project\.metadata\.plugins\org.eclipse.wst.server.core\tmp0四月 20, 2017 11:30:58 上午 org.apache.catalina.startup.VersionLoggerListener log信息: CATALINA_HOME: H:\tools\mglinker-eclipse\apache-tomcat-8.0.38四月 20, 2017 11:30:58 上午 org.apache.catalina.startup.VersionLoggerListener log信息: Command line argument: -agentlib:jdwp=transport=dt_socket,suspend=y,address=localhost:65153四月 20, 2017 11:30:58 上午 org.apache.catalina.startup.VersionLoggerListener log信息: Command line argument: -Dcatalina.base=H:\project\.metadata\.plugins\org.eclipse.wst.server.core\tmp0四月 20, 2017 11:30:58 上午 org.apache.catalina.startup.VersionLoggerListener log信息: Command line argument: -Dcatalina.home=H:\tools\mglinker-eclipse\apache-tomcat-8.0.38四月 20, 2017 11:30:58 上午 org.apache.catalina.startup.VersionLoggerListener log信息: Command line argument: -Dwtp.deploy=H:\project\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps四月 20, 2017 11:30:58 上午 org.apache.catalina.startup.VersionLoggerListener log信息: Command line argument: -Djava.endorsed.dirs=H:\tools\mglinker-eclipse\apache-tomcat-8.0.38\endorsed四月 20, 2017 11:30:58 上午 org.apache.catalina.startup.VersionLoggerListener log信息: Command line argument: -Dfile.encoding=UTF-8四月 20, 2017 11:30:58 上午 org.apache.catalina.core.AprLifecycleListener lifecycleEvent信息: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: D:\installFile\JDK\jdk1.8.0_102\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;D:/installFile/JDK/jdk1.8.0_102/bin/../jre/bin/server;D:/installFile/JDK/jdk1.8.0_102/bin/../jre/bin;D:/installFile/JDK/jdk1.8.0_102/bin/../jre/lib/amd64;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;D:\installFile\JDK\jdk1.8.0_102\bin;D:\installFile\JDK\jdk1.8.0_102\jre\bin;;H:\tools\code-gen-eclipse\apache-maven-3.3.9\bin;D:\Program Files\MySQL\MySQL Utilities 1.3.5\;H:\tools\code-gen-eclipse\eclipse;;.四月 20, 2017 11:30:58 上午 org.apache.coyote.AbstractProtocol init信息: Initializing ProtocolHandler ["http-nio-8088"]四月 20, 2017 11:30:58 上午 org.apache.tomcat.util.net.NioSelectorPool getSharedSelector信息: Using a shared selector for servlet write/read四月 20, 2017 11:30:58 上午 org.apache.coyote.AbstractProtocol init信息: Initializing ProtocolHandler ["ajp-nio-8010"]四月 20, 2017 11:30:58 上午 org.apache.tomcat.util.net.NioSelectorPool getSharedSelector信息: Using a shared selector for servlet write/read四月 20, 2017 11:30:58 上午 org.apache.catalina.startup.Catalina load信息: Initialization processed in 1033 ms四月 20, 2017 11:30:58 上午 org.apache.catalina.core.StandardService startInternal信息: Starting service Catalina四月 20, 2017 11:30:58 上午 org.apache.catalina.core.StandardEngine startInternal信息: Starting Servlet Engine: Apache Tomcat/8.0.38四月 20, 2017 11:30:59 上午 org.apache.jasper.servlet.TldScanner scanJars信息: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.四月 20, 2017 11:30:59 上午 org.apache.coyote.AbstractProtocol start信息: Starting ProtocolHandler ["http-nio-8088"]四月 20, 2017 11:30:59 上午 org.apache.coyote.AbstractProtocol start信息: Starting ProtocolHandler ["ajp-nio-8010"]四月 20, 2017 11:30:59 上午 org.apache.catalina.startup.Catalina start信息: Server startup in 1058 ms文件大小为:66024,当前已处理:4096文件大小为:66024,当前已处理:4096文件大小为:66024,当前已处理:4096文件大小为:66024,当前已处理:7592文件大小为:66024,当前已处理:11646文件大小为:66024,当前已处理:15700文件大小为:66024,当前已处理:15784文件大小为:66024,当前已处理:19838文件大小为:66024,当前已处理:23892文件大小为:66024,当前已处理:23976文件大小为:66024,当前已处理:28030文件大小为:66024,当前已处理:32084文件大小为:66024,当前已处理:32168文件大小为:66024,当前已处理:36222文件大小为:66024,当前已处理:40276文件大小为:66024,当前已处理:40360文件大小为:66024,当前已处理:44414文件大小为:66024,当前已处理:48468文件大小为:66024,当前已处理:48552文件大小为:66024,当前已处理:52606文件大小为:66024,当前已处理:56660文件大小为:66024,当前已处理:56744文件大小为:66024,当前已处理:60798文件大小为:66024,当前已处理:64852文件大小为:66024,当前已处理:64936文件大小为:66024,当前已处理:66024表单参数:userName=aa再到本地文件上传目录查看,已经成功上传文件。
文件上传需要注意几点:
1) 上传文件不要放到一个文件夹中,可以根据上传的文件进行分类,分开存储,
我这里是根据文件类型来存储的,实际业务中,可以根据功能模块等来分类
2) 上传的文件名有可能会重复,因此每次上传存储时需要给定一个唯一名进行存储,
这里使用的是时间戳,给文件重命名。
但是下载文件时,就需要再把文件名改回原先上传的名字,下面会演示
3) 实际项目中,在文件上传后,还需要将文件名,存储目录等信息备份到数据库,
方便下载时,根据文件目录直接查找目标文件
七,文件下载
在上篇中,我们简单演示了下文件下载的过程,就是将本地目标文件以流的形式直接输出到浏览器,并通知浏览器以附件形式下载。
这里我们演示的是,用户在浏览器端自主选择需要下载的文件。
1) 编写文件下载的servlet类
package com.example.servlet;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.URLEncoder;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.example.util.PropertiesUtil;/** * 文件下载 * 从服务器上获取资源写到客户本地 * 1,找到需要下载的文件 * 2,将文件以流的形式输出到客户端 * */public class FiledownloadServlet extends HttpServlet {private static final long serialVersionUID = -2006274549235667712L;@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//设置输入输出编码request.setCharacterEncoding("utf-8");response.setContentType("text/html");response.setCharacterEncoding("utf-8");//需要下载的文件名String fileName = request.getParameter("fileName");//获取文件夹目录,这里与上传目录一致String realPath = this.getServletContext().getRealPath(PropertiesUtil.getInstance().getProperty("upload.path"));/* * 获取文件目录 * 避免一个文件夹存储文件过多,且不方便管理,在上传文件的时候就制定规则生成相应文件夹,存储上传的文件 * 那么这里就需要根据存储规则找到文件目录 * 在文件上传时,是以文件名后缀作为存储文件夹的 */String dir = realPath + "\\" + fileName.substring(fileName.lastIndexOf(".")+1);//先判断文件夹是否存在,如果不存在需要创建一个File file_dir = new File(dir);if (!file_dir.exists()) {file_dir.mkdirs();}String filePath = dir +"\\" + fileName ;//文件如果不存在,则返回页面提示File file_load = new File(filePath);if (!file_load.exists()) {response.getWriter().println("资源不存在或已被删除");return;}//真正返回的文件名应该去掉上传时添加的时间戳唯一标识String preName = fileName.substring(0, fileName.lastIndexOf("-"));fileName = preName + fileName.substring(fileName.lastIndexOf("."));//设置content-disposition响应头控制浏览器以下载的形式打开文件//设置了输出编码并不能保证下载后的文件名中文不会乱码,这里需要额外设置文件名编码,URLEncoder.encode(fileName,"UTF-8")response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(fileName,"UTF-8"));//创建输入流InputStream in = new FileInputStream(filePath);//获取输出流OutputStream out = response.getOutputStream();int length = 0;byte[] buffer = new byte[1024];while ((length = in.read(buffer)) != -1) {out.write(buffer, 0, length);}out.flush();out.close();in.close();}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// TODO Auto-generated method stubsuper.doPost(req, resp);}}
2) 在web.xml中配置映射
<!-- 文件下载 --> <servlet> <servlet-name>FiledownloadServlet</servlet-name> <servlet-class>com.example.servlet.FiledownloadServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>FiledownloadServlet</servlet-name> <url-pattern>/download</url-pattern> </servlet-mapping>
3) 编写download.html
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Insert title here</title></head><body><a href="http://localhost:8088/webDemo/download?fileName=springboot-demo-20170420140211.log" title="点击下载文件">springboot-demo-20170420140211.log</a><br/><br/><a href="http://localhost:8088/webDemo/download?fileName=2-20170420140229.png" title="点击下载图片">2-20170420140229.png</a></body></html>4) 启动测试:
==============================================================
文件的上传和下载到此就告一段落了,这里是用的servlet实现的
当然也有很多其他方法可以实现,比如使用spring框架,在controller中实现
前端也有很多封装好的文件上传插件,比如bootstrap-fileinput
我们了解了原理,其他方法其实也是大同小异,以后有空再补充,这里就不多说了。
最后说明一下,这里上传的文件是放在WEN-INF目录下的,从浏览器无法直接访问,提高了文件的安全性
但是有时候我们需要直接在页面展示,比如图片等,那么上传目录就要改成webapp下,
例如我放一张图片test.png到目录/webapp/conf下面,在download.html中添加一行代码:
<a href="http://localhost:8088/webDemo/conf/test.png" title="点击查看图片">test.png</a>那么点击链接,就能直接查看到图片了,而不用到后台查找了。
下篇我们来学习如何将数据导出为excel,java_web 学习记录(七):jxl excel export
- java_web 学习记录(六):文件上传和下载
- springmvc学习记录----springmvc的文件上传和下载
- javaWeb学习记录:文件上传与下载
- java_web 学习记录(二):servlet
- java_web 学习记录(三):ajax
- java_web 学习记录(四):json
- java_web 学习记录(五):ServletContext
- 走进Struts2(六)— 文件上传和下载
- PHP学习-----文件操作/上传和下载
- 文件的上传和下载---学习笔记
- 文件的上传和下载---学习笔记
- SpringMVC学习记录(四)--文件上传与下载
- SpringMVC学习记录(四)--文件上传与下载
- SpringMVC学习记录(四)--文件上传与下载
- struts2学习笔记(六)文件上传与下载(上)jspServlet的文件上传与下载
- struts2学习笔记(六)文件上传与下载(下)基于Struts2的文件上传与下载
- 文件上传和下载
- 文件上传和下载
- 运维学习16
- 临时测试php又不想搭建vhost就用它把 php内置的web服务器
- Orange
- Lintcode 落单的数 II
- ProGuard代码混淆技术详解
- java_web 学习记录(六):文件上传和下载
- 编程之美-2.15 子数组之和的最大值(二维)
- Codeforces 505C Mr. Kitayuta, the Treasure Hunter DP+技巧优化
- 异或运算的经典算法题:找出数组中只出现一次的数字,其它数字都出现了两次
- 三层架构-循序渐进
- 查询、关键字
- 在线购物领域类图
- js适配屏幕大小
- java设置模式--单例模式