1.文件的上传
[1] 简介
将本地的文件传输到远程的服务器
上传文件需要通过表单来上传
上传文件实际上就是上传文件的流
[2] 表单的设置
我们使用type为file的input来上传文件,且method为post请求
form中有一个属性enctype
默认值是application/x-www-form-urlencoded,
该值的意思是请求体中的内容将会被URL编码
当上传文件的时候,并不希望请求体被URL编码,所以我们要修改该值
在文件上传时enctype的值应该设置为multipart/form-data
multipart/form-data:多部件的表单数据,当表单enctype设置为该值时,
表单中的数据将会分为多个部件上传到服务器
当多部件表单的形式上传文件时,表单的请求体将会被分成多个部分,
一个表单项对应了一个部件,多个部件使用类似于
—————————–7df232f2e07a4 这样的分割符分割
当表单设置为多部件表单时,那么request.getParameter()这个方法就废了。
[3] FileUpload
当接收是一个多部件表单时,我们需要手动的去解析表单中的内容,但是我们说手动解析太麻烦了。
我们使用commons-fileupload来解析表单
- commons-fileupload 依赖于 commons-io , 所以使用时需要同时导入2个jar包
commons-fileupload-1.3.1.jar
commons-io-2.4.jar
核心类:
DiskFileItemFactory
- 工厂类,用来构建解析器类实例
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload
ServletFileUpload upload = new ServletFileUpload(factory);
- 解析器类,用来解析request,获取表单信息
FileItem
List< FileItem> list=upload.parseRequest(request);
FileUpload会将表单中每一个部件都封装为一个FileItem对象,我们可以通过读取FileItem对象来解析表单信息
方法:
boolean isFormField() –> 判断当前FileItem是否是一个普通表单项,如果是则返回true , 否则返回false
String getFieldName() –> 获取表单的name属性的值
String getString(String encoding) –> 获取表单项的value属性值,也就是我们填写的内容
String getName() –> 获取上传文件的名字
String getContentType() –> 获取上传文件的类型,返回是一个文件的MIME值
long getSize() –> 获取上传文件的大小
void write(File file) –> 将上传文件写入到指定的文件中。
使用步骤:导入第三方jar包
1.创建工厂类实例
2.创建解析器类实例
3.解析request,获取表单信息
[4] 细节
问题1:
部分浏览器选择文件以后,上传的文件的名字,是文件的全路径,具体如下:
C:\Users\zhao\Desktop\day16\图片\企鹅.jpg
这种情况我们需要对文件名进行一个截取的操作
1.判断文件名中是否包含 \
if(name.contains("\\")){
int p =name.lastIndexOf("\\")+1;
name = name.substring(p);
}
问题2:
当用户上传同名文件时,先上传的文件会被后上传的给替换。
可以来修改一下文件名,我们需要为文件名加上一个唯一的标识
将文件名修改为 唯一标识_文件名
String prefix = UUID.randomUUID().toString().replace("-", "");
String fileName = prefix+"_"+name;
问题3:
如何限制上传文件的大小
- 单个文件的大小
通过调用解析器ServletFileUpload的setFileSizeMax()方法可以来限制单个文件的大小。
当设置了这个值以后,文件超出范围以后,会在程序抛出异常如下异常:
FileSizeLimitExceededException
我们可以通过捕获该异常的方式来处理文件大小超过限制
catch(FileSizeLimitExceededException e){
//出现该异常,说明单个文件大小超过限制,设置一个错误消息
request.setAttribute(“msg”, “单个文件不要超过50kb”);
//转发到index.jsp
request.getRequestDispatcher(“/index.jsp”).forward(request, response);
}
- 所有文件的大小
通过setSizeMax()来设置所有上传文件总的大小
当文件超出限制时,会抛出如下异常
SizeLimitExceededException
我们可以捕获异常并作出相应处理
catch(SizeLimitExceededException e){
//出现该异常,说明文件总大小超过限制,设置一个错误消息
request.setAttribute(“msg”, “文件总大小不要超过150KB”);
//转发到index.jsp
request.getRequestDispatcher(“/index.jsp”).forward(request, response);
}
2.文件的下载(理解)
[1] 简介
从远程服务器将文件下载到本地
一般下载文件我们只需要将文件的地址发送给浏览器即可,
但是当浏览器访问的是一个它可以打开的文件,浏览器会自动打开
如果我们将文件直接放到根目录下的,那么将不能限制文件的下载权限
下载实际上就是将文件以流的形式发送给浏览器
[2] 下载所需要的内容
1.获取到文件的流
- 被下载的文件的流
2.设置两个响应头
Content-Type –> 被下载的文件的类型,需要设置一个文件的MIME值
Content-Disposition –> 告诉浏览器如何处理文件
设置值为:attachment; filename=文件名
attachment告诉浏览器文件是一个附件,直接下载到本地
filename告诉浏览器文件的名字
[3] 下载相关的两个响应头
1) 文件类型 Content-Type –> 文件的MIME类型
2) 下载文件的信息 Content-Disposition –> attachment; filename=文件名
[4] 乱码问题
文件名字是设置到响应头中,但是我们响应头不支持直接写中文,所以如果文件名为中文,会出现乱码。
所以当向响应头中设置中文需要对文字进行编码
大部分浏览器使用如下代码对文件名编码即可
URLEncoder.encode(fileName, "utf-8");
但是,火狐使用的BASE64进行的编码,上边那种方式他不支持,我们单独处理
fileName = "=?utf-8?b?"+new BASE64Encoder().encode(fileName.getBytes("utf-8"))+"?=";
第一种方式:
//可以使用如下代码解决乱码问题
//在不同浏览器中需要调用不同代码,为了兼容不同的浏览器,我们需要在编码之前,对浏览器进行一个判断
//获取User-Agent这个请求头
String ua = request.getHeader("User-Agent");
//判断当前浏览器是否为火狐
if(ua.contains("Firefox")){
//是火狐
fileName = "=?utf-8?b?"+new BASE64Encoder().encode(fileName.getBytes("utf-8"))+"?=";
}else{
//对fileName进行URL编码
//encode需要两个参数,第一个被编码的字符串,第二个使用字符集
fileName = URLEncoder.encode(fileName, "utf-8");
}
第二种方式:
原理:谁问跟谁急
fileName = new String(fileName.getBytes("gbk"), "iso8859-1");
先用gbk给字符解码,然后在使用iso8859-1进行编码
这种方式有点小问题,有一些特殊字符不太支持,但是大部分都好使
//获取ServletContext
ServletContext servletContext = getServletContext();
//获取文件的真实路径
String realPath = servletContext.getRealPath("/WEB-INF/爱的就是你.mp3");
//获取文件名
String fileName = "爱的就是你.mp3";
处理文件名的乱码问题......
//获取被下载文件的流
InputStream in = new FileInputStream(realPath);
//获取文件的MIME类型
String mimeType = servletContext.getMimeType(realPath);
//设置文件的MIME类型
response.setContentType(mimeType);
//设置Content-Disposition这个响应头
response.setHeader("Content-Disposition", "attachment; filename="+fileName);
//将文件的流发送给浏览器
//获取一个和浏览器对接的输出流,将文件的流发送出去
ServletOutputStream out = response.getOutputStream();
//将输入流写到输出流
IOUtils.copy(in, out);
//关闭输入流
in.close();
3.国际化(I18N)(理解)
[1]国际化简介
国际化指的是一个网站当中国人访问显示中文,外国人访问显示外语。
国际化主要指的支持英语
[2]国际化的原理
我们的国际化操作实际就是在项目提供不同国际化资源文件,ResourceBundle可以根据不同Locale来加载不同的国际资源文件
[3]核心类
java.util.ResourceBundle 用来管理国际化资源文件
java.util.Locale 来表示国家和语言的信息
国际化资源文件:
1.国际化资源文件必须创建到类路径下
2.命名规范: 基础名语言国家.properties
基础名:可以随便起
语言:使用语言
zh,en国家:所在的国家
CN,US
[4]格式化标签库
> 我们可以使用JSTL的fmt标签来进行国际化操作:
> 导入JSTL的jar包
> 在页面中引入指定的标签库:
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<fmt:setBundle basename="基础名"/>
指定使用的国际化资源文件的基础名
{setBundle 是全局的,bundle是局部的,只在其标签体内有效。}
<fmt:setLocale value="zh_CN"/>
手动指定当前Locale对象
<fmt:message key="" />
在jsp中引用国际化资源文件中的内容,key的值对应国际化资源文件中的key值。
<fmt:formatDate dateStyle="full" timeStyle="full" value="<%=new Date() %>" type="both"/>
<fmt:formatDate value>
国际化日期:
dateStyle
timeStyle
指定日期和时间的风格
可选值:FULL LONG MEDIUM SHORT