您的位置:首页 > 其它

form表单action提交表单,页面不跳转且表单数据含文件的处理方法

2015-08-20 15:30 716 查看
在最近的项目中需要将含input[type='file']的表单提交给后台,并且后台需要将文件存储在数据库中。之前所用的方法都是先将文件上传到七牛服务器上,然后七牛会返回文件的下载地址,在提交表单的时候将文件的下载地址和其他表单元素一起提交即可。但是现在考虑到安全性,这些文件不能上传到七牛服务器上,得直接提交给后台存储到数据库中,在此需要注意以下问题:

1、提交表单时,如果要提交file,那么form标签里必须使用enctype="multipart/form-data"来设置编码。

2、提交表单时,为了使页面不跳转,引用jquery.form.js插件,使用ajaxSubmit方法提交表单;

3、提交到nodejs后先将文件上传至node服务器,然后再将文件传给后端。

下面说一个具体的例子(例子中用了angularjs+nodejs+express):

第一步:在package.json页面中加入需要的模块,然后npminstall进行模块安装,并创建存储上传文件的临时文件夹uploadFiles.

工程目录结构:



"dependencies":{
"body-parser":"~1.13.1",
"cookie-parser":"~1.3.5",
"debug":"~2.2.0",
"ejs":"~2.3.2",
"express":"~4.13.0",
"express-session":"*",
"morgan":"~1.6.1",
"serve-favicon":"~2.3.0",
"ali-data-mock":"0.1.3",
"ali-data-proxy-lite":"1.1.16",
"ccap":"*",
"fs-extra":"*",//上传文件需要导入的包;
"formidable":"*",
"request":"*"
}


第二步:html页面

<!----------------------------------编辑支付方式------------------------------------->
<divclass="modalfade"id="editChannel"tabindex="-1"role="dialog"aria-labelledby="editTit"aria-hidden="true">
<divclass="modal-dialog">
<divclass="modal-content">
<formenctype="multipart/form-data"id="upPayChannelForm"method="post">
/****该处设置form的编码方式(multipart/form-data表示有文件需要提交)******/
<divclass="modal-header">
<buttontype="button"class="close"data-dismiss="modal"aria-label="Close"><spanaria-hidden="true">×</span></button>
<h4class="modal-title"id="editTit">编辑支付方式</h4>
</div>
<divclass="modal-body">
<divclass="form-group">
<p>支付方式<spanclass="fill_in">(必填)</span></p>
<p><inputtype="text"class="form-control"name="name"value="{{upChannel.name}}"ng-model="upChannel.name"readonly/></p>
<phidden><inputtype="text"class="form-control"name="type"value="{{upChannel.type}}"ng-model="upChannel.type"/></p>
</div>
<divclass="form-group">
<p>收款账号<spanclass="fill_in">(必填)</span></p>
<p><inputtype="text"class="form-control"name="account"value="{{upChannel.account}}"ng-model="upChannel.account"/><p>
</div>
<divclass="form-group">
<p>私有密码<spanclass="fill_in">(必填)</span></p>
35<p><inputtype="password"class="form-control"name="privatePassword"value="{{upChannel.privatePassword}}"ng-model="upChannel.privatePassword"/></p>
</div>
<divclass="form-group">
<p>公钥<spanclass="fill_in">(必填)</span></p>
<p><inputtype="file"name="publickey"id="publicKeyUp"fileread="upChannel.publicKey"accept=".cer,.cex,.crt,.key"/></p>
</div>
<divclass="form-group">
<p>密钥<spanclass="fill_in">(必填)</span></p>
<p><inputtype="file"name="privateKey"id="privateKeyup"fileread="upChannel.privateKey"accept=".cer,.cex,.crt,.key"/></p>
</div>
<divclass="form-group">
<p>附加内容<spanclass="fill_in">(必填)</span></p>
<p><inputtype="text"class="form-control"name="addition"value="{{upChannel.addition}}"ng-model="upChannel.addition"/></p>
</div>
</div>
<divclass="modal-footer">
<buttontype="cancel"class="cancel"data-dismiss="modal">返回</button>
<buttontype="button"class="submitcreateNormalAppBtn"ng-click="updateChannel()">完成</button>
</div>
</form>
</div>
</div>
</div>

<scriptsrc="http://malsup.github.io/jquery.form.js"></script>//引入jquery.form.js文件,后面service中才能只提交数据,控制页面不跳转



第三步:controller中对表单进行验证:

//编辑支付方式;
$scope.upChannel={
"id":"",
"businessId":"",
"name":"",
"type":"",
"account":"",
"addition":"",
"privatePassword":"",
"userName":"",
"businessName":"",
"locked":"",
"publicKey":"",
"privateKey":""
}
$scope.updateChannel=function(){
//console.log(JSON.stringify($scope.upChannel));
if(checkUpChannel($scope.upChannel)){//表单验证通过后,checkUpChannel($scope.upChannel)函数对表单元素进行一般的验证;
channel.updateChannel($scope.upChannel).then(function(data){//验证通过后将表单中非file元素数据提交到service层处理;
if(data=="success"){
angular.element("#editChannel").modal("hide");
getChannelList(1,10);
}
},function(err){
if(err.code=='ECONNREFUSED'){
Tip(err.code);
}else{
Tip(err.statusCode);
}
});
}
}


