Java基础——Servlet(八)文件上传下载
一、简单的文件上传
常见的组件Smartupload , Apache 的 commons FileUpload
Smartupload上传的步骤:
1.初始化上传上下文
2.准备上传
3.保存文件
<% if(request.getParameter("flag")!=null){ SmartUpload su=new SmartUpload(); su.initialize(pageContext); su.upload(); su.save("/upload_files"); out.print("上传成功"); } %>
<form action="file_up.jsp?flag=ok" method="post" enctype="multipart/form-data" > //一定要用post <input type="file" name="file1" /> <input type="submit" value="上传"> </form>
注意:
1) 表单的 enctype 属性 一定要是 multipart/form-data, method 一定要是post
2) 要确保服务器上有 upload_files 这个文件夹 (当然,文件夹的名称是任意的)
二、多文件上传
<% if(request.getParameter("flag")!=null){ SmartUpload su=new SmartUpload(); su.initialize(pageContext); su.upload(); //别忘了 su.save("/upload_files"); SmartRequest req=su.getRequest(); //一定要这样取得 request 对象 String name=req.getParameter("userName"); out.write(name); SmartFiles files= su.getFiles(); int fileCount=files.getCount(); out.println("<h1>上传文件信息</h1>"); out.println("<hr>"); for(int i=0;i<fileCount;i++){ SmartFile f = files.getFile(i); out.println("表单项名称:"+f.getFieldName()+"<br>"); out.println("上传文件的名称"+f.getFileName()+"<br>"); out.println("文件的扩展名:"+f.getFileExt()+"<br>"); out.println("文件的大小:"+f.getSize()+"<hr>"); } } %>
<form action="multi_file_up.jsp?flag=ok" method="post" enctype="multipart/form-data" > <input type="file" name="file1" /> <br> <input type="file" name="file2" /> <br> <input type="file" name="file3" /> <br> <input type="file" name="file4" /> <br> 账号: <input type="text" name="userName" /> 密码: <input type="text" name="password" /> <input type="submit" value="上传"> </form>
三、使用 Servlet 上传文件
SmartUpload smart=new SmartUpload(); //它的参数: //Servlet servlet //ServletRequest request //ServletResponse response //String errpageUrl //boolean needSession //int buffer //boolean autoflush PageContext pagecontext=JspFactory.getDefaultFactory().getPageContext(this, request, response, "", true, 8192, true); smart.initialize(pagecontext); try { smart.upload(); //smart.save("/upload_files"); //由于后面是一个个存的,这个save就可以不要了 SmartFiles files=smart.getFiles(); for(int i=0;i<files.getCount();i++){ SmartFile f=files.getFile(i); String ip=request.getRemoteAddr(); String fileName=f.getFileName(); //文件名 //String fileExt =f.getFileExt(); //扩展名 String fullName=ip+"-"+fileName; //request.getServletContext().getRealPath("/"); f.saveAs("/upload_files"+java.io.File.separator+ fullName); } SmartRequest req=smart.getRequest(); String userName=req.getParameter("userName"); String password=req.getParameter("password"); System.out.println(userName+":"+password); } catch (SmartUploadException e) { e.printStackTrace(); }
四、文件上传与数据库操作
try { SmartUpload smart = new SmartUpload(); PageContext pageContext = null; pageContext = JspFactory.getDefaultFactory().getPageContext(this, request, response, "", true, 8192, true); smart.initialize(pageContext); smart.upload(); SmartFile f=smart.getFiles().getFile(0); // 1 取得上传的商品的信息 SmartRequest req = smart.getRequest(); String goodsName = req.getParameter("goodsName"); float price = Float.parseFloat(req.getParameter("price")); String des = req.getParameter("des"); String picture=f.getFileName(); //注意图片管理方面的问题,比如覆盖,删除等 GoodsInfo goods=new GoodsInfo(); goods.setGoodsName(goodsName); goods.setPrice(price); goods.setDes(des); goods.setPicture(picture); _dao.addGoods(goods); // 2 上传图片 f.saveAs("/goods_pic"+java.io.File.separator+picture); request.setAttribute("goods", goods); request.setAttribute("msg", "商品添加成功"); request.getRequestDispatcher("/goods/goods_add.jsp").forward(request, response); } catch (Exception ex) { ex.printStackTrace(); }
<form action="GoodsServlet" method="post" enctype="multipart/form-data"> 名称:<input type="text" name="goodsName" value="${goods.goodsName }" /> <br> 价格:<input type="text" name="price" /> <br> 描述:<input type="text" name="des" /> <br> 图片:<input type="file" name="picture" /> <br> <input type="submit" value="提交" /> <img src="${pageContext.request.contextPath }/goods_pic/${goods.picture }" > ${msg } </form>
五、文件的下载
//Servlet中 SmartUpload smart=new SmartUpload(); PageContext pageContext=JspFactory.getDefaultFactory().getPageContext(this, request, response, "", true, 8192, true); smart.initialize(pageContext); smart.setContentDisposition(null); // 用来指定下载数据的mine类型,传null 组件会自动的添加默认类型 try { smart.downloadFile("/goods_pic/lengtu.jpg"); } catch (SmartUploadException e) { e.printStackTrace(); } //jsp中 <a href="FileDownloadServlet" >下载</a>
六、附:文件上传请求消息的结构
//在jsp中的配置 <form action="FilieUpServlet" method="post" enctype="multipart/form-data"> <input type="text" name="userName" /> <input type="text" name="password" /> <input type="file" name="photo" /> <input type="submit" value="提交 "/> </form> //在Servlet中 public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletInputStream inputStream=request.getInputStream(); String filePath=getServletContext().getRealPath("/upload-files")+"/XXX.bmp"; //随给被上传的文件起个名字 FileOutputStream outStream=new FileOutputStream(filePath); byte[] buff=new byte[1024]; int len=0; while((len=inputStream.read(buff,0,buff.length))!=-1){ outStream.write(buff,0,len); } inputStream.close(); outStream.close(); System.out.println("成功"); }
说明 :上例中,form 的enctype 是默认的,在存文件的时候,也没有使用它传上的来的名称(传上来的名称是C:/pictture/....这样的)
操作以后,可以在upload-files 下 发现有 XXX.bmp 文件,用记事本打开,发现内容如下
userName=zhangsan&password=123&photo=C%3A%5Cpicture%5Cxiaoxin.bmp
上面的代码,由于没有获取实体的长度,只好先定义一个勺用来循环读取,可以看出:对于 application/x-wwww-form-urlencoded 编码的 form表单,所有字段URL参数的形式组合成了一行,并对其中的参数值都进行了URL编码,要想从上面的数据流中提取出各个字段的值,必须对读取到的内容进行拆分,然后再进行url解码,request.getParameter() 等方法可以直接读取上面的字段元素信息,所以Servlet程序中一般不用getInputStream或getReader方式来读取application/x-www-form-urlencoded 编码的表单字段信息。 如果要上传文件,form 元素的enctype 必须设置为 multipart/form-data,并且method必须为POST。
注意:request.getContentLength() 可以得到上传内容的长度,但要注意:并不能保证一次read方法的调用,就能读取到输入流中的所有内容,因为read方法在读取到指定个字节后或读取完网卡缓冲区中的内容后就返回,但网络传输的速度通常比cpu读网卡的速度慢,所以read方法可能只读到部分数据就返回了。实验表明,就算只上传一个图片文件,上传以后,这个图片文件也是不能用的.因为它里面还是有类似----7df1244802dc之类的内容,和普通图片的格式不对。
七、如何把图象存在数据库
1) 在GoodsInfo 这个实体类中加一个字段 private byte [] photo; //代表照片
2) 数据库中加一个 blob类型的字段 名字叫 photo,用来装载图片数据
3) Servlet中
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try{ SmartUpload smart = new SmartUpload(); PageContext pageContext = null; pageContext = JspFactory.getDefaultFactory().getPageContext(this, request, response, "", true, 8192, true); smart.initialize(pageContext); smart.upload(); SmartFile f = smart.getFiles().getFile(0); //取得上传的商品的信息 SmartRequest req = smart.getRequest(); String goodsName = req.getParameter("goodsName"); float price = Float.parseFloat(req.getParameter("price")); String des = req.getParameter("des"); String picture = f.getFileName(); GoodsInfo goods = new GoodsInfo(); goods.setGoodsName(goodsName); goods.setPrice(price); goods.setDes(des); goods.setPicture(picture); byte [] buff=new byte[f.getSize()]; //这里是关键 //将文件,转成字节数组,这里是关键 for(int i=0;i<f.getSize();i++){ buff[i]=f.getBinaryData(i); } goods.setPhoto(buff); //关键 _dao.addGoods(goods); } catch(Exception ex){ ex.printStackTrace(); } }
4) test_photo.jsp 中 :
<img src="${pageContext.request.contextPath }/goods/photo.jsp" />
5) photo.jsp 中:
<% GoodsInfo goods=new GoodsDao().getGoodsById(8); response.setContentType("image/jpg"); ByteArrayOutputStream imageStream=new ByteArrayOutputStream(); imageStream.write(goods.getPhoto()); ServletOutputStream streamOut=response.getOutputStream(); imageStream.writeTo(streamOut); imageStream.close(); out.clear(); out=pageContext.pushBody(); /*由于jsp container在处理完成请求后会调用releasePageContet方法释放所用的PageContext object, 并且同时调用getWriter方法,由于getWriter方法与在jsp页面中使用流相关的getOutputStream方法冲突, 所以会造成这种异常,解决办法是:只需要在jsp页面的最后加上两条语句: out.clear();out=pageContext.pushBody();即可(其中out,pageContext均为jsp内置对象! */ %>
八、不用插件的文件下载
//例一,最简单的 == Servlet1 == response.setContentType("application/x-msdownload"); response.setHeader("Content-Disposition" , "attachment;filename=xxx"); ServletOutputStream stream= response.getOutputStream(); stream.write("ha ha ha this is file".getBytes()); stream.close();
//例二 下载一幅服务器上的图象 == Servlet12 == response.setContentType("application/x-msdownload"); response.setHeader("Content-Disposition" , "attachment;filename=xxx"); String filePath=this.getServletContext().getRealPath("/")+"/goods_pic/"+"lengtu.jpg"; FileInputStream fis=new FileInputStream(filePath); ServletOutputStream outStream= response.getOutputStream(); byte[] buff=new byte[1024]; int len=0; while((len=fis.read(buff))!=-1){ outStream.write(buff,0,len); } fis.close(); outStream.close();
附:上传图片时的预览功能
function setImagePreview(docObj, localImagId, imgObjPreview, width, height) { if (docObj.files && docObj.files[0]) { //火狐下,直接设img属性 imgObjPreview.style.display = 'block'; imgObjPreview.style.width = width; imgObjPreview.style.height = height; //火狐7以上版本不能用上面的getAsDataURL()方式获取,需要一下方式 imgObjPreview.src = window.URL.createObjectURL(docObj.files[0]); } else { //IE下,使用滤镜 docObj.select(); var imgSrc = document.selection.createRange().text; //必须设置初始大小 localImagId.style.width = width; localImagId.style.height = height; //图片异常的捕捉,防止用户修改后缀来伪造图片 try { localImagId.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale)"; localImagId.filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = imgSrc; } catch (e) { alert("您上传的图片格式不正确,请重新选择!"); return false; } imgObjPreview.style.display = 'none'; document.selection.empty(); } } <form action="GoodsPhotoServlet" method="post" enctype="multipart/form-data"> 名称:<input type="text" name="goodsName" value="${goods.goodsName }" /> 价格:<input type="text" name="price" /> 描述:<inputtype="text" name="des" /> <br> 图片:<input type="file"name="picture" onchange="setImagePreview(this,localImag,preview,'100px','125px');" /> <input type="submit" value="提交" /> <div id="localImag" style="margin-left: 24px" ></div> <img id="preview" alt="请上传照片" style="width:122px; height: 145px;" /> </form>