web day22 文件上传,下载,JavaMail

上传

(上传不能使用BaseServlet)

1. 上传对表单限制

*method="post"

*enctype="multipart/form-data"

* 表单中需要添加文件表单项:<inputtype="file" name="xxx" />

<form action="xxx"method="post" enctype="multipart/form-data">

用户名;<input type="text"name="username"/><br/>

照 片:<input type="file"name="zhaoPian"/><br/>

<input type="submit" value="上传"/>

</form>

2. 上传对Servlet限制

*request.getParametere("xxx");这个方法在表单为enctype="multipart/form-data"时,它作废了。它永远都返回null

*ServletInputStream request.getInputStream();包含整个请求的体!

-------------------------------

多部件表单的体

1. 每隔出多个部件,即一个表单项一个部件。

2. 一个部件中自己包含请求头和空行,以及请求体。

3. 普通表单项:

> 1个头:Content-Disposition:包含name="xxxx",即表单项名称。

> 体就是表单项的值

4. 文件表单项:

> 2个头:

*Content-Disposition:包含name="xxxx",即表单项名称;还有一个filename="xxx",表示上传文件的名称

*Content-Type:它是上传文件的MIME类型,例如:image/pjpeg,表示上传的是图片,图上中jpg扩展名的图片。

> 体就是上传文件的内容。

===========================================

commons-fileupload

*commons-fileupload.jar

*commons-io.jar

这个小组件,它会帮我们解析request中的上传数据,解析后的结果是一个表单项数据封装到一个FileItem对象中。我们只需要调用FileItem的方法即可!

---------------

1. 上传三步

相关类:

* 工厂:DiskFileItemFactory

* 解析器:ServletFileUpload

* 表单项:FileItem

1).创建工厂:DiskFileItemFactoryfactory = new DiskFileItemFactory();

2).创建解析器:ServletFileUploadsfu = new ServletFileUpload(factory);

3).使用解析器来解析request,得到FileItem集合:List<FileItem> fileItemList= sfu.parseRequest(request);

2. FileItem

*boolean isFormField():是否为普通表单项!返回true为普通表单项,如果为false即文件表单项!

*String getFieldName():返回当前表单项的名称;

*String getString(String charset):返回表单项的值;

*String getName():返回上传的文件名称

*long getSize():返回上传文件的字节数

*InputStream getInputStream():返回上传文件对应的输入流

*void write(File destFile):把上传的文件内容保存到指定的文件中。

*String getContentType();

代码

public class Upload2Servlet extends HttpServlet {
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");

		/*
		 * 上传三步
		 * 1. 得到工厂
		 * 2. 通过工厂创建解析器
		 * 3. 解析request,得到FileItem集合
		 * 4. 遍历FileItem集合,调用其API完成文件的保存
		 */
		DiskFileItemFactory factory = new DiskFileItemFactory();
		ServletFileUpload sfu = new ServletFileUpload(factory);
		try {
			List<FileItem> fileItemList = sfu.parseRequest(request);
			FileItem fi1 = fileItemList.get(0);
			FileItem fi2 = fileItemList.get(1);

			System.out.println("普通表单项演示:" + fi1.getFieldName() +
					"=" + fi1.getString("UTF-8"));
			System.out.println("文件表单项演示:");
			System.out.println("Content-Type: " + fi2.getContentType());
			System.out.println("size: " + fi2.getSize());
			System.out.println("filename: " + fi2.getName());

			// 保存文件
			File destFile = new File("c:/baibing.jpg");
			fi2.write(destFile);
		} catch (FileUploadException e) {
			throw new RuntimeException(e);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}

---------------

上传的细节:

1. 文件必须保存到WEB-INF下!

* 目的是不让浏览器直接访问到!

* 把文件保存到WEB-INF目录下!

2. 文件名称相关问题

