文件上传

简介

最近发现这几篇很少写简介,说自己没时间写,可能是说服自己吧。总之能多写就多写。还有个一直存在的问题,每天写的博客质量不是很好。再次说服自己,现在处于学习阶段,写博客为了巩固知识点,以便后期作复习使用。其实我每次写博客之前笔记老早都在nopad++上写好了,所以大部分在wlw上直接粘贴的,请见谅

1. 文件上传必要前提

1. form表单:属性enctype必须取值为multipart/form-data
	enctype的默认值是:application/x-www-form-urlencoded
	form的enctype属性和请求消息头“Content-Type”作用是一样的,告知服务器请求正文的类型
2. 提交请求方式:post
3. 提供<input type="file" name="f1"/>的上传输入域

2. form请求正文内容

1. application/x-www-form-urlencoded:
	请求正文:name=abc&password=123&gender=female

2. 当form的enctype="multipart/form-data"时的正文内容:
	-----------------------------7de771e40c46         分界符分成了三部分:每一部分都是用MIME协议进行描述的
	Content-Disposition: form-data; name="name"

	goudan
	-----------------------------7de771e40c46
	Content-Disposition: form-data; name="f1"; filename="a.txt"
	Content-Type: text/plain

	aaaaaaaaaaa
	-----------------------------7de771e40c46
	Content-Disposition: form-data; name="f2"; filename="b.txt"
	Content-Type: text/plain

	bbbbbbbbbbbbbbbbbbb
	-----------------------------7de771e40c46--

3. 文件上传的原理

对请求正文是multipart/form-data类型的数据进行解析

4. 借助第三方的组件实现文件上传

commons-fileupload
常用的类:
	DiskFileItemFactory:产生FileItem的工厂类
	new DiskFileItemFactory(int sizeThreshold, File repository)
	sizeThreshold:指定一个缓存大小。默认大小10Kb
	repository:磁盘临时文件的存放目录。默认是当前用户的系统临时文件目录
	new DiskFileItemFactory()

	ServletFileUpload:核心解析器
	FileItem:代表着一个表单上传输入域

文件上传结合案例进行拓展知识

1. 文件上传和9个注意问题及解决方案

文件上传
	1. 解决乱码问题,request设置编码(可以解决上传文件名的乱码问题)
	2. 获取保存文件的资源路径
	3. 判断该路径是否存在,若不存在,就创建
	4. 判断表单提交的enctype是否multipart/form-data
	5. 得到文件上传的对象
	6. 转换用户的请求得到一个List<FileItem>
	7. 遍历该集合,获取每一个对象
	8. 判断每个对象是否是普通字段,如果是普通字段,获取字段名和字段值(可以指定编码)
	9. 如果不是普通字段,获取该对象的MIME类型
	10. 判断该类型是否是image类型(限制只能下载image类型)
	11. 获取上传文件的文件名
	12. 根据hashcode生成两级子目录的绝对路径
		获取文件的hashcode,根据位运算和左移拼接子目录,判断文件夹是否存在,返回拼接之后的目录
	13. 获取输出流关联到生成的目录
	14. 通过遍历的对象获取输入流
	15. IOUtils工具拷贝
	16. 关闭流之后,勿忘删除临时文件

文件上传要考虑的9个问题
1、如何保证服务器的安全
	把保存文件的目录放在WEB-INF下
2、中文编码问题:
	a、普通字段中文值
		FileItem.getString("UTF-8");
	b、中文的文件名
		request.setCharacterEncoding("UTF-8");
3、防止一个文件夹下的文件太多的问题
	分目录存储
	a、分日期创建:今天上传的文件放在以今天日期命名的文件夹中
	
	b、用文件名的hashCode计算存放目录		
4、防止同一个文件夹的文件重名
ID  STORE_PATH 					OLD_FILENAME NEW_FILENAME USER_ID
1   /WEB-INF/files/20140109		a.txt		  UUID1.txt		1 
2   /WEB-INF/files/20140109		a.txt		  UUID2.txt		2 

不用数据库
UUID1_a.txt
UUID2_a.txt
5、限制上传文件的大小:
a、单个文件大小
ServletFileUpload.setFileSizeMax(2*1024*1024);
b、总文件大小
ServletFileUpload.setSizeMax
6、临时文件的问题:commons-fileupload,上传使用缓存,默认是10kb,超出10kb的上传文件,使用磁盘作为临时缓存(临时文件,存在哪里?默认是系统的临时目录)
更改临时文件存放目录:DiskFileItemFactory.setRepository(File file)
FileItem.delete():删除临时文件。在关闭流之后调用。

7、限制上传文件的类型:
只允许上传图片:
判断上传文件的扩展名
+
判断上传内容的MIME类型
8、多文件上传时,用户没传全
						if(item.getName().equals("")){
							continue;
						}
9、文件上传进度条:异步与服务器进行通信,间隔性的通信
计算上传文件的进度比例
给ServletFileUpload注册一个监听器。

2. 文件下载及显示上传的文件列表

