文件上传也是项目中常用的功能,在之前做过的几个项目中,几乎每个项目都有个上传头像的功能。这次遇到的不是上传头像,而是需要上传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方式的:
<form action="uploadFile.action" enctype="multipart/form-data" method="post">
<table align="center" width="50%" border="1">
<tr>
<td>
上传资料:
</td>
<td>
<input type="file" multiple name="upload" id="file">
<input type="submit" value="上传" />
</td>
</tr>
</table>
</form>
s标签的:
<s:form action="uploadFile.action" theme="simple" method="post" enctype="multipart/form-data">
<table align="center" width="50%" border="1">
<tr>
<td>
上传文件
</td>
<td id="more" >
<s:file name="upload" label="输入要上传的文件名"></s:file>
<input type="button" value="上传更多..." οnclick="addMore()">
</td>
</tr>
<tr>
<td>
<s:submit value="确认"></s:submit>
</td>
<td>
<s:reset value="重置"></s:reset>
</td>
</tr>
</table>
</s:form>
显示上传文件验证结果的信息通过S标签显示如下:
<s:fielderror cssStyle="color:red" />
通过拦截器的配置,检验上传文件的类型,大小是否合法,不合法将会通过上述标签显示出来。
3、编写js
有人家写好的,我就先搬过来用用啦。
/* 上传多个文件上传 */
function addMore()
{
var td = document.getElementById("more");
var br = document.createElement("br");
var input = document.createElement("input");
var button = document.createElement("input");
input.type = "file";
input.name = "upload";
button.type = "button";
button.value = " 删除 ";
button.onclick = function()
{
td.removeChild(this);
}
td.appendChild(br);
td.appendChild(input);
td.appendChild(button);
};
4、编写action
需要定义几个必须的参数,用来获取文件信息,单个可以用String ,多个用数组或者list。
下边是用数组的方式:
//上传多个文件
private File[] upload;// 实际上传文件
private String[] uploadContentType; // 文件的内容类型
private String[] uploadFileName; // 上传文件名
// 注意FileName和ContentType 必须这样写!以你的<input type="file" name="upload">
private List<entity> entityList = new ArrayList<entity>();// 上传文件集合
private String message;
public static String FILE_ROOT = "";
public static String UPLOAD_PATH = "/upload"; // 上传文件路径
//......省略相应的get、set方法
这是把文件的属性信息进行处理,存入实体对象中,准备存入数据库,进行数据持久化。
try{
String path = ServletActionContext.getServletContext().getRealPath(FILE_ROOT);
String path2 = UPLOAD_PATH + "/testUpload/";
String targetDirectory = path + path2;
File file = new File(targetDirectory);// 获取文件流路径
if (!file.exists()) {
file.mkdirs();
}
for(int i = 0; i < upload.length; i++){
String fileName = uploadFileName[i];// 上传的文件名
String type = uploadContentType[i];// 文件类型
String realName = UUID.randomUUID().toString()
+ getExt(fileName);// 保存的文件名称,使用UUID+后缀进行保存
File target = new File(targetDirectory, realName);
FileUtils.copyFile(upload[i], target);// 上传至服务器的目录
entity.setsFilePath(path2 + realName);
entity.setsFileExt(getExt(fileName));
entity.setsFileType(type);
entity.setsFileName(fileName);//上传的文件名称
entity.setsFileRealName(realName);//保存数据库的文件名称 采用加密形式
entity.setId(UUIDHexGenerator.getUUID());
entity.setdCreateDate(new Date());
//省略 entity....;
entityList.add(entityInspect);
}
entityService.saveOrUpdateEntityList(entityList);//调用service层保存方法
} catch (Exception e) {
e.printStackTrace();
addActionError(e.getMessage());
}
5、配置struts.xml
<!--fileUpload拦截器,可用于限制上传文档的类型和文档大小 -->
<interceptor-ref name="fileUpload">
<!--限制文件大小20M,单位为字节-->
<param name="maximumSize">20971520</param>
<!--配置可上传文件类型为doc,ppt,xls,pdf,txt,word,zip,-->
<param name="allowedTypes">
image/bmp,image/x-png,image/png,image/gif,image/jpeg,image/jpg,image/pjpeg,
application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document,
application/pdf,application/vnd.ms-excel,application/vnd.ms-powerpoint,text/plain,
application/zip,application/x-zip-compressed
</param>
<!-- 配置路径,创建/image文件夹 -->
<!-- <param name="savePath">/image</param> -->
</interceptor-ref>
<interceptor-ref name="defaultStack"/>
<!-- 若上传的文件不符合要求则返回input -->
<result name="input">/pages/common/error.jsp</result>
在struts中配置是为了拦截上传的文件,进行合法性验证,当上传的文件大小超过设定的大小,文件类型不在被允许范围内时,上传失败,返回错误信息,默认返回input,跳转input设置的页面。该页面上设置
s:fielderror 标签,则会把具体的验证信息显示出来。
文件类型设置需用mine,具体戳这里,非常详细。
二、把文件参数存入数据库:(到action就够了,剩下这几步就不细写了)
6、编写entity(vo)(实体在action中也会用,可以早点设计好)
7、编写service
8、编写dao
总结:
都是基础,需要积累啊~~
项目中多个地方需要文件上传,想把它再封装一下,正在努力中。。。
考虑不周之处,还请大家指正~感激不尽。