Project Init

This commit is contained in:
haokai
2022-12-06 14:13:42 +08:00
commit bd4fd59121
57 changed files with 3633 additions and 0 deletions

65
.gitignore vendored Normal file
View File

@@ -0,0 +1,65 @@
/target/
!.mvn/wrapper/maven-wrapper.jar
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
*/.settings/
.DS_Store
*/.idea/
### NetBeans ###
/nbproject/private/
/build/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
#*.jar
*.war
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
# dev
# logserver-web/src/main/**/dev.properties
# logserver-web.src.resources.filters.dev.properties
logserver-web/src/test/
# Intellij
*.iml
### Maven template
target/

4
Dockerfile Normal file
View File

@@ -0,0 +1,4 @@
FROM registry.cn-hangzhou.aliyuncs.com/xhzy/tomcat8:1.0.0
COPY groot-meta-web/target/groot-meta.war /home/admin/tomcat/webapps/ROOT.war
ENV spring.config.location classpath:/,optional:file:/etc/shaman/static.properties,optional:classpath:/config/,optional:file:./,optional:file:./config/
CMD ["tomcat/bin/catalina.sh", "run"]

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.shuwen.groot</groupId>
<artifactId>groot-data-bank</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>groot-data-bank-api</artifactId>
<dependencies>
<!-- tools start -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- tools end -->
</dependencies>
</project>

View File

@@ -0,0 +1,29 @@
package com.shuwen.groot.api.dto;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:50
*/
@Getter
@Setter
public abstract class AbstractRequest implements Serializable {
/**
* 请求ID
*/
private String requestId;
/**
* 调用方标识
*/
private String appId;
/**
* 用户ID
*/
private String userId;
}

View File

@@ -0,0 +1,87 @@
package com.shuwen.groot.api.dto;
import com.alibaba.fastjson.JSON;
import com.shuwen.groot.api.enums.ErrorCode;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:50
*/
@Getter
@Setter
public class Response<T> implements Serializable {
/**
* 请求ID
*/
protected String requestId;
/**
* 是否成功
*/
protected Boolean success;
/**
* 错误码
*/
protected String code;
/**
* 错误信息
*/
protected String msg;
/**
* 详细返回结果
*/
protected T data;
public Response() {
}
public Response(String requestId, ErrorCode errorCode, String msg) {
this(requestId, errorCode, msg, null);
}
public Response(String requestId, ErrorCode errorCode, String msg, T data) {
this(requestId, errorCode == ErrorCode.PROCESS_SUCCESS, errorCode.getId(), msg, data);
}
public Response(String requestId, Boolean success, String code, String msg, T data) {
this.requestId = requestId;
this.success = success;
this.code = code;
this.msg = msg;
this.data = data;
}
public static <T> Response<T> succeed() {
return new Response<>(null, ErrorCode.PROCESS_SUCCESS, "处理成功");
}
public static <T> Response<T> succeed(String requestId) {
return new Response<>(requestId, ErrorCode.PROCESS_SUCCESS, "处理成功");
}
public static <T> Response<T> succeed(T data) {
return new Response<>(null, ErrorCode.PROCESS_SUCCESS, "处理成功", data);
}
public static <T> Response<T> succeed(String requestId, T data) {
return new Response<>(requestId, ErrorCode.PROCESS_SUCCESS, "处理成功", data);
}
public static <T> Response<T> fail(ErrorCode errorCode, String msg) {
return new Response<>(null, errorCode, msg);
}
public static <T> Response<T> fail(String requestId, ErrorCode errorCode, String msg) {
return new Response<>(requestId, errorCode, msg);
}
@Override
public String toString() {
return JSON.toJSONString(this);
}
}

View File

@@ -0,0 +1,24 @@
package com.shuwen.groot.api.dto.request;
import com.shuwen.groot.api.dto.AbstractRequest;
import lombok.Getter;
import lombok.Setter;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:56
*/
@Getter
@Setter
public class DeleteMaterialRequest extends AbstractRequest {
/**
* 素材ID
*/
private String id;
/**
* 所属图谱
*/
private String graph;
}

View File

@@ -0,0 +1,33 @@
package com.shuwen.groot.api.dto.request;
import com.shuwen.groot.api.dto.AbstractRequest;
import lombok.Getter;
import lombok.Setter;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:56
*/
@Getter
@Setter
public class UpdateMaterialRequest extends AbstractRequest {
/**
* 素材ID
*/
private String id;
/**
* 素材名称
*/
private String name;
/**
* 素材内容
*/
private String content = "#content";
/**
* 所属图谱
*/
private String graph;
}

View File

@@ -0,0 +1,45 @@
package com.shuwen.groot.api.dto.request;
import com.shuwen.groot.api.dto.AbstractRequest;
import com.shuwen.groot.api.enums.MaterialType;
import lombok.Getter;
import lombok.Setter;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:56
*/
@Getter
@Setter
public class UploadMaterialRequest extends AbstractRequest {
/**
* 素材名称
*/
private String name;
/**
* 素材URL地址
*/
private String url;
/**
* 素材内容
*/
private String content;
/**
* 素材缩略图地址
*/
private String cover;
/**
* 素材类型
*/
private MaterialType type;
/**
* 素材来源
*/
private String source;
/**
* 所属图谱
*/
private String graph;
}

View File

@@ -0,0 +1,57 @@
package com.shuwen.groot.api.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Created on 2020/4/9
*
* @author Kenn
*/
@Getter
@AllArgsConstructor
public enum ErrorCode {
/**
* 处理成功
*/
PROCESS_SUCCESS("PO-10000"),
/**
* 参数为空
*/
EMPTY_PARAMS("PO-10001"),
/**
* 参数错误
*/
PARAMS_ERROR("PO-10002"),
/**
* 数据已存在
*/
EXISTED("PO-10003"),
/**
* 数据不存在
*/
ABSENT("PO-10004"),
/**
* 内部错误
*/
INTERNAL_ERROR("PO-10005"),
/**
* 不支持错误
*/
NOT_SUPPORTED("PO-10006"),
/**
* 无效数据
*/
INVALID("PO-10007"),
/**
* 其他异常
*/
OTHER_ERROR("PO-50000");
private final String id;
@Override
public String toString() {
return id;
}
}

View File

@@ -0,0 +1,26 @@
package com.shuwen.groot.api.enums;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 17:20
*/
public enum MaterialType {
/**
* 图片
*/
IMAGE,
/**
* 视频
*/
VIDEO,
/**
* 音频
*/
AUDIO,
/**
* 文本
*/
DOCUMENT
}

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.shuwen.groot</groupId>
<artifactId>groot-data-bank</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>groot-data-bank-common</artifactId>
<dependencies>
<dependency>
<groupId>com.shuwen.groot</groupId>
<artifactId>groot-data-bank-api</artifactId>
</dependency>
<!-- tools start -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- tools end -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,75 @@
package com.shuwen.groot.common.base;
import com.google.common.base.Strings;
import com.shuwen.groot.common.enums.InternalErrorCode;
import com.shuwen.groot.common.exception.MaterialException;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.Collection;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:50
*/
public final class Preconditions {
private Preconditions() {
}
public static void checkNotEmpty(String str, InternalErrorCode code, Object errorMessage) {
if (StringUtils.isEmpty(str)) {
throw new MaterialException(code, String.valueOf(errorMessage));
}
}
public static void checkNotEmpty(String str, InternalErrorCode code, String errorMessageTemplate, Object... errorMessageArgs) {
if (StringUtils.isEmpty(str)) {
throw new MaterialException(code, Strings.lenientFormat(errorMessageTemplate, errorMessageArgs));
}
}
public static void checkEmpty(Collection<?> coll, InternalErrorCode code, Object errorMessage) {
if (CollectionUtils.isNotEmpty(coll)) {
throw new MaterialException(code, String.valueOf(errorMessage));
}
}
public static void checkEmpty(Collection<?> coll, InternalErrorCode code, String errorMessageTemplate, Object... errorMessageArgs) {
if (CollectionUtils.isNotEmpty(coll)) {
throw new MaterialException(code, Strings.lenientFormat(errorMessageTemplate, errorMessageArgs));
}
}
public static void checkNotEmpty(Collection<?> coll, InternalErrorCode code, Object errorMessage) {
if (CollectionUtils.isEmpty(coll)) {
throw new MaterialException(code, String.valueOf(errorMessage));
}
}
public static void checkNull(Object obj, InternalErrorCode code, Object errorMessage) {
if (obj != null) {
throw new MaterialException(code, String.valueOf(errorMessage));
}
}
public static void checkNotNull(Object obj, InternalErrorCode code, Object errorMessage) {
if (obj == null) {
throw new MaterialException(code, String.valueOf(errorMessage));
}
}
public static void checkExpression(boolean expression, InternalErrorCode code, Object errorMessage) {
if (!expression) {
throw new MaterialException(code, String.valueOf(errorMessage));
}
}
public static void checkExpression(boolean expression, InternalErrorCode code, String errorMessageTemplate, Object... errorMessageArgs) {
if (!expression) {
throw new MaterialException(code, Strings.lenientFormat(errorMessageTemplate, errorMessageArgs));
}
}
}

View File

