form表单action提交表单,页面不跳转且表单数据含文件的处理方法
在最近的项目中需要将含 input[type='file']的表单提交给后台 ,并且后台需要将文件存储在数据库中。之前所用的方法都是先将文件上传到七牛服务器上,然后七牛会返回文件的下载地址,在提交表单的时候将文件的下载地址和其他表单元素一起提交即可。但是现在考虑到安全性,这些文件不能上传到七牛服务器上,得直接提交给后台存储到数据库中,在此需要注意以下问题:
1、提交表单时,如果要提交file,那么form标签里必须使用 enctype="multipart/form-data" 来设置编码。
2、提交表单时,为了使页面不跳转,引用jquery.form.js插件,使用ajaxSubmit方法提交表单;
3、提交到nodejs后先将文件上传至node服务器,然后再将文件传给后端。
下面说一个具体的例子(例子中用了angularjs+nodejs+express):
第一步:在package.json页面中加入需要的模块,然后npm install进行模块安装,并创建存储上传文件的临时文件夹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页面
<!----------------------------------编辑支付方式------------------------------------->
<div class="modal fade" id="editChannel" tabindex="-1" role="dialog" aria-labelledby="editTit" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<form enctype="multipart/form-data" id="upPayChannelForm" method="post" >
/****该处设置form的编码方式(multipart/form-data表示有文件需要提交)******/
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="editTit">编辑支付方式</h4>
</div>
<div class="modal-body">
<div class="form-group">
<p>支付方式<span class="fill_in">(必填)</span></p>
<p><input type="text" class="form-control" name="name" value="{{upChannel.name}}" ng-model="upChannel.name" readonly/></p>
<p hidden><input type="text" class="form-control" name="type" value="{{upChannel.type}}" ng-model="upChannel.type"/></p>
</div>
<div class="form-group">
<p>收款账号<span class="fill_in">(必填)</span></p>
<p><input type="text" class="form-control" name="account" value="{{upChannel.account}}" ng-model="upChannel.account"/><p>
</div>
<div class="form-group">
<p>私有密码<span class="fill_in">(必填)</span></p>
35 <p><input type="password" class="form-control" name="privatePassword" value="{{upChannel.privatePassword}}" ng-model="upChannel.privatePassword"/></p>
</div>
<div class="form-group">
<p>公钥<span class="fill_in">(必填)</span></p>
<p><input type="file" name="publickey" id="publicKeyUp" fileread="upChannel.publicKey" accept=".cer,.cex,.crt,.key"/></p>
</div>
<div class="form-group">
<p>密钥<span class="fill_in">(必填)</span></p>
<p><input type="file" name="privateKey" id="privateKeyup" fileread="upChannel.privateKey" accept=".cer,.cex,.crt,.key"/></p>
</div>
<div class="form-group">
<p>附加内容<span class="fill_in">(必填)</span></p>
<p><input type="text" class="form-control" name="addition" value="{{upChannel.addition}}" ng-model="upChannel.addition"/></p>
</div>
</div>
<div class="modal-footer">
<button type="cancel" class="cancel" data-dismiss="modal">返回</button>
<button type="button" class="submit createNormalAppBtn" ng-click="updateChannel()">完成</button>
</div>
</form>
</div>
</div>
</div>
<script src="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){
var deferred= $q.defer();
var user=JSON.parse(utf8to16(base64decode($cookies.userPay)));//获取cookie console.log("service:"+JSON.stringify(upChannel));
//手动提交表单;
var upForm=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的返回内容
var data=JSON.parse(message);
//console.log(data);
if(data.code==200){
return deferred.resolve('success');
}else if(data.code=='ECONNREFUSED'){
return deferred.reject(data);
}else{
swal("",data.info,"error");
return deferred.reject(data);//结果正确后返回给controller
}
});
return deferred.promise;
}
第五步:在app.js文件里配置nodejs路由:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var ejs=require("ejs");
/***********文件上传1**************/
//var busboy = require('connect-busboy'); //middleware for form/file upload
/********设置nodejs路由对应的文件*************/
var index = require('./routes/index');
var ccap=require('./routes/ccap');
var jiami=require("./routes/jiami");
var changePwd=require('./routes/changePwd');
var login=require("./routes/login");
var business=require("./routes/pay/business");
var logs=require("./routes/pay/logs");
var channel=require("./routes/pay/channel");//配置路由
var config=require("./routes/pay/config");
//var fileUpload=require("./routes/fileUpload");
/********设置nodejs路由对应的文件*************/
var app = express();
/**********文件上传1*****************/
//app.use(busboy());
/***********文件上传2************/
//app.use(bodyParser({defer: true}));
// view engine setup
app.set('views', path.join(__dirname, 'views'));
//app.set('view engine', 'ejs');
app.engine('html',ejs.__express);
app.set('view engine', 'html');
// uncomment after placing your favicon in /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) {
// var ip=getClientIp(req);
console.log("获取的cookie是: "+req.cookies.userCookiesPay);
var url = req.originalUrl;
var userCookiesPay=req.cookies.userCookiesPay;
var businessIndex=url.indexOf('/business')!=-1;
var changePwdIndex=url.indexOf('/changePwd')!=-1;
var logsIndex=url.indexOf('/logs')!=-1;
var channelIndex=url.indexOf('/channel')!=-1;
var configIndex=url.indexOf('/config')!=-1;
if(url=='/login'&&!(userCookiesPay==undefined)){
return res.redirect('/');
}else if((userCookiesPay==undefined)&&(businessIndex||changePwdIndex||logsIndex||channelIndex||configIndex)){
return res.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路由************/
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
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
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
第六步:最重要的来了,在channel.js文件里进行上传文件和提交表单给后端:
var express = require('express');
var router = express.Router();
var crypto=require('crypto');
/****导入上传文件所需要的包********/
var request=require('request');
var path=require('path');//used for file path
var formidable = require('formidable');
var fs =require('fs-extra'); //File System-needed for renaming file etc
//编辑支付方式
router.post("/update",function(req,res){
/**********从action的path地址中获取需要的参数*********************/
var ip=getClientIp(req);
var clientIp=ip.substring(7,ip.length);
var businessId=req.query.businessId;
var userId=req.query.userId;
var modeId=req.query.modeId;
var name=req.query.name;
var type=req.query.type;
var publicName,privateName;
//定义一个表单,post存储表单中元素的name和value,为json格式数据;file为表单中选择的文件,
var form=new formidable.IncomingForm();
var post={},file={};
form.uploadDir="./../routes/uploadFiles";//表单中文件上传的临时文件的位置;
form.encoding="utf-8"; //设置form编码;
form.keepExtensions = true; //保留后缀
form.on('error', function(err) {
console.log(err); //各种错误
})
//POST:表单中除文件之外的普通数据,不包含文件 field:表单中元素的name value:表单中元素的value值
.on('field', function(field, value) {
if (form.type == 'multipart') { //有文件上传时 enctype="multipart/form-data"
if (field in post) {//同名表单 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中 <input type='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)
throw err;
})
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)));
var data={
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},function optionalCallback(err, httpResponse, body){
console.log('upload failed:'+err);
//console.log(httpResponse);
if (err) {
//return console.error('upload failed:', err);
console.log('upload failed:'+err);
var error=JSON.parse(err);
if(error.code=='ECONNREFUSED'){
res.status(error.code).send(error);
}else if(error.statusCode==404||error.statusCode==500){
res.status(error.statusCode).send(error);
}else{
var responseText=JSON.parse(error.responseText);
res.send(responseText);
}
}
console.log('Upload successful! Server responded with:', body);
res.send(body);//将后台返回的结果返回给service;
});
}
})
.on('end', function() {
console.log("success");
});
form.parse(req); //解析request对象 });
module.exports = router;
至此,编辑支付方式的表单就可以成功上传并存储在数库了。
form表单action提交表单,页面不跳转且表单数据含文件的处理方法的更多相关文章
- 在JS中模拟表单的post提交,进行页面的跳转
原文链接:https://blog.csdn.net/jal517486222/article/details/83147761 /* *功能: 模拟form表单的提交 *参数: URL 跳转地址 P ...
- js阻止表单默认提交、刷新页面
一.阻止刷新页面 在表单中的提交按钮<button></button>标签改为<input type="button">或者在<butto ...
- js的作用是临时修改 表单Action提交的地址,因为 又有新的动作需要把表单参数提交到 新的servlet中,这点很重要
JavaScript可以临时修稿 form表单的提交地址
- php 提交保存成功页面 倒计时 跳转
前几天做了一个简单的成功提示页面! 有需要的可以拿去用,写的不好 欢迎指正!~~ 因为工程是在CI下面做的,url 自己用的话需要改正下函数!site_url() 这个函数式CI框架的 <ht ...
- 使用jQuery.form插件,实现完美的表单异步提交
传送门:异步编程系列目录…… 时间真快,转眼一个月快结束了,一个月没写博客了!手开始生了,怎么开始呢…… 示例下载:使用jQuery.form插件,实现完美的表单异步提交.rar 月份的尾巴,今天的主 ...
- JavaWeb学习总结(十一):Session解决form表单重复提交
在平时开发中,如果网速比较慢的情况下,用户提交表单后,发现服务器半天都没有响应,那么用户可能会以为是自己没有提交表单,就会再点击提交按钮重复提交表单,我们在开发中必须防止表单重复提交. 一.表单重复提 ...
- java web学习总结(十三) -------------------使用Session防止表单重复提交
在平时开发中,如果网速比较慢的情况下,用户提交表单后,发现服务器半天都没有响应,那么用户可能会以为是自己没有提交表单,就会再点击提交按钮重复提交表单,我们在开发中必须防止表单重复提交. 一.表单重复提 ...
- 使用jQuery,实现完美的表单异步提交
jQuery异步提交表单 <form id="form1" method="post"> <table border="1" ...
- JavaWeb防止表单重复提交(转载)
转载自:http://blog.csdn.net/ye1992/article/details/42873219 在平时开发中,如果网速比较慢的情况下,用户提交表单后,发现服务器半天都没有响应,那么用 ...
随机推荐
- BeginInvoke与EndInvoke方法解决多线程接收委托返回值问题
BeginInvoke与EndInvoke方法解决多线程接收委托返回值问题 原文:http://www.sufeinet.com/thread-3707-1-1.html 大家可以先看看我上 ...
- AngularJS中实现日志服务
本篇体验使用AngularJS自定义一个记录日志的服务. 在AngularJS中,服务的一些写法是这样的: var app = angular.module('app',[]); app.provid ...
- shell 控制输出格式 echo printf
(1)echo [A@XY log]$ echo -e "ab\t45" #带格式输出ab 45[A@XY log]$ echo "ab\t45" ...
- Meanshift filter实现简单图片的卡通化效果
利用Meanshift filter和canny边缘检测的效果,可以实现简单的图片的卡通化效果.简单的说,就是用Meanshift filter的结果减去canny算法的结果得到卡通化的效果. ...
- PMBOK/CMM/CMMI/OPM3
1968年为了解决大型软件项目的软件危机,北大西洋公约组织(NATO)提出了“软件工程”这一术语,以改进软件开发设计过程. 1969年美国项目管理协会(PMI)组织成立,从1981年起经过30年的努力 ...
- 微信中直接下载APK
某天在微信中偶遇一个二维码,识别二维码竟然可以直接下载APK! 该二维码如下: 解码后获得地址:(在线解码工具) http://www.rmdown.com/newt66y.apk 这不就是个普通的A ...
- 关于创建可执行的jar文件(assembly)
java利用maven生成一个jar包,如何自动生成清单属性文件(MANIFEST.MF),如何解决jar依赖问题? 办法很简单: 只需在pom.xml文件中配置如下plugin即可: <plu ...
- ArcGIS Geodatabase版本控制机制的学习总结
本文是最近内部的一个学习的自我整理,只有关键信息,如果需要详细了解,请参阅ArcGIS帮助文档: http://resources.arcgis.com/zh-cn/help/main/10.1/in ...
- Solr4:数据导入(dataimport)时,不符合Solr日期类型要求的字段的处理
背景: 要求将一个SQL Server2012版本中的数据库导入到Solr中.数据表中有一字段用来存储birthday日期字段,为nvarchar类型,长度为8,格式为:yyyyMMdd. 导入Sol ...
- webapi mvc 基础
标题 状态 描述 WebAPI请求 http://www.cnblogs.com/babycool/p/3922738.html Media Formatters in ASP.NET W ...