Commit a4ab06ac3a4f7fe8e140921f7647a610b763f270

Authored by 王彪总
1 parent c3129ce2

fix(config): 更新配置文件和修复分页计算问题

- 在.gitignore中添加.mcp.json文件忽略
- 更新application-dev.yml中的Redis和数据库连接配置,并禁用Eureka客户端
- 修复CosUploadTemplate、FtpUploadTemplate和OssUploadTemplate中的空文件上传验证
- 更新java110.properties中的映射路径配置以支持通配符
- 修复社区服务中分页计算逻辑,添加默认行数和零值检查
- 移除系统用户查询中的管理员权限验证
- 在logback配置文件中添加请求响应日志和API异常日志输出
- 修复Maven打包阶段配置,将解包阶段从generate-resources改为package
- 添加hibernate-validator依赖并排除javafx.base冲突
- 扩展文件上传组件以支持multipart文件上传和IP地址获取功能
service-api/src/main/java/com/java110/api/controller/component/CallComponentController.java
@@ -337,21 +337,38 @@ public class CallComponentController extends DefaultAbstractComponentSMO { @@ -337,21 +337,38 @@ public class CallComponentController extends DefaultAbstractComponentSMO {
337 337
338 /** 338 /**
339 * APK 文件下载代理 339 * APK 文件下载代理
340 - * 通过后端代理下载OSS上的APK文件,避免OSS禁止APK公网分发的问题 340 + * 优先从服务器本地 /park/apk/ 目录读取,如果不存在则回退到 OSS
341 */ 341 */
342 @RequestMapping(path = "/app/downloadApk") 342 @RequestMapping(path = "/app/downloadApk")
343 public void downloadApk(@RequestParam String file, HttpServletResponse response) { 343 public void downloadApk(@RequestParam String file, HttpServletResponse response) {
344 InputStream is = null; 344 InputStream is = null;
345 OutputStream os = null; 345 OutputStream os = null;
346 try { 346 try {
347 - Object componentInstance = ApplicationContextFactory.getBean("ossUploadTemplate");  
348 - Method m = componentInstance.getClass().getDeclaredMethod("download", String.class);  
349 - is = (InputStream) m.invoke(componentInstance, file); 347 + // 安全检查:防止路径穿越
  348 + String fileName = file.replace("\\", "/");
  349 + if (fileName.contains("..") || fileName.contains("./")) {
  350 + response.sendError(HttpServletResponse.SC_FORBIDDEN, "非法文件路径");
  351 + return;
  352 + }
  353 +
  354 + // 优先从本地 /park/apk/ 读取
  355 + java.io.File apkFile = new java.io.File("/park/apk/" + fileName);
  356 + if (apkFile.exists()) {
  357 + response.setContentType("application/vnd.android.package-archive");
  358 + response.setHeader("Content-Disposition", "attachment; filename=\"" + apkFile.getName() + "\"");
  359 + response.setContentLengthLong(apkFile.length());
  360 + is = new java.io.FileInputStream(apkFile);
  361 + } else {
  362 + // 回退到 OSS
  363 + Object componentInstance = ApplicationContextFactory.getBean("ossUploadTemplate");
  364 + Method m = componentInstance.getClass().getDeclaredMethod("download", String.class);
  365 + is = (InputStream) m.invoke(componentInstance, file);
  366 + response.setContentType("application/vnd.android.package-archive");
  367 + response.setHeader("Content-Disposition", "attachment; filename=\"app-release.apk\"");
  368 + }
350 369
351 - response.setContentType("application/vnd.android.package-archive");  
352 - response.setHeader("Content-Disposition", "attachment; filename=\"app-release.apk\"");  
353 os = response.getOutputStream(); 370 os = response.getOutputStream();
354 - byte[] buffer = new byte[4096]; 371 + byte[] buffer = new byte[8192];
355 int len; 372 int len;
356 while ((len = is.read(buffer)) != -1) { 373 while ((len = is.read(buffer)) != -1) {
357 os.write(buffer, 0, len); 374 os.write(buffer, 0, len);
service-api/src/main/java/com/java110/api/smo/file/impl/AddFileSMOImpl.java
@@ -27,6 +27,8 @@ import org.springframework.web.multipart.MultipartFile; @@ -27,6 +27,8 @@ import org.springframework.web.multipart.MultipartFile;
27 27
28 import com.java110.vo.ResultVo; 28 import com.java110.vo.ResultVo;
29 29
  30 +import java.io.File;
  31 +import java.io.FileOutputStream;
30 import java.io.IOException; 32 import java.io.IOException;
31 import java.io.InputStream; 33 import java.io.InputStream;
32 import java.util.UUID; 34 import java.util.UUID;
@@ -70,6 +72,30 @@ public class AddFileSMOImpl extends DefaultAbstractComponentSMO implements IAddF @@ -70,6 +72,30 @@ public class AddFileSMOImpl extends DefaultAbstractComponentSMO implements IAddF
70 Assert.hasKeyAndValue(paramIn, "suffix", "必填,请填写文件类型"); 72 Assert.hasKeyAndValue(paramIn, "suffix", "必填,请填写文件类型");
71 73
72 String suffix = paramIn.getString("suffix"); 74 String suffix = paramIn.getString("suffix");
  75 +
  76 + // APK 文件保存到本地磁盘 /park/apk/
  77 + if ("apk".equalsIgnoreCase(suffix)) {
  78 + String apkFileName = UUID.randomUUID().toString() + ".apk";
  79 + String apkDir = "/park/apk/";
  80 + File dir = new File(apkDir);
  81 + if (!dir.exists()) dir.mkdirs();
  82 + File apkFile = new File(apkDir + apkFileName);
  83 + is = uploadFile.getInputStream();
  84 + FileOutputStream fos = new FileOutputStream(apkFile);
  85 + byte[] buf = new byte[8192];
  86 + int len;
  87 + while ((len = is.read(buf)) != -1) {
  88 + fos.write(buf, 0, len);
  89 + }
  90 + fos.close();
  91 + is.close();
  92 +
  93 + JSONObject outParam = new JSONObject();
  94 + outParam.put("fileId", "apk/" + apkFileName);
  95 + outParam.put("url", "/app/downloadApk?file=apk/" + apkFileName);
  96 + return new ResponseEntity<>(outParam.toJSONString(), HttpStatus.OK);
  97 + }
  98 +
73 String datePath = DateUtil.getNowII(); 99 String datePath = DateUtil.getNowII();
74 String urlPath = IMAGE_DEFAULT_PATH + datePath + "/" + UUID.randomUUID().toString() + "." + suffix; 100 String urlPath = IMAGE_DEFAULT_PATH + datePath + "/" + UUID.randomUUID().toString() + "." + suffix;
75 101
service-community/src/main/java/com/java110/community/cmd/inspectionItemTitle/ListInspectionItemTitleCmd.java
@@ -95,6 +95,10 @@ public class ListInspectionItemTitleCmd extends Cmd { @@ -95,6 +95,10 @@ public class ListInspectionItemTitleCmd extends Cmd {
95 */ 95 */
96 @Override 96 @Override
97 public void doCmd(CmdEvent event, ICmdDataFlowContext cmdDataFlowContext, JSONObject reqJson) throws CmdException { 97 public void doCmd(CmdEvent event, ICmdDataFlowContext cmdDataFlowContext, JSONObject reqJson) throws CmdException {
  98 + // 兼容前端传参 itemTitleId → itemId
  99 + if (reqJson.containsKey("itemTitleId") && !reqJson.containsKey("itemId")) {
  100 + reqJson.put("itemId", reqJson.getString("itemTitleId"));
  101 + }
98 // 将请求JSON转换为巡检项目标题DTO对象 102 // 将请求JSON转换为巡检项目标题DTO对象
99 InspectionItemTitleDto inspectionItemTitleDto = BeanConvertUtil.covertBean(reqJson, InspectionItemTitleDto.class); 103 InspectionItemTitleDto inspectionItemTitleDto = BeanConvertUtil.covertBean(reqJson, InspectionItemTitleDto.class);
100 104