新增打印据编号字段
新增保存图片到本地磁盘D盘接口
This commit is contained in:
@@ -123,6 +123,7 @@ public class SecurityConfig
|
|||||||
"/ws/**",
|
"/ws/**",
|
||||||
"/photo/**",
|
"/photo/**",
|
||||||
"/wisdom/stock/**",
|
"/wisdom/stock/**",
|
||||||
|
"/system/media/**",
|
||||||
"/wisdom/**",
|
"/wisdom/**",
|
||||||
"/mock/**",
|
"/mock/**",
|
||||||
"/information/device/**",
|
"/information/device/**",
|
||||||
|
|||||||
@@ -0,0 +1,464 @@
|
|||||||
|
//package com.zg.project.wisdom.controller;
|
||||||
|
//
|
||||||
|
//import com.zg.framework.web.domain.AjaxResult;
|
||||||
|
//import org.apache.commons.lang3.StringUtils;
|
||||||
|
//import org.springframework.http.MediaType;
|
||||||
|
//import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
|
//import org.springframework.util.unit.DataSize;
|
||||||
|
//import org.springframework.web.bind.annotation.*;
|
||||||
|
//import org.springframework.web.multipart.MultipartFile;
|
||||||
|
//
|
||||||
|
//import javax.annotation.Resource;
|
||||||
|
//import java.io.IOException;
|
||||||
|
//import java.io.InputStream;
|
||||||
|
//import java.io.OutputStream;
|
||||||
|
//import java.nio.file.*;
|
||||||
|
//import java.util.*;
|
||||||
|
//import java.util.concurrent.CompletableFuture;
|
||||||
|
//import java.util.concurrent.Semaphore;
|
||||||
|
//
|
||||||
|
///**
|
||||||
|
// * 多媒体上传控制器(支持图片与视频并行落盘)
|
||||||
|
// */
|
||||||
|
//@RestController
|
||||||
|
//@RequestMapping("/system/media")
|
||||||
|
//public class MediaUploadController {
|
||||||
|
//
|
||||||
|
// /** 根目录(如需配置化,可改为从 application.yml 读取) */
|
||||||
|
// private static final Path ROOT_DIR = Paths.get("D:/uploads");
|
||||||
|
//
|
||||||
|
// /** 本次上传总大小限制:100MB */
|
||||||
|
// private static final long MAX_TOTAL_BYTES = DataSize.ofMegabytes(100).toBytes();
|
||||||
|
//
|
||||||
|
// /** 图片/视频数量限制 */
|
||||||
|
// private static final int MAX_IMAGE_COUNT = 100;
|
||||||
|
// private static final int MAX_VIDEO_COUNT = 5;
|
||||||
|
//
|
||||||
|
// /** 单次请求内的并发上限(建议 2~4;默认 4) */
|
||||||
|
// private static final int PER_REQUEST_CONCURRENCY = 4;
|
||||||
|
//
|
||||||
|
// /** 注入线程池 Bean:threadPoolTaskExecutor */
|
||||||
|
// @Resource(name = "threadPoolTaskExecutor")
|
||||||
|
// private ThreadPoolTaskExecutor executor;
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 上传接口
|
||||||
|
// */
|
||||||
|
// @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
|
// public AjaxResult upload(
|
||||||
|
// @RequestParam("username") String username,
|
||||||
|
// @RequestParam("nameBase") String nameBase,
|
||||||
|
// @RequestParam(value = "imageNames", required = false) String imageNames,
|
||||||
|
// @RequestParam(value = "videoNames", required = false) String videoNames,
|
||||||
|
// @RequestPart(value = "images", required = false) MultipartFile[] images,
|
||||||
|
// @RequestPart(value = "videos", required = false) MultipartFile[] videos
|
||||||
|
// ) {
|
||||||
|
// try {
|
||||||
|
// // 1. 基础校验
|
||||||
|
// if (StringUtils.isBlank(username)) {
|
||||||
|
// return AjaxResult.error("username 不能为空");
|
||||||
|
// }
|
||||||
|
// if (StringUtils.isBlank(nameBase)) {
|
||||||
|
// return AjaxResult.error("nameBase(命名信息)不能为空");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// int imageCount = images == null ? 0 : images.length;
|
||||||
|
// int videoCount = videos == null ? 0 : videos.length;
|
||||||
|
//
|
||||||
|
// if (imageCount == 0 && videoCount == 0) {
|
||||||
|
// return AjaxResult.error("请至少上传一张图片或一段视频");
|
||||||
|
// }
|
||||||
|
// if (imageCount > MAX_IMAGE_COUNT) {
|
||||||
|
// return AjaxResult.error("图片最多支持上传 " + MAX_IMAGE_COUNT + " 张");
|
||||||
|
// }
|
||||||
|
// if (videoCount > MAX_VIDEO_COUNT) {
|
||||||
|
// return AjaxResult.error("视频最多支持上传 " + MAX_VIDEO_COUNT + " 段");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 2. 总体积校验
|
||||||
|
// long totalBytes = 0L;
|
||||||
|
// if (images != null) for (MultipartFile f : images) totalBytes += safeSize(f);
|
||||||
|
// if (videos != null) for (MultipartFile f : videos) totalBytes += safeSize(f);
|
||||||
|
// if (totalBytes > MAX_TOTAL_BYTES) {
|
||||||
|
// return AjaxResult.error("本次上传总大小超过 100 MB(约 " + (totalBytes / 1024 / 1024) + " MB)");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 3. 目标目录
|
||||||
|
// String base = sanitize(nameBase);
|
||||||
|
// String user = sanitize(username);
|
||||||
|
// String folderName = base + "_" + user;
|
||||||
|
// Path targetDir = ROOT_DIR.resolve(folderName).normalize();
|
||||||
|
// if (!targetDir.startsWith(ROOT_DIR)) {
|
||||||
|
// return AjaxResult.error("非法路径");
|
||||||
|
// }
|
||||||
|
// Files.createDirectories(targetDir);
|
||||||
|
//
|
||||||
|
// // 4. 解析前端传递的文件名
|
||||||
|
// List<String> imageNameList = new ArrayList<>();
|
||||||
|
// List<String> videoNameList = new ArrayList<>();
|
||||||
|
//
|
||||||
|
// if (StringUtils.isNotBlank(imageNames)) {
|
||||||
|
// try {
|
||||||
|
// imageNameList = Arrays.asList(imageNames.split(","));
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// // 如果解析失败,使用空列表
|
||||||
|
// imageNameList = new ArrayList<>();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (StringUtils.isNotBlank(videoNames)) {
|
||||||
|
// try {
|
||||||
|
// videoNameList = Arrays.asList(videoNames.split(","));
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// // 如果解析失败,使用空列表
|
||||||
|
// videoNameList = new ArrayList<>();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 5. 并发落盘任务
|
||||||
|
// int seq = 1;
|
||||||
|
// List<CompletableFuture<Map<String, Object>>> futures = new ArrayList<>();
|
||||||
|
// Semaphore semaphore = new Semaphore(PER_REQUEST_CONCURRENCY);
|
||||||
|
//
|
||||||
|
// // 5.1 图片处理
|
||||||
|
// if (images != null) {
|
||||||
|
// for (int i = 0; i < images.length; i++) {
|
||||||
|
// MultipartFile img = images[i];
|
||||||
|
// if (img == null || img.isEmpty()) continue;
|
||||||
|
//
|
||||||
|
// // 使用前端传递的文件名,如果没有则从原始文件名获取扩展名
|
||||||
|
// String originalName = i < imageNameList.size() ? imageNameList.get(i) : img.getOriginalFilename();
|
||||||
|
// String ext = getExtension(originalName).toLowerCase(Locale.ROOT);
|
||||||
|
// if (StringUtils.isBlank(ext)) {
|
||||||
|
// ext = "jpg"; // 图片默认扩展名
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// final String filename = String.format("%s%s%03d.%s", base, user, seq++, ext);
|
||||||
|
// final Path dest = targetDir.resolve(filename).normalize();
|
||||||
|
//
|
||||||
|
// futures.add(CompletableFuture.supplyAsync(() -> {
|
||||||
|
// acquire(semaphore);
|
||||||
|
// try { return saveOne(img, dest, "image"); }
|
||||||
|
// finally { semaphore.release(); }
|
||||||
|
// }, executor));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 5.2 视频处理
|
||||||
|
// if (videos != null) {
|
||||||
|
// for (int i = 0; i < videos.length; i++) {
|
||||||
|
// MultipartFile vid = videos[i];
|
||||||
|
// if (vid == null || vid.isEmpty()) continue;
|
||||||
|
//
|
||||||
|
// // 使用前端传递的文件名,如果没有则从原始文件名获取扩展名
|
||||||
|
// String originalName = i < videoNameList.size() ? videoNameList.get(i) : vid.getOriginalFilename();
|
||||||
|
// String ext = getExtension(originalName).toLowerCase(Locale.ROOT);
|
||||||
|
// if (StringUtils.isBlank(ext)) {
|
||||||
|
// ext = "mp4"; // 视频默认扩展名
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// final String filename = String.format("%s%s%03d.%s", base, user, seq++, ext);
|
||||||
|
// final Path dest = targetDir.resolve(filename).normalize();
|
||||||
|
//
|
||||||
|
// futures.add(CompletableFuture.supplyAsync(() -> {
|
||||||
|
// acquire(semaphore);
|
||||||
|
// try { return saveOne(vid, dest, "video"); }
|
||||||
|
// finally { semaphore.release(); }
|
||||||
|
// }, executor));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // 6. 等待完成并返回
|
||||||
|
// List<Map<String, Object>> files = new ArrayList<>(futures.size());
|
||||||
|
// for (CompletableFuture<Map<String, Object>> f : futures) {
|
||||||
|
// files.add(f.join());
|
||||||
|
// }
|
||||||
|
// files.sort(Comparator.comparing(m -> String.valueOf(m.get("path"))));
|
||||||
|
//
|
||||||
|
// Map<String, Object> data = new LinkedHashMap<>();
|
||||||
|
// data.put("folder", targetDir.toString());
|
||||||
|
// data.put("username", username);
|
||||||
|
// data.put("nameBase", nameBase);
|
||||||
|
// data.put("totalBytes", totalBytes);
|
||||||
|
// data.put("count", files.size());
|
||||||
|
// data.put("files", files);
|
||||||
|
//
|
||||||
|
// return AjaxResult.success("上传成功", data);
|
||||||
|
//
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// return AjaxResult.error("保存文件失败:" + e.getMessage());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // ========================= 辅助方法 =========================
|
||||||
|
//
|
||||||
|
// /** 安全获取文件大小,避免 NPE */
|
||||||
|
// private static long safeSize(MultipartFile f) {
|
||||||
|
// try { return (f == null) ? 0L : f.getSize(); }
|
||||||
|
// catch (Exception ignored) { return 0L; }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /** 获取扩展名(无则返回空字符串) */
|
||||||
|
// private static String getExtension(String originalName) {
|
||||||
|
// if (StringUtils.isBlank(originalName)) return "";
|
||||||
|
// int i = originalName.lastIndexOf('.');
|
||||||
|
// return (i >= 0 && i < originalName.length() - 1) ? originalName.substring(i + 1) : "";
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /** 单文件保存 */
|
||||||
|
// private Map<String, Object> saveOne(MultipartFile src, Path dest, String type) {
|
||||||
|
// try {
|
||||||
|
// Path parent = dest.getParent();
|
||||||
|
// if (parent == null) throw new IOException("父目录为空");
|
||||||
|
// if (!dest.normalize().startsWith(parent.normalize())) throw new IOException("非法路径");
|
||||||
|
//
|
||||||
|
// try (InputStream in = src.getInputStream();
|
||||||
|
// OutputStream out = Files.newOutputStream(dest,
|
||||||
|
// StandardOpenOption.CREATE,
|
||||||
|
// StandardOpenOption.TRUNCATE_EXISTING,
|
||||||
|
// StandardOpenOption.WRITE)) {
|
||||||
|
// in.transferTo(out);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Map<String, Object> m = new LinkedHashMap<>();
|
||||||
|
// m.put("type", type);
|
||||||
|
// m.put("path", dest.toString());
|
||||||
|
// m.put("sizeBytes", src.getSize());
|
||||||
|
// m.put("sizeMB", String.format(Locale.ROOT, "%.2f", src.getSize() / 1024.0 / 1024.0));
|
||||||
|
// return m;
|
||||||
|
//
|
||||||
|
// } catch (Exception ex) {
|
||||||
|
// throw new RuntimeException("保存失败:" + dest.getFileName() + ",原因:" + ex.getMessage(), ex);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /** 获取信号量许可证(受控并发) */
|
||||||
|
// private static void acquire(Semaphore sem) {
|
||||||
|
// try { sem.acquire(); }
|
||||||
|
// catch (InterruptedException e) {
|
||||||
|
// Thread.currentThread().interrupt();
|
||||||
|
// throw new RuntimeException("线程被中断", e);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /** 文件名/目录名清洗 */
|
||||||
|
// private static String sanitize(String s) {
|
||||||
|
// String cleaned = s.replaceAll("[^\\p{L}\\p{N}_-]", "_");
|
||||||
|
// return cleaned.length() > 64 ? cleaned.substring(0, 64) : cleaned;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
package com.zg.project.wisdom.controller;
|
||||||
|
|
||||||
|
import com.zg.framework.web.domain.AjaxResult;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
|
import org.springframework.util.unit.DataSize;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 多媒体上传控制器(支持图片与视频并行落盘)
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/system/media")
|
||||||
|
public class MediaUploadController {
|
||||||
|
|
||||||
|
/** 根目录(如需配置化,可改为从 application.yml 读取) */
|
||||||
|
private static final Path ROOT_DIR = Paths.get("D:/uploads");
|
||||||
|
|
||||||
|
/** 本次上传总大小限制:100MB */
|
||||||
|
private static final long MAX_TOTAL_BYTES = DataSize.ofMegabytes(100).toBytes();
|
||||||
|
|
||||||
|
/** 图片/视频数量限制 */
|
||||||
|
private static final int MAX_IMAGE_COUNT = 100;
|
||||||
|
private static final int MAX_VIDEO_COUNT = 5;
|
||||||
|
|
||||||
|
/** 单次请求内的并发上限(建议 2~4;默认 4) */
|
||||||
|
private static final int PER_REQUEST_CONCURRENCY = 4;
|
||||||
|
|
||||||
|
/** 注入线程池 Bean:threadPoolTaskExecutor */
|
||||||
|
@Resource(name = "threadPoolTaskExecutor")
|
||||||
|
private ThreadPoolTaskExecutor executor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传接口
|
||||||
|
*/
|
||||||
|
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
|
public AjaxResult upload(
|
||||||
|
@RequestParam("username") String username,
|
||||||
|
@RequestParam("nameBase") String nameBase,
|
||||||
|
@RequestPart(value = "images", required = false) MultipartFile[] images,
|
||||||
|
@RequestPart(value = "videos", required = false) MultipartFile[] videos
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
// 1. 基础校验
|
||||||
|
if (StringUtils.isBlank(username)) {
|
||||||
|
return AjaxResult.error("username 不能为空");
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(nameBase)) {
|
||||||
|
return AjaxResult.error("nameBase(命名信息)不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
int imageCount = images == null ? 0 : images.length;
|
||||||
|
int videoCount = videos == null ? 0 : videos.length;
|
||||||
|
|
||||||
|
if (imageCount == 0 && videoCount == 0) {
|
||||||
|
return AjaxResult.error("请至少上传一张图片或一段视频");
|
||||||
|
}
|
||||||
|
if (imageCount > MAX_IMAGE_COUNT) {
|
||||||
|
return AjaxResult.error("图片最多支持上传 " + MAX_IMAGE_COUNT + " 张");
|
||||||
|
}
|
||||||
|
if (videoCount > MAX_VIDEO_COUNT) {
|
||||||
|
return AjaxResult.error("视频最多支持上传 " + MAX_VIDEO_COUNT + " 段");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 总体积校验
|
||||||
|
long totalBytes = 0L;
|
||||||
|
if (images != null) for (MultipartFile f : images) totalBytes += safeSize(f);
|
||||||
|
if (videos != null) for (MultipartFile f : videos) totalBytes += safeSize(f);
|
||||||
|
if (totalBytes > MAX_TOTAL_BYTES) {
|
||||||
|
return AjaxResult.error("本次上传总大小超过 100 MB(约 " + (totalBytes / 1024 / 1024) + " MB)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 目标目录
|
||||||
|
String base = sanitize(nameBase);
|
||||||
|
String user = sanitize(username);
|
||||||
|
String folderName = base + "_" + user;
|
||||||
|
Path targetDir = ROOT_DIR.resolve(folderName).normalize();
|
||||||
|
if (!targetDir.startsWith(ROOT_DIR)) {
|
||||||
|
return AjaxResult.error("非法路径");
|
||||||
|
}
|
||||||
|
Files.createDirectories(targetDir);
|
||||||
|
|
||||||
|
// 4. 并发落盘任务
|
||||||
|
int seq = 1;
|
||||||
|
List<CompletableFuture<Map<String, Object>>> futures = new ArrayList<>();
|
||||||
|
Semaphore semaphore = new Semaphore(PER_REQUEST_CONCURRENCY);
|
||||||
|
|
||||||
|
// 4.1 图片(不做格式校验)
|
||||||
|
if (images != null) {
|
||||||
|
for (MultipartFile img : images) {
|
||||||
|
if (img == null || img.isEmpty()) continue;
|
||||||
|
|
||||||
|
String ext = getExtension(img.getOriginalFilename()).toLowerCase(Locale.ROOT);
|
||||||
|
final String filename = String.format(
|
||||||
|
"%s%s%03d%s", base, user, seq++, StringUtils.isBlank(ext) ? "" : "." + ext
|
||||||
|
);
|
||||||
|
final Path dest = targetDir.resolve(filename).normalize();
|
||||||
|
|
||||||
|
futures.add(CompletableFuture.supplyAsync(() -> {
|
||||||
|
acquire(semaphore);
|
||||||
|
try { return saveOne(img, dest, "image"); }
|
||||||
|
finally { semaphore.release(); }
|
||||||
|
}, executor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4.2 视频(不做格式校验)
|
||||||
|
if (videos != null) {
|
||||||
|
for (MultipartFile vid : videos) {
|
||||||
|
if (vid == null || vid.isEmpty()) continue;
|
||||||
|
|
||||||
|
String ext = getExtension(vid.getOriginalFilename()).toLowerCase(Locale.ROOT);
|
||||||
|
final String filename = String.format(
|
||||||
|
"%s%s%03d%s", base, user, seq++, StringUtils.isBlank(ext) ? "" : "." + ext
|
||||||
|
);
|
||||||
|
final Path dest = targetDir.resolve(filename).normalize();
|
||||||
|
|
||||||
|
futures.add(CompletableFuture.supplyAsync(() -> {
|
||||||
|
acquire(semaphore);
|
||||||
|
try { return saveOne(vid, dest, "video"); }
|
||||||
|
finally { semaphore.release(); }
|
||||||
|
}, executor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 等待完成并返回
|
||||||
|
List<Map<String, Object>> files = new ArrayList<>(futures.size());
|
||||||
|
for (CompletableFuture<Map<String, Object>> f : futures) {
|
||||||
|
files.add(f.join());
|
||||||
|
}
|
||||||
|
files.sort(Comparator.comparing(m -> String.valueOf(m.get("path"))));
|
||||||
|
|
||||||
|
Map<String, Object> data = new LinkedHashMap<>();
|
||||||
|
data.put("folder", targetDir.toString());
|
||||||
|
data.put("username", username);
|
||||||
|
data.put("nameBase", nameBase);
|
||||||
|
data.put("totalBytes", totalBytes);
|
||||||
|
data.put("count", files.size());
|
||||||
|
data.put("files", files);
|
||||||
|
|
||||||
|
return AjaxResult.success("上传成功", data);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
return AjaxResult.error("保存文件失败:" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================= 辅助方法 =========================
|
||||||
|
|
||||||
|
/** 安全获取文件大小,避免 NPE */
|
||||||
|
private static long safeSize(MultipartFile f) {
|
||||||
|
try { return (f == null) ? 0L : f.getSize(); }
|
||||||
|
catch (Exception ignored) { return 0L; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取扩展名(无则返回空字符串) */
|
||||||
|
private static String getExtension(String originalName) {
|
||||||
|
if (StringUtils.isBlank(originalName)) return "";
|
||||||
|
int i = originalName.lastIndexOf('.');
|
||||||
|
return (i >= 0 && i < originalName.length() - 1) ? originalName.substring(i + 1) : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 单文件保存 */
|
||||||
|
private Map<String, Object> saveOne(MultipartFile src, Path dest, String type) {
|
||||||
|
try {
|
||||||
|
Path parent = dest.getParent();
|
||||||
|
if (parent == null) throw new IOException("父目录为空");
|
||||||
|
if (!dest.normalize().startsWith(parent.normalize())) throw new IOException("非法路径");
|
||||||
|
|
||||||
|
try (InputStream in = src.getInputStream();
|
||||||
|
OutputStream out = Files.newOutputStream(dest,
|
||||||
|
StandardOpenOption.CREATE,
|
||||||
|
StandardOpenOption.TRUNCATE_EXISTING,
|
||||||
|
StandardOpenOption.WRITE)) {
|
||||||
|
in.transferTo(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> m = new LinkedHashMap<>();
|
||||||
|
m.put("type", type);
|
||||||
|
m.put("path", dest.toString());
|
||||||
|
m.put("sizeBytes", src.getSize());
|
||||||
|
m.put("sizeMB", String.format(Locale.ROOT, "%.2f", src.getSize() / 1024.0 / 1024.0));
|
||||||
|
return m;
|
||||||
|
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new RuntimeException("保存失败:" + dest.getFileName() + ",原因:" + ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取信号量许可证(受控并发) */
|
||||||
|
private static void acquire(Semaphore sem) {
|
||||||
|
try { sem.acquire(); }
|
||||||
|
catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
throw new RuntimeException("线程被中断", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 文件名/目录名清洗 */
|
||||||
|
private static String sanitize(String s) {
|
||||||
|
String cleaned = s.replaceAll("[^\\p{L}\\p{N}_-]", "_");
|
||||||
|
return cleaned.length() > 64 ? cleaned.substring(0, 64) : cleaned;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,4 +23,6 @@ public class PkDatDTO {
|
|||||||
private String xmMs;
|
private String xmMs;
|
||||||
/** 库位 */
|
/** 库位 */
|
||||||
private String pcode;
|
private String pcode;
|
||||||
|
/** 打印机编号 */
|
||||||
|
private Integer printer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ spring:
|
|||||||
druid:
|
druid:
|
||||||
# 主库数据源
|
# 主库数据源
|
||||||
master:
|
master:
|
||||||
|
# url: jdbc:mysql://101.132.133.142:3306/wisdom?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||||
url: jdbc:mysql://192.168.1.20:3306/wisdom?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
url: jdbc:mysql://192.168.1.20:3306/wisdom?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||||
# url: jdbc:mysql://192.168.1.251:3306/wisdom?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
# url: jdbc:mysql://192.168.1.251:3306/wisdom?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||||
# url: jdbc:mysql://localhost:3306/wisdom?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
# url: jdbc:mysql://localhost:3306/wisdom?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||||
|
|||||||
@@ -57,9 +57,9 @@ spring:
|
|||||||
servlet:
|
servlet:
|
||||||
multipart:
|
multipart:
|
||||||
# 单个文件大小
|
# 单个文件大小
|
||||||
max-file-size: 10MB
|
max-file-size: 100MB
|
||||||
# 设置总上传的文件大小
|
# 设置总上传的文件大小
|
||||||
max-request-size: 20MB
|
max-request-size: 100MB
|
||||||
# 服务模块
|
# 服务模块
|
||||||
devtools:
|
devtools:
|
||||||
restart:
|
restart:
|
||||||
@@ -68,6 +68,7 @@ spring:
|
|||||||
# redis 配置
|
# redis 配置
|
||||||
redis:
|
redis:
|
||||||
# 地址
|
# 地址
|
||||||
|
# host: 101.132.133.142
|
||||||
host: 192.168.1.20
|
host: 192.168.1.20
|
||||||
# host: 192.168.1.251
|
# host: 192.168.1.251
|
||||||
# host: localhost
|
# host: localhost
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
VALUES
|
VALUES
|
||||||
<foreach collection="list" item="item" separator=",">
|
<foreach collection="list" item="item" separator=",">
|
||||||
(#{item.wlNo}, #{item.realQty}, 1, 1, #{item.sapNo},
|
(#{item.wlNo}, #{item.realQty}, 1, 1, #{item.sapNo},
|
||||||
#{item.gysMc}, #{item.remark}, #{item.xmMs}, #{item.pcode}, 1)
|
#{item.gysMc}, #{item.remark}, #{item.xmMs}, #{item.pcode}, #{item.printer})
|
||||||
</foreach>
|
</foreach>
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user