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



0 0
原创粉丝点击