commons-fileupload包依賴于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"> 類型叫file。 在定義enctype=“multipart/form-data”后即使是普通的表單域也不能通過request.getParameter()來獲取。
由于原先的代碼中已經(jīng)使用了很多的request.getParameter()方法,所以不適合改動(dòng)所有的這個(gè)方法,我們需要想個(gè)新技巧來在不改動(dòng)或者很少改動(dòng)原先代碼的情況下實(shí)現(xiàn)文件上傳的功能。
實(shí)際上HttpServletRequest是個(gè)interface,所以在doPost、doGet那些方法中用的肯定不是HttpServletRequest的實(shí)例(因?yàn)榻涌谑菦]有實(shí)例的),那里的request是接口的某個(gè)具體實(shí)現(xiàn),這個(gè)實(shí)現(xiàn)是由容器tomcat自動(dòng)創(chuàng)建的,實(shí)際上調(diào)用的是RequestFacade(實(shí)現(xiàn)了HttpServletRequest接口的類,多態(tài))
現(xiàn)在如果上傳的form中有file,enctype="multipart/form-data">,先在BaseServlet(訪問各種ArticleServlet、ChannelServlet的入口)中用MultipartRequestWrap中的request代替原先的request,待會(huì)兒在仔細(xì)的研究關(guān)于具體MultipartRequestWrap,代替的代碼如下:
boolean isMultipart = ServletFileUpload.isMultipartContent(request);判斷request是否是multipart類型,如果是的話request = new MultipartRequestWrapper(request);用MultipartRequestWrapper中的request來替換原先的request(RequestFacade)。
關(guān)于用MultipartRequestWrapper代替RequestFacade,是用到了Decorator設(shè)計(jì)模式。
HttpServletRequestWrapper沒有默認(rèn)的無參的構(gòu)造方法
還需要?jiǎng)?chuàng)建Attachment(附件)的Bean類,同時(shí)添加到Article的Bean中:
以及在數(shù)據(jù)庫(kù)中創(chuàng)建attachment的table
接下來進(jìn)入正題:
在MultipartRequestWrapper中實(shí)現(xiàn)了request的多態(tài)替換,原有的代碼不需要改動(dòng)就能繼續(xù)使用request.getParameter()、request.getParameterMap()。(不替換前如果form中有文件上傳,那么request.getParameter()、request.getParameterMap()方法是不能用的)。這段代碼就不逐行分析了,將來用的時(shí)候在看吧,不難。
表單域中可能存在同名name的(譬如多選的下拉選擇框,當(dāng)選中多個(gè)時(shí)(相同的name)),這時(shí)就用到
這段代碼。
把Attachment數(shù)據(jù)放入request的代碼:
ArticleServlet中添加的代碼:
我們?cè)仁沁@么實(shí)現(xiàn)的:
為了往Article中添加一些Attachment,在ArticleServlet中創(chuàng)建List,再調(diào)用setAttachment()。而更好的實(shí)現(xiàn)應(yīng)該是:
避免了在ArticleServlet中做復(fù)雜的操作,同時(shí)在ArticleServlet中不需要知道attachments是個(gè)List還是Set……。好處還有可以由Article決定如何添加Attachment。注意這里有個(gè)GRASP模式(GRASP模式中的專家模式,專家模式:一個(gè)職責(zé)應(yīng)該放在具有這個(gè)職責(zé)所需信息的類中,往Article中添加Attachment的職責(zé)應(yīng)該放在具有Attachment的Article類中。)
1、在ArticleDaoForMyBatisImpl中添加文章(及附件)的代碼:
在Article.xml中插入t_attachment的代碼:
2、在ArticleDaoForMyBatisImpl中刪除文章(及附件)的代碼:
由于刪除文章的同時(shí)刪除附件,所以我們需要根據(jù)aritcle的id來找出article,再找出attachments和channels,原本可以再單獨(dú)調(diào)用findAttachmentByArticle,但是我們用了這種resultMap的簡(jiǎn)便辦法,通過一次調(diào)用Article a = (Article) session.selectOne(Article.class.getName()+".findById", articleId);就根據(jù)article的id字段取出t_channels和t_attachments表中的相關(guān)數(shù)據(jù),放到Article的channels、attachments屬性中。
附件的在硬盤中的存儲(chǔ)信息是放在t_attachment中的,所以我們根據(jù)List attachments = a.getAttachments();取出文章的信息,然后調(diào)用new File(realPath).delete();刪除硬盤中的附件信息。最后再
//刪除數(shù)據(jù)庫(kù)中的相關(guān)記錄
session.delete(Article.class.getName() + ".del_attachments_by_articleId", articleId);
//刪除文章
session.delete(Article.class.getName()+".del", articleId);
注意順序一定要對(duì),先刪了硬盤的數(shù)據(jù),再刪數(shù)據(jù)庫(kù)中的t_attachment,最后再刪t_article中的數(shù)據(jù),先刪對(duì)象的關(guān)聯(lián),再刪對(duì)象自己。(因?yàn)槿绻葎h了t_attachment,就找不到附件存儲(chǔ)在硬盤的地址信息了,先刪t_article,那么就沒有articleid了,也不好刪t_attachment了)。
3、在ArticleDaoForMyBatisImpl中不刪文章,只是單獨(dú)刪除附件:
ArticleServlet中刪除附件的代碼:
ArticleDaoForMyBatisImpl中的代碼:
Article.xml文件中的代碼:
聯(lián)系客服