1利用layui上传组件,制作多文件上传表格
创建.jsp文件,layui的引用路径记得改
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Demo</title>
<!-- 请勿在项目正式环境中引用该 layui.css 地址 -->
<link href="layui/css/layui.css" rel="stylesheet">
</head>
<body>
<div class="layui-upload">
<button type="button" class="layui-btn layui-btn-normal" id="ID-upload-demo-files">选择多文件</button>
<div class="layui-upload-list">
<table class="layui-table">
<colgroup>
<col style="min-width: 100px;">
<col width="150">
<col width="260">
<col width="150">
</colgroup>
<thead>
<th>文件名</th>
<th>大小</th>
<th>上传进度</th>
<th>操作</th>
</thead>
<tbody id="ID-upload-demo-files-list"></tbody>
</table>
</div>
<button type="button" class="layui-btn" id="ID-upload-demo-files-action">开始上传</button>
</div>
<!-- 请勿在项目正式环境中引用该 layui.js 地址 -->
<script src="layui/layui.js"></script>
<script>
layui.use(function(){
var upload = layui.upload;
var element = layui.element;
var $ = layui.$;
// 制作多文件上传表格
var uploadListIns = upload.render({
elem: '#ID-upload-demo-files',
elemList: $('#ID-upload-demo-files-list'), // 列表元素对象
url: 'upload.do', // 此处用的是第三方的 http 请求演示,实际使用时改成您自己的上传接口即可。
accept: 'file',
multiple: true,
number: 5,
auto: false,
bindAction: '#ID-upload-demo-files-action',
choose: function(obj){
var that = this;
var files = this.files = obj.pushFile(); // 将每次选择的文件追加到文件队列
// 读取本地文件
obj.preview(function(index, file, result){
var tr = $(['<tr id="upload-'+ index +'">',
'<td>'+ file.name +'</td>',
'<td>'+ (file.size/1024).toFixed(1) +'kb</td>',
'<td><div class="layui-progress" lay-filter="progress-demo-'+ index +'"><div class="layui-progress-bar" lay-percent=""></div></div></td>',
'<td>',
'<button class="layui-btn layui-btn-xs demo-reload layui-hide">重传</button>',
'<button class="layui-btn layui-btn-xs layui-btn-danger demo-delete">删除</button>',
'</td>',
'</tr>'].join(''));
// 单个重传
tr.find('.demo-reload').on('click', function(){
obj.upload(index, file);
});
// 删除
tr.find('.demo-delete').on('click', function(){
delete files[index]; // 删除对应的文件
tr.remove(); // 删除表格行
// 清空 input file 值,以免删除后出现同名文件不可选
uploadListIns.config.elem.next()[0].value = '';
});
that.elemList.append(tr);
element.render('progress'); // 渲染新加的进度条组件
});
},
done: function(res, index, upload){ // 成功的回调
var that = this;
// if(res.code == 0){ // 上传成功
var tr = that.elemList.find('tr#upload-'+ index)
var tds = tr.children();
tds.eq(3).html(''); // 清空操作
delete this.files[index]; // 删除文件队列已经上传成功的文件
return;
//}
this.error(index, upload);
},
allDone: function(obj){ // 多文件上传完毕后的状态回调
console.log(obj)
},
error: function(index, upload){ // 错误回调
var that = this;
var tr = that.elemList.find('tr#upload-'+ index);
var tds = tr.children();
// 显示重传
tds.eq(3).find('.demo-reload').removeClass('layui-hide');
},
progress: function(n, elem, e, index){ // 注意:index 参数为 layui 2.6.6 新增
element.progress('progress-demo-'+ index, n + '%'); // 执行进度条。n 即为返回的进度百分比
}
});
});
</script>
</body>
</html>
2创建uploadFileServlet.需要文件上传下载的包
commons-fileupload-1.4 commons-io-1.4放在lib文件夹下面
代码如下
package com.it.servlet;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.json.JSONException;
import org.json.JSONObject;
import com.it.util.SnowFlakeUtils;
/**
* Servlet implementation class UploadFileServlet
*/
public class UploadFileServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public UploadFileServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doPost(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("------开始上传----");
//创建map封装需要的返回值,前端需要通过done函数的res获取该值
response.setContentType("text/html;charset=utf-8");
//JSONObject工具,用户信息转换为字符串,需要引入org.json.jar包
JSONObject json = new JSONObject();
//判断用户是否是multipart类型
if(ServletFileUpload.isMultipartContent(request)){
//创建磁盘工厂,设置内存大小喝临时存储位置
DiskFileItemFactory factory = new DiskFileItemFactory();
//如果文件大小大于内存大小则存储在临时存储空间
//临时文件使用之后会自动删除
//如果不设置,默认的临时存储空间是
File tempDirFile = new File("D:\\tempDir");
if(!tempDirFile.exists()){
tempDirFile.mkdir();
}
factory.setRepository(tempDirFile);
//创建ServletFileUpload设置单个文件夹上传大小以及整个request域大小
ServletFileUpload upload=new ServletFileUpload(factory);
//解析request域,list中存放了表单数据加文件
try {
List <FileItem> list = upload.parseRequest(request);
for(FileItem item:list){
if(item.isFormField()){
//如果是表单数据
if(item.getFieldName().equals("user_id")){
String usr_id = item.getString("utf-8");
}
}else {
//如果上传的是文件
//解析出文件后缀名
String fileSuffxName = item.getName().substring(item.getName().lastIndexOf("."));
//用雪花算法生成一个名称加文件后缀形成一个新的名字
//最终将文件存储在d:\\upload目录中
File file = new File("D:\\upload\\"+SnowFlakeUtils.nextId()+fileSuffxName);
item.write(file);
json.put("data", "success");
}
}
} catch (Exception e) {
// TODO: handle exception
try {
json.put("data", "error");
} catch (JSONException e1) {
// TODO: handle exception
e1.printStackTrace();
}
}
}
//返回json字符串,告知前端上传成功还是失败
response.getWriter().print(json.toString());
}
}
其中所需雪花算法,需要创建一个工具类util,
用雪花算法生成一个名称加文件后缀形成一个新的名字
代码如下
package com.it.util;
import java.time.LocalDateTime;
public class SnowFlakeUtils {
//起始时间戳
private final static long START_STMP=1637666189914L;
private final static long SEQUENCE_BIT=12;//序列号占用12bit
private final static long MACHINE_BIT=5;//机器号占用5bit
private final static long MACHINE_HOUSE_BIT=5;//机房号占用5bit
/*
-1的源码 10000001
-1的反码 11111110
-1的补码 11111111
-1左移12位= 1111 1111 0000 0000 0000
-1 = 1111 1111 1111 1111 1111
异或运算 = 0000 0000 1111 1111 1111=4095
因此MAX_SEQUENCE的值为4095
*/
private final static long MAX_SEQUENCE=-1L^(-1L<<SEQUENCE_BIT);
//同理 MAX_MACHINE为31
private final static long MAX_MACHINE=-1L^(-1L<<MACHINE_BIT);
//同理 MAX_MACHINE_HOUSE值为31
private final static long MAX_MACHINE_HOUSE=-1L^(-1L<<MACHINE_HOUSE_BIT);
//机器ID
private static long machineID;
//机房ID
private static long machineHouseID;
private static long lastTime=0;//上一次生成ID的时间戳
private static long sequence=0;//序列号,默认为0
public SnowFlakeUtils(long machineID, long machineHouseID) {
this.machineID = machineID;
this.machineHouseID = machineHouseID;
}
public long getMachineID() {
return machineID;
}
public void setMachineID(long machineID) {
this.machineID = machineID;
}
public long getMachineHouseID() {
return machineHouseID;
}
public void setMachineHouseID(long machineHouseID) {
this.machineHouseID = machineHouseID;
}
/***
*产生下一个ID
* 用long型来表示我们生成的64位ID,
* @return
*/
public static synchronized long nextId(){
if(machineHouseID>MAX_MACHINE_HOUSE ||machineID>MAX_MACHINE){
throw new RuntimeException("机房ID或机器ID超出最大值");
}
//获取当前时间戳
long currentTime=System.currentTimeMillis();
//如果当前时间小于上一次生成ID的时间,抛出异常
if(currentTime<lastTime){
throw new RuntimeException("当前时间为异常值,请勿回拨时间!");
}
//如果当前时间等于上一次生成ID时间,说明是在同一毫秒中生成,那么序列号加一
else if(currentTime==lastTime){
/*
MAX_SEQUENCE: 0000 1111 1111 1111
&
4096: 0001 0000 0000 0000
= 0
当sequence小于4095时, (sequence+1)&MAX_SEQUENCE=sequence+1
当sequence等于4095时,(sequence+1)&MAX_SEQUENCE=0
*/
sequence= (sequence+1)&MAX_SEQUENCE;
if(sequence==0L){
//获取下一个毫秒值
currentTime=getNextMill();
}
}else{
//毫秒值不同,sequence初始为0
sequence=0L;
}
//更新最近一次生成时间的毫秒值
lastTime=currentTime;
return (currentTime-START_STMP)<<22//左移22位 空出机房ID5位+机器ID5位+序列号12位
|machineID<<12//左移12位 空出序列号12位
|machineHouseID<<17//左移17位 空出机器ID5位+序列号12位
|sequence;//序列号部分
}
/**
* 获取下一个毫秒值
* @return
*/
private static long getNextMill() {
long mill=System.currentTimeMillis();
//如果当前时间等于上一次的时间则一直自旋
while(mill==lastTime){
mill=System.currentTimeMillis();
}
return mill;
}
}
最终实现的效果如下
最后看上传的文件夹里面是否有自己上传的文件