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).创建工厂:DiskFileItemFactory   factory = new DiskFileItemFactory();

  2).创建解析器:ServletFileUpload      sfu = 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();

       int   index = 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.FileSizeLimitExceededException

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 :用来发送邮件。它是发送器




JavaMail与MyEclipse javaEE5冲突问题

MyEclipse中的JavaEE5中的mail包中只有接口,而没有实现,所以不能使用
会抛出:java.lang.NoClassDefFoundError: com/sun/mail/util/BEncoderStream异常


当导入mail.jar后,会抛出下面异常:java.lang.NoClassDefFoundError: com/sun/mail/util/LineInputStream
这是因为MyEclipse下有javamail的接口,并且mail.jar中也有javamail的接口,所以会出现冲突。


而MyEclipse中的JavaEE5是为了编译环境而存在的,真正发布到Tomcat环境后,就不需要MyEclipse的JavaEE5了。
但是,如果你非要在WEB项目下,运行main()方法,这就会出现问题。mail.jar中的类与MyEclipseEE5中的类冲突。
如果你发布到Tomcat下,因为Tomcat自己有JavaEE的jar包,所以MyEclipse的JavaEE5不会发到Tomcat下,所以
Tomcat运行不会抛出异常。


进入下面路径
D:\MyEclipse10\Common\plugins\com.genuitec.eclipse.j2eedt.core_10.0.0.me201110301321\data\libraryset\EE_5
找到javaee.jar,把这个jar包中与javax.mail相关的东西都删除。
再把mail.jar和activation.jar导入到项目中,这就不会出错了。


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

[Java]javamail中的javax.mail.AuthenticationFailedException:failedtoconnect

javamail中的javax.mail.AuthenticationFailedException:failedtoconnect java.lang.RuntimeException: javax.mail.AuthenticationFailedException: failed to connect
javax.mail.AuthenticationFailedException: failed to connect


帐号 和 密码 都是正确的,但是提示链接失败 (最后发现 这里密码  是指  客户端授权密码 )

解决方法在邮箱中设置

1.开启POP3服务 和 SMTP服务

2.然后让你用注册的手机接收验证码,然后设置授权密码

3.成功后代码中PasswordAuthentication("","")第二个参数也就是密码的字符串这里要填的是授权密码,如果没设置,填写邮箱的注册密码会出现如上异常错误


 

代码

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("itcast_cxf@163.com"));//设置发件人
		msg.setRecipients(RecipientType.TO, "itcast_cxf@126.com");//设置收件人
		msg.setRecipients(RecipientType.CC, "itcast_cxf@sohu.com");//设置抄送
		msg.setRecipients(RecipientType.BCC, "itcast_cxf@sina.com");//设置暗送
		
		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("itcast_cxf@163.com"));//设置发件人
		msg.setRecipients(RecipientType.TO, "itcast_cxf@126.com");//设置收件人
		
		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("itcast_cxf@163.com",
				"itcast_cxf@126.com,itcast_cxf@sina.com",
				"不是垃圾邮件能是什么呢?", "这里是正文");
		
		/*
		 * 创建两个附件对象
		 */
		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);
	}
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值