@@ -0,0 +1,62 @@
package com.shuwen.groot.common.enums;
import com.shuwen.groot.api.enums.ErrorCode;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:50
*/
@Getter
@AllArgsConstructor
public enum InternalErrorCode {
/**
* 调用正常
*/
SUCCESS(ErrorCode.PROCESS_SUCCESS),
/**
* OTS异常
*/
OSS_ERROR(ErrorCode.INTERNAL_ERROR),
/**
* 发送HTTP异常
*/
HTTP_ERROR(ErrorCode.INTERNAL_ERROR),
/**
* ES请求异常
*/
ELASTIC_ERROR(ErrorCode.INTERNAL_ERROR),
/**
* 其他错误
*/
OTHER_ERROR(ErrorCode.INTERNAL_ERROR),
/**
* 参数为空
*/
EMPTY_PARAMS(ErrorCode.EMPTY_PARAMS),
/**
* 参数错误
*/
PARAMS_ERROR(ErrorCode.PARAMS_ERROR),
/**
* 数据已存在
*/
EXISTED(ErrorCode.EXISTED),
/**
* 数据不存在
*/
ABSENT(ErrorCode.ABSENT),
/**
* 不支持操作
*/
NOT_SUPPORTED(ErrorCode.NOT_SUPPORTED),
/**
* 无效的
*/
INVALID(ErrorCode.INVALID);
private final ErrorCode code;
}

View File

@@ -0,0 +1,30 @@
package com.shuwen.groot.common.exception;
import com.shuwen.groot.common.enums.InternalErrorCode;
import lombok.Getter;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:50
*/
@Getter
public class MaterialException extends RuntimeException {
private final InternalErrorCode errorCode;
public MaterialException(InternalErrorCode errorCode) {
this.errorCode = errorCode;
}
public MaterialException(InternalErrorCode errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
public MaterialException(InternalErrorCode errorCode, String message, Throwable cause) {
super(message, cause);
this.errorCode = errorCode;
}
}

View File

@@ -0,0 +1,13 @@
package com.shuwen.groot.common.function;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:50
*/
@FunctionalInterface
public interface Procedure {
void apply();
}

View File

@@ -0,0 +1,16 @@
package com.shuwen.groot.common.utils;
import java.util.UUID;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:50
*/
public class IDUtils {
public static String getUUID() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
}

View File

@@ -0,0 +1,44 @@
package com.shuwen.groot.common.utils;
import com.shuwen.groot.common.enums.InternalErrorCode;
import com.shuwen.groot.common.exception.MaterialException;
import org.apache.commons.lang3.tuple.Pair;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:50
*/
public class OssUrlUtils {
public static Pair<String, String> extractHostPath(String requestUrl) {
String host;
String path;
try {
URL url = new URL(requestUrl);
host = url.getHost();
path = url.getPath();
return Pair.of(host, path);
} catch (MalformedURLException e) {
throw new MaterialException(InternalErrorCode.PARAMS_ERROR, "不合法的URL");
}
}
public static String extractBucket(String host) {
int index = host.indexOf(".");
return host.substring(0, index);
}
public static String extractKey(String path) {
return path.substring(1);
}
public static String extractSuffix(String key) {
int index = key.lastIndexOf(".");
return key.substring(index + 1);
}
}

View File

@@ -0,0 +1,30 @@
package com.shuwen.groot.common.utils;
import java.util.regex.Pattern;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:50
*/
public class RegExUtils {
private static final String NAME_REGEX = "^[0-9a-zA-Z_]+$";
private static final String DESC_REGEX = "[\u4e00-\u9fa5]+";
private static final String REL_NAME_REGEX = "[a-zA-Z\u4e00-\u9fa5]+";
public static boolean validateName(String name) {
return Pattern.matches(NAME_REGEX, name);
}
public static boolean validateDesc(String desc) {
return Pattern.matches(DESC_REGEX, desc);
}
public static boolean validateRelName(String desc) {
return Pattern.matches(REL_NAME_REGEX, desc);
}
}

View File

@@ -0,0 +1,25 @@
package com.shuwen.groot.common.utils;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:50
*/
public class SignUtils {
public static String sign(long timestamp, String secret) throws Exception {
String stringToSign = timestamp + "\n" + secret;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
return URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
}
}

View File

@@ -0,0 +1,27 @@
package com.shuwen.groot.common.utils;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Date;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:50
*/
public class TimeUtils {
private static final ZoneOffset ZONE_OFFSET = ZoneOffset.ofHours(8);
private static final ZoneId ZONE_ID = ZoneId.of("Asia/Shanghai");
public static LocalDateTime convert(long millisecond) {
return new Date(millisecond).toInstant().atOffset(ZONE_OFFSET).toLocalDateTime();
}
public static long convert(LocalDateTime localDateTime) {
return localDateTime.atZone(ZONE_ID).toInstant().toEpochMilli();
}
}

View File

@@ -0,0 +1,180 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.shuwen.groot</groupId>
<artifactId>groot-data-bank</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>groot-data-bank-manager</artifactId>
<dependencies>
<!-- project start -->
<dependency>
<groupId>com.shuwen.groot</groupId>
<artifactId>groot-data-bank-common</artifactId>
</dependency>
<!-- project end -->
<!-- spring boot start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- spring boot end -->
<!-- xhzy start -->
<dependency>
<groupId>com.shuwen.ops</groupId>
<artifactId>shaman-configmap</artifactId>
<exclusions>
<exclusion>
<artifactId>protobuf-java</artifactId>
<groupId>com.google.protobuf</groupId>
</exclusion>
<exclusion>
<groupId>io.kubernetes</groupId>
<artifactId>client-java-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.kubernetes</groupId>
<artifactId>client-java-api</artifactId>
<exclusions>
<exclusion>
<groupId>com.squareup.okio</groupId>
<artifactId>okio</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.shuwen.search</groupId>
<artifactId>search-proxy-api</artifactId>
</dependency>
<!-- xhzy end -->
<!-- aliyun start -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
</dependency>
<!-- aliyun end -->
<!-- service start -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-client</artifactId>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>jline</groupId>
<artifactId>jline</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
<exclusion>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- service end -->
<!-- jackson start -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- jackson end -->
<!-- tools start -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
</dependency>
<dependency>
<groupId>io.leopard</groupId>
<artifactId>javahost</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- tools end -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,34 @@
package com.shuwen.groot.manager.config;
import com.shuwen.groot.manager.constant.Constant;
import com.shuwen.search.proxy.api.service.ICrudService;
import com.shuwen.search.proxy.api.service.IFilterService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/5 15:50
*/
@Configuration
public class DubboConfig {
@DubboReference(version = "${dubbo.service.search.version}", group = "${dubbo.service.search.group}", retries = Constant.MAX_RETRY_TIME)
private ICrudService crudService;
@DubboReference(version = "${dubbo.service.search.version}", group = "${dubbo.service.search.group}", retries = Constant.MAX_RETRY_TIME)
private IFilterService filterService;
@Bean
public ICrudService crudService() {
return crudService;
}
@Bean
public IFilterService filterService() {
return filterService;
}
}

View File

@@ -0,0 +1,39 @@
package com.shuwen.groot.manager.config;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.TimeUnit;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:50
*/
@Configuration
public class OkHttpConfig {
private static final long TIMEOUT = 30L;
private static final int MAX_IDLE_CONNECTIONS = 800;
private static final long KEEP_ALIVE_DURATION = 5;
@Bean
public OkHttpClient okHttpClient(ConnectionPool pool) {
return new OkHttpClient.Builder()
.retryOnConnectionFailure(true)
.connectionPool(pool)
.connectTimeout(TIMEOUT, TimeUnit.SECONDS)
.readTimeout(TIMEOUT, TimeUnit.SECONDS)
.build();
}
@Bean
public ConnectionPool pool() {
return new ConnectionPool(MAX_IDLE_CONNECTIONS, KEEP_ALIVE_DURATION, TimeUnit.MINUTES);
}
}

View File

@@ -0,0 +1,27 @@
package com.shuwen.groot.manager.config.base;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* Project: meta-sales-manage
* Description:
* Author: Kenn
* Create: 2022/11/12 17:36
*/
@Getter
@Setter
@Component
@ConfigurationProperties(prefix = "oss")
public class OssConfig {
private String endpoint;
private String bucket;
private String ossUrl;
private String prefix;
}

View File

@@ -0,0 +1,74 @@
package com.shuwen.groot.manager.configmap;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Sets;
import com.shuwen.ops.shaman.configmap.Config;
import lombok.extern.slf4j.Slf4j;
import java.util.Set;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:50
*/
@Slf4j
public class DingAlertConfig {
private static final String DATA_ID = "ding_alert";
static {
Config.addListener(DATA_ID, DingAlertConfig::analyzeData);
}
private static synchronized void analyzeData(String configInfo) {
log.info("get ding alert config: {}", configInfo);
JSONObject config = JSONObject.parseObject(configInfo);
if (config.containsKey("alert")) {
alert = config.getBoolean("alert");
}
if (config.containsKey("biz")) {
biz = config.getString("biz");
}
if (config.containsKey("targets")) {
targets = Sets.newHashSet(config.getJSONArray("targets").toJavaList(String.class));
}
if (config.containsKey("webhook")) {
webhook = config.getString("webhook");
}
if (config.containsKey("secret")) {
secret = config.getString("secret");
}
}
private static Boolean alert;
private static String biz;
private static Set<String> targets;
private static String webhook;
private static String secret;
public static boolean alert() {
return alert != null && alert;
}
public static String biz() {
return biz;
}
public static Set<String> targets() {
return targets == null ? Sets.newHashSet() : targets;
}
public static String webhook() {
return webhook;
}
public static String secret() {
return secret;
}
}

View File

@@ -0,0 +1,14 @@
package com.shuwen.groot.manager.constant;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:50
*/
public class Constant {
public static final int INIT_RETRY_TIME = 0;
public static final int MAX_RETRY_TIME = 3;
}

View File

@@ -0,0 +1,56 @@
package com.shuwen.groot.manager.ding;
import com.google.common.collect.Lists;
import com.shuwen.groot.common.utils.SignUtils;
import com.shuwen.groot.manager.configmap.DingAlertConfig;
import com.shuwen.groot.manager.http.HttpHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:50
*/
@Slf4j
@Service
public class DingTalkNotifier {
@Resource
private HttpHandler httpHandler;
public MarkDownMessage build(String info, String graph, String type) {
MarkDownMessage message = new MarkDownMessage();
message.setTitle("groot-meta");
message.add(MarkDownMessage.getHeaderText(2, "groot-meta"));
List<String> items = Lists.newArrayList();
items.add("biz: " + DingAlertConfig.biz());
items.add("env: " + System.getenv("DEPLOY_ENV"));
items.add("graph: " + graph);
items.add("type: " + type);
items.add("alert" + info);
message.add(MarkDownMessage.getUnOrderListText(items));
message.setAtMobiles(DingAlertConfig.targets());
return message;
}
public void notify(MarkDownMessage message) {
if (DingAlertConfig.alert()) {
try {
httpHandler.doPost(url(), null, null, message.toString());
} catch (Exception e) {
log.error("can not alert message: {}", message.toString(), e);
}
}
}
private String url() throws Exception {
long timestamp = System.currentTimeMillis();
String sign = SignUtils.sign(timestamp, DingAlertConfig.secret());
return DingAlertConfig.webhook() + "&timestamp=" + timestamp + "&sign=" + sign;
}
}

View File

@@ -0,0 +1,87 @@
package com.shuwen.groot.manager.ding;
import com.alibaba.fastjson.JSON;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.Setter;
import org.apache.commons.collections4.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:50
*/
@Setter
public class MarkDownMessage {
/**
* 标题
*/
private String title;
/**
* 文本
*/
private final List<String> content = Lists.newArrayList();
/**
* 需要@的手机号
*/
private Set<String> atMobiles;
/**
* 是否@所有人
*/
private boolean isAtAll = false;
public void add(String text) {
this.content.add(text);
}
public static String getHeaderText(int headerType, String text) {
if (headerType >= 1 && headerType <= 6) {
StringBuilder numbers = new StringBuilder();
for (int i = 0; i < headerType; ++i) {
numbers.append("#");
}
return numbers + " " + text;
} else {
throw new IllegalArgumentException("headerType should be in [1, 6]");
}
}
public static String getUnOrderListText(List<String> unorderItem) {
if (unorderItem.isEmpty()) {
return "";
} else {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < unorderItem.size() - 1; ++i) {
builder.append("- ").append(unorderItem.get(i)).append("\n");
}
builder.append("- ").append(unorderItem.get(unorderItem.size() - 1));
return builder.toString();
}
}
@Override
public String toString() {
Map<String, Object> markdown = Maps.newHashMap();
markdown.put("title", this.title);
markdown.put("text", Joiner.on('\n').join(content));
Map<String, Object> items = Maps.newHashMap();
items.put("msgtype", "markdown");
items.put("markdown", markdown);
Map<String, Object> atItems = Maps.newHashMap();
if (CollectionUtils.isNotEmpty(atMobiles)) {
atItems.put("atMobiles", atMobiles);
}
atItems.put("isAtAll", isAtAll);
items.put("at", atItems);
return JSON.toJSONString(items);
}
}

