附件的批量上传
项目是工单管理系统,顾名思义就是管理工单的系统。在该项目的使用中你创建了工单,可以向该工单上传附件,但当时附件的上传仅仅是单一附件上传。因此二次开发要求开发一个附件的批量上传功能(值得说明一下项目使用的是ssh框架)。最初的业务要求是这样的:
将本地所有要上传的附件添加到一个excel的模板中,模板的样式如下所示
工单编号 | 附件路径 | 附件说明 |
---|---|---|
gdbh1 | c:/xxx/a.doc | gdbh1的附件说明 |
gdbh2 | d:/xxx/b.xls | gdbh2的附件说明 |
gdbh3 | e:/xxx/xxx/c.jpg | gdbh3的附件说明 |
注意:“附件路径”中的路径全都是上传这本地的路径,为未来的麻烦埋了个伏笔。
当填写好这个模板后,点击“导入”按钮,将模板提交给action,在action中对此模板进行解析。根据本地路径将文件上传到服务器中。这在本地测试每次都是成功的,但提交到测试服务器,出现了无法按照给定路径找到文件,无法上传成功的问题。
原因是:路径问题,在测试环境中是linux环境,按照本地的windows的文件路径自然是找不到文件。而原本项目中的文件上传是靠struts2中的<s:file>
实现的文件上传,此标签 当点击“浏览”时选定了文件,此时文件便已经上传到了一个临时的文件夹中,即使选择文件后将本地的文件删除,只要点击“导入”,文件依然会上传到服务器中。
因此,不得不把视线的思路改回到正统的批量上传上来。如图所示
图一
下面是前台jsp、js代码及action解析的代码
jsp代码:
<s:form enctype="multipart/form-data" method="POST">
<input type="hidden" name="executeMsg" id="executeMsg"/>
<input type="hidden" name="operators" id="operators"/>
<input type="hidden" name="flowcode" id=flowcode value="${flowcode}"/>
<input type="hidden" name="formModeId" id="formModeId" value="${formModeId}"/>
<input type="hidden" name="nextView" id="nextView" value="${nextView}"/>
<br>
<table width="600" border="0" cellspacing="0" cellpadding="0" align="center">
<!-- 以下附件 by zyc -->
<tr>
<td width="1%"><img src="/images/middle/box_topl.gif" width="11" height="19" /></td>
<td align="center" class="hui2">批量上传安全整改流程工单附件</td>
<td width="60%" background="/images/middle/box_topbg.gif"> </td>
<td width="1%"><img src="/images/middle/box_topr.gif" width="11" height="19" /></td>
</tr>
<tr>
<td background="/images/middle/box_middlel.gif"> </td>
<td colspan="2">
<table width="100%" border="0" id="table_together" style="width: 600px; text-align: center">
<tr>
<td align="center" width="135px">工单编号</td>
<td align="center" width="205px">附件地址</td>
<td align="center" width="135px">附件说明</td>
<td align="center" width="105px"><input value="添加" type="button" style="width: 40px; height: 25px" onclick="insertRows()">
<input value="导入" type="button" style="width: 40px; height: 25px" onClick="submitFile2()">
</td>
</tr>
<tr>
<td align="center"><input type="text" id="serialno" name="serialno" ></TD>
<td align="center"><s:file name="attachment" id="attachment2" ></s:file></TD>
<td align="center"><input type="text" id="remark" name="remark" ></TD>
<td align="center"><input value="删除" type="button" style="width: 40px; height: 25px" onClick="delTableRow(this)"></TD>
</tr>
</table>
<div>
1、此批量上传功能,“工单编号”及“附件地址”是必填项,“附件说明”未选填项 。<br>其中“工单编号”为上传的附件对应的工单。“附件地址”填写该附件所在路径,且文件必须填写扩展名。如:C:\xxx\abc.doc <br>
2、点击“添加”时,会增加一行以供添加附件。点击“删除”会删除指定的行。<br>
</div>
</td>
<td background="/images/middle/box_middler.gif"> </td>
</tr>
<!-- 以上附件 by zyc -->
<tr>
<td height="10"><img src="/images/middle/box_bottoml.gif" width="11" height="19" /></td>
<td height="10" colspan="2" background="/images/middle/box_bottombg.gif"> </td>
<td><img src="/images/middle/box_bottomr.gif" width="11" height="19" /></td>
</tr>
</table>
</s:form>
js代码:
var tempRow=0;
var maxRows=0;
function insertRows(){
var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串
var isOpera = userAgent.indexOf("Opera") > -1; //判断是否Opera浏览器
var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1 && !isOpera; //判断是否IE浏览器
var table_together = document.getElementById("table_together");
if (isIE){
tempRow=table_together.rows.length-1;
maxRows=tempRow;
tempRow=tempRow+1;
var Rows=table_together.rows;//类似数组的Rows
var newRow=table_together.insertRow(table_together.rows.length);//插入新的一行
var Cells=newRow.cells;//类似数组的Cells
for (i=0;i<4;i++){//每行的7列数据
var newCell=Rows(newRow.rowIndex).insertCell(Cells.length);
newCell.align="center";
switch (i) {
case 0: newCell.innerHTML='<td align="center"><input type="text" id="serialno" name="serialno"></TD>'; break;
case 1: newCell.innerHTML='<td align="center">'+
'<s:file name="attachment" id="attachment2" ></s:file>'+
'</TD>'; break;
case 2: newCell.innerHTML='<td align="center" ><input type="text" id="remark" name="remark"></TD>'; break;
case 3: newCell.innerHTML='<td align="center" ><input value="删除" type="button" style="width: 40px; height: 25px" onClick="delTableRow(this)"></TD>'; break;
}
}
maxRows+=1;
}else{
var rowObj = document.createElement("tr");
var cellObj = document.createElement("td");
cellObj.innerHTML = '<input type="text" id="serialno" name="serialno">';
rowObj.appendChild(cellObj)
cellObj = document.createElement("td");
cellObj.innerHTML = '<s:file name="attachment" id="attachment2" ></s:file>';
rowObj.appendChild(cellObj);
cellObj = document.createElement("td");
cellObj.innerHTML = '<input type="text" id="remark" name="remark">';
rowObj.appendChild(cellObj);
cellObj = document.createElement("td");
cellObj.innerHTML = '<input value="删除" type="button" style="width: 40px; height: 25px" onClick="delTableRow(this)">';
rowObj.appendChild(cellObj);
table_together.appendChild(rowObj);
}
}
function delTableRow(r){
var rowNum = r.parentNode.parentNode.rowIndex;
table_together.deleteRow(rowNum);
}
function submitFile2(){ //导入
var table_together = document.getElementById('table_together');
if(table_together.rows.length==1){
alert("请选择文件");
return false;
}
var form=document.forms[1];
var file = document.getElementsByName('attachment');
var serialno = document.getElementsByName('serialno');
var remark = document.getElementsByName('remark');
if(checkData(file,serialno,remark)){
form.action="${ctx}/maintenance/SafetyLanuchAction!saveSafetyFlowAttachments.do";
form.submit();
showProgressBar(this);
}
}
function checkData(file,serialno,remark){ //进行校验 进行验证
if(file.length-1!=serialno.length){ //如果工单编号与附件个数不等说明有空白项目 不予上传
alert("工单编号或文件未填写");
return false;
}
for(var i=1;i<file.length;i++){ //判断是否有空附件
if(file[i].value==""){
alert("存在空白的附件,请选择要上传的附件。");
return false;
}
}
for(var i=0;i<serialno.length;i++){ //判断是否有空工单编号
if(serialno[i].value==""){
alert("存在空白工单编号,请填写。");
return false;
}
}
for(var i=0;i<remark.length;i++){
if(remark[i].value.length>500){
alert("附件说明字数不能超过500字");
return false;
}
}
return true;
}
action代码如下:
此代码中上传成功跳转的页面采用的是已有的异常页面格式,这是欠妥的!!!
如果有使用者借用此action代码,要注意这一点,小心被骂。
public void saveSafetyFlowAttachments() throws ServletException, IOException {
StringBuffer msg = new StringBuffer(); //重复文件的提示信息
StringBuffer msg1 = new StringBuffer(); //文件过大的提示信息
StringBuffer msg2 = new StringBuffer(); //上传成功的提示信息
StringBuffer msg3 = new StringBuffer(); //工单不存在的提示信息
LogonVO logonVO = null;
int num = 0; //用以承接某一工单中存在的重复工单数
int numToJudge = 0; //计数器 用以确定需要批量上传的工单是否存在工单编号错误的情况
RecFlow recFlow = null; // 声明recFlow对象
//获得传来的.xls文件
Map<String, String[]> params = request.getParameterMap();
serialno = params.get("serialno"); //工单编号
remark = params.get("remark"); //附件说明
String flw_ids[] = new String[serialno.length]; //存储工单流水号的数组
String fileNames[] = new String[this.model.getAttachmentFileName().length]; //文件名
File files[] = new File[this.model.getAttachment().length]; //文件路径
List<Integer> upload_num = new ArrayList<Integer>(); //存储上传文件的 下标
for(int k=0;k<this.model.getAttachment().length;k++){
fileNames[k]=this.model.getAttachmentFileName()[k];
files[k]=this.model.getAttachment()[k];
logger.info("数据导入文件:"+fileNames[k]);
long fileSize=files[k].length();
if(fileSize>MAX_SIZE){
if (!StringUtils.isBlank(msg1.toString())) {
msg1.append(",<br>");
}
msg1.append(serialno[k].trim()+"工单的"+fileNames[k]);
continue;
}
//根据工单编号查询工单进而获取流水号
recFlow = recFlowManager.findByserialNO(serialno[k].trim());
//判断工单是否存在
if (recFlow==null) {
msg3.append(serialno[k].trim()+"工单不存在,请检查工单编号是否正确。<br>");
continue;
}else{
flw_ids[k] = recFlow.getFlowlsh();
upload_num.add(k);
}
numToJudge++;
flw_ids[k]=recFlow.getFlowlsh();
//查询工单重复数量
num = attachmentService.getNumberOfAttachments(flw_ids[k],fileNames[k]);
//如果该工单存在同名附件 则向msg注入信息
if (num>0&&msg.toString().indexOf(fileNames[k].toString())==-1) {
msg.append(serialno[k]+"工单,已经存在"+num+"个与"+fileNames[k]+"同名的文件。<br>");
}
}
//上传文件
if(numToJudge>0){ //如果flag为false 说明存在大于2M文件 如果等式不成立 说明某个工单不存在
for (Integer i : upload_num) {
AttachmentImpl attachmentImpl = new AttachmentImpl();
byte[] content = new byte[0];
if (files[i].exists()) {
content = FileCopyUtils.copyToByteArray(files[i]);
}
//获取登录人
HttpSession session = request.getSession(false);
logonVO = (LogonVO) session.getAttribute("logonVO");
attachmentImpl.setContent(content);
attachmentImpl.setMimeType(new MimetypesFileTypeMap().getContentType(files[i]));
attachmentImpl.setName(fileNames[i]);
attachmentImpl.setSize(content.length);
attachmentImpl.setRemark(remark[i]);
attachmentService.addAttachment(attachmentImpl, flw_ids[i], "",logonVO.getPersonCode());
}
}
if(upload_num.size()>0){
if(!StringUtils.isBlank(msg1.toString())){
msg2.append(msg1.toString()+"<br>附件太大了,因此不执行上传操作。<br>文件不能大于"+MAX_SIZE/(1024 * 1024)+"M。<br>");
}
if(!StringUtils.isBlank(msg3.toString())){
msg2.append(msg3.toString());
}
if(!StringUtils.isBlank(msg1.toString())||!StringUtils.isBlank(msg3.toString())){
msg2.append("其余上传成功。<br>");
}else{
msg2.append("上传成功。<br>");
}
if(!StringUtils.isBlank(msg.toString())){
msg2.append("其中"+msg.toString());
}
}
if(upload_num.size()==0){
if(!StringUtils.isBlank(msg1.toString())){
msg2.append(msg1.toString()+"<br>附件太大了,因此不执行上传操作。<br>文件不能大于"+MAX_SIZE/(1024 * 1024)+"M。<br>");
}
if(!StringUtils.isBlank(msg3.toString())){
msg2.append(msg3.toString());
}
}
String backBtn = "<br><button href='javascript:' onclick='self.location=document.referrer;'>返回</button> ";
throw new IllegalStateException(GlobalMessage.prefix+msg2.toString()+backBtn);
}