这篇文章描述在集群环境下,开发网页上传文件到服务端的过程,以及使用MongoDB管理文件。案例使用OpenText Cordys BOP 4平台。
OpenText Cordys BOP提供文件上传开发组件,用其可以设计、实现客户端网页向服务端上传文件功能。
此方案涉及到集群环境下文件共享技术,用于存储上传文件,在Linux环境下,使用了NFS共享文件系统。
NFS(Network File System)即网络文件系统,是FreeBSD支持的文件系统中的一种,它允许网络中的计算机之间通过TCP/IP网络共享资源。在NFS的应用中,本地NFS的客户端应用可以透明地读写位于远端NFS服务器上的文件,就像访问本地文件一样。
本案例设计是在服务端使用MongoDB GridFS管理存储上传文件。从共享文件系统临时文件夹中读取临时文件到MongoDB中。
示例代码片段如下:
public static com.unicom.common.attachment.C_MONGODB_FILE uploadFileImp(String fileName, String fileType, String fileSize, String fileContent, String gridFSName, String bizInstanceId, String oId) {
//校验入参合法性
if (fileName == null || "".equalsIgnoreCase(fileName.trim())) return null;
if (fileContent == null || "".equalsIgnoreCase(fileContent.trim())) return null;
//获取文件上传者的code
String uCode = BSF.getUser().split(",")[0].substring(3);
C_MONGODB_FILE file = null;
try {
DB db = MongoDBUtil.getDB();
GridFS gridFS = new GridFS(db, gridFSName);
File uploadTemp = new File(fileContent);
if (!uploadTemp.exists()) {
return null;
}
file = new C_MONGODB_FILE();
GridFSFile mongoFile = gridFS.createFile(uploadTemp);
mongoFile.put("filename", fileName);
mongoFile.put("bizInstanceId", bizInstanceId);
mongoFile.put("oId", oId);
mongoFile.put("uploadDate", new Date());
mongoFile.put("contentType", fileType);
mongoFile.put("fileUploader", uCode);
mongoFile.save();
file.setFILE_ID((String) mongoFile.getId());
file.setFILE_NAME(mongoFile.getFilename());
file.setFILE_TYPE(mongoFile.getContentType());
file.setFILE_SIZE(Float.toString(mongoFile.getLength()));
file.setFILE_CONTENT(mongoFile.getFilename());
uploadTemp.delete();
return file;
} catch (Exception e) {
return null;
}
}
上传入口存储上传文件到共享文件夹中,并传递文件名称到服务容器,处理请求。共享文件夹通过配置文件wcp.properties(在Linux环境/opt/Cordys/defaultInst/config/下)配置,其中参数为com.eibus.web.tools.upload.UploadWritePath,如下所示:
#EIB Properties
#Wed Dec 16 19:25:38 CST 2015
com.eibus.web.gateway=cn\=webgateway@msbop_test,cn\=cordys,cn\=defaultInst,o\=hlcuc.com
......
com.eibus.web.tools.upload.UploadWritePath=/opt/Cordys/defaultInst/content/uploadcontent
通过SecureCRT客户端工具[1],从服务器端下载wcp.properties配置文件。
也可以在Soap请求中使用Upload:FilePath属性来设置上传文件的临时文件夹,替换了wcp.properties中的配置。
<script id="requestString" type="cordys/xml">
<SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP:Body>
<UploadFile xmlns="http://unicom.com/common/attachment" preserveSpace="no" qAccess="0" qValues="">
<fileName />
<fileType />
<fileSize />
<fileContent>Upload:FilePath1</fileContent>
<gridFSName />
<bizInstanceId />
<oId />
</UploadFile>
</SOAP:Body>
</SOAP:Envelope>
</script>
</head>
不过有这样的可能,黑客可以不断发送上传请求,没有服务容器是可以处理他们。所以,建议设置共享文件夹的存储空间限制,如果是企业内网,可以忽略。
下图解释上传处理过程工作方式:
运维管理
由于此共享文件夹,没有服务监控,需要人工监控,最好每日进行监控,当文件数量超过管理限定,例如超过1000个,则执行删除操作(linux下删除操作命令为rm,而且是在用户下班后操作)。
例如下图为获取当前文件数量:
上传文件的临时目录
cd /opt/Cordys/defaultInst/content/uploadcontent
下载文件的临时目录
cd /opt/Cordys/defaultInst/content/downloadcontent
参考upload.htm代码片段:
<!DOCTYPE html>
<html onapplicationready="applicationReady()">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9,IE=10"/>
<title>上传附件</title>
<link href="../common/css/bootstrap.css" type="text/css" rel="stylesheet"/>
<link href="../common/css/bootstrap-table.css" type="text/css" rel="stylesheet"/>
<script type="text/javascript" src="../common/js/jquery.min.js"></script>
<script type="text/javascript" src="../common/js/rgdb.utils.js"></script>
<script type="text/javascript">
var gridFSName;
var oId;
var bizInstanceId;
var objData;
window.uploadTemp = {};
function applicationReady() {
if (system.isIE) {//ie方式
$('#ieUpload').attr("hidden", false);
} else {//非ie
$('#uploadForm1').attr("hidden", false);
}
if (window.opener && window.opener.objValue) {
objData = window.opener.objValue;
}
if (objData) {
if (objData.gridFSName)
gridFSName = objData.gridFSName;
if (objData.bizInstanceId)
bizInstanceId = objData.bizInstanceId;
if (objData.oId)
oId = objData.oId;
} else {
bizInstanceId = application.getParameter("bizInstanceId");
oId = application.getParameter("oId");
gridFSName = application.getParameter("gridFSName");
}
if (!gridFSName || !oId || !bizInstanceId) {
document.getElementById("btUpload").disabled = true;
application.showError("抱歉,参数异常,请关闭页面后重新尝试!");
}
}
function upload() {
document.getElementById("btUpload").disabled = true;
uploader.request = requestString.XMLDocument;
var fileFullName = "";
if (system.isIE) {
fileFullName = document.getElementById("chooseFileResult").value;
} else {
fileFullName = document.getElementById("file1").value;
}
window.fileName = fileFullName;
if (fileFullName != "") {
$('#ieUpload').attr("hidden", true);
$('#uploadForm1').attr("hidden", true);
var fileName = fileFullName.substr(fileFullName.lastIndexOf("\\") + 1);
//window.fileName = fileName;
window.uploadTemp.fileName = fileName;
var fileType = fileName.substr(fileName.lastIndexOf(".") + 1);
window.uploadTemp.fileType = fileType;
cordys.setNodeText(uploader.request, ".//*[local-name()='fileName']", fileName);
cordys.setNodeText(uploader.request, ".//*[local-name()='fileSize']", "");
cordys.setNodeText(uploader.request, ".//*[local-name()='fileType']", fileType);
cordys.setNodeText(uploader.request, ".//*[local-name()='gridFSName']", gridFSName);
cordys.setNodeText(uploader.request, ".//*[local-name()='oId']", oId);
cordys.setNodeText(uploader.request, ".//*[local-name()='bizInstanceId']", bizInstanceId);
if (system.isIE) {
uploader.uploadFile();
$('#progressbar').attr("hidden", false);
progressbar.start(3000);
setTimeout(function () {
application.inform("上传成功!");
progressbar.stop();
}, 3500);
} else {
uploader.uploadFile(document.getElementById("uploadForm1"));
$('#progressbar').attr("hidden", false);
progressbar.start(2700);
setTimeout(function () {
application.inform("上传成功!");
progressbar.stop();
}, 3000);
}
} else {
application.notify("请选择您要上传的附件!");
document.getElementById("btUpload").disabled = false;
}
}
function onUploadHandler() {
if (window.application.event.status == true) {
progressbar.setStatus(100);
progressbar.stop();
application.inform("上传成功!");
window.opener.window.getFileList();
} else {
application.showError("抱歉,上传失败!");
}
}
function doClose() {
getFileList();
}
</script>
<script id="requestString" type="cordys/xml">
<SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP:Body>
<UploadFile xmlns="http://unicom.com/common/attachment" preserveSpace="no" qAccess="0" qValues="">
<fileName />
<fileType />
<fileSize />
<fileContent>Upload:FilePath1</fileContent>
<gridFSName />
<bizInstanceId />
<oId />
</UploadFile>
</SOAP:Body>
</SOAP:Envelope>
</script>
</head>
<body style="border:0px;margin:0px;padding:50px 50px 50px 50px;overflow:hidden" class="taskbar" scroll="no">
<div class="panel panel-default">
<div class="panel-heading">
<strong>上传文件</strong>
</div>
<div class="panel-body">
<div cordysType="wcp.library.util.Upload" encode="true" id="uploader" onupload="onUploadHandler();"
style="display:none" xmlcontent="true"></div>
<div id="ieUpload" class="form-group" hidden="hidden">
<input name="chooseFileResult" class="fileInputIE" id="chooseFileResult"
onclick="this.value=chooseFileResult.value = uploader.browse(1)" type="text" placeholder="请点击输入框选择文件"
readonly>
</div>
<form action="com.eibus.web.tools.upload.Upload.wcp" enctype="multipart/form-data" id="uploadForm1"
method="post" name="uploadForm1" hidden="hidden">
<input id="file1" name="file1" type="file" class="fileInput" style="height:27px;"/>
</form>
<div cordysType="wcp.library.ui.ProgressBar" id="progressbar" style="width:100%;height: 25px;" class="light"
hidden="hidden">
</div>
<div class="row text-center" style="margin-top: 20px;">
<button id="btUpload" name="btUpload" onclick="upload()" class="btn btn-danger">上传</button>
<button id="btClose" name="btClose" onclick="doClose()" class="btn btn-danger" style="margin-left: 10px;">
关闭
</button>
</div>
</div>
</div>
</body>
</html>
<script type="text/javascript">
function getFileList() {
if(window.fileName != undefined){
var gridFSName1 = gridFSName;
if (window.isTransWkfl)
$('#btnAddAttachment').attr('disabled', true);
return $.cordys.utils.sendCordysAjax({
method: 'GetFileList',
namespace: 'http://unicom.com/common/attachment',
parameters:{
bizInstanceId: bizInstanceId,
gridFSName: gridFSName1
}
}).done(function (response) {
response = $.cordys.utils.formatCordysAjaxQueryEntity(response);
if (response) {
console.log(response);
//return response;
if(response.length > 0){
$.each(response,function(index,ele){
if(response[index]['FILE_NAME'] == window.uploadTemp.fileName){
application.container.close();
window.opener.window.getFileList();
window.close();
}else{
alert("正在上传,请稍等。。。 。。。");
}
});
}else{
alert("请稍等。。。 。。。");
}
}
}).fail(function (returnData) {
alert('附件上传失败!');
console.error('error' + returnData)
});
}else{
application.container.close();
window.opener.window.getFileList();
window.close();
}
}
</script>
参考:
[1] Cordys Web Gateway与XForm的监控及log文件下载(SecureCRT) 肖永威 2016.06