diff --git a/itools-core/itools-common/pom.xml b/itools-core/itools-common/pom.xml index cf83904e1f1f275704c62f3f2c6f2ce44ad72b4c..9f9b8ec917328bd0db2aa73d0019d075da4b1cc3 100644 --- a/itools-core/itools-common/pom.xml +++ b/itools-core/itools-common/pom.xml @@ -57,10 +57,20 @@ org.projectlombok lombok + io.springfox springfox-swagger2 + + io.springfox + springfox-swagger-ui + + + com.github.xiaoymin + swagger-bootstrap-ui + 1.9.6 + com.google.guava guava diff --git a/itools-core/itools-common/src/main/java/com/itools/core/config/Swagger2Config.java b/itools-core/itools-common/src/main/java/com/itools/core/config/Swagger2Config.java index a74eefb01d11aff07c537dd1cfee157d5a90739c..f0b05cc776a731666e9840c82f5448a8c10e7ab8 100644 --- a/itools-core/itools-common/src/main/java/com/itools/core/config/Swagger2Config.java +++ b/itools-core/itools-common/src/main/java/com/itools/core/config/Swagger2Config.java @@ -1,5 +1,6 @@ package com.itools.core.config; +import io.swagger.annotations.ApiOperation; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; @@ -19,8 +20,9 @@ public class Swagger2Config { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() - .apis(RequestHandlerSelectors.basePackage("com.xuchang.itools")) - .paths(PathSelectors.any()) +// .apis(RequestHandlerSelectors.basePackage("com.xuchang.itools")) +// .paths(PathSelectors.any()) + .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) .build(); } diff --git a/itools-core/itools-common/src/main/java/com/itools/core/validate/EnableValidator.java b/itools-core/itools-common/src/main/java/com/itools/core/validate/EnableValidator.java index cb426ad4888938799bf39be446e55221b32c8a46..fa6a9b1070480dfd5fe7e6191705b3528c473239 100644 --- a/itools-core/itools-common/src/main/java/com/itools/core/validate/EnableValidator.java +++ b/itools-core/itools-common/src/main/java/com/itools/core/validate/EnableValidator.java @@ -5,6 +5,9 @@ import org.springframework.context.annotation.Import; import java.lang.annotation.*; +/** + * @author xuchang + */ @Target(ElementType.TYPE) @Documented @Retention(RetentionPolicy.RUNTIME) diff --git a/itools-core/itools-utils/src/main/java/com/itools/core/utils/Base64.java b/itools-core/itools-utils/src/main/java/com/itools/core/utils/Base64.java new file mode 100644 index 0000000000000000000000000000000000000000..1fbfccb24d59c87aac21c9570019514b3fce0b62 --- /dev/null +++ b/itools-core/itools-utils/src/main/java/com/itools/core/utils/Base64.java @@ -0,0 +1,224 @@ +package com.itools.core.utils; + +public class Base64 { + private static final byte[] encodingTable = new byte[]{65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47}; + private static final byte[] decodingTable = new byte[128]; + + public Base64() { + } + + public static byte[] encode(byte[] data) { + int modulus = data.length % 3; + byte[] bytes; + if (modulus == 0) { + bytes = new byte[4 * data.length / 3]; + } else { + bytes = new byte[4 * (data.length / 3 + 1)]; + } + + int dataLength = data.length - modulus; + int b1 = 0; + + int b2; + for(b2 = 0; b1 < dataLength; b2 += 4) { + int a1 = data[b1] & 255; + int a2 = data[b1 + 1] & 255; + int a3 = data[b1 + 2] & 255; + bytes[b2] = encodingTable[a1 >>> 2 & 63]; + bytes[b2 + 1] = encodingTable[(a1 << 4 | a2 >>> 4) & 63]; + bytes[b2 + 2] = encodingTable[(a2 << 2 | a3 >>> 6) & 63]; + bytes[b2 + 3] = encodingTable[a3 & 63]; + b1 += 3; + } + + int d1; + switch(modulus) { + case 0: + default: + break; + case 1: + d1 = data[data.length - 1] & 255; + b1 = d1 >>> 2 & 63; + b2 = d1 << 4 & 63; + bytes[bytes.length - 4] = encodingTable[b1]; + bytes[bytes.length - 3] = encodingTable[b2]; + bytes[bytes.length - 2] = 61; + bytes[bytes.length - 1] = 61; + break; + case 2: + d1 = data[data.length - 2] & 255; + int d2 = data[data.length - 1] & 255; + b1 = d1 >>> 2 & 63; + b2 = (d1 << 4 | d2 >>> 4) & 63; + int b3 = d2 << 2 & 63; + bytes[bytes.length - 4] = encodingTable[b1]; + bytes[bytes.length - 3] = encodingTable[b2]; + bytes[bytes.length - 2] = encodingTable[b3]; + bytes[bytes.length - 1] = 61; + } + + return bytes; + } + + public static byte[] decode(byte[] data) { + data = discardNonBase64Bytes(data); + byte[] bytes; + if (data[data.length - 2] == 61) { + bytes = new byte[(data.length / 4 - 1) * 3 + 1]; + } else if (data[data.length - 1] == 61) { + bytes = new byte[(data.length / 4 - 1) * 3 + 2]; + } else { + bytes = new byte[data.length / 4 * 3]; + } + + int i = 0; + + byte b1; + byte b2; + byte b3; + byte b4; + for(int j = 0; i < data.length - 4; j += 3) { + b1 = decodingTable[data[i]]; + b2 = decodingTable[data[i + 1]]; + b3 = decodingTable[data[i + 2]]; + b4 = decodingTable[data[i + 3]]; + bytes[j] = (byte)(b1 << 2 | b2 >> 4); + bytes[j + 1] = (byte)(b2 << 4 | b3 >> 2); + bytes[j + 2] = (byte)(b3 << 6 | b4); + i += 4; + } + + if (data[data.length - 2] == 61) { + b1 = decodingTable[data[data.length - 4]]; + b2 = decodingTable[data[data.length - 3]]; + bytes[bytes.length - 1] = (byte)(b1 << 2 | b2 >> 4); + } else if (data[data.length - 1] == 61) { + b1 = decodingTable[data[data.length - 4]]; + b2 = decodingTable[data[data.length - 3]]; + b3 = decodingTable[data[data.length - 2]]; + bytes[bytes.length - 2] = (byte)(b1 << 2 | b2 >> 4); + bytes[bytes.length - 1] = (byte)(b2 << 4 | b3 >> 2); + } else { + b1 = decodingTable[data[data.length - 4]]; + b2 = decodingTable[data[data.length - 3]]; + b3 = decodingTable[data[data.length - 2]]; + b4 = decodingTable[data[data.length - 1]]; + bytes[bytes.length - 3] = (byte)(b1 << 2 | b2 >> 4); + bytes[bytes.length - 2] = (byte)(b2 << 4 | b3 >> 2); + bytes[bytes.length - 1] = (byte)(b3 << 6 | b4); + } + + return bytes; + } + + public static byte[] decode(String data) { + data = discardNonBase64Chars(data); + byte[] bytes; + if (data.charAt(data.length() - 2) == '=') { + bytes = new byte[(data.length() / 4 - 1) * 3 + 1]; + } else if (data.charAt(data.length() - 1) == '=') { + bytes = new byte[(data.length() / 4 - 1) * 3 + 2]; + } else { + bytes = new byte[data.length() / 4 * 3]; + } + + int i = 0; + + byte b1; + byte b2; + byte b3; + byte b4; + for(int j = 0; i < data.length() - 4; j += 3) { + b1 = decodingTable[data.charAt(i)]; + b2 = decodingTable[data.charAt(i + 1)]; + b3 = decodingTable[data.charAt(i + 2)]; + b4 = decodingTable[data.charAt(i + 3)]; + bytes[j] = (byte)(b1 << 2 | b2 >> 4); + bytes[j + 1] = (byte)(b2 << 4 | b3 >> 2); + bytes[j + 2] = (byte)(b3 << 6 | b4); + i += 4; + } + + if (data.charAt(data.length() - 2) == '=') { + b1 = decodingTable[data.charAt(data.length() - 4)]; + b2 = decodingTable[data.charAt(data.length() - 3)]; + bytes[bytes.length - 1] = (byte)(b1 << 2 | b2 >> 4); + } else if (data.charAt(data.length() - 1) == '=') { + b1 = decodingTable[data.charAt(data.length() - 4)]; + b2 = decodingTable[data.charAt(data.length() - 3)]; + b3 = decodingTable[data.charAt(data.length() - 2)]; + bytes[bytes.length - 2] = (byte)(b1 << 2 | b2 >> 4); + bytes[bytes.length - 1] = (byte)(b2 << 4 | b3 >> 2); + } else { + b1 = decodingTable[data.charAt(data.length() - 4)]; + b2 = decodingTable[data.charAt(data.length() - 3)]; + b3 = decodingTable[data.charAt(data.length() - 2)]; + b4 = decodingTable[data.charAt(data.length() - 1)]; + bytes[bytes.length - 3] = (byte)(b1 << 2 | b2 >> 4); + bytes[bytes.length - 2] = (byte)(b2 << 4 | b3 >> 2); + bytes[bytes.length - 1] = (byte)(b3 << 6 | b4); + } + + return bytes; + } + + private static byte[] discardNonBase64Bytes(byte[] data) { + byte[] temp = new byte[data.length]; + int bytesCopied = 0; + + for(int i = 0; i < data.length; ++i) { + if (isValidBase64Byte(data[i])) { + temp[bytesCopied++] = data[i]; + } + } + + byte[] newData = new byte[bytesCopied]; + System.arraycopy(temp, 0, newData, 0, bytesCopied); + return newData; + } + + private static String discardNonBase64Chars(String data) { + StringBuffer sb = new StringBuffer(); + int length = data.length(); + + for(int i = 0; i < length; ++i) { + if (isValidBase64Byte((byte)data.charAt(i))) { + sb.append(data.charAt(i)); + } + } + + return sb.toString(); + } + + private static boolean isValidBase64Byte(byte b) { + if (b == 61) { + return true; + } else if (b >= 0 && b < 128) { + return decodingTable[b] != -1; + } else { + return false; + } + } + + static { + int i; + for(i = 0; i < 128; ++i) { + decodingTable[i] = -1; + } + + for(i = 65; i <= 90; ++i) { + decodingTable[i] = (byte)(i - 65); + } + + for(i = 97; i <= 122; ++i) { + decodingTable[i] = (byte)(i - 97 + 26); + } + + for(i = 48; i <= 57; ++i) { + decodingTable[i] = (byte)(i - 48 + 52); + } + + decodingTable[43] = 62; + decodingTable[47] = 63; + } +} \ No newline at end of file diff --git a/itools-core/itools-utils/src/main/java/com/itools/core/utils/Base64Utils.java b/itools-core/itools-utils/src/main/java/com/itools/core/utils/Base64Utils.java new file mode 100644 index 0000000000000000000000000000000000000000..c033222e1687b569c8dea3c0b3925767536f2157 --- /dev/null +++ b/itools-core/itools-utils/src/main/java/com/itools/core/utils/Base64Utils.java @@ -0,0 +1,80 @@ +package com.itools.core.utils; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public class Base64Utils { + private static final int CACHE_SIZE = 1024; + + public Base64Utils() { + } + + public static byte[] decode(String base64) { + return Base64.decode(base64.getBytes()); + } + + public static String encode(byte[] bytes) { + return new String(Base64.encode(bytes)); + } + + public static String encodeFile(String filePath) throws IOException { + byte[] bytes = fileToByte(filePath); + return encode(bytes); + } + + public static void decodeToFile(String filePath, String base64) throws IOException { + byte[] bytes = decode(base64); + byteArrayToFile(bytes, filePath); + } + + public static byte[] fileToByte(String filePath) throws IOException { + byte[] data = new byte[0]; + File file = new File(filePath); + if (file.exists()) { + FileInputStream in = new FileInputStream(file); + ByteArrayOutputStream out = new ByteArrayOutputStream(2048); + byte[] cache = new byte[1024]; + boolean var6 = false; + + int nRead; + while((nRead = in.read(cache)) != -1) { + out.write(cache, 0, nRead); + out.flush(); + } + + out.close(); + in.close(); + data = out.toByteArray(); + } + + return data; + } + + public static void byteArrayToFile(byte[] bytes, String filePath) throws IOException { + InputStream in = new ByteArrayInputStream(bytes); + File destFile = new File(filePath); + if (!destFile.getParentFile().exists()) { + destFile.getParentFile().mkdirs(); + } + + destFile.createNewFile(); + OutputStream out = new FileOutputStream(destFile); + byte[] cache = new byte[1024]; + boolean var6 = false; + + int nRead; + while((nRead = in.read(cache)) != -1) { + out.write(cache, 0, nRead); + out.flush(); + } + + out.close(); + in.close(); + } +} \ No newline at end of file diff --git a/itools-core/itools-utils/src/main/java/com/itools/core/utils/ZipUtils.java b/itools-core/itools-utils/src/main/java/com/itools/core/utils/ZipUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..8591326727d639c3e534a23f694e3171ae732f48 --- /dev/null +++ b/itools-core/itools-utils/src/main/java/com/itools/core/utils/ZipUtils.java @@ -0,0 +1,56 @@ +package com.itools.core.utils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Iterator; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +public class ZipUtils { + private static int BUFFER_SIZE = 1024; + + public ZipUtils() { + } + + public static void toZip(List files, OutputStream outputStream) throws RuntimeException { + long start = System.currentTimeMillis(); + ZipOutputStream zipOutputStream = null; + + try { + zipOutputStream = new ZipOutputStream(outputStream); + Iterator var5 = files.iterator(); + + while(var5.hasNext()) { + File file = (File)var5.next(); + byte[] buf = new byte[BUFFER_SIZE]; + zipOutputStream.putNextEntry(new ZipEntry(file.getName())); + FileInputStream in = new FileInputStream(file); + + int len; + while((len = in.read(buf)) != -1) { + zipOutputStream.write(buf, 0, len); + } + + zipOutputStream.closeEntry(); + in.close(); + } + + long end = System.currentTimeMillis(); + System.out.println("压缩完成,耗时:" + (end - start) + " ms"); + } catch (Exception var17) { + throw new RuntimeException("zip error from ZipUtils", var17); + } finally { + if (zipOutputStream != null) { + try { + zipOutputStream.close(); + } catch (IOException var16) { + var16.printStackTrace(); + } + } + + } + } +} \ No newline at end of file diff --git a/itools-core/pom.xml b/itools-core/pom.xml index 970ae695e929b9a3e8a60d76d5be712cb1a27a21..b5c7361966f6bfc32a125d106e893fd8240e4ce7 100644 --- a/itools-core/pom.xml +++ b/itools-core/pom.xml @@ -34,7 +34,7 @@ 3.9.1 8.18.0 1.16.16 - 2.7.0 + 2.9.2 1.2.30 1.27.0.0 5.1.40 diff --git "a/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.assets/1604555758869.png" "b/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.assets/1604555758869.png" new file mode 100644 index 0000000000000000000000000000000000000000..0e32b4943355381dfec39417aa8afa398bbd8cd2 Binary files /dev/null and "b/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.assets/1604555758869.png" differ diff --git "a/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.assets/1604556120012.png" "b/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.assets/1604556120012.png" new file mode 100644 index 0000000000000000000000000000000000000000..8d7f13ae7c733f6fa572a2c2943233b320256d1d Binary files /dev/null and "b/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.assets/1604556120012.png" differ diff --git "a/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.assets/1604556346057.png" "b/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.assets/1604556346057.png" new file mode 100644 index 0000000000000000000000000000000000000000..44f988f8da16c2abfc259d24ab693495ce0f2020 Binary files /dev/null and "b/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.assets/1604556346057.png" differ diff --git "a/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.assets/1604556562914.png" "b/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.assets/1604556562914.png" new file mode 100644 index 0000000000000000000000000000000000000000..dc611f6980a833853d8a2af425eef00397d18359 Binary files /dev/null and "b/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.assets/1604556562914.png" differ diff --git "a/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.assets/1604556812426.png" "b/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.assets/1604556812426.png" new file mode 100644 index 0000000000000000000000000000000000000000..d529403d3712a85c91b4b97a45c78f48767e8cba Binary files /dev/null and "b/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.assets/1604556812426.png" differ diff --git "a/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.assets/1604558494167.png" "b/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.assets/1604558494167.png" new file mode 100644 index 0000000000000000000000000000000000000000..4f14c0a225654e62308ed6e39879f51689b026e8 Binary files /dev/null and "b/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.assets/1604558494167.png" differ diff --git "a/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.assets/1604561499549.png" "b/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.assets/1604561499549.png" new file mode 100644 index 0000000000000000000000000000000000000000..62202ac704972029a71cf63423b359afbfa63e8f Binary files /dev/null and "b/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.assets/1604561499549.png" differ diff --git "a/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.md" "b/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.md" new file mode 100644 index 0000000000000000000000000000000000000000..a55bd16b5fc2d6ec14e06d0f8c295a69cf011c99 --- /dev/null +++ "b/itools-fms/document/fms\346\216\245\345\217\243\346\226\207\346\241\243.md" @@ -0,0 +1,260 @@ +## fms接口文档 + +### 配置 + +#### 1.配置文件 + +```java +spring: + servlet: + multipart: + # 最大支持文件大小 + max-file-size: 20MB + # 最大支持请求大小 + max-request-size: 200MB + # 上传文件的临时目录 + location: /home/hash/AppSvr01/installedApps/fsnsh_backend-master/temp + + +fileStoreRootPath: /data/fsnsh/fssFile #文件存储路径,此路径应该是多个FSS服务的共享磁盘 +fileAccessUrlForOutter: http://192.168.0.97:8002/File/ +fileUploadLimitSize: 10 #批量上传限制的个数 +fileMaxRequestSize: 204800 #最大的请求数,单位KB,200MB +fileMaxFileSize: 20480 #单个文件最大大小,单位KB,20MB +``` + +#### 2.执行运行的DDL/DML + +DDL在`script`目录下,再执行DML脚本配置文件类型 + +```sql +INSERT INTO `fss_business_type`(`id`, `business_type`, `remark`, `fs_size`, `fs_type`, `create_date`, `update_date`) VALUES (1, '01', '文件上传', '102400', 'multipart/form-data,application/octet-stream,text/plain', '2019-08-20 18:48:57.000000', '2019-08-20 18:48:59.000000'); +INSERT INTO `fss_business_type`(`id`, `business_type`, `remark`, `fs_size`, `fs_type`, `create_date`, `update_date`) VALUES (2, '02', 'jar包上传', '102400', 'application/octet-stream,text/plain,multipart/form-data', '2019-08-28 15:24:34.000000', '2019-08-28 15:24:37.000000'); +INSERT INTO `fss_business_type`(`id`, `business_type`, `remark`, `fs_size`, `fs_type`, `create_date`, `update_date`) VALUES (3, 'currency', '通用类型', '102400', 'currency', '2019-10-14 20:21:37.000000', '2019-10-14 20:21:40.000000'); +INSERT INTO `fss_business_type`(`id`, `business_type`, `remark`, `fs_size`, `fs_type`, `create_date`, `update_date`) VALUES (4, '03', 'doc', '102400', 'multipart/form-data; boundary=----WebKitFormBoundaryV9UszO8Om8qv8nNM', '2020-07-30 16:05:31.000000', '2020-07-30 16:05:35.000000'); + +``` + + + +### 接口 + +#### 申请文件上传token + +接口url:`http://127.0.0.1:8002/UploadToken` + +请求方式:POST + +接口参数: + +| 字段名称 | 类型 | 描述 | +| ------------ | ------ | -------------------------------------------------------- | +| businessType | String | 文件类型 | +| fromSystemId | String | 上传的文件来自哪个子系统,系统编号 | +| needEncrypt | String | 是否需加密,后续扩展使用,本期不使用,默认否.0:否 1:是 | +| remark | String | 文件描述信息 | + +接口描述: + +上传文件,先获取token,token设置有效时间 + +businessType:文件类型; + +fromSystemId:上传的文件来自哪个子系统,系统编号; + +needEncrypt:是否需加密,后续扩展使用,本期不使用,默认否.0:否 1:是; + +remark:文件描述信息 + +![1604555758869](./fms接口文档.assets\1604555758869.png) + +#### 单个文件上传 + +接口url:`http://127.0.0.1:8002/File` + +请求方式:POST + +接口参数: + +| 字段名称 | 类型 | 描述 | +| ----------- | ------ | ---------------------------------- | +| file | String | 文件 | +| uploadToken | String | 上传的文件来自哪个子系统,系统编号 | +| fileName | String | 自定义文件名,为空选择默认名称 | + +接口描述: + +![1604561499549](./fms接口文档.assets\1604561499549.png) + +#### 批量上传 文件 + +接口url:`http://127.0.0.1:8002/FilesPath` + +请求方式:POST + +接口参数: + +| 字段名称 | 类型 | 描述 | +| ----------- | ------ | ---------------------------------- | +| files | String | 选取的多个文件 | +| uploadToken | String | 上传的文件来自哪个子系统,系统编号 | + +接口描述: + +返回的文件名称对应的文件标识id + +uniqueId:文件标识id + +fileName:文件名称 + +```json +{ + "returnCode": "0000", + "returnMsg": "Success", + "nonceStr": "07830f77001141d9bcbb3f42a90481b3", + "success": true, + "data": [ + { + "uniqueId": "8cbaea82593a417ab530b91ce1c26e74", + "fileName": "微信图片_20201105130745 - 副本 - 副本 (3).jpg" + }, + { + "uniqueId": "a18210fb568345c4ba883d20704dc87b", + "fileName": "微信图片_20201105130745 - 副本 - 副本 - 副本.jpg" + } + ] +} +``` + + + +![1604556346057](./fms接口文档.assets\1604556346057.png) + +#### 获取文件访问路径 + +接口url:`http://127.0.0.1:8002/FilePath` + +请求方式:POST + +接口参数: + +| 字段名称 | 类型 | 描述 | +| -------------- | ------ | --------------------------- | +| uniqueId | String | 文件的唯一ID | +| expiredTime | Long | 有效时长,单位分钟 | +| maxAccessCount | Long | 最大访问次数 | +| type | String | 文件下载 download/展示 show | + +接口描述: + +获取该文件的访问的路径,也是需要根据传入的过期时间,访问类型等等 + +![1604556562914](./fms接口文档.assets\1604556562914.png) + +#### 获取多个文件访问路径 + +接口url:`http://127.0.0.1:8002/FilesPath` + +请求方式:POST + +接口参数: + +| 字段名称 | 类型 | 描述 | +| -------------- | -------- | --------------------------- | +| uniqueIds | String[] | 文件的唯一IDS,数组 | +| expiredTime | Long | 有效时长,单位分钟 | +| maxAccessCount | Long | 最大访问次数 | +| type | String | 文件下载 download/展示 show | + +接口描述: + +获取该文件的访问的路径,也是需要根据传入的过期时间,访问类型等等 + +```json +{ + "returnCode": "0000", + "returnMsg": "Success", + "nonceStr": "22487d32278e463b9cc6f3989df230a9", + "success": true, + "data": [ + { + "uniqueId": "1f449166a6e141f9b3b2dce5aa4e0b6b", + "path": "http://192.168.0.97:8002/File/1f449166a6e141f9b3b2dce5aa4e0b6b?fileAccessToken=a58f0d6969a945a795dd8cfb3ea85d26" + }, + { + "uniqueId": "a18210fb568345c4ba883d20704dc87b", + "path": "http://192.168.0.97:8002/File/a18210fb568345c4ba883d20704dc87b?fileAccessToken=44e79a91414d4692ac0224452e0d2c3d" + } + ] +} +``` + + + +![1604558494167](./fms接口文档.assets\1604558494167.png) + +#### 下载、访问文件 + +接口url:`http://127.0.0.1:8002/File` + +请求方式:GET + +接口参数: + +| 字段名称 | 类型 | 描述 | +| --------------- | ------ | ------------- | +| uniqueId | String | 文件的唯一ID | +| fileAccessToken | String | 文件访问token | + +接口描述: + +访问文件 + +#### 获取base64 + +接口url:`http://127.0.0.1:8002/File/getFileBase64` + +请求方式:GET + +接口参数: + +| 字段名称 | 类型 | 描述 | +| -------- | ------ | ------------ | +| uniqueId | String | 文件的唯一ID | + +接口描述: + +根据文件标识id返回base64的文件 + +#### 获取文件记录信息 + +接口url:`http://127.0.0.1:8002/fssRecord` + +请求方式:GET + +接口参数: + +| 字段名称 | 类型 | 描述 | +| -------- | ------ | ------------ | +| uniqueId | String | 文件的唯一ID | + +接口描述: + +获取文件记录信息 (内部调用) + +#### 下载zip压缩文件接口 + +接口url:`http://127.0.0.1:8002/download/zip` + +请求方式:POST + +接口参数: + +| 字段名称 | 类型 | 描述 | +| --------- | -------- | ------------- | +| uniqueIds | String[] | 文件的唯一IDS | +| zipName | String | 压缩文件名称 | + +接口描述: + +根据文件标识id下载对应的标识的文件,返回zip的压缩文件 \ No newline at end of file diff --git a/itools-fms/itools-fms-core/pom.xml b/itools-fms/itools-fms-core/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..c32b56eb36cf39f34b6111bdb270b496d517f9f4 --- /dev/null +++ b/itools-fms/itools-fms-core/pom.xml @@ -0,0 +1,50 @@ + + + + itools-fms + com.itools.core + 1.0-SNAPSHOT + + 4.0.0 + + itools-fms-core + + + com.itools.core + itools-common + 1.0-SNAPSHOT + compile + + + com.itools.core + itools-fms-model + 1.0-SNAPSHOT + + + + io.springfox + springfox-swagger2 + 2.9.2 + + + io.springfox + springfox-swagger-ui + 2.9.2 + + + com.github.xiaoymin + swagger-bootstrap-ui + 1.9.6 + + + io.minio + minio + 7.0.2 + + + + + + \ No newline at end of file diff --git a/itools-fms/itools-fms-core/src/main/java/com/itools/core/annotation/FileStrategy.java b/itools-fms/itools-fms-core/src/main/java/com/itools/core/annotation/FileStrategy.java new file mode 100644 index 0000000000000000000000000000000000000000..57665e555d4c4964703bbdf989cfbf674310ff61 --- /dev/null +++ b/itools-fms/itools-fms-core/src/main/java/com/itools/core/annotation/FileStrategy.java @@ -0,0 +1,24 @@ +package com.itools.core.annotation; + +import com.itools.core.em.StrategyType; +import org.springframework.stereotype.Service; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @project: itools-backend + * @description: 选择文件系统的策略注解 + * @author: XUCHANG + * @create: 2021-04-01 15:57 + */ +@Service +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface FileStrategy { + + StrategyType value(); + +} diff --git a/itools-fms/itools-fms-core/src/main/java/com/itools/core/config/MinioConfig.java b/itools-fms/itools-fms-core/src/main/java/com/itools/core/config/MinioConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..cb3ebe48f4ff6e7330e198b6e77c00e3f84a6f51 --- /dev/null +++ b/itools-fms/itools-fms-core/src/main/java/com/itools/core/config/MinioConfig.java @@ -0,0 +1,49 @@ +package com.itools.core.config; + +import io.minio.MinioClient; +import io.minio.errors.InvalidEndpointException; +import io.minio.errors.InvalidPortException; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +/** + * @project: itools-backend + * @description: + * @author: XUCHANG + * @create: 2021-04-01 16:06 + */ +@Data +@Component +@ConfigurationProperties(prefix = "fms.minio") +public class MinioConfig { + + @ApiModelProperty("endPoint是一个URL,域名,IPv4或者IPv6地址") + private String endpoint; + + @ApiModelProperty("TCP/IP端口号") + private int port; + + @ApiModelProperty("accessKey类似于用户ID,用于唯一标识你的账户") + private String accessKey; + + @ApiModelProperty("secretKey是你账户的密码") + private String secretKey; + + @ApiModelProperty("如果是true,则用的是https而不是http,默认值是true") + private Boolean secure; + + @ApiModelProperty("默认存储桶") + private String bucketName; + + @ApiModelProperty("配置目录") + private String configDir; + + @Bean + public MinioClient getMinioClient() throws InvalidEndpointException, InvalidPortException { + MinioClient minioClient = new MinioClient(endpoint, port, accessKey, secretKey,secure); + return minioClient; + } +} \ No newline at end of file diff --git a/itools-fms/itools-fms-core/src/main/java/com/itools/core/config/MybatisPlusConfig.java b/itools-fms/itools-fms-core/src/main/java/com/itools/core/config/MybatisPlusConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..56a51101d22b2a1fbbb89ddb08bd311c054e7111 --- /dev/null +++ b/itools-fms/itools-fms-core/src/main/java/com/itools/core/config/MybatisPlusConfig.java @@ -0,0 +1,32 @@ +package com.itools.core.config; + +import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; +import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * @project: itools-backend + * @description: + * @author: XUCHANG + * @create: 2021-04-01 16:06 + */ +@Configuration +@EnableTransactionManagement +@MapperScan("com.itools.core.mapper") +public class MybatisPlusConfig { + @Bean + public PaginationInterceptor paginationInterceptor() { + + PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); + // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false + // paginationInterceptor.setOverflow(false); + // 设置最大单页限制数量,默认 500 条,-1 不受限制 + // paginationInterceptor.setLimit(500); + // 开启 count 的 join 优化,只针对部分 left join + paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true)); + return paginationInterceptor; + } +} diff --git a/itools-fms/itools-fms-core/src/main/java/com/itools/core/config/SwaggerAutoConfiguration.java b/itools-fms/itools-fms-core/src/main/java/com/itools/core/config/SwaggerAutoConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..ddd193ef8a2a939e7eadeb0227965e08f58185e6 --- /dev/null +++ b/itools-fms/itools-fms-core/src/main/java/com/itools/core/config/SwaggerAutoConfiguration.java @@ -0,0 +1,41 @@ +//package com.itools.core.config; +// +//import io.swagger.annotations.ApiOperation; +//import io.swagger.annotations.Contact; +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Configuration; +//import springfox.documentation.builders.ApiInfoBuilder; +//import springfox.documentation.builders.PathSelectors; +//import springfox.documentation.builders.RequestHandlerSelectors; +//import springfox.documentation.service.ApiInfo; +//import springfox.documentation.spi.DocumentationType; +//import springfox.documentation.spring.web.plugins.Docket; +//import springfox.documentation.swagger2.annotations.EnableSwagger2; +// +//@Configuration +//@EnableSwagger2 +//public class SwaggerAutoConfiguration{ +// +// @Bean +// public Docket createRestApi() { +// return new Docket(DocumentationType.SWAGGER_2) +// .groupName("") +// .apiInfo(apiInfo()) +// .select() +// .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) +// .paths(PathSelectors.any()) +// .build(); +// } +// +// +// private ApiInfo apiInfo() { +// return new ApiInfoBuilder() +// .title("**平台对外接口") +// .description("1.提供**后台使用的接口 2.提供对其他服务调用的服务") +//// .contact(new Contact("xtj332", "https://blog.csdn.net/xtj332", "xtj332111@163.com")) +// .version("1.0") +// .build(); +// } +// +// +//} \ No newline at end of file diff --git a/itools-fms/itools-fms-core/src/main/java/com/itools/core/config/SwaggerConfig.java b/itools-fms/itools-fms-core/src/main/java/com/itools/core/config/SwaggerConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..b19297eadf3b6f2ccc430e53829d9279364240af --- /dev/null +++ b/itools-fms/itools-fms-core/src/main/java/com/itools/core/config/SwaggerConfig.java @@ -0,0 +1,108 @@ +//package com.itools.core.config; +// +//import io.swagger.annotations.ApiOperation; +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Configuration; +//import org.springframework.context.annotation.Profile; +//import springfox.documentation.builders.ApiInfoBuilder; +//import springfox.documentation.builders.ParameterBuilder; +//import springfox.documentation.builders.PathSelectors; +//import springfox.documentation.builders.RequestHandlerSelectors; +//import springfox.documentation.schema.ModelRef; +//import springfox.documentation.service.*; +//import springfox.documentation.spi.DocumentationType; +//import springfox.documentation.spi.service.contexts.SecurityContext; +//import springfox.documentation.spring.web.plugins.Docket; +//import springfox.documentation.swagger2.annotations.EnableSwagger2; +// +//import java.time.LocalTime; +//import java.util.ArrayList; +//import java.util.List; +// +///** +// * SwaggerConfig api文档地址:/swagger-ui.html 或者 /doc.html +// */ +////指定在某些环境启用swagger的配置 +//@Profile({ +// "dev","test" +//}) +//// swagger暂不支持webflux +//@Configuration +//@EnableSwagger2 +//public class SwaggerConfig { +// @Bean +// public Docket createRestApi() { +// //定义swagger全局入参token +// ParameterBuilder tokenPar = new ParameterBuilder(); +// List pars = new ArrayList(); +// tokenPar.name("Authorization").description("用户令牌(无须鉴权的可以不传 格式:bearer 密文串").modelRef(new ModelRef("string")) +// .parameterType("header").required(false).build(); +// pars.add(tokenPar.build()); +// +// return new Docket(DocumentationType.SWAGGER_2) +// .directModelSubstitute(LocalTime.class, String.class) +// //.groupName("normal") //使用默认分组,便于网关层的swagger转发 +// .apiInfo(defaultTitleInfo()) //可设置默认分组api顶部说明文字 +// .useDefaultResponseMessages(false) +// .select() +// .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) +// //只允许生成ApiOperation注解的方法,其他系统内部用的api可隐藏 +// .build(); +//// //.globalOperationParameters(pars); +//// //设置安全模式,swagger全局设置token +//// .securitySchemes(securitySchemes()) +//// .securityContexts(securityContexts()); +// +// } +// +// /** +// * 安全模式,这里指定token通过Authorization头请求头传递 +// */ +// private List securitySchemes() +// { +// List apiKeyList = new ArrayList<>(); +// apiKeyList.add(new ApiKey("Authorization", "Authorization", "header")); +// return apiKeyList; +// } +// +// /** +// * 安全上下文 +// */ +// private List securityContexts() +// { +// List securityContexts = new ArrayList<>(); +// securityContexts.add( +// SecurityContext.builder() +// .securityReferences(defaultAuth()) +// .forPaths(PathSelectors.regex("^(?!auth).*$")) +// .build()); +// return securityContexts; +// } +// +// /** +// * 默认的安全上引用 +// */ +// private List defaultAuth() +// { +// AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); +// AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; +// authorizationScopes[0] = authorizationScope; +// List securityReferences = new ArrayList<>(); +// securityReferences.add(new SecurityReference("Authorization", authorizationScopes)); +// return securityReferences; +// } +// +// /** +// * 默认标题信息 +// * @return - +// */ +// private ApiInfo defaultTitleInfo() { +// return new ApiInfoBuilder() +// .title("接口地址使用Base URL")//大标题 +// .description("· 接口成功返回:{\"success\": true,\"code\": 20000,\"message\": \"成功\",\"data\": null} " +// + "
· 失败的返回:{\"success\": false,\"code\": 50002,\"message\": \"算术运算异常\",\"data\": null} " +// )//详细描述 +// .version("1.0")//版本 +// .build(); +// } +//} \ No newline at end of file diff --git a/itools-fms/itools-fms-core/src/main/java/com/itools/core/context/FileStrategyServiceContext.java b/itools-fms/itools-fms-core/src/main/java/com/itools/core/context/FileStrategyServiceContext.java new file mode 100644 index 0000000000000000000000000000000000000000..b0a54381097ce8e213354431819b90382201aa26 --- /dev/null +++ b/itools-fms/itools-fms-core/src/main/java/com/itools/core/context/FileStrategyServiceContext.java @@ -0,0 +1,52 @@ +package com.itools.core.context; + +import com.itools.core.em.StrategyType; +import com.itools.core.service.FileManagerService; +import lombok.Getter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +/** + * @project: itools-backend + * @description: + * @author: XUCHANG + * @create: 2021-04-01 16:02 + */ +@Component +public class FileStrategyServiceContext { + @Autowired + private Environment environment; + @Getter + private final static Map fileServiceMap; + + static { + fileServiceMap = new HashMap<>(); + } + + public FileManagerService get(String type) { + return fileServiceMap.get(type); + } + + /** + * 获取默认或者配置的文件服务策略 + * @return + */ + public FileManagerService get(){ + boolean containsProperty = environment.containsProperty("fms.strategy"); + if (containsProperty){ + fileServiceMap.get(environment.getProperty("fms.strategy")); + } + return fileServiceMap.get(StrategyType.NIO.getType()); + } + + public void put(String type, FileManagerService calcService) { + fileServiceMap.put(type, calcService); + } + public Map getMap(){ + return fileServiceMap; + } +} diff --git a/itools-fms/itools-fms-core/src/main/java/com/itools/core/em/FmsCodeBean.java b/itools-fms/itools-fms-core/src/main/java/com/itools/core/em/FmsCodeBean.java new file mode 100644 index 0000000000000000000000000000000000000000..f2db4555a7b3f9b8183e1cdfe7319519bef238dc --- /dev/null +++ b/itools-fms/itools-fms-core/src/main/java/com/itools/core/em/FmsCodeBean.java @@ -0,0 +1,80 @@ +package com.itools.core.em; + + +import com.itools.core.code.SystemCode; + +/** + * @description: + * @author: XUCHANG + * @create: 2021-03-28 15:51 + */ +@SystemCode +public class FmsCodeBean { + + public enum FmsCode { + /** + * 文件系统内部错误 + */ + FAIL("FSS01", "文件系统内部错误"), + /** + * BUSINESS_TYPE不存在 + */ + ERROR_BUSINESS_TYPE_NOT_EXIST("FSS02", "BUSINESS_TYPE不存在"), + /** + * 文件不能为空 + */ + ERROR_FILE_IS_NULL("FSS11", "文件不能为空"), + /** + * 参数错误 + */ + ERROR_PARAMS("FSS12", "参数错误"), + /** + * 文件上传时间限定超时 + */ + ERROR_TIMEOUT("FSS13", "文件上传时间限定超时"), + /** + * 文件大小超过限制 + */ + ERROR_FILESIZE_OUT_OFF_LIMIT("FSS14", "文件大小超过限制"), + /** + * 该文件类型不允许 + */ + ERROR_FILETYPE("FSS15", "该文件类型不允许"), + /** + * 文件ID非法 + */ + INVALID_FS_UNIQUE_ID("FSS21", "文件ID非法"), + + ERROR_TRANS_BASE64("FSS22", "文件转base64失败"), + /** + * 鉴权失败 + */ + INVALID_FS_TOKEN("401", "鉴权失败"), + /** + * 找不到该文件 + * 错误码直接放到response中,所以按照http的规范设置 + */ + NOT_EXIST_FILE("404", "找不到该文件"), + + FILE_LIMIT_SIZE("FSS23", "文件上传个数受限"), + + FILE_MULTIPART_UPLOAD("FSS24", "批量上传文件失败"), + ; + + public final String code; + public final String message; + + FmsCode(String code, String message) { + this.code = code; + this.message = message; + } + + public String getCode() { + return code; + } + + public String getMessage() { + return message; + } + } +} diff --git a/itools-fms/itools-fms-core/src/main/java/com/itools/core/em/FmsConstants.java b/itools-fms/itools-fms-core/src/main/java/com/itools/core/em/FmsConstants.java new file mode 100644 index 0000000000000000000000000000000000000000..5322ffce67d7c383e291a42a2ebab3e6e39909d1 --- /dev/null +++ b/itools-fms/itools-fms-core/src/main/java/com/itools/core/em/FmsConstants.java @@ -0,0 +1,13 @@ +package com.itools.core.em; + +/** + * @description: + * @author: XUCHANG + * @create: 2021-03-28 15:51 + */ +public interface FmsConstants { + + String FSS_RECORD_ID_SEQ_NAME="FSS:FssRecord:ID"; + + +} diff --git a/itools-fms/itools-fms-core/src/main/java/com/itools/core/em/StrategyType.java b/itools-fms/itools-fms-core/src/main/java/com/itools/core/em/StrategyType.java new file mode 100644 index 0000000000000000000000000000000000000000..85be616086b5a0f05c0475d1c42b7a22476079a8 --- /dev/null +++ b/itools-fms/itools-fms-core/src/main/java/com/itools/core/em/StrategyType.java @@ -0,0 +1,37 @@ +package com.itools.core.em; + +import com.itools.core.utils.StringUtils; + +/** + * @project: itools-backend + * @description: + * @author: XUCHANG + * @create: 2021-04-01 16:02 + */ +public enum StrategyType { + NIO("nio", "NIO","nioFileManagerServiceImpl"), + MINIO("minio", "miniio文件系统","minioFileManagerServiceImpl"), + FASTDFS("fastdfs", "fastdfs文件系统","fastDfsFileManagerServiceImpl"); + private String type; + private String desc; + private String beanName; + + StrategyType(String type, String desc,String beanName) { + this.type = type; + this.desc = desc; + this.beanName = beanName; + } + + public String getType() { + return type; + } + + public static String getType(String beanName) { + for (StrategyType strategyType : StrategyType.values()){ + if (StringUtils.equals(beanName,strategyType.beanName)){ + return strategyType.type; + } + } + return null; + } +} \ No newline at end of file diff --git a/itools-fms/itools-fms-core/src/main/java/com/itools/core/listener/FileStrategyListener.java b/itools-fms/itools-fms-core/src/main/java/com/itools/core/listener/FileStrategyListener.java new file mode 100644 index 0000000000000000000000000000000000000000..06b83d88643b09bfa6cd5315fbd00b625e6ff2d0 --- /dev/null +++ b/itools-fms/itools-fms-core/src/main/java/com/itools/core/listener/FileStrategyListener.java @@ -0,0 +1,44 @@ +package com.itools.core.listener; + +import com.itools.core.annotation.FileStrategy; +import com.itools.core.context.FileStrategyServiceContext; +import com.itools.core.em.StrategyType; +import com.itools.core.service.FileManagerService; +import com.itools.core.utils.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * @project: itools-backend + * @description: + * @author: XUCHANG + * @create: 2021-04-01 16:06 + */ +@Component +public class FileStrategyListener implements ApplicationListener { + @Autowired + private FileStrategyServiceContext fileStrategyServiceContext; + + /** + * 监听类 + * @param contextRefreshedEvent + */ + @Override + public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { + + Map beans = contextRefreshedEvent.getApplicationContext().getBeansOfType(FileManagerService.class); + beans.forEach((k, service) -> { + String type = StrategyType.getType(k); + fileStrategyServiceContext.put(type, service); +// if (StringUtils.equals(k,)) +// Class clazz = service.getClass(); +// FileStrategy fileStrategy = (FileStrategy)clazz.getAnnotation(FileStrategy.class); +// fileStrategyServiceContext.put(fileStrategy.value().getType(), service); + }); + } +} diff --git a/itools-fms/itools-fms-core/src/main/java/com/itools/core/service/FileManagerService.java b/itools-fms/itools-fms-core/src/main/java/com/itools/core/service/FileManagerService.java new file mode 100644 index 0000000000000000000000000000000000000000..e2aab474688e6f09dfbf6bf2ce8e78ee9d2814a4 --- /dev/null +++ b/itools-fms/itools-fms-core/src/main/java/com/itools/core/service/FileManagerService.java @@ -0,0 +1,27 @@ +package com.itools.core.service; + +import com.itools.core.base.CommonResult; +import com.itools.core.param.FmsUploadTokenParam; +import org.springframework.web.multipart.MultipartFile; + +/** + * @description: + * @author: XUCHANG + * @create: 2021-04-01 15:44 + */ +public interface FileManagerService { + /** + * 批量上传文件 + * @param files 文件 + * @param param 上传的参数 + * @return + */ + CommonResult mutipartUploadFiles(MultipartFile[] files, FmsUploadTokenParam param); + /** + * 单个上传文件 + * @param file 文件 + * @param param 上传的参数 + * @return + */ + CommonResult mutipartUploadFiles(MultipartFile file, FmsUploadTokenParam param); +} diff --git a/itools-fms/itools-fms-core/src/main/java/com/itools/core/service/impl/FastDfsFileManagerServiceImpl.java b/itools-fms/itools-fms-core/src/main/java/com/itools/core/service/impl/FastDfsFileManagerServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..a12356c20ae6b9e10dc00ba6edd3e7c6364cc3f7 --- /dev/null +++ b/itools-fms/itools-fms-core/src/main/java/com/itools/core/service/impl/FastDfsFileManagerServiceImpl.java @@ -0,0 +1,40 @@ +package com.itools.core.service.impl; + +import com.itools.core.annotation.FileStrategy; +import com.itools.core.base.CommonResult; +import com.itools.core.em.StrategyType; +import com.itools.core.param.FmsUploadTokenParam; +import com.itools.core.service.FileManagerService; +import org.springframework.web.multipart.MultipartFile; + +/** + * @project: itools-backend + * @description: + * @author: XUCHANG + * @create: 2021-04-01 16:17 + */ +@FileStrategy(value = StrategyType.FASTDFS) +public class FastDfsFileManagerServiceImpl implements FileManagerService { + /** + * 批量上传文件 + * @param files 文件 + * @param param 上传的参数 + * @return + */ + @Override + public CommonResult mutipartUploadFiles(MultipartFile[] files, FmsUploadTokenParam param) { + return CommonResult.success(StrategyType.FASTDFS.getType()); + } + + /** + * 单个上传文件 + * + * @param file 文件 + * @param param 上传的参数 + * @return + */ + @Override + public CommonResult mutipartUploadFiles(MultipartFile file, FmsUploadTokenParam param) { + return null; + } +} diff --git a/itools-fms/itools-fms-core/src/main/java/com/itools/core/service/impl/MinioFileManagerServiceImpl.java b/itools-fms/itools-fms-core/src/main/java/com/itools/core/service/impl/MinioFileManagerServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..062a426f8e2af6341143ef1720f45cfcff9889b3 --- /dev/null +++ b/itools-fms/itools-fms-core/src/main/java/com/itools/core/service/impl/MinioFileManagerServiceImpl.java @@ -0,0 +1,40 @@ +package com.itools.core.service.impl; + +import com.itools.core.annotation.FileStrategy; +import com.itools.core.base.CommonResult; +import com.itools.core.em.StrategyType; +import com.itools.core.param.FmsUploadTokenParam; +import com.itools.core.service.FileManagerService; +import org.springframework.web.multipart.MultipartFile; + +/** + * @project: itools-backend + * @description: + * @author: XUCHANG + * @create: 2021-04-01 16:17 + */ +@FileStrategy(value = StrategyType.MINIO) +public class MinioFileManagerServiceImpl implements FileManagerService { + /** + * 批量上传文件 + * @param files 文件 + * @param param 上传的参数 + * @return + */ + @Override + public CommonResult mutipartUploadFiles(MultipartFile[] files, FmsUploadTokenParam param) { + return CommonResult.success(StrategyType.MINIO.getType()); + } + + /** + * 单个上传文件 + * + * @param file 文件 + * @param param 上传的参数 + * @return + */ + @Override + public CommonResult mutipartUploadFiles(MultipartFile file, FmsUploadTokenParam param) { + return null; + } +} diff --git a/itools-fms/itools-fms-core/src/main/java/com/itools/core/service/impl/NioFileManagerServiceImpl.java b/itools-fms/itools-fms-core/src/main/java/com/itools/core/service/impl/NioFileManagerServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..dea9526e4865e4f0ed6d417e258d2970505a868e --- /dev/null +++ b/itools-fms/itools-fms-core/src/main/java/com/itools/core/service/impl/NioFileManagerServiceImpl.java @@ -0,0 +1,40 @@ +package com.itools.core.service.impl; + +import com.itools.core.annotation.FileStrategy; +import com.itools.core.base.CommonResult; +import com.itools.core.em.StrategyType; +import com.itools.core.param.FmsUploadTokenParam; +import com.itools.core.service.FileManagerService; +import org.springframework.web.multipart.MultipartFile; + +/** + * @project: itools-backend + * @description: + * @author: XUCHANG + * @create: 2021-04-01 16:17 + */ +@FileStrategy(value = StrategyType.NIO) +public class NioFileManagerServiceImpl implements FileManagerService { + /** + * 批量上传文件 + * @param files 文件 + * @param param 上传的参数 + * @return + */ + @Override + public CommonResult mutipartUploadFiles(MultipartFile[] files, FmsUploadTokenParam param) { + return CommonResult.success(StrategyType.NIO.getType()); + } + + /** + * 单个上传文件 + * + * @param file 文件 + * @param param 上传的参数 + * @return + */ + @Override + public CommonResult mutipartUploadFiles(MultipartFile file, FmsUploadTokenParam param) { + return null; + } +} diff --git a/itools-fms/itools-fms-core/src/main/java/com/itools/core/utils/MinioUtil.java b/itools-fms/itools-fms-core/src/main/java/com/itools/core/utils/MinioUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..561de3f73ae1bcef3ae8497f263204bc3fcfb982 --- /dev/null +++ b/itools-fms/itools-fms-core/src/main/java/com/itools/core/utils/MinioUtil.java @@ -0,0 +1,430 @@ +package com.itools.core.utils; + +import io.minio.MinioClient; +import io.minio.ObjectStat; +import io.minio.PutObjectOptions; +import io.minio.Result; +import io.minio.errors.ErrorResponseException; +import io.minio.errors.InvalidExpiresRangeException; +import io.minio.messages.Bucket; +import io.minio.messages.DeleteError; +import io.minio.messages.Item; +import lombok.SneakyThrows; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +/** + * @project: itools-backend + * @description: 存储桶命名要求 + * 存储桶的命名需符合以下一个或多个规则 + * + * 存储桶名称的长度介于 3 和 63 个字符之间,并且只能包含小写字母、数字、句点和短划线。 + * 存储桶名称中的每个标签必须以小写字母或数字开头。 + * 存储桶名称不能包含下划线、以短划线结束、包含连续句点或在句点旁边使用短划线。 + * 存储桶名称不能采用 IP 地址格式 (198.51.100.24)。 + * 存储桶用作可公开访问的 URL,因此您选择的存储桶名称必须具有全局唯一性。如果您选择的名称已被其他一些帐户用于创建存储桶,则必须使用其他名称。 + * @author: XUCHANG + * @create: 2021-04-01 16:06 + */ +@Component +public class MinioUtil { + + @Autowired + private MinioClient minioClient; + + private static final int DEFAULT_EXPIRY_TIME = 7 * 24 * 3600; + + /** + * 检查存储桶是否存在 + * + * @param bucketName 存储桶名称 + * @return + */ + @SneakyThrows + public boolean bucketExists(String bucketName) { + boolean flag = false; + flag = minioClient.bucketExists(bucketName); + if (flag) { + return true; + } + return false; + } + + /** + * 创建存储桶 + * + * @param bucketName 存储桶名称 + */ + @SneakyThrows + public boolean makeBucket(String bucketName) { + boolean flag = bucketExists(bucketName); + if (!flag) { + minioClient.makeBucket(bucketName); + return true; + } else { + return false; + } + } + + /** + * 列出所有存储桶名称 + * + * @return + */ + @SneakyThrows + public List listBucketNames() { + List bucketList = listBuckets(); + List bucketListName = new ArrayList<>(); + for (Bucket bucket : bucketList) { + bucketListName.add(bucket.name()); + } + return bucketListName; + } + + /** + * 列出所有存储桶 + * + * @return + */ + @SneakyThrows + public List listBuckets() { + return minioClient.listBuckets(); + } + + /** + * 删除存储桶 + * + * @param bucketName 存储桶名称 + * @return + */ + @SneakyThrows + public boolean removeBucket(String bucketName) { + boolean flag = bucketExists(bucketName); + if (flag) { + Iterable> myObjects = listObjects(bucketName); + for (Result result : myObjects) { + Item item = result.get(); + // 有对象文件,则删除失败 + if (item.size() > 0) { + return false; + } + } + // 删除存储桶,注意,只有存储桶为空时才能删除成功。 + minioClient.removeBucket(bucketName); + flag = bucketExists(bucketName); + if (!flag) { + return true; + } + + } + return false; + } + + /** + * 列出存储桶中的所有对象名称 + * + * @param bucketName 存储桶名称 + * @return + */ + @SneakyThrows + public List listObjectNames(String bucketName) { + List listObjectNames = new ArrayList<>(); + boolean flag = bucketExists(bucketName); + if (flag) { + Iterable> myObjects = listObjects(bucketName); + for (Result result : myObjects) { + Item item = result.get(); + listObjectNames.add(item.objectName()); + } + } + return listObjectNames; + } + + /** + * 列出存储桶中的所有对象 + * + * @param bucketName 存储桶名称 + * @return + */ + @SneakyThrows + public Iterable> listObjects(String bucketName) { + boolean flag = bucketExists(bucketName); + if (flag) { + return minioClient.listObjects(bucketName); + } + return null; + } + + /** + * 通过文件上传到对象 + * + * @param bucketName 存储桶名称 + * @param objectName 存储桶里的对象名称 + * @param fileName File name + * @return + */ + @SneakyThrows + public boolean putObject(String bucketName, String objectName, String fileName) { + boolean flag = bucketExists(bucketName); + if (flag) { + minioClient.putObject(bucketName, objectName, fileName, null); + ObjectStat statObject = statObject(bucketName, objectName); + if (statObject != null && statObject.length() > 0) { + return true; + } + } + return false; + + } + + /** + * 文件上传 + * + * @param bucketName + * @param multipartFile + */ + @SneakyThrows + public void putObject(String bucketName, MultipartFile multipartFile, String filename) { + PutObjectOptions putObjectOptions = new PutObjectOptions(multipartFile.getSize(), PutObjectOptions.MIN_MULTIPART_SIZE); + putObjectOptions.setContentType(multipartFile.getContentType()); + minioClient.putObject(bucketName, filename, multipartFile.getInputStream(), putObjectOptions); + } + + /** + * 通过InputStream上传对象 + * + * @param bucketName 存储桶名称 + * @param objectName 存储桶里的对象名称 + * @param stream 要上传的流 + * @return + */ + @SneakyThrows + public boolean putObject(String bucketName, String objectName, InputStream stream) { + boolean flag = bucketExists(bucketName); + if (flag) { + minioClient.putObject(bucketName, objectName, stream, new PutObjectOptions(stream.available(), -1)); + ObjectStat statObject = statObject(bucketName, objectName); + if (statObject != null && statObject.length() > 0) { + return true; + } + } + return false; + } + + /** + * 以流的形式获取一个文件对象 + * + * @param bucketName 存储桶名称 + * @param objectName 存储桶里的对象名称 + * @return + */ + @SneakyThrows + public InputStream getObject(String bucketName, String objectName) { + boolean flag = bucketExists(bucketName); + if (flag) { + ObjectStat statObject = statObject(bucketName, objectName); + if (statObject != null && statObject.length() > 0) { + InputStream stream = minioClient.getObject(bucketName, objectName); + return stream; + } + } + return null; + } + + /** + * 以流的形式获取一个文件对象(断点下载) + * + * @param bucketName 存储桶名称 + * @param objectName 存储桶里的对象名称 + * @param offset 起始字节的位置 + * @param length 要读取的长度 (可选,如果无值则代表读到文件结尾) + * @return + */ + @SneakyThrows + public InputStream getObject(String bucketName, String objectName, long offset, Long length) { + boolean flag = bucketExists(bucketName); + if (flag) { + ObjectStat statObject = statObject(bucketName, objectName); + if (statObject != null && statObject.length() > 0) { + InputStream stream = minioClient.getObject(bucketName, objectName, offset, length); + return stream; + } + } + return null; + } + + /** + * 下载并将文件保存到本地 + * + * @param bucketName 存储桶名称 + * @param objectName 存储桶里的对象名称 + * @param fileName File name + * @return + */ + @SneakyThrows + public boolean getObject(String bucketName, String objectName, String fileName) { + boolean flag = bucketExists(bucketName); + if (flag) { + ObjectStat statObject = statObject(bucketName, objectName); + if (statObject != null && statObject.length() > 0) { + minioClient.getObject(bucketName, objectName, fileName); + return true; + } + } + return false; + } + + /** + * 删除一个对象 + * + * @param bucketName 存储桶名称 + * @param objectName 存储桶里的对象名称 + */ + @SneakyThrows + public boolean removeObject(String bucketName, String objectName) { + boolean flag = bucketExists(bucketName); + if (flag) { + minioClient.removeObject(bucketName, objectName); + return true; + } + return false; + } + + /** + * 删除指定桶的多个文件对象,返回删除错误的对象列表,全部删除成功,返回空列表 + * + * @param bucketName 存储桶名称 + * @param objectNames 含有要删除的多个object名称的迭代器对象 + * @return + */ + @SneakyThrows + public List removeObject(String bucketName, List objectNames) { + List deleteErrorNames = new ArrayList<>(); + boolean flag = bucketExists(bucketName); + if (flag) { + Iterable> results = minioClient.removeObjects(bucketName, objectNames); + for (Result result : results) { + DeleteError error = result.get(); + deleteErrorNames.add(error.objectName()); + } + } + return deleteErrorNames; + } + + /** + * 生成一个给HTTP GET请求用的presigned URL。 + * 浏览器/移动端的客户端可以用这个URL进行下载,即使其所在的存储桶是私有的。这个presigned URL可以设置一个失效时间,默认值是7天。 + * + * @param bucketName 存储桶名称 + * @param objectName 存储桶里的对象名称 + * @param expires 失效时间(以秒为单位),默认是7天,不得大于七天 + * @return + */ + @SneakyThrows + public String presignedGetObject(String bucketName, String objectName, Integer expires) { + boolean flag = bucketExists(bucketName); + String url = ""; + if (flag) { + if (expires < 1 || expires > DEFAULT_EXPIRY_TIME) { + throw new InvalidExpiresRangeException(expires, + "expires must be in range of 1 to " + DEFAULT_EXPIRY_TIME); + } + url = minioClient.presignedGetObject(bucketName, objectName, expires); + } + return url; + } + + /** + * 生成一个给HTTP PUT请求用的presigned URL。 + * 浏览器/移动端的客户端可以用这个URL进行上传,即使其所在的存储桶是私有的。这个presigned URL可以设置一个失效时间,默认值是7天。 + * + * @param bucketName 存储桶名称 + * @param objectName 存储桶里的对象名称 + * @param expires 失效时间(以秒为单位),默认是7天,不得大于七天 + * @return + */ + @SneakyThrows + public String presignedPutObject(String bucketName, String objectName, Integer expires) { + boolean flag = bucketExists(bucketName); + String url = ""; + if (flag) { + if (expires < 1 || expires > DEFAULT_EXPIRY_TIME) { + throw new InvalidExpiresRangeException(expires, + "expires must be in range of 1 to " + DEFAULT_EXPIRY_TIME); + } + url = minioClient.presignedPutObject(bucketName, objectName, expires); + } + return url; + } + + /** + * 获取对象的元数据 + * + * @param bucketName 存储桶名称 + * @param objectName 存储桶里的对象名称 + * @return + */ + @SneakyThrows + public ObjectStat statObject(String bucketName, String objectName) { + boolean flag = bucketExists(bucketName); + if (flag) { + ObjectStat statObject = minioClient.statObject(bucketName, objectName); + return statObject; + } + return null; + } + + /** + * 文件访问路径 + * + * @param bucketName 存储桶名称 + * @param objectName 存储桶里的对象名称 + * @return + */ + @SneakyThrows + public String getObjectUrl(String bucketName, String objectName) { + boolean flag = bucketExists(bucketName); + String url = ""; + if (flag) { + url = minioClient.getObjectUrl(bucketName, objectName); + } + return url; + } + + + + public void downloadFile(String bucketName, String fileName, String originalName, HttpServletResponse response) { + try { + + InputStream file = minioClient.getObject(bucketName, fileName); + String filename = new String(fileName.getBytes("ISO8859-1"), StandardCharsets.UTF_8); + if (StringUtils.isNotEmpty(originalName)) { + fileName = originalName; + } + response.setHeader("Content-Disposition", "attachment;filename=" + filename); + ServletOutputStream servletOutputStream = response.getOutputStream(); + int len; + byte[] buffer = new byte[1024]; + while ((len = file.read(buffer)) > 0) { + servletOutputStream.write(buffer, 0, len); + } + servletOutputStream.flush(); + file.close(); + servletOutputStream.close(); + } catch (ErrorResponseException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} \ No newline at end of file diff --git a/itools-fms/itools-fms-model/pom.xml b/itools-fms/itools-fms-model/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..f7be9ab8fa10a0a0e5ef12a223e814b10a793bf4 --- /dev/null +++ b/itools-fms/itools-fms-model/pom.xml @@ -0,0 +1,33 @@ + + + + itools-fms + com.itools.core + 1.0-SNAPSHOT + + 4.0.0 + + itools-fms-model + + + + com.baomidou + mybatis-plus-boot-starter + + + org.springframework.boot + spring-boot-starter-jdbc + + + com.baomidou + mybatis-plus-generator + + + org.projectlombok + lombok + + + + \ No newline at end of file diff --git a/itools-fms/itools-fms-model/src/main/java/com/itools/core/dto/accessToken/FmsAccessTokenDTO.java b/itools-fms/itools-fms-model/src/main/java/com/itools/core/dto/accessToken/FmsAccessTokenDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..ada12f03f8a82c48a0993c79b8f1916431f1e800 --- /dev/null +++ b/itools-fms/itools-fms-model/src/main/java/com/itools/core/dto/accessToken/FmsAccessTokenDTO.java @@ -0,0 +1,28 @@ +package com.itools.core.dto.accessToken; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * @project: itools-backend + * @description: + * @author: XUCHANG + * @create: 2021-03-28 15:51 + */ +@Data +@TableName("itools_fms_access_token") +public final class FmsAccessTokenDTO { + /** + * 文件访问token + */ + private String fileAccessToken; + /** + * 文件的唯一id + */ + private String uniqueId; + /** + * 访问类型:show或者download + */ + private String type; + +} diff --git a/itools-fms/itools-fms-model/src/main/java/com/itools/core/dto/businessType/FmsBusinessTypeDTO.java b/itools-fms/itools-fms-model/src/main/java/com/itools/core/dto/businessType/FmsBusinessTypeDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..9a0ff7923a590bf84a8d2546b727da6e7ffde612 --- /dev/null +++ b/itools-fms/itools-fms-model/src/main/java/com/itools/core/dto/businessType/FmsBusinessTypeDTO.java @@ -0,0 +1,52 @@ +package com.itools.core.dto.businessType; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.util.Date; + +/** + * @project: itools-backend + * @description: + * @author: XUCHANG + * @create: 2021-03-28 15:51 + */ +@Data +@TableName("itools_fms_business_type") +public class FmsBusinessTypeDTO { + /** + * 主键 + */ + private Long id; + + /** + * 业务类型 + */ + private String businessType; + + /** + * 说明 + */ + private String remark; + + /** + * 文件大小, 单位kb + */ + private String fsSize; + + /** + * 文件类型,逗号分隔符,例如: jpg,png + */ + private String fsType; + + /** + * 创建时间 + */ + private Date createDate; + + /** + * 更新时间 + */ + private Date updateDate; + +} \ No newline at end of file diff --git a/itools-fms/itools-fms-model/src/main/java/com/itools/core/dto/fileRecord/FmsRecordDTO.java b/itools-fms/itools-fms-model/src/main/java/com/itools/core/dto/fileRecord/FmsRecordDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..cc3932d1ff5b478eeaea763f1eae0134cb0c211c --- /dev/null +++ b/itools-fms/itools-fms-model/src/main/java/com/itools/core/dto/fileRecord/FmsRecordDTO.java @@ -0,0 +1,77 @@ +package com.itools.core.dto.fileRecord; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.util.Date; +import java.util.List; +/** + * @description: + * @author: XUCHANG + * @create: 2021-03-28 15:51 + */ +@Data +@TableName("itools_fms_record") +public class FmsRecordDTO { + /** + * 主键 + */ + private Long id; + + /** + * HTTP协议定义的文件类型,文件上传从文件流中获取 + * 文件存取时使用该字段填入response的content-type字段 + */ + private String contentType; + + /** + * 文件所属系统,文件上传时指定 + */ + private String fromSystemId; + + /** + * 文件大小,单位为字节 + */ + private Long fileSize; + + /** + * 文件的全局唯一ID,后续访问均使用该ID + */ + private String uniqueId; + /** + * 文件的全局唯一IDs,后续访问均使用该IDs + */ + private List uniqueIds; + + /** + * 文件描述信息 + */ + private String remark; + + /** + * 原文件名,来自入参 + */ + private String origFileName; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 删除时间 + */ + private Date deleteTime; + + /** + * 是否已删除文件本身,也即是说,删除文件时数据库记录仅仅将该字段置位1,并不实际删除数据库记录 + * 0:没有删除 + * 1:已删除 + */ + private String deleted; +} \ No newline at end of file diff --git a/itools-fms/itools-fms-model/src/main/java/com/itools/core/param/FmsAccessTokenParam.java b/itools-fms/itools-fms-model/src/main/java/com/itools/core/param/FmsAccessTokenParam.java new file mode 100644 index 0000000000000000000000000000000000000000..01f4a848076de84859efb24c4b66d120c8a574ba --- /dev/null +++ b/itools-fms/itools-fms-model/src/main/java/com/itools/core/param/FmsAccessTokenParam.java @@ -0,0 +1,69 @@ +package com.itools.core.param; + + +/** + * @project: itools-backend + * @description: + * @author: XUCHANG + * @create: 2021-03-28 15:51 + */ +public class FmsAccessTokenParam { + /** + * 有效时长 + */ + private int expiredTime; + + /** + * 最大访问次数 + */ + private int maxAccessCount; + + /** + * 文件访问唯一id + */ + private String uniqueId; + + private String type; + + public FmsAccessTokenParam(int expiredTime, int maxAccessCount, String uniqueId, String type) { + this.expiredTime = expiredTime; + this.maxAccessCount = maxAccessCount; + this.uniqueId = uniqueId; + this.type = type; + } + + public FmsAccessTokenParam() { + } + + public int getExpiredTime() { + return expiredTime; + } + + public void setExpiredTime(int expiredTime) { + this.expiredTime = expiredTime; + } + + public int getMaxAccessCount() { + return maxAccessCount; + } + + public void setMaxAccessCount(int maxAccessCount) { + this.maxAccessCount = maxAccessCount; + } + + public String getUniqueId() { + return uniqueId; + } + + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } +} diff --git a/itools-fms/itools-fms-model/src/main/java/com/itools/core/param/FmsBusinessTypeParam.java b/itools-fms/itools-fms-model/src/main/java/com/itools/core/param/FmsBusinessTypeParam.java new file mode 100644 index 0000000000000000000000000000000000000000..209597469c8edca3ad2d81a4e9017c5e48c6863c --- /dev/null +++ b/itools-fms/itools-fms-model/src/main/java/com/itools/core/param/FmsBusinessTypeParam.java @@ -0,0 +1,102 @@ +package com.itools.core.param; + +import java.util.Date; + +/** + * @project: itools-backend + * @description: + * @author: XUCHANG + * @create: 2021-03-28 15:51 + */ +public class FmsBusinessTypeParam { + /** + * 主键 + */ + private Long id; + + /** + * 业务类型 + */ + private String businessType; + + /** + * 说明 + */ + private String remark; + + /** + * 文件大小, 单位kb + */ + private String fsSize; + + /** + * 文件类型,逗号分隔符,例如: jpg,png + */ + private String fsType; + + /** + * 创建时间 + */ + private Date createDate; + + /** + * 更新时间 + */ + private Date updateDate; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getBusinessType() { + return businessType; + } + + public void setBusinessType(String businessType) { + this.businessType = businessType; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public String getFsSize() { + return fsSize; + } + + public void setFsSize(String fsSize) { + this.fsSize = fsSize; + } + + public String getFsType() { + return fsType; + } + + public void setFsType(String fsType) { + this.fsType = fsType; + } + + public Date getCreateDate() { + return createDate; + } + + public void setCreateDate(Date createDate) { + this.createDate = createDate; + } + + public Date getUpdateDate() { + return updateDate; + } + + public void setUpdateDate(Date updateDate) { + this.updateDate = updateDate; + } +} \ No newline at end of file diff --git a/itools-fms/itools-fms-model/src/main/java/com/itools/core/param/FmsUploadTokenParam.java b/itools-fms/itools-fms-model/src/main/java/com/itools/core/param/FmsUploadTokenParam.java new file mode 100644 index 0000000000000000000000000000000000000000..fb5b2c4e418f53ef6f3164fecfe408df2c7cf120 --- /dev/null +++ b/itools-fms/itools-fms-model/src/main/java/com/itools/core/param/FmsUploadTokenParam.java @@ -0,0 +1,58 @@ +package com.itools.core.param; + +import com.itools.core.result.FmsBusinessTypeResult; + +/** + * @project: itools-backend + * @description: + * @author: XUCHANG + * @create: 2021-03-28 15:51 + */ +public class FmsUploadTokenParam { + + private FmsBusinessTypeResult fsBusinessType; + private String fromSystemId; + private String needEncrypt; + private String remark; + private String originalFilename; + + public FmsBusinessTypeResult getFsBusinessType() { + return fsBusinessType; + } + + public void setFsBusinessType(FmsBusinessTypeResult fsBusinessType) { + this.fsBusinessType = fsBusinessType; + } + + public String getFromSystemId() { + return fromSystemId; + } + + public void setFromSystemId(String fromSystemId) { + this.fromSystemId = fromSystemId; + } + + public String getNeedEncrypt() { + return needEncrypt; + } + + public void setNeedEncrypt(String needEncrypt) { + this.needEncrypt = needEncrypt; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public String getOriginalFilename() { + return originalFilename; + } + + public void setOriginalFilename(String originalFilename) { + this.originalFilename = originalFilename; + } +} diff --git a/itools-fms/itools-fms-model/src/main/java/com/itools/core/request/FmsBase64FileUploadRequest.java b/itools-fms/itools-fms-model/src/main/java/com/itools/core/request/FmsBase64FileUploadRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..42ac3265b99d833fa5590324ca603f1e6b76dbd8 --- /dev/null +++ b/itools-fms/itools-fms-model/src/main/java/com/itools/core/request/FmsBase64FileUploadRequest.java @@ -0,0 +1,55 @@ +package com.itools.core.request; + +/** + * @project: itools-backend + * @description: + * @author: XUCHANG + * @create: 2021-03-28 15:51 + */ +public class FmsBase64FileUploadRequest { + + String fileBaseSixFour; + String fileName; + String businessType; + String uploadToken; + + public String getFileBaseSixFour() { + return fileBaseSixFour; + } + + + public void setFileBaseSixFour(String fileBaseSixFour) { + this.fileBaseSixFour = fileBaseSixFour; + } + + + public String getFileName() { + return fileName; + } + + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + + public String getBusinessType() { + return businessType; + } + + + public void setBusinessType(String businessType) { + this.businessType = businessType; + } + + + public String getUploadToken() { + return uploadToken; + } + + + public void setUploadToken(String uploadToken) { + this.uploadToken = uploadToken; + } + +} diff --git a/itools-fms/itools-fms-model/src/main/java/com/itools/core/request/FmsFileAccessUrlRequest.java b/itools-fms/itools-fms-model/src/main/java/com/itools/core/request/FmsFileAccessUrlRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..6f06b4fdd27b19ea2ab72374e9ef2d2e42cbf0f5 --- /dev/null +++ b/itools-fms/itools-fms-model/src/main/java/com/itools/core/request/FmsFileAccessUrlRequest.java @@ -0,0 +1,51 @@ +package com.itools.core.request; + +import java.io.Serializable; +import java.util.List; + +/** + * @Author XUCHANG + * @description: + * @Date 2020/11/5 13:46 + */ +public class FmsFileAccessUrlRequest implements Serializable { + private List uniqueIds; + private Integer expiredTime; + private Integer maxAccessCount; + private String type; + + public FmsFileAccessUrlRequest() { + } + + public List getUniqueIds() { + return uniqueIds; + } + + public void setUniqueIds(List uniqueIds) { + this.uniqueIds = uniqueIds; + } + + public Integer getExpiredTime() { + return expiredTime; + } + + public void setExpiredTime(Integer expiredTime) { + this.expiredTime = expiredTime; + } + + public Integer getMaxAccessCount() { + return maxAccessCount; + } + + public void setMaxAccessCount(Integer maxAccessCount) { + this.maxAccessCount = maxAccessCount; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } +} diff --git a/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsAccessTokenResult.java b/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsAccessTokenResult.java new file mode 100644 index 0000000000000000000000000000000000000000..0eb4450aa99264db05e17c0a8f3d497ad1e1fbe8 --- /dev/null +++ b/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsAccessTokenResult.java @@ -0,0 +1,67 @@ +package com.itools.core.result; + +/** + * @Author XUCHANG + * @description: + * @Date 2020/11/5 14:35 + */ +public class FmsAccessTokenResult { + /** + * 有效时长 + */ + private int expiredTime; + + /** + * 最大访问次数 + */ + private int maxAccessCount; + + /** + * 文件访问唯一id + */ + private String uniqueId; + + private String type; + + public FmsAccessTokenResult(int expiredTime, int maxAccessCount, String uniqueId, String type) { + this.expiredTime = expiredTime; + this.maxAccessCount = maxAccessCount; + this.uniqueId = uniqueId; + this.type = type; + } + + public FmsAccessTokenResult() { + } + + public int getExpiredTime() { + return expiredTime; + } + + public void setExpiredTime(int expiredTime) { + this.expiredTime = expiredTime; + } + + public int getMaxAccessCount() { + return maxAccessCount; + } + + public void setMaxAccessCount(int maxAccessCount) { + this.maxAccessCount = maxAccessCount; + } + + public String getUniqueId() { + return uniqueId; + } + + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } +} diff --git a/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsBusinessTypeResult.java b/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsBusinessTypeResult.java new file mode 100644 index 0000000000000000000000000000000000000000..b1a65469b7e5410ea3bf396aad6aa4a19d919914 --- /dev/null +++ b/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsBusinessTypeResult.java @@ -0,0 +1,104 @@ +package com.itools.core.result; + +import java.io.Serializable; +import java.util.Date; + +/** + * @Author XUCHANG + * @description: + * @Date 2020/11/5 14:35 + */ +public class FmsBusinessTypeResult implements Serializable { + + private static final long serialVersionUID = -5246507559164483529L; + /** + * 主键 + */ + private Long id; + + /** + * 业务类型 + */ + private String businessType; + + /** + * 说明 + */ + private String remark; + + /** + * 文件大小, 单位kb + */ + private String fsSize; + + /** + * 文件类型,逗号分隔符,例如: jpg,png + */ + private String fsType; + + /** + * 创建时间 + */ + private Date createDate; + + /** + * 更新时间 + */ + private Date updateDate; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getBusinessType() { + return businessType; + } + + public void setBusinessType(String businessType) { + this.businessType = businessType; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public String getFsSize() { + return fsSize; + } + + public void setFsSize(String fsSize) { + this.fsSize = fsSize; + } + + public String getFsType() { + return fsType; + } + + public void setFsType(String fsType) { + this.fsType = fsType; + } + + public Date getCreateDate() { + return createDate; + } + + public void setCreateDate(Date createDate) { + this.createDate = createDate; + } + + public Date getUpdateDate() { + return updateDate; + } + + public void setUpdateDate(Date updateDate) { + this.updateDate = updateDate; + } +} \ No newline at end of file diff --git a/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsDetailRecordResult.java b/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsDetailRecordResult.java new file mode 100644 index 0000000000000000000000000000000000000000..cb29afe06f246700fb5978f7584ccc718c7a6ca2 --- /dev/null +++ b/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsDetailRecordResult.java @@ -0,0 +1,156 @@ +package com.itools.core.result; + +import java.util.Date; + +/** + * @Author XUCHANG + * @description: + * @Date 2020/11/4 18:01 + */ +public class FmsDetailRecordResult { + /** + * 主键 + */ + private Long id; + + /** + * HTTP协议定义的文件类型,文件上传从文件流中获取 + * 文件存取时使用该字段填入response的content-type字段 + */ + private String contentType; + + /** + * 文件所属系统,文件上传时指定 + */ + private String fromSystemId; + + /** + * 文件大小,单位为字节 + */ + private Long fileSize; + + /** + * 文件的全局唯一ID,后续访问均使用该ID + */ + private String uniqueId; + + /** + * 文件描述信息 + */ + private String remark; + + /** + * 原文件名,来自入参 + */ + private String origFileName; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 删除时间 + */ + private Date deleteTime; + + /** + * 是否已删除文件本身,也即是说,删除文件时数据库记录仅仅将该字段置位1,并不实际删除数据库记录 + * 0:没有删除 + * 1:已删除 + */ + private String deleted; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getContentType() { + return contentType; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + public String getFromSystemId() { + return fromSystemId; + } + + public void setFromSystemId(String fromSystemId) { + this.fromSystemId = fromSystemId; + } + + public Long getFileSize() { + return fileSize; + } + + public void setFileSize(Long fileSize) { + this.fileSize = fileSize; + } + + public String getUniqueId() { + return uniqueId; + } + + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public String getOrigFileName() { + return origFileName; + } + + public void setOrigFileName(String origFileName) { + this.origFileName = origFileName; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + + public Date getDeleteTime() { + return deleteTime; + } + + public void setDeleteTime(Date deleteTime) { + this.deleteTime = deleteTime; + } + + public String getDeleted() { + return deleted; + } + + public void setDeleted(String deleted) { + this.deleted = deleted; + } +} \ No newline at end of file diff --git a/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsFileRecordPathResult.java b/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsFileRecordPathResult.java new file mode 100644 index 0000000000000000000000000000000000000000..18b04c685136c95e141c5d79dcc1f0d5166514d1 --- /dev/null +++ b/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsFileRecordPathResult.java @@ -0,0 +1,32 @@ +package com.itools.core.result; + +import java.io.Serializable; + +/** + * @Author XUCHANG + * @description: + * @Date 2020/11/5 14:35 + */ +public class FmsFileRecordPathResult implements Serializable { + /** + * 文件访问唯一id + */ + private String uniqueId; + private String path; + + public String getUniqueId() { + return uniqueId; + } + + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } +} diff --git a/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsFileUploadResult.java b/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsFileUploadResult.java new file mode 100644 index 0000000000000000000000000000000000000000..675c01835bb920501e6322cc994eab0ef6dff9c5 --- /dev/null +++ b/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsFileUploadResult.java @@ -0,0 +1,21 @@ +package com.itools.core.result; + +/** + * @Author XUCHANG + * @description: + * @Date 2020/11/5 14:35 + */ +public class FmsFileUploadResult { + /** + * 成功时必填,该文件的唯一ID + */ + private String uniqueId; + + public String getUniqueId() { + return uniqueId; + } + + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } +} diff --git a/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsMultipartFileResult.java b/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsMultipartFileResult.java new file mode 100644 index 0000000000000000000000000000000000000000..9d6b560c4c8f4fa03e3c3c12c3db60411760265d --- /dev/null +++ b/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsMultipartFileResult.java @@ -0,0 +1,35 @@ +package com.itools.core.result; + +import java.io.Serializable; + +/** + * @Author XUCHANG + * @description: + * @Date 2020/11/4 18:01 + */ +public class FmsMultipartFileResult implements Serializable { + /** + * 文件访问唯一id + */ + private String uniqueId; + /** + * 文件名称 + */ + private String fileName; + + public String getUniqueId() { + return uniqueId; + } + + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } +} diff --git a/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsRecordResult.java b/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsRecordResult.java new file mode 100644 index 0000000000000000000000000000000000000000..470226e692f505c8578a45bd32df402e6b48af3d --- /dev/null +++ b/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsRecordResult.java @@ -0,0 +1,20 @@ +package com.itools.core.result; + +/** + * @Author XUCHANG + * @description: + * @Date 2020/11/4 18:01 + */ +public class FmsRecordResult { + + private FmsDetailRecordResult fssRecord; + + public FmsDetailRecordResult getFssRecord() { + return fssRecord; + } + + public void setFssRecord(FmsDetailRecordResult fssRecord) { + this.fssRecord = fssRecord; + } + +} diff --git a/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsUploadTokenResult.java b/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsUploadTokenResult.java new file mode 100644 index 0000000000000000000000000000000000000000..2eb7f12fde6012ae68a6554981c0d9bbc958841d --- /dev/null +++ b/itools-fms/itools-fms-model/src/main/java/com/itools/core/result/FmsUploadTokenResult.java @@ -0,0 +1,49 @@ +package com.itools.core.result; + +import java.io.Serializable; + +/** + * @Author XUCHANG + * @description: + * @Date 2020/11/4 18:01 + */ +public class FmsUploadTokenResult implements Serializable { + + private FmsBusinessTypeResult fsBusinessType; + + private String fromSystemId; + private String needEncrypt; + private String remark; + + public FmsBusinessTypeResult getFsBusinessType() { + return fsBusinessType; + } + + public void setFsBusinessType(FmsBusinessTypeResult fsBusinessType) { + this.fsBusinessType = fsBusinessType; + } + + public String getFromSystemId() { + return fromSystemId; + } + + public void setFromSystemId(String fromSystemId) { + this.fromSystemId = fromSystemId; + } + + public String getNeedEncrypt() { + return needEncrypt; + } + + public void setNeedEncrypt(String needEncrypt) { + this.needEncrypt = needEncrypt; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } +} diff --git a/itools-fms/itools-fms-server/pom.xml b/itools-fms/itools-fms-server/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..9c509107e9d8af9492bce0cd16c691fa1af9790d --- /dev/null +++ b/itools-fms/itools-fms-server/pom.xml @@ -0,0 +1,90 @@ + + + + itools-fms + com.itools.core + 1.0-SNAPSHOT + + 4.0.0 + + itools-fms-server + + + com.itools.core + itools-fms-core + 1.0-SNAPSHOT + + + com.itools.core + itools-fms-model + 1.0-SNAPSHOT + + + com.itools.core + itools-common + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-web + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config + + + org.projectlombok + lombok + + + com.baomidou + mybatis-plus-boot-starter + + + org.springframework.boot + spring-boot-starter-jdbc + + + com.baomidou + mybatis-plus-generator + + + + mysql + mysql-connector-java + + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.apache.commons + commons-pool2 + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/itools-fms/itools-fms-server/src/main/java/com/itools/core/FileSystemApplication.java b/itools-fms/itools-fms-server/src/main/java/com/itools/core/FileSystemApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..d19c47834b18cde23968ead5e8a32d6a260bd434 --- /dev/null +++ b/itools-fms/itools-fms-server/src/main/java/com/itools/core/FileSystemApplication.java @@ -0,0 +1,54 @@ +package com.itools.core; + +import com.itools.core.snowflake.config.EnableSequenceService; +import com.itools.core.validate.EnableValidator; +import lombok.extern.log4j.Log4j2; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.Banner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +/** + * @description: + * @author: XUCHANG + * @create: 2021-03-28 15:51 + */ +@SpringBootApplication +@EnableSequenceService +@EnableValidator +@MapperScan("com.itools.core.mapper") +public class FileSystemApplication { + public static void main(String[] args) { + SpringApplication springApplication = new SpringApplication(FileSystemApplication.class); + springApplication.setBannerMode(Banner.Mode.OFF); + springApplication.run(args); + } + @Bean + public CorsFilter corsFilter() { + final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + final CorsConfiguration config = new CorsConfiguration(); + // 允许cookies跨域 + config.setAllowCredentials(true); + // 允许向该服务器提交请求的URI,*表示全部允许。。这里尽量限制来源域,比如http://xxxx:8080 ,以降低安全风险。。 + config.addAllowedOrigin("*"); + // 允许访问的头信息,*表示全部 + config.addAllowedHeader("*"); + // 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了 + config.setMaxAge(18000L); + // 允许提交请求的方法,*表示全部允许,也可以单独设置GET、PUT等 + config.addAllowedMethod("*"); + config.addAllowedMethod("HEAD"); + // 允许Get的请求方法 + config.addAllowedMethod("GET"); + config.addAllowedMethod("PUT"); + config.addAllowedMethod("POST"); + config.addAllowedMethod("DELETE"); + config.addAllowedMethod("PATCH"); + source.registerCorsConfiguration("/**", config); + return new CorsFilter(source); + } +} diff --git a/itools-fms/itools-fms-server/src/main/java/com/itools/core/controller/FmsFileRecordController.java b/itools-fms/itools-fms-server/src/main/java/com/itools/core/controller/FmsFileRecordController.java new file mode 100644 index 0000000000000000000000000000000000000000..0ad6405bded3208a709bb8816808385a177caa4b --- /dev/null +++ b/itools-fms/itools-fms-server/src/main/java/com/itools/core/controller/FmsFileRecordController.java @@ -0,0 +1,44 @@ +package com.itools.core.controller; + + +import com.itools.core.base.CommonResult; +import com.itools.core.log.Logable; +import com.itools.core.result.FmsRecordResult; +import com.itools.core.result.FmsDetailRecordResult; +import com.itools.core.service.FmsRecordService; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.io.IOException; + +/** + * @description: + * @author: XUCHANG + * @create: 2021-04-01 11:26 + */ +@RestController +@ApiOperation("FmsFileRecordController") +public class FmsFileRecordController { + + @Autowired + private FmsRecordService fmsRecordService; + + /** + * 获取文件记录信息 (内部调用) + * @return + * @throws IOException + */ + @RequestMapping(value = "/fssRecord", method = RequestMethod.GET) + @Logable + @ApiOperation(value = "获取文件记录信息", notes = "获取文件记录信息", httpMethod = "GET") + public CommonResult queryFssRecordByUniqueId(@RequestParam("uniqueId") String uniqueId) { + FmsRecordResult response = new FmsRecordResult(); + FmsDetailRecordResult record = fmsRecordService.queryFssRecordByUniqueId(uniqueId); + response.setFssRecord(record); + return CommonResult.success(response); + } +} diff --git a/itools-fms/itools-fms-server/src/main/java/com/itools/core/controller/FmsFileSystemController.java b/itools-fms/itools-fms-server/src/main/java/com/itools/core/controller/FmsFileSystemController.java new file mode 100644 index 0000000000000000000000000000000000000000..1750651794168d23eacec1a92d9a53032badcfcb --- /dev/null +++ b/itools-fms/itools-fms-server/src/main/java/com/itools/core/controller/FmsFileSystemController.java @@ -0,0 +1,313 @@ +package com.itools.core.controller; + +import com.itools.core.base.CommonResult; +import com.itools.core.em.FmsCodeBean; +import com.itools.core.exception.AppException; +import com.itools.core.log.Logable; +import com.itools.core.param.FmsAccessTokenParam; +import com.itools.core.param.FmsUploadTokenParam; +import com.itools.core.param.FmsBusinessTypeParam; +import com.itools.core.request.FmsBase64FileUploadRequest; +import com.itools.core.result.*; +import com.itools.core.service.FmsAccessTokenService; +import com.itools.core.service.FmsBusinessTypeService; +import com.itools.core.service.FmsFileSystemService; +import com.itools.core.utils.Base64Utils; +import com.itools.core.utils.StringUtils; +import com.itools.core.utils.ZipUtils; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.FileCopyUtils; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import sun.misc.BASE64Encoder; + +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.List; +/** + * @description: + * @author: XUCHANG + * @create: 2021-04-01 11:26 + */ +@RestController +@ApiOperation("FmsFileSystemController") +public class FmsFileSystemController { + + @Autowired + private FmsBusinessTypeService fmsBusinessTypeService; + + @Autowired + private FmsAccessTokenService fmsAccessTokenService; + + @Autowired + private FmsFileSystemService fmsFileSystemService; + + private static final String SHOW = "show"; + + private static final String DOWNLOAD = "download"; + + private static final Logger LOGGER = LoggerFactory.getLogger(FmsFileSystemController.class); + + @PostMapping("FilePath") + @Logable + @ApiOperation(value = "获取文件访问路径", notes = "获取文件访问路径", httpMethod = "POST") + @ApiImplicitParams({ + @ApiImplicitParam(name = "uniqueId", value = "文件的唯一ID", required = true, dataType = "String", paramType = "query"), + @ApiImplicitParam(name = "expiredTime", value = "有效时长,单位分钟", required = true, dataType = "Long", paramType = "query"), + @ApiImplicitParam(name = "maxAccessCount", value = "最大访问次数", required = false, dataType = "Long", paramType = "query"), + @ApiImplicitParam(name = "type", value = "文件下载 download/展示 show", required = true, dataType = "String", paramType = "query") + }) + public CommonResult getFileAccessUrl(String uniqueId, Integer expiredTime, @RequestParam(defaultValue = "-1", required = false) int maxAccessCount, String type) { + String fileUrlByFileId = fmsFileSystemService.getFileUrlByFileId(uniqueId, expiredTime, maxAccessCount, type); + return CommonResult.success(fileUrlByFileId); + } + + @PostMapping("FilesPath") + @Logable + @ApiOperation(value = "获取文件访问路径", notes = "获取文件访问路径", httpMethod = "POST") + @ApiImplicitParams({ + @ApiImplicitParam(name = "uniqueIds", value = "文件的唯一IDS数组", required = true, dataType = "String", paramType = "query"), + @ApiImplicitParam(name = "expiredTime", value = "有效时长,单位分钟", required = true, dataType = "Long", paramType = "query"), + @ApiImplicitParam(name = "maxAccessCount", value = "最大访问次数", required = false, dataType = "Long", paramType = "query"), + @ApiImplicitParam(name = "type", value = "文件下载 download/展示 show", required = true, dataType = "String", paramType = "query") + }) + public CommonResult getFileAccessUrl(@RequestParam(value = "uniqueIds",required = false) List uniqueIds, + @RequestParam(value = "expiredTime",required = false) Integer expiredTime, + @RequestParam(value = "maxAccessCount",defaultValue = "-1", required = false) Integer maxAccessCount, + @RequestParam(value = "type",required = false) String type) { + return fmsFileSystemService.getFileUrlByFileIds(uniqueIds, expiredTime, maxAccessCount, type); + } + + /** + * 仅内部微服务使用,不应该对外开放 + * @param businessType + * @param fromSystemId + * @param needEncrypt + * @param remark + * @return + */ + @PostMapping("UploadToken") + @Logable + @ApiOperation(value = "申请文件上传token", notes = "申请文件上传token", httpMethod = "POST") + @ApiImplicitParams({ + @ApiImplicitParam(name = "businessType", value = "文件类型", required = true, dataType = "String", paramType = "query"), + @ApiImplicitParam(name = "fromSystemId", value = "上传的文件来自哪个子系统,系统编号", required = true, dataType = "String", paramType = "query"), + @ApiImplicitParam(name = "needEncrypt", value = "是否需加密,后续扩展使用,本期不使用,默认否.0:否 1:是", required = false, dataType = "String", paramType = "query"), + @ApiImplicitParam(name = "remark", value = "文件描述信息", required = false, dataType = "String", paramType = "query") + }) + public CommonResult applyUploadToken(String businessType, String fromSystemId, @RequestParam(required = false, defaultValue = "0") String needEncrypt, String remark) { + String uploadToken = fmsFileSystemService.applyUploadToken(businessType, fromSystemId, needEncrypt, remark); + return CommonResult.success(uploadToken); + } + + @GetMapping("File/{uniqueId}") + @Logable + public void downloadFile(@PathVariable String uniqueId, @RequestParam("fileAccessToken") String fileAccessToken, HttpServletResponse response) { + try { + FmsAccessTokenResult fsAccessToken = fmsAccessTokenService.getFileAccessToken(fileAccessToken); + if (fsAccessToken == null) { + throw new AppException(FmsCodeBean.FmsCode.INVALID_FS_TOKEN.code); + } + if (!uniqueId.equals(fsAccessToken.getUniqueId())) { + throw new AppException(FmsCodeBean.FmsCode.NOT_EXIST_FILE.code); + } + FmsAccessTokenParam param = new FmsAccessTokenParam(); + BeanUtils.copyProperties(fsAccessToken , param); + FmsDetailRecordResult fsUploadRecord = fmsFileSystemService.getFileUploadRecord(param, uniqueId, fileAccessToken); + String type = fsAccessToken.getType(); + if (SHOW.equals(type)) { + response.addHeader("Content-Length", "" + fsUploadRecord.getFileSize()); + } else if (DOWNLOAD.equals(type)) { + // 设置文件名, 可用于下载 + response.addHeader("Content-Length", "" + fsUploadRecord.getFileSize()); + response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(fsUploadRecord.getOrigFileName(), "utf-8")); + } + response.setCharacterEncoding("UTF-8"); + response.setContentType(fsUploadRecord.getContentType()); + OutputStream outputStream = response.getOutputStream(); + FileCopyUtils.copy(new FileInputStream(fmsFileSystemService.getFileLocalPath(fsUploadRecord.getUniqueId() , fsUploadRecord.getOrigFileName())), outputStream); + } catch (AppException e) { + String errorCode = e.getErrorCode(); + response.setStatus(Integer.parseInt(errorCode)); + return; + } catch (IOException e) { + response.setStatus(500); + return; + } + } + + @GetMapping("File/getFileBase64") + @Logable + public CommonResult getFileBase64(@RequestParam("uniqueId")String uniqueId){ + FmsDetailRecordResult fsUploadRecord = fmsFileSystemService.getFileUploadRecord(uniqueId); + try { + String path = fmsFileSystemService.getFileLocalPath(fsUploadRecord.getUniqueId() , fsUploadRecord.getOrigFileName()); + File file = new File(path); + FileInputStream fileInputStream = new FileInputStream(file); + byte[] buffer = new byte[(int)file.length()]; + fileInputStream.read(buffer); + fileInputStream.close(); + return CommonResult.success(new BASE64Encoder().encode(buffer)); + } catch (Exception e) { + LOGGER.error(FmsCodeBean.FmsCode.ERROR_TRANS_BASE64.code, e); + throw new AppException(FmsCodeBean.FmsCode.ERROR_TRANS_BASE64.code, FmsCodeBean.FmsCode.ERROR_TRANS_BASE64.message); + } + } + + /** + * 此接口不对外开放,仅供内部微服务使用 + * @param base64Req + * @return + */ + @PostMapping("File/BaseSixFour") + @Logable + @ApiOperation(value = "文件上传", notes = "文件上传", httpMethod = "POST") + public CommonResult uploadFileBase64(@RequestBody(required = true) FmsBase64FileUploadRequest base64Req) { + FmsUploadTokenResult fsUploadToken = fmsBusinessTypeService.getFsBusinessTypeByUploadToken(base64Req.getUploadToken()); + if (fsUploadToken == null) { + throw new AppException(FmsCodeBean.FmsCode.ERROR_TIMEOUT.code); + } + FmsBusinessTypeResult fsBusinessType = fsUploadToken.getFsBusinessType(); + byte[] fileBytes; + try { + //将字符串转换为byte数组 + fileBytes = Base64Utils.decode(base64Req.getFileBaseSixFour()); + } catch (Exception e) { + throw new AppException(FmsCodeBean.FmsCode.FAIL.code); + } + + String fsSize = fsBusinessType.getFsSize(); + Long limitSize = Long.parseLong(fsSize); + long fileSize = fileBytes.length; + int mult = 1024; + if (fileSize > (limitSize * mult)) { + throw new AppException(FmsCodeBean.FmsCode.ERROR_FILESIZE_OUT_OFF_LIMIT.code); + } + if (!fsBusinessType.getBusinessType().equals(base64Req.getBusinessType())) { + // 文件类型不一致 + throw new AppException(FmsCodeBean.FmsCode.ERROR_FILETYPE.code); + } + FmsBusinessTypeParam fmsBusinessTypeParam = new FmsBusinessTypeParam(); + BeanUtils.copyProperties(fsBusinessType , fmsBusinessTypeParam); + FmsUploadTokenParam fmsUploadTokenParam = new FmsUploadTokenParam(); + BeanUtils.copyProperties(fsUploadToken , fmsUploadTokenParam); + String fileUploadResponse = fmsFileSystemService.saveFileFromBytes(fileBytes, base64Req.getFileName(), fmsBusinessTypeParam, fmsUploadTokenParam); + fmsBusinessTypeService.deleteFsBusinessTypeByUploadToken(base64Req.getUploadToken()); + return CommonResult.success(fileUploadResponse); + } + + /** + * 返回文件的唯一ID + * @param file + * @param uploadToken + * @return + */ + @PostMapping("File") + @Logable + @ApiOperation(value = "文件上传", notes = "文件上传", httpMethod = "POST") + @ApiImplicitParams({ + @ApiImplicitParam(name = "uploadToken", value = "文件上传token", required = true, dataType = "String", paramType = "query") + }) + public CommonResult fileUpload(@RequestPart(name = "file", required = true) MultipartFile file, + String uploadToken, + String fileName) { + //压缩过后的文件名称前端无法获取,额外的字段标识 + String originalFilename = file.getOriginalFilename(); + if (!StringUtils.isBlank(fileName)){ + originalFilename = fileName; + } + FmsFileUploadResult response = new FmsFileUploadResult(); + if (file == null || StringUtils.isBlank(originalFilename)) { + // 文件不能为空 + throw new AppException(FmsCodeBean.FmsCode.ERROR_FILE_IS_NULL.code); + } + FmsUploadTokenResult fsUploadToken = fmsBusinessTypeService.getFsBusinessTypeByUploadToken(uploadToken); + if (fsUploadToken == null) { + throw new AppException(FmsCodeBean.FmsCode.ERROR_TIMEOUT.code); + } + FmsBusinessTypeResult fsBusinessType = fsUploadToken.getFsBusinessType(); + String fsSize = fsBusinessType.getFsSize(); + Long limitSize = Long.parseLong(fsSize); + long fileSize = file.getSize(); + int mult = 102400; + if (fileSize > (limitSize * mult)) { + throw new AppException(FmsCodeBean.FmsCode.ERROR_FILESIZE_OUT_OFF_LIMIT.code); + } + String fsType = fsBusinessType.getFsType(); + if (StringUtils.equals(fsType, "currency")){ + //如果取值为currency,则不判断类型 + }else { + String suffix = originalFilename.substring(originalFilename.lastIndexOf(".") + 1); + String contentType = file.getContentType(); + if (contentType == null || !fsType.contains(suffix.trim().toLowerCase()) || !fsType.contains(contentType)) { + LOGGER.error(FmsCodeBean.FmsCode.ERROR_FILETYPE.code, "文件类型:" + suffix + " || " + contentType); + // 文件后缀错误 + throw new AppException(FmsCodeBean.FmsCode.ERROR_FILETYPE.code); + } + } + + FmsUploadTokenParam param = new FmsUploadTokenParam(); + BeanUtils.copyProperties(fsUploadToken , param); + param.setOriginalFilename(originalFilename); + String uniqueId = fmsFileSystemService.saveFile(file, param); + fmsBusinessTypeService.deleteFsBusinessTypeByUploadToken(uploadToken); + response.setUniqueId(uniqueId); + return CommonResult.success(response); + } + + /** + * 文件批量上传 + * @param files 文件 + * @param uploadToken 申请的token + * @return + */ + @PostMapping("/Files") + @Logable + @ApiOperation(value = "批量上传文件", notes = "批量上传文件", httpMethod = "POST") + @ApiImplicitParams({ + @ApiImplicitParam(name = "uploadToken", value = "文件上传token", required = true, dataType = "String", paramType = "query") + }) + public CommonResult filesMultipartUpload(@RequestPart(name = "files", required = true) MultipartFile[] files, String uploadToken) { + + return fmsFileSystemService.filesMultipartUpload(files,uploadToken); + } + + @ApiOperation(value = "下载zip压缩文件接口", notes = "下载zip压缩文件接口", httpMethod = "GET") + @Logable + @RequestMapping(value = "/download/zip",method = RequestMethod.GET) + public void downloadZipByUniqueIds(@RequestParam("uniqueIds") List uniqueIds, + @RequestParam(value = "zipName", required = false) String zipName, + HttpServletResponse response) throws IOException { + if (StringUtils.isBlank(zipName)) { + zipName = "attachment"; + } + List paths = new ArrayList<>(); + List files = new ArrayList<>(); + for (String uniqueId : uniqueIds) { + FmsDetailRecordResult fsUploadRecord = fmsFileSystemService.getFileUploadRecord(uniqueId); + String path = fmsFileSystemService.getFileLocalPath(uniqueId, fsUploadRecord.getOrigFileName()); + paths.add(path); + File file = new File(path); + files.add(file); + } + try { + response.setContentType("application/zip"); + response.setHeader("Content-Disposition", "attachment; fileName=" + URLEncoder.encode(zipName + ".zip", "utf-8")); + OutputStream outputStream = response.getOutputStream(); + ZipUtils.toZip(files, outputStream); + } catch (FileNotFoundException e) { + throw new AppException(FmsCodeBean.FmsCode.NOT_EXIST_FILE.code); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} \ No newline at end of file diff --git a/itools-fms/itools-fms-server/src/main/java/com/itools/core/controller/TestController.java b/itools-fms/itools-fms-server/src/main/java/com/itools/core/controller/TestController.java new file mode 100644 index 0000000000000000000000000000000000000000..2ad997e7358deda46f1eab8aaa8e2e627683cd4e --- /dev/null +++ b/itools-fms/itools-fms-server/src/main/java/com/itools/core/controller/TestController.java @@ -0,0 +1,35 @@ +package com.itools.core.controller; + +import com.itools.core.base.CommonResult; +import com.itools.core.context.FileStrategyServiceContext; +import com.itools.core.em.StrategyType; +import com.itools.core.service.FileManagerService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @project: itools-backend + * @description: + * @author: XUCHANG + * @create: 2021-04-01 16:23 + */ +@RestController +public class TestController { + @Qualifier("fastDfsFileManagerServiceImpl") + @Autowired + private FileManagerService fileManagerService; + + @Autowired + private FileStrategyServiceContext fileStrategyServiceContext; + @GetMapping("/test") + public CommonResult test(){ + FileManagerService fileManagerService2 = fileStrategyServiceContext.get(StrategyType.NIO.getType()); + return fileManagerService2.mutipartUploadFiles(); + } + @GetMapping("/test2") + public CommonResult test2(){ + return fileManagerService.mutipartUploadFiles(); + } +} diff --git a/itools-fms/itools-fms-server/src/main/java/com/itools/core/mapper/FmsAccessTokenMapper.java b/itools-fms/itools-fms-server/src/main/java/com/itools/core/mapper/FmsAccessTokenMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..e770dbd97ae9aeebf5f4537c6735abe1886b1114 --- /dev/null +++ b/itools-fms/itools-fms-server/src/main/java/com/itools/core/mapper/FmsAccessTokenMapper.java @@ -0,0 +1,34 @@ +package com.itools.core.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.itools.core.dto.accessToken.FmsAccessTokenDTO; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; + + +/** + * @description: + * @author: XUCHANG + * @create: 2021-03-28 15:51 + */ +@Repository +public interface FmsAccessTokenMapper extends BaseMapper { + + + /** + * 根据主键(fileAccessToken)查询 + * + * @param fileAccessToken + * @return + */ + FmsAccessTokenDTO selectByPrimaryKey(String fileAccessToken); + + /** + * 批量插入 + * @param records + * @return + */ + int multipartInsert(@Param("records") List records); +} \ No newline at end of file diff --git a/itools-fms/itools-fms-server/src/main/java/com/itools/core/mapper/FmsBusinessTypeMapper.java b/itools-fms/itools-fms-server/src/main/java/com/itools/core/mapper/FmsBusinessTypeMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..7fd866bf82157577ba2a9746da4123871cbdf413 --- /dev/null +++ b/itools-fms/itools-fms-server/src/main/java/com/itools/core/mapper/FmsBusinessTypeMapper.java @@ -0,0 +1,52 @@ +package com.itools.core.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.itools.core.dto.businessType.FmsBusinessTypeDTO; +import org.springframework.stereotype.Repository; + +import java.util.List; +/** + * @description: + * @author: XUCHANG + * @create: 2021-03-28 15:51 + */ +@Repository +public interface FmsBusinessTypeMapper extends BaseMapper { + /** + * 根据主键删除 + * @param id + * @return + */ + int deleteByPrimaryKey(Long id); + + /** + * 插入非空参数 + * @param record + * @return + */ + int insertSelective(FmsBusinessTypeDTO record); + /** + * 根据主键查询 + * @param id + * @return + */ + FmsBusinessTypeDTO selectByPrimaryKey(Long id); + /** + * 根据主键更新非空参数 + * @param record + * @return + */ + int updateByPrimaryKeySelective(FmsBusinessTypeDTO record); + /** + * 根据主键更新所有参数 + * @param record + * @return + */ + int updateByPrimaryKey(FmsBusinessTypeDTO record); + /** + * 根据入参条件查询 + * @param record + * @return + */ + List selectBySelective(FmsBusinessTypeDTO record); +} \ No newline at end of file diff --git a/itools-fms/itools-fms-server/src/main/java/com/itools/core/mapper/FmsFileRecordMapper.java b/itools-fms/itools-fms-server/src/main/java/com/itools/core/mapper/FmsFileRecordMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..28a6eb7539fafa1b4ca8c897ef3c591bd218dd7a --- /dev/null +++ b/itools-fms/itools-fms-server/src/main/java/com/itools/core/mapper/FmsFileRecordMapper.java @@ -0,0 +1,54 @@ +package com.itools.core.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.itools.core.dto.fileRecord.FmsRecordDTO; +import org.springframework.stereotype.Repository; + +import java.util.List; +/** + * @description: + * @author: XUCHANG + * @create: 2021-03-28 15:51 + */ +@Repository +public interface FmsFileRecordMapper extends BaseMapper { + + /** + * 根据主键更新非空参数 + * @param record + * @return + */ + int updateByPrimaryKeySelective(FmsRecordDTO record); + + /** + * 根据入参条件查询 + * @param record + * @return + */ + List selectbySelective(FmsRecordDTO record); + /** + * 插入非空参数 + * @param record + * @return + */ + int insertSelective(FmsRecordDTO record); + /** + * 根据主键查询 + * @param id + * @return + */ + FmsRecordDTO selectByPrimaryKey(Long id); + /** + * 根据主键删除 + * @param id + * @return + */ + int deleteByPrimaryKey(Long id); + /** + * 根据主键更新所有参数 + * @param record + * @return + */ + int updateByPrimaryKey(FmsRecordDTO record); + +} \ No newline at end of file diff --git a/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/FmsAccessTokenService.java b/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/FmsAccessTokenService.java new file mode 100644 index 0000000000000000000000000000000000000000..0cd8e5fbd93873f140bc679593f99e32c7d47d9d --- /dev/null +++ b/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/FmsAccessTokenService.java @@ -0,0 +1,40 @@ +package com.itools.core.service; + + +import com.itools.core.result.FmsAccessTokenResult; + +/** + * @description: + * @author: XUCHANG + * @create: 2021-04-01 11:26 + */ +public interface FmsAccessTokenService { + + /** + * 从缓存中获取FsAccessToken信息 + * + * @param fileAccessToken + * @return + */ + FmsAccessTokenResult getFileAccessToken(String fileAccessToken); + + /** + * 缓存FsAccessToken信息 + * + * @param fileAccessToken + * @param expiredTime + * @param maxAccessCount + * @param uniqueId + * @param type + * @return + */ + FmsAccessTokenResult cacheFileAccessToken(String fileAccessToken, int expiredTime, int maxAccessCount, String uniqueId, String type); + + + /** + * 删除缓存数据 + * + * @param fileAccessToken + */ + void deleteFileAccessToken(String fileAccessToken); +} diff --git a/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/FmsBusinessTypeService.java b/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/FmsBusinessTypeService.java new file mode 100644 index 0000000000000000000000000000000000000000..488b149faaa71470f62cde0d109f030bab5a224d --- /dev/null +++ b/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/FmsBusinessTypeService.java @@ -0,0 +1,42 @@ +package com.itools.core.service; + + +import com.itools.core.param.FmsUploadTokenParam; +import com.itools.core.result.FmsUploadTokenResult; +import com.itools.core.result.FmsBusinessTypeResult; + +import java.util.List; + +/** + * @description: + * @author: XUCHANG + * @create: 2021-04-01 11:26 + */ +public interface FmsBusinessTypeService { + + /** + * 查询FsBusinessType列表 + * + * @param businessType + * @return + */ + List queryFsBusinessTypeList(String businessType); + + /** + * 根据 uploadToken ,缓存FsBusinessType对象 + * + * @param uploadToken + * @return + */ + FmsUploadTokenResult cacheFsUploadToken(String uploadToken, FmsUploadTokenParam fsUploadToken); + + /** + * 根据 uploadToken ,获取FsBusinessType对象 + * + * @param uploadToken + * @return + */ + FmsUploadTokenResult getFsBusinessTypeByUploadToken(String uploadToken); + + void deleteFsBusinessTypeByUploadToken(String uploadToken); +} diff --git a/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/FmsFileSystemService.java b/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/FmsFileSystemService.java new file mode 100644 index 0000000000000000000000000000000000000000..3f8cae691f31043a952840fc61d3b6df94f4da6d --- /dev/null +++ b/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/FmsFileSystemService.java @@ -0,0 +1,128 @@ +package com.itools.core.service; + +import com.itools.core.base.CommonResult; +import com.itools.core.param.FmsAccessTokenParam; +import com.itools.core.param.FmsUploadTokenParam; +import com.itools.core.param.FmsBusinessTypeParam; +import com.itools.core.result.FmsBusinessTypeResult; +import com.itools.core.result.FmsDetailRecordResult; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +/** + * @project: itools-backend + * @description: + * @author: XUCHANG + * @create: 2021-04-01 11:26 + */ +public interface FmsFileSystemService { + + /** + * 根据uniqeId和文件名得到本地文件存储路径 + * @param uniqueId + * @param fileName + * @return + */ + String getFileLocalPath(String uniqueId, String fileName); + + + + /** + * 存储文件 + * + * @param file + * @param fsUploadToken + * @return + */ + String saveFile(MultipartFile file, FmsUploadTokenParam fsUploadToken); + + + + /** + * 申请文件上传token + * @param businessType + * @param fromSystemId + * @param needEncrypt + * @param remark + * @return + */ + String applyUploadToken(String businessType, String fromSystemId, String needEncrypt, String remark); + + + /** + * 存储文件 + * 使用字节流输入文件 + * 返回文件的全局唯一ID + * @param fileBytes + * @param fileName + * @param fsBusinessType + * @param fsUploadToken + * @return + */ + String saveFileFromBytes(byte[] fileBytes, String fileName, FmsBusinessTypeParam fsBusinessType, FmsUploadTokenParam fsUploadToken); + + + + + /** + * 获取文件访问路径,如果超时时间设置为小于等于0,那么返回的有效路径可以永久访问 + * + * @param uniqueId + * @param expiredTime + * @param maxAccessCount + * @return + */ + String getFileUrlByFileId(String uniqueId, int expiredTime, int maxAccessCount, String type); + + /** + * 获得uniqueId对应的文件上传记录 + * 会检查 + * @param fsAccessToken + * @param uniqueId + * @param fileAccessToken + * @return + */ + FmsDetailRecordResult getFileUploadRecord(FmsAccessTokenParam fsAccessToken, String uniqueId, String fileAccessToken); + + + /** + * 获得uniqueId对应的文件上传记录 + * @param uniqueId + * @return + */ + FmsDetailRecordResult getFileUploadRecord(String uniqueId); + + /** + * 文件批量上传 + * @param files + * @param param + * @return + */ + CommonResult uploadFiles(MultipartFile[] files, FmsUploadTokenParam param); + + /** + * 验证文件 + * @param files + * @param fsBusinessType + */ + void verifyFiles(MultipartFile[] files, FmsBusinessTypeResult fsBusinessType); + + /** + * 文件批量上传的业务逻辑 + * @param files + * @param uploadToken + * @return + */ + CommonResult filesMultipartUpload(MultipartFile[] files, String uploadToken); + + /** + * 获取文件访问路径,如果超时时间设置为小于等于0,那么返回的有效路径可以永久访问 + * @param uniqueIds + * @param expiredTime + * @param maxAccessCount + * @param type + * @return + */ + CommonResult getFileUrlByFileIds(List uniqueIds, Integer expiredTime, int maxAccessCount, String type); +} diff --git a/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/FmsRecordService.java b/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/FmsRecordService.java new file mode 100644 index 0000000000000000000000000000000000000000..0df6b921120361a7b198c3a63f045168b9e4ab9c --- /dev/null +++ b/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/FmsRecordService.java @@ -0,0 +1,16 @@ +package com.itools.core.service; + + +import com.itools.core.result.FmsDetailRecordResult; + +/** + * @description: + * @author: XUCHANG + * @create: 2021-04-01 11:26 + */ +public interface FmsRecordService { + + + FmsDetailRecordResult queryFssRecordByUniqueId(String uniqueId); + +} diff --git a/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/impl/FmsAccessTokenServiceImpl.java b/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/impl/FmsAccessTokenServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..be0b5dedfe30145eafaea2499d455b2c627c68eb --- /dev/null +++ b/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/impl/FmsAccessTokenServiceImpl.java @@ -0,0 +1,126 @@ +package com.itools.core.service.impl; + +import com.alibaba.fastjson.JSON; +import com.itools.core.dto.accessToken.FmsAccessTokenDTO; +import com.itools.core.em.FmsCodeBean; +import com.itools.core.exception.AppException; +import com.itools.core.log.Logable; +import com.itools.core.mapper.FmsAccessTokenMapper; +import com.itools.core.result.FmsAccessTokenResult; +import com.itools.core.service.FmsAccessTokenService; +import com.itools.core.utils.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * @description: + * @author: XUCHANG + * @create: 2021-03-28 15:51 + */ +@Service +public class FmsAccessTokenServiceImpl implements FmsAccessTokenService { + + @Autowired + private RedisTemplate redisTemplate; + @Autowired + private FmsAccessTokenMapper fmsAccessTokenMapper; + /** + * 从缓存中或者数据库中获取FsAccessToken信息 + * + * @param fileAccessToken + * @return + */ + @Override + public FmsAccessTokenResult getFileAccessToken(String fileAccessToken) { + Object object = redisTemplate.opsForValue().get(fileAccessToken); + if (object != null){ + FmsAccessTokenResult result = JSON.parseObject((String) object, FmsAccessTokenResult.class); + return result; + }else { + FmsAccessTokenDTO fssFmsAccessTokenDto = fmsAccessTokenMapper.selectByPrimaryKey(fileAccessToken); + if (fssFmsAccessTokenDto == null){ + return null; + } + FmsAccessTokenResult result = new FmsAccessTokenResult(); + BeanUtils.copyProperties(fssFmsAccessTokenDto, result); + return result; + } + } + + /** + * 缓存FsAccessToken信息,如果过期时间小于等于0,则会将accessToken持久化(缓存到数据库) + * @param fileAccessToken + * @param expiredTime + * @param maxAccessCount + * @param uniqueId + * @param type + * @return + */ + @Override + public FmsAccessTokenResult cacheFileAccessToken(String fileAccessToken, int expiredTime, int maxAccessCount, String uniqueId, String type) { + if (StringUtils.isBlank(fileAccessToken)) { + throw new AppException(FmsCodeBean.FmsCode.FAIL.code); + } + FmsAccessTokenResult fmsAccessTokenResult = new FmsAccessTokenResult(expiredTime, maxAccessCount, uniqueId, type); + if (expiredTime > 0){ + redisTemplate.opsForValue().set(fileAccessToken , JSON.toJSONString(fmsAccessTokenResult) , expiredTime , TimeUnit.MINUTES); + }else { + FmsAccessTokenDTO fssFmsAccessTokenDto = new FmsAccessTokenDTO(); + fssFmsAccessTokenDto.setFileAccessToken(fileAccessToken); + fssFmsAccessTokenDto.setType(type); + fssFmsAccessTokenDto.setUniqueId(uniqueId); + fmsAccessTokenMapper.insert(fssFmsAccessTokenDto); + } + return fmsAccessTokenResult; + } + /** + * 缓存FsAccessToken信息,如果过期时间小于等于0,则会将accessToken持久化(缓存到数据库) + * @param fileAccessToken + * @param expiredTime + * @param maxAccessCount + * @param uniqueIds + * @param type + * @return + */ + public List cacheFileAccessToken(String fileAccessToken, int expiredTime, int maxAccessCount, List uniqueIds, String type) { + if (StringUtils.isBlank(fileAccessToken)) { + throw new AppException(FmsCodeBean.FmsCode.FAIL.code); + } + List fssAccessTokens = new ArrayList<>(); + for (String uniqueId : uniqueIds){ + FmsAccessTokenResult fmsAccessTokenResult = new FmsAccessTokenResult(expiredTime, maxAccessCount, uniqueId, type); + if (expiredTime > 0){ + redisTemplate.opsForValue().set(fileAccessToken , JSON.toJSONString(fmsAccessTokenResult) , expiredTime , TimeUnit.MINUTES); + }else { + FmsAccessTokenDTO fssFmsAccessTokenDto = new FmsAccessTokenDTO(); + fssFmsAccessTokenDto.setFileAccessToken(fileAccessToken); + fssFmsAccessTokenDto.setType(type); + fssFmsAccessTokenDto.setUniqueId(uniqueId); + fssAccessTokens.add(fssFmsAccessTokenDto); + } + } + if (!CollectionUtils.isEmpty(fssAccessTokens)){ + fmsAccessTokenMapper.multipartInsert(fssAccessTokens); + } + return fssAccessTokens; + } + + /** + * 删除缓存数据 + * + * @param fileAccessToken + */ + @Override + @CacheEvict(value = "fileAccessToken", key = "#fileAccessToken") + @Logable(businessTag = "FsAccessService") + public void deleteFileAccessToken(String fileAccessToken) { + } +} diff --git a/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/impl/FmsBusinessTypeServiceImpl.java b/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/impl/FmsBusinessTypeServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..b61c808b63027ca0ce928d3a3441fcaaee0375f5 --- /dev/null +++ b/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/impl/FmsBusinessTypeServiceImpl.java @@ -0,0 +1,88 @@ +package com.itools.core.service.impl; + +import com.itools.core.dto.businessType.FmsBusinessTypeDTO; +import com.itools.core.log.Logable; +import com.itools.core.mapper.FmsBusinessTypeMapper; +import com.itools.core.param.FmsUploadTokenParam; +import com.itools.core.result.FmsUploadTokenResult; +import com.itools.core.result.FmsBusinessTypeResult; +import com.itools.core.service.FmsBusinessTypeService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/** + * @description: + * @author: XUCHANG + * @create: 2021-03-28 15:51 + */ +@Service +public class FmsBusinessTypeServiceImpl implements FmsBusinessTypeService { + @Autowired + private FmsBusinessTypeMapper fmsBusinessTypeMapper; + + /** + * 查询FsBusinessType列表 + * + * @param businessType + * @return + */ + @Override + @Cacheable(value = "fsBusinessTypes", key = "#businessType") + @Logable + public List queryFsBusinessTypeList(String businessType) { + if (StringUtils.isBlank(businessType)) { + return null; + } + FmsBusinessTypeDTO tmp = new FmsBusinessTypeDTO(); + tmp.setBusinessType(businessType); + List fssBusinessTypes = fmsBusinessTypeMapper.selectBySelective(tmp); + List fmsBusinessTypeResults = new ArrayList<>(); + for (FmsBusinessTypeDTO fssBusinessType : fssBusinessTypes){ + FmsBusinessTypeResult fmsBusinessTypeResult = new FmsBusinessTypeResult(); + BeanUtils.copyProperties(fssBusinessType , fmsBusinessTypeResult); + fmsBusinessTypeResults.add(fmsBusinessTypeResult); + } + return fmsBusinessTypeResults; + } + + /** + * 根据 uploadToken ,缓存FsBusinessType对象 + * + * @param uploadToken + * @return + */ + @Override + @Cacheable(value = "fsBusinessType", key = "#uploadToken") + @Logable + public FmsUploadTokenResult cacheFsUploadToken(String uploadToken, FmsUploadTokenParam fmsUploadTokenParam) { + FmsUploadTokenResult result = new FmsUploadTokenResult(); + BeanUtils.copyProperties(fmsUploadTokenParam, result); + return result; + } + + /** + * 根据 uploadToken ,获取FsBusinessType对象 + * + * @param uploadToken + * @return + */ + @Override + @Cacheable(value = "fsBusinessType", key = "#uploadToken") + @Logable + public FmsUploadTokenResult getFsBusinessTypeByUploadToken(String uploadToken) { + return null; + } + + @Override + @CacheEvict(value = "fsBusinessType", key = "#uploadToken") + @Logable + public void deleteFsBusinessTypeByUploadToken(String uploadToken) { + } +} diff --git a/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/impl/FmsFileSystemServiceImpl.java b/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/impl/FmsFileSystemServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..cb04324c02c1ce149f4cd0c846663be7dae4c96b --- /dev/null +++ b/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/impl/FmsFileSystemServiceImpl.java @@ -0,0 +1,565 @@ +package com.itools.core.service.impl; + +import com.alibaba.fastjson.JSON; +import com.itools.core.base.CommonResult; +import com.itools.core.dto.accessToken.FmsAccessTokenDTO; +import com.itools.core.dto.fileRecord.FmsRecordDTO; +import com.itools.core.em.FmsCodeBean; +import com.itools.core.em.FmsConstants; +import com.itools.core.exception.AppException; +import com.itools.core.log.Logable; +import com.itools.core.mapper.FmsAccessTokenMapper; +import com.itools.core.mapper.FmsFileRecordMapper; +import com.itools.core.param.FmsAccessTokenParam; +import com.itools.core.param.FmsUploadTokenParam; +import com.itools.core.param.FmsBusinessTypeParam; +import com.itools.core.result.*; +import com.itools.core.service.FmsFileSystemService; +import com.itools.core.service.impl.task.MyUploadFileTask; +import com.itools.core.snowflake.SequenceService; +import com.itools.core.utils.CollectionUtils; +import com.itools.core.utils.UUIDUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.FileCopyUtils; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.concurrent.FutureTask; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * @description: + * @author: XUCHANG + * @create: 2021-03-28 15:51 + */ +@Service +public class FmsFileSystemServiceImpl implements FmsFileSystemService { + + + @Value("${fileStoreRootPath}") + String fileStoreRootPath; + + @Value("${fileAccessUrlForOutter}") + String fileAccessUrlForOutter; + + @Value("${fileUploadLimitSize}") + Integer fileUploadLimitSize; + + @Value("${fileMaxRequestSize}") + Integer fileMaxRequestSize; + + @Value("${fileMaxFileSize}") + Integer fileMaxFileSize; + + @Autowired + FmsFileSystemServiceImpl self; + + @Autowired + SequenceService sequenceService; + + @Autowired + FmsBusinessTypeServiceImpl fmsBusinessTypeService; + + @Autowired + RedisTemplate redisTemplate; + + + @Autowired + private FmsFileRecordMapper fmsFileRecordMapper; + + @Autowired + FmsAccessTokenServiceImpl fmsAccessTokenService; + + @Autowired + private FmsAccessTokenMapper fmsAccessTokenMapper; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + //文件的type + private final static String CURRENCY_TYPE = "currency"; + //线程池:核心线程:5,非核心线程:5,阻塞队列:10 + private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 0, TimeUnit.SECONDS, new LinkedBlockingDeque(10)); + + /** + * 根据uniqeId和文件名得到本地文件存储路径 + * @param uniqueId + * @param fileName + * @return + */ + @Override + public String getFileLocalPath(String uniqueId , String fileName) { + if (StringUtils.isBlank(uniqueId)) { + throw new AppException(FmsCodeBean.FmsCode.INVALID_FS_UNIQUE_ID.code); + } + String path = fileStoreRootPath+File.separator; + int pathLength = 4; + for(int i=0;i fsBusinessTypes = fmsBusinessTypeService.queryFsBusinessTypeList(businessType); + if (fsBusinessTypes == null || fsBusinessTypes.isEmpty()) { + throw new AppException(FmsCodeBean.FmsCode.ERROR_BUSINESS_TYPE_NOT_EXIST.code); + } + FmsUploadTokenParam fsUploadToken = new FmsUploadTokenParam(); + fsUploadToken.setFromSystemId(fromSystemId); + fsUploadToken.setFsBusinessType(fsBusinessTypes.get(0)); + fsUploadToken.setNeedEncrypt(needEncrypt); + fsUploadToken.setRemark(remark); + fmsBusinessTypeService.cacheFsUploadToken(uploadToken, fsUploadToken); + return uploadToken; + } + + + /** + * 存储文件 + * 使用字节流输入文件 + * 返回文件的全局唯一ID + * @param fileBytes + * @param fileName + * @param fsBusinessType + * @param fsUploadToken + * @return + */ + @Override + public String saveFileFromBytes(byte[] fileBytes, String fileName, FmsBusinessTypeParam fsBusinessType, FmsUploadTokenParam fsUploadToken) { + String uniqueId = UUIDUtils.uuid(); + saveFileToLocal(fileBytes, fileName, uniqueId); + + String originalFilename = StringUtils.isBlank(fileName) ? uniqueId : fileName; + String contentType = fsBusinessType.getFsType(); + + return createAndPersistDBRecord(originalFilename, contentType, (long) fileBytes.length, fsUploadToken, uniqueId); + } + + + + protected void saveFileToLocal(byte[] fileBytes, String fileName, String uuid) { + File outputFile = new File(getFileLocalPath(uuid , fileName)); + if (!outputFile.getParentFile().exists()) { + outputFile.getParentFile().mkdirs(); + } + try { + outputFile.createNewFile(); + } catch (IOException e) { + throw new AppException(FmsCodeBean.FmsCode.FAIL.code, e); + } + try (OutputStream out = new FileOutputStream(outputFile)) { + FileCopyUtils.copy(fileBytes, out); + } catch (IOException e) { + throw new AppException(FmsCodeBean.FmsCode.FAIL.code, e); + } + } + + /** + * 获取文件访问路径 + * + * @param uniqueId + * @param expiredTime + * @param maxAccessCount + * @return + */ + @Override + @Logable + public String getFileUrlByFileId(String uniqueId, int expiredTime, int maxAccessCount, String type) { + FmsRecordDTO tmp = new FmsRecordDTO(); + tmp.setUniqueId(uniqueId); + List fsUploadRecords = fmsFileRecordMapper.selectbySelective(tmp); + if (fsUploadRecords == null || fsUploadRecords.isEmpty()) { + logger.error(FmsCodeBean.FmsCode.NOT_EXIST_FILE.message,new AppException(FmsCodeBean.FmsCode.NOT_EXIST_FILE.code, FmsCodeBean.FmsCode.NOT_EXIST_FILE.message)); + return ""; + } + String fileAccessToken = UUIDUtils.uuid(); + //String fileAccessUrlForOutter = "http://192.168.0.135:8150/fs/File/";//本地路径 + String path = fileAccessUrlForOutter + uniqueId + "?fileAccessToken=" + fileAccessToken; + // 缓存文件token + FmsAccessTokenResult fsAccessToken = fmsAccessTokenService.cacheFileAccessToken(fileAccessToken, expiredTime, maxAccessCount, uniqueId, type); + if (fsAccessToken == null) { + throw new AppException(FmsCodeBean.FmsCode.FAIL.code); + } + return path; + } + + /** + * 获得uniqueId对应的文件上传记录 + * 会检查 + * @param fsAccessToken + * @param uniqueId + * @param fileAccessToken + * @return + */ + @Override + @Logable + public FmsDetailRecordResult getFileUploadRecord(FmsAccessTokenParam fsAccessToken, String uniqueId, String fileAccessToken) { + FmsRecordDTO tmp = new FmsRecordDTO(); + tmp.setUniqueId(uniqueId); + List fsUploadRecords = fmsFileRecordMapper.selectbySelective(tmp); + if (fsUploadRecords == null || fsUploadRecords.isEmpty()) { + // 无该文件,返回404 + throw new AppException(FmsCodeBean.FmsCode.NOT_EXIST_FILE.code); + } + int maxAccessCount = fsAccessToken.getMaxAccessCount(); + if (fsAccessToken.getExpiredTime() > 0){ + if (maxAccessCount != -1) { + // 次数减一 + maxAccessCount--; + if (maxAccessCount == 0) { + // 删除缓存 + fmsAccessTokenService.deleteFileAccessToken(fileAccessToken); + } else { + // 更新缓存 + int expiredTime = fsAccessToken.getExpiredTime(); + fmsAccessTokenService.cacheFileAccessToken(fileAccessToken, expiredTime, maxAccessCount, uniqueId, fsAccessToken.getType()); + // 更新缓存时间 + redisTemplate.expire(fileAccessToken, expiredTime, TimeUnit.MINUTES); + } + } + } + + // 返回该文件 + FmsRecordDTO fssRecord = fsUploadRecords.get(0); + FmsDetailRecordResult result = new FmsDetailRecordResult(); + BeanUtils.copyProperties(fssRecord , result); + return result; + } + + @Override + public FmsDetailRecordResult getFileUploadRecord(String uniqueId) { + FmsRecordDTO tmp = new FmsRecordDTO(); + tmp.setUniqueId(uniqueId); + List fsUploadRecords = fmsFileRecordMapper.selectbySelective(tmp); + if (fsUploadRecords == null || fsUploadRecords.isEmpty()) { + // 无该文件,返回404 + throw new AppException(FmsCodeBean.FmsCode.NOT_EXIST_FILE.code); + } + FmsRecordDTO fssRecord = fsUploadRecords.get(0); + FmsDetailRecordResult result = new FmsDetailRecordResult(); + BeanUtils.copyProperties(fssRecord , result); + return result; + } + + /** + * 文件批量上传 + * @param files + * @param param + * @return + */ + @Override + public CommonResult uploadFiles(MultipartFile[] files, FmsUploadTokenParam param) { + + //收集文件数对应的结果 + List results = new ArrayList<>(); + List> taskList = new ArrayList<>(); + for (MultipartFile file : files){ + //执行多线程上传 执行上传的service,文件,参数 +// this.saveFile(file,param); + String uuid = UUIDUtils.uuid(); + FutureTask futureTask = new FutureTask<>(new MyUploadFileTask(self,file,param,uuid)); + taskList.add(futureTask); + //返回信息 + FmsMultipartFileResult multipartFileResult = new FmsMultipartFileResult(); + multipartFileResult.setFileName(file.getOriginalFilename()); + multipartFileResult.setUniqueId(String.valueOf(uuid)); + results.add(multipartFileResult); + try { + threadPoolExecutor.execute(futureTask); + }catch (Exception e){ + logger.error("批量上传文件失败"); + throw new AppException(FmsCodeBean.FmsCode.FILE_MULTIPART_UPLOAD.code); + } + } + //待所有线程任务完成,返回结果。其中一个上传失败,抛出异常 + for(FutureTask task: taskList){ + if (task == null){ + logger.error("批量上传文件失败"); + throw new AppException(FmsCodeBean.FmsCode.FILE_MULTIPART_UPLOAD.code); + } + } + + return CommonResult.success(results); + } + + /** + * 验证文件 + * @param files + * @param fsBusinessType + */ + @Override + public void verifyFiles(MultipartFile[] files, FmsBusinessTypeResult fsBusinessType) { + if (files.length == 0 || files == null){ + throw new AppException(FmsCodeBean.FmsCode.ERROR_FILE_IS_NULL.code); + } + if (files.length > fileUploadLimitSize){ + throw new AppException(FmsCodeBean.FmsCode.FILE_LIMIT_SIZE.code); + } + //所有文件大小,单位字节 + long allFileSize = 0; + for (MultipartFile file : files){ + if (file == null || StringUtils.isBlank(file.getOriginalFilename())) { + // 文件不能为空 + throw new AppException(FmsCodeBean.FmsCode.ERROR_FILE_IS_NULL.code); + } + //通用类型的文件大小,单位kb + String fsSize = fsBusinessType.getFsSize(); + //通用类型的文件大小,单位kb + Long limitSize = Long.parseLong(fsSize); + //文件的大小,单位字节 + long fileSize = file.getSize(); + //总文件累计,单位字节 + allFileSize += fileSize; + //类型允许的文件大小,KB转字节 + long allowFileSize = limitSize * 1024; + //判断文件大小与限制的大小是否符合 + if (fileSize > allowFileSize || fileSize > (fileMaxFileSize * 1024)) { + logger.error("文件名称{}的大小{}字节的文件超过限制【类型限制大小{}KB,单个文件限制大小{}KB】",file.getOriginalFilename(),fileSize,fileSize,fileMaxFileSize); + throw new AppException(FmsCodeBean.FmsCode.ERROR_FILESIZE_OUT_OFF_LIMIT.code); + } + String fsType = fsBusinessType.getFsType(); + if (!StringUtils.equals(fsType, CURRENCY_TYPE)){ + //如果取值不为currency,则判断类型 + String originFileName = file.getOriginalFilename(); + String suffix = originFileName.substring(originFileName.lastIndexOf(".") + 1); + String contentType = file.getContentType(); + if (contentType == null || !fsType.contains(suffix.trim().toLowerCase()) || !fsType.contains(contentType)) { + logger.error(FmsCodeBean.FmsCode.ERROR_FILETYPE.code, "文件类型:" + suffix + " || " + contentType); + // 文件后缀错误 + throw new AppException(FmsCodeBean.FmsCode.ERROR_FILETYPE.code); + } + } + } + //请求的文件大小限制,KB转字节 + if (allFileSize > (fileMaxRequestSize * 1024)){ + logger.error("文件的总大小为{}字节,已经超过请求限制的{}字节大小",allFileSize,fileMaxRequestSize * 1024); + throw new AppException(FmsCodeBean.FmsCode.ERROR_FILESIZE_OUT_OFF_LIMIT.code); + } + } + + /** + * 文件批量上传的业务逻辑 + * @param files + * @param uploadToken + * @return + */ + @Override + @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class) + public CommonResult filesMultipartUpload(MultipartFile[] files, String uploadToken) { + //验证token是否合理 + FmsUploadTokenResult fsUploadToken = fmsBusinessTypeService.getFsBusinessTypeByUploadToken(uploadToken); + if (fsUploadToken == null) { + throw new AppException(FmsCodeBean.FmsCode.ERROR_TIMEOUT.code); + } + //获取文件允许是类型 + FmsBusinessTypeResult fsBusinessType = fsUploadToken.getFsBusinessType(); + //验证文件 + self.verifyFiles(files,fsBusinessType); + FmsUploadTokenParam param = new FmsUploadTokenParam(); + BeanUtils.copyProperties(fsUploadToken , param); + //批量上传 + CommonResult fileResult = self.uploadFiles(files,param); +// String uniqueId = fsService.saveFile(file, param); + //删除token + fmsBusinessTypeService.deleteFsBusinessTypeByUploadToken(uploadToken); + return CommonResult.success(fileResult.getData()); + } + + /** + * 获取文件访问路径,如果超时时间设置为小于等于0,那么返回的有效路径可以永久访问 + * @param uniqueIds + * @param expiredTime + * @param maxAccessCount + * @param type + * @return + */ + @Override + @Transactional(propagation = Propagation.SUPPORTS,readOnly = true,rollbackFor = Exception.class) + public CommonResult getFileUrlByFileIds(List uniqueIds, Integer expiredTime, int maxAccessCount, String type) { + + if (CollectionUtils.isEmpty(uniqueIds)){ + logger.error(FmsCodeBean.FmsCode.NOT_EXIST_FILE.message,new AppException(FmsCodeBean.FmsCode.NOT_EXIST_FILE.code, FmsCodeBean.FmsCode.NOT_EXIST_FILE.message)); + return CommonResult.success(new ArrayList<>()); + } + //根据uniqueIds查询任务记录 + FmsRecordDTO tmp = new FmsRecordDTO(); + tmp.setUniqueIds(uniqueIds); + List fsUploadRecords = fmsFileRecordMapper.selectbySelective(tmp); + if (CollectionUtils.isEmpty(fsUploadRecords)) { + logger.error(FmsCodeBean.FmsCode.NOT_EXIST_FILE.message,new AppException(FmsCodeBean.FmsCode.NOT_EXIST_FILE.code, FmsCodeBean.FmsCode.NOT_EXIST_FILE.message)); + return CommonResult.success(new ArrayList<>()); + } + //返回 uniqueId--文件path + List recordPathResults = new ArrayList<>(); + //文件访问令牌的批量添加 + List fssAccessTokens = new ArrayList<>(); + for (FmsRecordDTO fssRecord : fsUploadRecords){ + String uniqueId = fssRecord.getUniqueId(); + String fileAccessToken = UUIDUtils.uuid(); + //String fileAccessUrlForOutter = "http://192.168.0.135:8150/fs/File/";//本地路径 + String path = fileAccessUrlForOutter + uniqueId + "?fileAccessToken=" + fileAccessToken; + // 缓存文件token(方式一) +// FsAccessTokenResult fsAccessToken = fsAccessService.cacheFileAccessToken(fileAccessToken, expiredTime, maxAccessCount, uniqueId, type); +// if (fsAccessToken == null) { +// throw new AppException(FSSCodeBean.FSSCode.FAIL.code); +// } + // 缓存文件token(方式二) + FmsAccessTokenResult fmsAccessTokenResult = new FmsAccessTokenResult(expiredTime, maxAccessCount, uniqueId, type); + if (expiredTime > 0){ + redisTemplate.opsForValue().set(fileAccessToken , JSON.toJSONString(fmsAccessTokenResult) , expiredTime , TimeUnit.MINUTES); + }else { + FmsAccessTokenDTO fssFmsAccessTokenDto = new FmsAccessTokenDTO(); + fssFmsAccessTokenDto.setFileAccessToken(fileAccessToken); + fssFmsAccessTokenDto.setType(type); + fssFmsAccessTokenDto.setUniqueId(uniqueId); + fssAccessTokens.add(fssFmsAccessTokenDto); + } + FmsFileRecordPathResult fmsFileRecordPathResult = new FmsFileRecordPathResult(); + fmsFileRecordPathResult.setPath(path); + fmsFileRecordPathResult.setUniqueId(uniqueId); + recordPathResults.add(fmsFileRecordPathResult); + } + if (!CollectionUtils.isEmpty(fssAccessTokens)){ + fmsAccessTokenMapper.multipartInsert(fssAccessTokens); + } + return CommonResult.success(recordPathResults); + } + + +} diff --git a/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/impl/FmsRecordServiceImpl.java b/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/impl/FmsRecordServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..a2d8f7c30978adb1375c332637ef3504a03c4920 --- /dev/null +++ b/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/impl/FmsRecordServiceImpl.java @@ -0,0 +1,37 @@ +package com.itools.core.service.impl; + +import com.itools.core.dto.fileRecord.FmsRecordDTO; +import com.itools.core.mapper.FmsFileRecordMapper; +import com.itools.core.result.FmsDetailRecordResult; +import com.itools.core.service.FmsRecordService; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +/** + * @description: + * @author: XUCHANG + * @create: 2021-03-28 15:51 + */ +@Service +public class FmsRecordServiceImpl implements FmsRecordService { + + @Autowired + private FmsFileRecordMapper fmsFileRecordMapper; + + @Override + public FmsDetailRecordResult queryFssRecordByUniqueId(String uniqueId) { + FmsRecordDTO queryParams = new FmsRecordDTO(); + queryParams.setUniqueId(uniqueId); + List list = fmsFileRecordMapper.selectbySelective(queryParams); + if (list.size() > 0) { + FmsRecordDTO record = list.get(0); + FmsDetailRecordResult result = new FmsDetailRecordResult(); + BeanUtils.copyProperties(record , result); + return result; + } + return null; + } + +} diff --git a/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/impl/task/MyUploadFileTask.java b/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/impl/task/MyUploadFileTask.java new file mode 100644 index 0000000000000000000000000000000000000000..89f4d2ab7b23f89194d2c0ab1da6ef13315484b2 --- /dev/null +++ b/itools-fms/itools-fms-server/src/main/java/com/itools/core/service/impl/task/MyUploadFileTask.java @@ -0,0 +1,37 @@ +package com.itools.core.service.impl.task; + +import com.itools.core.param.FmsUploadTokenParam; +import com.itools.core.service.impl.FmsFileSystemServiceImpl; +import org.springframework.web.multipart.MultipartFile; + +import java.util.concurrent.Callable; + +/** + * @description: + * @author: XUCHANG + * @create: 2021-03-28 15:51 + */ +public class MyUploadFileTask implements Callable { + private FmsFileSystemServiceImpl self; + private MultipartFile file; + private FmsUploadTokenParam param; + private String uuid; + + public MyUploadFileTask(FmsFileSystemServiceImpl self, MultipartFile file, FmsUploadTokenParam param, String uuid) { + this.self = self; + this.file = file; + this.param = param; + this.uuid = uuid; + } + + @Override + public String call() { + try { + String file = self.saveFile(this.file, param, uuid); + return file; + }catch (Exception e){ + return null; + } + } + +} diff --git a/itools-fms/itools-fms-server/src/main/resources/application-dev.yml b/itools-fms/itools-fms-server/src/main/resources/application-dev.yml new file mode 100644 index 0000000000000000000000000000000000000000..63caa3501a8047dad4f1039a86af32a9e8912c87 --- /dev/null +++ b/itools-fms/itools-fms-server/src/main/resources/application-dev.yml @@ -0,0 +1,88 @@ +#组件中的全局异常处理的code +system: + errorCode: Code001 +#分布式雪花算法策略 +sequence: + enable: true + type: snowflake + generate: simple + +#fms文件系统配置项 +spring: + servlet: + multipart: + # 最大支持文件大小 + max-file-size: 20MB + # 最大支持请求大小 + max-request-size: 200MB + # 上传文件的临时目录 +# location: /home/hash/AppSvr01/installedApps/fsnsh_backend-master/temp + + +fileStoreRootPath: /data/fmsFile #文件存储路径,此路径应该是多个FSS服务的共享磁盘 +fileAccessUrlForOutter: http://127.0.0.1:8002/File/ +fileUploadLimitSize: 10 #批量上传限制的个数 +fileMaxRequestSize: 204800 #最大的请求数,单位KB,200MB +fileMaxFileSize: 20480 #单个文件最大大小,单位KB,20MB + +fms: + #系统文件管理策略【nio原生的文件系统,miniio文件系统,fastdfs文件系统】 + strategy: nio + #文件配置 + file: + store-root-path: /data/fmsFile #文件存储路径,此路径应该是多个fms服务的共享磁盘 + access-url-for-outter: http://127.0.0.1:8002/File/ #文件访问 + upload-limit-size: 10 #批量上传限制的个数 + max-request-size: 204800 #最大的请求数,单位KB,200MB + max-file-size: 20480 #单个文件最大大小,单位KB,20MB + #minio文件配置 + minio: + endpoint: 172.28.43.29 + port: 9000 + accessKey: minio + secretKey: miniopassword + secure: false + bucketName: "hope-bucket" + configDir: "/home/data/" + + +#脚本自动初始化执行 +initDB: + #启用开关 + is-use: false + # ddl脚本,可以支持多个,用,分割,文件建议最多5个 + ddl: init/ddl.sql + # dml脚本,可以支持多个,用,分割,文件建议最多5个 + dml: init/dml.sql + # function脚本,可以支持多个,用,分割,文件建议最多5个 + function: init/function.sql + # 分支环境 + env: dev + # 版本 + version: 1.0 + # 脚本设置的分隔符 + delimiter: ; + +# mybatis-plus相关配置 +mybatis-plus: + mapper-locations: classpath:/mapper/**/*Mapper.xml + typeAliasesPackage: com.itools.core + global-config: + db-column-underline: true + db-config: + logic-delete-field: del_flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2) + logic-delete-value: 1 # 逻辑已删除值(默认为 1) + logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) + configuration: + default-enum-type-handler: com.baomidou.mybatisplus.extension.handlers.MybatisEnumTypeHandler + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl +#security: +# oauth2: +# client: +# client-id: product-server +# client-secret: 123456 +# user-authorization-uri: http://127.0.0.1:8888/oauth/authorize +# access-token-uri: http://127.0.0.1:8888/oauth/token +# resource: +# jwt: +# key-uri: http://127.0.0.1:8888/oauth/token_key \ No newline at end of file diff --git a/itools-fms/itools-fms-server/src/main/resources/application.yml b/itools-fms/itools-fms-server/src/main/resources/application.yml new file mode 100644 index 0000000000000000000000000000000000000000..868ebd792bb346d220ce09abcc31e519373a0a76 --- /dev/null +++ b/itools-fms/itools-fms-server/src/main/resources/application.yml @@ -0,0 +1,28 @@ +server: + port: 8002 +spring: + application: + name: itools-fms-server + profiles: + active: dev + + redis: + host: 127.0.0.1 + database: 0 + + datasource: + type: com.zaxxer.hikari.HikariDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost:3306/itools?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC + username: root + password: root + hikari: + minimum-idle: 5 + idle-timeout: 600000 + maximum-pool-size: 10 + auto-commit: true + pool-name: MyHikariCP + max-lifetime: 1800000 + connection-timeout: 30000 + connection-test-query: SELECT 1 + diff --git a/itools-fms/itools-fms-server/src/main/resources/bootstrap.yml b/itools-fms/itools-fms-server/src/main/resources/bootstrap.yml new file mode 100644 index 0000000000000000000000000000000000000000..94abc03c5d8f9970c038099a293134e50b57e0a8 --- /dev/null +++ b/itools-fms/itools-fms-server/src/main/resources/bootstrap.yml @@ -0,0 +1,17 @@ +# Nacos Server 的地址 +spring: +# profiles: +# active: dev + cloud: + nacos: + config: + server-addr: 106.54.85.156:8848 + file-extension: yaml + prefix: itools-fms-server + remote-first: true + namespace: e32f7110-9472-427b-8b1a-a71cdebdfdb8 + group: dev + discovery: + server-addr: 106.54.85.156:8848 + namespace: e32f7110-9472-427b-8b1a-a71cdebdfdb8 + group: dev diff --git a/itools-fms/itools-fms-server/src/main/resources/mapper/FmsAccessTokenMapper.xml b/itools-fms/itools-fms-server/src/main/resources/mapper/FmsAccessTokenMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..766b770495e7cdebb05f4cac0b79f7fc77ebc840 --- /dev/null +++ b/itools-fms/itools-fms-server/src/main/resources/mapper/FmsAccessTokenMapper.xml @@ -0,0 +1,27 @@ + + + + + + + + + + file_access_token, unique_id, type + + + + + + + insert into itools_fms_access_token (file_access_token, unique_id, type) + values (#{item.fileAccessToken,jdbcType=VARCHAR}, #{item.uniqueId,jdbcType=VARCHAR}, #{item.type,jdbcType=VARCHAR}) + + + + \ No newline at end of file diff --git a/itools-fms/itools-fms-server/src/main/resources/mapper/FmsBusinessTypeMapper.xml b/itools-fms/itools-fms-server/src/main/resources/mapper/FmsBusinessTypeMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..66f2f052f4d2657945587965bf0832f123490773 --- /dev/null +++ b/itools-fms/itools-fms-server/src/main/resources/mapper/FmsBusinessTypeMapper.xml @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + ID, BUSINESS_TYPE, REMARK, FS_SIZE, FS_TYPE, CREATE_DATE, UPDATE_DATE + + + + + delete from itools_fms_business_type + where ID = #{id,jdbcType=BIGINT} + + + + insert into itools_fms_business_type + + + ID, + + + BUSINESS_TYPE, + + + REMARK, + + + FS_SIZE, + + + FS_TYPE, + + + CREATE_DATE, + + + UPDATE_DATE, + + + + + #{id,jdbcType=BIGINT}, + + + #{businessType,jdbcType=VARCHAR}, + + + #{remark,jdbcType=VARCHAR}, + + + #{fsSize,jdbcType=VARCHAR}, + + + #{fsType,jdbcType=VARCHAR}, + + + #{createDate,jdbcType=TIMESTAMP}, + + + #{updateDate,jdbcType=TIMESTAMP}, + + + + + update itools_fms_business_type + + + BUSINESS_TYPE = #{businessType,jdbcType=VARCHAR}, + + + REMARK = #{remark,jdbcType=VARCHAR}, + + + FS_SIZE = #{fsSize,jdbcType=VARCHAR}, + + + FS_TYPE = #{fsType,jdbcType=VARCHAR}, + + + CREATE_DATE = #{createDate,jdbcType=TIMESTAMP}, + + + UPDATE_DATE = #{updateDate,jdbcType=TIMESTAMP}, + + + where ID = #{id,jdbcType=BIGINT} + + + update itools_fms_business_type + set BUSINESS_TYPE = #{businessType,jdbcType=VARCHAR}, + REMARK = #{remark,jdbcType=VARCHAR}, + FS_SIZE = #{fsSize,jdbcType=VARCHAR}, + FS_TYPE = #{fsType,jdbcType=VARCHAR}, + CREATE_DATE = #{createDate,jdbcType=TIMESTAMP}, + UPDATE_DATE = #{updateDate,jdbcType=TIMESTAMP} + where ID = #{id,jdbcType=BIGINT} + + \ No newline at end of file diff --git a/itools-fms/itools-fms-server/src/main/resources/mapper/FmsFileRecordMapper.xml b/itools-fms/itools-fms-server/src/main/resources/mapper/FmsFileRecordMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..33c2199480354421958816e3b782759c25544cd2 --- /dev/null +++ b/itools-fms/itools-fms-server/src/main/resources/mapper/FmsFileRecordMapper.xml @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + ID, CONTENT_TYPE, FROM_SYSTEM_ID, FILE_SIZE, UNIQUE_ID, REMARK, ORIG_FILE_NAME, CREATE_TIME, + UPDATE_TIME, DELETE_TIME, DELETED + + + + + delete from itools_fms_record + where ID = #{id,jdbcType=DECIMAL} + + + + insert into itools_fms_record + + + ID, + + + CONTENT_TYPE, + + + FROM_SYSTEM_ID, + + + FILE_SIZE, + + + UNIQUE_ID, + + + REMARK, + + + ORIG_FILE_NAME, + + + CREATE_TIME, + + + UPDATE_TIME, + + + DELETE_TIME, + + + DELETED, + + + + + #{id,jdbcType=DECIMAL}, + + + #{contentType,jdbcType=VARCHAR}, + + + #{fromSystemId,jdbcType=VARCHAR}, + + + #{fileSize,jdbcType=DECIMAL}, + + + #{uniqueId,jdbcType=VARCHAR}, + + + #{remark,jdbcType=VARCHAR}, + + + #{origFileName,jdbcType=VARCHAR}, + + + #{createTime,jdbcType=TIMESTAMP}, + + + #{updateTime,jdbcType=TIMESTAMP}, + + + #{deleteTime,jdbcType=TIMESTAMP}, + + + #{deleted,jdbcType=CHAR}, + + + + + update itools_fms_record + + + CONTENT_TYPE = #{contentType,jdbcType=VARCHAR}, + + + FROM_SYSTEM_ID = #{fromSystemId,jdbcType=VARCHAR}, + + + FILE_SIZE = #{fileSize,jdbcType=DECIMAL}, + + + UNIQUE_ID = #{uniqueId,jdbcType=VARCHAR}, + + + REMARK = #{remark,jdbcType=VARCHAR}, + + + ORIG_FILE_NAME = #{origFileName,jdbcType=VARCHAR}, + + + CREATE_TIME = #{createTime,jdbcType=TIMESTAMP}, + + + UPDATE_TIME = #{updateTime,jdbcType=TIMESTAMP}, + + + DELETE_TIME = #{deleteTime,jdbcType=TIMESTAMP}, + + + DELETED = #{deleted,jdbcType=CHAR}, + + + where ID = #{id,jdbcType=DECIMAL} + + + update itools_fms_record + set CONTENT_TYPE = #{contentType,jdbcType=VARCHAR}, + FROM_SYSTEM_ID = #{fromSystemId,jdbcType=VARCHAR}, + FILE_SIZE = #{fileSize,jdbcType=DECIMAL}, + UNIQUE_ID = #{uniqueId,jdbcType=VARCHAR}, + REMARK = #{remark,jdbcType=VARCHAR}, + ORIG_FILE_NAME = #{origFileName,jdbcType=VARCHAR}, + CREATE_TIME = #{createTime,jdbcType=TIMESTAMP}, + UPDATE_TIME = #{updateTime,jdbcType=TIMESTAMP}, + DELETE_TIME = #{deleteTime,jdbcType=TIMESTAMP}, + DELETED = #{deleted,jdbcType=CHAR} + where ID = #{id,jdbcType=DECIMAL} + + \ No newline at end of file diff --git a/itools-fms/pom.xml b/itools-fms/pom.xml index 870bb4fb2283c8f7e01e8dee0e4ba065a4992103..71ee5d66e5f7cd433e559f2fa8d2bfc8e0b60446 100644 --- a/itools-fms/pom.xml +++ b/itools-fms/pom.xml @@ -11,5 +11,97 @@ pom itools-fms + + itools-fms-model + itools-fms-core + itools-fms-server + + + 3.3.2 + 1.1.21 + 2.1.7.RELEASE + 1.2.30 + 1.27.0.0 + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring.boot.version} + pom + import + + + + org.springframework.cloud + spring-cloud-dependencies + Greenwich.SR3 + pom + import + + + + + com.alibaba.cloud + spring-cloud-alibaba-dependencies + 2.1.1.RELEASE + pom + import + + + com.baomidou + mybatis-plus-boot-starter + ${mybatis-plus.version} + + + com.baomidou + mybatis-plus-generator + ${mybatis-plus.version} + + + + com.alibaba + fastjson + ${fastjson.version} + + + net.oschina.zcx7878 + fastdfs-client-java + ${fastdfs-client-java.version} + + + + + + com.itools.core + itools-core + 1.0-SNAPSHOT + + + + org.springframework.boot + spring-boot-starter-web + + + org.projectlombok + lombok + + + + + mysql + mysql-connector-java + + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.apache.commons + commons-pool2 + + \ No newline at end of file diff --git a/itools-fms/script/itools-fms b/itools-fms/script/itools-fms new file mode 100644 index 0000000000000000000000000000000000000000..1d276a9b46a4b0826b6947922425cd52c3d8683d --- /dev/null +++ b/itools-fms/script/itools-fms @@ -0,0 +1,40 @@ +CREATE TABLE `itools_fms_record` ( + `id` bigint(32) NOT NULL COMMENT '主键', + `content_type` varchar(100) DEFAULT NULL COMMENT 'HTTP协议定义的文件类型,文件上传从文件流中获取文件存取时使用该字段填入response的content-type字段', + `from_system_id` varchar(50) DEFAULT NULL COMMENT '件所属系统,文件上传时指定', + `file_size` bigint(20) DEFAULT NULL COMMENT '文件大小,单位为字节', + `unique_id` varchar(50) DEFAULT NULL COMMENT '文件的全局唯一ID,后续访问均使用该ID', + `remark` varchar(200) DEFAULT NULL COMMENT '文件描述信息', + `orig_file_name` varchar(200) DEFAULT NULL COMMENT '原文件名,来自入参', + `create_time` timestamp(6) NULL DEFAULT NULL COMMENT '创建时间', + `update_time` timestamp(6) NULL DEFAULT NULL COMMENT '更新时间', + `delete_time` timestamp(6) NULL DEFAULT NULL COMMENT '删除时间', + `deleted` char(1) DEFAULT NULL COMMENT '是否已删除文件本身,也即是说,删除文件时数据库记录仅仅将该字段置位1,并不实际删除数据库记录0:没有删除1:已删除', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE KEY `UK_FS_ID` (`unique_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + + +CREATE TABLE `itools_fms_access_token` ( + `file_access_token` varchar(32) COLLATE utf8mb4_bin NOT NULL COMMENT '文件访问token', + `unique_id` char(32) COLLATE utf8mb4_bin NOT NULL COMMENT '文件的唯一id', + `type` varchar(10) COLLATE utf8mb4_bin NOT NULL COMMENT 'show或者download', + PRIMARY KEY (`file_access_token`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='该表存储的是永久的accessToken,用于支持文件的永久访问或者下载'; + +CREATE TABLE `itools_fms_business_type` ( + `id` bigint(20) NOT NULL COMMENT '主键', + `business_type` varchar(20) DEFAULT NULL COMMENT '01-营业执照 02-身份证正面 03-身份证背面 04-授权文件 05-政策图片 06-金融机构图片 07-金融产品图片', + `remark` varchar(100) DEFAULT NULL COMMENT '说明', + `fs_size` varchar(20) DEFAULT NULL COMMENT '文件大小, 单位kb', + `fs_type` varchar(100) DEFAULT NULL COMMENT '文件类型,逗号分隔符,例如: jpg,png', + `create_date` timestamp(6) NULL DEFAULT NULL COMMENT '创建时间', + `update_date` timestamp(6) NULL DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE KEY `UK_FS_BT` (`business_type`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + +INSERT INTO `itools_fms_business_type`(`id`, `business_type`, `remark`, `fs_size`, `fs_type`, `create_date`, `update_date`) VALUES (1, '01', '文件上传', '102400', 'multipart/form-data,application/octet-stream,text/plain', '2019-08-20 18:48:57.000000', '2019-08-20 18:48:59.000000'); +INSERT INTO `itools_fms_business_type`(`id`, `business_type`, `remark`, `fs_size`, `fs_type`, `create_date`, `update_date`) VALUES (2, '02', 'jar包上传', '102400', 'application/octet-stream,text/plain,multipart/form-data', '2019-08-28 15:24:34.000000', '2019-08-28 15:24:37.000000'); +INSERT INTO `itools_fms_business_type`(`id`, `business_type`, `remark`, `fs_size`, `fs_type`, `create_date`, `update_date`) VALUES (3, 'currency', '通用类型', '102400', 'currency', '2019-10-14 20:21:37.000000', '2019-10-14 20:21:40.000000'); +INSERT INTO `itools_fms_business_type`(`id`, `business_type`, `remark`, `fs_size`, `fs_type`, `create_date`, `update_date`) VALUES (4, '03', 'doc', '102400', 'multipart/form-data; boundary=----WebKitFormBoundaryV9UszO8Om8qv8nNM', '2020-07-30 16:05:31.000000', '2020-07-30 16:05:35.000000'); \ No newline at end of file diff --git a/itools-oms/itools-oms-jwt-sample-example/pom.xml b/itools-oms/itools-oms-jwt-sample-example/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..548c710bd7fedd3bc74134c427ccc587eb874f72 --- /dev/null +++ b/itools-oms/itools-oms-jwt-sample-example/pom.xml @@ -0,0 +1,44 @@ + + + + itools-oms + com.itools.core + 1.0-SNAPSHOT + + 4.0.0 + + itools-oms-jwt-sample-example + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.cloud + spring-cloud-starter-oauth2 + + + + io.jsonwebtoken + jjwt + 0.9.1 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + \ No newline at end of file diff --git a/itools-oms/itools-oms-jwt-sample-example/src/main/java/com/itools/core/OmsSampleApplication.java b/itools-oms/itools-oms-jwt-sample-example/src/main/java/com/itools/core/OmsSampleApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..f50ed748e30a6167435d9f3898476522d6e46ca0 --- /dev/null +++ b/itools-oms/itools-oms-jwt-sample-example/src/main/java/com/itools/core/OmsSampleApplication.java @@ -0,0 +1,17 @@ +package com.itools.core; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @project: itools-backend + * @description: + * @author: XUCHANG + * @create: 2021-03-30 16:29 + */ +@SpringBootApplication +public class OmsSampleApplication { + public static void main(String[] args) { + SpringApplication.run(OmsSampleApplication.class); + } +} diff --git a/itools-oms/itools-oms-jwt-sample-example/src/main/java/com/itools/core/config/ClientWebsecurityConfigurer.java b/itools-oms/itools-oms-jwt-sample-example/src/main/java/com/itools/core/config/ClientWebsecurityConfigurer.java new file mode 100644 index 0000000000000000000000000000000000000000..8d12cec6c3af651d5b10c6df2a70609b6262b6cc --- /dev/null +++ b/itools-oms/itools-oms-jwt-sample-example/src/main/java/com/itools/core/config/ClientWebsecurityConfigurer.java @@ -0,0 +1,31 @@ +package com.itools.core.config; + +import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +@EnableWebSecurity(debug = true) +@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true,jsr250Enabled = true) +@EnableOAuth2Sso +public class ClientWebsecurityConfigurer extends WebSecurityConfigurerAdapter { + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Override + public void configure(HttpSecurity http) throws Exception { + http + .antMatcher("/**") + .authorizeRequests() + .antMatchers("/oauth/**","/login/**","/logout/**").permitAll() + .anyRequest().authenticated(); + } +} diff --git a/itools-oms/itools-oms-jwt-sample-example/src/main/java/com/itools/core/config/JwtTokenEnhancer.java b/itools-oms/itools-oms-jwt-sample-example/src/main/java/com/itools/core/config/JwtTokenEnhancer.java new file mode 100644 index 0000000000000000000000000000000000000000..8472d8a308e171dbf3a05aecc93c39486e972d7f --- /dev/null +++ b/itools-oms/itools-oms-jwt-sample-example/src/main/java/com/itools/core/config/JwtTokenEnhancer.java @@ -0,0 +1,23 @@ +package com.itools.core.config; + +import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.security.oauth2.provider.token.TokenEnhancer; + +import java.util.HashMap; +import java.util.Map; + +public class JwtTokenEnhancer implements TokenEnhancer { + + @Override + public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, + OAuth2Authentication authentication) { + Map info = new HashMap<>(); + info.put("enhance", "enhance info"); + info.put("appId", "appId"); + ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info); + return accessToken; + } + +} \ No newline at end of file diff --git a/itools-oms/itools-oms-jwt-sample-example/src/main/java/com/itools/core/config/JwtTokenStoreConfig.java b/itools-oms/itools-oms-jwt-sample-example/src/main/java/com/itools/core/config/JwtTokenStoreConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..90075763f41bc7423c3a90ba6a87f8c02a576541 --- /dev/null +++ b/itools-oms/itools-oms-jwt-sample-example/src/main/java/com/itools/core/config/JwtTokenStoreConfig.java @@ -0,0 +1,29 @@ +package com.itools.core.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.oauth2.provider.token.TokenStore; +import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; +import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; + +@Configuration +public class JwtTokenStoreConfig { + + @Bean + public TokenStore jwtTokenStore(){ + return new JwtTokenStore(jwtAccessTokenConverter()); + } + + @Bean + public JwtAccessTokenConverter jwtAccessTokenConverter(){ + JwtAccessTokenConverter accessTokenConverter = new + JwtAccessTokenConverter(); + //配置JWT使用的秘钥 + accessTokenConverter.setSigningKey("123123"); + return accessTokenConverter; + } + @Bean + public JwtTokenEnhancer jwtTokenEnhancer() { + return new JwtTokenEnhancer(); + } +} \ No newline at end of file diff --git a/itools-oms/itools-oms-jwt-sample-example/src/main/java/com/itools/core/config/Solution.java b/itools-oms/itools-oms-jwt-sample-example/src/main/java/com/itools/core/config/Solution.java new file mode 100644 index 0000000000000000000000000000000000000000..d29fdbed5d2a564d8be57d2bd34567278c741c27 --- /dev/null +++ b/itools-oms/itools-oms-jwt-sample-example/src/main/java/com/itools/core/config/Solution.java @@ -0,0 +1,54 @@ +package com.itools.core.config; + +import java.util.ArrayList; +import java.util.List; + +class Solution { + public static int clumsy(int N) { + List sit = new ArrayList<>(); + sit.add("*"); + sit.add("/"); + sit.add("+"); + sit.add("-"); + int sum = N; + if(N<=0){ + return sum; + } + int index = 0; + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(N); + while((N-1) >0 ){ + if(index >= sit.size()){ + index = 0; + } + + stringBuilder.append(sit.get(index)); + stringBuilder.append(N-1); + sum = run(sit.get(index),sum,N-1); + index++; + N--; + } + System.out.println(stringBuilder.toString()); + return sum; + + } + private static int run(String sit,int left,int right){ + int res = 0; + System.out.println(left+sit+right); + if(sit.equals("*")){ + res = left * right; + }else if(sit.equals("/")){ + res = left / right; + }else if(sit.equals("+")){ + res = left + right; + }else{ + res = left - right; + } + + return res; + } + + public static void main(String[] args) { + System.out.println(clumsy(10)); + } +} \ No newline at end of file diff --git a/itools-oms/itools-oms-jwt-sample-example/src/main/java/com/itools/core/controller/ProductController.java b/itools-oms/itools-oms-jwt-sample-example/src/main/java/com/itools/core/controller/ProductController.java new file mode 100644 index 0000000000000000000000000000000000000000..6884fb0dbb3d3c0e393c229be68fbd1e3876c745 --- /dev/null +++ b/itools-oms/itools-oms-jwt-sample-example/src/main/java/com/itools/core/controller/ProductController.java @@ -0,0 +1,15 @@ +package com.itools.core.controller; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/product") +public class ProductController { + + @RequestMapping("/selectProductInfoById") + public String selectProductInfoById(long id) { + + return "获取产品信息成功"+id; + } +} \ No newline at end of file diff --git a/itools-oms/itools-oms-jwt-sample-example/src/main/resources/application.yml b/itools-oms/itools-oms-jwt-sample-example/src/main/resources/application.yml new file mode 100644 index 0000000000000000000000000000000000000000..7bad5bedb4de920b6e98a850d4487fde72e784ea --- /dev/null +++ b/itools-oms/itools-oms-jwt-sample-example/src/main/resources/application.yml @@ -0,0 +1,17 @@ +server: + port: 8085 +spring: + application: + name: example-server + main: + allow-bean-definition-overriding: true +security: + oauth2: + client: + client-id: example-server + client-secret: 123456 + user-authorization-uri: http://127.0.0.1:8888/oauth/authorize + access-token-uri: http://127.0.0.1:8888/oauth/token + resource: + jwt: + key-uri: http://127.0.0.1:8888/oauth/token_key diff --git a/itools-oms/itools-oms-server/src/main/java/com/itools/core/config/AuthorizationServerConfig.java b/itools-oms/itools-oms-server/src/main/java/com/itools/core/config/AuthorizationServerConfig.java index 2c44ec83069929fd3220e35fd129f8a395b384b0..5004e9b94225a02665c86f2dfb7e18821238feb7 100644 --- a/itools-oms/itools-oms-server/src/main/java/com/itools/core/config/AuthorizationServerConfig.java +++ b/itools-oms/itools-oms-server/src/main/java/com/itools/core/config/AuthorizationServerConfig.java @@ -2,12 +2,14 @@ package com.itools.core.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; @@ -27,7 +29,10 @@ import java.util.List; /** * @project: itools-backend - * @description: + * @description: 继承AuthorizationServerConfigurerAdapter来配置OAuth2.0 授权服务器。 + * ClientDetailsServiceConfigurer :用来配置客户端详情服务(ClientDetailsService),客户端详情信息在这里进行初始化,你能够把客户端详情信息写死在这里或者是通过数据库来存储调取详情信息。 + * AuthorizationServerEndpointsConfigurer :用来配置令牌(token)的访问端点和令牌服务(token services)。 + * AuthorizationServerSecurityConfigurer :用来配置令牌端点的安全约束. * @author: XUCHANG * @create: 2021-03-28 15:51 */ @@ -61,10 +66,14 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap public JwtTokenEnhancer jwtTokenEnhancer() { return new JwtTokenEnhancer(); } + + /** + * 配置client_details + * @param clients + * @throws Exception + */ @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { - //password模式 - // http://localhost:8888/oauth/token?username=fox&password=123456&grant_type=password&client_id=gateway-server&client_secret=123123&scope=read clients.withClientDetails(clientDetails()); } @@ -111,15 +120,29 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap //refresh_token是否重复使用 .reuseRefreshTokens(false) //刷新令牌授权包含对用户信息的检查 - .userDetailsService(userDetailsService) - //支持GET,POST请求 - .allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST); + .userDetailsService(userDetailsService); + //支持GET,POST请求 PUT DELETE + endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST,HttpMethod.PUT,HttpMethod.DELETE); } +// @Override +// public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { +// //允许表单认证 +// security.allowFormAuthenticationForClients() +// // 配置校验token需要带入clientId 和clientSeret配置 +// .checkTokenAccess("isAuthenticated()"); +// } @Override - public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { - //允许表单认证 - security.allowFormAuthenticationForClients() - // 配置校验token需要带入clientId 和clientSeret配置 - .checkTokenAccess("isAuthenticated()"); + public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { + oauthServer + .tokenKeyAccess("permitAll()") + .checkTokenAccess("permitAll()") + .allowFormAuthenticationForClients(); } +// @Bean +// public FilterRegistrationBean oauth2ClientFilterRegistration(OAuth2ClientContextFilter oAuth2ClientContextFilter) { +// FilterRegistrationBean registration = new FilterRegistrationBean(); +// registration.setFilter(oAuth2ClientContextFilter); +// registration.setOrder(-100); +// return registration; +// } } diff --git a/itools-oms/itools-oms-server/src/main/java/com/itools/core/config/JwtTokenEnhancer.java b/itools-oms/itools-oms-server/src/main/java/com/itools/core/config/JwtTokenEnhancer.java index 80bc0d63d1d5a08211d1fc3d22df21e017de2fc2..fd85b844914a3c86e648fee2f180bf72057dc762 100644 --- a/itools-oms/itools-oms-server/src/main/java/com/itools/core/config/JwtTokenEnhancer.java +++ b/itools-oms/itools-oms-server/src/main/java/com/itools/core/config/JwtTokenEnhancer.java @@ -7,7 +7,12 @@ import org.springframework.security.oauth2.provider.token.TokenEnhancer; import java.util.HashMap; import java.util.Map; - +/** + * @project: itools-backend + * @description: + * @author: XUCHANG + * @create: 2021-03-28 15:51 + */ public class JwtTokenEnhancer implements TokenEnhancer { @Override diff --git a/itools-oms/itools-oms-server/src/main/java/com/itools/core/config/JwtTokenStoreConfig.java b/itools-oms/itools-oms-server/src/main/java/com/itools/core/config/JwtTokenStoreConfig.java index 56de5562053a2246c9336769e68ef147f8524c32..8ef1614e5b58268917d45eca0f7aff915309fe1a 100644 --- a/itools-oms/itools-oms-server/src/main/java/com/itools/core/config/JwtTokenStoreConfig.java +++ b/itools-oms/itools-oms-server/src/main/java/com/itools/core/config/JwtTokenStoreConfig.java @@ -5,7 +5,12 @@ import org.springframework.context.annotation.Configuration; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; - +/** + * @project: itools-backend + * @description: + * @author: XUCHANG + * @create: 2021-03-28 15:51 + */ @Configuration public class JwtTokenStoreConfig { diff --git a/itools-oms/itools-oms-server/src/main/java/com/itools/core/config/ResourceServerConfig.java b/itools-oms/itools-oms-server/src/main/java/com/itools/core/config/ResourceServerConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..cdb8fb0a00c9f5287c158c565daf4d50a37f534c --- /dev/null +++ b/itools-oms/itools-oms-server/src/main/java/com/itools/core/config/ResourceServerConfig.java @@ -0,0 +1,36 @@ +//package com.itools.core.config; +// +//import org.springframework.context.annotation.Configuration; +//import org.springframework.core.annotation.Order; +//import org.springframework.security.config.annotation.web.builders.HttpSecurity; +//import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; +//import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; +// +///** +// * @project: itools-backend +// * @description: 这个类表明了此应用是OAuth2 的资源服务器,此处主要指定了受资源服务器保护的资源链接 +// * @author: XUCHANG +// * @create: 2021-03-28 15:51 +// */ +//@Order(6) +//@Configuration +//@EnableResourceServer +//public class ResourceServerConfig extends ResourceServerConfigurerAdapter { +// +// @Override +// public void configure(HttpSecurity http) throws Exception { +// +// +// http.csrf().disable()//禁用了 csrf 功能 +// .authorizeRequests()//限定签名成功的请求 +//// .antMatchers("/decision/**","/govern/**").hasAnyRole("USER","ADMIN") +//// .antMatchers("/admin/**").hasRole("ADMIN") +// .antMatchers("/**").authenticated()//签名成功后可访问,不受role限制 +//// .antMatchers("/admin/login","/oauth/**").permitAll() +// .anyRequest().permitAll()//其他没有限定的请求,允许访问 +// .and().anonymous()//对于没有配置权限的其他请求允许匿名访问 +// .and().formLogin()//使用 spring security 默认登录页面 +// .and().httpBasic();//启用http 基础验证 +// } +// +//} \ No newline at end of file diff --git a/itools-oms/itools-oms-server/src/main/java/com/itools/core/config/WebSecurityConfig.java b/itools-oms/itools-oms-server/src/main/java/com/itools/core/config/WebSecurityConfig.java index 54a07a0beccad0f6857fca8968e846d551796012..99d049083688212e0fd5dca30407359e813276b5 100644 --- a/itools-oms/itools-oms-server/src/main/java/com/itools/core/config/WebSecurityConfig.java +++ b/itools-oms/itools-oms-server/src/main/java/com/itools/core/config/WebSecurityConfig.java @@ -3,9 +3,13 @@ package com.itools.core.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @@ -17,7 +21,10 @@ import org.springframework.security.crypto.password.PasswordEncoder; * @author: XUCHANG * @create: 2021-03-28 15:51 */ +@Order(2) @Configuration +@EnableWebSecurity(debug = true) +@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true,jsr250Enabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired @@ -45,11 +52,37 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { - http.formLogin() + http.formLogin().permitAll() .and().authorizeRequests() - .antMatchers("/user/getCurrentUser","/user/login","/login.html","/error.html","/session/invalid").permitAll() + .antMatchers("/user/getCurrentUser","/login","/oauth/**","/oauth/authorize","/login/**","/logout/**","/error").permitAll() .anyRequest().authenticated() + .and().httpBasic() .and().csrf().disable(); +// http +// .antMatcher("/**") +// .authorizeRequests() +// .antMatchers( +// HttpMethod.GET, +// "/*.html", +// "/**/*.html", +// "/**/*.css", +// "/**/*.js", +// "/**/*.jpg", +// "/**/*.png", +// "/error", +// "/favicon.ico" +// ).permitAll() +// .antMatchers("/swagger-ui.html").anonymous() +// .antMatchers("/swagger-resources/**").anonymous() +// .antMatchers("/user/getCurrentUser","/oauth/**","/oauth2/**","/login/**","/logout/**").permitAll() +// .anyRequest().authenticated(); +// http +// .antMatcher("/**") +// .authorizeRequests() +// .antMatchers("/oauth/**","/login/**","/logout/**").permitAll() +// .anyRequest().authenticated() +// .and() +// .formLogin().permitAll(); } } diff --git a/itools-oms/itools-oms-server/src/main/java/com/itools/core/mapper/PermissionMapper.java b/itools-oms/itools-oms-server/src/main/java/com/itools/core/mapper/PermissionMapper.java index cd93134bd0d3d1f3ee564852cebf100f162ca64e..23b9ec2bf43b2e58a9118c470a8068e54a8c128b 100644 --- a/itools-oms/itools-oms-server/src/main/java/com/itools/core/mapper/PermissionMapper.java +++ b/itools-oms/itools-oms-server/src/main/java/com/itools/core/mapper/PermissionMapper.java @@ -1,5 +1,6 @@ package com.itools.core.mapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.itools.core.param.SysPermission; import org.apache.ibatis.annotations.Select; import org.springframework.stereotype.Repository; @@ -13,7 +14,7 @@ import java.util.List; * @create: 2021-03-29 13:57 */ @Repository -public interface PermissionMapper { +public interface PermissionMapper extends BaseMapper { @Select("SELECT\n" + " p.*\n" + diff --git a/itools-oms/itools-oms-server/src/main/java/com/itools/core/mapper/UserMapper.java b/itools-oms/itools-oms-server/src/main/java/com/itools/core/mapper/UserMapper.java index ccd9a904f353d713596b93300ead2adeb43094ba..3fdb1d655417a58d940d14d4ad49e4d938e45754 100644 --- a/itools-oms/itools-oms-server/src/main/java/com/itools/core/mapper/UserMapper.java +++ b/itools-oms/itools-oms-server/src/main/java/com/itools/core/mapper/UserMapper.java @@ -1,5 +1,6 @@ package com.itools.core.mapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.itools.core.param.SysUser; import org.apache.ibatis.annotations.Select; import org.springframework.stereotype.Repository; @@ -11,7 +12,7 @@ import org.springframework.stereotype.Repository; * @create: 2021-03-29 13:57 */ @Repository -public interface UserMapper { +public interface UserMapper extends BaseMapper { @Select("select * from tb_user where username=#{username}") SysUser getByUsername(String username); diff --git a/itools-oms/itools-oms-server/src/main/java/com/itools/core/package-info.java b/itools-oms/itools-oms-server/src/main/java/com/itools/core/package-info.java index c3640d612a530dea3d9cc4a6953fafbdab56aead..a0dfc6590c9787b7a0393b8bfb926313477b0fc3 100644 --- a/itools-oms/itools-oms-server/src/main/java/com/itools/core/package-info.java +++ b/itools-oms/itools-oms-server/src/main/java/com/itools/core/package-info.java @@ -15,6 +15,20 @@ * 12、SessionManagementFilter * 13、ExceptionTranslationFilter 处理 AccessDeniedException 和 AuthenticationException 异常 * 14、FilterSecurityInterceptor AbstractInterceptUrlConfigurer.createFilterSecurityInterceptor + * + * 接口 + * /oauth/authorize:授权端点 + * /oauth/token:令牌端点 + * /oauth/confirm_access:用户确认授权提交端点 + * /oauth/error:授权服务错误信息端点 + * /oauth/check_token:用于资源服务访问的令牌解析端点 + * /oauth/token_key:提供公有密匙的端点,如果使用JWT令牌的话 + * + * 授权模式 + * 授权码模式(authorization code) + * 简化模式(implicit) + * 密码模式(resource owner password credentials) + * 客户端模式(client credentials) * @author: XUCHANG * @create: 2021-03-29 17:30 */ diff --git a/itools-oms/itools-oms-server/src/main/resources/application-dev.yml b/itools-oms/itools-oms-server/src/main/resources/application-dev.yml index 434bee2682dcc1ff04967fb83b1257c8131856bd..f7ecb63eff2fbe49a81923d1b7adfe52c0f4a395 100644 --- a/itools-oms/itools-oms-server/src/main/resources/application-dev.yml +++ b/itools-oms/itools-oms-server/src/main/resources/application-dev.yml @@ -1,12 +1,14 @@ +#组件中的全局异常处理的code system: errorCode: Code001 - +#分布式雪花算法策略 sequence: enable: true type: snowflake generate: simple - +#脚本自动初始化执行 initDB: + #启用开关 is-use: false # ddl脚本,可以支持多个,用,分割,文件建议最多5个 ddl: init/ddl.sql @@ -21,7 +23,6 @@ initDB: # 脚本设置的分隔符 delimiter: ; - # mybatis-plus相关配置 mybatis-plus: mapper-locations: classpath:/mapper/**/*Mapper.xml @@ -35,7 +36,6 @@ mybatis-plus: configuration: default-enum-type-handler: com.baomidou.mybatisplus.extension.handlers.MybatisEnumTypeHandler log-impl: org.apache.ibatis.logging.stdout.StdOutImpl - #security: # oauth2: # client: diff --git a/itools-oms/pom.xml b/itools-oms/pom.xml index af64d4e6047af166ce93330c7d72390cc3777bda..020d67b8f3a526416a5ba02b9e1572104cf22648 100644 --- a/itools-oms/pom.xml +++ b/itools-oms/pom.xml @@ -17,6 +17,7 @@ itools-oms-model itools-oms-core itools-oms-server + itools-oms-jwt-sample-example