Fragment upload and breakpoint continue

Keywords: Fragment Spring JQuery Mybatis

We may encounter the upload of large files in our work. If we transfer them once, we may encounter various problems such as network and timeout. Here, we will introduce the scheme in two ways: fragment upload and breakpoint continue transfer.

1, Slice upload

Principle of fragment upload: the front end first requests the interface to obtain the uuid of this upload, upload time and other information to return to the front end page. The front end splits the files to be uploaded, including the uuid returned to the front end by the server, the md5 of the file, the identification of the uploaded section, and the file name. When the number of uploaded pieces is equal to the total number of pieces, merge all pieces and delete the temporary pieces.

This is demonstrated by springboot+freemarker
(the tool class used by the server and js used by the front end are also used for breakpoint resuming, which will be pasted after the introduction of breakpoint resuming.)

1. First, add the configuration file application.properties (mysql is also introduced because the breakpoint renewal depends on mysql)

server.port=8080

spring.freemarker.expose-spring-macro-helpers=true
# Whether to load template from the file system first to support hot loading. The default value is true
spring.freemarker.prefer-file-system-access=true
# Set the suffix of the template
spring.freemarker.suffix=.ftl
# Set the loading path of the template. Multiple paths are separated by commas. Default:
spring.freemarker.template-loader-path=classpath:/templates/
spring.mvc.static-path-pattern=/static/**


spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/pingyougou
spring.datasource.username=root
spring.datasource.password=root

#Configure. xml file path
mybatis.config-locations=classpath:mybatis/mybatis-config.xml
mybatis.mapper-locations=classpath:conf/mapper/*Mapper.xml
#Configure model path
mybatis.type-aliases-package=com.yin.freemakeradd.pojo

2. Introducing the controller class

localhost:8080/upload2/index breakpoint upload entry

@Controller
@RequestMapping(value = "/test")
public class IndexController {
    @GetMapping(value = "/upload/index")
    public String  index(Model model){
        return "breakpointBurst";
    }

    @GetMapping(value = "/upload2/index")
    public String  index2(Model model){
        return "burst";
    }

}

Specific upload logic of fragment upload

@RestController
@RequestMapping(value = "/burst/test")
public class BurstController {

    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");

    private static final String temp_dir = "C:\\Users\\Administrator\\Desktop\\upload";
    private static final String final_dir = "C:\\Users\\Administrator\\Desktop\\test";
    /**
     * Upload files
     *
     * @param request
     * @return
     * @throws IllegalStateException
     * @throws IOException
     */
    @RequestMapping(value = "/upload")
    public Map<String, Object> upload(
            HttpServletRequest request, @RequestParam(value = "data",required = false) MultipartFile multipartFile) throws IllegalStateException, IOException, Exception {


        String uuid = request.getParameter("uuid");
        String fileName = request.getParameter("name");
        //Total size
        String size = request.getParameter("size");
        //Total number of slices
        int total = Integer.valueOf(request.getParameter("total"));
        //What is the current film
        int index = Integer.valueOf(request.getParameter("index"));
        //md5 of the entire file
        String fileMd5 = request.getParameter("filemd5"); 
        //Date of the first segment upload of the file (e.g. 20200118)
        String date = request.getParameter("date"); 
        //Piecewise md5
        String md5 = request.getParameter("md5"); 

        //Generate the path information of the uploaded file by day
        String savePath = "\\upload" + File.separator + date;
        String saveDirectory = temp_dir + savePath +File.separator+uuid;
        //Verify that the path exists and create a directory if it does not exist
        File path = new File(saveDirectory);
        if (!path.exists()) {
            path.mkdirs();
        }
        //File fragmentation location
        //File file = new File(saveDirectory, uuid + "_" + index);


        multipartFile.transferTo(new File(saveDirectory, uuid + "_" + index));


        if (path.isDirectory()) {
            File[] fileArray = path.listFiles();
            if (fileArray != null) {
                if (fileArray.length == total) {
                    //Upload all blocks, merge
                    String suffix = NameUtil.getExtensionName(fileName);
                    String dir = final_dir + savePath;
                    File newFile = new File(dir, uuid + "." + suffix);
                    File copyDir = new File(dir);
                    if(!copyDir.mkdir()){
                        copyDir.mkdirs();
                    }
                    FileOutputStream outputStream = new FileOutputStream(newFile, true);//File append write
                    byte[] byt = new byte[10 * 1024 * 1024];
                    int len;

                   // FileInputStream temp = null; / / fragment file
                    for (int i = 0; i < total; i++) {
                        int j = i + 1;
                        FileInputStream temp  = new FileInputStream(new File(saveDirectory, uuid + "_" + j));
                        while ((len = temp.read(byt)) != -1) {
                            System.out.println("-----" + len);
                            outputStream.write(byt, 0, len);
                        }
                        //Closed flow
                        temp.close();

                    }

                    outputStream.close();
                    //Delete temporary files
                    FileUtil.deleteFolder( temp_dir+ savePath +File.separator+uuid);
                }
            }
        }

        HashMap map = new HashMap<>();
        map.put("fileId", uuid);
        return map;
    }

    /**
     * Get the id and date before uploading the file (in case of fragment upload, it can be handed to the front end for processing)
     *
     * @param request
     * @return
     * @throws IOException
     */
    @RequestMapping(value = "/isUpload")
    public Map<String, Object> getUpload(HttpServletRequest request) throws Exception {

        HashMap<String,Object> map = new HashMap<>();
        String uuid = UUID.randomUUID().toString();
        map.put("fileId", uuid);
        map.put("date", formatter.format(LocalDateTime.now()));
        return map;


    }


}

