实现多文件上传下载

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;
    }
}

最终实现的效果如下


 最后看上传的文件夹里面是否有自己上传的文件

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值