一. 显示下载页面ListServlet
1. 获取服务器中的保存资源路径
2. 建立map集合用于存储UUID文件名和原始文件名
3. 遍历资源路径所有文件
	3.1 判断文件是否是文件,如果是文件,获取文件名称
		根据分隔符分隔获取原始文件名
		将UUID文件名和原始文件名添加到map集合中
	3.2 否则不是文件的话,继续递归文件夹

4. 将map设置到request域中
5. 转发到显示下载列表listfiles.jsp

二、下载列表页面设计
	1. listfiles.jsp-->遍历requestScope域中的map
	2. 因为链接资源有文件名,将每个资源路径加上<c:url>标签,注意这里使用的真实路径,所以是key的值
	3. 显示下载内容,连接到<c:url>标签的连接
	
三、 DownloadServlet类
	1. 设置编码问题,告诉浏览器输出编码格式
	2. 获取要下载的文件名,进行编码再解码
	3. 获取该文件的的真实路径,通过再创建hashcode结构目录
	4. 创建输入流关联该文件
	5. 得到一个输出流
	6. 拷贝输入流到输出流中
	7. 关闭流,提示文件下载成功

 

JavaMail邮件开发

1. 邮件开发协议

1. SMTP协议:(重点)
    发送邮件的协议    Simple Message Transfer Protocal
    使用的端口:25
2. POP协议:
    接收邮件的协议    Post Office Protocal
    使用的端口:110

2. 邮件收发过程理解

其实你可以把邮件服务器理解为邮局!如果你需要给朋友寄一封信,那么你需要把信放到邮筒中,这样你的信会“自动”到达邮局,邮局会把信邮到另一个省市的邮局中。然后这封信会被送到收信人的邮箱中。最终收信人需要自己经常查看邮箱是否有新的信件。
其实每个邮件服务器都由SMTP服务器和POP3服务器构成,其中SMTP服务器负责发邮件的请求,而POP3负责收邮件的请求

3. 手工telnet收发邮件

手工发送一封邮件(熟悉SMTP协议)准备:
itheimacloud@163.com iamsorry

itheimacloud     aXRoZWltYWNsb3Vk
iamsorry    aWFtc29ycnk=

smtp.163.com   发送邮件的服务器   smtp.qq.com    smtp.126.com
pop.163.com 

开始发送:
telnet smtp.163.com 25
---------------------------------以下属于SMTP协议的内容
ehlo wyj          向服务器打招呼

auth login             请求认证

aXRoZWltYWNsb3Vk

aWFtc29ycnk=

mail from:<itheimacloud@163.com>
rcpt to:<itheima14@163.com>

data               标识邮件内容开始(内容需要遵守一定的格式:RFC822规范)
from:itheimacloud@163.com
to:itheima14@163.com
subject:this is test mail

aaaaaaaaaaaaaaa
bbbbbbbbbbbbbbb
.                   <CR><LF>.代表结束 
----------------------------------
quit

4. JavaMail概述及注意事项

1. JavaMail概述
Java Mail是由SUN公司提供的专门针对邮件的API,主要Jar包:mail.jar、activation.jar
2.注意事项 
在MyEclipse中,会自动给web项目导入javax.mail包中的类,但是不全(其实是只有接口,而没有接口的实现类),所以只靠MyEclipse中的类是不能运行java mail项目的,但是如果这时你再去自行导入mail.jar时,就会出现冲突。
处理方案:到下面路径中找到javaee.jar文件,把javax.mail删除!!!
D:\Program Files\MyEclipse\Common\plugins\com.genuitec.eclipse.j2eedt.core_10.0.0.me201110301321\data\libraryset\EE_5

5. 利用java实现邮件发送过程

1.设置一些必要的协议,远程邮件服务器地址
	Properties props = new Properties();
	props.setProperty("mail.transport.protocol", "smtp");
	props.setProperty("mail.host", "smtp.163.com");
2. 根据第一步设置相关邮件发送的信息,得到一个session对象<==>连接
	Session session = Session.getInstance(props);
	session.setDebug(true);用户查看底层发送邮件的相关代码

3. 得到一个Message对象,message对象
	MimeMessage msg = new MimeMessage(session);
	3.1 发送者
		msg.setFrom(new InternetAddress("itheimacloud@163.com"));
	3.2 接受者	发送TO 抄送cc,密送bcc
		msg.setRecipients(RecipientType.TO, "itheima14@163.com");
	3.3 主题
		msg.setSubject("明天去爬山!");
	3.4 正文
		msg.setText("<a href='http:localhost:8080/day20_email/servlet/EmailServlet?activeCode="+UUID.randomUUID().toString()+"'>激活邮件地址,要想激活必须先点我</a>");

4. 创建一个邮件发送对象
	Transport tp = session.getTransport();
	4.1 邮件发送对象(设置登录远程邮件服务器账户和密码)
		tp.connect("itheimacloud","iamsorry");
	4.2 发送
		tp.sendMessage(msg, msg.getAllRecipients());
	4.3 邮件发送对象进行关闭
		tp.close();