diff --git a/blade-core-boot/pom.xml b/blade-core-boot/pom.xml
index 061af72..d4a5f37 100644
--- a/blade-core-boot/pom.xml
+++ b/blade-core-boot/pom.xml
@@ -5,7 +5,7 @@
org.springblade
blade-tool
- 3.4.1
+ 3.5.0
4.0.0
diff --git a/blade-core-boot/src/main/resources/bootstrap.yml b/blade-core-boot/src/main/resources/bootstrap.yml
index 57d74a0..12ccbe4 100644
--- a/blade-core-boot/src/main/resources/bootstrap.yml
+++ b/blade-core-boot/src/main/resources/bootstrap.yml
@@ -101,7 +101,7 @@ mybatis-plus:
swagger:
title: SpringBlade 接口文档系统
description: SpringBlade 接口文档系统
- version: 3.4.1
+ version: 3.5.0
license: Powered By SpringBlade
licenseUrl: https://bladex.vip
terms-of-service-url: https://bladex.vip
diff --git a/blade-core-cloud/pom.xml b/blade-core-cloud/pom.xml
index 91cc7e2..0139e3e 100644
--- a/blade-core-cloud/pom.xml
+++ b/blade-core-cloud/pom.xml
@@ -5,7 +5,7 @@
blade-tool
org.springblade
- 3.4.1
+ 3.5.0
4.0.0
diff --git a/blade-core-crypto/pom.xml b/blade-core-crypto/pom.xml
new file mode 100644
index 0000000..ef61ae5
--- /dev/null
+++ b/blade-core-crypto/pom.xml
@@ -0,0 +1,29 @@
+
+
+
+ blade-tool
+ org.springblade
+ 3.5.0
+
+ 4.0.0
+
+ blade-core-crypto
+ ${project.artifactId}
+ ${blade.tool.version}
+ jar
+
+
+
+ org.springblade
+ blade-core-tool
+ ${blade.tool.version}
+
+
+ org.springframework.cloud
+ spring-cloud-context
+
+
+
+
diff --git a/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/annotation/decrypt/ApiDecrypt.java b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/annotation/decrypt/ApiDecrypt.java
new file mode 100644
index 0000000..6defbd0
--- /dev/null
+++ b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/annotation/decrypt/ApiDecrypt.java
@@ -0,0 +1,32 @@
+package org.springblade.core.api.crypto.annotation.decrypt;
+
+import org.springblade.core.api.crypto.enums.CryptoType;
+
+import java.lang.annotation.*;
+
+/**
+ *
解密含有{@link org.springframework.web.bind.annotation.RequestBody}注解的参数请求数据,可用于整个控制类或者某个控制器上
+ *
+ * @author licoy.cn, L.cm
+ */
+@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface ApiDecrypt {
+
+ /**
+ * 解密类型
+ *
+ * @return 类型
+ */
+ CryptoType value();
+
+ /**
+ * 私钥,用于某些需要单独配置私钥的方法,没有时读取全局配置的私钥
+ *
+ * @return 私钥
+ */
+ String secretKey() default "";
+
+}
diff --git a/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/annotation/decrypt/ApiDecryptAes.java b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/annotation/decrypt/ApiDecryptAes.java
new file mode 100644
index 0000000..7dfcbb4
--- /dev/null
+++ b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/annotation/decrypt/ApiDecryptAes.java
@@ -0,0 +1,28 @@
+package org.springblade.core.api.crypto.annotation.decrypt;
+
+import org.springblade.core.api.crypto.enums.CryptoType;
+import org.springframework.core.annotation.AliasFor;
+
+import java.lang.annotation.*;
+
+/**
+ * aes 解密
+ *
+ * @author licoy.cn, L.cm
+ * @see ApiDecrypt
+ */
+@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@ApiDecrypt(CryptoType.AES)
+public @interface ApiDecryptAes {
+
+ /**
+ * Alias for {@link ApiDecrypt#secretKey()}.
+ *
+ * @return {String}
+ */
+ @AliasFor(annotation = ApiDecrypt.class)
+ String secretKey() default "";
+
+}
diff --git a/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/annotation/decrypt/ApiDecryptDes.java b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/annotation/decrypt/ApiDecryptDes.java
new file mode 100644
index 0000000..d2efc7b
--- /dev/null
+++ b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/annotation/decrypt/ApiDecryptDes.java
@@ -0,0 +1,28 @@
+package org.springblade.core.api.crypto.annotation.decrypt;
+
+import org.springblade.core.api.crypto.enums.CryptoType;
+import org.springframework.core.annotation.AliasFor;
+
+import java.lang.annotation.*;
+
+/**
+ * des 解密
+ *
+ * @author licoy.cn
+ * @see ApiDecrypt
+ */
+@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@ApiDecrypt(CryptoType.DES)
+public @interface ApiDecryptDes {
+
+ /**
+ * Alias for {@link ApiDecrypt#secretKey()}.
+ *
+ * @return {String}
+ */
+ @AliasFor(annotation = ApiDecrypt.class)
+ String secretKey() default "";
+
+}
diff --git a/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/annotation/encrypt/ApiEncrypt.java b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/annotation/encrypt/ApiEncrypt.java
new file mode 100644
index 0000000..fb50bd3
--- /dev/null
+++ b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/annotation/encrypt/ApiEncrypt.java
@@ -0,0 +1,33 @@
+package org.springblade.core.api.crypto.annotation.encrypt;
+
+
+import org.springblade.core.api.crypto.enums.CryptoType;
+
+import java.lang.annotation.*;
+
+/**
+ * 加密{@link org.springframework.web.bind.annotation.ResponseBody}响应数据,可用于整个控制类或者某个控制器上
+ *
+ * @author licoy.cn, L.cm
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface ApiEncrypt {
+
+ /**
+ * 加密类型
+ *
+ * @return 类型
+ */
+ CryptoType value();
+
+ /**
+ * 私钥,用于某些需要单独配置私钥的方法,没有时读取全局配置的私钥
+ *
+ * @return 私钥
+ */
+ String secretKey() default "";
+
+}
diff --git a/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/annotation/encrypt/ApiEncryptAes.java b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/annotation/encrypt/ApiEncryptAes.java
new file mode 100644
index 0000000..2b45790
--- /dev/null
+++ b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/annotation/encrypt/ApiEncryptAes.java
@@ -0,0 +1,28 @@
+package org.springblade.core.api.crypto.annotation.encrypt;
+
+import org.springblade.core.api.crypto.enums.CryptoType;
+import org.springframework.core.annotation.AliasFor;
+
+import java.lang.annotation.*;
+
+/**
+ * aes 加密
+ *
+ * @author licoy.cn, L.cm
+ * @see ApiEncrypt
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@ApiEncrypt(CryptoType.AES)
+public @interface ApiEncryptAes {
+
+ /**
+ * Alias for {@link ApiEncrypt#secretKey()}.
+ *
+ * @return {String}
+ */
+ @AliasFor(annotation = ApiEncrypt.class)
+ String secretKey() default "";
+
+}
diff --git a/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/annotation/encrypt/ApiEncryptDes.java b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/annotation/encrypt/ApiEncryptDes.java
new file mode 100644
index 0000000..036de8a
--- /dev/null
+++ b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/annotation/encrypt/ApiEncryptDes.java
@@ -0,0 +1,28 @@
+package org.springblade.core.api.crypto.annotation.encrypt;
+
+import org.springblade.core.api.crypto.enums.CryptoType;
+import org.springframework.core.annotation.AliasFor;
+
+import java.lang.annotation.*;
+
+/**
+ * des 加密
+ *
+ * @author licoy.cn, L.cm
+ * @see ApiEncrypt
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@ApiEncrypt(CryptoType.DES)
+public @interface ApiEncryptDes {
+
+ /**
+ * Alias for {@link ApiEncrypt#secretKey()}.
+ *
+ * @return {String}
+ */
+ @AliasFor(annotation = ApiEncrypt.class)
+ String secretKey() default "";
+
+}
diff --git a/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/bean/CryptoInfoBean.java b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/bean/CryptoInfoBean.java
new file mode 100644
index 0000000..e1e6d3f
--- /dev/null
+++ b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/bean/CryptoInfoBean.java
@@ -0,0 +1,25 @@
+package org.springblade.core.api.crypto.bean;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.springblade.core.api.crypto.enums.CryptoType;
+
+/**
+ * argumentResolvers) {
+ argumentResolvers.add(new ApiDecryptParamResolver(apiCryptoProperties));
+ }
+
+}
diff --git a/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/config/ApiCryptoProperties.java b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/config/ApiCryptoProperties.java
new file mode 100644
index 0000000..e548359
--- /dev/null
+++ b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/config/ApiCryptoProperties.java
@@ -0,0 +1,46 @@
+package org.springblade.core.api.crypto.config;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * api 签名配置类
+ *
+ * @author licoy.cn, L.cm
+ */
+@Getter
+@Setter
+@ConfigurationProperties(ApiCryptoProperties.PREFIX)
+public class ApiCryptoProperties {
+ /**
+ * 前缀
+ */
+ public static final String PREFIX = "blade.api.crypto";
+
+ /**
+ * 是否开启 api 签名
+ */
+ private Boolean enabled = Boolean.TRUE;
+
+ /**
+ * url的参数签名,传递的参数名。例如:/user?data=签名后的数据
+ */
+ private String paramName = "data";
+
+ /**
+ * aes 密钥
+ */
+ private String aesKey;
+
+ /**
+ * des 密钥
+ */
+ private String desKey;
+
+ /**
+ * rsa 私钥
+ */
+ private String rsaPrivateKey;
+
+}
diff --git a/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/core/ApiDecryptParamResolver.java b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/core/ApiDecryptParamResolver.java
new file mode 100644
index 0000000..a03f80d
--- /dev/null
+++ b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/core/ApiDecryptParamResolver.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (c) 2018-2028, DreamLu 卢春梦 (qq596392912@gmail.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springblade.core.api.crypto.core;
+
+import lombok.RequiredArgsConstructor;
+import org.springblade.core.api.crypto.annotation.decrypt.ApiDecrypt;
+import org.springblade.core.api.crypto.bean.CryptoInfoBean;
+import org.springblade.core.api.crypto.config.ApiCryptoProperties;
+import org.springblade.core.api.crypto.util.ApiCryptoUtil;
+import org.springblade.core.tool.jackson.JsonUtil;
+import org.springblade.core.tool.utils.Charsets;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springframework.core.MethodParameter;
+import org.springframework.core.annotation.AnnotatedElementUtils;
+import org.springframework.lang.Nullable;
+import org.springframework.web.bind.support.WebDataBinderFactory;
+import org.springframework.web.context.request.NativeWebRequest;
+import org.springframework.web.method.support.HandlerMethodArgumentResolver;
+import org.springframework.web.method.support.ModelAndViewContainer;
+
+import java.lang.reflect.Parameter;
+
+/**
+ * param 参数 解析
+ *
+ * @author L.cm
+ */
+@RequiredArgsConstructor
+public class ApiDecryptParamResolver implements HandlerMethodArgumentResolver {
+ private final ApiCryptoProperties properties;
+
+ @Override
+ public boolean supportsParameter(MethodParameter parameter) {
+ return AnnotatedElementUtils.hasAnnotation(parameter.getParameter(), ApiDecrypt.class);
+ }
+
+ @Nullable
+ @Override
+ public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer mavContainer,
+ NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
+ Parameter parameter = methodParameter.getParameter();
+ ApiDecrypt apiDecrypt = AnnotatedElementUtils.getMergedAnnotation(parameter, ApiDecrypt.class);
+ String text = webRequest.getParameter(properties.getParamName());
+ if (StringUtil.isBlank(text)) {
+ return null;
+ }
+ CryptoInfoBean infoBean = new CryptoInfoBean(apiDecrypt.value(), apiDecrypt.secretKey());
+ byte[] textBytes = text.getBytes(Charsets.UTF_8);
+ byte[] decryptData = ApiCryptoUtil.decryptData(properties, textBytes, infoBean);
+ return JsonUtil.readValue(decryptData, parameter.getType());
+ }
+}
diff --git a/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/core/ApiDecryptRequestBodyAdvice.java b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/core/ApiDecryptRequestBodyAdvice.java
new file mode 100644
index 0000000..28075c0
--- /dev/null
+++ b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/core/ApiDecryptRequestBodyAdvice.java
@@ -0,0 +1,87 @@
+package org.springblade.core.api.crypto.core;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.core.api.crypto.annotation.decrypt.ApiDecrypt;
+import org.springblade.core.api.crypto.bean.CryptoInfoBean;
+import org.springblade.core.api.crypto.bean.DecryptHttpInputMessage;
+import org.springblade.core.api.crypto.config.ApiCryptoProperties;
+import org.springblade.core.api.crypto.exception.DecryptBodyFailException;
+import org.springblade.core.api.crypto.util.ApiCryptoUtil;
+import org.springblade.core.tool.utils.ClassUtil;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.core.MethodParameter;
+import org.springframework.core.annotation.Order;
+import org.springframework.http.HttpInputMessage;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.lang.NonNull;
+import org.springframework.util.StreamUtils;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Type;
+
+/**
+ * 请求数据的加密信息解密处理
+ * 本类只对控制器参数中含有{@link org.springframework.web.bind.annotation.RequestBody}
+ * 以及package为org.springblade.core.api.signature.annotation.decrypt
下的注解有效
+ *
+ * @author licoy.cn, L.cm
+ * @see RequestBodyAdvice
+ */
+@Slf4j
+@Order(1)
+@AutoConfiguration
+@ControllerAdvice
+@RequiredArgsConstructor
+@ConditionalOnProperty(value = ApiCryptoProperties.PREFIX + ".enabled", havingValue = "true", matchIfMissing = true)
+public class ApiDecryptRequestBodyAdvice implements RequestBodyAdvice {
+ private final ApiCryptoProperties properties;
+
+ @Override
+ public boolean supports(MethodParameter methodParameter, @NonNull Type targetType, @NonNull Class extends HttpMessageConverter>> converterType) {
+ return ClassUtil.isAnnotated(methodParameter.getMethod(), ApiDecrypt.class);
+ }
+
+ @Override
+ public Object handleEmptyBody(Object body, @NonNull HttpInputMessage inputMessage, @NonNull MethodParameter parameter,
+ @NonNull Type targetType, @NonNull Class extends HttpMessageConverter>> converterType) {
+ return body;
+ }
+
+ @NonNull
+ @Override
+ public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, @NonNull MethodParameter parameter,
+ @NonNull Type targetType, @NonNull Class extends HttpMessageConverter>> converterType) throws IOException {
+ // 判断 body 是否为空
+ InputStream messageBody = inputMessage.getBody();
+ if (messageBody.available() <= 0) {
+ return inputMessage;
+ }
+ byte[] decryptedBody = null;
+ CryptoInfoBean cryptoInfoBean = ApiCryptoUtil.getDecryptInfo(parameter);
+ if (cryptoInfoBean != null) {
+ // base64 byte array
+ byte[] bodyByteArray = StreamUtils.copyToByteArray(messageBody);
+ decryptedBody = ApiCryptoUtil.decryptData(properties, bodyByteArray, cryptoInfoBean);
+ }
+ if (decryptedBody == null) {
+ throw new DecryptBodyFailException("Decryption error, " +
+ "please check if the selected source data is encrypted correctly." +
+ " (解密错误,请检查选择的源数据的加密方式是否正确。)");
+ }
+ InputStream inputStream = new ByteArrayInputStream(decryptedBody);
+ return new DecryptHttpInputMessage(inputStream, inputMessage.getHeaders());
+ }
+
+ @NonNull
+ @Override
+ public Object afterBodyRead(@NonNull Object body, @NonNull HttpInputMessage inputMessage, @NonNull MethodParameter parameter, @NonNull Type targetType, @NonNull Class extends HttpMessageConverter>> converterType) {
+ return body;
+ }
+
+}
diff --git a/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/core/ApiEncryptResponseBodyAdvice.java b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/core/ApiEncryptResponseBodyAdvice.java
new file mode 100644
index 0000000..a491d54
--- /dev/null
+++ b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/core/ApiEncryptResponseBodyAdvice.java
@@ -0,0 +1,64 @@
+package org.springblade.core.api.crypto.core;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.core.api.crypto.annotation.encrypt.ApiEncrypt;
+import org.springblade.core.api.crypto.bean.CryptoInfoBean;
+import org.springblade.core.api.crypto.config.ApiCryptoProperties;
+import org.springblade.core.api.crypto.exception.EncryptBodyFailException;
+import org.springblade.core.api.crypto.util.ApiCryptoUtil;
+import org.springblade.core.tool.jackson.JsonUtil;
+import org.springblade.core.tool.utils.ClassUtil;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.core.MethodParameter;
+import org.springframework.core.annotation.Order;
+import org.springframework.http.MediaType;
+import org.springframework.http.server.ServerHttpRequest;
+import org.springframework.http.server.ServerHttpResponse;
+import org.springframework.lang.NonNull;
+import org.springframework.lang.Nullable;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
+
+
+/**
+ * 响应数据的加密处理
+ * 本类只对控制器参数中含有{@link org.springframework.web.bind.annotation.ResponseBody}
+ * 或者控制类上含有{@link org.springframework.web.bind.annotation.RestController}
+ * 以及package为org.springblade.core.api.signature.annotation.encrypt
下的注解有效
+ *
+ * @author licoy.cn, L.cm
+ * @see ResponseBodyAdvice
+ */
+@Slf4j
+@Order(1)
+@AutoConfiguration
+@ControllerAdvice
+@RequiredArgsConstructor
+@ConditionalOnProperty(value = ApiCryptoProperties.PREFIX + ".enabled", havingValue = "true", matchIfMissing = true)
+public class ApiEncryptResponseBodyAdvice implements ResponseBodyAdvice {
+ private final ApiCryptoProperties properties;
+
+ @Override
+ public boolean supports(MethodParameter returnType, @NonNull Class converterType) {
+ return ClassUtil.isAnnotated(returnType.getMethod(), ApiEncrypt.class);
+ }
+
+ @Nullable
+ @Override
+ public Object beforeBodyWrite(Object body, @NonNull MethodParameter returnType, @NonNull MediaType selectedContentType,
+ @NonNull Class selectedConverterType, @NonNull ServerHttpRequest request, @NonNull ServerHttpResponse response) {
+ if (body == null) {
+ return null;
+ }
+ response.getHeaders().setContentType(MediaType.TEXT_PLAIN);
+ CryptoInfoBean cryptoInfoBean = ApiCryptoUtil.getEncryptInfo(returnType);
+ if (cryptoInfoBean != null) {
+ byte[] bodyJsonBytes = JsonUtil.toJsonAsBytes(body);
+ return ApiCryptoUtil.encryptData(properties, bodyJsonBytes, cryptoInfoBean);
+ }
+ throw new EncryptBodyFailException();
+ }
+
+}
diff --git a/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/enums/CryptoType.java b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/enums/CryptoType.java
new file mode 100644
index 0000000..0139c2e
--- /dev/null
+++ b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/enums/CryptoType.java
@@ -0,0 +1,20 @@
+package org.springblade.core.api.crypto.enums;
+
+/**
+ * 加密方式
+ *
+ * @author licoy.cn, L.cm
+ */
+public enum CryptoType {
+
+ /**
+ * des
+ */
+ DES,
+
+ /**
+ * aes
+ */
+ AES
+
+}
diff --git a/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/exception/DecryptBodyFailException.java b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/exception/DecryptBodyFailException.java
new file mode 100644
index 0000000..a103dbf
--- /dev/null
+++ b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/exception/DecryptBodyFailException.java
@@ -0,0 +1,13 @@
+package org.springblade.core.api.crypto.exception;
+
+/**
+ * 解密数据失败异常
+ *
+ * @author licoy.cn
+ */
+public class DecryptBodyFailException extends RuntimeException {
+
+ public DecryptBodyFailException(String message) {
+ super(message);
+ }
+}
diff --git a/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/exception/EncryptBodyFailException.java b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/exception/EncryptBodyFailException.java
new file mode 100644
index 0000000..eb3bf70
--- /dev/null
+++ b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/exception/EncryptBodyFailException.java
@@ -0,0 +1,17 @@
+package org.springblade.core.api.crypto.exception;
+
+/**
+ * 加密数据失败异常
+ *
+ * @author licoy.cn
+ */
+public class EncryptBodyFailException extends RuntimeException {
+
+ public EncryptBodyFailException() {
+ super("Encrypted data failed. (加密数据失败)");
+ }
+
+ public EncryptBodyFailException(String message) {
+ super(message);
+ }
+}
diff --git a/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/exception/EncryptMethodNotFoundException.java b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/exception/EncryptMethodNotFoundException.java
new file mode 100644
index 0000000..f148fe8
--- /dev/null
+++ b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/exception/EncryptMethodNotFoundException.java
@@ -0,0 +1,14 @@
+package org.springblade.core.api.crypto.exception;
+
+/**
+ * 加密方式未找到或未定义异常
+ *
+ * @author licoy.cn
+ */
+public class EncryptMethodNotFoundException extends RuntimeException {
+
+ public EncryptMethodNotFoundException() {
+ super("Encryption method is not defined. (加密方式未定义)");
+ }
+
+}
diff --git a/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/exception/KeyNotConfiguredException.java b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/exception/KeyNotConfiguredException.java
new file mode 100644
index 0000000..4fc05f5
--- /dev/null
+++ b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/exception/KeyNotConfiguredException.java
@@ -0,0 +1,14 @@
+package org.springblade.core.api.crypto.exception;
+
+
+/**
+ * 未配置KEY运行时异常
+ *
+ * @author licoy.cn, L.cm
+ */
+public class KeyNotConfiguredException extends RuntimeException {
+
+ public KeyNotConfiguredException(String message) {
+ super(message);
+ }
+}
diff --git a/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/util/ApiCryptoUtil.java b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/util/ApiCryptoUtil.java
new file mode 100644
index 0000000..bade259
--- /dev/null
+++ b/blade-core-crypto/src/main/java/org/springblade/core/api/crypto/util/ApiCryptoUtil.java
@@ -0,0 +1,117 @@
+package org.springblade.core.api.crypto.util;
+
+import org.springblade.core.api.crypto.annotation.decrypt.ApiDecrypt;
+import org.springblade.core.api.crypto.annotation.encrypt.ApiEncrypt;
+import org.springblade.core.api.crypto.bean.CryptoInfoBean;
+import org.springblade.core.api.crypto.config.ApiCryptoProperties;
+import org.springblade.core.api.crypto.enums.CryptoType;
+import org.springblade.core.api.crypto.exception.EncryptBodyFailException;
+import org.springblade.core.api.crypto.exception.EncryptMethodNotFoundException;
+import org.springblade.core.api.crypto.exception.KeyNotConfiguredException;
+import org.springblade.core.tool.utils.AesUtil;
+import org.springblade.core.tool.utils.ClassUtil;
+import org.springblade.core.tool.utils.DesUtil;
+import org.springblade.core.tool.utils.StringUtil;
+import org.springframework.core.MethodParameter;
+import org.springframework.lang.Nullable;
+
+/**
+ * 辅助检测工具类
+ *
+ * @author licoy.cn, L.cm
+ */
+public class ApiCryptoUtil {
+
+ /**
+ * 获取方法控制器上的加密注解信息
+ *
+ * @param methodParameter 控制器方法
+ * @return 加密注解信息
+ */
+ @Nullable
+ public static CryptoInfoBean getEncryptInfo(MethodParameter methodParameter) {
+ ApiEncrypt encryptBody = ClassUtil.getAnnotation(methodParameter.getMethod(), ApiEncrypt.class);
+ if (encryptBody == null) {
+ return null;
+ }
+ return new CryptoInfoBean(encryptBody.value(), encryptBody.secretKey());
+ }
+
+ /**
+ * 获取方法控制器上的解密注解信息
+ *
+ * @param methodParameter 控制器方法
+ * @return 加密注解信息
+ */
+ @Nullable
+ public static CryptoInfoBean getDecryptInfo(MethodParameter methodParameter) {
+ ApiDecrypt decryptBody = ClassUtil.getAnnotation(methodParameter.getMethod(), ApiDecrypt.class);
+ if (decryptBody == null) {
+ return null;
+ }
+ return new CryptoInfoBean(decryptBody.value(), decryptBody.secretKey());
+ }
+
+ /**
+ * 选择加密方式并进行加密
+ *
+ * @param jsonData json 数据
+ * @param infoBean 加密信息
+ * @return 加密结果
+ */
+ public static String encryptData(ApiCryptoProperties properties, byte[] jsonData, CryptoInfoBean infoBean) {
+ CryptoType type = infoBean.getType();
+ if (type == null) {
+ throw new EncryptMethodNotFoundException();
+ }
+ String secretKey = infoBean.getSecretKey();
+ if (type == CryptoType.DES) {
+ secretKey = ApiCryptoUtil.checkSecretKey(properties.getDesKey(), secretKey, "DES");
+ return DesUtil.encryptToBase64(jsonData, secretKey);
+ }
+ if (type == CryptoType.AES) {
+ secretKey = ApiCryptoUtil.checkSecretKey(properties.getAesKey(), secretKey, "AES");
+ return AesUtil.encryptToBase64(jsonData, secretKey);
+ }
+ throw new EncryptBodyFailException();
+ }
+
+ /**
+ * 选择加密方式并进行解密
+ *
+ * @param bodyData byte array
+ * @param infoBean 加密信息
+ * @return 解密结果
+ */
+ public static byte[] decryptData(ApiCryptoProperties properties, byte[] bodyData, CryptoInfoBean infoBean) {
+ CryptoType type = infoBean.getType();
+ if (type == null) {
+ throw new EncryptMethodNotFoundException();
+ }
+ String secretKey = infoBean.getSecretKey();
+ if (type == CryptoType.AES) {
+ secretKey = ApiCryptoUtil.checkSecretKey(properties.getAesKey(), secretKey, "AES");
+ return AesUtil.decryptFormBase64(bodyData, secretKey);
+ }
+ if (type == CryptoType.DES) {
+ secretKey = ApiCryptoUtil.checkSecretKey(properties.getDesKey(), secretKey, "DES");
+ return DesUtil.decryptFormBase64(bodyData, secretKey);
+ }
+ throw new EncryptMethodNotFoundException();
+ }
+
+ /**
+ * 检验私钥
+ *
+ * @param k1 配置的私钥
+ * @param k2 注解上的私钥
+ * @param keyName key名称
+ * @return 私钥
+ */
+ private static String checkSecretKey(String k1, String k2, String keyName) {
+ if (StringUtil.isBlank(k1) && StringUtil.isBlank(k2)) {
+ throw new KeyNotConfiguredException(String.format("%s key is not configured (未配置%s)", keyName, keyName));
+ }
+ return StringUtil.isBlank(k2) ? k1 : k2;
+ }
+}
diff --git a/blade-core-datascope/pom.xml b/blade-core-datascope/pom.xml
index 8d0e52f..54a4c34 100644
--- a/blade-core-datascope/pom.xml
+++ b/blade-core-datascope/pom.xml
@@ -5,7 +5,7 @@
blade-tool
org.springblade
- 3.4.1
+ 3.5.0
4.0.0
diff --git a/blade-core-develop/pom.xml b/blade-core-develop/pom.xml
index 47c59ab..f7988ea 100644
--- a/blade-core-develop/pom.xml
+++ b/blade-core-develop/pom.xml
@@ -5,7 +5,7 @@
blade-tool
org.springblade
- 3.4.1
+ 3.5.0
4.0.0
@@ -40,5 +40,4 @@
-
diff --git a/blade-core-launch/pom.xml b/blade-core-launch/pom.xml
index 527a0fc..b353659 100644
--- a/blade-core-launch/pom.xml
+++ b/blade-core-launch/pom.xml
@@ -5,7 +5,7 @@
blade-tool
org.springblade
- 3.4.1
+ 3.5.0
4.0.0
diff --git a/blade-core-launch/src/main/java/org/springblade/core/launch/constant/AppConstant.java b/blade-core-launch/src/main/java/org/springblade/core/launch/constant/AppConstant.java
index cd09d6c..f255ca6 100644
--- a/blade-core-launch/src/main/java/org/springblade/core/launch/constant/AppConstant.java
+++ b/blade-core-launch/src/main/java/org/springblade/core/launch/constant/AppConstant.java
@@ -25,7 +25,7 @@ public interface AppConstant {
/**
* 应用版本
*/
- String APPLICATION_VERSION = "3.4.1";
+ String APPLICATION_VERSION = "3.5.0";
/**
* 基础包
diff --git a/blade-core-launch/src/main/java/org/springblade/core/launch/constant/TokenConstant.java b/blade-core-launch/src/main/java/org/springblade/core/launch/constant/TokenConstant.java
index 1cb3364..f65910f 100644
--- a/blade-core-launch/src/main/java/org/springblade/core/launch/constant/TokenConstant.java
+++ b/blade-core-launch/src/main/java/org/springblade/core/launch/constant/TokenConstant.java
@@ -22,7 +22,6 @@ package org.springblade.core.launch.constant;
*/
public interface TokenConstant {
- String SIGN_KEY = "bladexisapowerfulmicroservicearchitectureupgradedandoptimizedfromacommercialproject";
String AVATAR = "avatar";
String HEADER = "blade-auth";
String BEARER = "bearer";
@@ -44,4 +43,13 @@ public interface TokenConstant {
String DEFAULT_AVATAR = "https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png";
Integer AUTH_LENGTH = 7;
+ /**
+ * token签名
+ */
+ String SIGN_KEY = "bladexisapowerfulmicroservicearchitectureupgradedandoptimizedfromacommercialproject";
+ /**
+ * key安全长度,具体见:https://tools.ietf.org/html/rfc7518#section-3.2
+ */
+ int SIGN_KEY_LENGTH = 32;
+
}
diff --git a/blade-core-loadbalancer/pom.xml b/blade-core-loadbalancer/pom.xml
index 49b11cb..62d505b 100644
--- a/blade-core-loadbalancer/pom.xml
+++ b/blade-core-loadbalancer/pom.xml
@@ -5,7 +5,7 @@
blade-tool
org.springblade
- 3.4.1
+ 3.5.0
4.0.0
diff --git a/blade-core-log/pom.xml b/blade-core-log/pom.xml
index fb1bb8a..7c3ea29 100644
--- a/blade-core-log/pom.xml
+++ b/blade-core-log/pom.xml
@@ -5,7 +5,7 @@
blade-tool
org.springblade
- 3.4.1
+ 3.5.0
4.0.0
@@ -39,5 +39,4 @@
${mybatis.plus.version}
-
diff --git a/blade-core-log/src/main/java/org/springblade/core/log/config/BladeErrorMvcAutoConfiguration.java b/blade-core-log/src/main/java/org/springblade/core/log/config/BladeErrorMvcAutoConfiguration.java
index 7490d61..fad5f36 100644
--- a/blade-core-log/src/main/java/org/springblade/core/log/config/BladeErrorMvcAutoConfiguration.java
+++ b/blade-core-log/src/main/java/org/springblade/core/log/config/BladeErrorMvcAutoConfiguration.java
@@ -19,6 +19,7 @@ package org.springblade.core.log.config;
import lombok.AllArgsConstructor;
import org.springblade.core.log.error.BladeErrorAttributes;
import org.springblade.core.log.error.BladeErrorController;
+import org.springblade.core.log.props.BladeLogProperties;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@@ -28,6 +29,7 @@ import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorController;
@@ -45,15 +47,18 @@ import javax.servlet.Servlet;
@AllArgsConstructor
@ConditionalOnWebApplication
@AutoConfigureBefore(ErrorMvcAutoConfiguration.class)
+@EnableConfigurationProperties(BladeLogProperties.class)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class})
public class BladeErrorMvcAutoConfiguration {
private final ServerProperties serverProperties;
+ private final BladeLogProperties bladeLogProperties;
+
@Bean
@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
public DefaultErrorAttributes errorAttributes() {
- return new BladeErrorAttributes();
+ return new BladeErrorAttributes(bladeLogProperties);
}
@Bean
diff --git a/blade-core-log/src/main/java/org/springblade/core/log/config/BladeLogToolAutoConfiguration.java b/blade-core-log/src/main/java/org/springblade/core/log/config/BladeLogToolAutoConfiguration.java
index 1627f6b..37cf711 100644
--- a/blade-core-log/src/main/java/org/springblade/core/log/config/BladeLogToolAutoConfiguration.java
+++ b/blade-core-log/src/main/java/org/springblade/core/log/config/BladeLogToolAutoConfiguration.java
@@ -25,8 +25,11 @@ import org.springblade.core.log.event.ErrorLogListener;
import org.springblade.core.log.event.UsualLogListener;
import org.springblade.core.log.feign.ILogClient;
import org.springblade.core.log.logger.BladeLogger;
+import org.springblade.core.log.props.BladeLogProperties;
import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
/**
@@ -44,28 +47,33 @@ public class BladeLogToolAutoConfiguration {
private final BladeProperties bladeProperties;
@Bean
+ @ConditionalOnProperty(value = BladeLogProperties.PREFIX + "api.enabled", havingValue = "true", matchIfMissing = true)
public ApiLogAspect apiLogAspect() {
return new ApiLogAspect();
}
@Bean
- public BladeLogger bladeLogger() {
- return new BladeLogger();
- }
-
- @Bean
+ @ConditionalOnProperty(value = BladeLogProperties.PREFIX + "api.enabled", havingValue = "true", matchIfMissing = true)
public ApiLogListener apiLogListener() {
return new ApiLogListener(logService, serverInfo, bladeProperties);
}
@Bean
+ @ConditionalOnProperty(value = BladeLogProperties.PREFIX + "error.enabled", havingValue = "true", matchIfMissing = true)
public ErrorLogListener errorEventListener() {
return new ErrorLogListener(logService, serverInfo, bladeProperties);
}
@Bean
+ @ConditionalOnProperty(value = BladeLogProperties.PREFIX + "usual.enabled", havingValue = "true", matchIfMissing = true)
public UsualLogListener bladeEventListener() {
return new UsualLogListener(logService, serverInfo, bladeProperties);
}
+ @Bean
+ @ConditionalOnProperty(value = BladeLogProperties.PREFIX + "usual.enabled", havingValue = "true", matchIfMissing = true)
+ public BladeLogger bladeLogger() {
+ return new BladeLogger();
+ }
+
}
diff --git a/blade-core-log/src/main/java/org/springblade/core/log/error/BladeErrorAttributes.java b/blade-core-log/src/main/java/org/springblade/core/log/error/BladeErrorAttributes.java
index 5e2f7da..a3de7bd 100644
--- a/blade-core-log/src/main/java/org/springblade/core/log/error/BladeErrorAttributes.java
+++ b/blade-core-log/src/main/java/org/springblade/core/log/error/BladeErrorAttributes.java
@@ -15,7 +15,9 @@
*/
package org.springblade.core.log.error;
+import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.springblade.core.log.props.BladeLogProperties;
import org.springblade.core.log.publisher.ErrorLogPublisher;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.api.ResultCode;
@@ -34,7 +36,9 @@ import java.util.Map;
* @author Chill
*/
@Slf4j
+@RequiredArgsConstructor
public class BladeErrorAttributes extends DefaultErrorAttributes {
+ private final BladeLogProperties bladeLogProperties;
@Override
public Map getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
@@ -50,7 +54,9 @@ public class BladeErrorAttributes extends DefaultErrorAttributes {
result = R.fail(status, error.getMessage());
}
//发送服务异常事件
- ErrorLogPublisher.publishEvent(error, requestUri);
+ if (bladeLogProperties.getError()) {
+ ErrorLogPublisher.publishEvent(error, requestUri);
+ }
return BeanUtil.toMap(result);
}
diff --git a/blade-core-log/src/main/java/org/springblade/core/log/error/BladeRestExceptionTranslator.java b/blade-core-log/src/main/java/org/springblade/core/log/error/BladeRestExceptionTranslator.java
index 881b881..77294bd 100644
--- a/blade-core-log/src/main/java/org/springblade/core/log/error/BladeRestExceptionTranslator.java
+++ b/blade-core-log/src/main/java/org/springblade/core/log/error/BladeRestExceptionTranslator.java
@@ -15,9 +15,11 @@
*/
package org.springblade.core.log.error;
+import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.internal.engine.path.PathImpl;
import org.springblade.core.log.exception.ServiceException;
+import org.springblade.core.log.props.BladeLogProperties;
import org.springblade.core.log.publisher.ErrorLogPublisher;
import org.springblade.core.secure.exception.SecureException;
import org.springblade.core.tool.api.R;
@@ -59,8 +61,11 @@ import java.util.Set;
@ConditionalOnClass({Servlet.class, DispatcherServlet.class})
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@RestControllerAdvice
+@RequiredArgsConstructor
public class BladeRestExceptionTranslator {
+ private final BladeLogProperties bladeLogProperties;
+
@ExceptionHandler(MissingServletRequestParameterException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public R handleError(MissingServletRequestParameterException e) {
@@ -155,7 +160,9 @@ public class BladeRestExceptionTranslator {
public R handleError(Throwable e) {
log.error("服务器异常", e);
//发送服务异常事件
- ErrorLogPublisher.publishEvent(e, UrlUtil.getPath(WebUtil.getRequest().getRequestURI()));
+ if (bladeLogProperties.getError()) {
+ ErrorLogPublisher.publishEvent(e, UrlUtil.getPath(WebUtil.getRequest().getRequestURI()));
+ }
return R.fail(ResultCode.INTERNAL_SERVER_ERROR, (Func.isEmpty(e.getMessage()) ? ResultCode.INTERNAL_SERVER_ERROR.getMessage() : e.getMessage()));
}
diff --git a/blade-core-log/src/main/java/org/springblade/core/log/props/BladeLogProperties.java b/blade-core-log/src/main/java/org/springblade/core/log/props/BladeLogProperties.java
new file mode 100644
index 0000000..4fa1583
--- /dev/null
+++ b/blade-core-log/src/main/java/org/springblade/core/log/props/BladeLogProperties.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.log.props;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * 异步配置
+ *
+ * @author Chill
+ */
+@Getter
+@Setter
+@ConfigurationProperties(BladeLogProperties.PREFIX)
+public class BladeLogProperties {
+ /**
+ * 前缀
+ */
+ public static final String PREFIX = "blade.log";
+
+ /**
+ * 是否开启 api 日志
+ */
+ private Boolean api = Boolean.TRUE;
+ /**
+ * 是否开启 error 日志
+ */
+ private Boolean error = Boolean.TRUE;
+ /**
+ * 是否开启 usual 日志
+ */
+ private Boolean usual = Boolean.TRUE;
+}
diff --git a/blade-core-mybatis/pom.xml b/blade-core-mybatis/pom.xml
index 8caac07..3f77aa7 100644
--- a/blade-core-mybatis/pom.xml
+++ b/blade-core-mybatis/pom.xml
@@ -5,7 +5,7 @@
blade-tool
org.springblade
- 3.4.1
+ 3.5.0
4.0.0
diff --git a/blade-core-mybatis/src/main/java/org/springblade/core/mp/intercept/QueryInterceptor.java b/blade-core-mybatis/src/main/java/org/springblade/core/mp/intercept/QueryInterceptor.java
index f101a81..db5717f 100644
--- a/blade-core-mybatis/src/main/java/org/springblade/core/mp/intercept/QueryInterceptor.java
+++ b/blade-core-mybatis/src/main/java/org/springblade/core/mp/intercept/QueryInterceptor.java
@@ -1,18 +1,17 @@
-/*
- * Copyright (c) 2018-2028, DreamLu All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * Neither the name of the dreamlu.net developer nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- * Author: DreamLu 卢春梦 (596392912@qq.com)
+/**
+ * Copyright (c) 2018-2028, DreamLu 卢春梦 (qq596392912@gmail.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package org.springblade.core.mp.intercept;
diff --git a/blade-core-oss/pom.xml b/blade-core-oss/pom.xml
index 1020e2f..3772d4b 100644
--- a/blade-core-oss/pom.xml
+++ b/blade-core-oss/pom.xml
@@ -5,7 +5,7 @@
blade-tool
org.springblade
- 3.4.1
+ 3.5.0
4.0.0
@@ -21,17 +21,23 @@
blade-core-tool
${blade.tool.version}
+
+
+ com.aliyun.oss
+ aliyun-sdk-oss
+ 3.14.0
+
+
+
+ io.minio
+ minio
+ 8.3.7
+
com.qiniu
qiniu-java-sdk
- 7.2.18
-
-
-
- com.aliyun.oss
- aliyun-sdk-oss
- 3.1.0
+ 7.9.4
diff --git a/blade-core-oss/src/main/java/org/springblade/core/oss/AliossTemplate.java b/blade-core-oss/src/main/java/org/springblade/core/oss/AliossTemplate.java
index 184b8f8..fded6c8 100644
--- a/blade-core-oss/src/main/java/org/springblade/core/oss/AliossTemplate.java
+++ b/blade-core-oss/src/main/java/org/springblade/core/oss/AliossTemplate.java
@@ -45,11 +45,12 @@ import java.util.Map;
* @author Chill
*/
@AllArgsConstructor
-public class AliossTemplate {
- private OSSClient ossClient;
- private OssProperties ossProperties;
- private OssRule ossRule;
+public class AliossTemplate implements OssTemplate {
+ private final OSSClient ossClient;
+ private final OssProperties ossProperties;
+ private final OssRule ossRule;
+ @Override
@SneakyThrows
public void makeBucket(String bucketName) {
if (!bucketExists(bucketName)) {
@@ -57,31 +58,37 @@ public class AliossTemplate {
}
}
+ @Override
@SneakyThrows
public void removeBucket(String bucketName) {
ossClient.deleteBucket(getBucketName(bucketName));
}
+ @Override
@SneakyThrows
public boolean bucketExists(String bucketName) {
return ossClient.doesBucketExist(getBucketName(bucketName));
}
+ @Override
@SneakyThrows
public void copyFile(String bucketName, String fileName, String destBucketName) {
ossClient.copyObject(getBucketName(bucketName), fileName, getBucketName(destBucketName), fileName);
}
+ @Override
@SneakyThrows
public void copyFile(String bucketName, String fileName, String destBucketName, String destFileName) {
ossClient.copyObject(getBucketName(bucketName), fileName, getBucketName(destBucketName), destFileName);
}
+ @Override
@SneakyThrows
public OssFile statFile(String fileName) {
return statFile(ossProperties.getBucketName(), fileName);
}
+ @Override
@SneakyThrows
public OssFile statFile(String bucketName, String fileName) {
ObjectMetadata stat = ossClient.getObjectMetadata(getBucketName(bucketName), fileName);
@@ -95,46 +102,55 @@ public class AliossTemplate {
return ossFile;
}
+ @Override
@SneakyThrows
public String filePath(String fileName) {
return getOssHost().concat(StringPool.SLASH).concat(fileName);
}
+ @Override
@SneakyThrows
public String filePath(String bucketName, String fileName) {
return getOssHost(bucketName).concat(StringPool.SLASH).concat(fileName);
}
+ @Override
@SneakyThrows
public String fileLink(String fileName) {
return getOssHost().concat(StringPool.SLASH).concat(fileName);
}
+ @Override
@SneakyThrows
public String fileLink(String bucketName, String fileName) {
return getOssHost(bucketName).concat(StringPool.SLASH).concat(fileName);
}
+ @Override
@SneakyThrows
public BladeFile putFile(MultipartFile file) {
return putFile(ossProperties.getBucketName(), file.getOriginalFilename(), file);
}
+ @Override
@SneakyThrows
public BladeFile putFile(String fileName, MultipartFile file) {
return putFile(ossProperties.getBucketName(), fileName, file);
}
+ @Override
@SneakyThrows
public BladeFile putFile(String bucketName, String fileName, MultipartFile file) {
return putFile(bucketName, fileName, file.getInputStream());
}
+ @Override
@SneakyThrows
public BladeFile putFile(String fileName, InputStream stream) {
return putFile(ossProperties.getBucketName(), fileName, stream);
}
+ @Override
@SneakyThrows
public BladeFile putFile(String bucketName, String fileName, InputStream stream) {
return put(bucketName, stream, fileName, false);
@@ -160,25 +176,30 @@ public class AliossTemplate {
BladeFile file = new BladeFile();
file.setOriginalName(originalName);
file.setName(key);
+ file.setDomain(getOssHost(bucketName));
file.setLink(fileLink(bucketName, key));
return file;
}
+ @Override
@SneakyThrows
public void removeFile(String fileName) {
ossClient.deleteObject(getBucketName(), fileName);
}
+ @Override
@SneakyThrows
public void removeFile(String bucketName, String fileName) {
ossClient.deleteObject(getBucketName(bucketName), fileName);
}
+ @Override
@SneakyThrows
public void removeFiles(List fileNames) {
fileNames.forEach(this::removeFile);
}
+ @Override
@SneakyThrows
public void removeFiles(String bucketName, List fileNames) {
fileNames.forEach(fileName -> removeFile(getBucketName(bucketName), fileName));
@@ -227,11 +248,6 @@ public class AliossTemplate {
return getUploadToken(bucketName, ossProperties.getArgs().get("expireTime", 3600L));
}
- /**
- * TODO 上传大小限制、基础路径
- *
- * 获取上传凭证,普通上传
- */
public String getUploadToken(String bucketName, long expireTime) {
String baseDir = "upload";
@@ -258,11 +274,22 @@ public class AliossTemplate {
return JsonUtil.toJson(respMap);
}
+ /**
+ * 获取域名
+ *
+ * @param bucketName 存储桶名称
+ * @return String
+ */
public String getOssHost(String bucketName) {
String prefix = ossProperties.getEndpoint().contains("https://") ? "https://" : "http://";
return prefix + getBucketName(bucketName) + StringPool.DOT + ossProperties.getEndpoint().replaceFirst(prefix, StringPool.EMPTY);
}
+ /**
+ * 获取域名
+ *
+ * @return String
+ */
public String getOssHost() {
return getOssHost(ossProperties.getBucketName());
}
diff --git a/blade-core-oss/src/main/java/org/springblade/core/oss/MinioTemplate.java b/blade-core-oss/src/main/java/org/springblade/core/oss/MinioTemplate.java
new file mode 100644
index 0000000..c9023cc
--- /dev/null
+++ b/blade-core-oss/src/main/java/org/springblade/core/oss/MinioTemplate.java
@@ -0,0 +1,417 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.oss;
+
+import io.minio.*;
+import io.minio.http.Method;
+import io.minio.messages.Bucket;
+import io.minio.messages.DeleteObject;
+import lombok.AllArgsConstructor;
+import lombok.SneakyThrows;
+import org.springblade.core.oss.enums.PolicyType;
+import org.springblade.core.oss.model.BladeFile;
+import org.springblade.core.oss.model.OssFile;
+import org.springblade.core.oss.props.OssProperties;
+import org.springblade.core.oss.rule.OssRule;
+import org.springblade.core.tool.utils.DateUtil;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.StringPool;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.InputStream;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+/**
+ * MinIOTemplate
+ *
+ * @author Chill
+ */
+@AllArgsConstructor
+public class MinioTemplate implements OssTemplate {
+
+ /**
+ * MinIO客户端
+ */
+ private final MinioClient client;
+
+ /**
+ * 存储桶命名规则
+ */
+ private final OssRule ossRule;
+
+ /**
+ * 配置类
+ */
+ private final OssProperties ossProperties;
+
+
+ @Override
+ @SneakyThrows
+ public void makeBucket(String bucketName) {
+ if (
+ !client.bucketExists(
+ BucketExistsArgs.builder().bucket(getBucketName(bucketName)).build()
+ )
+ ) {
+ client.makeBucket(
+ MakeBucketArgs.builder().bucket(getBucketName(bucketName)).build()
+ );
+ client.setBucketPolicy(
+ SetBucketPolicyArgs.builder().bucket(getBucketName(bucketName)).config(getPolicyType(getBucketName(bucketName), PolicyType.READ)).build()
+ );
+ }
+ }
+
+ @SneakyThrows
+ public Bucket getBucket() {
+ return getBucket(getBucketName());
+ }
+
+ @SneakyThrows
+ public Bucket getBucket(String bucketName) {
+ Optional bucketOptional = client.listBuckets().stream().filter(bucket -> bucket.name().equals(getBucketName(bucketName))).findFirst();
+ return bucketOptional.orElse(null);
+ }
+
+ @SneakyThrows
+ public List listBuckets() {
+ return client.listBuckets();
+ }
+
+ @Override
+ @SneakyThrows
+ public void removeBucket(String bucketName) {
+ client.removeBucket(
+ RemoveBucketArgs.builder().bucket(getBucketName(bucketName)).build()
+ );
+ }
+
+ @Override
+ @SneakyThrows
+ public boolean bucketExists(String bucketName) {
+ return client.bucketExists(
+ BucketExistsArgs.builder().bucket(getBucketName(bucketName)).build()
+ );
+ }
+
+ @Override
+ @SneakyThrows
+ public void copyFile(String bucketName, String fileName, String destBucketName) {
+ copyFile(bucketName, fileName, destBucketName, fileName);
+ }
+
+ @Override
+ @SneakyThrows
+ public void copyFile(String bucketName, String fileName, String destBucketName, String destFileName) {
+ client.copyObject(
+ CopyObjectArgs.builder()
+ .source(CopySource.builder().bucket(getBucketName(bucketName)).object(fileName).build())
+ .bucket(getBucketName(destBucketName))
+ .object(destFileName)
+ .build()
+ );
+ }
+
+ @Override
+ @SneakyThrows
+ public OssFile statFile(String fileName) {
+ return statFile(ossProperties.getBucketName(), fileName);
+ }
+
+ @Override
+ @SneakyThrows
+ public OssFile statFile(String bucketName, String fileName) {
+ StatObjectResponse stat = client.statObject(
+ StatObjectArgs.builder().bucket(getBucketName(bucketName)).object(fileName).build()
+ );
+ OssFile ossFile = new OssFile();
+ ossFile.setName(Func.isEmpty(stat.object()) ? fileName : stat.object());
+ ossFile.setLink(fileLink(ossFile.getName()));
+ ossFile.setHash(String.valueOf(stat.hashCode()));
+ ossFile.setLength(stat.size());
+ ossFile.setPutTime(DateUtil.toDate(stat.lastModified().toLocalDateTime()));
+ ossFile.setContentType(stat.contentType());
+ return ossFile;
+ }
+
+ @Override
+ public String filePath(String fileName) {
+ return getBucketName().concat(StringPool.SLASH).concat(fileName);
+ }
+
+ @Override
+ public String filePath(String bucketName, String fileName) {
+ return getBucketName(bucketName).concat(StringPool.SLASH).concat(fileName);
+ }
+
+ @Override
+ @SneakyThrows
+ public String fileLink(String fileName) {
+ return ossProperties.getEndpoint().concat(StringPool.SLASH).concat(getBucketName()).concat(StringPool.SLASH).concat(fileName);
+ }
+
+ @Override
+ @SneakyThrows
+ public String fileLink(String bucketName, String fileName) {
+ return ossProperties.getEndpoint().concat(StringPool.SLASH).concat(getBucketName(bucketName)).concat(StringPool.SLASH).concat(fileName);
+ }
+
+ @Override
+ @SneakyThrows
+ public BladeFile putFile(MultipartFile file) {
+ return putFile(ossProperties.getBucketName(), file.getOriginalFilename(), file);
+ }
+
+ @Override
+ @SneakyThrows
+ public BladeFile putFile(String fileName, MultipartFile file) {
+ return putFile(ossProperties.getBucketName(), fileName, file);
+ }
+
+ @Override
+ @SneakyThrows
+ public BladeFile putFile(String bucketName, String fileName, MultipartFile file) {
+ return putFile(bucketName, file.getOriginalFilename(), file.getInputStream());
+ }
+
+ @Override
+ @SneakyThrows
+ public BladeFile putFile(String fileName, InputStream stream) {
+ return putFile(ossProperties.getBucketName(), fileName, stream);
+ }
+
+ @Override
+ @SneakyThrows
+ public BladeFile putFile(String bucketName, String fileName, InputStream stream) {
+ return putFile(bucketName, fileName, stream, "application/octet-stream");
+ }
+
+ @SneakyThrows
+ public BladeFile putFile(String bucketName, String fileName, InputStream stream, String contentType) {
+ makeBucket(bucketName);
+ String originalName = fileName;
+ fileName = getFileName(fileName);
+ client.putObject(
+ PutObjectArgs.builder()
+ .bucket(getBucketName(bucketName))
+ .object(fileName)
+ .stream(stream, stream.available(), -1)
+ .contentType(contentType)
+ .build()
+ );
+ BladeFile file = new BladeFile();
+ file.setOriginalName(originalName);
+ file.setName(fileName);
+ file.setDomain(getOssHost(bucketName));
+ file.setLink(fileLink(bucketName, fileName));
+ return file;
+ }
+
+ @Override
+ @SneakyThrows
+ public void removeFile(String fileName) {
+ removeFile(ossProperties.getBucketName(), fileName);
+ }
+
+ @Override
+ @SneakyThrows
+ public void removeFile(String bucketName, String fileName) {
+ client.removeObject(
+ RemoveObjectArgs.builder().bucket(getBucketName(bucketName)).object(fileName).build()
+ );
+ }
+
+ @Override
+ @SneakyThrows
+ public void removeFiles(List fileNames) {
+ removeFiles(ossProperties.getBucketName(), fileNames);
+ }
+
+ @Override
+ @SneakyThrows
+ public void removeFiles(String bucketName, List fileNames) {
+ Stream stream = fileNames.stream().map(DeleteObject::new);
+ client.removeObjects(RemoveObjectsArgs.builder().bucket(getBucketName(bucketName)).objects(stream::iterator).build());
+ }
+
+ /**
+ * 根据规则生成存储桶名称规则
+ *
+ * @return String
+ */
+ private String getBucketName() {
+ return getBucketName(ossProperties.getBucketName());
+ }
+
+ /**
+ * 根据规则生成存储桶名称规则
+ *
+ * @param bucketName 存储桶名称
+ * @return String
+ */
+ private String getBucketName(String bucketName) {
+ return ossRule.bucketName(bucketName);
+ }
+
+ /**
+ * 根据规则生成文件名称规则
+ *
+ * @param originalFilename 原始文件名
+ * @return string
+ */
+ private String getFileName(String originalFilename) {
+ return ossRule.fileName(originalFilename);
+ }
+
+ /**
+ * 获取文件外链
+ *
+ * @param bucketName bucket名称
+ * @param fileName 文件名称
+ * @param expires 过期时间
+ * @return url
+ */
+ @SneakyThrows
+ public String getPresignedObjectUrl(String bucketName, String fileName, Integer expires) {
+ return client.getPresignedObjectUrl(
+ GetPresignedObjectUrlArgs.builder()
+ .method(Method.GET)
+ .bucket(getBucketName(bucketName))
+ .object(fileName)
+ .expiry(expires)
+ .build()
+ );
+ }
+
+ /**
+ * 获取存储桶策略
+ *
+ * @param policyType 策略枚举
+ * @return String
+ */
+ public String getPolicyType(PolicyType policyType) {
+ return getPolicyType(getBucketName(), policyType);
+ }
+
+ /**
+ * 获取存储桶策略
+ *
+ * @param bucketName 存储桶名称
+ * @param policyType 策略枚举
+ * @return String
+ */
+ public static String getPolicyType(String bucketName, PolicyType policyType) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("{\n");
+ builder.append(" \"Statement\": [\n");
+ builder.append(" {\n");
+ builder.append(" \"Action\": [\n");
+
+ switch (policyType) {
+ case WRITE:
+ builder.append(" \"s3:GetBucketLocation\",\n");
+ builder.append(" \"s3:ListBucketMultipartUploads\"\n");
+ break;
+ case READ_WRITE:
+ builder.append(" \"s3:GetBucketLocation\",\n");
+ builder.append(" \"s3:ListBucket\",\n");
+ builder.append(" \"s3:ListBucketMultipartUploads\"\n");
+ break;
+ default:
+ builder.append(" \"s3:GetBucketLocation\"\n");
+ break;
+ }
+
+ builder.append(" ],\n");
+ builder.append(" \"Effect\": \"Allow\",\n");
+ builder.append(" \"Principal\": \"*\",\n");
+ builder.append(" \"Resource\": \"arn:aws:s3:::");
+ builder.append(bucketName);
+ builder.append("\"\n");
+ builder.append(" },\n");
+ if (PolicyType.READ.equals(policyType)) {
+ builder.append(" {\n");
+ builder.append(" \"Action\": [\n");
+ builder.append(" \"s3:ListBucket\"\n");
+ builder.append(" ],\n");
+ builder.append(" \"Effect\": \"Deny\",\n");
+ builder.append(" \"Principal\": \"*\",\n");
+ builder.append(" \"Resource\": \"arn:aws:s3:::");
+ builder.append(bucketName);
+ builder.append("\"\n");
+ builder.append(" },\n");
+
+ }
+ builder.append(" {\n");
+ builder.append(" \"Action\": ");
+
+ switch (policyType) {
+ case WRITE:
+ builder.append("[\n");
+ builder.append(" \"s3:AbortMultipartUpload\",\n");
+ builder.append(" \"s3:DeleteObject\",\n");
+ builder.append(" \"s3:ListMultipartUploadParts\",\n");
+ builder.append(" \"s3:PutObject\"\n");
+ builder.append(" ],\n");
+ break;
+ case READ_WRITE:
+ builder.append("[\n");
+ builder.append(" \"s3:AbortMultipartUpload\",\n");
+ builder.append(" \"s3:DeleteObject\",\n");
+ builder.append(" \"s3:GetObject\",\n");
+ builder.append(" \"s3:ListMultipartUploadParts\",\n");
+ builder.append(" \"s3:PutObject\"\n");
+ builder.append(" ],\n");
+ break;
+ default:
+ builder.append("\"s3:GetObject\",\n");
+ break;
+ }
+
+ builder.append(" \"Effect\": \"Allow\",\n");
+ builder.append(" \"Principal\": \"*\",\n");
+ builder.append(" \"Resource\": \"arn:aws:s3:::");
+ builder.append(bucketName);
+ builder.append("/*\"\n");
+ builder.append(" }\n");
+ builder.append(" ],\n");
+ builder.append(" \"Version\": \"2012-10-17\"\n");
+ builder.append("}\n");
+ return builder.toString();
+ }
+
+ /**
+ * 获取域名
+ *
+ * @param bucketName 存储桶名称
+ * @return String
+ */
+ public String getOssHost(String bucketName) {
+ return ossProperties.getEndpoint() + StringPool.SLASH + getBucketName(bucketName);
+ }
+
+ /**
+ * 获取域名
+ *
+ * @return String
+ */
+ public String getOssHost() {
+ return getOssHost(ossProperties.getBucketName());
+ }
+
+}
diff --git a/blade-core-oss/src/main/java/org/springblade/core/oss/OssTemplate.java b/blade-core-oss/src/main/java/org/springblade/core/oss/OssTemplate.java
new file mode 100644
index 0000000..fbddf7b
--- /dev/null
+++ b/blade-core-oss/src/main/java/org/springblade/core/oss/OssTemplate.java
@@ -0,0 +1,202 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.oss;
+
+
+import org.springblade.core.oss.model.BladeFile;
+import org.springblade.core.oss.model.OssFile;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.InputStream;
+import java.util.List;
+
+/**
+ * OssTemplate抽象API
+ *
+ * @author Chill
+ */
+public interface OssTemplate {
+
+ /**
+ * 创建 存储桶
+ *
+ * @param bucketName 存储桶名称
+ */
+ void makeBucket(String bucketName);
+
+ /**
+ * 删除 存储桶
+ *
+ * @param bucketName 存储桶名称
+ */
+ void removeBucket(String bucketName);
+
+ /**
+ * 存储桶是否存在
+ *
+ * @param bucketName 存储桶名称
+ * @return boolean
+ */
+ boolean bucketExists(String bucketName);
+
+ /**
+ * 拷贝文件
+ *
+ * @param bucketName 存储桶名称
+ * @param fileName 存储桶文件名称
+ * @param destBucketName 目标存储桶名称
+ */
+ void copyFile(String bucketName, String fileName, String destBucketName);
+
+ /**
+ * 拷贝文件
+ *
+ * @param bucketName 存储桶名称
+ * @param fileName 存储桶文件名称
+ * @param destBucketName 目标存储桶名称
+ * @param destFileName 目标存储桶文件名称
+ */
+ void copyFile(String bucketName, String fileName, String destBucketName, String destFileName);
+
+ /**
+ * 获取文件信息
+ *
+ * @param fileName 存储桶文件名称
+ * @return InputStream
+ */
+ OssFile statFile(String fileName);
+
+ /**
+ * 获取文件信息
+ *
+ * @param bucketName 存储桶名称
+ * @param fileName 存储桶文件名称
+ * @return InputStream
+ */
+ OssFile statFile(String bucketName, String fileName);
+
+ /**
+ * 获取文件相对路径
+ *
+ * @param fileName 存储桶对象名称
+ * @return String
+ */
+ String filePath(String fileName);
+
+ /**
+ * 获取文件相对路径
+ *
+ * @param bucketName 存储桶名称
+ * @param fileName 存储桶对象名称
+ * @return String
+ */
+ String filePath(String bucketName, String fileName);
+
+ /**
+ * 获取文件地址
+ *
+ * @param fileName 存储桶对象名称
+ * @return String
+ */
+ String fileLink(String fileName);
+
+ /**
+ * 获取文件地址
+ *
+ * @param bucketName 存储桶名称
+ * @param fileName 存储桶对象名称
+ * @return String
+ */
+ String fileLink(String bucketName, String fileName);
+
+ /**
+ * 上传文件
+ *
+ * @param file 上传文件类
+ * @return BladeFile
+ */
+ BladeFile putFile(MultipartFile file);
+
+ /**
+ * 上传文件
+ *
+ * @param file 上传文件类
+ * @param fileName 上传文件名
+ * @return BladeFile
+ */
+ BladeFile putFile(String fileName, MultipartFile file);
+
+ /**
+ * 上传文件
+ *
+ * @param bucketName 存储桶名称
+ * @param fileName 上传文件名
+ * @param file 上传文件类
+ * @return BladeFile
+ */
+ BladeFile putFile(String bucketName, String fileName, MultipartFile file);
+
+ /**
+ * 上传文件
+ *
+ * @param fileName 存储桶对象名称
+ * @param stream 文件流
+ * @return BladeFile
+ */
+ BladeFile putFile(String fileName, InputStream stream);
+
+ /**
+ * 上传文件
+ *
+ * @param bucketName 存储桶名称
+ * @param fileName 存储桶对象名称
+ * @param stream 文件流
+ * @return BladeFile
+ */
+ BladeFile putFile(String bucketName, String fileName, InputStream stream);
+
+ /**
+ * 删除文件
+ *
+ * @param fileName 存储桶对象名称
+ */
+ void removeFile(String fileName);
+
+ /**
+ * 删除文件
+ *
+ * @param bucketName 存储桶名称
+ * @param fileName 存储桶对象名称
+ */
+ void removeFile(String bucketName, String fileName);
+
+ /**
+ * 批量删除文件
+ *
+ * @param fileNames 存储桶对象名称集合
+ */
+ void removeFiles(List fileNames);
+
+ /**
+ * 批量删除文件
+ *
+ * @param bucketName 存储桶名称
+ * @param fileNames 存储桶对象名称集合
+ */
+ void removeFiles(String bucketName, List fileNames);
+
+
+}
diff --git a/blade-core-oss/src/main/java/org/springblade/core/oss/QiniuTemplate.java b/blade-core-oss/src/main/java/org/springblade/core/oss/QiniuTemplate.java
index 9c53efe..57392d9 100644
--- a/blade-core-oss/src/main/java/org/springblade/core/oss/QiniuTemplate.java
+++ b/blade-core-oss/src/main/java/org/springblade/core/oss/QiniuTemplate.java
@@ -33,8 +33,6 @@ import org.springblade.core.tool.utils.StringPool;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.List;
@@ -44,57 +42,56 @@ import java.util.List;
* @author Chill
*/
@AllArgsConstructor
-public class QiniuTemplate {
- private Auth auth;
- private UploadManager uploadManager;
- private BucketManager bucketManager;
- private OssProperties ossProperties;
- private OssRule ossRule;
-
+public class QiniuTemplate implements OssTemplate {
+ private final Auth auth;
+ private final UploadManager uploadManager;
+ private final BucketManager bucketManager;
+ private final OssProperties ossProperties;
+ private final OssRule ossRule;
+ @Override
@SneakyThrows
public void makeBucket(String bucketName) {
if (!CollectionUtil.contains(bucketManager.buckets(), getBucketName(bucketName))) {
- bucketManager.createBucket(getBucketName(bucketName), Zone.zone0().getRegion());
+ bucketManager.createBucket(getBucketName(bucketName), Zone.autoZone().getRegion());
}
}
-
+ @Override
@SneakyThrows
public void removeBucket(String bucketName) {
- bucketManager.deleteBucket(getBucketName(bucketName));
+
}
-
+ @Override
@SneakyThrows
public boolean bucketExists(String bucketName) {
return CollectionUtil.contains(bucketManager.buckets(), getBucketName(bucketName));
}
-
+ @Override
@SneakyThrows
public void copyFile(String bucketName, String fileName, String destBucketName) {
bucketManager.copy(getBucketName(bucketName), fileName, getBucketName(destBucketName), fileName);
}
-
+ @Override
@SneakyThrows
public void copyFile(String bucketName, String fileName, String destBucketName, String destFileName) {
bucketManager.copy(getBucketName(bucketName), fileName, getBucketName(destBucketName), destFileName);
}
-
+ @Override
@SneakyThrows
public OssFile statFile(String fileName) {
return statFile(ossProperties.getBucketName(), fileName);
}
-
+ @Override
@SneakyThrows
public OssFile statFile(String bucketName, String fileName) {
FileInfo stat = bucketManager.stat(getBucketName(bucketName), fileName);
OssFile ossFile = new OssFile();
- ossFile.setName(stat.key);
ossFile.setName(Func.isEmpty(stat.key) ? fileName : stat.key);
ossFile.setLink(fileLink(ossFile.getName()));
ossFile.setHash(stat.hash);
@@ -104,80 +101,55 @@ public class QiniuTemplate {
return ossFile;
}
-
+ @Override
@SneakyThrows
public String filePath(String fileName) {
return getBucketName().concat(StringPool.SLASH).concat(fileName);
}
-
+ @Override
@SneakyThrows
public String filePath(String bucketName, String fileName) {
return getBucketName(bucketName).concat(StringPool.SLASH).concat(fileName);
}
-
+ @Override
@SneakyThrows
public String fileLink(String fileName) {
return ossProperties.getEndpoint().concat(StringPool.SLASH).concat(fileName);
}
-
+ @Override
@SneakyThrows
public String fileLink(String bucketName, String fileName) {
return ossProperties.getEndpoint().concat(StringPool.SLASH).concat(fileName);
}
-
- /**
- * 获取文件公开链接
- *
- * @param fileName 文件名
- * @return 文件公开链接
- */
- public String publicFileLink(String fileName) {
- return String.format("%s/%s", ossProperties.getEndpoint(), fileName);
- }
-
- /**
- * 获取文件私有链接
- *
- * @param fileName 文件名
- * @param expireTime 超时时间
- * @return 私有文件链接
- */
- @SneakyThrows
- public String privateFileLink(String fileName, Long expireTime) {
- String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()).replace("+", "%20");
- String publicUrl = String.format("%s/%s", ossProperties.getEndpoint(), encodedFileName);
- return auth.privateDownloadUrl(publicUrl, expireTime);
- }
-
-
+ @Override
@SneakyThrows
public BladeFile putFile(MultipartFile file) {
return putFile(ossProperties.getBucketName(), file.getOriginalFilename(), file);
}
-
+ @Override
@SneakyThrows
public BladeFile putFile(String fileName, MultipartFile file) {
return putFile(ossProperties.getBucketName(), fileName, file);
}
-
+ @Override
@SneakyThrows
public BladeFile putFile(String bucketName, String fileName, MultipartFile file) {
- return putFile(bucketName, fileName, file);
+ return putFile(bucketName, fileName, file.getInputStream());
}
-
+ @Override
@SneakyThrows
public BladeFile putFile(String fileName, InputStream stream) {
return putFile(ossProperties.getBucketName(), fileName, stream);
}
-
+ @Override
@SneakyThrows
public BladeFile putFile(String bucketName, String fileName, InputStream stream) {
return put(bucketName, stream, fileName, false);
@@ -185,9 +157,8 @@ public class QiniuTemplate {
@SneakyThrows
public BladeFile put(String bucketName, InputStream stream, String key, boolean cover) {
- BladeFile file = new BladeFile();
- file.setOriginalName(key);
makeBucket(bucketName);
+ String originalName = key;
key = getFileName(key);
// 覆盖上传
if (cover) {
@@ -201,30 +172,33 @@ public class QiniuTemplate {
retry++;
}
}
+ BladeFile file = new BladeFile();
+ file.setOriginalName(originalName);
file.setName(key);
+ file.setDomain(getOssHost());
file.setLink(fileLink(bucketName, key));
return file;
}
-
+ @Override
@SneakyThrows
public void removeFile(String fileName) {
bucketManager.delete(getBucketName(), fileName);
}
-
+ @Override
@SneakyThrows
public void removeFile(String bucketName, String fileName) {
bucketManager.delete(getBucketName(bucketName), fileName);
}
-
+ @Override
@SneakyThrows
public void removeFiles(List fileNames) {
fileNames.forEach(this::removeFile);
}
-
+ @Override
@SneakyThrows
public void removeFiles(String bucketName, List fileNames) {
fileNames.forEach(fileName -> removeFile(getBucketName(bucketName), fileName));
@@ -261,6 +235,9 @@ public class QiniuTemplate {
/**
* 获取上传凭证,普通上传
+ *
+ * @param bucketName 存储桶名称
+ * @return string
*/
public String getUploadToken(String bucketName) {
return auth.uploadToken(getBucketName(bucketName));
@@ -268,9 +245,22 @@ public class QiniuTemplate {
/**
* 获取上传凭证,覆盖上传
+ *
+ * @param bucketName 存储桶名称
+ * @param key key
+ * @return string
*/
private String getUploadToken(String bucketName, String key) {
return auth.uploadToken(getBucketName(bucketName), key);
}
+ /**
+ * 获取域名
+ *
+ * @return String
+ */
+ public String getOssHost() {
+ return ossProperties.getEndpoint();
+ }
+
}
diff --git a/blade-core-oss/src/main/java/org/springblade/core/oss/config/AliossConfiguration.java b/blade-core-oss/src/main/java/org/springblade/core/oss/config/AliossConfiguration.java
index 661d94e..7736fc7 100644
--- a/blade-core-oss/src/main/java/org/springblade/core/oss/config/AliossConfiguration.java
+++ b/blade-core-oss/src/main/java/org/springblade/core/oss/config/AliossConfiguration.java
@@ -22,11 +22,10 @@ import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import lombok.AllArgsConstructor;
import org.springblade.core.oss.AliossTemplate;
import org.springblade.core.oss.props.OssProperties;
-import org.springblade.core.oss.rule.BladeOssRule;
import org.springblade.core.oss.rule.OssRule;
import org.springframework.boot.autoconfigure.AutoConfiguration;
-import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@@ -37,20 +36,15 @@ import org.springframework.context.annotation.Bean;
*
* @author Chill
*/
-@AutoConfiguration
@AllArgsConstructor
-@AutoConfigureAfter(QiniuConfiguration.class)
+@AutoConfiguration(after = OssConfiguration.class)
@EnableConfigurationProperties(OssProperties.class)
+@ConditionalOnClass({OSSClient.class})
@ConditionalOnProperty(value = "oss.name", havingValue = "alioss")
public class AliossConfiguration {
- private OssProperties ossProperties;
-
- @Bean
- @ConditionalOnMissingBean(OssRule.class)
- public OssRule ossRule() {
- return new BladeOssRule();
- }
+ private final OssProperties ossProperties;
+ private final OssRule ossRule;
@Bean
@ConditionalOnMissingBean(OSSClient.class)
@@ -74,9 +68,9 @@ public class AliossConfiguration {
}
@Bean
+ @ConditionalOnBean({OSSClient.class})
@ConditionalOnMissingBean(AliossTemplate.class)
- @ConditionalOnBean({OSSClient.class, OssRule.class})
- public AliossTemplate aliossTemplate(OSSClient ossClient, OssRule ossRule) {
+ public AliossTemplate aliossTemplate(OSSClient ossClient) {
return new AliossTemplate(ossClient, ossProperties, ossRule);
}
diff --git a/blade-core-oss/src/main/java/org/springblade/core/oss/config/MinioConfiguration.java b/blade-core-oss/src/main/java/org/springblade/core/oss/config/MinioConfiguration.java
new file mode 100644
index 0000000..2ce0757
--- /dev/null
+++ b/blade-core-oss/src/main/java/org/springblade/core/oss/config/MinioConfiguration.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.oss.config;
+
+import io.minio.MinioClient;
+import lombok.AllArgsConstructor;
+import lombok.SneakyThrows;
+import org.springblade.core.oss.MinioTemplate;
+import org.springblade.core.oss.props.OssProperties;
+import org.springblade.core.oss.rule.OssRule;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+
+/**
+ * Minio配置类
+ *
+ * @author Chill
+ */
+@AllArgsConstructor
+@AutoConfiguration(after = OssConfiguration.class)
+@ConditionalOnClass({MinioClient.class})
+@EnableConfigurationProperties(OssProperties.class)
+@ConditionalOnProperty(value = "oss.name", havingValue = "minio")
+public class MinioConfiguration {
+
+ private final OssProperties ossProperties;
+ private final OssRule ossRule;
+
+
+ @Bean
+ @SneakyThrows
+ @ConditionalOnMissingBean(MinioClient.class)
+ public MinioClient minioClient() {
+ return MinioClient.builder()
+ .endpoint(ossProperties.getEndpoint())
+ .credentials(ossProperties.getAccessKey(), ossProperties.getSecretKey())
+ .build();
+ }
+
+ @Bean
+ @ConditionalOnBean({MinioClient.class})
+ @ConditionalOnMissingBean(MinioTemplate.class)
+ public MinioTemplate minioTemplate(MinioClient minioClient) {
+ return new MinioTemplate(minioClient, ossRule, ossProperties);
+ }
+
+}
diff --git a/blade-core-oss/src/main/java/org/springblade/core/oss/config/OssConfiguration.java b/blade-core-oss/src/main/java/org/springblade/core/oss/config/OssConfiguration.java
new file mode 100644
index 0000000..f80edd5
--- /dev/null
+++ b/blade-core-oss/src/main/java/org/springblade/core/oss/config/OssConfiguration.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.oss.config;
+
+import lombok.AllArgsConstructor;
+import org.springblade.core.oss.props.OssProperties;
+import org.springblade.core.oss.rule.BladeOssRule;
+import org.springblade.core.oss.rule.OssRule;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+
+/**
+ * Oss配置类
+ *
+ * @author Chill
+ */
+@AutoConfiguration
+@AllArgsConstructor
+@EnableConfigurationProperties(OssProperties.class)
+public class OssConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean(OssRule.class)
+ public OssRule ossRule() {
+ return new BladeOssRule();
+ }
+
+}
diff --git a/blade-core-oss/src/main/java/org/springblade/core/oss/config/QiniuConfiguration.java b/blade-core-oss/src/main/java/org/springblade/core/oss/config/QiniuConfiguration.java
index 0d64a9c..44394f9 100644
--- a/blade-core-oss/src/main/java/org/springblade/core/oss/config/QiniuConfiguration.java
+++ b/blade-core-oss/src/main/java/org/springblade/core/oss/config/QiniuConfiguration.java
@@ -15,47 +15,45 @@
*/
package org.springblade.core.oss.config;
-import com.qiniu.common.Zone;
import com.qiniu.storage.BucketManager;
+import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.util.Auth;
import lombok.AllArgsConstructor;
import org.springblade.core.oss.QiniuTemplate;
import org.springblade.core.oss.props.OssProperties;
-import org.springblade.core.oss.rule.BladeOssRule;
import org.springblade.core.oss.rule.OssRule;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
/**
- * Oss配置类
+ * Qiniu配置类
*
* @author Chill
*/
-@AutoConfiguration
@AllArgsConstructor
+@AutoConfiguration(after = OssConfiguration.class)
+@ConditionalOnClass({Auth.class, UploadManager.class, BucketManager.class})
@EnableConfigurationProperties(OssProperties.class)
@ConditionalOnProperty(value = "oss.name", havingValue = "qiniu")
public class QiniuConfiguration {
- private OssProperties ossProperties;
+ private final OssProperties ossProperties;
+ private final OssRule ossRule;
@Bean
- @ConditionalOnMissingBean(OssRule.class)
- public OssRule ossRule() {
- return new BladeOssRule();
- }
-
- @Bean
- public com.qiniu.storage.Configuration qiniuConfiguration() {
- return new com.qiniu.storage.Configuration(Zone.autoZone());
+ @ConditionalOnMissingBean(com.qiniu.storage.Configuration.class)
+ public com.qiniu.storage.Configuration qnConfiguration() {
+ return new com.qiniu.storage.Configuration(Region.autoRegion());
}
@Bean
+ @ConditionalOnMissingBean(Auth.class)
public Auth auth() {
return Auth.create(ossProperties.getAccessKey(), ossProperties.getSecretKey());
}
@@ -73,11 +71,10 @@ public class QiniuConfiguration {
}
@Bean
+ @ConditionalOnBean({Auth.class, UploadManager.class, BucketManager.class})
@ConditionalOnMissingBean(QiniuTemplate.class)
- @ConditionalOnBean({Auth.class, UploadManager.class, BucketManager.class, OssRule.class})
- public QiniuTemplate qiniuTemplate(Auth auth, UploadManager uploadManager, BucketManager bucketManager, OssRule ossRule) {
+ public QiniuTemplate qiniuTemplate(Auth auth, UploadManager uploadManager, BucketManager bucketManager) {
return new QiniuTemplate(auth, uploadManager, bucketManager, ossProperties, ossRule);
}
-
}
diff --git a/blade-core-oss/src/main/java/org/springblade/core/oss/enums/PolicyType.java b/blade-core-oss/src/main/java/org/springblade/core/oss/enums/PolicyType.java
new file mode 100644
index 0000000..4d3d44c
--- /dev/null
+++ b/blade-core-oss/src/main/java/org/springblade/core/oss/enums/PolicyType.java
@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.oss.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * minio策略配置
+ *
+ * @author SCMOX
+ */
+@Getter
+@AllArgsConstructor
+public enum PolicyType {
+
+ /**
+ * 只读
+ */
+ READ("read", "只读"),
+
+ /**
+ * 只写
+ */
+ WRITE("write", "只写"),
+
+ /**
+ * 读写
+ */
+ READ_WRITE("read_write", "读写");
+
+ /**
+ * 类型
+ */
+ private final String type;
+ /**
+ * 描述
+ */
+ private final String policy;
+
+}
diff --git a/blade-core-oss/src/main/java/org/springblade/core/oss/model/BladeFile.java b/blade-core-oss/src/main/java/org/springblade/core/oss/model/BladeFile.java
index 3b746c7..77dbfc4 100644
--- a/blade-core-oss/src/main/java/org/springblade/core/oss/model/BladeFile.java
+++ b/blade-core-oss/src/main/java/org/springblade/core/oss/model/BladeFile.java
@@ -28,6 +28,10 @@ public class BladeFile {
* 文件地址
*/
private String link;
+ /**
+ * 域名地址
+ */
+ private String domain;
/**
* 文件名
*/
diff --git a/blade-core-oss/src/main/java/org/springblade/core/oss/props/OssProperties.java b/blade-core-oss/src/main/java/org/springblade/core/oss/props/OssProperties.java
index 41a64f8..f02049e 100644
--- a/blade-core-oss/src/main/java/org/springblade/core/oss/props/OssProperties.java
+++ b/blade-core-oss/src/main/java/org/springblade/core/oss/props/OssProperties.java
@@ -61,7 +61,7 @@ public class OssProperties {
/**
* 默认的存储桶名称
*/
- private String bucketName = "bladex";
+ private String bucketName = "blade";
/**
* 自定义属性
diff --git a/blade-core-report/pom.xml b/blade-core-report/pom.xml
index 029877b..20f6b64 100644
--- a/blade-core-report/pom.xml
+++ b/blade-core-report/pom.xml
@@ -5,7 +5,7 @@
blade-tool
org.springblade
- 3.4.1
+ 3.5.0
4.0.0
diff --git a/blade-core-secure/pom.xml b/blade-core-secure/pom.xml
index 016a26e..fa278e9 100644
--- a/blade-core-secure/pom.xml
+++ b/blade-core-secure/pom.xml
@@ -5,7 +5,7 @@
blade-tool
org.springblade
- 3.4.1
+ 3.5.0
4.0.0
diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/config/SecureConfiguration.java b/blade-core-secure/src/main/java/org/springblade/core/secure/config/SecureConfiguration.java
index 2e06e06..be228c8 100644
--- a/blade-core-secure/src/main/java/org/springblade/core/secure/config/SecureConfiguration.java
+++ b/blade-core-secure/src/main/java/org/springblade/core/secure/config/SecureConfiguration.java
@@ -21,6 +21,7 @@ import org.springblade.core.secure.aspect.AuthAspect;
import org.springblade.core.secure.interceptor.ClientInterceptor;
import org.springblade.core.secure.interceptor.SecureInterceptor;
import org.springblade.core.secure.props.BladeSecureProperties;
+import org.springblade.core.secure.props.BladeTokenProperties;
import org.springblade.core.secure.provider.ClientDetailsServiceImpl;
import org.springblade.core.secure.provider.IClientDetailsService;
import org.springblade.core.secure.registry.SecureRegistry;
@@ -41,7 +42,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Order
@AutoConfiguration
@AllArgsConstructor
-@EnableConfigurationProperties({BladeSecureProperties.class})
+@EnableConfigurationProperties({BladeSecureProperties.class, BladeTokenProperties.class})
public class SecureConfiguration implements WebMvcConfigurer {
private final SecureRegistry secureRegistry;
diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/props/BladeTokenProperties.java b/blade-core-secure/src/main/java/org/springblade/core/secure/props/BladeTokenProperties.java
new file mode 100644
index 0000000..c2104bc
--- /dev/null
+++ b/blade-core-secure/src/main/java/org/springblade/core/secure/props/BladeTokenProperties.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.secure.props;
+
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.core.launch.constant.TokenConstant;
+import org.springblade.core.tool.utils.StringPool;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * secure放行额外配置
+ *
+ * @author Chill
+ */
+@Slf4j
+@Data
+@ConfigurationProperties("blade.token")
+public class BladeTokenProperties {
+
+ /**
+ * token签名
+ */
+ private String signKey = StringPool.EMPTY;
+
+ /**
+ * 获取签名规则
+ */
+ public String getSignKey() {
+ if (this.signKey.length() < TokenConstant.SIGN_KEY_LENGTH) {
+ log.warn("Token已启用默认签名,请前往blade.token.sign-key设置32位的key");
+ return TokenConstant.SIGN_KEY;
+ }
+ return this.signKey;
+ }
+
+}
diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/utils/AuthUtil.java b/blade-core-secure/src/main/java/org/springblade/core/secure/utils/AuthUtil.java
new file mode 100644
index 0000000..fe7205f
--- /dev/null
+++ b/blade-core-secure/src/main/java/org/springblade/core/secure/utils/AuthUtil.java
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.secure.utils;
+
+/**
+ * Secure工具类
+ *
+ * @author Chill
+ */
+public class AuthUtil extends SecureUtil{
+
+}
diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/utils/SecureUtil.java b/blade-core-secure/src/main/java/org/springblade/core/secure/utils/SecureUtil.java
index e904e60..053bdc2 100644
--- a/blade-core-secure/src/main/java/org/springblade/core/secure/utils/SecureUtil.java
+++ b/blade-core-secure/src/main/java/org/springblade/core/secure/utils/SecureUtil.java
@@ -25,6 +25,7 @@ import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.TokenInfo;
import org.springblade.core.secure.constant.SecureConstant;
import org.springblade.core.secure.exception.SecureException;
+import org.springblade.core.secure.props.BladeTokenProperties;
import org.springblade.core.secure.provider.IClientDetails;
import org.springblade.core.secure.provider.IClientDetailsService;
import org.springblade.core.tool.constant.RoleConstant;
@@ -54,12 +55,45 @@ public class SecureUtil {
private final static String TENANT_ID = TokenConstant.TENANT_ID;
private final static String CLIENT_ID = TokenConstant.CLIENT_ID;
private final static Integer AUTH_LENGTH = TokenConstant.AUTH_LENGTH;
- private static final String BASE64_SECURITY = Base64.getEncoder().encodeToString(TokenConstant.SIGN_KEY.getBytes(Charsets.UTF_8));
+ private static IClientDetailsService CLIENT_DETAILS_SERVICE;
+ private static BladeTokenProperties TOKEN_PROPERTIES;
+ private static String BASE64_SECURITY;
- private static final IClientDetailsService clientDetailsService;
- static {
- clientDetailsService = SpringUtil.getBean(IClientDetailsService.class);
+ /**
+ * 获取客户端服务类
+ *
+ * @return clientDetailsService
+ */
+ private static IClientDetailsService getClientDetailsService() {
+ if (CLIENT_DETAILS_SERVICE == null) {
+ CLIENT_DETAILS_SERVICE = SpringUtil.getBean(IClientDetailsService.class);
+ }
+ return CLIENT_DETAILS_SERVICE;
+ }
+
+ /**
+ * 获取配置类
+ *
+ * @return jwtProperties
+ */
+ private static BladeTokenProperties getTokenProperties() {
+ if (TOKEN_PROPERTIES == null) {
+ TOKEN_PROPERTIES = SpringUtil.getBean(BladeTokenProperties.class);
+ }
+ return TOKEN_PROPERTIES;
+ }
+
+ /**
+ * 获取Token签名
+ *
+ * @return String
+ */
+ private static String getBase64Security() {
+ if (BASE64_SECURITY == null) {
+ BASE64_SECURITY = Base64.getEncoder().encodeToString(getTokenProperties().getSignKey().getBytes(Charsets.UTF_8));
+ }
+ return BASE64_SECURITY;
}
/**
@@ -301,7 +335,7 @@ public class SecureUtil {
public static Claims parseJWT(String jsonWebToken) {
try {
return Jwts.parserBuilder()
- .setSigningKey(Base64.getDecoder().decode(BASE64_SECURITY)).build()
+ .setSigningKey(Base64.getDecoder().decode(getBase64Security())).build()
.parseClaimsJws(jsonWebToken).getBody();
} catch (Exception ex) {
return null;
@@ -338,7 +372,7 @@ public class SecureUtil {
Date now = new Date(nowMillis);
//生成签名密钥
- byte[] apiKeySecretBytes = Base64.getDecoder().decode(BASE64_SECURITY);
+ byte[] apiKeySecretBytes = Base64.getDecoder().decode(getBase64Security());
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
//添加构成JWT的类
@@ -434,7 +468,7 @@ public class SecureUtil {
* @return clientDetails
*/
private static IClientDetails clientDetails(String clientId) {
- return clientDetailsService.loadClientByClientId(clientId);
+ return getClientDetailsService().loadClientByClientId(clientId);
}
/**
diff --git a/blade-core-social/pom.xml b/blade-core-social/pom.xml
index 2072104..bf1637f 100644
--- a/blade-core-social/pom.xml
+++ b/blade-core-social/pom.xml
@@ -5,7 +5,7 @@
blade-tool
org.springblade
- 3.4.1
+ 3.5.0
4.0.0
@@ -32,5 +32,4 @@
httpclient
-
diff --git a/blade-core-swagger/pom.xml b/blade-core-swagger/pom.xml
index 7f50c3d..814dc05 100644
--- a/blade-core-swagger/pom.xml
+++ b/blade-core-swagger/pom.xml
@@ -5,7 +5,7 @@
blade-tool
org.springblade
- 3.4.1
+ 3.5.0
4.0.0
diff --git a/blade-core-swagger/src/main/java/org/springblade/core/swagger/SwaggerProperties.java b/blade-core-swagger/src/main/java/org/springblade/core/swagger/SwaggerProperties.java
index 30bf3cf..25042fc 100644
--- a/blade-core-swagger/src/main/java/org/springblade/core/swagger/SwaggerProperties.java
+++ b/blade-core-swagger/src/main/java/org/springblade/core/swagger/SwaggerProperties.java
@@ -55,7 +55,7 @@ public class SwaggerProperties {
/**
* 版本
**/
- private String version = "3.4.1";
+ private String version = "3.5.0";
/**
* 许可证
**/
diff --git a/blade-core-test/pom.xml b/blade-core-test/pom.xml
index 4e06412..792ca47 100644
--- a/blade-core-test/pom.xml
+++ b/blade-core-test/pom.xml
@@ -5,7 +5,7 @@
org.springblade
blade-tool
- 3.4.1
+ 3.5.0
4.0.0
@@ -27,5 +27,4 @@
spring-boot-starter-test
-
diff --git a/blade-core-tool/pom.xml b/blade-core-tool/pom.xml
index ad76442..f6c4960 100644
--- a/blade-core-tool/pom.xml
+++ b/blade-core-tool/pom.xml
@@ -6,7 +6,7 @@
org.springblade
blade-tool
- 3.4.1
+ 3.5.0
4.0.0
diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/config/JacksonConfiguration.java b/blade-core-tool/src/main/java/org/springblade/core/tool/config/JacksonConfiguration.java
index 50386ae..e439b79 100644
--- a/blade-core-tool/src/main/java/org/springblade/core/tool/config/JacksonConfiguration.java
+++ b/blade-core-tool/src/main/java/org/springblade/core/tool/config/JacksonConfiguration.java
@@ -21,12 +21,14 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.AllArgsConstructor;
+import org.springblade.core.tool.jackson.BladeJacksonProperties;
import org.springblade.core.tool.jackson.BladeJavaTimeModule;
import org.springblade.core.tool.utils.DateUtil;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
@@ -45,6 +47,7 @@ import java.util.TimeZone;
@AllArgsConstructor
@ConditionalOnClass(ObjectMapper.class)
@AutoConfigureBefore(JacksonAutoConfiguration.class)
+@EnableConfigurationProperties(BladeJacksonProperties.class)
public class JacksonConfiguration {
@Primary
diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/config/MessageConfiguration.java b/blade-core-tool/src/main/java/org/springblade/core/tool/config/MessageConfiguration.java
index 1997103..17e03ef 100644
--- a/blade-core-tool/src/main/java/org/springblade/core/tool/config/MessageConfiguration.java
+++ b/blade-core-tool/src/main/java/org/springblade/core/tool/config/MessageConfiguration.java
@@ -18,6 +18,7 @@ package org.springblade.core.tool.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
+import org.springblade.core.tool.jackson.BladeJacksonProperties;
import org.springblade.core.tool.jackson.MappingApiJackson2HttpMessageConverter;
import org.springblade.core.tool.utils.Charsets;
import org.springframework.boot.autoconfigure.AutoConfiguration;
@@ -40,6 +41,7 @@ import java.util.List;
public class MessageConfiguration implements WebMvcConfigurer {
private final ObjectMapper objectMapper;
+ private final BladeJacksonProperties properties;
/**
* 使用 JACKSON 作为JSON MessageConverter
@@ -51,7 +53,7 @@ public class MessageConfiguration implements WebMvcConfigurer {
converters.add(new ByteArrayHttpMessageConverter());
converters.add(new ResourceHttpMessageConverter());
converters.add(new ResourceRegionHttpMessageConverter());
- converters.add(new MappingApiJackson2HttpMessageConverter(objectMapper));
+ converters.add(new MappingApiJackson2HttpMessageConverter(objectMapper, properties));
}
}
diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/AbstractReadWriteJackson2HttpMessageConverter.java b/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/AbstractReadWriteJackson2HttpMessageConverter.java
index f41a151..47c286a 100644
--- a/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/AbstractReadWriteJackson2HttpMessageConverter.java
+++ b/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/AbstractReadWriteJackson2HttpMessageConverter.java
@@ -36,8 +36,8 @@ import org.springframework.util.TypeUtils;
import java.io.IOException;
import java.lang.reflect.Type;
-import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -64,9 +64,9 @@ public abstract class AbstractReadWriteJackson2HttpMessageConverter extends Abst
initSsePrettyPrinter();
}
- public AbstractReadWriteJackson2HttpMessageConverter(ObjectMapper readObjectMapper, ObjectMapper writeObjectMapper, MediaType... supportedMediaTypes) {
+ public AbstractReadWriteJackson2HttpMessageConverter(ObjectMapper readObjectMapper, ObjectMapper writeObjectMapper, List supportedMediaTypes) {
this(readObjectMapper, writeObjectMapper);
- setSupportedMediaTypes(Arrays.asList(supportedMediaTypes));
+ setSupportedMediaTypes(supportedMediaTypes);
}
private void initSsePrettyPrinter() {
diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/BladeJacksonProperties.java b/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/BladeJacksonProperties.java
new file mode 100644
index 0000000..9b65bda
--- /dev/null
+++ b/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/BladeJacksonProperties.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2018-2028, DreamLu 卢春梦 (qq596392912@gmail.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.tool.jackson;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * jackson 配置
+ *
+ * @author L.cm
+ */
+@Getter
+@Setter
+@ConfigurationProperties("blade.jackson")
+public class BladeJacksonProperties {
+
+ /**
+ * 支持 MediaType text/plain,用于和 blade-api-crypto 一起使用
+ */
+ private Boolean supportTextPlain = Boolean.FALSE;
+
+}
diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/JsonUtil.java b/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/JsonUtil.java
index 8bdac8d..27da19c 100644
--- a/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/JsonUtil.java
+++ b/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/JsonUtil.java
@@ -24,10 +24,8 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.extern.slf4j.Slf4j;
-import org.springblade.core.tool.utils.DateUtil;
-import org.springblade.core.tool.utils.Exceptions;
-import org.springblade.core.tool.utils.StringPool;
-import org.springblade.core.tool.utils.StringUtil;
+import org.springblade.core.tool.utils.*;
+import org.springframework.lang.Nullable;
import java.io.IOException;
import java.io.InputStream;
@@ -268,6 +266,127 @@ public class JsonUtil {
}
}
+
+ /**
+ * 将json byte 数组反序列化成对象
+ *
+ * @param content json bytes
+ * @param valueType class
+ * @param T 泛型标记
+ * @return Bean
+ */
+ @Nullable
+ public static T readValue(@Nullable byte[] content, Class valueType) {
+ if (ObjectUtil.isEmpty(content)) {
+ return null;
+ }
+ try {
+ return getInstance().readValue(content, valueType);
+ } catch (IOException e) {
+ throw Exceptions.unchecked(e);
+ }
+ }
+
+ /**
+ * 将json反序列化成对象
+ *
+ * @param jsonString jsonString
+ * @param valueType class
+ * @param T 泛型标记
+ * @return Bean
+ */
+ @Nullable
+ public static T readValue(@Nullable String jsonString, Class valueType) {
+ if (StringUtil.isBlank(jsonString)) {
+ return null;
+ }
+ try {
+ return getInstance().readValue(jsonString, valueType);
+ } catch (IOException e) {
+ throw Exceptions.unchecked(e);
+ }
+ }
+
+ /**
+ * 将json反序列化成对象
+ *
+ * @param in InputStream
+ * @param valueType class
+ * @param T 泛型标记
+ * @return Bean
+ */
+ @Nullable
+ public static T readValue(@Nullable InputStream in, Class valueType) {
+ if (in == null) {
+ return null;
+ }
+ try {
+ return getInstance().readValue(in, valueType);
+ } catch (IOException e) {
+ throw Exceptions.unchecked(e);
+ }
+ }
+
+ /**
+ * 将json反序列化成对象
+ *
+ * @param content bytes
+ * @param typeReference 泛型类型
+ * @param T 泛型标记
+ * @return Bean
+ */
+ @Nullable
+ public static T readValue(@Nullable byte[] content, TypeReference typeReference) {
+ if (ObjectUtil.isEmpty(content)) {
+ return null;
+ }
+ try {
+ return getInstance().readValue(content, typeReference);
+ } catch (IOException e) {
+ throw Exceptions.unchecked(e);
+ }
+ }
+
+ /**
+ * 将json反序列化成对象
+ *
+ * @param jsonString jsonString
+ * @param typeReference 泛型类型
+ * @param T 泛型标记
+ * @return Bean
+ */
+ @Nullable
+ public static T readValue(@Nullable String jsonString, TypeReference typeReference) {
+ if (StringUtil.isBlank(jsonString)) {
+ return null;
+ }
+ try {
+ return getInstance().readValue(jsonString, typeReference);
+ } catch (IOException e) {
+ throw Exceptions.unchecked(e);
+ }
+ }
+
+ /**
+ * 将json反序列化成对象
+ *
+ * @param in InputStream
+ * @param typeReference 泛型类型
+ * @param T 泛型标记
+ * @return Bean
+ */
+ @Nullable
+ public static T readValue(@Nullable InputStream in, TypeReference typeReference) {
+ if (in == null) {
+ return null;
+ }
+ try {
+ return getInstance().readValue(in, typeReference);
+ } catch (IOException e) {
+ throw Exceptions.unchecked(e);
+ }
+ }
+
/**
* 将json字符串转成 JsonNode
*
diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/MappingApiJackson2HttpMessageConverter.java b/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/MappingApiJackson2HttpMessageConverter.java
index 9eb0e81..3c19cc9 100644
--- a/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/MappingApiJackson2HttpMessageConverter.java
+++ b/blade-core-tool/src/main/java/org/springblade/core/tool/jackson/MappingApiJackson2HttpMessageConverter.java
@@ -22,6 +22,8 @@ import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.lang.Nullable;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
/**
* 针对 api 服务对 android 和 ios 和 web 处理的 分读写的 jackson 处理
@@ -38,22 +40,26 @@ public class MappingApiJackson2HttpMessageConverter extends AbstractReadWriteJac
@Nullable
private String jsonPrefix;
- /**
- * Construct a new {@link MappingApiJackson2HttpMessageConverter} using default configuration
- * provided by {@link Jackson2ObjectMapperBuilder}.
- */
- public MappingApiJackson2HttpMessageConverter() {
- this(Jackson2ObjectMapperBuilder.json().build());
- }
-
/**
* Construct a new {@link MappingApiJackson2HttpMessageConverter} with a custom {@link ObjectMapper}.
* You can use {@link Jackson2ObjectMapperBuilder} to build it easily.
+ *
* @param objectMapper ObjectMapper
* @see Jackson2ObjectMapperBuilder#json()
*/
- public MappingApiJackson2HttpMessageConverter(ObjectMapper objectMapper) {
- super(objectMapper, initWriteObjectMapper(objectMapper), MediaType.APPLICATION_JSON, new MediaType("application", "*+json"));
+ public MappingApiJackson2HttpMessageConverter(ObjectMapper objectMapper, BladeJacksonProperties properties) {
+ super(objectMapper, initWriteObjectMapper(objectMapper), initMediaType(properties));
+ }
+
+ private static List initMediaType(BladeJacksonProperties properties) {
+ List supportedMediaTypes = new ArrayList<>();
+ supportedMediaTypes.add(MediaType.APPLICATION_JSON);
+ supportedMediaTypes.add(new MediaType("application", "*+json"));
+ // 支持 text 文本,用于报文签名
+ if (Boolean.TRUE.equals(properties.getSupportTextPlain())) {
+ supportedMediaTypes.add(MediaType.TEXT_PLAIN);
+ }
+ return supportedMediaTypes;
}
private static ObjectMapper initWriteObjectMapper(ObjectMapper readObjectMapper) {
diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/support/Kv.java b/blade-core-tool/src/main/java/org/springblade/core/tool/support/Kv.java
index cbd6a53..1417960 100644
--- a/blade-core-tool/src/main/java/org/springblade/core/tool/support/Kv.java
+++ b/blade-core-tool/src/main/java/org/springblade/core/tool/support/Kv.java
@@ -43,6 +43,15 @@ public class Kv extends LinkedCaseInsensitiveMap {
return new Kv();
}
+ /**
+ * 创建Kv
+ *
+ * @return Kv
+ */
+ public static Kv create() {
+ return new Kv();
+ }
+
public static HashMap newMap() {
return new HashMap<>(16);
}
diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/utils/AesUtil.java b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/AesUtil.java
index cf8116f..82d1e55 100644
--- a/blade-core-tool/src/main/java/org/springblade/core/tool/utils/AesUtil.java
+++ b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/AesUtil.java
@@ -15,73 +15,257 @@
*/
package org.springblade.core.tool.utils;
+import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.Charset;
import java.util.Arrays;
+import java.util.Objects;
/**
- * 完全兼容微信所使用的AES加密方式。
+ * 完全兼容微信所使用的AES加密工具类
* aes的key必须是256byte长(比如32个字符),可以使用AesKit.genAesKey()来生成一组key
*
* @author L.cm
*/
public class AesUtil {
- private AesUtil() {
- }
+ public static final Charset DEFAULT_CHARSET = Charsets.UTF_8;
+ /**
+ * 获取密钥
+ *
+ * @return {String}
+ */
public static String genAesKey() {
return StringUtil.random(32);
}
- public static byte[] encrypt(byte[] content, String aesTextKey) {
- return encrypt(content, aesTextKey.getBytes(Charsets.UTF_8));
- }
-
+ /**
+ * 加密
+ *
+ * @param content 文本内容
+ * @param aesTextKey 文本密钥
+ * @return byte[]
+ */
public static byte[] encrypt(String content, String aesTextKey) {
- return encrypt(content.getBytes(Charsets.UTF_8), aesTextKey.getBytes(Charsets.UTF_8));
+ return encrypt(content.getBytes(DEFAULT_CHARSET), aesTextKey);
}
- public static byte[] encrypt(String content, java.nio.charset.Charset charset, String aesTextKey) {
- return encrypt(content.getBytes(charset), aesTextKey.getBytes(Charsets.UTF_8));
+ /**
+ * 加密
+ *
+ * @param content 文本内容
+ * @param charset 编码
+ * @param aesTextKey 文本密钥
+ * @return byte[]
+ */
+ public static byte[] encrypt(String content, Charset charset, String aesTextKey) {
+ return encrypt(content.getBytes(charset), aesTextKey);
}
- public static byte[] decrypt(byte[] content, String aesTextKey) {
- return decrypt(content, aesTextKey.getBytes(Charsets.UTF_8));
+ /**
+ * 加密
+ *
+ * @param content 内容
+ * @param aesTextKey 文本密钥
+ * @return byte[]
+ */
+ public static byte[] encrypt(byte[] content, String aesTextKey) {
+ return encrypt(content, Objects.requireNonNull(aesTextKey).getBytes(DEFAULT_CHARSET));
}
- public static String decryptToStr(byte[] content, String aesTextKey) {
- return new String(decrypt(content, aesTextKey.getBytes(Charsets.UTF_8)), Charsets.UTF_8);
+ /**
+ * hex加密
+ *
+ * @param content 文本内容
+ * @param aesTextKey 文本密钥
+ * @return {String}
+ */
+ public static String encryptToHex(String content, String aesTextKey) {
+ return HexUtil.encodeToString(encrypt(content, aesTextKey));
}
- public static String decryptToStr(byte[] content, String aesTextKey, java.nio.charset.Charset charset) {
- return new String(decrypt(content, aesTextKey.getBytes(Charsets.UTF_8)), charset);
+ /**
+ * hex加密
+ *
+ * @param content 内容
+ * @param aesTextKey 文本密钥
+ * @return {String}
+ */
+ public static String encryptToHex(byte[] content, String aesTextKey) {
+ return HexUtil.encodeToString(encrypt(content, aesTextKey));
}
- public static byte[] encrypt(byte[] content, byte[] aesKey) {
- Assert.isTrue(aesKey.length == 32, "IllegalAesKey, aesKey's length must be 32");
- try {
- Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
- SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
- IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16);
- cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
- return cipher.doFinal(Pkcs7Encoder.encode(content));
- } catch (Exception e) {
- throw Exceptions.unchecked(e);
+ /**
+ * Base64加密
+ *
+ * @param content 文本内容
+ * @param aesTextKey 文本密钥
+ * @return {String}
+ */
+ public static String encryptToBase64(String content, String aesTextKey) {
+ return Base64Util.encodeToString(encrypt(content, aesTextKey));
+ }
+
+ /**
+ * Base64加密
+ *
+ * @param content 内容
+ * @param aesTextKey 文本密钥
+ * @return {String}
+ */
+ public static String encryptToBase64(byte[] content, String aesTextKey) {
+ return Base64Util.encodeToString(encrypt(content, aesTextKey));
+ }
+
+ /**
+ * hex解密
+ *
+ * @param content 文本内容
+ * @param aesTextKey 文本密钥
+ * @return {String}
+ */
+ @Nullable
+ public static String decryptFormHexToString(@Nullable String content, String aesTextKey) {
+ byte[] hexBytes = decryptFormHex(content, aesTextKey);
+ if (hexBytes == null) {
+ return null;
}
+ return new String(hexBytes, DEFAULT_CHARSET);
}
+ /**
+ * hex解密
+ *
+ * @param content 文本内容
+ * @param aesTextKey 文本密钥
+ * @return byte[]
+ */
+ @Nullable
+ public static byte[] decryptFormHex(@Nullable String content, String aesTextKey) {
+ if (StringUtil.isBlank(content)) {
+ return null;
+ }
+ return decryptFormHex(content.getBytes(DEFAULT_CHARSET), aesTextKey);
+ }
+
+ /**
+ * hex解密
+ *
+ * @param content 内容
+ * @param aesTextKey 文本密钥
+ * @return byte[]
+ */
+ public static byte[] decryptFormHex(byte[] content, String aesTextKey) {
+ return decrypt(HexUtil.decode(content), aesTextKey);
+ }
+
+ /**
+ * Base64解密
+ *
+ * @param content 文本内容
+ * @param aesTextKey 文本密钥
+ * @return {String}
+ */
+ @Nullable
+ public static String decryptFormBase64ToString(@Nullable String content, String aesTextKey) {
+ byte[] hexBytes = decryptFormBase64(content, aesTextKey);
+ if (hexBytes == null) {
+ return null;
+ }
+ return new String(hexBytes, DEFAULT_CHARSET);
+ }
+
+ /**
+ * Base64解密
+ *
+ * @param content 文本内容
+ * @param aesTextKey 文本密钥
+ * @return byte[]
+ */
+ @Nullable
+ public static byte[] decryptFormBase64(@Nullable String content, String aesTextKey) {
+ if (StringUtil.isBlank(content)) {
+ return null;
+ }
+ return decryptFormBase64(content.getBytes(DEFAULT_CHARSET), aesTextKey);
+ }
+
+ /**
+ * Base64解密
+ *
+ * @param content 内容
+ * @param aesTextKey 文本密钥
+ * @return byte[]
+ */
+ public static byte[] decryptFormBase64(byte[] content, String aesTextKey) {
+ return decrypt(Base64Util.decode(content), aesTextKey);
+ }
+
+ /**
+ * 解密
+ *
+ * @param content 内容
+ * @param aesTextKey 文本密钥
+ * @return {String}
+ */
+ public static String decryptToString(byte[] content, String aesTextKey) {
+ return new String(decrypt(content, aesTextKey), DEFAULT_CHARSET);
+ }
+
+ /**
+ * 解密
+ *
+ * @param content 内容
+ * @param aesTextKey 文本密钥
+ * @return byte[]
+ */
+ public static byte[] decrypt(byte[] content, String aesTextKey) {
+ return decrypt(content, Objects.requireNonNull(aesTextKey).getBytes(DEFAULT_CHARSET));
+ }
+
+ /**
+ * 解密
+ *
+ * @param content 内容
+ * @param aesKey 密钥
+ * @return byte[]
+ */
+ public static byte[] encrypt(byte[] content, byte[] aesKey) {
+ return aes(Pkcs7Encoder.encode(content), aesKey, Cipher.ENCRYPT_MODE);
+ }
+
+ /**
+ * 加密
+ *
+ * @param encrypted 内容
+ * @param aesKey 密钥
+ * @return byte[]
+ */
public static byte[] decrypt(byte[] encrypted, byte[] aesKey) {
+ return Pkcs7Encoder.decode(aes(encrypted, aesKey, Cipher.DECRYPT_MODE));
+ }
+
+ /**
+ * ase加密
+ *
+ * @param encrypted 内容
+ * @param aesKey 密钥
+ * @param mode 模式
+ * @return byte[]
+ */
+ private static byte[] aes(byte[] encrypted, byte[] aesKey, int mode) {
Assert.isTrue(aesKey.length == 32, "IllegalAesKey, aesKey's length must be 32");
try {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
- cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
- return Pkcs7Encoder.decode(cipher.doFinal(encrypted));
+ cipher.init(mode, keySpec, iv);
+ return cipher.doFinal(encrypted);
} catch (Exception e) {
throw Exceptions.unchecked(e);
}
@@ -90,16 +274,13 @@ public class AesUtil {
/**
* 提供基于PKCS7算法的加解密接口.
*/
- static class Pkcs7Encoder {
- static int BLOCK_SIZE = 32;
+ private static class Pkcs7Encoder {
+ private static final int BLOCK_SIZE = 32;
- static byte[] encode(byte[] src) {
+ private static byte[] encode(byte[] src) {
int count = src.length;
// 计算需要填充的位数
int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
- if (amountToPad == 0) {
- amountToPad = BLOCK_SIZE;
- }
// 获得补位所用的字符
byte pad = (byte) (amountToPad & 0xFF);
byte[] pads = new byte[amountToPad];
@@ -113,8 +294,8 @@ public class AesUtil {
return dest;
}
- static byte[] decode(byte[] decrypted) {
- int pad = (int) decrypted[decrypted.length - 1];
+ private static byte[] decode(byte[] decrypted) {
+ int pad = decrypted[decrypted.length - 1];
if (pad < 1 || pad > BLOCK_SIZE) {
pad = 0;
}
diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ClassUtil.java b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ClassUtil.java
index c08eea9..1234c0e 100644
--- a/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ClassUtil.java
+++ b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/ClassUtil.java
@@ -28,7 +28,7 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
- * 类工具类
+ * 类操作工具
*
* @author L.cm
*/
@@ -106,4 +106,24 @@ public class ClassUtil extends org.springframework.util.ClassUtils {
return AnnotatedElementUtils.findMergedAnnotation(beanType, annotationType);
}
+
+ /**
+ * 判断是否有注解 Annotation
+ *
+ * @param method Method
+ * @param annotationType 注解类
+ * @param 泛型标记
+ * @return {boolean}
+ */
+ public static boolean isAnnotated(Method method, Class annotationType) {
+ // 先找方法,再找方法上的类
+ boolean isMethodAnnotated = AnnotatedElementUtils.isAnnotated(method, annotationType);
+ if (isMethodAnnotated) {
+ return true;
+ }
+ // 获取类上面的Annotation,可能包含组合注解,故采用spring的工具类
+ Class> targetClass = method.getDeclaringClass();
+ return AnnotatedElementUtils.isAnnotated(targetClass, annotationType);
+ }
+
}
diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/utils/DesUtil.java b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/DesUtil.java
new file mode 100644
index 0000000..5e826a0
--- /dev/null
+++ b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/DesUtil.java
@@ -0,0 +1,207 @@
+/**
+ * Copyright (c) 2018-2028, DreamLu 卢春梦 (qq596392912@gmail.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.tool.utils;
+
+import org.springframework.lang.Nullable;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.DESKeySpec;
+import java.util.Objects;
+
+/**
+ * DES加解密处理工具
+ *
+ * @author L.cm
+ */
+public class DesUtil {
+ /**
+ * 数字签名,密钥算法
+ */
+ public static final String DES_ALGORITHM = "DES";
+
+ /**
+ * 生成 des 密钥
+ *
+ * @return 密钥
+ */
+ public static String genDesKey() {
+ return StringUtil.random(16);
+ }
+
+ /**
+ * DES加密
+ *
+ * @param data byte array
+ * @param password 密钥
+ * @return des hex
+ */
+ public static String encryptToHex(byte[] data, String password) {
+ return HexUtil.encodeToString(encrypt(data, password));
+ }
+
+ /**
+ * DES加密
+ *
+ * @param data 字符串内容
+ * @param password 密钥
+ * @return des hex
+ */
+ @Nullable
+ public static String encryptToHex(@Nullable String data, String password) {
+ if (StringUtil.isBlank(data)) {
+ return null;
+ }
+ byte[] dataBytes = data.getBytes(Charsets.UTF_8);
+ return encryptToHex(dataBytes, password);
+ }
+
+ /**
+ * DES解密
+ *
+ * @param data 字符串内容
+ * @param password 密钥
+ * @return des context
+ */
+ @Nullable
+ public static String decryptFormHex(@Nullable String data, String password) {
+ if (StringUtil.isBlank(data)) {
+ return null;
+ }
+ byte[] hexBytes = HexUtil.decode(data);
+ return new String(decrypt(hexBytes, password), Charsets.UTF_8);
+ }
+
+ /**
+ * DES加密
+ *
+ * @param data byte array
+ * @param password 密钥
+ * @return des hex
+ */
+ public static String encryptToBase64(byte[] data, String password) {
+ return Base64Util.encodeToString(encrypt(data, password));
+ }
+
+ /**
+ * DES加密
+ *
+ * @param data 字符串内容
+ * @param password 密钥
+ * @return des hex
+ */
+ @Nullable
+ public static String encryptToBase64(@Nullable String data, String password) {
+ if (StringUtil.isBlank(data)) {
+ return null;
+ }
+ byte[] dataBytes = data.getBytes(Charsets.UTF_8);
+ return encryptToBase64(dataBytes, password);
+ }
+
+ /**
+ * DES解密
+ *
+ * @param data 字符串内容
+ * @param password 密钥
+ * @return des context
+ */
+ public static byte[] decryptFormBase64(byte[] data, String password) {
+ byte[] dataBytes = Base64Util.decode(data);
+ return decrypt(dataBytes, password);
+ }
+
+ /**
+ * DES解密
+ *
+ * @param data 字符串内容
+ * @param password 密钥
+ * @return des context
+ */
+ @Nullable
+ public static String decryptFormBase64(@Nullable String data, String password) {
+ if (StringUtil.isBlank(data)) {
+ return null;
+ }
+ byte[] dataBytes = Base64Util.decodeFromString(data);
+ return new String(decrypt(dataBytes, password), Charsets.UTF_8);
+ }
+
+ /**
+ * DES加密
+ *
+ * @param data 内容
+ * @param desKey 密钥
+ * @return byte array
+ */
+ public static byte[] encrypt(byte[] data, byte[] desKey) {
+ return des(data, desKey, Cipher.ENCRYPT_MODE);
+ }
+
+ /**
+ * DES加密
+ *
+ * @param data 内容
+ * @param desKey 密钥
+ * @return byte array
+ */
+ public static byte[] encrypt(byte[] data, String desKey) {
+ return encrypt(data, Objects.requireNonNull(desKey).getBytes(Charsets.UTF_8));
+ }
+
+ /**
+ * DES解密
+ *
+ * @param data 内容
+ * @param desKey 密钥
+ * @return byte array
+ */
+ public static byte[] decrypt(byte[] data, byte[] desKey) {
+ return des(data, desKey, Cipher.DECRYPT_MODE);
+ }
+
+ /**
+ * DES解密
+ *
+ * @param data 内容
+ * @param desKey 密钥
+ * @return byte array
+ */
+ public static byte[] decrypt(byte[] data, String desKey) {
+ return decrypt(data, Objects.requireNonNull(desKey).getBytes(Charsets.UTF_8));
+ }
+
+ /**
+ * DES加密/解密公共方法
+ *
+ * @param data byte数组
+ * @param desKey 密钥
+ * @param mode 加密:{@link Cipher#ENCRYPT_MODE},解密:{@link Cipher#DECRYPT_MODE}
+ * @return des
+ */
+ private static byte[] des(byte[] data, byte[] desKey, int mode) {
+ try {
+ SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM);
+ Cipher cipher = Cipher.getInstance(DES_ALGORITHM);
+ DESKeySpec desKeySpec = new DESKeySpec(desKey);
+ cipher.init(mode, keyFactory.generateSecret(desKeySpec), Holder.SECURE_RANDOM);
+ return cipher.doFinal(data);
+ } catch (Exception e) {
+ throw Exceptions.unchecked(e);
+ }
+ }
+
+}
diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/utils/HexUtil.java b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/HexUtil.java
new file mode 100644
index 0000000..c2b3c4a
--- /dev/null
+++ b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/HexUtil.java
@@ -0,0 +1,163 @@
+/**
+ * Copyright (c) 2018-2028, DreamLu 卢春梦 (qq596392912@gmail.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.tool.utils;
+
+import org.springframework.lang.Nullable;
+
+import java.nio.charset.Charset;
+
+/**
+ * hex 工具,编解码全用 byte
+ *
+ * @author L.cm
+ */
+public class HexUtil {
+ public static final Charset DEFAULT_CHARSET = Charsets.UTF_8;
+ private static final byte[] DIGITS_LOWER = new byte[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+ private static final byte[] DIGITS_UPPER = new byte[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+ /**
+ * encode Hex
+ *
+ * @param data data to hex
+ * @return hex bytes
+ */
+ public static byte[] encode(byte[] data) {
+ return encode(data, true);
+ }
+
+ /**
+ * encode Hex
+ *
+ * @param data data to hex
+ * @param toLowerCase 是否小写
+ * @return hex bytes
+ */
+ public static byte[] encode(byte[] data, boolean toLowerCase) {
+ return encode(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
+ }
+
+ /**
+ * encode Hex
+ *
+ * @param data Data to Hex
+ * @return bytes as a hex string
+ */
+ private static byte[] encode(byte[] data, byte[] digits) {
+ int len = data.length;
+ byte[] out = new byte[len << 1];
+ for (int i = 0, j = 0; i < len; i++) {
+ out[j++] = digits[(0xF0 & data[i]) >>> 4];
+ out[j++] = digits[0xF & data[i]];
+ }
+ return out;
+ }
+
+ /**
+ * encode Hex
+ *
+ * @param data Data to Hex
+ * @param toLowerCase 是否小写
+ * @return bytes as a hex string
+ */
+ public static String encodeToString(byte[] data, boolean toLowerCase) {
+ return new String(encode(data, toLowerCase), DEFAULT_CHARSET);
+ }
+
+ /**
+ * encode Hex
+ *
+ * @param data Data to Hex
+ * @return bytes as a hex string
+ */
+ public static String encodeToString(byte[] data) {
+ return new String(encode(data), DEFAULT_CHARSET);
+ }
+
+ /**
+ * encode Hex
+ *
+ * @param data Data to Hex
+ * @return bytes as a hex string
+ */
+ @Nullable
+ public static String encodeToString(@Nullable String data) {
+ if (StringUtil.isBlank(data)) {
+ return null;
+ }
+ return encodeToString(data.getBytes(DEFAULT_CHARSET));
+ }
+
+ /**
+ * decode Hex
+ *
+ * @param data Hex data
+ * @return decode hex to bytes
+ */
+ @Nullable
+ public static byte[] decode(@Nullable String data) {
+ if (StringUtil.isBlank(data)) {
+ return null;
+ }
+ return decode(data.getBytes(DEFAULT_CHARSET));
+ }
+
+ /**
+ * encode Hex
+ *
+ * @param data Data to Hex
+ * @return bytes as a hex string
+ */
+ @Nullable
+ public static String decodeToString(@Nullable String data) {
+ byte[] decodeBytes = decode(data);
+ if (decodeBytes == null) {
+ return null;
+ }
+ return new String(decodeBytes, DEFAULT_CHARSET);
+ }
+
+ /**
+ * decode Hex
+ *
+ * @param data Hex data
+ * @return decode hex to bytes
+ */
+ public static byte[] decode(byte[] data) {
+ int len = data.length;
+ if ((len & 0x01) != 0) {
+ throw new IllegalArgumentException("hexBinary needs to be even-length: " + len);
+ }
+ byte[] out = new byte[len >> 1];
+ for (int i = 0, j = 0; j < len; i++) {
+ int f = toDigit(data[j], j) << 4;
+ j++;
+ f |= toDigit(data[j], j);
+ j++;
+ out[i] = (byte) (f & 0xFF);
+ }
+ return out;
+ }
+
+ private static int toDigit(byte b, int index) {
+ int digit = Character.digit(b, 16);
+ if (digit == -1) {
+ throw new IllegalArgumentException("Illegal hexadecimal byte " + b + " at index " + index);
+ }
+ return digit;
+ }
+
+}
diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Holder.java b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Holder.java
new file mode 100644
index 0000000..fcb8d22
--- /dev/null
+++ b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/Holder.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2018-2028, DreamLu 卢春梦 (qq596392912@gmail.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springblade.core.tool.utils;
+
+import java.security.SecureRandom;
+import java.util.Random;
+
+/**
+ * 一些常用的单利对象
+ *
+ * @author L.cm
+ */
+public class Holder {
+
+ /**
+ * RANDOM
+ */
+ public final static Random RANDOM = new Random();
+
+ /**
+ * SECURE_RANDOM
+ */
+ public final static SecureRandom SECURE_RANDOM = new SecureRandom();
+}
diff --git a/blade-core-transaction/pom.xml b/blade-core-transaction/pom.xml
index b6e089f..353deab 100644
--- a/blade-core-transaction/pom.xml
+++ b/blade-core-transaction/pom.xml
@@ -5,7 +5,7 @@
blade-tool
org.springblade
- 3.4.1
+ 3.5.0
4.0.0
diff --git a/pom.xml b/pom.xml
index 53a0339..8634417 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springblade
blade-tool
- 3.4.1
+ 3.5.0
pom
blade-tool
@@ -36,7 +36,7 @@
- 3.4.1
+ 3.5.0
1.8
3.8.1
@@ -80,6 +80,7 @@
blade-core-transaction
blade-core-report
blade-core-datascope
+ blade-core-crypto