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