 * 有的浏览器上传的文件名是绝对路径,这需要切割!C:\files\baibing.jpg

String filename = fi2.getName();

intindex = filename.lastIndexOf("\\");

if(index!= -1) {

filename = filename.substring(index+1);

}

* 文件名乱码或者普通表单项乱码:request.setCharacterEncoding("utf-8");因为fileupload内部会调用request.getCharacterEncoding();

>request.setCharacterEncoding("utf-8");//优先级低

>servletFileUpload.setHeaderEncoding("utf-8");//优先级高

* 文件同名问题;我们需要为每个文件添加名称前缀,这个前缀要保证不能重复。uuid

>filename = CommonUtils.uuid() + "_" + filename;

3. 目录打散

* 不能在一个目录下存放之多文件。

> 首字符打散:使用文件的首字母做为目录名称,例如:abc.txt,那么我们把文件保存到a目录下。如果a目录这时不存在,那么创建之。

> 时间打散:使用当前日期做为目录。

> 哈希打散:

* 通过文件名称得到int值,即调用hashCode()

* 它int值转换成16进制0~9, A~F

* 获取16进制的前两位用来生成目录,目录为二层!例如:1B2C3D4E5F,/1/B/保存文件。

4. 上传文件的大小限制

* 单个文件大小限制

> sfu.setFileSizeMax(100*1024):限制单个文件大小为100KB

> 上面的方法调用,必须在解析开始之前调用!

> 如果上传的文件超出限制,在parseRequest()方法执行时,会抛出异常!FileUploadBase.FileSizeLimitExceededException

* 整个请求所有数据大小限制

> sfu.setSizeMax(1024 * 1024);//限制整个表单大小为1M

> 这个方法也是必须在parseRequest()方法之前调用

> 如果上传的文件超出限制,在parseRequest()方法执行时,会抛出异常!FileUploadBase.SizeLimitExceededException

5. 缓存大小与临时目录

* 缓存大小:超出多大,才向硬盘保存!默认为10KB

* 临时目录:向硬盘的什么目录保存

设置缓存大小与临时目录:newDiskFileItemFactory(20*1024, new File("F:/temp"))

代码

public class Upload3Servlet extends HttpServlet {

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");

		/*
		 * 上传三步
		 */
		// 工厂
		DiskFileItemFactory factory = new DiskFileItemFactory(20*1024, new File("F:/f/temp"));
		// 解析器
		ServletFileUpload sfu = new ServletFileUpload(factory);
//		sfu.setFileSizeMax(100 * 1024);//限制单个文件大小为100K
//		sfu.setSizeMax(1024 * 1024);//限制整个表单大小为1M

