下载:
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 = new String(filename.getBytes("GBK"),"ISO-8859-1")

JavaMail
是java提供的一组API,用来发送      

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

邮件协议概述
    与HTPP协议相同,收发邮件也需要传输协议
        SMTP(Simple Mail Transfer Protocol,简单邮件传输协议) 发邮件协议
        POP3(Post Office Protocol Version 3,邮局协议第3版) 收邮件协议
        IMAP(Internet Message Access Protocol,因特网消息访问协议)收发邮件协议  
SMTP服务器的端口为25服务器名称为smtp.xxx.xxx
pop3服务器的端口号为110,服务器名称为pop3.xxx.xxx

163: smtp.163.com 和pop3.163.com
1、与服务器打招呼:ehlo 你的名字
2、发出登录请求 auth login
3、输入加密后的邮箱名 【lalal@163.com】bGFsYWxAMTYzLmNvbQ==
4、输入加密后的邮箱密码
5、输入谁来发送邮件 mail from:<lalal@163.com>
6、输入把邮件发给谁即 rcpt to:<lal@163.com>
7、发送填写数据请求:data
8、开始输入数据,数据包含:from、to、subject以及邮件内容,如果输入结束后,以一个"."为一行表示结束
9、最后:quit

telnet收邮件
pop3无需使用Base64加密
收邮件连接的服务器是pop3.xxx.xxx默认端口是110
    连接Pop3服务器:telnet pop3.xxx.com 110
    user 命令:user 用户名 
    pass命令 pass 密码
    stat命令:用来查看邮箱中邮件的个数,所占的空间
    list:用来查看所有邮件,或指定邮件的状态。list 1是查看第一封邮件的大小。list是查看邮件列表
    retr:查看指定邮件的内容 retr 1#
    dele:标记某邮件删除。不是马上,在退出后删除
    quit:退出

JavaMail
使用MyEclipse创建web项目时。如果只在web项目运行javamail没事 发布到Tomcat也没事
但是如果在web项目写测试就出现问题
Myeclipse会自动给web项目导入javax.mail包中的类,但是不全(只有接口,没有接口实现类)如果导入mail.jar会出现冲突
    在D:\myeclipse\plugins\com.genuitec.eclipse.j2eedt.core_13.0.0.me201605020208\data\libraryset\EE_5 中的javaee.jar文件删除javax.mail

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.stmp.auth","true");

    Authenticator auth = new Authenticator(){
            protected PaswordAuthentication getPasswordAuthentication(){
                return new PasswordAuthentication("root","root");
            }
    };
    Session session = Session.getInstance(props,auth);
2、MimeMessage
    表示一个邮件对象,可以调用它的setFrom();设置发件人、收件人、主题、正文
3、TransPost
    只有一个功能,发邮件          

在使用telnet发邮件时,需要处理Base64编码的问题,但使用JavaMail不必处理。由JavaMail来处理
第一步:获得session
    Session session = Session.getInstance(Properties prop,Authenticator auth)
    其中prop需要指定两个键值,一个是指定服务器主机名,另一个是指定是否需要认证。我们需要认证
    Properties prop = new Properties();
    prop.setProperty("mail.host","smtp.163.com");//设置服务器主机名
    prop.setProperty("mail.smtp.auth","true");//设置需要认证

    其中Authenticator是一个接口表示认证器,即校验客户端的身份,需要自己去实现。实现这个接口需要账户和密码
        Authenticator auth = new Authenticator(){
            public PasswordAuthentication getPasswordAuthentication(){
                new PasswordAuthentication("root","root");//用户名和密码
            }
        }       

    通过上面的就可以获取Session对象了
        Session session = Session.getInstance(prop,auth);   

第二步:创建MimeMessage对象
    创建MimeMessage需要使用Session对象来创建
        MinmeMessage msg = new MimeMessage(session);