View File

@@ -0,0 +1,94 @@
package com.shuwen.groot.manager.http;
import com.alibaba.fastjson.JSONObject;
import com.shuwen.groot.common.enums.InternalErrorCode;
import com.shuwen.groot.manager.constant.Constant;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Objects;
import static com.shuwen.groot.common.base.Preconditions.checkExpression;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:50
*/
@Component
public class HttpHandler {
@Resource
private OkHttpClient okHttpClient;
public String doPost(String url, JSONObject queries, JSONObject headers, String body) {
String exactUrl = url(url, queries);
if (StringUtils.isEmpty(exactUrl)) {
return null;
}
RequestBody requestBody = RequestBody.create(body, MediaType.parse("application/json; charset=utf-8"));
Request request = builder(exactUrl, headers)
.post(requestBody)
.build();
return execute(request, Constant.INIT_RETRY_TIME);
}
public String doGet(String url, JSONObject queries, JSONObject headers) {
String exactUrl = url(url, queries);
if (StringUtils.isEmpty(exactUrl)) {
return null;
}
Request request = builder(exactUrl, headers)
.build();
return execute(request, Constant.INIT_RETRY_TIME);
}
private String url(String url, JSONObject queries) {
HttpUrl httpUrl = HttpUrl.parse(url);
if (httpUrl == null) {
return null;
}
HttpUrl.Builder urlBuilder = httpUrl.newBuilder();
if (MapUtils.isNotEmpty(queries)) {
queries.forEach((key, value) -> urlBuilder.addQueryParameter(key, (String) value));
}
return urlBuilder.toString();
}
private Request.Builder builder(String url, JSONObject headers) {
Request.Builder builder = new Request.Builder().url(url);
if (MapUtils.isNotEmpty(headers)) {
headers.forEach((key, value) -> builder.addHeader(key, (String) value));
}
return builder;
}
private String execute(Request request, int retryTimes) {
Response response = null;
try {
response = okHttpClient.newCall(request).execute();
ResponseBody body = response.body();
if (body == null) {
return null;
}
return body.string();
} catch (Exception e) {
checkExpression(retryTimes < Constant.MAX_RETRY_TIME, InternalErrorCode.HTTP_ERROR, e);
return execute(request, ++retryTimes);
} finally {
if (Objects.nonNull(response)) {
response.close();
}
}
}
}

View File

@@ -0,0 +1,142 @@
package com.shuwen.groot.manager.oss;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.CopyObjectResult;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.OSSObject;
import com.shuwen.groot.common.enums.InternalErrorCode;
import com.shuwen.groot.common.exception.MaterialException;
import com.shuwen.groot.common.utils.OssUrlUtils;
import com.shuwen.groot.manager.config.base.OssConfig;
import com.shuwen.groot.manager.constant.Constant;
import com.shuwen.ops.shaman.configmap.util.ConfigMapUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Locale;
/**
* Project: meta-sales-manage
* Description:
* Author: Kenn
* Create: 2022/11/12 17:36
*/
@Slf4j
@Component
public class OssHandler {
private static final Long DURATION_SECONDS = 3600L;
private OSS oss;
private String env;
@Autowired
private OssConfig ossConfig;
public String materialUrlPrefix = "groot:";
@PostConstruct
public void init() {
this.env = System.getenv("DEPLOY_ENV");
ConfigMapUtils.processAkSkChange(s -> {
log.info("aksk is changed, need to reconstruct oss client");
if (oss != null) {
oss.shutdown();
}
oss = new OSSClientBuilder()
.build(ossConfig.getEndpoint(), ConfigMapUtils.getAk(), ConfigMapUtils.getSk());
});
materialUrlPrefix = "groot-" + (env == null ? "test:" : env.toLowerCase(Locale.ROOT) + ":");
}
public String copy(String sourceBucket, String sourceKey, String destinationKeyLatterPart) {
String destinationKey = ossConfig.getPrefix() + "/" + destinationKeyLatterPart;
copy(sourceBucket, sourceKey, ossConfig.getBucket(), destinationKey, Constant.INIT_RETRY_TIME);
return materialUrlPrefix + "/" + destinationKey;
}
public String getImageInfo(String bucket, String key) {
OSSObject ossObject = null;
try {
GetObjectRequest request = new GetObjectRequest(bucket, key);
request.setProcess("image/info");
ossObject = oss.getObject(request);
return IOUtils.toString(ossObject.getResponse().getContent(), StandardCharsets.UTF_8);
} catch (Exception e) {
log.error("get image info fail, bucket: {}, key: {}", bucket, key, e);
throw new MaterialException(InternalErrorCode.OSS_ERROR, "获取图片信息失败");
} finally {
IOUtils.closeQuietly(ossObject);
}
}
public String convert(String url) {
return url.replaceFirst(materialUrlPrefix, ossConfig.getOssUrl());
}
public String sign(String url) {
Pair<String, String> hostPath = OssUrlUtils.extractHostPath(url);
String host = hostPath.getKey();
if (!host.contains("oss-cn-hangzhou")) {
return url;
}
String bucket = OssUrlUtils.extractBucket(hostPath.getKey());
String key = OssUrlUtils.extractKey(hostPath.getValue());
return sign(bucket, key);
}
private CopyObjectResult copy(String sourceBucketName, String sourceKey, String destinationBucketName, String destinationKey, int retryTimes) {
try {
return oss.copyObject(sourceBucketName, sourceKey, destinationBucketName, destinationKey);
} catch (Exception e) {
if (retryTimes >= 3) {
log.error("can not copy object, source bucket: {}, source key: {}, destination bucket: {}, destination key: {}",
sourceBucketName, sourceKey, destinationBucketName, destinationKey, e);
throw new MaterialException(InternalErrorCode.OSS_ERROR, "oss拷贝异常");
}
return copy(sourceBucketName, sourceKey, destinationBucketName, destinationKey, ++retryTimes);
}
}
private String sign(String bucket, String key) {
Date expiration = new Date(new Date().getTime() + DURATION_SECONDS * 1000);
URL signUrl = sign(bucket, key, expiration, Constant.INIT_RETRY_TIME);
String newUrl = StringUtils.replace(signUrl.toString(), "oss-cn-hangzhou-internal", "oss-cn-hangzhou");
if (StringUtils.isNotEmpty(env) && env.equals("PROD")) {
return StringUtils.replace(newUrl, "http", "https", 1);
} else {
return newUrl;
}
}
private URL sign(String bucketName, String objectName, Date expiration, int retryTimes) {
try {
return oss.generatePresignedUrl(bucketName, objectName, expiration);
} catch (Exception e) {
if (retryTimes >= 3) {
log.error("can not sign url, bucket: {}, object: {}", bucketName, objectName, e);
throw new MaterialException(InternalErrorCode.OSS_ERROR, "OSS地址签名异常");
}
return sign(bucketName, objectName, expiration, ++retryTimes);
}
}
@PreDestroy
public void shutdown() {
if (oss != null) {
oss.shutdown();
}
}
}

