该类负责配置和初始化Apache Tika组件,用于文档内容检测和解析。 + * 通过加载自定义的tika-config.xml配置文件来定制Tika的行为。
+ * + *使用示例:
+ *+ * {@code + * // 自动注入Tika实例 + * @Autowired + * private Tika tika; + * + * // 使用Tika检测文件类型 + * String fileType = tika.detect(file); + * + * // 使用Tika解析文件内容 + * String content = tika.parseToString(file); + * } + *+ * + * @author system + * @version 1.0 + * + * @see Tika + * @see TikaConfig + * @see Detector + * @see Parser + */ +@Configuration +@RequiredArgsConstructor +public class MyTikaConfig { + + /** + * Spring资源加载器,用于加载类路径下的配置文件 + */ + private final ResourceLoader resourceLoader; + + /** + * 创建并配置Tika实例 + * + *
该方法会从类路径下加载tika-config.xml配置文件,基于该配置创建TikaConfig, + * 然后获取配置中的检测器(Detector)和解析器(Parser),最终构建Tika实例。
+ * + *配置文件的预期位置:src/main/resources/tika-config.xml
+ * + * @return 配置好的Tika实例,可用于文件类型检测和内容解析 + * @throws TikaException 当Tika配置处理过程中发生错误时抛出 + * @throws IOException 当读取配置文件发生I/O错误时抛出 + * @throws SAXException 当解析XML配置文件发生错误时抛出 + * + * @see TikaConfig + * @see Detector + * @see AutoDetectParser + * + * @example 使用自定义配置的Tika实例 + *+ * {@code + * Tika tika = myTikaConfig.tika(); + * String mimeType = tika.detect(new File("document.pdf")); + * String content = tika.parseToString(new File("document.pdf")); + * } + *+ */ + @Bean + public Tika tika() throws TikaException, IOException, SAXException { + // 从类路径加载Tika配置文件 + Resource resource = resourceLoader.getResource("classpath:tika-config.xml"); + InputStream inputStream = resource.getInputStream(); + + // 基于配置文件创建Tika配置 + TikaConfig config = new TikaConfig(inputStream); + + // 从配置中获取文件类型检测器 + Detector detector = config.getDetector(); + + // 创建自动检测解析器,使用自定义配置 + Parser autoDetectParser = new AutoDetectParser(config); + + // 构建并返回Tika实例,组合检测器和解析器 + return new Tika(detector, autoDetectParser); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/common/config/tika/handle/FileCharsetCheck.java b/src/main/java/com/example/demo/common/config/tika/handle/FileCharsetCheck.java new file mode 100644 index 0000000..b6f59bd --- /dev/null +++ b/src/main/java/com/example/demo/common/config/tika/handle/FileCharsetCheck.java @@ -0,0 +1,65 @@ +package com.example.demo.common.config.tika.handle; + +import lombok.extern.slf4j.Slf4j; +import org.apache.tika.detect.AutoDetectReader; +import org.apache.tika.exception.TikaException; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; + +/** + * 文件字符集检测工具类 + *
+ * 该类使用Apache Tika库的AutoDetectReader自动检测输入流的字符集编码。 + * 主要用于识别文件或数据流的字符集,如UTF-8、GBK、ISO-8859-1等。 + *
+ * + * @author system + * @version 1.0 + */ +@Slf4j +public class FileCharsetCheck { + + /** + * 检测输入流的字符集编码 + *+ * 该方法通过分析输入流的前几个字节来自动识别字符集编码。 + * 如果检测过程中发生异常,将记录错误日志并返回null。 + *
+ * + *注意:该方法会读取输入流的起始部分内容,但不会重置流的位置。 + * 调用者需要自行处理输入流的位置重置或重新创建输入流。
+ * + *使用示例:
+ *{@code + * InputStream inputStream = new FileInputStream("example.txt"); + * String charset = FileCharsetCheck.check(inputStream); + * if (charset != null) { + * System.out.println("文件编码: " + charset); + * } else { + * System.out.println("编码检测失败"); + * } + * }+ * + * @param input 要检测的输入流,不能为null + * @return 检测到的字符集名称(如"UTF-8"),如果检测失败则返回null + * @throws IllegalArgumentException 如果输入流为null + * + * @see AutoDetectReader + * @see Charset + */ + public static String check(InputStream input) { + if (input == null) { + throw new IllegalArgumentException("输入流不能为null"); + } + + try { + Charset charset = new AutoDetectReader(input).getCharset(); + return charset.name(); + } catch (IOException | TikaException e) { + log.error("解析文件编码异常!", e); + } + return null; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/common/config/tika/handle/FileTypeCheck.java b/src/main/java/com/example/demo/common/config/tika/handle/FileTypeCheck.java new file mode 100644 index 0000000..57d5330 --- /dev/null +++ b/src/main/java/com/example/demo/common/config/tika/handle/FileTypeCheck.java @@ -0,0 +1,119 @@ +package com.example.demo.common.config.tika.handle; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; +import org.apache.tika.Tika; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * 文件类型检查工具类 + * 使用Apache Tika库检测文件真实类型,防止文件类型欺骗攻击 + * 通过白名单机制限制可上传的文件类型,增强系统安全性 + * + * @author system + * @version 1.0 + */ +@Slf4j +public class FileTypeCheck { + + /** + * 允许的文件类型白名单 + * 包含办公文档、图片、媒体文件、数据文件等常见安全文件类型 + */ + private static final List
+ * 该类定义了常见的文件MIME类型常量,用于文件上传、下载、验证等场景。 + * 所有常量均为标准的MIME类型字符串。 + * 参考了标准MIME类型定义及常见文件格式:cite[2]:cite[9]。 + *
+ * + * @author system + * @version 1.0 + */ +public class FileTypeConst { + + /* 电子文档与数据文件 */ + + /** + * Excel 97-2003 工作表格式 (.xls) + */ + public static final String FILE_TYPE_XLS = "application/vnd.ms-excel"; + + /** + * Excel 2007及以上 工作表格式 (.xlsx) + */ + public static final String FILE_TYPE_XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; + + /** + * Word 97-2003 文档格式 (.doc) + */ + public static final String FILE_TYPE_DOC = "application/msword"; + + /** + * Word 2007及以上 文档格式 (.docx) + */ + public static final String FILE_TYPE_DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; + + /** + * PowerPoint 97-2003 演示文稿格式 (.ppt) + */ + public static final String FILE_TYPE_PPT = "application/vnd.ms-powerpoint"; + + /** + * PowerPoint 2007及以上 演示文稿格式 (.pptx) + */ + public static final String FILE_TYPE_PPTX = "application/vnd.openxmlformats-officedocument.presentationml.presentation"; + + /** + * Adobe PDF 文档格式 (.pdf) + */ + public static final String FILE_TYPE_PDF = "application/pdf"; + + /** + * JSON 数据格式 (.json) + */ + public static final String FILE_TYPE_JSON = "application/json"; + + /** + * XML 数据格式 (.xml) + */ + public static final String FILE_TYPE_XML = "application/xml"; + + /** + * 纯文本文件格式 (.txt) + */ + public static final String FILE_TYPE_TXT = "text/plain"; + + /** + * CSV 逗号分隔值文件格式 (.csv) + */ + public static final String FILE_TYPE_CSV = "text/csv"; + + /** + * HTML 网页文件格式 (.html, .htm) + */ + public static final String FILE_TYPE_HTML = "text/html"; + + /** + * CSS 样式表文件格式 (.css) + */ + public static final String FILE_TYPE_CSS = "text/css"; + + /* 压缩文件 */ + + /** + * ZIP 压缩文件格式 (.zip) + */ + public static final String FILE_TYPE_ZIP = "application/zip"; + + /** + * RAR 压缩文件格式 (.rar) + */ + public static final String FILE_TYPE_RAR = "application/vnd.rar"; + + /** + * 7-Zip 压缩文件格式 (.7z) + */ + public static final String FILE_TYPE_7Z = "application/x-7z-compressed"; + + /** + * GZIP 压缩文件格式 (.gz) + */ + public static final String FILE_TYPE_GZ = "application/gzip"; + + /** + * TAR 归档文件格式 (.tar) + */ + public static final String FILE_TYPE_TAR = "application/x-tar"; + + /* 可执行文件与安装包 */ + + /** + * Windows 可执行程序格式 (.exe) + */ + public static final String FILE_TYPE_EXE = "application/x-msdownload"; + + /** + * Windows 安装包格式 (.msi) + */ + public static final String FILE_TYPE_MSI = "application/x-msi"; + + /** + * Android 应用安装包格式 (.apk) + */ + public static final String FILE_TYPE_APK = "application/vnd.android.package-archive"; + + /** + * Debian/Ubuntu 系统安装包格式 (.deb) + */ + public static final String FILE_TYPE_DEB = "application/vnd.debian.binary-package"; + + /** + * Red Hat/CentOS 系统安装包格式 (.rpm) + */ + public static final String FILE_TYPE_RPM = "application/x-rpm"; + + /** + * macOS 磁盘映像文件格式 (.dmg) + */ + public static final String FILE_TYPE_DMG = "application/x-apple-diskimage"; + + /** + * Java 归档文件格式 (.jar) + */ + public static final String FILE_TYPE_JAR = "application/java-archive"; + + /* 图片与图形文件 */ + + /** + * JPEG 图像格式 (.jpg, .jpeg) + */ + public static final String FILE_TYPE_JPEG = "image/jpeg"; + + /** + * PNG 图像格式 (.png) + */ + public static final String FILE_TYPE_PNG = "image/png"; + + /** + * GIF 图像格式 (.gif) + */ + public static final String FILE_TYPE_GIF = "image/gif"; + + /** + * BMP 位图格式 (.bmp) + */ + public static final String FILE_TYPE_BMP = "image/bmp"; + + /** + * WebP 图像格式 (.webp) + */ + public static final String FILE_TYPE_WEBP = "image/webp"; + + /** + * TIFF 高质量图像格式 (.tiff, .tif) + */ + public static final String FILE_TYPE_TIFF = "image/tiff"; + + /** + * ICO 图标文件格式 (.ico) + */ + public static final String FILE_TYPE_ICO = "image/x-icon"; + + /** + * SVG 矢量图形格式 (.svg) - 标准MIME类型为 image/svg+xml:cite[2] + */ + public static final String FILE_TYPE_SVG = "image/svg+xml"; + + /** + * HEIC/HEIF 高效图像文件格式 (.heic, .heif) + */ + public static final String FILE_TYPE_HEIC = "image/heic"; + + /* 音频文件 */ + + /** + * MP3 音频格式 (.mp3) + */ + public static final String FILE_TYPE_MP3 = "audio/mpeg"; + + /** + * WAV 音频格式 (.wav) + */ + public static final String FILE_TYPE_WAV = "audio/wav"; + + /** + * AAC 高级音频编码格式 (.aac) + */ + public static final String FILE_TYPE_AAC = "audio/aac"; + + /** + * OGG 音频格式 (.ogg, .oga) + */ + public static final String FILE_TYPE_OGG_AUDIO = "audio/ogg"; + + /** + * FLAC 无损音频格式 (.flac) + */ + public static final String FILE_TYPE_FLAC = "audio/flac"; + + /** + * MIDI 音乐文件格式 (.mid, .midi) + */ + public static final String FILE_TYPE_MIDI = "audio/midi"; + + /* 视频文件 */ + + /** + * MP4 视频格式 (.mp4) + */ + public static final String FILE_TYPE_MP4 = "video/mp4"; + + /** + * AVI 音频视频交错格式 (.avi) + */ + public static final String FILE_TYPE_AVI = "video/x-msvideo"; + + /** + * MOV QuickTime 视频格式 (.mov) + */ + public static final String FILE_TYPE_MOV = "video/quicktime"; + + /** + * WebM 开放网络媒体格式 (.webm) + */ + public static final String FILE_TYPE_WEBM = "video/webm"; + + /** + * MPEG-1/2 视频格式 (.mpeg, .mpg) + */ + public static final String FILE_TYPE_MPEG = "video/mpeg"; + + /** + * WMV Windows Media 视频格式 (.wmv) + */ + public static final String FILE_TYPE_WMV = "video/x-ms-wmv"; + + /** + * FLV Flash 视频格式 (.flv) + */ + public static final String FILE_TYPE_FLV = "video/x-flv"; + + /** + * 3GPP 多媒体容器格式 (.3gp) + */ + public static final String FILE_TYPE_3GP = "video/3gpp"; + + /* 脚本与源代码文件 */ + + /** + * JavaScript 文件格式 (.js) + */ + public static final String FILE_TYPE_JS = "application/javascript"; + + /** + * TypeScript 文件格式 (.ts) - 通常作为文本处理 + */ + public static final String FILE_TYPE_TS = "application/typescript"; + + /** + * Python 脚本文件格式 (.py) + */ + public static final String FILE_TYPE_PY = "text/x-python"; + + /** + * Java 源代码文件格式 (.java) + */ + public static final String FILE_TYPE_JAVA = "text/x-java-source"; + + /** + * C/C++ 头文件格式 (.h) + */ + public static final String FILE_TYPE_H = "text/x-c"; + + /** + * C/C++ 源文件格式 (.c, .cpp) + */ + public static final String FILE_TYPE_C = "text/x-c"; + + /** + * PHP 脚本文件格式 (.php) + */ + public static final String FILE_TYPE_PHP = "application/x-php"; + + /** + * Shell 脚本文件格式 (.sh) + */ + public static final String FILE_TYPE_SH = "application/x-sh"; + + /** + * PowerShell 脚本文件格式 (.ps1) + */ + public static final String FILE_TYPE_PS1 = "application/x-powershell"; + + /** + * Batch 批处理文件格式 (.bat) - 通常作为文本处理 + */ + public static final String FILE_TYPE_BAT = "application/x-msdownload"; + + /* 字体文件 */ + + /** + * TrueType 字体格式 (.ttf) + */ + public static final String FILE_TYPE_TTF = "font/ttf"; + + /** + * OpenType 字体格式 (.otf) + */ + public static final String FILE_TYPE_OTF = "font/otf"; + + /** + * Web Open Font 格式 (.woff) + */ + public static final String FILE_TYPE_WOFF = "font/woff"; + + /** + * Web Open Font 格式 2.0 (.woff2) + */ + public static final String FILE_TYPE_WOFF2 = "font/woff2"; + + /* 其他文件类型 */ + + /** + * 电子邮件格式 (.eml) + */ + public static final String FILE_TYPE_EML = "message/rfc822"; + + /** + * iCalendar 日历文件格式 (.ics) + */ + public static final String FILE_TYPE_ICS = "text/calendar"; + + /** + * SQL 数据库转储文件格式 (.sql) + */ + public static final String FILE_TYPE_SQL = "application/sql"; + + /** + * 电子书 EPUB 格式 (.epub) + */ + public static final String FILE_TYPE_EPUB = "application/epub+zip"; + + /** + * 虚拟磁盘文件格式 (.iso) + */ + public static final String FILE_TYPE_ISO = "application/x-iso9660-image"; +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/common/constant/GlobalConstants.java b/src/main/java/com/example/demo/common/constant/GlobalConstants.java new file mode 100644 index 0000000..050936e --- /dev/null +++ b/src/main/java/com/example/demo/common/constant/GlobalConstants.java @@ -0,0 +1,163 @@ +package com.example.demo.common.constant; + +/** + * 系统常量类 + * 定义系统中使用的各种常量,包括错误码、文件类型、状态码等 + * + * @author system + * @version 1.0 + */ +public class GlobalConstants { + + /** 否 */ + public static final String N = "0"; + + /** 是 */ + public static final String Y = "1"; + + // ==================== 文件相关常量 ==================== // + + public static class FileExtensionType { + + /** + * XML文件扩展名 + */ + public static final String FILE_EXTENSION_XML = ".xml"; + + /** + * TXT文件扩展名 + */ + public static final String FILE_EXTENSION_TXT = ".txt"; + + } + + public static class FileStatus { + + /** + * 文件上传状态:已上传 + */ + public static final String FILE_STATUS_UPLOADED = "uploaded"; + + /** + * 文件状态:已解析 + */ + public static final String FILE_STATUS_PARSED = "parsed"; + + /** + * 文件状态:已转换 + */ + public static final String FILE_STATUS_CONVERTED = "converted"; + + } + + // ==================== XML解析相关常量 ==================== // + + public static class XMLTagType { + + /** + * XML标签类型:根节点 + */ + public static final String XML_TAG_TYPE_ROOT = "root"; + + /** + * XML标签类型:普通节点 + */ + public static final String XML_TAG_TYPE_NODE = "node"; + + /** + * XML标签类型:叶子节点 + */ + public static final String XML_TAG_TYPE_LEAF = "leaf"; + + /** + * XML属性:label + */ + public static final String XML_ATTR_LABEL = "label"; + + /** + * XML属性:isNull + */ + public static final String XML_ATTR_IS_NULL = "isNull"; + + /** + * XML属性:node + */ + public static final String XML_ATTR_NODE = "node"; + + } + + // ==================== 通用状态常量 ==================== // + + public static class Status { + + /** + * 未删除状态 + */ + public static final String NOT_DELETED = "0"; + + /** + * 已删除状态 + */ + public static final String DELETED = "1"; + + /** + * 启用状态 + */ + public static final String ENABLED = "1"; + + /** + * 禁用状态 + */ + public static final String DISABLED = "0"; + + } + + // ==================== 字符集常量 ==================== // + + public static class Charset { + + /** + * UTF-8字符集 + */ + public static final String CHARSET_UTF8 = "UTF-8"; + + } + + // ==================== 路径常量 ==================== // + + public static class Path { + + /** + * 路径分隔符 + */ + public static final String PATH_SEPARATOR = "/"; + + /** + * Windows路径分隔符 + */ + public static final String WINDOWS_PATH_SEPARATOR = "\\"; + + } + + // ==================== 缓存相关常量 ==================== // + + public static class Cache { + + /** + * 解析规则缓存键前缀 + */ + public static final String CACHE_KEY_PARSE_RULE = "parse_rule:"; + + /** + * 映射规则缓存键前缀 + */ + public static final String CACHE_KEY_MAPPER_RULE = "mapper_rule:"; + + /** + * 默认缓存过期时间(秒) + */ + public static final long DEFAULT_CACHE_EXPIRE = 3600L; + + } + +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/common/domain/BaseDTO.java b/src/main/java/com/example/demo/common/domain/BaseDTO.java new file mode 100644 index 0000000..276ecb1 --- /dev/null +++ b/src/main/java/com/example/demo/common/domain/BaseDTO.java @@ -0,0 +1,58 @@ +package com.example.demo.common.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 基础数据传输对象 + * 所有DTO类的基类,用于数据在不同层之间的传递 + * + * @author system + * @version 1.0 + */ +@Schema(description = "基础数据传输对象") +@Getter +@Setter +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public class BaseDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @Schema(description = "ID") + private String id; + + /** + * 创建时间 + */ + @Schema(description = "创建时间") + private Date createdTime; + + /** + * 创建人ID + */ + @Schema(description = "创建人ID") + private String createdId; + + /** + * 更新时间 + */ + @Schema(description = "更新时间") + private Date updatedTime; + + /** + * 更新人ID + */ + @Schema(description = "更新人ID") + private String updatedId; +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/common/domain/BaseEntity.java b/src/main/java/com/example/demo/common/domain/BaseEntity.java new file mode 100644 index 0000000..b494c1f --- /dev/null +++ b/src/main/java/com/example/demo/common/domain/BaseEntity.java @@ -0,0 +1,104 @@ +package com.example.demo.common.domain; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.core.keygen.KeyGenerators; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.experimental.SuperBuilder; +import org.springframework.format.annotation.DateTimeFormat; + +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 基础实体类 + * 所有数据库实体类的基类,包含通用字段和注解 + * + * @author system + * @version 1.0 + */ +@Schema(description = "基础实体类") +@Getter +@Setter +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public class BaseEntity implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @Id(keyType = KeyType.Generator, value = KeyGenerators.uuid) + @Schema(description = "ID") + private String id; + + /** + * 命名空间 + */ + @Schema(description = "命名空间") + private String nameSpace; + + /** + * 排序字段 + */ + @Schema(description = "排序字段") + private String sortName; + + /** + * 是否删除(0:未删除,1:已删除) + */ + @Column(isLogicDelete = true) + @Schema(description = "是否删除") + private String isDelete; + + /** + * 乐观锁版本号 + */ + @Column(version = true) + @Schema(description = "乐观锁版本号") + private Integer revision; + + /** + * 创建时间 + */ + @Column(onInsertValue = "now()") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @Schema(description = "创建时间") + private Date createdTime; + + /** + * 创建人ID + */ + @Schema(description = "创建人ID") + private String createdId; + + /** + * 更新时间 + */ + @Column(onUpdateValue = "now()", onInsertValue = "now()") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @Schema(description = "更新时间") + private Date updatedTime; + + /** + * 更新人ID + */ + @Schema(description = "更新人ID") + private String updatedId; + + /** + * 租户ID + */ + @Schema(description = "租户ID") + private String tenantId; +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/common/domain/BaseQueryDTO.java b/src/main/java/com/example/demo/common/domain/BaseQueryDTO.java new file mode 100644 index 0000000..24ac4ca --- /dev/null +++ b/src/main/java/com/example/demo/common/domain/BaseQueryDTO.java @@ -0,0 +1,62 @@ +package com.example.demo.common.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import cn.zhxu.bs.bean.DbField; +import lombok.experimental.SuperBuilder; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 基础查询数据传输对象 + * 所有查询DTO类的基类,用于封装查询条件 + * + * @author system + * @version 1.0 + */ +@Schema(description = "基础查询数据传输对象") +@Getter +@Setter +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public class BaseQueryDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 模糊查询 + */ + @Schema(description = "模糊查询") + private String fuzzy; + + /** + * 分页参数:当前页码 + */ + @Builder.Default + @Schema(description = "当前页码") + private Integer pageNum = 1; + + /** + * 分页参数:每页条数 + */ + @Builder.Default + @Schema(description = "每页条数") + private Integer pageSize = 10; + + /** + * 排序字段 + */ + @Schema(description = "排序字段") + private String sortField; + + /** + * 排序方式:asc或desc + */ + @Schema(description = "排序方式") + private String sortOrder; + +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/common/domain/BaseVO.java b/src/main/java/com/example/demo/common/domain/BaseVO.java new file mode 100644 index 0000000..063f48d --- /dev/null +++ b/src/main/java/com/example/demo/common/domain/BaseVO.java @@ -0,0 +1,80 @@ +package com.example.demo.common.domain; + +import com.mybatisflex.annotation.Column; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.experimental.SuperBuilder; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 基础视图对象 + * 所有VO类的基类,用于向前端返回数据 + * + * @author system + * @version 1.0 + */ +@Schema(description = "基础视图对象") +@Getter +@Setter +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public class BaseVO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @Schema(description = "ID") + private String id; + + /** + * 键 + */ + @Schema(description = "key") + private String key; + + /** + * 名称 + */ + @Schema(description = "name") + private String name; + + /** + * 创建时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @Schema(description = "创建时间") + private Date createdTime; + + /** + * 创建人ID + */ + @Schema(description = "创建人ID") + private String createdId; + + /** + * 更新时间 + */ + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @Schema(description = "更新时间") + private Date updatedTime; + + /** + * 更新人ID + */ + @Schema(description = "更新人ID") + private String updatedId; + + /** + * 是否删除(0:未删除,1:已删除) + */ + @Schema(description = "是否删除") + private String isDelete; +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/common/exception/BusinessException.java b/src/main/java/com/example/demo/common/exception/BusinessException.java new file mode 100644 index 0000000..3c707d5 --- /dev/null +++ b/src/main/java/com/example/demo/common/exception/BusinessException.java @@ -0,0 +1,76 @@ +package com.example.demo.common.exception; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; + +import java.io.Serial; + +/** + * 业务异常类 + * 用于表示业务逻辑中的异常情况 + * + * @author system + * @version 1.0 + */ +@Getter +@Setter(value = AccessLevel.PRIVATE) +public class BusinessException extends RuntimeException { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 错误码 + */ + private int code; + + /** + * 构造函数 + * + * @param code 错误码 + * @param message 错误信息 + */ + public BusinessException(int code, String message) { + super(message); + this.code = code; + } + + /** + * 构造函数,使用默认错误码 + * + * @param message 错误信息 + */ + public BusinessException(String message) { + super(message); + this.code = 500; + } + + /** + * 构造函数,包含异常原因 + * + * @param code 错误码 + * @param message 错误信息 + * @param cause 异常原因 + */ + public BusinessException(int code, String message, Throwable cause) { + super(message, cause); + this.code = code; + } + + /** + * 构造函数,包含异常原因,使用默认错误码 + * + * @param message 错误信息 + * @param cause 异常原因 + */ + public BusinessException(String message, Throwable cause) { + super(message, cause); + this.code = 500; + } + + @Override + public String toString() { + return "BusinessException{code=" + code + ", message='" + getMessage() + "'}"; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/common/exception/global/GlobalExceptionHandler.java b/src/main/java/com/example/demo/common/exception/global/GlobalExceptionHandler.java new file mode 100644 index 0000000..c0f7dbf --- /dev/null +++ b/src/main/java/com/example/demo/common/exception/global/GlobalExceptionHandler.java @@ -0,0 +1,138 @@ +package com.example.demo.common.exception.global; + +import com.example.demo.common.wrapper.WrapMapper; +import com.example.demo.common.wrapper.Wrapper; +import com.example.demo.common.exception.BusinessException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.validation.BindException; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.multipart.MaxUploadSizeExceededException; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 全局异常处理器 + * 统一处理系统异常,返回规范的错误响应 + * + * @author system + * @version 1.0 + */ +@Slf4j +@RestControllerAdvice +public class GlobalExceptionHandler { + + /** + * 处理业务异常 + * + * @param e 业务异常 + * @return 错误响应 + */ + @ExceptionHandler(BusinessException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Wrapper