上传文件的要求

表单的要求

1.表单的提交方式必须为POST方式
2.必须添加表单的另一属性enctype=”multipart/form-data”

Servlet的要求

1.若表单中加属性enctype,则在Servlet无法使用req.getParameter(“xxx”)方法,任何表单项都会返回null。
2.在Servlet提供了另外一种获取表单数据的方法req.getInputStream(),得到的是整个请求体。

需要的jar包

commons-fileupload-1.2.2.jar
commons-io-2.6.jar

commons-fileupload介绍

<dl> <dt> 从表单中获取请求体数据后,我们需要借助该包对请求体解析,解析完成后的数据存放在 FileItem对象当中,只需要用该对象的具体方法即可以得到我们想要的表单数据。 </dt> <dt> 如何获得FileItem对象? </dt> <dd> 1.创建工厂:DiskFileItemFactory dff = new DiskFileItemFactory();
2.创建解析器:ServletFileUpload sfu = new ServletFileUpload(dff);
3.得到FileItem类型的LIst: List<FileItem> list = sfu.parseRequest(request)
4.遍历List,获得需要的数据。 </dd> </dl>

FileItem介绍(不完全介绍)

方法 作用
getFieldName() 返回当前表单项的名称
getName() 返回上传文件的名称
getString(String charset) 获得当前表单项的值
isFormField() 是否是普通表单项
getSize() 返回上传文件的大小(字节数)
getInputStream() 返回上传文件对应的输入流
write(File file) 把上传的文件保存到指定文件中

示例:

<body>
  <h1>上传文件</h1>
  <form action='<c:url value='/UpLoadServlet'></c:url>' method="post" enctype="multipart/form-data">
    用户名:<input type="text" name="username"><br>
    照片:<input type="file" name="photo"><br>
    <input type="submit" value="上传">
  </form>
  </body>
package tqb.upload.web.servlet;

import java.io.File;
import java.io.IOException;
import java.util.List;

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.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

@WebServlet("/UpLoadServlet")
public class UpLoadServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //处理post请求编码
        request.setCharacterEncoding("utf-8");

        // 创建工厂
        DiskFileItemFactory factory = new DiskFileItemFactory();

        // 创建解析器
        ServletFileUpload sfu = new ServletFileUpload(factory);

        // 获得Fileitem类型的List
        try {
            List<FileItem> list = sfu.parseRequest(request);

            FileItem f1 = list.get(0);
            FileItem f2 = list.get(1);

            System.out.println("普通表单项:" + f1.getFieldName() + "=" + f1.getString("utf-8"));
            System.out.println("文件表单项:");
            System.out.println("Content-Type:" + f2.getContentType());
            System.out.println(f2.getName());
            System.out.println(f2.getSize());

            try {
                f2.write(new File("C:\\Users\\lenovo\\Desktop\\photo.jpg"));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } catch (FileUploadException e) {
            throw new RuntimeException(e);
        }

    }

}

上传文件的细节

<dl> <dt> 1.文件必须保存到WEB-INF中,避免用户可以从浏览器可以直接访问 </dt> <dt> 2.文件名称相关问题 </dt> <dd> a.有的浏览器上传文件的文件名是绝对路径,需要切割!如:C:\hello\hello.txt </dd> <dd> b.文件乱码或普通表单项乱码,解决办法: req.setCharacterEncoding(“utf-8”); </dd> <dd> c.文件同名问题:解决办法: uuid </dd> <dt> 3.目录打散,不要在一个目录下放过多的文件 </dt> <dt> 4.上传文件的大小限制 </dt> <dd> a.单个文件的大小限制 </dd> <dd> b.整个请求数据的大小限制 </dd> </dl>

5.缓存大小与临时目录
代码实现:

package tqb.upload.web.servlet;

import java.io.File;
import java.io.IOException;
import java.util.List;

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.FileSizeLimitExceededException;
import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import cn.itcast.commons.CommonUtils;

@WebServlet("/UpLoadServlet")
public class UpLoadServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().append("Served at: ").append(request.getContextPath());
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //编码设置
        response.setContentType("text/html;charset=utf-8");
        request.setCharacterEncoding("utf-8");

        //创建工厂
// DiskFileItemFactory factory = new DiskFileItemFactory();
        //缓存大小与临时目录,第一个参数为上传文件大小超过多少时会在硬盘建立缓存目录(默认为10kb),第二个参数为缓存目录的位置
        DiskFileItemFactory factory = new DiskFileItemFactory(20 * 1024, new File("D:/temp"));
        //创建解析器
        ServletFileUpload sfu = new ServletFileUpload(factory);

        //限制单个文件的上传大小(1M)
// sfu.setFileSizeMax(1024 * 1024);
        //限制整体请求体的大小(2M)
