赞
踩
springboot中,对于大文件上传,可以使用
spring.servlet.multipart.max-file-size
设置文件上传大小限制,但对于超大的文件,此参数不宜国大,也需要在因为网络等原因断掉传输后能够断点续传。
package com.iscas.biz.controller.common.file; import com.iscas.biz.domain.common.FileInfo; import com.iscas.biz.service.common.FileInfoService; import com.iscas.templet.common.BaseController; import com.iscas.templet.common.ResponseEntity; import com.iscas.templet.exception.BaseException; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import lombok.RequiredArgsConstructor; 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 java.io.IOException; import java.util.List; /** * 文件服务控制器-带断点续传 * * @author zhuquanwen * @vesion 1.0 * @date 2022/1/10 14:38 * @since jdk1.8 */ @RestController @RequestMapping("/files") @RequiredArgsConstructor @Api(tags = "文件上传示例-支持断点续传") public class FragmentFileServerController extends BaseController { private final FileInfoService fileInfoService; @PostMapping("/upload") @ApiOperation(value = "文件上传", notes = "文件上传") @ApiImplicitParams( { @ApiImplicitParam(name = "file", value = "上传的文件", required = true, dataType = "MultipartFile"), @ApiImplicitParam(name = "suffix", value = "文件后缀", required = true, dataType = "String"), @ApiImplicitParam(name = "shardIndex", value = "分片索引号", required = true, dataType = "Integer"), @ApiImplicitParam(name = "shardSize", value = "当前上传分片大小", required = true, dataType = "Integer"), @ApiImplicitParam(name = "shardTotal", value = "分片数目", required = true, dataType = "Integer"), @ApiImplicitParam(name = "size", value = "文件大小", required = true, dataType = "Integer"), @ApiImplicitParam(name = "key", value = "文件的key,MD5码:文件名 + 文件大小 + 文件类型 + 文件最后修改时间的MD5码", required = true, dataType = "String"), @ApiImplicitParam(name = "name", value = "文件名称", required = true, dataType = "String") } ) public ResponseEntity upload(MultipartFile file, String suffix, int shardIndex, int shardSize, int shardTotal, int size, String key, String name) { try { fileInfoService.upload(file, suffix, shardIndex, shardSize, shardTotal, size, key, name); } catch (IOException | InterruptedException e) { e.printStackTrace(); } return getResponse(); } @PostMapping("/check") @ApiOperation(value = "文件上传", notes = "文件上传") @ApiImplicitParams( { @ApiImplicitParam(name = "key", value = "文件的key,MD5码:文件名 + 文件大小 + 文件类型 + 文件最后修改时间的MD5码", required = true, dataType = "String") } ) public ResponseEntity check(String key) throws BaseException { List<FileInfo> check = fileInfoService.check(key); //如果这个key存在的话 那么就获取上一个分片去继续上传 if (check.size() != 0) { return getResponse().setValue(check.get(0)); } return getResponse().setStatus(500).setValue("no sliver"); } }
/* Navicat Premium Data Transfer Source Server : 192.168.100.88 Source Server Type : MySQL Source Server Version : 80022 Source Host : 192.168.100.88:3306 Source Schema : newframe Target Server Type : MySQL Target Server Version : 80022 File Encoding : 65001 Date: 11/01/2022 09:47:24 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for file_info -- ---------------------------- DROP TABLE IF EXISTS `file_info`; CREATE TABLE `file_info` ( `id` int(0) NOT NULL AUTO_INCREMENT COMMENT 'ID', `path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '相对路径', `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件名', `suffix` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件后缀', `size` bigint(0) NULL DEFAULT NULL COMMENT '文件大小(字节B)', `created_at` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `updated_at` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '修改时间', `shard_index` int(0) NULL DEFAULT NULL COMMENT '已经上传的分片', `shard_size` int(0) NULL DEFAULT NULL COMMENT '分片大小(字节B)', `shard_total` int(0) NULL DEFAULT NULL COMMENT '分片总数', `file_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '文件标识', PRIMARY KEY (`id`) USING BTREE, INDEX `file_key`(`file_key`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of file_info -- ---------------------------- INSERT INTO `file_info` VALUES (6, 'files\\89042_20170622172520.zip', '89042_20170622172520.zip', 'zip', 29378779, '2022-01-10 18:10:33', '2022-01-10 18:10:33', 2, 20971520, 2, '1uyBa5FxkgCsYwMCcA4GAk'); INSERT INTO `file_info` VALUES (7, 'files\\雷达-网关-添加2个接口.zip', '雷达-网关-添加2个接口.zip', 'zip', 52495657, '2022-01-11 09:03:46', '2022-01-11 09:03:46', 3, 20971520, 3, '79cIXgIuvSCGWKAkU4sKgs'); INSERT INTO `file_info` VALUES (8, 'files\\2883.exe', '2883.exe', 'exe', 60015792, '2022-01-11 09:23:27', '2022-01-11 09:23:27', 3, 20971520, 3, '5qAsd53tSMk0EiU04SScoq'); INSERT INTO `file_info` VALUES (9, 'files\\apache-jmeter-5.4.1.zip', 'apache-jmeter-5.4.1.zip', 'zip', 74032019, '2022-01-11 09:41:14', '2022-01-11 09:41:14', 4, 20971520, 4, '3Fhy0osUsgeGKqeq0Icua'); SET FOREIGN_KEY_CHECKS = 1;
FileInfo实体:
package com.iscas.biz.domain.common; /** * 文件上传的实体 * @author zhuquanwen * @vesion 1.0 * @date 2022/1/10 14:47 * @since jdk1.8 */ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import lombok.experimental.Accessors; import java.time.LocalDateTime; @Data @Accessors(chain = true) @TableName(value = "file_info") public class FileInfo { /** * id */ @TableId(value = "id", type = IdType.AUTO) private Integer id; /** * 相对路径 */ private String path; /** * 文件名 */ private String name; /** * 后缀 */ private String suffix; /** * 大小|字节B */ private Long size; /** * 创建时间 */ private LocalDateTime createdAt; /** * 修改时间 */ private LocalDateTime updatedAt; /** * 已上传分片 */ private Integer shardIndex; /** * 分片大小|B */ private Integer shardSize; /** * 分片总数 */ private Integer shardTotal; /** * 文件标识 */ private String fileKey; }
FileInfoMapper:
package com.iscas.biz.mapper.common;
import com.iscas.biz.domain.common.FileInfo;
import com.iscas.biz.mp.enhancer.mapper.DynamicMapper;
/**
*
* @author zhuquanwen
* @vesion 1.0
* @date 2022/1/10 14:58
* @since jdk1.8
*/
public interface FileInfoMapper extends DynamicMapper<FileInfo> {
}
package com.iscas.biz.service.common; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.iscas.biz.domain.common.FileInfo; import com.iscas.biz.mapper.common.FileInfoMapper; import com.iscas.common.tools.core.io.file.FileUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.text.MessageFormat; import java.time.LocalDateTime; import java.util.List; /** * @author zhuquanwen * @vesion 1.0 * @date 2022/1/10 15:05 * @since jdk1.8 */ @Service @Slf4j public class FileInfoService extends ServiceImpl<FileInfoMapper, FileInfo> { @Value("${file.server.path}") private String fileServerPath; /** * 保存文件 */ public void saveFile(FileInfo fileInfo) { LambdaQueryWrapper<FileInfo> lambdaQuery = new QueryWrapper<FileInfo>().lambda(); lambdaQuery.eq(FileInfo::getFileKey, fileInfo.getFileKey()); saveOrUpdate(fileInfo, lambdaQuery); } /** * 检查文件 */ public List<FileInfo> check(String key) { LambdaQueryWrapper<FileInfo> lambda = new QueryWrapper<FileInfo>().lambda(); lambda.eq(FileInfo::getFileKey, key); return list(lambda); } /** * 文件上传 */ public void upload(MultipartFile file, String suffix, int shardIndex, int shardSize, int shardTotal, long size, String key, String name) throws IOException, InterruptedException { log.info("上传文件开始"); File pFile = new File(fileServerPath, "files"); FileUtils.makeDirectory(pFile); //设置文件新的名字 String fileName = MessageFormat.format("{0}.{1}", key, suffix); //生成分片的名字 String localFileName = MessageFormat.format("{0}.{1}", fileName, shardIndex); // 以绝对路径保存重名命后的文件 File targetFile = new File(pFile, localFileName); //上传这个文件 file.transferTo(targetFile); //数据库持久化这个数据 LocalDateTime now = LocalDateTime.now(); FileInfo fileInfo = new FileInfo(); fileInfo.setPath("files" + File.separator + localFileName) .setName(name) .setSuffix(suffix) .setSize(size) .setCreatedAt(now) .setUpdatedAt(now) .setShardIndex(shardIndex) .setShardSize(shardSize) .setShardTotal(shardTotal) .setFileKey(key); //判断当前是不是最后一个分页 如果不是就继续等待其他分页 合并分页 if (shardIndex == shardTotal) { fileInfo.setPath("files" + File.separator + name); this.merge(fileInfo, fileName); } //插入到数据库中 //保存的时候 去处理一下 这个逻辑 saveFile(fileInfo); log.info("上传成功"); } /** * 合并文件 */ private void merge(FileInfo fileInfo, String fileName) throws IOException { //合并分片开始 log.info("分片合并开始"); //获取到的路径 没有.1 .2 这样的东西 Integer shardTotal = fileInfo.getShardTotal(); String newFileName = fileServerPath + File.separator + "files" + File.separator + fileInfo.getName(); File newFile = new File(newFileName); // 文件追加写入 FileOutputStream os = new FileOutputStream(newFile, true); //分片文件 FileInputStream fis = null; try { for (int i = 0; i < shardTotal; i++) { // 读取第i个分片 String shardFileName = fileServerPath + File.separator + "files" + File.separator + fileName + "." + (i + 1); fis = new FileInputStream(shardFileName); fis.transferTo(os); fis.close(); } } finally { if (fis != null) { fis.close(); } os.close(); log.info("IO流关闭"); } log.debug("分片结束了"); log.debug("删除分片开始"); for (int i = 0; i < shardTotal; i++) { String filePath = fileServerPath + File.separator + "files" + File.separator + fileName + "." + (i + 1); File file = new File(filePath); boolean result = file.delete(); log.info("删除{},{}", filePath, result ? "成功" : "失败"); } log.info("删除分片结束"); } }
fileupload.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>断点文件上传</title> <script src="jquery-3.4.1.min.js" charset="utf-8"></script> <script src="md5.js" charset="UTF-8"></script> <script src="tool.js" charset="UTF-8"></script> </head> <script type="text/javascript"> const urlPrefix = "http://localhost:7901/demo/"; //上传文件 function upload(shardIndex) { console.log(shardIndex); //永安里from表单提交 var fd = new FormData(); //获取表单中的file var file = $('#inputfile').get(0).files[0]; //获取文件名 var name = file.name; //文件分片 以20MB去分片 var shardSize = 20 * 1024 * 1024; //定义分片索引 var shardIndex = shardIndex; //定义分片的起始位置 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(); //把文件的信息存储为一个字符串 var filedetails = file.name + file.size + file.type + file.lastModifiedDate; //使用当前文件的信息用md5加密生成一个key 这个加密是根据文件的信息来加密的 如果相同的文件 加的密还是一样的 var key = hex_md5(filedetails); var key10 = parseInt(key, 16); //把加密的信息 转为一个64位的 var key62 = Tool._10to62(key10); //前面的参数必须和controller层定义的一样 fd.append('file', fileShard); fd.append('suffix', suffix); fd.append('shardIndex', shardIndex); fd.append('shardSize', shardSize); fd.append('shardTotal', shardTotal); fd.append('size', size); fd.append("key", key62); fd.append("name", name); $.ajax({ url: urlPrefix + "/files/upload", type: "post", cache: false, data: fd, processData: false, contentType: false, success: function (data) { //这里应该是一个递归调用 if (shardIndex < shardTotal) { var index = shardIndex + 1; upload(index); } else { alert(data) } }, error: function () { //请求出错处理 } }) //发送ajax请求把参数传递到后台里面 } //判断这个加密文件存在不存在 function check() { var file = $('#inputfile').get(0).files[0]; //把视频的信息存储为一个字符串 var filedetails = file.name + file.size + file.type + file.lastModifiedDate; //使用当前文件的信息用md5加密生成一个key 这个加密是根据文件的信息来加密的 如果相同的文件 加的密还是一样的 var key = hex_md5(filedetails); var key10 = parseInt(key, 16); //把加密的信息 转为一个64位的 var key62 = Tool._10to62(key10); //检查这个key存在不存在 $.ajax({ url: urlPrefix + "/files/check", type: "post", data: {'key': key62}, success: function (data) { console.log(data); if (data.status == 500) { //这个方法必须抽离出来 upload(1); } else { if (data.value.shardIndex == data.value.shardTotal) { alert("文件无修改,已上传成功"); } else { //找到这个是第几片 去重新上传 upload(parseInt(data.data.shardIndex)); } } } }) } </script> <body> <input name="file" type="file" id="inputfile"/> <br/> <button onclick="check()">提交</button> </body> </html>
jquery-3.4.1.min.js就不附加了,下面附md5.js和tool.js
md5.js:
var KEY = "!@#QWERT"; /* * 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; }
tool.js:
Tool = { /** * 空校验 null或""都返回true */ isEmpty: function (obj) { if ((typeof obj == 'string')) { return !obj || obj.replace(/\s+/g, "") == "" } else { return (!obj || JSON.stringify(obj) === "{}" || obj.length === 0); } }, /** * 非空校验 */ isNotEmpty: function (obj) { return !this.isEmpty(obj); }, /** * 长度校验 */ isLength: function (str, min, max) { return $.trim(str).length >= min && $.trim(str).length <= max; }, /** * 时间格式化,date为空时取当前时间 */ dateFormat: function (format, date) { let result; if (!date) { date = new Date(); } const option = { "y+": date.getFullYear().toString(), // 年 "M+": (date.getMonth() + 1).toString(), // 月 "d+": date.getDate().toString(), // 日 "h+": date.getHours().toString(), // 时 "m+": date.getMinutes().toString(), // 分 "s+": date.getSeconds().toString() // 秒 }; for (let i in option) { result = new RegExp("(" + i + ")").exec(format); if (result) { format = format.replace(result[1], (result[1].length == 1) ? (option[i]) : (option[i].padStart(result[1].length, "0"))) } } return format; }, /** * 移除对象数组中的对象 * @param array * @param obj * @returns {number} */ removeObj: function (array, obj) { let index = -1; for (let i = 0; i < array.length; i++) { if (array[i] === obj) { array.splice(i, 1); index = i; break; } } return index; }, /** * 10进制转62进制 * @param number * @returns {string} * @private */ _10to62: function (number) { let chars = '0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ'; let radix = chars.length; let arr = []; do { let mod = number % radix; number = (number - mod) / radix; arr.unshift(chars[mod]); } while (number); return arr.join(''); }, /** * 保存登录用户信息 */ setLoginUser: function (loginUser) { SessionStorage.set(SESSION_KEY_LOGIN_USER, loginUser); }, /** * 获取登录用户信息 */ getLoginUser: function () { return SessionStorage.get(SESSION_KEY_LOGIN_USER) || {}; }, /** * 随机生成[len]长度的[radix]进制数 * @param len * @param radix 默认62 * @returns {string} */ uuid: function (len, radix) { let chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); let uuid = []; radix = radix || chars.length; for (let i = 0; i < len; i++) { uuid[i] = chars[0 | Math.random() * radix]; } return uuid.join(''); }, /** * 查找是否有权限 * @param id 资源id */ hasResource: function (id) { let _this = this; let resources = _this.getLoginUser().resources; if (_this.isEmpty(resources)) { return false; } for (let i = 0; i < resources.length; i++) { if (id === resources[i].id) { return true; } } return false; } };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。