JavaWeb之上传下载与JavaMail

title: JavaWeb之上传下载与JavaMail
tag: JavaWeb upload JavaMail
categories: JavaWeb upload JavaMail


若图片无法显示,请前往我的博客查看,相应文章链接:http://codingxiaxw.cn/2016/11/02/31-%E4%B8%8A%E4%BC%A0%E4%B8%8B%E8%BD%BD%E4%B8%8EJavaMail/

对于JavaWeb中的上传与下载,别说你从没遇到过。

当我们要向网站中上传文件或者需要从网站上下载文件时,其实我们就已经玩了一遍上传与下载了。那么我们上传的文件会保存在服务器的哪里呢?下载的文件又是从服务器的哪里传过来的?这些又是怎么实现的呢?

另外很多时候我们注册某个公司的账号时,注册成功后该公司会给你填入的邮箱发送一封邮件,要求你点击邮件中的链接来给该账号激活。这个功能又是怎么实现的呢?

下面我将告诉你如何用代码实现这些功能。

1.对于多部件表单的体的理解

通过抓包的方式可以看到服务器发送过来的响应,理解如下:

  • 1.分隔出多个部件,即一个表单项一个部件。
  • 2.一个部件中包含请求头和空行,以及请求体。
  • 3.普通表单项:

1个头:Context-Disposition:包含name=“xxxx”,即表单项名称。
体就是表单项的值。

  • 4.文件表单项:

有2个头:a.Content-Disposition:包含name=“xxxx”,即表单项名称;还有一个filename=“xxx”,表示上传文件的名称。
Content-Type:它是上传文件的MIME类型,例如:image/pjpeg,表示上传的是图片,图片为jpg扩展名的图片。
体就是上传文件的内容。

2.实现文件的上传

首先我们需要明确的是要实现上传和下载功能都要借助第三方Jar包 fileupload.jar,依赖jar包为:commons-io.jar

2.1上传对表单的限制

  • 1.method必须为"post".
  • 2.必须对表单form添加enctype="multipart/form-data"的属性。
  • 3.表单中需要添加文件表单项:<input type="file" name="xxx"/>,除了文件表单项叫文件表单项外其他所有的input表单项都叫普通表单项。

2.2上传对servlet的限制

  • 1.在servlet中通过方法request.getParameter("xxx");得到表单中的参数时得到返回值不再是Object对象,而是返回的null,因为文件表单form添加了enctype="multipart/form-data的属性。
  • 2.解决方法:在Servlet中通过方法ServletInputStream request.getInputStream();得到表单中的参数,然而得到的内容将是表单的整个请求体。

2.3上传的代码实现

涉及到的类:

  • 1.工厂类:FileItemFactory类
  • 2.解析器类:ServletFileUpload类
  • 3.表单项:FileItem

代码步骤:

  • 1.创建工厂:DiskFileItemFactory factory=new DiskFileItemFactory();
  • 2.创建解析器:ServletFileUpload sfu=new ServletFileUpload(factory);
  • 3.使用解析器来解析request,得到的是FileItem集合:List<FileItem> fileItemList=sfu.parseRequest(request);

Demo:

image

FileItem的API

  • boolean isFormField():是否为普通表单项,如果返回true则为普通表单项,如果为false则为文件表单项。
  • String getFieldName():返回当前表单项的名称。
  • String getString(String charset):返回表单项的值,参数传入utf-8即可。这个方法不适合文件表单项。
  • String getName():返回上传的文件名称。
  • long getSize():返回上传文件的字节数。
  • InputStream getInputStream():返回上传文件对应的输入流。
  • void write(File file):把上传的文件内容保存到指定的文件中。
  • String getContextType();

2.4上传的细节

  • 1.文件必须保存到WEB-INF文件下

为了不让浏览器直接访问到。

  • 2.文件名称相关问题
    • a.有的浏览器上传的文件名是绝对路径,如c:\file\图片.jpg,这时需要对文件名进行切割,切割的代码为:
String fileName=file2.getName();//file2为FileItem对象  
    int index=fileName.lastIndex("\\");  
    if(index!=-1)
    {
        fileName=fileName.substring(index+1);
    }
  • b.文件名乱码或者普通表单项乱码

解决方法:告诉fileupload你的编码方式,在servlet中设置代码request.setCharacterEncoding("utf-8");因为fileupload内部会调用request.getCharacterEncoding();得到你的编码方式。
解决方法1,在servlet中添加:request.setCharacterEncoding("utf-8");//优先级比下面的方式低
解决方法2,在servlet中添加:servletFileUpload.setHeaderEncoding("utf-8");//优先级比上面的方式低。也就是说,当同时出现解决方法1中的代码和解决方法2中的代码时,会优先使用方法2来设置编码方式。

  • c.文件同名问题:我们需要为上传过来的每个文件都添加名称前缀,而且这个前缀要保证不能重复(使用uuid解决).

fileName=CommonUtils.uuid()+"_"+fileName;

  • 3.因为不能在一个目录下存放过多文件,所以我们需要对目录进行打散,打散的方法有如下3种:
    • a.首字符打散:使用文件的首字母作为目录名称,例如:abc.text,那么我们就把文件保存到a目录下,如果a目录不存在,那么创建之。(缺点:若文件名称为中文咋办?)
    • b.时间打散:使用当前日期作为目录
    • 哈希打散:(缺点,存在目录下的文件我们不清楚)1.通过文件名称得到int值,即调用hashCode();2.把int值转换成16进制0-9,A-F;3.获取16进制的前2位用来生成目录,目录为二层!例如:1B2C3D4E5F,生成的目录为/1/B,在其下保存文件。
  • 4.上传文件的大小限制
    • a.单个文件的大小限制

