JavaWeb文件上传与下载
要实现Web开发的上传功能,通常需要完成两步操作:一是在Web页面中添加上传输入项;二是在Servlet中读取上传文件的数据,保存到数据库,然后从数据库拿到路径,进行下载。
上传大多数情况是通过表单的形式提交给服务器,使用标签。
使用标签需要注意以下两点:
1.必须设置name属性,不然浏览器不会发送上传文件的数据。
2.必须将method属性设置为post,ectype属性设置为“multipart/form-data”类型。
from会被分为两部分:表单字段和上传字段,然后通过FileItemFactory工厂类 将请求消息实体中的每一个项目封装成单独的DiskFileItem (FileItem接口的实现) 对象的任务。
由于在Servlet直接读取上传数据,并且解析出相应文件数据是一项非常麻烦的工作。为了方便处理上传数据,Apache组织提供了一个开源组件Commons-FileUpload。该组件可以将“multipart/form-data”类型请求的各种表单域解析出来,并实现一个或多个文件上传,同时也可以限制上传文件的大小等内容。其性能十分优异,使用极其简单。
jar下载地址
上传
1.创建一个上传表单
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>up.html</title>
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="this is my page">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
</head>
<body>
<form action="UploadServlet3" method="post" enctype="multipart/form-data" >
id:<input type="text" name="user_id"><br>
name:<input type="text" name="user_name"><br>
file:<input type="file" name="file_name"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
2.创建一个Files容器存放文件
package com.it.bean;
import java.io.Serializable;
public class Files implements Serializable{
private static final long serialVersionUID = 1L;
private String f_id;
private String f_name;
private String f_path;
public Files() {
super();
// TODO Auto-generated constructor stub
}
public Files(String fId, String fName, String fPath) {
super();
f_id = fId;
f_name = fName;
f_path = fPath;
}
public String getF_id() {
return f_id;
}
public void setF_id(String fId) {
f_id = fId;
}
public String getF_name() {
return f_name;
}
public void setF_name(String fName) {
f_name = fName;
}
public String getF_path() {
return f_path;
}
public void setF_path(String fPath) {
f_path = fPath;
}
}
3.数据库建表语句
create table users_file(
f_id varchar(200) primary key,
f_name varchar(200),
f_path varchar(200)
)
4.为了防止文件名重复问题我们存入的时候封装了一个类FileUtil来处理文件路径
package com.it.tools;
import java.util.UUID;
public class FileUtil {
//使用UUID处理文件名
public static String getRealPath(String parent,String filename){
String path =parent+"\\"+UUID.randomUUID()+getExt(filename);
return path;
}
//获取后缀名
public static String getExt(String filename){
if(filename.lastIndexOf('.')!=-1){
return filename.substring(filename.lastIndexOf('.'));
}return "";
}
}
5.创建上传文件的Servlet
package com.it.controller;
import com.it.bean.Files;
import com.it.service.FilesServices;
import com.it.service.impl.FilesServicesImpl;
import com.it.tools.FileUtil;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
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 java.io.*;
import java.util.List;
import java.util.Map;
@WebServlet(name = "UploadServlet3",urlPatterns = {"/UploadServlet3"})
public class UploadServlet3 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//使用uploadjar包
//生成对象
Files files=new Files();
//生成services
FilesServices filesServices=new FilesServicesImpl();
//设置id为系统当前时间
files.setF_id(String.valueOf(System.currentTimeMillis()));
request.setCharacterEncoding("utf-8");
//创建FileItemFactory工厂类 将请求消息实体中的每一个项目封装成单独的DiskFileItem (FileItem接口的实现) 对象的任务
FileItemFactory fileItemFactory=new DiskFileItemFactory();
//创建处理上传的核心 servlet servletFileupload
ServletFileUpload servletFileUpload=new ServletFileUpload(fileItemFactory);
// 解决上传表单项乱码问题
servletFileUpload.setHeaderEncoding("utf-8");
//解析上传文件的multipart/form-data流,返回按照传输顺序解析出的FileItem实例列表
try {
List<FileItem> fileItemList=servletFileUpload.parseRequest(request);
//迭代列表
for (FileItem fileItem:fileItemList) {
//表单字段
if(fileItem.isFormField()){
//getFieldName方法用于返回表单标签name属性的值。
if(fileItem.getFieldName().equals("user_id")){
//获取它对应的值 设置编码格式
System.out.println(fileItem.getString("utf-8"));
}
if(fileItem.getFieldName().equals("user_name")){
//获取它对应的值 设置编码格式
System.out.println(fileItem.getString("utf-8"));
}
}else{
// getName方法用于获得文件上传字段中的文件名
files.setF_name(fileItem.getName());
//父级目录
String parent="d:\\upload";
//String path =parent+"\\"+UUID.randomUUID()+getExt(filename);
//父级路径+随机名+.后缀名
files.setF_path(FileUtil.getRealPath(parent,fileItem.getName()));
filesServices.add(files);
//将文件写入到指定文件夹下
InputStream in= fileItem.getInputStream();
OutputStream out=new FileOutputStream(new File(files.getF_path()));
//读取上传文件
byte b[]=new byte[1024*10];
int len=0;
while((len=in.read(b))!=-1){
//写文件
out.write(b);
}
out.flush();
out.close();
in.close();
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
下载
1.创建展示的servlet
package com.it.controller;
import com.it.bean.Files;
import com.it.service.FilesServices;
import com.it.service.impl.FilesServicesImpl;
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 java.io.File;
import java.io.IOException;
import java.util.List;
@WebServlet(name = "ShowServlet",urlPatterns = {"/ShowServlet"})
public class ShowServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("utf-8");
//生成对象
Files files=new Files();
//生成services
FilesServices filesServices=new FilesServicesImpl();
//查询所有
List<Files> filesList =filesServices.queryAllFiles(files);
//存入到request
request.setAttribute("fileList",filesList);
//转发
request.getRequestDispatcher("downLoad.jsp").forward(request,response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
2.创建JSP(同步)使用EL表达式,从数据库中遍历文件名,设置为超级链接
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--同步遍历--%>
<c:forEach items="${fileList}" var="files" varStatus="i">
${i.index+1}.
<a href="down.do?f_id=${files.f_id}">${files.f_name}</a><br>
</c:forEach>
</body>
</html>
3.创建一个Base64Util类用来重编码
关于Base64Util的作用可以参考:Base64Util的作用
package com.it.tools;
import java.io.UnsupportedEncodingException;
import sun.misc.BASE64Encoder;
public class Base64Util {
public static String base64EncodeFileName(String fileName) {
BASE64Encoder base64Encoder = new BASE64Encoder();
try {
return "=?UTF-8?B?"
+ new String(base64Encoder.encode(fileName
.getBytes("UTF-8"))) + "?=";
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
3.当点击超级链接时,从数据库获取指定路径
package com.it.controller;
import com.it.bean.Files;
import com.it.service.FilesServices;
import com.it.service.impl.FilesServicesImpl;
import com.it.tools.Base64Util;
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 java.io.*;
import java.net.URLEncoder;
@WebServlet(name = "DownServlet",urlPatterns = {"/down.do"})
public class DownServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//通过id找到路径 然后下载
String f_id=request.getParameter("f_id");
//生成对象
Files files=new Files();
files.setF_id(f_id);
//生成services
FilesServices filesServices=new FilesServicesImpl();
//找路径 名字
Files files1=filesServices.findById(files);
String files_path=files1.getF_path();
String files_name=files1.getF_name();
//设置响应头MIME类型 获取文件的mime
//MIME映射策略就是在网页中使用哪个应用程序(即插件),打开哪种文件
//response.setContentType(MIME)的作用是使客户端浏览器,区分不同种类的数据,并根据不同的MIME调用浏览器内不同的程序嵌入模块来处理相应的数据。
response.setContentType(this.getServletContext().getMimeType(files1.getF_name()));
//User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。
//获得浏览器请求头中的User-Agent
String agents=request.getHeader("user-agent");
//判断浏览器的的不同对文件转码,文件名URL BASE64 重编码 IE 火狐
if(agents.contains("MSIE")){
//编码
files_name= URLEncoder.encode(files_name,"utf-8");
}else if(agents.contains("Firefox")){
files_name= Base64Util.base64EncodeFileName(files_name);
}else{
files_name=URLEncoder.encode(files_name,"utf-8");
}
//设置响应头下载附件格式 下载中文文件名乱码问题
response.setHeader( "Content-Disposition", "attachment; filename="+files_name);
//完成下载 先读取后写入
InputStream in= new FileInputStream((new File(files_path)));
//服务器给出响应 response
OutputStream out=response.getOutputStream();
byte b[]=new byte[1024*10];
int len=0;
while((len=in.read(b))!=-1){
//写入到浏览器默认的下载路径
out.write(b);
}
out.flush();
out.close();
in.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}