1、后端上传
//使用缓存字节流和字节数组来最快的写入视频流
private String uploadFile(FileInfo fileInfo, String filePath) {
//filePath = filePath.replaceAll("/", "\\\\\\\\");
//文件上传项
String filename = fileInfo.getFileName(); //获得上传文件名称
//判断文件夹是否存在,不存在则新建
File file = new File(filePath + filename);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
try {
//使用缓冲字节流来上传文件
BufferedInputStream bis = new BufferedInputStream(fileInfo.getInputStream());
//文件存储位置
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath + filename));
//使用字节数组来加快写视频数据
byte[] bytes = new byte[2048];
int len;
while ((len = bis.read(bytes)) != -1) {
bos.write(bytes, 0, len);
}
bis.close();
bos.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
//返回url地址
return filePath + filename;
}
//自己创建的文件对象
package com.inpor.mc.util.ftp;
import java.io.InputStream;
import java.io.Serializable;
/**
* Created by lijunqi on 2015/6/4.
* 上传的文件信息
*/
public class FileInfo implements Serializable {
private String fileName;//上传文件的名称
private String contentType;//上传文件的类型
private Long fileSize;//上传文件输入流
private String parentPath;//存储文件父目录
private InputStream inputStream;//上传文件输入流
private String filePath; //文件路径
private byte[] datas;//数据
private Long ftpId;
private boolean isJdbc = false;
public FileInfo() {
}
/**
* 构建fileInfo
*/
public FileInfo(String fileName, String contentType, String parentPath, InputStream inputStream) {
this.fileName = fileName;
this.contentType = contentType;
this.parentPath = parentPath;
this.inputStream = inputStream;
}
/**
* 构建fileInfo
*/
public FileInfo(String fileName, String contentType, InputStream inputStream) {
this.fileName = fileName;
this.contentType = contentType;
this.inputStream = inputStream;
}
/**
* 构建fileInfo
*/
public FileInfo(String fileName, String contentType, Long fileSize, String parentPath, InputStream inputStream) {
this.fileName = fileName;
this.contentType = contentType;
this.fileSize = fileSize;
this.parentPath = parentPath;
this.inputStream = inputStream;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public Long getFileSize() {
return fileSize;
}
public void setFileSize(Long fileSize) {
this.fileSize = fileSize;
}
public String getParentPath() {
return parentPath;
}
public void setParentPath(String parentPath) {
this.parentPath = parentPath;
}
public InputStream getInputStream() {
return inputStream;
}
public void setInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public byte[] getDatas() {
return datas;
}
public void setDatas(byte[] datas) {
this.datas = datas;
}
public Long getFtpId() {
return ftpId;
}
public void setFtpId(Long ftpId) {
this.ftpId = ftpId;
}
public boolean isJdbc() {
return isJdbc;
}
public void setJdbc(boolean jdbc) {
isJdbc = jdbc;
}
public FileInfo cloneThis() throws CloneNotSupportedException {
FileInfo cloneInfo = new FileInfo();
cloneInfo.setFileName(this.fileName);
cloneInfo.setContentType(this.contentType);
cloneInfo.setFileSize(this.fileSize);
cloneInfo.setParentPath(this.parentPath);
cloneInfo.setInputStream(this.inputStream);
cloneInfo.setFilePath(this.filePath);
cloneInfo.setDatas(this.datas);
cloneInfo.setFtpId(this.ftpId);
cloneInfo.setJdbc(this.isJdbc);
return cloneInfo;
}
}
2、前端上传组件
2.1、第一个组件kendoUI的使用
function generateUpload() {
var uploadTimestamp = $("#upload-timestamp").val();
var uploadIndex = $("#upload-index").val();
var uploadDeptId = $("#upload-deptId").val();
var uploadSaveUrl = getBackCtx() + "/studio/myresc/uploadResource?timestamp=" + uploadTimestamp + "&index=" + uploadIndex + "&deptId=" + uploadDeptId;
var uploadRemoveUrl = getBackCtx() + "/studio/myresc/removeUploadResc?type=0×tamp=" + uploadTimestamp + "&index=" + uploadIndex + "&deptId=" + uploadDeptId;
var uploadDiv = $("#videos-upload .form-control");
uploadDiv.html('<input type="file" name="videos" id="videos" />');
$("#videos").kendoUpload({
async: {
saveUrl: uploadSaveUrl,
removeUrl: uploadRemoveUrl,
autoUpload: true
},
complete: onComplete,
cancel: onCancel,
remove: onRemove,
showFileList: true,
success: function (e) {
var operation = e.operation;
var responseData = e.response;
if (responseData != undefined && responseData.error != undefined) {
showBubble("文件" + responseData.error);
isUploadSuccess = false;
return;
}
isUploadSuccess = true;
$.each(e.files, function (index, value) {
var name = value.name;
if (operation == 'upload') {
showBubble("文件" + "【" + name + "】" + "上传成功" + "!");
} else {
showBubble("文件" + "【" + name + "】" + "移除成功" + "!");
}
});
},
multiple: true,
error: onError,
upload: onUpload,
select: onSelect,
progress: onProgress,
localization: {
uploadSelectedFiles: "上传",
cancel: "取消",
remove: "移除",
retry: "重试",
select: "请选择...",
statusUploaded: "已完成",
statusFailed: "上传失败",
statusUploading: "上传中..."
}
});
}
或者直接在文件加载时,某个元素被点击是加载:
<script>
$(document).ready(function() {
$("#files").kendoUpload({
async: {
saveUrl: "save",
removeUrl: "remove",
autoUpload: true
}
});
});
</script>
2.2、使用AngularJS上传文件
<p>
<input id="fileUpload" type="file" />
<button ng-click="ok()">上传</button><br>
<input ng-model="user.username" />
<input ng-model="user.password" />
</p>
$scope.ok = function () {
var form = new FormData(); var file = document.getElementById("fileUpload").files[0];
var user =JSON.stringify($scope.user);
form.append('file', file);
form.append('user',user); $http({
method: 'POST',
url: '/addUser',
data: form,
headers: {'Content-Type': undefined},
transformRequest: angular.identity
}).success(function (data) {
console.log('operation success');
}).error(function (data) {
console.log('operation fail');
})
};
后台:
@RequestMapping("/upload")
public Map<String, Object> upload(@RequestParam(value = "file") MultipartFile file, @RequestParam(value = "user", required = true) String user) {
try {
FileInputStream in = (FileInputStream) headImg.getInputStream();
//将Json对象解析为UserModel对象
FileOutputStream out = new FileOutputStream("filePathAndName"))
ObjectMapper objectMapper = new ObjectMapper();
UserModel userModel = objectMapper.readValue(user, UserModel.class);
//保存文件到filePathAndName
int hasRead = 0;
byte[] bytes = new byte[1024];
while ((hasRead = in.read(bytes)) > 0) {
out.write(bytes, 0, hasRead);
}
} catch (IOException e) {
e.printStackTrace();
}
}
2.3、使用elementUI组件实现上传
<el-upload
class="upload-demo"
action="https://jsonplaceholder.typicode.com/posts/"
:on-preview="handlePreview"
:on-remove="handleRemove"
:before-remove="beforeRemove"
multiple
:limit="3"
:on-exceed="handleExceed"
:file-list="fileList">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
<script>
export default {
data() {
return {
fileList: [{name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}, {name: 'food2.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}]
};
},
methods: {
handleRemove(file, fileList) {
console.log(file, fileList);
},
handlePreview(file) {
console.log(file);
},
handleExceed(files, fileList) {
this.$message.warning(`当前限制选择 3 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`);
},
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${ file.name }?`);
}
}
}
</script>
后端代码跟2.2同理。
3、知识扩展
- 上传大文件时,怎么快速向服务器写视频数据,最快的组合是使用字节缓冲流+字节数组的方案最快。
- 写文档文件时使用字符流reader/writer更好,而其他类型的文件时使用inputsteam/outputsteam更好。