View File

@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.shuwen.groot</groupId>
<artifactId>groot-data-bank</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>groot-data-bank-service</artifactId>
<dependencies>
<!-- spring boot start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<!-- spring boot end -->
<!-- project start -->
<dependency>
<groupId>com.shuwen.groot</groupId>
<artifactId>groot-data-bank-api</artifactId>
</dependency>
<dependency>
<groupId>com.shuwen.groot</groupId>
<artifactId>groot-data-bank-common</artifactId>
</dependency>
<dependency>
<groupId>com.shuwen.groot</groupId>
<artifactId>groot-data-bank-manager</artifactId>
</dependency>
<!-- project end -->
<!-- tools start -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<exclusions>
<exclusion>
<groupId>org.checkerframework</groupId>
<artifactId>checker-qual</artifactId>
</exclusion>
<exclusion>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- tools end -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,48 @@
package com.shuwen.groot.service;
import com.shuwen.groot.api.dto.request.DeleteMaterialRequest;
import com.shuwen.groot.api.dto.request.UpdateMaterialRequest;
import com.shuwen.groot.api.dto.request.UploadMaterialRequest;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:55
*/
public interface IMaterialService {
/**
* 上传素材
*
* @param request 上传请求
* @return 结果
*/
Object upload(UploadMaterialRequest request);
/**
* 更新素材
*
* @param request 更新请求
* @return 结果
*/
Object update(UpdateMaterialRequest request);
/**
* 删除素材
*
* @param request 删除请求
* @return 结果
*/
Object delete(DeleteMaterialRequest request);
/**
* 获取素材
*
* @param materialId 素材ID
* @param graph 图谱名称
* @param convertUrl 是否地址转换
* @param signUrl 是否加签
* @return 结果
*/
Object get(String materialId, String graph, boolean convertUrl, boolean signUrl);
}

View File

@@ -0,0 +1,27 @@
package com.shuwen.groot.service.dto.http;
import lombok.Getter;
import lombok.Setter;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 17:06
*/
@Getter
@Setter
public class AudioInfo {
private double audioDuration;
private int audioChannel;
private int audioSampleRate;
private int audioBitRate;
private double fileSize;
private String format;
}

View File

@@ -0,0 +1,23 @@
package com.shuwen.groot.service.dto.http;
import lombok.Getter;
import lombok.Setter;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 17:06
*/
@Getter
@Setter
public class ImageInfo {
private String format;
private double size;
private int height;
private int width;
}

View File

@@ -0,0 +1,41 @@
package com.shuwen.groot.service.dto.http;
import lombok.Getter;
import lombok.Setter;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 17:06
*/
@Getter
@Setter
public class VideoInfo {
private double videoDuration;
private int videoWidth;
private int videoHeight;
private String videoDar;
private int videoBitRate;
private int videoVoiceRate;
private int videoFps;
private double audioDuration;
private int audioChannel;
private int audioSampleRate;
private int audioBitRate;
private double fileSize;
private String format;
}

View File

@@ -0,0 +1,41 @@
package com.shuwen.groot.service.dto.material;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/3 10:44
*/
@Getter
@Setter
public class AudioMaterial extends Material {
/**
* 音频时长
*/
@JsonProperty("audio_duration")
@JSONField(name = "audio_duration")
private double audioDuration;
/**
* 音频通道
*/
@JsonProperty("audio_channel")
@JSONField(name = "audio_channel")
private int audioChannel;
/**
* 音频采样率
*/
@JsonProperty("audio_sample_rate")
@JSONField(name = "audio_sample_rate")
private int audioSampleRate;
/**
* 音频比特率
*/
@JsonProperty("audio_bit_rate")
@JSONField(name = "audio_bit_rate")
private int audioBitRate;
}

View File

@@ -0,0 +1,23 @@
package com.shuwen.groot.service.dto.material;
import lombok.Getter;
import lombok.Setter;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/3 10:45
*/
@Getter
@Setter
public class ImageMaterial extends Material{
/**
* 高
*/
private int height;
/**
* 宽
*/
private int width;
}

View File

@@ -0,0 +1,74 @@
package com.shuwen.groot.service.dto.material;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.shuwen.groot.api.enums.MaterialType;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/3 10:44
*/
@Getter
@Setter
public abstract class Material {
/**
* 素材ID
*/
private String id;
/**
* 素材类型
*/
private MaterialType type;
/**
* 素材来源
*/
private String source;
/**
* 素材名称
*/
private String name;
/**
* 素材地址
*/
private String url;
/**
* 素材封面
*/
private String cover;
/**
* 素材格式
*/
private String format;
/**
* 素材大小
*/
private double size;
/**
* 素材信息
*/
private String content;
/**
* 关联实体信息
*/
@JsonProperty("related_entity_list")
@JSONField(name = "related_entity_list")
private List<RelatedEntity> relatedEntityList;
/**
* 创建时间
*/
@JsonProperty("create_time")
@JSONField(name = "create_time")
private long createTime;
/**
* 更新时间
*/
@JsonProperty("update_time")
@JSONField(name = "update_time")
private long updateTime;
}

View File

@@ -0,0 +1,23 @@
package com.shuwen.groot.service.dto.material;
import lombok.Getter;
import lombok.Setter;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/3 11:43
*/
@Getter
@Setter
public class RelatedEntity {
/**
* 实体类型
*/
private String label;
/**
* 实体ID
*/
private String entityId;
}

View File

@@ -0,0 +1,79 @@
package com.shuwen.groot.service.dto.material;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/3 10:45
*/
@Getter
@Setter
public class VideoMaterial extends Material {
/**
* 高
*/
private int height;
/**
* 宽
*/
private int width;
/**
* 视频时长
*/
@JsonProperty("video_duration")
@JSONField(name = "video_duration")
private double videoDuration;
/**
* 视频高宽比
*/
@JsonProperty("video_dar")
@JSONField(name = "video_dar")
private String videoDar;
/**
* 视频比特率
*/
@JsonProperty("video_bit_rate")
@JSONField(name = "video_bit_rate")
private int videoBitRate;
/**
* 声速
*/
@JsonProperty("voice_rate")
@JSONField(name = "voice_rate")
private int voiceRate;
/**
* 视频每秒帧数
*/
@JsonProperty("video_fps")
@JSONField(name = "video_fps")
private int videoFps;
/**
* 音频时长
*/
@JsonProperty("audio_duration")
@JSONField(name = "audio_duration")
private double audioDuration;
/**
* 音频通道
*/
@JsonProperty("audio_channel")
@JSONField(name = "audio_channel")
private int audioChannel;
/**
* 音频采样率
*/
@JsonProperty("audio_sample_rate")
@JSONField(name = "audio_sample_rate")
private int audioSampleRate;
/**
* 音频比特率
*/
@JsonProperty("audio_bit_rate")
@JSONField(name = "audio_bit_rate")
private int audioBitRate;
}

View File

