配送单据接口修改
This commit is contained in:
189
src/main/java/com/delivery/common/utils/LocalPhotoUtil.java
Normal file
189
src/main/java/com/delivery/common/utils/LocalPhotoUtil.java
Normal file
@@ -0,0 +1,189 @@
|
||||
package com.delivery.common.utils;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 本地图片保存工具
|
||||
* - 根目录:photo.root(默认 /data/upload/images)
|
||||
* - 目录结构:{documentType}/yyyy-MM-dd/
|
||||
* - 文件命名:
|
||||
* 入库:billNo_gysMc_yyyyMMddHHmmssSSS_index.ext
|
||||
* 出库:billNo_xmMs_yyyyMMddHHmmssSSS_index.ext
|
||||
*/
|
||||
@Component
|
||||
public class LocalPhotoUtil {
|
||||
|
||||
/** 磁盘根目录(Linux 默认) */
|
||||
@Value("${photo.root:/data/upload/images}")
|
||||
private String rootPath;
|
||||
|
||||
@Value("${photo.base-url:http://192.168.1.28/files}")
|
||||
private String baseUrl;
|
||||
|
||||
private static final String ILLEGAL_CHARS = "\\/:*?\"<>|";
|
||||
private static final long MAX_SIZE = 10 * 1024 * 1024; // 10MB
|
||||
private static final Set<String> ALLOWED =
|
||||
new HashSet<>(Arrays.asList("jpg","jpeg","png","gif","webp","bmp"));
|
||||
|
||||
/** yyyy-MM-dd(目录) */
|
||||
private String today() {
|
||||
return new SimpleDateFormat("yyyy-MM-dd").format(new Date());
|
||||
}
|
||||
|
||||
/** yyyyMMddHHmmssSSS(文件戳) */
|
||||
private String nowStamp() {
|
||||
return new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成基础名:
|
||||
* - 入库(photoType=0):billNo_gysMc
|
||||
* - 出库(photoType=1):billNo_xmMs
|
||||
* - 若为空 → 一律替换成 "无"
|
||||
*/
|
||||
public String buildBaseName(String photoType, String billNo, String xmMs, String gysMc) {
|
||||
String safeBillNo = sanitize(defaultString(billNo));
|
||||
String part;
|
||||
if ("0".equals(photoType)) {
|
||||
part = sanitize(defaultString(gysMc, "无"));
|
||||
} else {
|
||||
part = sanitize(defaultString(xmMs, "无"));
|
||||
}
|
||||
return sanitize(safeBillNo + "_" + part);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存单个文件
|
||||
* @param file 文件
|
||||
* @param subDir 一级子目录(documentType)
|
||||
* @param baseName 基础名
|
||||
* @param index 序号(从1开始)
|
||||
*/
|
||||
public SaveResult saveOne(MultipartFile file, String subDir, String baseName, int index) throws Exception {
|
||||
if (file == null || file.isEmpty()) {
|
||||
throw new IllegalArgumentException("文件为空");
|
||||
}
|
||||
if (file.getSize() > MAX_SIZE) {
|
||||
throw new IllegalArgumentException("图片不能超过10MB");
|
||||
}
|
||||
|
||||
String ext = resolveExt(file);
|
||||
String safeSub = sanitize(limitLen(defaultString(subDir, ""), 40));
|
||||
String dirPart = (safeSub.isEmpty() ? "" : safeSub + File.separator) + today() + File.separator;
|
||||
|
||||
String stamp = nowStamp();
|
||||
String safeBase = sanitize(limitLen(baseName, 80));
|
||||
String fileName = safeBase + "_" + stamp + "_" + index + ext;
|
||||
|
||||
File dir = new File(ensureTrailingSlash(rootPath), dirPart);
|
||||
Files.createDirectories(dir.toPath());
|
||||
|
||||
File dest = new File(dir, fileName);
|
||||
File tmp = new File(dir, fileName + ".uploading");
|
||||
|
||||
try (InputStream in = file.getInputStream()) {
|
||||
Files.copy(in, tmp.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
Files.move(tmp.toPath(), dest.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
|
||||
|
||||
SaveResult r = new SaveResult();
|
||||
String webPath = (dirPart + fileName).replace("\\", "/");
|
||||
r.setWebPath(webPath); // /{subDir}/yyyy-MM-dd/xxx.jpg
|
||||
r.setFileName(fileName);
|
||||
r.setAbsPath(dest.getAbsolutePath());
|
||||
r.setUrl(joinUrl(baseUrl, webPath)); // http://ip/files/...
|
||||
r.setSize(file.getSize());
|
||||
return r;
|
||||
}
|
||||
|
||||
/** 批量保存 */
|
||||
public List<SaveResult> saveBatch(List<MultipartFile> files, String subDir, String baseName) throws Exception {
|
||||
if (files == null || files.isEmpty()) return Collections.emptyList();
|
||||
List<SaveResult> list = new ArrayList<>(files.size());
|
||||
for (int i = 0; i < files.size(); i++) {
|
||||
list.add(saveOne(files.get(i), subDir, baseName, i + 1));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/** 扩展名解析 + 白名单校验 */
|
||||
private String resolveExt(MultipartFile file) {
|
||||
String origin = file.getOriginalFilename();
|
||||
if (origin != null) {
|
||||
int dot = origin.lastIndexOf('.');
|
||||
if (dot >= 0) {
|
||||
String pure = origin.substring(dot + 1).toLowerCase(Locale.ROOT);
|
||||
if (ALLOWED.contains(pure)) return "." + pure;
|
||||
}
|
||||
}
|
||||
String ct = String.valueOf(file.getContentType()).toLowerCase(Locale.ROOT);
|
||||
if (ct.contains("png")) return ".png";
|
||||
if (ct.contains("jpeg") || ct.contains("jpg")) return ".jpg";
|
||||
if (ct.contains("gif")) return ".gif";
|
||||
if (ct.contains("webp")) return ".webp";
|
||||
if (ct.contains("bmp")) return ".bmp";
|
||||
return ".bin";
|
||||
}
|
||||
|
||||
/** 清洗文件名 */
|
||||
public String sanitize(String name) {
|
||||
if (name == null) return "unnamed";
|
||||
String t = name.trim().replaceAll("\\s+", " ");
|
||||
StringBuilder sb = new StringBuilder(t.length());
|
||||
for (int i = 0; i < t.length(); i++) {
|
||||
char c = t.charAt(i);
|
||||
sb.append(ILLEGAL_CHARS.indexOf(c) >= 0 ? '_' : c);
|
||||
}
|
||||
String out = sb.toString();
|
||||
String upper = out.toUpperCase(Locale.ROOT);
|
||||
if (upper.matches("CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9]")) {
|
||||
out = "_" + out;
|
||||
}
|
||||
if (out.length() > 100) out = out.substring(0, 100);
|
||||
return out;
|
||||
}
|
||||
|
||||
private String defaultString(String s) { return s == null ? "" : s; }
|
||||
private String defaultString(String s, String def) { return (s == null || s.isEmpty()) ? def : s; }
|
||||
|
||||
private String ensureTrailingSlash(String p) {
|
||||
return (p.endsWith("/") || p.endsWith("\\")) ? p : (p + File.separator);
|
||||
}
|
||||
private String limitLen(String s, int max) {
|
||||
if (s == null) return "";
|
||||
return s.length() > max ? s.substring(0, max) : s;
|
||||
}
|
||||
private String joinUrl(String base, String path) {
|
||||
String b = base.endsWith("/") ? base.substring(0, base.length()-1) : base;
|
||||
String p = path.startsWith("/") ? path.substring(1) : path;
|
||||
return b + "/" + p;
|
||||
}
|
||||
|
||||
/** 返回值对象 */
|
||||
public static class SaveResult {
|
||||
private String webPath; // 相对Web路径(/subDir/yyyy-MM-dd/xxx.jpg)
|
||||
private String fileName; // 文件名
|
||||
private String absPath; // 服务器绝对路径
|
||||
private String url; // 可直接访问的URL
|
||||
private long size; // 字节
|
||||
|
||||
public String getWebPath() { return webPath; }
|
||||
public void setWebPath(String webPath) { this.webPath = webPath; }
|
||||
public String getFileName() { return fileName; }
|
||||
public void setFileName(String fileName) { this.fileName = fileName; }
|
||||
public String getAbsPath() { return absPath; }
|
||||
public void setAbsPath(String absPath) { this.absPath = absPath; }
|
||||
public String getUrl() { return url; }
|
||||
public void setUrl(String url) { this.url = url; }
|
||||
public long getSize() { return size; }
|
||||
public void setSize(long size) { this.size = size; }
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ public class DeliveryOrderController extends BaseController
|
||||
/**
|
||||
* 查询配送单据主列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('document:order:list')")
|
||||
// @PreAuthorize("@ss.hasPermi('document:order:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(DeliveryOrder deliveryOrder)
|
||||
{
|
||||
@@ -64,7 +64,7 @@ public class DeliveryOrderController extends BaseController
|
||||
/**
|
||||
* 获取配送单据主详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('document:order:query')")
|
||||
// @PreAuthorize("@ss.hasPermi('document:order:query')")
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getInfo(@PathVariable("id") Long id)
|
||||
{
|
||||
@@ -105,6 +105,11 @@ public class DeliveryOrderController extends BaseController
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 保存配送单
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
// @PreAuthorize("@ss.hasPermi('document:order:add')")
|
||||
// @Log(title = "配送单据主-保存(含附件)", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/save")
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.delivery.project.document.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.delivery.framework.web.domain.BaseEntity;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
@@ -115,6 +116,12 @@ public class DeliveryOrder extends BaseEntity
|
||||
@Excel(name = "是否删除", readConverterExp = "0=正常,1=已删除")
|
||||
private String isDelete;
|
||||
|
||||
/** 连表查询用:附件列表 */
|
||||
private List<DeliveryAttachment> attachments;
|
||||
|
||||
public List<DeliveryAttachment> getAttachments() { return attachments; }
|
||||
public void setAttachments(List<DeliveryAttachment> attachments) { this.attachments = attachments; }
|
||||
|
||||
public void setId(Long id)
|
||||
{
|
||||
this.id = id;
|
||||
|
||||
Reference in New Issue
Block a user