		// 解析,得到List
		try {
			List<FileItem> list = sfu.parseRequest(request);
			FileItem fi = list.get(1);

			//////////////////////////////////////////////////////

			/*
			 * 1. 得到文件保存的路径
			 */
			String root = this.getServletContext().getRealPath("/WEB-INF/files/");
			/*
			 * 2. 生成二层目录
			 *   1). 得到文件名称
			 *   2). 得到hashCode
			 *   3). 转发成16进制
			 *   4). 获取前二个字符用来生成目录
			 */
			String filename = fi.getName();//获取上传的文件名称
			/*
			 * 处理文件名的绝对路径问题
			 */
			int index = filename.lastIndexOf("\\");
			if(index != -1) {
				filename = filename.substring(index+1);
			}
			/*
			 * 给文件名称添加uuid前缀,处理文件同名问题
			 */
			String savename = CommonUtils.uuid() + "_" + filename;

			/*
			 * 1. 得到hashCode
			 */
			int hCode = filename.hashCode();
			String hex = Integer.toHexString(hCode);

			/*
			 * 2. 获取hex的前两个字母,与root连接在一起,生成一个完整的路径
			 */
			File dirFile = new File(root, hex.charAt(0) + "/" + hex.charAt(1));

			/*
			 * 3. 创建目录链
			 */
			dirFile.mkdirs();

			/*
			 * 4. 创建目录文件
			 */
			File destFile = new File(dirFile, savename);

			/*
			 * 5. 保存
			 */
			fi.write(destFile);

			///////////////////////////////////////////////////////

		} catch (FileUploadException e) {
			if(e instanceof FileUploadBase.FileSizeLimitExceededException) {
				request.setAttribute("msg", "您上传的文件超出了100KB!");
				request.getRequestDispatcher("/form3.jsp").forward(request, response);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

------------------------------

下载

1. 下载就是向客户端响应字节数据!

原来我们响应的都是html的字符数据!

把一个文件变成字节数组,使用response.getOutputStream()来各应给浏览器!!!

2. 下载的要求

* 两个头一个流!

> Content-Type:你传递给客户端的文件是什么MIME类型,例如:image/pjpeg

* 通过文件名称调用ServletContext的getMimeType()方法,得到MIME类型!

> Content-Disposition:它的默认值为inline,表示在浏览器窗口中打开!attachment;filename=xxx

* 在filename=后面跟随的是显示在下载框中的文件名称!

> 流:要下载的文件数据!

* 自己new一个输入流即可!

---------------------------

下载的细节

1. 显示在下载框中的中文名称时,会出现乱码。

*FireFox:Base64编码。

* 其他大部分浏览器:URL编码。

通用方案:filename = newString(filename.getBytes("GBK"), "ISO-8859-1");

或↓

代码

public class Download1Servlet extends HttpServlet {
	@Override
	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		/*
		 * 两个头一个流
		 * 1. Content-Type
		 * 2. Content-Disposition
		 * 3. 流:下载文件的数据
		 */
		String filename = "F:/流光飞舞.mp3";

		// 为了使下载框中显示中文文件名称不出乱码!
//		String framename = new String("流光%飞舞.mp3".getBytes("GBK"), "ISO-8859-1");
		String framename = filenameEncoding("流光%飞舞.mp3", req);

		String contentType = this.getServletContext()
				.getMimeType(filename);//通过文件名称获取MIME类型
		String contentDisposition = "attachment;filename=" + framename;
		// 一个流
		FileInputStream input = new FileInputStream(filename);

		//设置头
		resp.setHeader("Content-Type", contentType);
		resp.setHeader("Content-Disposition", contentDisposition);

		// 获取绑定了响应端的流
		ServletOutputStream output = resp.getOutputStream();

		IOUtils.copy(input, output);//把输入流中的数据写入到输出流中。

		input.close();
	}

	// 用来对下载的文件名称进行编码的!
	public static String filenameEncoding(String filename, HttpServletRequest request) throws IOException {
		String agent = request.getHeader("User-Agent"); //获取浏览器
		if (agent.contains("Firefox")) {
			BASE64Encoder base64Encoder = new BASE64Encoder();
			filename = "=?utf-8?B?"
					+ base64Encoder.encode(filename.getBytes("utf-8"))
					+ "?=";
		} else if(agent.contains("MSIE")) {
			filename = URLEncoder.encode(filename, "utf-8");
		} else {
			filename = URLEncoder.encode(filename, "utf-8");
		}
		return filename;
	}
}

---------------------------

Java Mail

1 收发邮件

发邮件是从客户端把邮件发送到邮件服务器,收邮件是把邮件服务器的邮件下载到客户端。

2 邮件协议概述

与HTTP协议相同,收发邮件也是需要有传输协议的。

SMTP:(Simple Mail Transfer Protocol,简单邮件传输协议)发邮件协议;

POP3:(Post Office Protocol Version 3,邮局协议第3版)收邮件协议;

IMAP:(Internet Message Access Protocol,因特网消息访问协议)收发邮件协议.

3收发邮件过程

4邮件服务器名称

smtp服务器的端口号为25,服务器名称为smtp.xxx.xxx。

pop3服务器的端口号为110,服务器名称为pop3.xxx.xxx。

例:

163:smtp.163.com和pop3.163.com;

126:smtp.126.com和pop3.126.com;

qq:smtp.qq.com和pop3.qq.com;

sohu:smtp.sohu.com和pop3.sohu.com;

sina:smtp.sina.com和pop3.sina.com。

telnet 收发邮件

BASE64是一种加密算法,这种加密方式是可逆的!它的作用是使加密后的文本无法用肉眼识别。

代码

public class Base64Utils {
	public static String encode(String s) {
		return encode(s, "utf-8");
	}

	public static String decode(String s) {
		return decode(s, "utf-8");
	}

	public static String encode(String s, String charset) {
		try {
			byte[] bytes = s.getBytes(charset);
			bytes = Base64.encodeBase64(bytes);
			return new String(bytes, charset);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public static String decode(String s, String charset) {
		try {
			byte[] bytes = s.getBytes(charset);
			bytes = Base64.decodeBase64(bytes);
			return new String(bytes, charset);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

JavaMail

Java Mail是由SUN公司提供的专门针对邮件的API,主要Jar包:mail.jar、activation.jar。

java mail中主要类:

javax.mail.Session :会话(就相当于连接数据库时的Connection对象)

javax.mail.internet.MimeMessage :邮件类,包含邮件的主题(标题)、内容,收件人/发件人地址,设置抄送/暗送,设置附件

javax.mail.Transport :用来发送邮件。它是发送器

代码

public class Demo1 {
	@Test
	public void fun1() throws Exception {
		/*
		 * 1. 得到session
		 */
		Properties props = new Properties();
		props.setProperty("mail.host", "smtp.163.com");
		props.setProperty("mail.smtp.auth", "true");

		Authenticator auth = new Authenticator() {
			@Override
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication("itcast_cxf", "itcast");
			}
		};

		Session session = Session.getInstance(props, auth);

		/*
		 * 2. 创建MimeMessage
		 */
		MimeMessage msg = new MimeMessage(session);
		msg.setFrom(new InternetAddress("[email protected]"));//设置发件人
		msg.setRecipients(RecipientType.TO, "[email protected]");//设置收件人
		msg.setRecipients(RecipientType.CC, "[email protected]");//设置抄送
		msg.setRecipients(RecipientType.BCC, "[email protected]");//设置暗送

		msg.setSubject("这是来自ITCAST的测试邮件");
		msg.setContent("这就是一封垃圾邮件!", "text/html;charset=utf-8");

		/*
		 * 3. 发
		 */
		Transport.send(msg);
	}

	/**
	 * 带有附件的邮件!!!
	 */
	@Test
	public void fun2() throws Exception {
		/*
		 * 1. 得到session
		 */
		Properties props = new Properties();
		props.setProperty("mail.host", "smtp.163.com");
		props.setProperty("mail.smtp.auth", "true");

		Authenticator auth = new Authenticator() {
			@Override
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication("itcast_cxf", "itcast");
			}
		};

		Session session = Session.getInstance(props, auth);

		/*
		 * 2. 创建MimeMessage
		 */
		MimeMessage msg = new MimeMessage(session);
		msg.setFrom(new InternetAddress("[email protected]"));//设置发件人
		msg.setRecipients(RecipientType.TO, "[email protected]");//设置收件人

		msg.setSubject("这是来自ITCAST的测试邮件有附件");

		////////////////////////////////////////////////////////
		/*
		 * 当发送包含附件的邮件时,邮件体就为多部件形式!
		 * 1. 创建一个多部件的部件内容!MimeMultipart
		 *   MimeMultipart就是一个集合,用来装载多个主体部件!
		 * 2. 我们需要创建两个主体部件,一个是文本内容的,另一个是附件的。
		 *   主体部件叫MimeBodyPart
		 * 3. 把MimeMultipart设置给MimeMessage的内容!
		 */
		MimeMultipart list = new MimeMultipart();//创建多部分内容

		// 创建MimeBodyPart
		MimeBodyPart part1 = new MimeBodyPart();
		// 设置主体部件的内容
		part1.setContent("这是一封包含附件的垃圾邮件", "text/html;charset=utf-8");
		// 把主体部件添加到集合中
		list.addBodyPart(part1);

		// 创建MimeBodyPart
		MimeBodyPart part2 = new MimeBodyPart();
		part2.attachFile(new File("F:/f/白冰.jpg"));//设置附件的内容
		part2.setFileName(MimeUtility.encodeText("大美女.jpg"));//设置显示的文件名称,其中encodeText用来处理中文乱码问题
		list.addBodyPart(part2);

		msg.setContent(list);//把它设置给邮件作为邮件的内容。

		////////////////////////////////////////////////////////

		/*
		 * 3. 发
		 */
		Transport.send(msg);
	}

	@Test
	public void fun3() throws Exception {
		/*
		 * 1. 得到session
		 */
		Session session = MailUtils.createSession("smtp.163.com",
				"itcast_cxf", "itcast");
		/*
		 * 2. 创建邮件对象
		 */
		Mail mail = new Mail("[email protected]",
				"[email protected],[email protected]",
				"不是垃圾邮件能是什么呢?", "这里是正文");

		/*
		 * 创建两个附件对象
		 */
		AttachBean ab1 = new AttachBean(new File("F:/f/白冰.jpg"), "小美女.jpg");
		AttachBean ab2 = new AttachBean(new File("F:/f/big.jpg"), "我的羽绒服.jpg");

		// 添加到mail中
		mail.addAttach(ab1);
		mail.addAttach(ab2);

		/*
		 * 3. 发送
		 */
		MailUtils.send(session, mail);
	}
}
时间: 2024-10-29 19:11:33

web day22 文件上传,下载,JavaMail的相关文章

Win Form + ASP.NET Web Service 文件上传下载--HYAppFrame

本章节主要讲解HYAppFrame服务器端如何ASP.NET Web Service实现文件(含大文件)上传,WinForm客户端如何下载文件. 1    服务器端文件上传 1.1 上传文件 函数FileUpload(stringfileFullPath, byte[] file)用于上传文件,生成文件前检查文件路径所在文件夹是否存在,不存在则首先创建文件夹. [WebMethod(EnableSession = true,Description = "上传文件")] public i

java+web+大文件上传下载

文件上传是最古老的互联网操作之一,20多年来几乎没有怎么变化,还是操作麻烦.缺乏交互.用户体验差. 一.前端代码 英国程序员Remy Sharp总结了这些新的接口 ,本文在他的基础之上,讨论在前端采用HTML5的API,对文件上传进行渐进式增强:     * iframe上传  * ajax上传  * 进度条  * 文件预览  * 拖放上传 1.1 传统形式 文件上传的传统形式,是使用表单元素file,参考 http://www.ruanyifeng.com/blog/2012/08/file_

Web下文件上传下载的路径问题

工程结构 1.生成一个文件到指定文件夹下 //产生一个唯一的名字 this.setFileName(String.valueOf(System.currentTimeMillis())); String path = ServletActionContext.getServletContext().getRealPath("/template/WordExportTemplate"); //工程下的完整路径名 String filepath = path +"\\"

java web 文件上传下载

文件上传下载案例: 首先是此案例工程的目录结构: 处理上传: FileUploadServlet.java 1 package fnz.fileUploadTest; 2 3 import java.io.File; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.io.PrintWriter; 7 import java.text.SimpleDateFormat; 8 import java.

Android与Asp.Net Web服务器的文件上传下载BUG汇总【更新】

遇到的问题: 1.java.io.IOException: open failed: EINVAL (Invalid argument)异常,在模拟器中的sd卡创建文件夹和文件时报错 出错原因可能是:(1)文件名称中含有不符合规范的字符,比如“:”,“?”或者空格等.(2)需要先创建文件夹目录再创建文件,不能直接创建文件. 2. android.os.NetworkOnMainThreadException异常,从服务器请求数据后,写入文件时报错 出错原因:在主线程内执行了访问http的操作,最

28、java文件上传下载、邮件收发

文件上传下载 前台: 1. 提交方式:post 2. 表单中有文件上传的表单项: <input type="file" /> 3. 指定表单类型: 默认类型:enctype="application/x-www-form-urlencoded" 文件上传类型:multipart/form-data FileUpload 文件上传功能开发中比较常用,apache也提供了文件上传组件! FileUpload组件: 1. 下载源码 2. 项目中引入jar文件

文件上传下载—servlet API实现

servlet API实现文件上传下载需要的jar包: UploadServlet.java package com.ymw.web.servlet; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.UUID; import javax.servl

.Net Core 图片文件上传下载

当下.Net Core项目可是如雨后春笋一般发展起来,作为.Net大军中的一员,我热忱地拥抱了.Net Core并且积极使用其进行业务的开发,我们先介绍下.Net Core项目下实现文件上传下载接口. 一.开发环境 毋庸置疑,宇宙第一IDE VisualStudio 2017 二.项目结构 FilesController 文件上传下载控制器 PictureController 图片上传下载控制器 Return_Helper_DG 返回值帮助类 三.关键代码 1.首先我们来看Startup.cs

SpringMVC文件上传下载

在Spring MVC的基础框架搭建起来后,我们测试了spring mvc中的返回值类型,如果你还没有搭建好springmvc的架构请参考博文->http://www.cnblogs.com/qixiaoyizhan/p/5819392.html 今天我们来讲讲spring mvc中的文件上传和下载的几种方法. 首先附上文件目录->我们需要配置的我做了记号-> 一.文件上传 首先为了方便后续的操作,以及精简代码,我们在Utils包下封装一个文件上传下载的帮助类: Files_Helper