@@ -0,0 +1,164 @@
package com.shuwen.groot.service.handler;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.shuwen.groot.api.enums.MaterialType;
import com.shuwen.groot.common.enums.InternalErrorCode;
import com.shuwen.groot.common.exception.MaterialException;
import com.shuwen.groot.manager.constant.Constant;
import com.shuwen.groot.service.dto.material.AudioMaterial;
import com.shuwen.groot.service.dto.material.ImageMaterial;
import com.shuwen.groot.service.dto.material.Material;
import com.shuwen.groot.service.dto.material.VideoMaterial;
import com.shuwen.search.proxy.api.entity.base.FieldFilter;
import com.shuwen.search.proxy.api.entity.dto.common.CrudReqDto;
import com.shuwen.search.proxy.api.entity.dto.common.CrudRespDto;
import com.shuwen.search.proxy.api.entity.dto.common.FilterReqDto;
import com.shuwen.search.proxy.api.entity.dto.common.ItemsRespDto;
import com.shuwen.search.proxy.api.entity.enums.FieldFilterTypeEnum;
import com.shuwen.search.proxy.api.service.ICrudService;
import com.shuwen.search.proxy.api.service.IFilterService;
import org.apache.commons.lang3.EnumUtils;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
import java.util.Locale;
import static com.shuwen.groot.common.base.Preconditions.checkExpression;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/5 16:02
*/
@Component
public class ElasticSearchHandler {
private static final String INDEX_PROJECT = "groot-data";
private static final String MATERIAL_INDEX_GROUP_SUFFIX = "material";
private static final String MATERIAL_INDEX_TYPE = "default";
@Resource
private ICrudService crudService;
@Resource
private IFilterService filterService;
public void add(Material material, String graph) {
CrudReqDto crudReqDto = materialCrud(material.getId(), material.getType(), graph);
crudReqDto.setContent(JSON.toJSONString(material));
add(crudReqDto, Constant.INIT_RETRY_TIME);
}
public Material get(String id, String graph) {
FilterReqDto filterReqDto = new FilterReqDto();
filterReqDto.setProject(INDEX_PROJECT);
String indexGroup = graph + "_" + MATERIAL_INDEX_GROUP_SUFFIX;
filterReqDto.setIndexGroup(indexGroup);
filterReqDto.setIndex(graph + "_material_index");
FieldFilter fieldFilter = new FieldFilter("_id", FieldFilterTypeEnum.TERM, id);
filterReqDto.must(fieldFilter);
List<Object> items = filter(filterReqDto, Constant.INIT_RETRY_TIME);
if (items == null) {
return null;
}
if (items.size() != 1) {
return null;
}
JSONObject data = (JSONObject) JSON.toJSON(items.get(0));
MaterialType materialType = EnumUtils.getEnum(MaterialType.class, data.getString("type"));
switch (materialType) {
case IMAGE:
return data.toJavaObject(ImageMaterial.class);
case AUDIO:
return data.toJavaObject(AudioMaterial.class);
case VIDEO:
return data.toJavaObject(VideoMaterial.class);
default:
throw new MaterialException(InternalErrorCode.PARAMS_ERROR);
}
}
public void update(Material material, String graph) {
CrudReqDto crudReqDto = materialCrud(material.getId(), material.getType(), graph);
JSONObject content = new JSONObject()
.fluentPut("name", material.getName())
.fluentPut("content", null)
.fluentPut("update_time", material.getUpdateTime());
crudReqDto.setContent(content.toJSONString());
update(crudReqDto, Constant.INIT_RETRY_TIME);
}
public void delete(String id, MaterialType materialType, String graph) {
CrudReqDto crudReqDto = materialCrud(id, materialType, graph);
delete(crudReqDto, Constant.INIT_RETRY_TIME);
}
private CrudReqDto materialCrud(String id, MaterialType materialType, String graph) {
String indexGroup = graph + "_" + MATERIAL_INDEX_GROUP_SUFFIX;
String index = materialType.name().toLowerCase(Locale.ROOT);
CrudReqDto crudReqDto = new CrudReqDto();
crudReqDto.setProject(INDEX_PROJECT);
crudReqDto.setIndexGroup(indexGroup);
crudReqDto.setIndex(index);
crudReqDto.setType(MATERIAL_INDEX_TYPE);
crudReqDto.setId(id);
return crudReqDto;
}
private void add(CrudReqDto reqDto, int retryTimes) {
try {
CrudRespDto respDto = crudService.add(reqDto);
if (!respDto.getSucceed()) {
throw new MaterialException(InternalErrorCode.ELASTIC_ERROR, respDto.getMessage());
}
} catch (Exception e) {
checkExpression(retryTimes < Constant.MAX_RETRY_TIME, InternalErrorCode.ELASTIC_ERROR, e);
add(reqDto, ++retryTimes);
}
}
private void update(CrudReqDto reqDto, int retryTimes) {
try {
CrudRespDto respDto = crudService.update(reqDto);
if (!respDto.getSucceed()) {
throw new MaterialException(InternalErrorCode.ELASTIC_ERROR, respDto.getMessage());
}
} catch (Exception e) {
checkExpression(retryTimes < Constant.MAX_RETRY_TIME, InternalErrorCode.ELASTIC_ERROR, e);
update(reqDto, ++retryTimes);
}
}
private void delete(CrudReqDto reqDto, int retryTimes) {
try {
CrudRespDto respDto = crudService.delete(reqDto);
if (!respDto.getSucceed()) {
throw new MaterialException(InternalErrorCode.ELASTIC_ERROR, respDto.getMessage());
}
} catch (Exception e) {
checkExpression(retryTimes < Constant.MAX_RETRY_TIME, InternalErrorCode.ELASTIC_ERROR, e);
delete(reqDto, ++retryTimes);
}
}
private List<Object> filter(FilterReqDto reqDto, int retryTimes) {
try {
ItemsRespDto respDto = filterService.filter(reqDto);
if (!respDto.getSucceed()) {
throw new MaterialException(InternalErrorCode.ELASTIC_ERROR, respDto.getMessage());
}
if (respDto.getData() != null) {
return respDto.getData().getItems();
}
return null;
} catch (Exception e) {
checkExpression(retryTimes < Constant.MAX_RETRY_TIME, InternalErrorCode.ELASTIC_ERROR, e);
return filter(reqDto, ++retryTimes);
}
}
}

View File

@@ -0,0 +1,179 @@
package com.shuwen.groot.service.handler;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.shuwen.groot.common.enums.InternalErrorCode;
import com.shuwen.groot.common.exception.MaterialException;
import com.shuwen.groot.common.utils.OssUrlUtils;
import com.shuwen.groot.manager.http.HttpHandler;
import com.shuwen.groot.manager.oss.OssHandler;
import com.shuwen.groot.service.dto.http.AudioInfo;
import com.shuwen.groot.service.dto.http.ImageInfo;
import com.shuwen.groot.service.dto.http.VideoInfo;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/5 11:18
*/
@Component
public class MaterialHandler {
@Resource
private OssHandler ossHandler;
@Resource
private HttpHandler httpHandler;
@Value("${media.utils.url}")
private String mediaUtilUrl;
public String copy(String url, String id, String graph) {
Pair<String, String> hostPath = OssUrlUtils.extractHostPath(url);
String sourceBucket = OssUrlUtils.extractBucket(hostPath.getKey());
String sourceKey = OssUrlUtils.extractKey(hostPath.getValue());
String suffix = OssUrlUtils.extractSuffix(sourceKey);
String destinationKeyLatterPart = graph + "/material/" + id + "." + suffix;
return ossHandler.copy(sourceBucket, sourceKey, destinationKeyLatterPart);
}
public String copyCover(String thumb, String id, String graph) {
Pair<String, String> hostPath = OssUrlUtils.extractHostPath(thumb);
String sourceBucket = OssUrlUtils.extractBucket(hostPath.getKey());
String sourceKey = OssUrlUtils.extractKey(hostPath.getValue());
String suffix = OssUrlUtils.extractSuffix(sourceKey);
String destinationKeyLatterPart = graph + "/thumb/" + id + "." + suffix;
return ossHandler.copy(sourceBucket, sourceKey, destinationKeyLatterPart);
}
public ImageInfo getImageInfo(String url) {
Pair<String, String> hostPath = OssUrlUtils.extractHostPath(url);
String bucket = OssUrlUtils.extractBucket(hostPath.getKey());
String key = OssUrlUtils.extractKey(hostPath.getValue());
String info = ossHandler.getImageInfo(bucket, key);
if (StringUtils.isEmpty(info)) {
throw new MaterialException(InternalErrorCode.OSS_ERROR, "无法获取image信息");
}
ImageInfo imageInfo = new ImageInfo();
JSONObject infoJson = JSON.parseObject(info);
long fileSize = 0;
if (infoJson.containsKey("FileSize")) {
JSONObject valueJson = infoJson.getJSONObject("FileSize");
if (valueJson.containsKey("value")) {
fileSize = valueJson.getLong("value");
}
}
imageInfo.setSize(fileSize);
String format = null;
if (infoJson.containsKey("Format")) {
JSONObject valueJson = infoJson.getJSONObject("Format");
if (valueJson.containsKey("value")) {
format = valueJson.getString("value");
}
}
imageInfo.setFormat(format);
int height = 0;
if (infoJson.containsKey("ImageHeight")) {
JSONObject valueJson = infoJson.getJSONObject("ImageHeight");
if (valueJson.containsKey("value")) {
height = valueJson.getIntValue("value");
}
}
imageInfo.setHeight(height);
int width = 0;
if (infoJson.containsKey("ImageWidth")) {
JSONObject valueJson = infoJson.getJSONObject("ImageWidth");
if (valueJson.containsKey("value")) {
width = valueJson.getIntValue("value");
}
}
imageInfo.setWidth(width);
return imageInfo;
}
public AudioInfo getAudioInfo(String url) {
JSONObject info = getInfo(url);
if (info == null) {
throw new MaterialException(InternalErrorCode.HTTP_ERROR, "无法获取audio信息");
}
AudioInfo audioInfo = info.toJavaObject(AudioInfo.class);
Pair<String, String> hostPath = OssUrlUtils.extractHostPath(url);
String key = OssUrlUtils.extractKey(hostPath.getValue());
String suffix = OssUrlUtils.extractSuffix(key);
audioInfo.setFormat(suffix);
return audioInfo;
}
public VideoInfo getVideoInfo(String url) {
JSONObject info = getInfo(url);
if (info == null) {
throw new MaterialException(InternalErrorCode.HTTP_ERROR, "无法获取video信息");
}
VideoInfo videoInfo = info.toJavaObject(VideoInfo.class);
Pair<String, String> hostPath = OssUrlUtils.extractHostPath(url);
String key = OssUrlUtils.extractKey(hostPath.getValue());
String suffix = OssUrlUtils.extractSuffix(key);
videoInfo.setFormat(suffix);
return videoInfo;
}
public String cover(String url) {
String requestUrl = mediaUtilUrl + "/video/v5/thumb";
JSONObject queries = new JSONObject()
.fluentPut("url", url);
String req = httpHandler.doGet(requestUrl, queries, new JSONObject());
if (StringUtils.isEmpty(req)) {
throw new MaterialException(InternalErrorCode.HTTP_ERROR, "指定video截帧结果为空");
}
JSONObject response = JSON.parseObject(req);
if (!response.containsKey("code") || !response.getString("code").equals("200") || !response.containsKey("data")) {
throw new MaterialException(InternalErrorCode.HTTP_ERROR, "指定video截帧失败");
}
JSONObject data = response.getJSONObject("data");
if (!data.containsKey("out_url")) {
throw new MaterialException(InternalErrorCode.HTTP_ERROR, "指定video截帧结果为空");
}
return data.getString("out_url");
}
public String convert(String url) {
return ossHandler.convert(url);
}
public String sign(String url) {
return ossHandler.sign(url);
}
private JSONObject getInfo(String url) {
String requestUrl = mediaUtilUrl + "/video/v2/info";
JSONObject body = new JSONObject()
.fluentPut("url", url)
.fluentPut("isInternal", true);
String req = httpHandler.doPost(requestUrl, new JSONObject(), new JSONObject(), body.toJSONString());
if (StringUtils.isEmpty(req)) {
return null;
}
JSONObject response = JSON.parseObject(req);
if (!response.containsKey("code") || !response.getString("code").equals("200") || !response.containsKey("data")) {
return null;
}
return response.getJSONObject("data");
}
}

