文件下载的步骤:
jsp省略;
servlet代码:
1 public class DownServlet extends HttpServlet{ 2 3 @Override 4 protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 5 req.setCharacterEncoding("utf-8"); 6 resp.setContentType("text/html;charset=utf-8"); 7 8 //获取文件名 9 String fileName = req.getParameter("fileName"); 10 //获取文件的具体位置 11 String realPath = this.getServletContext().getRealPath("down"); 12 13 File file =new File(realPath+"/"+fileName); 14 //创建输入流 15 InputStream is= new FileInputStream(file); 16 //设置响应头 17 resp.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8")); 18 //创建输出流 19 //OutputStream os=new FileOutputStream(); 20 ServletOutputStream os = resp.getOutputStream(); 21 //声明一次读取大小 22 int len=0; 23 //中间容器 24 byte [] buffer= new byte[200]; 25 //循环读取 26 while((len=is.read(buffer))!=-1){ 27 os.write(buffer, 0, len); 28 } 29 os.flush(); 30 os.close(); 31 } 32 }
文件上传:
主要代码:
1 public class UploadServlet extends HttpServlet { 2 @Override 3 protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 4 req.setCharacterEncoding("utf-8"); 5 resp.setContentType("text/html;charset=utf-8"); 6 UserDao dao = new UserDao(); 7 User user = new User(); 8 InputStream is = null; 9 OutputStream os = null; 10 try { 11 // 获取工厂类 12 DiskFileItemFactory factory = new DiskFileItemFactory(); 13 // 获取对象 14 ServletFileUpload fileUpload = new ServletFileUpload(factory); 15 List<FileItem> fileItemList = fileUpload.parseRequest(req); 16 // 遍历文件条目fileItem 17 for (FileItem fileItem : fileItemList) { 18 if (fileItem.isFormField()) {// type:普通文本 19 if ("username".equals(fileItem.getFieldName())) { 20 // String username = fileItem.getFieldName(); 21 user.setUsername(fileItem.getString("UTF-8")); 22 } 23 if ("birth".equals(fileItem.getFieldName())) { 24 // String username = fileItem.getFieldName(); 25 user.setBirth(DateUtil.stringParserDate(fileItem.getString())); 26 } 27 if ("addr".equals(fileItem.getFieldName())) { 28 // String username = fileItem.getFieldName(); 29 user.setAddr(fileItem.getString("utf-8")); 30 } 31 } else { 32 // type:file 33 // 获取文件上传目的地的 路径 34 String realPath = this.getServletContext().getRealPath("upload"); 35 System.out.println(realPath); 36 // 获取 文件名 37 String fieldName = fileItem.getName(); 38 if (fieldName != null) { 39 user.setPhoto(realPath + "/" + fieldName); 40 } 41 // 获取输入流 42 is = fileItem.getInputStream(); 43 // 创建输出流 44 File f = new File(realPath + "/" + fieldName); 45 os = new FileOutputStream(f); 46 // 声明一次读取大小 47 int len = 0; 48 // 中间容器 49 byte[] buffer = new byte[200]; 50 // 循环读取 51 while ((len = is.read(buffer)) != -1) { 52 os.write(buffer, 0, len); 53 } 54 } 55 } 56 } catch (FileUploadException e) { 57 e.printStackTrace(); 58 } finally { 59 os.flush(); 60 os.close(); 61 is.close(); 62 } 63 boolean flag = dao.addUser(user); 64 if (flag) { 65 req.getRequestDispatcher("index.jsp").forward(req, resp); 66 } 67 } 68 }
文件条目:FileItem类总结:
FileItem类的常用方法
1.boolean isFormField():isFormField方法用来判断FileItem对象里面封装的数据是一个普通文本表单字段,还是一个文件表单字段。如果是普通文本表单字段,返回一个true否则返回一个false。因此可以用该方法判断是否是普通表单域还是文件上传表单域。
2.String getName():getName方法用来获得文件上传字段中的文件名。
3.String getFieldName():getFieldName方法用来返回表单标签的name属性的值。
4.void write(File file):write方法将FileItem对象中的内容保存到某个指定的文件中。如果FileItem对象中的内容是保存在某个临时文件中,该方法完成后,临时文件可以会被删除。该方法也可以将普通表单字段保存在一个文件中,但最主要的用途是把上传的文件内容保存在本地文件系统中。
5.String getString():getString(“utf-8”)(在获取普通文本内容时容易乱码)方法将FileItem对象中保存的数据流内容以一个字符串返回。它有两个重载形式。public Java.lang.String getString()和public java.lang.String getString(java.lang.String encodeing) throws java.io.UnsupportedEncodingException。前者使用缺省的字符集编码将主体内容转换成字符串,后者使用参数指定的字符集编码。如果在读取普通表单字段元素的内容时,出现了乱码现象,可以调用第二个方法,并传入 正确的字符集编码名称。
6.String getContentType():此方法用来获得上传文件的类型,即标段字段元素描述头属性“content-type”的值,如image/jpeg。如果FileItem对象对应的是普通的表单字段,将返回null。
7.boolean isInMemory():判断FileItem对象封装的数据是保存在内存中还是硬盘中。
8.void delete():此方法用来清空FileItem对象中封装的主体内容,如果内容是被保存在临时文件中,该方法会把临时文件删除。
9.InputStream getInputStream()。以流的形式返回上传文件的主体内容。
10.long getSize():返回上传文件的大小。
转一篇fileupload详细总结:
前台页面不用多说 主要是form表单中设置 enctype="multipart/form-data" 很重要。
处理上传jsp文件
判断表单是否是Multipart类型的。这里可以直接对request进行判断
if (ServletFileUpload.isMultipartContent(request)) {
// 创建文件处理工厂,它用于生成 FileItem 对象。
DiskFileItemFactory factory = new DiskFileItemFactory();
设置文件的缓存路径
String tempdir =this.getServletContext().getRealPath("/upload/temp");
Java.io.File d = new java.io.File(savedir);
if(!d.exists()){
d.mkdirs();
}
factory.setSizeThreshold(1024*1024); // 设置最多只允许在内存中存储的数据,单位:字节
factory.setRepository(d); // 设置一旦文件大小超过getSizeThreshold()的值时数据存放在硬盘的目录(默认可以不用设置)
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);
// 设置允许用户上传文件大小,单位:字节
upload.setSizeMax(yourMaxRequestSize);
//上传文件,并解析出所有的表单字段,包括普通字段和文件字段
List items = upload.parseRequest(request);
//下面对每个字段进行处理,分普通字段和文件字段
Iterator it = items.iterator();
while(it.hasNext()){
FileItem fileItem = (FileItem) it.next();
//如果是普通字段
if(fileItem.isFormField()){ //是普通的字段
System.out.println(fileItem.getFieldName() + " " + fileItem.getName() + " " + new String(fileItem.getString().getBytes("iso8859-1"), "gbk"));
fileItem.getFieldName();//得到字段name属性的值
fileItem.getName();//得到file字段的文件名全路径名,如果不是file字段,为null
fileItem.getString();//得到该字段的值,默认的编码格式
fileItem.getString("UTF-8");//指定编码格式
}else{//文件字段
System.out.println(fileItem.getFieldName() + " " +
fileItem.getName() + " " +//得到file字段的文件名全路径名
fileItem.isInMemory() + " " +//用来判断FileItem类对象封装的主体内容是存储在内存中,还是存储在临时文件中,如果存储在内存中则返回true,否则返回false
fileItem.getContentType() + " " +//文件类型
fileItem.getSize()); //文件大小
//什么东西都有了 ,想怎么处理都可以了
//保存文件,其实就是把缓存里的数据写到目标路径下
if(fileItem.getName()!=null && fileItem.getSize()!=0){
File fullFile = new File(fileItem.getName());
File newFile = new File("c:/temp/" + fullFile.getName());
try {
fileItem.write(newFile);
} catch (Exception e) {
e.printStackTrace();
}
}else{
System.out.println("文件没有选择 或 文件内容为空");
}
一、文件上传入门
1. 应用:
用户上传头像、上传图片、邮件上传附件等
2. 页面表单的实现
文件上传表单和普通表单有两个区别
1) 需要文件上传字段 <input type=”file” />
2) form 表单的 enctype 属性需要指定为 multipart/form-data
3. 服务器端解析request
在 Servlet 中通过 request.getInputStream 获得表单上传数据,会发现数据是分段发送的
由于自己写程序解析有难度,我们可以使用Apache 开发的开源组件Commons-fileupload
需要导入 jar 包Commons-fileupload 和Commons-io
4 . UploadServlet 中处理文件上传程序
// 1. 创建工厂类
DiskFileItemFactory factory = new DiskFileItemFactory();
// 2. 创建FileUpload对象
ServletFileUpload upload = new ServletFileUpload(factory);
// 3. 判断是否是上传表单
boolean b = upload.isMultipartContent(request);
if(!b) {
// 不是文件上传
request.setAttribute("message", "对不起,不是文件上传表单!");
request.getRequestDispatcher("/message.jsp").forward(request, response);
return;
}
// 是文件上传表单
// 4. 解析request,获得FileItem项
List<FileItem> fileitems = upload.parseRequest(request);
// 5. 遍历集合
for(FileItem item : fileitems) {
// 判断是不是普通字段
if(item.isFormField()) {
String name = item.getFieldName();
String value = item.getString();
// 手工的转换了
value = new String(value.getBytes("iso-8859-1"),"utf-8");
System.out.println(name + "=" + value);
} else {
// 文件上传字段
// 获得文件名
String filename = item.getName();
System.out.println(filename);
filename = filename.substring(filename.lastIndexOf("\")+1);
System.out.println(filename);
// 创建文件
ServletContext context = getServletContext();
String dir = context.getRealPath("WEN-INF/upload");
File file = new File(dir, filename);
file.createNewFile();
// 获得流,读取数据写入文件
InputStream in = item.getInputStream();
FileOutputStream fos = new FileOutputStream(file);
int len;
byte[] buffer = new byte[1024];
while((len=in.read(buffer))>0)
fos.write(buffer,0,len);
fos.close();
in.close();
item.delete(); // 删除临时文件
}
二、 文件上传处理细节
1. 中文乱码问题
1) 文件名中文乱码问题,解决办法: 告诉文件上传组件以什么编码方式来解码文件名
ServletUpload.setCharacterEncoding(“utf-8”);
request. setCharacterEncoding(“utf-8”);
2) 普通字段中文乱码问题
fileitem.getString(“utf-8”);
2. 临时文件
对于大文件不能缓存在内存,需要缓存到硬盘,为了方便管理,我们需要设置临时文件存放目录
// 设置临时文件的存放位置
factory.setRepository(new File("d:/temp"));
文件上传完毕需要删除临时文件,否则会导致服务器存在两份上传文件
// 注意,需要先将流进行关闭,否则会导致临时文件无法删除
out.close();
in.close();
// 删除临时文件
fileitem.delete();
3. 文件存放目录
1) 目录需要隐藏,禁止外界直接访问
2) 文件名需要保证不重复
3) 文件应该分目录存放
三、上传进度条
1. 实现进度监听
需要实现对文件上传进度的监听,需要给FileUpload 对象添加 ProgressListener
在upload方法中对与进度相关的数据进行处理
upload.setProgressListener(new ProgressListener() {
long num = 0;
public void update(long bytesRead, long contentLength, int items) {
long progress = bytesRead*100/contentLength;
if(progress==num)
return;
num = progress;
System.out.println("上传进度:" + progress + "%");
// request.getSession().setAttribute("progress", progress);
}
});
2. 在 jsp 页面显示进度
实验:
1) 使用 iframe 发送请求, 请求一个Servlet, 在Servlet 中返回响应,发送自增的num
此时会发现 iframe 会不停第想Servlet发送请求
2) 点击文件上传按钮后,iframe立刻停止刷新,直至上传完毕页面跳转至新页面
3)为了观察实验结果,将form 的 target 指定为 iframe, UploadServlet回送上传完毕的结果
4) 出现上述问题的原因,浏览器不支持多线程同时访问服务器只能同时发送一个请求,
这样的访问方式为同步访问
5) 要在文件上传的同时在iframe中实现进度访问,就需要ie浏览器与服务器进行异步交互
此时就需要 XMLHttpRequest 对象
在JavaScript中可以直接使用XMLHttpRequest 对象与服务器进行异步通信
获得XmlHttpRequest 对象的方式有两种
ie7以上版本
var xhr = null;
if(window.XMLHttpRequest)
xhr = new XMLHttpRequest();
ie7以下版本
if(window.ActiveXObject)
xhr = new ActiveXObject(“Microsoft.XMLHTTP”);
获得对象后需要调用open方法输入请求地址
注意请求方式, 地址的输入, 并且需要设置为true 指定异步访问该地址
xhr.open(“get”,”/upload/servlet/UploadServlet”, false)
// 调用send 方法发送请求,post方式需要发送消息体,get方式则不用直接传入null值
xhr.send(null);
// 访问 responseText 属性获得 Servlet 回送的数据
document.write(xhr.responseText);
四、 api方法
1. DiskFileItemFactory 对象
设置缓冲区大小,字节为单位,默认为10K,一般不用修改
factory.setSizeThreshold(1000);
设置临时文件存放目录
factory.setRepository(file);
2. ServletFileUpload 对象
判断是否为文件上传表单
boolean b = upload.isMultipartContent(request);
解析request对象
List<FileItem> list = upload.parseRequest(request);
设置上传文件的最大值
setFileSizeMax(long fileSizeMax)
设置上传文件总量的最大值
setSizeMax(long sizeMax)
设置编码格式
setHeaderEncoding(java.lang.String encoding)
注册进度监听器
setProgressListener(ProgressListener pListener)
3. FileItem 对象
获得表单字段的属性名
item.getFieldName();
获得普通字段的值
item.getString(charsetName)
获得文件上传字段的文件名
item.getName()
获得文件上传的流
item.getInputStream()
public class DownServlet extends HttpServlet{
@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.setCharacterEncoding("utf-8");resp.setContentType("text/html;charset=utf-8");//获取文件名String fileName = req.getParameter("fileName");//获取文件的具体位置String realPath = this.getServletContext().getRealPath("down");File file =new File(realPath+"/"+fileName);//创建输入流InputStream is= new FileInputStream(file);//设置响应头resp.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));//创建输出流//OutputStream os=new FileOutputStream();ServletOutputStream os = resp.getOutputStream();//声明一次读取大小int len=0;//中间容器byte [] buffer= new byte[200];//循环读取while((len=is.read(buffer))!=-1){os.write(buffer, 0, len);}os.flush();os.close(); }}