上传
两个步骤:
用户在页面中选择要上传的文件, 然后将请求提交到 Servlet
Servlet 收到请求, 解析用户上传的文件, 然后将文件存储到服务器
上传文件表单
- <form action="Servlet" method="post" enctype="multipart/form-data">
- <input type="file" name="file" /><br /><br />
- <input type="submit" value="上传" />
- </form>
注意:
表单的 method 属性必须为 post
表单的 enctype 属性必须为 multipart/form-data
上传文件的控件是 intput,type 属性为 file
注意: Servelet
当 enctype="multipart/form-data" 时, 再使用 getParamter()获取到内容永远为空.
需要引入解析请求中的参数和文件, 这个工具就是 commons-fileupload.
commons-fileupload
它的作用就是可以从 request 对象中解析出, 用户发送的请求参数和上传文件的流.
commons-fileupload 包依赖 commons-io, 两个包需要同时导入.
核心类:
DiskFileItemFactory
工厂类, 用于创建 ServletFileUpload, 设置缓存等
该类一般直接使用构造器直接创建实例
方法:
public void setSizeThreshold(int sizeThreshold): 用于设置缓存文件的大小(默认值 10kb)
public void setRepository(File repository): 用于设置缓存文件位置(默认系统缓存目录)
ServletFileUpload
该类用于解析 request 对象从而获取用户发送的请求参数(包括普通参数和文件参数)
该类需要调用有参构造器创建实例, 构造器中需要一个 DiskFileItemFactory 作为参数
方法:
public List<FileItem>parseRequest(HttpServletRequest request): 解析 request 对象, 获取请求参数, 返回的是一个 List,List 中保存的是一个 FileItem 对象, 一个对象代表一个请求参数.
public void setFileSizeMax(long fileSizeMax): 设置单个文件的大小限制, 单位为 B. 如果上传文件超出限制, 会在 parseRequest()抛出异常 FileSizeLimitExceededException.
public void setSizeMax(long sizeMax): 限制请求内容的总大小, 单位为 B. 如果上传文件超出限制, 会在 parseRequest()抛出异常 SizeLimitExceededException.
FileItem
该类用于封装用户发送的参数和文件, 也就是用户发送来的信息将会被封装成一个 FileItem 对象, 我们通过该对象获取请求参数或上传文件的信息.
该类不用我们手动创建, 由 ServletFileItem 解析 request 后返回.
方法:
String getFieldName(): 获取表单项的名字, 也就是 input 当中的 name 属性的值.
String getName(): 获取上传的文件名, 普通的请求参数为 null.
String getString(String encoding): 获取内容, encoding 参数需要指定一个字符集.
1 若为文件, 将文件的流转换为字符串.
2 若为请求参数, 则获取请求参数的 value.
boolean isFormField(): 判断当前的 FileItem 封装的是普通请求参数, 还是一个文件.
1 如果为普通参数返回: true
2 如果为文件参数返回: false
String getContentType(): 获取上传文件的 MIME 类型
long getSize(): 获取内容的大小
write(): 将文件上传到服务器
- // 创建工厂类
- DiskFileItemFactory factory = new DiskFileItemFactory();
- // 创建请求解析器
- ServletFileUpload fileUpload = new ServletFileUpload(factory);
- // 设置上传单个文件的的大小
- fileUpload.setFileSizeMax(1024*1024*3);
- // 设置上传总文件的大小
- fileUpload.setSizeMax(1024*1024*3*10);
- // 设置响应内容的编码
- response.setContentType("text/html;charset=utf-8");
- try {
- // 解析请求信息, 获取 FileItem 的集合
- List<FileItem> items = fileUpload.parseRequest(request);
- // 遍历集合
- for (FileItem fileItem : items) {
- // 如果是普通的表单项
- if(fileItem.isFormField()){
- // 获取参数名
- String fieldName = fileItem.getFieldName();
- // 获取参数值
- String value = fileItem.getString("utf-8");
- System.out.println(fieldName+"="+value);
- // 如果是文件表单项
- }else{
- // 获取文件名
- String fileName = fileItem.getName();
- // 获取上传路径
- String realPath = getServletContext().getRealPath("/web-INF/upload");
- // 检查 upload 文件夹是否存在, 如果不存在则创建
- File f = new File(realPath);
- if(!f.exists()){
- f.mkdir();
- };
- // 为避免重名生成一个 uuid 作为文件名的前缀
- String prefix = UUID.randomUUID().toString().replace("-", "");
- // 将文件写入到服务器中
- fileItem.write(new File(realPath+"/"+prefix+"_"+fileName));
- // 清除文件缓存
- fileItem.delete();
- }
- }
- } catch (Exception e) {
- if(e instanceof SizeLimitExceededException){
- // 文件总大小超出限制
- response.getWriter().print("上传文件的总大小不能超过 30M");
- }else if(e instanceof FileSizeLimitExceededException){
- // 单个文件大小超出限制
- response.getWriter().print("上传单个文件的大小不能超过 3M");
- }
- }
- response.getWriter().print("上传成功");
下载
下载文件的关键点:
服务器以一个流的形式将文件发送给浏览器.
发送流的同时还需要设置几个响应头, 来告诉浏览器下载的信息.
具体响应头如下:
Content-Type
下载文件的 MIME 类型
可以通过 servletContext. getMimeType(String file)获取
也可以直接手动指定
使用 response.setContentType(String type);
响应头样式: Content-Type: audio/mpeg
Content-Disposition
下载文件的名字, 主要作用是提供一个默认的用户名
通过 response.setHeader("Content-Disposition", disposition)设置
响应头样式: Content-Disposition: attachment; filename=xxx.mp3
Content-Length
下载文件的长度, 用于设置文件的长处(不必须)
通过 response. setContentLength(int len)设置.
设置后样式: Content-Length: 3140995
接下来需要以输入流的形式读入硬盘上的文件
FileInputStream is = new FileInputStream(file);
这个流就是我们一会要发送给浏览器的内容
通过 response 获取一个输出流, 并将文件 (输入流) 通过该流发送给浏览器
获取输出流: ServletOutputStream out = response.getOutputStream();
通过输出流向浏览器发送文件(不要忘了关闭输入流)
步骤演示
以下步骤都是在同一个 Servlet 的 doGet()方法中编写的
1. 获取文件的流:
- String realPath = getServletContext().getRealPath("/WEB-INF/mp3 / 中国话. mp3");
- // 获取文件的 File 对象
- File file = new File(realPath);
- // 获取文件的输入流
- FileInputStream in = new FileInputStream(file);
2. 获取头信息:
- // 获取文件的 MIME 信息
- String contentType = getServletContext().getMimeType(realPath);
- // 设置下载文件的名字
- String filename = "zhongguohua.mp3";
- // 创建 Content-Disposition 信息
- String disposition = "attachment; filename="+ filename ;
- // 获取文件长度
- long size = file.length();
3. 设置头信息
- // 设置 Content-Type
- response.setContentType(contentType);
- // 设置 Content-Disposition
- response.setHeader("Content-Disposition", disposition);
- // 设置文件长度
- response.setContentLength((int)size);
4. 发送文件
- // 通过 response 获取输出流, 用于向浏览器输出内容
- ServletOutputStream out = response.getOutputStream();
- // 将文件输入流通过输出流输出
- byte[] b = new byte[1024];
- int len = 0;
- while((len=is.read(b))> 0){
- out.write(b, 0, len);
- }
- // 最后不要忘记关闭输入流, 输出流由 Tomcat 自己处理, 我们不用手动关闭
- is.close();
乱码
中文文件名会出现乱码问题. 解决此问题的方法很简单, 在获取文件名之后为文件名进行编码:
filename = java.NET.URLEncoder.encode(filename,"utf-8");
火狐浏览器比较特殊需要特殊处理一下.
1. 先要获取客户端信息(通过获取请求头中的 User-Agent 信息)
String ua = request.getHeader("User-Agent");
2. 然后判断浏览器版本, 做不同的处理
- // 判断客户端是否为火狐
- if(ua.contains("Firefox")){
- // 若为火狐使用 BASE64 编码
- filename = "=?utf-8?B?"+new BASE64Encoder().encode(filename.getBytes("utf-8"))+"?=";
- }else{
- // 否则使用 UTF-8
- filename = URLEncoder.encode(filename,"utf-8");
- }
- String string = new String("你好. jpg".getBytes("gbk"), "iso8859-1");
来源: https://www.cnblogs.com/Open-ing/p/12151037.html