项目:status2 spring hibernate
最近写了个模块,人员档案库,由于客户要求要实现多文件上传,所以苦逼的又要学习新的知识了,多文件上传已经实现了,所以在这里做个笔记。
1,首先到官网下载js,css,引入项目
或将文件拖到这里,单个文件大小不超过2M,单次上传文件总大小不超过20M
(function( $ ){
// 当domReady的时候开始初始化
$(function() {
var $wrap = $('#uploader'),
// 图片容器
$queue = $( '
' )
.appendTo( $wrap.find( '.queueList' ) ),
// 状态栏,包括进度和控制按钮
$statusBar = $wrap.find( '.statusBar' ),
// 文件总体选择信息。
$info = $statusBar.find( '.info' ),
// 上传按钮
$upload = $wrap.find( '.uploadBtn' ),
// 没选择文件之前的内容。
$placeHolder = $wrap.find( '.placeholder' ),
$progress = $statusBar.find( '.progress' ).hide(),
// 添加的文件数量
fileCount = 0,
// 添加的文件总大小
fileSize = 0,
// 所有文件的进度信息,key为file id
percentages = {},
// 实例化
uploader = WebUploader.create({
pick: {
id: '#filePicker',
label: '点击选择文件',
name:"multiFile"
},
formData: {
//这里可以向后台传自定义的参数比如 key:value
},
dnd: '#dndArea',
paste: '#uploader',
swf: '../../js/webuploader/Uploader.swf',//引用Uploader.swf,去官网下载
fileVal:'multiFile',
chunked: false, // 是否分片上传
chunkSize: 512 * 1024,
server: 'http://localhost:8080/ctcst/archives_uploadInformation.action', //提交到服务器
//规定文件上传的格式
accept: {
title: 'file',
extensions: 'gif,jpg,jpeg,bmp,png',
mimeTypes: 'image/*'
},
// 禁掉全局的拖拽功能。这样不会出现图片拖进页面的时候,把图片打开。
disableGlobalDnd: true,
fileNumLimit: 10,
fileSizeLimit: 20 * 1024 * 1024, // 20 M
fileSingleSizeLimit: 2 * 1024 * 1024 // 2 M
});
// 拖拽时不接受 js, txt 文件。
uploader.on( 'dndAccept', function( items ) {
var denied = false,
len = items.length,
i = 0,
// 修改js类型
unAllowed = 'text/plain;application/javascript ';
for ( ; i < len; i++ ) {
// 如果在列表里面
if ( ~unAllowed.indexOf( items[ i ].type ) ) {
denied = true;
break;
}
}
return !denied;
});
// 添加“添加文件”的按钮,
uploader.addButton({
id: '#filePicker2',
label: '继续添加'
});
uploader.on('ready', function() {
window.uploader = uploader;
});
// 上传失败触发
uploader.on('uploadError', function (file, reason) {
console.log(file);
console.log(reason);
console.log('上传失败' + reason);
});
//成功时触发
uploader.on('uploadSuccess', function (file, response) {
console.log(file);
console.log(response);
console.log('上传成功' + response);
});
// 文件上传后服务端响应,服务端处理失败返回false,调用uploadError事件
uploader.on('uploadAccept', function(obj, ret){
console.log(obj);
console.log(ret);
console.log('uploadAccept===执行了');
});
// 当有文件添加进来时执行,负责view的创建
function addFile( file ) {
var $li = $( '' +
''+
'' + file.name + '
' +
'
' +
' ' ),
$btns = $('' +
'删除' +
'向右旋转' +
'向左旋转').appendTo( $li ),
$prgress = $li.find('p.progress span'),
$wrap = $li.find( 'p.imgWrap' ),
$info = $(''),
showError = function( code ) {
switch( code ) {
case 'exceed_size':
text = '文件大小超出';
break;
case 'interrupt':
text = '上传暂停';
break;
default:
text = '上传失败,请重试';
break;
}
$info.text( text ).appendTo( $li );
};
if ( file.getStatus() === 'invalid' ) {
showError( file.statusText );
} else {
// @todo lazyload
$wrap.text( '预览中' );
uploader.makeThumb( file, function( error, src ) {
var img;
if ( error ) {
// 跟据文件类型显示对应缩略图 jpg,png直接预览
// gif,jpg,jpeg,bmp,png,zip,rar,pdf,xls,xlsx,doc,docx
var fileExt = file.ext;
switch (fileExt) {
case 'zip':
src = getadress() + '/csim/ctcst/archives/images/ZIP.jpg';
break;
case 'xlsx':
src = getadress() + '/csim/ctcst/archives/images/XLSX.png';
break;
case 'rar':
src = getadress() + '/csim/ctcst/archives/images/RAR.jpg';
break;
case 'pdf':
src = getadress() + '/csim/ctcst/archives/images/PDF.jpg';
break;
case 'xls':
src = getadress() + '/csim/ctcst/archives/images/XLS.png';
break;
case 'doc':
src = getadress() + '/csim/ctcst/archives/images/DOC.png';
break;
case 'docx':
src = getadress() + '/csim/ctcst/archives/images/DOCX.png';
break;
default :
$wrap.text( '文件格式不支持预览' );
return;
}
}
if( isSupportBase64 ) {
img = $('
');
$wrap.empty().append( img );
}
}, thumbnailWidth, thumbnailHeight );
percentages[ file.id ] = [ file.size, 0 ];
file.rotation = 0;
}
file.on('statuschange', function( cur, prev ) {
if ( prev === 'progress' ) {
$prgress.hide().width(0);
} else if ( prev === 'queued' ) {
//取消旋转删除div
//$li.off( 'mouseenter mouseleave' );
//$btns.remove();
}
// 成功
if ( cur === 'error' || cur === 'invalid' ) {
//console.log( file.statusText );
showError( file.statusText );
percentages[ file.id ][ 1 ] = 1;
} else if ( cur === 'interrupt' ) {
showError( 'interrupt' );
} else if ( cur === 'queued' ) {
percentages[ file.id ][ 1 ] = 0;
} else if ( cur === 'progress' ) {
$info.remove();
$prgress.css('display', 'block');
} else if ( cur === 'complete' ) {
$li.append( '' );
}
$li.removeClass( 'state-' + prev ).addClass( 'state-' + cur );
});
$li.on( 'mouseenter', function() {
$btns.stop().animate({height: 30});
});
$li.on( 'mouseleave', function() {
$btns.stop().animate({height: 0});
});
$btns.on( 'click', 'span', function() {
var index = $(this).index(),
deg;
switch ( index ) {
case 0:
uploader.removeFile( file );
return;
case 1:
file.rotation += 90;
break;
case 2:
file.rotation -= 90;
break;
}
if ( supportTransition ) {
deg = 'rotate(' + file.rotation + 'deg)';
$wrap.css({
'-webkit-transform': deg,
'-mos-transform': deg,
'-o-transform': deg,
'transform': deg
});
} else {
$wrap.css( 'filter', 'progid:DXImageTransform.Microsoft.BasicImage(rotation='+ (~~((file.rotation/90)%4 + 4)%4) +')');
}
});
$li.appendTo( $queue );
}
// 负责view的销毁
function removeFile( file ) {
var $li = $('#'+file.id);
delete percentages[ file.id ];
updateTotalProgress();
$li.off().find('.file-panel').off().end().remove();
}
});
})( jQuery );
后台接收数据如下:
第一步:建一个vo类,用于接收前台传来的参数
public class UploadImagesVo {
private String id;
//文件上传需要的参数
private File multiFile[];
private String multiFileFileName[];
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public File[] getMultiFile() {
return multiFile;
}
public void setMultiFile(File[] multiFile) {
this.multiFile = multiFile;
}
public String[] getMultiFileFileName() {
return multiFileFileName;
}
public void setMultiFileFileName(String[] multiFileFileName) {
this.multiFileFileName = multiFileFileName;
}
}
Entity
@Table(name = "PX_DA_UPLOAD_INFO")
public class UploadInfromation {
private String id;
private String dataCategory;//资料类别 ,个人资料 班级资料
private String type;//类型 如:培训详情,鉴定详情
private String batchNo;//班级编号==属于哪个班级
private String fileName;//重命名之后的文件名称
private String uploadName;//文件原始名称
private String fileId;//文件的唯一标识
private String path;//文件全路径
private String filePath;//文件所在路径
private String jgNo; //上传文件机构编号
private String idNumber; //个人身份证
@Id
@GeneratedValue(generator = "upload_info_uuid")
@GenericGenerator(name = "upload_info_uuid", strategy = "uuid")
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getIdNumber() {
return idNumber;
}
public void setIdNumber(String idNumber) {
this.idNumber = idNumber;
}
public String getFileId() {
return fileId;
}
public void setFileId(String fileId) {
this.fileId = fileId;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public String getDataCategory() {
return dataCategory;
}
public void setDataCategory(String dataCategory) {
this.dataCategory = dataCategory;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getBatchNo() {
return batchNo;
}
public void setBatchNo(String batchNo) {
this.batchNo = batchNo;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getUploadName() {
return uploadName;
}
public void setUploadName(String uploadName) {
this.uploadName = uploadName;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getJgNo() {
return jgNo;
}
public void setJgNo(String jgNo) {
this.jgNo = jgNo;
}
}
@SuppressWarnings("serial")
public class ArchivesAction extends ActionSupport implements ModelDriven{
private UploadImagesVo vo = new UploadImagesVo();
private IUploadImagesService uploadService;
/**
* 上传信息
*/
public void uploadInformation(){
Json json = new Json();
try {
UploadInformVo up = uploadService.uploadInformations(vo);
json.setObj(up);
json.setSuccess(true);
}catch (Exception e){
e.printStackTrace();
json.setMsg(e.getMessage());
}
writeJson(json);
}
/**
* 写出json
* @param object 任何类型
*/
public void writeJson(Object object) {
try {
String json = JSON.toJSONStringWithDateFormat(object, "yyyy-MM-dd");
ServletActionContext.getResponse().setContentType(
"text/html;charset=utf-8");
ServletActionContext.getResponse().getWriter().write(json);
ServletActionContext.getResponse().getWriter().flush();
ServletActionContext.getResponse().getWriter().close();
} catch (IOException e) {
e.printStackTrace();
}
}
public IUploadImagesService getUploadService() {
return uploadService;
}
@Resource
public void setUploadService(IUploadImagesService uploadService) {
this.uploadService = uploadService;
}
@Override
public UploadImagesVo getModel() {
return vo;
}
}
public interface IUploadInformDao extends IBaseDAO{
}
@Component
public class UploadInformDao extends BaseDAO implements IUploadInformDao {
}
public interface IUploadImagesService {
/**
* 文件上传
* @param vo
* @throws Exception
*/
public UploadInformVo uploadInformations(UploadImagesVo vo) throws Exception;
}
@Component
public class UploadImagesService implements IUploadImagesService {
private IUploadInformDao uploadInformDao;
/**
* 文件上传
* @param vo
* @throws Exception
*/
public UploadInformVo uploadInformations(UploadImagesVo vo) throws Exception{
//取到当前登录的用户信息
Users user = SecurityUser.getCurrentUserInfo();
//生成MD5值
String MD5 = getMd5ByFile(vo.getMultiFile()[0]);
//上传的文件名
String fileName =MD5+vo.getMultiFileFileName()[0].substring(vo.getMultiFileFileName()[0].lastIndexOf("."));
//指定输出的路径,从项目的配置文件里读取
PropertiesUtil propertiesu = PropertiesUtil.getInstance();
String path = propertiesu.getKeyValue("archivesPath");
if(!StringUtil.isNull(vo.getLx())){
path+= File.separatorChar+vo.getLx();
}
if(!StringUtil.isNull(vo.getTypes())){
path+=File.separatorChar+vo.getTypes();
}
if(!StringUtil.isNull(vo.getBatchNo())){
path+=File.separatorChar+vo.getBatchNo();
}
if(!StringUtil.isNull(vo.getIdNumber())){
path+=File.separatorChar+vo.getIdNumber();
}
//查询上传的图片是否已经上传过了,每个图片的MD5是唯一的
UploadInfromation upload = new UploadInfromation();
upload.setFilePath(path);
upload.setFileId(MD5);
List list = uploadInformDao.findByProperties(upload);
if(list.size() > 0){
throw new Exception(vo.getMultiFileFileName()[0]+" 文件在"+path+" 这个路径中已存在");
}
//取到文件并调用outFile方法写到指定的路径
File file = vo.getMultiFile()[0];
outFile(path, file,fileName);
//然后把数据保存到数据库
if(!StringUtil.isNull(vo.getBatchNo())){
upload.setBatchNo(vo.getBatchNo());
}
if(!StringUtil.isNull(vo.getIdNumber())){
upload.setIdNumber(vo.getIdNumber());
}
upload.setDataCategory(vo.getLx());
upload.setType(vo.getTypes());
upload.setFileName(fileName);
upload.setUploadName(vo.getMultiFileFileName()[0]);
String filePath = path + File.separatorChar +fileName;
upload.setPath(filePath);
upload.setJgNo(user.getUnitId());
uploadInformDao.save(upload);
//通过写出去图片的路径生成Base64编码,并用vo返回到jsp页面展示
String str = imageToBase64(upload.getPath());
UploadInformVo vov = new UploadInformVo();
BeanUtils.copyProperties(upload,vov);
String s = vo.getMultiFileFileName()[0].substring(vo.getMultiFileFileName()[0].indexOf(".")+1,vo.getMultiFileFileName()[0].length());
String src = "data:image/"+s+";base64,"+str;
vov.setBase64(src);
return vov;
}
/**
* 生成md5
* @param file 图片文件
* @return MD5值
* @throws FileNotFoundException
*/
private String getMd5ByFile(File file) throws FileNotFoundException {
String value = null;
FileInputStream in = new FileInputStream(file);
try {
MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(byteBuffer);
BigInteger bi = new BigInteger(1, md5.digest());
value = bi.toString(16);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(null != in) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return value;
}
/**
* 通过文件路径将文件转成Base64编码
* @param path 文件路径
* @return base64结果
*/
private String imageToBase64(String path) {
// 将图片文件转化为字节数组字符串,并对其进行Base64编码处理
byte[] data = null;
// 读取图片字节数组
try {
InputStream in = new FileInputStream(path);
data = new byte[in.available()];
in.read(data);
in.close();
} catch (IOException e) {
e.printStackTrace();
}
// 对字节数组Base64编码
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(data);// 返回Base64编码过的字节数组字符串
}
/**
* 指定的地方写出文件
* @param outPath 文件路径
* @param tempFile 文件
* @param fileName 文件名
* @throws IOException 错误异常
*/
private void outFile(String outPath,File tempFile,String fileName) throws IOException {
RandomAccessFile raFile = null;
BufferedInputStream inputStream=null;
try{
File dirFile = new File(outPath);
if(!dirFile.exists()) {
dirFile.mkdirs();
}
File outFile = new File(outPath + File.separatorChar +fileName);
raFile = new RandomAccessFile(outFile, "rw");
raFile.seek(raFile.length());
inputStream = new BufferedInputStream(new FileInputStream(tempFile));
byte[] buf = new byte[1024];
int length = 0;
while ((length = inputStream.read(buf)) != -1) {
raFile.write(buf, 0, length);
}
}catch(Exception e){
throw new IOException(e.getMessage());
}finally{
try {
if (inputStream != null) {
inputStream.close();
}
if (raFile != null) {
raFile.close();
}
}catch(Exception e){
throw new IOException(e.getMessage());
}
}
}
public IUploadInformDao getUploadInformDao() {
return uploadInformDao;
}
@Resource
public void setUploadInformDao(IUploadInformDao uploadInformDao) {
this.uploadInformDao = uploadInformDao;
}
}
总结:到这里一个完整示例的多文件上传,再把数据保存到数据库已经完成了,这个示例仅供参考,毕竟我们用的框架是不一样,还有项目的ssh框架还有一定的分装,但是实现思路都是一样的,在这里留个笔记。也希望能给同学们一点启发,谢谢。