Struts2 实现上传附件(支持多附件)

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本人声明。否则将追究法律责任。
作者: 永恒の_☆    地址: http://blog.csdn.net/chenghui0317/article/details/9531879

一、简单介绍

     使用Struts2上传附件功能非常容易实现,只需要使用普通的Action类 用来获取上传的附件对象,然后保存到指定的路径下即可。基本原理和Servlet上传附件一样,只不过封装附件的方式实现不一样罢了。servlet上传附件的地址:http://blog.csdn.net/ch656409110/article/details/9502143


二、准备条件

     准备一个struts2环境的项目

    common-io.jar  ,下载地址:http://commons.apache.org/io/download_io.cgi

    common-upload.jar ,下载地址:http://jakarta.apache.org/commons/fileupload/


三、实现思路

    准备一个上传附件的页面,代码如下:

<form name="saveForm" action="${ctx}/house/save.action" method="post" οnsubmit="return checkSaveHouseForm();" enctype="multipart/form-data">
    <tr>
        <td class="field">上传附件:</td>
        <td>
            <input type="file" name="upload" class="text" οnblur="checkUpload()"/> 
            <span id="sp_upload" class="message"></span>
            <br />
        </td>
    </tr>
    <tr>
        <td class="field">附件名称:</td>
        <td>
            <input type="text" name="fileName" class="text"/>
        </td>
    </tr>
    <div class="buttons"><input type="submit" name="submit" value="发布"/></div>
</form>

页面中定义的附件控件名称是 upload,那么在Action类中也要定义相同的upload属性,如下:

    private File upload;   //upload file
    private String uploadFileName;   //附件名称
    private String uploadContentType; //附件类型
    private String savePath;    //附件保存的路径
    private List<String> fileName ;  //用户输入的名称
    //省略get set方法

需要注意的是,如果定义附件对象的附加属性,要以附件对象为前缀,比如upload为名的附件。

并且savePath的get方法要去读取才能获得,代码如下:

	public synchronized String getSavePath() {
		return ServletActionContext.getServletContext().getRealPath(savePath);
	}

封装好对象之后,接下来处理业务逻辑,具体代码如下:

//处理上传的附件
				System.err.println(upload.getAbsolutePath());
				System.err.println(upload.getName());
				System.err.println(uploadFileName);
				  
				fileName = fileName + uploadFileName.substring(uploadFileName.lastIndexOf("."));
				File target = new File(getSavePath(), fileName);
				//直接调用org.apache.commons.io.FileUtils下的copyFile 将上传的附件复制到指定的目录下
				//FileUtils.copyFile(upload, target);
				
				//另外还可以通过输入流读取字符之后 用输出流写入到磁盘中也是一样的。
				OutputStream outputStream = new FileOutputStream(new File(getSavePath(),fileName));
				InputStream inputStream = new FileInputStream(getUpload());
				
				byte[] buffers = new byte[1024];
				int length = 0;
				while((length = inputStream.read(buffers))!=-1){
					outputStream.write(buffers, 0, length);
				}
				inputStream.close();
				outputStream.close();
				
				house.setAttachUrl(savePath + Constant.SEPARATOR + fileName);
				houseBiz.saveHouse(house);
				
				ServletActionContext.getRequest().setAttribute("attachurl", house.getAttachUrl());

上面代码中 有两种实现将上传的附件放到指定目录的方法,都可以实现的。另外第一种更加方便一些,直接调用org.apache.commons.io.FileUtils下的copyFile 将上传的附件复制到指定的目录下。

然后struts.xml配置文件中需要配置一下我们action的跳转,以及附件保存路径等等信息,具体如下:

	<package name="house" namespace="/house" extends="struts-default">
		<action name="*" class="com.struts2.web.action.HouseAction" method="{1}">
			<result name="listPage">/WEB-INF/system/page/house_list.jsp</result>
			<result name="detail">/WEB-INF/system/page/house_detail.jsp</result>
			<result name="detail">/WEB-INF/system/page/house_detail.jsp</result>
			<result name="loadSuccess">/WEB-INF/system/page/saveHouse.jsp</result>
			
			<param name="savePath">/attach</param>
             <interceptor-ref name="defaultStack">
                   <!-- 配置允许上传的文件类型,多个用","分隔 -->
                   <param name="fileUpload.allowedTypes">
                     image/bmp,image/png,image/gif,image/jpeg,image/jpg ,image/x-png, image/pjpeg
                   </param>
                   <!-- 配置允许上传的文件大小,单位字节 -->
                   <param name="fileUpload.maximumSize">102400</param>
             </interceptor-ref>
			<result name="saveSuccess">/WEB-INF/system/page/saveHouseSuccess.jsp</result>
			<result name="input">/WEB-INF/system/page/saveHouseFail.jsp</result>
		</action>
	</package>

