01-文件上传

文件上传下载

文件上传

文件上传的应用
比如个人信息的管理,上传头像
比如商品信息的管理,上传商品的图片
这些都需要通过浏览器客户端将图片上传到服务器的磁盘上

文件上传原理

所谓的文件上传就是服务器端通过request对象获取输入流,将浏览器端上传的数据读取出来,保存到服务器端

客户端浏览器注意事项

  • 请求方式必须是 post
  • 需要使用组件
  • 表单必须设置enctype=“multipart/form-data”
    服务器端处理 通过request对象,获取InputStream, 可以将浏览器提交的所有数据读取到.
上传开源框架-commons-upload

Apache 开源组织提供了一个用来处理表单文件上传的一个开源组件( Commons-fileupload),该组件性能优异,并且其API使用极其简单,可以让开发人员轻松实现web文件上传功能,因此在web开发中实现文件上传功能,通常使用Commons-fileupload组件实现。

使用Commons-fileupload组件实现文件上传,需要导入该组件相应的支撑jar包:Commons-fileupload和commons-io, commons-io 不属于文件上传组件的开发jar文件,但Commons-fileupload 组件从1.1版本开始,它工作时需要commons-io包的支持jar包路径:

保存一个完整的表单信息,除了将文件上传到服务器以外,还需要将其他表单项信息保存到对象,并存储到数据中心,而对应的图片信息则保存为保存的路径即可。
那么怎么获取到其他的表单项数据?item.getFileName(),item.getString()
为了更好完成对其他表单项的值的获取,需要借助另一个开源框架 BeanUtils
它除了自身的jar包,还依赖于commons-logging.jar

所需要的包

文件上传案例




上传单个图片到磁盘
<body>
     <!-- enctype: 编码类型,提交的表单为二进制内容:multipart/form-data
                    默认为文本编码类型: application/x-www-form-urlencoded
          注意: 表单中的参数就不能通过getParameter去取值了,
          要想取表单中的值需要第三方jar包解析    ;
                    但是action属性中的参数是可获取到的     
      -->
	 <form action="RegisterServlet?action=upload" method="post" 
	   enctype="multipart/form-data">
	 	
	 	用户名:<input type="text" name="username" /><br/>
	 	密码:<input type="text" name="password" /><br/>
	 	文件上传:<input type="file" name="file" /><br/>
	 	<input type="submit" value="提交" />
 	 </form>
</body>
//版本1:解析图片,存储到D:/b.jpg
	private void deal1(HttpServletRequest request) throws IOException, FileNotFoundException {
		String action = request.getParameter("action");
		if("upload".equals(action)){
			
			//1. 实例化文件上传的工厂
			DiskFileItemFactory factory = new DiskFileItemFactory();
			
			//2.从工厂中获取fileUpload的对象
			ServletFileUpload fileUpload = new ServletFileUpload(factory);
			
			//3.通过fileUpload对象解析request
			try {
				//解析request后,将内容放入第三方提供的FileItem实体类中
				List<FileItem> list = fileUpload.parseRequest(request);
				//遍历集合,取出FileItem实体类中的数据
				for(FileItem fileItem : list){
					//System.out.println(fileItem);  //打印FileItem实体类对象
					//判断是否为文本表单内容
					if(!fileItem.isFormField()){  //处理非文本表单内容---处理图片
						
						//-------io流操作-------
						InputStream iStream = fileItem.getInputStream();
						int len;
						byte[] b = new byte[1024];
						FileOutputStream fos = new FileOutputStream("d://"+fileItem.getName());
						while((len=iStream.read(b))!=-1){
							fos.write(b, 0, len);
						}
						//----------关流s----------
						iStream.close();
						fos.close();
					}
				}
				
				
			} catch (FileUploadException e) {
				e.printStackTrace();
			}
			
		}
	}

优化版

