java+js实现文件分片上传

备注

 为了方便测试引入了vue.js和axios.js;
 文件访问路径
 http://localhost:1011/static/files/87badbee40b746dba924beae49f702b8.md
 static/ 后面的是数据库存储的路径

数据库表

CREATE TABLE `file_entity` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `file_name` varchar(64) DEFAULT NULL COMMENT '文件名称',
  `file_url` varchar(255) DEFAULT NULL COMMENT '文件路径',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '修改时间',
  `type` int(11) DEFAULT NULL COMMENT '文件类型',
  `del` bit(1) DEFAULT b'0' COMMENT '状态',
  `shard_index` bigint(20) DEFAULT NULL COMMENT '已上传分片',
  `shard_total` bigint(20) DEFAULT NULL COMMENT '分片总数',
  `file_key` varchar(255) DEFAULT NULL COMMENT '文件标识',
  `suffix` varchar(64) DEFAULT NULL COMMENT '文件名后缀',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

java代码

pom 依赖

<!-- tkMybatis -->
			<dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.35</version>
            </dependency>
            <dependency>
                <groupId>tk.mybatis</groupId>
                <artifactId>mapper-spring-boot-starter</artifactId>
                <version>2.1.2</version>
            </dependency>
             <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.78</version>
            </dependency>

配置类

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author zhaohanqing
 * @createTime 2022-03-02 16:19
 * @description
 */
@Configuration
public class FilePathConfig implements WebMvcConfigurer {
    @Value("${file.local.path}")
    private String fileLocalPath;

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("file:" + fileLocalPath);
    }
}

文件上传路径类

public class UploadPathConstant {
    /** 文件上传路径 */
    public static final String  FILE_VIDEO = "files/";
}

yml配置

file:     #文件上传路径配置文件
  local:
    path: D:/files/

实体类

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import java.io.Serializable;
import java.util.Date;

/**
 * @author zhaohanqing
 * @createTime 2022-04-18 14:26
 * @description
 */
@Data
public class FileEntity implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(generator = "JDBC")
    private Long id;
    private String fileName;
    /**
     * 文件路径
     */
    private String fileUrl;
    /**
     * 创建时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createTime = new Date();
    /**
     * 修改时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date updateTime = new Date();
    /**
     * 文件类型 1 图片,2 视频
     */
    private Integer type;
    /**
     * 状态0:正常, 1:禁用
     */
    @JsonIgnore
    private Boolean del = false;
    /**
     * 已上传分片
     */
    private Long shardIndex;
    /**
     * 分片总数
     */
    private Long shardTotal;
    /**
     * 文件标识
     */
    @JsonIgnore
    private String fileKey;

    /**
     * 文件名后缀
     */
    @JsonIgnore
    private String suffix;
}

mapper

import com.store.entity.FileEntity;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import tk.mybatis.mapper.common.Mapper;

import java.util.List;

/**
 * @author zhaohanqing
 * @createTime 2022-04-18 17:23
 * @description
 */
public interface FileEntityMapper extends Mapper<FileEntity> {

    /**
     * 根据fileKey修改上传下标
     * @author zhaohanqing
     * @createTime 2022/4/19 15:46
     * @param fileEntity
     * @return
     */
    void updateShardIndexByFileKey(FileEntity fileEntity);

    /**
     * 查询所有fileKey
     * @author zhaohanqing
     * @createTime 2022/4/19 15:49
     * @param
     * @return
     */
    @Select("SELECT file_key from file_entity where del = 0")
    List<String> selectFileKey();

    /**
     * 根据fileKey查询数据
     * @author zhaohanqing
     * @createTime 2022/4/19 15:41
     * @param fileKey
     * @return
     */
    @Select("SELECT COUNT(*) FROM file_entity WHERE del = 0 AND file_key = #{fileKey}")
    int selectByFileKey(@Param("fileKey") String fileKey);
}

mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.store.mapper.FileEntityMapper">
    <update id="updateShardIndexByFileKey">
        update file_entity
        set shard_index = #{shardIndex},
            update_time = #{updateTime}
        where file_key = #{fileKey}
    </update>

service

