feat(config): 添加上传配置并重构文件上传路径管理

- 新增 UploadConfig 配置类统一管理上传路径
- 将硬编码的上传目录路径改为配置驱动
- 添加 EscapeCharacterUtils 工具类处理转义字符
- 修复 application-dev.yml 和 application-prod.yml 中的上传路径格式
- 在 SkillGenServiceImpl 中集成转义字符清理功能
- 更新 CommonController 使用配置类管理上传目录
This commit is contained in:
wangzhiwei 2026-03-04 14:48:50 +08:00
parent 11bc1959f0
commit af0ae4bac1
7 changed files with 138 additions and 11 deletions

View File

@ -0,0 +1,48 @@
package com.kexue.skills.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 上传配置类
* 用于读取web.upload配置
*/
@Data
@Component
@ConfigurationProperties(prefix = "web.upload")
public class UploadConfig {
/**
* 上传路径
*/
private String path;
/**
* 文件上传目录
*/
public String getFileUploadDir() {
return path + "file/";
}
/**
* 图片上传目录
*/
public String getImgUploadDir() {
return path + "images/";
}
/**
* 文件访问路径前缀
*/
public String getFileUrlPrefix() {
return "/upload/file/";
}
/**
* 图片访问路径前缀
*/
public String getImgUrlPrefix() {
return "/upload/images/";
}
}

View File