Segment front end display:

<!DOCTYPE HTML>
<html>
<head>

    <meta charset="utf-8">

    <title>HTML5 Large file fragment upload example</title>

    <script src="http://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
    <script type="text/javascript" src="/static/md5.js"></script>
    <script>

        var i = -1;

        var succeed = 0;

        var databgein;  //start time

        var dataend;    //End time

        var action = false;    //false to check whether the fragment has been uploaded (default); true to upload the file

        var page = {

            init: function () {

                $("#upload").click(function () {
                    $("#upload").attr('disabled', true)
                    databgein = new Date();
                    var file = $("#file")[0].files[0]; / / file object

                    isUpload(file);
                });

            }

        };

        $(function () {

            page.init();

        });

        function isUpload(file) {

            //Construct a form. FormData is new in HTML5

            var form = new FormData();


            var r = new FileReader();

            r.readAsBinaryString(file);

            $(r).load(function (e) {

                var bolb = e.target.result;

                var md5 = hex_md5(bolb);

                form.append("md5", md5);


                //Ajax submission

                $.ajax({

                    url: "http://localhost:8080//burst/test/isUpload",

                    type: "POST",

                    data: form,
					 //asynchronous
                    async: true,       
					//It's important to tell jquery not to process the form
                    processData: false,  
					//It is important to specify false to form the correct content type
                    contentType: false,  

                    success: function (dataObj) {

                        // var dataObj = eval("("+data+")");

                        var uuid = dataObj.fileId;
                        var date = dataObj.date;

                        //No files uploaded
                        upload(file, uuid, md5, date);


                    }, error: function (XMLHttpRequest, textStatus, errorThrown) {

                        alert("Server error!");

                    }

                });

            })

        }

        /*
         * file File object
         * uuid uuid generated by backend
         * filemd5 md5 of the entire file
         * date  Date of the first segment upload of the file (e.g. 20170122)
        */
        function upload(file, uuid, filemd5, date) {

            name = file.name;        //file name

            size = file.size;        //Total size

            var shardSize = 512 * 1024,    //Take 0.5m as a piece

                    shardCount = Math.ceil(size / shardSize);  //Total number of slices


            if (i > shardCount) {

                i = -1;

                i = shardCount;

            } else {

                i += 1;  //Only when detecting fragments, i can add 1; no need to add 1 when uploading files


            }

            //Calculate the start and end positions of each piece

            var start = i * shardSize,

            end = Math.min(size, start + shardSize);


            //Construct a form. FormData is new in HTML5

            var form = new FormData();


            form.append("action", "upload");  //Upload and segment directly

            form.append("data", file.slice(start, end));  //slice method is used to cut out a part of a file
            $("#param").append("action==upload ");


            form.append("uuid", uuid);

            form.append("filemd5", filemd5);

            form.append("date", date);

            form.append("name", name);

            form.append("size", size);

            form.append("total", shardCount);  //Total number of slices

            form.append("index", i + 1);        //What is the current film

            var ssindex = i + 1;
            $("#param").append("index==" + ssindex + "<br/>");

            //Cut segments by size
            var data = file.slice(start, end);

            var r = new FileReader();

            r.readAsBinaryString(data);

            $(r).load(function (e) {

                var bolb = e.target.result;

                var md5 = hex_md5(bolb);

                form.append("md5", md5);


                //Ajax submission

                $.ajax({

                    url: "http://localhost:8080//burst/test/upload",

                    type: "POST",

                    data: form,

                    async: true,        //asynchronous

                    processData: false,  //It's important to tell jquery not to process the form

                    contentType: false,  //It is important to specify false to form the correct content type

                    success: function (dataObj) {

                        //var dataObj = eval("("+data+")");

                        var fileuuid = dataObj.fileId;


                        //Whether the partition returned by the server is uploaded successfully

                        //Changing the interface
                        ++succeed;

                        $("#output").text(succeed + " / " + shardCount);

                        if (i + 1 == shardCount) {

                            dataend = new Date();

                            $("#uuid").append(fileuuid);

                            $("#usetime").append(dataend.getTime() - databgein.getTime());
                            $("#upload").attr('disabled', false);

                        } else if (i + 1 < shardCount) {

                            //Recursive call
                            upload(file, uuid, filemd5, date);

                        } else {
                            i = -1;
                            succeed = 0;
                            $("#upload").attr('disabled', true)
                            databgein = new Date();
                            file = $("#file")[0].files[0]; / / file object

                            isUpload(file);
                        }


                    }, error: function (XMLHttpRequest, textStatus, errorThrown) {
                        $("#upload").attr('disabled', false);
                        alert("Server error!");

                    }

                });

            })

        }


    </script>