// sfu.setSizeMax(2048 * 1024);
        //得到List
        try {

            List<FileItem> list = sfu.parseRequest(request);
            FileItem f1 = list.get(0);
            FileItem f2 = list.get(1);
            //得到普通表单项名称
// f1.getFieldName();
            //得到普通表单项值
// f1.getString();

            //得到文件根目录
            String root = this.getServletContext().getRealPath("/WEB-INF/files");

            //得到文件表单项名称
            String upName = f2.getName();

            //处理文件上传是带路径名
            int index = upName.lastIndexOf("\\");
            if (index != -1){
                upName = upName.substring(index + 1);
            }

            //处理文件同名问题,保存就按这个保存
            String newName = CommonUtils.uuid() + "_" + upName;

            //哈希方法打散目录
            /* * 1.获取哈希值,转16进制 * 2.分别得到前两个字符 * 3.创建目录 * 4.将上传得文件保存到目录之中 */
            int hashCode = newName.hashCode();
            String hexString = Integer.toHexString(hashCode);
            File path = new File(root,hexString.charAt(0) + "/" + hexString.charAt(1)); 
            //有该文件得话不创建,没有的话自动创建
            path.mkdirs();

            //将文件保存在指定位置
            try {
                f2.write(new File(path,newName));
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (FileUploadException e) {
            if (e instanceof FileSizeLimitExceededException){
                request.setAttribute("msg", "文件大小超过1M,上传失败!");
                request.getRequestDispatcher("/index.jsp").forward(request, response);
            }
            if(e instanceof SizeLimitExceededException){
                request.setAttribute("msg", "整体大小超过2M,上传失败!");
                request.getRequestDispatcher("/index.jsp").forward(request, response);
            }
        }
    }
}

邮件的发送

<dl> <dt> 有关于邮件的协议 </dt> <dd> SMTP 简单邮件传输协议 发邮件的协议 端口号:25 服务器名称为:stmp.xxx.xxx 如:stmp.163.com </dd> <dd> POP3 邮局协议第三版 收邮件的协议 端口号:110 服务器名称:pop3.xxx.xxx 如:pop3.163.com </dd> <dd> IMAP 因特网消息访问协议 收发邮件的协议(了解) </dd> <dt> 依赖的jar包: </dt> <dd> javax.mail-1.6.2.jar </dd> <dd> activation-1.1.1.jar </dd> </dl>

不带附件的邮件

package tqb.mail;

import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import org.junit.Test;

/** * 邮件的发送(不带附件) * @author tqb * */
public class MyMail {
    /* * */
    @Test
    public void fun() throws AddressException, 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
            public PasswordAuthentication getPasswordAuthentication() {
                /* * 用户名,密码 */
                return new PasswordAuthentication("username", "password");
            }
        };

        Session session = Session.getInstance(props, auth);

        /* * 2.获得MimeMessage */
        MimeMessage msg = new MimeMessage(session); 
        //发件人
        msg.setFrom(new InternetAddress("tqb820965236@163.com"));
        //收件人
        msg.setRecipients(RecipientType.TO, "820965236@qq.com");
        //抄送人
// msg.setRecipients(RecipientType.CC, "");
        //暗送人(看不到,但是会收到消息)
// msg.setRecipients(RecipientType.BCC, "");
        //标题
        msg.setSubject("这是一个测试邮件");
        //正文
        msg.setContent("邮件正文,测试邮件,不要理会!!!", "text/html;charset=utf-8");

        /* * 3.发送邮件 */
        Transport.send(msg);
    }
}

带附件的邮件

package tqb.mail;

import java.io.File;
import java.io.IOException;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;

import org.junit.Test;

/** * 发送带有附件的邮件 * @author tqb * */
public class MyMail2 {
    @Test
    public void fun() throws MessagingException, IOException{
        /* * 创建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("username","password");
            }
        };

        Session session = Session.getInstance(props, auth);

        /* * 得到mimeMessage */
        MimeMessage msg = new MimeMessage(session);

        msg.setSubject("带附件的邮件");

        //创建多部分主体
        MimeMultipart list = new MimeMultipart();
        //创建MimeBodyPart
        MimeBodyPart part1 = new MimeBodyPart();
        part1.setContent("这是带有附件的垃圾邮件","text/html;charset=utf-8");
        MimeBodyPart part2 = new MimeBodyPart();
        //附件
        part2.attachFile(new File("C:\\Users\\lenovo\\Desktop\\dogcom.exe"));
        //附件的名称+编码(防止乱码)
        part2.setFileName(MimeUtility.encodeWord("狗子.exe"));

        //将MimeBodyPart添加至MimeMultipart
        list.addBodyPart(part1);
        list.addBodyPart(part2);
        msg.setContent(list);
        msg.setFrom(new InternetAddress("tqb820965236@163.com"));
        msg.setRecipients(RecipientType.TO, "820965236@qq.com");

        /* * 发送邮件 */
        Transport.send(msg);
    }
}