1.sfu.setFilesizeMax(100*1024);限制单个文件大小为100kb,此方法调用必须在解析开始之前调用。
2.如果上传的文件超过限制,则在parseRequest()方法时,会抛出异常。

  • b.整个请求所有文件大小限制

sfu.setSizeMax(1024*1024);限制整个表单大小为1M。此方法调用必须在解析开始之前调用。
如果上传的文件超过限制,则在parseRequest()方法时,会抛出异常。超出限制大小时显示错误信息代码:需要在jsp文件中增加${msg}。
代码如下: [图片上传失败...(image-e3398e-1526285981316)]

  • 5.缓存大小与临时目录
    • 缓存大小:超出多大,才向硬盘中保存。默认为10KB。
    • 临时目录:向硬盘的什么目录保存。

说明:设置缓存大小与临时目录,在创建工厂时,调用DiskFileItemFactory的有参构造器:DiskFileItemFactory factory=new DiskFileItemFactory(缓存大小,硬盘临时目录路径);。当文件正在上传时,会在硬盘的该临时目录下出现这个文件;而当文件上传完毕时,硬盘下该临时目录下的这个文件就会消失。最后保存在web-inf的target目录下。

3.实现文件的下载

下文文件就是向客户端响应字节数据。当不涉及文件下载时你向服务器发出一个请求时,服务器返回的响应都是html的字符数据;而当涉及到文件下载时,服务器会把一个文件变成字节数组,使用response.getOutputStream();来响应给浏览器。

3.1文件下载的要求

设置两个头一个流:

  • Content-Type:你传递给客户端的文件是什么MIME类型,例如:image/pjpeg。可以通过文件名称调用ServletContext的getMimeType()方法得到MIME类型。
  • Content-Disposition:它的默认值为inline,表示在浏览器窗口中打开。attachment;fileName=xxx;在fileName后面跟随的是显示在下载框中的文件名称。
  • 流:要下载的文件数据。自己new一个输入流即可。

3.2下载Demo

[图片上传失败...(image-6e30dd-1526285981316)]

3.3下载的细节

1.显示在下载框中的中文名称时,会出现乱码。

  • FireFox:Base64编码
  • 其它大部分浏览器:url编码

通用方案:frameName=new String(filename.getBytes("GBK"),"ISO-8859-1");

代码见下:[图片上传失败...(image-2fb7a5-1526285981316)]

注意downutil.jar包的使用

4.JavaMail

JavaMail是Java提供的一组API,用来发送和接收邮件。

需要导入的jar包为:1.mail.jar2.activation.jar

4.1与邮件相关的协议

smtp 25-->简单的邮件传输协议。
pop3 110-->邮局协议第三版

4.2核心类

1.Session(这跟我们Servlet中的HttpSession不同哦).

如果你得到了它,表示已经与服务器连接上了,与Connectin的作用相似。

得到Session,需要使用Session.getInstance(Properties,authenticator);方法。

得到Session对象的Demo如下:

Properties props=new Properties();
props.setProperty(“mail.host”,”smtp.163.com”);
props.setProperty(“mail.smtp.auth”,”true”);

Authenticator auth=new Authenticator(){
protected PasswordAuthentication getPasswordAuthentication(){
    return new PasswordAuthentication(“username”,”password”);
    }
};

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

2.MimeMessage
它表示一个邮件对象,你可以调用它的setFrom()方法进行设置发件人、设置主题、设置正文。

3.TransPort
它只有一个发邮件的功能。

4.3完整Demo如下

[图片上传失败...(image-1bdb39-1526285981316)]

4.4带有附件的邮件

image

2018.3.19更

欢迎加入我的Java交流1群:659957958。群里目前已有1800人,每天都非常活跃,但为了筛选掉那些不怀好意的朋友进来搞破坏,所以目前入群方式已改成了付费方式,你只需要支付9块钱,即可获取到群文件中的所有干货以及群里面各位前辈们的疑惑解答;为了鼓励良好风气的发展,让每个新人提出的问题都得到解决,所以我将得到的入群收费收入都以红包的形式发放到那些主动给新手们解决疑惑的朋友手中。在这里,我们除了谈技术,还谈生活、谈理想;在这里,我们为你的学习方向指明方向,为你以后的求职道路提供指路明灯;在这里,我们把所有好用的干货都与你分享。还在等什么,快加入我们吧!

2018.4.21更:如果群1已满或者无法加入,请加Java学习交流2群:305335626 。群2作为群1的附属群,除了日常的技术交流、资料分享、学习方向指明外,还会在每年互联网的秋春招时节在群内发布大量的互联网内推方式,话不多说,快上车吧!

5.联系

If you have some questions after you see this article,you can tell your doubts in the comments area or you can find some info by clicking these links.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,373评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,732评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,163评论 0 238
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,700评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,036评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,425评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,737评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,421评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,141评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,398评论 2 243
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,908评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,276评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,907评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,018评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,772评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,448评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,325评论 2 261

推荐阅读更多精彩内容