package org.jeecg.modules.demo.copywriting.controller;
|
|
import java.io.File;
|
import java.io.FileInputStream;
|
import java.util.*;
|
import java.util.stream.Collectors;
|
import java.io.IOException;
|
import java.io.UnsupportedEncodingException;
|
import java.net.URLDecoder;
|
|
import com.alibaba.fastjson2.JSONObject;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.core.io.ByteArrayResource;
|
import org.springframework.http.*;
|
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
import com.github.yulichang.wrapper.MPJLambdaWrapper;
|
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletResponse;
|
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.system.query.QueryGenerator;
|
import org.jeecg.common.system.query.QueryRuleEnum;
|
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.modules.demo.contract.entity.SemanticWord;
|
import org.jeecg.modules.demo.contract.service.ISemanticWordService;
|
import org.jeecg.modules.demo.copywriting.entity.Copywriting;
|
import org.jeecg.modules.demo.copywriting.service.ICopywritingService;
|
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import lombok.extern.slf4j.Slf4j;
|
|
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
|
import org.jeecgframework.poi.excel.entity.ExportParams;
|
import org.jeecgframework.poi.excel.entity.ImportParams;
|
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
|
import org.jeecg.common.system.base.controller.JeecgController;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.http.HttpStatus;
|
import org.springframework.http.ResponseEntity;
|
import org.springframework.util.LinkedMultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
import org.springframework.web.servlet.ModelAndView;
|
import com.alibaba.fastjson.JSON;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.Operation;
|
import org.jeecg.common.aspect.annotation.AutoLog;
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
/**
|
* @Description: 文案
|
* @Author: jeecg-boot
|
* @Date: 2025-10-13
|
* @Version: V1.0
|
*/
|
@Tag(name="文案")
|
@RestController
|
@RequestMapping("/copywriting/copywriting")
|
@Slf4j
|
public class CopywritingController extends JeecgController<Copywriting, ICopywritingService> {
|
@Autowired
|
private ICopywritingService copywritingService;
|
@Autowired
|
private ISemanticWordService semanticWordService;;
|
|
/**
|
* 分页列表查询
|
*
|
* @param copywriting
|
* @param pageNo
|
* @param pageSize
|
* @param req
|
* @return
|
*/
|
//@AutoLog(value = "文案-分页列表查询")
|
@Operation(summary="文案-分页列表查询")
|
@GetMapping(value = "/list")
|
public Result<IPage<Copywriting>> queryPageList(Copywriting copywriting,
|
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
|
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
|
HttpServletRequest req) {
|
|
QueryWrapper<Copywriting> queryWrapper = QueryGenerator.initQueryWrapper(copywriting, req.getParameterMap());
|
|
if (StringUtils.isNotBlank(copywriting.getTitleLike())) {
|
queryWrapper.like("title", copywriting.getTitleLike());
|
}
|
if (StringUtils.isNotBlank(copywriting.getTitleLike()) && StringUtils.isNotBlank(copywriting.getWordLike())) {
|
queryWrapper.or();
|
}
|
if (StringUtils.isNotBlank(copywriting.getWordLike())){
|
queryWrapper.exists("SELECT 1 FROM semantic_word WHERE semantic_word.id = copywriting.word_id " +
|
"AND semantic_word.word LIKE '%" + copywriting.getWordLike() + "%'");
|
|
}
|
Page<Copywriting> page = new Page<Copywriting>(pageNo, pageSize);
|
IPage<Copywriting> pageList = copywritingService.page(page, queryWrapper);
|
for (Copywriting item : pageList.getRecords()) {
|
item.setSemanticWord(semanticWordService.getById(item.getWordId()));
|
}
|
return Result.OK(pageList);
|
}
|
|
/**
|
* 添加
|
*
|
* @param copywriting
|
* @return
|
*/
|
@AutoLog(value = "文案-添加")
|
@Operation(summary="文案-添加")
|
@RequiresPermissions("copywriting:copywriting:add")
|
@PostMapping(value = "/add")
|
public Result<String> add(@RequestBody Copywriting copywriting) {
|
if (copywriting.getOutStatus() == null) {
|
copywriting.setOutStatus("1");
|
}
|
copywritingService.save(copywriting);
|
|
return Result.OK("添加成功!");
|
}
|
|
/**
|
* 编辑
|
*
|
* @param copywriting
|
* @return
|
*/
|
@AutoLog(value = "文案-编辑")
|
@Operation(summary="文案-编辑")
|
@RequiresPermissions("copywriting:copywriting:edit")
|
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
|
public Result<String> edit(@RequestBody Copywriting copywriting) {
|
copywritingService.updateById(copywriting);
|
return Result.OK("编辑成功!");
|
}
|
|
/**
|
* 通过id删除
|
*
|
* @param id
|
* @return
|
*/
|
@AutoLog(value = "文案-通过id删除")
|
@Operation(summary="文案-通过id删除")
|
@RequiresPermissions("copywriting:copywriting:delete")
|
@DeleteMapping(value = "/delete")
|
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
|
copywritingService.removeById(id);
|
return Result.OK("删除成功!");
|
}
|
|
/**
|
* 批量删除
|
*
|
* @param ids
|
* @return
|
*/
|
@AutoLog(value = "文案-批量删除")
|
@Operation(summary="文案-批量删除")
|
@RequiresPermissions("copywriting:copywriting:deleteBatch")
|
@DeleteMapping(value = "/deleteBatch")
|
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
|
this.copywritingService.removeByIds(Arrays.asList(ids.split(",")));
|
return Result.OK("批量删除成功!");
|
}
|
|
/**
|
* 通过id查询
|
*
|
* @param id
|
* @return
|
*/
|
//@AutoLog(value = "文案-通过id查询")
|
@Operation(summary="文案-通过id查询")
|
@GetMapping(value = "/queryById")
|
public Result<Copywriting> queryById(@RequestParam(name="id",required=true) String id) {
|
Copywriting copywriting = copywritingService.getById(id);
|
if(copywriting==null) {
|
return Result.error("未找到对应数据");
|
}
|
return Result.OK(copywriting);
|
}
|
|
/**
|
* 导出excel
|
*
|
* @param request
|
* @param copywriting
|
*/
|
@RequiresPermissions("copywriting:copywriting:exportXls")
|
@RequestMapping(value = "/exportXls")
|
public ModelAndView exportXls(HttpServletRequest request, Copywriting copywriting) {
|
return super.exportXls(request, copywriting, Copywriting.class, "文案");
|
}
|
|
|
@Value("${jeecg.path.upload}")
|
private String uploadPath;
|
/**
|
* 通过excel导入数据
|
*
|
* @param request
|
* @param response
|
* @return
|
*/
|
@RequiresPermissions("copywriting:copywriting:importExcel")
|
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
|
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
|
return super.importExcel(request, response, Copywriting.class);
|
}
|
|
|
@RequiresPermissions("copywriting:copywriting:aiCreateCopyWriting")
|
@RequestMapping(value = "/aiCreateCopyWriting", method = RequestMethod.POST)
|
public Result<?> aiCreateCopyWriting(
|
@RequestParam("jianli") String jianli,
|
@RequestParam String wenanyaoqiu,
|
@RequestParam String louchu,
|
@RequestParam String youshang,
|
@RequestParam String wenti,
|
@RequestParam String user) {
|
if (jianli == null || jianli.equals("")) {
|
return Result.error("请选择文件");
|
}
|
// 配置信息
|
String serverFileRoot = uploadPath;
|
String workflowUrl = "http://14.103.174.44/v1/workflows/run";
|
String fileUploadUrl = "http://14.103.174.44/v1/files/upload"; // 文件上传接口(假设)
|
String authToken = "app-J1Tqytg0ZetcrVTF2fVHHY8B";
|
String userId = user;
|
String appId = "cf85fe4d-b76b-4c4c-801a-1336c880d473";
|
|
try {
|
// 步骤1:上传简历文件,获取 upload_file_id 列表
|
List<String> jianliFileList = Arrays.asList(jianli.split(","));
|
List<String> jianliFileIds = new ArrayList<>();
|
for (String fileName : jianliFileList) {
|
// 修正:只过滤路径遍历字符,保留合法的 /
|
String safeFileName = File.separator + fileName.trim()
|
// 过滤 ../ 和 ./ 序列(防止访问上级目录)
|
.replaceAll("\\.\\./", "")
|
.replaceAll("\\./", "");
|
|
// 进一步安全校验:确保拼接后的文件路径在服务器根目录下(核心安全措施)
|
File file = new File(serverFileRoot + safeFileName);
|
String canonicalPath = file.getCanonicalPath(); // 获取标准化路径(自动解析 ../ 等)
|
String canonicalRootPath = new File(serverFileRoot).getCanonicalPath();
|
|
// 校验:如果文件路径不在服务器根目录下,视为非法请求
|
if (!canonicalPath.startsWith(canonicalRootPath)) {
|
throw new RuntimeException("非法文件访问:" + fileName);
|
}
|
|
// 再判断文件是否存在
|
if (!file.exists() || !file.isFile()) {
|
return Result.error("服务器不存在文件:" + safeFileName + ",路径:" + file.getAbsolutePath());
|
}
|
// 调用文件上传接口,获取 upload_file_id
|
String fileId = uploadFileToServer(file, fileUploadUrl, authToken);
|
jianliFileIds.add(fileId);
|
}
|
|
// 步骤2:构建 inputs 参数(按接口要求格式)
|
Map<String, Object> inputs = new HashMap<>();
|
|
// 处理简历文件(jianli 是 variable_name,对应接口的 {variable_name})
|
if (!jianliFileIds.isEmpty()) {
|
// 若支持多个文件,可能需要数组形式;单个文件则直接放对象
|
List<Map<String, String>> jianliFiles = new ArrayList<>();
|
for (String fileId : jianliFileIds) {
|
Map<String, String> fileInfo = new HashMap<>();
|
fileInfo.put("transfer_method", "local_file"); // 固定值,接口要求
|
fileInfo.put("upload_file_id", fileId); // 上传文件返回的ID
|
fileInfo.put("type", "document"); // 文件类型,如 document/image 等(按接口要求)
|
jianliFiles.add(fileInfo);
|
}
|
inputs.put("jianli", jianliFiles); // jianli 对应 {variable_name}
|
} else {
|
inputs.put("jianli", new ArrayList<>()); // 空文件列表
|
}
|
|
// 添加其他文本参数
|
inputs.put("wenanyaoqiu", wenanyaoqiu);
|
inputs.put("louchu", louchu);
|
inputs.put("youshang", youshang);
|
inputs.put("wenti", wenti);
|
|
// 添加系统参数
|
inputs.put("sys.user_id", userId);
|
inputs.put("sys.app_id", appId);
|
|
// 步骤3:构建完整请求体
|
Map<String, Object> requestBody = new HashMap<>();
|
requestBody.put("inputs", inputs); // 顶层 inputs 容器
|
requestBody.put("user", user); // 顶层 inputs 容器
|
|
// 步骤4:调用工作流接口
|
RestTemplate restTemplate = new RestTemplate();
|
HttpHeaders headers = new HttpHeaders();
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
headers.set("Authorization", "Bearer " + authToken);
|
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
|
ResponseEntity<String> response = restTemplate.postForEntity(workflowUrl, requestEntity, String.class);
|
|
if (response.getStatusCode() == HttpStatus.OK) {
|
return Result.OK("文案生成成功", JSONObject.parseObject(response.getBody()).getJSONObject("data").getJSONObject("outputs").getString("http"));
|
} else {
|
return Result.error("工作流接口异常,状态码:" + response.getStatusCodeValue());
|
}
|
|
} catch (NullPointerException e) {
|
e.printStackTrace();
|
return Result.error("不支持的文件格式:"+jianli.split("\\.")[jianli.split("\\.").length-1]);
|
} catch (Exception e) {
|
e.printStackTrace();
|
return Result.error("生成文案异常:" + e.getMessage());
|
}
|
}
|
|
/**
|
* 调用文件上传接口,获取 upload_file_id(修正版)
|
*/
|
private String uploadFileToServer(File file, String uploadUrl, String authToken) throws Exception {
|
// 构建文件上传请求(multipart/form-data 格式)
|
HttpHeaders headers = new HttpHeaders();
|
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
|
headers.set("Authorization", "Bearer " + authToken);
|
|
// 读取文件内容
|
byte[] fileBytes = new byte[(int) file.length()];
|
try (FileInputStream fis = new FileInputStream(file)) {
|
fis.read(fileBytes);
|
}
|
|
// 构建多部分请求体
|
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
|
parts.add("file", new ByteArrayResource(fileBytes) {
|
@Override
|
public String getFilename() {
|
return file.getName(); // 必须设置文件名
|
}
|
});
|
|
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(parts, headers);
|
RestTemplate restTemplate = new RestTemplate();
|
ResponseEntity<Map> response = restTemplate.postForEntity(uploadUrl, requestEntity, Map.class);
|
|
// 修正:只要状态码是200 OK,且包含id字段,就是上传成功
|
if ((response.getStatusCode() == HttpStatus.OK || response.getStatusCode() == HttpStatus.CREATED) && response.getBody() != null) {
|
Object fileId = response.getBody().get("id");
|
if (fileId != null) {
|
return fileId.toString(); // 成功返回upload_file_id
|
} else {
|
throw new RuntimeException("文件上传成功,但未返回id字段,响应:" + response.getBody());
|
}
|
} else {
|
throw new RuntimeException("文件上传失败,状态码:" + response.getStatusCode() + ",响应:" + response.getBody());
|
}
|
}
|
}
|