最近有个项目需求是上传文件,一般是压缩包。上传到服务器进行进一步的操作。且需要支持单、多文件上传
由于项目一直使用的是angularjs写的前端,所有学习研究了下它自己的上传插件,写了个demo。简单记录一下,留作笔记
插件的GitHub地址:点击跳转
api地址:点击跳转
官方案例:点击跳转
大部分逻辑都在代码注解中体现出来,不在累赘。直接贴代码
1 . 未使用angular-file-upload控件
<!DOCTYPE html>
<html>
<head>
<!-- 页面meta -->
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>上传任务测试</title>
<meta content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no" name="viewport">
<link rel="stylesheet" href="../plugins/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="../plugins/adminLTE/css/AdminLTE.css">
<link rel="stylesheet" href="../plugins/adminLTE/css/skins/_all-skins.min.css">
<link rel="stylesheet" href="../css/style.css">
<script src="../plugins/jQuery/jquery-2.2.3.min.js"></script>
<script src="../plugins/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../plugins/bootstrap/js/bootstrap-filestyle.js"></script>
<!-- 引入的文件上传样式 -->
<script type="text/javascript" src="../plugins/angularjs/angular.min.js"></script>
<script type="text/javascript" src="../plugins/angularjs/ui-bootstrap-tpls.min.js"></script>
<!-- 提示model文件 -->
<script type="text/javascript" src="../js/base.js"></script>
<script type="text/javascript" src="../js/controller/baseController.js"></script>
<script type="text/javascript" src="../js/controller/uploadController.js"></script>
<script type="text/javascript" src="../js/service/uploadService.js">
</script>
</head>
<body class="hold-transition skin-red sidebar-mini" ng-app="report" ng-controller="uploadController">
<!-- 正文区域 -->
<div class="box-body">
<!--tab页-->
<div class="nav-tabs-custom">
<div class="tab-content">
<div class="tab-pane active" id="home">
<div class="modal-body">
<!-- bootstrap开始 -->
<div class="well">
<h3>文件上传测试</h3>
<hr>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
<input type="file" name="file" id="file">
</div>
</div>
<div class="col-xs-2">
<div class="form-group">
<button type="submit" class="btn btn-primary"
ng-click="uploadfile()">
<span class="glyphicon glyphicon-ok"></span> 上传
</button>
</div>
</div>
</div>
</div>
<!-- bootstrap结束-->
</div>
</div>
</div>
</div>
</div>
</body>
<script type="text/javascript">
//样式初始化
$('#file').filestyle({
'placeholder' : '请选择上传的源码压缩包(200M以内)'
})
</script>
</html>
这是没使用上传插件编写的文件上传,核心是
<script type="text/javascript" src="../js/controller/uploadController.js"></script>
<script type="text/javascript" src="../js/service/uploadService.js">
这两个js文件中的方法
当点击上传按钮就会触发controller中的uploadfile方法,
$scope.uploadfile=function(){
//新增
uploadService.uploadFile().success(
function(response){
if(response.success){
alert("上传成功!");
$window.location.reload();//引入window服务,刷新当前页
}else{
alert("上传失败!");
}
}
);
}
然后去调用uploadservice中的上传方法
//上传文件
this.uploadFile=function(){
var formdata=new FormData();
formdata.append('file',file.files[0]); //file 文件上传框的name,就是根据这个来去页面获取文件
return $http({
url:'../upload.do', //文件上传时候对应的controller
method:'post',
data:formdata, //上传的数据
headers:{ 'Content-Type':undefined },
transformRequest: angular.identity
});
}
参数解释:
这样就会将前台选择的文件传递到后台进行处理,后台对应的Java方法如下,具体根据实际需求进行修改
@RestController
public class UploadController {
@RequestMapping("/upload")
public Result uploadCode(MultipartFile file) throws Exception {
long startTime = System.currentTimeMillis();
String originalFilename = file.getOriginalFilename();// 取文件的全名(带后缀的)
System.out.println("文件名字"+originalFilename);
Boolean remoteZipToFile = false;// 文件解压缩是否成功标识符
try {
// 重命名上传后的文件名(存储的文件名字)
String fileName = file.getOriginalFilename();
// 定义上传后的存储路径
String path = "/Users/zshuai/Desktop/上传/" + fileName;
File localFile = new File(path);
// 如果这个文件目录不存在,先创建
if (!localFile.exists()) {
localFile.mkdirs();
}
file.transferTo(localFile);// 保存到代码运行的服务器上
remoteZipToFile = true;
long endTime = System.currentTimeMillis();
System.out.println("采用file.Transto的运行时间:" + String.valueOf(endTime - startTime) + "ms");
} catch (Exception e) {
e.printStackTrace();
}
return new Result(remoteZipToFile, originalFilename);
}
至于显示文件格式大小之类的,前端可以相应处理,本demo在后端springmvc.xml中设置了文件上传的大小,为800M
2. 使用angular-file-upload控件
页面
<!DOCTYPE html>
<html id="ng-app" ng-app="app"> <!-- id="ng-app" IE<8 -->
<head>
<title>文件上传控件</title>
<link rel="stylesheet" href="../plugins/bootstrap/css/bootstrap.min.css">
<!-- Fix for old browsers -->
<script src="../js/es5-shim.min.js"></script>
<script src="../js/es5-sham.min.js"></script>
<script src="../plugins/jQuery/jquery-2.2.3.min.js"></script>
<script src="../js/console-sham.js"></script>
<script src="../plugins/bootstrap/js/bootstrap.min.js"></script>
<!--<script src="../bower_components/angular/angular.js"></script>-->
<script type="text/javascript" src="../plugins/angularjs/angular.min.js"></script>
<script src="../js/angular-file-upload.min.js"></script>
<script src="controllers.js"></script>
<style>
.my-drop-zone { border: dotted 3px lightgray; }
.nv-file-over { border: dotted 3px red; } /* Default class applied to drop zones on over */
.another-file-over-class { border: dotted 3px green; }
html, body { height: 100%; }
</style>
</head>
<!-- nv-file-drop:支持文件脱拽选择; nv-file-select:点击选择;uploader用于绑定在控制器中新建的upload对象。 -->
<body ng-controller="AppController" nv-file-drop="" uploader="uploader" filters="queueLimit, customFilter">
<div class="container">
<div class="row">
<div class="col-md-3">
<h3>选择文件</h3>
多文件
<input type="file" nv-file-select="" uploader="uploader" multiple /><br/>
单文件
<input type="file" nv-file-select="" uploader="uploader" />
</div>
<div class="col-md-9" style="margin-bottom: 40px">
<h3>上传队列</h3>
<p>队列长度: {{ uploader.queue.length }}</p>
<table class="table">
<thead>
<tr>
<th width="50%">Name</th>
<th ng-show="uploader.isHTML5">尺寸</th>
<th ng-show="uploader.isHTML5">进展</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in uploader.queue">
<td><strong>{{ item.file.name }}</strong></td>
<td ng-show="uploader.isHTML5" nowrap>{{ item.file.size/1024/1024|number:2 }} MB</td>
<td ng-show="uploader.isHTML5">
<div class="progress" style="margin-bottom: 0;">
<div class="progress-bar" role="progressbar" ng-style="{ 'width': item.progress + '%' }"></div>
</div>
</td>
<td class="text-center">
<span ng-show="item.isSuccess"><i class="glyphicon glyphicon-ok"></i></span>
<span ng-show="item.isCancel"><i class="glyphicon glyphicon-ban-circle"></i></span>
<span ng-show="item.isError"><i class="glyphicon glyphicon-remove"></i></span>
</td>
<td nowrap>
<button type="button" class="btn btn-success btn-xs" ng-click="item.upload()" ng-disabled="item.isReady || item.isUploading || item.isSuccess">
<span class="glyphicon glyphicon-upload"></span> 上传
</button>
<button type="button" class="btn btn-warning btn-xs" ng-click="item.cancel()" ng-disabled="!item.isUploading">
<span class="glyphicon glyphicon-ban-circle"></span> 取消
</button>
<button type="button" class="btn btn-danger btn-xs" ng-click="item.remove()">
<span class="glyphicon glyphicon-trash"></span> 移除
</button>
</td>
</tr>
</tbody>
</table>
<div>
<div>
队列进度:
<div class="progress" style="">
<div class="progress-bar" role="progressbar" ng-style="{ 'width': uploader.progress + '%' }"></div>
</div>
</div>
<button type="button" class="btn btn-success btn-s" ng-click="uploader.uploadAll()" ng-disabled="!uploader.getNotUploadedItems().length">
<span class="glyphicon glyphicon-upload"></span> 上传全部
</button>
<button type="button" class="btn btn-warning btn-s" ng-click="uploader.cancelAll()" ng-disabled="!uploader.isUploading">
<span class="glyphicon glyphicon-ban-circle"></span> 全部取消
</button>
<button type="button" class="btn btn-danger btn-s" ng-click="uploader.clearQueue()" ng-disabled="!uploader.queue.length">
<span class="glyphicon glyphicon-trash"></span> 移除所有
</button>
</div>
</div>
</div>
</div>
</body>
</html>
注意看里面的注解
<!-- nv-file-drop:支持文件脱拽选择; nv-file-select:点击选择;uploader用于绑定在控制器中新建的upload对象。 -->
此案例是依据官网提供的demo,再理解使用的时候加上自己的注释然后调用自己后台的方法实现
官网demo将前端controller以及service都写在一起,就没再变动,直接在里面进行修改使用
var app = angular.module('app', [ 'angularFileUpload' ]);
app.controller( 'AppController', [ '$scope', 'FileUploader', function($scope, FileUploader) {
//注册过滤器
var uploader = $scope.uploader = new FileUploader({
url : '../upload.do' // 上传路径
});
// FILTERS
// a sync filter
//过滤器
uploader.filters .push({
name : 'syncFilter',
fn : function(item /* {File|FileLikeObject} */,
options) {
console.log('syncFilter');
return this.queue.length < 10;
}
});
// an async filter
uploader.filters.push({
name : 'asyncFilter',
fn : function(item /* {File|FileLikeObject} */, options,
deferred) {
console.log('asyncFilter');
setTimeout(deferred.resolve, 1e3);
}
});
// 回调函数
//添加文件失败时
uploader.onWhenAddingFileFailed = function( item /* {File|FileLikeObject} */, filter, options) {
console.info('onWhenAddingFileFailed', item, filter,
options);
};
//将单个文件添加到队列后触发
uploader.onAfterAddingFile = function(fileItem) {
console.info('onAfterAddingFile', fileItem);
};
//将所有拖动或选定的文件添加到队列后触发
uploader.onAfterAddingAll = function(addedFileItems) {
console.info('onAfterAddingAll', addedFileItems);
};
//在上传文件之前触发
uploader.onBeforeUploadItem = function(item) {
console.info('onBeforeUploadItem', item);
};
//文件上传进度
uploader.onProgressItem = function(fileItem, progress) {
console.info('onProgressItem', fileItem, progress);
};
//上传队列进度
uploader.onProgressAll = function(progress) {
console.info('onProgressAll', progress);
};
//已上传成功的文件
uploader.onSuccessItem = function(fileItem, response,
status, headers) {
console.info('onSuccessItem', fileItem, response,
status, headers);
};
//上传错误
uploader.onErrorItem = function(fileItem, response, status,
headers) {
console.info('onErrorItem', fileItem, response, status, headers);
alert("文件体积超过单个文件最大值800M(该数值对应后台配置文件中的springmvc.xml中的配置)")
};
//取消上传
uploader.onCancelItem = function(fileItem, response,
status, headers) {
console.info('onCancelItem', fileItem, response,
status, headers);
};
//文件上传完成(独立于操作的成功)
uploader.onCompleteItem = function(fileItem, response,
status, headers) {
console.info('onCompleteItem', fileItem, response,
status, headers);
};
//在上传整个队列时加载所有内容,或在上传单个独立文件时加载文件
uploader.onCompleteAll = function() {
console.info('onCompleteAll');
};
console.info('uploader', uploader);
} ]);
里面添加了很多自己的个人理解注释,都是通过解读API理解后进行标注,若有不对的地方请留言告知,感谢
这样就简单实现了单文件、多文件的上传,且支持进度显示等操作,当然可以根据自己的实际需求进行二次开发。
补充:
上传文件时候涉及附带参数,以便区分(比如区分那个用户上传的)
一种是直接在上传路径URL中写死,这种静态的,如果参数是变化的,动态的,就不行了,可以用如下格式
// 注册量化分析工具过滤器
var uploader = $scope.uploader = new FileUploader({
url : '../upload.do' // 上传路径
});
//在上传文件之前触发,添加检测任务ID以及检测工具tag用来区分
uploader.onBeforeUploadItem = function(item) {
formData = [{"id":ids},{"tag":"fx"}];
Array.prototype.push.apply(item.formData, formData);
};
其中的参数可根据自己的需求进行动态设置绑定,因为onBeforeUploadItem此函数为将文件上传前触发,从时间逻辑上完全可以实现。后端接收直接根据参数key来获取即可
@RequestMapping("/upload")
//id: 代表检测任务的ID tag:代表那个工具发Q起的请求
public Result uploadCode(MultipartFile file,String id, String tag) throws Exception {
System.out.println("tid为:"+id);
if (tag.equals("fx")) {
System.out.println("分析工具");
}