CMS项目总结:18、文件上传commons-fileupload

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()来获取。

由于原先的代码中已经使用了很多的request.getParameter()方法,所以不适合改动所有的这个方法,我们需要想个新技巧来在不改动或者很少改动原先代码的情况下实现文件上传的功能。

 

实际上HttpServletRequest是个interface,所以在doPostdoGet那些方法中用的肯定不是HttpServletRequest的实例(因为接口是没有实例的),那里的request是接口的某个具体实现,这个实现是由容器tomcat自动创建的,实际上调用的是RequestFacade(实现了HttpServletRequest接口的类,多态)

现在如果上传的form中有fileenctype="multipart/form-data">先在BaseServlet(访问各种ArticleServletChannelServlet的入口)中用MultipartRequestWrap中的request代替原先的request,待会儿在仔细的研究关于具体MultipartRequestWrap,代替的代码如下:

CMS项目总结:18、文件上传commons-fileupload_第1张图片

boolean isMultipart = ServletFileUpload.isMultipartContent(request);判断request是否是multipart类型,如果是的话request = new MultipartRequestWrapper(request);MultipartRequestWrapper中的request来替换原先的requestRequestFacade)。

关于用MultipartRequestWrapper代替RequestFacade,是用到了Decorator设计模式。

CMS项目总结:18、文件上传commons-fileupload_第2张图片

CMS项目总结:18、文件上传commons-fileupload_第3张图片

CMS项目总结:18、文件上传commons-fileupload_第4张图片

HttpServletRequestWrapper没有默认的无参的构造方法

还需要创建Attachment(附件)的Bean类,同时添加到ArticleBean中:

CMS项目总结:18、文件上传commons-fileupload_第5张图片

以及在数据库中创建attachmenttable

CMS项目总结:18、文件上传commons-fileupload_第6张图片

接下来进入正题:

CMS项目总结:18、文件上传commons-fileupload_第7张图片

1分析MultipartRequestWrap的代码:

CMS项目总结:18、文件上传commons-fileupload_第8张图片

CMS项目总结:18、文件上传commons-fileupload_第9张图片

在MultipartRequestWrapper中实现了request的多态替换,原有的代码不需要改动就能继续使用request.getParameter()request.getParameterMap()。(不替换前如果form中有文件上传,那么request.getParameter()request.getParameterMap()方法是不能用的)。这段代码就不逐行分析了,将来用的时候在看吧,不难。

表单域中可能存在同名name的(譬如多选的下拉选择框,当选中多个时(相同的name)),这时就用到

CMS项目总结:18、文件上传commons-fileupload_第10张图片

这段代码。

Attachment数据放入request的代码:

CMS项目总结:18、文件上传commons-fileupload_第11张图片

2、Attachment插入Article中;

CMS项目总结:18、文件上传commons-fileupload_第12张图片

ArticleServlet中添加的代码:

我们原先是这么实现的:

CMS项目总结:18、文件上传commons-fileupload_第13张图片

为了往Article中添加一些Attachment,在ArticleServlet中创建List,再调用setAttachment()。而更好的实现应该是:

CMS项目总结:18、文件上传commons-fileupload_第14张图片

避免了在ArticleServlet中做复杂的操作,同时在ArticleServlet中不需要知道attachments是个List还是Set……。好处还有可以由Article决定如何添加Attachment注意这里有个GRASP模式(GRASP模式中的专家模式,专家模式:一个职责应该放在具有这个职责所需信息的类中,往Article中添加Attachment的职责应该放在具有AttachmentArticle类中。)

3、添加文章时往数据库中填充t_attachment表中的字段,删除文章时将文章对应的附件信息从t_attachment表中删除

1、在ArticleDaoForMyBatisImpl中添加文章(及附件)的代码:

CMS项目总结:18、文件上传commons-fileupload_第15张图片

在Article.xml中插入t_attachment的代码:

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

CMS项目总结:18、文件上传commons-fileupload_第16张图片

由于删除文章的同时删除附件,所以我们需要根据aritcle的id来找出article,再找出attachmentschannels,原本可以再单独调用findAttachmentByArticle,但是我们用了这种resultMap的简便办法,通过一次调用Article a = (Article) session.selectOne(Article.class.getName()+".findById", articleId);就根据articleid字段取出t_channelst_attachments表中的相关数据,放到Articlechannelsattachments属性中。

CMS项目总结:18、文件上传commons-fileupload_第17张图片

附件的在硬盘中的存储信息是放在t_attachment中的,所以我们根据List attachments = a.getAttachments();取出文章的信息,然后调用new File(realPath).delete();删除硬盘中的附件信息。最后再

//删除数据库中的相关记录

session.delete(Article.class.getName() + ".del_attachments_by_articleId", articleId);

//删除文章

session.delete(Article.class.getName()+".del", articleId);

注意顺序一定要对,先删了硬盘的数据,再删数据库中的t_attachment,最后再删t_article中的数据,先删对象的关联,再删对象自己。(因为如果先删了t_attachment,就找不到附件存储在硬盘的地址信息了,先删t_article,那么就没有articleid了,也不好删t_attachment了)。

3、ArticleDaoForMyBatisImpl中不删文章,只是单独删除附件:

ArticleServlet中删除附件的代码:

CMS项目总结:18、文件上传commons-fileupload_第18张图片

ArticleDaoForMyBatisImpl中的代码:

CMS项目总结:18、文件上传commons-fileupload_第19张图片

Article.xml文件中的代码:

你可能感兴趣的:(设计模式,cms,数据库,bean,Decorator,interface)