</head>

<body>

<input type="file" id="file"/>

<button id="upload">upload</button>

<span id="output" style="font-size:12px">wait for</span>


<span id="usetime" style="font-size:12px;margin-left:20px;">Use time</span>

<span id="uuid" style="font-size:12px;margin-left:20px;">uuid==</span>

<br/>

<br/>
<br/>
<br/>
<span id="param" style="font-size:12px;margin-left:20px;">param==</span>


</body>

</html>

Every time a fragment upload fails, it needs to regenerate a unique uuid for upload, and upload from scratch. However, compared with the later breakpoint continuation, it also has the advantages of less than half of the interaction between the upload and the server, and does not rely on the database.

2, Breakpoint resume

Principle of breakpoint continuous transmission: the front end first requests the interface to obtain whether to upload this time through the MD5 of the uploaded file. If the upload passes MD5, the last uuid will be returned to the front end. The front end splits the files to be uploaded, including the uuid returned to the front end by the server, the MD5 of the file, and the identification of the uploaded piece. First, check whether the piece is uploaded. If it is uploaded, skip to the next piece. If not, upload the file again. When uploading the first piece, record the information to mysql. After uploading, the file information will be changed to upload successfully. Delete temporary folders.
1. Since the configuration file application.properties and the entry controller have been added first, we will not continue to post them here.

2. Upload specific controller

@RestController
@RequestMapping(value = "/breakpointBusrt/test")
public class BreakpointBurstController {
    @Autowired
    private FileUploadService fileUploadService;

    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");