public class DownloadServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        /*
         * 两个头一个流
         * 1、Content-Type
         * 2、Content-Disposition
         * 3、流:下载文件的数据
         */
        String filename="H:/乌啦啦.mp3";
        //为了使下载框中显示中文名称不出乱码
//      String framename = new String("乌啦啦.mp3".getBytes("GBK"),"ISO-8859-1");
        String framename = filenameEncoding("乌啦啦.mp3",request);
        String contentType = this.getServletContext()
            .getMimeType(filename);//通过文件名称获取MIME类型
        System.out.println(framename);
        String contentDisposition = "attachment;filename="+framename;
        //一个流
        FileInputStream input = new FileInputStream(filename);

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

        //获取绑定了响应端的流
        ServletOutputStream output = response.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")||agent.contains("Mozilla")){
            BASE64Encoder base64Encoder = new BASE64Encoder();
//          用把字符串变成Base64编码  和URL编码很像  通过utf-8变成字符数组
            filename = "=?UTF-8?B?"+base64Encoder.encode(filename.getBytes("UTF-8"))+"?=";
            //=?UTF-8?B?"+"wocao"+"?=
            //base64Encoder.encode(filename.getBytes("UTF-8"))
            //Mozilla
//          filename = "=?UTF-8?B?" + (new String(Base64.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;
    }
}
public class Demo1 {
    @Test
    public void fun1() throws IOException{
        //BASE64编码
        String s = "lalal@163.com";
        BASE64Encoder encoder = new BASE64Encoder();
        s = encoder.encode(s.getBytes("UTF-8"));
        System.out.println(s);
        //mail from:<lalal@163.com>
        //rcpt to:<lal@qq.com>
        /*
         * from:<lalal@163.com>
         * to:<lalal@qq.com>
         * subject:我哈哈
         * 
         * 我了啦啊
         */
        //BASE64解码
        BASE64Decoder decoder = new BASE64Decoder();
        byte[] bytes = decoder.decodeBuffer(s);
        System.out.println(new String(bytes,"utf-8"));
    }
}
public class Demo2 {
    @Test
    public void fun1() throws MessagingException{
        /*
         * 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("lalal@163.com", "密码");
            }
        };

        Session session = Session.getInstance(props, auth);
        /*
         * 2、创建MimeMessage
         */
        MimeMessage msg  = new MimeMessage(session);
        msg.setFrom(new InternetAddress("lalal@163.com"));//设置发件人
        msg.setRecipients(RecipientType.TO, "lala@qq.com");//设置收件人
        msg.setRecipients(RecipientType.CC, "lala@qq.com");//设置抄送
        msg.setRecipients(RecipientType.BCC, "lala@qq.com");//设置暗送

        msg.setSubject("测试邮件");
        msg.setContent("邮件", "text/html;charset=utf-8");
        /*
         * 3、发
         */
        Transport.send(msg);
    }
    /**
     * 带有附件的邮件
     * @throws MessagingException 
     * @throws IOException 
     */
    @Test
    public void fun2() throws MessagingException, IOException{
        /*
         * 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("lalal@163.com", "密码");
            }
        };

        Session session = Session.getInstance(props, auth);
        /*
         * 2、创建MimeMessage
         */
        MimeMessage msg  = new MimeMessage(session);
        msg.setFrom(new InternetAddress("lalal@163.com"));//设置发件人
        msg.setRecipients(RecipientType.TO, "lala@qq.com");//设置收件人

        msg.setSubject("有附件");
        /*
         * 当发送包含附件的邮件时,邮件体就为多部件形式
         * 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("D:/abc.mp3"));
        part2.setFileName(MimeUtility.encodeText("abc.mp3"));//设置显示的文件名称,其中encodeText用来处理乱码问题
        list.addBodyPart(part2);
        msg.setContent(list);//设置给邮件作为邮件的内容
        /*
         * 3、发
         */
        Transport.send(msg);
    }
}