文件上传与下载之数据库实现

文件上传与下载之数据库实现

一、Javabean与数据库设计

1、javabean设计

为了实现文件上传与下载的功能,我们把文件相关的信息封装到FileUploadDownload对象中,方便操作和管理文件的信息

private String id;

private Stringuuidname;  //上传文件的名称,文件的uuid名

private String filename;//上传文件的真实名称

private Stringsavepath;     //记住文件的位置

private Dateuploadtime;     //文件的上传时间

private Stringdescription;  //文件的描述

private String username;

2、数据库fileChange与表file

文件相关信息对象: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, 工具类

 

(1)组织包结构:

文件上传与下载之数据库实现_第1张图片

 

(2)导入jar包:

Beanutils(2个jar)+c3p0(1jar,1配置文件)+dbutils(1个jar)+ mysql驱动(1个)+commons-fileupload(2jar)

 文件上传与下载之数据库实现_第2张图片

(3)Javabean:

三、项目代码实现

1、项目使用说明

访问index.jsp页面,选择上传文件或者查看文件列表

(1)选择上传文件

   此时跳转访问上传表单页面upload.jsp,然后用户自己选择上传文件,并填写相关信息,然后提交表单;(页面)

提交表单之后,访问UploadServlet,UploadServlet通过调用工具类WebUtils,进行上传文件,并且获得上传文件信息;web层)

然后web层调用service层【FileService】的insert方法,进行保存文件相关的信息;service层)

最后,service层【FileService】通过调用dao层的insert方法进行插入。至此,上传完成dao层)

注意:此处的dao层与service是进行了解耦合的,通过

FileDaodao接口)+FileDaoFactory dao工厂)+ FileDaoImpl dao实现类)+dao.propertiesdao配置文件) 完成解耦合。

service实际上调用的FileDaoFactory(dao工厂)的静态方法,加上反射技术和配置文件的引用,使得dao工厂读取配置文件就可以创建dao接口对应的实现类的实例。从而实现解耦合的操作。

 

(2)选择查看文件列表

此时跳转访问ListFileServlet(web层),然后调用service层的list方法,最后调用dao层的list方法,返回文件查询列表,保存并显示在 listFile.jsp页面,

 

然后用户根据自己的需要,选择自己要下载的文件,点击文件名进行下载,跳转访问DownloadServlet(层),通过先后调用service层和dao层的select(id)方法看看要下载的文件是否存在,如果不存在,则进行提示;如果存在,则进行下载文件

2、项目结构图

文件上传与下载之数据库实现_第3张图片

文件上传与下载之数据库实现_第4张图片

3、上传代码

(1)页面:index.jsp+upload.jsp+message.jsp

【1】index.jsp            

<%@ page language="java" import="java.util.*"pageEncoding="UTF-8"%>


  
  
 
  


      上传文件
查询文件

【2】upload.jsp

<%@ page language="java" import="java.util.*"pageEncoding="UTF-8"%>


  
 
  
 
  
 

文件上传

上传文件名
上传者
上传描述

【3】message.jsp

<%@ page language="java" import="java.util.*"pageEncoding="UTF-8"%>


  
 
  
 
  
    ${message }
  

 

(2)web层: UploadServlet

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);

	}

}

(3)service层:FileService

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;
	}

}

(4)dao层:FileDao+FileDaoFactory+FileDaoImpl+ dao.properties

【1】FileDao

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获得文件的全部信息
}

【2】FileDaoFactory

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;
		}
	}
}

【3】FileDaoImpl

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;
		}
	}
}

【4】dao.properties

FileDao=file.daoImpl.FileDaoImpl

(5)上传工具类:WebUtils

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;//保存路径
	}
}


(6)数据库相关:JDBCUtils工具类+c3p0-config.xml配置文件【通用】

【1】JDBCUtils工具类

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();
	}
}


【2】c3p0-config.xml配置文件



   
      root
      1234
      com.mysql.jdbc.Driver
      jdbc:mysql://localhost/fileChange?useSSL=false
    

(7)web配置文件web.xml【通用】



  
    UploadServlet
    file.web.UploadServlet
  
  
    ListFileServlet
    file.web.ListFileServlet
  
  
    DownloadServlet
    file.web.DownloadServlet
  
 
 
 
  
    UploadServlet
    /upload
  
  
    ListFileServlet
    /listFile
  
  
    DownloadServlet
    /download
  
 


4、查询文件代码

(1)页面(查询文件结果显示):ListFile.jsp

<%@ 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 } 下载

(2)web层:ListFileServlet

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);

	}

}

(3)说明   

其它service层和dao层代码,已经在3、上传代码中提供

5、下载文件代码

(1)web层:DownloadServlet

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);

	}

}

(2)说明   

其它service层和dao层代码,已经在3、上传代码中提供

四、项目效果图

1、主页

文件上传与下载之数据库实现_第5张图片

2、上传文件

文件上传与下载之数据库实现_第6张图片

3、查询和下载文件

文件上传与下载之数据库实现_第7张图片

4、下载文件

文件上传与下载之数据库实现_第8张图片

五、实现源码

可看本人的github项目地址:

https://github.com/Forever99/file_upload_download

 

你可能感兴趣的:(javaWeb学习案例实现)