文件上传
1.上传对表单限制
- method="post"
- enctype="multipart/form-data"
- 表单中需要添加文件表单项:<input type="file" name="xxx" />
<h3>${msg }</h3> <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限制
- 文件上传不能使用BaseServlet
- request.getParametere("xxx");这个方法在表单为enctype="multipart/form-data"时,它作废了。它永远都返回null
- ServletInputStream request.getInputStream();包含整个请求的体!
3.上传三步
导入jar(commons-fileupload)
- commons-fileupload.jar
- commons-io.jar
相关类:
- 工厂:DiskFileItemFactory
- 解析器:ServletFileUpload
表单项:FileItem
1.创建工厂:DiskFileItemFactory factory = new DiskFileItemFactory(); 2.创建解析器:ServletFileUpload sfu = new ServletFileUpload(factory); 3.使用解析器来解析request,得到FileItem集合:List<FileItem> fileItemList = sfu.parseRequest(request);
4.FileItem
- boolean isFormField():是否为普通表单项!返回true为普通表单项,如果为false即文件表单项!
- String getFieldName():返回当前表单项的名称;
- String getString(String charset):返回表单项的值;
- String getName():返回上传的文件名称
- long getSize():返回上传文件的字节数
- InputStream getInputStream():返回上传文件对应的输入流
- void write(File destFile):把上传的文件内容保存到指定的文件中。
- String getContentType();获取上传的文件的类型
5.上传的细节
- 保存到WEB-INF下!(目的是不让浏览器直接访问到)
- 有的浏览器上传的文件名是绝对路径,这需要切割
目录打散
哈希打散: 通过文件名称得到int值,即调用hashCode() 它int值转换成16进制0~9, A~F 获取16进制的前两位用来生成目录,目录为二层!例如:1B2C3D4E5F,/1/B/保存文件。
6.代码
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); /* * 上传三步 */ // 工厂,设置缓存,超过20k,向目录保存 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("/form.jsp").forward(request, response); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }
文件下载
1.下载就是向客户端响应字节数据!
把一个文件变成字节数组,使用response.getOutputStream()来各应给浏览器!!!
2.下载的要求
两个头一个流!
Content-Type:你传递给客户端的文件是什么MIME类型,例如:image/pjpeg
通过文件名称调用ServletContext的getMimeType()方法,得到MIME类型!
Content-Disposition:它的默认值为inline,表示在浏览器窗口中打开!attachment;filename=xxx
在filename=后面跟随的是显示在下载框中的文件名称!
流:要下载的文件数据!
自己new一个输入流即可!
3.代码
@Override public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { /* * 两个头一个流 * 1. Content-Type * 2. Content-Disposition * 3. 流:下载文件的数据 */ String filename = "F:/清白之年.mp3"; // 为了使下载框中显示中文文件名称不出乱码! 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; }
JavaMail
注意:一般邮箱需要开通POP3/SMTP/IMAP功能,发过去邮件很可能在垃圾箱里面
1.导入jar
mail.jaractivation.jar
2.主要类
javax.mail.Sessionjavax.mail.internet.MimeMessagejavax.mail.Transport
3.代码
- 无附件
@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); }