    private static final String temp_dir = "C:\\Users\\Administrator\\Desktop\\upload";
    private static final String final_dir = "C:\\Users\\Administrator\\Desktop\\test";
    /**
     * Upload files
     *
     * @param request
     * @return
     * @throws IllegalStateException
     * @throws IOException
     */
    @RequestMapping(value = "/upload")
    public Map<String, Object> upload(
            HttpServletRequest request, @RequestParam(value = "data",required = false) MultipartFile multipartFile) throws IllegalStateException, IOException, Exception {

        String action = request.getParameter("action");
        String uuid = request.getParameter("uuid");
        String fileName = request.getParameter("name");
        String size = request.getParameter("size");//Total size
        int total = Integer.valueOf(request.getParameter("total"));//Total number of slices
        int index = Integer.valueOf(request.getParameter("index"));//What is the current film
        String fileMd5 = request.getParameter("filemd5"); //md5 of the entire file
        String date = request.getParameter("date"); //Date of the first segment upload of the file (e.g. 20170122)
        String md5 = request.getParameter("md5"); //Piecewise md5

        //Generate the path information of the uploaded file by day
        String savePath = "\\upload" + File.separator + date;
        String saveDirectory = temp_dir + savePath +File.separator+uuid;
        //Verify that the path exists and create a directory if it does not exist
        File path = new File(saveDirectory);
        if (!path.exists()) {
            path.mkdirs();
        }
        //File fragmentation location
        File file = new File(saveDirectory, uuid + "_" + index);

        //Perform different operations according to different action s. check: verify whether the fragment has been uploaded; upload: upload the fragment directly
        Map<String, Object> map = null;
        if("check".equals(action)){
            String md5Str = FileMd5Util.getFileMD5(file);
            if (md5Str != null && md5Str.length() == 31) {
                System.out.println("check length =" + md5.length() + " md5Str length" + md5Str.length() + "   " + md5 + " " + md5Str);
                md5Str = "0" + md5Str;
            }
            if (md5Str != null && md5Str.equals(md5)) {
                //Fragment has been uploaded
                map = new HashMap<>();
                map.put("flag", "2");
                map.put("fileId", uuid);
                map.put("status", true);
                return map;
            } else {
                //Fragment not uploaded
                map = new HashMap<>();
                map.put("flag", "1");
                map.put("fileId", uuid);
                map.put("status", true);
                return map;
            }
        }else if("upload".equals(action)){
            //There is an error in the process of fragment upload. If there is any residue, delete the fragment and upload again
            if (file.exists()) {
                file.delete();
            }
            multipartFile.transferTo(new File(saveDirectory, uuid + "_" + index));
        }

        if (path.isDirectory()) {
            File[] fileArray = path.listFiles();
            if (fileArray != null) {
                if (fileArray.length == total) {
                    //Upload all blocks, merge
                    String suffix = NameUtil.getExtensionName(fileName);
                    String dir = final_dir + savePath;
                    File newFile = new File(dir, uuid + "." + suffix);
                    File copyDir = new File(dir);
                    if(!copyDir.mkdir()){
                        copyDir.mkdirs();
                    }
                    //File append write
                    FileOutputStream outputStream = new FileOutputStream(newFile, true);
                    byte[] byt = new byte[10 * 1024 * 1024];
                    int len;

                    //FileInputStream temp = null; / / fragment file
                    for (int i = 0; i < total; i++) {
                        int j = i + 1;
                        FileInputStream temp = new FileInputStream(new File(saveDirectory, uuid + "_" + j));
                        while ((len = temp.read(byt)) != -1) {
                            System.out.println("-----" + len);
                            outputStream.write(byt, 0, len);
                        }
                        //Closed flow
                        temp.close();
                    }

                    outputStream.close();
                    //Modify FileRes record to upload successfully
                    fileUploadService.updateUploadRecord(fileMd5, FileConstant.FileStatusEnum.UPLOAD_FINSH.getStatus());

                }else if(index == 1){
                    //Record to the database when the first segment of the file is uploaded
                    FileUploadRecord fileUploadRecord = new FileUploadRecord();
                    String name = NameUtil.getFileNameNoEx(fileName);
                    if (name.length() > 50) {
                        name = name.substring(0, 50);
                    }
                    String suffix = NameUtil.getExtensionName(fileName);
                    fileUploadRecord.setName(name);
                    fileUploadRecord.setTimeContent(date);
                    fileUploadRecord.setUuid(uuid);
                    fileUploadRecord.setPath(savePath + File.separator + uuid + "." + suffix);
                    fileUploadRecord.setSize(size);
                    fileUploadRecord.setMd5(fileMd5);
                    fileUploadRecord.setStatus(FileConstant.FileStatusEnum.UPLOAD_BEGIN.getStatus());
                    fileUploadService.insertUploadRecord(fileUploadRecord);
                }
            }
        }

        map = new HashMap<>();
        map.put("flag", "3");
        map.put("fileId", uuid);
        map.put("status", true);
        return map;
    }
    /**
     * Check before uploading files
     *
     * @param request
     * @return
     * @throws IOException
     */
    @RequestMapping(value = "/isUpload")
    public Map<String, Object> isUpload(HttpServletRequest request) throws Exception {

        String fileMd5 = request.getParameter("md5");

        FileUploadRecord fileUploadRecord=fileUploadService.findByFileMd5(fileMd5);
        HashMap<String,Object> map = new HashMap<>();
        if(Objects.isNull(fileUploadRecord)){
            //No files uploaded
            String uuid = UUID.randomUUID().toString();
            map.put("flag", "1");
            map.put("fileId", uuid);
            map.put("date", formatter.format(LocalDateTime.now()));
            map.put("status", true);
            return map;
        }

        if(FileConstant.FileStatusEnum.UPLOAD_FINSH.getStatus().equals(fileUploadRecord.getStatus())){
            //File uploaded successfully
            map.put("flag", "3");
            map.put("fileId", fileUploadRecord.getUuid());
            map.put("date",fileUploadRecord.getTimeContent());
            map.put("status", true);
            return map;
        }

        if(FileConstant.FileStatusEnum.UPLOAD_FINSH.getStatus().equals(fileUploadRecord.getStatus())){
            map.put("flag", "1");
            map.put("fileId",  fileUploadRecord.getUuid());
            map.put("date", fileUploadRecord.getTimeContent());
            map.put("status", true);
            return map;
        }
        //Wrong state
        String uuid = UUID.randomUUID().toString();
        map.put("flag", "1");
        map.put("fileId", uuid);
        map.put("date", formatter.format(LocalDateTime.now()));
        map.put("status", true);
        return map;


    }


}

