说明位于src类下面
javaweb工程:上传下载案例
1,导包:共10个
mysql驱动
mysql-connector-java-5.0.8-bin.jar
c3po连接池
c3p0-0.9.2-pre1.jar
mchange-commons-0.2.jar
dbutils操作数据库
commons-dbutils-1.2.jar
jstl开发库
jstl.jar
standard.jar
beanUtils开发包及其依赖的log4j开发包
commons-beanutils-1.8.0.jar
commons-logging.jar
fileupload组件及其依赖的IO包
commons-fileupload-1.2.1.jar
commons-io-1.4.jar
2 创建组织程序的包
3 准备库和表
mysql -uroot -proot
set character_set_client=gb2312;
set character_set_results=gb2312;
create database day18 character set utf8 collate utf8_general_ci;
use day18;
create table upfile
(
id varchar(40) primary key, 使用UUID算法生成(36位),便于扩展
uuidname varchar(100) not null unique, 形如X-X-X-X.txt
filename varchar(100) not null, 形如a.txt
savepath varchar(255) not null, 形如C:\...\day18_upload\WEB-INF\upload\15\4
uptime datetime not null,
description varchar(255),
username varchar(40) not null 通常应该是外键列
)character set utf8 collate utf8_general_ci;
2.做实体
domain包下Upfile类代表实体
成员:String id,uuidname,filename,savepath,Date uptime,decription,username,getter&setter
3.做dao(为与service解耦,工厂模式)
dao.impl包UpfileDaoImpl
方法:void add(Upfile)
方法:List<Upfile> getAll()实际开发要用分页完成
方法:Upfile find(id)
方法:void update(Upfile)
方法:void delete(id)
3.1用DbUtils简化开发,QueryRunner构造时需要连接池DataSource
建个工具类JdbcUtils提供C3P0根据配置文件c3p0-config.xml生成的连接池
4.做DaoFactory(为与service解耦,工厂模式)
在factory包下建一个DaoFactory
单例:构造私有化,自已new,提供公开方法获取
读配置文件 dao.properties
#key是接口的simpleName,value是实现类的完整名称
UpfileDao=cn.itcast.dao.impl.UpfileDaoImpl
泛型方法public <T> T createDao(Class<T> interfaceClass)
5.做service层
薄薄的业务层,内部维护了一个私有成员dao,
所有功能调用dao工厂产生的dao实现类的实例完成
6.做web层(从index.jsp开始)
request.getContextPath();
/day18_upload
request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
http://localhost:8080/day18_upload/
dao.properties位于src类下面
#key是接口的simpleName,value是实现类的完整名称
UpfileDao=cn.itcast.dao.impl.UpfileDaoImpl
c3p0-config.xml位于src类下面
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/day18</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</default-config>
<named-config name="pre_eminent">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/day18</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</named-config>
</c3p0-config>
Upfile位于domain包
package cn.itcast.domain;
import java.util.Date;
/*mysql -uroot -proot
set character_set_client=gb2312;
set character_set_results=gb2312;
create database day18 character set utf8 collate utf8_general_ci;
use day18;
create table upfile
(
id varchar(40) primary key, 使用UUID算法生成(36位),便于扩展
uuidname varchar(100) not null unique, 形如X-X-X-X.txt
filename varchar(100) not null, 形如a.txt
savepath varchar(255) not null, 形如C:\\...\\day18_upload\\WEB-INF\\upload\\15\\4
uptime datetime not null,
description varchar(255),
username varchar(40) not null 通常应该是外键列
)character set utf8 collate utf8_general_ci;*/
//成员:String id,uuidname,filename,savepath,Date uptime,decription,username,getter&setter
public class Upfile {
String id;
String uuidname;
String filename;
String savepath;
Date uptime;
String description;
String username;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUuidname() {
return uuidname;
}
public void setUuidname(String uuidname) {
this.uuidname = uuidname;
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public String getSavepath() {
return savepath;
}
public void setSavepath(String savepath) {
this.savepath = savepath;
}
public Date getUptime() {
return uptime;
}
public void setUptime(Date uptime) {
this.uptime = uptime;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
JdbcUtils位于utils包
package cn.itcast.utils;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
/*用DbUtils简化开发,QueryRunner构造时需要连接池DataSource
建个工具类JdbcUtils提供C3P0根据配置文件c3p0-config.xml生成的连接池
下面是关于删除时,工具类提供的方法
1,定义一个成员!线程局部 (thread-local) 变量
2,提供获取(绑定在当前线程上的)连接的方法
3,提供(绑定在当前线程上的连接的)开启事务的方法
4,提供(绑定在当前线程上的连接的)提交事务的方法
5,提供释放连接(并从当前线程中移除该连接)的方法*/
public class JdbcUtils {
//线程局部 (thread-local) 变量
private static ThreadLocal<Connection> threadLocal=new ThreadLocal<Connection>();
//定义成员DataSource记住C3P0创建出来的数据源(即连接池)
private static DataSource ds;
static{
//用类成员DataSource记住根据配置文件创建出来的连接池!
ds=new ComboPooledDataSource();
}
public static DataSource getDataSource(){
return ds;
}
// 事务方法1:获取绑定在当前线程上的连接!
//如果没有,从池中取出一个绑定到当前线程!
public static Connection getConnection() {
Connection conn;
try {
//本方法的目的是:得到当前线程上绑定的连接
conn=threadLocal.get();
if (conn==null) {
//如果当前线程上还没有绑定连接(如线程范围内的首次获取)
//就从DBCP连接池中取出一个连接,并绑定到当前线程上,供线程上后面的dao使用!
conn=ds.getConnection();
threadLocal.set(conn);
}
//返回绑定在当前线程的连接,目的达到!
return conn;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
//ThreadLocal处理事务,静态方法2:开启事务
//获得当前线程上绑定的连接,并开启事务
public static void startTransaction() {
Connection conn;
conn=JdbcUtils.getConnection();
try {
//此时当前线程上必定绑定了连接,开启事务!
conn.setAutoCommit(false);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
//ThreadLocal处理事务,静态方法3:提交事务
public static void commitTransaction() {
//获得当前线程上绑定的连接,并提交事务
Connection conn;
conn=JdbcUtils.getConnection();
try {
//得到当前线程上绑定的连接并提交事务
conn.commit();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
//ThreadLocal处理事务,静态方法3:关闭连接,并解除绑定!千万注意!
//释放当前线程上绑定的连接,即归还给连接池!
public static void freeConnection() {
Connection conn;
conn=JdbcUtils.getConnection();
try {
conn.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}finally{
//千万记得关闭连接时,要解除线程上绑定的连接
//从threadlocal容器(map<线程名,连接>)中移除对应当前线程的连接
threadLocal.remove();
}
}
}
UpfileDaoImpl位于dao.impl包
package cn.itcast.dao.impl;
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 cn.itcast.dao.UpfileDao;
import cn.itcast.domain.Upfile;
import cn.itcast.exception.DaoException;
import cn.itcast.utils.JdbcUtils;
/*做dao(为与service解耦,工厂模式
dao.impl包UpfileDaoImpl
方法:void add(Upfile)
方法:List<Upfile> getAll()实际开发要用分页完成
方法:Upfile find(id)
方法:void update(Upfile)
方法:void delete(id)
3.1用DbUtils简化开发,QueryRunner构造时需要连接池DataSource
建个工具类JdbcUtils提供连接池*/
/*库和表
mysql -uroot -proot
set character_set_client=gb2312;
set character_set_results=gb2312;
create database day18 character set utf8 collate utf8_general_ci;
use day18;
create table upfile
(
id varchar(40) primary key, 使用UUID算法生成(36位),便于扩展
uuidname varchar(100) not null unique, 形如X-X-X-X.txt
filename varchar(100) not null, 形如a.txt
savepath varchar(255) not null, 形如C:\\...\\day18_upload\\WEB-INF\\upload\\15\\4
uptime datetime not null,
description varchar(255),
username varchar(40) not null 通常应该是外键列
)character set utf8 collate utf8_general_ci;*/
public class UpfileDaoImpl implements UpfileDao {
/* (non-Javadoc)
* @see cn.itcast.dao.impl.UpfileDao#add(cn.itcast.domain.Upfile)
*/
public void add(Upfile f){
//操作数据库,不管三七二十一,先new 个QueryRunner
QueryRunner qr=new QueryRunner(JdbcUtils.getDataSource());
String sql="insert into upfile(id,uuidname,filename,savepath,uptime,description,username) values(?,?,?,?,?,?,?)";
Object[] params={f.getId(),f.getUuidname(),f.getFilename(),f.getSavepath(),f.getUptime(),f.getDescription(),f.getUsername()};
try {
qr.update(sql, params);
} catch (SQLException e) {
//有异常,抓,抛自定义DAO异常
throw new DaoException(e);
}
}
/* (non-Javadoc)
* @see cn.itcast.dao.impl.UpfileDao#find(java.lang.String)
*/
public Upfile find(String id){
try {
//操作数据库,不管三七二十一,先new 个QueryRunner
QueryRunner qr=new QueryRunner(JdbcUtils.getDataSource());
String sql="select * from upfile where id=?";
return (Upfile) qr.query(sql, id, new BeanHandler(Upfile.class));
} catch (Exception e) {
//有异常,抓,抛自定义DAO异常
throw new DaoException(e);
}
}
//实际开发中,要用分而查询
/* (non-Javadoc)
* @see cn.itcast.dao.impl.UpfileDao#getAll()
*/
public List<Upfile> getAll(){
try {
//操作数据库,不管三七二十一,先new 个QueryRunner
QueryRunner qr=new QueryRunner(JdbcUtils.getDataSource());
//根据上传时间降序排列
String sql="select * from upfile order by uptime desc";
return (List<Upfile>) qr.query(sql, new BeanListHandler(Upfile.class));
} catch (Exception e) {
//有异常,抓,抛自定义DAO异常
throw new DaoException(e);
}
}
/* (non-Javadoc)
* @see cn.itcast.dao.impl.UpfileDao#update(cn.itcast.domain.Upfile)
*/
public void update(Upfile f){
//操作数据库,不管三七二十一,先new 个QueryRunner
QueryRunner qr=new QueryRunner(JdbcUtils.getDataSource());
String sql="update upfile set uuidname=?,filename=?,savepath=?,uptime=?,description=?,username=? where id=?";
Object[] params={f.getUuidname(),f.getFilename(),f.getSavepath(),f.getUptime(),f.getDescription(),f.getUsername(),f.getId()};
try {
qr.update(sql, params);
} catch (SQLException e) {
//有异常,抓,抛自定义DAO异常
throw new DaoException(e);
}
}
//因为删除记录和删除文件是同一个事务里面的!
//所以删除操作 必须使用JdbcUtils获取连接!
//即JdbcUtils获取绑定在当前线程上的连接!如果没有,从池中取出一个绑定到当前线程!
public void delete(String id){
try {
//操作数据库,不管三七二十一,先new 个QueryRunner
//new的时候,不能传连接池给它了,因后面要自己控制事务提交
QueryRunner qr=new QueryRunner();
String sql="delete from upfile where id=?";
qr.update(JdbcUtils.getConnection(), sql, id);
} catch (Exception e) {
//有异常,抓,抛自定义DAO异常
throw new DaoException(e);
}
}
}
UpfileDao位于dao包
package cn.itcast.dao;
import java.util.List;
import cn.itcast.domain.Upfile;
public interface UpfileDao {
public abstract void add(Upfile f);
public abstract Upfile find(String id);
//实际开发中,要用分而查询
public abstract List<Upfile> getAll();
public abstract void update(Upfile f);
public abstract void delete(String id);
}
DaoFactory位于factory包
package cn.itcast.factory;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import cn.itcast.exception.DaoException;
/*为与service解耦,工厂模式)
在factory包下建一个DaoFactory
单例:构造私有化,自已new,提供公开方法获取
读配置文件 dao.properties
#key是接口的simpleName,value是实现类的完整名称
UpfileDao=cn.itcast.dao.impl.UpfileDaoImpl
泛型方法public <T> T createDao(Class<T> interfaceClass)*/
public class DaoFactory {
//1单例
private DaoFactory(){ };
private static final DaoFactory instance=new DaoFactory();
public static DaoFactory getInstance(){
return instance;
}
//2读配置
private static Properties pro=new Properties();
static{
InputStream in=DaoFactory.class.getClassLoader().getResourceAsStream("dao.properties");
try {
pro.load(in);
} catch (IOException e) {
// 静态代码块中异常只可抓后转型
throw new DaoException(e);
}
}
//3泛型方法(重点)
public <T> T createDao(Class<T> interfaceClass){
String key=interfaceClass.getSimpleName();
String value=pro.getProperty(key);
try {
return (T) Class.forName(value).newInstance();
} catch (Exception e) {
throw new DaoException(e);
}
}
}
BusinessServiceImpl位于service.impl包
package cn.itcast.service.impl;
import java.io.File;
import java.util.List;
import cn.itcast.dao.UpfileDao;
import cn.itcast.domain.Upfile;
import cn.itcast.factory.DaoFactory;
import cn.itcast.service.BusinessService;
import cn.itcast.utils.JdbcUtils;
public class BusinessServiceImpl implements BusinessService {
//薄薄的业务层,内部维护了一个私有成员dao,
//所有功能调用dao工厂产生的dao实现类的实例完成
private UpfileDao dao=DaoFactory.getInstance().createDao(UpfileDao.class);
public void addUpfile(Upfile f){
dao.add(f);
}
public List<Upfile> getAllUpfile(){
return dao.getAll();
}
public Upfile findUpfile(String id){
return dao.find(id);
}
public void updateUpfile(Upfile f){
dao.update(f);
}
//重点是删除记录和文件!
//service业务层(通过工具类JdbcUtils)负责:开启事务,提交事务,释放连接!
//dao删除时通过JdbcUtils获取线程上绑定的连接
public void deleteUpfile(String id){
//1,开启事务
JdbcUtils.startTransaction();
//2,删除记录
dao.delete(id);
//int i=1/0;
//3,删除文件
Upfile f=dao.find(id);
File file=new File(f.getSavepath()+File.separator+f.getUuidname());
if(file.exists()){
file.delete();
}
//4,全部删除时,才提交事务
JdbcUtils.commitTransaction();
//5,千万记得释放连接和从ThreadLocal中移除连接
JdbcUtils.freeConnection();
}
}
BusinessService位于service包
package cn.itcast.service;
import java.util.List;
import cn.itcast.domain.Upfile;
public interface BusinessService {
public abstract void addUpfile(Upfile f);
public abstract List<Upfile> getAllUpfile();
public abstract Upfile findUpfile(String id);
public abstract void updateUpfile(Upfile f);
public abstract void deleteUpfile(String id);
}
DaoException位于exception包
package cn.itcast.exception;
public class DaoException extends RuntimeException {
public DaoException() {
super();
}
public DaoException(String message, Throwable cause) {
super(message, cause);
}
public DaoException(String message) {
super(message);
}
public DaoException(Throwable cause) {
super(cause);
}
}
NoFileWebException位于exception包
package cn.itcast.exception;
import java.io.PrintStream;
import java.io.PrintWriter;
public class NoFileWebException extends Exception {
public NoFileWebException() {
super();
}
public NoFileWebException(String message, Throwable cause) {
super(message, cause);
}
public NoFileWebException(String message) {
super(message);
}
public NoFileWebException(Throwable cause) {
super(cause);
}
}
UnSupportedFileWebException位于exception包
package cn.itcast.exception;
public class UnSupportedFileWebException extends Exception {
public UnSupportedFileWebException() {
super();
}
public UnSupportedFileWebException(String message, Throwable cause) {
super(message, cause);
}
public UnSupportedFileWebException(String message) {
super(message);
}
public UnSupportedFileWebException(Throwable cause) {
super(cause);
}
}
WebUtils位于utils包
package cn.itcast.utils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Date;
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.FileUploadException;
import org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import cn.itcast.domain.Upfile;
import cn.itcast.exception.NoFileWebException;
import cn.itcast.exception.UnSupportedFileWebException;
/*WebUtils将是整个案例的重点!
首先是简单步骤,处理上传文件数据
第1步,首先new 一个未经过配置的工厂实例DiskFileItemFactory
第2步,用提供的工厂创建一个解析上传文件的解析器实例ServletFileUpload!!
第3步,用解析器的parseRequest方法,解析request中提交的数据
每个表单项都封装成一个FileItem对象,加入list集合!
第4步,迭代list集合
第5步,isFormField判断普通字段还是上传字段
如果是上传字段getInputStream,一顿狂写
下面是详细地处理上传文件过程~注意各类细节问题~*/
public class WebUtils {
//参数中父路径诸如:\\WEB-INF\\upload
public static Upfile doUpload(HttpServletRequest request, String parentPath) throws UnSupportedFileWebException,FileUploadException, UnsupportedEncodingException, IllegalAccessException, InvocationTargetException, NoFileWebException{
Upfile bean=new Upfile();
try{
List<String> types=Arrays.asList("jpg","bmp","gif","png","txt","avi","pdf","mkv","mp3");
DiskFileItemFactory factory=new DiskFileItemFactory();
//重点一句,获取并创建临时目录
String tempStr=request.getSession().getServletContext().getRealPath("/WEB-INF/temp");
File temp=new File(tempStr);
if (!temp.exists()) {
temp.mkdirs();
}
ServletFileUpload upload=new ServletFileUpload(factory);
//设置允许上传的文件大小,FileSizeLimitExceededException
//如果超过会抛异常,工具类必须抓住,原样转抛
upload.setFileSizeMax(1024*1024*50);
//细节:在解析request之前,必须先解决上传文件名的中文乱码问题
upload.setHeaderEncoding("UTF-8");
List<FileItem> list=upload.parseRequest(request);
for (FileItem item : list) {
if (item.isFormField()) {
//username=aaa description=bbb
String fieldName=item.getFieldName();
//或者手动转fieldValue=new String(fieldValue.getBytes("iso8859-1"),"utf-8");
String fieldValue=item.getString("utf-8");
//将表单的值封装到bean里面去,需要提前准备好一个Bean
//已封装好2个:username,description,
BeanUtils.setProperty(bean, fieldName, fieldValue);
} else {
//如果表单项是file,用个流关联,狂读写
//1,getName先得到上传文件原始名filename称形如a.txt
//注意getName是针对上传文件,取其文件名的
// item.getName() 如果是IE6 C:\Documents and Settings\Admin\桌面\a.txt
// item.getName() 如果是IE7 a.txt
//得到上传文件名(向下兼容IE6)A.TXT(这个数据库中专门有一个列存原始名称)
String filename=item.getName();
filename=filename.substring(filename.lastIndexOf("\\")+1);
if (filename==null || "".equals(filename.trim())) {
//如果文件名是空的,抛异常给service
throw new NoFileWebException();
}
//1.1,判断后缀是否允许!
String ext=filename.substring(filename.lastIndexOf(".")+1);
if(!types.contains(ext)){
throw new UnSupportedFileWebException();
}
//2,用UUID算法,生成uuidname(不含原始文件名,只取其后缀)如X-X-X-X.txt
//得到文件的保存名称X-X-X.TXT
String uuidname=generateUUIDName(filename);
//3,根据uuidname的哈希值(如X-X-X-X.txt)和父路径,
//生成savepath:C:\\...\\day18_upload\\WEB-INF\\upload\\15\\4
//得到文件的保存路径\\upload\\4\\3
String savepath=generateSavePath(parentPath,uuidname);
//4,根据savepath和uuidname组成目的地,一顿狂读写
InputStream in = null;
OutputStream out = null;
try {
in=item.getInputStream();
// \\upload\\4\\3X-X-X.TXT
out=new FileOutputStream(savepath+File.separator+uuidname);
byte[] buf = new byte[1024];
int len = 0;
while ((len = in.read(buf)) != -1) {
out.write(buf, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
throw new RuntimeException("in关闭失败!");
}
in = null;
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
throw new RuntimeException("out关闭失败!");
}
out = null;
}
//删除临时文件:在程序中处理完上传文件后,
//一定要记得调用item.delete()方法,以删除临时文件
//必须是在关闭流之后,finally代码块中,确保删除成功!
item.delete(); //虽然有时会自动删除临时文件
}
//将文件写入磁盘之后,封装所有信息,返回bean
//前面普通表单已经封装两列:username,description
//ID,考虑 到与其他表合并,所有用唯一ID
bean.setId(UUID.randomUUID().toString());
// x-x-x.txt
bean.setUuidname(uuidname);//X-X-X-X.txt
//A.TXT(这个数据库中专门有一个列存原始名称)
bean.setFilename(filename);//a.txt
// /upload/4/3
bean.setSavepath(savepath);//C:\\...\\day18_upload\\WEB-INF\\upload\\15\\4
bean.setUptime(new Date());
}
}
}catch(FileSizeLimitExceededException e){
throw e;
}
return bean;
}
private static String generateSavePath(String parentPath, String uuidname) {
//根据uuidname的哈希值(如X-X-X-X.txt)和父路径,
//生成savepath:C:\\...\\day18_upload\\WEB-INF\\upload\\15\\4
//别忘记健壮性判断
int hashCode=uuidname.hashCode();
int dir1=hashCode&15;
int dir2=(hashCode>>4)&15;
String savepath=parentPath+File.separator+dir1+File.separator+dir2;
File file=new File(savepath);
if (!file.exists()) {
file.mkdirs();
}
return savepath;
}
private static String generateUUIDName(String filename) {
//用UUID算法,生成uuidname(不含原始文件名,只取其后缀)如X-X-X-X.txt
//因为专门有一列存UUID名,还有一列专门存原始文件名,a.txt
//所以不需要原始文件名,只需要加后缀
String ext=filename.substring(filename.lastIndexOf("."));
return UUID.randomUUID().toString()+ext;
}
}
UpfileServlet位于web.controller包
package cn.itcast.web.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import cn.itcast.domain.Upfile;
import cn.itcast.exception.NoFileWebException;
import cn.itcast.exception.UnSupportedFileWebException;
import cn.itcast.service.BusinessService;
import cn.itcast.service.impl.BusinessServiceImpl;
import cn.itcast.utils.WebUtils;
public class UpfileServlet extends HttpServlet {
//doGet处理首页发来的上传文件请求,生成一个表单页面,给用户上传
//doGet处理生成显示上传页面,并跳转到jsp,
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.getRequestDispatcher("/WEB-INF/jsp/addfile.jsp").forward(request, response);
return;
}
//正式处理上传的Post请求
//doPost处理上传表单页面发来的Post文件上传,并告诉用户是否上传成功
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//这儿将是整个案例的重点!
//首先判断是不是文件上传,以防万一
if (!ServletFileUpload.isMultipartContent(request)) {
request.setAttribute("message", "非法提交");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}
try {
//如果是文件上传,简化书写,
//使用一个WebUtils工具类完成处理文件上传相关细节
String parentPath=this.getServletContext().getRealPath("/WEB-INF/upload");
//工具处理后,返回一个封将好的Upfile对象(只允许单文件上传)
Upfile f=WebUtils.doUpload(request,parentPath);
//此处应该对f进行有效性校验~
//调用业务层:添加文件信息到数据库
BusinessService service=new BusinessServiceImpl();
service.addUpfile(f);
request.setAttribute("message", "文件上传成功");
}catch (NoFileWebException e) {
//明显知道是什么异常了,不需要记录
request.setAttribute("message", "不允许上传空文件");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}catch (UnSupportedFileWebException e) {
//明显知道是什么异常了,不需要记录
request.setAttribute("message", "不支持的文件类型");
} catch (FileSizeLimitExceededException e) {
//明显知道是什么异常了,不需要记录
request.setAttribute("message", "文件不能超过50M");
} catch (Exception e) {
e.printStackTrace();
request.setAttribute("message", "文件上传失败");
}
//无论上传成功或是失败都跳至全局消息显示页面
request.getRequestDispatcher("/message.jsp").forward(request, response);
}
}
ListAllfilesServlet位于web.controller包
package cn.itcast.web.controller;
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 cn.itcast.domain.Upfile;
import cn.itcast.service.BusinessService;
import cn.itcast.service.impl.BusinessServiceImpl;
public class ListAllfilesServlet extends HttpServlet {
//处理首页发来的GET请求,生成JSP页面,
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
BusinessService service=new BusinessServiceImpl();
List<Upfile> list=service.getAllUpfile();
request.setAttribute("list", list);
request.getRequestDispatcher("/WEB-INF/jsp/listfiles.jsp").forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
DownLoadFileServlet位于web.controller包
package cn.itcast.web.controller;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
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 cn.itcast.domain.Upfile;
import cn.itcast.service.BusinessService;
import cn.itcast.service.impl.BusinessServiceImpl;
public class DownLoadFileServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String id=request.getParameter("id");
BusinessService service=new BusinessServiceImpl();
Upfile f=service.findUpfile(id);
//首先健壮性判断
File file=new File(f.getSavepath()+File.separator+f.getUuidname());
if (!file.exists()) {
//存跳返
request.setAttribute("message", "对不起您访问的资源已被删除~");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}
//文件若存在,设置response头,解决文件名的乱码问题
response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(f.getFilename(),"utf-8"));
//这时,才read_b
InputStream in = null;
OutputStream out = null;
try {
in=new FileInputStream(file);
out=response.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while ((len = in.read(buf)) != -1) {
out.write(buf, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
throw new RuntimeException("in关闭失败!");
}
in = null;
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
throw new RuntimeException("out关闭失败!");
}
out = null;
}
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
DeleteFileServlet位于web.controller包
package cn.itcast.web.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.itcast.service.BusinessService;
import cn.itcast.service.impl.BusinessServiceImpl;
public class DeleteFileServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
//必须事务处理,先删除记录,后删除文件
//因为若发生意外,记录可以回滚
String id=request.getParameter("id");
BusinessService service=new BusinessServiceImpl();
//调用service层,删除记录和文件!重点是BusinessServiceImpl和JDBCUTILS
service.deleteUpfile(id);
request.setAttribute("message", "删除成功");
request.getRequestDispatcher("/message.jsp").forward(request, response);
} catch (Exception e) {
//出现异常不要紧,记录下来,并给友好提示!
e.printStackTrace();
request.setAttribute("message", "删除失败");
request.getRequestDispatcher("/message.jsp").forward(request,response);
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
//out.write("path:"+path);
//path:/day18_upload
//out.write("basePath:"+basePath);
//basePath:http://localhost:8080/day18_upload/
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>day18上传下载案例首页</title>
</head>
<frameset rows="30%,*">
<frame name="head" src="${pageContext.request.contextPath}/head.jsp">
<frame name="main" src="#">
</frameset>
</html>
head.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>head</title>
</head>
<body>
<a href="${pageContext.request.contextPath }/servlet/UpfileServlet" target="main">上传文件</a>
<a href="${pageContext.request.contextPath }/servlet/ListAllfilesServlet" target="main">列出所有文件</a>
</body>
</html>
addfile.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>添加上传文件页面</title>
</head>
<body style="text-align:center;">
<form action="${pageContext.request.contextPath }/servlet/UpfileServlet" method="post" enctype="multipart/form-data">
<table width="40%" frame="border">
<tr>
<td>上传用户</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>文件</td>
<td><input type="file" name="file_XXX"></td>
</tr>
<tr>
<td>描述信息</td>
<td><textarea cols="30" rows="5" name="description"></textarea></td>
</tr>
<tr>
<td>点击开始上传</td>
<td><input type="submit" value="开始上传"></td>
</tr>
</table>
</form>
</body>
</html>
listfiles.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>foreach迭代生成文件列表</title>
</head>
<body style="text-align: center;">
<table width="90%" frame="border">
<tr>
<td>文件名</td>
<td>上传者</td>
<td>文件描述</td>
<td>上传时间</td>
<td>操作</td>
</tr>
<c:forEach var="f" items="${list}">
<tr>
<td>${f.filename }</td>
<td>${f.username }</td>
<td>${f.description }</td>
<td>${f.uptime }</td>
<td>
<a href="${pageContext.request.contextPath }/servlet/DownLoadFileServlet?id=${f.id }">下载</a>
<a href="${pageContext.request.contextPath }/servlet/DeleteFileServlet?id=${f.id }">删除</a>
<a href="${pageContext.request.contextPath }/servlet/UpdateFileServlet">修改</a>
</td>
</tr>
</c:forEach>
</table>
</body>
</html>