commons-fileupload包依賴(lài)于commons-io
<form action="ArticleServlet" method="post" enctype="multipart/form-data"> 涉及到上傳文件一定要在form中定義enctype="multipart/form-data">,并且method=“post”
<input type="file" name="attachs" id="attachs"> 類(lèi)型叫file。 在定義enctype=“multipart/form-data”后即使是普通的表單域也不能通過(guò)request.getParameter()來(lái)獲取。
由于原先的代碼中已經(jīng)使用了很多的request.getParameter()方法,所以不適合改動(dòng)所有的這個(gè)方法,我們需要想個(gè)新技巧來(lái)在不改動(dòng)或者很少改動(dòng)原先代碼的情況下實(shí)現文件上傳的功能。
實(shí)際上HttpServletRequest是個(gè)interface,所以在doPost、doGet那些方法中用的肯定不是HttpServletRequest的實(shí)例(因為接口是沒(méi)有實(shí)例的),那里的request是接口的某個(gè)具體實(shí)現,這個(gè)實(shí)現是由容器tomcat自動(dòng)創(chuàng )建的,實(shí)際上調用的是RequestFacade(實(shí)現了HttpServletRequest接口的類(lèi),多態(tài))
現在如果上傳的form中有file,enctype="multipart/form-data">,先在BaseServlet(訪(fǎng)問(wèn)各種ArticleServlet、ChannelServlet的入口)中用MultipartRequestWrap中的request代替原先的request,待會(huì )兒在仔細的研究關(guān)于具體MultipartRequestWrap,代替的代碼如下:

boolean isMultipart = ServletFileUpload.isMultipartContent(request);判斷request是否是multipart類(lèi)型,如果是的話(huà)request = new MultipartRequestWrapper(request);用MultipartRequestWrapper中的request來(lái)替換原先的request(RequestFacade)。
關(guān)于用MultipartRequestWrapper代替RequestFacade,是用到了Decorator設計模式。



HttpServletRequestWrapper沒(méi)有默認的無(wú)參的構造方法
還需要創(chuàng )建Attachment(附件)的Bean類(lèi),同時(shí)添加到Article的Bean中:

以及在數據庫中創(chuàng )建attachment的table

接下來(lái)進(jìn)入正題:



在MultipartRequestWrapper中實(shí)現了request的多態(tài)替換,原有的代碼不需要改動(dòng)就能繼續使用request.getParameter()、request.getParameterMap()。(不替換前如果form中有文件上傳,那么request.getParameter()、request.getParameterMap()方法是不能用的)。這段代碼就不逐行分析了,將來(lái)用的時(shí)候在看吧,不難。
表單域中可能存在同名name的(譬如多選的下拉選擇框,當選中多個(gè)時(shí)(相同的name)),這時(shí)就用到

這段代碼。
把Attachment數據放入request的代碼:


ArticleServlet中添加的代碼:
我們原先是這么實(shí)現的:

為了往Article中添加一些Attachment,在ArticleServlet中創(chuàng )建List,再調用setAttachment()。而更好的實(shí)現應該是:

避免了在A(yíng)rticleServlet中做復雜的操作,同時(shí)在ArticleServlet中不需要知道attachments是個(gè)List還是Set……。好處還有可以由Article決定如何添加Attachment。注意這里有個(gè)GRASP模式(GRASP模式中的專(zhuān)家模式,專(zhuān)家模式:一個(gè)職責應該放在具有這個(gè)職責所需信息的類(lèi)中,往Article中添加Attachment的職責應該放在具有Attachment的Article類(lèi)中。)
1、在ArticleDaoForMyBatisImpl中添加文章(及附件)的代碼:

在A(yíng)rticle.xml中插入t_attachment的代碼:

2、在ArticleDaoForMyBatisImpl中刪除文章(及附件)的代碼:

由于刪除文章的同時(shí)刪除附件,所以我們需要根據aritcle的id來(lái)找出article,再找出attachments和channels,原本可以再單獨調用findAttachmentByArticle,但是我們用了這種resultMap的簡(jiǎn)便辦法,通過(guò)一次調用Article a = (Article) session.selectOne(Article.class.getName()+".findById", articleId);就根據article的id字段取出t_channels和t_attachments表中的相關(guān)數據,放到Article的channels、attachments屬性中。

附件的在硬盤(pán)中的存儲信息是放在t_attachment中的,所以我們根據List attachments = a.getAttachments();取出文章的信息,然后調用new File(realPath).delete();刪除硬盤(pán)中的附件信息。最后再
//刪除數據庫中的相關(guān)記錄
session.delete(Article.class.getName() + ".del_attachments_by_articleId", articleId);

//刪除文章
session.delete(Article.class.getName()+".del", articleId);
注意順序一定要對,先刪了硬盤(pán)的數據,再刪數據庫中的t_attachment,最后再刪t_article中的數據,先刪對象的關(guān)聯(lián),再刪對象自己。(因為如果先刪了t_attachment,就找不到附件存儲在硬盤(pán)的地址信息了,先刪t_article,那么就沒(méi)有articleid了,也不好刪t_attachment了)。
3、在ArticleDaoForMyBatisImpl中不刪文章,只是單獨刪除附件:
ArticleServlet中刪除附件的代碼:

ArticleDaoForMyBatisImpl中的代碼:

Article.xml文件中的代碼:


聯(lián)系客服