//版本2:io流的优化;图片的路径要跟着项目走--不能随意指定:d:/a.jpg
	private void deal2(HttpServletRequest request) throws IOException, FileNotFoundException {
		String action = request.getParameter("action");
		if("upload".equals(action)){
			
			//1. 实例化文件上传的工厂
			DiskFileItemFactory factory = new DiskFileItemFactory();
			
			//2.从工厂中获取fileUpload的对象
			ServletFileUpload fileUpload = new ServletFileUpload(factory);
			
			//3.通过fileUpload对象解析request
				try {
					List<FileItem> list = fileUpload.parseRequest(request);
					for(FileItem fileItem : list){
						if(!fileItem.isFormField()){  
							//图片的路径要跟着项目走--不能随意指定:d:/a.jpg
							//io流的优化
							
							//获取的是项目的部署路径下的upload
							String path = getServletContext().getRealPath("upload");
							//判断部署的upload路径是否存在,如果不存在则创建
							File parent = new File(path);
							if(!parent.exists()){
								parent.mkdirs();   //创建父目录
							}
							
							//拼完整图片的文件路径
							File allFile = new File(parent, fileItem.getName());
							
							
							//------------io流操作:第三方处理-----------
							//参数1:上传的文件资源
							IOUtils.copy(fileItem.getInputStream(), new FileOutputStream(allFile));
						}
					}
					
				} catch (FileUploadException e) {
					e.printStackTrace();
				}
		}
	}
解决重名的问题
//版本3:处理文件上传的重名问题?  uuid,时间
	private void deal3(HttpServletRequest request) throws IOException, FileNotFoundException {
		String action = request.getParameter("action");
		if("upload".equals(action)){
			
			//1. 实例化文件上传的工厂
			DiskFileItemFactory factory = new DiskFileItemFactory();
			
			//2.从工厂中获取fileUpload的对象
			ServletFileUpload fileUpload = new ServletFileUpload(factory);
			
			//3.通过fileUpload对象解析request
			
			List<FileItem> list;
			try {
				list = fileUpload.parseRequest(request);
				for(FileItem fileItem : list){
					if(!fileItem.isFormField()){  
						//图片的路径要跟着项目走--不能随意指定:d:/a.jpg
						//io流的优化
						
						//获取的是项目的部署路径下的upload
						String path = getServletContext().getRealPath("upload");
						
						//处理日期
						SimpleDateFormat sdf = new SimpleDateFormat("/yyyy/MM/dd/HH/mm/ss");
						String strDate = sdf.format(new Date());
						
						//判断部署的upload路径是否存在,如果不存在则创建
						File parent = new File(path+strDate);
						if(!parent.exists()){
							parent.mkdirs();   //创建父目录
						}
						
						//--处理重命名方式1: uuid
						//String uuid = UUID.randomUUID().toString();
						//String fileName = uuid+"_"+fileItem.getName();
						//File allFile = new File(parent, fileName);
						
						//处理重命名方式2: 日期处理: 2019/3/11/11/38/56/a.jpg  2019/3/11/11/38/57/a.jpg
						File allFile = new File(parent, fileItem.getName());
						
						IOUtils.copy(fileItem.getInputStream(), new FileOutputStream(allFile));
					}
				}
				
			} catch (FileUploadException e) {

				e.printStackTrace();
			}
					
		}
	}
上传文件并使用BeanUtils保存checkbox表单
<body>
     <!-- enctype: 编码类型,提交的表单为二进制内容:multipart/form-data
                    默认为文本编码类型: application/x-www-form-urlencoded
          注意: 表单中的参数就不能通过getParameter去取值了, 要想取表单中的值需要第三方jar包解析    ;
                    但是action属性中的参数是可获取到的     
      -->
	 <form action="RegisterServlet?action=upload" method="post" enctype="multipart/form-data">
	 	
	 	用户名:<input type="text" name="username" /><br/>
	 	密码:<input type="text" name="password" /><br/>
	 	爱好:<input type="checkbox" name="loves" value="eat" /><input type="checkbox" name="loves"  value="drink"/><input type="checkbox" name="loves"  value="play"/><br/>
	 	文件上传:<input type="file" name="file" /><br/>
	 	<input type="submit" value="提交" />
 	 </form>