View File

@@ -0,0 +1,206 @@
package com.shuwen.groot.service.impl;
import com.shuwen.groot.api.dto.request.DeleteMaterialRequest;
import com.shuwen.groot.api.dto.request.UpdateMaterialRequest;
import com.shuwen.groot.api.dto.request.UploadMaterialRequest;
import com.shuwen.groot.api.enums.MaterialType;
import com.shuwen.groot.common.enums.InternalErrorCode;
import com.shuwen.groot.common.exception.MaterialException;
import com.shuwen.groot.service.IMaterialService;
import com.shuwen.groot.service.dto.http.AudioInfo;
import com.shuwen.groot.service.dto.http.ImageInfo;
import com.shuwen.groot.service.dto.http.VideoInfo;
import com.shuwen.groot.service.dto.material.AudioMaterial;
import com.shuwen.groot.service.dto.material.ImageMaterial;
import com.shuwen.groot.service.dto.material.Material;
import com.shuwen.groot.service.dto.material.VideoMaterial;
import com.shuwen.groot.service.handler.ElasticSearchHandler;
import com.shuwen.groot.service.handler.MaterialHandler;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.UUID;
import static com.shuwen.groot.common.base.Preconditions.checkNotEmpty;
import static com.shuwen.groot.common.base.Preconditions.checkNotNull;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 17:06
*/
@Service
public class MaterialServiceImpl implements IMaterialService {
@Resource
private MaterialHandler materialHandler;
@Resource
private ElasticSearchHandler elasticSearchHandler;
@Override
public Object upload(UploadMaterialRequest request) {
check(request);
String id = UUID.randomUUID().toString();
// 拷贝素材到素材库地址
String url = materialHandler.copy(request.getUrl(), id, request.getGraph());
Material material;
// 获取素材信息
switch (request.getType()) {
case IMAGE:
ImageInfo imageInfo = materialHandler.getImageInfo(request.getUrl());
ImageMaterial imageMaterial = new ImageMaterial();
BeanUtils.copyProperties(imageInfo, imageMaterial);
material = imageMaterial;
break;
case AUDIO:
AudioInfo audioInfo = materialHandler.getAudioInfo(request.getUrl());
AudioMaterial audioMaterial = new AudioMaterial();
BeanUtils.copyProperties(audioInfo, audioMaterial);
audioMaterial.setSize(audioInfo.getFileSize());
material = audioMaterial;
break;
case VIDEO:
VideoInfo videoInfo = materialHandler.getVideoInfo(request.getUrl());
VideoMaterial videoMaterial = new VideoMaterial();
BeanUtils.copyProperties(videoInfo, videoMaterial);
videoMaterial.setSize(videoInfo.getFileSize());
material = videoMaterial;
break;
default:
throw new MaterialException(InternalErrorCode.PARAMS_ERROR);
}
// 基本信息
material.setId(id);
material.setUrl(url);
material.setType(request.getType());
material.setSource(request.getSource());
material.setName(request.getName());
material.setContent(request.getContent());
// 获取封面
String cover = request.getCover();
if (StringUtils.isEmpty(cover)) {
if (request.getType() == MaterialType.VIDEO) {
String serviceCover = materialHandler.cover(request.getUrl());
cover = materialHandler.copyCover(serviceCover, id, request.getGraph());
} else if (request.getType() == MaterialType.IMAGE) {
cover = url;
} else if (request.getType() == MaterialType.AUDIO) {
cover = "groot-test:/meta-sales-manage/default/audio.png";
}
} else {
cover = materialHandler.copyCover(cover, id, request.getGraph());
}
material.setCover(cover);
// 实体识别
// TODO 待定
long time = System.currentTimeMillis();
material.setCreateTime(time);
material.setUpdateTime(time);
// 写入索引
elasticSearchHandler.add(material, request.getGraph());
return id;
}
@Override
public Object update(UpdateMaterialRequest request) {
check(request);
// 从ES获取素材
Material material = elasticSearchHandler.get(request.getId(), request.getGraph());
checkNotNull(material, InternalErrorCode.ABSENT, "The point material is not exist");
// 更新名称或内容
if (!StringUtils.equals(request.getName(), material.getName())) {
material.setName(request.getName());
}
if (StringUtils.isNotEmpty(request.getContent())) {
if (!StringUtils.equals(request.getContent(), "#content")) {
material.setContent(request.getContent());
}
} else {
material.setContent(null);
}
long time = System.currentTimeMillis();
material.setUpdateTime(time);
// 更新ES
elasticSearchHandler.update(material, request.getGraph());
return material.getId();
}
@Override
public Object delete(DeleteMaterialRequest request) {
check(request);
// 从ES获取素材
Material material = elasticSearchHandler.get(request.getId(), request.getGraph());
checkNotNull(material, InternalErrorCode.ABSENT, "The point material is not exist");
// 更新ES
elasticSearchHandler.delete(material.getId(), material.getType(), request.getGraph());
return material.getId();
}
@Override
public Object get(String id, String graph, boolean convertUrl, boolean signUrl) {
checkNotEmpty(id, InternalErrorCode.EMPTY_PARAMS, "The material id is empty");
checkNotEmpty(graph, InternalErrorCode.EMPTY_PARAMS, "The graph is empty");
// 从ES获取素材
Material material = elasticSearchHandler.get(id, graph);
checkNotNull(material, InternalErrorCode.ABSENT, "The point material is not exist");
// 转换素材地址和封面
if (convertUrl) {
String url = materialHandler.convert(material.getUrl());
if (signUrl) {
url = materialHandler.sign(url);
}
material.setUrl(url);
if (StringUtils.isNotEmpty(material.getCover())) {
String cover = materialHandler.convert(material.getCover());
if (signUrl) {
cover = materialHandler.sign(cover);
}
material.setCover(cover);
}
}
return material;
}
private void check(UploadMaterialRequest request) {
checkNotEmpty(request.getName(), InternalErrorCode.EMPTY_PARAMS, "The material name is empty");
checkNotEmpty(request.getUrl(), InternalErrorCode.EMPTY_PARAMS, "The material url is empty");
checkNotNull(request.getType(), InternalErrorCode.EMPTY_PARAMS, "The material type is empty");
checkNotEmpty(request.getSource(), InternalErrorCode.EMPTY_PARAMS, "The material source is empty");
checkNotEmpty(request.getGraph(), InternalErrorCode.EMPTY_PARAMS, "The graph is empty");
}
private void check(UpdateMaterialRequest request) {
checkNotEmpty(request.getId(), InternalErrorCode.EMPTY_PARAMS, "The material id is empty");
checkNotEmpty(request.getName(), InternalErrorCode.EMPTY_PARAMS, "The material name is empty");
checkNotEmpty(request.getGraph(), InternalErrorCode.EMPTY_PARAMS, "The graph is empty");
}
private void check(DeleteMaterialRequest request) {
checkNotEmpty(request.getId(), InternalErrorCode.EMPTY_PARAMS, "The material id is empty");
checkNotEmpty(request.getGraph(), InternalErrorCode.EMPTY_PARAMS, "The graph is empty");
}
}

222
groot-data-bank-web/pom.xml Normal file
View File