3. Uploaded front page

<!DOCTYPE HTML>
<html>
<head>

    <meta charset="utf-8">

    <title>HTML5 Large file fragment upload example</title>

    <script src="http://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
    <script type="text/javascript"  src="/static/md5.js"></script>
    <script>

        var i = -1;

        var succeed = 0;

        var databgein;  //start time

        var dataend;    //End time

        var action=false;    //false to check whether the fragment has been uploaded (default); true to upload the file

        var page = {

            init: function(){

                $("#upload").click(function(){
                    $("#upload").attr('disabled',true)
                    databgein=new Date();
                    var file = $("#file")[0].files[0]; / / file object

                    isUpload(file);
                });

            }

        };

        $(function(){

            page.init();

        });

        function isUpload (file) {

            //Construct a form. FormData is new in HTML5

            var form = new FormData();


            var r = new FileReader();

            r.readAsBinaryString(file);

            $(r).load(function(e){

                var bolb = e.target.result;

                var md5 = hex_md5(bolb);

                form.append("md5", md5);


                //Ajax submission

                $.ajax({

                    url: "http://localhost:8080//breakpointBusrt/test/isUpload",

                    type: "POST",

                    data: form,

                    async: true,        //asynchronous

                    processData: false,  //It's important to tell jquery not to process the form

                    contentType: false,  //It is important to specify false to form the correct content type

                    success: function(dataObj){

                        // var dataObj = eval("("+data+")");

                        var uuid = dataObj.fileId;
                        var date = dataObj.date;

                        if (dataObj.flag == "1") {
                            //No files uploaded
                            upload(file,uuid,md5,date);

                        } else if(dataObj.flag == "2") {
                            //Uploaded part
                            upload(file,uuid,md5,date);

                        } else if(dataObj.flag == "3") {
                            //The file has been uploaded
                            alert("The file has been uploaded,Seconds passed!!");
                            $("#uuid").append(uuid);

                        }

                    },error: function(XMLHttpRequest, textStatus, errorThrown) {

                        alert("Server error!");

                    }

                });

            })

        }

        /*
         * file File object
         * uuid uuid generated by backend
         * filemd5 md5 of the entire file
         * date  Date of the first file fragment upload
        */
        function upload (file,uuid,filemd5,date) {

            name = file.name;        //file name

            size = file.size;        //Total size

            var shardSize = 512 * 1024 ,    //Take 0.5m as a piece

                    shardCount = Math.ceil(size / shardSize);  //Total number of slices


            if (i > shardCount) {

                i = -1;

                i = shardCount;

            } else {

                if(!action){

                    i += 1;  //Only when detecting fragments, i can add 1; no need to add 1 when uploading files

                }

            }

            //Calculate the start and end positions of each piece

            var start = i * shardSize,

                    end = Math.min(size, start + shardSize);


            //Construct a form. FormData is new in HTML5

            var form = new FormData();

            if(!action){

                form.append("action", "check");  //Check whether the slice is uploaded
                $("#param").append("action==check ");

            }else{

                form.append("action", "upload");  //Upload and segment directly

                form.append("data", file.slice(start,end));  //slice method is used to cut out a part of a file
                $("#param").append("action==upload ");
            }

            form.append("uuid", uuid);

            form.append("filemd5", filemd5);

            form.append("date", date);

            form.append("name", name);

            form.append("size", size);

            form.append("total", shardCount);  //Total number of slices

            form.append("index", i+1);        //What is the current film

            var ssindex = i+1;
            $("#param").append("index=="+ssindex+"<br/>");

            //Cut segments by size
            var data = file.slice(start, end);

            var r = new FileReader();

            r.readAsBinaryString(data);

            $(r).load(function(e){

                var bolb = e.target.result;

                var md5 = hex_md5(bolb);

                form.append("md5", md5);


                //Ajax submission

                $.ajax({

                    url: "http://localhost:8080//breakpointBusrt/test/upload",

                    type: "POST",

                    data: form,

                    async: true,        //asynchronous

                    processData: false,  //It's important to tell jquery not to process the form

                    contentType: false,  //It is important to specify false to form the correct content type

                    success: function(dataObj){



                        var fileuuid = dataObj.fileId;

                        var flag = dataObj.flag;

                        //The server returns whether the fragment has been uploaded
                        if(!action){

                            if (flag == "1") {
                                //Not uploaded
                                action = true;
                            } else if(dataObj.flag == "2") {
                                //Uploaded
                                action = false;
                                ++succeed;
                            }

                            //Recursive call
                            upload(file,uuid,filemd5,date);

                        }else{
                            //Whether the partition returned by the server is uploaded successfully

                            //Changing the interface
                            ++succeed;

                            $("#output").text(succeed + " / " + shardCount);

                            if (i+1 == shardCount) {

                                dataend=new Date();

                                $("#uuid").append(fileuuid);

                                $("#usetime").append(dataend.getTime()-databgein.getTime());
                                $("#upload").attr('disabled',false);

                            } else {
                                //Uploaded successfully, then detect the next fragment
                                action = false;
                                //Recursive call
                                upload(file,uuid,filemd5,date);

                            }


                        }

                    },error: function(XMLHttpRequest, textStatus, errorThrown) {
                        $("#upload").attr('disabled',false);
                        alert("Server error!");

                    }

                });

            })

        }


    </script>