</body>
	//版本4:在后台存储完整数据
	private void deal4(HttpServletRequest request)
			throws UnsupportedEncodingException, IOException, FileNotFoundException {
		//1. 实例化文件上传的工厂
		DiskFileItemFactory factory = new DiskFileItemFactory();
		
		//2.从工厂中获取fileUpload的对象
		ServletFileUpload fileUpload = new ServletFileUpload(factory);
		
		//3.通过fileUpload对象解析request
		
		List<FileItem> list;
		User user = new User();
		Map<String, String> map = new HashMap<>();
		try {
			list = fileUpload.parseRequest(request);
			for(FileItem fileItem : list){
				if(fileItem.isFormField()){  //处理文本表单内容
					
					//获取到map集合中key对应的值,如果为空,则进行存储;否则,进行与旧值拼接
					String value = map.get(fileItem.getFieldName());
					if(value == null){
						map.put(fileItem.getFieldName(), fileItem.getString("utf-8"));
					}else{
						map.put(fileItem.getFieldName(), value+","+fileItem.getString("utf-8"));
					}
					
					
				}else{    //处理二进制内容
					//获取的是项目的部署路径下的upload
					String path = getServletContext().getRealPath("upload");
					
					//判断部署的upload路径是否存在,如果不存在则创建
					File parent = new File(path);
					if(!parent.exists()){
						parent.mkdirs();   //创建父目录
					}
					
					//--处理重命名方式1: uuid
					String uuid = UUID.randomUUID().toString();
					String fileName = uuid+"_"+fileItem.getName();
					File allFile = new File(parent, fileName);
					
					IOUtils.copy(fileItem.getInputStream(), new FileOutputStream(allFile));
					
					//user.setUrl(allFile.getAbsolutePath());  //存储图片路径
				}
			}
			
		} catch (FileUploadException e) {

			e.printStackTrace();
		}
		//将map的数据注入的User对象,["username":"zs","password":"123"]
		try {
			BeanUtils.populate(user, map);
			
		} catch (IllegalAccessException | InvocationTargetException e) {
			e.printStackTrace();
		}
	}
展示单个图片、展示多个图片
	//版本5:展示单个图片、展示多个图片
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String action = request.getParameter("action");
		if("upload".equals(action)){
			
			DiskFileItemFactory factory = new DiskFileItemFactory();
			ServletFileUpload fileUpload = new ServletFileUpload(factory);
			
			List<FileItem> list;
			User user = new User();
			Map<String, String> map = new HashMap<>();
			try {
				list = fileUpload.parseRequest(request);
				for(FileItem fileItem : list){
					if(fileItem.isFormField()){  //处理文本表单内容
						
						//获取到map集合中key对应的值,如果为空,则进行存储;否则,进行与旧值拼接
						String value = map.get(fileItem.getFieldName());
						if(value == null){
							map.put(fileItem.getFieldName(), fileItem.getString("utf-8"));
						}else{
							map.put(fileItem.getFieldName(), value+","+fileItem.getString("utf-8"));
						}
						
						
					}else{    //处理二进制内容
						//获取的是项目的部署路径下的upload
						String path = getServletContext().getRealPath("upload");
						
						//判断部署的upload路径是否存在,如果不存在则创建
						File parent = new File(path);
						if(!parent.exists()){
							parent.mkdirs();   //创建父目录
						}
						
						//--处理重命名方式1: uuid
						String uuid = UUID.randomUUID().toString();
						String fileName = uuid+"_"+fileItem.getName();
						File allFile = new File(parent, fileName);
						
						IOUtils.copy(fileItem.getInputStream(), new FileOutputStream(allFile));
						
						//注意:此处不能存带盘符的完整路径;应该存相对路径
						//user.setUrl(allFile.getAbsolutePath());  //存储图片路径
						//需求1: 存储单张图片路径
						//user.setUrl("upload"+File.separator+fileName);  //File.separator 获取路径符号
						//需求2: 存储多张图片路径
						user.getUrList().add("upload"+File.separator+fileName);
					}
				}
				
			} catch (FileUploadException e) {

				e.printStackTrace();
			}
			//将map的数据注入的User对象,["username":"zs","password":"123"]
			try {
				BeanUtils.populate(user, map);
				
				request.setAttribute("urls", user.getUrList());
				request.getRequestDispatcher("show2.jsp").forward(request, response);
				
			} catch (IllegalAccessException | InvocationTargetException e) {
				e.printStackTrace();
			}
					
		}
	}