@ -1,6 +1,7 @@
package com.kexue.skills.controller; package com.kexue.skills.controller;
import com.kexue.skills.common.CommonResult; import com.kexue.skills.common.CommonResult;
import com.kexue.skills.config.UploadConfig;
import com.kexue.skills.entity.request.UploadResponse; import com.kexue.skills.entity.request.UploadResponse;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@ -8,6 +9,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@ -21,13 +23,13 @@ import java.nio.file.StandardCopyOption;
*/ */
@RestController @RestController
@RequestMapping("api/common") @RequestMapping("api/common")
@Tag(name = "公共 Api") @Tag(name = "Common Api")
@CrossOrigin(origins = "*") @CrossOrigin(origins = "*")
@Slf4j @Slf4j
public class CommonController { public class CommonController {
private static final String FILE_UPLOAD_DIR = "/data/service/hyxp-portal/upload/file/"; @Resource
private static final String IMG_UPLOAD_DIR = "/data/service/hyxp-portal/upload/images/"; private UploadConfig uploadConfig;
/** /**
@ -49,7 +51,7 @@ public class CommonController {
try { try {
// 创建上传目录如果不存在 // 创建上传目录如果不存在
Path uploadPath = Paths.get(FILE_UPLOAD_DIR); Path uploadPath = Paths.get(uploadConfig.getFileUploadDir());
if (!Files.exists(uploadPath)) { if (!Files.exists(uploadPath)) {
Files.createDirectories(uploadPath); Files.createDirectories(uploadPath);
} }
@ -62,7 +64,7 @@ public class CommonController {
UploadResponse uploadResponse = new UploadResponse(); UploadResponse uploadResponse = new UploadResponse();
uploadResponse.setFileName(file.getOriginalFilename()); uploadResponse.setFileName(file.getOriginalFilename());
uploadResponse.setFileUrl("/upload/file/" + file.getOriginalFilename()); uploadResponse.setFileUrl(uploadConfig.getFileUrlPrefix() + file.getOriginalFilename());
return CommonResult.success(uploadResponse); return CommonResult.success(uploadResponse);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
@ -94,7 +96,7 @@ public class CommonController {
try { try {
// 创建上传目录如果不存在 // 创建上传目录如果不存在
Path uploadPath = Paths.get(IMG_UPLOAD_DIR); Path uploadPath = Paths.get(uploadConfig.getImgUploadDir());
if (!Files.exists(uploadPath)) { if (!Files.exists(uploadPath)) {
Files.createDirectories(uploadPath); Files.createDirectories(uploadPath);
} }
@ -107,7 +109,7 @@ public class CommonController {
UploadResponse uploadResponse = new UploadResponse(); UploadResponse uploadResponse = new UploadResponse();
uploadResponse.setFileName(image.getOriginalFilename()); uploadResponse.setFileName(image.getOriginalFilename());
uploadResponse.setFileUrl("/upload/images/" + image.getOriginalFilename()); uploadResponse.setFileUrl(uploadConfig.getImgUrlPrefix() + image.getOriginalFilename());
return CommonResult.success(uploadResponse); return CommonResult.success(uploadResponse);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();

View File

@ -17,6 +17,7 @@ import com.kexue.skills.entity.response.SkillResponse;
import com.kexue.skills.mapper.CmsContentMapper; import com.kexue.skills.mapper.CmsContentMapper;
import com.kexue.skills.service.CmsTagService; import com.kexue.skills.service.CmsTagService;
import com.kexue.skills.service.SkillGenService; import com.kexue.skills.service.SkillGenService;
import com.kexue.skills.utils.EscapeCharacterUtils;
import jodd.util.StringUtil; import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -215,7 +216,7 @@ public class SkillGenServiceImpl implements SkillGenService {
} }
} }
} }
String systemContent = "你是一个专业的AI技能设计助手。请基于用户提供的Skill名称、描述、标签按照skills目录结构输出完整的skills内容包括skills.md本体内容、scripts目录中的脚本等并打包成一个YAML文件技能包。请严格遵循以下规范1. 包含必需的文件和目录2. 多行内容使用 | 字面块3. 内容从行首开始4. 空目录用 children: [] 表示5. 文件内容要实际有用6.输出一个完整的YAML文档对于每个节点的内容要输出type文件对应file目录对应directory每个节点都必须有name和content属性,无需其他额外说明。"; String systemContent = "你是一个专业的AI技能设计助手。请基于用户提供的Skill名称、描述、标签按照skills目录结构输出完整的skills内容包括skills.md本体内容、scripts目录中的脚本等并打包成一个YAML文件技能包。请严格遵循以下规范1. 包含必需的文件和目录2. 多行内容使用 | 字面块3. 内容从行首开始4. 空目录用 children: [] 表示5. 文件内容要实际有用6.输出一个完整的YAML文档概要含核心属性name、version、description、author、created、tags 等,其中 structure 为核心节点,用于描述 skill 包的文件目录结构structure 下的每个节点均含基础属性name、type、path、format、descriptioncontent 和 children 为互选属性,由 type 决定type 为 file 时,展示文件具体内容在 content 字段type 为 directory 时,展示子目录 / 文件节点在 children [] 数组中,无需其他额外说明。";
String userContent = "请根据以下Skill信息生成skills.md文档内容Skill名称SKILL_NAME,Skill描述DESCRIPTION,Skill标签TAGS 摘要SUMMARY。"; String userContent = "请根据以下Skill信息生成skills.md文档内容Skill名称SKILL_NAME,Skill描述DESCRIPTION,Skill标签TAGS 摘要SUMMARY。";
userContent = userContent.replace("SKILL_NAME", request.getName()).replace("DESCRIPTION", request.getDescription()).replace("TAGS", tagsList.toString()).replace("SUMMARY", request.getRequirement()); userContent = userContent.replace("SKILL_NAME", request.getName()).replace("DESCRIPTION", request.getDescription()).replace("TAGS", tagsList.toString()).replace("SUMMARY", request.getRequirement());
SkillRequest skillRequest = new SkillRequest(true, deepSeekConfig.getChat().getModel(),systemContent,userContent,deepSeekConfig.getChat().getTemperature(), 8192,"text"); SkillRequest skillRequest = new SkillRequest(true, deepSeekConfig.getChat().getModel(),systemContent,userContent,deepSeekConfig.getChat().getTemperature(), 8192,"text");
@ -225,6 +226,7 @@ public class SkillGenServiceImpl implements SkillGenService {
log.info("Deepseek API响应: {}", deepseekResponse); log.info("Deepseek API响应: {}", deepseekResponse);
JSONObject responseJson = JSON.parseObject(deepseekResponse); JSONObject responseJson = JSON.parseObject(deepseekResponse);
String content = responseJson.getJSONArray("choices").toJavaList(JSONObject.class).get(0).getJSONObject("message").getString("content"); String content = responseJson.getJSONArray("choices").toJavaList(JSONObject.class).get(0).getJSONObject("message").getString("content");
content = EscapeCharacterUtils.removeEscapeCharacters( content);//去除转义字符
CmsContent cmsContent = getCmsContent(request, content, StpUtil.getLoginIdAsLong(),defaultIcon); CmsContent cmsContent = getCmsContent(request, content, StpUtil.getLoginIdAsLong(),defaultIcon);
// 保存到数据库 // 保存到数据库
cmsContentMapper.insert(cmsContent); cmsContentMapper.insert(cmsContent);
@ -300,7 +302,7 @@ public class SkillGenServiceImpl implements SkillGenService {
if (choices != null && !choices.isEmpty()) { if (choices != null && !choices.isEmpty()) {
JSONObject latestChoice = choices.get(0); JSONObject latestChoice = choices.get(0);
JSONObject message = latestChoice.getJSONObject("message"); JSONObject message = latestChoice.getJSONObject("message");
return message.getString("content"); return EscapeCharacterUtils.removeEscapeCharacters( message.getString("content"));//去除转义字符
} }
} catch (Exception e) { } catch (Exception e) {
log.error("调用Deepseek API失败: {}", e.getMessage(), e); log.error("调用Deepseek API失败: {}", e.getMessage(), e);

File diff suppressed because one or more lines are too long

View File

@ -103,7 +103,7 @@ jetcache:
web: web:
upload: upload:
path: /kexue/agent-skills/upload/ path: /kexue/agentSkills/upload/
# 支付配置 # 支付配置

View File

@ -100,7 +100,7 @@ jetcache:
web: web:
upload: upload:
path: /kexue/agent-skills/upload/ path: /kexue/agentSkills/upload/
payment: payment:
# 微信支付配置 # 微信支付配置

View File

@ -89,3 +89,8 @@ sms:
template-param-name: code template-param-name: code
template-cache: true template-cache: true
# 上传配置
web:
upload:
path: /kexue/agentSkills/upload/