第四步:service中:

//编辑支付方式
updateChannel:function(upChannel){
vardeferred=$q.defer();
varuser=JSON.parse(utf8to16(base64decode($cookies.userPay)));//获取cookie

console.log("service:"+JSON.stringify(upChannel));
//手动提交表单;
varupForm=document.getElementById("upPayChannelForm");
//设置表单要提交的路径,这里的'/channel/update'是node端配置的路由;
upForm.action='/channel/update?userId='+user.userId+'&businessId='+user.businessId+'&modeId='+upChannel.id+'&name='+upChannel.name+'&type='+upChannel.type;

//使用jqeury.form.js插件中的ajaxSubmit提交表单,但是页面并不跳转,在一般的表单提交中,如果设置了action属性,那么在提交时页面会自动跳转到action属性所对应的页面中

$("#upPayChannelForm").ajaxSubmit(function(message){

//对于表单提交成功后处理,message为提交页面saveReport.htm的返回内容
vardata=JSON.parse(message);
//console.log(data);
if(data.code==200){
returndeferred.resolve('success');
}elseif(data.code=='ECONNREFUSED'){
returndeferred.reject(data);
}else{
swal("",data.info,"error");
returndeferred.reject(data);//结果正确后返回给controller
}
});
returndeferred.promise;
}


第五步:在app.js文件里配置nodejs路由:

varexpress=require('express');
varpath=require('path');
varfavicon=require('serve-favicon');
varlogger=require('morgan');
varcookieParser=require('cookie-parser');
varbodyParser=require('body-parser');
varejs=require("ejs");

/***********文件上传1**************/
//varbusboy=require('connect-busboy');//middlewareforform/fileupload

/********设置nodejs路由对应的文件*************/
varindex=require('./routes/index');
varccap=require('./routes/ccap');
varjiami=require("./routes/jiami");
varchangePwd=require('./routes/changePwd');
varlogin=require("./routes/login");
varbusiness=require("./routes/pay/business");
varlogs=require("./routes/pay/logs");
varchannel=require("./routes/pay/channel");//配置路由
varconfig=require("./routes/pay/config");

//varfileUpload=require("./routes/fileUpload");
/********设置nodejs路由对应的文件*************/

varapp=express();
/**********文件上传1*****************/
//app.use(busboy());
/***********文件上传2************/
//app.use(bodyParser({defer:true}));

//viewenginesetup
app.set('views',path.join(__dirname,'views'));
//app.set('viewengine','ejs');
app.engine('html',ejs.__express);
app.set('viewengine','html');

//uncommentafterplacingyourfaviconin/public
//app.use(favicon(path.join(__dirname,'public','favicon.ico')));

app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:false}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname,'public')));

//登录拦截器
app.use(function(req,res,next){
//varip=getClientIp(req);
console.log("获取的cookie是:"+req.cookies.userCookiesPay);
varurl=req.originalUrl;
varuserCookiesPay=req.cookies.userCookiesPay;
varbusinessIndex=url.indexOf('/business')!=-1;
varchangePwdIndex=url.indexOf('/changePwd')!=-1;
varlogsIndex=url.indexOf('/logs')!=-1;
varchannelIndex=url.indexOf('/channel')!=-1;
varconfigIndex=url.indexOf('/config')!=-1;
if(url=='/login'&&!(userCookiesPay==undefined)){
returnres.redirect('/');
}elseif((userCookiesPay==undefined)&&(businessIndex||changePwdIndex||logsIndex||channelIndex||configIndex)){
returnres.redirect('/');
}
next();
});
/***********node路由************/
app.use('/',index);
app.use('/ccap',ccap);
app.use("/app/jiami",jiami);
app.use("/login",login);
app.use("/changePwd",changePwd);
app.use("/business",business);
app.use("/logs",logs);
app.use("/channel",channel);
app.use("/config",config);

//app.use("/fileUpload",fileUpload);

/***********node路由************/

//catch404andforwardtoerrorhandler
app.use(function(req,res,next){
varerr=newError('NotFound');
err.status=404;
next(err);
});

//errorhandlers

//developmenterrorhandler
//willprintstacktrace
if(app.get('env')==='development'){
app.use(function(err,req,res,next){
res.status(err.status||500);
res.render('error',{
message:err.message,
error:err
});
});
}

//productionerrorhandler
//nostacktracesleakedtouser
app.use(function(err,req,res,next){
res.status(err.status||500);
res.render('error',{
message:err.message,
error:{}
});
});
module.exports=app;


第六步:最重要的来了,在channel.js文件里进行上传文件和提交表单给后端:

varexpress=require('express');
varrouter=express.Router();
varcrypto=require('crypto');
/****导入上传文件所需要的包********/
varrequest=require('request');
varpath=require('path');//usedforfilepath
varformidable=require('formidable');
varfs=require('fs-extra');//FileSystem-neededforrenamingfileetc

//编辑支付方式
router.post("/update",function(req,res){
/**********从action的path地址中获取需要的参数*********************/
varip=getClientIp(req);
varclientIp=ip.substring(7,ip.length);
varbusinessId=req.query.businessId;
varuserId=req.query.userId;
varmodeId=req.query.modeId;
varname=req.query.name;
vartype=req.query.type;
varpublicName,privateName;
//定义一个表单,post存储表单中元素的name和value,为json格式数据;file为表单中选择的文件,
varform=newformidable.IncomingForm();
varpost={},file={};
form.uploadDir="./../routes/uploadFiles";//表单中文件上传的临时文件的位置;
form.encoding="utf-8";//设置form编码;
form.keepExtensions=true;//保留后缀
form.on('error',function(err){
console.log(err);//各种错误
})
//POST:表单中除文件之外的普通数据,不包含文件field:表单中元素的namevalue:表单中元素的value值
.on('field',function(field,value){
if(form.type=='multipart'){//有文件上传时enctype="multipart/form-data"
if(fieldinpost){//同名表单checkbox返回array同get处理
if(util.isArray(post[field])===false){
post[field]=[post[field]];
}
post[field].push(value);
return;
}
}
if(field=='name'){
post[field]=name;
}else{
post[field]=value;
}
if(field=='type'){
post[field]=type;
}else{
post[field]=value;
}
console.log(field+"---"+post[field]);
})
.on('file',function(field,file){//上传文件,对表单中选择的每个文件进行遍历;
console.log("表单中的内容:"+JSON.stringify(post));
//console.log(file);//打印上传文件结构
console.log(field);//文件field,即html中<inputtype='file'name='XXX'/>中的name属性值;
console.log(file.name);//文件名称
console.log(file.size);//文件大小
console.log(file.type);//文件类型
console.log(file.path);//文件路径
if(field=='publickey'){
publicName=file.name;
}
if(field=='privateKey'){
privateName=file.name;
}
file[field]=file;
//console.log("fiel["+field+']='+file[field]);
fs.rename(file.path,form.uploadDir+"/"+file.name,function(err){
//默认会将上传的文件自动生成一个文件名存储在设置的路径下,现在将改文件重新命名为上传文件本身的名称移动到工程目录下;
if(err)
throwerr;
})
console.log("参数列表:"+modeId+"-"+userId+"-"+businessId+"-"+clientIp+"-"+post['name']+"-"+post['account']+"-"+post['type']+"-"+post['addition']+"-"+post['privatePassword']);
console.log(publicName+"/"+privateName+"/"+(privateName!=undefined&&publicName!=undefined));

if(privateName!=undefined&&publicName!=undefined){//判断两个文件都上传完成后,开始将表单提交给后端;
//console.log(fs.createReadStream(path.join(form.uploadDir+"/",publicName)));
//console.log(fs.createReadStream(path.join(form.uploadDir+"/",privateName)));
vardata={
modeId:modeId,
userId:userId,
businessId:businessId,
ip:clientIp,
name:post['name'],
account:post['account'],
type:post['type'],
addition:post['addition'],
privatePassword:post['privatePassword'],
publicKey:fs.createReadStream(path.join(form.uploadDir+"/",publicName)),//读取上传的文件,并存储在文件流中
privateKey:fs.createReadStream(path.join(form.uploadDir+"/",privateName))//读取上传的文件,并存储在文件流中

};
//request.post直接请求后台接口,url:为后台接口,?后面是需要跟的参数,formData:是需要传递的表单数据(有文件的话包含了文件),optionCallback为回调函数,请求成功后所做的处理。
request.post({url:'http://10.3.30.117:8888/payplus/internal/v1/pay/business/'+businessId+'/mode/'+modeId+'/update?name='+post['name']+'&account='+post['account']+'&addition='+post['addition']+'&type='+post['type']+'&privatePassword='+post['privatePassword']+'&userId='+userId+'&ip='+clientIp,formData:data},functionoptionalCallback(err,httpResponse,body){
console.log('uploadfailed:'+err);
//console.log(httpResponse);
if(err){
//returnconsole.error('uploadfailed:',err);
console.log('uploadfailed:'+err);
varerror=JSON.parse(err);
if(error.code=='ECONNREFUSED'){
res.status(error.code).send(error);
}elseif(error.statusCode==404||error.statusCode==500){
res.status(error.statusCode).send(error);
}else{
varresponseText=JSON.parse(error.responseText);
res.send(responseText);
}
}
console.log('Uploadsuccessful!Serverrespondedwith:',body);
res.send(body);//将后台返回的结果返回给service;
});
}
})
.on('end',function(){
console.log("success");
});
form.parse(req);//解析request对象

});
module.exports=router;


至此,编辑支付方式的表单就可以成功上传并存储在数库了。


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: