美文网首页JavaEE
JavaWeb基础恢复之发邮件、上传、下载

JavaWeb基础恢复之发邮件、上传、下载

作者: 平安喜乐698 | 来源:发表于2018-04-22 20:55 被阅读25次
    目录
        1. 发邮件
        2. 上传
        3. 下载
    
    1. 发邮件
    1. 概念
    邮件服务器
        类似于邮局(作为中间者,将发件人写好的邮件传递给收件人)。如:sina、sohu、163
    电子邮箱
        用户在邮件服务器上申请的一个账户。
    
    邮件传输协议
        发送邮件,需要遵循一定的通讯规则
            SMTP协议
                用来定义这种通讯规则。
                处理用户smtp请求(邮件发送请求)的服务器称之为SMTP服务器(邮件发送服务器)。
        接收邮件,也需要遵循一定的通讯规则
            POP3协议
                用来定义这种通讯规则
    
    发件/收件步骤
        发件人点击发送邮件按钮
            1.通过smtp协议连接并发送邮件到发件邮箱所属的smtp服务器1上;
            2.smtp服务器1通过smtp协议将邮件发送到收件邮箱所属的smtp服务器2上,并存储在收件箱账号所拥有的存储空间中。
        收件人
            1.通过pop3协议连接POP3服务器;
            2.POP3服务器从收件箱账号所拥有的存储空间中查阅邮件显示给收件人。
    
    SMTP协议(说明)
        1.和连接上的smtp服务器打声招呼
            ehlo hello
        2.登陆smtp服务器(用户名密码必须Base64加密)
            auth login
        3.发件邮箱,收件邮箱
          MAIL FROM:发件邮箱
          RCPT TO:收件邮箱
        4.邮件内容
            DATA
            From: 发件邮箱
            To:收件邮箱
            Subject: 主题
            空格
            邮件内容
        5.表示邮件内容完毕
            . 
        6. 断开连接
            QUIT 
    
    POP3协议(说明)
            user username --登录邮箱的用户名(不需Base64加密)
            pass password --登录邮箱使用的密码(不需Base64加密)
            retr 1  --读取第一封邮件(内容经过Base64加密)
            stat
                返回邮箱里面的邮件数量以及邮件占用的空间大小信息
      list 数字
                返回某一封邮件的统计信息
            quit 
                断开与POP3服务器的连接
    
    用来获取Base64加密后的用户名密码
            /*System.out.print("请输入用户名:");
            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
            String userName = in.readLine();
            System.out.print("请输入密码:");
            String password = in.readLine();
            BASE64Encoder encoder = new BASE64Encoder();
            System.out.println("编码后的用户名为:" + encoder.encode(userName.getBytes()));
            System.out.println("编码后的密码为:" + encoder.encode(password.getBytes()));*/
            
    用来获取Base64解密后的邮件内容
            BASE64Decoder decoder = new BASE64Decoder();
            //邮件主题的Base64编码
            String emailSubject = "=?GBK?B?08q8/rLiytQ=?=";
            //邮件文本内容的Base64编码
            String emailPlainContent = "vPK1pbXE08q8/reiy82y4srUo6E=";
            //带html标签和邮件内容的Base64编码
            String emailHtmlContent = "PFA+vPK1pbXE08q8/reiy82y4srUo6E8L1A+";
            //将使用Base64编码过后的文本内容再使用Base64来解码
            emailSubject = new String(decoder.decodeBuffer(emailSubject),"GBK");
            emailPlainContent = new String(decoder.decodeBuffer(emailPlainContent),"GBK");
            emailHtmlContent = new String(decoder.decodeBuffer(emailHtmlContent),"GBK");
            System.out.println("邮件标题:"+emailSubject);
            System.out.println("邮件内容:"+emailPlainContent);
            System.out.println("带html标签的邮件内容:"+emailHtmlContent);
    

    RFC882文档

        规定了如何编写一封简单的邮件(纯文本邮件),包含邮件头和邮件体两部分(使用空行分隔)。
    
    邮件头包含:
        from字段     --指明发件人
        to字段       --指明收件人
        subject字段   --指明邮件主题
        cc字段       --抄送,将邮件发送给收件人的同时抄送给另一个收件人,收件人可以看到邮件抄送给了谁
        bcc字段      --密送,将邮件发送给收件人的同时将邮件秘密发送给另一个收件人,收件人无法看到邮件密送给了谁
    邮件内容
        具体内容
    
    RFC882文档 不能发送图片、附件
    

    MIME协议

        是对RFC822文档的升级和补充
        MIME协议描述的邮件称之为MIME邮件
        MIME协议描述的数据称之为MIME消息
    对于一封复杂邮件,如果包含了多个不同的数据,MIME协议规定了要使用分隔线对多段数据进行分隔,并使用Content-Type头字段对数据的类型、以及多个数据之间的关系进行描述
    
    JavaMail创建邮件
        基于MIME协议,可用于创建复杂邮件。
    
    API
        Message类:创建邮件
        Transport类:发送邮件
        Store类:接收邮件
        Session类:会话,连接客户端与邮件服务器并建立绘话
    
    步骤:
        1. 创建session
        2.创建message
        3.创建transport连接服务器,发送邮件,关闭连接。
    
    1. 简单使用
    1. jar包
    下载所需jar包(mail.jar、activation.jar)
        放在WEB-INF的lib下
    

    Oracle官网下载mail.jar包
    Oracle官网下载activation.jar包

    1. 相关文件

    注册页

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <base href="<%=basePath%>">
        
        <title>My JSP 'MyJsp.jsp' starting page</title>
        
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">    
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
        <meta http-equiv="description" content="This is my page">
        <!--
        <link rel="stylesheet" type="text/css" href="styles.css">
        -->
    
      </head>
      
      <body>
        <form action="${pageContext.request.contextPath}/servlet/RegisterServlet" method="post">
            用户名:<input type="text" name="username"><br/>
            密码:<input type="password" name="password"><br/>
            邮箱:<input type="text" name="email"><br/>
            <input type="submit" value="注册">
        </form>
      </body>
    </html>
    

    注册成功后的显示页面

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <base href="<%=basePath%>">
        
        <title>My JSP 'message.jsp' starting page</title>
        
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">    
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
        <meta http-equiv="description" content="This is my page">
        <!--
        <link rel="stylesheet" type="text/css" href="styles.css">
        -->
    
      </head>
      
      <body>
        ${message}
      </body>
    </html>
    

    处理表单请求

    package com.sst.cx;
    
    import java.io.IOException;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    
    @WebServlet("/RegisterServlet")
    public class RegisterServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;
           
    
        public RegisterServlet() {
            super();
            // TODO Auto-generated constructor stub
        }
    
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            try{
                String username = request.getParameter("username");
                String password = request.getParameter("password");
                String email = request.getParameter("email");
                User user = new User();
                user.setEmail(email);
                user.setPassword(password);
                user.setUsername(username);
                
                System.out.println("把用户信息注册到数据库中");
                //用户注册成功之后就使用用户注册时的邮箱给用户发送一封Email
                //发送邮件是一件非常耗时的事情,因此这里开辟了另一个线程来专门发送邮件
                SendMail send = new SendMail(user);
                //启动线程,线程启动之后就会执行run方法来发送邮件
                send.start();
                
                //注册用户
                //new UserService().registerUser(user);
                request.setAttribute("message", "恭喜您,注册成功,我们已经发了一封带了注册信息的电子邮件,请查收,如果没有收到,可能是网络原因,过一会儿就收到了!!");
                request.getRequestDispatcher("/message.jsp").forward(request, response);
            }catch (Exception e) {
                e.printStackTrace();
                request.setAttribute("message", "注册失败!!");
                request.getRequestDispatcher("/message.jsp").forward(request, response);
            }
        }
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doGet(request,response);
        }
    }
    

    用户类

    package com.sst.cx;
    
    public class User {
    
        public String getUsername() {
            return username;
        }
        public void setUsername(String username) {
            this.username = username;
        }
        public String getPassword() {
            return password;
        }
        public void setPassword(String password) {
            this.password = password;
        }
        public String getEmail() {
            return email;
        }
        public void setEmail(String email) {
            this.email = email;
        }
        private String username;
        private String password;
        private String email;
    }
    

    发送邮件类

    package com.sst.cx;
    
    import java.util.Properties;
    
    import javax.mail.Message;
    import javax.mail.Session;
    import javax.mail.Transport;
    import javax.mail.internet.InternetAddress;
    import javax.mail.internet.MimeMessage;
    
    public class SendMail extends Thread {
    
        // 发件邮箱
        private String from = "chenxiang698@sohu.com";
        // 发件邮箱的用户名
        private String username = "chenxiang698";
        // 发件邮箱的密码
        private String password = "密码";
        // 发送邮件的服务器
        private String host = "smtp.sohu.com";
        
        // 用户模型
        private User user;
        public SendMail(User user){
            this.user = user;
        }
        
        /* 重写run方法的实现,在run方法中发送邮件给指定的用户
         * @see java.lang.Thread#run()
         */
        @Override
        public void run() {
            try{
                // 1.创建Session
                // 参数
                Properties prop = new Properties();
                // 设置 服务器
                prop.setProperty("mail.host", host);
                // 设置 协议
                prop.setProperty("mail.transport.protocol", "smtp");
                // 设置 是否认证
                prop.setProperty("mail.smtp.auth", "true");
                // 设置 端口
                prop.setProperty("mail.smtp.port", "25");
                // 设置 超时时间
                prop.setProperty("mail.smtp.timeout","1000");
                // 设置 开启tls
                prop.put("mail.smtp.starttls.enable", "true");
                // 
                Session session = Session.getInstance(prop);
                session.setDebug(true);
                // 2.创建邮件
                Message message = createEmail(session,user);
                // 3.连接邮箱服务器并登录邮箱 ,发送邮件,关闭连接
                Transport ts = session.getTransport();
                ts.connect(host, username, password);
                ts.sendMessage(message, message.getAllRecipients());
                ts.close();
            }catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        
        /**
        * @Method: createEmail
        * @Description: 创建要发送的邮件
        * 
        *
        * @param session
        * @param user
        * @return
        * @throws Exception
        */ 
        public Message createEmail(Session session,User user) throws Exception{
            // 创建邮件
            MimeMessage message = new MimeMessage(session);
            // 设置 发件邮箱
            message.setFrom(new InternetAddress(from));
            // 设置 收件邮箱
            message.setRecipient(Message.RecipientType.TO, new InternetAddress(user.getEmail()));
            // 设置 邮件主题
            message.setSubject("用户注册邮件");
            
            // 设置 邮件内容
            String info = "恭喜您注册成功,您的用户名:" + user.getUsername() + ",您的密码:" + user.getPassword() + ",请妥善保管,如有问题请联系网站客服!!";
            message.setContent(info, "text/html;charset=UTF-8");
            // 保存
            message.saveChanges();
    
    /*
    带图片
    
            // 文本
            MimeBodyPart text = new MimeBodyPart();
            text.setContent("这是一封邮件正文带图片<img src=''>的邮件", "text/html;charset=UTF-8");
            // 图片
            MimeBodyPart image = new MimeBodyPart();
            DataHandler dh = new DataHandler(new FileDataSource("图片路径"));
            image.setDataHandler(dh);
            image.setContentID("xxx.jpg");
            // 描述数据关系
            MimeMultipart mm = new MimeMultipart();
            mm.addBodyPart(text);
            mm.addBodyPart(image);
            mm.setSubType("related");
    
            message.setContent(mm);
            message.saveChanges();
            // 保存邮件到本地
            message.writeTo(new FileOutputStream("保存路径"));
    */
    
    /*
    带附件
    
           MimeBodyPart text = new MimeBodyPart();
            text.setContent("使用JavaMail创建的带附件的邮件", "text/html;charset=UTF-8");
            
            // 创建邮件附件
            MimeBodyPart attach = new MimeBodyPart();
            DataHandler dh = new DataHandler(new FileDataSource("src\\2.jpg"));
            attach.setDataHandler(dh);
            attach.setFileName(dh.getName());  //
            
            // 创建容器描述数据关系
            MimeMultipart mp = new MimeMultipart();
            mp.addBodyPart(text);
            mp.addBodyPart(attach);
            mp.setSubType("mixed");
            
            message.setContent(mp);
            message.saveChanges();
    */
    
    /*
    图片+附件
    
            //正文
            MimeBodyPart text = new MimeBodyPart();
            text.setContent("xxx这是女的xxxx<br/><img src='cid:aaa.jpg'>","text/html;charset=UTF-8");
            
            //图片
            MimeBodyPart image = new MimeBodyPart();
            image.setDataHandler(new DataHandler(new FileDataSource("src\\3.jpg")));
            image.setContentID("aaa.jpg");
            
            //附件1
            MimeBodyPart attach = new MimeBodyPart();
            DataHandler dh = new DataHandler(new FileDataSource("src\\4.zip"));
            attach.setDataHandler(dh);
            attach.setFileName(dh.getName());
            
            //附件2
            MimeBodyPart attach2 = new MimeBodyPart();
            DataHandler dh2 = new DataHandler(new FileDataSource("src\\波子.zip"));
            attach2.setDataHandler(dh2);
            attach2.setFileName(MimeUtility.encodeText(dh2.getName()));
            
            //描述关系:正文和图片
            MimeMultipart mp1 = new MimeMultipart();
            mp1.addBodyPart(text);
            mp1.addBodyPart(image);
            mp1.setSubType("related");
            
            //描述关系:正文和附件
            MimeMultipart mp2 = new MimeMultipart();
            mp2.addBodyPart(attach);
            mp2.addBodyPart(attach2);
            
            //代表正文的bodypart
            MimeBodyPart content = new MimeBodyPart();
            content.setContent(mp1);
            mp2.addBodyPart(content);
            mp2.setSubType("mixed");
            
            message.setContent(mp2);
            message.saveChanges();
    */
            return message;
        }
    }
    
    1. 如果连接失败
        检查账号密码
        打开发件邮箱,开启POP3/SMTP服务、IMAP/SMTP服务
    
    2. 上传
    浏览器上传是将文件以流的形式提交到服务器
    
    
    上传需注意:
        1、为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下。
        2、为防止文件覆盖,要为上传文件产生一个唯一的文件名。
        3、为防止一个目录下出现太多文件,要使用hash算法打散存储。
        4、要限制上传文件的最大值。
        5、要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。
    
    存储文件位于
    /Users/用户名/Workspaces/MyEclipse 2015/.metadata/.me_tcat7/webapps/项目名/下
    
    1. 下载common-fileupload.jar、common-io.jar
    

    Apache官网下载common-fileupload.jar
    Apache官网下载common-io.jar

    相关文件

    上传文件jsp

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <base href="<%=basePath%>">
        
        <title>My JSP 'Upload.jsp' starting page</title>
        
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">    
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
        <meta http-equiv="description" content="This is my page">
        <!--
        <link rel="stylesheet" type="text/css" href="styles.css">
        -->
    
      </head>
      
      <body>
       <form action="${pageContext.request.contextPath}/servlet/UploadServlet" enctype="multipart/form-data" method="post">
            上传用户:<input type="text" name="username"><br/>
            上传文件1:<input type="file" name="file1"><br/>
            上传文件2:<input type="file" name="file2"><br/>
            <input type="submit" value="提交">
        </form>
      </body>
    </html>
    

    上传文件处理类

    package com.sst.cx;
    
    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.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.commons.fileupload.FileItem;
    import org.apache.commons.fileupload.FileUploadBase;
    import org.apache.commons.fileupload.ProgressListener;
    import org.apache.commons.fileupload.disk.DiskFileItemFactory;
    import org.apache.commons.fileupload.servlet.ServletFileUpload;
    
    
    
    
    /**
     * Servlet implementation class UploadServlet
     */
    @WebServlet("/UploadServlet")
    public class UploadServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;
           
        /**
         * @see HttpServlet#HttpServlet()
         */
        public UploadServlet() {
            super();
            // TODO Auto-generated constructor stub
        }
    
        public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
                    //得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
                    String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
                    //上传时生成的临时文件保存目录
                    String tempPath = this.getServletContext().getRealPath("/WEB-INF/temp");
                    File tmpFile = new File(tempPath);
                    if (!tmpFile.exists()) {
                        //创建临时目录
                        tmpFile.mkdir();
                    }
                    
                    //消息提示
                    String message = "";
                    try{
                        //使用Apache文件上传组件处理文件上传步骤:
                        //1、创建一个DiskFileItemFactory工厂
                        DiskFileItemFactory factory = new DiskFileItemFactory();
                        //设置工厂的缓冲区的大小,当上传的文件大小超过缓冲区的大小时,就会生成一个临时文件存放到指定的临时目录当中。
                        factory.setSizeThreshold(1024*100);//设置缓冲区的大小为100KB,如果不指定,那么缓冲区的大小默认是10KB
                        //设置上传时生成的临时文件的保存目录
                        factory.setRepository(tmpFile);
                        //2、创建一个文件上传解析器
                        ServletFileUpload upload = new ServletFileUpload(factory);
                        //监听文件上传进度
                        upload.setProgressListener(new ProgressListener(){
                            public void update(long pBytesRead, long pContentLength, int arg2) {
                                System.out.println("文件大小为:" + pContentLength + ",当前已处理:" + pBytesRead);
                                /**
                                 * 文件大小为:14608,当前已处理:4096
                                    文件大小为:14608,当前已处理:7367
                                    文件大小为:14608,当前已处理:11419
                                    文件大小为:14608,当前已处理:14608
                                 */
                            }
                        });
                         //解决上传文件名的中文乱码
                        upload.setHeaderEncoding("UTF-8"); 
                        //3、判断提交上来的数据是否是上传表单的数据
                        if(!ServletFileUpload.isMultipartContent(request)){
                            //按照传统方式获取数据
                            return;
                        }
                        
                        //设置上传单个文件的大小的最大值,目前是设置为1024*1024字节,也就是1MB
                        upload.setFileSizeMax(1024*1024);
                        //设置上传文件总量的最大值,最大值=同时上传的多个文件的大小的最大值的和,目前设置为10MB
                        upload.setSizeMax(1024*1024*10);
                        //4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
                        List<FileItem> list = upload.parseRequest(request);
                        for(FileItem item : list){
                            //如果fileitem中封装的是普通输入项的数据
                            if(item.isFormField()){
                                String name = item.getFieldName();
                                //解决普通输入项的数据的中文乱码问题
                                String value = item.getString("UTF-8");
                                //value = new String(value.getBytes("iso8859-1"),"UTF-8");
                                System.out.println(name + "=" + value);
                            }else{//如果fileitem中封装的是上传文件
                                //得到上传的文件名称,
                                String filename = item.getName();
                                System.out.println(filename);
                                if(filename==null || filename.trim().equals("")){
                                    continue;
                                }
                                //注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如:  c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt
                                //处理获取到的上传文件的文件名的路径部分,只保留文件名部分
                                filename = filename.substring(filename.lastIndexOf("\\")+1);
                                //得到上传文件的扩展名
                                String fileExtName = filename.substring(filename.lastIndexOf(".")+1);
                                //如果需要限制上传的文件类型,那么可以通过文件的扩展名来判断上传的文件类型是否合法
                                System.out.println("上传的文件的扩展名是:"+fileExtName);
                                //获取item中的上传文件的输入流
                                InputStream in = item.getInputStream();
                                //得到文件保存的名称
                                String saveFilename = makeFileName(filename);
                                //得到文件的保存目录
                                String realSavePath = makePath(saveFilename, savePath);
                                //创建一个文件输出流
                                FileOutputStream out = new FileOutputStream(realSavePath + "\\" + saveFilename);
                                //创建一个缓冲区
                                byte buffer[] = new byte[1024];
                                //判断输入流中的数据是否已经读完的标识
                                int len = 0;
                                //循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据
                                while((len=in.read(buffer))>0){
                                    //使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" + filename)当中
                                    out.write(buffer, 0, len);
                                }
                                //关闭输入流
                                in.close();
                                //关闭输出流
                                out.close();
                                //删除处理文件上传时生成的临时文件
                                //item.delete();
                                message = "文件上传成功!";
                            }
                        }
                    }catch (FileUploadBase.FileSizeLimitExceededException e) {
                        e.printStackTrace();
                        request.setAttribute("message", "单个文件超出最大值!!!");
                        request.getRequestDispatcher("/message.jsp").forward(request, response);
                        return;
                    }catch (FileUploadBase.SizeLimitExceededException e) {
                        e.printStackTrace();
                        request.setAttribute("message", "上传文件的总的大小超出限制的最大值!!!");
                        request.getRequestDispatcher("/message.jsp").forward(request, response);
                        return;
                    }catch (Exception e) {
                        message= "文件上传失败!";
                        e.printStackTrace();
                    }
                    request.setAttribute("message",message);
                    request.getRequestDispatcher("/message.jsp").forward(request, response);
        }
        
        /**
        * @Method: makeFileName
        * @Description: 生成上传文件的文件名,文件名以:uuid+"_"+文件的原始名称
        * 
        * @param filename 文件的原始名称
        * @return uuid+"_"+文件的原始名称
        */ 
        private String makeFileName(String filename){  //2.jpg
            //为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名
            return UUID.randomUUID().toString() + "_" + filename;
        }
        
        /**
         * 为防止一个目录下面出现太多文件,要使用hash算法打散存储
        * @Method: makePath
        * @Description: 
        *
        *
        * @param filename 文件名,要根据文件名生成存储目录
        * @param savePath 文件存储路径
        * @return 新的存储目录
        */ 
        private String makePath(String filename,String savePath){
            //得到文件名的hashCode的值,得到的就是filename这个字符串对象在内存中的地址
            int hashcode = filename.hashCode();
            int dir1 = hashcode&0xf;  //0--15
            int dir2 = (hashcode&0xf0)>>4;  //0-15
            //构造新的保存目录
            String dir = savePath + "\\" + dir1 + "\\" + dir2;  //upload\2\3  upload\3\5
            //File既可以代表文件也可以代表目录
            File file = new File(dir);
            //如果目录不存在
            if(!file.exists()){
                //创建目录
                file.mkdirs();
            }
            return dir;
        }
    
        /**
         * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
         */
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doGet(request,response);
        }
    
    }
    
    3. 下载

    获取要下载的文件列表处理类

    package com.sst.cx;
    
    import java.io.File;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * Servlet implementation class FileListServlet
     */
    @WebServlet("/FileListServlet")
    public class FileListServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;
    
         public void doGet(HttpServletRequest request, HttpServletResponse response)
                    throws ServletException, IOException {
                // 获取上传文件的目录
                String uploadFilePath = this.getServletContext().getRealPath("/WEB-INF/upload");
                // 存储要下载的文件名
                Map<String,String> fileNameMap = new HashMap<String,String>();
                // 递归遍历filepath目录下的所有文件和目录,将文件的文件名存储到map集合中
                listfile(new File(uploadFilePath),fileNameMap);//File既可以代表一个文件也可以代表一个目录
                // 将Map集合发送到listfile.jsp页面进行显示
                request.setAttribute("fileNameMap", fileNameMap);
                request.getRequestDispatcher("/fileList.jsp").forward(request, response);
            }
            
            /**
            * @Method: listfile
            * @Description: 递归遍历指定目录下的所有文件
            * 
            * @param file 即代表一个文件,也代表一个文件目录
            * @param map 存储文件名的Map集合
            */ 
            public void listfile(File file,Map<String,String> map){
                //如果file代表的不是一个文件,而是一个目录
                if(!file.isFile()){
                    //列出该目录下的所有文件和目录
                    File files[] = file.listFiles();
                    //遍历files[]数组
                    for(File f : files){
                        //递归
                        listfile(f,map);
                    }
                }else{
                    /**
                     * 处理文件名,上传后的文件是以uuid_文件名的形式去重新命名的,去除文件名的uuid_部分
                        file.getName().indexOf("_")检索字符串中第一次出现"_"字符的位置,如果文件名类似于:9349249849-88343-8344_阿_凡_达.avi
                        那么file.getName().substring(file.getName().indexOf("_")+1)处理之后就可以得到阿_凡_达.avi部分
                     */
                    String realName = file.getName().substring(file.getName().indexOf("_")+1);
                    //file.getName()得到的是文件的原始名称,这个名称是唯一的,因此可以作为key,realName是处理过后的名称,有可能会重复
                    map.put(file.getName(), realName);
                }
            }
            
    
        
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doGet(request,response);
        }
    
    }
    

    文件下载处理类

    package com.sst.cx;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.net.URLEncoder;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * Servlet implementation class DownloadServlet
     */
    @WebServlet("/DownloadServlet")
    public class DownloadServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;
    
        public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            // 得到要下载的文件名
            String fileName = request.getParameter("filename");  //23239283-92489-阿凡达.avi
            fileName = new String(fileName.getBytes("iso8859-1"),"UTF-8");
            // 上传的文件都是保存在/WEB-INF/upload目录下的子目录当中
            String fileSaveRootPath=this.getServletContext().getRealPath("/WEB-INF/upload");
            //通过文件名找出文件的所在目录
            // String path = findFileSavePathByFileName(fileName,fileSaveRootPath);
            String path=fileSaveRootPath;
            //得到要下载的文件
            File file = new File(path + "/" + fileName);
            //如果文件不存在
            if(!file.exists()){
                request.setAttribute("message", "您要下载的资源已被删除!!");
                request.getRequestDispatcher("/message.jsp").forward(request, response);
                return;
            }
            //处理文件名
            String realname = fileName.substring(fileName.indexOf("_")+1);
            //设置响应头,控制浏览器下载该文件
            response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(realname, "UTF-8"));
            //读取要下载的文件,保存到文件输入流
            FileInputStream in = new FileInputStream(path + "/" + fileName);
            //创建输出流
            OutputStream out = response.getOutputStream();
            //创建缓冲区
            byte buffer[] = new byte[1024];
            int len = 0;
            //循环将输入流中的内容读取到缓冲区当中
            while((len=in.read(buffer))>0){
                //输出缓冲区的内容到浏览器,实现文件下载
                out.write(buffer, 0, len);
            }
            //关闭文件输入流
            in.close();
            //关闭输出流
            out.close();
        }
        
        /**
        * @Method: findFileSavePathByFileName
        * @Description: 通过文件名和存储上传文件根目录找出要下载的文件的所在路径
        *
        * @param filename 要下载的文件名
        * @param saveRootPath 上传文件保存的根目录,也就是/WEB-INF/upload目录
        * @return 要下载的文件的存储目录
        */ 
        public String findFileSavePathByFileName(String filename,String saveRootPath){
            int hashcode = filename.hashCode();
            int dir1 = hashcode&0xf;  //0--15
            int dir2 = (hashcode&0xf0)>>4;  //0-15
            String dir = saveRootPath + "\\" + dir1 + "\\" + dir2;  //upload\2\3  upload\3\5
            File file = new File(dir);
            if(!file.exists()){
                //创建目录
                file.mkdirs();
            }
            return dir;
        }
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doGet(request,response);
        }
    
    }
    
    

    文件下载列表页jsp

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <base href="<%=basePath%>">
        
        <title>My JSP 'fileList.jsp' starting page</title>
        
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">    
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
        <meta http-equiv="description" content="This is my page">
        <!--
        <link rel="stylesheet" type="text/css" href="styles.css">
        -->
    
      </head>
      
      <body>
          <c:forEach var="me" items="${fileNameMap}">
            <c:url value="/servlet/DownloadServlet" var="downurl">
                <c:param name="filename" value="${me.key}"></c:param>
            </c:url>
            ${me.value}<a href="${downurl}">下载</a>
            <br/>
            </c:forEach>
      </body>
    </html>
    

    相关文章

      网友评论

        本文标题:JavaWeb基础恢复之发邮件、上传、下载

        本文链接:https://www.haomeiwen.com/subject/lifflftx.html