一、文件上传
1.文件上传的作用
例如网络硬盘,就是用来上传下载文件的。
--------------------
2.限制:
1.上传对表单的限制
method=“post”
enctype=“multipart/form-data” url编码
表单中需要添加文件表单项:<input type="file" name="xxx"/>
<form action="xxx" method="post" enctype=“multipart/form-data”>
用户名:<input type="text" name="username"/>
照片:<input type="file" name="zhaopian"/>
<input type="submit" value="上传"/>
</form>
2.上传对servlet的限制
request.getParameter("xxx");这个方法在表单为enctype=“multipart/form-data”时,作废。它永远都返回null。
ServletInputStream request.getInputStream();包含整个请求的体!
--------------------
3.多部件表单的体:
1.没隔出多个部件,即一个表单项一个部件。
2.一个部件中自己包含请求头和空行,以及请求体。
3.普通表单项:
>1个头:Content-Disposition:包含name="xxx" ,即表单项名称。
>体就是表单项的值
4.文件表单项:
>2个头:
Content-Disposition:包含name="xxx",即表单项名称;还有一个filename=“xxx”,表示上传文件的名称。
Content-Type:它是上传文件的MIME类型。例如image/pipeg,表示上传的是图片。
>体就是上传文件的内容。
--------------------
4.commons-fileupload
commons-fileupload.jar
commons-io.jar
这个小组件可以帮我们解析request中的上传数据,解析后的结果是一个表单项数据封装到一个FileItem对象中,我们只需要调用FileItem中的方法即可。
上传三步:
相关类:
工厂:DiskFileItemFactory
解析器:ServletFileUpload
表单项:FileItem
1)创建工厂:DiskFileItemFactory factory = new DiskFileItemFactory();
2)创建解析器:ServletFileUpload sfu = new ServletFileUpload(factory);
3)使用解析器来解析request,得到FileItem集合:List<FileItem> fileItemList = sfu.parseRequest(request);
FileItem
boolean isFormField():是否为普通表单项!返回true为普通表单项,如果为false为文件表单项
String getFiledName():返回当前表单项的名称
String getString(String charset):返回当前表单项的值
String getName():返回上传的文件名称
long getSize():返回上传文件的字节数
InputStream getInputStream():返回上传文件的输入流
void write(File destFile):把上传的文件内容保存到指定的文件中
String getContentType():
--------------------
5.上传的细节(上传不能使用BaseServlet)
1.文件必须保存在WEB-INF下
目的是不让浏览器直接访问到
2.文件名称相关问题
有的浏览器上传的文件名是绝对路径,这需要切割!c:\files\xxxx.jpg
String filename = fi2.getName();
int index = filename.lastIndexOf("\\");
if(index != -1){
filename = filename.substring(index+1);
}
文件名乱码或普通表单项乱码:使用request.setCharacterEncoding("utf-8");(优先级低)解决。因为fileupload内部会调用request.setCharacterEncoding();
或者使用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.上传文件的大小限制
单个文件大小限制
new ServletFileUpload(factory).setFileSizeMax(100*1024);//限制单个文件大小小于100KB
上面方法的调用必须在解析(也就是parse.Request()方法)之前调用
如果上传文件超出限制,在parseRequest() 方法调用执行时,会抛出异常。FileUploadBase.FileSizeLimitExceededException
整个请求所有数据大小限制
new ServletFileUpload(factory).setSizeMax(1024*1024);//限制整个表单大小小于1M
上面方法的调用必须在解析(也就是parse.Request()方法)之前调用
如果上传文件超出限制,在parseRequest() 方法调用执行时,会抛出异常。FileUploadBase.SizeLimitExceededException
5.缓存大小与临时目录
缓存大小:超出多大才向硬盘保存。默认为10KB
临时目录:向硬盘的什么位置保存
设置缓存大小与临时目录:new DiskFileItemFactory(20*1024, new File("f:/f/temp"));
二、文件下载
1.下载就是向客户端响应字节数据
原来我们响应的都是字符数据!
把一个文件变成字节数组,使用response.getOutputStream()来响应给浏览器。
2.下载的要求:
两个头一个流:
Content-Type:你传递给客户端的文件是什么MIME类型,例如:image/pjpeg
通过文件名称调用ServletContext的getMimeType() 方法,得到MIME类型。
Content-Disposition:它的默认值是inline,表示在浏览器窗口中打开!attachment;filename=xxx
在filename=后面跟随的是显示在下载框中的文件名称
流:要下载的文件数据
自己new一个输入流即可
3.下载的细节:
1.显示在下载框中的中文名称会乱码。
1.FireFox:Base64编码。
其他大部分浏览器:使用URL编码。
通用方案:filename= new String(filename.getBytes("GBK"),"ISO-8859-1");
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;
}
三、javaMail(是java提供的一组API,用来接收或发送邮件)
邮件协议:类似于HTTP协议,收发邮件也需要传输协议。
SMTP:(Simple Mail Transfer Protocol,简单邮件传输协议)发邮件协议
POP3:(Post Office Protocol Version 3,邮局协议第三版)收邮件协议
IMAP:(Internet Message Access Protocol,因特网访问协议)收发邮件协议
邮件服务器名称
smtp服务器的端口号为25,服务器名称为smtp.xxx.xxx
pop3服务器的端口号为110,服务器名称为pop3.xxx.xxx
例如:
163:smtp.163.com和pop3.163.com
126:smtp.126.com和pop3.126.com
sina:smtp.sina.com和pop3.sina.com
javaMail:
1.导包:
mail.jar
actvition.jar
核心类:
1.session:
如果得到了它,说明已经于服务器连接上了,与Connection的作用相似。
得到session,需要使用Session.getInstance(Properties,Authenticator);
Properties props = new Properties();
props.setProperty("mail.host","smtp.163.com");
props.setProperty("mail.smtp.auth","true");
Authenticator auth = new Authenticator(){
protected new PasswordAuthentication getPasswordAuthentication(){
return new PasswordAuthentication(username,password);
}
};
Session session = Session.getInstance(props,auth);
2.MimeMessage
它表示一个邮件对象,你可以调用它的setFrom() ,设置发件人,设置收件人,设置主题,设置正文
MimeMessage msg = new MimeMessage(session);
msg.setFrom(new InternetAddress("xxx@163.com"));//设置发件人
msg.setRecipients(MimeMessage.RecipientType.TO,"xxx@126.com");//设置收件人
msg.setSubject("这是来自163的测试邮件");
//当发送包含附件的邮件时,邮件体就为多部件形式
/**
* 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 part2 = new MimeBodyPart();
part2.attachFile(new File(""));//设置附件的内容
part2.setFileName(MimeUtility.encodeText(""));//设置附件名称,MimeUtility.encodeText解决中文乱码问题
list.addBodyPart(part2);
msg.setContent(list);
3.TransPort
发邮件
TransPort.send(msg);