import com.store.entity.FileEntity;
import com.store.enums.FileTypeEnum;
import com.store.enums.HttpCodeEnum;
import com.store.mapper.FileEntityMapper;
import com.store.service.IFileEntityService;
import com.store.utils.ResultUtil;
import com.store.utils.UUIDUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zhaohanqing
 * @createTime 2022-04-18 14:31
 * @description
 */
@Service
public class FileEntityServiceImpl {

    private final Logger logger = LoggerFactory.getLogger(FileEntityServiceImpl.class);
    @Value("${file.local.path}")
    public String fileLocalPath;
    @Resource
    private FileEntityMapper fileEntityMapper;
    /**
     *
     * @author zhaohanqing
     * @createTime 2022/4/19 13:58
     * @param fileEntity
     * @param uploadFile
     * @return
     */
    public ResultUtil addFileEntity(FileEntity fileEntity, MultipartFile uploadFile) throws Exception {
       if (uploadFile == null && null == fileEntity.getFileKey() && null == fileEntity.getShardIndex() && null == fileEntity.getSuffix()) {
           return ResultUtil.error(HttpCodeEnum.ILLEGAL_PARAMS);
        }
        String localFileName = fileEntity.getFileKey() + "." + fileEntity.getShardIndex();
        File targetFile = new File(this.fileLocalPath + UploadPathConstant.FILE_VIDEO, localFileName);
        /*
         * 判断是否存在文件夹,不存在则新建
         */
        if (!targetFile.getParentFile().exists()) {
            targetFile.getParentFile().mkdirs();
        }
        uploadFile.transferTo(targetFile);
        fileEntity.setFileUrl(UploadPathConstant.FILE_VIDEO + fileEntity.getFileKey() + "." + fileEntity.getSuffix());
        /*
         * 将数据持久化到数据库
         */
        save(fileEntity);
        /*
         * 最后一片的时候合并分片
         */
        if (fileEntity.getShardIndex().equals(fileEntity.getShardTotal())) {
            merge(fileEntity);
        }
        return ResultUtil.success(HttpCodeEnum.OK);
    }
    /**
     * 将数据写入数据库
     * @author zhaohanqing
     * @createTime 2022/4/19 15:24
     * @param fileEntity
     * @return
     */
    private void save(FileEntity fileEntity) {
            int byFileKey = this.fileEntityMapper.selectByFileKey(fileEntity.getFileKey());
            fileEntity.setUpdateTime(new Date());
            if (byFileKey == 0) {
                fileEntity.setCreateTime(new Date());
                this.fileEntityMapper.insert(fileEntity);
                return;
            }
            this.fileEntityMapper.updateShardIndexByFileKey(fileEntity);
    }
    /**
     * 合并分片
     * @author zhaohanqing
     * @createTime 2022/4/19 15:35
     * @param fileEntity
     * @return
     */
    private void mergeFileEntity(FileEntity fileEntity) throws Exception {
        String fileName = fileEntity.getFileKey();
        Long shardTotal = fileEntity.getShardTotal();
        File newFile = new File(this.fileLocalPath +  UploadPathConstant.FILE_VIDEO + fileName + "." + fileEntity.getSuffix());
        FileOutputStream outputStream = new FileOutputStream(newFile, true);
        FileInputStream fileInputStream = null;
        byte[] byt = new byte[10485760];
        try {
            for (int i = 0; i < shardTotal.longValue(); i++) {
                fileInputStream = new FileInputStream(new File(this.fileLocalPath + UploadPathConstant.FILE_VIDEO + fileName + "." + (i + 1)));
                int len;
                while ((len = fileInputStream.read(byt)) != -1) {
                    outputStream.write(byt, 0, len);
                }
            }
        } catch (IOException e) {
            logger.error("", e);
        } finally {
            try {
                if (fileInputStream != null) {
                    fileInputStream.close();
                }
                outputStream.close();
                logger.info("close");
            } catch (Exception e) {
                logger.error("Exception", e);
            }
        }
        System.gc();
        Thread.sleep(100L);
        for (int i = 0; i < shardTotal; i++) {
            String filePath = this.fileLocalPath + UploadPathConstant.FILE_VIDEO + fileName + "." + (i + 1);
            File file = new File(filePath);
            file.delete();
        }
    }

controller

import com.store.entity.FileEntity;
import com.store.enums.HttpCodeEnum;
import com.store.service.FileEntityServiceImpl;
import com.store.utils.ResultUtil;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;

/**
 * @author zhaohanqing
 * @createTime 2022-04-18 14:24
 * @description 文件管理
 */
@RestController
@RequestMapping("/fileEntity")
public class FileEntityController extends BaseController {
    @Resource
    private FileEntityServiceImpl fileEntityService;

