扫描
This commit is contained in:
@@ -98,4 +98,36 @@ COMMENT ON COLUMN x_user_file.update_time IS '修改时间';
|
||||
COMMENT ON COLUMN x_user_file.proxy_by IS '代理人';
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for x_file_risk
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS x_file_risk;
|
||||
CREATE TABLE x_file_risk (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
file_code VARCHAR(32) DEFAULT NULL,
|
||||
max_risk_level VARCHAR(2) DEFAULT NULL,
|
||||
risk_json TEXT DEFAULT NULL,
|
||||
dify_file_json TEXT DEFAULT NULL,
|
||||
deleted BOOLEAN DEFAULT FALSE,
|
||||
create_by BIGINT DEFAULT NULL,
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
update_by BIGINT DEFAULT NULL,
|
||||
update_time TIMESTAMP DEFAULT NULL,
|
||||
proxy_by BIGINT DEFAULT NULL,
|
||||
CONSTRAINT uk_file_code UNIQUE (file_code)
|
||||
);
|
||||
COMMENT ON TABLE x_file_risk IS '文件风险';
|
||||
COMMENT ON COLUMN x_file_risk.id IS '主键ID';
|
||||
COMMENT ON COLUMN x_file_risk.file_code IS '文件编码';
|
||||
COMMENT ON COLUMN x_file_risk.max_risk_level IS '最高风险等级:1重度/2中度/3轻度';
|
||||
COMMENT ON COLUMN x_file_risk.risk_json IS '风险详情JSON';
|
||||
COMMENT ON COLUMN x_file_risk.dify_file_json IS 'Dify文件上传响应JSON';
|
||||
COMMENT ON COLUMN x_file_risk.deleted IS '是否删除';
|
||||
COMMENT ON COLUMN x_file_risk.create_by IS '创建人';
|
||||
COMMENT ON COLUMN x_file_risk.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN x_file_risk.update_by IS '修改人';
|
||||
COMMENT ON COLUMN x_file_risk.update_time IS '修改时间';
|
||||
COMMENT ON COLUMN x_file_risk.proxy_by IS '代理人';
|
||||
|
||||
|
||||
|
||||
|
||||
17
db/file.sql
17
db/file.sql
@@ -48,3 +48,20 @@ CREATE TABLE `x_user_file` (
|
||||
`proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户文件';
|
||||
|
||||
CREATE TABLE `x_file_risk` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`file_code` varchar(32) DEFAULT NULL COMMENT '文件编码',
|
||||
`max_risk_level` varchar(2) DEFAULT NULL COMMENT '最高风险等级:1重度/2中度/3轻度',
|
||||
`risk_json` text DEFAULT NULL COMMENT '风险详情JSON',
|
||||
`dify_file_json` text DEFAULT NULL COMMENT 'Dify文件上传响应JSON',
|
||||
|
||||
`deleted` bit(1) DEFAULT b'0' COMMENT '是否删除',
|
||||
`create_by` bigint(20) DEFAULT NULL COMMENT '创建人',
|
||||
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` bigint(20) DEFAULT NULL COMMENT '修改人',
|
||||
`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
|
||||
`proxy_by` bigint(20) DEFAULT NULL COMMENT '代理人',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE KEY `uk_file_code` (`file_code`) USING BTREE COMMENT '文件编码唯一索引'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件风险';
|
||||
|
||||
@@ -55,7 +55,7 @@ public class ChatServiceImpl implements ChatService {
|
||||
ChatQueryDTO queryDTO = ChatQueryDTO.builder().orgId(orgId).personUserId(personUserId).status(
|
||||
ChatStatusEnum.ACTIVE.getStatus()).build();
|
||||
|
||||
return RedissonUtils.lockAndSave(getLockDTO(orgId, personUserId),
|
||||
ChatDTO chatDTO = RedissonUtils.lockAndSave(getLockDTO(orgId, personUserId),
|
||||
() -> this.find(queryDTO), () -> {
|
||||
List<OrgUserDTO> orgUserDTOs = orgUserMapper.listOrgUserDTO(
|
||||
OrgUserQueryDTO.builder().orgId(orgId).administrator(Boolean.TRUE).build());
|
||||
@@ -65,8 +65,9 @@ public class ChatServiceImpl implements ChatService {
|
||||
chat.setOrgUserId(orgUserDTOs.get(0).getUserId());
|
||||
chat.setStatus(ChatStatusEnum.ACTIVE.getStatus());
|
||||
chatMapper.saveEntity(chat);
|
||||
return chat.getId();
|
||||
return ChatMapMapper.INSTANCE.toDTO(chat);
|
||||
});
|
||||
return chatDTO.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -27,6 +27,15 @@ public interface DynamicTableMapMapper {
|
||||
DynamicTable toEntity(
|
||||
DynamicTableDTO dynamicTableDto);
|
||||
|
||||
/**
|
||||
* entity to dto
|
||||
*
|
||||
* @param dynamicTable
|
||||
* @return
|
||||
* @author sr on 2024-04-09
|
||||
*/
|
||||
DynamicTableDTO toDto(DynamicTable dynamicTable);
|
||||
|
||||
|
||||
/**
|
||||
* @param dynamicTableCreateDTO
|
||||
|
||||
@@ -53,14 +53,15 @@ public class DynamicTableServiceImpl implements DynamicTableService {
|
||||
List<DynamicTableColumnDTO> columnDTOs = dynamicTableCreateDTO.getColumnDTOs();
|
||||
checkColumn(columnDTOs);
|
||||
|
||||
return RedissonUtils.lockAndSave(getLockDTO(userId, tableType),
|
||||
DynamicTableDTO dynamicTableDTO = RedissonUtils.lockAndSave(getLockDTO(userId, tableType),
|
||||
() -> this.find(dynamicTableQueryDTO), () -> {
|
||||
DynamicTable dynamicTable =
|
||||
DynamicTableMapMapper.INSTANCE.toEntity(dynamicTableCreateDTO);
|
||||
dynamicTable.setColumnData(JsonUtils.toDefaultJsonString(columnDTOs));
|
||||
dynamicTableMapper.saveEntity(dynamicTable);
|
||||
return dynamicTable.getId();
|
||||
return DynamicTableMapMapper.INSTANCE.toDto(dynamicTable);
|
||||
});
|
||||
return dynamicTableDTO.getId();
|
||||
|
||||
// Long userId = dynamicTableCreateDTO.getUserId();
|
||||
// String tableType = dynamicTableCreateDTO.getTableType();
|
||||
|
||||
@@ -14,16 +14,25 @@ public class FileProperties {
|
||||
/** 文件上传路径 **/
|
||||
private String uploadDir;
|
||||
|
||||
/** 传输发送目录 **/
|
||||
private String transferSendDir;
|
||||
|
||||
/** 传输接收目录 **/
|
||||
private String transferReceiveDir;
|
||||
|
||||
private final Storage storage = new Storage();
|
||||
|
||||
/** 文件位置:1内网2外网 **/
|
||||
private String location;
|
||||
private final Transfer transfer = new Transfer();
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public static class Transfer {
|
||||
/** 文件位置:1内网2外网 **/
|
||||
private String location;
|
||||
|
||||
/** 传输发送目录 **/
|
||||
private String sendDir;
|
||||
|
||||
/** 传输接收目录 **/
|
||||
private String receiveDir;
|
||||
|
||||
/** 解包风险校验开关 **/
|
||||
private Boolean unpackRiskCheck = false;
|
||||
}
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
|
||||
@@ -129,4 +129,14 @@ public interface ConfigService {
|
||||
*/
|
||||
ConfigDTO getConfigDto(String code, Long orgId, boolean enable);
|
||||
|
||||
/**
|
||||
* 创建或修改配置
|
||||
* 如果配置已存在则修改,不存在则创建
|
||||
*
|
||||
* @param orgId 机构ID
|
||||
* @param configCode 配置编码
|
||||
* @param configValue 配置值
|
||||
*/
|
||||
void createOrModify(Long orgId, String configCode, String configValue);
|
||||
|
||||
}
|
||||
|
||||
@@ -154,4 +154,26 @@ public class ConfigServiceImpl implements ConfigService {
|
||||
return dto;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void createOrModify(Long orgId, String configCode, String configValue) {
|
||||
// 查询是否已存在配置
|
||||
ConfigDTO existConfig = queryOrgConfigByCode(orgId, configCode);
|
||||
|
||||
if (existConfig != null) {
|
||||
// 存在则修改
|
||||
configMapper.updateEntitySelective(
|
||||
Config.builder().id(existConfig.getId()).configValue(configValue).build());
|
||||
} else {
|
||||
// 不存在则创建
|
||||
Config config = Config.builder()
|
||||
.configCode(configCode)
|
||||
.configValue(configValue)
|
||||
.orgId(orgId)
|
||||
.enable(true)
|
||||
.build();
|
||||
configMapper.saveEntity(config);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -321,14 +321,14 @@ public class RedissonUtils {
|
||||
* @return
|
||||
* @author sr on 2024-04-18
|
||||
*/
|
||||
public static <T extends IBaseDTO> Long lockAndSave(LockDTO lockDTO, Supplier<T> existSupplier,
|
||||
Supplier<Long> saveSupplier) {
|
||||
public static <T extends IBaseDTO> T lockAndSave(LockDTO lockDTO, Supplier<T> existSupplier,
|
||||
Supplier<T> saveSupplier) {
|
||||
return lockAndSave(lockDTO, existSupplier, saveSupplier, true, null);
|
||||
}
|
||||
|
||||
|
||||
public static <T extends IBaseDTO> Long lockAndSave(LockDTO lockDTO, Supplier<T> existSupplier,
|
||||
Supplier<Long> saveSupplier, String existMsg) {
|
||||
public static <T extends IBaseDTO> T lockAndSave(LockDTO lockDTO, Supplier<T> existSupplier,
|
||||
Supplier<T> saveSupplier, String existMsg) {
|
||||
return lockAndSave(lockDTO, existSupplier, saveSupplier, true, existMsg);
|
||||
}
|
||||
|
||||
@@ -343,12 +343,12 @@ public class RedissonUtils {
|
||||
* @return
|
||||
* @author sr on 2024-04-18
|
||||
*/
|
||||
public static <T extends IBaseDTO> Long lockAndSave(LockDTO lockDTO, Supplier<T> existSupplier,
|
||||
Supplier<Long> saveSupplier, boolean hasTransaction, String existMsg) throws ExistException{
|
||||
public static <T extends IBaseDTO> T lockAndSave(LockDTO lockDTO, Supplier<T> existSupplier,
|
||||
Supplier<T> saveSupplier, boolean hasTransaction, String existMsg) throws ExistException {
|
||||
IBaseDTO baseDTO = existSupplier.get();
|
||||
if (baseDTO != null) {
|
||||
if (StringUtils.isBlank(existMsg)) {
|
||||
return baseDTO.getId();
|
||||
return (T) baseDTO;
|
||||
} else {
|
||||
throw new ExistException(existMsg);
|
||||
}
|
||||
@@ -358,7 +358,7 @@ public class RedissonUtils {
|
||||
baseDTO = existSupplier.get();
|
||||
if (baseDTO != null) {
|
||||
if (StringUtils.isBlank(existMsg)) {
|
||||
return baseDTO.getId();
|
||||
return (T) baseDTO;
|
||||
} else {
|
||||
throw new ExistException(existMsg);
|
||||
}
|
||||
|
||||
23
src/main/java/com/senmesh/sdk/dify/config/DifyConfig.java
Normal file
23
src/main/java/com/senmesh/sdk/dify/config/DifyConfig.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package com.senmesh.sdk.dify.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Dify配置
|
||||
*
|
||||
* @author sr
|
||||
*/
|
||||
@Data
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(DifyProperties.class)
|
||||
@ConditionalOnProperty(name = DifyConfig.DIFY_ENABLE, havingValue = "true")
|
||||
public class DifyConfig {
|
||||
|
||||
static final String DIFY_ENABLE = "dify.enable";
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.senmesh.sdk.dify.config;
|
||||
|
||||
import java.io.Serializable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Dify配置属性
|
||||
*
|
||||
* @author sr
|
||||
*/
|
||||
@ConfigurationProperties(prefix = DifyProperties.PREFIX)
|
||||
@Data
|
||||
@Component
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class DifyProperties implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final String PREFIX = "dify";
|
||||
|
||||
/** Dify服务地址 */
|
||||
private String host;
|
||||
|
||||
}
|
||||
|
||||
69
src/main/java/com/senmesh/sdk/dify/dto/DifyChatRequest.java
Normal file
69
src/main/java/com/senmesh/sdk/dify/dto/DifyChatRequest.java
Normal file
@@ -0,0 +1,69 @@
|
||||
package com.senmesh.sdk.dify.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Dify对话请求
|
||||
*
|
||||
* @author sr
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class DifyChatRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 输入参数 */
|
||||
private Map<String, Object> inputs;
|
||||
|
||||
/** 查询内容 */
|
||||
private String query;
|
||||
|
||||
/** 响应模式: blocking/streaming */
|
||||
@Builder.Default
|
||||
private String responseMode = "blocking";
|
||||
|
||||
/** 会话ID */
|
||||
private String conversationId;
|
||||
|
||||
/** 用户标识 */
|
||||
private String user;
|
||||
|
||||
/** 文件列表 */
|
||||
private List<DifyFileInfo> files;
|
||||
|
||||
/**
|
||||
* 文件信息
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public static class DifyFileInfo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 文件类型: image/document */
|
||||
private String type;
|
||||
|
||||
/** 传输方式: remote_url/local_file */
|
||||
@Builder.Default
|
||||
private String transferMethod = "local_file";
|
||||
|
||||
/** 远程URL */
|
||||
private String url;
|
||||
|
||||
/** 上传文件ID */
|
||||
private String uploadFileId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
144
src/main/java/com/senmesh/sdk/dify/dto/DifyChatResponse.java
Normal file
144
src/main/java/com/senmesh/sdk/dify/dto/DifyChatResponse.java
Normal file
@@ -0,0 +1,144 @@
|
||||
package com.senmesh.sdk.dify.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Dify对话响应
|
||||
*
|
||||
* @author sr
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class DifyChatResponse implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 消息ID */
|
||||
private String messageId;
|
||||
|
||||
/** 会话ID */
|
||||
private String conversationId;
|
||||
|
||||
/** 模式 */
|
||||
private String mode;
|
||||
|
||||
/** 回答内容 */
|
||||
private String answer;
|
||||
|
||||
/** 元数据 */
|
||||
private Metadata metadata;
|
||||
|
||||
/** 创建时间 */
|
||||
private Long createdAt;
|
||||
|
||||
/**
|
||||
* 元数据
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public static class Metadata implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 使用量 */
|
||||
private Usage usage;
|
||||
|
||||
/** 检索器资源 */
|
||||
private List<RetrieverResource> retrieverResources;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用量
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public static class Usage implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 提示词token数 */
|
||||
private Integer promptTokens;
|
||||
|
||||
/** 提示词单位价格 */
|
||||
private String promptUnitPrice;
|
||||
|
||||
/** 提示词价格单位 */
|
||||
private String promptPriceUnit;
|
||||
|
||||
/** 提示词价格 */
|
||||
private String promptPrice;
|
||||
|
||||
/** 完成token数 */
|
||||
private Integer completionTokens;
|
||||
|
||||
/** 完成单位价格 */
|
||||
private String completionUnitPrice;
|
||||
|
||||
/** 完成价格单位 */
|
||||
private String completionPriceUnit;
|
||||
|
||||
/** 完成价格 */
|
||||
private String completionPrice;
|
||||
|
||||
/** 总token数 */
|
||||
private Integer totalTokens;
|
||||
|
||||
/** 总价格 */
|
||||
private String totalPrice;
|
||||
|
||||
/** 货币 */
|
||||
private String currency;
|
||||
|
||||
/** 延迟(毫秒) */
|
||||
private Double latency;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检索器资源
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public static class RetrieverResource implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 位置 */
|
||||
private Integer position;
|
||||
|
||||
/** 数据集ID */
|
||||
private String datasetId;
|
||||
|
||||
/** 数据集名称 */
|
||||
private String datasetName;
|
||||
|
||||
/** 文档ID */
|
||||
private String documentId;
|
||||
|
||||
/** 文档名称 */
|
||||
private String documentName;
|
||||
|
||||
/** 分段ID */
|
||||
private String segmentId;
|
||||
|
||||
/** 分数 */
|
||||
private Double score;
|
||||
|
||||
/** 内容 */
|
||||
private String content;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.senmesh.sdk.dify.dto;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Dify文件上传请求
|
||||
*
|
||||
* @author sr
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class DifyFileUploadRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 文件输入流 */
|
||||
private InputStream inputStream;
|
||||
|
||||
/** 文件名 */
|
||||
private String fileName;
|
||||
|
||||
/** 文件MIME类型 */
|
||||
private String contentType;
|
||||
|
||||
/** 用户标识 */
|
||||
private String user;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.senmesh.sdk.dify.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Dify文件上传响应
|
||||
*
|
||||
* @author sr
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class DifyFileUploadResponse implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 文件ID */
|
||||
private String id;
|
||||
|
||||
/** 文件名 */
|
||||
private String name;
|
||||
|
||||
/** 文件大小 */
|
||||
private Long size;
|
||||
|
||||
/** 文件扩展名 */
|
||||
private String extension;
|
||||
|
||||
/** MIME类型 */
|
||||
private String mimeType;
|
||||
|
||||
/** 创建者 */
|
||||
private String createdBy;
|
||||
|
||||
/** 创建时间 */
|
||||
private Long createdAt;
|
||||
|
||||
}
|
||||
|
||||
206
src/main/java/com/senmesh/sdk/dify/service/DifyClient.java
Normal file
206
src/main/java/com/senmesh/sdk/dify/service/DifyClient.java
Normal file
@@ -0,0 +1,206 @@
|
||||
package com.senmesh.sdk.dify.service;
|
||||
|
||||
import com.senmesh.common.AlitaResult;
|
||||
import com.senmesh.common.util.JsonUtils;
|
||||
import com.senmesh.sdk.common.constant.SdkConstants;
|
||||
import com.senmesh.sdk.common.util.HttpUtils;
|
||||
import com.senmesh.sdk.dify.config.DifyProperties;
|
||||
import com.senmesh.sdk.dify.dto.DifyChatRequest;
|
||||
import com.senmesh.sdk.dify.dto.DifyChatResponse;
|
||||
import com.senmesh.sdk.dify.dto.DifyFileUploadRequest;
|
||||
import com.senmesh.sdk.dify.dto.DifyFileUploadResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* Dify客户端
|
||||
*
|
||||
* @author sr
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class DifyClient {
|
||||
|
||||
private static DifyProperties difyProperties;
|
||||
|
||||
private static final String FILE_UPLOAD_URI = "/v1/files/upload";
|
||||
private static final String CHAT_MESSAGES_URI = "/v1/chat-messages";
|
||||
|
||||
/**
|
||||
* 构造方法 - 用于Spring注入,同时设置静态变量
|
||||
*/
|
||||
@Autowired
|
||||
public DifyClient(DifyProperties difyProperties) {
|
||||
DifyClient.difyProperties = difyProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件到Dify(静态方法 - 只传apiKey)
|
||||
*
|
||||
* @param apiKey API密钥
|
||||
* @param request 文件上传请求
|
||||
* @return 上传结果
|
||||
*/
|
||||
public static AlitaResult<DifyFileUploadResponse> uploadFile(String apiKey, DifyFileUploadRequest request) {
|
||||
if (difyProperties == null) {
|
||||
return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "DifyProperties未初始化");
|
||||
}
|
||||
return uploadFile(difyProperties.getHost(), apiKey, request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件到Dify(静态方法)
|
||||
*
|
||||
* @param host Dify服务地址
|
||||
* @param apiKey API密钥
|
||||
* @param request 文件上传请求
|
||||
* @return 上传结果
|
||||
*/
|
||||
public static AlitaResult<DifyFileUploadResponse> uploadFile(String host, String apiKey, DifyFileUploadRequest request) {
|
||||
try {
|
||||
// 参数校验
|
||||
if (StringUtils.isBlank(host)) {
|
||||
return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "Dify服务地址不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(apiKey)) {
|
||||
return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "API密钥不能为空");
|
||||
}
|
||||
if (request == null || request.getInputStream() == null) {
|
||||
return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "文件输入流不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(request.getFileName())) {
|
||||
return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "文件名不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(request.getUser())) {
|
||||
return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "用户标识不能为空");
|
||||
}
|
||||
|
||||
String url = host + FILE_UPLOAD_URI;
|
||||
|
||||
// 构建请求头
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
|
||||
headers.set("Authorization", "Bearer " + apiKey);
|
||||
|
||||
// 构建请求体
|
||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||
|
||||
// 将InputStream转换为ByteArrayResource
|
||||
byte[] fileBytes = org.springframework.util.StreamUtils.copyToByteArray(request.getInputStream());
|
||||
ByteArrayResource fileResource = new ByteArrayResource(fileBytes) {
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return request.getFileName();
|
||||
}
|
||||
};
|
||||
|
||||
body.add("file", fileResource);
|
||||
body.add("user", request.getUser());
|
||||
|
||||
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
|
||||
|
||||
log.info("dify uploadFile request url:{}, user:{}, fileName:{}",
|
||||
url, request.getUser(), request.getFileName());
|
||||
|
||||
// 发送请求
|
||||
ResponseEntity<DifyFileUploadResponse> response = HttpUtils.restTemplate.exchange(
|
||||
url,
|
||||
HttpMethod.POST,
|
||||
requestEntity,
|
||||
DifyFileUploadResponse.class
|
||||
);
|
||||
|
||||
DifyFileUploadResponse result = response.getBody();
|
||||
log.info("dify uploadFile response:{}", JsonUtils.toJsonString(result));
|
||||
|
||||
return AlitaResult.success(result);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("dify uploadFile error:", e);
|
||||
return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_ERROR_CODE, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送对话消息(静态方法 - 只传apiKey)
|
||||
*
|
||||
* @param apiKey API密钥
|
||||
* @param request 对话请求
|
||||
* @return 对话结果
|
||||
*/
|
||||
public static AlitaResult<DifyChatResponse> chatMessages(String apiKey, DifyChatRequest request) {
|
||||
if (difyProperties == null) {
|
||||
return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "DifyProperties未初始化");
|
||||
}
|
||||
return chatMessages(difyProperties.getHost(), apiKey, request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送对话消息(静态方法)
|
||||
*
|
||||
* @param host Dify服务地址
|
||||
* @param apiKey API密钥
|
||||
* @param request 对话请求
|
||||
* @return 对话结果
|
||||
*/
|
||||
public static AlitaResult<DifyChatResponse> chatMessages(String host, String apiKey, DifyChatRequest request) {
|
||||
try {
|
||||
// 参数校验
|
||||
if (StringUtils.isBlank(host)) {
|
||||
return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "Dify服务地址不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(apiKey)) {
|
||||
return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "API密钥不能为空");
|
||||
}
|
||||
if (request == null) {
|
||||
return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "请求参数不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(request.getQuery())) {
|
||||
return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "查询内容不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(request.getUser())) {
|
||||
return AlitaResult.error(SdkConstants.SDK_INVOKE_NOT_REACH_CODE, "用户标识不能为空");
|
||||
}
|
||||
|
||||
String url = host + CHAT_MESSAGES_URI;
|
||||
|
||||
// 构建请求头
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.set("Authorization", "Bearer " + apiKey);
|
||||
|
||||
HttpEntity<DifyChatRequest> requestEntity = new HttpEntity<>(request, headers);
|
||||
|
||||
log.info("dify chatMessages request url:{}, body:{}", url, JsonUtils.toJsonString(request));
|
||||
|
||||
// 发送请求
|
||||
ResponseEntity<DifyChatResponse> response = HttpUtils.restTemplate.exchange(
|
||||
url,
|
||||
HttpMethod.POST,
|
||||
requestEntity,
|
||||
DifyChatResponse.class
|
||||
);
|
||||
|
||||
DifyChatResponse result = response.getBody();
|
||||
log.info("dify chatMessages response:{}", JsonUtils.toJsonString(result));
|
||||
|
||||
return AlitaResult.success(result);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("dify chatMessages error:", e);
|
||||
return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_ERROR_CODE, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
100
src/main/java/com/senmesh/sfile/constant/RiskLevelEnum.java
Normal file
100
src/main/java/com/senmesh/sfile/constant/RiskLevelEnum.java
Normal file
@@ -0,0 +1,100 @@
|
||||
package com.senmesh.sfile.constant;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.EnumValue;
|
||||
import com.senmesh.mybatis.handle.BaseEnum;
|
||||
|
||||
/**
|
||||
* 风险等级枚举
|
||||
*/
|
||||
public enum RiskLevelEnum implements BaseEnum<String> {
|
||||
|
||||
/**
|
||||
* 重度风险
|
||||
*/
|
||||
SEVERE("1", "重度"),
|
||||
|
||||
/**
|
||||
* 中度风险
|
||||
*/
|
||||
MODERATE("2", "中度"),
|
||||
|
||||
/**
|
||||
* 轻度风险
|
||||
*/
|
||||
MILD("3", "轻度");
|
||||
|
||||
/**
|
||||
* 风险等级
|
||||
*/
|
||||
@EnumValue
|
||||
private final String level;
|
||||
|
||||
/**
|
||||
* 等级描述
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
RiskLevelEnum(String level, String desc) {
|
||||
this.level = level;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public String getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return this.level;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据等级获取枚举
|
||||
*
|
||||
* @param level 等级
|
||||
* @return RiskLevelEnum
|
||||
*/
|
||||
public static RiskLevelEnum getByLevel(String level) {
|
||||
for (RiskLevelEnum riskLevelEnum : RiskLevelEnum.values()) {
|
||||
if (riskLevelEnum.getLevel().equals(level)) {
|
||||
return riskLevelEnum;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为重度风险
|
||||
*
|
||||
* @param level 等级
|
||||
* @return true-重度,false-非重度
|
||||
*/
|
||||
public static boolean isSevere(String level) {
|
||||
return SEVERE.getLevel().equals(level);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为中度风险
|
||||
*
|
||||
* @param level 等级
|
||||
* @return true-中度,false-非中度
|
||||
*/
|
||||
public static boolean isModerate(String level) {
|
||||
return MODERATE.getLevel().equals(level);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为轻度风险
|
||||
*
|
||||
* @param level 等级
|
||||
* @return true-轻度,false-非轻度
|
||||
*/
|
||||
public static boolean isMild(String level) {
|
||||
return MILD.getLevel().equals(level);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.senmesh.sfile.controller;
|
||||
|
||||
import com.senmesh.common.AlitaResult;
|
||||
import com.senmesh.sdk.dify.dto.DifyChatRequest;
|
||||
import com.senmesh.sdk.dify.dto.DifyChatResponse;
|
||||
import com.senmesh.sdk.dify.dto.DifyFileUploadRequest;
|
||||
import com.senmesh.sdk.dify.dto.DifyFileUploadResponse;
|
||||
import com.senmesh.sfile.service.DifyService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* Dify接口Controller
|
||||
*
|
||||
* @author sr
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/dify")
|
||||
@Api(tags = "Dify接口")
|
||||
@ConditionalOnBean(DifyService.class)
|
||||
public class DifyController {
|
||||
|
||||
@Autowired
|
||||
private DifyService difyService;
|
||||
|
||||
@ApiOperation("上传文件到Dify")
|
||||
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
public AlitaResult<DifyFileUploadResponse> uploadFile(
|
||||
@RequestParam("apiKey") String apiKey,
|
||||
@RequestParam("file") MultipartFile file,
|
||||
@RequestParam("user") String user) throws Exception {
|
||||
DifyFileUploadRequest request = DifyFileUploadRequest.builder()
|
||||
.inputStream(file.getInputStream())
|
||||
.fileName(file.getOriginalFilename())
|
||||
.contentType(file.getContentType())
|
||||
.user(user)
|
||||
.build();
|
||||
return difyService.uploadFile(apiKey, request);
|
||||
}
|
||||
|
||||
@ApiOperation("发送对话消息")
|
||||
@PostMapping("/chat")
|
||||
public AlitaResult<DifyChatResponse> chatMessages(
|
||||
@RequestParam("apiKey") String apiKey,
|
||||
@Validated @RequestBody DifyChatRequest request) {
|
||||
return difyService.chatMessages(apiKey, request);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.senmesh.sfile.controller;
|
||||
|
||||
import com.senmesh.common.AlitaResult;
|
||||
import com.senmesh.common.util.UserContextHolder;
|
||||
import com.senmesh.sfile.dto.FileRiskCreateDTO;
|
||||
import com.senmesh.sfile.dto.FileRiskDTO;
|
||||
import com.senmesh.sfile.dto.FileRiskQueryDTO;
|
||||
import com.senmesh.sfile.service.FileRiskService;
|
||||
import com.senmesh.tkmybatis.pojo.Page;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 文件风险Controller
|
||||
*/
|
||||
@RestController
|
||||
@Api(tags = "文件风险")
|
||||
public class FileRiskController {
|
||||
|
||||
@Autowired
|
||||
private FileRiskService fileRiskService;
|
||||
|
||||
@PostMapping("/file_risk/create")
|
||||
@ApiOperation("创建文件风险")
|
||||
public AlitaResult<FileRiskDTO> create(@Valid @RequestBody FileRiskCreateDTO createDTO) {
|
||||
FileRiskDTO fileRiskDTO = fileRiskService.create(createDTO);
|
||||
return AlitaResult.success(fileRiskDTO);
|
||||
}
|
||||
|
||||
@GetMapping("/file_risk/rule")
|
||||
@ApiOperation("获取风险规则")
|
||||
public AlitaResult<String> getRiskRule() {
|
||||
return AlitaResult.success(fileRiskService.getRiskRule(UserContextHolder.getExistLoginOrgId()));
|
||||
}
|
||||
|
||||
@PostMapping("/file_risk/rule")
|
||||
@ApiOperation("保存风险规则")
|
||||
public AlitaResult<Void> saveRiskRule(@RequestBody String riskRule) {
|
||||
fileRiskService.saveRiskRule(riskRule);
|
||||
return AlitaResult.success();
|
||||
}
|
||||
|
||||
@GetMapping("/file_risk/min_audit_risk_level")
|
||||
@ApiOperation("获取最低审核风险等级")
|
||||
public AlitaResult<String> getMinAuditRiskLevel() {
|
||||
return AlitaResult.success(fileRiskService.getMinAuditRiskLevel(UserContextHolder.getExistLoginOrgId()));
|
||||
}
|
||||
|
||||
@PostMapping("/file_risk/min_audit_risk_level")
|
||||
@ApiOperation("保存最低审核风险等级")
|
||||
public AlitaResult<Void> saveMinAuditRiskLevel(@RequestBody String minAuditRiskLevel) {
|
||||
fileRiskService.saveMinAuditRiskLevel(minAuditRiskLevel);
|
||||
return AlitaResult.success();
|
||||
}
|
||||
|
||||
@GetMapping("/file_risk/scan")
|
||||
@ApiOperation("扫描文件风险")
|
||||
public AlitaResult<FileRiskDTO> scanFileRisk(
|
||||
@ApiParam(value = "文件编码", required = true) @RequestParam String fileCode) {
|
||||
FileRiskDTO fileRiskDTO = fileRiskService.scanFileRisk(fileCode);
|
||||
return AlitaResult.success(fileRiskDTO);
|
||||
}
|
||||
|
||||
@GetMapping("/file_risk/list")
|
||||
@ApiOperation("列表查询文件风险")
|
||||
public AlitaResult<List<FileRiskDTO>> list(FileRiskQueryDTO queryDTO) {
|
||||
List<FileRiskDTO> list = fileRiskService.list(queryDTO);
|
||||
return AlitaResult.success(list);
|
||||
}
|
||||
|
||||
@GetMapping("/file_risk/page")
|
||||
@ApiOperation("分页查询文件风险")
|
||||
public AlitaResult<Page<FileRiskDTO>> page(FileRiskQueryDTO queryDTO) {
|
||||
fileRiskService.page(queryDTO);
|
||||
return AlitaResult.success(queryDTO.getPageResult());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
package com.senmesh.sfile.controller;
|
||||
|
||||
import com.senmesh.common.AlitaResult;
|
||||
import com.senmesh.sfile.service.RiskFileService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 风险文件Controller
|
||||
*/
|
||||
@RestController
|
||||
@Api(tags = "风险文件")
|
||||
public class RiskFileController {
|
||||
|
||||
@Autowired
|
||||
private RiskFileService riskFileService;
|
||||
|
||||
@GetMapping("/risk_file/rule")
|
||||
@ApiOperation("获取风险规则")
|
||||
public AlitaResult<String> getRiskRule() {
|
||||
return AlitaResult.success(riskFileService.getRiskRule());
|
||||
}
|
||||
|
||||
@PostMapping("/risk_file/rule")
|
||||
@ApiOperation("保存风险规则")
|
||||
public AlitaResult<Void> saveRiskRule(@RequestBody String riskRule) {
|
||||
riskFileService.saveRiskRule(riskRule);
|
||||
return AlitaResult.success();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import com.senmesh.sfile.dto.UserFileDTO;
|
||||
import com.senmesh.sfile.dto.UserFileModifyDTO;
|
||||
import com.senmesh.sfile.dto.UserFileModifyStatusDTO;
|
||||
import com.senmesh.sfile.dto.UserFileQueryDTO;
|
||||
import com.senmesh.sfile.dto.UserFileStatisticsDTO;
|
||||
import com.senmesh.sfile.service.UserFileService;
|
||||
import com.senmesh.tkmybatis.pojo.Page;
|
||||
import io.swagger.annotations.Api;
|
||||
@@ -84,5 +85,12 @@ public class UserFileController {
|
||||
userFileService.page(queryDTO);
|
||||
return AlitaResult.success(queryDTO.getPageResult());
|
||||
}
|
||||
|
||||
@GetMapping("/statistics/category")
|
||||
@ApiOperation("按文件种类统计")
|
||||
public AlitaResult<List<UserFileStatisticsDTO>> statisticsByCategory(UserFileQueryDTO queryDTO) {
|
||||
queryDTO.setUserId(UserContextHolder.getExistLoginUserId());
|
||||
return AlitaResult.success(userFileService.statisticsByCategory(queryDTO));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.senmesh.sfile.controller;
|
||||
|
||||
import com.senmesh.common.AlitaResult;
|
||||
import com.senmesh.common.util.UserContextHolder;
|
||||
import com.senmesh.sfile.dto.UserSpaceCreateDTO;
|
||||
import com.senmesh.sfile.dto.UserSpaceDTO;
|
||||
import com.senmesh.sfile.dto.UserSpaceModifyDTO;
|
||||
@@ -29,13 +30,14 @@ public class UserSpaceController {
|
||||
@PostMapping("/create")
|
||||
@ApiOperation("创建")
|
||||
public AlitaResult<Long> create(@Validated @RequestBody UserSpaceCreateDTO createDTO) {
|
||||
|
||||
createDTO.setUserId(UserContextHolder.getExistLoginUserId());
|
||||
return AlitaResult.success(userSpaceService.create(createDTO));
|
||||
}
|
||||
|
||||
@PostMapping("/modify")
|
||||
@ApiOperation("修改")
|
||||
public AlitaResult<Boolean> modify(@Validated @RequestBody UserSpaceModifyDTO modifyDTO) {
|
||||
modifyDTO.setUserId(UserContextHolder.getExistLoginUserId());
|
||||
userSpaceService.modify(modifyDTO);
|
||||
return AlitaResult.success(true);
|
||||
}
|
||||
@@ -50,20 +52,9 @@ public class UserSpaceController {
|
||||
@GetMapping("/find")
|
||||
@ApiOperation("查询")
|
||||
public AlitaResult<UserSpaceDTO> find(UserSpaceQueryDTO queryDTO) {
|
||||
queryDTO.setUserId(UserContextHolder.getExistLoginUserId());
|
||||
return AlitaResult.success(userSpaceService.find(queryDTO));
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@ApiOperation("列表查询")
|
||||
public AlitaResult<List<UserSpaceDTO>> list(UserSpaceQueryDTO queryDTO) {
|
||||
return AlitaResult.success(userSpaceService.list(queryDTO));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@ApiOperation("分页查询")
|
||||
public AlitaResult<Page<UserSpaceDTO>> page(UserSpaceQueryDTO queryDTO) {
|
||||
userSpaceService.page(queryDTO);
|
||||
return AlitaResult.success(queryDTO.getPageResult());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
23
src/main/java/com/senmesh/sfile/convert/FileRiskConvert.java
Normal file
23
src/main/java/com/senmesh/sfile/convert/FileRiskConvert.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package com.senmesh.sfile.convert;
|
||||
|
||||
import com.senmesh.sfile.dto.FileRiskCreateDTO;
|
||||
import com.senmesh.sfile.dto.FileRiskDTO;
|
||||
import com.senmesh.sfile.entity.FileRisk;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* 文件风险转换器
|
||||
*/
|
||||
@Mapper
|
||||
public interface FileRiskConvert {
|
||||
|
||||
FileRiskConvert INSTANCE = Mappers.getMapper(FileRiskConvert.class);
|
||||
|
||||
FileRisk toEntity(FileRiskDTO dto);
|
||||
|
||||
FileRiskDTO toDto(FileRisk entity);
|
||||
|
||||
FileRisk toEntity(FileRiskCreateDTO dto);
|
||||
}
|
||||
|
||||
26
src/main/java/com/senmesh/sfile/dao/FileRiskMapper.java
Normal file
26
src/main/java/com/senmesh/sfile/dao/FileRiskMapper.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package com.senmesh.sfile.dao;
|
||||
|
||||
import com.senmesh.sfile.dto.FileRiskDTO;
|
||||
import com.senmesh.sfile.dto.FileRiskQueryDTO;
|
||||
import com.senmesh.sfile.entity.FileRisk;
|
||||
import com.senmesh.tkmybatis.mybatis.MyMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 文件风险Mapper
|
||||
*/
|
||||
@Mapper
|
||||
public interface FileRiskMapper extends MyMapper<FileRisk> {
|
||||
|
||||
/**
|
||||
* 查询列表(PageHelper会根据queryDTO自动判断是否分页)
|
||||
*
|
||||
* @param queryDTO 查询DTO
|
||||
* @return List<FileRiskDTO>
|
||||
*/
|
||||
List<FileRiskDTO> list(@Param("param") FileRiskQueryDTO queryDTO);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.senmesh.sfile.dao;
|
||||
|
||||
import com.senmesh.sfile.dto.UserFileDTO;
|
||||
import com.senmesh.sfile.dto.UserFileQueryDTO;
|
||||
import com.senmesh.sfile.dto.UserFileStatisticsDTO;
|
||||
import com.senmesh.sfile.entity.UserFile;
|
||||
import com.senmesh.tkmybatis.mybatis.MyMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
@@ -54,5 +55,13 @@ public interface UserFileMapper extends MyMapper<UserFile> {
|
||||
@Param("oldStatus") String oldStatus,
|
||||
@Param("newStatus") String newStatus,
|
||||
@Param("operateUserId") Long operateUserId);
|
||||
|
||||
/**
|
||||
* 按文件种类统计文件个数和总大小
|
||||
*
|
||||
* @param queryDTO 查询DTO
|
||||
* @return List<UserFileStatisticsDTO>
|
||||
*/
|
||||
List<UserFileStatisticsDTO> statisticsByCategory(@Param("param") UserFileQueryDTO queryDTO);
|
||||
}
|
||||
|
||||
|
||||
31
src/main/java/com/senmesh/sfile/dto/FileRiskCreateDTO.java
Normal file
31
src/main/java/com/senmesh/sfile/dto/FileRiskCreateDTO.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package com.senmesh.sfile.dto;
|
||||
|
||||
import com.senmesh.common.dto.BaseOperateDTO;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
||||
/**
|
||||
* 文件风险创建DTO
|
||||
*/
|
||||
@ApiModel("文件风险创建DTO")
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class FileRiskCreateDTO extends BaseOperateDTO {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("文件编码")
|
||||
@NotEmpty(message = "文件编码不能为空")
|
||||
private String fileCode;
|
||||
}
|
||||
|
||||
37
src/main/java/com/senmesh/sfile/dto/FileRiskDTO.java
Normal file
37
src/main/java/com/senmesh/sfile/dto/FileRiskDTO.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package com.senmesh.sfile.dto;
|
||||
|
||||
import com.senmesh.common.dto.BaseDTO;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
/**
|
||||
* 文件风险DTO
|
||||
*/
|
||||
@ApiModel("文件风险")
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class FileRiskDTO extends BaseDTO {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("文件编码")
|
||||
private String fileCode;
|
||||
|
||||
@ApiModelProperty("最高风险等级:1重度/2中度/3轻度")
|
||||
private String maxRiskLevel;
|
||||
|
||||
@ApiModelProperty("风险详情JSON")
|
||||
private String riskJson;
|
||||
|
||||
@ApiModelProperty("Dify文件上传响应JSON")
|
||||
private String difyFileJson;
|
||||
}
|
||||
|
||||
34
src/main/java/com/senmesh/sfile/dto/FileRiskQueryDTO.java
Normal file
34
src/main/java/com/senmesh/sfile/dto/FileRiskQueryDTO.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package com.senmesh.sfile.dto;
|
||||
|
||||
import com.senmesh.common.dto.PageQueryDTO;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 文件风险查询DTO
|
||||
*/
|
||||
@ApiModel("文件风险查询DTO")
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class FileRiskQueryDTO extends PageQueryDTO<FileRiskDTO> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("主键ID")
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty("文件编码")
|
||||
private String fileCode;
|
||||
|
||||
@ApiModelProperty("最高风险等级:1重度/2中度/3轻度")
|
||||
private String maxRiskLevel;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.senmesh.sfile.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 用户文件统计DTO
|
||||
*/
|
||||
@ApiModel("用户文件统计DTO")
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UserFileStatisticsDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("文件种类")
|
||||
private String fileCategory;
|
||||
|
||||
@ApiModelProperty("文件个数")
|
||||
private Long fileCount;
|
||||
|
||||
@ApiModelProperty("文件总大小(kb)")
|
||||
private Long totalSize;
|
||||
}
|
||||
|
||||
44
src/main/java/com/senmesh/sfile/entity/FileRisk.java
Normal file
44
src/main/java/com/senmesh/sfile/entity/FileRisk.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package com.senmesh.sfile.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.senmesh.common.entity.BaseEntity;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
/**
|
||||
* 文件风险
|
||||
*/
|
||||
@TableName("x_file_risk")
|
||||
@Data
|
||||
@SuperBuilder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class FileRisk extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 文件编码
|
||||
*/
|
||||
private String fileCode;
|
||||
|
||||
/**
|
||||
* 最高风险等级:1重度/2中度/3轻度
|
||||
*/
|
||||
private String maxRiskLevel;
|
||||
|
||||
/**
|
||||
* 风险详情JSON
|
||||
*/
|
||||
private String riskJson;
|
||||
|
||||
/**
|
||||
* Dify文件上传响应JSON
|
||||
*/
|
||||
private String difyFileJson;
|
||||
}
|
||||
|
||||
26
src/main/java/com/senmesh/sfile/mapper/FileRiskMapper.xml
Normal file
26
src/main/java/com/senmesh/sfile/mapper/FileRiskMapper.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.senmesh.sfile.dao.FileRiskMapper">
|
||||
|
||||
<select id="list" resultType="com.senmesh.sfile.dto.FileRiskDTO">
|
||||
SELECT t.*
|
||||
<include refid="queryFromSql"></include>
|
||||
ORDER BY t.id DESC
|
||||
</select>
|
||||
|
||||
<sql id="queryFromSql">
|
||||
FROM x_file_risk t
|
||||
WHERE t.deleted = FALSE
|
||||
<if test='param.id != null'>
|
||||
AND t.id = #{param.id}
|
||||
</if>
|
||||
<if test='param.fileCode != null and param.fileCode.trim() != ""'>
|
||||
AND t.file_code = #{param.fileCode}
|
||||
</if>
|
||||
<if test='param.maxRiskLevel != null and param.maxRiskLevel.trim() != ""'>
|
||||
AND t.max_risk_level = #{param.maxRiskLevel}
|
||||
</if>
|
||||
</sql>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -9,6 +9,26 @@
|
||||
ORDER BY t.id DESC
|
||||
</select>
|
||||
|
||||
<select id="statisticsByCategory" resultType="com.senmesh.sfile.dto.UserFileStatisticsDTO">
|
||||
SELECT
|
||||
COALESCE(fc.file_category, '未分类') AS file_category,
|
||||
COUNT(t.id) AS file_count,
|
||||
COALESCE(SUM(fr.file_size), 0) AS total_size
|
||||
FROM x_user_file t
|
||||
LEFT JOIN xs_file_record fr ON t.file_code = fr.file_code AND fr.deleted = FALSE
|
||||
LEFT JOIN x_file_category fc ON fr.file_suffix = fc.file_suffix AND fc.deleted = FALSE
|
||||
WHERE t.deleted = FALSE
|
||||
AND t.file_type = '1'
|
||||
<if test='param.userId != null'>
|
||||
AND t.user_id = #{param.userId}
|
||||
</if>
|
||||
<if test='param.rootType != null and param.rootType.trim() != ""'>
|
||||
AND t.root_type = #{param.rootType}
|
||||
</if>
|
||||
GROUP BY fc.file_category
|
||||
ORDER BY total_size DESC
|
||||
</select>
|
||||
|
||||
<sql id="queryFromSql">
|
||||
FROM x_user_file t
|
||||
LEFT JOIN xs_file_record fr ON t.file_code = fr.file_code AND fr.deleted = FALSE
|
||||
|
||||
@@ -4,12 +4,21 @@
|
||||
<mapper namespace="com.senmesh.sfile.dao.UserSpaceMapper">
|
||||
|
||||
<select id="list" resultType="com.senmesh.sfile.dto.UserSpaceDTO">
|
||||
SELECT t.*
|
||||
<include refid="queryFromSql"></include>
|
||||
ORDER BY t.id DESC
|
||||
</select>
|
||||
|
||||
<sql id="queryFromSql">
|
||||
SELECT t.id,
|
||||
t.user_id,
|
||||
t.total_size,
|
||||
(SELECT COALESCE(SUM(fr.file_size), 0)
|
||||
FROM x_user_file uf
|
||||
LEFT JOIN xs_file_record fr ON uf.file_code = fr.file_code AND fr.deleted = FALSE
|
||||
WHERE uf.deleted = FALSE
|
||||
AND uf.user_id = t.user_id
|
||||
AND uf.file_type = '1') AS used_size,
|
||||
t.deleted,
|
||||
t.create_by,
|
||||
t.create_time,
|
||||
t.update_by,
|
||||
t.update_time,
|
||||
t.proxy_by
|
||||
FROM x_user_space t
|
||||
WHERE t.deleted = FALSE
|
||||
<if test='param.id != null'>
|
||||
@@ -18,6 +27,8 @@
|
||||
<if test='param.userId != null'>
|
||||
AND t.user_id = #{param.userId}
|
||||
</if>
|
||||
</sql>
|
||||
ORDER BY t.id DESC
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
|
||||
91
src/main/java/com/senmesh/sfile/service/FileRiskService.java
Normal file
91
src/main/java/com/senmesh/sfile/service/FileRiskService.java
Normal file
@@ -0,0 +1,91 @@
|
||||
package com.senmesh.sfile.service;
|
||||
|
||||
import com.senmesh.sfile.dto.FileRiskCreateDTO;
|
||||
import com.senmesh.sfile.dto.FileRiskDTO;
|
||||
import com.senmesh.sfile.dto.FileRiskQueryDTO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 文件风险Service
|
||||
*/
|
||||
public interface FileRiskService {
|
||||
|
||||
/**
|
||||
* 创建文件风险(带锁)
|
||||
* 根据fileCode查询,如果存在则直接返回,不存在则创建
|
||||
*
|
||||
* @param createDTO 创建DTO
|
||||
* @return 文件风险DTO
|
||||
*/
|
||||
FileRiskDTO create(FileRiskCreateDTO createDTO);
|
||||
|
||||
/**
|
||||
* 获取风险规则
|
||||
*
|
||||
* @param orgId 机构ID
|
||||
* @return 风险规则配置值
|
||||
*/
|
||||
String getRiskRule(Long orgId);
|
||||
|
||||
/**
|
||||
* 保存风险规则
|
||||
*
|
||||
* @param riskRule 风险规则配置值
|
||||
*/
|
||||
void saveRiskRule(String riskRule);
|
||||
|
||||
/**
|
||||
* 获取最低审核风险等级
|
||||
*
|
||||
* @param orgId 机构ID
|
||||
* @return 最低审核风险等级配置值
|
||||
*/
|
||||
String getMinAuditRiskLevel(Long orgId);
|
||||
|
||||
/**
|
||||
* 保存最低审核风险等级
|
||||
*
|
||||
* @param minAuditRiskLevel 最低审核风险等级配置值
|
||||
*/
|
||||
void saveMinAuditRiskLevel(String minAuditRiskLevel);
|
||||
|
||||
/**
|
||||
* 扫描文件风险
|
||||
* 1. 根据fileCode查询,如果存在则直接返回
|
||||
* 2. 如果不存在,则走扫描逻辑:
|
||||
* - 拿到文件流调dify上传文件
|
||||
* - 调用获取风险规则
|
||||
* - 调用dify chat拿风险结果
|
||||
* - 获取结果中的max_risk_level
|
||||
* - 保存数据
|
||||
*
|
||||
* @param fileCode 文件编码
|
||||
* @return 文件风险DTO
|
||||
*/
|
||||
FileRiskDTO scanFileRisk(String fileCode);
|
||||
|
||||
/**
|
||||
* 列表查询文件风险
|
||||
*
|
||||
* @param queryDTO 查询条件
|
||||
* @return 文件风险DTO列表
|
||||
*/
|
||||
List<FileRiskDTO> list(FileRiskQueryDTO queryDTO);
|
||||
|
||||
/**
|
||||
* 分页查询文件风险
|
||||
*
|
||||
* @param queryDTO 查询条件
|
||||
*/
|
||||
void page(FileRiskQueryDTO queryDTO);
|
||||
|
||||
/**
|
||||
* 单个查询文件风险
|
||||
*
|
||||
* @param queryDTO 查询条件
|
||||
* @return 文件风险DTO
|
||||
*/
|
||||
FileRiskDTO find(FileRiskQueryDTO queryDTO);
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.senmesh.sfile.service;
|
||||
|
||||
/**
|
||||
* 风险文件Service
|
||||
*/
|
||||
public interface RiskFileService {
|
||||
|
||||
/**
|
||||
* 获取风险规则
|
||||
*
|
||||
* @return 风险规则配置值
|
||||
*/
|
||||
String getRiskRule();
|
||||
|
||||
/**
|
||||
* 保存风险规则
|
||||
*
|
||||
* @param riskRule 风险规则配置值
|
||||
*/
|
||||
void saveRiskRule(String riskRule);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.senmesh.sfile.dto.UserFileDTO;
|
||||
import com.senmesh.sfile.dto.UserFileModifyDTO;
|
||||
import com.senmesh.sfile.dto.UserFileModifyStatusDTO;
|
||||
import com.senmesh.sfile.dto.UserFileQueryDTO;
|
||||
import com.senmesh.sfile.dto.UserFileStatisticsDTO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -111,5 +112,13 @@ public interface UserFileService {
|
||||
* @return UserFileDTO
|
||||
*/
|
||||
UserFileDTO findOne(UserFileQueryDTO queryDTO);
|
||||
|
||||
/**
|
||||
* 按文件种类统计文件个数和总大小
|
||||
*
|
||||
* @param queryDTO 查询DTO
|
||||
* @return List<UserFileStatisticsDTO>
|
||||
*/
|
||||
List<UserFileStatisticsDTO> statisticsByCategory(UserFileQueryDTO queryDTO);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,266 @@
|
||||
package com.senmesh.sfile.service.impl;
|
||||
|
||||
import com.senmesh.common.AlitaResult;
|
||||
import com.senmesh.common.constant.CommonConstants;
|
||||
import com.senmesh.common.util.JsonUtils;
|
||||
import com.senmesh.common.util.ListUtil;
|
||||
import com.senmesh.common.util.UserContextHolder;
|
||||
import com.senmesh.component.file.service.FileService;
|
||||
import com.senmesh.config.dto.ConfigDTO;
|
||||
import com.senmesh.config.dto.ConfigOperatorDTO;
|
||||
import com.senmesh.config.entity.Config;
|
||||
import com.senmesh.config.service.ConfigService;
|
||||
import com.senmesh.sdk.dify.dto.DifyChatRequest;
|
||||
import com.senmesh.sdk.dify.dto.DifyChatResponse;
|
||||
import com.senmesh.sdk.dify.dto.DifyFileUploadRequest;
|
||||
import com.senmesh.sdk.dify.dto.DifyFileUploadResponse;
|
||||
import com.senmesh.sdk.dify.service.DifyClient;
|
||||
import com.senmesh.common.exception.util.Assert;
|
||||
import com.senmesh.frame.redis.dto.LockDTO;
|
||||
import com.senmesh.frame.redis.redisson.RedissonUtils;
|
||||
import com.senmesh.sfile.convert.FileRiskConvert;
|
||||
import com.senmesh.sfile.dao.FileRiskMapper;
|
||||
import com.senmesh.sfile.dto.FileRiskCreateDTO;
|
||||
import com.senmesh.sfile.dto.FileRiskDTO;
|
||||
import com.senmesh.sfile.dto.FileRiskQueryDTO;
|
||||
import com.senmesh.sfile.entity.FileRisk;
|
||||
import com.senmesh.sfile.service.FileRiskService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 文件风险ServiceImpl
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class FileRiskServiceImpl implements FileRiskService {
|
||||
|
||||
private static final String RISK_RULE_CONFIG_CODE = "risk_rule";
|
||||
private static final String MIN_AUDIT_RISK_LEVEL_CONFIG_CODE = "min_audit_risk_level";
|
||||
|
||||
/**
|
||||
* 规则生成 API Key
|
||||
*/
|
||||
@Value("${dify.risk.rule.api-key}")
|
||||
private String riskRuleApiKey;
|
||||
|
||||
/**
|
||||
* 文件智能风险预警 API Key
|
||||
*/
|
||||
@Value("${dify.risk.scan.api-key}")
|
||||
private String riskScanApiKey;
|
||||
|
||||
@Autowired
|
||||
private ConfigService configService;
|
||||
|
||||
@Autowired
|
||||
private FileRiskMapper fileRiskMapper;
|
||||
|
||||
@Autowired
|
||||
private FileService fileService;
|
||||
|
||||
/**
|
||||
* 获取文件风险锁DTO
|
||||
*
|
||||
* @param fileCode 文件编码
|
||||
* @return LockDTO
|
||||
*/
|
||||
public static LockDTO getLockDTO(String fileCode) {
|
||||
Assert.notBlank(fileCode, "文件编码不能为空");
|
||||
return LockDTO.builder()
|
||||
.methodName("filerisk")
|
||||
.tryLockWaitTime(0L)
|
||||
.lockTimeout(60 * 5L)
|
||||
.arg(fileCode)
|
||||
.failMsg("该文件风险正在被操作")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public FileRiskDTO create(FileRiskCreateDTO createDTO) {
|
||||
String fileCode = createDTO.getFileCode();
|
||||
FileRiskQueryDTO queryDTO = FileRiskQueryDTO.builder().fileCode(fileCode).build();
|
||||
|
||||
return RedissonUtils.lockAndSave(getLockDTO(fileCode),
|
||||
() -> this.find(queryDTO), () -> {
|
||||
FileRisk fileRisk = FileRiskConvert.INSTANCE.toEntity(createDTO);
|
||||
fileRiskMapper.saveEntity(fileRisk);
|
||||
return FileRiskConvert.INSTANCE.toDto(fileRisk);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRiskRule(Long orgId) {
|
||||
ConfigDTO configDTO = configService.queryOrgConfigByCode(orgId, RISK_RULE_CONFIG_CODE);
|
||||
return configDTO == null ? null : configDTO.getConfigValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void saveRiskRule(String riskRule) {
|
||||
configService.createOrModify(UserContextHolder.getExistLoginOrgId(), RISK_RULE_CONFIG_CODE, riskRule);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMinAuditRiskLevel(Long orgId) {
|
||||
ConfigDTO configDTO = configService.queryOrgConfigByCode(orgId, MIN_AUDIT_RISK_LEVEL_CONFIG_CODE);
|
||||
return configDTO == null ? null : configDTO.getConfigValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void saveMinAuditRiskLevel(String minAuditRiskLevel) {
|
||||
configService.createOrModify(UserContextHolder.getExistLoginOrgId(), MIN_AUDIT_RISK_LEVEL_CONFIG_CODE, minAuditRiskLevel);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public FileRiskDTO scanFileRisk(String fileCode) {
|
||||
// 1. 查询或创建记录
|
||||
FileRiskQueryDTO queryDTO = FileRiskQueryDTO.builder().fileCode(fileCode).build();
|
||||
FileRiskDTO fileRiskDTO = this.find(queryDTO);
|
||||
|
||||
if (fileRiskDTO == null) {
|
||||
// 1.1 记录不存在,创建新记录
|
||||
log.info("文件风险不存在,创建新记录,fileCode: {}", fileCode);
|
||||
FileRiskCreateDTO createDTO = FileRiskCreateDTO.builder()
|
||||
.fileCode(fileCode)
|
||||
.build();
|
||||
fileRiskDTO = this.create(createDTO);
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(fileRiskDTO.getRiskJson())) {
|
||||
return fileRiskDTO;
|
||||
}
|
||||
|
||||
// 2. 如果 difyFileJson 为空,则上传文件
|
||||
DifyFileUploadResponse uploadResponse = null;
|
||||
if (StringUtils.isBlank(fileRiskDTO.getDifyFileJson())) {
|
||||
uploadResponse = uploadFileToDify(fileRiskDTO, fileCode, riskScanApiKey);
|
||||
} else {
|
||||
// 从 difyFileJson 中解析 uploadFileId
|
||||
uploadResponse = JsonUtils.toObject(fileRiskDTO.getDifyFileJson(), DifyFileUploadResponse.class);
|
||||
}
|
||||
|
||||
// 3. 如果 riskJson 为空,则调用 Dify Chat 分析
|
||||
|
||||
DifyChatRequest chatRequest = DifyChatRequest.builder()
|
||||
.query("请分析这个文件的风险")
|
||||
.user(String.valueOf(UserContextHolder.getLoginUserId()))
|
||||
.files(Collections.singletonList(
|
||||
DifyChatRequest.DifyFileInfo.builder()
|
||||
.type(uploadResponse.getMimeType())
|
||||
.uploadFileId(uploadResponse.getId())
|
||||
.build()
|
||||
))
|
||||
.build();
|
||||
|
||||
AlitaResult<DifyChatResponse> chatResult = DifyClient.chatMessages(riskScanApiKey, chatRequest);
|
||||
Assert.isTrue(chatResult.getSuccess() ,
|
||||
"调用 Dify Chat 失败,fileCode: " + fileCode + ", error: " + chatResult.getMsg());
|
||||
|
||||
DifyChatResponse chatResponse = chatResult.getData();
|
||||
String answer = chatResponse.getAnswer();
|
||||
|
||||
// 解析风险等级
|
||||
String maxRiskLevel = parseMaxRiskLevel(chatResponse);
|
||||
if (StringUtils.isBlank(maxRiskLevel)) {
|
||||
log.warn("未能从 Dify 返回结果中解析出 max_risk_level,fileCode: {}", fileCode);
|
||||
maxRiskLevel = null; // 默认为空
|
||||
}
|
||||
|
||||
// 更新 riskJson 和 maxRiskLevel
|
||||
FileRisk updateFileRisk = FileRisk.builder()
|
||||
.id(fileRiskDTO.getId())
|
||||
.maxRiskLevel(maxRiskLevel)
|
||||
.riskJson(answer)
|
||||
.build();
|
||||
fileRiskMapper.updateEntitySelective(updateFileRisk);
|
||||
log.info("更新文件风险成功,fileCode: {}, maxRiskLevel: {}", fileCode, maxRiskLevel);
|
||||
|
||||
// 更新 DTO
|
||||
fileRiskDTO.setMaxRiskLevel(maxRiskLevel);
|
||||
fileRiskDTO.setRiskJson(answer);
|
||||
return fileRiskDTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileRiskDTO> list(FileRiskQueryDTO queryDTO) {
|
||||
queryDTO.disablePage();
|
||||
return fileRiskMapper.list(queryDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void page(FileRiskQueryDTO queryDTO) {
|
||||
fileRiskMapper.list(queryDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileRiskDTO find(FileRiskQueryDTO queryDTO) {
|
||||
List<FileRiskDTO> list = this.list(queryDTO);
|
||||
return ListUtil.first(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件到 Dify
|
||||
*
|
||||
* @param fileRiskDTO 文件风险DTO
|
||||
* @param fileCode 文件编码
|
||||
* @param apiKey API密钥
|
||||
* @return DifyFileUploadResponse
|
||||
*/
|
||||
private DifyFileUploadResponse uploadFileToDify(FileRiskDTO fileRiskDTO, String fileCode, String apiKey) {
|
||||
// 1. 获取文件流
|
||||
InputStream fileStream = fileService.getFile(fileCode);
|
||||
Assert.notNull(fileStream, "获取文件流失败,fileCode: " + fileCode);
|
||||
|
||||
// 2. 上传文件到 Dify
|
||||
DifyFileUploadRequest uploadRequest = DifyFileUploadRequest.builder()
|
||||
.inputStream(fileStream)
|
||||
.fileName(fileCode)
|
||||
.user(String.valueOf(UserContextHolder.getLoginUserId()))
|
||||
.build();
|
||||
|
||||
AlitaResult<DifyFileUploadResponse> uploadResult = DifyClient.uploadFile(apiKey, uploadRequest);
|
||||
Assert.isTrue(uploadResult.getSuccess() ,
|
||||
"上传文件到 Dify 失败,fileCode: " + fileCode + ", error: " + uploadResult.getMsg());
|
||||
|
||||
DifyFileUploadResponse uploadResponse = uploadResult.getData();
|
||||
String difyFileJson = JsonUtils.toJsonString(uploadResponse);
|
||||
// 3. 更新 difyFileJson 字段
|
||||
FileRisk updateFileRisk = FileRisk.builder()
|
||||
.id(fileRiskDTO.getId())
|
||||
.difyFileJson(difyFileJson)
|
||||
.build();
|
||||
fileRiskMapper.updateEntitySelective(updateFileRisk);
|
||||
|
||||
// 更新 DTO
|
||||
fileRiskDTO.setDifyFileJson(difyFileJson);
|
||||
|
||||
return uploadResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Dify返回的响应中解析最高风险等级
|
||||
*
|
||||
* @param chatResponse Dify返回的响应
|
||||
* @return 最高风险等级:1重度/2中度/3轻度
|
||||
*/
|
||||
private String parseMaxRiskLevel(DifyChatResponse chatResponse) {
|
||||
Map<String, Object> resultMap = JsonUtils.toMap(chatResponse.getAnswer());
|
||||
return String.valueOf(resultMap.get("max_risk_level"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
package com.senmesh.sfile.service.impl;
|
||||
|
||||
import com.senmesh.common.constant.CommonConstants;
|
||||
import com.senmesh.common.util.UserContextHolder;
|
||||
import com.senmesh.config.dto.ConfigDTO;
|
||||
import com.senmesh.config.dto.ConfigOperatorDTO;
|
||||
import com.senmesh.config.entity.Config;
|
||||
import com.senmesh.config.service.ConfigService;
|
||||
import com.senmesh.sfile.service.RiskFileService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 风险文件ServiceImpl
|
||||
*/
|
||||
@Service
|
||||
public class RiskFileServiceImpl implements RiskFileService {
|
||||
|
||||
private static final String RISK_RULE_CONFIG_CODE = "risk_rule";
|
||||
|
||||
@Autowired
|
||||
private ConfigService configService;
|
||||
|
||||
@Override
|
||||
public String getRiskRule() {
|
||||
ConfigDTO configDTO = configService.queryOrgConfigByCode(UserContextHolder.getExistLoginOrgId(), RISK_RULE_CONFIG_CODE);
|
||||
return configDTO == null ? null : configDTO.getConfigValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void saveRiskRule(String riskRule) {
|
||||
// 查询是否已存在配置
|
||||
ConfigDTO existConfig = configService.queryOrgConfigByCode(UserContextHolder.getExistLoginOrgId(), RISK_RULE_CONFIG_CODE);
|
||||
|
||||
if (existConfig != null) {
|
||||
// 存在则修改
|
||||
ConfigOperatorDTO modifyDTO = ConfigOperatorDTO.builder()
|
||||
.id(existConfig.getId())
|
||||
.configCode(RISK_RULE_CONFIG_CODE)
|
||||
.configValue(riskRule)
|
||||
.orgId(UserContextHolder.getExistLoginOrgId())
|
||||
.enable(true)
|
||||
.build();
|
||||
configService.modify(modifyDTO);
|
||||
} else {
|
||||
// 不存在则创建
|
||||
ConfigOperatorDTO createDTO = ConfigOperatorDTO.builder()
|
||||
.configCode(RISK_RULE_CONFIG_CODE)
|
||||
.configValue(riskRule)
|
||||
.orgId(UserContextHolder.getExistLoginOrgId())
|
||||
.enable(true)
|
||||
.build();
|
||||
configService.create(createDTO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.senmesh.sfile.service.impl;
|
||||
|
||||
import com.senmesh.common.exception.util.Assert;
|
||||
import com.senmesh.common.util.JsonUtils;
|
||||
import com.senmesh.common.util.UserContextHolder;
|
||||
import com.senmesh.component.file.config.FileProperties;
|
||||
import com.senmesh.component.file.service.FileService;
|
||||
import com.senmesh.sfile.constant.FileLocationEnum;
|
||||
@@ -9,13 +10,16 @@ import com.senmesh.sfile.constant.FileStatusEnum;
|
||||
import com.senmesh.sfile.constant.FileTypeEnum;
|
||||
import com.senmesh.sfile.constant.RootTypeEnum;
|
||||
import com.senmesh.sfile.dto.ExpandUserFileDTO;
|
||||
import com.senmesh.sfile.dto.FileRiskDTO;
|
||||
import com.senmesh.sfile.dto.TransferMetadataDTO;
|
||||
import com.senmesh.sfile.dto.UserFileCreateDTO;
|
||||
import com.senmesh.sfile.dto.UserFileDTO;
|
||||
import com.senmesh.sfile.dto.UserFileModifyStatusDTO;
|
||||
import com.senmesh.sfile.service.FileRiskService;
|
||||
import com.senmesh.sfile.service.TransferFileMonitorService;
|
||||
import com.senmesh.sfile.service.UserFileService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -56,9 +60,12 @@ public class TransferFileMonitorServiceImpl implements TransferFileMonitorServic
|
||||
@Autowired
|
||||
private FileService fileService;
|
||||
|
||||
@Autowired
|
||||
private FileRiskService fileRiskService;
|
||||
|
||||
@Override
|
||||
public void scanAndProcess() {
|
||||
String transferReceiveDir = fileProperties.getTransferReceiveDir();
|
||||
String transferReceiveDir = fileProperties.getTransfer().getReceiveDir();
|
||||
Path receiveDir = Paths.get(transferReceiveDir);
|
||||
|
||||
try {
|
||||
@@ -300,7 +307,7 @@ public class TransferFileMonitorServiceImpl implements TransferFileMonitorServic
|
||||
Assert.notEmpty(files, "expandUserFile 缺少 files");
|
||||
|
||||
// 2. 确定 rootType 并设置到 folder 中
|
||||
String location = fileProperties.getLocation();
|
||||
String location = fileProperties.getTransfer().getLocation();
|
||||
String rootType;
|
||||
if (FileLocationEnum.INTERNAL.getLocation().equals(location)) {
|
||||
rootType = RootTypeEnum.EXTERNAL_TO_INTERNAL.getType();
|
||||
@@ -371,7 +378,15 @@ public class TransferFileMonitorServiceImpl implements TransferFileMonitorServic
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 调用 UserFileService 的重载方法创建文件夹和文件
|
||||
// 5. 检查是否开启解包风险校验
|
||||
String fileStatus = FileStatusEnum.NORMAL.getStatus();
|
||||
if (Boolean.TRUE.equals(fileProperties.getTransfer().getUnpackRiskCheck())) {
|
||||
log.info("解包风险校验已开启,开始扫描文件: {}", fileName);
|
||||
fileStatus = scanFilesForRisk(files, folder);
|
||||
}
|
||||
folder.setFileStatus(fileStatus);
|
||||
|
||||
// 6. 调用 UserFileService 的重载方法创建文件夹和文件
|
||||
ExpandUserFileDTO result = userFileService.create(folder, files);
|
||||
|
||||
log.info("文件解包成功: {}, 创建文件夹ID: {}", fileName, result.getFolder().getId());
|
||||
@@ -383,6 +398,49 @@ public class TransferFileMonitorServiceImpl implements TransferFileMonitorServic
|
||||
throw new RuntimeException("解包文件失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫描文件风险
|
||||
* for循环文件扫描,拿到最高风险等级,跟最低审核风险等级比较,如果不小于则状态给审批中,否则给正常
|
||||
*
|
||||
* @param files 文件列表
|
||||
* @param folder 文件夹信息
|
||||
* @return 文件状态
|
||||
*/
|
||||
private String scanFilesForRisk(List<UserFileDTO> files, UserFileDTO folder) {
|
||||
// 1. 获取最低审核风险等级
|
||||
Long orgId = UserContextHolder.getExistLoginOrgId();
|
||||
String minAuditRiskLevel = fileRiskService.getMinAuditRiskLevel(orgId);
|
||||
if (StringUtils.isBlank(minAuditRiskLevel)) {
|
||||
log.info("未配置最低审核风险等级,默认不审核");
|
||||
return FileStatusEnum.NORMAL.getStatus();
|
||||
}
|
||||
|
||||
// 2. for循环扫描文件,获取最高风险等级
|
||||
String maxRiskLevel = "3"; // 默认轻度风险
|
||||
for (UserFileDTO file : files) {
|
||||
String fileCode = file.getFileCode();
|
||||
if (StringUtils.isBlank(fileCode)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FileRiskDTO fileRiskDTO = fileRiskService.scanFileRisk(fileCode);
|
||||
String riskLevel = fileRiskDTO.getMaxRiskLevel();
|
||||
if (StringUtils.isNotBlank(riskLevel) && riskLevel.compareTo(maxRiskLevel) < 0) {
|
||||
maxRiskLevel = riskLevel;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 比较最高风险等级和最低审核风险等级
|
||||
if (maxRiskLevel.compareTo(minAuditRiskLevel) <= 0) {
|
||||
log.info("文件风险等级 {} 不小于最低审核风险等级 {},状态设置为待审核", maxRiskLevel, minAuditRiskLevel);
|
||||
return FileStatusEnum.PENDING_REVIEW.getStatus();
|
||||
} else {
|
||||
log.info("文件风险等级 {} 小于最低审核风险等级 {},状态设置为正常", maxRiskLevel, minAuditRiskLevel);
|
||||
return FileStatusEnum.NORMAL.getStatus();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 .finish 文件到发送目录,告诉对方处理完成
|
||||
*
|
||||
@@ -391,7 +449,7 @@ public class TransferFileMonitorServiceImpl implements TransferFileMonitorServic
|
||||
private void createFinishFile(String zipFileName) {
|
||||
try {
|
||||
// 获取发送目录
|
||||
String transferSendDir = fileProperties.getTransferSendDir();
|
||||
String transferSendDir = fileProperties.getTransfer().getSendDir();
|
||||
Path sendPath = Paths.get(transferSendDir);
|
||||
|
||||
// 确保发送目录存在
|
||||
|
||||
@@ -53,7 +53,7 @@ public class TransferUserFileServiceImpl implements TransferUserFileService {
|
||||
Long userId = UserContextHolder.getExistLoginUserId();
|
||||
|
||||
// 根据 FileProperties#location 的类型决定是内穿外还是外传内
|
||||
String location = fileProperties.getLocation();
|
||||
String location = fileProperties.getTransfer().getLocation();
|
||||
String rootType;
|
||||
if (FileLocationEnum.INTERNAL.getLocation().equals(location)) {
|
||||
// 内网 -> 内穿外
|
||||
@@ -63,7 +63,6 @@ public class TransferUserFileServiceImpl implements TransferUserFileService {
|
||||
rootType = RootTypeEnum.EXTERNAL_TO_INTERNAL.getType();
|
||||
}
|
||||
|
||||
// TODO 扫描文件审核
|
||||
// 调用UserFileService的重载create方法
|
||||
ExpandUserFileCreateDTO expandCreateDTO = ExpandUserFileCreateDTO.builder()
|
||||
.userFileId(createDTO.getUserFileId())
|
||||
@@ -95,7 +94,7 @@ public class TransferUserFileServiceImpl implements TransferUserFileService {
|
||||
List<UserFileDTO> files = expandUserFileDTO.getFiles();
|
||||
|
||||
// 1. 创建传输发送目录
|
||||
String transferSendDir = fileProperties.getTransferSendDir();
|
||||
String transferSendDir = fileProperties.getTransfer().getSendDir();
|
||||
Path transferPath = Paths.get(transferSendDir);
|
||||
if (!Files.exists(transferPath)) {
|
||||
Files.createDirectories(transferPath);
|
||||
@@ -145,7 +144,5 @@ public class TransferUserFileServiceImpl implements TransferUserFileService {
|
||||
|
||||
log.info("传输文件打包完成: {}", finalFilePath);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.senmesh.sfile.dto.UserFileDTO;
|
||||
import com.senmesh.sfile.dto.UserFileModifyDTO;
|
||||
import com.senmesh.sfile.dto.UserFileModifyStatusDTO;
|
||||
import com.senmesh.sfile.dto.UserFileQueryDTO;
|
||||
import com.senmesh.sfile.dto.UserFileStatisticsDTO;
|
||||
import com.senmesh.sfile.entity.UserFile;
|
||||
import com.senmesh.sfile.service.UserFileService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -175,7 +176,7 @@ public class UserFileServiceImpl implements UserFileService {
|
||||
.fileType(FileTypeEnum.FOLDER.getType())
|
||||
.fileName(folder.getFileName())
|
||||
.parentId(0L)
|
||||
.fileStatus(FileStatusEnum.NORMAL.getStatus())
|
||||
.fileStatus(folder.getFileStatus())
|
||||
.build();
|
||||
UserFileDTO folderDTO = this.create(folderCreateDTO);
|
||||
Long folderId = folderDTO.getId();
|
||||
@@ -196,7 +197,7 @@ public class UserFileServiceImpl implements UserFileService {
|
||||
.fileCode(fileInfo.getFileCode())
|
||||
.parentId(folderId)
|
||||
.parentPath(folderPath)
|
||||
.fileStatus(FileStatusEnum.NORMAL.getStatus())
|
||||
.fileStatus(folder.getFileStatus())
|
||||
.build();
|
||||
|
||||
UserFileDTO createdFile = this.create(fileCreateDTO);
|
||||
@@ -327,5 +328,11 @@ public class UserFileServiceImpl implements UserFileService {
|
||||
Assert.notNull(userFileDTO, "文件不存在");
|
||||
return userFileDTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserFileStatisticsDTO> statisticsByCategory(UserFileQueryDTO queryDTO) {
|
||||
queryDTO.disablePage();
|
||||
return userFileMapper.statisticsByCategory(queryDTO);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,14 +48,15 @@ public class UserSpaceServiceImpl implements UserSpaceService {
|
||||
Long userId = createDTO.getUserId();
|
||||
UserSpaceQueryDTO queryDTO = UserSpaceQueryDTO.builder().userId(userId).build();
|
||||
|
||||
return RedissonUtils.lockAndSave(getLockDTO(userId),
|
||||
UserSpaceDTO userSpaceDTO = RedissonUtils.lockAndSave(getLockDTO(userId),
|
||||
() -> this.find(queryDTO), () -> {
|
||||
UserSpace userSpace = UserSpaceConvert.INSTANCE.toEntity(createDTO);
|
||||
userSpace.setTotalSize(DEFAULT_TOTAL_SIZE);
|
||||
userSpace.setUsedSize(0L);
|
||||
userSpaceMapper.saveEntity(userSpace);
|
||||
return userSpace.getId();
|
||||
return UserSpaceConvert.INSTANCE.toDto(userSpace);
|
||||
});
|
||||
return userSpaceDTO.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -24,6 +24,15 @@ public interface OrgMapMapper {
|
||||
Org toEntity(
|
||||
OrgDTO orgDto);
|
||||
|
||||
/**
|
||||
* entity to dto
|
||||
*
|
||||
* @param org
|
||||
* @return
|
||||
* @author sr on 2024-04-18
|
||||
*/
|
||||
OrgDTO toDto(Org org);
|
||||
|
||||
/**
|
||||
* @param orgCreateDTO
|
||||
* @return
|
||||
|
||||
@@ -80,14 +80,15 @@ public class OrgServiceImpl implements OrgService {
|
||||
Assert.notNull(orgTypeEnum, "机构类型有误");
|
||||
Assert.isTrue(orgTypeEnum != OrgTypeEnum.ORG_TYPE_PLATFORM, "该机构类型不支持创建");
|
||||
String orgName = orgCreateDTO.getOrgName();
|
||||
Long orgId = RedissonUtils.lockAndSave(getLockDTO(orgName),
|
||||
OrgDTO orgDTO = RedissonUtils.lockAndSave(getLockDTO(orgName),
|
||||
() -> this.find(OrgQueryDTO.builder().orgName(orgName).build()), () -> {
|
||||
Org org =
|
||||
OrgMapMapper.INSTANCE.toEntity(orgCreateDTO);
|
||||
initCreateOrg(org);
|
||||
orgMapper.saveEntity(org);
|
||||
return org.getId();
|
||||
return OrgMapMapper.INSTANCE.toDto(org);
|
||||
}, "该机构名称已存在");
|
||||
Long orgId = orgDTO.getId();
|
||||
// 创建管理员用户
|
||||
userService.createOrgUser(OrgUserCreateDTO.builder().orgId(orgId).phone(orgCreateDTO.getPhone()).realName(orgCreateDTO.getRealName())
|
||||
.administrator(Boolean.TRUE).build());
|
||||
|
||||
@@ -44,12 +44,16 @@ java.io.tmpdir=/var/${spring.application.name}/upload/tmpdir
|
||||
|
||||
#文件存储配置
|
||||
file.storage.type=local
|
||||
|
||||
#文件传输配置
|
||||
### 文件位置:1内网2外网
|
||||
file.location=1
|
||||
file.transfer.location=1
|
||||
### 传输发送目录
|
||||
file.transfer-send-dir=D:/work/git/demo/transfer/send
|
||||
file.transfer.send-dir=D:/work/git/demo/transfer/send
|
||||
### 传输接收目录
|
||||
file.transfer-receive-dir=D:/work/git/demo/transfer/receive
|
||||
file.transfer.receive-dir=D:/work/git/demo/transfer/receive
|
||||
### 解包风险校验
|
||||
file.transfer.unpack-risk-check=false
|
||||
|
||||
|
||||
#发号器
|
||||
@@ -138,26 +142,12 @@ sms.numLimit=0
|
||||
sms.phoneSms=
|
||||
|
||||
|
||||
#讯飞配置
|
||||
xf.httpAPIPassword=
|
||||
#在控制台-我的应用获取
|
||||
xf.appId=
|
||||
xf.apiSecret=
|
||||
xf.apiKey=
|
||||
#语音听写地址
|
||||
xf.iatHostUrl=https://iat-api.xfyun.cn/v2/iat
|
||||
#语音合成地址
|
||||
xf.ttsHostUrl=https://tts-api.xfyun.cn/v2/tts
|
||||
#机器翻译niutrans
|
||||
xf.otsHostUrl=https://ntrans.xfyun.cn/v2/ots
|
||||
#实时语音转写
|
||||
xf.rtasr.APIKey=
|
||||
|
||||
#deepseek配置
|
||||
deepseek.httpAPIPassword=
|
||||
|
||||
#ai配置
|
||||
#对话提供者,对应配置的PREFIX
|
||||
ai.chatProvider=deepseek
|
||||
#dify配置
|
||||
dify.enable=false
|
||||
dify.host=https://flow.senmesh.com
|
||||
# 规则生成 API Key
|
||||
dify.risk.rule.api-key=app-agFkKV5EsAEZfCC6wGSDraak
|
||||
# 文件智能风险预警 API Key
|
||||
dify.risk.scan.api-key=app-K9WlRD9hEhLbesUK8HDf3ATP
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user