文件上传也是项目中常用的功能,在之前做过的几个项目中,几乎每个项目都有个上传头像的功能。这次遇到的不是上传头像,而是需要上传pdf、图片等多种格式的文件了,而这个模块的主要业务逻辑就是围绕着这些文档来进行。所以文件上传、下载、预览都需要涉及。先整上传吧。
设计数据库时有两种方案比较:
一是把每次上传的文件地址拼接字符串放在一条记录里。二是每个文件对应一条记录。
这两者的区别就是:
前者,需要用js拼接文件路径等属性的字符串,对数据做查询排序等处理还需要查询出来后,用js等代码进行处理。插入一条记录即可。
后者,存文件的五个属性(realname文件加密名、filename文件名、type类型、ext扩展名、path路径),日后查询处理更方便。一次上传多个文件,需要批量插入。除了存文件的属性外,其他的信息信息也要存,因此数据库冗余信息比较多。
鉴于这个文件在此系统中需要频繁查询展示。所以选用第二种方式。
输入流输出流上传 VS FileUtiles.copy上传
//TODO:
单文件上传 VS 多文件上传
上传文件时一次选择多个文件,然后上传,可以在html页的<input type = "file" name="upload" multiple />中添加"multiple"属性,h5支持,IE10+支持。
还可以通过js动态生成多个input来达到一次上传多个文件的目的。
文件上传有单文件上传和多文件上传,区别就是在action中接收从jsp页面传过来的file对象的值时,单文件用字符串,多文件用数组或list集合。
在网上找到了demo,写的非常棒,既有讲解,又有源码,代码还比较严谨,链接给大家。基本的理解就是从他这里得来的。不过还是自己理一遍,思路更清晰。
Struts2文件上传,分两大步:
一、文件上传至服务器磁盘相应路径下:
1、引入jar包
//TODO:
2、编写jsp
在编写jsp时有两种方式:html编写或者s标签。
网上查有两种说法:在速度上html的要优于s标签的。因为s标签解析比较费时间。但是在s标签<s:from>里设置theme="simple" 属性,s标签解析出来的html代码也就没有过多的冗余了,而且s标签的验证功能强大。两种方法都给大家列出来。
html方式的:
1. <form action="uploadFile.action" enctype="multipart/form-data" method="post"> 2. <table align="center" width="50%" border="1"> 3. <tr> 4. <td> 5. 上传资料: 6. </td> 7. <td> 8. <input type="file" multiple name="upload" id="file"> 9. <input type="submit" value="上传" /> 10. </td> 11. </tr> 12. </table> 13. </form>
s标签的:
1. <s:form action="uploadFile.action" theme="simple" method="post" enctype="multipart/form-data"> 2. <table align="center" width="50%" border="1"> 3. <tr> 4. <td> 5. 上传文件 6. </td> 7. <td id="more" > 8. <s:file name="upload" label="输入要上传的文件名"></s:file> 9. <input type="button" value="上传更多..." οnclick="addMore()"> 10. </td> 11. </tr> 12. <tr> 13. <td> 14. <s:submit value="确认"></s:submit> 15. </td> 16. <td> 17. <s:reset value="重置"></s:reset> 18. </td> 19. </tr> 20. </table> 21. </s:form>
显示上传文件验证结果的信息通过S标签显示如下:
<s:fielderror cssStyle="color:red" />
通过拦截器的配置,检验上传文件的类型,大小是否合法,不合法将会通过上述标签显示出来。
3、编写js
有人家写好的,我就先搬过来用用啦。
1. /* 上传多个文件上传 */ 2. function addMore() 3. { 4. var td = document.getElementById("more"); 5. var br = document.createElement("br"); 6. var input = document.createElement("input"); 7. var button = document.createElement("input"); 8. input.type = "file"; 9. input.name = "upload"; 10. button.type = "button"; 11. button.value = " 删除 "; 12. button.onclick = function() 13. { 14. td.removeChild(this); 15. } 16. td.appendChild(br); 17. td.appendChild(input); 18. td.appendChild(button); 19. };
4、编写action
需要定义几个必须的参数,用来获取文件信息,单个可以用String ,多个用数组或者list。
下边是用数组的方式:
1. //上传多个文件 2. private File[] upload;// 实际上传文件 3. private String[] uploadContentType; // 文件的内容类型 4. private String[] uploadFileName; // 上传文件名 5. // 注意FileName和ContentType 必须这样写!以你的<input type="file" name="upload"> 6. private List<entity> entityList = new ArrayList<entity>();// 上传文件集合 7. private String message; 8. public static String FILE_ROOT = ""; 9. public static String UPLOAD_PATH = "/upload"; // 上传文件路径 10. 11. //......省略相应的get、set方法 12.
这是把文件的属性信息进行处理,存入实体对象中,准备存入数据库,进行数据持久化。
1. try{ 2. String path = ServletActionContext.getServletContext().getRealPath(FILE_ROOT); 3. String path2 = UPLOAD_PATH + "/testUpload/"; 4. String targetDirectory = path + path2; 5. File file = new File(targetDirectory);// 获取文件流路径 6. if (!file.exists()) { 7. file.mkdirs(); 8. } 9. 10. for(int i = 0; i < upload.length; i++){ 11. String fileName = uploadFileName[i];// 上传的文件名 12. String type = uploadContentType[i];// 文件类型 13. String realName = UUID.randomUUID().toString() 14. + getExt(fileName);// 保存的文件名称,使用UUID+后缀进行保存 15. File target = new File(targetDirectory, realName); 16. FileUtils.copyFile(upload[i], target);// 上传至服务器的目录 17. 18. 19. entity.setsFilePath(path2 + realName); 20. entity.setsFileExt(getExt(fileName)); 21. entity.setsFileType(type); 22. entity.setsFileName(fileName);//上传的文件名称 23. entity.setsFileRealName(realName);//保存数据库的文件名称 采用加密形式 24. entity.setId(UUIDHexGenerator.getUUID()); 25. entity.setdCreateDate(new Date()); 26. //省略 entity....; 27. 28. 29. entityList.add(entityInspect); 30. 31. } 32. entityService.saveOrUpdateEntityList(entityList);//调用service层保存方法 33. 34. } catch (Exception e) { 35. e.printStackTrace(); 36. addActionError(e.getMessage()); 37. }
5、配置struts.xml
1. <!--fileUpload拦截器,可用于限制上传文档的类型和文档大小 --> 2. <interceptor-ref name="fileUpload"> 3. <!--限制文件大小20M,单位为字节--> 4. <param name="maximumSize">20971520</param> 5. <!--配置可上传文件类型为doc,ppt,xls,pdf,txt,word,zip,--> 6. <param name="allowedTypes"> 7. image/bmp,image/x-png,image/png,image/gif,image/jpeg,image/jpg,image/pjpeg, 8. application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document, 9. application/pdf,application/vnd.ms-excel,application/vnd.ms-powerpoint,text/plain, 10. application/zip,application/x-zip-compressed 11. </param> 12. <!-- 配置路径,创建/image文件夹 --> 13. <!-- <param name="savePath">/image</param> --> 14. </interceptor-ref> 15. <interceptor-ref name="defaultStack"/>
1. <!-- 若上传的文件不符合要求则返回input --> 2. <result name="input">/pages/common/error.jsp</result>
在struts中配置是为了拦截上传的文件,进行合法性验证,当上传的文件大小超过设定的大小,文件类型不在被允许范围内时,上传失败,返回错误信息,默认返回input,跳转input设置的页面。该页面上设置 s:fielderror 标签,则会把具体的验证信息显示出来。
文件类型设置需用mine,具体戳这里,非常详细。
二、把文件参数存入数据库:(到action就够了,剩下这几步就不细写了)
6、编写entity(vo)(实体在action中也会用,可以早点设计好)
7、编写service
8、编写dao
总结:
都是基础,需要积累啊~~
项目中多个地方需要文件上传,想把它再封装一下,正在努力中。。。
考虑不周之处,还请大家指正~感激不尽。