@@ -0,0 +1,222 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.shuwen.groot</groupId>
<artifactId>groot-data-bank</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>groot-data-bank-web</artifactId>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- project start -->
<dependency>
<groupId>com.shuwen.groot</groupId>
<artifactId>groot-data-bank-service</artifactId>
</dependency>
<!-- project end -->
<!-- spring boot start -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<!-- spring boot end -->
<!-- micrometer start -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<!-- micrometer end -->
<!-- tools start -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
</dependency>
<!-- tools end -->
<!-- test start -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.skyscreamer</groupId>
<artifactId>jsonassert</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<scope>test</scope>
</dependency>
<!-- test end -->
</dependencies>
<profiles>
<profile>
<id>offline</id>
<properties>
<activatedProperties>offline</activatedProperties>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>application*.yml</exclude>
</excludes>
</resource>
</resources>
</build>
</profile>
<profile>
<id>online</id>
<properties>
<activatedProperties>online</activatedProperties>
</properties>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>application*.yml</exclude>
<exclude>shaman-config/**</exclude>
</excludes>
</resource>
</resources>
</build>
</profile>
</profiles>
<build>
<finalName>${project.parent.artifactId}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>application.yml</include>
<include>application-${activatedProperties}.yml</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<id>enforce-dependency-convergence</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<DependencyConvergence/>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,31 @@
package com.shuwen.groot;
import com.shuwen.ops.shaman.configmap.ShamanPropertySourceFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.PropertySource;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* Created on 2020/4/9
*
* @author Kenn
*/
@EnableCaching
@EnableScheduling
@SpringBootApplication
@PropertySource(name = "k8s-app", value = "groot-meta", factory = ShamanPropertySourceFactory.class)
public class Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Application.class);
}
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}

View File

@@ -0,0 +1,32 @@
package com.shuwen.groot.controller.advice;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.google.common.base.Joiner;
import com.shuwen.groot.api.dto.Response;
import com.shuwen.groot.api.enums.ErrorCode;
import com.shuwen.groot.api.enums.MaterialType;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:50
*/
@RestControllerAdvice
public class GraphControllerAdvice {
@ExceptionHandler(InvalidFormatException.class)
public Response<Object> handlerException(InvalidFormatException e) {
Class<?> clazz = e.getTargetType();
String message;
if (clazz == MaterialType.class) {
message = String.format("Material types are only supported: %s", Joiner.on(", ").join(MaterialType.values()));
return Response.fail(ErrorCode.PARAMS_ERROR, message);
} else {
message = e.getMessage();
return Response.fail(ErrorCode.OTHER_ERROR, message);
}
}
}

View File

@@ -0,0 +1,183 @@
package com.shuwen.groot.controller.aspect;
import com.google.common.base.Splitter;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.shuwen.groot.api.dto.AbstractRequest;
import com.shuwen.groot.api.dto.Response;
import com.shuwen.groot.api.enums.ErrorCode;
import com.shuwen.groot.common.enums.InternalErrorCode;
import com.shuwen.groot.common.exception.MaterialException;
import com.shuwen.groot.common.utils.IDUtils;
import com.shuwen.groot.controller.log.AccessLogContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:50
*/
@Slf4j
@Component
@Aspect
@Order(1)
public class GlobalAspect {
private static final Set<InternalErrorCode> IGNORE_STACK_MESSAGE = Sets.newHashSet(
InternalErrorCode.EMPTY_PARAMS,
InternalErrorCode.PARAMS_ERROR,
InternalErrorCode.ABSENT,
InternalErrorCode.EXISTED,
InternalErrorCode.NOT_SUPPORTED,
InternalErrorCode.INVALID
);
@Resource
private HttpServletRequest httpServletRequest;
@SuppressWarnings("unchecked")
@Around("execution(* com.shuwen.groot.controller.core..*.*(..))")
public Object around(ProceedingJoinPoint pjd) throws Throwable {
long start = System.currentTimeMillis();
String requestId;
// 获取请求URL
String uri = httpServletRequest.getRequestURI();
// 解析URL Query Params
Map<String, Object> params = getQueryParams(httpServletRequest);
// 解析Header
Map<String, Object> headers = getHeaders(httpServletRequest);
AbstractRequest request = null;
Object[] args = pjd.getArgs();
if (args != null && args.length > 0) {
if (args[0] instanceof AbstractRequest) {
request = ((AbstractRequest) args[0]);
requestId = request.getRequestId();
if (StringUtils.isEmpty(requestId)) {
requestId = IDUtils.getUUID();
}
request.setRequestId(requestId);
} else {
requestId = IDUtils.getUUID();
}
} else {
requestId = IDUtils.getUUID();
}
Response<Object> response;
try {
Object result = pjd.proceed();
if (result == null) {
response = Response.succeed(requestId);
} else if (result instanceof Response){
response = (Response<Object>) result;
response.setRequestId(requestId);
} else {
response = Response.succeed(requestId, result);
}
AccessLogContext.log(uri, params, headers, request, response, start);
} catch (MaterialException e) {
response = handleException(requestId, uri, params, headers, request, start, e);
} catch (Exception e) {
response = handleOtherException(requestId, uri, params, headers, request, start, e);
}
return response;
}
@SuppressWarnings("UnstableApiUsage")
private Map<String, Object> getQueryParams(HttpServletRequest request) {
String queryString = request.getQueryString();
if (StringUtils.isEmpty(queryString)) {
return Maps.newHashMap();
}
return Splitter.on("&").splitToStream(queryString)
.filter(Objects::nonNull).map(paramStr -> {
if (StringUtils.isEmpty(paramStr)) {
return null;
}
String[] segments = StringUtils.split(paramStr, "=", 2);
if (segments.length == 1) {
return null;
}
String valueStr = segments[1];
if (valueStr.contains(",")) {
return Pair.of(segments[0], valueStr.split(","));
} else {
return Pair.of(segments[0], valueStr);
}
})
.filter(Objects::nonNull)
.collect(Collectors.toMap(Pair::getKey, Pair::getValue));
}
private Map<String, Object> getHeaders(HttpServletRequest request) {
Enumeration<String> enumeration = request.getHeaderNames();
Map<String, Object> headers = new LinkedHashMap<>();
while (enumeration.hasMoreElements()) {
String name = enumeration.nextElement();
List<String> values = new ArrayList<>();
Enumeration<String> valueEnum = request.getHeaders(name);
while (valueEnum.hasMoreElements()) {
String value = valueEnum.nextElement();
values.add(value);
}
if (values.size() == 0) {
continue;
}
if (values.size() == 1) {
headers.put(name, values.get(0));
} else {
headers.put(name, values);
}
}
return headers;
}
private <T extends AbstractRequest> Response<Object> handleException(String requestId, String uri, Map<String, Object> params,
Map<String, Object> headers, T request, long start, MaterialException e) {
Response<Object> response;
if (e.getErrorCode() != null) {
response = Response.fail(requestId, e.getErrorCode().getCode(), e.getMessage());
} else {
response = Response.fail(requestId, ErrorCode.INTERNAL_ERROR, e.getMessage());
}
if (IGNORE_STACK_MESSAGE.contains(e.getErrorCode())) {
log.error("graph exception, uri: {}, request id: {}, error code: {}, error message: {}", uri, response.getRequestId(),
e.getErrorCode(), e.getMessage());
AccessLogContext.log(uri, params, headers, request, response, e.getErrorCode(), e.getMessage(), start);
} else {
log.error("graph exception, uri: {}, request id: {}", uri, response.getRequestId(), e);
AccessLogContext.log(uri, params, headers, request, response, e.getErrorCode(), e, start);
}
return response;
}
private <T extends AbstractRequest> Response<Object> handleOtherException(String requestId, String uri, Map<String, Object> params,
Map<String, Object> headers, T request, long start, Exception e) {
Response<Object> response = Response.fail(requestId, ErrorCode.INTERNAL_ERROR, e.getMessage());
log.error("other exception, uri: {}, request id: {}", uri, response.getRequestId(), e);
AccessLogContext.log(uri, params, headers, request, response, InternalErrorCode.OTHER_ERROR, e, start);
return response;
}
}

View File

@@ -0,0 +1,57 @@
package com.shuwen.groot.controller.core;
import com.shuwen.groot.api.dto.request.DeleteMaterialRequest;
import com.shuwen.groot.api.dto.request.UpdateMaterialRequest;
import com.shuwen.groot.api.dto.request.UploadMaterialRequest;
import com.shuwen.groot.service.IMaterialService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:53
*/
@Slf4j
@RestController
@RequestMapping("/api/material/v1")
public class MaterialController {
@Resource
private IMaterialService materialService;
@RequestMapping(value = "/upload", produces = "application/json", method = RequestMethod.POST)
@ResponseBody
public Object upload(@RequestBody UploadMaterialRequest request) {
return materialService.upload(request);
}
@RequestMapping(value = "/update", produces = "application/json", method = RequestMethod.POST)
@ResponseBody
public Object update(@RequestBody UpdateMaterialRequest request) {
return materialService.update(request);
}
@RequestMapping(value = "/delete", produces = "application/json", method = RequestMethod.POST)
@ResponseBody
public Object delete(@RequestBody DeleteMaterialRequest request) {
return materialService.delete(request);
}
@RequestMapping(value = "/get", produces = "application/json", method = RequestMethod.GET)
@ResponseBody
public Object get(@RequestParam(value = "id") String id,
@RequestParam(value = "graph") String graph,
@RequestParam(value = "convertUrl", defaultValue = "true", required = false) boolean convertUrl,
@RequestParam(value = "signUrl", defaultValue = "true", required = false) boolean signUrl) {
return materialService.get(id, graph, convertUrl, signUrl);
}
}

