说明位于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>