JavaWeb_14_文件上传下载_fileupload案例

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



  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: javaweb_cloud_elevue_pro微服务框架旗舰版源码是一套针对Java开发的微服务框架,该框架提供了一系列功能和组件,用于帮助开发者更轻松地构建和管理微服务架构。 该框架的源码是指该框架的具体实现代码,通过阅读源码,开发者可以深入了解框架的设计思想和实现细节,有助于更好地理解和使用该框架。 javaweb_cloud_elevue_pro微服务框架旗舰版源码的特点主要包括以下几点: 1. 模块化设计:源码采用模块化设计,将整个框架拆分成多个独立的模块,每个模块负责不同的功能,有利于代码的组织和维护。 2. 弹性扩展:框架采用了微服务架构,可以很方便地进行系统扩展,支持动态添加和移除服务实例,以适应不同的业务需求。 3. 高可用性:框架提供了集群和负载均衡的支持,可以提高系统的可用性和性能。 4. 分布式事务管理:源码包含了分布式事务管理的实现,可以保证系统在多节点环境下的数据一致性。 5. 可靠消息传递:框架提供了消息队列和分布式任务调度的功能,可以确保消息的可靠传递和任务的可靠执行。 6. 监控和管理:框架提供了丰富的监控和管理功能,可以对系统进行实时监控和管理,方便开发者进行故障排查和性能调优。 总之,javaweb_cloud_elevue_pro微服务框架旗舰版源码是一套成熟的微服务框架实现代码,通过研究源码,开发者可以更好地理解和使用该框架,提高开发效率和系统稳定性。 ### 回答2: javaweb_cloud_elevue_pro微服务框架是一款功能强大的微服务开发框架,是javaweb_cloud_elevue_pro产品家族中的旗舰版。 该框架的源码提供了一套完整的微服务解决方案,包含了丰富的功能模块和技术组件,可用于构建高性能、稳定可靠的分布式系统。 源码中包含了一系列核心组件,如服务注册与发现、负载均衡、熔断降级、分布式配置中心等,这些组件可以快速搭建起一个具有高可用性和可伸缩性的微服务架构。 此外,框架的源码还提供了一套易用的开发工具和开发规范,使开发者能够快速上手并高效地开发微服务应用。开发者可以根据自己的业务需求,选择合适的组件和模块进行使用,从而实现个性化的定制和扩展。 与其他微服务框架相比,javaweb_cloud_elevue_pro微服务框架的源码具有以下特点: 1. 高性能:框架使用了一系列优化的算法和技术,能够实现高效的请求处理和资源利用,保证系统的稳定和可靠。 2. 可扩展:源码提供了丰富的扩展接口和插件机制,开发者可以根据自己的需求进行个性化的扩展和定制。 3. 易用性:框架的源码结构清晰,文档详细,附带了示例和教程,使开发者能够快速理解和掌握框架的使用方法。 4. 社区支持:javaweb_cloud_elevue_pro框架拥有一个活跃的社区,开发者可以在社区中获取帮助、交流经验,并参与框架的改进和贡献。 总之,javaweb_cloud_elevue_pro微服务框架旗舰版源码提供了一个完整的微服务解决方案和一套易用的开发工具,可帮助开发者快速构建高性能、稳定可靠的分布式系统。它是微服务领域中的佼佼者,值得开发者深入研究和使用。 ### 回答3: javaweb_cloud_elevue_pro微服务框架旗舰版源码是一套用于构建微服务架构的开源代码。该框架旨在提供一种简单、高效的方式来搭建和管理分布式系统。 该框架基于Java语言,采用了云计算、分布式计算和微服务架构的设计理念,提供了一套完整的解决方案来构建和管理分布式应用。 该框架具有以下特点: 1. 架构灵活:框架提供了一套灵活的架构设计,可以根据业务需求进行扩展和定制。 2. 模块化设计:框架采用模块化设计,各个微服务模块之间可以独立部署和调用,实现了高内聚、低耦合的分布式系统。 3. 高可用性:框架支持负载均衡、容错和故障恢复等机制,保证了系统的高可用性和容错性。 4. 弹性扩展:框架支持水平扩展,可以根据需求动态增加或减少服务实例,实现了系统的弹性扩展和负载均衡。 5. 服务治理:框架提供了服务注册与发现、负载均衡、熔断器等功能,实现了对微服务的有效治理和管理。 6. 高性能:框架采用了高性能、高并发的设计和优化策略,提升了系统的性能和扩展能力。 总体而言,javaweb_cloud_elevue_pro微服务框架旗舰版源码是一套功能强大、灵活可扩展的微服务架构代码,可帮助开发人员快速构建和管理分布式系统。无论是在企业级应用程序还是在云计算环境中,该框架都能提供优秀的支持,并具有较高的性能和可靠性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值