</head>

<body>

<input type="file" id="file" />

<button id="upload">upload</button>

<span id="output" style="font-size:12px">wait for</span>


<span id="usetime" style="font-size:12px;margin-left:20px;">Use time</span>

<span id="uuid" style="font-size:12px;margin-left:20px;">uuid==</span>

<br/>

<br/>
<br/>
<br/>
<span id="param" style="font-size:12px;margin-left:20px;">param==</span>



</body>

</html>

Here we use mybatis, which we all use. In this case, you can only paste the table building statement and entity class

DROP TABLE IF EXISTS `upload_file_record`;
CREATE TABLE `upload_file_record`  (
  `uuid` varchar(50) not null,
  `name` varchar(50)   not null COMMENT 'file name',
  `timeContent` varchar(10) not NULL COMMENT 'yyyyMMdd',
  `c_path` varchar(225) CHARACTER SET utf8 COLLATE utf8_general_ci not NULL COMMENT 'File address',
  `c_size` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci not NULL  COMMENT 'Size',
  `file_md5` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci not NULL  COMMENT 'fileMd5',
  `status`  TINYINT(2)  not NULL  COMMENT 'File upload status',
  `createTime` TIMESTAMP   COMMENT 'Creation time',
  PRIMARY KEY (`uuid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

Entity class:

package com.yin.freemakeradd.pojo;

import com.yin.freemakeradd.utils.NameUtil;

import java.io.File;

/**
 * @author yin
 * @Date 2020/1/17 22:31
 * @Method
 */
 @Data
public class FileUploadRecord {

     private String uuid;
      private String name;

      private String timeContent;

      private String path;

      private String size;

      private String md5;

      private Integer status;

      private String createTime;


Attached (here you will use the tool class and md5.js to paste out):

1. The server uses md5 generation tool

public class FileMd5Util {
    public static final String KEY_MD5 = "MD5";
    public static final String CHARSET_ISO88591 = "ISO-8859-1";
    /**
     * Get MD5 of one file:hex string,test OK!
     *
     * @param file
     * @return
     */
    public static String getFileMD5(File file) {
        if (!file.exists() || !file.isFile()) {
            return null;
        }
        MessageDigest digest = null;
        FileInputStream in = null;
        byte buffer[] = new byte[1024];
        int len;
        try {
            digest = MessageDigest.getInstance("MD5");
            in = new FileInputStream(file);
            while ((len = in.read(buffer, 0, 1024)) != -1) {
                digest.update(buffer, 0, len);
            }
            in.close();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        BigInteger bigInt = new BigInteger(1, digest.digest());
        return bigInt.toString(16);
    }

    /***
     * Get MD5 of one file!test ok!
     *
     * @param filepath
     * @return
     */
    public static String getFileMD5(String filepath) {
        File file = new File(filepath);
        return getFileMD5(file);
    }

    /**
     * MD5 encrypt,test ok
     *
     * @param data
     * @return byte[]
     * @throws Exception
     */
    public static byte[] encryptMD5(byte[] data) throws Exception {

        MessageDigest md5 = MessageDigest.getInstance(KEY_MD5);
        md5.update(data);
        return md5.digest();
    }

    public static byte[] encryptMD5(String data) throws Exception {
        return encryptMD5(data.getBytes(CHARSET_ISO88591));
    }
    /***
     * compare two file by Md5
     *
     * @param file1
     * @param file2
     * @return
     */
    public static boolean isSameMd5(File file1,File file2){
        String md5_1= FileMd5Util.getFileMD5(file1);
        String md5_2= FileMd5Util.getFileMD5(file2);
        return md5_1.equals(md5_2);
    }
    /***
     * compare two file by Md5
     *
     * @param filepath1
     * @param filepath2
     * @return
     */
    public static boolean isSameMd5(String filepath1,String filepath2){
        File file1=new File(filepath1);
        File file2=new File(filepath2);
        return isSameMd5(file1, file2);
    }

 
}

2. File name generation tool.

public class NameUtil {
    /**
     * Java File operation get file extension
     */
    public static String getExtensionName(String filename) {
        if ((filename != null) && (filename.length() > 0)) {
            int dot = filename.lastIndexOf('.');
            if ((dot > -1) && (dot < (filename.length() - 1))) {
                return filename.substring(dot + 1);
            }
        }
        return filename.toLowerCase();
    }

    /**
     * Java File operation get file name without extension
     */
    public static String getFileNameNoEx(String filename) {
        if ((filename != null) && (filename.length() > 0)) {
            int dot = filename.lastIndexOf('.');
            if ((dot > -1) && (dot < (filename.length()))) {
                return filename.substring(0, dot);
            }
        }
        return filename.toLowerCase();
    }

    public static void main(String[] args) {
        String str = "AAbbbCC.jpg";
        System.out.println(getExtensionName(str).toLowerCase());
        System.out.println(getFileNameNoEx(str).toUpperCase());
    }
}

Delete file tool class

package com.yin.freemakeradd.utils;

import java.io.File;

public class FileUtil {

    /**
     * Delete single file
     * @param   filePath    File name of the deleted file
     * @return If the file is deleted successfully, true will be returned; otherwise, false will be returned
     */
    public static boolean deleteFile(String filePath) {
        File file = new File(filePath);
        if (file.isFile() && file.exists()) {
            return file.delete();
        }
        return false;
    }

    /**
     * Delete folders and files in directories
     * @param   filePath File path of the deleted directory
     * @return  If the directory is deleted successfully, true will be returned; otherwise, false will be returned
     */
    public static boolean deleteDirectory(String filePath) {
        boolean flag = false;
        //Automatically add a file separator if filePath does not end with a file separator
        if (!filePath.endsWith(File.separator)) {
            filePath = filePath + File.separator;
        }
        File dirFile = new File(filePath);
        if (!dirFile.exists() || !dirFile.isDirectory()) {
            return false;
        }
        flag = true;
        File[] files = dirFile.listFiles();
        //Traverse all files (including subdirectories) under the deleted folder
        for (int i = 0; i < files.length; i++) {
            if (files[i].isFile()) {
                //Delete child file
                flag = deleteFile(files[i].getAbsolutePath());
                if (!flag){
                    break;
                }

            } else {
                //delete a sub dir
                flag = deleteDirectory(files[i].getAbsolutePath());
                if (!flag){
                    break;
                }
            }
        }
        if (!flag){
            return false;
        }
        //Delete the current empty directory
        return dirFile.delete();
    }

    /**
     * Delete the specified directory or file according to the path, whether it exists or not
     * @param filePath  Directory or file to delete
     * @return If the deletion is successful, true will be returned; otherwise, false will be returned.
     */
    public static boolean deleteFolder(String filePath) {
        File file = new File(filePath);
        if (!file.exists()) {
            return false;
        } else {
            if (file.isFile()) {
                // Call delete file method on file
                return deleteFile(filePath);
            } else {
                // Call delete directory method when directory
                return deleteDirectory(filePath);
            }
        }
    }

    public static void main(String[] args) {
        deleteFolder("C:\\Users\\Administrator\\Desktop\\upload"+"\\upload" + File.separator + "20200118"+File.separator+"eed4e9e3-52f0-4755-a391-aaba54d606cc");
    }
}

Introduce md5.js file into the front end

/* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
* Digest Algorithm, as defined in RFC 1321.
* Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
* Distributed under the BSD License
* See http://pajhome.org.uk/crypt/md5 for more info.
    */

/*
 * Configurable variables. You may need to tweak these to be compatible with
 * the server-side, but the defaults work in most cases.
 */
var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */
var chrsz   = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      */

/*
 * These are the functions you'll usually want to call
 * They take string arguments and return either hex or base-64 encoded strings
 */
function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }

/*
 * Perform a simple self-test to see if the VM is working
 */
function md5_vm_test()
{
    return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
}

/*
 * Calculate the MD5 of an array of little-endian words, and a bit length
 */
function core_md5(x, len)
{
    /* append padding */
    x[len >> 5] |= 0x80 << ((len) % 32);
    x[(((len + 64) >>> 9) << 4) + 14] = len;

    var a =  1732584193;
    var b = -271733879;
    var c = -1732584194;
    var d =  271733878;

    for(var i = 0; i < x.length; i += 16)
    {
        var olda = a;
        var oldb = b;
        var oldc = c;
        var oldd = d;

        a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
        d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
        c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
        b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
        a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
        d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
        c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
        b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
        a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
        d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
        c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
        b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
        a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
        d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
        c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
        b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);

        a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
        d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
        c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
        b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
        a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
        d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
        c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
        b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
        a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
        d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
        c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
        b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
        a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
        d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
        c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
        b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);

        a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
        d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
        c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
        b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
        a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
        d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
        c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
        b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
        a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
        d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
        c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
        b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
        a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
        d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
        c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
        b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);

        a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
        d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
        c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
        b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
        a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
        d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
        c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
        b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
        a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
        d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
        c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
        b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
        a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
        d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
        c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
        b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);

        a = safe_add(a, olda);
        b = safe_add(b, oldb);
        c = safe_add(c, oldc);
        d = safe_add(d, oldd);
    }
    return Array(a, b, c, d);

}

/*
 * These functions implement the four basic operations the algorithm uses.
 */
function md5_cmn(q, a, b, x, s, t)
{
    return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
}
function md5_ff(a, b, c, d, x, s, t)
{
    return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg(a, b, c, d, x, s, t)
{
    return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh(a, b, c, d, x, s, t)
{
    return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii(a, b, c, d, x, s, t)
{
    return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}

/*
 * Calculate the HMAC-MD5, of a key and some data
 */
function core_hmac_md5(key, data)
{
    var bkey = str2binl(key);
    if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);

    var ipad = Array(16), opad = Array(16);
    for(var i = 0; i < 16; i++)
    {
        ipad[i] = bkey[i] ^ 0x36363636;
        opad[i] = bkey[i] ^ 0x5C5C5C5C;
    }

    var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
    return core_md5(opad.concat(hash), 512 + 128);
}

/*
 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
 * to work around bugs in some JS interpreters.
 */
function safe_add(x, y)
{
    var lsw = (x & 0xFFFF) + (y & 0xFFFF);
    var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
    return (msw << 16) | (lsw & 0xFFFF);
}

/*
 * Bitwise rotate a 32-bit number to the left.
 */
function bit_rol(num, cnt)
{
    return (num << cnt) | (num >>> (32 - cnt));
}

/*
 * Convert a string to an array of little-endian words
 * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
 */
function str2binl(str)
{
    var bin = Array();
    var mask = (1 << chrsz) - 1;
    for(var i = 0; i < str.length * chrsz; i += chrsz)
        bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
    return bin;
}

/*
 * Convert an array of little-endian words to a string
 */
function binl2str(bin)
{
    var str = "";
    var mask = (1 << chrsz) - 1;
    for(var i = 0; i < bin.length * 32; i += chrsz)
        str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
    return str;
}

/*
 * Convert an array of little-endian words to a hex string.
 */
function binl2hex(binarray)
{
    var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
    var str = "";
    for(var i = 0; i < binarray.length * 4; i++)
    {
        str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
            hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
    }
    return str;
}

/*
 * Convert an array of little-endian words to a base-64 string
 */
function binl2b64(binarray)
{
    var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    var str = "";
    for(var i = 0; i < binarray.length * 4; i += 3)
    {
        var triplet = (((binarray[i   >> 2] >> 8 * ( i   %4)) & 0xFF) << 16)
            | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
            |  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
        for(var j = 0; j < 4; j++)
        {
            if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
            else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
        }
    }
    return str;
}

57 original articles published, praised 9, 7626 visitors
Private letter follow

Posted by joey3002 on Sat, 18 Jan 2020 06:46:06 -0800