View File

@@ -0,0 +1,58 @@
package com.shuwen.groot.controller.log;
import com.alibaba.fastjson.JSONObject;
import com.shuwen.groot.api.dto.AbstractRequest;
import com.shuwen.groot.api.dto.Response;
import com.shuwen.groot.common.enums.InternalErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import java.util.Map;
/**
* Project: groot-material
* Description:
* Author: Kenn
* Create: 2022/12/2 16:50
*/
@Slf4j(topic = "access")
public class AccessLogContext {
public static void log(String path, Map<String, Object> params, Map<String, Object> headers, AbstractRequest request,
Response<?> response, long start) {
JSONObject json = build(path, params, headers, request, response, start);
json.put("code", InternalErrorCode.SUCCESS);
log.info(json.toJSONString());
}
public static void log(String path, Map<String, Object> params, Map<String, Object> headers, AbstractRequest request,
Response<?> response, InternalErrorCode code, Exception e, long start) {
JSONObject json = build(path, params, headers, request, response, start);
json.put("code", code);
json.put("message", ExceptionUtils.getStackTrace(e));
log.info(json.toJSONString());
}
public static void log(String path, Map<String, Object> params, Map<String, Object> headers, AbstractRequest request,
Response<?> response, InternalErrorCode code, String message, long start) {
JSONObject json = build(path, params, headers, request, response, start);
json.put("code", code);
json.put("message", message);
log.info(json.toJSONString());
}
private static JSONObject build(String path, Map<String, Object> params, Map<String, Object> headers, AbstractRequest request,
Response<?> response, long start) {
JSONObject json = new JSONObject();
json.put("requestId", response.getRequestId());
json.put("appId", request != null ? request.getAppId() : null);
json.put("userId", request != null ? request.getUserId() : null);
json.put("path", path);
json.put("params", params);
json.put("headers", headers);
json.put("request", request);
json.put("response", response);
json.put("cost", System.currentTimeMillis() - start);
return json;
}
}

View File

@@ -0,0 +1,18 @@
package com.shuwen.groot.controller.status;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Created on 2020/4/9
*
* @author Kenn
*/
@RestController
public class StatusController {
@GetMapping("/ok")
public String ok() {
return "ok";
}
}

View File

@@ -0,0 +1,3 @@
logging:
file:
path: /Users/Kenn/Documents/logs/groot-meta

View File

@@ -0,0 +1,3 @@
logging:
file:
path: /home/admin/logs

View File

@@ -0,0 +1,43 @@
spring:
profiles:
active: @activatedProperties@
output:
ansi.enabled: detect
jackson:
default-property-inclusion: non_null
mapper:
ACCEPT_CASE_INSENSITIVE_ENUMS: true
deserialization:
READ_UNKNOWN_ENUM_VALUES_AS_NULL: true
groovy:
template:
check-template-location: false
config:
use-legacy-processing: true
main:
allow-bean-definition-overriding: true
management:
endpoint:
metrics.enabled: true
prometheus.enabled: true
endpoints:
web:
exposure.include: "*"
base-path: /
path-mapping:
prometheus: /prometheus
enabled-by-default: false
metrics:
export.prometheus.enabled: true
dubbo:
application:
id: nft-platform
name: nft-platform
protocol:
id: dubbo
name: dubbo
port: 7078
registry:
protocol: zookeeper
logging:
config: classpath:logback-spring.xml

View File

@@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="true">
<!-- 参考SpringBoot默认的logback配置增加了error日志文件 -->
<!-- org/springframework/boot/logging/logback/base.xml -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
<property name="LOG_PATH" value="${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}"/>
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN:-%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<!-- 控制台日志 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<appender name="infoFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/info.log</file>
<append>true</append>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %c{1} %L [%p] %m%n %caller{0}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/info.log.%d{yyyy-MM-dd}</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
</appender>
<appender name="errorFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/error.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %c{1} %L [%p] %m%n %caller{0}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/error.log.%d{yyyy-MM-dd}</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
</appender>
<appender name="debugFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/debug.log</file>
<append>true</append>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %c{1} %L [%p] %m%n %caller{0}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/debug.log.%d{yyyy-MM-dd}</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
</appender>
<logger name="com.shuwen.groot" additivity="true">
<appender-ref ref="debugFile"/>
<appender-ref ref="infoFile"/>
<appender-ref ref="errorFile"/>
</logger>
<appender name="accessFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/access.log</file>
<append>true</append>
<encoder>
<pattern>%m%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/access.log.%d{yyyy-MM-dd}</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
</appender>
<logger name="access" level="INFO" additivity="true">
<appender-ref ref="accessFile"/>
</logger>
<!-- CONSOLE日志开关 -->
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</configuration>

View File

@@ -0,0 +1,17 @@
server:
port: 9999
dubbo:
registry:
address: 116.62.230.200:2181,116.62.225.137:2181,116.62.227.195:2181
service:
search:
version: 2.0
group: xhzy_es_test
oss:
endpoint: oss-cn-hangzhou.aliyuncs.com
bucket: xhzy-test
ossUrl: https://xhzy-test.oss-cn-hangzhou.aliyuncs.com
prefix: groot-material
media:
utils:
url: http://test.thumb-image.shuwen.com

View File

@@ -0,0 +1,33 @@
package com.shuwen.groot;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import org.springframework.test.web.servlet.MockMvc;
/**
* Project: groot-meta
* Description:
* Author: Kenn
* Create: 2020/04/10 09:36
*/
@SpringJUnitConfig
@SpringBootTest(classes = Application.class)
@AutoConfigureMockMvc
public abstract class TestApplication {
protected static String MEDIA_TYPE = "application/json;charset=utf-8";
@Autowired
protected MockMvc mockMvc;
protected MockHttpSession session;
@BeforeEach
public void setUp() {
session = new MockHttpSession();
}
}

297
pom.xml Normal file
View File

@@ -0,0 +1,297 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.6</version>
<relativePath/>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.shuwen.groot</groupId>
<artifactId>groot-data-bank</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>groot-data-bank-api</module>
<module>groot-data-bank-common</module>
<module>groot-data-bank-service</module>
<module>groot-data-bank-manager</module>
<module>groot-data-bank-web</module>
</modules>
<distributionManagement>
<repository>
<id>private-releases</id>
<name>maven-releases</name>
<url>https://mvn.ops.xinhuazhiyun.com/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>private-snapshots</id>
<name>maven-snapshots</name>
<url>https://mvn.ops.xinhuazhiyun.com/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<aliyun.oss.version>3.15.2</aliyun.oss.version>
<dubbo.version>2.7.17</dubbo.version>
<curator.version>4.2.0</curator.version>
<zookeeper.version>3.4.14</zookeeper.version>
<lombok.version>1.18.24</lombok.version>
<fastjson.version>1.2.83</fastjson.version>
<commons.io.version>2.6</commons.io.version>
<commons.pool2.version>2.11.1</commons.pool2.version>
<commons.lang3.version>3.12.0</commons.lang3.version>
<commons.collections4.version>4.4</commons.collections4.version>
<commons.codec.version>1.15</commons.codec.version>
<guava.version>31.1-jre</guava.version>
<kotlin.version>1.5.21</kotlin.version>
<log4j2.version>2.19.0</log4j2.version>
<mockito.version>4.8.0</mockito.version>
<shuwen.configmap.version>1.0.7</shuwen.configmap.version>
<shuwen.search.version>1.1.10-SNAPSHOT</shuwen.search.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- project start -->
<dependency>
<groupId>com.shuwen.groot</groupId>
<artifactId>groot-data-bank-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.shuwen.groot</groupId>
<artifactId>groot-data-bank-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.shuwen.groot</groupId>
<artifactId>groot-data-bank-service</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.shuwen.groot</groupId>
<artifactId>groot-data-bank-manager</artifactId>
<version>${project.version}</version>
</dependency>
<!-- project end -->
<!-- xhzy start -->
<dependency>
<groupId>com.shuwen.ops</groupId>
<artifactId>shaman-configmap</artifactId>
<version>${shuwen.configmap.version}</version>
</dependency>
<dependency>
<groupId>io.kubernetes</groupId>
<artifactId>client-java-api</artifactId>
<version>1.0.0-xhzy-3</version>
</dependency>
<dependency>
<groupId>com.shuwen.search</groupId>
<artifactId>search-proxy-api</artifactId>
<version>${shuwen.search.version}</version>
</dependency>
<!-- xhzy end -->
<!-- aliyun start -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>${aliyun.oss.version}</version>
</dependency>
<!-- aliyun end -->
<!-- service start -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>${curator.version}</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>${curator.version}</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-client</artifactId>
<version>${curator.version}</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>${zookeeper.version}</version>
</dependency>
<!-- service end -->
<!-- log4j start -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j2.version}</version>
</dependency>
<!-- log4j end -->
<!-- tools start -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons.io.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>${commons.pool2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons.lang3.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>${commons.collections4.version}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons.codec.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-common</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>io.leopard</groupId>
<artifactId>javahost</artifactId>
<version>0.9.12</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.32</version>
</dependency>
<!-- tools end -->
<!-- test start -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>${mockito.version}</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>${mockito.version}</version>
</dependency>
<dependency>
<groupId>org.skyscreamer</groupId>
<artifactId>jsonassert</artifactId>
<version>1.5.0</version>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.12.10</version>
</dependency>
<!-- test end -->
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>