    /**
     * 文件分片上传
     * @author zhaohanqing
     * @createTime 2022/4/18 14:33
     * @param fileEntity
     * @param uploadFile
     * @return
     */
    @PostMapping("addFileEntity")
    public ResultUtil addFileEntity(FileEntity fileEntity, MultipartFile uploadFile) throws Exception {
        if (null == fileEntity || fileEntity.getType() == null) {
            return ResultUtil.error(HttpCodeEnum.ILLEGAL_PARAMS);
        }
        return fileEntityService.addFileEntity(fileEntity, uploadFile);
    }
}

前端代码

html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="https://zhaohq.life/js/vue.js"></script>
		<script src="https://zhaohq.life/js/axios.js"></script>
		<script src="https://zhaohq.life/js/uuidv4.min.js"></script>

	</head>
	<body>
		<div id="app">
			<input type="file" @change="addFile($event)" />
			<div @click="addClick">上传</div>
		</div>
	</body>
	<script>
		let app = new Vue({
			el: '#app',
			data: {
				name: 'vue',
				fileList: []
			},
			methods: {
				test(videoTestName, shardIndex, key) {
					//获取表单中的file
					var file = this.fileList[0];
					//文件分片  以20MB去分片
					var shardSize = 20 * 1024 * 1024;
					//定义分片的起始位置
					var start = (shardIndex - 1) * shardSize;
					//定义分片结束的位置  file哪里来的?
					var end = Math.min(file.size, start + shardSize);
					//从文件中截取当前的分片数据
					var fileShard = file.slice(start, end);
					//分片的大小
					var size = file.size;
					//总片数
					var shardTotal = Math.ceil(size / shardSize);
					//文件的后缀名
					var fileName = file.name;
					var suffix = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length).toLowerCase();
					
					let params = new FormData(); // 创建form对象
					params.append('type',2)
					params.append('uploadFile', fileShard);
					params.append('shardIndex', shardIndex);
					params.append('shardTotal', shardTotal);
					params.append('fileKey', key);
					params.append('suffix', suffix);
					axios.post('http://127.0.0.1:18080/webadmin/fileEntity/addFileEntity', params).then(res => {
						if (shardIndex < shardTotal) {
							var index = shardIndex + 1;
							this.test(videoTestName, index,key);
						} else {
							console.log("上传成功");
						}
					});



				},
				addClick() {
					console.log("点击了");
					// 发送 POST 请求
					let a = uuidv4().replace(/-/g, "");
					this.test("文件名", 1, a)
				},
			
				addFile(e) {
					console.log(e.target.files);
					this.fileList = [...e.target.files]
				}

			}
		})
	</script>
</html>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
简单的利用javajs实现文件 package com.fendou.myString; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.Iterator; 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.FileItemFactory; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; public class FileUpload extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { boolean a=ServletFileUpload.isMultipartContent(request); if(a){ FileItemFactory factory=new DiskFileItemFactory(); ServletFileUpload upload=new ServletFileUpload (factory); Iterator items; try{ items=upload.parseRequest (request).iterator(); while(items.hasNext()){ FileItem item=(FileItem) items.next(); if(!item.isFormField()){ String name=item.getName (); String fileName=name.substring(name.lastIndexOf("\\")+1, name.length()); String path=request.getRealPath("file")+File.pathSeparatorChar+fileName; File uploadFile=new File (path); request.getSession ().setAttribute("file", uploadFile); item.write(uploadFile); response.setContentType ("text/html"); response.setCharacterEncoding("utf-8"); PrintWriter out=response.getWriter(); // out.print("<font size='2'> 上文件为:"+name+"<br>"); // out.print("保存在服务器上 的地址为:"+path+"</font>"); } } }catch(Exception e){ e.printStackTrace(); } } response.sendRedirect("smartupload.jsp"); } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值