文件下载

主要实现方式有两种

1.	超链接下载
2.	以超链接的方式下载压缩文件
3.	以超链接的方式下载图片文件
4.	以超链接的方式下载中文文件名的文件
5.	Servlet下载

有些超链接搞不定的事情就交给Servlet来搞定

采用流的方式来读和写

设置响应的头部信息

response.setHeader(“Content-disposition”, “attachment;fileName=”+fileName);
细节:

下载的文件名是中文怎么办?

代码
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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">
<title>Insert title here</title>
</head>
<body>
      <!-- 英文路径直接下载 -->
      <a href="download/b.jpg">下载b.jpg</a><br/>
      <a href="download/b.rar">下载b.rar</a><br/>
      
      <!-- 带中文路径 -->
      <a href="DownloadServlet?path=download/高圆圆.rar">下载高圆圆.rar</a><br/>
</body>
</html>
package com.qf.servlet;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;

public class DownloadServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String path = request.getParameter("path");
		path = new String(path.getBytes("iso-8859-1"), "utf-8");  //download/高圆圆.jar
		
		//注意: 往往上传或下载的图片名不要有中文,且不要以数字开头
		
		//获取文件名
		String fileName = path.substring(path.indexOf("/")+1);
		
		//将中文文件名进行转码,类似cookie应用
		fileName = URLEncoder.encode(fileName, "utf-8");
		
		//设置响应的头部信息
		response.setHeader("Content-disposition", "attachment;fileName="+fileName);
		
		//注意:io流的读写,是针对完整路径
		path = getServletContext().getRealPath(path);
		//通过第三方方式写出去
		IOUtils.copy(new FileInputStream(path), response.getOutputStream());
	}


	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}

}

总结:

1. 文件上传案例:
   1. 导入jar包:Commons-fileupload和commons-io
   2. 客户端的操作:
      	1.表单的请求方式:method=post
	    2.设置enctype=multipart/form-data
	    3.控件类型: type="file"
   3. 服务器端的操作:
	   	1.创建DiskFileItemFactory
		2.创建ServletFileUpload
		3.通过ServletFileUpload的parseRequest方法得到所有的FileItem   
	4. 	遍历集合中的所有FileItem对象
	    判断如果为非文本表单内容,则将该图片通过io流方式取出
2. 文件上传操作及优化----版本升级
   1. 获取到FileItem对象后,取出io流内容----先读后写
   2. 存储图片路径跟着项目走(存到部署目录下);第三方io操作优化
   3. 处理文件名重名问题:  加前缀uuid、加入时间目录
   4. 存储完整表单数据: 文本表单、二进制数据等
         建立实体类---存图片时,只需存图片路径即可  
                               存文本表单时,需通过第三方jar包去注入
         导入jar包:    BeanUtils、commons-logging.jar                        
	存复选框数据时,如何存?
	判断map集合中是否存储该key,如果有则拼接;   
   5、存单张图片、存多张图片(实体类中要有集合的属性用于存url路径)
3. 文件的下载:
   1.简单的图片下载可以通过超链接直接下载即可  
   2.如果超链接下载不了(例如中文图片名);通过servlet去处理
   servlet处理步骤: 获取到图片路径
                   get请求的转码
                                      提取图片的文件名用于设置头部信息,且仍需转码
                                      通过io流进行下载: IOUtils.copy                 

other

写相对路径报错


然后

说明web项目和java项目还是有区别的



  1. List item
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值