文件上传与下载之数据库实现
为了实现文件上传与下载的功能,我们把文件相关的信息封装到FileUploadDownload对象中,方便操作和管理文件的信息
private String id;
private Stringuuidname; //上传文件的名称,文件的uuid名
private String filename;//上传文件的真实名称
private Stringsavepath; //记住文件的位置
private Dateuploadtime; //文件的上传时间
private Stringdescription; //文件的描述
private String username;
文件相关信息对象:FileUploadDownload里的信息存在file表中
--数据库 建库建表语句
create database fileChange;
use fileChange;
create table file(
id varchar(100) primary key,
uuidname varchar(100),
filename varchar(100),
savepath varchar(100),
uploadtime Timestamp,
description varchar(100),
username varchar(30)
组织包结构 , 导入jar包, javabean, 工具类
Beanutils(2个jar)+c3p0(1jar,1配置文件)+dbutils(1个jar)+ mysql驱动(1个)+commons-fileupload(2jar)
访问index.jsp页面,选择上传文件或者查看文件列表
(1)选择上传文件
此时跳转访问上传表单页面upload.jsp,然后用户自己选择上传文件,并填写相关信息,然后提交表单;(页面)
提交表单之后,访问UploadServlet,UploadServlet通过调用工具类WebUtils,进行上传文件,并且获得上传文件信息;(web层)
然后web层调用service层【FileService】的insert方法,进行保存文件相关的信息;(service层)
最后,service层【FileService】通过调用dao层的insert方法进行插入。至此,上传完成(dao层)
注意:此处的dao层与service是进行了解耦合的,通过
FileDao(dao接口)+FileDaoFactory (dao工厂)+ FileDaoImpl (dao实现类)+dao.properties(dao配置文件) 完成解耦合。
service实际上调用的FileDaoFactory(dao工厂)的静态方法,加上反射技术和配置文件的引用,使得dao工厂读取配置文件就可以创建dao接口对应的实现类的实例。从而实现解耦合的操作。
(2)选择查看文件列表
此时跳转访问ListFileServlet(web层),然后调用service层的list方法,最后调用dao层的list方法,返回文件查询列表,保存并显示在 listFile.jsp页面,
然后用户根据自己的需要,选择自己要下载的文件,点击文件名进行下载,跳转访问DownloadServlet(层),通过先后调用service层和dao层的select(id)方法看看要下载的文件是否存在,如果不存在,则进行提示;如果存在,则进行下载文件
<%@ page language="java" import="java.util.*"pageEncoding="UTF-8"%>
上传文件
查询文件
<%@ page language="java" import="java.util.*"pageEncoding="UTF-8"%>
文件上传
<%@ page language="java" import="java.util.*"pageEncoding="UTF-8"%>
${message }
package file.web;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import file.domain.FileUploadDownload;
import file.service.FileService;
import file.utils.WebUtils;
public class UploadServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if (!ServletFileUpload.isMultipartContent(request)) {
request.setAttribute("message", "不是请求的信息表单,请确认表单属性是否正确");
request.getRequestDispatcher("/message.jsp").forward(request,
response);
return;
}
try {
//调用工具类,获得上传文件信息
FileUploadDownload fud=WebUtils.doFileUpload(request);
FileService service=new FileService();
service.insert(fud);//保存上传文件信息
request.setAttribute("message", "上传文件成功");
request.getRequestDispatcher("/message.jsp").forward(request,response);
} catch (FileSizeLimitExceededException e) {
request.setAttribute("message", "对不起,您上传的文件大小超过了大小的限制");
request.getRequestDispatcher("/message.jsp").forward(request,response);
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
package file.service;
import java.util.List;
import file.dao.FileDao;
import file.daoFactory.FileDaoFactory;
import file.domain.FileUploadDownload;
//上传文件的业务层
public class FileService {
//FileDaoImpl实现类实例
FileDao f= FileDaoFactory.getInstance().createDao(FileDao.class);
//上传文件
public void insert(FileUploadDownload fud) {
f.insert(fud);//调用dao层进行添加
}
//查询文件
public List list() {
List list=f.list();
return list;
}
//通过id获得文件对象的全部信息
public FileUploadDownload select(String id) {
FileUploadDownload fud=f.select(id);
return fud;
}
}
package file.dao;
import java.util.List;
import file.domain.FileUploadDownload;
//dao接口
public interface FileDao {
public void insert(FileUploadDownload fud);//上传文件
public List list();//查询文件
public FileUploadDownload select(String id);//通过id获得文件的全部信息
}
package file.daoFactory;
import java.util.ResourceBundle;
//dao工厂
public class FileDaoFactory {
private FileDaoFactory(){};//不能构造
private static FileDaoFactory factory=new FileDaoFactory();
//获取工厂实例
public static FileDaoFactory getInstance(){
return factory;
}
//用于返回传进来的一个类的实例对象
/*
* 1、传进来FileDao.class
* 2、读取dao.properties文件,获取FileDao对应的实现类
* 3、FileDao对应的实现类实例
*/
public T createDao(Class t){
//1、FileDao.class-->FileDao
String simpleName=t.getSimpleName();
//2、读取配置文件,获取FileDao对应的实现类
//FileDao=file.daoImpl.FileDaoImpl
String calzzName=ResourceBundle.getBundle("dao").getString(simpleName);
try {
//3、FileDao对应的实现类实例
T instance=(T) Class.forName(calzzName).newInstance();
return instance;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
package file.daoImpl;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import file.dao.FileDao;
import file.domain.FileUploadDownload;
import file.utils.JDBCUtils;
//dao实现类
public class FileDaoImpl implements FileDao {
QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
@Override
public void insert(FileUploadDownload fud) {// 上传文件
/*
*
* private String id; private String uuidname; //上传文件的名称,文件的uuid名
* private String filename; //上传文件的真实名称 private String savepath;
* //记住文件的位置 private Date uploadtime; //文件的上传时间 private String
* description; //文件的描述 private String username;
*/
Object[] param = { fud.getId(), fud.getUuidname(), fud.getFilename(),
fud.getSavepath(), fud.getDescription(), fud.getUsername() };// 没有时间:fud.getUploadtime()
try {
qr.update("insert into file values(?,?,?,?,null,?,?)", param);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public List list() {// 查询文件
try {
List list = qr.query("select * from file",
new BeanListHandler(FileUploadDownload.class));
return list;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
@Override
public FileUploadDownload select(String id) {//通过id获得文件的全部信息
try {
FileUploadDownload fud=qr.query("select * from file where id=?",new BeanHandler(FileUploadDownload.class),id);
return fud;
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
}
FileDao=file.daoImpl.FileDaoImpl
package file.utils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import file.domain.FileUploadDownload;
/*
* 上传文件的工具类
*/
public class WebUtils {
public static FileUploadDownload doFileUpload(HttpServletRequest request) throws FileSizeLimitExceededException {
FileUploadDownload fud = new FileUploadDownload();// 文件信息对象
try {
DiskFileItemFactory factory = new DiskFileItemFactory();
// 临时文件夹temp
factory.setRepository(new File(request.getSession().getServletContext().getContextPath()+"/temp"));
// factory.setRepository(new File("/temp"));// 临时文件夹temp
factory.setSizeThreshold(1024 * 1024);// 临时缓冲区大小为1M
ServletFileUpload parse = new ServletFileUpload(factory);// 解析器
//上传文件大小
parse.setFileSizeMax(1024 * 1024 * 2);// 单个文件大小限制为2M
parse.setSizeMax(1024 * 1024 * 20);// 总的文件大小限制为20M
//解决中文文件名的乱码
parse.setHeaderEncoding("utf-8");
List list = parse.parseRequest(request);
for (FileItem fileItem : list) {
// 普通表单
if (fileItem.isFormField()) {
String fieldName = fileItem.getFieldName();
// String value = fileItem.getString();
String value = fileItem.getString("utf-8");// 解决字段的中文乱码问题
System.out.println("fieldName:" + fieldName);
System.out.println("value:" + value);
// 将当前字段封装到fud对象中对应的字段中去
//普通字段都通过这个保存到fud中
BeanUtils.setProperty(fud, fieldName, value);
}
// 文件
else {
String filename = fileItem.getName();// 获取文件名
//文件名:aa.txt 与c:\a\b\c\aa.txt的处理 统一
int index=filename.lastIndexOf("\\");
if(index!=-1){
filename=filename.substring(index+1);
}
String realPath=request.getSession().getServletContext().getRealPath("/WEB_INF/upload");
//生成随机文件夹
String savePath=generateSavePath(realPath,filename);
//生成唯一的文件名
String uuidname=generateUUIDName(filename);
// 上传文件
InputStream in = fileItem.getInputStream();// 获取文件读取流
// OutputStream out = new FileOutputStream("d:/" + name);
//保存文件夹:savePath 唯一文件名:uuidname
OutputStream out = new FileOutputStream(new File(savePath,uuidname));
byte[] buf = new byte[1024];
int len = 0;
while ((len = in.read(buf)) != -1) {
out.write(buf, 0, len);
}
in.close();
out.close();
//删除临时文件
fileItem.delete();
fud.setFilename(filename);//文件名
fud.setUuidname(uuidname);//唯一文件名
fud.setSavepath(savePath);//保存路径
fud.setId(UUID.randomUUID().toString());//id
}
}
return fud;//返回文件信息封装对象
} catch (FileUploadBase.FileSizeLimitExceededException e) {
// e.printStackTrace();//仅仅只是打印异常错误信息
//使用失败,因为此处并没有response
// request.setAttribute("message", "对不起,您上传的文件大小超过了大小的限制");
// request.getRequestDispatcher("/message.jsp").forward(request,response);
//怎么办?
//抛出一个异常出去 实际上异常也是一个返回值
//抛异常【编译时异常 还是 运行时异常】
//编译时异常
throw e;//记得抛出异常要在方法中进行声明
}
catch(Exception e){
throw new RuntimeException(e);//抛出运行时异常
}
}
//生成唯一的文件名
private static String generateUUIDName(String filename) {
return UUID.randomUUID().toString()+"_"+filename;
}
//生成随机文件夹
private static String generateSavePath(String realPath, String filename) {
int hashCode=filename.hashCode();
//通过位运算,计算出一级和二级目录的数字
int first=hashCode & (0xf);//以及目录
int second=(hashCode>>4)&(0xf);//二级目录
String savePath=realPath+"/"+first+"/"+second;
File f=new File(savePath);
if(!f.exists()){
f.mkdirs();//创建多级目录
}
return savePath;//保存路径
}
}
package file.utils;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
/**
* 工具类 提供数据库连接池 和数据库连接
*
* @author zhanglei
*
*/
public class JDBCUtils {
private static DataSource dataSource = new ComboPooledDataSource();
public static DataSource getDataSource() {
return dataSource;
}
/**
* 当DBUtils需要手动控制事务时,调用该方法获得一个连接
*
* @return
* @throws SQLException
*/
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}
root
1234
com.mysql.jdbc.Driver
jdbc:mysql://localhost/fileChange?useSSL=false
UploadServlet
file.web.UploadServlet
ListFileServlet
file.web.ListFileServlet
DownloadServlet
file.web.DownloadServlet
UploadServlet
/upload
ListFileServlet
/listFile
DownloadServlet
/download
<%@ page language="java" import="java.util.*"pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core"prefix="c" %>
上传者 上传文件名 上传时间 文件位置 文件描述 下载
${file.username }
${file.filename }
${file.uploadtime }
${file.savepath }
${file.description }
下载
package file.web;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import file.domain.FileUploadDownload;
import file.service.FileService;
public class ListFileServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//查询显示所有的数据到页面
FileService service=new FileService();
List list=service.list();
request.setAttribute("list", list);//保留查询结果
request.getRequestDispatcher("/listFile.jsp").forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
其它service层和dao层代码,已经在3、上传代码中提供
package file.web;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import file.domain.FileUploadDownload;
import file.service.FileService;
public class DownloadServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//得到id参数
String id = request.getParameter("id");
FileService service=new FileService();
FileUploadDownload fud=service.select(id);//通过id获取文件相关信息
String path=fud.getSavepath();//保存路径
String uuidname=fud.getUuidname();//保存文件名
File f=new File(path,uuidname);//要下载的文件的存放位置 path/name
//健壮性判断
if(!f.exists()){
request.setAttribute("message", "对不起,当前文件已删除");
request.getRequestDispatcher("/message.jsp").forward(request, response);
}
//将中文的文件名编码后再放到http的响应头中去,编码之后浏览器收到后会自动解码
String filename=URLEncoder.encode(fud.getFilename(),"utf-8");
//设置参数,使得浏览器可以以下载的方式打开文件。
response.setHeader("content-disposition", "attachement;filename="+filename);
//将要下载的文件当做一个inputStream读取进来
InputStream in=new FileInputStream(f);
//读进来后,再写到response.getOutputStream()去就可以了
//相应的数据
OutputStream out=response.getOutputStream();
byte[] buf=new byte[1024];
int len=0;
while((len=in.read(buf))!=-1){
out.write(buf, 0, len);
}
in.close();
out.close();
System.out.println("下载文件成功");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
其它service层和dao层代码,已经在3、上传代码中提供
可看本人的github项目地址:
https://github.com/Forever99/file_upload_download