这里需要指定上传的附件指定的位置,即加一个<param>标签就好了,然后指定 上传的附件的限制类型、以及上传大小。

然后下面这种配置 是网上很多,反正我试了很多次,都不起作用。

<interceptor-ref name="fileUpload">  
    <param name="allowedTypes">image/jpg,image/png,image/gif,image/jpeg,image/pjpeg</param>  
    <param name="maximunSize">10000</param>  
</interceptor-ref>  
<interceptor-ref name="defaultStack"></interceptor-ref> 
实践证明  <interceptor-ref name="defaultStack"></interceptor-ref> 必须加上,否则接收的所有参数都为null,因为上面有引用fileUpload这个拦截器。


接下来就可以部署项目,启动服务器运行了。

首先选择附件,效果如下:



选择发布按钮,然后服务器就会进行上传操作。效果如下:

然后  在控制台可以在到action中输出的上传附件信息。效果如下:


可见,在请求提交后服务器先把附件放在服务器的一个临时文件夹下,当真正上传成功后就会把该临时文件删除。


这样,使用struts2上传单个文件效果完成了。


四、多附件上传

接下来看看多附件上传,在upload上传页面肯定需要多个file控件,代码如下:

<form name="saveForm" action="${ctx}/house/save.action" method="post" οnsubmit="return checkSaveHouseForm();" enctype="multipart/form-data">
    <tr>
        <td class="field">上传附件:</td>
        <td>
            <input type="file" name="upload" class="text" οnblur="checkUpload()"/> 
            <span id="sp_upload" class="message"></span>
            <br />
        </td>
    </tr>
    <tr>
        <td class="field">附件名称:</td>
        <td>
            <input type="text" name="fileName" class="text"/>
        </td>
    </tr>
    <tr>
        <td class="field">上传附件:</td>
        <td>
            <input type="file" name="upload" class="text"/> 
            <br />
        </td>
    </tr>
    <tr>
        <td class="field">附件名称:</td>
        <td>
            <input type="text" name="fileName" class="text" οnblur="checkFileName()"/>
            <span id="sp_fileName" class="message"></span>
        </td>
    </tr>
</table>
<div class="buttons"><input type="submit" name="submit" value="发布"/></div>
</form>
较上面而言 仅仅多了一个附件控件 和 附件名称控件。

然后后台需要改了,原先单个附件上传可以定义FIle 类型的对象接收参数,现在可是多个。所以需要重新定义属性,代码如下:

    private List<File> upload;   //upload file
    private List<String> uploadFileName;   //附件名称
    private List<String> uploadContentType; //附件类型
    private String savePath;    //附件保存的路径
    private List<String> fileName ;  //用户输入的名称
    //省略了get set 方法

实践 发现,这里定义 List 类型或者该属性原有类型的数组 都可以接收成功,可见struts2还是蛮强大的。

比如:

    private File[] upload;   //upload file
    private String[] uploadFileName;   //附件名称
    private String[] uploadContentType; //附件类型
    private String savePath;    //附件保存的路径
    private String[] fileName ;  //用户输入的名称
    //省略了get set 方法

然后处理上传的时候需要用循环来依次上传,具体代码如下:

//处理上传的附件  
				if(upload!=null){
					for (int i=0; i<upload.size(); i++) {
						fileName.set(i, fileName.get(i) + uploadFileName.get(i).substring(uploadFileName.get(i).lastIndexOf(".")));
						File target = new File(getSavePath(), fileName.get(i));
						//直接调用org.apache.commons.io.FileUtils下的copyFile 将上传的附件复制到指定的目录下
						//FileUtils.copyFile(upload, target);
						
						//另外还可以通过输入流读取字符之后 用输出流写入到磁盘中也是一样的。
						OutputStream outputStream = new FileOutputStream(new File(getSavePath(),fileName.get(i)));
						InputStream inputStream = new FileInputStream(getUpload().get(i));
						
						byte[] buffers = new byte[1024];
						int length = 0;
						while((length = inputStream.read(buffers))!=-1){
							outputStream.write(buffers, 0, length);
						}
						inputStream.close();
						outputStream.close();
						if(house.getAttachUrl()!=null && !house.getAttachUrl().equals("")){
							house.setAttachUrl(house.getAttachUrl() + "," + savePath + Constant.SEPARATOR + fileName.get(i));
						}else{
							house.setAttachUrl(savePath + Constant.SEPARATOR + fileName.get(i));
						}
					}
				}
				houseBiz.saveHouse(house);
				
				ServletActionContext.getRequest().setAttribute("attachurl", house.getAttachUrl());

显示上传后的代码具体如下:

		<div class="box">
			<div class="msg">
				<p>恭喜:添加住房成功!</p>
				<p><a href="${ctx}">返回首页</a></p>
				<%
					String attachurl = (String)request.getAttribute("attachurl");
					if(attachurl!=null){
						String []strs = attachurl.split(",");
						for(int i=0; i<strs.length; i++){
							out.print("<img src='"+request.getContextPath()+strs[i]+"' width='400' height='270'/><br/><br/>");	
						}
					}
				%>
			</div>
		</div>
ok,再重新部署,启动服务器然后在执行一遍,效果如下图:

点击发布按钮,效果如下:


界面上是成功了,然后在去附件指定目录查看 是否真正成功。

这样,多附件上传就成功完成了。


五、限制上传的附件类型和大小

前面已经配置的很清楚了,当我们想要过滤一些不好的情况,比如上传附件的大小上限,以及类型的限制。可以先在前台判断,当然如果前台被屏蔽了 就只能通过后台再次判断上传的附件是否满足需求,否则服务器会被搞垮的。

当附件的大小超过上限,默认的2M大小,如果给超过上限 就不会传到服务器,服务器不会抛出异常,进入sturts.xml中配置的input对应的页面,然后可以在页面中添加

<s:fielderror></s:fielderror> 标签捕捉具体异常。

  具体异常信息显示如下图所示:

当上传的附件不是图片格式的话,也不会上传到服务器,会显示如下结果:


这样子显示好吗?感觉不太友好,全是一片英文字母。所以为了友好显示后台抛出的异常可以这样:

在处理上传附件的Action中重写addActionError(),当异常类型是超出上限的时候我就修改提示,具体代码如下:

	@Override
	public void addActionError(String anErrorMessage) {
	    if (anErrorMessage.startsWith("the request was rejected because its size")) {
	    	super.addActionError("抱歉,你上传的文件超过了上限 !!");
	    } else {
	    	super.addActionError(anErrorMessage);
	    }
	}

说实话,这种方式在我以前的项目中可以实现,但是这里一直不成功,我也不知道为什么。。。。

不过可以用另一种方法,给struts指定一个属性文件,比如struts.properties  ,直接放在classpath的根目录下。

例子如下:

struts.messages.error.content.type.not.allowed=\u62B1\u6B49\uFF0C\u60A8\u4E0A\u4F20\u7684\u9644\u4EF6\u4E0D\u662F\u56FE\u7247\u683C\u5F0F\u7684\uFF01
struts.messages.error.file.too.large=\u62B1\u6B49\uFF0C\u60A8\u4E0A\u4F20\u7684\u9644\u4EF6\u592A\u5927\uFF0C\u6700\u591A10M!
struts.messages.error.uploading=\u62B1\u6B49\uFF0C\u4E0A\u4F20\u51FA\u9519\u4E86\uFF01
然后在struts的配置文件中指定一下,就好了,具体如下:
<!-- 指定struts属性文件 -->
<constant name="struts.custom.i18n.resources" value="struts" />

然后在试试看就会发现效果以前好多了,如下图:


这个是附件太大的友好提示,因为传了两个附件,所有显示了两个。


这个是附件类型错误的友好提示。


六、实现下载功能

 其实这个下载功能和在Servlet 中处理的实现方式一样,所以不在累赘。servlet上传附件的地址:http://blog.csdn.net/ch656409110/article/details/9502143







  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值